From 9021c02bcd93329e9c2c24065cb6db119fe87563 Mon Sep 17 00:00:00 2001 From: Brian Cloutier Date: Mon, 10 Dec 2018 22:47:56 -0800 Subject: [PATCH] Failing blockchain tests now emit a state diff - Instead of failing with "these block hashes do not match", blockchain tests now fail with "this part of the state tree does not match". - The tests were inefficient, they first checked that the state hash matched and then checked that the states matched. It's unlikely the states will ever not match! - Some validations needed to be deferred until after state-tree comparison, or else they would fail the test early with an unhelpful message. - minor: tools.fixtures.helpers.chain_vm_configuration didn't support Constantinople --- eth/tools/fixtures/helpers.py | 13 ++++++++++--- tests/json-fixtures/test_blockchain.py | 22 ++++++++++++++++------ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/eth/tools/fixtures/helpers.py b/eth/tools/fixtures/helpers.py index 06c0c15b3d..c9e2457cca 100644 --- a/eth/tools/fixtures/helpers.py +++ b/eth/tools/fixtures/helpers.py @@ -40,6 +40,7 @@ BaseVM, ) from eth.vm.forks import ( + ConstantinopleVM, ByzantiumVM, TangerineWhistleVM, FrontierVM, @@ -123,6 +124,10 @@ def chain_vm_configuration(fixture: Dict[str, Any]) -> Iterable[Tuple[int, Type[ return ( (0, ByzantiumVM), ) + elif network == 'Constantinople': + return ( + (0, ConstantinopleVM), + ) elif network == 'FrontierToHomesteadAt5': HomesteadVM = BaseHomesteadVM.configure(support_dao_fork=False) return ( @@ -193,8 +198,10 @@ def new_chain_from_fixture(fixture: Dict[str, Any], ) -def apply_fixture_block_to_chain(block_fixture: Dict[str, Any], - chain: BaseChain) -> Tuple[BaseBlock, BaseBlock, BaseBlock]: +def apply_fixture_block_to_chain( + block_fixture: Dict[str, Any], + chain: BaseChain, + perform_validation: bool=True) -> Tuple[BaseBlock, BaseBlock, BaseBlock]: ''' :return: (premined_block, mined_block, rlp_encoded_mined_block) ''' @@ -209,7 +216,7 @@ def apply_fixture_block_to_chain(block_fixture: Dict[str, Any], block = rlp.decode(block_fixture['rlp'], sedes=block_class) - mined_block, _, _ = chain.import_block(block) + mined_block, _, _ = chain.import_block(block, perform_validation=perform_validation) rlp_encoded_mined_block = rlp.encode(mined_block, sedes=block_class) diff --git a/tests/json-fixtures/test_blockchain.py b/tests/json-fixtures/test_blockchain.py index 1aa902890a..cf33387d7e 100644 --- a/tests/json-fixtures/test_blockchain.py +++ b/tests/json-fixtures/test_blockchain.py @@ -111,8 +111,10 @@ def test_blockchain_fixtures(fixture_data, fixture): # 2 - loop over blocks: # - apply transactions # - mine block - # 4 - profit!! + # 3 - diff resulting state with expected state + # 4 - check that all previous blocks were valid + mined_blocks = list() for block_fixture in fixture['blocks']: should_be_good_block = 'blockHeader' in block_fixture @@ -121,11 +123,15 @@ def test_blockchain_fixtures(fixture_data, fixture): continue if should_be_good_block: - (block, mined_block, block_rlp) = apply_fixture_block_to_chain(block_fixture, chain) - assert_mined_block_unchanged(block, mined_block) + (block, mined_block, block_rlp) = apply_fixture_block_to_chain( + block_fixture, + chain, + perform_validation=False # we manually validate below + ) + mined_blocks.append((block, mined_block)) else: try: - apply_fixture_block_to_chain(block_fixture, chain) + (block, mined_block, block_rlp) = apply_fixture_block_to_chain(block_fixture, chain) except (TypeError, rlp.DecodingError, rlp.DeserializationError, ValidationError) as err: # failure is expected on this bad block pass @@ -133,6 +139,10 @@ def test_blockchain_fixtures(fixture_data, fixture): raise AssertionError("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'] + if latest_block_hash != fixture['lastblockhash']: + verify_account_db(fixture['postState'], chain.get_vm().state.account_db) + assert False, 'the state must be different if the hashes are' - verify_account_db(fixture['postState'], chain.get_vm().state.account_db) + for block, mined_block in mined_blocks: + assert_mined_block_unchanged(block, mined_block) + chain.validate_block(block)