mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-04 14:53:08 +00:00
Core transaction processing logic
With lots of TODOs to fill in afterward; this is just a start.
This commit is contained in:
parent
1763b6bc37
commit
cc61c7211c
@ -17,9 +17,6 @@ pub struct CpuColumnsView<T: Copy> {
|
||||
/// Filter. 1 if the row is part of bootstrapping the kernel code, 0 otherwise.
|
||||
pub is_bootstrap_kernel: T,
|
||||
|
||||
/// Filter. 1 if the row is part of bootstrapping a contract's code, 0 otherwise.
|
||||
pub is_bootstrap_contract: T,
|
||||
|
||||
/// Filter. 1 if the row corresponds to a cycle of execution and 0 otherwise.
|
||||
/// Lets us re-use columns in non-cycle rows.
|
||||
pub is_cpu_cycle: T,
|
||||
|
||||
@ -11,6 +11,15 @@ pub static KERNEL: Lazy<Kernel> = Lazy::new(combined_kernel);
|
||||
|
||||
pub(crate) fn combined_kernel() -> Kernel {
|
||||
let files = vec![
|
||||
include_str!("asm/core/bootloader.asm"),
|
||||
include_str!("asm/core/create.asm"),
|
||||
include_str!("asm/core/create_addresses.asm"),
|
||||
include_str!("asm/core/intrinsic_gas.asm"),
|
||||
include_str!("asm/core/nonce.asm"),
|
||||
include_str!("asm/core/process_txn.asm"),
|
||||
include_str!("asm/core/terminate.asm"),
|
||||
include_str!("asm/core/transfer.asm"),
|
||||
include_str!("asm/core/util.asm"),
|
||||
include_str!("asm/curve/bn254/curve_add.asm"),
|
||||
include_str!("asm/curve/bn254/curve_mul.asm"),
|
||||
include_str!("asm/curve/bn254/moddiv.asm"),
|
||||
@ -33,7 +42,6 @@ pub(crate) fn combined_kernel() -> Kernel {
|
||||
include_str!("asm/rlp/read_to_memory.asm"),
|
||||
include_str!("asm/storage/read.asm"),
|
||||
include_str!("asm/storage/write.asm"),
|
||||
include_str!("asm/transactions/process_normalized.asm"),
|
||||
include_str!("asm/transactions/router.asm"),
|
||||
include_str!("asm/transactions/type_0.asm"),
|
||||
include_str!("asm/transactions/type_1.asm"),
|
||||
|
||||
11
evm/src/cpu/kernel/asm/core/bootloader.asm
Normal file
11
evm/src/cpu/kernel/asm/core/bootloader.asm
Normal file
@ -0,0 +1,11 @@
|
||||
// Loads some prover-provided contract code into the code segment of memory,
|
||||
// then hashes the code and returns the hash.
|
||||
|
||||
global bootload_contract:
|
||||
// stack: retdest
|
||||
|
||||
// TODO
|
||||
|
||||
// stack: code_hash, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
59
evm/src/cpu/kernel/asm/core/call.asm
Normal file
59
evm/src/cpu/kernel/asm/core/call.asm
Normal file
@ -0,0 +1,59 @@
|
||||
// Handlers for call-like operations, namely CALL, CALLCODE, STATICCALL and DELEGATECALL.
|
||||
|
||||
// Creates a new sub context and executes the code of the given account.
|
||||
global call:
|
||||
// stack: gas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
%address
|
||||
%stack (self, gas, address, value)
|
||||
// These are (should_transfer_value, value, static, gas, sender, storage, code_addr)
|
||||
-> (1, value, 0, gas, self, address, address)
|
||||
%jump(call_common)
|
||||
|
||||
// Creates a new sub context as if calling itself, but with the code of the
|
||||
// given account. In particular the storage remains the same.
|
||||
global call_code:
|
||||
// stack: gas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
%address
|
||||
%stack (self, gas, address, value)
|
||||
// These are (should_transfer_value, value, static, gas, sender, storage, code_addr)
|
||||
-> (1, value, 0, gas, self, self, address)
|
||||
%jump(call_common)
|
||||
|
||||
// Creates a new sub context and executes the code of the given account.
|
||||
// Equivalent to CALL, except that it does not allow any state modifying
|
||||
// instructions or sending ETH in the sub context. The disallowed instructions
|
||||
// are CREATE, CREATE2, LOG0, LOG1, LOG2, LOG3, LOG4, SSTORE, SELFDESTRUCT and
|
||||
// CALL if the value sent is not 0.
|
||||
global static_all:
|
||||
// stack: gas, address, args_offset, args_size, ret_offset, ret_size
|
||||
%address
|
||||
%stack (self, gas, address)
|
||||
// These are (should_transfer_value, value, static, gas, sender, storage, code_addr)
|
||||
-> (0, 0, 1, gas, self, address, address)
|
||||
%jump(call_common)
|
||||
|
||||
// Creates a new sub context as if calling itself, but with the code of the
|
||||
// given account. In particular the storage, the current sender and the current
|
||||
// value remain the same.
|
||||
global delegate_call:
|
||||
// stack: gas, address, args_offset, args_size, ret_offset, ret_size
|
||||
%address
|
||||
%sender
|
||||
%callvalue
|
||||
%stack (self, sender, value, gas, address)
|
||||
// These are (should_transfer_value, value, static, gas, sender, storage, code_addr)
|
||||
-> (0, value, 0, gas, sender, self, address)
|
||||
%jump(call_common)
|
||||
|
||||
call_common:
|
||||
// stack: should_transfer_value, value, static, gas, sender, storage, code_addr, args_offset, args_size, ret_offset, ret_size
|
||||
// TODO: Set all the appropriate metadata fields...
|
||||
%create_context
|
||||
// stack: new_ctx, after_call
|
||||
// Now, switch to the new context and go to usermode with PC=0.
|
||||
SET_CONTEXT
|
||||
PUSH 0
|
||||
EXIT_KERNEL
|
||||
|
||||
after_call:
|
||||
// TODO: Set RETURNDATA etc.
|
||||
84
evm/src/cpu/kernel/asm/core/create.asm
Normal file
84
evm/src/cpu/kernel/asm/core/create.asm
Normal file
@ -0,0 +1,84 @@
|
||||
// Create a new contract account with the traditional address scheme, i.e.
|
||||
// address = KEC(RLP(sender, nonce))[12:]
|
||||
// This can be used both for the CREATE instruction and for contract-creation
|
||||
// transactions.
|
||||
//
|
||||
// Pre stack: CODE_ADDR, code_len, retdest
|
||||
// Post stack: address
|
||||
// Note: CODE_ADDR refers to a (context, segment, offset) tuple.
|
||||
global create:
|
||||
// stack: sender, endowment, CODE_ADDR, code_len, retdest
|
||||
DUP1 %get_nonce
|
||||
// stack: nonce, sender, endowment, CODE_ADDR, code_len, retdest
|
||||
// Call get_create_address and have it return to create_inner.
|
||||
%stack (nonce, sender)
|
||||
-> (sender, nonce, create_inner, sender)
|
||||
%jump(get_create_address)
|
||||
|
||||
// CREATE2; see EIP-1014. Address will be
|
||||
// address = KEC(0xff || sender || salt || code_hash)[12:]
|
||||
//
|
||||
// Pre stack: sender, endowment, salt, CODE_ADDR, code_len, retdest
|
||||
// Post stack: address
|
||||
// Note: CODE_ADDR refers to a (context, segment, offset) tuple.
|
||||
global create2:
|
||||
// stack: sender, endowment, salt, CODE_ADDR, code_len, retdest
|
||||
// Call get_create2_address and have it return to create_inner.
|
||||
%stack (sender, endowment, salt) -> (salt, sender, endowment)
|
||||
// stack: salt, sender, endowment, CODE_ADDR, code_len, retdest
|
||||
DUP7 DUP7 DUP7 DUP7 // CODE_ADDR and code_len
|
||||
// stack: CODE_ADDR, code_len, salt, sender, endowment, CODE_ADDR, code_len, retdest
|
||||
PUSH create_inner
|
||||
// stack: create_inner, CODE_ADDR, code_len, salt, sender, endowment, CODE_ADDR, code_len, retdest
|
||||
SWAP5 // create_inner <-> salt
|
||||
// stack: salt, CODE_ADDR, code_len, create_inner, sender, endowment, CODE_ADDR, code_len, retdest
|
||||
DUP7 // sender
|
||||
// stack: sender, salt, CODE_ADDR, code_len, create_inner, sender, endowment, CODE_ADDR, code_len, retdest
|
||||
%jump(get_create2_address)
|
||||
|
||||
// Pre stack: address, sender, endowment, CODE_ADDR, code_len, retdest
|
||||
// Post stack: address
|
||||
// Note: CODE_ADDR refers to a (context, segment, offset) tuple.
|
||||
create_inner:
|
||||
// stack: address, sender, endowment, CODE_ADDR, code_len, retdest
|
||||
%stack (address, sender, endowment)
|
||||
-> (sender, address, endowment, sender, address)
|
||||
// TODO: Need to handle insufficient balance failure.
|
||||
%transfer_eth
|
||||
// stack: sender, address, CODE_ADDR, code_len, retdest
|
||||
|
||||
%increment_nonce
|
||||
// stack: address, CODE_ADDR, code_len, retdest
|
||||
|
||||
%create_context
|
||||
// stack: new_ctx, address, CODE_ADDR, code_len, retdest
|
||||
%stack (new_ctx, address, src_ctx, src_segment, src_offset, code_len)
|
||||
-> (new_ctx, @SEGMENT_CODE, 0,
|
||||
src_ctx, src_segment, src_offset,
|
||||
code_len, run_constructor,
|
||||
new_ctx, address)
|
||||
%jump(memcpy)
|
||||
|
||||
run_constructor:
|
||||
// stack: new_ctx, address, retdest
|
||||
// At this point, the initialization code has been loaded.
|
||||
// Save our return address in memory, so we'll be in `after_constructor`
|
||||
// after the new context returns.
|
||||
// Note: We can't use %mstore_context_metadata because we're writing to
|
||||
// memory owned by the new context, not the current one.
|
||||
%stack (new_ctx) -> (new_ctx, @SEGMENT_CONTEXT_METADATA,
|
||||
@CTX_METADATA_PARENT_PC, after_constructor, new_ctx)
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, address, retdest
|
||||
|
||||
// Now, switch to the new context and go to usermode with PC=0.
|
||||
SET_CONTEXT
|
||||
// stack: (empty, since we're in the new context)
|
||||
PUSH 0
|
||||
EXIT_KERNEL
|
||||
|
||||
after_constructor:
|
||||
// stack: address, retdest
|
||||
// TODO: If code was returned, store it in the account.
|
||||
SWAP1
|
||||
JUMP
|
||||
27
evm/src/cpu/kernel/asm/core/create_addresses.asm
Normal file
27
evm/src/cpu/kernel/asm/core/create_addresses.asm
Normal file
@ -0,0 +1,27 @@
|
||||
// Computes the address of a contract based on the conventional scheme, i.e.
|
||||
// address = KEC(RLP(sender, nonce))[12:]
|
||||
//
|
||||
// Pre stack: sender, nonce, retdest
|
||||
// Post stack: address
|
||||
global get_create_address:
|
||||
// stack: sender, nonce, retdest
|
||||
// TODO: Replace with actual implementation.
|
||||
%pop2
|
||||
PUSH 123
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
// Computes the address for a contract based on the CREATE2 rule, i.e.
|
||||
// address = KEC(0xff || sender || salt || code_hash)[12:]
|
||||
//
|
||||
// Pre stack: sender, salt, CODE_ADDR, code_len, retdest
|
||||
// Post stack: address
|
||||
//
|
||||
// Note: CODE_ADDR is a (context, segment, offset) tuple.
|
||||
global get_create2_address:
|
||||
// stack: sender, salt, CODE_ADDR, code_len, retdest
|
||||
// TODO: Replace with actual implementation.
|
||||
%pop6
|
||||
PUSH 123
|
||||
SWAP1
|
||||
JUMP
|
||||
65
evm/src/cpu/kernel/asm/core/intrinsic_gas.asm
Normal file
65
evm/src/cpu/kernel/asm/core/intrinsic_gas.asm
Normal file
@ -0,0 +1,65 @@
|
||||
// After the transaction data has been parsed into a normalized set of fields
|
||||
// (see NormalizedTxnField), this routine processes the transaction.
|
||||
|
||||
global intrinsic_gas:
|
||||
// stack: retdest
|
||||
// Calculate the number of zero and nonzero bytes in the txn data.
|
||||
PUSH 0 // zeros = 0
|
||||
PUSH 0 // i = 0
|
||||
|
||||
count_zeros_loop:
|
||||
// stack: i, zeros, retdest
|
||||
DUP1
|
||||
%mload_txn_field(@TXN_FIELD_DATA_LEN)
|
||||
EQ
|
||||
// stack: i == data.len, i, zeros, retdest
|
||||
%jumpi(count_zeros_finish)
|
||||
|
||||
// stack: i, zeros, retdest
|
||||
DUP1
|
||||
%mload_kernel(@SEGMENT_TXN_DATA)
|
||||
ISZERO
|
||||
// stack: data[i] == 0, i, zeros
|
||||
%stack (data_i_is_zero, i, zeros) -> (data_i_is_zero, zeros, i)
|
||||
ADD
|
||||
// stack: zeros', i, retdest
|
||||
SWAP1
|
||||
// stack: i, zeros', retdest
|
||||
%add_const(1)
|
||||
// stack: i', zeros', retdest
|
||||
%jump(count_zeros_loop)
|
||||
|
||||
count_zeros_finish:
|
||||
// stack: i, zeros, retdest
|
||||
POP
|
||||
// stack: zeros, retdest
|
||||
DUP1
|
||||
// stack: zeros, zeros, retdest
|
||||
%mload_txn_field(@TXN_FIELD_DATA_LEN)
|
||||
// stack: data.len, zeros, zeros, retdest
|
||||
SUB
|
||||
// stack: nonzeros, zeros, retdest
|
||||
%mul_const(@GAS_TXDATANONZERO)
|
||||
// stack: gas_nonzeros, zeros, retdest
|
||||
SWAP1
|
||||
%mul_const(@GAS_TXDATAZERO)
|
||||
// stack: gas_zeros, gas_nonzeros, retdest
|
||||
ADD
|
||||
// stack: gas_txndata, retdest
|
||||
|
||||
%is_contract_creation
|
||||
%mul_const(@GAS_TXCREATE)
|
||||
// stack: gas_creation, gas_txndata, retdest
|
||||
|
||||
PUSH @GAS_TRANSACTION
|
||||
// stack: gas_txn, gas_creation, gas_txndata, retdest
|
||||
|
||||
// TODO: Add num_access_list_addresses * GAS_ACCESSLISTADDRESS
|
||||
// TODO: Add num_access_list_slots * GAS_ACCESSLISTSTORAGE
|
||||
|
||||
ADD
|
||||
ADD
|
||||
// stack: total_gas, retdest
|
||||
|
||||
SWAP1
|
||||
JUMP
|
||||
28
evm/src/cpu/kernel/asm/core/nonce.asm
Normal file
28
evm/src/cpu/kernel/asm/core/nonce.asm
Normal file
@ -0,0 +1,28 @@
|
||||
// Increment the nonce of the given account.
|
||||
// Pre stack: address, retdest
|
||||
// Post stack: (empty)
|
||||
|
||||
global get_nonce:
|
||||
// stack: address, retdest
|
||||
// TODO: Replace with actual implementation.
|
||||
JUMP
|
||||
|
||||
// Convenience macro to call get_nonce and return where we left off.
|
||||
%macro get_nonce
|
||||
%stack (address) -> (address, %%after)
|
||||
%jump(get_nonce)
|
||||
%%after:
|
||||
%endmacro
|
||||
|
||||
global increment_nonce:
|
||||
// stack: address, retdest
|
||||
// TODO: Replace with actual implementation.
|
||||
POP
|
||||
JUMP
|
||||
|
||||
// Convenience macro to call increment_nonce and return where we left off.
|
||||
%macro increment_nonce
|
||||
%stack (address) -> (address, %%after)
|
||||
%jump(increment_nonce)
|
||||
%%after:
|
||||
%endmacro
|
||||
39
evm/src/cpu/kernel/asm/core/process_txn.asm
Normal file
39
evm/src/cpu/kernel/asm/core/process_txn.asm
Normal file
@ -0,0 +1,39 @@
|
||||
// After the transaction data has been parsed into a normalized set of fields
|
||||
// (see NormalizedTxnField), this routine processes the transaction.
|
||||
|
||||
global process_normalized_txn:
|
||||
// stack: (empty)
|
||||
PUSH validate
|
||||
%jump(intrinsic_gas)
|
||||
|
||||
validate:
|
||||
// stack: intrinsic_gas
|
||||
// TODO: Check gas >= intrinsic_gas.
|
||||
// TODO: Check sender_balance >= intrinsic_gas + value.
|
||||
|
||||
buy_gas:
|
||||
// TODO: Deduct gas from sender (some may be refunded later).
|
||||
|
||||
increment_nonce:
|
||||
// TODO: Increment nonce.
|
||||
|
||||
process_based_on_type:
|
||||
%is_contract_creation
|
||||
%jumpi(process_contract_creation_txn)
|
||||
%jump(process_message_txn)
|
||||
|
||||
process_contract_creation_txn:
|
||||
// stack: (empty)
|
||||
// Push the code address & length onto the stack, then call `create`.
|
||||
%mload_txn_field(@TXN_FIELD_DATA_LEN)
|
||||
// stack: code_len
|
||||
PUSH 0
|
||||
// stack: code_offset, code_len
|
||||
PUSH @SEGMENT_TXN_DATA
|
||||
// stack: code_segment, code_offset, code_len
|
||||
PUSH 0 // context
|
||||
// stack: CODE_ADDR, code_len
|
||||
%jump(create)
|
||||
|
||||
process_message_txn:
|
||||
// TODO
|
||||
56
evm/src/cpu/kernel/asm/core/terminate.asm
Normal file
56
evm/src/cpu/kernel/asm/core/terminate.asm
Normal file
@ -0,0 +1,56 @@
|
||||
// Handlers for operations which terminate the current context, namely STOP,
|
||||
// RETURN, SELFDESTRUCT, REVERT, and exceptions such as stack underflow.
|
||||
|
||||
global stop:
|
||||
// TODO: Set parent context's CTX_METADATA_RETURNDATA_SIZE to 0.
|
||||
%jump(terminate_common)
|
||||
|
||||
global return:
|
||||
// TODO: Set parent context's CTX_METADATA_RETURNDATA_SIZE.
|
||||
// TODO: Copy returned memory to parent context's RETURNDATA (but not if we're returning from a constructor?)
|
||||
// TODO: Copy returned memory to parent context's memory (as specified in their call instruction)
|
||||
%jump(terminate_common)
|
||||
|
||||
global selfdestruct:
|
||||
%consume_gas_const(@GAS_SELFDESTRUCT)
|
||||
// TODO
|
||||
%jump(terminate_common)
|
||||
|
||||
global revert:
|
||||
// TODO
|
||||
%jump(terminate_common)
|
||||
|
||||
// The execution is in an exceptional halt-ing state if
|
||||
// - there is insufficient gas
|
||||
// - the instruction is invalid
|
||||
// - there are insufficient stack items
|
||||
// - a JUMP/JUMPI destination is invalid
|
||||
// - the new stack size would be larger than 1024, or
|
||||
// - state modification is attempted during a static call
|
||||
global exception:
|
||||
// TODO
|
||||
%jump(terminate_common)
|
||||
|
||||
terminate_common:
|
||||
// stack: success
|
||||
// We want to move the success flag from our (child) context's stack to the
|
||||
// parent context's stack. We will write it to memory, specifically
|
||||
// SEGMENT_KERNEL_GENERAL[0], then load it after the context switch.
|
||||
PUSH 0
|
||||
// stack: 0, success
|
||||
%mstore_kernel(@SEGMENT_KERNEL_GENERAL)
|
||||
// stack: (empty)
|
||||
|
||||
// Go back to the parent context.
|
||||
%mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT)
|
||||
SET_CONTEXT
|
||||
// stack: (empty)
|
||||
|
||||
// Load the success flag that we stored in SEGMENT_KERNEL_GENERAL[0].
|
||||
PUSH 0
|
||||
%mload_kernel(@SEGMENT_KERNEL_GENERAL)
|
||||
// stack: success
|
||||
|
||||
// JUMP to the parent IP.
|
||||
%mload_context_metadata(@CTX_METADATA_PARENT_PC)
|
||||
JUMP
|
||||
16
evm/src/cpu/kernel/asm/core/transfer.asm
Normal file
16
evm/src/cpu/kernel/asm/core/transfer.asm
Normal file
@ -0,0 +1,16 @@
|
||||
// Transfers some ETH from one address to another. The amount is given in wei.
|
||||
// Pre stack: from, to, amount, retdest
|
||||
// Post stack: (empty)
|
||||
|
||||
global transfer_eth:
|
||||
// stack: from, to, amount, retdest
|
||||
// TODO: Replace with actual implementation.
|
||||
%pop3
|
||||
JUMP
|
||||
|
||||
// Convenience macro to call transfer_eth and return where we left off.
|
||||
%macro transfer_eth
|
||||
%stack (from, to, amount) -> (from, to, amount, %%after)
|
||||
%jump(transfer_eth)
|
||||
%%after:
|
||||
%endmacro
|
||||
32
evm/src/cpu/kernel/asm/core/util.asm
Normal file
32
evm/src/cpu/kernel/asm/core/util.asm
Normal file
@ -0,0 +1,32 @@
|
||||
// Return the next context ID, and record the old context ID in the new one's
|
||||
// @CTX_METADATA_PARENT_CONTEXT field. Does not actually enter the new context.
|
||||
%macro create_context
|
||||
%next_context_id
|
||||
GET_CONTEXT
|
||||
%stack (ctx, next_ctx)
|
||||
-> (next_ctx, @SEGMENT_NORMALIZED_TXN, @CTX_METADATA_PARENT_CONTEXT,
|
||||
ctx, next_ctx)
|
||||
MSTORE_GENERAL
|
||||
// stack: next_ctx
|
||||
%endmacro
|
||||
|
||||
// Get and increment @GLOBAL_METADATA_LARGEST_CONTEXT to determine the next context ID.
|
||||
%macro next_context_id
|
||||
// stack: (empty)
|
||||
%mload_global_metadata(@GLOBAL_METADATA_LARGEST_CONTEXT)
|
||||
%add_const(1)
|
||||
// stack: new_ctx
|
||||
DUP1
|
||||
%mstore_global_metadata(@GLOBAL_METADATA_LARGEST_CONTEXT)
|
||||
// stack: new_ctx
|
||||
%endmacro
|
||||
|
||||
// Returns whether the current transaction is a contract creation transaction.
|
||||
%macro is_contract_creation
|
||||
// stack: (empty)
|
||||
%mload_txn_field(@TXN_FIELD_TO)
|
||||
// stack: to
|
||||
ISZERO
|
||||
// If there is no "to" field, then this is a contract creation.
|
||||
// stack: to == 0
|
||||
%endmacro
|
||||
8
evm/src/cpu/kernel/asm/keccak.asm
Normal file
8
evm/src/cpu/kernel/asm/keccak.asm
Normal file
@ -0,0 +1,8 @@
|
||||
// Computes the Keccak256 hash of some arbitrary bytes in memory.
|
||||
// The given memory values should be in the range of a byte.
|
||||
//
|
||||
// Pre stack: ADDR, len, retdest
|
||||
// Post stack: hash
|
||||
global keccak_general:
|
||||
// stack: ADDR, len
|
||||
// TODO
|
||||
@ -33,3 +33,15 @@
|
||||
%mload_current(@SEGMENT_CONTEXT_METADATA)
|
||||
// stack: (empty)
|
||||
%endmacro
|
||||
|
||||
%macro address
|
||||
%mload_context_metadata(0) // TODO: Read proper field.
|
||||
%endmacro
|
||||
|
||||
%macro sender
|
||||
%mload_context_metadata(0) // TODO: Read proper field.
|
||||
%endmacro
|
||||
|
||||
%macro callvalue
|
||||
%mload_context_metadata(0) // TODO: Read proper field.
|
||||
%endmacro
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
// After the transaction data has been parsed into a normalized set of fields
|
||||
// (see TxnField), this routine processes the transaction.
|
||||
|
||||
global process_normalized_txn:
|
||||
// TODO
|
||||
@ -134,7 +134,12 @@ impl<'a> Interpreter<'a> {
|
||||
}
|
||||
|
||||
pub(crate) fn get_txn_field(&self, field: NormalizedTxnField) -> U256 {
|
||||
self.memory.context_memory[0].segments[Segment::TxnFields as usize].content[field as usize]
|
||||
self.memory.context_memory[0].segments[Segment::TxnFields as usize].get(field as usize)
|
||||
}
|
||||
|
||||
pub(crate) fn set_txn_field(&mut self, field: NormalizedTxnField, value: U256) {
|
||||
self.memory.context_memory[0].segments[Segment::TxnFields as usize]
|
||||
.set(field as usize, value);
|
||||
}
|
||||
|
||||
pub(crate) fn get_txn_data(&self) -> &[U256] {
|
||||
|
||||
54
evm/src/cpu/kernel/tests/core/create_addresses.rs
Normal file
54
evm/src/cpu/kernel/tests/core/create_addresses.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::cpu::kernel::aggregator::KERNEL;
|
||||
use crate::cpu::kernel::interpreter::Interpreter;
|
||||
|
||||
#[test]
|
||||
fn test_get_create_address() -> Result<()> {
|
||||
let get_create_address = KERNEL.global_labels["get_create_address"];
|
||||
|
||||
// TODO: Replace with real data once we have a real implementation.
|
||||
let retaddr = 0xdeadbeefu32.into();
|
||||
let nonce = 5.into();
|
||||
let sender = 0.into();
|
||||
let expected_addr = 123.into();
|
||||
|
||||
let initial_stack = vec![retaddr, nonce, sender];
|
||||
let mut interpreter = Interpreter::new_with_kernel(get_create_address, initial_stack);
|
||||
interpreter.run()?;
|
||||
|
||||
assert_eq!(interpreter.stack(), &[expected_addr]);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_create2_address() -> Result<()> {
|
||||
let get_create2_address = KERNEL.global_labels["get_create2_address"];
|
||||
|
||||
// TODO: Replace with real data once we have a real implementation.
|
||||
let retaddr = 0xdeadbeefu32.into();
|
||||
let code_len = 0.into();
|
||||
let code_offset = 0.into();
|
||||
let code_segment = 0.into();
|
||||
let code_context = 0.into();
|
||||
let salt = 5.into();
|
||||
let sender = 0.into();
|
||||
let expected_addr = 123.into();
|
||||
|
||||
let initial_stack = vec![
|
||||
retaddr,
|
||||
code_len,
|
||||
code_offset,
|
||||
code_segment,
|
||||
code_context,
|
||||
salt,
|
||||
sender,
|
||||
];
|
||||
let mut interpreter = Interpreter::new_with_kernel(get_create2_address, initial_stack);
|
||||
interpreter.run()?;
|
||||
|
||||
assert_eq!(interpreter.stack(), &[expected_addr]);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
27
evm/src/cpu/kernel/tests/core/intrinsic_gas.rs
Normal file
27
evm/src/cpu/kernel/tests/core/intrinsic_gas.rs
Normal file
@ -0,0 +1,27 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::cpu::kernel::aggregator::KERNEL;
|
||||
use crate::cpu::kernel::interpreter::Interpreter;
|
||||
use crate::cpu::kernel::txn_fields::NormalizedTxnField;
|
||||
|
||||
const GAS_TX: u32 = 21_000;
|
||||
const GAS_TXCREATE: u32 = 32_000;
|
||||
|
||||
#[test]
|
||||
fn test_intrinsic_gas() -> Result<()> {
|
||||
let intrinsic_gas = KERNEL.global_labels["intrinsic_gas"];
|
||||
|
||||
// Contract creation transaction.
|
||||
let initial_stack = vec![0xdeadbeefu32.into()];
|
||||
let mut interpreter = Interpreter::new_with_kernel(intrinsic_gas, initial_stack.clone());
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), vec![(GAS_TX + GAS_TXCREATE).into()]);
|
||||
|
||||
// Message transaction.
|
||||
let mut interpreter = Interpreter::new_with_kernel(intrinsic_gas, initial_stack);
|
||||
interpreter.set_txn_field(NormalizedTxnField::To, 123.into());
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), vec![GAS_TX.into()]);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
2
evm/src/cpu/kernel/tests/core/mod.rs
Normal file
2
evm/src/cpu/kernel/tests/core/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
mod create_addresses;
|
||||
mod intrinsic_gas;
|
||||
@ -1,3 +1,4 @@
|
||||
mod core;
|
||||
mod curve_ops;
|
||||
mod ecrecover;
|
||||
mod exp;
|
||||
|
||||
@ -18,7 +18,7 @@ pub(crate) enum Segment {
|
||||
/// General purpose kernel memory, used by various kernel functions.
|
||||
/// In general, calling a helper function can result in this memory being clobbered.
|
||||
KernelGeneral = 7,
|
||||
/// Contains normalized transaction fields; see `TxnField`.
|
||||
/// Contains normalized transaction fields; see `NormalizedTxnField`.
|
||||
TxnFields = 8,
|
||||
/// Contains the data field of a transaction.
|
||||
TxnData = 9,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user