def test_bare_contract_deployment_to_alternate_registry(click_runner, test_registry): if os.path.exists(ALTERNATE_REGISTRY_FILEPATH): os.remove(ALTERNATE_REGISTRY_FILEPATH) assert not os.path.exists(ALTERNATE_REGISTRY_FILEPATH) command = ('contracts', '--contract-name', StakingEscrowDeployer.contract_name, '--bare', '--provider', TEST_PROVIDER_URI, '--registry-infile', MOCK_REGISTRY_FILEPATH, '--registry-outfile', ALTERNATE_REGISTRY_FILEPATH, '--poa', '--ignore-deployed') user_input = '0\n' + 'Y\n' + 'DEPLOY' result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # Verify alternate registry output assert os.path.exists(MOCK_REGISTRY_FILEPATH) assert os.path.exists(ALTERNATE_REGISTRY_FILEPATH) old_registry = LocalContractRegistry(filepath=MOCK_REGISTRY_FILEPATH) new_registry = LocalContractRegistry(filepath=ALTERNATE_REGISTRY_FILEPATH) assert old_registry != new_registry old_enrolled_names = list(old_registry.enrolled_names).count(StakingEscrowDeployer.contract_name) new_enrolled_names = list(new_registry.enrolled_names).count(StakingEscrowDeployer.contract_name) assert new_enrolled_names == old_enrolled_names + 1
def new_local_registry(): filename = f'{BASE_TEMP_PREFIX}mock-empty-registry-{datetime.now().strftime(DATETIME_FORMAT)}.json' registry_filepath = BASE_TEMP_DIR / filename registry = LocalContractRegistry(filepath=registry_filepath) registry.write(InMemoryContractRegistry().read()) yield registry if registry_filepath.exists(): registry_filepath.unlink()
def new_local_registry(): filename = f'{BASE_TEMP_PREFIX}mock-empty-registry-{datetime.now().strftime(DATETIME_FORMAT)}.json' registry_filepath = os.path.join(BASE_TEMP_DIR, filename) registry = LocalContractRegistry(filepath=registry_filepath) registry.write(InMemoryContractRegistry().read()) yield registry if os.path.exists(registry_filepath): os.remove(registry_filepath)
def test_rollback(click_runner, testerchain, registry_filepath): """Roll 'em back!""" # Input Components yes = 'Y\n' # Stage Rollbacks old_secret = INSECURE_SECRETS[PLANNED_UPGRADES] rollback_secret = generate_insecure_secret() user_input = '0\n' + yes + old_secret + rollback_secret + rollback_secret contracts_to_rollback = ( 'StakingEscrow', # v4 -> v3 'PolicyManager', # v4 -> v3 'Adjudicator', # v4 -> v3 ) # Execute Rollbacks for contract_name in contracts_to_rollback: command = ('rollback', '--contract-name', contract_name, '--registry-infile', registry_filepath, '--provider', TEST_PROVIDER_URI, '--poa') result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # TODO unify this, trust more to registry_filepath, reduce calls registry = LocalContractRegistry(filepath=registry_filepath) records = registry.search(contract_name=contract_name) assert len(records) == 4 *old_records, v3, v4 = records current_target, rollback_target = v4, v3 _name, _version, current_target_address, *abi = current_target _name, _version, rollback_target_address, *abi = rollback_target assert current_target_address != rollback_target_address # Ensure the proxy targets the rollback target (previous version) with pytest.raises(BlockchainInterface.UnknownContract): testerchain.get_proxy_contract( registry=registry, target_address=current_target_address, proxy_name='Dispatcher') proxy = testerchain.get_proxy_contract( registry=registry, target_address=rollback_target_address, proxy_name='Dispatcher') # Deeper - Ensure the proxy targets the old deployment on-chain targeted_address = proxy.functions.target().call() assert targeted_address != current_target assert targeted_address == rollback_target_address
def test_rollback(click_runner, testerchain, registry_filepath, agency): """Roll 'em back!""" # Stage Rollbacks contracts_to_rollback = ( 'StakingEscrow', # v4 -> v3 'PolicyManager', # v4 -> v3 'Adjudicator', # v4 -> v3 ) # Execute Rollbacks for contract_name in contracts_to_rollback: command = ('rollback', '--contract-name', contract_name, '--registry-infile', str(registry_filepath.absolute()), '--network', TEMPORARY_DOMAIN, '--provider', TEST_PROVIDER_URI, '--signer', TEST_PROVIDER_URI) user_input = '0\n' + YES_ENTER result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0, result.output # TODO unify this, trust more to registry_filepath, reduce calls registry = LocalContractRegistry(filepath=registry_filepath) records = registry.search(contract_name=contract_name) assert len(records) == 4 *old_records, v3, v4 = records current_target, rollback_target = v4, v3 _name, _version, current_target_address, *abi = current_target _name, _version, rollback_target_address, *abi = rollback_target assert current_target_address != rollback_target_address # Ensure the proxy targets the rollback target (previous version) with pytest.raises(BlockchainInterface.UnknownContract): testerchain.get_proxy_contract( registry=registry, target_address=current_target_address, proxy_name='Dispatcher') proxy = testerchain.get_proxy_contract( registry=registry, target_address=rollback_target_address, proxy_name='Dispatcher') # Deeper - Ensure the proxy targets the old deployment on-chain targeted_address = proxy.functions.target().call() assert targeted_address != current_target assert targeted_address == rollback_target_address
def test_transfer_tokens(click_runner, registry_filepath): # # Setup # # Let's transfer some NU to a random stranger recipient_address = to_checksum_address(os.urandom(20)) registry = LocalContractRegistry(filepath=registry_filepath) token_agent = NucypherTokenAgent(registry=registry) assert token_agent.get_balance(address=recipient_address) == 0 command = [ 'transfer-tokens', '--target-address', recipient_address, '--value', 42, '--registry-infile', registry_filepath, '--provider', TEST_PROVIDER_URI, '--poa' ] user_input = '0\n' + 'Y\n' + 'Y\n' result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # Check that the NU has arrived to the recipient assert token_agent.get_balance(address=recipient_address) == 42
def test_nucypher_deploy_allocation_contracts(click_runner, testerchain, registry_filepath, mock_allocation_infile, token_economics): # # Main # deploy_command = ('allocations', '--registry-infile', registry_filepath, '--allocation-infile', mock_allocation_infile.filepath, '--allocation-outfile', MOCK_ALLOCATION_REGISTRY_FILEPATH, '--provider', TEST_PROVIDER_URI, '--poa') account_index = '0\n' yes = 'Y\n' user_input = account_index + yes + yes result = click_runner.invoke(deploy, deploy_command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # ensure that a pre-allocation recipient has the allocated token quantity. beneficiary = testerchain.client.accounts[-1] allocation_registry = AllocationRegistry( filepath=MOCK_ALLOCATION_REGISTRY_FILEPATH) registry = LocalContractRegistry(filepath=registry_filepath) user_escrow_agent = UserEscrowAgent( registry=registry, beneficiary=beneficiary, allocation_registry=allocation_registry) assert user_escrow_agent.unvested_tokens == token_economics.minimum_allowed_locked
def get_registry(self, emitter, debug): try: eth_node = None if self.geth: eth_node = get_provider_process() # Note: For test compatibility. if not BlockchainInterfaceFactory.is_interface_initialized( provider_uri=self.provider_uri): BlockchainInterfaceFactory.initialize_interface( provider_uri=self.provider_uri, provider_process=eth_node, poa=self.poa, light=self.light, sync=False, emitter=emitter) blockchain = BlockchainInterfaceFactory.get_interface( provider_uri=self.provider_uri) emitter.echo(message="Reading Latest Chaindata...") blockchain.connect() except Exception as e: if debug: raise click.secho(str(e), bold=True, fg='red') raise click.Abort if self.registry_filepath: registry = LocalContractRegistry(filepath=self.registry_filepath) else: registry = InMemoryContractRegistry.from_latest_publication( network=self.network) return registry
def establish_deployer_registry(emitter, registry_infile: str = None, registry_outfile: str = None, use_existing_registry: bool = False, dev: bool = False) -> LocalContractRegistry: # Establish a contract registry from disk if specified filepath = registry_infile default_registry_filepath = os.path.join( DEFAULT_CONFIG_ROOT, BaseContractRegistry.REGISTRY_NAME) if registry_outfile: registry_infile = registry_infile or default_registry_filepath if use_existing_registry: try: _result = shutil.copyfile(registry_infile, registry_outfile) except shutil.SameFileError: raise click.BadArgumentUsage( f"--registry-infile and --registry-outfile must not be the same path '{registry_infile}'." ) filepath = registry_outfile if dev: # TODO: Need a way to detect a geth --dev registry filepath here. (then deprecate the --dev flag) filepath = os.path.join(DEFAULT_CONFIG_ROOT, BaseContractRegistry.DEVELOPMENT_REGISTRY_NAME) registry_filepath = filepath or default_registry_filepath # All Done. registry = LocalContractRegistry(filepath=registry_filepath) emitter.message(f"Configured to registry filepath {registry_filepath}") return registry
def test_manual_proxy_retargeting(testerchain, click_runner, token_economics): # A local, alternate filepath registry exists assert os.path.exists(ALTERNATE_REGISTRY_FILEPATH) local_registry = LocalContractRegistry(filepath=ALTERNATE_REGISTRY_FILEPATH) deployer = StakingEscrowDeployer(deployer_address=testerchain.etherbase_account, registry=local_registry, economics=token_economics) proxy_deployer = deployer.get_proxy_deployer() # Un-targeted enrollment is indeed un targeted by the proxy untargeted_deployment = deployer.get_latest_enrollment() assert proxy_deployer.target_contract.address != untargeted_deployment.address # MichWill still owns this proxy. michwill = testerchain.unassigned_accounts[1] assert proxy_deployer.contract.functions.owner().call() == michwill command = ('upgrade', '--retarget', '--deployer-address', michwill, '--contract-name', StakingEscrowDeployer.contract_name, '--target-address', untargeted_deployment.address, '--provider', TEST_PROVIDER_URI, '--registry-infile', ALTERNATE_REGISTRY_FILEPATH) # Upgrade user_input = '0\n' + 'Y\n' + 'Y\n' result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # The proxy target has been updated. proxy_deployer = deployer.get_proxy_deployer() assert proxy_deployer.target_contract.address == untargeted_deployment.address
def establish_deployer_registry(emitter, registry_infile: str = None, registry_outfile: str = None, use_existing_registry: bool = False, download_registry: bool = False, dev: bool = False ) -> BaseContractRegistry: if download_registry: registry = InMemoryContractRegistry.from_latest_publication() emitter.message(PRODUCTION_REGISTRY_ADVISORY.format(source=registry.source)) return registry # Establish a contract registry from disk if specified filepath = registry_infile default_registry_filepath = os.path.join(DEFAULT_CONFIG_ROOT, BaseContractRegistry.REGISTRY_NAME) if registry_outfile: registry_infile = registry_infile or default_registry_filepath if use_existing_registry: try: _result = shutil.copyfile(registry_infile, registry_outfile) except shutil.SameFileError: raise click.BadArgumentUsage(f"--registry-infile and --registry-outfile must not be the same path '{registry_infile}'.") filepath = registry_outfile if dev: # TODO: Need a way to detect a geth --dev registry filepath here. (then deprecate the --dev flag) filepath = os.path.join(DEFAULT_CONFIG_ROOT, BaseContractRegistry.DEVELOPMENT_REGISTRY_NAME) registry_filepath = filepath or default_registry_filepath # All Done. registry = LocalContractRegistry(filepath=registry_filepath) emitter.message(LOCAL_REGISTRY_ADVISORY.format(registry_filepath=registry_filepath)) return registry
def _get_staking_agent(click_config, emitter, geth, poa, provider_uri, registry_filepath): try: ETH_NODE = None if geth: ETH_NODE = get_provider_process() # Note: For test compatibility. if not BlockchainInterfaceFactory.is_interface_initialized( provider_uri=provider_uri): BlockchainInterfaceFactory.initialize_interface( provider_uri=provider_uri, provider_process=ETH_NODE, poa=poa, sync=False, show_sync_progress=False) blockchain = BlockchainInterfaceFactory.get_interface( provider_uri=provider_uri) emitter.echo(message="Reading Latest Chaindata...") blockchain.connect() except Exception as e: if click_config.debug: raise click.secho(str(e), bold=True, fg='red') raise click.Abort if registry_filepath: registry = LocalContractRegistry(filepath=registry_filepath) else: registry = InMemoryContractRegistry.from_latest_publication() staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=registry) return staking_agent
def test_bare_contract_deployment_to_alternate_registry(click_runner, agency_local_registry): if ALTERNATE_REGISTRY_FILEPATH.exists(): ALTERNATE_REGISTRY_FILEPATH.unlink() assert not ALTERNATE_REGISTRY_FILEPATH.exists() command = ('contracts', '--contract-name', StakingEscrowDeployer.contract_name, '--mode', 'bare', '--provider', TEST_PROVIDER_URI, '--signer', TEST_PROVIDER_URI, '--registry-infile', str(agency_local_registry.filepath.absolute()), '--registry-outfile', str(ALTERNATE_REGISTRY_FILEPATH.absolute()), '--network', TEMPORARY_DOMAIN, '--ignore-deployed') user_input = '0\n' + 'Y\n' + 'DEPLOY' result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # Verify alternate registry output assert agency_local_registry.filepath.exists() assert ALTERNATE_REGISTRY_FILEPATH.exists() new_registry = LocalContractRegistry(filepath=ALTERNATE_REGISTRY_FILEPATH) assert agency_local_registry != new_registry old_enrolled_names = list(agency_local_registry.enrolled_names).count(StakingEscrowDeployer.contract_name) new_enrolled_names = list(new_registry.enrolled_names).count(StakingEscrowDeployer.contract_name) assert new_enrolled_names == old_enrolled_names + 1
def test_deploy_multisig_contract(click_runner, multisig_parameters_filepath, multisig_owners, new_local_registry): # # Main # command = [ 'contracts', '--registry-infile', new_local_registry.filepath, '--provider', TEST_PROVIDER_URI, '--contract-name', 'MultiSig', '--parameters', multisig_parameters_filepath ] user_input = '0\n' + 'Y\n' result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # # Agency # registry = LocalContractRegistry(filepath=new_local_registry.filepath) agent = MultiSigAgent(registry=registry) assert agent.owners == multisig_owners assert agent.threshold == MULTISIG_THRESHOLD assert agent.nonce == 0
def _get_registry(provider_uri, registry_filepath): BlockchainInterfaceFactory.initialize_interface(provider_uri=provider_uri) if registry_filepath: registry = LocalContractRegistry.from_latest_publication() else: registry = InMemoryContractRegistry.from_latest_publication() return registry
def get_registry(network: str, registry_filepath: str = None) -> BaseContractRegistry: if registry_filepath: registry = LocalContractRegistry(filepath=registry_filepath) else: registry = InMemoryContractRegistry.from_latest_publication( network=network) return registry
def _get_registry(registry_filepath, network): if registry_filepath: registry = LocalContractRegistry.from_latest_publication( network=network) else: registry = InMemoryContractRegistry.from_latest_publication( network=network) return registry
def get_registry(self, connect_blockchain: bool = False, emitter=None, debug=None): if connect_blockchain: self.connect_blockchain(emitter, debug) if self.registry_filepath: registry = LocalContractRegistry(filepath=self.registry_filepath) else: registry = InMemoryContractRegistry.from_latest_publication( network=self.network) return registry
def test_transfer_ownership(click_runner, testerchain, agency, test_registry): local_registry = LocalContractRegistry(filepath=MOCK_REGISTRY_FILEPATH) staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=local_registry) policy_agent = ContractAgency.get_agent(PolicyManagerAgent, registry=local_registry) adjudicator_agent = ContractAgency.get_agent(AdjudicatorAgent, registry=local_registry) assert staking_agent.owner == testerchain.etherbase_account assert policy_agent.owner == testerchain.etherbase_account assert adjudicator_agent.owner == testerchain.etherbase_account maclane = testerchain.unassigned_accounts[0] ownership_command = ('transfer-ownership', '--registry-infile', MOCK_REGISTRY_FILEPATH, '--provider', TEST_PROVIDER_URI, '--target-address', maclane, '--poa') account_index = '0\n' yes = 'Y\n' user_input = account_index + yes + yes result = click_runner.invoke(deploy, ownership_command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 assert staking_agent.owner == maclane assert policy_agent.owner == maclane assert adjudicator_agent.owner == maclane michwill = testerchain.unassigned_accounts[1] ownership_command = ('transfer-ownership', '--deployer-address', maclane, '--contract-name', STAKING_ESCROW_CONTRACT_NAME, '--registry-infile', MOCK_REGISTRY_FILEPATH, '--provider', TEST_PROVIDER_URI, '--target-address', michwill, '--poa') user_input = yes result = click_runner.invoke(deploy, ownership_command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 assert staking_agent.owner != maclane assert staking_agent.owner == michwill
def test_transfer_tokens(click_runner, registry_filepath, get_random_checksum_address, testerchain): # Let's transfer some NU to a random stranger recipient_address = get_random_checksum_address() registry = LocalContractRegistry(filepath=registry_filepath) token_agent = NucypherTokenAgent(registry=registry) assert token_agent.get_balance(address=recipient_address) == 0 command = [ 'transfer-tokens', '--target-address', recipient_address, '--value', 42, '--registry-infile', registry_filepath, '--provider', TEST_PROVIDER_URI ] user_input = '0\n' + YES_ENTER + YES_ENTER result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # Check that the NU has arrived to the recipient assert token_agent.get_balance(address=recipient_address) == 42 # Let's approve an allowance to a random spender spender_address = get_random_checksum_address() owner_address = testerchain.client.accounts[0] assert token_agent.get_allowance(spender=spender_address, owner=owner_address) == 0 command = [ 'transfer-tokens', '--target-address', spender_address, '--value', 42, '--allowance', '--registry-infile', registry_filepath, '--provider', TEST_PROVIDER_URI ] user_input = '0\n' + YES_ENTER + YES_ENTER result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # Check that the NU was approved for the spender assert token_agent.get_allowance(spender=spender_address, owner=owner_address) == 42
def test_nucypher_deploy_inspect_fully_deployed(click_runner, testerchain, agency): local_registry = LocalContractRegistry(filepath=MOCK_REGISTRY_FILEPATH) staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=local_registry) policy_agent = ContractAgency.get_agent(PolicyManagerAgent, registry=local_registry) adjudicator_agent = ContractAgency.get_agent(AdjudicatorAgent, registry=local_registry) status_command = ('inspect', '--registry-infile', MOCK_REGISTRY_FILEPATH, '--provider', TEST_PROVIDER_URI, '--poa') result = click_runner.invoke(deploy, status_command, catch_exceptions=False) assert result.exit_code == 0 assert staking_agent.owner in result.output assert policy_agent.owner in result.output assert adjudicator_agent.owner in result.output
def test_manual_proxy_retargeting(monkeypatch, testerchain, click_runner, application_economics): # A local, alternate filepath registry exists assert ALTERNATE_REGISTRY_FILEPATH.exists() local_registry = LocalContractRegistry( filepath=ALTERNATE_REGISTRY_FILEPATH) deployer = StakingEscrowDeployer(registry=local_registry, economics=application_economics) proxy_deployer = deployer.get_proxy_deployer() # Un-targeted enrollment is indeed un targeted by the proxy untargeted_deployment = deployer.get_latest_enrollment() assert proxy_deployer.target_contract.address != untargeted_deployment.address # MichWill still owns this proxy. michwill = testerchain.unassigned_accounts[1] assert proxy_deployer.contract.functions.owner().call() == michwill command = ('upgrade', '--retarget', '--deployer-address', michwill, '--contract-name', StakingEscrowDeployer.contract_name, '--target-address', untargeted_deployment.address, '--eth-provider', TEST_ETH_PROVIDER_URI, '--signer', TEST_ETH_PROVIDER_URI, '--registry-infile', str(ALTERNATE_REGISTRY_FILEPATH.absolute()), '--confirmations', 4, '--network', TEMPORARY_DOMAIN) # Upgrade user_input = '0\n' + YES_ENTER + YES_ENTER + YES_ENTER result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # The proxy target has been updated. proxy_deployer = deployer.get_proxy_deployer() assert proxy_deployer.target_contract.address == untargeted_deployment.address
def test_upgrade_contracts(click_runner, test_registry_source_manager, test_registry, testerchain, registry_filepath, agency): NetworksInventory.DEFAULT = TEMPORARY_DOMAIN registry_filepath = test_registry.commit(filepath=registry_filepath) # # Setup # # Check the existing state of the registry before the meat and potatoes expected_enrollments = 11 with open(registry_filepath, 'r') as file: raw_registry_data = file.read() registry_data = json.loads(raw_registry_data) assert len(registry_data) == expected_enrollments # # Input Components # cli_action = 'upgrade' base_command = ( '--registry-infile', registry_filepath, '--provider', TEST_PROVIDER_URI, '--signer', TEST_PROVIDER_URI, '--confirmations', 1, '--network', TEMPORARY_DOMAIN, '--force' # skip registry preflight check for tests ) # # Stage Upgrades # contracts_to_upgrade = ( 'StakingEscrow', # v1 -> v2 'PolicyManager', # v1 -> v2 'Adjudicator', # v1 -> v2 'StakingInterface', # v1 -> v2 'StakingEscrow', # v2 -> v3 'StakingEscrow', # v3 -> v4 'Adjudicator', # v2 -> v3 'PolicyManager', # v2 -> v3 'StakingInterface', # v2 -> v3 'StakingInterface', # v3 -> v4 'PolicyManager', # v3 -> v4 'Adjudicator', # v3 -> v4 ) # NOTE: Keep all versions the same in this test (all version 4, for example) # Each contract starts at version 1 version_tracker = {name: 1 for name in CONTRACTS_TO_UPGRADE} # # Upgrade Contracts # for contract_name in contracts_to_upgrade: # Select proxy (Dispatcher vs Router) if contract_name == "StakingInterface": proxy_name = "StakingInterfaceRouter" else: proxy_name = 'Dispatcher' registry = LocalContractRegistry(filepath=registry_filepath) real_old_contract = testerchain.get_contract_by_name( contract_name=contract_name, registry=registry, proxy_name=proxy_name, use_proxy_address=False) # Ensure the proxy targets the current deployed contract proxy = testerchain.get_proxy_contract( registry=registry, target_address=real_old_contract.address, proxy_name=proxy_name) targeted_address = proxy.functions.target().call() assert targeted_address == real_old_contract.address # Assemble CLI command command = (cli_action, '--contract-name', contract_name, '--ignore-deployed', *base_command) # Select upgrade interactive input scenario current_version = version_tracker[contract_name] user_input = '0\n' + YES_ENTER + YES_ENTER + YES_ENTER # Execute upgrade (Meat) result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0, result.output assert "Successfully deployed" in result.output # Mutate the version tracking version_tracker[contract_name] += 1 expected_enrollments += 1 # Verify the registry is updated (Potatoes) with open(registry_filepath, 'r') as file: # Read the registry file directly, bypassing its interfaces raw_registry_data = file.read() registry_data = json.loads(raw_registry_data) assert len( registry_data ) == expected_enrollments, f'Unexpected number of enrollments for {contract_name}' # Check that there is more than one entry, since we've deployed a "version 2" expected_contract_enrollments = current_version + 1 registered_names = [r[0] for r in registry_data] contract_enrollments = registered_names.count(contract_name) assert contract_enrollments > 1, f"New contract is not enrolled in {registry_filepath}" error = f"Incorrect number of records enrolled for {contract_name}. " \ f"Expected {expected_contract_enrollments} got {contract_enrollments}." assert contract_enrollments == expected_contract_enrollments, error # Ensure deployments are different addresses registry = LocalContractRegistry(filepath=registry_filepath) records = registry.search(contract_name=contract_name) assert len(records) == contract_enrollments, error old, new = records[-2:] # Get the last two entries old_name, _old_version, old_address, *abi = old # Previous version new_name, _new_version, new_address, *abi = new # New version assert old_address == real_old_contract.address assert old_name == new_name # TODO: Inspect ABI / Move to different test. assert old_address != new_address # Ensure the proxy now targets the new deployment proxy = testerchain.get_proxy_contract(registry=registry, target_address=new_address, proxy_name=proxy_name) targeted_address = proxy.functions.target().call() assert targeted_address != old_address assert targeted_address == new_address
def test_nucypher_deploy_contracts(click_runner, mock_allocation_infile, token_economics, registry_filepath): # # Main # command = [ 'contracts', '--registry-outfile', registry_filepath, '--provider', TEST_PROVIDER_URI, '--poa' ] user_input = '0\n' + 'Y\n' + (f'{INSECURE_SECRETS[1]}\n' * 8) + 'DEPLOY' result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # Ensure there is a report on each contract contract_names = tuple(a.registry_contract_name for a in EthereumContractAgent.__subclasses__()) for registry_name in contract_names: assert registry_name in result.output # Check that the primary contract registry was written # and peek at some of the registered entries assert os.path.isfile(registry_filepath) with open(registry_filepath, 'r') as file: # Ensure every contract's name was written to the file, somehow raw_registry_data = file.read() for registry_name in contract_names: assert registry_name in raw_registry_data # Ensure the Registry is JSON deserializable registry_data = json.loads(raw_registry_data) # and that is has the correct number of entries assert len(registry_data) == 9 # Read several records token_record, escrow_record, dispatcher_record, *other_records = registry_data registered_name, registered_address, registered_abi = token_record # # Agency # registry = LocalContractRegistry(filepath=registry_filepath) token_agent = NucypherTokenAgent(registry=registry) assert token_agent.contract_name == registered_name assert token_agent.registry_contract_name == registered_name assert token_agent.contract_address == registered_address # Now show that we can use contract Agency and read from the blockchain assert token_agent.get_balance() == 0 staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=registry) assert staking_agent.get_current_period() # and at least the others can be instantiated assert PolicyManagerAgent(registry=registry) # This agent wasn't instantiated before, so we have to supply the blockchain blockchain = staking_agent.blockchain assert AdjudicatorAgent(registry=registry)
def test_manual_deployment_of_idle_network(click_runner): if os.path.exists(ALTERNATE_REGISTRY_FILEPATH_2): os.remove(ALTERNATE_REGISTRY_FILEPATH_2) assert not os.path.exists(ALTERNATE_REGISTRY_FILEPATH_2) registry = LocalContractRegistry(filepath=ALTERNATE_REGISTRY_FILEPATH_2) registry.write(InMemoryContractRegistry().read()) # TODO: Manual deployments from scratch require an existing but empty registry (i.e., a json file just with "[]") user_input = '0\n' + YES_ENTER + 'DEPLOY' # 1. Deploy NuCypherToken command = ('contracts', '--contract-name', NUCYPHER_TOKEN_CONTRACT_NAME, '--provider', TEST_PROVIDER_URI, '--network', TEMPORARY_DOMAIN, '--registry-infile', ALTERNATE_REGISTRY_FILEPATH_2) result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0, result.output assert os.path.exists(ALTERNATE_REGISTRY_FILEPATH_2) new_registry = LocalContractRegistry(filepath=ALTERNATE_REGISTRY_FILEPATH_2) deployed_contracts = [NUCYPHER_TOKEN_CONTRACT_NAME] assert list(new_registry.enrolled_names) == deployed_contracts # 2. Deploy StakingEscrow in INIT mode command = ('contracts', '--contract-name', STAKING_ESCROW_CONTRACT_NAME, '--mode', 'init', '--provider', TEST_PROVIDER_URI, '--network', TEMPORARY_DOMAIN, '--registry-infile', ALTERNATE_REGISTRY_FILEPATH_2) result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 deployed_contracts.extend([STAKING_ESCROW_STUB_CONTRACT_NAME, DISPATCHER_CONTRACT_NAME]) assert list(new_registry.enrolled_names) == deployed_contracts # 3. Deploy PolicyManager command = ('contracts', '--contract-name', POLICY_MANAGER_CONTRACT_NAME, '--provider', TEST_PROVIDER_URI, '--network', TEMPORARY_DOMAIN, '--registry-infile', ALTERNATE_REGISTRY_FILEPATH_2) result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 deployed_contracts.extend([POLICY_MANAGER_CONTRACT_NAME, DISPATCHER_CONTRACT_NAME]) assert list(new_registry.enrolled_names) == deployed_contracts # 4. Deploy Adjudicator command = ('contracts', '--contract-name', ADJUDICATOR_CONTRACT_NAME, '--provider', TEST_PROVIDER_URI, '--network', TEMPORARY_DOMAIN, '--registry-infile', ALTERNATE_REGISTRY_FILEPATH_2) result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 deployed_contracts.extend([ADJUDICATOR_CONTRACT_NAME, DISPATCHER_CONTRACT_NAME]) assert list(new_registry.enrolled_names) == deployed_contracts # 5. Deploy StakingEscrow in IDLE mode command = ('contracts', '--contract-name', STAKING_ESCROW_CONTRACT_NAME, '--mode', 'idle', '--provider', TEST_PROVIDER_URI, '--network', TEMPORARY_DOMAIN, '--registry-infile', ALTERNATE_REGISTRY_FILEPATH_2) result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 deployed_contracts.extend([STAKING_ESCROW_CONTRACT_NAME]) assert list(new_registry.enrolled_names) == deployed_contracts # 6. Activate StakingEscrow command = ('contracts', '--contract-name', STAKING_ESCROW_CONTRACT_NAME, '--activate', '--provider', TEST_PROVIDER_URI, '--network', TEMPORARY_DOMAIN, '--registry-infile', ALTERNATE_REGISTRY_FILEPATH_2) user_input = '0\n' + YES_ENTER + YES_ENTER + INSECURE_DEVELOPMENT_PASSWORD result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 assert list(new_registry.enrolled_names) == deployed_contracts
def test_upgrade_contracts(click_runner, registry_filepath, testerchain): # # Setup # # Check the existing state of the registry before the meat and potatoes expected_enrollments = 9 with open(registry_filepath, 'r') as file: raw_registry_data = file.read() registry_data = json.loads(raw_registry_data) assert len(registry_data) == expected_enrollments # # Input Components # cli_action = 'upgrade' base_command = ('--registry-infile', registry_filepath, '--provider', TEST_PROVIDER_URI, '--poa') # Generate user inputs yes = 'Y\n' # :-) upgrade_inputs = dict() for version, insecure_secret in INSECURE_SECRETS.items(): next_version = version + 1 old_secret = INSECURE_SECRETS[version] try: new_secret = INSECURE_SECRETS[next_version] except KeyError: continue # addr-----secret----new deploy secret (2x for confirmation) user_input = '0\n' + yes + old_secret + (new_secret * 2) upgrade_inputs[next_version] = user_input # # Stage Upgrades # contracts_to_upgrade = ( 'StakingEscrow', # v1 -> v2 'PolicyManager', # v1 -> v2 'Adjudicator', # v1 -> v2 'UserEscrowProxy', # v1 -> v2 'StakingEscrow', # v2 -> v3 'StakingEscrow', # v3 -> v4 'Adjudicator', # v2 -> v3 'PolicyManager', # v2 -> v3 'UserEscrowProxy', # v2 -> v3 'UserEscrowProxy', # v3 -> v4 'PolicyManager', # v3 -> v4 'Adjudicator', # v3 -> v4 ) # NOTE: Keep all versions the same in this test (all version 4, for example) # Each contract starts at version 1 version_tracker = {name: 1 for name in contracts_to_upgrade} # # Upgrade Contracts # for contract_name in contracts_to_upgrade: # Select proxy (Dispatcher vs Linker) if contract_name == "UserEscrowProxy": proxy_name = "UserEscrowLibraryLinker" else: proxy_name = 'Dispatcher' registry = LocalContractRegistry(filepath=registry_filepath) real_old_contract = testerchain.get_contract_by_name( name=contract_name, registry=registry, proxy_name=proxy_name, use_proxy_address=False) # Ensure the proxy targets the current deployed contract proxy = testerchain.get_proxy(registry=registry, target_address=real_old_contract.address, proxy_name=proxy_name) targeted_address = proxy.functions.target().call() assert targeted_address == real_old_contract.address # Assemble CLI command command = (cli_action, '--contract-name', contract_name, *base_command) # Select upgrade interactive input scenario current_version = version_tracker[contract_name] new_version = current_version + 1 user_input = upgrade_inputs[new_version] # Execute upgrade (Meat) result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # TODO: Console painting # Mutate the version tracking version_tracker[contract_name] += 1 expected_enrollments += 1 # Verify the registry is updated (Potatoes) with open(registry_filepath, 'r') as file: # Read the registry file directly, bypassing its interfaces raw_registry_data = file.read() registry_data = json.loads(raw_registry_data) assert len( registry_data ) == expected_enrollments, f'Unexpected number of enrollments for {contract_name}' # Check that there is more than one entry, since we've deployed a "version 2" expected_contract_enrollments = current_version + 1 registered_names = [r[0] for r in registry_data] contract_enrollments = registered_names.count(contract_name) assert contract_enrollments > 1, f"New contract is not enrolled in {MOCK_REGISTRY_FILEPATH}" error = f"Incorrect number of records enrolled for {contract_name}. " \ f"Expected {expected_contract_enrollments} got {contract_enrollments}." assert contract_enrollments == expected_contract_enrollments, error # Ensure deployments are different addresses registry = LocalContractRegistry(filepath=registry_filepath) records = registry.search(contract_name=contract_name) assert len(records) == contract_enrollments, error old, new = records[-2:] # Get the last two entries old_name, old_address, *abi = old # Previous version new_name, new_address, *abi = new # New version assert old_address == real_old_contract.address assert old_name == new_name # TODO: Inspect ABI / Move to different test. assert old_address != new_address # Ensure the proxy now targets the new deployment proxy = testerchain.get_proxy(registry=registry, target_address=new_address, proxy_name=proxy_name) targeted_address = proxy.functions.target().call() assert targeted_address != old_address assert targeted_address == new_address
def __init__(self, # Base config_root: str = None, filepath: str = None, # Mode dev_mode: bool = False, federated_only: bool = False, # Identity checksum_address: str = None, crypto_power: CryptoPower = None, # Keyring keyring: NucypherKeyring = None, keyring_root: str = None, # Learner learn_on_same_thread: bool = False, abort_on_learning_error: bool = False, start_learning_now: bool = True, # Network controller_port: int = None, domains: Set[str] = None, # TODO: Mapping between learning domains and "registry" domains - #1580 interface_signature: Signature = None, network_middleware: RestMiddleware = None, # Node Storage known_nodes: set = None, node_storage: NodeStorage = None, reload_metadata: bool = True, save_metadata: bool = True, # Blockchain poa: bool = False, light: bool = False, sync: bool = False, provider_uri: str = None, provider_process=None, gas_strategy: Union[Callable, str] = DEFAULT_GAS_STRATEGY, # Registry registry: BaseContractRegistry = None, registry_filepath: str = None, emitter=None, ): self.log = Logger(self.__class__.__name__) UNINITIALIZED_CONFIGURATION.bool_value(False) # Identity # NOTE: NodeConfigurations can only be used with Self-Characters self.is_me = True self.checksum_address = checksum_address # Network self.controller_port = controller_port or self.DEFAULT_CONTROLLER_PORT self.network_middleware = network_middleware or self.DEFAULT_NETWORK_MIDDLEWARE() self.interface_signature = interface_signature # Keyring self.crypto_power = crypto_power self.keyring = keyring or NO_KEYRING_ATTACHED self.keyring_root = keyring_root or UNINITIALIZED_CONFIGURATION # Contract Registry if registry and registry_filepath: if registry.filepath != registry_filepath: error = f"Inconsistent registry filepaths for '{registry.filepath}' and '{registry_filepath}'." raise ValueError(error) else: self.log.warn(f"Registry and registry filepath were both passed.") self.registry = registry or NO_BLOCKCHAIN_CONNECTION.bool_value(False) self.registry_filepath = registry_filepath or UNINITIALIZED_CONFIGURATION # Blockchain self.poa = poa self.is_light = light self.provider_uri = provider_uri or NO_BLOCKCHAIN_CONNECTION self.provider_process = provider_process or NO_BLOCKCHAIN_CONNECTION # Learner self.federated_only = federated_only self.domains = domains or {self.DEFAULT_DOMAIN} self.learn_on_same_thread = learn_on_same_thread self.abort_on_learning_error = abort_on_learning_error self.start_learning_now = start_learning_now self.save_metadata = save_metadata self.reload_metadata = reload_metadata self.known_nodes = known_nodes or set() # handpicked # Configuration self.__dev_mode = dev_mode self.config_file_location = filepath or UNINITIALIZED_CONFIGURATION self.config_root = UNINITIALIZED_CONFIGURATION # # Federated vs. Blockchain arguments consistency # # # Federated # if self.federated_only: # Check for incompatible values blockchain_args = {'filepath': registry_filepath, 'poa': poa, 'provider_process': provider_process, 'provider_uri': provider_uri, 'gas_strategy': gas_strategy} if any(blockchain_args.values()): bad_args = (f"{arg}={val}" for arg, val in blockchain_args.items() if val) self.log.warn(f"Arguments {bad_args} are incompatible with federated_only. " f"Overridden with a sane default.") # Clear decentralized attributes to ensure consistency with a # federated configuration. self.poa = False self.is_light = False self.provider_uri = None self.provider_process = None self.registry_filepath = None self.gas_strategy = None # # Decentralized # else: self.gas_strategy = gas_strategy is_initialized = BlockchainInterfaceFactory.is_interface_initialized(provider_uri=self.provider_uri) if not is_initialized and provider_uri: BlockchainInterfaceFactory.initialize_interface(provider_uri=self.provider_uri, poa=self.poa, light=self.is_light, provider_process=self.provider_process, sync=sync, emitter=emitter, gas_strategy=gas_strategy) else: self.log.warn(f"Using existing blockchain interface connection ({self.provider_uri}).") if not self.registry: # TODO: These two code blocks are untested. if not self.registry_filepath: # TODO: Registry URI (goerli://speedynet.json) :-) self.log.info(f"Fetching latest registry from source.") self.registry = InMemoryContractRegistry.from_latest_publication(network=list(self.domains)[0]) # TODO: #1580 else: self.registry = LocalContractRegistry(filepath=self.registry_filepath) self.log.info(f"Using local registry ({self.registry}).") if dev_mode: self.__temp_dir = UNINITIALIZED_CONFIGURATION self.__setup_node_storage() self.initialize(password=DEVELOPMENT_CONFIGURATION) else: self.__temp_dir = LIVE_CONFIGURATION self.config_root = config_root or self.DEFAULT_CONFIG_ROOT self._cache_runtime_filepaths() self.__setup_node_storage(node_storage=node_storage) super().__init__(filepath=self.config_file_location, config_root=self.config_root)
def agency_local_registry(testerchain, agency, test_registry): registry = LocalContractRegistry(filepath=MOCK_REGISTRY_FILEPATH) registry.write(test_registry.read()) yield registry if os.path.exists(MOCK_REGISTRY_FILEPATH): os.remove(MOCK_REGISTRY_FILEPATH)
def agency_local_registry(testerchain, agency, test_registry): registry = LocalContractRegistry(filepath=MOCK_REGISTRY_FILEPATH) registry.write(test_registry.read()) yield registry if MOCK_REGISTRY_FILEPATH.exists(): MOCK_REGISTRY_FILEPATH.unlink()
def test_nucypher_deploy_contracts(click_runner, token_economics, registry_filepath, testerchain): # # Main # assert not os.path.exists( registry_filepath), f"Registry File '{registry_filepath}' Exists." assert not os.path.lexists( registry_filepath), f"Registry File '{registry_filepath}' Exists." command = [ 'contracts', '--registry-outfile', registry_filepath, '--provider', TEST_PROVIDER_URI, '--se-test-mode' ] user_input = '0\n' + 'Y\n' + 'DEPLOY' result = click_runner.invoke(deploy, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # Ensure there is a report on each primary contract contract_names = tuple( a.contract_name for a in ContractAdministrator.primary_deployer_classes) for registry_name in contract_names: assert registry_name in result.output # Check that the primary contract registry was written # and peek at some of the registered entries assert os.path.isfile(registry_filepath) with open(registry_filepath, 'r') as file: # Ensure every contract's name was written to the file, somehow raw_registry_data = file.read() for registry_name in contract_names: assert registry_name in raw_registry_data # Ensure the Registry is JSON deserializable registry_data = json.loads(raw_registry_data) # and that is has the correct number of entries assert len(registry_data) == 9 # Read several records token_record, escrow_record, dispatcher_record, *other_records = registry_data registered_name, registered_version, registered_address, registered_abi = token_record # # Agency # registry = LocalContractRegistry(filepath=registry_filepath) token_agent = NucypherTokenAgent(registry=registry) assert token_agent.contract_name == registered_name assert token_agent.registry_contract_name == registered_name assert token_agent.contract_address == registered_address assert token_agent.contract.version == registered_version # Now show that we can use contract Agency and read from the blockchain assert token_agent.get_balance() == 0 staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=registry) assert staking_agent.get_current_period() assert staking_agent.contract.functions.isTestContract().call() # and at least the others can be instantiated assert PolicyManagerAgent(registry=registry) assert AdjudicatorAgent(registry=registry)