Exemple #1
0
def noproof_consensus_chain(request):
    return api.build(
        MiningChain,
        api.fork_at(request.param, 0),
        api.disable_pow_check(),
        api.genesis(),
    )
def chain(base_chain):
    chain = api.build(
        base_chain,
        api.mine_blocks(3),
    )
    assert chain.get_canonical_head().block_number == 3
    return chain
def test_tx_class_resolution(initial_block_number,
                             expected_initial_tx_class,
                             expected_outdated_tx_class,
                             expected_future_tx_class):
    chain = api.build(
        MiningChain,
        api.frontier_at(0),
        api.homestead_at(5),
        api.spurious_dragon_at(10),
        api.disable_pow_check,
        api.genesis
    )
    validator = DefaultTransactionValidator(chain, initial_block_number)
    assert validator.get_appropriate_tx_class() == expected_initial_tx_class

    if expected_outdated_tx_class is not None:
        assert validator.is_outdated_tx_class(expected_outdated_tx_class)

    # The `get_appropriate_tx_class` method has a cache decorator applied
    # To test it properly, we need to clear the cache
    validator.get_appropriate_tx_class.cache_clear()

    # Check that the validator uses the correct tx class when we have reached the tip of the chain
    for n in range(10):
        chain.mine_block()

    assert validator.get_appropriate_tx_class() == expected_future_tx_class
Exemple #4
0
def noproof_consensus_chain(vm_class):
    # This will always have the same vm configuration as the POW chain
    return api.build(
        MiningChain,
        api.fork_at(vm_class, 0),
        api.disable_pow_check(),
        api.genesis(params=dict(gas_limit=100000)),
    )
def test_import_block_with_reorg(chain, funded_address_private_key):
    # mine ahead 3 blocks on the fork chain
    fork_chain = api.build(
        chain,
        api.copy(),
        api.mine_block(extra_data=b'fork-it'),
        api.mine_blocks(2),
    )
    # mine ahead 2 blocks on the main chain
    main_chain = api.build(
        chain,
        api.mine_blocks(2)
    )

    block_4 = main_chain.get_canonical_block_by_number(4)
    f_block_4 = fork_chain.get_canonical_block_by_number(4)

    assert f_block_4.number == block_4.number == 4
    assert f_block_4 != block_4
    assert f_block_4.header.difficulty <= block_4.header.difficulty

    block_5 = main_chain.get_canonical_block_by_number(5)
    f_block_5 = fork_chain.get_canonical_block_by_number(5)

    assert f_block_5.number == block_5.number == 5
    assert f_block_5 != block_5
    assert f_block_5.header.difficulty <= block_5.header.difficulty

    f_block_6 = fork_chain.get_canonical_block_by_number(6)
    pre_reorg_chain_head = main_chain.header

    # now we proceed to import the blocks from the fork chain into the main
    # chain.  Blocks 4 and 5 should import resulting in no re-organization.
    for block in (f_block_4, f_block_5):
        block_import_result = main_chain.import_block(block)
        assert not block_import_result.new_canonical_blocks
        assert not block_import_result.old_canonical_blocks
        # ensure that the main chain head has not changed.
        assert main_chain.header == pre_reorg_chain_head

    # now we import block 6 from the fork chain.  This should cause a re-org.
    block_import_result = main_chain.import_block(f_block_6)
    assert block_import_result.new_canonical_blocks == (f_block_4, f_block_5, f_block_6)
    assert block_import_result.old_canonical_blocks == (block_4, block_5)

    assert main_chain.get_canonical_head() == f_block_6.header
Exemple #6
0
def base_chain(request):
    chain = api.build(
        MiningChain,
        request.param(0),
        api.disable_pow_check(),
        api.genesis(),
    )

    return chain
def base_chain(request):
    if request.param is api.homestead_at:
        fork_fns = (request.param(0), api.dao_fork_at(0))
    else:
        fork_fns = (request.param(0),)

    chain = api.build(
        MiningChain,
        *fork_fns,
        api.disable_pow_check(),
        api.genesis(),
    )

    return chain
def test_import_block_with_reorg_with_current_head_as_uncle(
        chain,
        funded_address_private_key):
    """
    https://github.com/ethereum/py-evm/issues/1185
    """

    main_chain, fork_chain = api.build(
        chain,
        api.chain_split(
            (api.mine_block(),),  # this will be the 'uncle'
            (api.mine_block(extra_data=b'fork-it'),),
        ),
    )

    # the chain head from the main chain will become an uncle once we
    # import the fork chain blocks.
    uncle = main_chain.get_canonical_head()

    fork_chain = api.build(
        fork_chain,
        api.mine_block(uncles=(uncle,)),
    )
    head = fork_chain.get_canonical_head()
    block_a = fork_chain.get_canonical_block_by_number(head.block_number - 1)
    block_b = fork_chain.get_canonical_block_by_number(head.block_number)

    final_chain = api.build(
        main_chain,
        api.import_block(block_a),
        api.import_block(block_b),  # the block with the uncle.
    )

    header = final_chain.get_canonical_head()
    block = final_chain.get_canonical_block_by_number(header.block_number)

    assert len(block.uncles) == 1
def test_block_gap_tracking(chain, funded_address, funded_address_private_key,
                            has_uncle, has_transaction, can_fetch_block):

    # Mine three common blocks
    common_chain = api.build(
        chain,
        api.mine_blocks(3),
    )

    assert common_chain.get_canonical_head().block_number == 3
    assert common_chain.chaindb.get_chain_gaps() == ((), 4)

    tx = new_transaction(
        common_chain.get_vm(),
        from_=funded_address,
        to=ZERO_ADDRESS,
        private_key=funded_address_private_key,
    )
    uncle = api.build(common_chain,
                      api.mine_block()).get_canonical_block_header_by_number(4)
    uncles = [uncle] if has_uncle else []
    transactions = [tx] if has_transaction else []

    # Split and have the main chain mine four blocks, the uncle chain two blocks
    main_chain, uncle_chain = api.build(
        common_chain,
        api.chain_split(
            (
                # We have four different scenarios for our replaced blocks:
                #   1. Replaced by a trivial block without uncles or transactions
                #   2. Replaced by a block with transactions
                #   3. Replaced by a block with uncles
                #   4. 2 and 3 combined
                api.mine_block(uncles=uncles, transactions=transactions),
                api.mine_block(),
                api.mine_block(),
                api.mine_block(),
            ),
            # This will be the uncle chain
            (
                api.mine_block(extra_data=b'fork-it'),
                api.mine_block(),
            ),
        ),
    )

    main_head = main_chain.get_canonical_head()
    assert main_head.block_number == 7
    assert uncle_chain.get_canonical_head().block_number == 5

    assert main_chain.chaindb.get_chain_gaps() == ((), 8)
    assert uncle_chain.chaindb.get_chain_gaps() == ((), 6)

    main_header_6 = main_chain.chaindb.get_canonical_block_header_by_number(6)
    main_header_6_score = main_chain.chaindb.get_score(main_header_6.hash)

    gap_chain = api.copy(common_chain)
    assert gap_chain.get_canonical_head() == common_chain.get_canonical_head()

    gap_chain.chaindb.persist_checkpoint_header(main_header_6,
                                                main_header_6_score)
    # We created a gap in the chain of headers
    assert gap_chain.chaindb.get_header_chain_gaps() == (((4, 5), ), 7)
    # ...but not in the chain of blocks (yet!)
    assert gap_chain.chaindb.get_chain_gaps() == ((), 4)
    block_7 = main_chain.get_canonical_block_by_number(7)
    block_7_receipts = block_7.get_receipts(main_chain.chaindb)
    # Persist block 7 on top of the checkpoint
    gap_chain.chaindb.persist_unexecuted_block(block_7, block_7_receipts)
    assert gap_chain.chaindb.get_header_chain_gaps() == (((4, 5), ), 8)
    # Now we have a gap in the chain of blocks, too
    assert gap_chain.chaindb.get_chain_gaps() == (((4, 6), ), 8)

    # Overwriting header 3 doesn't cause us to re-open a block gap
    gap_chain.chaindb.persist_header_chain(
        [main_chain.chaindb.get_canonical_block_header_by_number(3)])
    assert gap_chain.chaindb.get_chain_gaps() == (((4, 6), ), 8)

    # Now get the uncle block
    uncle_block = uncle_chain.get_canonical_block_by_number(4)
    uncle_block_receipts = uncle_block.get_receipts(uncle_chain.chaindb)

    # Put the uncle block in the gap
    gap_chain.chaindb.persist_unexecuted_block(uncle_block,
                                               uncle_block_receipts)
    assert gap_chain.chaindb.get_header_chain_gaps() == (((5, 5), ), 8)
    assert gap_chain.chaindb.get_chain_gaps() == (((5, 6), ), 8)

    # Trying to save another uncle errors as its header isn't the parent of the checkpoint
    second_uncle = uncle_chain.get_canonical_block_by_number(5)
    second_uncle_receipts = second_uncle.get_receipts(uncle_chain.chaindb)
    with pytest.raises(CheckpointsMustBeCanonical):
        gap_chain.chaindb.persist_unexecuted_block(second_uncle,
                                                   second_uncle_receipts)

    # Now close the gap in the header chain with the actual correct headers
    actual_headers = [
        main_chain.chaindb.get_canonical_block_header_by_number(block_number)
        for block_number in range(4, 7)
    ]
    gap_chain.chaindb.persist_header_chain(actual_headers)
    # No more gaps in the header chain
    assert gap_chain.chaindb.get_header_chain_gaps() == ((), 8)
    # We detected the de-canonicalized uncle and re-opened the block gap
    assert gap_chain.chaindb.get_chain_gaps() == (((4, 6), ), 8)

    if can_fetch_block:
        # We can fetch the block even if the gap tracking reports it as missing if the block is
        # a "trivial" block, meaning one that doesn't have transactions nor uncles and hence
        # can be loaded by just the header alone.
        block_4 = gap_chain.get_canonical_block_by_number(4)
        assert block_4 == main_chain.get_canonical_block_by_number(4)
    else:
        # The uncle block was implicitly de-canonicalized with its header,
        # hence we can not fetch it any longer.
        with pytest.raises(BlockNotFound):
            gap_chain.get_canonical_block_by_number(4)
        # Add the missing block and assert the gap shrinks
        assert gap_chain.chaindb.get_chain_gaps() == (((4, 6), ), 8)
        block_4 = main_chain.get_canonical_block_by_number(4)
        block_4_receipts = block_4.get_receipts(main_chain.chaindb)
        gap_chain.chaindb.persist_unexecuted_block(block_4, block_4_receipts)
        assert gap_chain.chaindb.get_chain_gaps() == (((5, 6), ), 8)
Exemple #10
0
def pow_consensus_chain(vm_class):
    return api.build(
        MiningChain,
        api.fork_at(vm_class, 0),
        api.genesis(),
    )
Exemple #11
0
def pow_consensus_chain(request):
    return api.build(
        MiningChain,
        api.fork_at(request.param, 0),
        api.genesis(),
    )