Skip to content

Commit

Permalink
Check the keys in the state trie correspond to accounts and storage l…
Browse files Browse the repository at this point in the history
…inked lists (#502)

* Check account linked list keys.

* Check storage keys

* Small improvement

* inline some macro calls (#528)

* Update Pre stack comments

---------

Co-authored-by: Robin Salen <[email protected]>
Co-authored-by: Robin Salen <[email protected]>
  • Loading branch information
3 people authored Aug 26, 2024
1 parent c5eaf71 commit 9529cf8
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 47 deletions.
11 changes: 9 additions & 2 deletions evm_arithmetization/src/cpu/kernel/asm/memory/syscalls.asm
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,15 @@ mcopy_empty:
// stack: new_dest_offset, copy_size, extra_size, segment, src_ctx, kexit_info, dest_offset, offset, size

GET_CONTEXT
%stack (context, new_dest_offset, copy_size, extra_size, segment, src_ctx, kexit_info, dest_offset, offset, size) ->
(src_ctx, segment, offset, @SEGMENT_MAIN_MEMORY, dest_offset, context, copy_size, codecopy_large_offset, copy_size, src_ctx, kexit_info, new_dest_offset, offset, extra_size)

// The following 4-lines block is the inlined version of
// %stack (context, new_dest_offset, copy_size, extra_size, segment, src_ctx, kexit_info, dest_offset, offset, size) ->
// (src_ctx, segment, offset, @SEGMENT_MAIN_MEMORY, dest_offset, context, copy_size, codecopy_large_offset, copy_size, src_ctx, kexit_info, new_dest_offset, offset, extra_size)
PUSH codecopy_large_offset
SWAP4 SWAP10 POP SWAP1 SWAP7
PUSH @SEGMENT_MAIN_MEMORY
DUP10 DUP5 SWAP7 DUP9

%build_address
SWAP3 %build_address
// stack: DST, SRC, copy_size, codecopy_large_offset, copy_size, src_ctx, kexit_info, new_dest_offset, offset, extra_size
Expand Down
199 changes: 154 additions & 45 deletions evm_arithmetization/src/cpu/kernel/asm/mpt/linked_list/initial_tries.asm
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
// for i =0..n_leaves. This is used to constraint the
// initial state and account tries payload pointers such that they are exactly
// those of the initial accounts and linked lists.
// Pre stack: node_ptr, account_ptr_ptr, storage_ptr_ptr, retdest
// Pre stack: node_ptr, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
// Post stack: account_ptr_ptr, storage_ptr_ptr
global mpt_set_payload:
// stack: node_ptr, account_ptr_ptr, storage_ptr_ptr, retdest
// stack: node_ptr, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
DUP1 %mload_trie_data
// stack: node_type, node_ptr, account_ptr_ptr, storage_ptr_ptr, retdest
// Increment node_ptr, so it points to the node payload instead of its type.
Expand All @@ -21,18 +21,25 @@ global mpt_set_payload:
PANIC

skip:
// stack: node_type, after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest
%stack (node_type, after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest) -> (retdest, account_ptr_ptr, storage_ptr_ptr)
// The following 2-lines block is the inlined version of
// %stack (node_type, after_node_type, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest) ->
// (retdest, account_ptr_ptr, storage_ptr_ptr)
POP POP SWAP3 POP
SWAP3 SWAP1 POP

JUMP

%macro mpt_set_payload
%stack(node_ptr, account_ptr_ptr, storage_ptr_ptr) -> (node_ptr, account_ptr_ptr, storage_ptr_ptr, %%after)
%stack (node_ptr, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles) ->
(node_ptr, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, %%after)
%jump(mpt_set_payload)
%%after:
%endmacro

%macro set_initial_tries
PUSH %%after
PUSH 0 // empty nibbles
PUSH 0 // num nibbles
PUSH @SEGMENT_STORAGE_LINKED_LIST
%add_const(8) // The first node is the special node, of size 5, so the first value is at position 5 + 3.
PUSH @SEGMENT_ACCOUNTS_LINKED_LIST
Expand All @@ -48,94 +55,174 @@ skip:
%mstore_global_metadata(@GLOBAL_METADATA_INITIAL_STORAGE_LINKED_LIST_LEN)
%endmacro

// Pre stack: node_ptr, storage_ptr_ptr, retdest
// Pre stack: node_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
// Post stack: storage_ptr_ptr
global mpt_set_storage_payload:
// stack: node_ptr, storage_ptr_ptr, retdest
// stack: node_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
DUP1 %mload_trie_data
// stack: node_type, node_ptr, storage_ptr_ptr, retdest
// stack: node_type, node_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
// Increment node_ptr, so it points to the node payload instead of its type.
SWAP1 %increment SWAP1
// stack: node_type, after_node_type, storage_ptr_ptr, retdest
// stack: node_type, after_node_type, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest

DUP1 %eq_const(@MPT_NODE_EMPTY) %jumpi(storage_skip)
DUP1 %eq_const(@MPT_NODE_BRANCH) %jumpi(set_payload_storage_branch)
DUP1 %eq_const(@MPT_NODE_EXTENSION) %jumpi(set_payload_storage_extension)
DUP1 %eq_const(@MPT_NODE_LEAF) %jumpi(set_payload_storage_leaf)

storage_skip:
// stack: node_type, after_node_type, storage_ptr_ptr, retdest
%stack (node_type, after_node_type, storage_ptr_ptr, retdest) -> (retdest, storage_ptr_ptr)
// stack: node_type, after_node_type, storage_ptr_ptr, num_nibbles, packedـnibbles, retdest
%stack (node_type, after_node_type, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest) -> (retdest, storage_ptr_ptr)
JUMP

%macro mpt_set_storage_payload
%stack(node_ptr, storage_ptr_ptr) -> (node_ptr, storage_ptr_ptr, %%after)
%stack(node_ptr, storage_ptr_ptr, num_nibbles, nibbles) -> (node_ptr, storage_ptr_ptr, num_nibbles, nibbles, %%after)
%jump(mpt_set_storage_payload)
%%after:
%endmacro

set_payload_branch:
// stack: node_type, after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest
// stack: node_type, after_node_type, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
POP

PUSH 0 // child counter
// Call mpt_set_payload on each child
%rep 16
%stack
(child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr) ->
(child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, child_ptr_ptr)
// stack: child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, child_ptr_ptr, retdest
// The following 4-lines block is the inlined version of
// %stack (i, child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles) ->
// (num_nibbles, packed_nibbles, 1, i, child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, i, num_nibbles, packed_nibbles, child_ptr_ptr)
SWAP2 DUP2 DUP4
PUSH 1
DUP9 DUP9 SWAP8
SWAP6 SWAP10 SWAP9

// We do not check the stored nibbles here, as the current value is not written yet.
%merge_nibbles
// stack: num_merged_nibbles, merged_nibbles, child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, i, num_nibbles, packed_nibbles, child_ptr_ptr

// The following line is the inlined version of
// %stack (num_merged_nibbles, merged_nibbles, child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr) ->
// (child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, num_merged_nibbles, merged_nibbles)
SWAP3 SWAP1 SWAP4 SWAP2

// stack: child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, num_merged_nibbles, merged_nibbles, i, num_nibbles, packed_nibbles, child_ptr_ptr, retdest
%mload_trie_data
// stack: child_ptr, account_ptr_ptr, storage_ptr_ptr, child_ptr_ptr, retdest
// stack: child_ptr, account_ptr_ptr, storage_ptr_ptr, num_merged_nibbles, merged_nibbles, i, num_nibbles, packed_nibbles, child_ptr_ptr, retdest
%mpt_set_payload
// stack: account_ptr_ptr', storage_ptr_ptr', child_ptr_ptr, retdest
// stack: account_ptr_ptr', storage_ptr_ptr', i, num_nibbles, packed_nibbles, child_ptr_ptr, retdest
// The following line is the inlined version of
// %stack (account_ptr_ptr_p, storage_ptr_ptr_p, i, num_nibbles, packed_nibbles, child_ptr_ptr) ->
// (child_ptr_ptr, i, account_ptr_ptr_p, storage_ptr_ptr_p, num_nibbles, packed_nibbles)
SWAP2 SWAP1 SWAP3 SWAP4 SWAP5

// stack: (child_ptr_ptr, i, account_ptr_ptr_p, storage_ptr_ptr_p, num_nibbles, packed_nibbles, retdest)
%increment
SWAP1
SWAP2
%increment
%endrep
// stack: child_ptr_ptr', account_ptr_ptr', storage_ptr_ptr', retdest
%stack (child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, retdest) -> (retdest, account_ptr_ptr, storage_ptr_ptr)
// stack: i, child_ptr_ptr', account_ptr_ptr', storage_ptr_ptr', num_nibbles, packed_nibbles, retdest
POP
%stack (child_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest) ->
(retdest, account_ptr_ptr, storage_ptr_ptr)
JUMP

set_payload_storage_branch:
// stack: node_type, child_ptr_ptr, storage_ptr_ptr, retdest
// stack: node_type, child_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
POP

// Child counter
PUSH 0
// Call mpt_set_storage_payload on each child
%rep 16
%stack
(child_ptr_ptr, storage_ptr_ptr) ->
(child_ptr_ptr, storage_ptr_ptr, child_ptr_ptr)
// stack: child_ptr_ptr, storage_ptr_ptr, child_ptr_ptr, retdest
// The following 3-lines block is the inlined version of
// %stack (i, child_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles) ->
// (num_nibbles, packed_nibbles, 1, i, child_ptr_ptr, storage_ptr_ptr, i, num_nibbles, packed_nibbles, child_ptr_ptr)
SWAP1 SWAP4 SWAP3
SWAP2 DUP5 DUP3
PUSH 1 DUP7 DUP7

%merge_nibbles
// stack: num_merged_nibbles, merged_nibbles, child_ptr_ptr, storage_ptr_ptr, i, num_nibbles, packed_nibbles, child_ptr_ptr, retdest
%stack (num_merged_nibbles, merged_nibbles, child_ptr_ptr, storage_ptr_ptr) ->
(child_ptr_ptr, storage_ptr_ptr, num_merged_nibbles, merged_nibbles)
%mload_trie_data
// stack: child_ptr, storage_ptr_ptr, child_ptr_ptr, retdest
// stack: child_ptr, storage_ptr_ptr, num_merged_nibbles, merged_nibbles, i, num_nibbles, packed_nibbles, child_ptr_ptr, retdest
%mpt_set_storage_payload
// stack: storage_ptr_ptr', child_ptr_ptr, retdest
// stack: storage_ptr_ptr', i, num_nibbles, packed_nibbles, child_ptr_ptr, retdest
%stack (storage_ptr_ptr_p, i, num_nibbles, packed_nibbles, child_ptr_ptr) ->
(child_ptr_ptr, i, storage_ptr_ptr_p, num_nibbles, packed_nibbles)
%increment
SWAP1
%increment
%endrep
// stack: child_ptr_ptr', storage_ptr_ptr', retdest
%stack (child_ptr_ptr, storage_ptr_ptr, retdest) -> (retdest, storage_ptr_ptr)
// stack: i, child_ptr_ptr', storage_ptr_ptr', num_nibbles, packed_nibbles, retdest
%stack (i, child_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest) -> (retdest, storage_ptr_ptr)
JUMP

set_payload_extension:
// stack: node_type, after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest
// stack: node_type, after_node_type, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
POP
// stack: after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest
// stack: after_node_type, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
DUP1 %mload_trie_data // num_nibbles
DUP2 %increment %mload_trie_data // nibbles
SWAP2
%add_const(2) %mload_trie_data
// stack: child_ptr, after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest
// stack: child_ptr, loaded_num_nibbles, loaded_nibbles, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest

// The following 2-lines block is the inlined version of
// %stack (child_ptr, loaded_num_nibbles, loaded_nibbles, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles) ->
// (num_nibbles, packed_nibbles, loaded_num_nibbles, loaded_nibbles, child_ptr, account_ptr_ptr, storage_ptr_ptr)
SWAP4 SWAP6 SWAP1
SWAP2 SWAP3 SWAP5

%merge_nibbles
// stack: merged_num_nibbles, merged_nibbles, child_ptr, account_ptr_ptr, storage_ptr_ptr, retdest
%stack (merged_num_nibbles, merged_nibbles, child_ptr, account_ptr_ptr, storage_ptr_ptr) ->
(child_ptr, account_ptr_ptr, storage_ptr_ptr, merged_num_nibbles, merged_nibbles)
%jump(mpt_set_payload)

set_payload_storage_extension:
// stack: node_type, after_node_type, storage_ptr_ptr, retdest
// stack: node_type, after_node_type, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
POP
// stack: after_node_type, storage_ptr_ptr, retdest
// stack: after_node_type, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
DUP1 %mload_trie_data // num_nibbles
DUP2 %increment %mload_trie_data // nibbles
SWAP2
// stack: after_node_type, loaded_num_nibbles, loaded_packed_nibbles, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
%add_const(2) %mload_trie_data
// stack: child_ptr, storage_ptr_ptr, retdest
// stack: child_ptr, loaded_num_nibbles, loaded_packed_nibbles, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest

// The following 2-lines block is the inlined version of
// %stack (child_ptr, loaded_num_nibbles, loaded_packed_nibbles, storage_ptr_ptr, num_nibbles, packed_nibbles) ->
// (num_nibbles, packed_nibbles, loaded_num_nibbles, loaded_packed_nibbles, child_ptr, storage_ptr_ptr)
SWAP1 SWAP2 SWAP3
SWAP5 SWAP1 SWAP4

%merge_nibbles
%stack (merged_num_nibbles, merged_nibbles, child_ptr, storage_ptr_ptr) ->
(child_ptr, storage_ptr_ptr, merged_num_nibbles, merged_nibbles)
%jump(mpt_set_storage_payload)

set_payload_leaf:
// stack: node_type, after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest
// stack: node_type, after_node_type, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
POP
DUP1 %increment %mload_trie_data
DUP2 %mload_trie_data

// The following 2-lines block is the inlined version of
// %stack (loaded_num_nibbles, loaded_packed_nibbles, after_node_type, account_ptr_ptr, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest) ->
// (num_nibbles, packed_nibbles, loaded_num_nibbles, loaded_packed_nibbles, after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest)
SWAP2 SWAP4 SWAP6
SWAP1 SWAP3 SWAP5

%merge_nibbles
// stack: merged_len, merged_nibbles, after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest
PUSH 64 %assert_eq
DUP3 %sub_const(2) MLOAD_GENERAL
// stack: addr_key, merged_nibbles, after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest
%assert_eq
// stack: after_node_type, account_ptr_ptr, storage_ptr_ptr, retdest
%add_const(2) // The payload pointer starts at index 3, after num_nibbles and packed_nibbles.
DUP1
// stack: payload_ptr_ptr, payload_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, retdest
Expand All @@ -145,9 +232,15 @@ set_payload_leaf:
%mload_trie_data // storage_root_ptr = account[2]

// stack: storage_root_ptr, payload_ptr_ptr, account_ptr_ptr, storage_ptr_ptr, retdest
%stack
(storage_root_ptr, payload_ptr_ptr, account_ptr_ptr, storage_ptr_ptr) ->
(storage_root_ptr, storage_ptr_ptr, after_set_storage_payload, storage_root_ptr, payload_ptr_ptr, account_ptr_ptr)

// The following 4-lines block is the inlined version of
// %stack (storage_root_ptr, payload_ptr_ptr, account_ptr_ptr, storage_ptr_ptr) ->
// (storage_root_ptr, storage_ptr_ptr, 0, 0, after_set_storage_payload, storage_root_ptr, payload_ptr_ptr, account_ptr_ptr)
PUSH 0 PUSH 0
DUP3 SWAP4 SWAP5 SWAP6
PUSH after_set_storage_payload
SWAP4
%jump(mpt_set_storage_payload)
after_set_storage_payload:
// stack: storage_ptr_ptr', storage_root_ptr, payload_ptr_ptr, account_ptr_ptr, retdest
Expand All @@ -159,9 +252,14 @@ after_set_storage_payload:
DUP6 %decrement
MLOAD_GENERAL
%add_const(2) // dyn_storage_root_ptr_ptr = dyn_paylod_ptr[2]
%stack
(dyn_storage_root_ptr_ptr, new_storage_root_ptr_ptr, new_payload_ptr, storage_ptr_ptr_p, storage_root_ptr, payload_ptr_ptr, account_ptr_ptr) ->
(new_storage_root_ptr_ptr, storage_root_ptr, dyn_storage_root_ptr_ptr, storage_root_ptr, payload_ptr_ptr, new_payload_ptr, account_ptr_ptr, storage_ptr_ptr_p)

// The following 3-lines block is the inlined version of
// %stack (dyn_storage_root_ptr_ptr, new_storage_root_ptr_ptr, new_payload_ptr, storage_ptr_ptr_p, storage_root_ptr, payload_ptr_ptr, account_ptr_ptr) ->
// (new_storage_root_ptr_ptr, storage_root_ptr, dyn_storage_root_ptr_ptr, storage_root_ptr, payload_ptr_ptr, new_payload_ptr, account_ptr_ptr, storage_ptr_ptr_p)
DUP5
SWAP3 SWAP5 SWAP1 SWAP4
SWAP7 SWAP6 SWAP4 SWAP2

%mstore_trie_data // The initial account pointer in the linked list has no storage root so we need to manually set it.
%mstore_trie_data // The dynamic account pointer in the linked list has no storage root so we need to manually set it.
%mstore_trie_data // Set the leaf payload pointing to next account in the linked list.
Expand All @@ -173,8 +271,19 @@ after_set_storage_payload:
JUMP

set_payload_storage_leaf:
// stack: node_type, after_node_type, storage_ptr_ptr, retdest
// stack: node_type, after_node_type, storage_ptr_ptr, num_nibbles, packed_nibbles, retdest
POP
DUP1 %increment %mload_trie_data
DUP2 %mload_trie_data
%stack (loaded_num_nibbles, loaded_nibbles, after_node_type, storage_ptr_ptr, num_nibbles, packed_nibbles) ->
(num_nibbles, packed_nibbles, loaded_num_nibbles, loaded_nibbles, after_node_type, storage_ptr_ptr)
%merge_nibbles
// stack: merged_num_nibbles, merged_nibbles, after_node_type, storage_ptr_ptr, retdest
PUSH 64 %assert_eq
// stack: merged_nibbles, after_node_type, storage_ptr_ptr, retdest
DUP3 %sub_const(2) MLOAD_GENERAL
// stack: slot_key, merged_nibbles, after_node_type, storage_ptr_ptr, retdest
%assert_eq
// stack: after_node_type, storage_ptr_ptr, retdest
%add_const(2) // The value pointer starts at index 3, after num_nibbles and packed_nibbles.
// stack: value_ptr_ptr, storage_ptr_ptr, retdest
Expand Down
12 changes: 12 additions & 0 deletions evm_arithmetization/src/cpu/kernel/tests/account_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ pub(crate) fn prepare_interpreter<F: Field>(
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(0.into()) // Initial nibbles
.expect("The stack should not overflow");
interpreter
.push(0.into()) // Initial number of nibbles
.expect("The stack should not overflow");
interpreter
.push((Segment::StorageLinkedList as usize + 8).into())
.expect("The stack should not overflow");
Expand Down Expand Up @@ -407,6 +413,12 @@ fn prepare_interpreter_all_accounts<F: Field>(
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(0.into()) // Initial nibbles
.expect("The stack should not overflow");
interpreter
.push(0.into()) // Initial number of nibbles
.expect("The stack should not overflow");
interpreter
.push((Segment::StorageLinkedList as usize + 8).into())
.expect("The stack should not overflow");
Expand Down
6 changes: 6 additions & 0 deletions evm_arithmetization/src/cpu/kernel/tests/mpt/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ fn test_state_trie(
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(0.into()) // Initial nibbles
.expect("The stack should not overflow");
interpreter
.push(0.into()) // Initial number of nibbles
.expect("The stack should not overflow");
interpreter
.push((Segment::StorageLinkedList as usize + 8).into())
.expect("The stack should not overflow");
Expand Down
6 changes: 6 additions & 0 deletions evm_arithmetization/src/cpu/kernel/tests/mpt/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ fn test_state_trie(
interpreter
.push(0xDEADBEEFu32.into())
.expect("The stack should not overflow");
interpreter
.push(0.into()) // Initial nibbles
.expect("The stack should not overflow");
interpreter
.push(0.into()) // Initial number of nibbles
.expect("The stack should not overflow");
interpreter
.push((Segment::StorageLinkedList as usize + 8).into())
.expect("The stack should not overflow");
Expand Down

0 comments on commit 9529cf8

Please sign in to comment.