Пример #1
0
async def test_header_sync_with_multi_peers(request, event_loop, chaindb_mainnet_100):
    # In this test we start with one of our peers announcing block #100, and we sync all
    # headers up to that...
    light_chain, _, server = await get_lightchain_with_peers(
        request, event_loop, chaindb_mainnet_100)

    head = server.chaindb.get_canonical_head()
    await wait_for_head(light_chain.chaindb, head)
    assert_canonical_chains_are_equal(light_chain.chaindb, server.chaindb, head.block_number)

    # Now a second peer comes along and announces block #100 as well, but it's different
    # from the one we already have, so we need to fetch that too. And since it has a higher total
    # difficulty than the current head, it will become our new chain head.
    server2_chaindb = server.chaindb
    head_parent = server2_chaindb.get_block_header_by_hash(head.parent_hash)
    difficulty = head.difficulty + 1
    new_head = BlockHeader.from_parent(
        head_parent, head_parent.gas_limit, difficulty=difficulty,
        timestamp=head.timestamp, coinbase=head.coinbase)
    server2_chaindb.persist_header_to_db(new_head)
    assert server2_chaindb.get_canonical_head() == new_head
    client2, server2 = await get_client_and_server_peer_pair(
        request,
        event_loop,
        client_chaindb=light_chain.chaindb,
        server_chaindb=server2_chaindb)

    light_chain.register_peer(client2)
    await wait_for_head(light_chain.chaindb, new_head)
    assert_canonical_chains_are_equal(light_chain.chaindb, server2.chaindb, new_head.block_number)
Пример #2
0
def create_frontier_header_from_parent(parent_header, **header_params):
    if 'difficulty' not in header_params:
        # Use setdefault to ensure the new header has the same timestamp we use to calculate its
        # difficulty.
        header_params.setdefault('timestamp', parent_header.timestamp + 1)
        header_params['difficulty'] = compute_frontier_difficulty(
            parent_header,
            header_params['timestamp'],
        )
    if 'gas_limit' not in header_params:
        header_params['gas_limit'] = compute_gas_limit(
            parent_header,
            gas_limit_floor=GENESIS_GAS_LIMIT,
        )

    header = BlockHeader.from_parent(parent=parent_header, **header_params)

    return header
Пример #3
0
    def from_genesis(cls,
                     chaindb,
                     genesis_params,
                     genesis_state=None):
        """
        Initialize the Chain from a genesis state.
        """
        state_db = chaindb.get_state_db(BLANK_ROOT_HASH, read_only=False)

        if genesis_state is None:
            genesis_state = {}

        for account, account_data in genesis_state.items():
            state_db.set_balance(account, account_data['balance'])
            state_db.set_nonce(account, account_data['nonce'])
            state_db.set_code(account, account_data['code'])

            for slot, value in account_data['storage'].items():
                state_db.set_storage(account, slot, value)

        if 'state_root' not in genesis_params:
            # If the genesis state_root was not specified, use the value
            # computed from the initialized state database.
            genesis_params = assoc(genesis_params, 'state_root', state_db.root_hash)
        elif genesis_params['state_root'] != state_db.root_hash:
            # If the genesis state_root was specified, validate that it matches
            # the computed state from the initialized state database.
            raise ValidationError(
                "The provided genesis state root does not match the computed "
                "genesis state root.  Got {0}.  Expected {1}".format(
                    state_db.root_hash,
                    genesis_params['state_root'],
                )
            )

        genesis_header = BlockHeader(**genesis_params)
        genesis_chain = cls(chaindb, genesis_header)
        chaindb.persist_block_to_db(genesis_chain.get_block())
        return cls.from_genesis_header(chaindb, genesis_header)
Пример #4
0
async def test_full_header_sync_and_reorg(request, event_loop, chaindb_mainnet_100):
    # Here we create our server with a populated chaindb, so upon startup it will announce its
    # chain head and the client will fetch all headers
    light_chain, _, server = await get_lightchain_with_peers(
        request, event_loop, chaindb_mainnet_100)

    # ... and our client should then fetch all headers.
    head = server.chaindb.get_canonical_head()
    await wait_for_head(light_chain.chaindb, head)
    assert_canonical_chains_are_equal(light_chain.chaindb, server.chaindb, head.block_number)

    head_parent = server.chaindb.get_block_header_by_hash(head.parent_hash)
    difficulty = head.difficulty + 1
    new_head = BlockHeader.from_parent(
        head_parent, head_parent.gas_limit, difficulty=difficulty,
        timestamp=head.timestamp, coinbase=head.coinbase)
    server.chaindb.persist_header(new_head)
    assert server.chaindb.get_canonical_head() == new_head
    server.send_announce(head_number=head.block_number, reorg_depth=1)

    await wait_for_head(light_chain.chaindb, new_head)
    assert_canonical_chains_are_equal(light_chain.chaindb, server.chaindb, new_head.block_number)
Пример #5
0
    def from_genesis(cls,
                     chaindb: BaseChainDB,
                     genesis_params: Dict[str, HeaderParams],
                     genesis_state: AccountState=None) -> 'BaseChain':
        """
        Initializes the Chain from a genesis state.
        """
        genesis_vm_class = cls.get_vm_class_for_block_number(BlockNumber(0))
        account_db = genesis_vm_class.get_state_class().get_account_db_class()(
            chaindb.db,
            BLANK_ROOT_HASH,
        )

        if genesis_state is None:
            genesis_state = {}

        # mutation
        apply_state_dict(account_db, genesis_state)
        account_db.persist()

        if 'state_root' not in genesis_params:
            # If the genesis state_root was not specified, use the value
            # computed from the initialized state database.
            genesis_params = assoc(genesis_params, 'state_root', account_db.state_root)
        elif genesis_params['state_root'] != account_db.state_root:
            # If the genesis state_root was specified, validate that it matches
            # the computed state from the initialized state database.
            raise ValidationError(
                "The provided genesis state root does not match the computed "
                "genesis state root.  Got {0}.  Expected {1}".format(
                    account_db.state_root,
                    genesis_params['state_root'],
                )
            )

        genesis_header = BlockHeader(**genesis_params)
        genesis_chain = cls(chaindb, genesis_header)
        chaindb.persist_block(genesis_chain.get_block())
        return cls.from_genesis_header(chaindb, genesis_header)
Пример #6
0
async def test_full_header_sync_and_reorg(request, event_loop, chaindb_mainnet_100):
    # Here we create our server with a populated chaindb, so upon startup it will announce its
    # chain head and the client will fetch all headers
    light_chain, _, server = await get_lightchain_with_peers(
        request, event_loop, chaindb_mainnet_100)

    # ... and our client should then fetch all headers.
    head = server.chaindb.get_canonical_head()
    await wait_for_head(light_chain.chaindb, head)
    assert_canonical_chains_are_equal(light_chain.chaindb, server.chaindb, head.block_number)

    head_parent = server.chaindb.get_block_header_by_hash(head.parent_hash)
    difficulty = head.difficulty + 1
    new_head = BlockHeader.from_parent(
        head_parent, head_parent.gas_limit, difficulty=difficulty,
        timestamp=head.timestamp, coinbase=head.coinbase)
    server.chaindb.persist_header_to_db(new_head)
    assert server.chaindb.get_canonical_head() == new_head
    server.send_announce(head_number=head.block_number, reorg_depth=1)

    await wait_for_head(light_chain.chaindb, new_head)
    assert_canonical_chains_are_equal(light_chain.chaindb, server.chaindb, new_head.block_number)
Пример #7
0
def test_vm_success_using_fixture(fixture_name, fixture):
    db = MemoryDB()
    meta_evm = EVMForTesting(db=db)
    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'],
    )
    evm = meta_evm(header=header)
    block = evm.block

    setup_state_db(fixture['pre'], block.state_db)

    Transaction = evm.get_transaction_class()

    unsigned_transaction = Transaction.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 = evm.apply_transaction(transaction)
    except InvalidTransaction:
        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

    for account, account_data in sorted(fixture['post'].items()):
        for slot, expected_storage_value in sorted(
                account_data['storage'].items()):
            actual_storage_value = evm.block.state_db.get_storage(
                account, slot)

            assert actual_storage_value == expected_storage_value

        expected_nonce = account_data['nonce']
        expected_code = account_data['code']
        expected_balance = account_data['balance']

        actual_nonce = evm.block.state_db.get_nonce(account)
        actual_code = evm.block.state_db.get_code(account)
        actual_balance = evm.block.state_db.get_balance(account)
        balance_delta = expected_balance - actual_balance

        assert actual_nonce == expected_nonce
        assert actual_code == expected_code
        assert balance_delta == 0, "Expected: {0} - Actual: {1} | Delta: {2}".format(
            expected_balance, actual_balance, balance_delta)

    assert evm.block.state_db.state.root_hash == fixture['postStateRoot']
Пример #8
0
def test_vm_fixtures(fixture_name, fixture):
    db = MemoryDB()
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
    )
    meta_evm = EVMForTesting.configure(db=db)(header=header)
    evm = meta_evm.get_evm()
    setup_state_db(fixture['pre'], evm.state_db)

    message = Message(
        origin=fixture['exec']['origin'],
        to=fixture['exec']['address'],
        sender=fixture['exec']['caller'],
        value=fixture['exec']['value'],
        data=fixture['exec']['data'],
        code=evm.state_db.get_code(fixture['exec']['address']),
        gas=fixture['exec']['gas'],
        gas_price=fixture['exec']['gasPrice'],
    )
    computation = evm.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)

        for child_computation, created_call in zip(
                computation.children, fixture.get('callcreates', [])):
            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']

    for account, account_data in post_state.items():
        for slot, expected_storage_value in account_data['storage'].items():
            actual_storage_value = evm.state_db.get_storage(account, slot)

            assert actual_storage_value == expected_storage_value

        expected_nonce = account_data['nonce']
        expected_code = account_data['code']
        expected_balance = account_data['balance']

        actual_nonce = evm.state_db.get_nonce(account)
        actual_code = evm.state_db.get_code(account)
        actual_balance = evm.state_db.get_balance(account)

        assert actual_nonce == expected_nonce
        assert actual_code == expected_code
        assert actual_balance == expected_balance
Пример #9
0
    (SPURIOUS_DRAGON_MAINNET_BLOCK, SpuriousDragonVM),
    (BYZANTIUM_MAINNET_BLOCK, ByzantiumVM),
)

MAINNET_NETWORK_ID = 1

MainnetChain = Chain.configure(
    'MainnetChain',
    vm_configuration=MAINNET_VM_CONFIGURATION,
    network_id=MAINNET_NETWORK_ID,
)

MAINNET_GENESIS_HEADER = BlockHeader(
    difficulty=17179869184,
    extra_data=decode_hex(
        "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"),
    gas_limit=5000,
    gas_used=0,
    bloom=0,
    mix_hash=constants.ZERO_HASH32,
    nonce=constants.GENESIS_NONCE,
    block_number=0,
    parent_hash=constants.ZERO_HASH32,
    receipt_root=constants.BLANK_ROOT_HASH,
    uncles_hash=constants.EMPTY_UNCLE_HASH,
    state_root=decode_hex(
        "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"),
    timestamp=0,
    transaction_root=constants.BLANK_ROOT_HASH,
)
Пример #10
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']
Пример #11
0
def test_get_vm_class_for_block_number_evm_not_found():
    evm_class = EVM.configure(vm_configuration=())
    evm = evm_class(MemoryDB(), BlockHeader(1, 0, 100))
    with pytest.raises(EVMNotFound):
        evm.get_vm_class_for_block_number(constants.GENESIS_BLOCK_NUMBER)
Пример #12
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())
Пример #13
0
def header(request):
    block_number = request.param
    difficulty = 1
    gas_limit = 1
    return BlockHeader(difficulty, block_number, gas_limit)
Пример #14
0
def genesis_header():
    return BlockHeader(
        difficulty=GENESIS_DIFFICULTY,
        block_number=GENESIS_BLOCK_NUMBER,
        gas_limit=GENESIS_GAS_LIMIT,
    )
Пример #15
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)
Пример #16
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_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_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))
Пример #19
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)
Пример #20
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 = MemoryDB()
    evm = MainnetEVM.from_genesis(
        db,
        genesis_params=genesis_params,
        genesis_state=fixture['pre'],
    )

    genesis_block = evm.get_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

        try:
            block = rlp.decode(
                block_data['rlp'],
                sedes=evm.get_vm().get_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 = evm.import_block(block)
            assert_rlp_equal(mined_block, block)
        except ValidationError as err:
            assert not should_be_good_block, "Block should be good: {0}".format(
                err)
            continue
        else:
            assert should_be_good_block, "Block should have caused a validation error"

    assert evm.get_block_by_number(evm.get_block().number -
                                   1).hash == fixture['lastblockhash']

    verify_state_db(fixture['postState'], evm.get_state_db())
Пример #21
0

# Ethereum mainnet headers, from two headers before to ten headers after the fork:
ETH_HEADERS_NEAR_FORK = [
    BlockHeader(
        difficulty=62352470509925,
        block_number=1919998,
        gas_limit=4712388,
        timestamp=1469020835,
        coinbase=
        b'\xbc\xdf\xc3[\x86\xbe\xdfr\xf0\xcd\xa0F\xa3\xc1h)\xa2\xefA\xd1',
        parent_hash=
        b'\xe7\xe3\xe8+\xf3C\xbe\xf9\xa2R\xb8\x7f\x06r\x9adZop\x9b.RK\x9e\xf4\xf9;\xb9\xf2]S\x8d',  # noqa: E501
        uncles_hash=
        b'\x1d\xccM\xe8\xde\xc7]z\xab\x85\xb5g\xb6\xcc\xd4\x1a\xd3\x12E\x1b\x94\x8at\x13\xf0\xa1B\xfd@\xd4\x93G',  # noqa: E501
        state_root=
        b'\x1f!\x88?4\xde&\x93\xb4\xadGD\xc26a\xdbd\xca\xcb=\xa2\x1dr \xceW\xb97d\xb3\xbb\xfe',  # noqa: E501
        transaction_root=
        b'\xf2n\xb9\x94\x0e\xbb\xe8\x0c\xc3\xab\xbc\x9ev\xe9\xb7\xb1\x0f\xbcG\xc0\xd2\x12\xf9\x81\xa6q/\xf7\xf4\x97\xd3\xb4',  # noqa: E501
        receipt_root=
        b'D\xda\xa2\x9c4?\xa0/\xe8\x8fH\xf8?z\xc2\x1e\xfa\xc8j\xb0w8\r\xed\x81[(n\xd2jx\x1f',  # noqa: E501
        bloom=0,
        gas_used=420000,
        extra_data=b'\xd7\x83\x01\x04\n\x84Geth\x87go1.6.2\x85linux',
        mix_hash=
        b'\x8d\x03\xe0$?1\xa6\xcd\x11\x04E\x1f\xfc\x10#[\x04\x16N\xbe[\xd4u-\xa6\xb54t\x8d\x87}\x9f',  # noqa: E501
        nonce=b'a\xd8\xc5\xdf\xfd\x0e\xb2v',
    ),
    BlockHeader(
        difficulty=62382916183238,
        block_number=1919999,
        gas_limit=4707788,
Пример #22
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']
Пример #23
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']
Пример #24
0
    (SPURIOUS_DRAGON_ROPSTEN_BLOCK, SpuriousDragonVM),
    (BYZANTIUM_ROPSTEN_BLOCK, ByzantiumVM),
)

ROPSTEN_NETWORK_ID = 3

RopstenChain = Chain.configure(
    'RopstenChain',
    vm_configuration=ROPSTEN_VM_CONFIGURATION,
    network_id=ROPSTEN_NETWORK_ID,
)

ROPSTEN_GENESIS_HEADER = BlockHeader(
    difficulty=1048576,
    extra_data=decode_hex(
        "0x3535353535353535353535353535353535353535353535353535353535353535"),
    gas_limit=16777216,
    gas_used=0,
    bloom=0,
    mix_hash=constants.ZERO_HASH32,
    nonce=constants.GENESIS_NONCE,
    block_number=0,
    parent_hash=constants.ZERO_HASH32,
    receipt_root=constants.BLANK_ROOT_HASH,
    uncles_hash=constants.EMPTY_UNCLE_HASH,
    state_root=decode_hex(
        "0x217b0bbcfb72e2d57e28f33cb361b9983513177755dc3f33ce3e7022ed62b77b"),
    timestamp=0,
    transaction_root=constants.BLANK_ROOT_HASH,
)
Пример #25
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)