mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-04 23:03:08 +00:00
Merge pull request #768 from mir-protocol/mpt_insert_1
MPT insert logic, part 1
This commit is contained in:
commit
fb7ef3197a
@ -43,12 +43,13 @@ pub(crate) fn combined_kernel() -> Kernel {
|
||||
include_str!("asm/mpt/hash.asm"),
|
||||
include_str!("asm/mpt/hash_trie_specific.asm"),
|
||||
include_str!("asm/mpt/hex_prefix.asm"),
|
||||
include_str!("asm/mpt/insert.asm"),
|
||||
include_str!("asm/mpt/insert_trie_specific.asm"),
|
||||
include_str!("asm/mpt/load.asm"),
|
||||
include_str!("asm/mpt/read.asm"),
|
||||
include_str!("asm/mpt/storage_read.asm"),
|
||||
include_str!("asm/mpt/storage_write.asm"),
|
||||
include_str!("asm/mpt/util.asm"),
|
||||
include_str!("asm/mpt/write.asm"),
|
||||
include_str!("asm/ripemd/box.asm"),
|
||||
include_str!("asm/ripemd/compression.asm"),
|
||||
include_str!("asm/ripemd/constants.asm"),
|
||||
|
||||
@ -39,7 +39,7 @@ global mpt_hash_receipt_trie:
|
||||
%%after:
|
||||
%endmacro
|
||||
|
||||
encode_account:
|
||||
global encode_account:
|
||||
// stack: rlp_pos, value_ptr, retdest
|
||||
// First, we compute the length of the RLP data we're about to write.
|
||||
// The nonce and balance fields are variable-length, so we need to load them
|
||||
|
||||
118
evm/src/cpu/kernel/asm/mpt/insert.asm
Normal file
118
evm/src/cpu/kernel/asm/mpt/insert.asm
Normal file
@ -0,0 +1,118 @@
|
||||
// Return a copy of the given node, with the given key set to the given value.
|
||||
//
|
||||
// Pre stack: node_ptr, num_nibbles, key, value_ptr, retdest
|
||||
// Post stack: updated_node_ptr
|
||||
global mpt_insert:
|
||||
// stack: node_ptr, num_nibbles, key, value_ptr, retdest
|
||||
DUP1 %mload_trie_data
|
||||
// stack: node_type, node_ptr, num_nibbles, key, value_ptr, retdest
|
||||
// Increment node_ptr, so it points to the node payload instead of its type.
|
||||
SWAP1 %increment SWAP1
|
||||
// stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
|
||||
DUP1 %eq_const(@MPT_NODE_EMPTY) %jumpi(mpt_insert_empty)
|
||||
DUP1 %eq_const(@MPT_NODE_BRANCH) %jumpi(mpt_insert_branch)
|
||||
DUP1 %eq_const(@MPT_NODE_EXTENSION) %jumpi(mpt_insert_extension)
|
||||
DUP1 %eq_const(@MPT_NODE_LEAF) %jumpi(mpt_insert_leaf)
|
||||
|
||||
// There's still the MPT_NODE_HASH case, but if we hit a hash node,
|
||||
// it means the prover failed to provide necessary Merkle data, so panic.
|
||||
PANIC
|
||||
|
||||
mpt_insert_empty:
|
||||
// stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
%pop2
|
||||
// stack: num_nibbles, key, value_ptr, retdest
|
||||
// We will append a new leaf node to our MPT tape and return a pointer to it.
|
||||
%get_trie_data_size
|
||||
// stack: leaf_ptr, num_nibbles, key, value_ptr, retdest
|
||||
PUSH @MPT_NODE_LEAF %append_to_trie_data
|
||||
// stack: leaf_ptr, num_nibbles, key, value_ptr, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: leaf_ptr, key, value_ptr, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: leaf_ptr, value_ptr, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: leaf_ptr, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
mpt_insert_branch:
|
||||
// stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
%get_trie_data_size
|
||||
// stack: updated_branch_ptr, node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
SWAP1
|
||||
%append_to_trie_data
|
||||
// stack: updated_branch_ptr, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
SWAP1
|
||||
// stack: node_payload_ptr, updated_branch_ptr, num_nibbles, key, value_ptr, retdest
|
||||
|
||||
// Copy the original node's data to our updated node.
|
||||
DUP1 %mload_trie_data %append_to_trie_data // Copy child[0]
|
||||
DUP1 %add_const(1) %mload_trie_data %append_to_trie_data // ...
|
||||
DUP1 %add_const(2) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(3) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(4) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(5) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(6) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(7) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(8) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(9) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(10) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(11) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(12) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(13) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(14) %mload_trie_data %append_to_trie_data
|
||||
DUP1 %add_const(15) %mload_trie_data %append_to_trie_data // Copy child[15]
|
||||
%add_const(16) %mload_trie_data %append_to_trie_data // Copy value_ptr
|
||||
|
||||
// At this point, we branch based on whether the key terminates with this branch node.
|
||||
// stack: updated_branch_ptr, num_nibbles, key, value_ptr, retdest
|
||||
DUP2 %jumpi(mpt_insert_branch_nonterminal)
|
||||
|
||||
// The key terminates here, so the value will be placed right in our (updated) branch node.
|
||||
// stack: updated_branch_ptr, num_nibbles, key, value_ptr, retdest
|
||||
SWAP3
|
||||
// stack: value_ptr, num_nibbles, key, updated_branch_ptr, retdest
|
||||
DUP4 %add_const(17)
|
||||
// stack: updated_branch_value_ptr_ptr, value_ptr, num_nibbles, key, updated_branch_ptr, retdest
|
||||
%mstore_trie_data
|
||||
// stack: num_nibbles, key, updated_branch_ptr, retdest
|
||||
%pop2
|
||||
// stack: updated_branch_ptr, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
mpt_insert_branch_nonterminal:
|
||||
// The key continues, so we split off the first (most significant) nibble,
|
||||
// and recursively insert into the child associated with that nibble.
|
||||
// stack: updated_branch_ptr, num_nibbles, key, value_ptr, retdest
|
||||
%stack (updated_branch_ptr, num_nibbles, key) -> (num_nibbles, key, updated_branch_ptr)
|
||||
%split_first_nibble
|
||||
// stack: first_nibble, num_nibbles, key, updated_branch_ptr, value_ptr, retdest
|
||||
DUP4 %increment ADD
|
||||
// stack: child_ptr_ptr, num_nibbles, key, updated_branch_ptr, value_ptr, retdest
|
||||
%stack (child_ptr_ptr, num_nibbles, key, updated_branch_ptr, value_ptr)
|
||||
-> (child_ptr_ptr, num_nibbles, key, value_ptr,
|
||||
mpt_insert_branch_nonterminal_after_recursion,
|
||||
child_ptr_ptr, updated_branch_ptr)
|
||||
%mload_trie_data // Deref child_ptr_ptr, giving child_ptr
|
||||
%jump(mpt_insert)
|
||||
mpt_insert_branch_nonterminal_after_recursion:
|
||||
// stack: updated_child_ptr, child_ptr_ptr, updated_branch_ptr, retdest
|
||||
SWAP1 %mstore_trie_data // Store the pointer to the updated child.
|
||||
// stack: updated_branch_ptr, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
mpt_insert_extension:
|
||||
// stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
POP
|
||||
// stack: node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
PANIC // TODO
|
||||
|
||||
mpt_insert_leaf:
|
||||
// stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
POP
|
||||
// stack: node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
PANIC // TODO
|
||||
14
evm/src/cpu/kernel/asm/mpt/insert_trie_specific.asm
Normal file
14
evm/src/cpu/kernel/asm/mpt/insert_trie_specific.asm
Normal file
@ -0,0 +1,14 @@
|
||||
// Insertion logic specific to a particular trie.
|
||||
|
||||
// Mutate the state trie, inserting the given key-value pair.
|
||||
global mpt_insert_state_trie:
|
||||
// stack: num_nibbles, key, value_ptr, retdest
|
||||
%stack (num_nibbles, key, value_ptr)
|
||||
-> (num_nibbles, key, value_ptr, mpt_insert_state_trie_save)
|
||||
%mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT)
|
||||
// stack: state_root_ptr, num_nibbles, key, value_ptr, mpt_insert_state_trie_save, retdest
|
||||
%jump(mpt_insert)
|
||||
mpt_insert_state_trie_save:
|
||||
// stack: updated_node_ptr, retdest
|
||||
%mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT)
|
||||
JUMP
|
||||
@ -9,9 +9,9 @@ global load_all_mpts:
|
||||
PUSH 1
|
||||
%set_trie_data_size
|
||||
|
||||
%load_mpt_and_return_root_ptr %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT)
|
||||
%load_mpt_and_return_root_ptr %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_ROOT)
|
||||
%load_mpt_and_return_root_ptr %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_ROOT)
|
||||
%load_mpt %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT)
|
||||
%load_mpt %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_ROOT)
|
||||
%load_mpt %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_ROOT)
|
||||
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: num_storage_tries, retdest
|
||||
@ -30,7 +30,7 @@ storage_trie_loop:
|
||||
// stack: i, storage_trie_addr, i, num_storage_tries, retdest
|
||||
%mstore_kernel(@SEGMENT_STORAGE_TRIE_ADDRS)
|
||||
// stack: i, num_storage_tries, retdest
|
||||
%load_mpt_and_return_root_ptr
|
||||
%load_mpt
|
||||
// stack: root_ptr, i, num_storage_tries, retdest
|
||||
DUP2
|
||||
// stack: i, root_ptr, i, num_storage_tries, retdest
|
||||
@ -45,13 +45,11 @@ storage_trie_loop_end:
|
||||
|
||||
// Load an MPT from prover inputs.
|
||||
// Pre stack: retdest
|
||||
// Post stack: (empty)
|
||||
// Post stack: node_ptr
|
||||
load_mpt:
|
||||
// stack: retdest
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: node_type, retdest
|
||||
DUP1 %append_to_trie_data
|
||||
// stack: node_type, retdest
|
||||
|
||||
DUP1 %eq_const(@MPT_NODE_EMPTY) %jumpi(load_mpt_empty)
|
||||
DUP1 %eq_const(@MPT_NODE_BRANCH) %jumpi(load_mpt_branch)
|
||||
@ -61,94 +59,108 @@ load_mpt:
|
||||
PANIC // Invalid node type
|
||||
|
||||
load_mpt_empty:
|
||||
// stack: node_type, retdest
|
||||
POP
|
||||
// stack: retdest
|
||||
// TRIE_DATA[0] = 0, and an empty node has type 0, so we can simply return the null pointer.
|
||||
%stack (node_type, retdest) -> (retdest, 0)
|
||||
JUMP
|
||||
|
||||
load_mpt_branch:
|
||||
// stack: node_type, retdest
|
||||
POP
|
||||
// stack: retdest
|
||||
%get_trie_data_size
|
||||
// stack: node_ptr, node_type, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
// Save the offset of our 16 child pointers so we can write them later.
|
||||
// Then advance out current trie pointer beyond them, so we can load the
|
||||
// value and have it placed after our child pointers.
|
||||
%get_trie_data_size
|
||||
// stack: ptr_children, retdest
|
||||
DUP1 %add_const(16)
|
||||
// stack: ptr_value, ptr_children, retdest
|
||||
// stack: children_ptr, node_ptr, retdest
|
||||
DUP1 %add_const(17) // Skip over 16 children plus the value pointer
|
||||
// stack: value_ptr, children_ptr, node_ptr, retdest
|
||||
%set_trie_data_size
|
||||
// stack: ptr_children, retdest
|
||||
// We need to append a pointer to where the value will live.
|
||||
// %load_leaf_value will append the value just after this pointer;
|
||||
// we add 1 to account for the pointer itself.
|
||||
%get_trie_data_size %increment %append_to_trie_data
|
||||
// stack: ptr_children, retdest
|
||||
%load_leaf_value
|
||||
// stack: children_ptr, node_ptr, retdest
|
||||
%load_value
|
||||
// stack: children_ptr, value_ptr, node_ptr, retdest
|
||||
SWAP1
|
||||
|
||||
// Load the 16 children.
|
||||
%rep 16
|
||||
%load_mpt_and_return_root_ptr
|
||||
// stack: child_ptr, ptr_next_child, retdest
|
||||
%load_mpt
|
||||
// stack: child_ptr, next_child_ptr_ptr, value_ptr, node_ptr, retdest
|
||||
DUP2
|
||||
// stack: ptr_next_child, child_ptr, ptr_next_child, retdest
|
||||
// stack: next_child_ptr_ptr, child_ptr, next_child_ptr_ptr, value_ptr, node_ptr, retdest
|
||||
%mstore_trie_data
|
||||
// stack: ptr_next_child, retdest
|
||||
// stack: next_child_ptr_ptr, value_ptr, node_ptr, retdest
|
||||
%increment
|
||||
// stack: ptr_next_child, retdest
|
||||
// stack: next_child_ptr_ptr, value_ptr, node_ptr, retdest
|
||||
%endrep
|
||||
|
||||
// stack: ptr_next_child, retdest
|
||||
POP
|
||||
// stack: value_ptr_ptr, value_ptr, node_ptr, retdest
|
||||
%mstore_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
load_mpt_extension:
|
||||
// stack: node_type, retdest
|
||||
POP
|
||||
// stack: retdest
|
||||
%get_trie_data_size
|
||||
// stack: node_ptr, node_type, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
PROVER_INPUT(mpt) // read num_nibbles
|
||||
%append_to_trie_data
|
||||
PROVER_INPUT(mpt) // read packed_nibbles
|
||||
%append_to_trie_data
|
||||
// stack: retdest
|
||||
// stack: node_ptr, retdest
|
||||
|
||||
// Let i be the current trie data size. We still need to expand this node by
|
||||
// one element, appending our child pointer. Thus our child node will start
|
||||
// at i + 1. So we will set our child pointer to i + 1.
|
||||
%get_trie_data_size
|
||||
%increment
|
||||
%append_to_trie_data
|
||||
// stack: retdest
|
||||
// stack: child_ptr_ptr, node_ptr, retdest
|
||||
// Increment trie_data_size, to leave room for child_ptr_ptr, before we load our child.
|
||||
DUP1 %increment %set_trie_data_size
|
||||
// stack: child_ptr_ptr, node_ptr, retdest
|
||||
|
||||
%load_mpt
|
||||
// stack: retdest
|
||||
// stack: child_ptr, child_ptr_ptr, node_ptr, retdest
|
||||
SWAP1
|
||||
%mstore_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
load_mpt_leaf:
|
||||
// stack: node_type, retdest
|
||||
POP
|
||||
// stack: retdest
|
||||
%get_trie_data_size
|
||||
// stack: node_ptr, node_type, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
PROVER_INPUT(mpt) // read num_nibbles
|
||||
%append_to_trie_data
|
||||
PROVER_INPUT(mpt) // read packed_nibbles
|
||||
%append_to_trie_data
|
||||
// stack: retdest
|
||||
// We need to append a pointer to where the value will live.
|
||||
// %load_leaf_value will append the value just after this pointer;
|
||||
// we add 1 to account for the pointer itself.
|
||||
%get_trie_data_size %increment %append_to_trie_data
|
||||
// stack: retdest
|
||||
%load_leaf_value
|
||||
// stack: retdest
|
||||
// stack: node_ptr, retdest
|
||||
// We save value_ptr_ptr = get_trie_data_size, then increment trie_data_size
|
||||
// to skip over the slot for value_ptr. We will write value_ptr after the
|
||||
// load_value call.
|
||||
%get_trie_data_size
|
||||
// stack: value_ptr_ptr, node_ptr, retdest
|
||||
DUP1 %increment %set_trie_data_size
|
||||
// stack: value_ptr_ptr, node_ptr, retdest
|
||||
%load_value
|
||||
// stack: value_ptr, value_ptr_ptr, node_ptr, retdest
|
||||
SWAP1 %mstore_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
load_mpt_digest:
|
||||
// stack: node_type, retdest
|
||||
POP
|
||||
// stack: retdest
|
||||
%get_trie_data_size
|
||||
// stack: node_ptr, node_type, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
PROVER_INPUT(mpt) // read digest
|
||||
%append_to_trie_data
|
||||
// stack: retdest
|
||||
// stack: node_ptr, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
// Convenience macro to call load_mpt and return where we left off.
|
||||
@ -158,34 +170,37 @@ load_mpt_digest:
|
||||
%%after:
|
||||
%endmacro
|
||||
|
||||
%macro load_mpt_and_return_root_ptr
|
||||
// stack: (empty)
|
||||
%get_trie_data_size
|
||||
// stack: ptr
|
||||
%load_mpt
|
||||
// stack: ptr
|
||||
%endmacro
|
||||
|
||||
// Load a leaf from prover input, and append it to trie data.
|
||||
%macro load_leaf_value
|
||||
// Load a leaf from prover input, append it to trie data, and return a pointer to it.
|
||||
%macro load_value
|
||||
// stack: (empty)
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: leaf_len
|
||||
// stack: value_len
|
||||
DUP1 ISZERO
|
||||
%jumpi(%%return_null)
|
||||
// stack: value_len
|
||||
%get_trie_data_size
|
||||
SWAP1
|
||||
// stack: value_len, value_ptr
|
||||
DUP1 %append_to_trie_data
|
||||
// stack: leaf_len
|
||||
// stack: value_len, value_ptr
|
||||
%%loop:
|
||||
DUP1 ISZERO
|
||||
// stack: leaf_len == 0, leaf_len
|
||||
%jumpi(%%finish)
|
||||
// stack: leaf_len
|
||||
// stack: value_len == 0, value_len, value_ptr
|
||||
%jumpi(%%finish_loop)
|
||||
// stack: value_len, value_ptr
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: leaf_part, leaf_len
|
||||
// stack: leaf_part, value_len, value_ptr
|
||||
%append_to_trie_data
|
||||
// stack: leaf_len
|
||||
// stack: value_len, value_ptr
|
||||
%decrement
|
||||
// stack: leaf_len'
|
||||
// stack: value_len', value_ptr
|
||||
%jump(%%loop)
|
||||
%%finish:
|
||||
%%finish_loop:
|
||||
// stack: value_len, value_ptr
|
||||
POP
|
||||
// stack: (empty)
|
||||
// stack: value_ptr
|
||||
%jump(%%end)
|
||||
%%return_null:
|
||||
%stack (value_len) -> (0)
|
||||
%%end:
|
||||
%endmacro
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
// TODO: Need a special case for deleting, if value = ''.
|
||||
// Or canonicalize once, before final hashing, to remove empty leaves etc.
|
||||
|
||||
// Return a copy of the given node, with the given key set to the given value.
|
||||
//
|
||||
// Pre stack: node_ptr, num_nibbles, key, value_ptr, retdest
|
||||
// Post stack: updated_node_ptr
|
||||
global mpt_insert:
|
||||
// stack: node_ptr, num_nibbles, key, value_ptr, retdest
|
||||
DUP1 %mload_trie_data
|
||||
// stack: node_type, node_ptr, num_nibbles, key, value_ptr, retdest
|
||||
// Increment node_ptr, so it points to the node payload instead of its type.
|
||||
SWAP1 %increment SWAP1
|
||||
// stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
|
||||
DUP1 %eq_const(@MPT_NODE_EMPTY) %jumpi(mpt_insert_empty)
|
||||
DUP1 %eq_const(@MPT_NODE_BRANCH) %jumpi(mpt_insert_branch)
|
||||
DUP1 %eq_const(@MPT_NODE_EXTENSION) %jumpi(mpt_insert_extension)
|
||||
DUP1 %eq_const(@MPT_NODE_LEAF) %jumpi(mpt_insert_leaf)
|
||||
|
||||
// There's still the MPT_NODE_HASH case, but if we hit a hash node,
|
||||
// it means the prover failed to provide necessary Merkle data, so panic.
|
||||
PANIC
|
||||
|
||||
mpt_insert_empty:
|
||||
// stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
POP
|
||||
// stack: node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
PANIC // TODO
|
||||
|
||||
mpt_insert_branch:
|
||||
// stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
POP
|
||||
// stack: node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
PANIC // TODO
|
||||
|
||||
mpt_insert_extension:
|
||||
// stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
POP
|
||||
// stack: node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
PANIC // TODO
|
||||
|
||||
mpt_insert_leaf:
|
||||
// stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
POP
|
||||
// stack: node_payload_ptr, num_nibbles, key, value_ptr, retdest
|
||||
PANIC // TODO
|
||||
@ -168,10 +168,19 @@ impl<'a> Interpreter<'a> {
|
||||
self.memory.context_memory[0].segments[Segment::GlobalMetadata as usize].get(field as usize)
|
||||
}
|
||||
|
||||
pub(crate) fn set_global_metadata_field(&mut self, field: GlobalMetadata, value: U256) {
|
||||
self.memory.context_memory[0].segments[Segment::GlobalMetadata as usize]
|
||||
.set(field as usize, value)
|
||||
}
|
||||
|
||||
pub(crate) fn get_trie_data(&self) -> &[U256] {
|
||||
&self.memory.context_memory[0].segments[Segment::TrieData as usize].content
|
||||
}
|
||||
|
||||
pub(crate) fn get_trie_data_mut(&mut self) -> &mut Vec<U256> {
|
||||
&mut self.memory.context_memory[0].segments[Segment::TrieData as usize].content
|
||||
}
|
||||
|
||||
pub(crate) fn get_rlp_memory(&self) -> Vec<u8> {
|
||||
self.memory.context_memory[0].segments[Segment::RlpRaw as usize]
|
||||
.content
|
||||
@ -205,7 +214,7 @@ impl<'a> Interpreter<'a> {
|
||||
self.push(if x { U256::one() } else { U256::zero() });
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> U256 {
|
||||
pub(crate) fn pop(&mut self) -> U256 {
|
||||
self.stack_mut().pop().expect("Pop on empty stack.")
|
||||
}
|
||||
|
||||
|
||||
173
evm/src/cpu/kernel/tests/mpt/insert.rs
Normal file
173
evm/src/cpu/kernel/tests/mpt/insert.rs
Normal file
@ -0,0 +1,173 @@
|
||||
use anyhow::Result;
|
||||
use eth_trie_utils::partial_trie::{Nibbles, PartialTrie};
|
||||
use eth_trie_utils::trie_builder::InsertEntry;
|
||||
use ethereum_types::{BigEndianHash, H256};
|
||||
|
||||
use crate::cpu::kernel::aggregator::KERNEL;
|
||||
use crate::cpu::kernel::constants::global_metadata::GlobalMetadata;
|
||||
use crate::cpu::kernel::interpreter::Interpreter;
|
||||
use crate::cpu::kernel::tests::mpt::{extension_to_leaf, test_account_1_rlp, test_account_2_rlp};
|
||||
use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp};
|
||||
use crate::generation::TrieInputs;
|
||||
|
||||
#[test]
|
||||
fn mpt_insert_empty() -> Result<()> {
|
||||
let insert = InsertEntry {
|
||||
nibbles: Nibbles {
|
||||
count: 3,
|
||||
packed: 0xABC.into(),
|
||||
},
|
||||
v: test_account_2_rlp(),
|
||||
};
|
||||
test_state_trie(Default::default(), insert)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Enable when mpt_insert_leaf is done.
|
||||
fn mpt_insert_leaf_same_key() -> Result<()> {
|
||||
let key = Nibbles {
|
||||
count: 3,
|
||||
packed: 0xABC.into(),
|
||||
};
|
||||
let state_trie = PartialTrie::Leaf {
|
||||
nibbles: key,
|
||||
value: test_account_1_rlp(),
|
||||
};
|
||||
let insert = InsertEntry {
|
||||
nibbles: key,
|
||||
v: test_account_2_rlp(),
|
||||
};
|
||||
|
||||
test_state_trie(state_trie, insert)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mpt_insert_branch_replacing_empty_child() -> Result<()> {
|
||||
let children = std::array::from_fn(|_| Box::new(PartialTrie::Empty));
|
||||
let state_trie = PartialTrie::Branch {
|
||||
children,
|
||||
value: vec![],
|
||||
};
|
||||
|
||||
let insert = InsertEntry {
|
||||
nibbles: Nibbles {
|
||||
count: 3,
|
||||
packed: 0xABC.into(),
|
||||
},
|
||||
v: test_account_2_rlp(),
|
||||
};
|
||||
|
||||
test_state_trie(state_trie, insert)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Enable when mpt_insert_extension is done.
|
||||
fn mpt_insert_extension_to_leaf_same_key() -> Result<()> {
|
||||
let state_trie = extension_to_leaf(test_account_1_rlp());
|
||||
|
||||
let insert = InsertEntry {
|
||||
nibbles: Nibbles {
|
||||
count: 3,
|
||||
packed: 0xABCDEF.into(),
|
||||
},
|
||||
v: test_account_2_rlp(),
|
||||
};
|
||||
|
||||
test_state_trie(state_trie, insert)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: Enable when mpt_insert_leaf is done.
|
||||
fn mpt_insert_branch_to_leaf_same_key() -> Result<()> {
|
||||
let leaf = PartialTrie::Leaf {
|
||||
nibbles: Nibbles {
|
||||
count: 3,
|
||||
packed: 0xBCD.into(),
|
||||
},
|
||||
value: test_account_1_rlp(),
|
||||
};
|
||||
let mut children = std::array::from_fn(|_| Box::new(PartialTrie::Empty));
|
||||
children[0xA] = Box::new(leaf);
|
||||
let state_trie = PartialTrie::Branch {
|
||||
children,
|
||||
value: vec![],
|
||||
};
|
||||
|
||||
let insert = InsertEntry {
|
||||
nibbles: Nibbles {
|
||||
count: 4,
|
||||
packed: 0xABCD.into(),
|
||||
},
|
||||
v: test_account_2_rlp(),
|
||||
};
|
||||
|
||||
test_state_trie(state_trie, insert)
|
||||
}
|
||||
|
||||
fn test_state_trie(state_trie: PartialTrie, insert: InsertEntry) -> Result<()> {
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie: state_trie.clone(),
|
||||
transactions_trie: Default::default(),
|
||||
receipts_trie: Default::default(),
|
||||
storage_tries: vec![],
|
||||
};
|
||||
let load_all_mpts = KERNEL.global_labels["load_all_mpts"];
|
||||
let mpt_insert_state_trie = KERNEL.global_labels["mpt_insert_state_trie"];
|
||||
let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"];
|
||||
|
||||
let initial_stack = vec![0xDEADBEEFu32.into()];
|
||||
let mut interpreter = Interpreter::new_with_kernel(load_all_mpts, initial_stack);
|
||||
interpreter.generation_state.mpt_prover_inputs = all_mpt_prover_inputs_reversed(&trie_inputs);
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), vec![]);
|
||||
|
||||
// Next, execute mpt_insert_state_trie.
|
||||
interpreter.offset = mpt_insert_state_trie;
|
||||
let trie_data = interpreter.get_trie_data_mut();
|
||||
if trie_data.is_empty() {
|
||||
// In the assembly we skip over 0, knowing trie_data[0] = 0 by default.
|
||||
// Since we don't explicitly set it to 0, we need to do so here.
|
||||
trie_data.push(0.into());
|
||||
}
|
||||
let value_ptr = trie_data.len();
|
||||
let account: AccountRlp = rlp::decode(&insert.v).expect("Decoding failed");
|
||||
let account_data = account.to_vec();
|
||||
trie_data.push(account_data.len().into());
|
||||
trie_data.extend(account_data);
|
||||
let trie_data_len = trie_data.len().into();
|
||||
interpreter.set_global_metadata_field(GlobalMetadata::TrieDataSize, trie_data_len);
|
||||
interpreter.push(0xDEADBEEFu32.into());
|
||||
interpreter.push(value_ptr.into()); // value_ptr
|
||||
interpreter.push(insert.nibbles.packed); // key
|
||||
interpreter.push(insert.nibbles.count.into()); // num_nibbles
|
||||
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack().len(), 0);
|
||||
|
||||
// Now, execute mpt_hash_state_trie.
|
||||
interpreter.offset = mpt_hash_state_trie;
|
||||
interpreter.push(0xDEADBEEFu32.into());
|
||||
interpreter.run()?;
|
||||
|
||||
assert_eq!(
|
||||
interpreter.stack().len(),
|
||||
1,
|
||||
"Expected 1 item on stack, found {:?}",
|
||||
interpreter.stack()
|
||||
);
|
||||
let hash = H256::from_uint(&interpreter.stack()[0]);
|
||||
|
||||
let expected_state_trie_hash = apply_insert(state_trie, insert).calc_hash();
|
||||
assert_eq!(hash, expected_state_trie_hash);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply_insert(trie: PartialTrie, insert: InsertEntry) -> PartialTrie {
|
||||
let mut trie = Box::new(trie);
|
||||
if let Some(updated_trie) = PartialTrie::insert_into_trie(&mut trie, insert) {
|
||||
*updated_trie
|
||||
} else {
|
||||
*trie
|
||||
}
|
||||
}
|
||||
@ -1,26 +1,19 @@
|
||||
use anyhow::Result;
|
||||
use ethereum_types::{BigEndianHash, H256, U256};
|
||||
use eth_trie_utils::partial_trie::{Nibbles, PartialTrie};
|
||||
use ethereum_types::{BigEndianHash, U256};
|
||||
|
||||
use crate::cpu::kernel::aggregator::KERNEL;
|
||||
use crate::cpu::kernel::constants::global_metadata::GlobalMetadata;
|
||||
use crate::cpu::kernel::constants::trie_type::PartialTrieType;
|
||||
use crate::cpu::kernel::interpreter::Interpreter;
|
||||
use crate::cpu::kernel::tests::mpt::extension_to_leaf;
|
||||
use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp};
|
||||
use crate::cpu::kernel::tests::mpt::{extension_to_leaf, test_account_1, test_account_1_rlp};
|
||||
use crate::generation::mpt::all_mpt_prover_inputs_reversed;
|
||||
use crate::generation::TrieInputs;
|
||||
|
||||
#[test]
|
||||
fn load_all_mpts() -> Result<()> {
|
||||
let account = AccountRlp {
|
||||
nonce: U256::from(1111),
|
||||
balance: U256::from(2222),
|
||||
storage_root: H256::from_uint(&U256::from(3333)),
|
||||
code_hash: H256::from_uint(&U256::from(4444)),
|
||||
};
|
||||
let account_rlp = rlp::encode(&account);
|
||||
|
||||
fn load_all_mpts_empty() -> Result<()> {
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie: extension_to_leaf(account_rlp.to_vec()),
|
||||
state_trie: Default::default(),
|
||||
transactions_trie: Default::default(),
|
||||
receipts_trie: Default::default(),
|
||||
storage_tries: vec![],
|
||||
@ -28,13 +21,174 @@ fn load_all_mpts() -> Result<()> {
|
||||
|
||||
let load_all_mpts = KERNEL.global_labels["load_all_mpts"];
|
||||
|
||||
let initial_stack = vec![0xdeadbeefu32.into()];
|
||||
let initial_stack = vec![0xDEADBEEFu32.into()];
|
||||
let mut interpreter = Interpreter::new_with_kernel(load_all_mpts, initial_stack);
|
||||
interpreter.generation_state.mpt_prover_inputs = all_mpt_prover_inputs_reversed(&trie_inputs);
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), vec![]);
|
||||
|
||||
assert_eq!(interpreter.get_trie_data(), vec![]);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::StateTrieRoot),
|
||||
0.into()
|
||||
);
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::TransactionTrieRoot),
|
||||
0.into()
|
||||
);
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::ReceiptTrieRoot),
|
||||
0.into()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::NumStorageTries),
|
||||
trie_inputs.storage_tries.len().into()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_all_mpts_leaf() -> Result<()> {
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie: PartialTrie::Leaf {
|
||||
nibbles: Nibbles {
|
||||
count: 3,
|
||||
packed: 0xABC.into(),
|
||||
},
|
||||
value: test_account_1_rlp(),
|
||||
},
|
||||
transactions_trie: Default::default(),
|
||||
receipts_trie: Default::default(),
|
||||
storage_tries: vec![],
|
||||
};
|
||||
|
||||
let load_all_mpts = KERNEL.global_labels["load_all_mpts"];
|
||||
|
||||
let initial_stack = vec![0xDEADBEEFu32.into()];
|
||||
let mut interpreter = Interpreter::new_with_kernel(load_all_mpts, initial_stack);
|
||||
interpreter.generation_state.mpt_prover_inputs = all_mpt_prover_inputs_reversed(&trie_inputs);
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), vec![]);
|
||||
|
||||
let type_leaf = U256::from(PartialTrieType::Leaf as u32);
|
||||
assert_eq!(
|
||||
interpreter.get_trie_data(),
|
||||
vec![
|
||||
0.into(),
|
||||
type_leaf,
|
||||
3.into(),
|
||||
0xABC.into(),
|
||||
5.into(), // value ptr
|
||||
4.into(), // value length
|
||||
test_account_1().nonce,
|
||||
test_account_1().balance,
|
||||
test_account_1().storage_root.into_uint(),
|
||||
test_account_1().code_hash.into_uint(),
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::TransactionTrieRoot),
|
||||
0.into()
|
||||
);
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::ReceiptTrieRoot),
|
||||
0.into()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::NumStorageTries),
|
||||
trie_inputs.storage_tries.len().into()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_all_mpts_empty_branch() -> Result<()> {
|
||||
let children = std::array::from_fn(|_| Box::new(PartialTrie::Empty));
|
||||
let state_trie = PartialTrie::Branch {
|
||||
children,
|
||||
value: vec![],
|
||||
};
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie,
|
||||
transactions_trie: Default::default(),
|
||||
receipts_trie: Default::default(),
|
||||
storage_tries: vec![],
|
||||
};
|
||||
|
||||
let load_all_mpts = KERNEL.global_labels["load_all_mpts"];
|
||||
|
||||
let initial_stack = vec![0xDEADBEEFu32.into()];
|
||||
let mut interpreter = Interpreter::new_with_kernel(load_all_mpts, initial_stack);
|
||||
interpreter.generation_state.mpt_prover_inputs = all_mpt_prover_inputs_reversed(&trie_inputs);
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), vec![]);
|
||||
|
||||
let type_branch = U256::from(PartialTrieType::Branch as u32);
|
||||
assert_eq!(
|
||||
interpreter.get_trie_data(),
|
||||
vec![
|
||||
0.into(), // First address is unused, so that 0 can be treated as a null pointer.
|
||||
type_branch,
|
||||
0.into(), // child 0
|
||||
0.into(), // ...
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(),
|
||||
0.into(), // child 16
|
||||
0.into(), // value_ptr
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::TransactionTrieRoot),
|
||||
0.into()
|
||||
);
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::ReceiptTrieRoot),
|
||||
0.into()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::NumStorageTries),
|
||||
trie_inputs.storage_tries.len().into()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_all_mpts_ext_to_leaf() -> Result<()> {
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie: extension_to_leaf(test_account_1_rlp()),
|
||||
transactions_trie: Default::default(),
|
||||
receipts_trie: Default::default(),
|
||||
storage_tries: vec![],
|
||||
};
|
||||
|
||||
let load_all_mpts = KERNEL.global_labels["load_all_mpts"];
|
||||
|
||||
let initial_stack = vec![0xDEADBEEFu32.into()];
|
||||
let mut interpreter = Interpreter::new_with_kernel(load_all_mpts, initial_stack);
|
||||
interpreter.generation_state.mpt_prover_inputs = all_mpt_prover_inputs_reversed(&trie_inputs);
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), vec![]);
|
||||
|
||||
let type_empty = U256::from(PartialTrieType::Empty as u32);
|
||||
let type_extension = U256::from(PartialTrieType::Extension as u32);
|
||||
let type_leaf = U256::from(PartialTrieType::Leaf as u32);
|
||||
assert_eq!(
|
||||
@ -50,12 +204,10 @@ fn load_all_mpts() -> Result<()> {
|
||||
0xDEF.into(), // key part
|
||||
9.into(), // value pointer
|
||||
4.into(), // value length
|
||||
account.nonce,
|
||||
account.balance,
|
||||
account.storage_root.into_uint(),
|
||||
account.code_hash.into_uint(),
|
||||
type_empty, // txn trie
|
||||
type_empty, // receipt trie
|
||||
test_account_1().nonce,
|
||||
test_account_1().balance,
|
||||
test_account_1().storage_root.into_uint(),
|
||||
test_account_1().code_hash.into_uint(),
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@ -1,10 +1,40 @@
|
||||
use eth_trie_utils::partial_trie::{Nibbles, PartialTrie};
|
||||
use ethereum_types::{BigEndianHash, H256, U256};
|
||||
|
||||
use crate::generation::mpt::AccountRlp;
|
||||
|
||||
mod hash;
|
||||
mod hex_prefix;
|
||||
mod insert;
|
||||
mod load;
|
||||
mod read;
|
||||
|
||||
pub(crate) fn test_account_1() -> AccountRlp {
|
||||
AccountRlp {
|
||||
nonce: U256::from(1111),
|
||||
balance: U256::from(2222),
|
||||
storage_root: H256::from_uint(&U256::from(3333)),
|
||||
code_hash: H256::from_uint(&U256::from(4444)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn test_account_1_rlp() -> Vec<u8> {
|
||||
rlp::encode(&test_account_1()).to_vec()
|
||||
}
|
||||
|
||||
pub(crate) fn test_account_2() -> AccountRlp {
|
||||
AccountRlp {
|
||||
nonce: U256::from(5555),
|
||||
balance: U256::from(6666),
|
||||
storage_root: H256::from_uint(&U256::from(7777)),
|
||||
code_hash: H256::from_uint(&U256::from(8888)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn test_account_2_rlp() -> Vec<u8> {
|
||||
rlp::encode(&test_account_2()).to_vec()
|
||||
}
|
||||
|
||||
/// A `PartialTrie` where an extension node leads to a leaf node containing an account.
|
||||
pub(crate) fn extension_to_leaf(value: Vec<u8>) -> PartialTrie {
|
||||
PartialTrie::Extension {
|
||||
|
||||
@ -13,6 +13,17 @@ pub(crate) struct AccountRlp {
|
||||
pub(crate) code_hash: H256,
|
||||
}
|
||||
|
||||
impl AccountRlp {
|
||||
pub(crate) fn to_vec(&self) -> Vec<U256> {
|
||||
vec![
|
||||
self.nonce,
|
||||
self.balance,
|
||||
self.storage_root.into_uint(),
|
||||
self.code_hash.into_uint(),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn all_mpt_prover_inputs_reversed(trie_inputs: &TrieInputs) -> Vec<U256> {
|
||||
let mut inputs = all_mpt_prover_inputs(trie_inputs);
|
||||
inputs.reverse();
|
||||
@ -25,12 +36,7 @@ pub(crate) fn all_mpt_prover_inputs(trie_inputs: &TrieInputs) -> Vec<U256> {
|
||||
|
||||
mpt_prover_inputs(&trie_inputs.state_trie, &mut prover_inputs, &|rlp| {
|
||||
let account: AccountRlp = rlp::decode(rlp).expect("Decoding failed");
|
||||
vec![
|
||||
account.nonce,
|
||||
account.balance,
|
||||
account.storage_root.into_uint(),
|
||||
account.code_hash.into_uint(),
|
||||
]
|
||||
account.to_vec()
|
||||
});
|
||||
|
||||
mpt_prover_inputs(&trie_inputs.transactions_trie, &mut prover_inputs, &|rlp| {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user