def test_state_fixtures(fixture_name, fixture): 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'], ) db = MemoryDB() meta_evm = EVMForTesting.configure(db=db)(header=header) evm = meta_evm.get_evm() block = evm.block setup_state_db(fixture['pre'], evm.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 verify_state_db(fixture['post'], evm.state_db)
def test_blockchain_fixtures(fixture_data, fixture): try: chain = new_chain_from_fixture(fixture) except ValueError as e: raise AssertionError("could not load chain for %r" % fixture_data) from e genesis_params = genesis_params_from_fixture(fixture) 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'] 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_fixture in fixture['blocks']: should_be_good_block = 'blockHeader' in block_fixture if 'rlp_error' in block_fixture: assert not should_be_good_block continue try: (block, mined_block, block_rlp) = apply_fixture_block_to_chain(block_fixture, chain) except (TypeError, rlp.DecodingError, rlp.DeserializationError, ValidationError) as err: assert not should_be_good_block, "Block should be good: {0}".format( err) else: assert_rlp_equal(block, mined_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.state_db(read_only=True) as state_db: verify_state_db(fixture['postState'], state_db)
def test_state_fixtures(fixture_name, fixture): 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'], ) db = get_db_backend() chain = ChainForTesting(db=db, header=header) state_db = setup_state_db(fixture['pre'], chain.get_state_db()) chain.header.state_root = state_db.root_hash unsigned_transaction = chain.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 = chain.apply_transaction(transaction) except ValidationError: 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 verify_state_db(fixture['post'], chain.get_state_db())
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())
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())
def test_vm_fixtures(fixture, vm_class): 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 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.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)
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)
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)