Beispiel #1
0
def test_apply_transaction(chain_without_block_validation):  # noqa: F811
    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_ = chain.funded_address
    tx1 = new_transaction(
        vm_example,
        from_,
        recipient1,
        amount,
        private_key=chain.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=chain.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 = BaseChainDB(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 = BaseChainDB(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 = BaseChainDB(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
Beispiel #2
0
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