def test_contract_registry(tempfile_path): # ABC with pytest.raises(TypeError): BaseContractRegistry(filepath='test') with pytest.raises(BaseContractRegistry.RegistryError): bad_registry = LocalContractRegistry(filepath='/fake/file/path/registry.json') bad_registry.search(contract_address='0xdeadbeef') # Tests everything is as it should be when initially created test_registry = LocalContractRegistry(filepath=tempfile_path) assert test_registry.read() == list() # Test contract enrollment and dump_chain test_name = 'TestContract' test_addr = '0xDEADBEEF' test_abi = ['fake', 'data'] test_version = "some_version" test_registry.enroll(contract_name=test_name, contract_address=test_addr, contract_abi=test_abi, contract_version=test_version) # Search by name... contract_records = test_registry.search(contract_name=test_name) assert len(contract_records) == 1, 'More than one record for {}'.format(test_name) assert len(contract_records[0]) == 4, 'Registry record is the wrong length' name, version, address, abi = contract_records[0] assert name == test_name assert address == test_addr assert abi == test_abi assert version == test_version # ...or by address contract_record = test_registry.search(contract_address=test_addr) name, version, address, abi = contract_record assert name == test_name assert address == test_addr assert abi == test_abi assert version == test_version # Check that searching for an unknown contract raises with pytest.raises(BaseContractRegistry.UnknownContract): test_registry.search(contract_name='this does not exist') current_dataset = test_registry.read() # Corrupt the registry with a duplicate address current_dataset.append([test_name, test_addr, test_abi]) test_registry.write(current_dataset) # Check that searching for an unknown contract raises with pytest.raises(BaseContractRegistry.InvalidRegistry): test_registry.search(contract_address=test_addr)
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_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_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