def test_transaction_fixtures(fixture_name, fixture): header = BlockHeader(1, fixture.get('blocknumber', 0), 100) evm = MainnetEVM(MemoryDB(), header=header) vm = evm.get_vm() TransactionClass = vm.get_transaction_class() if 'sender' in fixture: transaction = rlp.decode(fixture['rlp'], sedes=TransactionClass) expected = normalize_signed_transaction(fixture['transaction']) assert transaction.nonce == expected['nonce'] assert transaction.gas_price == expected['gasPrice'] assert transaction.gas == expected['gasLimit'] assert transaction.to == expected['to'] assert transaction.value == expected['value'] assert transaction.data == expected['data'] assert transaction.v == expected['v'] assert transaction.r == expected['r'] assert transaction.s == expected['s'] sender = to_canonical_address(fixture['sender']) assert transaction.sender == sender else: # check RLP correctness try: transaction = rlp.decode(fixture['rlp'], sedes=TransactionClass) except rlp.exceptions.ObjectDeserializationError: return # check parameter correctness try: transaction.validate() except ValidationError: return
def test_trie_using_fixtures(fixture_name, fixture): keys_and_values = fixture['in'] deletes = tuple(k for k, v in keys_and_values if v is None) remaining = {k: v for k, v in keys_and_values if k not in deletes} for kv_permutation in itertools.islice( itertools.permutations(keys_and_values), 100): print("in it") trie = Trie(db=MemoryDB()) for key, value in kv_permutation: if value is None: del trie[key] else: trie[key] = value for key in deletes: del trie[key] for key, expected_value in remaining.items(): assert key in trie actual_value = trie[key] assert actual_value == expected_value for key in deletes: assert key not in trie expected_root = fixture['root'] actual_root = trie.root_hash assert actual_root == expected_root
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_get_vm_class_for_block_number(): evm_class = EVM.configure( vm_configuration=( (constants.GENESIS_BLOCK_NUMBER, FrontierVM), (constants.HOMESTEAD_MAINNET_BLOCK, HomesteadVM), ), ) evm = evm_class(MemoryDB(), BlockHeader(1, 0, 100)) assert evm.get_vm_class_for_block_number( constants.GENESIS_BLOCK_NUMBER,) == FrontierVM assert evm.get_vm_class_for_block_number( constants.HOMESTEAD_MAINNET_BLOCK - 1) == FrontierVM assert evm.get_vm_class_for_block_number( constants.HOMESTEAD_MAINNET_BLOCK) == HomesteadVM assert evm.get_vm_class_for_block_number( constants.HOMESTEAD_MAINNET_BLOCK + 1) == HomesteadVM
def load_state(cls, dbfile=None): """ Create or load State. returns: (State, is_new) where 'is_new' is T|F indicating whether this the first run. """ if not dbfile: return (cls(MemoryDB(), b'testchain', 0, BLANK_ROOT_HASH), True) # ASSSUMES THE PATH TO THE FILE EXISTS - IF NEW db = VanillaDB(dbfile) serial = db.get(CHAIN_METADATA_KEY) if serial: meta = rlp.decode(serial, sedes=chainMetaData) return (cls(db, meta.chainid, meta.height, meta.apphash), db.is_new) return (cls(db, b'', 0, BLANK_ROOT_HASH), db.is_new)
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 load_state(cls, dbfile=None): """ Create or load State. returns: State """ if not dbfile: return (cls(MemoryDB(), 0, 0, BLANK_ROOT_HASH))
def test_vm_success_using_fixture(fixture_name, fixture): db = MemoryDB() meta_evm = EVMForTesting(db=db) 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'], ) evm = meta_evm(header=header) block = evm.block setup_state_db(fixture['pre'], block.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 for account, account_data in sorted(fixture['post'].items()): for slot, expected_storage_value in sorted( account_data['storage'].items()): actual_storage_value = evm.block.state_db.get_storage( account, slot) assert actual_storage_value == expected_storage_value expected_nonce = account_data['nonce'] expected_code = account_data['code'] expected_balance = account_data['balance'] actual_nonce = evm.block.state_db.get_nonce(account) actual_code = evm.block.state_db.get_code(account) actual_balance = evm.block.state_db.get_balance(account) balance_delta = expected_balance - actual_balance assert actual_nonce == expected_nonce assert actual_code == expected_code assert balance_delta == 0, "Expected: {0} - Actual: {1} | Delta: {2}".format( expected_balance, actual_balance, balance_delta) assert evm.block.state_db.state.root_hash == fixture['postStateRoot']
def test_get_vm_class_for_block_number_evm_not_found(): evm_class = EVM.configure(vm_configuration=()) evm = evm_class(MemoryDB(), BlockHeader(1, 0, 100)) with pytest.raises(EVMNotFound): evm.get_vm_class_for_block_number(constants.GENESIS_BLOCK_NUMBER)
def test_vm_fixtures(fixture_name, fixture): db = MemoryDB() header = BlockHeader( coinbase=fixture['env']['currentCoinbase'], difficulty=fixture['env']['currentDifficulty'], block_number=fixture['env']['currentNumber'], gas_limit=fixture['env']['currentGasLimit'], timestamp=fixture['env']['currentTimestamp'], ) meta_evm = EVMForTesting.configure(db=db)(header=header) evm = meta_evm.get_evm() setup_state_db(fixture['pre'], evm.state_db) message = Message( origin=fixture['exec']['origin'], to=fixture['exec']['address'], sender=fixture['exec']['caller'], value=fixture['exec']['value'], data=fixture['exec']['data'], code=evm.state_db.get_code(fixture['exec']['address']), gas=fixture['exec']['gas'], gas_price=fixture['exec']['gasPrice'], ) computation = evm.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) for child_computation, created_call in zip( computation.children, fixture.get('callcreates', [])): 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'] for account, account_data in post_state.items(): for slot, expected_storage_value in account_data['storage'].items(): actual_storage_value = evm.state_db.get_storage(account, slot) assert actual_storage_value == expected_storage_value expected_nonce = account_data['nonce'] expected_code = account_data['code'] expected_balance = account_data['balance'] actual_nonce = evm.state_db.get_nonce(account) actual_code = evm.state_db.get_code(account) actual_balance = evm.state_db.get_balance(account) assert actual_nonce == expected_nonce assert actual_code == expected_code assert actual_balance == expected_balance