Пример #1
0
def test_uncle_block_inclusion_validity(vm_fn):
    # This test ensures that a forked block which is behind by
    # more than 6 layers cannot act as an ancestor to the current block

    OTHER_MINER_ADDRESS = 20 * b'\x01'

    chain = build(
        MiningChain,
        vm_fn(0),
        disable_pow_check(),
        genesis(),
        mine_block(),  # 1
        mine_block(),  # 2
    )

    fork_chain = build(
        chain,
        at_block_number(1),
        mine_block(extra_data=b'fork-it!',
                   coinbase=OTHER_MINER_ADDRESS),  # fork 2
    )

    # we don't use canonical head here because the fork chain is non-canonical.
    uncle = fork_chain.get_block_header_by_hash(fork_chain.header.parent_hash)
    assert uncle.block_number == 2

    with pytest.raises(ValidationError):
        chain = build(
            chain,
            # Mines blocks from 3 to 8 (both numbers inclusive)
            mine_blocks(6),
            # Mine block 9 with uncle
            mine_block(uncles=[uncle]),
        )
def test_chain_builder_build_uncle_fork(mining_chain):
    chain = build(
        mining_chain,
        mine_block(),  # 1
        mine_block(),  # 2
    )

    fork_chain = build(
        chain,
        at_block_number(1),
        mine_block(extra_data=b'fork-it!'),  # fork 2
    )

    # we don't use canonical head here because the fork chain is non-canonical.
    uncle = fork_chain.get_block_header_by_hash(fork_chain.header.parent_hash)
    assert uncle.block_number == 2
    assert uncle != chain.get_canonical_head()

    chain = build(
        chain,
        mine_block(uncles=[uncle]),  # 3
    )

    header = chain.get_canonical_head()
    block = chain.get_block_by_hash(header.hash)
    assert len(block.uncles) == 1
    assert block.uncles[0] == uncle
def test_chain_builder_build_two_default_blocks(mining_chain):
    chain = build(
        mining_chain,
        mine_block(),
        mine_block(),
    )

    header = chain.get_canonical_head()
    assert header.block_number == 2
Пример #4
0
def test_rewards_nephew_uncle_different_vm(vm_fn_uncle, vm_fn_nephew,
                                           miner_1_balance, miner_2_balance):
    OTHER_MINER_ADDRESS = 20 * b'\x01'
    TOTAL_BLOCKS_CANONICAL_CHAIN = 10
    VM_CHANGE_BLOCK_NUMBER = 4

    chain = build(
        MiningChain,
        vm_fn_uncle(0),
        vm_fn_nephew(VM_CHANGE_BLOCK_NUMBER),
        disable_pow_check(),
        genesis(),
        mine_blocks(TOTAL_BLOCKS_CANONICAL_CHAIN - 1),
    )

    fork_chain = build(
        chain,
        at_block_number(3),
        mine_block(extra_data=b'fork-it!',
                   coinbase=OTHER_MINER_ADDRESS),  # fork 2
    )

    # we don't use canonical head here because the fork chain is non-canonical.
    uncle = fork_chain.get_block_header_by_hash(fork_chain.header.parent_hash)
    assert uncle.block_number == 4

    chain = build(
        chain,
        mine_block(uncles=[uncle]),
    )

    header = chain.get_canonical_head()
    block = chain.get_block_by_hash(header.hash)
    assert len(block.uncles) == 1
    assert block.uncles[0] == uncle

    vm = chain.get_vm()
    coinbase_balance = vm.state.get_balance(block.header.coinbase)
    other_miner_balance = vm.state.get_balance(uncle.coinbase)

    uncle_vm = chain.get_vm_class_for_block_number(0)
    nephew_vm = chain.get_vm_class_for_block_number(VM_CHANGE_BLOCK_NUMBER)

    # We first test if the balance matches what we would determine
    # if we made all the API calls involved ourselves.
    assert coinbase_balance == (uncle_vm.get_block_reward() * 3 +
                                nephew_vm.get_block_reward() *
                                (TOTAL_BLOCKS_CANONICAL_CHAIN - 3) +
                                vm.get_nephew_reward())
    assert other_miner_balance == vm.get_uncle_reward(block.number, uncle)

    # But we also ensure the balance matches the numbers that we calculated on paper
    assert coinbase_balance == to_wei(miner_1_balance, 'ether')
    assert other_miner_balance == to_wei(miner_2_balance, 'ether')
Пример #5
0
async def test_eth_api_head_info_updates_with_announce(alice, bob,
                                                       common_base_chain,
                                                       LESAPI_class):
    # bob mines two blocks on his chain
    got_announce = asyncio.Event()

    async def _handle_announce(connection, msg):
        got_announce.set()

    alice.connection.add_command_handler(Announce, _handle_announce)

    bob_genesis = common_base_chain.headerdb.get_canonical_block_header_by_number(
        0)

    assert alice.connection.has_logic(LESAPI_class.name)

    les_api = alice.connection.get_logic(LESAPI_class.name, LESAPI_class)

    assert les_api.head_info.head_hash == bob_genesis.hash
    assert les_api.head_info.head_td == bob_genesis.difficulty
    assert les_api.head_info.head_number == 0

    bob_chain = build(
        common_base_chain,
        mine_block(),
        mine_block(),
    )
    head = bob_chain.get_canonical_head()

    les_proto = bob.les_api.protocol
    assert isinstance(les_proto, BaseLESProtocol)
    assert head.block_number == 2
    total_difficulty = bob_chain.headerdb.get_score(head.hash)
    les_proto.send(
        Announce(
            AnnouncePayload(
                head_hash=head.hash,
                head_number=head.block_number,
                head_td=total_difficulty,
                reorg_depth=0,
                params=(),
            )))

    await asyncio.wait_for(got_announce.wait(), timeout=1)
    await asyncio.sleep(0.1)

    assert les_api.head_info.head_hash == head.hash
    assert les_api.head_info.head_td == total_difficulty
    assert les_api.head_info.head_number == 2
Пример #6
0
def test_rewards_uncle_created_at_different_generations(
        vm_fn, fork_at_block_number, miner_1_balance, miner_2_balance):
    OTHER_MINER_ADDRESS = 20 * b'\x01'
    TOTAL_BLOCKS_CANONICAL_CHAIN = 10

    chain = build(
        MiningChain,
        vm_fn(0),
        disable_pow_check(),
        genesis(),
        mine_blocks(TOTAL_BLOCKS_CANONICAL_CHAIN - 1),
    )

    fork_chain = build(
        chain,
        at_block_number(fork_at_block_number),
        mine_block(extra_data=b'fork-it!',
                   coinbase=OTHER_MINER_ADDRESS),  # fork 2
    )

    # we don't use canonical head here because the fork chain is non-canonical.
    uncle = fork_chain.get_block_header_by_hash(fork_chain.header.parent_hash)
    assert uncle.block_number == fork_at_block_number + 1

    chain = build(
        chain,
        mine_block(uncles=[uncle]),
    )

    header = chain.get_canonical_head()
    block = chain.get_block_by_hash(header.hash)

    vm = chain.get_vm()
    coinbase_balance = vm.state.account_db.get_balance(block.header.coinbase)
    other_miner_balance = vm.state.account_db.get_balance(uncle.coinbase)

    # We first test if the balance matches what we would determine
    # if we made all the API calls involved ourselves.
    assert coinbase_balance == (
        vm.get_block_reward() * TOTAL_BLOCKS_CANONICAL_CHAIN +
        vm.get_nephew_reward())

    assert other_miner_balance == vm.get_uncle_reward(block.number, uncle)

    # But we also ensure the balance matches the numbers that we calculated on paper
    assert coinbase_balance == to_wei(miner_1_balance, 'ether')
    assert other_miner_balance == to_wei(miner_2_balance, 'ether')
def test_chain_builder_mine_block_with_parameters(mining_chain):
    chain = build(
        mining_chain,
        mine_block(extra_data=b'test-setting-extra-data'),
    )

    header = chain.get_canonical_head()
    assert header.extra_data == b'test-setting-extra-data'
Пример #8
0
async def test_handshake_with_incompatible_fork_id(alice_chain, bob_chain):

    alice_chain = build(alice_chain, mine_block())

    pair_factory = ETHPeerPairFactory(alice_peer_context=ChainContextFactory(
        headerdb=AsyncHeaderDB(alice_chain.headerdb.db),
        vm_configuration=((1, PetersburgVM), (2, MuirGlacierVM))), )
    with pytest.raises(WrongForkIDFailure):
        async with pair_factory as (alice, bob):
            pass
def test_chain_builder_chain_split(mining_chain):
    chain_a, chain_b = build(
        mining_chain,
        chain_split(
            (mine_block(extra_data=b'chain-a'), mine_block()),
            (mine_block(extra_data=b'chain-b'), mine_block(), mine_block()),
        ),
    )

    first_a = chain_a.get_canonical_block_by_number(1).header
    first_b = chain_b.get_canonical_block_by_number(1).header

    assert first_a.extra_data == b'chain-a'
    assert first_b.extra_data == b'chain-b'

    head_a = chain_a.get_canonical_head()
    assert head_a.block_number == 2

    head_b = chain_b.get_canonical_head()
    assert head_b.block_number == 3
Пример #10
0
async def test_eth_api_head_info_updates_with_newblock(alice, bob, bob_chain,
                                                       ETHAPI_class):
    # mine two blocks on bob's chain
    bob_chain = build(
        bob_chain,
        mine_block(),
        mine_block(),
    )

    got_new_block = asyncio.Event()

    async def _handle_new_block(connection, msg):
        got_new_block.set()

    alice.connection.add_command_handler(NewBlock, _handle_new_block)

    bob_genesis = bob_chain.headerdb.get_canonical_block_header_by_number(0)

    bob_eth_api = bob.connection.get_logic(ETHAPI_class.name, ETHAPI_class)
    alice_eth_api = alice.connection.get_logic(ETHAPI_class.name, ETHAPI_class)

    assert alice_eth_api.head_info.head_hash == bob_genesis.hash
    assert alice_eth_api.head_info.head_td == bob_genesis.difficulty
    assert not hasattr(alice_eth_api.head_info, 'head_number')

    head = bob_chain.get_canonical_head()
    assert head.block_number == 2
    head_block = bob_chain.get_block_by_header(head)
    total_difficulty = bob_chain.headerdb.get_score(head.hash)

    bob_eth_api.send_new_block(
        head_block,
        total_difficulty,
    )

    await asyncio.wait_for(got_new_block.wait(), timeout=1)

    assert alice_eth_api.head_info.head_hash == head.parent_hash
    assert alice_eth_api.head_info.head_td == bob_chain.headerdb.get_score(
        head.parent_hash)
    assert alice_eth_api.head_info.head_number == 1
Пример #11
0
def alice_chain_on_fork(bob_chain):
    bob_genesis = bob_chain.headerdb.get_canonical_block_header_by_number(0)

    chain = build(
        MiningChain,
        latest_mainnet_at(0),
        disable_pow_check(),
        genesis(params={"timestamp": bob_genesis.timestamp}),
        mine_block(),
    )

    return chain
def test_chain_builder_at_block_number(mining_chain):
    pre_fork_chain = build(
        mining_chain,
        mine_block(),  # 1
        mine_block(),  # 2
        mine_block(),  # 3
    )
    block_1 = pre_fork_chain.get_canonical_block_by_number(1)
    block_2 = pre_fork_chain.get_canonical_block_by_number(2)
    block_3 = pre_fork_chain.get_canonical_block_by_number(3)

    chain = build(
        pre_fork_chain,
        at_block_number(2),
        mine_block(extra_data=b'fork-it!'),  # fork 3
        mine_block(),  # fork 4
        mine_block(),  # fork 5
    )

    # ensure that our chain is ahead of the pre_fork_chain
    head = chain.get_canonical_head()
    assert head.block_number == 5

    pre_fork_head = pre_fork_chain.get_canonical_head()
    assert pre_fork_head.block_number == 3

    f_block_1 = chain.get_canonical_block_by_number(1)
    f_block_2 = chain.get_canonical_block_by_number(2)
    f_block_3 = chain.get_canonical_block_by_number(3)

    # verify that the fork diverges from the pre_fork_chain
    assert f_block_1 == block_1
    assert f_block_2 == block_2
    assert f_block_3 != block_3
Пример #13
0
async def test_eth_api_head_info_updates_with_announce(alice, bob,
                                                       common_base_chain):
    # bob mines two blocks on his chain
    bob_chain = build(
        common_base_chain,
        mine_block(),
        mine_block(),
    )

    got_announce = asyncio.Event()

    async def _handle_announce(connection, msg):
        got_announce.set()

    alice.connection.add_command_handler(Announce, _handle_announce)

    bob_genesis = bob_chain.headerdb.get_canonical_block_header_by_number(0)
    les_api = alice.connection.get_logic(LESAPI.name, LESAPI)

    assert les_api.head_info.head_hash == bob_genesis.hash
    assert les_api.head_info.head_td == bob_genesis.difficulty
    assert les_api.head_info.head_number == 0

    les_proto = bob.connection.get_protocol_by_type(LESProtocolV2)
    head = bob_chain.get_canonical_head()
    assert head.block_number == 2
    total_difficulty = bob_chain.headerdb.get_score(head.hash)
    les_proto.send_announce(
        head,
        total_difficulty,
    )

    await asyncio.wait_for(got_announce.wait(), timeout=1)

    assert alice.connection.has_logic(LESAPI.name)

    assert les_api.head_info.head_hash == head.hash
    assert les_api.head_info.head_td == total_difficulty
    assert les_api.head_info.head_number == 2
def test_chain_builder_mine_block_with_transactions(
        mining_chain, funded_address, funded_address_private_key):
    tx = new_transaction(
        mining_chain.get_vm(),
        from_=funded_address,
        to=ZERO_ADDRESS,
        private_key=funded_address_private_key,
    )

    chain = build(
        mining_chain,
        mine_block(transactions=[tx]),
    )

    block = chain.get_canonical_block_by_number(1)
    assert len(block.transactions) == 1
    assert block.transactions[0] == tx
def test_chain_builder_mine_block_only_on_mining_chain(regular_chain):
    with pytest.raises(ValidationError, match="MiningChain"):
        mine_block()(regular_chain)