def test_upgradeability(temp_dir_path): # Prepare remote source for compilation download_github_dir(GITHUB_SOURCE_LINK, temp_dir_path) solidity_compiler = SolidityCompiler(source_dirs=[SourceDirs(SolidityCompiler.default_contract_dir()), SourceDirs(temp_dir_path)]) # Prepare the blockchain provider_uri = 'tester://pyevm/2' try: blockchain_interface = BlockchainDeployerInterface(provider_uri=provider_uri, compiler=solidity_compiler, gas_strategy=free_gas_price_strategy) blockchain_interface.connect() origin = blockchain_interface.client.accounts[0] BlockchainInterfaceFactory.register_interface(interface=blockchain_interface) blockchain_interface.transacting_power = TransactingPower(password=INSECURE_DEVELOPMENT_PASSWORD, account=origin) blockchain_interface.transacting_power.activate() # Check contracts with multiple versions raw_contracts = blockchain_interface._raw_contract_cache contract_name = AdjudicatorDeployer.contract_name test_adjudicator = len(raw_contracts[contract_name]) > 1 contract_name = StakingEscrowDeployer.contract_name test_staking_escrow = len(raw_contracts[contract_name]) > 1 contract_name = PolicyManagerDeployer.contract_name test_policy_manager = len(raw_contracts[contract_name]) > 1 if not test_adjudicator and not test_staking_escrow and not test_policy_manager: return # Prepare master version of contracts and upgrade to the latest registry = InMemoryContractRegistry() token_deployer = NucypherTokenDeployer(registry=registry, deployer_address=origin) token_deployer.deploy() staking_escrow_deployer = StakingEscrowDeployer(registry=registry, deployer_address=origin) deploy_earliest_contract(blockchain_interface, staking_escrow_deployer) if test_staking_escrow: staking_escrow_deployer.upgrade(contract_version="latest", confirmations=0) if test_policy_manager: policy_manager_deployer = PolicyManagerDeployer(registry=registry, deployer_address=origin) deploy_earliest_contract(blockchain_interface, policy_manager_deployer) policy_manager_deployer.upgrade(contract_version="latest", confirmations=0) if test_adjudicator: adjudicator_deployer = AdjudicatorDeployer(registry=registry, deployer_address=origin) deploy_earliest_contract(blockchain_interface, adjudicator_deployer) adjudicator_deployer.upgrade(contract_version="latest", confirmations=0) finally: # Unregister interface with contextlib.suppress(KeyError): del BlockchainInterfaceFactory._interfaces[provider_uri]
def test_multiversion_contract(): # Prepare compiler base_dir = os.path.join(dirname(abspath(__file__)), "contracts", "multiversion") v1_dir = os.path.join(base_dir, "v1") v2_dir = os.path.join(base_dir, "v2") root_dir = SolidityCompiler.default_contract_dir() solidity_compiler = SolidityCompiler(source_dirs=[ SourceDirs(root_dir, {v2_dir}), SourceDirs(root_dir, {v1_dir}) ]) # Prepare chain blockchain_interface = BlockchainDeployerInterface( provider_uri='tester://pyevm/2', compiler=solidity_compiler) blockchain_interface.connect() origin = blockchain_interface.client.accounts[0] blockchain_interface.transacting_power = TransactingPower( password=INSECURE_DEVELOPMENT_PASSWORD, account=origin) blockchain_interface.transacting_power.activate() # Searching both contract through raw data contract_name = "VersionTest" requested_version = "v1.2.3" version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version=requested_version) assert version == requested_version version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version="latest") assert version == requested_version requested_version = "v1.1.4" version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version=requested_version) assert version == requested_version version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version="earliest") assert version == requested_version # Deploy different contracts and check their versions registry = InMemoryContractRegistry() contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="v1.1.4") assert contract.version == "v1.1.4" assert contract.functions.VERSION().call() == 1 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="earliest") assert contract.version == "v1.1.4" assert contract.functions.VERSION().call() == 1 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="v1.2.3") assert contract.version == "v1.2.3" assert contract.functions.VERSION().call() == 2 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="latest") assert contract.version == "v1.2.3" assert contract.functions.VERSION().call() == 2 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name) assert contract.version == "v1.2.3" assert contract.functions.VERSION().call() == 2
def test_multiversion_contract(): # Prepare compiler base_dir = TEST_MULTIVERSION_CONTRACTS v1_dir, v2_dir = base_dir / 'v1', base_dir / 'v2' bundles = [ SourceBundle(base_path=SOLIDITY_SOURCE_ROOT, other_paths=(v1_dir, )), SourceBundle(base_path=SOLIDITY_SOURCE_ROOT, other_paths=(v2_dir, )) ] compiled_contracts = multiversion_compile(source_bundles=bundles) # Prepare chain BlockchainDeployerInterface.GAS_STRATEGIES = { **BlockchainDeployerInterface.GAS_STRATEGIES, 'free': free_gas_price_strategy } blockchain_interface = BlockchainDeployerInterface( provider_uri='tester://pyevm/2', gas_strategy='free') blockchain_interface.connect(compile_now=False) blockchain_interface._raw_contract_cache = compiled_contracts origin = blockchain_interface.client.accounts[0] blockchain_interface.transacting_power = TransactingPower( password=INSECURE_DEVELOPMENT_PASSWORD, signer=Web3Signer(blockchain_interface.client), account=origin) blockchain_interface.transacting_power.activate() # Searching both contract through raw data contract_name = "VersionTest" requested_version = "v1.2.3" version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version=requested_version) assert version == requested_version version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version="latest") assert version == requested_version requested_version = "v1.1.4" version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version=requested_version) assert version == requested_version version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version="earliest") assert version == requested_version # Deploy different contracts and check their versions registry = InMemoryContractRegistry() contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="v1.1.4") assert contract.version == "v1.1.4" assert contract.functions.VERSION().call() == 1 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="earliest") assert contract.version == "v1.1.4" assert contract.functions.VERSION().call() == 1 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="v1.2.3") assert contract.version == "v1.2.3" assert contract.functions.VERSION().call() == 2 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="latest") assert contract.version == "v1.2.3" assert contract.functions.VERSION().call() == 2 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name) assert contract.version == "v1.2.3" assert contract.functions.VERSION().call() == 2
def test_upgradeability(temp_dir_path): # Prepare remote source for compilation download_github_dir(GITHUB_SOURCE_LINK, temp_dir_path) # Prepare the blockchain BlockchainDeployerInterface.SOURCES = [ SourceBundle(base_path=SOLIDITY_SOURCE_ROOT), SourceBundle(base_path=Path(temp_dir_path)) ] provider_uri = 'tester://pyevm/2' # TODO: Testerchain caching Issues try: blockchain_interface = BlockchainDeployerInterface( provider_uri=provider_uri, gas_strategy='free') blockchain_interface.connect() origin = blockchain_interface.client.accounts[0] BlockchainInterfaceFactory.register_interface( interface=blockchain_interface) blockchain_interface.transacting_power = TransactingPower( password=INSECURE_DEVELOPMENT_PASSWORD, account=origin) blockchain_interface.transacting_power.activate() economics = make_token_economics(blockchain_interface) # Check contracts with multiple versions contract_name = AdjudicatorDeployer.contract_name skip_adjudicator_test = skip_test(blockchain_interface, contract_name) contract_name = StakingEscrowDeployer.contract_name skip_staking_escrow_test = skip_test(blockchain_interface, contract_name) contract_name = PolicyManagerDeployer.contract_name skip_policy_manager_test = skip_test(blockchain_interface, contract_name) if not skip_adjudicator_test and not skip_staking_escrow_test and not skip_policy_manager_test: return # Prepare master version of contracts and upgrade to the latest registry = InMemoryContractRegistry() token_deployer = NucypherTokenDeployer(registry=registry, deployer_address=origin, economics=economics) token_deployer.deploy() staking_escrow_deployer = StakingEscrowDeployer( registry=registry, deployer_address=origin, economics=economics) staking_escrow_deployer.deploy(deployment_mode=constants.INIT) policy_manager_deployer = PolicyManagerDeployer( registry=registry, deployer_address=origin, economics=economics) deploy_base_contract(blockchain_interface, policy_manager_deployer, skipt_test=skip_policy_manager_test) adjudicator_deployer = AdjudicatorDeployer(registry=registry, deployer_address=origin, economics=economics) deploy_base_contract(blockchain_interface, adjudicator_deployer, skipt_test=skip_adjudicator_test) if skip_staking_escrow_test: worklock_deployer = WorklockDeployer(registry=registry, deployer_address=origin, economics=economics) worklock_deployer.deploy() staking_escrow_deployer = StakingEscrowDeployer( registry=registry, deployer_address=origin, economics=economics) deploy_base_contract(blockchain_interface, staking_escrow_deployer, skipt_test=skip_staking_escrow_test) if not skip_staking_escrow_test: # TODO prepare at least one staker before calling upgrade staking_escrow_deployer.upgrade(contract_version="latest", confirmations=0) if not skip_policy_manager_test: policy_manager_deployer.upgrade(contract_version="latest", confirmations=0) if not skip_adjudicator_test: adjudicator_deployer.upgrade(contract_version="latest", confirmations=0) finally: # Unregister interface # TODO: Move to method? with contextlib.suppress(KeyError): del BlockchainInterfaceFactory._interfaces[provider_uri]
def deploy(click_config, action, poa, provider_uri, geth, enode, deployer_address, contract_name, allocation_infile, allocation_outfile, registry_infile, registry_outfile, no_compile, amount, recipient_address, config_root, sync, force): """Manage contract and registry deployment""" ETH_NODE = None # # Validate # # Ensure config root exists, because we need a default place to put output files. config_root = config_root or DEFAULT_CONFIG_ROOT if not os.path.exists(config_root): os.makedirs(config_root) # # Connect to Blockchain # if geth: # Spawn geth child process ETH_NODE = NuCypherGethDevnetProcess(config_root=config_root) ETH_NODE.ensure_account_exists(password=click_config.get_password( confirm=True)) ETH_NODE.start() # TODO: Graceful shutdown provider_uri = ETH_NODE.provider_uri # Establish a contract registry from disk if specified registry, registry_filepath = None, (registry_outfile or registry_infile) if registry_filepath is not None: registry = EthereumContractRegistry( registry_filepath=registry_filepath) # Deployment-tuned blockchain connection blockchain = BlockchainDeployerInterface(provider_uri=provider_uri, poa=poa, registry=registry, compiler=SolidityCompiler(), fetch_registry=False, sync_now=sync) # # Deployment Actor # if not deployer_address: for index, address in enumerate(blockchain.client.accounts): click.secho(f"{index} --- {address}") choices = click.IntRange(0, len(blockchain.client.accounts)) deployer_address_index = click.prompt("Select deployer address", default=0, type=choices) deployer_address = blockchain.client.accounts[deployer_address_index] # Verify Address if not force: click.confirm("Selected {} - Continue?".format(deployer_address), abort=True) # TODO: Integrate with Deployer Actor (Character) blockchain.transacting_power = BlockchainPower(blockchain=blockchain, account=deployer_address) deployer = Deployer(blockchain=blockchain, deployer_address=deployer_address) # Verify ETH Balance click.secho(f"\n\nDeployer ETH balance: {deployer.eth_balance}") if deployer.eth_balance == 0: click.secho("Deployer address has no ETH.", fg='red', bold=True) raise click.Abort() if not blockchain.client.is_local: # (~ dev mode; Assume accounts are already unlocked) password = click.prompt("Enter ETH node password", hide_input=True) blockchain.client.unlockAccount(deployer_address, password) # Add ETH Bootnode or Peer if enode: if geth: blockchain.w3.geth.admin.addPeer(enode) click.secho(f"Added ethereum peer {enode}") else: raise NotImplemented # TODO: other backends # # Action switch # if action == 'upgrade': if not contract_name: raise click.BadArgumentUsage( message="--contract-name is required when using --upgrade") existing_secret = click.prompt( 'Enter existing contract upgrade secret', hide_input=True) new_secret = click.prompt('Enter new contract upgrade secret', hide_input=True, confirmation_prompt=True) deployer.upgrade_contract(contract_name=contract_name, existing_plaintext_secret=existing_secret, new_plaintext_secret=new_secret) elif action == 'rollback': existing_secret = click.prompt( 'Enter existing contract upgrade secret', hide_input=True) new_secret = click.prompt('Enter new contract upgrade secret', hide_input=True, confirmation_prompt=True) deployer.rollback_contract(contract_name=contract_name, existing_plaintext_secret=existing_secret, new_plaintext_secret=new_secret) elif action == "contracts": registry_filepath = deployer.blockchain.registry.filepath if os.path.isfile(registry_filepath): click.secho( f"\nThere is an existing contract registry at {registry_filepath}.\n" f"Did you mean 'nucypher-deploy upgrade'?\n", fg='yellow') click.confirm( "Optionally, destroy existing local registry and continue?", abort=True) click.confirm( f"Confirm deletion of contract registry '{registry_filepath}'?", abort=True) os.remove(registry_filepath) # # Deploy Single Contract # if contract_name: # TODO: Handle secret collection for single contract deployment try: deployer_func = deployer.deployers[contract_name] except KeyError: message = f"No such contract {contract_name}. Available contracts are {deployer.deployers.keys()}" click.secho(message, fg='red', bold=True) raise click.Abort() else: # Deploy single contract _txs, _agent = deployer_func() # TODO: Painting for single contract deployment if ETH_NODE: ETH_NODE.stop() return # # Stage Deployment # # Track tx hashes, and new agents __deployment_transactions = dict() __deployment_agents = dict() secrets = click_config.collect_deployment_secrets() click.clear() click.secho(NU_BANNER) w3 = deployer.blockchain.w3 click.secho(f"Current Time ........ {maya.now().iso8601()}") click.secho( f"Web3 Provider ....... {deployer.blockchain.provider_uri}") click.secho( f"Block ............... {deployer.blockchain.client.block_number}") click.secho( f"Gas Price ........... {deployer.blockchain.client.gas_price}") click.secho(f"Deployer Address .... {deployer.checksum_address}") click.secho(f"ETH ................. {deployer.eth_balance}") click.secho( f"Chain ID ............ {deployer.blockchain.client.chain_id}") click.secho( f"Chain Name .......... {deployer.blockchain.client.chain_name}") # Ask - Last chance to gracefully abort if not force: click.secho( "\nDeployment successfully staged. Take a deep breath. \n", fg='green') if click.prompt("Type 'DEPLOY' to continue") != 'DEPLOY': raise click.Abort() # Delay - Last chance to crash and abort click.secho(f"Starting deployment in 3 seconds...", fg='red') time.sleep(1) click.secho(f"2...", fg='yellow') time.sleep(1) click.secho(f"1...", fg='green') time.sleep(1) click.secho(f"Deploying...", bold=True) # # DEPLOY < ------- # txhashes, deployers = deployer.deploy_network_contracts( staker_secret=secrets.staker_secret, policy_secret=secrets.policy_secret, adjudicator_secret=secrets.adjudicator_secret, user_escrow_proxy_secret=secrets.escrow_proxy_secret) # Success __deployment_transactions.update(txhashes) # # Paint # total_gas_used = 0 # TODO: may be faulty for contract_name, transactions in __deployment_transactions.items(): # Paint heading heading = '\n{} ({})'.format( contract_name, deployers[contract_name].contract_address) click.secho(heading, bold=True) click.echo('*' * (42 + 3 + len(contract_name))) for tx_name, txhash in transactions.items(): # Wait for inclusion in the blockchain receipt = deployer.blockchain.w3.eth.waitForTransactionReceipt( txhash) click.secho("OK", fg='green', nl=False, bold=True) # Accumulate gas total_gas_used += int(receipt['gasUsed']) # Paint click.secho(" | {}".format(tx_name), fg='yellow', nl=False) click.secho(" | {}".format(txhash.hex()), fg='yellow', nl=False) click.secho(" ({} gas)".format(receipt['cumulativeGasUsed'])) click.secho("Block #{} | {}\n".format( receipt['blockNumber'], receipt['blockHash'].hex())) # Paint outfile paths click.secho( "Cumulative Gas Consumption: {} gas".format(total_gas_used), bold=True, fg='blue') registry_outfile = deployer.blockchain.registry.filepath click.secho('Generated registry {}'.format(registry_outfile), bold=True, fg='blue') # Save transaction metadata receipts_filepath = deployer.save_deployment_receipts( transactions=__deployment_transactions) click.secho(f"Saved deployment receipts to {receipts_filepath}", fg='blue', bold=True) elif action == "allocations": if not allocation_infile: allocation_infile = click.prompt("Enter allocation data filepath") click.confirm("Continue deploying and allocating?", abort=True) deployer.deploy_beneficiaries_from_file( allocation_data_filepath=allocation_infile, allocation_outfile=allocation_outfile) elif action == "transfer": token_agent = NucypherTokenAgent(blockchain=blockchain) click.confirm( f"Transfer {amount} from {token_agent.contract_address} to {recipient_address}?", abort=True) txhash = token_agent.transfer( amount=amount, sender_address=token_agent.contract_address, target_address=recipient_address) click.secho(f"OK | {txhash}") elif action == "destroy-registry": registry_filepath = deployer.blockchain.registry.filepath click.confirm( f"Are you absolutely sure you want to destroy the contract registry at {registry_filepath}?", abort=True) os.remove(registry_filepath) click.secho(f"Successfully destroyed {registry_filepath}", fg='red') else: raise click.BadArgumentUsage(message=f"Unknown action '{action}'") if ETH_NODE: ETH_NODE.stop()
def test_deployer_interface_multiversion_contract(): # Prepare compiler base_dir = TEST_MULTIVERSION_CONTRACTS v1_dir, v2_dir = base_dir / 'v1', base_dir / 'v2' # TODO: Check type of sources # I am a contract administrator and I an compiling a new updated version of an existing contract... # Represents "Manually hardcoding" a new source directory on BlockchainDeployerInterface.SOURCES. BlockchainDeployerInterface.SOURCES = (SourceBundle(base_path=v1_dir), SourceBundle(base_path=v2_dir)) # Prepare chain BlockchainInterfaceFactory._interfaces.clear() blockchain_interface = BlockchainDeployerInterface( provider_uri='tester://pyevm', gas_strategy='free') blockchain_interface.connect() BlockchainInterfaceFactory.register_interface( interface=blockchain_interface) # Lets this test run in isolation origin = blockchain_interface.client.accounts[0] blockchain_interface.transacting_power = TransactingPower( password=INSECURE_DEVELOPMENT_PASSWORD, signer=Web3Signer(blockchain_interface.client), account=origin) blockchain_interface.transacting_power.activate() # Searching both contract through raw data contract_name = "VersionTest" requested_version = "v1.2.3" version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version=requested_version) assert version == requested_version version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version="latest") assert version == requested_version requested_version = "v1.1.4" version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version=requested_version) assert version == requested_version version, _data = blockchain_interface.find_raw_contract_data( contract_name=contract_name, requested_version="earliest") assert version == requested_version # Deploy different contracts and check their versions registry = InMemoryContractRegistry() contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="v1.1.4") assert contract.version == "v1.1.4" assert contract.functions.VERSION().call() == 1 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="earliest") assert contract.version == "v1.1.4" assert contract.functions.VERSION().call() == 1 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="v1.2.3") assert contract.version == "v1.2.3" assert contract.functions.VERSION().call() == 2 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name, contract_version="latest") assert contract.version == "v1.2.3" assert contract.functions.VERSION().call() == 2 contract, receipt = blockchain_interface.deploy_contract( deployer_address=origin, registry=registry, contract_name=contract_name) assert contract.version == "v1.2.3" assert contract.functions.VERSION().call() == 2
def test_upgradeability(temp_dir_path, token_economics): # Prepare remote source for compilation download_github_dir(GITHUB_SOURCE_LINK, temp_dir_path) solidity_compiler = SolidityCompiler(source_dirs=[ SourceDirs(SolidityCompiler.default_contract_dir()), SourceDirs(temp_dir_path) ]) # Prepare the blockchain blockchain_interface = BlockchainDeployerInterface( provider_uri='tester://pyevm/2', compiler=solidity_compiler) blockchain_interface.connect() origin = blockchain_interface.client.accounts[0] BlockchainInterfaceFactory.register_interface( interface=blockchain_interface) blockchain_interface.transacting_power = TransactingPower( password=INSECURE_DEVELOPMENT_PASSWORD, account=origin) blockchain_interface.transacting_power.activate() # Check contracts with multiple versions raw_contracts = blockchain_interface._raw_contract_cache contract_name = AdjudicatorDeployer.contract_name test_adjudicator = len(raw_contracts[contract_name]) > 1 contract_name = StakingEscrowDeployer.contract_name test_staking_escrow = len(raw_contracts[contract_name]) > 1 contract_name = PolicyManagerDeployer.contract_name test_policy_manager = len(raw_contracts[contract_name]) > 1 if not test_adjudicator and not test_staking_escrow and not test_policy_manager: return # Prepare master version of contracts and upgrade to the latest registry = InMemoryContractRegistry() token_deployer = NucypherTokenDeployer(registry=registry, deployer_address=origin) token_deployer.deploy() staking_escrow_deployer = StakingEscrowDeployer(registry=registry, deployer_address=origin) deploy_earliest_contract(blockchain_interface, staking_escrow_deployer, secret=STAKING_ESCROW_DEPLOYMENT_SECRET) if test_staking_escrow: upgrade_to_latest_contract(staking_escrow_deployer, secret=STAKING_ESCROW_DEPLOYMENT_SECRET) if test_policy_manager: policy_manager_deployer = PolicyManagerDeployer( registry=registry, deployer_address=origin) deploy_earliest_contract(blockchain_interface, policy_manager_deployer, secret=POLICY_MANAGER_DEPLOYMENT_SECRET) upgrade_to_latest_contract(policy_manager_deployer, secret=POLICY_MANAGER_DEPLOYMENT_SECRET) if test_adjudicator: adjudicator_deployer = AdjudicatorDeployer(registry=registry, deployer_address=origin) deploy_earliest_contract(blockchain_interface, adjudicator_deployer, secret=ADJUDICATOR_DEPLOYMENT_SECRET) upgrade_to_latest_contract(adjudicator_deployer, secret=ADJUDICATOR_DEPLOYMENT_SECRET)