Journal of state changes + state reversion (#1028)

* Add segments and global metadata

* Add journal asm files

* Start revert

* Revert access lists

* Revert balance transfer

* Revert code change

* Revert nonce change

* Revert storage change

* Checkpoints

* Add some journal entries

* Add some journal entries

* Add some journal entries

* Fix revert

* Checkpoint in sys_call

* Minor

* PR feedback

* More checkpoints

* Fix checkpoint check

* Minor

* Checkpoints in precompiles

* Storage change checkpoint

* Add touched addresses

* Add touched addresses revert

* Add touched addresses journal events

* Delete all empty touch addresses

* Implement selfdestruct

* Update aggregator.rs
This commit is contained in:
wborgeaud 2023-05-12 13:04:46 +02:00 committed by GitHub
parent 74ba303255
commit bfd6834dc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 893 additions and 17 deletions

View File

@ -42,6 +42,7 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/core/util.asm"),
include_str!("asm/core/access_lists.asm"),
include_str!("asm/core/selfdestruct_list.asm"),
include_str!("asm/core/touched_addresses.asm"),
include_str!("asm/core/precompiles/main.asm"),
include_str!("asm/core/precompiles/ecrec.asm"),
include_str!("asm/core/precompiles/sha256.asm"),
@ -134,6 +135,16 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/rlp/read_to_memory.asm"),
include_str!("asm/shift.asm"),
include_str!("asm/signed.asm"),
include_str!("asm/journal/journal.asm"),
include_str!("asm/journal/account_loaded.asm"),
include_str!("asm/journal/account_destroyed.asm"),
include_str!("asm/journal/account_touched.asm"),
include_str!("asm/journal/balance_transfer.asm"),
include_str!("asm/journal/nonce_change.asm"),
include_str!("asm/journal/storage_change.asm"),
include_str!("asm/journal/storage_loaded.asm"),
include_str!("asm/journal/code_change.asm"),
include_str!("asm/journal/revert.asm"),
include_str!("asm/transactions/common_decoding.asm"),
include_str!("asm/transactions/router.asm"),
include_str!("asm/transactions/type_0.asm"),

View File

@ -41,6 +41,7 @@ insert_accessed_addresses_loop:
insert_address:
%stack (i, len, addr, retdest) -> (i, addr, len, retdest)
DUP2 %journal_add_account_loaded // Add a journal entry for the loaded account.
%mstore_kernel(@SEGMENT_ACCESSED_ADDRESSES) // Store new address at the end of the array.
// stack: len, retdest
%increment
@ -52,6 +53,35 @@ insert_accessed_addresses_found:
%stack (i, len, addr, retdest) -> (retdest, 0) // Return 0 to indicate that the address was already present.
JUMP
/// Remove the address from the access list.
/// Panics if the address is not in the access list.
global remove_accessed_addresses:
// stack: addr, retdest
%mload_global_metadata(@GLOBAL_METADATA_ACCESSED_ADDRESSES_LEN)
// stack: len, addr, retdest
PUSH 0
remove_accessed_addresses_loop:
%stack (i, len, addr, retdest) -> (i, len, i, len, addr, retdest)
EQ %jumpi(panic)
// stack: i, len, addr, retdest
DUP1 %mload_kernel(@SEGMENT_ACCESSED_ADDRESSES)
// stack: loaded_addr, i, len, addr, retdest
DUP4
// stack: addr, loaded_addr, i, len, addr, retdest
EQ %jumpi(remove_accessed_addresses_found)
// stack: i, len, addr, retdest
%increment
%jump(remove_accessed_addresses_loop)
remove_accessed_addresses_found:
%stack (i, len, addr, retdest) -> (len, 1, i, retdest)
SUB DUP1 %mstore_global_metadata(@GLOBAL_METADATA_ACCESSED_ADDRESSES_LEN) // Decrement the access list length.
// stack: len-1, i, retdest
%mload_kernel(@SEGMENT_ACCESSED_ADDRESSES) // Load the last address in the access list.
// stack: last_addr, i, retdest
SWAP1
%mstore_kernel(@SEGMENT_ACCESSED_ADDRESSES) // Store the last address at the position of the removed address.
JUMP
%macro insert_accessed_storage_keys
%stack (addr, key, value) -> (addr, key, value, %%after)
@ -87,6 +117,8 @@ insert_accessed_storage_keys_loop:
%jump(insert_accessed_storage_keys_loop)
insert_storage_key:
// stack: i, len, addr, key, value, retdest
DUP4 DUP4 %journal_add_storage_loaded // Add a journal entry for the loaded storage key.
// stack: i, len, addr, key, value, retdest
DUP1 %increment
DUP1 %increment
@ -106,3 +138,46 @@ insert_accessed_storage_keys_found:
%mload_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
%stack (original_value, len, addr, key, value, retdest) -> (retdest, 0, original_value) // Return 0 to indicate that the storage key was already present.
JUMP
/// Remove the storage key and its value from the access list.
/// Panics if the key is not in the list.
global remove_accessed_storage_keys:
// stack: addr, key, retdest
%mload_global_metadata(@GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN)
// stack: len, addr, key, retdest
PUSH 0
remove_accessed_storage_keys_loop:
%stack (i, len, addr, key, retdest) -> (i, len, i, len, addr, key, retdest)
EQ %jumpi(panic)
// stack: i, len, addr, key, retdest
DUP1 %increment %mload_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
// stack: loaded_key, i, len, addr, key, retdest
DUP2 %mload_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
// stack: loaded_addr, loaded_key, i, len, addr, key, retdest
DUP5 EQ
// stack: loaded_addr==addr, loaded_key, i, len, addr, key, retdest
SWAP1 DUP6 EQ
// stack: loaded_key==key, loaded_addr==addr, i, len, addr, key, retdest
MUL // AND
%jumpi(remove_accessed_storage_keys_found)
// stack: i, len, addr, key, retdest
%add_const(3)
%jump(remove_accessed_storage_keys_loop)
remove_accessed_storage_keys_found:
%stack (i, len, addr, key, retdest) -> (len, 3, i, retdest)
SUB DUP1 %mstore_global_metadata(@GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN) // Decrease the access list length.
// stack: len-3, i, retdest
DUP1 %add_const(2) %mload_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
// stack: last_value, len-3, i, retdest
DUP2 %add_const(1) %mload_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
// stack: last_key, last_value, len-3, i, retdest
DUP3 %mload_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
// stack: last_addr, last_key, last_value, len-3, i, retdest
DUP5 %mstore_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS) // Move the last tuple to the position of the removed tuple.
// stack: last_key, last_value, len-3, i, retdest
DUP4 %add_const(1) %mstore_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
// stack: last_value, len-3, i, retdest
DUP3 %add_const(2) %mstore_kernel(@SEGMENT_ACCESSED_STORAGE_KEYS)
// stack: len-3, i, retdest
%pop2 JUMP

View File

@ -11,6 +11,8 @@ global sys_call:
MUL // Cheaper than AND
%jumpi(fault_exception)
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
%stack (kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size) ->
(args_size, args_offset, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size)
%checked_mem_expansion
@ -21,6 +23,7 @@ global sys_call:
SWAP2
// stack: address, gas, kexit_info, value, args_offset, args_size, ret_offset, ret_size
%u256_to_addr // Truncate to 160 bits
DUP1 %insert_touched_addresses
DUP1 %insert_accessed_addresses
%call_charge_gas(1, 1)
@ -34,6 +37,7 @@ global sys_call:
%copy_mem_to_calldata
// stack: new_ctx, kexit_info, callgas, address, value, args_offset, args_size, ret_offset, ret_size
DUP5 DUP5 %address %transfer_eth %jumpi(panic) // TODO: Fix this panic.
DUP5 DUP5 %address %journal_add_balance_transfer
DUP3 %set_new_ctx_gas_limit
%set_new_ctx_parent_pc(after_call_instruction)
DUP9 DUP9 DUP4 DUP4 DUP8 // Duplicate address, new_ctx, kexit_info, ret_offset, and ret_size.
@ -55,6 +59,8 @@ global sys_call:
// 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 sys_callcode:
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size
%stack (kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size) ->
(args_size, args_offset, kexit_info, gas, address, value, args_offset, args_size, ret_offset, ret_size)
@ -66,6 +72,7 @@ global sys_callcode:
SWAP2
// stack: address, gas, kexit_info, value, args_offset, args_size, ret_offset, ret_size
%u256_to_addr // Truncate to 160 bits
DUP1 %insert_touched_addresses
DUP1 %insert_accessed_addresses
%call_charge_gas(1, 0)
@ -103,6 +110,8 @@ global sys_callcode:
// are CREATE, CREATE2, LOG0, LOG1, LOG2, LOG3, LOG4, SSTORE, SELFDESTRUCT and
// CALL if the value sent is not 0.
global sys_staticcall:
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size
%stack (kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size) ->
(args_size, args_offset, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size)
@ -114,6 +123,7 @@ global sys_staticcall:
SWAP2
// stack: address, gas, kexit_info, args_offset, args_size, ret_offset, ret_size
%u256_to_addr // Truncate to 160 bits
DUP1 %insert_touched_addresses
DUP1 %insert_accessed_addresses
// Add a value of 0 to the stack. Slightly inefficient but that way we can reuse %call_charge_gas.
@ -151,6 +161,8 @@ global sys_staticcall:
// given account. In particular the storage, the current sender and the current
// value remain the same.
global sys_delegatecall:
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size
%stack (kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size) ->
(args_size, args_offset, kexit_info, gas, address, args_offset, args_size, ret_offset, ret_size)
@ -162,6 +174,7 @@ global sys_delegatecall:
SWAP2
// stack: address, gas, kexit_info, args_offset, args_size, ret_offset, ret_size
%u256_to_addr // Truncate to 160 bits
DUP1 %insert_touched_addresses
DUP1 %insert_accessed_addresses
// Add a value of 0 to the stack. Slightly inefficient but that way we can reuse %call_charge_gas.
@ -197,6 +210,8 @@ global sys_delegatecall:
// 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
DUP1 ISZERO %jumpi(after_call_instruction_failed)
after_call_instruction_contd:
SWAP3
// stack: kexit_info, leftover_gas, new_ctx, success, ret_offset, ret_size
// Add the leftover gas into the appropriate bits of kexit_info.
@ -207,6 +222,11 @@ global after_call_instruction:
%copy_returndata_to_mem
EXIT_KERNEL
after_call_instruction_failed:
// stack: success, leftover_gas, new_ctx, kexit_info, ret_offset, ret_size
%mload_context_metadata(@CTX_METADATA_CHECKPOINT) %revert_checkpoint
%jump(after_call_instruction_contd)
// 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
@ -295,6 +315,7 @@ global after_call_instruction:
// Switch to the new context and go to usermode with PC=0.
DUP1 // new_ctx
SET_CONTEXT
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
PUSH 0 // jump dest
EXIT_KERNEL
// (Old context) stack: new_ctx

View File

@ -91,6 +91,7 @@ global create_common:
// stack: status, address, value, code_offset, code_len, kexit_info
%jumpi(fault_exception)
// stack: address, value, code_offset, code_len, kexit_info
DUP2 DUP2 %address %journal_add_balance_transfer // Add journal entry for the balance transfer.
%create_context
// stack: new_ctx, address, value, code_offset, code_len, kexit_info
@ -192,10 +193,15 @@ after_constructor:
// TODO: Should it be copy-on-write (with make_account_copy) instead of mutating the trie?
global set_codehash:
// stack: addr, codehash, retdest
%mpt_read_state_trie
// stack: account_ptr, codehash, retdest
DUP1 %insert_touched_addresses
DUP1 %mpt_read_state_trie
// stack: account_ptr, addr, codehash, retdest
%add_const(3)
// stack: codehash_ptr, codehash, retdest
// stack: codehash_ptr, addr, codehash, retdest
DUP1 %mload_trie_data
// stack: prev_codehash, codehash_ptr, addr, codehash, retdest
DUP3 %journal_add_code_change // Add the code change to the journal.
%stack (codehash_ptr, addr, codehash) -> (codehash_ptr, codehash)
%mstore_trie_data
// stack: retdest
JUMP

View File

@ -3,6 +3,7 @@
// Post stack: status
%macro create_contract_account
// stack: value, address
DUP2 %insert_touched_addresses
DUP2 %mpt_read_state_trie
// stack: existing_account_ptr, value, address
// If the account doesn't exist, there's no need to check its balance or nonce,
@ -23,6 +24,7 @@
// Write the new account's data to MPT data, and get a pointer to it.
%get_trie_data_size
// stack: account_ptr, new_acct_value, address
PUSH 0 DUP4 %journal_add_nonce_change
PUSH 1 %append_to_trie_data // nonce = 1
// stack: account_ptr, new_acct_value, address
SWAP1 %append_to_trie_data // balance = new_acct_value

View File

@ -22,17 +22,21 @@ global nonce:
// Increment the given account's nonce. Assumes the account already exists; panics otherwise.
global increment_nonce:
// stack: address, retdest
DUP1
%mpt_read_state_trie
// stack: account_ptr, retdest
// stack: account_ptr, address, retdest
DUP1 ISZERO %jumpi(increment_nonce_no_such_account)
// stack: nonce_ptr, retdest
// stack: nonce_ptr, address, retdest
DUP1 %mload_trie_data
// stack: nonce, nonce_ptr, retdest
// stack: nonce, nonce_ptr, address, retdest
DUP1 DUP4 %journal_add_nonce_change
// stack: nonce, nonce_ptr, address, retdest
%increment
SWAP1
// stack: nonce_ptr, nonce', retdest
// stack: nonce_ptr, nonce', address, retdest
%mstore_trie_data
// stack: retdest
// stack: address, retdest
POP
JUMP
global increment_nonce_no_such_account:
PANIC

View File

@ -4,6 +4,7 @@ global precompile_blake2_f:
// stack: new_ctx, (old stack)
DUP1
SET_CONTEXT
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: (empty)
PUSH 0x100000000 // = 2^32 (is_kernel = true)
// stack: kexit_info

View File

@ -4,6 +4,7 @@ global precompile_bn_add:
// stack: new_ctx, (old stack)
DUP1
SET_CONTEXT
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: (empty)
PUSH 0x100000000 // = 2^32 (is_kernel = true)
// stack: kexit_info

View File

@ -4,6 +4,7 @@ global precompile_bn_mul:
// stack: new_ctx, (old stack)
DUP1
SET_CONTEXT
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: (empty)
PUSH 0x100000000 // = 2^32 (is_kernel = true)
// stack: kexit_info

View File

@ -4,6 +4,7 @@ global precompile_ecrec:
// stack: new_ctx, (old stack)
DUP1
SET_CONTEXT
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: (empty)
PUSH 0x100000000 // = 2^32 (is_kernel = true)
// stack: kexit_info

View File

@ -133,6 +133,7 @@ global precompile_expmod:
// stack: new_ctx, (old stack)
DUP1
SET_CONTEXT
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: (empty)
PUSH 0x100000000 // = 2^32 (is_kernel = true)
// stack: kexit_info

View File

@ -4,6 +4,7 @@ global precompile_id:
// stack: new_ctx, (old stack)
DUP1
SET_CONTEXT
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: (empty)
PUSH 0x100000000 // = 2^32 (is_kernel = true)
// stack: kexit_info

View File

@ -4,6 +4,7 @@ global precompile_rip160:
// stack: new_ctx, (old stack)
DUP1
SET_CONTEXT
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: (empty)
PUSH 0x100000000 // = 2^32 (is_kernel = true)
// stack: kexit_info

View File

@ -4,6 +4,7 @@ global precompile_sha256:
// stack: new_ctx, (old stack)
DUP1
SET_CONTEXT
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: (empty)
PUSH 0x100000000 // = 2^32 (is_kernel = true)
// stack: kexit_info

View File

@ -4,6 +4,7 @@ global precompile_snarkv:
// stack: new_ctx, (old stack)
DUP1
SET_CONTEXT
%checkpoint %mstore_context_metadata(@CTX_METADATA_CHECKPOINT) // Checkpoint and store it in context metadata.
// stack: (empty)
PUSH 0x100000000 // = 2^32 (is_kernel = true)
// stack: kexit_info

View File

@ -174,6 +174,8 @@ global process_contract_creation_txn_after_constructor:
// stack: leftover_gas, new_ctx, address, retdest
%pay_coinbase_and_refund_sender
// TODO: Delete accounts in self-destruct list and empty touched addresses.
%delete_all_touched_addresses
%delete_all_selfdestructed_addresses
// stack: new_ctx, address, retdest
POP
POP
@ -265,6 +267,8 @@ global process_message_txn_after_call:
// stack: leftover_gas, new_ctx, retdest
%pay_coinbase_and_refund_sender
// TODO: Delete accounts in self-destruct list and empty touched addresses.
%delete_all_touched_addresses
%delete_all_selfdestructed_addresses
// stack: new_ctx, retdest
POP
JUMP

View File

@ -1,5 +1,6 @@
/// Self-destruct list.
/// Implemented as an append-only array, with the length stored in the global metadata.
/// Implemented as an array, with the length stored in the global metadata.
/// Note: This array allows duplicates.
%macro insert_selfdestruct_list
// stack: addr
@ -10,3 +11,61 @@
%increment
%mstore_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN) // Store new length.
%endmacro
/// Remove one occurrence of the address from the list.
/// Panics if the address is not in the list.
global remove_selfdestruct_list:
// stack: addr, retdest
%mload_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN)
// stack: len, addr, retdest
PUSH 0
remove_selfdestruct_list_loop:
%stack (i, len, addr, retdest) -> (i, len, i, len, addr, retdest)
EQ %jumpi(panic)
// stack: i, len, addr, retdest
DUP1 %mload_kernel(@SEGMENT_SELFDESTRUCT_LIST)
// stack: loaded_addr, i, len, addr, retdest
DUP4
// stack: addr, loaded_addr, i, len, addr, retdest
EQ %jumpi(remove_selfdestruct_list_found)
// stack: i, len, addr, retdest
%increment
%jump(remove_selfdestruct_list_loop)
remove_selfdestruct_list_found:
%stack (i, len, addr, retdest) -> (len, 1, i, retdest)
SUB DUP1 %mstore_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN) // Decrement the list length.
// stack: len-1, i, retdest
%mload_kernel(@SEGMENT_SELFDESTRUCT_LIST) // Load the last address in the list.
// stack: last_addr, i, retdest
SWAP1
%mstore_kernel(@SEGMENT_SELFDESTRUCT_LIST) // Store the last address at the position of the removed address.
JUMP
global delete_all_selfdestructed_addresses:
// stack: retdest
%mload_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN)
// stack: len, retdest
PUSH 0
delete_all_selfdestructed_addresses_loop:
// stack: i, len, retdest
DUP2 DUP2 EQ %jumpi(delete_all_selfdestructed_addresses_done)
// stack: i, len, retdest
DUP1 %mload_kernel(@SEGMENT_SELFDESTRUCT_LIST)
// stack: loaded_addr, i, len, retdest
DUP1 %is_non_existent ISZERO %jumpi(bingo)
// stack: loaded_addr, i, len, retdest
POP %increment %jump(delete_all_selfdestructed_addresses_loop)
bingo:
// stack: loaded_addr, i, len, retdest
%delete_account
%increment %jump(delete_all_selfdestructed_addresses_loop)
delete_all_selfdestructed_addresses_done:
// stack: i, len, retdest
%pop2 JUMP
%macro delete_all_selfdestructed_addresses
%stack () -> (%%after)
%jump(delete_all_selfdestructed_addresses)
%%after:
// stack: (empty)
%endmacro

View File

@ -85,9 +85,13 @@ global sys_selfdestruct:
// stack: balance_ptr, 0, balance, address, recipient, kexit_info
%mstore_trie_data // TODO: This should be a copy-on-write operation.
%stack (balance, address, recipient, kexit_info) ->
(address, recipient, balance, address, recipient, recipient, balance, kexit_info)
%journal_add_account_destroyed
// If the recipient is the same as the address, then we're done.
// Otherwise, send the balance to the recipient.
%stack (balance, address, recipient, kexit_info) -> (address, recipient, recipient, balance, kexit_info)
// stack: address, recipient, recipient, balance, kexit_info
EQ %jumpi(sys_selfdestruct_same_addr)
// stack: recipient, balance, kexit_info
%add_eth
@ -148,8 +152,8 @@ sys_revert_finish:
// - state modification is attempted during a static call
global fault_exception:
// stack: (empty)
%mload_context_metadata(@CTX_METADATA_CHECKPOINT) %revert_checkpoint
PUSH 0 // leftover_gas
// TODO: Revert state changes.
// Set the parent context's return data size to 0.
%mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 0)
PUSH 0 // success

View File

@ -0,0 +1,103 @@
%macro insert_touched_addresses
%stack (addr) -> (addr, %%after)
%jump(insert_touched_addresses)
%%after:
// stack: (empty)
%endmacro
%macro insert_touched_addresses_no_return
%insert_touched_addresses
POP
%endmacro
/// Inserts the address into the list if it is not already present.
global insert_touched_addresses:
// stack: addr, retdest
%mload_global_metadata(@GLOBAL_METADATA_TOUCHED_ADDRESSES_LEN)
// stack: len, addr, retdest
PUSH 0
insert_touched_addresses_loop:
%stack (i, len, addr, retdest) -> (i, len, i, len, addr, retdest)
EQ %jumpi(insert_address)
// stack: i, len, addr, retdest
DUP1 %mload_kernel(@SEGMENT_TOUCHED_ADDRESSES)
// stack: loaded_addr, i, len, addr, retdest
DUP4
// stack: addr, loaded_addr, i, len, addr, retdest
EQ %jumpi(insert_touched_addresses_found)
// stack: i, len, addr, retdest
%increment
%jump(insert_touched_addresses_loop)
insert_address:
%stack (i, len, addr, retdest) -> (i, addr, len, retdest)
DUP2 %journal_add_account_touched // Add a journal entry for the touched account.
%mstore_kernel(@SEGMENT_TOUCHED_ADDRESSES) // Store new address at the end of the array.
// stack: len, retdest
%increment
%mstore_global_metadata(@GLOBAL_METADATA_TOUCHED_ADDRESSES_LEN) // Store new length.
JUMP
insert_touched_addresses_found:
%stack (i, len, addr, retdest) -> (retdest)
JUMP
/// Remove the address from the list.
/// Panics if the address is not in the list.
/// TODO: Unused?
global remove_touched_addresses:
// stack: addr, retdest
%mload_global_metadata(@GLOBAL_METADATA_TOUCHED_ADDRESSES_LEN)
// stack: len, addr, retdest
PUSH 0
remove_touched_addresses_loop:
%stack (i, len, addr, retdest) -> (i, len, i, len, addr, retdest)
EQ %jumpi(panic)
// stack: i, len, addr, retdest
DUP1 %mload_kernel(@SEGMENT_TOUCHED_ADDRESSES)
// stack: loaded_addr, i, len, addr, retdest
DUP4
// stack: addr, loaded_addr, i, len, addr, retdest
EQ %jumpi(remove_touched_addresses_found)
// stack: i, len, addr, retdest
%increment
%jump(remove_touched_addresses_loop)
remove_touched_addresses_found:
%stack (i, len, addr, retdest) -> (len, 1, i, retdest)
SUB DUP1 %mstore_global_metadata(@GLOBAL_METADATA_TOUCHED_ADDRESSES_LEN) // Decrement the list length.
// stack: len-1, i, retdest
%mload_kernel(@SEGMENT_TOUCHED_ADDRESSES) // Load the last address in the list.
// stack: last_addr, i, retdest
SWAP1
%mstore_kernel(@SEGMENT_TOUCHED_ADDRESSES) // Store the last address at the position of the removed address.
JUMP
global delete_all_touched_addresses:
// stack: retdest
%mload_global_metadata(@GLOBAL_METADATA_TOUCHED_ADDRESSES_LEN)
// stack: len, retdest
PUSH 0
delete_all_touched_addresses_loop:
// stack: i, len, retdest
DUP2 DUP2 EQ %jumpi(delete_all_touched_addresses_done)
// stack: i, len, retdest
DUP1 %mload_kernel(@SEGMENT_TOUCHED_ADDRESSES)
// stack: loaded_addr, i, len, retdest
DUP1 %is_empty %jumpi(bingo)
// stack: loaded_addr, i, len, retdest
POP %increment %jump(delete_all_touched_addresses_loop)
bingo:
// stack: loaded_addr, i, len, retdest
%delete_account
%increment %jump(delete_all_touched_addresses_loop)
delete_all_touched_addresses_done:
// stack: i, len, retdest
%pop2 JUMP
%macro delete_all_touched_addresses
%stack () -> (%%after)
%jump(delete_all_touched_addresses)
%%after:
// stack: (empty)
%endmacro

View File

@ -29,6 +29,7 @@ global transfer_eth_failure:
// TODO: Should it be copy-on-write (with make_account_copy) instead of mutating the trie?
global deduct_eth:
// stack: addr, amount, retdest
DUP1 %insert_touched_addresses
%mpt_read_state_trie
// stack: account_ptr, amount, retdest
DUP1 ISZERO %jumpi(deduct_eth_no_such_account) // If the account pointer is null, return 1.
@ -65,6 +66,7 @@ global deduct_eth_insufficient_balance:
// TODO: Should it be copy-on-write (with make_account_copy) instead of mutating the trie?
global add_eth:
// stack: addr, amount, retdest
DUP1 %insert_touched_addresses
DUP1 %mpt_read_state_trie
// stack: account_ptr, addr, amount, retdest
DUP1 ISZERO %jumpi(add_eth_new_account) // If the account pointer is null, we need to create the account.

View File

@ -0,0 +1,18 @@
// struct AccountDestroyed { address, target, prev_balance }
%macro journal_add_account_destroyed
%journal_add_3(@JOURNAL_ENTRY_ACCOUNT_DESTROYED)
%endmacro
global revert_account_destroyed:
// stack: entry_type, ptr, retdest
POP
%journal_load_3
// stack: address, target, prev_balance, retdest
PUSH revert_account_destroyed_contd DUP2
%jump(remove_selfdestruct_list)
revert_account_destroyed_contd:
// stack: address, target, prev_balance, retdest
SWAP1 %transfer_eth %jumpi(panic)
JUMP

View File

@ -0,0 +1,12 @@
// struct AccountLoaded { address }
%macro journal_add_account_loaded
%journal_add_1(@JOURNAL_ENTRY_ACCOUNT_LOADED)
%endmacro
global revert_account_loaded:
// stack: entry_type, ptr, retdest
POP
%journal_load_1
// stack: address, retdest
%jump(remove_accessed_addresses)

View File

@ -0,0 +1,10 @@
// struct AccountTouched { address }
%macro journal_add_account_touched
%journal_add_1(@JOURNAL_ENTRY_ACCOUNT_TOUCHED)
%endmacro
// Note: We don't need to remove touched addresses. In fact doing so leads to bugs because of the way we load accounts in the MPT.
global revert_account_touched:
// stack: entry_type, ptr, retdest
%pop2 JUMP

View File

@ -0,0 +1,16 @@
// struct BalanceTransfer { from, to, balance }
%macro journal_add_balance_transfer
%journal_add_3(@JOURNAL_ENTRY_BALANCE_TRANSFER)
%endmacro
global revert_balance_transfer:
// stack: entry_type, ptr, retdest
POP
%journal_load_3
// stack: from, to, balance, retdest
SWAP1
// stack: to, from, balance, retdest
%transfer_eth
%jumpi(panic) // This should never happen.
JUMP

View File

@ -0,0 +1,17 @@
// struct CodeChange { address, prev_codehash }
%macro journal_add_code_change
%journal_add_2(@JOURNAL_ENTRY_CODE_CHANGE)
%endmacro
global revert_code_change:
// stack: ptr, retdest
%journal_load_2
// stack: address, prev_codehash, retdest
%mpt_read_state_trie
// stack: account_ptr, prev_codehash, retdest
%add_const(3)
// stack: codehash_ptr, prev_codehash, retdest
%mstore_trie_data
// stack: retdest
JUMP

View File

@ -0,0 +1,192 @@
%macro journal_size
%mload_global_metadata(@GLOBAL_METADATA_JOURNAL_LEN)
%endmacro
%macro mstore_journal
// stack: virtual, value
%mstore_kernel(@SEGMENT_JOURNAL)
// stack: (empty)
%endmacro
%macro mload_journal
// stack: virtual
%mload_kernel(@SEGMENT_JOURNAL)
// stack: value
%endmacro
%macro append_journal
// stack: pointer
%journal_size
// stack: journal_size, pointer
SWAP1 DUP2
// stack: journal_size, pointer, journal_size
%mstore_journal
// stack: journal_size
%increment
%mstore_global_metadata(@GLOBAL_METADATA_JOURNAL_LEN)
%endmacro
%macro journal_data_size
%mload_global_metadata(@GLOBAL_METADATA_JOURNAL_DATA_LEN)
%endmacro
%macro mstore_journal_data
// stack: virtual, value
%mstore_kernel(@SEGMENT_JOURNAL_DATA)
// stack: (empty)
%endmacro
%macro mload_journal_data
// stack: virtual
%mload_kernel(@SEGMENT_JOURNAL_DATA)
// stack: value
%endmacro
%macro append_journal_data
// stack: value
%journal_data_size
// stack: size, value
SWAP1 DUP2
// stack: size, value, size
%mstore_journal_data
// stack: size
%increment
%mstore_global_metadata(@GLOBAL_METADATA_JOURNAL_DATA_LEN)
%endmacro
%macro journal_add_1(type)
// stack: w
%journal_data_size
// stack: ptr, w
PUSH $type %append_journal_data
// stack: ptr, w
SWAP1
// stack: w, ptr
%append_journal_data
// stack: ptr
%append_journal
%endmacro
%macro journal_add_2(type)
// stack: w, x
%journal_data_size
// stack: ptr, w, x
PUSH $type %append_journal_data
// stack: ptr, w, x
SWAP1 %append_journal_data
// stack: ptr, x
SWAP1 %append_journal_data
// stack: ptr
%append_journal
%endmacro
%macro journal_add_3(type)
// stack: w, x, y
%journal_data_size
// stack: ptr, w, x, y
PUSH $type %append_journal_data
// stack: ptr, w, x, y
SWAP1 %append_journal_data
// stack: ptr, x, y
SWAP1 %append_journal_data
// stack: ptr, y
SWAP1 %append_journal_data
// stack: ptr
%append_journal
%endmacro
%macro journal_add_4(type)
// stack: w, x, y, z
%journal_data_size
// stack: ptr, w, x, y, z
PUSH $type %append_journal_data
// stack: ptr, w, x, y, z
SWAP1 %append_journal_data
// stack: ptr, x, y, z
SWAP1 %append_journal_data
// stack: ptr, y, z
SWAP1 %append_journal_data
// stack: ptr, z
SWAP1 %append_journal_data
// stack: ptr
%append_journal
%endmacro
%macro journal_load_1
// ptr
%add_const(1)
%mload_journal_data
// w
%endmacro
%macro journal_load_2
// ptr
DUP1
%add_const(2)
%mload_journal_data
// x, ptr
SWAP1
%add_const(1)
%mload_journal_data
// w, x
%endmacro
%macro journal_load_3
// ptr
DUP1
%add_const(3)
%mload_journal_data
// y, ptr
SWAP1
DUP1
// ptr, ptr, y
%add_const(2)
%mload_journal_data
// x, ptr, y
SWAP1
%add_const(1)
%mload_journal_data
// w, x, y
%endmacro
%macro journal_load_4
// ptr
DUP1
%add_const(4)
%mload_journal_data
// z, ptr
SWAP1
DUP1
// ptr, ptr, z
%add_const(3)
%mload_journal_data
// y, ptr, z
SWAP1
DUP1
// ptr, ptr, y, z
%add_const(2)
%mload_journal_data
// x, ptr, y, z
SWAP1
%add_const(1)
%mload_journal_data
// w, x, y, z
%endmacro
%macro current_checkpoint
%mload_global_metadata(@GLOBAL_METADATA_CURRENT_CHECKPOINT)
%endmacro
%macro checkpoint
// stack: (empty)
%current_checkpoint
// stack: current_checkpoint
%journal_size
// stack: journal_size, current_checkpoint
DUP2 %mstore_kernel(@SEGMENT_JOURNAL_CHECKPOINTS)
// stack: current_checkpoint
DUP1 %increment
%mstore_global_metadata(@GLOBAL_METADATA_CURRENT_CHECKPOINT)
// stack: current_checkpoint
%endmacro

View File

@ -0,0 +1,17 @@
// struct NonceChange { address, prev_nonce }
%macro journal_add_nonce_change
%journal_add_2(@JOURNAL_ENTRY_NONCE_CHANGE)
%endmacro
global revert_nonce_change:
// stack: entry_type, ptr, retdest
POP
%journal_load_2
// stack: address, prev_nonce, retdest
%mpt_read_state_trie
// stack: nonce_ptr, prev_nonce retdest
%mstore_trie_data
// stack: retdest
JUMP

View File

@ -0,0 +1,84 @@
%macro revert
// stack: journal_size
%decrement
%stack (journal_size_m_1) -> (journal_size_m_1, %%after, journal_size_m_1)
%mload_journal
// stack: ptr, %%after, journal_size-1
DUP1 %mload_journal_data
// stack: entry_type, ptr, %%after, journal_size-1
DUP1 %eq_const(@JOURNAL_ENTRY_ACCOUNT_LOADED) %jumpi(revert_account_loaded)
DUP1 %eq_const(@JOURNAL_ENTRY_ACCOUNT_DESTROYED) %jumpi(revert_account_destroyed)
DUP1 %eq_const(@JOURNAL_ENTRY_ACCOUNT_TOUCHED) %jumpi(revert_account_touched)
DUP1 %eq_const(@JOURNAL_ENTRY_BALANCE_TRANSFER) %jumpi(revert_balance_transfer)
DUP1 %eq_const(@JOURNAL_ENTRY_NONCE_CHANGE) %jumpi(revert_nonce_change)
DUP1 %eq_const(@JOURNAL_ENTRY_STORAGE_CHANGE) %jumpi(revert_storage_change)
DUP1 %eq_const(@JOURNAL_ENTRY_STORAGE_LOADED) %jumpi(revert_storage_loaded)
%eq_const(@JOURNAL_ENTRY_CODE_CHANGE) %jumpi(revert_code_change)
PANIC // This should never happen.
%%after:
// stack: journal_size-1
%endmacro
global revert_batch:
// stack: target_size, retdest
%journal_size
// stack: journal_size, target_size, retdest
DUP2 DUP2 LT %jumpi(panic) // Sanity check to avoid infinite loop.
while_loop:
// stack: journal_size, target_size, retdest
DUP2 DUP2 EQ %jumpi(revert_batch_done)
// stack: journal_size, target_size, retdest
%revert
// stack: journal_size-1, target_size, retdest
%jump(while_loop)
revert_batch_done:
// stack: journal_size, target_size, retdest
%mstore_global_metadata(@GLOBAL_METADATA_JOURNAL_LEN)
POP JUMP
revert_one_checkpoint:
// stack: current_checkpoint, retdest
DUP1 ISZERO %jumpi(first_checkpoint)
// stack: current_checkpoint, retdest
%decrement
// stack: current_checkpoint-1, retdest
DUP1 %mload_kernel(@SEGMENT_JOURNAL_CHECKPOINTS)
// stack: target_size, current_checkpoints-1, retdest
%jump(do_revert)
first_checkpoint:
// stack: current_checkpoint, retdest
%decrement
// stack: current_checkpoint-1, retdest
PUSH 0
// stack: target_size, current_checkpoints-1, retdest
do_revert:
%stack (target_size, current_checkpoints_m_1, retdest) -> (target_size, after_revert, current_checkpoints_m_1, retdest)
%jump(revert_batch)
after_revert:
// stack: current_checkpoint-1, retdest
SWAP1 JUMP
global revert_checkpoint:
// stack: target_checkpoint, retdest
%current_checkpoint
// stack: current_checkpoint, target_checkpoint, retdest
DUP2 DUP2 LT %jumpi(panic) // Sanity check that current_cp >= target_cp. This should never happen.
while:
// stack: current_checkpoint, target_checkpoint, retdest
DUP2 DUP2 EQ %jumpi(revert_checkpoint_done)
%stack (current_checkpoint) -> (current_checkpoint, while)
%jump(revert_one_checkpoint)
revert_checkpoint_done:
// stack: current_checkpoint, target_checkpoint, retdest
POP
%mstore_global_metadata(@GLOBAL_METADATA_CURRENT_CHECKPOINT)
JUMP
%macro revert_checkpoint
%stack (target_checkpoint) -> (target_checkpoint, %%after)
%jump(revert_checkpoint)
%%after:
// stack: (empty)
%endmacro

View File

@ -0,0 +1,61 @@
// struct StorageChange { address, slot, prev_value }
%macro journal_add_storage_change
%journal_add_3(@JOURNAL_ENTRY_STORAGE_CHANGE)
%endmacro
global revert_storage_change:
// stack: entry_type, ptr, retdest
POP
%journal_load_3
// stack: address, slot, prev_value, retdest
DUP3 ISZERO %jumpi(delete)
// stack: address, slot, prev_value, retdest
SWAP1 %slot_to_storage_key
// stack: storage_key, address, prev_value, retdest
PUSH 64 // storage_key has 64 nibbles
// stack: 64, storage_key, address, prev_value, retdest
DUP3 %mpt_read_state_trie
DUP1 ISZERO %jumpi(panic)
// stack: account_ptr, 64, storage_key, address, prev_value, retdest
%add_const(2)
// stack: storage_root_ptr_ptr, 64, storage_key, address, prev_value, retdest
%mload_trie_data
%stack (storage_root_ptr, num_nibbles, storage_key, address, prev_value, retdest) ->
(storage_root_ptr, num_nibbles, storage_key, prev_value, new_storage_root, address, retdest)
%jump(mpt_insert)
delete:
// stack: address, slot, prev_value, retdest
SWAP2 POP
%stack (slot, address, retdest) -> (slot, new_storage_root, address, retdest)
%slot_to_storage_key
// stack: storage_key, new_storage_root, address, retdest
PUSH 64 // storage_key has 64 nibbles
// stack: 64, storage_key, new_storage_root, address, retdest
DUP4 %mpt_read_state_trie
DUP1 ISZERO %jumpi(panic)
// stack: account_ptr, 64, storage_key, new_storage_root, address, retdest
%add_const(2)
// stack: storage_root_ptr_ptr, 64, storage_key, new_storage_root, address, retdest
%mload_trie_data
// stack: storage_root_ptr, 64, storage_key, new_storage_root, address, retdest
%jump(mpt_delete)
new_storage_root:
// stack: new_storage_root_ptr, address, retdest
DUP2 %mpt_read_state_trie
// stack: old_account_ptr, new_storage_root_ptr, address, retdest
%make_account_copy
// stack: new_account_ptr, new_storage_root_ptr, address, retdest
// Update the copied account with our new storage root pointer.
%stack (new_account_ptr, new_storage_root_ptr) -> (new_account_ptr, new_storage_root_ptr, new_account_ptr)
%add_const(2)
// stack: new_account_storage_root_ptr_ptr, new_storage_root_ptr, new_account_ptr, address, retdest
%mstore_trie_data
// stack: new_account_ptr, address, retdest
DUP2 %addr_to_state_key
%stack (state_key, new_account_ptr, address, retdest) -> (state_key, new_account_ptr, retdest)
%jump(mpt_insert_state_trie)

View File

@ -0,0 +1,12 @@
// struct StorageLoaded { address, slot }
%macro journal_add_storage_loaded
%journal_add_2(@JOURNAL_ENTRY_STORAGE_LOADED)
%endmacro
global revert_storage_loaded:
// stack: entry_type, ptr, retdest
POP
%journal_load_2
// stack: address, slot, retdest
%jump(remove_accessed_storage_keys)

View File

@ -22,3 +22,24 @@ mpt_delete_leaf:
%pop4
PUSH 0 // empty node ptr
SWAP1 JUMP
global delete_account:
%stack (address, retdest) -> (address, delete_account_save, retdest)
%addr_to_state_key
// stack: key, delete_account_save, retdest
PUSH 64
// stack: 64, key, delete_account_save, retdest
%mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT)
// stack: state_root_prt, 64, key, delete_account_save, retdest
%jump(mpt_delete)
delete_account_save:
// stack: updated_state_root_ptr, retdest
%mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT)
JUMP
%macro delete_account
%stack (address) -> (address, %%after)
%jump(delete_account)
%%after:
// stack: (empty)
%endmacro

View File

@ -85,9 +85,13 @@ sstore_no_refund:
sstore_after_refund:
// stack: kexit_info, current_value, slot, value
// Check if `value` is equal to `current_value`, and if so exit the kernel early.
%stack (kexit_info, current_value, slot, value) -> (value, current_value, slot, value, kexit_info)
%stack (kexit_info, current_value, slot, value) -> (value, current_value, current_value, slot, value, kexit_info)
EQ %jumpi(sstore_noop)
// stack: current_value, slot, value, kexit_info
DUP2 %address %journal_add_storage_change
// stack: slot, value, kexit_info
// If the value is zero, delete the slot from the storage trie.
// stack: slot, value, kexit_info
DUP2 ISZERO %jumpi(sstore_delete)
@ -134,8 +138,8 @@ after_state_insert:
EXIT_KERNEL
sstore_noop:
// stack: slot, value, kexit_info
%pop2
// stack: current_value, slot, value, kexit_info
%pop3
EXIT_KERNEL
// Delete the slot from the storage trie.

View File

@ -28,10 +28,11 @@ pub(crate) enum ContextMetadata {
StackSize = 11,
/// The gas limit for this call (not the entire transaction).
GasLimit = 12,
Checkpoint = 13,
}
impl ContextMetadata {
pub(crate) const COUNT: usize = 13;
pub(crate) const COUNT: usize = 14;
pub(crate) fn all() -> [Self; Self::COUNT] {
[
@ -48,6 +49,7 @@ impl ContextMetadata {
Self::MemWords,
Self::StackSize,
Self::GasLimit,
Self::Checkpoint,
]
}
@ -67,6 +69,7 @@ impl ContextMetadata {
ContextMetadata::MemWords => "CTX_METADATA_MEM_WORDS",
ContextMetadata::StackSize => "CTX_METADATA_STACK_SIZE",
ContextMetadata::GasLimit => "CTX_METADATA_GAS_LIMIT",
ContextMetadata::Checkpoint => "CTX_METADATA_CHECKPOINT",
}
}
}

View File

@ -51,10 +51,18 @@ pub(crate) enum GlobalMetadata {
AccessedStorageKeysLen = 24,
/// Length of the self-destruct list.
SelfDestructListLen = 25,
/// Length of the journal.
JournalLen = 26,
/// Length of the `JournalData` segment.
JournalDataLen = 27,
/// Current checkpoint.
CurrentCheckpoint = 28,
TouchedAddressesLen = 29,
}
impl GlobalMetadata {
pub(crate) const COUNT: usize = 25;
pub(crate) const COUNT: usize = 29;
pub(crate) fn all() -> [Self; Self::COUNT] {
[
@ -83,6 +91,10 @@ impl GlobalMetadata {
Self::AccessedAddressesLen,
Self::AccessedStorageKeysLen,
Self::SelfDestructListLen,
Self::JournalLen,
Self::JournalDataLen,
Self::CurrentCheckpoint,
Self::TouchedAddressesLen,
]
}
@ -114,6 +126,10 @@ impl GlobalMetadata {
Self::AccessedAddressesLen => "GLOBAL_METADATA_ACCESSED_ADDRESSES_LEN",
Self::AccessedStorageKeysLen => "GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN",
Self::SelfDestructListLen => "GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN",
Self::JournalLen => "GLOBAL_METADATA_JOURNAL_LEN",
Self::JournalDataLen => "GLOBAL_METADATA_JOURNAL_DATA_LEN",
Self::CurrentCheckpoint => "GLOBAL_METADATA_CURRENT_CHECKPOINT",
Self::TouchedAddressesLen => "GLOBAL_METADATA_TOUCHED_ADDRESSES_LEN",
}
}
}

View File

@ -0,0 +1,43 @@
#[allow(dead_code)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub(crate) enum JournalEntry {
AccountLoaded = 0,
AccountDestroyed = 1,
AccountTouched = 2,
BalanceTransfer = 3,
NonceChange = 4,
StorageChange = 5,
StorageLoaded = 6,
CodeChange = 7,
}
impl JournalEntry {
pub(crate) const COUNT: usize = 8;
pub(crate) fn all() -> [Self; Self::COUNT] {
[
Self::AccountLoaded,
Self::AccountDestroyed,
Self::AccountTouched,
Self::BalanceTransfer,
Self::NonceChange,
Self::StorageChange,
Self::StorageLoaded,
Self::CodeChange,
]
}
/// The variable name that gets passed into kernel assembly code.
pub(crate) fn var_name(&self) -> &'static str {
match self {
Self::AccountLoaded => "JOURNAL_ENTRY_ACCOUNT_LOADED",
Self::AccountDestroyed => "JOURNAL_ENTRY_ACCOUNT_DESTROYED",
Self::AccountTouched => "JOURNAL_ENTRY_ACCOUNT_TOUCHED",
Self::BalanceTransfer => "JOURNAL_ENTRY_BALANCE_TRANSFER",
Self::NonceChange => "JOURNAL_ENTRY_NONCE_CHANGE",
Self::StorageChange => "JOURNAL_ENTRY_STORAGE_CHANGE",
Self::StorageLoaded => "JOURNAL_ENTRY_STORAGE_LOADED",
Self::CodeChange => "JOURNAL_ENTRY_CODE_CHANGE",
}
}
}

View File

@ -6,12 +6,14 @@ use hex_literal::hex;
use crate::cpu::decode::invalid_opcodes_user;
use crate::cpu::kernel::constants::context_metadata::ContextMetadata;
use crate::cpu::kernel::constants::global_metadata::GlobalMetadata;
use crate::cpu::kernel::constants::journal_entry::JournalEntry;
use crate::cpu::kernel::constants::trie_type::PartialTrieType;
use crate::cpu::kernel::constants::txn_fields::NormalizedTxnField;
use crate::memory::segments::Segment;
pub(crate) mod context_metadata;
pub(crate) mod global_metadata;
pub(crate) mod journal_entry;
pub(crate) mod trie_type;
pub(crate) mod txn_fields;
@ -67,6 +69,9 @@ pub fn evm_constants() -> HashMap<String, U256> {
for trie_type in PartialTrieType::all() {
c.insert(trie_type.var_name().into(), (trie_type as u32).into());
}
for entry in JournalEntry::all() {
c.insert(entry.var_name().into(), (entry as u32).into());
}
c.insert(
"INVALID_OPCODES_USER".into(),
U256::from_little_endian(&invalid_opcodes_user()),

View File

@ -50,10 +50,16 @@ pub enum Segment {
AccessedStorageKeys = 24,
/// List of addresses that have called SELFDESTRUCT in the current transaction.
SelfDestructList = 25,
/// Journal of state changes. List of pointers to `JournalData`. Length in `GlobalMetadata`.
Journal = 26,
JournalData = 27,
JournalCheckpoints = 28,
/// List of addresses that have been touched in the current transaction.
TouchedAddresses = 29,
}
impl Segment {
pub(crate) const COUNT: usize = 26;
pub(crate) const COUNT: usize = 30;
pub(crate) fn all() -> [Self; Self::COUNT] {
[
@ -83,6 +89,10 @@ impl Segment {
Self::AccessedAddresses,
Self::AccessedStorageKeys,
Self::SelfDestructList,
Self::Journal,
Self::JournalData,
Self::JournalCheckpoints,
Self::TouchedAddresses,
]
}
@ -115,6 +125,10 @@ impl Segment {
Segment::AccessedAddresses => "SEGMENT_ACCESSED_ADDRESSES",
Segment::AccessedStorageKeys => "SEGMENT_ACCESSED_STORAGE_KEYS",
Segment::SelfDestructList => "SEGMENT_SELFDESTRUCT_LIST",
Segment::Journal => "SEGMENT_JOURNAL",
Segment::JournalData => "SEGMENT_JOURNAL_DATA",
Segment::JournalCheckpoints => "SEGMENT_JOURNAL_CHECKPOINTS",
Segment::TouchedAddresses => "SEGMENT_TOUCHED_ADDRESSES",
}
}
@ -147,6 +161,10 @@ impl Segment {
Segment::AccessedAddresses => 256,
Segment::AccessedStorageKeys => 256,
Segment::SelfDestructList => 256,
Segment::Journal => 256,
Segment::JournalData => 256,
Segment::JournalCheckpoints => 256,
Segment::TouchedAddresses => 256,
}
}
}

View File

@ -90,6 +90,33 @@ where
Ok((proof, outputs))
}
/// Generate traces, then create all STARK proofs. Returns information about the post-state,
/// intended for debugging, in addition to the proof.
pub fn dont_prove_with_outputs<F, C, const D: usize>(
all_stark: &AllStark<F, D>,
config: &StarkConfig,
inputs: GenerationInputs,
timing: &mut TimingTree,
) -> Result<(PublicValues, GenerationOutputs)>
where
F: RichField + Extendable<D>,
C: GenericConfig<D, F = F>,
[(); ArithmeticStark::<F, D>::COLUMNS]:,
[(); CpuStark::<F, D>::COLUMNS]:,
[(); KeccakStark::<F, D>::COLUMNS]:,
[(); KeccakSpongeStark::<F, D>::COLUMNS]:,
[(); LogicStark::<F, D>::COLUMNS]:,
[(); MemoryStark::<F, D>::COLUMNS]:,
{
timed!(timing, "build kernel", Lazy::force(&KERNEL));
let (_traces, public_values, outputs) = timed!(
timing,
"generate all traces",
generate_traces(all_stark, inputs, config, timing)?
);
Ok((public_values, outputs))
}
/// Compute all STARK proofs.
pub(crate) fn prove_with_traces<F, C, const D: usize>(
all_stark: &AllStark<F, D>,