def tx( vm, from_, to, amount, private_key=None, gas_price=10, gas=100000, data=b''): if request.param: return new_transaction( vm, from_, to, amount, private_key, gas_price, gas, data) else: return new_transaction( vm, from_, to, amount, private_key=None, gas_price=gas_price, gas=gas, data=data)
def test_estimate_gas(chain, data, gas_estimator, to, on_pending, expected, funded_address, funded_address_private_key, should_sign_tx): if gas_estimator: chain.gas_estimator = gas_estimator vm = chain.get_vm() amount = 100 from_ = funded_address tx_params = dict(vm=vm, from_=from_, to=to, amount=amount, data=data) # either make a signed or unsigned transaction if should_sign_tx: tx = new_transaction(private_key=funded_address_private_key, **tx_params) else: tx = new_transaction(**tx_params) if on_pending: # estimate on *pending* block pending_header = chain.create_header_from_parent( chain.get_canonical_head()) assert chain.estimate_gas(tx, pending_header) == expected else: # estimates on top of *latest* block assert chain.estimate_gas(tx) == expected
def test_get_cumulative_gas_used(chain, funded_address, funded_address_private_key): vm = chain.get_vm() # Empty block. block = vm.mine_block() chain.import_block(block) block1 = chain.get_canonical_block_by_number(1) blockgas = vm.get_cumulative_gas_used(block1) assert blockgas == 0 # Only one transaction in the block. recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 vm = chain.get_vm() from_ = funded_address tx = new_transaction(vm, from_, recipient, amount, funded_address_private_key) vm.apply_transaction(tx) block = vm.mine_block() chain.import_block(block) block2 = chain.get_canonical_block_by_number(2) blockgas = vm.get_cumulative_gas_used(block2) assert blockgas == constants.GAS_TX
def test_apply_transaction( chain, funded_address, funded_address_private_key, funded_address_initial_balance): vm = chain.get_vm() tx_idx = len(vm.block.transactions) recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 from_ = funded_address tx = new_transaction(vm, from_, recipient, amount, funded_address_private_key) computation, _ = vm.apply_transaction(tx) access_logs = computation.vm_state.access_logs assert not computation.is_error tx_gas = tx.gas_price * constants.GAS_TX with vm.state.state_db(read_only=True) as state_db: assert state_db.get_balance(from_) == ( funded_address_initial_balance - amount - tx_gas) assert state_db.get_balance(recipient) == amount block = vm.block assert block.transactions[tx_idx] == tx assert block.header.gas_used == constants.GAS_TX assert len(access_logs.reads) > 0 assert len(access_logs.writes) > 0
def test_import_block(chain, funded_address, funded_address_private_key): recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 from_ = funded_address tx = new_transaction(chain.get_vm(), from_, recipient, amount, funded_address_private_key) if isinstance(chain, MiningChain): # Can use the mining chain functionality to build transactions in-flight pending_header = chain.header new_block, _, computation = chain.apply_transaction(tx) else: # Have to manually build the block for the import_block test new_block, _, computations = chain.build_block_with_transactions([tx]) computation = computations[0] # Generate the pending header to import the new block on pending_header = chain.create_header_from_parent( chain.get_canonical_head()) assert not computation.is_error # import the built block validation_vm = chain.get_vm(pending_header) block = validation_vm.import_block(new_block) assert block.transactions == (tx, )
def test_building_block_incrementally_with_multiple_transactions( chain, funded_address, funded_address_private_key): txns = [] head_hash = chain.get_canonical_head().hash for expected_len in range(1, 4): tx = new_transaction( chain.get_vm(), from_=funded_address, to=ADDRESS_1010, private_key=funded_address_private_key, ) txns.append(tx) _, _, computation = chain.apply_transaction(tx) assert computation.is_success # test that the pending block has the expected number of transactions vm = chain.get_vm() assert len(vm.block.transactions) == expected_len assert vm.block.transactions[-1] == tx # test that the *latest* block hasn't changed assert chain.get_canonical_head().hash == head_hash mined_block = chain.mine_block() assert len(mined_block.transactions) == 3 for expected, actual in zip(txns, mined_block.transactions): assert expected == actual
def tx(chain, funded_address, funded_address_private_key): recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 vm = chain.get_vm() from_ = funded_address return new_transaction(vm, from_, recipient, amount, funded_address_private_key)
def test_get_cumulative_gas_used(chain): vm = chain.get_vm() # Empty block. block = vm.mine_block() chain.import_block(block) block1 = chain.get_canonical_block_by_number(1) blockgas = vm.get_cumulative_gas_used(block1) assert blockgas == 0 # Only one transaction in the block. recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 vm = chain.get_vm() from_ = chain.funded_address tx = new_transaction(vm, from_, recipient, amount, chain.funded_address_private_key) vm.apply_transaction(tx) block = vm.mine_block() chain.import_block(block) block2 = chain.get_canonical_block_by_number(2) blockgas = vm.get_cumulative_gas_used(block2) assert blockgas == constants.GAS_TX
def test_estimate_gas( chain, data, gas_estimator, to, on_pending, expected, funded_address, funded_address_private_key): if gas_estimator: chain.gas_estimator = gas_estimator vm = chain.get_vm() if to: recipient = to else: recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 from_ = funded_address tx = new_transaction(vm, from_, recipient, amount, funded_address_private_key, data=data) if on_pending: # estimate on *pending* block assert chain.estimate_gas(tx, chain.header) == expected else: # estimates on top of *latest* block assert chain.estimate_gas(tx) == expected
def mk_estimation_txn(chain, from_, from_key, data): vm = chain.get_vm() tx_params = dict(from_=from_, to=ADDR_1010, amount=200, private_key=from_key, gas=chain.header.gas_limit, data=data) return new_transaction(vm, **tx_params)
def test_import_block(chain, funded_address, funded_address_private_key): vm = chain.get_vm() recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 from_ = funded_address tx = new_transaction(vm, from_, recipient, amount, funded_address_private_key) computation, _ = vm.apply_transaction(tx) assert not computation.is_error parent_vm = chain.get_chain_at_block_parent(vm.block).get_vm() block = parent_vm.import_block(vm.block) assert block.transactions == [tx]
def test_import_block(chain_without_block_validation): # noqa: F811 chain = chain_without_block_validation # noqa: F811 vm = chain.get_vm() recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 from_ = chain.funded_address tx = new_transaction(vm, from_, recipient, amount, chain.funded_address_private_key) computation = vm.apply_transaction(tx) assert not computation.is_error parent_vm = chain.get_chain_at_block_parent(vm.block).get_vm() block = parent_vm.import_block(vm.block) assert block.transactions == [tx]
def estimation_txn(chain, from_, from_key, data): to = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') gas = chain.header.gas_limit amount = 200 vm = chain.get_vm() return new_transaction(vm, from_, to, amount, from_key, gas=gas, data=data)
def test_import_block(chain, funded_address, funded_address_private_key): recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 from_ = funded_address tx = new_transaction(chain.get_vm(), from_, recipient, amount, funded_address_private_key) new_block, _, computation = chain.apply_transaction(tx) assert not computation.is_error parent_vm = chain.get_chain_at_block_parent(new_block).get_vm() block = parent_vm.import_block(new_block) assert block.transactions == (tx, )
def test_missing_state_root(chain_without_block_validation, funded_address): valid_vm = chain_without_block_validation.get_vm() tx = new_transaction(valid_vm, from_=funded_address, to=ADDRESS) head = chain_without_block_validation.get_canonical_head() header_with_bad_state_root = head.copy(state_root=b'X' * 32) busted_vm = chain_without_block_validation.get_vm( header_with_bad_state_root) # notice that the state root is missing by the raised MissingAccountTrieNode with pytest.raises(MissingAccountTrieNode): busted_vm.state.apply_transaction(tx)
def test_import_block(chain_without_block_validation): # noqa: F811 chain = chain_without_block_validation # noqa: F811 recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 vm = chain.get_vm() from_ = chain.funded_address tx = new_transaction(vm, from_, recipient, amount, chain.funded_address_private_key) computation = vm.apply_transaction(tx) assert not computation.is_error block = chain.import_block(vm.block) assert block.transactions == [tx] assert chain.get_block_by_hash(block.hash) == block assert chain.get_canonical_block_by_number(block.number) == block
def main(): args = parse_args() # print('Called with args:') # print(args) # genesis address init_address = to_canonical_address( "8888f1f195afa192cfee860698584c030f4c9db1") base_state = base_genesis_state(init_address, funded_address_initial_balance()) # just an address simple_contract_address = create_simple_contract_address() # create chain klass = MiningChain.configure( __name__='MyTestChain', vm_configuration=((constants.GENESIS_BLOCK_NUMBER, SpuriousDragonVM), ), network_id=1337, ) chain = klass.from_genesis( MemoryDB(), GENESIS_PARAMS, genesis_state(base_state, simple_contract_address, args.data)) # TODO # signature = 'getMeaningOfLife()' # function name # function_selector = function_signature_to_4byte_selector(signature) ''' new_transaction( vm, from_, to, amount=0, private_key=None, gas_price=10, gas=100000, data=b'' ) ''' call_txn = new_transaction( chain.get_vm(), SENDER, simple_contract_address, gas_price=0, # data=function_selector, data=decode_hex(args.signature), ) result_bytes = chain.get_transaction_result(call_txn, chain.get_canonical_head())
def test_get_transaction_result(chain, simple_contract_address, signature, gas_price, expected): function_selector = function_signature_to_4byte_selector(signature) call_txn = new_transaction( chain.get_vm(), b'\xff' * 20, simple_contract_address, gas_price=gas_price, data=function_selector, ) result_bytes = chain.get_transaction_result(call_txn, chain.get_canonical_head()) assert result_bytes == expected
def test_get_transaction_result_revert(vm, chain_from_vm, simple_contract_address, signature, expected): chain = chain_from_vm(vm) function_selector = function_signature_to_4byte_selector(signature) call_txn = new_transaction( chain.get_vm(), b'\xff' * 20, simple_contract_address, data=function_selector, ) with pytest.raises(expected): chain.get_transaction_result(call_txn, chain.get_canonical_head())
def test_chaindb_get_receipt_by_index( chain, funded_address, funded_address_private_key): NUMBER_BLOCKS_IN_CHAIN = 5 TRANSACTIONS_IN_BLOCK = 10 REQUIRED_BLOCK_NUMBER = 2 REQUIRED_RECEIPT_INDEX = 3 for block_number in range(NUMBER_BLOCKS_IN_CHAIN): for tx_index in range(TRANSACTIONS_IN_BLOCK): tx = new_transaction( chain.get_vm(), from_=funded_address, to=force_bytes_to_address(b'\x10\x10'), private_key=funded_address_private_key, ) new_block, tx_receipt, computation = chain.apply_transaction(tx) assert computation.is_success if (block_number + 1) == REQUIRED_BLOCK_NUMBER and tx_index == REQUIRED_RECEIPT_INDEX: actual_receipt = tx_receipt chain.mine_block() # Check that the receipt retrieved is indeed the actual one chaindb_retrieved_receipt = chain.chaindb.get_receipt_by_index( REQUIRED_BLOCK_NUMBER, REQUIRED_RECEIPT_INDEX, ) assert chaindb_retrieved_receipt == actual_receipt # Raise error if block number is not found with pytest.raises(ReceiptNotFound): chain.chaindb.get_receipt_by_index( NUMBER_BLOCKS_IN_CHAIN + 1, REQUIRED_RECEIPT_INDEX, ) # Raise error if receipt index is out of range with pytest.raises(ReceiptNotFound): chain.chaindb.get_receipt_by_index( NUMBER_BLOCKS_IN_CHAIN, TRANSACTIONS_IN_BLOCK + 1, )
def test_apply_transaction(chain_without_block_validation): # noqa: F811 chain = chain_without_block_validation # noqa: F811 vm = chain.get_vm() tx_idx = len(vm.block.transactions) recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 from_ = chain.funded_address tx = new_transaction(vm, from_, recipient, amount, chain.funded_address_private_key) computation = vm.apply_transaction(tx) assert not computation.is_error tx_gas = tx.gas_price * constants.GAS_TX with vm.state.state_db(read_only=True) as state_db: assert state_db.get_balance(from_) == ( chain.funded_address_initial_balance - amount - tx_gas) assert state_db.get_balance(recipient) == amount block = vm.block assert block.transactions[tx_idx] == tx assert block.header.gas_used == constants.GAS_TX
def test_apply_transaction(chain, funded_address, funded_address_private_key, funded_address_initial_balance): vm = chain.get_vm() recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 from_ = funded_address tx = new_transaction(vm, from_, recipient, amount, funded_address_private_key) new_header, _, computation = vm.apply_transaction(vm.block.header, tx) assert not computation.is_error tx_gas = tx.gas_price * constants.GAS_TX account_db = vm.state.account_db assert account_db.get_balance(from_) == (funded_address_initial_balance - amount - tx_gas) assert account_db.get_balance(recipient) == amount assert new_header.gas_used == constants.GAS_TX
def test_building_block_incrementally_with_single_transaction( chain, funded_address, funded_address_private_key): head_hash = chain.get_canonical_head().hash tx = new_transaction( chain.get_vm(), from_=funded_address, to=ADDRESS_1010, private_key=funded_address_private_key, ) _, _, computation = chain.apply_transaction(tx) assert computation.is_success # test that the *latest* block hasn't changed assert chain.get_canonical_head().hash == head_hash mined_block = chain.mine_block() assert len(mined_block.transactions) == 1 actual_tx = mined_block.transactions[0] assert actual_tx == tx
def test_apply_transaction(chain, funded_address, funded_address_private_key, funded_address_initial_balance): vm = chain.get_vm() tx_idx = len(vm.block.transactions) recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 from_ = funded_address tx = new_transaction(vm, from_, recipient, amount, funded_address_private_key) computation, _ = vm.apply_transaction(tx) assert not computation.is_error tx_gas = tx.gas_price * constants.GAS_TX state_db = vm.state.read_only_state_db assert state_db.get_balance(from_) == (funded_address_initial_balance - amount - tx_gas) assert state_db.get_balance(recipient) == amount block = vm.block assert block.transactions[tx_idx] == tx assert block.header.gas_used == constants.GAS_TX
def main(): # genesis address init_address = to_canonical_address( "8888f1f195afa192cfee860698584c030f4c9db1") base_state = base_genesis_state(init_address, funded_address_initial_balance()) simple_contract_address = RECEIVER # create chain klass = MiningChain.configure( __name__='MyTestChain', vm_configuration=((constants.GENESIS_BLOCK_NUMBER, ByzantiumVM), )) chain = klass.from_genesis( MemoryDB(), GENESIS_PARAMS, genesis_state(base_state, simple_contract_address)) # chain = klass.from_genesis(MemoryDB(), GENESIS_PARAMS, base_state) vm = chain.get_vm() # tx = vm.create_unsigned_transaction( # nonce=vm.state.account_db.get_nonce(SENDER), # gas_price=0x1, # gas=0x90710, # to=simple_contract_address, # value=0x10, # data=DATA.encode(), # ) # signed_tx = tx.as_signed_transaction(SENDER_PRIVATE_KEY) # _, _, computation = chain.apply_transaction(signed_tx, 0x90777) call_txn = new_transaction( vm, SENDER, RECEIVER, amount=0x10, data=DATA.encode(), ) result_bytes = chain.get_transaction_result(call_txn, chain.get_canonical_head(), 1000)
def test_apply_transaction( chain_without_block_validation, funded_address, funded_address_private_key): chain = chain_without_block_validation # Don't change these variables vm = chain.get_vm() chaindb = copy.deepcopy(vm.chaindb) block0 = copy.deepcopy(vm.block) prev_block_hash = chain.get_canonical_block_by_number(0).hash initial_state_root = vm.block.header.state_root # (1) Get VM.apply_transaction(transaction) result for assertion # The first transaction chain1 = copy.deepcopy(chain) vm_example = chain1.get_vm() recipient1 = decode_hex('0x1111111111111111111111111111111111111111') amount = 100 from_ = funded_address tx1 = new_transaction( vm_example, from_, recipient1, amount, private_key=funded_address_private_key, ) computation, result_block = vm_example.apply_transaction(tx1) # The second transaction recipient2 = decode_hex('0x2222222222222222222222222222222222222222') tx2 = new_transaction( vm_example, from_, recipient2, amount, private_key=funded_address_private_key, ) computation, result_block = vm_example.apply_transaction(tx2) assert len(result_block.transactions) == 2 # (2) Test State.apply_transaction(...) # Use SpuriousDragonState to apply transaction chaindb1 = copy.deepcopy(chaindb) block1 = copy.deepcopy(block0) prev_hashes = vm.get_prev_hashes( last_block_hash=prev_block_hash, db=vm.chaindb, ) execution_context = block1.header.create_execution_context(prev_hashes) state1 = SpuriousDragonState( chaindb=chaindb1, execution_context=execution_context, state_root=block1.header.state_root, gas_used=0, ) parent_hash = copy.deepcopy(prev_hashes[0]) computation, block, _ = state1.apply_transaction( tx1, block1, ) # Check if prev_hashes hasn't been changed assert parent_hash == prev_hashes[0] # Make sure that block1 hasn't been changed assert block1.header.state_root == initial_state_root execution_context = block.header.create_execution_context(prev_hashes) state1 = SpuriousDragonState( chaindb=chaindb1, execution_context=execution_context, state_root=block.header.state_root, gas_used=computation.state.gas_used, ) computation, block, _ = state1.apply_transaction( tx2, block, ) post_state = computation.state # Check block data are correct assert block.header.state_root == result_block.header.state_root assert block.header.gas_limit == result_block.header.gas_limit assert block.header.gas_used == result_block.header.gas_used assert block.header.transaction_root == result_block.header.transaction_root assert block.header.receipt_root == result_block.header.receipt_root # Make sure that state1 hasn't been changed assert post_state.state_root == result_block.header.state_root
def test_create_block(chain): # (1) Empty block. # block = vm.mine_block() block0 = chain.import_block(chain.get_vm().block) initial_state_root = block0.header.state_root # (2) Use VM.apply_transaction to get the witness data chain1 = copy.deepcopy(chain) vm1 = chain1.get_vm() # The first transaction vm = chain.get_vm() recipient1 = decode_hex('0x1111111111111111111111111111111111111111') amount = 100 from_ = chain.funded_address tx1 = new_transaction(vm1, from_, recipient1, amount, chain.funded_address_private_key) # Get the witness of tx1 computation, _ = vm1.apply_transaction(tx1) transaction_witness1 = computation.vm_state.access_logs.reads # The second transaction recipient2 = decode_hex('0x2222222222222222222222222222222222222222') tx2 = new_transaction(vm1, from_, recipient2, amount, chain.funded_address_private_key) # Get the witness of tx2 computation, block = vm1.apply_transaction(tx2) transaction_witness2 = computation.vm_state.access_logs.reads # Check AccessLogs witness_db = BaseChainDB(MemoryDB(computation.vm_state.access_logs.writes)) state_db = witness_db.get_state_db(block.header.state_root, read_only=True) assert state_db.get_balance(recipient2) == amount with pytest.raises(KeyError): state_db.get_balance(recipient1) # Create a block and import to chain coinbase = decode_hex('0x3333333333333333333333333333333333333333') vm1.block.header.coinbase = coinbase assert len(vm1.block.transactions) == 2 block1 = chain1.import_block(vm1.block) # Check the block vm1 = chain1.get_vm() assert block1.header.coinbase == coinbase assert len(block1.transactions) == 2 assert len(block1.get_receipts(vm1.chaindb)) == 2 with vm1.state.state_db(read_only=True) as state_db1: assert state_db1.root_hash == block1.header.state_root # (3) Try to create a block by witnesses vm2 = copy.deepcopy(vm) transaction_packages = [ (tx1, transaction_witness1), (tx2, transaction_witness2), ] prev_hashes = vm2.get_prev_hashes( last_block_hash=block0.hash, db=vm2.chaindb, ) parent_header = block0.header # Create a block block2 = vm2.create_block( transaction_packages=transaction_packages, prev_hashes=prev_hashes, coinbase=coinbase, parent_header=parent_header, ) # Check the block assert len(block2.transactions) == 2 assert block2.header.block_number == 2 assert block2.header.coinbase == coinbase # Check if block2 == block1 assert block2.hash == block1.hash # Check if the given parameters are changed assert block0.header.state_root == initial_state_root assert block0.header.block_number == 1
def test_apply_transaction( # noqa: F811 chain_without_block_validation, funded_address, funded_address_private_key): chain = chain_without_block_validation # noqa: F811 # Don't change these variables vm = chain.get_vm() chaindb = copy.deepcopy(vm.chaindb) block0 = copy.deepcopy(vm.block) prev_block_hash = chain.get_canonical_block_by_number(0).hash initial_state_root = vm.block.header.state_root # (1) Get VM.apply_transaction(transaction) result for assertion # The first transaction chain1 = copy.deepcopy(chain) vm_example = chain1.get_vm() recipient1 = decode_hex('0x1111111111111111111111111111111111111111') amount = 100 from_ = funded_address tx1 = new_transaction( vm_example, from_, recipient1, amount, private_key=funded_address_private_key, ) computation, result_block = vm_example.apply_transaction(tx1) # The second transaction recipient2 = decode_hex('0x2222222222222222222222222222222222222222') tx2 = new_transaction( vm_example, from_, recipient2, amount, private_key=funded_address_private_key, ) computation, result_block = vm_example.apply_transaction(tx2) assert len(result_block.transactions) == 2 # (2) Test VMState.apply_transaction(...) # Use FrontierVMState to apply transaction chaindb1 = copy.deepcopy(chaindb) block1 = copy.deepcopy(block0) prev_hashes = vm.get_prev_hashes( last_block_hash=prev_block_hash, db=vm.chaindb, ) execution_context = ExecutionContext.from_block_header(block1.header, prev_hashes) vm_state1 = FrontierVMState( chaindb=chaindb1, execution_context=execution_context, state_root=block1.header.state_root, receipts=[], ) parent_hash = copy.deepcopy(prev_hashes[0]) computation, block, _ = vm_state1.apply_transaction( tx1, block1, ) access_logs1 = computation.vm_state.access_logs # Check if prev_hashes hasn't been changed assert parent_hash == prev_hashes[0] # Make sure that block1 hasn't been changed assert block1.header.state_root == initial_state_root execution_context = ExecutionContext.from_block_header(block.header, prev_hashes) vm_state1 = FrontierVMState( chaindb=chaindb1, execution_context=execution_context, state_root=block.header.state_root, receipts=computation.vm_state.receipts, ) computation, block, _ = vm_state1.apply_transaction( tx2, block, ) access_logs2 = computation.vm_state.access_logs post_vm_state = computation.vm_state # Check AccessLogs witness_db = ChainDB(MemoryDB(access_logs2.writes)) state_db = witness_db.get_state_db(block.header.state_root, read_only=True) assert state_db.get_balance(recipient2) == amount with pytest.raises(KeyError): _ = state_db.get_balance(recipient1) # Check block data are correct assert block.header.state_root == result_block.header.state_root assert block.header.gas_limit == result_block.header.gas_limit assert block.header.gas_used == result_block.header.gas_used assert block.header.transaction_root == result_block.header.transaction_root assert block.header.receipt_root == result_block.header.receipt_root # Make sure that vm_state1 hasn't been changed assert post_vm_state.state_root == result_block.header.state_root # (3) Testing using witness as db data # Witness_db block2 = copy.deepcopy(block0) witness_db = ChainDB(MemoryDB(access_logs1.reads)) prev_hashes = vm.get_prev_hashes( last_block_hash=prev_block_hash, db=vm.chaindb, ) execution_context = ExecutionContext.from_block_header(block2.header, prev_hashes) # Apply the first transaction vm_state2 = FrontierVMState( chaindb=witness_db, execution_context=execution_context, state_root=block2.header.state_root, receipts=[], ) computation, block, _ = vm_state2.apply_transaction( tx1, block2, ) # Update witness_db recent_trie_nodes = merge(access_logs2.reads, access_logs1.writes) witness_db = ChainDB(MemoryDB(recent_trie_nodes)) execution_context = ExecutionContext.from_block_header(block.header, prev_hashes) # Apply the second transaction vm_state2 = FrontierVMState( chaindb=witness_db, execution_context=execution_context, state_root=block.header.state_root, receipts=computation.vm_state.receipts, ) computation, block, _ = vm_state2.apply_transaction( tx2, block, ) # After applying assert block.header.state_root == computation.vm_state.state_root assert block.header.transaction_root == result_block.header.transaction_root assert block.header.receipt_root == result_block.header.receipt_root assert block.hash == result_block.hash # (3) Testing using witness_db and block_header to reconstruct vm_state prev_hashes = vm.get_prev_hashes( last_block_hash=prev_block_hash, db=vm.chaindb, ) execution_context = ExecutionContext.from_block_header(block.header, prev_hashes) vm_state3 = FrontierVMState( chaindb=witness_db, execution_context=execution_context, state_root=block.header.state_root, ) assert vm_state3.state_root == post_vm_state.state_root assert vm_state3.state_root == result_block.header.state_root
def test_apply_transaction( # noqa: F811 chain_without_block_validation, funded_address, funded_address_private_key): chain = chain_without_block_validation # noqa: F811 # Don't change these variables vm = chain.get_vm() chaindb = copy.deepcopy(vm.chaindb) block0 = copy.deepcopy(vm.block) prev_block_hash = chain.get_canonical_block_by_number(0).hash initial_state_root = vm.block.header.state_root # (1) Get VM.apply_transaction(transaction) result for assertion # The first transaction chain1 = copy.deepcopy(chain) vm_example = chain1.get_vm() recipient1 = decode_hex('0x1111111111111111111111111111111111111111') amount = 100 from_ = funded_address tx1 = new_transaction( vm_example, from_, recipient1, amount, private_key=funded_address_private_key, ) computation, result_block = vm_example.apply_transaction(tx1) # The second transaction recipient2 = decode_hex('0x2222222222222222222222222222222222222222') tx2 = new_transaction( vm_example, from_, recipient2, amount, private_key=funded_address_private_key, ) computation, result_block = vm_example.apply_transaction(tx2) assert len(result_block.transactions) == 2 # (2) Test VMState.apply_transaction(...) # Use SpuriousDragonVMState to apply transaction chaindb1 = copy.deepcopy(chaindb) block1 = copy.deepcopy(block0) prev_hashes = vm.get_prev_hashes( last_block_hash=prev_block_hash, db=vm.chaindb, ) execution_context = block1.header.create_execution_context(prev_hashes) vm_state1 = SpuriousDragonVMState( chaindb=chaindb1, execution_context=execution_context, state_root=block1.header.state_root, receipts=[], ) parent_hash = copy.deepcopy(prev_hashes[0]) computation, block, _ = vm_state1.apply_transaction( tx1, block1, ) access_logs1 = computation.vm_state.access_logs # Check if prev_hashes hasn't been changed assert parent_hash == prev_hashes[0] # Make sure that block1 hasn't been changed assert block1.header.state_root == initial_state_root execution_context = block.header.create_execution_context(prev_hashes) vm_state1 = SpuriousDragonVMState( chaindb=chaindb1, execution_context=execution_context, state_root=block.header.state_root, receipts=computation.vm_state.receipts, ) computation, block, _ = vm_state1.apply_transaction( tx2, block, ) access_logs2 = computation.vm_state.access_logs post_vm_state = computation.vm_state # Check AccessLogs witness_db = ChainDB(MemoryDB(access_logs2.writes)) state_db = witness_db.get_state_db(block.header.state_root, read_only=True) assert state_db.get_balance(recipient2) == amount with pytest.raises(KeyError): _ = state_db.get_balance(recipient1) # Check block data are correct assert block.header.state_root == result_block.header.state_root assert block.header.gas_limit == result_block.header.gas_limit assert block.header.gas_used == result_block.header.gas_used assert block.header.transaction_root == result_block.header.transaction_root assert block.header.receipt_root == result_block.header.receipt_root # Make sure that vm_state1 hasn't been changed assert post_vm_state.state_root == result_block.header.state_root # (3) Testing using witness as db data # Witness_db block2 = copy.deepcopy(block0) witness_db = ChainDB(MemoryDB(access_logs1.reads)) prev_hashes = vm.get_prev_hashes( last_block_hash=prev_block_hash, db=vm.chaindb, ) execution_context = block2.header.create_execution_context(prev_hashes) # Apply the first transaction vm_state2 = SpuriousDragonVMState( chaindb=witness_db, execution_context=execution_context, state_root=block2.header.state_root, receipts=[], ) computation, block, _ = vm_state2.apply_transaction( tx1, block2, ) # Update witness_db recent_trie_nodes = merge(access_logs2.reads, access_logs1.writes) witness_db = ChainDB(MemoryDB(recent_trie_nodes)) execution_context = block.header.create_execution_context(prev_hashes) # Apply the second transaction vm_state2 = SpuriousDragonVMState( chaindb=witness_db, execution_context=execution_context, state_root=block.header.state_root, receipts=computation.vm_state.receipts, ) computation, block, _ = vm_state2.apply_transaction( tx2, block, ) # After applying assert block.header.state_root == computation.vm_state.state_root assert block.header.transaction_root == result_block.header.transaction_root assert block.header.receipt_root == result_block.header.receipt_root assert block.hash == result_block.hash # (3) Testing using witness_db and block_header to reconstruct vm_state prev_hashes = vm.get_prev_hashes( last_block_hash=prev_block_hash, db=vm.chaindb, ) execution_context = block.header.create_execution_context(prev_hashes) vm_state3 = SpuriousDragonVMState( chaindb=witness_db, execution_context=execution_context, state_root=block.header.state_root, ) assert vm_state3.state_root == post_vm_state.state_root assert vm_state3.state_root == result_block.header.state_root