Ejemplo n.º 1
0
def vm():
    header = CollationHeader(
        shard_id=0,
        expected_period_number=2,
        period_start_prevhash=decode_hex(
            "3c4cc7b99c7eb9281e9a8d15cd4b2f98c5df085e929f15388c699b41cdde78d7"
        ),
        parent_hash=ZERO_HASH32,
        transaction_root=EMPTY_SHA3,
        coinbase=to_canonical_address(
            "8888f1f195afa192cfee860698584c030f4c9db1"),
        state_root=EMPTY_SHA3,
        receipt_root=EMPTY_SHA3,
        number=10,
    )
    chaindb = ChainDB(
        get_db_backend(),
        account_state_class=ShardingAccountStateDB,
        trie_class=BinaryTrie,
    )
    vm = ShardingVM(header=header, chaindb=chaindb)
    vm_state = vm.state
    with vm_state.state_db() as statedb:
        for address, code in HELPER_CONTRACTS.items():
            statedb.set_code(address, code)
        statedb.set_balance(ACCOUNT_ADDRESS, INITIAL_BALANCE)
    # Update state_root manually
    vm.block.header.state_root = vm_state.state_root

    return vm
Ejemplo n.º 2
0
def chain_without_block_validation():
    """
    Return a Chain object containing just the genesis block.

    This Chain does not perform any validation when importing new blocks.

    The Chain's state includes one funded account and a private key for it, which can be found in
    the funded_address and private_keys variables in the chain itself.
    """
    # Disable block validation so that we don't need to construct finalized blocks.
    overrides = {
        'ensure_blocks_are_equal': lambda self, b1, b2: None,
        'validate_block': lambda self, block: None,
    }
    klass = Chain.configure(
        name='TestChainWithoutBlockValidation',
        vm_configuration=((constants.GENESIS_BLOCK_NUMBER, FrontierVM), ),
        **overrides,
    )
    private_key = decode_hex(
        '0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8')
    funded_addr = private_key_to_address(private_key)
    initial_balance = 100000000
    genesis_params = {
        'block_number':
        constants.GENESIS_BLOCK_NUMBER,
        'difficulty':
        constants.GENESIS_DIFFICULTY,
        'gas_limit':
        constants.GENESIS_GAS_LIMIT,
        'parent_hash':
        constants.GENESIS_PARENT_HASH,
        'coinbase':
        constants.GENESIS_COINBASE,
        'nonce':
        constants.GENESIS_NONCE,
        'mix_hash':
        constants.GENESIS_MIX_HASH,
        'extra_data':
        constants.GENESIS_EXTRA_DATA,
        'timestamp':
        1501851927,
        'state_root':
        decode_hex(
            '0x9d354f9b5ba851a35eced279ef377111387197581429cfcc7f744ef89a30b5d4'
        )
    }
    genesis_state = {
        funded_addr: {
            'balance': initial_balance,
            'nonce': 0,
            'code': b'',
            'storage': {},
        }
    }
    chain = klass.from_genesis(get_db_backend(), genesis_params, genesis_state)
    chain.funded_address = funded_addr
    chain.funded_address_initial_balance = initial_balance
    chain.funded_address_private_key = private_key
    return chain
Ejemplo n.º 3
0
def test_vm_not_found_if_no_matching_block_number():
    chain_class = Chain.configure('TestChain', vm_configuration=(
        (10, FrontierVM),
    ))
    chain = chain_class(get_db_backend(), BlockHeader(1, 0, 100))
    with pytest.raises(VMNotFound):
        chain.get_vm_class_for_block_number(9)
def test_vm_not_found_if_no_matching_block_number():
    chain_class = Chain.configure('TestChain', vm_configuration=(
        (10, FrontierVM),
    ))
    chain = chain_class(get_db_backend(), BlockHeader(1, 0, 100))
    with pytest.raises(VMNotFound):
        chain.get_vm_class_for_block_number(9)
Ejemplo n.º 5
0
def chaindb(request):
    if request.param is MainAccountStateDB:
        trie_class = HexaryTrie
    else:
        trie_class = BinaryTrie
    return ChainDB(
        get_db_backend(),
        account_state_class=request.param,
        trie_class=trie_class,
    )
Ejemplo n.º 6
0
def setup_tester_chain():
    from evm.vm.flavors import MainnetTesterChain
    from evm.db import get_db_backend

    db = get_db_backend()
    genesis_params = get_default_genesis_params()
    account_keys = get_default_account_keys()
    genesis_state = generate_genesis_state(account_keys)

    chain = MainnetTesterChain.from_genesis(db, genesis_params, genesis_state)
    return account_keys, chain
Ejemplo n.º 7
0
def setup_tester_chain():
    from evm.chains.tester import MainnetTesterChain
    from evm.db import get_db_backend
    from evm.db.chain import ChainDB

    db = ChainDB(get_db_backend())
    genesis_params = get_default_genesis_params()
    account_keys = get_default_account_keys()
    genesis_state = generate_genesis_state(account_keys)

    chain = MainnetTesterChain.from_genesis(db, genesis_params, genesis_state)
    return account_keys, chain
Ejemplo n.º 8
0
def test_get_vm_class_for_block_number():
    chain_class = Chain.configure(vm_configuration=(
        (constants.GENESIS_BLOCK_NUMBER, FrontierVM),
        (constants.HOMESTEAD_MAINNET_BLOCK, HomesteadVM),
    ), )
    chain = chain_class(get_db_backend(), BlockHeader(1, 0, 100))
    assert chain.get_vm_class_for_block_number(
        constants.GENESIS_BLOCK_NUMBER, ) == FrontierVM
    assert chain.get_vm_class_for_block_number(
        constants.HOMESTEAD_MAINNET_BLOCK - 1) == FrontierVM
    assert chain.get_vm_class_for_block_number(
        constants.HOMESTEAD_MAINNET_BLOCK) == HomesteadVM
    assert chain.get_vm_class_for_block_number(
        constants.HOMESTEAD_MAINNET_BLOCK + 1) == HomesteadVM
Ejemplo n.º 9
0
def test_transaction_fixtures(fixture_name, fixture):
    header = BlockHeader(1, fixture.get('blocknumber', 0), 100)
    chain = MainnetChain(get_db_backend(), header=header)
    vm = chain.get_vm()
    TransactionClass = vm.get_transaction_class()

    if 'sender' in fixture:
        transaction = rlp.decode(fixture['rlp'], sedes=TransactionClass)
        expected = normalize_signed_transaction(fixture['transaction'])

        assert transaction.nonce == expected['nonce']
        assert transaction.gas_price == expected['gasPrice']
        assert transaction.gas == expected['gasLimit']
        assert transaction.to == expected['to']
        assert transaction.value == expected['value']
        assert transaction.data == expected['data']
        assert transaction.v == expected['v']
        assert transaction.r == expected['r']
        assert transaction.s == expected['s']

        sender = to_canonical_address(fixture['sender'])

        try:
            assert transaction.sender == sender
        except BadSignature:
            assert not (27 <= transaction.v <= 34)
    else:
        # check RLP correctness
        try:
            transaction = rlp.decode(fixture['rlp'], sedes=TransactionClass)
        # fixture normalization changes the fixture key from rlp to rlpHex
        except KeyError:
            assert fixture['rlpHex']
            return
        # rlp is a list of bytes when it shouldn't be
        except TypeError as err:
            assert err.args == (
                "'bytes' object cannot be interpreted as an integer", )
            return
        # rlp is invalid or not in the correct form
        except (rlp.exceptions.ObjectDeserializationError,
                rlp.exceptions.DecodingError):
            return

        # check parameter correctness
        try:
            transaction.validate()
        except ValidationError:
            return
Ejemplo n.º 10
0
def new_chain_from_fixture(fixture):
    db = ChainDB(get_db_backend())

    vm_config = chain_vm_configuration(fixture)

    ChainFromFixture = MainnetChain.configure(
        'ChainFromFixture',
        vm_configuration=vm_config,
    )

    return ChainFromFixture.from_genesis(
        db,
        genesis_params=genesis_params_from_fixture(fixture),
        genesis_state=fixture['pre'],
    )
Ejemplo n.º 11
0
def new_chain_from_fixture(fixture):
    db = BaseChainDB(get_db_backend())

    vm_config = chain_vm_configuration(fixture)

    ChainFromFixture = MainnetChain.configure(
        'ChainFromFixture',
        vm_configuration=vm_config,
    )

    return ChainFromFixture.from_genesis(
        db,
        genesis_params=genesis_params_from_fixture(fixture),
        genesis_state=fixture['pre'],
    )
Ejemplo n.º 12
0
def test_state_fixtures(fixture_name, fixture):
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
        parent_hash=fixture['env']['previousHash'],
    )
    db = get_db_backend()
    chain = ChainForTesting(db=db, header=header)

    state_db = setup_state_db(fixture['pre'], chain.get_state_db())
    chain.header.state_root = state_db.root_hash

    unsigned_transaction = chain.create_unsigned_transaction(
        nonce=fixture['transaction']['nonce'],
        gas_price=fixture['transaction']['gasPrice'],
        gas=fixture['transaction']['gasLimit'],
        to=fixture['transaction']['to'],
        value=fixture['transaction']['value'],
        data=fixture['transaction']['data'],
    )
    transaction = unsigned_transaction.as_signed_transaction(
        private_key=fixture['transaction']['secretKey'])

    try:
        computation = chain.apply_transaction(transaction)
    except ValidationError:
        transaction_error = True
    else:
        transaction_error = False

    if not transaction_error:
        expected_logs = [{
            'address': log_entry[0],
            'topics': log_entry[1],
            'data': log_entry[2],
        } for log_entry in computation.get_log_entries()]
        expected_logs == fixture['logs']

        expected_output = fixture['out']
        if isinstance(expected_output, int):
            assert len(computation.output) == expected_output
        else:
            assert computation.output == expected_output

    verify_state_db(fixture['post'], chain.get_state_db())
Ejemplo n.º 13
0
    def reset_to_genesis(self, overrides=None):
        from evm.chains.tester import MainnetTesterChain
        from evm.db import get_db_backend

        base_db = get_db_backend()
        genesis_params = get_default_genesis_params()

        # Genesis params overrides
        if overrides is not None:
            genesis_params.update(overrides)

        account_keys = get_default_account_keys()
        genesis_state = generate_genesis_state(account_keys)
        chain = MainnetTesterChain.from_genesis(base_db, genesis_params, genesis_state)

        self.account_keys, self.chain = account_keys, chain
Ejemplo n.º 14
0
def test_transaction_fixtures(fixture):
    header = BlockHeader(1, fixture['blocknumber'], 100)
    chain = MainnetChain(ChainDB(get_db_backend()), header=header)
    vm = chain.get_vm()
    TransactionClass = vm.get_transaction_class()

    if 'sender' in fixture:
        transaction = rlp.decode(fixture['rlp'], sedes=TransactionClass)
        expected = normalize_signed_transaction(fixture['transaction'])

        assert transaction.nonce == expected['nonce']
        assert transaction.gas_price == expected['gasPrice']
        assert transaction.gas == expected['gasLimit']
        assert transaction.to == expected['to']
        assert transaction.value == expected['value']
        assert transaction.data == expected['data']
        assert transaction.v == expected['v']
        assert transaction.r == expected['r']
        assert transaction.s == expected['s']

        sender = to_canonical_address(fixture['sender'])

        try:
            assert transaction.sender == sender
        except BadSignature:
            assert not (27 <= transaction.v <= 34)
    else:
        # check RLP correctness
        try:
            transaction = rlp.decode(fixture['rlp'], sedes=TransactionClass)
        # fixture normalization changes the fixture key from rlp to rlpHex
        except KeyError:
            assert fixture['rlpHex']
            return
        # rlp is a list of bytes when it shouldn't be
        except TypeError as err:
            assert err.args == ("'bytes' object cannot be interpreted as an integer",)
            return
        # rlp is invalid or not in the correct form
        except (rlp.exceptions.ObjectDeserializationError, rlp.exceptions.DecodingError):
            return

        # check parameter correctness
        try:
            transaction.validate()
        except ValidationError:
            return
def test_get_vm_class_for_block_number():
    chain_class = Chain.configure(
        name='TestChain',
        vm_configuration=(
            (constants.GENESIS_BLOCK_NUMBER, FrontierVM),
            (HOMESTEAD_MAINNET_BLOCK, HomesteadVM),
        ),
    )
    chain = chain_class(get_db_backend(), BlockHeader(1, 0, 100))
    assert chain.get_vm_class_for_block_number(
        constants.GENESIS_BLOCK_NUMBER,) == FrontierVM
    assert chain.get_vm_class_for_block_number(
        HOMESTEAD_MAINNET_BLOCK - 1) == FrontierVM
    assert chain.get_vm_class_for_block_number(
        HOMESTEAD_MAINNET_BLOCK) == HomesteadVM
    assert chain.get_vm_class_for_block_number(
        HOMESTEAD_MAINNET_BLOCK + 1) == HomesteadVM
Ejemplo n.º 16
0
def chain_without_block_validation(chaindb, funded_address,
                                   funded_address_initial_balance):
    """
    Return a Chain object containing just the genesis block.

    This Chain does not perform any validation when importing new blocks.

    The Chain's state includes one funded account and a private key for it, which can be found in
    the funded_address and private_keys variables in the chain itself.
    """
    # Disable block validation so that we don't need to construct finalized blocks.
    overrides = {
        'import_block': import_block_without_validation,
        'validate_block': lambda self, block: None,
    }
    klass = Chain.configure(
        name='TestChainWithoutBlockValidation',
        vm_configuration=((constants.GENESIS_BLOCK_NUMBER, FrontierVM), ),
        **overrides,
    )
    genesis_params = {
        'block_number': constants.GENESIS_BLOCK_NUMBER,
        'difficulty': constants.GENESIS_DIFFICULTY,
        'gas_limit': constants.GENESIS_GAS_LIMIT,
        'parent_hash': constants.GENESIS_PARENT_HASH,
        'coinbase': constants.GENESIS_COINBASE,
        'nonce': constants.GENESIS_NONCE,
        'mix_hash': constants.GENESIS_MIX_HASH,
        'extra_data': constants.GENESIS_EXTRA_DATA,
        'timestamp': 1501851927,
    }
    genesis_state = {
        funded_address: {
            'balance': funded_address_initial_balance,
            'nonce': 0,
            'code': b'',
            'storage': {},
        }
    }
    chain = klass.from_genesis(ChainDB(get_db_backend()), genesis_params,
                               genesis_state)
    return chain
Ejemplo n.º 17
0
def setup_tester_chain():
    from evm.chains.tester import MainnetTesterChain
    from evm.db import get_db_backend
    from evm.vm.forks.byzantium import ByzantiumVM

    class ByzantiumNoProofVM(ByzantiumVM):
        """Byzantium VM rules, without validating any miner proof of work"""
        def validate_seal(self, header):
            pass

    class MainnetTesterNoProofChain(MainnetTesterChain):
        vm_configuration = ((0, ByzantiumNoProofVM), )

    genesis_params = get_default_genesis_params()
    account_keys = get_default_account_keys()
    genesis_state = generate_genesis_state(account_keys)

    base_db = get_db_backend()

    chain = MainnetTesterNoProofChain.from_genesis(base_db, genesis_params,
                                                   genesis_state)
    return account_keys, chain
Ejemplo n.º 18
0
def test_blockchain_fixtures(fixture_name, fixture):
    genesis_params = {
        'parent_hash': fixture['genesisBlockHeader']['parentHash'],
        'uncles_hash': fixture['genesisBlockHeader']['uncleHash'],
        'coinbase': fixture['genesisBlockHeader']['coinbase'],
        'state_root': fixture['genesisBlockHeader']['stateRoot'],
        'transaction_root': fixture['genesisBlockHeader']['transactionsTrie'],
        'receipt_root': fixture['genesisBlockHeader']['receiptTrie'],
        'bloom': fixture['genesisBlockHeader']['bloom'],
        'difficulty': fixture['genesisBlockHeader']['difficulty'],
        'block_number': fixture['genesisBlockHeader']['number'],
        'gas_limit': fixture['genesisBlockHeader']['gasLimit'],
        'gas_used': fixture['genesisBlockHeader']['gasUsed'],
        'timestamp': fixture['genesisBlockHeader']['timestamp'],
        'extra_data': fixture['genesisBlockHeader']['extraData'],
        'mix_hash': fixture['genesisBlockHeader']['mixHash'],
        'nonce': fixture['genesisBlockHeader']['nonce'],
    }
    expected_genesis_header = BlockHeader(**genesis_params)

    # TODO: find out if this is supposed to pass?
    # if 'genesisRLP' in fixture:
    #     assert rlp.encode(genesis_header) == fixture['genesisRLP']

    db = get_db_backend()
    chain = MainnetChain
    # TODO: It would be great if we can figure out an API for re-configuring
    # start block numbers that was more elegant.
    if fixture_name.startswith('Homestead'):
        chain = Chain.configure('HomesteadChain',
                                vm_configuration=[(0, HomesteadVM)])
    elif fixture_name.startswith('EIP150'):
        chain = Chain.configure('EIP150VM', vm_configuration=[(0, EIP150VM)])
    elif fixture_name.startswith('TestNetwork'):
        homestead_vm = HomesteadVM.configure(dao_fork_block_number=8)
        chain = Chain.configure('TestNetworkChain',
                                vm_configuration=[
                                    (0, FrontierVM),
                                    (5, homestead_vm),
                                    (10, EIP150VM),
                                ])

    chain = chain.from_genesis(
        db,
        genesis_params=genesis_params,
        genesis_state=fixture['pre'],
    )

    genesis_block = chain.get_canonical_block_by_number(0)
    genesis_header = genesis_block.header

    assert_rlp_equal(genesis_header, expected_genesis_header)

    # 1 - mine the genesis block
    # 2 - loop over blocks:
    #     - apply transactions
    #     - mine block
    # 4 - profit!!

    for block_data in fixture['blocks']:
        should_be_good_block = 'blockHeader' in block_data

        if 'rlp_error' in block_data:
            assert not should_be_good_block
            continue

        # The block to import may be in a different block-class-range than the
        # chain's current one, so we use the block number specified in the
        # fixture to look up the correct block class.
        if should_be_good_block:
            block_number = block_data['blockHeader']['number']
            block_class = chain.get_vm_class_for_block_number(
                block_number).get_block_class()
        else:
            block_class = chain.get_vm().get_block_class()

        try:
            block = rlp.decode(block_data['rlp'], sedes=block_class, db=db)
        except (TypeError, rlp.DecodingError, rlp.DeserializationError) as err:
            assert not should_be_good_block, "Block should be good: {0}".format(
                err)
            continue

        try:
            mined_block = chain.import_block(block)
        except ValidationError as err:
            assert not should_be_good_block, "Block should be good: {0}".format(
                err)
            continue
        else:
            assert_rlp_equal(mined_block, block)
            assert should_be_good_block, "Block should have caused a validation error"

    latest_block_hash = chain.get_canonical_block_by_number(
        chain.get_block().number - 1).hash
    assert latest_block_hash == fixture['lastblockhash']

    verify_state_db(fixture['postState'], chain.get_state_db())
Ejemplo n.º 19
0
def test_raises_if_db_path_is_not_specified(config_env):
    with pytest.raises(TypeError):
        get_db_backend()
Ejemplo n.º 20
0
def test_state_fixtures(fixture, fixture_vm_class):
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
        parent_hash=fixture['env']['previousHash'],
    )
    chaindb = ChainDB(get_db_backend())
    vm = fixture_vm_class(header=header, chaindb=chaindb)

    vm_state = vm.state
    with vm_state.mutable_state_db() as state_db:
        setup_state_db(fixture['pre'], state_db)
    # Update state_root manually
    vm.block.header.state_root = vm_state.state_root

    if 'secretKey' in fixture['transaction']:
        unsigned_transaction = vm.create_unsigned_transaction(
            nonce=fixture['transaction']['nonce'],
            gas_price=fixture['transaction']['gasPrice'],
            gas=fixture['transaction']['gasLimit'],
            to=fixture['transaction']['to'],
            value=fixture['transaction']['value'],
            data=fixture['transaction']['data'],
        )
        private_key = keys.PrivateKey(fixture['transaction']['secretKey'])
        transaction = unsigned_transaction.as_signed_transaction(
            private_key=private_key)
    elif 'vrs' in fixture['transaction']:
        v, r, s = (
            fixture['transaction']['v'],
            fixture['transaction']['r'],
            fixture['transaction']['s'],
        )
        transaction = vm.create_transaction(
            nonce=fixture['transaction']['nonce'],
            gas_price=fixture['transaction']['gasPrice'],
            gas=fixture['transaction']['gasLimit'],
            to=fixture['transaction']['to'],
            value=fixture['transaction']['value'],
            data=fixture['transaction']['data'],
            v=v,
            r=r,
            s=s,
        )

    try:
        computation, _ = vm.apply_transaction(transaction)
    except ValidationError as err:
        transaction_error = err
        LOGGER.warn("Got transaction error:")
        LOGGER.warn(traceback.format_exc())
    else:
        transaction_error = False

    if not transaction_error:
        log_entries = computation.get_log_entries()
        actual_logs_hash = hash_log_entries(log_entries)
        if 'logs' in fixture['post']:
            expected_logs_hash = fixture['post']['logs']
            assert expected_logs_hash == actual_logs_hash
        elif log_entries:
            raise AssertionError("Got log {0} entries. hash:{1}".format(
                len(log_entries),
                actual_logs_hash,
            ))

        if 'out' in fixture:
            expected_output = fixture['out']
            if isinstance(expected_output, int):
                assert len(computation.output) == expected_output
            else:
                assert computation.output == expected_output

    assert vm.block.header.state_root == fixture['post']['hash']
Ejemplo n.º 21
0
def test_vm_fixtures(fixture, vm_class, computation_getter):
    chaindb = ChainDB(get_db_backend())
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
    )
    vm = vm_class(header=header, chaindb=chaindb)
    vm_state = vm.state
    with vm_state.state_db() as state_db:
        setup_state_db(fixture['pre'], state_db)
        code = state_db.get_code(fixture['exec']['address'])
    # Update state_root manually
    vm.block.header.state_root = vm_state.state_root

    computation = computation_getter(fixture, code, vm)

    # Update state_root manually
    vm.block.header.state_root = computation.vm_state.state_root

    if 'post' in fixture:
        #
        # Success checks
        #
        assert not computation.is_error

        log_entries = computation.get_log_entries()
        if 'logs' in fixture:
            actual_logs_hash = hash_log_entries(log_entries)
            expected_logs_hash = fixture['logs']
            assert expected_logs_hash == actual_logs_hash
        elif log_entries:
            raise AssertionError("Got log entries: {0}".format(log_entries))

        expected_output = fixture['out']
        assert computation.output == expected_output

        gas_meter = computation.gas_meter

        expected_gas_remaining = fixture['gas']
        actual_gas_remaining = gas_meter.gas_remaining
        gas_delta = actual_gas_remaining - expected_gas_remaining
        assert gas_delta == 0, "Gas difference: {0}".format(gas_delta)

        call_creates = fixture.get('callcreates', [])
        assert len(computation.children) == len(call_creates)

        call_creates = fixture.get('callcreates', [])
        for child_computation, created_call in zip(computation.children, call_creates):
            to_address = created_call['destination']
            data = created_call['data']
            gas_limit = created_call['gasLimit']
            value = created_call['value']

            assert child_computation.msg.to == to_address
            assert data == child_computation.msg.data or child_computation.msg.code
            assert gas_limit == child_computation.msg.gas
            assert value == child_computation.msg.value
        post_state = fixture['post']
    else:
        #
        # Error checks
        #
        assert computation.is_error
        assert isinstance(computation._error, VMError)
        post_state = fixture['pre']

    with vm.state.state_db(read_only=True) as state_db:
        verify_state_db(post_state, state_db)
Ejemplo n.º 22
0
def test_vm_fixtures(fixture, vm_class, computation_getter):
    chaindb = ChainDB(get_db_backend())
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
    )
    vm = vm_class(header=header, chaindb=chaindb)
    vm_state = vm.state
    with vm_state.state_db() as state_db:
        setup_state_db(fixture['pre'], state_db)
        code = state_db.get_code(fixture['exec']['address'])
    # Update state_root manually
    vm.block.header.state_root = vm_state.state_root

    computation = computation_getter(fixture, code, vm)

    # Update state_root manually
    vm.block.header.state_root = computation.vm_state.state_root

    if 'post' in fixture:
        #
        # Success checks
        #
        assert not computation.is_error

        log_entries = computation.get_log_entries()
        if 'logs' in fixture:
            actual_logs_hash = hash_log_entries(log_entries)
            expected_logs_hash = fixture['logs']
            assert expected_logs_hash == actual_logs_hash
        elif log_entries:
            raise AssertionError("Got log entries: {0}".format(log_entries))

        expected_output = fixture['out']
        assert computation.output == expected_output

        gas_meter = computation.gas_meter

        expected_gas_remaining = fixture['gas']
        actual_gas_remaining = gas_meter.gas_remaining
        gas_delta = actual_gas_remaining - expected_gas_remaining
        assert gas_delta == 0, "Gas difference: {0}".format(gas_delta)

        call_creates = fixture.get('callcreates', [])
        assert len(computation.children) == len(call_creates)

        call_creates = fixture.get('callcreates', [])
        for child_computation, created_call in zip(computation.children,
                                                   call_creates):
            to_address = created_call['destination']
            data = created_call['data']
            gas_limit = created_call['gasLimit']
            value = created_call['value']

            assert child_computation.msg.to == to_address
            assert data == child_computation.msg.data or child_computation.msg.code
            assert gas_limit == child_computation.msg.gas
            assert value == child_computation.msg.value
        post_state = fixture['post']
    else:
        #
        # Error checks
        #
        assert computation.is_error
        assert isinstance(computation._error, VMError)
        post_state = fixture['pre']

    with vm.state.state_db(read_only=True) as state_db:
        verify_state_db(post_state, state_db)
Ejemplo n.º 23
0
def test_blockchain_fixtures(fixture, chain_vm_configuration):
    genesis_params = {
        'parent_hash': fixture['genesisBlockHeader']['parentHash'],
        'uncles_hash': fixture['genesisBlockHeader']['uncleHash'],
        'coinbase': fixture['genesisBlockHeader']['coinbase'],
        'state_root': fixture['genesisBlockHeader']['stateRoot'],
        'transaction_root': fixture['genesisBlockHeader']['transactionsTrie'],
        'receipt_root': fixture['genesisBlockHeader']['receiptTrie'],
        'bloom': fixture['genesisBlockHeader']['bloom'],
        'difficulty': fixture['genesisBlockHeader']['difficulty'],
        'block_number': fixture['genesisBlockHeader']['number'],
        'gas_limit': fixture['genesisBlockHeader']['gasLimit'],
        'gas_used': fixture['genesisBlockHeader']['gasUsed'],
        'timestamp': fixture['genesisBlockHeader']['timestamp'],
        'extra_data': fixture['genesisBlockHeader']['extraData'],
        'mix_hash': fixture['genesisBlockHeader']['mixHash'],
        'nonce': fixture['genesisBlockHeader']['nonce'],
    }
    expected_genesis_header = BlockHeader(**genesis_params)

    # TODO: find out if this is supposed to pass?
    # if 'genesisRLP' in fixture:
    #     assert rlp.encode(genesis_header) == fixture['genesisRLP']
    db = BaseChainDB(get_db_backend())

    ChainForTesting = MainnetChain.configure(
        'ChainForTesting',
        vm_configuration=chain_vm_configuration,
    )

    chain = ChainForTesting.from_genesis(
        db,
        genesis_params=genesis_params,
        genesis_state=fixture['pre'],
    )

    genesis_block = chain.get_canonical_block_by_number(0)
    genesis_header = genesis_block.header

    assert_rlp_equal(genesis_header, expected_genesis_header)

    # 1 - mine the genesis block
    # 2 - loop over blocks:
    #     - apply transactions
    #     - mine block
    # 4 - profit!!

    for block_data in fixture['blocks']:
        should_be_good_block = 'blockHeader' in block_data

        if 'rlp_error' in block_data:
            assert not should_be_good_block
            continue

        # The block to import may be in a different block-class-range than the
        # chain's current one, so we use the block number specified in the
        # fixture to look up the correct block class.
        if should_be_good_block:
            block_number = block_data['blockHeader']['number']
            block_class = chain.get_vm_class_for_block_number(
                block_number).get_block_class()
        else:
            block_class = chain.get_vm().get_block_class()

        try:
            block = rlp.decode(block_data['rlp'],
                               sedes=block_class,
                               chaindb=chain.chaindb)
        except (TypeError, rlp.DecodingError, rlp.DeserializationError) as err:
            assert not should_be_good_block, "Block should be good: {0}".format(
                err)
            continue

        try:
            mined_block = chain.import_block(block)
        except ValidationError as err:
            assert not should_be_good_block, "Block should be good: {0}".format(
                err)
            continue
        else:
            assert_rlp_equal(mined_block, block)
            assert should_be_good_block, "Block should have caused a validation error"

    latest_block_hash = chain.get_canonical_block_by_number(
        chain.get_block().number - 1).hash
    assert latest_block_hash == fixture['lastblockhash']

    with chain.get_vm().state_db(read_only=True) as state_db:
        verify_state_db(fixture['postState'], state_db)
def test_invalid_if_no_vm_configuration():
    chain_class = Chain.configure('TestChain', vm_configuration=())
    with pytest.raises(ValueError):
        chain_class(get_db_backend(), BlockHeader(1, 0, 100))
Ejemplo n.º 25
0
def test_vm_fixtures(fixture_name, fixture):
    db = get_db_backend()
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
    )
    chain = ChainForTesting(db=db, header=header)
    vm = chain.get_vm()
    with vm.state_db() as state_db:
        setup_state_db(fixture['pre'], state_db)
        code = state_db.get_code(fixture['exec']['address'])

    message = Message(
        origin=fixture['exec']['origin'],
        to=fixture['exec']['address'],
        sender=fixture['exec']['caller'],
        value=fixture['exec']['value'],
        data=fixture['exec']['data'],
        code=code,
        gas=fixture['exec']['gas'],
        gas_price=fixture['exec']['gasPrice'],
    )
    computation = vm.apply_computation(message)

    if 'post' in fixture:
        #
        # Success checks
        #
        assert computation.error is None

        expected_logs = [{
            'address': log_entry[0],
            'topics': log_entry[1],
            'data': log_entry[2],
        } for log_entry in computation.get_log_entries()]
        expected_logs == fixture['logs']

        expected_output = fixture['out']
        assert computation.output == expected_output

        gas_meter = computation.gas_meter

        expected_gas_remaining = fixture['gas']
        actual_gas_remaining = gas_meter.gas_remaining
        gas_delta = actual_gas_remaining - expected_gas_remaining
        assert gas_delta == 0, "Gas difference: {0}".format(gas_delta)

        call_creates = fixture.get('callcreates', [])
        assert len(computation.children) == len(call_creates)

        call_creates = fixture.get('callcreates', [])
        for child_computation, created_call in zip(computation.children,
                                                   call_creates):
            to_address = created_call['destination']
            data = created_call['data']
            gas_limit = created_call['gasLimit']
            value = created_call['value']

            assert child_computation.msg.to == to_address
            assert data == child_computation.msg.data or child_computation.msg.code
            assert gas_limit == child_computation.msg.gas
            assert value == child_computation.msg.value
        post_state = fixture['post']
    else:
        #
        # Error checks
        #
        assert computation.error
        assert isinstance(computation.error, VMError)
        post_state = fixture['pre']

    with vm.state_db(read_only=True) as state_db:
        verify_state_db(post_state, state_db)
Ejemplo n.º 26
0
def chaindb():
    return ChainDB(get_db_backend())
Ejemplo n.º 27
0
def test_state_fixtures(fixture, fixture_vm_class):
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
        parent_hash=fixture['env']['previousHash'],
    )
    chaindb = ChainDB(get_db_backend())
    vm = fixture_vm_class(header=header, chaindb=chaindb)

    vm_state = vm.state
    with vm_state.state_db() as state_db:
        setup_state_db(fixture['pre'], state_db)
    # Update state_root manually
    vm.block.header.state_root = vm_state.state_root

    if 'secretKey' in fixture['transaction']:
        unsigned_transaction = vm.create_unsigned_transaction(
            nonce=fixture['transaction']['nonce'],
            gas_price=fixture['transaction']['gasPrice'],
            gas=fixture['transaction']['gasLimit'],
            to=fixture['transaction']['to'],
            value=fixture['transaction']['value'],
            data=fixture['transaction']['data'],
        )
        private_key = keys.PrivateKey(fixture['transaction']['secretKey'])
        transaction = unsigned_transaction.as_signed_transaction(private_key=private_key)
    elif 'vrs' in fixture['transaction']:
        v, r, s = (
            fixture['transaction']['v'],
            fixture['transaction']['r'],
            fixture['transaction']['s'],
        )
        transaction = vm.create_transaction(
            nonce=fixture['transaction']['nonce'],
            gas_price=fixture['transaction']['gasPrice'],
            gas=fixture['transaction']['gasLimit'],
            to=fixture['transaction']['to'],
            value=fixture['transaction']['value'],
            data=fixture['transaction']['data'],
            v=v,
            r=r,
            s=s,
        )

    try:
        computation, _ = vm.apply_transaction(transaction)
    except ValidationError as err:
        transaction_error = err
        LOGGER.warn("Got transaction error:")
        LOGGER.warn(traceback.format_exc())
    else:
        transaction_error = False

    if not transaction_error:
        log_entries = computation.get_log_entries()
        actual_logs_hash = hash_log_entries(log_entries)
        if 'logs' in fixture['post']:
            expected_logs_hash = fixture['post']['logs']
            assert expected_logs_hash == actual_logs_hash
        elif log_entries:
            raise AssertionError("Got log {0} entries. hash:{1}".format(
                len(log_entries),
                actual_logs_hash,
            ))

        if 'out' in fixture:
            expected_output = fixture['out']
            if isinstance(expected_output, int):
                assert len(computation.output) == expected_output
            else:
                assert computation.output == expected_output

    assert vm.block.header.state_root == fixture['post']['hash']
Ejemplo n.º 28
0
def test_state_fixtures(fixture, fixture_vm_class):
    if fixture_vm_class is not ShardingVMForTesting:
        account_state_class = MainAccountStateDB
        trie_class = HexaryTrie
        header = BlockHeader(
            coinbase=fixture['env']['currentCoinbase'],
            difficulty=fixture['env']['currentDifficulty'],
            block_number=fixture['env']['currentNumber'],
            gas_limit=fixture['env']['currentGasLimit'],
            timestamp=fixture['env']['currentTimestamp'],
            parent_hash=fixture['env']['previousHash'],
        )
    else:
        account_state_class = ShardingAccountStateDB
        trie_class = BinaryTrie
        header = CollationHeader(
            shard_id=fixture['env']['shardID'],
            expected_period_number=fixture['env']['expectedPeriodNumber'],
            period_start_prevhash=fixture['env']['periodStartHash'],
            parent_hash=fixture['env']['previousHash'],
            coinbase=fixture['env']['currentCoinbase'],
            number=fixture['env']['currentNumber'],
        )

    chaindb = ChainDB(get_db_backend(),
                      account_state_class=account_state_class,
                      trie_class=trie_class)
    vm = fixture_vm_class(header=header, chaindb=chaindb)

    vm_state = vm.state
    with vm_state.mutable_state_db() as state_db:
        state_db.apply_state_dict(fixture['pre'])
    # Update state_root manually
    vm.block.header.state_root = vm_state.state_root
    if 'secretKey' in fixture['transaction']:
        unsigned_transaction = vm.create_unsigned_transaction(
            nonce=fixture['transaction']['nonce'],
            gas_price=fixture['transaction']['gasPrice'],
            gas=fixture['transaction']['gasLimit'],
            to=fixture['transaction']['to'],
            value=fixture['transaction']['value'],
            data=fixture['transaction']['data'],
        )
        private_key = keys.PrivateKey(fixture['transaction']['secretKey'])
        transaction = unsigned_transaction.as_signed_transaction(
            private_key=private_key)
    elif 'vrs' in fixture['transaction']:
        v, r, s = (
            fixture['transaction']['v'],
            fixture['transaction']['r'],
            fixture['transaction']['s'],
        )
        transaction = vm.create_transaction(
            nonce=fixture['transaction']['nonce'],
            gas_price=fixture['transaction']['gasPrice'],
            gas=fixture['transaction']['gasLimit'],
            to=fixture['transaction']['to'],
            value=fixture['transaction']['value'],
            data=fixture['transaction']['data'],
            v=v,
            r=r,
            s=s,
        )
    else:
        # sharding transaction
        transaction = vm.create_transaction(
            chain_id=fixture['transaction']['chainID'],
            shard_id=fixture['transaction']['shardID'],
            to=fixture['transaction']['to'],
            data=fixture['transaction']['data'],
            gas=fixture['transaction']['gasLimit'],
            gas_price=fixture['transaction']['gasPrice'],
            access_list=fixture['transaction']['accessList'],
            code=fixture['transaction']['code'],
        )

    try:
        computation, _ = vm.apply_transaction(transaction)
    except ValidationError as err:
        transaction_error = err
        LOGGER.warn("Got transaction error", exc_info=True)
    else:
        transaction_error = False

    if not transaction_error:
        log_entries = computation.get_log_entries()
        actual_logs_hash = hash_log_entries(log_entries)
        if 'logs' in fixture['post']:
            expected_logs_hash = fixture['post']['logs']
            assert expected_logs_hash == actual_logs_hash
        elif log_entries:
            raise AssertionError("Got log {0} entries. hash:{1}".format(
                len(log_entries),
                actual_logs_hash,
            ))

        if 'out' in fixture:
            expected_output = fixture['out']
            if isinstance(expected_output, int):
                assert len(computation.output) == expected_output
            else:
                assert computation.output == expected_output

    assert vm.block.header.state_root == fixture['post']['hash']
Ejemplo n.º 29
0
def chain():
    """
    Return a Chain object containing just the genesis block.

    The Chain's state includes one funded account, which can be found in the funded_address in the
    chain itself.

    This Chain will perform all validations when importing new blocks, so only valid and finalized
    blocks can be used with it. If you want to test importing arbitrarily constructe, not
    finalized blocks, use the chain_without_block_validation fixture instead.
    """
    genesis_params = {
        "bloom":
        0,
        "coinbase":
        to_canonical_address("8888f1f195afa192cfee860698584c030f4c9db1"),
        "difficulty":
        131072,
        "extra_data":
        b"B",
        "gas_limit":
        3141592,
        "gas_used":
        0,
        "mix_hash":
        decode_hex(
            "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
        ),
        "nonce":
        decode_hex("0102030405060708"),
        "block_number":
        0,
        "parent_hash":
        decode_hex(
            "0000000000000000000000000000000000000000000000000000000000000000"
        ),
        "receipt_root":
        decode_hex(
            "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
        ),
        "state_root":
        decode_hex(
            "cafd881ab193703b83816c49ff6c2bf6ba6f464a1be560c42106128c8dbc35e7"
        ),
        "timestamp":
        1422494849,
        "transaction_root":
        decode_hex(
            "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
        ),
        "uncles_hash":
        decode_hex(
            "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")
    }
    funded_addr = to_canonical_address(
        "a94f5374fce5edbc8e2a8697c15331677e6ebf0b")
    initial_balance = 10000000000
    genesis_state = {
        funded_addr: {
            "balance": initial_balance,
            "nonce": 0,
            "code": b"",
            "storage": {}
        }
    }
    klass = Chain.configure(name='TestChain',
                            vm_configuration=((constants.GENESIS_BLOCK_NUMBER,
                                               FrontierVM), ))
    chain = klass.from_genesis(ChainDB(get_db_backend()), genesis_params,
                               genesis_state)
    chain.funded_address = funded_addr
    chain.funded_address_initial_balance = initial_balance
    return chain
def level_db(config_env, tmpdir):
    level_db_path = str(tmpdir.mkdir("level_db_path"))
    return get_db_backend(db_path=level_db_path)
Ejemplo n.º 31
0
def chaindb(request):
    return ChainDB(get_db_backend())
def test_raises_if_db_path_is_not_specified(config_env):
    with pytest.raises(TypeError):
        get_db_backend()
Ejemplo n.º 33
0
def chaindb():
    return ChainDB(get_db_backend())
Ejemplo n.º 34
0
def shard_db():
    return ShardDB(get_db_backend())
Ejemplo n.º 35
0
def level_db(config_env, tmpdir):
    level_db_path = str(tmpdir.mkdir("level_db_path"))
    return get_db_backend(db_path=level_db_path)
Ejemplo n.º 36
0
def shard_chaindb():
    return ChainDB(
        get_db_backend(),
        account_state_class=ShardingAccountStateDB,
        trie_class=BinaryTrie,
    )
Ejemplo n.º 37
0
def db():
    return get_db_backend()
Ejemplo n.º 38
0
def test_state_fixtures(fixture, fixture_vm_class):
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
        parent_hash=fixture['env']['previousHash'],
    )

    chaindb = ChainDB(get_db_backend())
    vm = fixture_vm_class(header=header, chaindb=chaindb)

    state = vm.state
    apply_state_dict(state.account_db, fixture['pre'])
    state.account_db.persist()

    # Update state_root manually
    vm.block = vm.block.copy(header=vm.block.header.copy(state_root=state.state_root))
    if 'secretKey' in fixture['transaction']:
        unsigned_transaction = vm.create_unsigned_transaction(
            nonce=fixture['transaction']['nonce'],
            gas_price=fixture['transaction']['gasPrice'],
            gas=fixture['transaction']['gasLimit'],
            to=fixture['transaction']['to'],
            value=fixture['transaction']['value'],
            data=fixture['transaction']['data'],
        )
        private_key = keys.PrivateKey(fixture['transaction']['secretKey'])
        transaction = unsigned_transaction.as_signed_transaction(private_key=private_key)
    elif 'vrs' in fixture['transaction']:
        v, r, s = (
            fixture['transaction']['v'],
            fixture['transaction']['r'],
            fixture['transaction']['s'],
        )
        transaction = vm.create_transaction(
            nonce=fixture['transaction']['nonce'],
            gas_price=fixture['transaction']['gasPrice'],
            gas=fixture['transaction']['gasLimit'],
            to=fixture['transaction']['to'],
            value=fixture['transaction']['value'],
            data=fixture['transaction']['data'],
            v=v,
            r=r,
            s=s,
        )

    try:
        header, receipt, computation = vm.apply_transaction(vm.block.header, transaction)
        transactions = vm.block.transactions + (transaction, )
        receipts = vm.block.get_receipts(chaindb) + (receipt, )
        block = vm.set_block_transactions(vm.block, header, transactions, receipts)
    except ValidationError as err:
        block = vm.block
        transaction_error = err
        LOGGER.warn("Got transaction error", exc_info=True)
    else:
        transaction_error = False

    if not transaction_error:
        log_entries = computation.get_log_entries()
        actual_logs_hash = hash_log_entries(log_entries)
        if 'logs' in fixture['post']:
            expected_logs_hash = fixture['post']['logs']
            assert expected_logs_hash == actual_logs_hash
        elif log_entries:
            raise AssertionError("Got log {0} entries. hash:{1}".format(
                len(log_entries),
                actual_logs_hash,
            ))

        if 'out' in fixture:
            expected_output = fixture['out']
            if isinstance(expected_output, int):
                assert len(computation.output) == expected_output
            else:
                assert computation.output == expected_output

    assert block.header.state_root == fixture['post']['hash']
Ejemplo n.º 39
0
def test_vm_fixtures(fixture, vm_class, computation_getter):
    chaindb = ChainDB(get_db_backend())
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
    )
    vm = vm_class(header=header, chaindb=chaindb)
    state = vm.state
    setup_account_db(fixture['pre'], state.account_db)
    code = state.account_db.get_code(fixture['exec']['address'])
    # Update state_root manually
    vm.block = vm.block.copy(header=vm.block.header.copy(
        state_root=state.state_root))

    message = Message(
        to=fixture['exec']['address'],
        sender=fixture['exec']['caller'],
        value=fixture['exec']['value'],
        data=fixture['exec']['data'],
        code=code,
        gas=fixture['exec']['gas'],
    )
    transaction_context = BaseTransactionContext(
        origin=fixture['exec']['origin'],
        gas_price=fixture['exec']['gasPrice'],
    )
    computation = vm.state.get_computation(
        message, transaction_context).apply_computation(
            vm.state,
            message,
            transaction_context,
        )
    # Update state_root manually
    vm.block = vm.block.copy(
        header=vm.block.header.copy(state_root=computation.state.state_root), )

    if 'post' in fixture:
        #
        # Success checks
        #
        assert not computation.is_error

        log_entries = computation.get_log_entries()
        if 'logs' in fixture:
            actual_logs_hash = hash_log_entries(log_entries)
            expected_logs_hash = fixture['logs']
            assert expected_logs_hash == actual_logs_hash
        elif log_entries:
            raise AssertionError("Got log entries: {0}".format(log_entries))

        expected_output = fixture['out']
        assert computation.output == expected_output

        gas_meter = computation._gas_meter

        expected_gas_remaining = fixture['gas']
        actual_gas_remaining = gas_meter.gas_remaining
        gas_delta = actual_gas_remaining - expected_gas_remaining
        assert gas_delta == 0, "Gas difference: {0}".format(gas_delta)

        call_creates = fixture.get('callcreates', [])
        assert len(computation.children) == len(call_creates)

        call_creates = fixture.get('callcreates', [])
        for child_computation, created_call in zip(computation.children,
                                                   call_creates):
            to_address = created_call['destination']
            data = created_call['data']
            gas_limit = created_call['gasLimit']
            value = created_call['value']

            assert child_computation.msg.to == to_address
            assert data == child_computation.msg.data or child_computation.msg.code
            assert gas_limit == child_computation.msg.gas
            assert value == child_computation.msg.value
        expected_account_db = fixture['post']
    else:
        #
        # Error checks
        #
        assert computation.is_error
        assert isinstance(computation._error, VMError)
        expected_account_db = fixture['pre']

    verify_account_db(expected_account_db, vm.state.account_db)
def test_invalid_if_no_vm_configuration():
    chain_class = Chain.configure('TestChain', vm_configuration=())
    with pytest.raises(ValueError):
        chain_class(get_db_backend(), BlockHeader(1, 0, 100))