mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-12 02:33:06 +00:00
Merge pull request #903 from mir-protocol/misc_evm_fixes
Misc EVM fixes
This commit is contained in:
commit
eea8ab6260
@ -12,6 +12,7 @@ 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/call.asm"),
|
||||
include_str!("asm/core/create.asm"),
|
||||
include_str!("asm/core/create_addresses.asm"),
|
||||
include_str!("asm/core/intrinsic_gas.asm"),
|
||||
|
||||
@ -24,12 +24,6 @@ global extcodehash:
|
||||
%eq_const(@EMPTY_STRING_HASH)
|
||||
%endmacro
|
||||
|
||||
%macro codesize
|
||||
// stack: (empty)
|
||||
%address
|
||||
%extcodesize
|
||||
%endmacro
|
||||
|
||||
%macro extcodesize
|
||||
%stack (address) -> (address, 0, @SEGMENT_KERNEL_ACCOUNT_CODE, %%after)
|
||||
%jump(load_code)
|
||||
@ -82,91 +76,92 @@ global extcodecopy:
|
||||
%jump(load_code)
|
||||
|
||||
extcodecopy_contd:
|
||||
// stack: code_length, size, offset, dest_offset, retdest
|
||||
// stack: code_size, size, offset, dest_offset, retdest
|
||||
SWAP1
|
||||
// stack: size, code_length, offset, dest_offset, retdest
|
||||
// stack: size, code_size, offset, dest_offset, retdest
|
||||
PUSH 0
|
||||
|
||||
// Loop copying the `code[offset]` to `memory[dest_offset]` until `i==size`.
|
||||
// Each iteration increments `offset, dest_offset, i`.
|
||||
// TODO: Consider implementing this with memcpy.
|
||||
extcodecopy_loop:
|
||||
// stack: i, size, code_length, offset, dest_offset, retdest
|
||||
// stack: i, size, code_size, offset, dest_offset, retdest
|
||||
DUP2 DUP2 EQ
|
||||
// stack: i == size, i, size, code_length, offset, dest_offset, retdest
|
||||
// stack: i == size, i, size, code_size, offset, dest_offset, retdest
|
||||
%jumpi(extcodecopy_end)
|
||||
%stack (i, size, code_length, offset, dest_offset, retdest)
|
||||
-> (offset, code_length, offset, code_length, dest_offset, i, size, retdest)
|
||||
%stack (i, size, code_size, offset, dest_offset, retdest)
|
||||
-> (offset, code_size, offset, code_size, dest_offset, i, size, retdest)
|
||||
LT
|
||||
// stack: offset < code_length, offset, code_length, dest_offset, i, size, retdest
|
||||
// stack: offset < code_size, offset, code_size, dest_offset, i, size, retdest
|
||||
DUP2
|
||||
// stack: offset, offset < code_length, offset, code_length, dest_offset, i, size, retdest
|
||||
// stack: offset, offset < code_size, offset, code_size, dest_offset, i, size, retdest
|
||||
%mload_current(@SEGMENT_KERNEL_ACCOUNT_CODE)
|
||||
// stack: opcode, offset < code_length, offset, code_length, dest_offset, i, size, retdest
|
||||
%stack (opcode, offset_lt_code_length, offset, code_length, dest_offset, i, size, retdest)
|
||||
-> (offset_lt_code_length, 0, opcode, offset, code_length, dest_offset, i, size, retdest)
|
||||
// If `offset >= code_length`, use `opcode=0`. Necessary since `SEGMENT_KERNEL_ACCOUNT_CODE` might be clobbered from previous calls.
|
||||
// stack: opcode, offset < code_size, offset, code_size, dest_offset, i, size, retdest
|
||||
%stack (opcode, offset_lt_code_size, offset, code_size, dest_offset, i, size, retdest)
|
||||
-> (offset_lt_code_size, 0, opcode, offset, code_size, dest_offset, i, size, retdest)
|
||||
// If `offset >= code_size`, use `opcode=0`. Necessary since `SEGMENT_KERNEL_ACCOUNT_CODE` might be clobbered from previous calls.
|
||||
%select_bool
|
||||
// stack: opcode, offset, code_length, dest_offset, i, size, retdest
|
||||
// stack: opcode, offset, code_size, dest_offset, i, size, retdest
|
||||
DUP4
|
||||
// stack: dest_offset, opcode, offset, code_length, dest_offset, i, size, retdest
|
||||
// stack: dest_offset, opcode, offset, code_size, dest_offset, i, size, retdest
|
||||
%mstore_main
|
||||
// stack: offset, code_length, dest_offset, i, size, retdest
|
||||
// stack: offset, code_size, dest_offset, i, size, retdest
|
||||
%increment
|
||||
// stack: offset+1, code_length, dest_offset, i, size, retdest
|
||||
// stack: offset+1, code_size, dest_offset, i, size, retdest
|
||||
SWAP2
|
||||
// stack: dest_offset, code_length, offset+1, i, size, retdest
|
||||
// stack: dest_offset, code_size, offset+1, i, size, retdest
|
||||
%increment
|
||||
// stack: dest_offset+1, code_length, offset+1, i, size, retdest
|
||||
// stack: dest_offset+1, code_size, offset+1, i, size, retdest
|
||||
SWAP3
|
||||
// stack: i, code_length, offset+1, dest_offset+1, size, retdest
|
||||
// stack: i, code_size, offset+1, dest_offset+1, size, retdest
|
||||
%increment
|
||||
// stack: i+1, code_length, offset+1, dest_offset+1, size, retdest
|
||||
%stack (i, code_length, offset, dest_offset, size, retdest) -> (i, size, code_length, offset, dest_offset, retdest)
|
||||
// stack: i+1, code_size, offset+1, dest_offset+1, size, retdest
|
||||
%stack (i, code_size, offset, dest_offset, size, retdest) -> (i, size, code_size, offset, dest_offset, retdest)
|
||||
%jump(extcodecopy_loop)
|
||||
|
||||
extcodecopy_end:
|
||||
%stack (i, size, code_length, offset, dest_offset, retdest) -> (retdest)
|
||||
%stack (i, size, code_size, offset, dest_offset, retdest) -> (retdest)
|
||||
JUMP
|
||||
|
||||
|
||||
// Loads the code at `address` into memory, at the given context and segment, starting at offset 0.
|
||||
// Checks that the hash of the loaded code corresponds to the `codehash` in the state trie.
|
||||
// Pre stack: address, ctx, segment, retdest
|
||||
// Post stack: code_len
|
||||
// Post stack: code_size
|
||||
global load_code:
|
||||
%stack (address, ctx, segment, retdest) -> (extcodehash, address, load_code_ctd, ctx, segment, retdest)
|
||||
JUMP
|
||||
load_code_ctd:
|
||||
// stack: codehash, ctx, segment, retdest
|
||||
PROVER_INPUT(account_code::length)
|
||||
// stack: code_length, codehash, ctx, segment, retdest
|
||||
// stack: code_size, codehash, ctx, segment, retdest
|
||||
PUSH 0
|
||||
|
||||
// Loop non-deterministically querying `code[i]` and storing it in `SEGMENT_KERNEL_ACCOUNT_CODE` at offset `i`, until `i==code_length`.
|
||||
// Loop non-deterministically querying `code[i]` and storing it in `SEGMENT_KERNEL_ACCOUNT_CODE`
|
||||
// at offset `i`, until `i==code_size`.
|
||||
load_code_loop:
|
||||
// stack: i, code_length, codehash, ctx, segment, retdest
|
||||
// stack: i, code_size, codehash, ctx, segment, retdest
|
||||
DUP2 DUP2 EQ
|
||||
// stack: i == code_length, i, code_length, codehash, ctx, segment, retdest
|
||||
// stack: i == code_size, i, code_size, codehash, ctx, segment, retdest
|
||||
%jumpi(load_code_check)
|
||||
PROVER_INPUT(account_code::get)
|
||||
// stack: opcode, i, code_length, codehash, ctx, segment, retdest
|
||||
// stack: opcode, i, code_size, codehash, ctx, segment, retdest
|
||||
DUP2
|
||||
// stack: i, opcode, i, code_length, codehash, ctx, segment, retdest
|
||||
// stack: i, opcode, i, code_size, codehash, ctx, segment, retdest
|
||||
DUP7 // segment
|
||||
DUP7 // context
|
||||
MSTORE_GENERAL
|
||||
// stack: i, code_length, codehash, ctx, segment, retdest
|
||||
// stack: i, code_size, codehash, ctx, segment, retdest
|
||||
%increment
|
||||
// stack: i+1, code_length, codehash, ctx, segment, retdest
|
||||
// stack: i+1, code_size, codehash, ctx, segment, retdest
|
||||
%jump(load_code_loop)
|
||||
|
||||
// Check that the hash of the loaded code equals `codehash`.
|
||||
load_code_check:
|
||||
// stack: i, code_length, codehash, ctx, segment, retdest
|
||||
%stack (i, code_length, codehash, ctx, segment, retdest)
|
||||
-> (ctx, segment, 0, code_length, codehash, retdest, code_length)
|
||||
// stack: i, code_size, codehash, ctx, segment, retdest
|
||||
%stack (i, code_size, codehash, ctx, segment, retdest)
|
||||
-> (ctx, segment, 0, code_size, codehash, retdest, code_size)
|
||||
KECCAK_GENERAL
|
||||
// stack: shouldbecodehash, codehash, retdest, code_length
|
||||
// stack: shouldbecodehash, codehash, retdest, code_size
|
||||
%assert_eq
|
||||
JUMP
|
||||
|
||||
@ -1,115 +1,178 @@
|
||||
// Handlers for call-like operations, namely CALL, CALLCODE, STATICCALL and DELEGATECALL.
|
||||
|
||||
// TODO: Take kexit_info
|
||||
|
||||
// Creates a new sub context and executes the code of the given account.
|
||||
global call:
|
||||
global sys_call:
|
||||
// stack: kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
%address
|
||||
%stack (self, gas, address, value)
|
||||
// These are (static, should_transfer_value, value, sender, address, code_addr, gas)
|
||||
-> (0, 1, value, self, address, address, gas)
|
||||
%jump(call_common)
|
||||
%create_context
|
||||
// stack: new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
|
||||
// Each line in the block below does not change the stack.
|
||||
DUP4 %set_new_ctx_addr
|
||||
%address %set_new_ctx_caller
|
||||
DUP5 %set_new_ctx_value
|
||||
DUP5 DUP5 %address %transfer_eth
|
||||
%set_new_ctx_parent_ctx
|
||||
%set_new_ctx_parent_pc(after_call_instruction)
|
||||
|
||||
// TODO: Copy memory[args_offset..args_offset + args_size] CALLDATA
|
||||
// TODO: Set child gas
|
||||
// TODO: Populate code and codesize field.
|
||||
|
||||
// stack: new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
%stack (new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
-> (new_ctx, kexit_info, ret_offset, ret_size)
|
||||
%enter_new_ctx
|
||||
|
||||
// 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, retdest
|
||||
%address
|
||||
%stack (self, gas, address, value)
|
||||
// These are (static, should_transfer_value, value, sender, address, code_addr, gas)
|
||||
-> (0, 1, value, self, self, address, gas)
|
||||
%jump(call_common)
|
||||
global sys_callcode:
|
||||
// stack: kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
%create_context
|
||||
// stack: new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
|
||||
// Each line in the block below does not change the stack.
|
||||
%address %set_new_ctx_addr
|
||||
%address %set_new_ctx_caller
|
||||
DUP5 %set_new_ctx_value
|
||||
DUP5 DUP5 %address %transfer_eth
|
||||
%set_new_ctx_parent_ctx
|
||||
%set_new_ctx_parent_pc(after_call_instruction)
|
||||
|
||||
// stack: new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size
|
||||
%stack (new_ctx, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size)
|
||||
-> (new_ctx, kexit_info, ret_offset, ret_size)
|
||||
%enter_new_ctx
|
||||
|
||||
// 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, retdest
|
||||
%address
|
||||
%stack (self, gas, address)
|
||||
// These are (static, should_transfer_value, value, sender, address, code_addr, gas)
|
||||
-> (1, 0, 0, self, address, address, gas)
|
||||
%jump(call_common)
|
||||
global sys_staticcall:
|
||||
// stack: kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size
|
||||
%create_context
|
||||
// stack: new_ctx, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size
|
||||
|
||||
// Each line in the block below does not change the stack.
|
||||
%set_static_true
|
||||
DUP4 %set_new_ctx_addr
|
||||
%address %set_new_ctx_caller
|
||||
PUSH 0 %set_new_ctx_value
|
||||
%set_new_ctx_parent_ctx
|
||||
%set_new_ctx_parent_pc(after_call_instruction)
|
||||
|
||||
%stack (new_ctx, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size)
|
||||
-> (new_ctx, kexit_info, ret_offset, ret_size)
|
||||
%enter_new_ctx
|
||||
|
||||
// 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, retdest
|
||||
%address
|
||||
%sender
|
||||
%callvalue
|
||||
%stack (self, sender, value, gas, address)
|
||||
// These are (static, should_transfer_value, value, sender, address, code_addr, gas)
|
||||
-> (0, 0, value, sender, self, address, gas)
|
||||
%jump(call_common)
|
||||
|
||||
// Pre stack: static, should_transfer_value, value, sender, address, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
|
||||
// Post stack: success, leftover_gas
|
||||
global call_common:
|
||||
// stack: static, should_transfer_value, value, sender, address, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
|
||||
global sys_delegatecall:
|
||||
// stack: kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size
|
||||
%create_context
|
||||
// Store the static flag in metadata.
|
||||
%stack (new_ctx, static) -> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_STATIC, static, new_ctx)
|
||||
// stack: new_ctx, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size
|
||||
|
||||
// Each line in the block below does not change the stack.
|
||||
%address %set_new_ctx_addr
|
||||
%caller %set_new_ctx_caller
|
||||
%callvalue %set_new_ctx_value
|
||||
%set_new_ctx_parent_ctx
|
||||
%set_new_ctx_parent_pc(after_call_instruction)
|
||||
|
||||
%stack (new_ctx, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size)
|
||||
-> (new_ctx, kexit_info, ret_offset, ret_size)
|
||||
%enter_new_ctx
|
||||
|
||||
// We go here after any CALL type instruction (but not after the special call by the transaction originator).
|
||||
global after_call_instruction:
|
||||
// stack: success, leftover_gas, new_ctx, kexit_info, ret_offset, ret_size
|
||||
SWAP3
|
||||
// stack: kexit_info, leftover_gas, new_ctx, success, ret_offset, ret_size
|
||||
// Add the leftover gas into the appropriate bits of kexit_info.
|
||||
SWAP1 %shl_const(192) ADD
|
||||
// stack: kexit_info, new_ctx, success, ret_offset, ret_size
|
||||
|
||||
// The callee's terminal instruction will have populated RETURNDATA.
|
||||
// TODO: Copy RETURNDATA to memory[ret_offset..ret_offset + ret_size].
|
||||
|
||||
%stack (kexit_info, new_ctx, success, ret_offset, ret_size)
|
||||
-> (kexit_info, success)
|
||||
EXIT_KERNEL
|
||||
|
||||
// Set @CTX_METADATA_STATIC to 1. Note that there is no corresponding set_static_false routine
|
||||
// because it will already be 0 by default.
|
||||
%macro set_static_true
|
||||
// stack: new_ctx
|
||||
%stack (new_ctx) -> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_STATIC, 1, new_ctx)
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, should_transfer_value, value, sender, address, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
|
||||
// stack: new_ctx
|
||||
%endmacro
|
||||
|
||||
// Store the address in metadata.
|
||||
%stack (new_ctx, should_transfer_value, value, sender, address)
|
||||
-> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_ADDRESS, address,
|
||||
new_ctx, should_transfer_value, value, sender, address)
|
||||
%macro set_new_ctx_addr
|
||||
// stack: called_addr, new_ctx
|
||||
%stack (called_addr, new_ctx)
|
||||
-> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_ADDRESS, called_addr, new_ctx)
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, should_transfer_value, value, sender, address, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
|
||||
// stack: new_ctx
|
||||
%endmacro
|
||||
|
||||
// Store the caller in metadata.
|
||||
%stack (new_ctx, should_transfer_value, value, sender)
|
||||
-> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CALLER, sender,
|
||||
new_ctx, should_transfer_value, value, sender)
|
||||
%macro set_new_ctx_caller
|
||||
// stack: sender, new_ctx
|
||||
%stack (sender, new_ctx)
|
||||
-> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CALLER, sender, new_ctx)
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, should_transfer_value, value, sender, address, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
|
||||
// stack: new_ctx
|
||||
%endmacro
|
||||
|
||||
// Store the call value field in metadata.
|
||||
%stack (new_ctx, should_transfer_value, value, sender, address) =
|
||||
-> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CALL_VALUE, value,
|
||||
should_transfer_value, sender, address, value, new_ctx)
|
||||
%macro set_new_ctx_value
|
||||
// stack: value, new_ctx
|
||||
%stack (value, new_ctx)
|
||||
-> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CALL_VALUE, value, new_ctx)
|
||||
MSTORE_GENERAL
|
||||
// stack: should_transfer_value, sender, address, value, new_ctx, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
|
||||
// stack: new_ctx
|
||||
%endmacro
|
||||
|
||||
%maybe_transfer_eth
|
||||
// stack: new_ctx, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
|
||||
%macro set_new_ctx_code_size
|
||||
// stack: code_size, new_ctx
|
||||
%stack (code_size, new_ctx)
|
||||
-> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CODE_SIZE, code_size, new_ctx)
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx
|
||||
%endmacro
|
||||
|
||||
// Store parent context in metadata.
|
||||
%macro set_new_ctx_gas_limit
|
||||
// stack: gas_limit, new_ctx
|
||||
%stack (gas_limit, new_ctx)
|
||||
-> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CODE_SIZE, gas_limit, new_ctx)
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx
|
||||
%endmacro
|
||||
|
||||
%macro set_new_ctx_parent_ctx
|
||||
// stack: new_ctx
|
||||
GET_CONTEXT
|
||||
PUSH @CTX_METADATA_PARENT_CONTEXT
|
||||
PUSH @SEGMENT_CONTEXT_METADATA
|
||||
DUP4 // new_ctx
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
|
||||
// stack: new_ctx
|
||||
%endmacro
|
||||
|
||||
// Store parent PC = after_call.
|
||||
%stack (new_ctx) -> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_PARENT_PC, after_call, new_ctx)
|
||||
%macro set_new_ctx_parent_pc(label)
|
||||
// stack: new_ctx
|
||||
%stack (new_ctx)
|
||||
-> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_PARENT_PC, $label, new_ctx)
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, code_addr, gas, args_offset, args_size, ret_offset, ret_size, retdest
|
||||
// stack: new_ctx
|
||||
%endmacro
|
||||
|
||||
// TODO: Populate CALLDATA
|
||||
// TODO: Save parent gas and set child gas
|
||||
// TODO: Populate code
|
||||
|
||||
// TODO: Temporary, remove after above steps are done.
|
||||
%stack (new_ctx, code_addr, gas, args_offset, args_size) -> (new_ctx)
|
||||
// stack: new_ctx, ret_offset, ret_size, retdest
|
||||
|
||||
// Now, switch to the new context and go to usermode with PC=0.
|
||||
%macro enter_new_ctx
|
||||
// stack: new_ctx
|
||||
// Switch to the new context and go to usermode with PC=0.
|
||||
DUP1 // new_ctx
|
||||
SET_CONTEXT
|
||||
PUSH 0 // jump dest
|
||||
EXIT_KERNEL
|
||||
|
||||
after_call:
|
||||
// stack: new_ctx, ret_offset, ret_size, retdest
|
||||
// TODO: Set RETURNDATA.
|
||||
// TODO: Return to caller w/ EXIT_KERNEL.
|
||||
// TODO: Return leftover gas
|
||||
// (Old context) stack: new_ctx
|
||||
%endmacro
|
||||
|
||||
@ -26,14 +26,18 @@ global create:
|
||||
// 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
|
||||
// Pre stack: sender, endowment, salt, CODE_ADDR: 3, code_len, retdest
|
||||
// Post stack: address
|
||||
// Note: CODE_ADDR refers to a (context, segment, offset) tuple.
|
||||
global sys_create2:
|
||||
// stack: sender, endowment, salt, CODE_ADDR, code_len, retdest
|
||||
// stack: sender, endowment, salt, CODE_ADDR: 3, code_len, retdest
|
||||
DUP7 DUP7 DUP7 DUP7 // CODE_ADDR: 3, code_len
|
||||
KECCAK_GENERAL
|
||||
// stack: code_hash, sender, endowment, salt, CODE_ADDR: 3, code_len, retdest
|
||||
|
||||
// Call get_create2_address and have it return to create_inner.
|
||||
%stack (sender, endowment, salt, CODE_ADDR: 3, code_len)
|
||||
-> (sender, salt, CODE_ADDR, code_len, create_inner, sender, endowment, CODE_ADDR, code_len)
|
||||
%stack (code_hash, sender, endowment, salt)
|
||||
-> (sender, salt, code_hash, create_inner, sender, endowment)
|
||||
// stack: sender, salt, CODE_ADDR, code_len, create_inner, sender, endowment, CODE_ADDR, code_len, retdest
|
||||
%jump(get_create2_address)
|
||||
|
||||
|
||||
@ -14,14 +14,12 @@ global get_create_address:
|
||||
// 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
|
||||
// Pre stack: sender, salt, code_hash, 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
|
||||
// stack: sender, salt, code_hash, retdest
|
||||
// TODO: Replace with actual implementation.
|
||||
%pop6
|
||||
%pop3
|
||||
PUSH 123
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
@ -39,7 +39,7 @@ global buy_gas:
|
||||
// stack: gas_cost, retdest
|
||||
%mload_txn_field(@TXN_FIELD_ORIGIN)
|
||||
// stack: sender_addr, gas_cost, retdest
|
||||
%deduct_eth
|
||||
%deduct_eth // TODO: It should be transferred to coinbase instead?
|
||||
// stack: deduct_eth_status, retdest
|
||||
global txn_failure_insufficient_balance:
|
||||
%jumpi(panic)
|
||||
@ -114,69 +114,28 @@ global process_message_txn_return:
|
||||
JUMP
|
||||
|
||||
global process_message_txn_code_loaded:
|
||||
// stack: code_len, new_ctx, retdest
|
||||
POP
|
||||
// stack: code_size, new_ctx, retdest
|
||||
%set_new_ctx_code_size
|
||||
// stack: new_ctx, retdest
|
||||
|
||||
// Store the address in metadata.
|
||||
%mload_txn_field(@TXN_FIELD_TO)
|
||||
PUSH @CTX_METADATA_ADDRESS
|
||||
PUSH @SEGMENT_CONTEXT_METADATA
|
||||
DUP4 // new_ctx
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, retdest
|
||||
|
||||
// Store the caller in metadata.
|
||||
%mload_txn_field(@TXN_FIELD_ORIGIN)
|
||||
PUSH @CTX_METADATA_CALLER
|
||||
PUSH @SEGMENT_CONTEXT_METADATA
|
||||
DUP4 // new_ctx
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, retdest
|
||||
|
||||
// Store the call value field in metadata.
|
||||
%mload_txn_field(@TXN_FIELD_VALUE)
|
||||
PUSH @CTX_METADATA_CALL_VALUE
|
||||
PUSH @SEGMENT_CONTEXT_METADATA
|
||||
DUP4 // new_ctx
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, retdest
|
||||
|
||||
// No need to write @CTX_METADATA_STATIC, because it's 0 which is the default.
|
||||
|
||||
// Store parent context in metadata.
|
||||
GET_CONTEXT
|
||||
PUSH @CTX_METADATA_PARENT_CONTEXT
|
||||
PUSH @SEGMENT_CONTEXT_METADATA
|
||||
DUP4 // new_ctx
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, retdest
|
||||
|
||||
// Store parent PC = process_message_txn_after_call.
|
||||
PUSH process_message_txn_after_call
|
||||
PUSH @CTX_METADATA_PARENT_PC
|
||||
PUSH @SEGMENT_CONTEXT_METADATA
|
||||
DUP4 // new_ctx
|
||||
MSTORE_GENERAL
|
||||
// stack: new_ctx, retdest
|
||||
|
||||
// Set the new context's gas limit.
|
||||
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
|
||||
PUSH @CTX_METADATA_GAS_LIMIT
|
||||
PUSH @SEGMENT_CONTEXT_METADATA
|
||||
DUP4 // new_ctx
|
||||
MSTORE_GENERAL
|
||||
// Each line in the block below does not change the stack.
|
||||
%mload_txn_field(@TXN_FIELD_TO) %set_new_ctx_addr
|
||||
%mload_txn_field(@TXN_FIELD_ORIGIN) %set_new_ctx_caller
|
||||
%mload_txn_field(@TXN_FIELD_VALUE) %set_new_ctx_value
|
||||
%set_new_ctx_parent_ctx
|
||||
%set_new_ctx_parent_pc(process_message_txn_after_call)
|
||||
%mload_txn_field(@TXN_FIELD_GAS_LIMIT) %set_new_ctx_gas_limit
|
||||
// stack: new_ctx, retdest
|
||||
|
||||
// TODO: Copy TXN_DATA to CALLDATA
|
||||
|
||||
// Now, switch to the new context and go to usermode with PC=0.
|
||||
SET_CONTEXT
|
||||
// stack: retdest
|
||||
PUSH 0 // jump dest
|
||||
EXIT_KERNEL
|
||||
%enter_new_ctx
|
||||
|
||||
global process_message_txn_after_call:
|
||||
// stack: success, retdest
|
||||
POP // Pop success for now. Will go into the receipt when we support that.
|
||||
// stack: success, leftover_gas, new_ctx, retdest
|
||||
POP // TODO: Success will go into the receipt when we support that.
|
||||
// stack: leftover_gas, new_ctx, retdest
|
||||
POP // TODO: Refund leftover gas.
|
||||
// stack: new_ctx, retdest
|
||||
POP
|
||||
JUMP
|
||||
|
||||
@ -13,24 +13,16 @@ global sys_sgt:
|
||||
PANIC
|
||||
global sys_sar:
|
||||
PANIC
|
||||
global sys_address:
|
||||
PANIC
|
||||
global sys_balance:
|
||||
PANIC
|
||||
global sys_origin:
|
||||
PANIC
|
||||
global sys_caller:
|
||||
PANIC
|
||||
global sys_callvalue:
|
||||
PANIC
|
||||
global sys_calldataload:
|
||||
PANIC
|
||||
global sys_calldatasize:
|
||||
PANIC
|
||||
global sys_calldatacopy:
|
||||
PANIC
|
||||
global sys_codesize:
|
||||
PANIC
|
||||
global sys_codecopy:
|
||||
PANIC
|
||||
global sys_gasprice:
|
||||
@ -70,12 +62,6 @@ global sys_selfbalance:
|
||||
PANIC
|
||||
global sys_basefee:
|
||||
PANIC
|
||||
global sys_msize:
|
||||
// stack: kexit_info
|
||||
%mload_context_metadata(@CTX_METADATA_MSIZE)
|
||||
// stack: msize, kexit_info
|
||||
SWAP1
|
||||
EXIT_KERNEL
|
||||
global sys_gas:
|
||||
// stack: kexit_info
|
||||
DUP1 %shr_const(192)
|
||||
@ -96,11 +82,3 @@ global sys_log3:
|
||||
PANIC
|
||||
global sys_log4:
|
||||
PANIC
|
||||
global sys_call:
|
||||
PANIC
|
||||
global sys_callcode:
|
||||
PANIC
|
||||
global sys_delegatecall:
|
||||
PANIC
|
||||
global sys_staticcall:
|
||||
PANIC
|
||||
|
||||
@ -3,36 +3,37 @@
|
||||
|
||||
global sys_stop:
|
||||
// stack: kexit_info
|
||||
%refund_leftover_gas
|
||||
// stack: (empty)
|
||||
%leftover_gas
|
||||
// stack: leftover_gas
|
||||
// TODO: Set parent context's CTX_METADATA_RETURNDATA_SIZE to 0.
|
||||
PUSH 1 // success
|
||||
%jump(terminate_common)
|
||||
|
||||
global sys_return:
|
||||
// stack: kexit_info
|
||||
%refund_leftover_gas
|
||||
// stack: (empty)
|
||||
%leftover_gas
|
||||
// stack: leftover_gas
|
||||
// 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)
|
||||
// TODO: Copy returned memory to parent context's RETURNDATA.
|
||||
PUSH 1 // success
|
||||
%jump(terminate_common)
|
||||
|
||||
global sys_selfdestruct:
|
||||
// stack: kexit_info
|
||||
%consume_gas_const(@GAS_SELFDESTRUCT)
|
||||
%refund_leftover_gas
|
||||
// stack: (empty)
|
||||
%leftover_gas
|
||||
// stack: leftover_gas
|
||||
// TODO: Destroy account.
|
||||
PUSH 1 // success
|
||||
%jump(terminate_common)
|
||||
|
||||
global sys_revert:
|
||||
// stack: kexit_info
|
||||
%refund_leftover_gas
|
||||
// stack: (empty)
|
||||
%leftover_gas
|
||||
// stack: leftover_gas
|
||||
// TODO: Revert state changes.
|
||||
// TODO: Set parent context's CTX_METADATA_RETURNDATA_SIZE.
|
||||
// TODO: Copy returned memory to parent context's RETURNDATA.
|
||||
PUSH 0 // success
|
||||
%jump(terminate_common)
|
||||
|
||||
@ -44,24 +45,36 @@ global sys_revert:
|
||||
// - the new stack size would be larger than 1024, or
|
||||
// - state modification is attempted during a static call
|
||||
global fault_exception:
|
||||
// stack: (empty)
|
||||
PUSH 0 // leftover_gas
|
||||
// TODO: Revert state changes.
|
||||
// TODO: Set parent context's CTX_METADATA_RETURNDATA_SIZE to 0.
|
||||
PUSH 0 // success
|
||||
%jump(terminate_common)
|
||||
|
||||
terminate_common:
|
||||
// stack: success
|
||||
global terminate_common:
|
||||
// stack: success, leftover_gas
|
||||
// TODO: Panic if we exceeded our gas limit?
|
||||
|
||||
// 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
|
||||
// stack: 0, success, leftover_gas
|
||||
%mstore_kernel_general
|
||||
// stack: leftover_gas
|
||||
|
||||
// Similarly, we write leftover_gas to SEGMENT_KERNEL_GENERAL[1] so that
|
||||
// we can later read it after switching to the parent context.
|
||||
PUSH 1
|
||||
// stack: 1, leftover_gas
|
||||
%mstore_kernel_general
|
||||
// stack: (empty)
|
||||
|
||||
// Similarly, we write the parent PC to SEGMENT_KERNEL_GENERAL[1] so that
|
||||
// Similarly, we write the parent PC to SEGMENT_KERNEL_GENERAL[2] so that
|
||||
// we can later read it after switching to the parent context.
|
||||
%mload_context_metadata(@CTX_METADATA_PARENT_PC)
|
||||
PUSH 1
|
||||
PUSH 2
|
||||
%mstore_kernel(@SEGMENT_KERNEL_GENERAL)
|
||||
// stack: (empty)
|
||||
|
||||
@ -70,20 +83,19 @@ terminate_common:
|
||||
SET_CONTEXT
|
||||
// stack: (empty)
|
||||
|
||||
// Load the success flag and parent PC that we stored in SEGMENT_KERNEL_GENERAL.
|
||||
PUSH 0 %mload_kernel_general
|
||||
PUSH 1 %mload_kernel_general
|
||||
// Load the fields that we stored in SEGMENT_KERNEL_GENERAL.
|
||||
PUSH 1 %mload_kernel_general // leftover_gas
|
||||
PUSH 0 %mload_kernel_general // success
|
||||
PUSH 2 %mload_kernel_general // parent_pc
|
||||
|
||||
// stack: parent_pc, success
|
||||
// stack: parent_pc, success, leftover_gas
|
||||
JUMP
|
||||
|
||||
%macro refund_leftover_gas
|
||||
%macro leftover_gas
|
||||
// stack: kexit_info
|
||||
%shr_const(192)
|
||||
// stack: gas_used
|
||||
%mload_context_metadata(@CTX_METADATA_GAS_LIMIT)
|
||||
SUB
|
||||
// stack: leftover_gas
|
||||
POP // TODO: Refund to caller.
|
||||
// stack: (empty)
|
||||
%endmacro
|
||||
|
||||
@ -6,7 +6,7 @@ global main:
|
||||
PUSH hash_initial_tries
|
||||
%jump(load_all_mpts)
|
||||
|
||||
hash_initial_tries:
|
||||
global hash_initial_tries:
|
||||
%mpt_hash_state_trie %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_DIGEST_BEFORE)
|
||||
%mpt_hash_txn_trie %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_DIGEST_BEFORE)
|
||||
%mpt_hash_receipt_trie %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_DIGEST_BEFORE)
|
||||
|
||||
@ -38,18 +38,57 @@
|
||||
%mload_context_metadata(@CTX_METADATA_ADDRESS)
|
||||
%endmacro
|
||||
|
||||
%macro sender
|
||||
global sys_address:
|
||||
// stack: kexit_info
|
||||
%address
|
||||
// stack: address, kexit_info
|
||||
SWAP1
|
||||
EXIT_KERNEL
|
||||
|
||||
%macro caller
|
||||
%mload_context_metadata(@CTX_METADATA_CALLER)
|
||||
%endmacro
|
||||
|
||||
global sys_caller:
|
||||
// stack: kexit_info
|
||||
%caller
|
||||
// stack: caller, kexit_info
|
||||
SWAP1
|
||||
EXIT_KERNEL
|
||||
|
||||
%macro callvalue
|
||||
%mload_context_metadata(@CTX_METADATA_CALL_VALUE)
|
||||
%endmacro
|
||||
|
||||
%macro codesize
|
||||
%mload_context_metadata(@CTX_METADATA_CODE_SIZE)
|
||||
%endmacro
|
||||
|
||||
global sys_codesize:
|
||||
// stack: kexit_info
|
||||
%codesize
|
||||
// stack: codesize, kexit_info
|
||||
SWAP1
|
||||
EXIT_KERNEL
|
||||
|
||||
global sys_callvalue:
|
||||
// stack: kexit_info
|
||||
%callvalue
|
||||
// stack: callvalue, kexit_info
|
||||
SWAP1
|
||||
EXIT_KERNEL
|
||||
|
||||
%macro msize
|
||||
%mload_context_metadata(@CTX_METADATA_MSIZE)
|
||||
%endmacro
|
||||
|
||||
global sys_msize:
|
||||
// stack: kexit_info
|
||||
%msize
|
||||
// stack: msize, kexit_info
|
||||
SWAP1
|
||||
EXIT_KERNEL
|
||||
|
||||
%macro update_msize
|
||||
// stack: offset
|
||||
%add_const(32)
|
||||
@ -64,4 +103,3 @@
|
||||
// stack: new_msize
|
||||
%mstore_context_metadata(@CTX_METADATA_MSIZE)
|
||||
%endmacro
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use std::time::Instant;
|
||||
|
||||
use ethereum_types::U256;
|
||||
use itertools::{izip, Itertools};
|
||||
@ -111,6 +112,7 @@ pub(crate) fn assemble(
|
||||
let mut local_labels = Vec::with_capacity(files.len());
|
||||
let mut macro_counter = 0;
|
||||
for file in files {
|
||||
let start = Instant::now();
|
||||
let mut file = file.body;
|
||||
file = expand_macros(file, ¯os, &mut macro_counter);
|
||||
file = inline_constants(file, &constants);
|
||||
@ -125,6 +127,7 @@ pub(crate) fn assemble(
|
||||
&mut prover_inputs,
|
||||
));
|
||||
expanded_files.push(file);
|
||||
debug!("Expanding file took {:?}", start.elapsed());
|
||||
}
|
||||
let mut code = vec![];
|
||||
for (file, locals) in izip!(expanded_files, local_labels) {
|
||||
@ -134,6 +137,7 @@ pub(crate) fn assemble(
|
||||
debug!("Assembled file size: {} bytes", file_len);
|
||||
}
|
||||
assert_eq!(code.len(), offset, "Code length doesn't match offset.");
|
||||
debug!("Total kernel size: {} bytes", code.len());
|
||||
Kernel::new(code, global_labels, prover_inputs)
|
||||
}
|
||||
|
||||
|
||||
@ -28,23 +28,12 @@ fn test_get_create2_address() -> Result<()> {
|
||||
|
||||
// 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 code_hash = 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 initial_stack = vec![retaddr, code_hash, salt, sender];
|
||||
let mut interpreter = Interpreter::new_with_kernel(get_create2_address, initial_stack);
|
||||
interpreter.run()?;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user