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)
Exemple #2
0
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
Exemple #4
0
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
Exemple #5
0
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