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
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
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)
def pow_consensus_chain(vm_class): return api.build( MiningChain, api.fork_at(vm_class, 0), api.genesis(), )
def pow_consensus_chain(request): return api.build( MiningChain, api.fork_at(request.param, 0), api.genesis(), )