mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-04 23:03:08 +00:00
Treat storage tries as sub-tries of the state trie
I.e. have leaves in the state trie point to the root of a storage trie
This commit is contained in:
parent
34865026df
commit
7f366cdace
@ -14,7 +14,7 @@ ethereum-types = "0.14.0"
|
||||
hex = { version = "0.4.3", optional = true }
|
||||
hex-literal = "0.3.4"
|
||||
itertools = "0.10.3"
|
||||
keccak-hash = "0.9.0"
|
||||
keccak-hash = "0.10.0"
|
||||
log = "0.4.14"
|
||||
num = "0.4.0"
|
||||
maybe_rayon = { path = "../maybe_rayon" }
|
||||
|
||||
@ -48,6 +48,7 @@ pub(crate) fn combined_kernel() -> Kernel {
|
||||
include_str!("asm/mpt/insert_leaf.asm"),
|
||||
include_str!("asm/mpt/insert_trie_specific.asm"),
|
||||
include_str!("asm/mpt/load.asm"),
|
||||
include_str!("asm/mpt/load_trie_specific.asm"),
|
||||
include_str!("asm/mpt/read.asm"),
|
||||
include_str!("asm/mpt/storage_read.asm"),
|
||||
include_str!("asm/mpt/storage_write.asm"),
|
||||
|
||||
@ -47,7 +47,29 @@ mpt_hash_hash_rlp_after_unpacking:
|
||||
// Pre stack: node_ptr, encode_value, retdest
|
||||
// Post stack: result, result_len
|
||||
global encode_or_hash_node:
|
||||
%stack (node_ptr, encode_value) -> (node_ptr, encode_value, maybe_hash_node)
|
||||
// stack: node_ptr, encode_value, retdest
|
||||
DUP1 %mload_trie_data
|
||||
|
||||
// Check if we're dealing with a concrete node, i.e. not a hash node.
|
||||
// stack: node_type, node_ptr, encode_value, retdest
|
||||
DUP1
|
||||
PUSH @MPT_NODE_HASH
|
||||
SUB
|
||||
%jumpi(encode_or_hash_concrete_node)
|
||||
|
||||
// If we got here, node_type == @MPT_NODE_HASH.
|
||||
// Load the hash and return (hash, 32).
|
||||
// stack: node_type, node_ptr, encode_value, retdest
|
||||
POP
|
||||
// stack: node_ptr, encode_value, retdest
|
||||
%increment // Skip over node type prefix
|
||||
// stack: hash_ptr, encode_value, retdest
|
||||
%mload_trie_data
|
||||
// stack: hash, encode_value, retdest
|
||||
%stack (hash, encode_value, retdest) -> (retdest, hash, 32)
|
||||
JUMP
|
||||
encode_or_hash_concrete_node:
|
||||
%stack (node_type, node_ptr, encode_value) -> (node_type, node_ptr, encode_value, maybe_hash_node)
|
||||
%jump(encode_node)
|
||||
maybe_hash_node:
|
||||
// stack: result_ptr, result_len, retdest
|
||||
@ -75,22 +97,22 @@ after_packed_small_rlp:
|
||||
// RLP encode the given trie node, and return an (pointer, length) pair
|
||||
// indicating where the data lives within @SEGMENT_RLP_RAW.
|
||||
//
|
||||
// Pre stack: node_ptr, encode_value, retdest
|
||||
// Pre stack: node_type, node_ptr, encode_value, retdest
|
||||
// Post stack: result_ptr, result_len
|
||||
global encode_node:
|
||||
// stack: node_ptr, encode_value, retdest
|
||||
DUP1 %mload_trie_data
|
||||
encode_node:
|
||||
// stack: node_type, node_ptr, encode_value, retdest
|
||||
// Increment node_ptr, so it points to the node payload instead of its type.
|
||||
SWAP1 %increment SWAP1
|
||||
// stack: node_type, node_payload_ptr, encode_value, retdest
|
||||
|
||||
DUP1 %eq_const(@MPT_NODE_EMPTY) %jumpi(encode_node_empty)
|
||||
DUP1 %eq_const(@MPT_NODE_HASH) %jumpi(encode_node_hash)
|
||||
DUP1 %eq_const(@MPT_NODE_BRANCH) %jumpi(encode_node_branch)
|
||||
DUP1 %eq_const(@MPT_NODE_EXTENSION) %jumpi(encode_node_extension)
|
||||
DUP1 %eq_const(@MPT_NODE_LEAF) %jumpi(encode_node_leaf)
|
||||
PANIC // Invalid node type? Shouldn't get here.
|
||||
|
||||
// If we got here, node_type is either @MPT_NODE_HASH, which should have
|
||||
// been handled earlier in encode_or_hash_node, or something invalid.
|
||||
PANIC
|
||||
|
||||
global encode_node_empty:
|
||||
// stack: node_type, node_payload_ptr, encode_value, retdest
|
||||
@ -105,14 +127,6 @@ global encode_node_empty:
|
||||
%stack (retdest) -> (retdest, 0, 1)
|
||||
JUMP
|
||||
|
||||
global encode_node_hash:
|
||||
// stack: node_type, node_payload_ptr, encode_value, retdest
|
||||
POP
|
||||
// stack: node_payload_ptr, encode_value, retdest
|
||||
%mload_trie_data
|
||||
%stack (hash, encode_value, retdest) -> (retdest, hash, 32)
|
||||
JUMP
|
||||
|
||||
encode_node_branch:
|
||||
// stack: node_type, node_payload_ptr, encode_value, retdest
|
||||
POP
|
||||
|
||||
@ -72,8 +72,13 @@ global encode_account:
|
||||
// stack: balance, rlp_pos_4, value_ptr, retdest
|
||||
SWAP1 %encode_rlp_scalar
|
||||
// stack: rlp_pos_5, value_ptr, retdest
|
||||
DUP2 %add_const(2) %mload_trie_data // storage_root = value[2]
|
||||
// stack: storage_root, rlp_pos_5, value_ptr, retdest
|
||||
PUSH encode_account_after_hash_storage_trie
|
||||
PUSH encode_storage_value
|
||||
DUP4 %add_const(2) %mload_trie_data // storage_root_ptr = value[2]
|
||||
// stack: storage_root_ptr, encode_storage_value, encode_account_after_hash_storage_trie, rlp_pos_5, value_ptr, retdest
|
||||
%jump(mpt_hash)
|
||||
encode_account_after_hash_storage_trie:
|
||||
// stack: storage_root_digest, rlp_pos_5, value_ptr, retdest
|
||||
SWAP1 %encode_rlp_256
|
||||
// stack: rlp_pos_6, value_ptr, retdest
|
||||
SWAP1 %add_const(3) %mload_trie_data // code_hash = value[3]
|
||||
@ -88,3 +93,6 @@ encode_txn:
|
||||
|
||||
encode_receipt:
|
||||
PANIC // TODO
|
||||
|
||||
encode_storage_value:
|
||||
PANIC // TODO
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
// TODO: Receipt trie leaves are variable-length, so we need to be careful not
|
||||
// to permit buffer over-reads.
|
||||
|
||||
// Load all partial trie data from prover inputs.
|
||||
global load_all_mpts:
|
||||
// stack: retdest
|
||||
@ -9,47 +6,20 @@ global load_all_mpts:
|
||||
PUSH 1
|
||||
%set_trie_data_size
|
||||
|
||||
%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)
|
||||
%load_mpt(mpt_load_state_trie_value) %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT)
|
||||
%load_mpt(mpt_load_txn_trie_value) %mstore_global_metadata(@GLOBAL_METADATA_TXN_TRIE_ROOT)
|
||||
%load_mpt(mpt_load_receipt_trie_value) %mstore_global_metadata(@GLOBAL_METADATA_RECEIPT_TRIE_ROOT)
|
||||
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: num_storage_tries, retdest
|
||||
DUP1 %mstore_global_metadata(@GLOBAL_METADATA_NUM_STORAGE_TRIES)
|
||||
// stack: num_storage_tries, retdest
|
||||
PUSH 0 // i = 0
|
||||
// stack: i, num_storage_tries, retdest
|
||||
storage_trie_loop:
|
||||
DUP2 DUP2 EQ
|
||||
// stack: i == num_storage_tries, i, num_storage_tries, retdest
|
||||
%jumpi(storage_trie_loop_end)
|
||||
// stack: i, num_storage_tries, retdest
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: storage_trie_addr, i, num_storage_tries, retdest
|
||||
DUP2
|
||||
// stack: i, storage_trie_addr, i, num_storage_tries, retdest
|
||||
%mstore_kernel(@SEGMENT_STORAGE_TRIE_ADDRS)
|
||||
// stack: i, num_storage_tries, retdest
|
||||
%load_mpt
|
||||
// stack: root_ptr, i, num_storage_tries, retdest
|
||||
DUP2
|
||||
// stack: i, root_ptr, i, num_storage_tries, retdest
|
||||
%mstore_kernel(@SEGMENT_STORAGE_TRIE_PTRS)
|
||||
// stack: i, num_storage_tries, retdest
|
||||
%jump(storage_trie_loop)
|
||||
storage_trie_loop_end:
|
||||
// stack: i, num_storage_tries, retdest
|
||||
%pop2
|
||||
// stack: retdest
|
||||
JUMP
|
||||
|
||||
// Load an MPT from prover inputs.
|
||||
// Pre stack: retdest
|
||||
// Pre stack: load_value, retdest
|
||||
// Post stack: node_ptr
|
||||
load_mpt:
|
||||
// stack: retdest
|
||||
global load_mpt:
|
||||
// stack: load_value, retdest
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: node_type, retdest
|
||||
// stack: node_type, load_value, retdest
|
||||
|
||||
DUP1 %eq_const(@MPT_NODE_EMPTY) %jumpi(load_mpt_empty)
|
||||
DUP1 %eq_const(@MPT_NODE_BRANCH) %jumpi(load_mpt_branch)
|
||||
@ -60,146 +30,144 @@ load_mpt:
|
||||
|
||||
load_mpt_empty:
|
||||
// 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)
|
||||
%stack (node_type, load_value, retdest) -> (retdest, 0)
|
||||
JUMP
|
||||
|
||||
load_mpt_branch:
|
||||
// stack: node_type, retdest
|
||||
// stack: node_type, load_value, retdest
|
||||
%get_trie_data_size
|
||||
// stack: node_ptr, node_type, retdest
|
||||
// stack: node_ptr, node_type, load_value, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
// stack: node_ptr, load_value, retdest
|
||||
// Save the offset of our 16 child pointers so we can write them later.
|
||||
// Then advance our current trie pointer beyond them, so we can load the
|
||||
// value and have it placed after our child pointers.
|
||||
%get_trie_data_size
|
||||
// stack: children_ptr, node_ptr, retdest
|
||||
// stack: children_ptr, node_ptr, load_value, 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: children_ptr, node_ptr, retdest
|
||||
%load_value
|
||||
// stack: end_of_branch_ptr, children_ptr, node_ptr, load_value, retdest
|
||||
DUP1 %set_trie_data_size
|
||||
// Now the top of the stack points to where the branch node will end and the
|
||||
// value will begin, if there is a value. But we need to ask the prover if a
|
||||
// value is present, and point to null if not.
|
||||
// stack: end_of_branch_ptr, children_ptr, node_ptr, load_value, retdest
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: is_value_present, end_of_branch_ptr, children_ptr, node_ptr, load_value, retdest
|
||||
%jumpi(load_mpt_branch_value_present)
|
||||
// There is no value present, so value_ptr = null.
|
||||
%stack (end_of_branch_ptr) -> (0)
|
||||
// stack: value_ptr, children_ptr, node_ptr, load_value, retdest
|
||||
%jump(load_mpt_branch_after_load_value)
|
||||
load_mpt_branch_value_present:
|
||||
// stack: value_ptr, children_ptr, node_ptr, load_value, retdest
|
||||
PUSH load_mpt_branch_after_load_value
|
||||
DUP5 // load_value
|
||||
JUMP
|
||||
load_mpt_branch_after_load_value:
|
||||
// stack: value_ptr, children_ptr, node_ptr, load_value, retdest
|
||||
SWAP1
|
||||
// stack: children_ptr, value_ptr, node_ptr, retdest
|
||||
// stack: children_ptr, value_ptr, node_ptr, load_value, retdest
|
||||
|
||||
// Load the 16 children.
|
||||
%rep 16
|
||||
DUP4 // load_value
|
||||
%load_mpt
|
||||
// stack: child_ptr, next_child_ptr_ptr, value_ptr, node_ptr, retdest
|
||||
// stack: child_ptr, next_child_ptr_ptr, value_ptr, node_ptr, load_value, retdest
|
||||
DUP2
|
||||
// stack: next_child_ptr_ptr, child_ptr, next_child_ptr_ptr, value_ptr, node_ptr, retdest
|
||||
// stack: next_child_ptr_ptr, child_ptr, next_child_ptr_ptr, value_ptr, node_ptr, load_value, retdest
|
||||
%mstore_trie_data
|
||||
// stack: next_child_ptr_ptr, value_ptr, node_ptr, retdest
|
||||
// stack: next_child_ptr_ptr, value_ptr, node_ptr, load_value, retdest
|
||||
%increment
|
||||
// stack: next_child_ptr_ptr, value_ptr, node_ptr, retdest
|
||||
// stack: next_child_ptr_ptr, value_ptr, node_ptr, load_value, retdest
|
||||
%endrep
|
||||
|
||||
// stack: value_ptr_ptr, value_ptr, node_ptr, retdest
|
||||
// stack: value_ptr_ptr, value_ptr, node_ptr, load_value, retdest
|
||||
%mstore_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
SWAP1
|
||||
%stack (node_ptr, load_value, retdest) -> (retdest, node_ptr)
|
||||
JUMP
|
||||
|
||||
load_mpt_extension:
|
||||
// stack: node_type, retdest
|
||||
// stack: node_type, load_value, retdest
|
||||
%get_trie_data_size
|
||||
// stack: node_ptr, node_type, retdest
|
||||
// stack: node_ptr, node_type, load_value, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
// stack: node_ptr, load_value, retdest
|
||||
PROVER_INPUT(mpt) // read num_nibbles
|
||||
%append_to_trie_data
|
||||
PROVER_INPUT(mpt) // read packed_nibbles
|
||||
%append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
// stack: node_ptr, load_value, retdest
|
||||
|
||||
%get_trie_data_size
|
||||
// stack: child_ptr_ptr, node_ptr, retdest
|
||||
// stack: child_ptr_ptr, node_ptr, load_value, 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: child_ptr, child_ptr_ptr, node_ptr, retdest
|
||||
SWAP1
|
||||
%mstore_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
SWAP1
|
||||
%stack (child_ptr_ptr, node_ptr, load_value, retdest)
|
||||
-> (load_value, load_mpt_extension_after_load_mpt,
|
||||
child_ptr_ptr, retdest, node_ptr)
|
||||
%jump(load_mpt)
|
||||
load_mpt_extension_after_load_mpt:
|
||||
// stack: child_ptr, child_ptr_ptr, retdest, node_ptr
|
||||
SWAP1 %mstore_trie_data
|
||||
// stack: retdest, node_ptr
|
||||
JUMP
|
||||
|
||||
load_mpt_leaf:
|
||||
// stack: node_type, retdest
|
||||
// stack: node_type, load_value, retdest
|
||||
%get_trie_data_size
|
||||
// stack: node_ptr, node_type, retdest
|
||||
// stack: node_ptr, node_type, load_value, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
// stack: node_ptr, load_value, retdest
|
||||
PROVER_INPUT(mpt) // read num_nibbles
|
||||
%append_to_trie_data
|
||||
PROVER_INPUT(mpt) // read packed_nibbles
|
||||
%append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
// stack: node_ptr, load_value, 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.
|
||||
// to skip over the slot for value_ptr_ptr. We will write to value_ptr_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
|
||||
// stack: value_ptr_ptr, node_ptr, load_value, retdest
|
||||
DUP1 %increment
|
||||
// stack: value_ptr, value_ptr_ptr, node_ptr, load_value, retdest
|
||||
DUP1 %set_trie_data_size
|
||||
// stack: value_ptr, value_ptr_ptr, node_ptr, load_value, retdest
|
||||
%stack (value_ptr, value_ptr_ptr, node_ptr, load_value, retdest)
|
||||
-> (load_value, load_mpt_leaf_after_load_value,
|
||||
value_ptr_ptr, value_ptr, retdest, node_ptr)
|
||||
JUMP
|
||||
load_mpt_leaf_after_load_value:
|
||||
// stack: value_ptr_ptr, value_ptr, retdest, node_ptr
|
||||
%mstore_trie_data
|
||||
// stack: retdest, node_ptr
|
||||
JUMP
|
||||
|
||||
load_mpt_digest:
|
||||
// stack: node_type, retdest
|
||||
// stack: node_type, load_value, retdest
|
||||
%get_trie_data_size
|
||||
// stack: node_ptr, node_type, retdest
|
||||
// stack: node_ptr, node_type, load_value, retdest
|
||||
SWAP1 %append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
// stack: node_ptr, load_value, retdest
|
||||
PROVER_INPUT(mpt) // read digest
|
||||
%append_to_trie_data
|
||||
// stack: node_ptr, retdest
|
||||
SWAP1
|
||||
%stack (node_ptr, load_value, retdest) -> (retdest, node_ptr)
|
||||
JUMP
|
||||
|
||||
// Convenience macro to call load_mpt and return where we left off.
|
||||
// Pre stack: load_value
|
||||
// Post stack: node_ptr
|
||||
%macro load_mpt
|
||||
PUSH %%after
|
||||
%stack (load_value) -> (load_value, %%after)
|
||||
%jump(load_mpt)
|
||||
%%after:
|
||||
%endmacro
|
||||
|
||||
// Load a value from prover input, append it to trie data, and return a pointer to it.
|
||||
// Return null if the value is empty.
|
||||
%macro load_value
|
||||
// stack: (empty)
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: value_len
|
||||
DUP1 %jumpi(%%has_value)
|
||||
%stack (value_len) -> (0)
|
||||
%jump(%%end)
|
||||
%%has_value:
|
||||
// stack: value_len
|
||||
%get_trie_data_size
|
||||
// stack: value_ptr, value_len
|
||||
SWAP1
|
||||
// stack: value_len, value_ptr
|
||||
%%loop:
|
||||
DUP1 ISZERO
|
||||
// stack: value_len == 0, value_len, value_ptr
|
||||
%jumpi(%%finish_loop)
|
||||
// stack: value_len, value_ptr
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: value_part, value_len, value_ptr
|
||||
%append_to_trie_data
|
||||
// stack: value_len, value_ptr
|
||||
%decrement
|
||||
// stack: value_len', value_ptr
|
||||
%jump(%%loop)
|
||||
%%finish_loop:
|
||||
// stack: value_len, value_ptr
|
||||
POP
|
||||
// stack: value_ptr
|
||||
%%end:
|
||||
// Convenience macro to call load_mpt and return where we left off.
|
||||
// Pre stack: (empty)
|
||||
// Post stack: node_ptr
|
||||
%macro load_mpt(load_value)
|
||||
PUSH %%after
|
||||
PUSH $load_value
|
||||
%jump(load_mpt)
|
||||
%%after:
|
||||
%endmacro
|
||||
|
||||
40
evm/src/cpu/kernel/asm/mpt/load_trie_specific.asm
Normal file
40
evm/src/cpu/kernel/asm/mpt/load_trie_specific.asm
Normal file
@ -0,0 +1,40 @@
|
||||
global mpt_load_state_trie_value:
|
||||
// stack: retdest
|
||||
|
||||
// Load and append the nonce and balance.
|
||||
PROVER_INPUT(mpt) %append_to_trie_data
|
||||
PROVER_INPUT(mpt) %append_to_trie_data
|
||||
|
||||
// Now increment the trie data size by 2, to leave room for our storage trie
|
||||
// pointer and code hash fields, before calling load_mpt which will append
|
||||
// our storage trie data.
|
||||
%get_trie_data_size
|
||||
// stack: storage_trie_ptr_ptr, retdest
|
||||
DUP1 %add_const(2)
|
||||
// stack: storage_trie_ptr, storage_trie_ptr_ptr, retdest
|
||||
%set_trie_data_size
|
||||
// stack: storage_trie_ptr_ptr, retdest
|
||||
|
||||
%load_mpt(mpt_load_storage_trie_value)
|
||||
// stack: storage_trie_ptr, storage_trie_ptr_ptr, retdest
|
||||
DUP2 %mstore_trie_data
|
||||
// stack: storage_trie_ptr_ptr, retdest
|
||||
%increment
|
||||
// stack: code_hash_ptr, retdest
|
||||
PROVER_INPUT(mpt)
|
||||
// stack: code_hash, code_hash_ptr, retdest
|
||||
SWAP1 %mstore_trie_data
|
||||
// stack: retdest
|
||||
JUMP
|
||||
|
||||
global mpt_load_txn_trie_value:
|
||||
// stack: retdest
|
||||
PANIC // TODO
|
||||
|
||||
global mpt_load_receipt_trie_value:
|
||||
// stack: retdest
|
||||
PANIC // TODO
|
||||
|
||||
global mpt_load_storage_trie_value:
|
||||
// stack: retdest
|
||||
PANIC // TODO
|
||||
@ -21,7 +21,7 @@ pub(crate) enum ContextMetadata {
|
||||
/// prohibited.
|
||||
Static = 8,
|
||||
/// Pointer to the initial version of the state trie, at the creation of this context. Used when
|
||||
/// we need to revert a context. See also `StorageTrieCheckpointPointers`.
|
||||
/// we need to revert a context.
|
||||
StateTrieCheckpointPointer = 9,
|
||||
}
|
||||
|
||||
|
||||
@ -18,9 +18,6 @@ pub(crate) enum GlobalMetadata {
|
||||
TransactionTrieRoot = 5,
|
||||
/// A pointer to the root of the receipt trie within the `TrieData` buffer.
|
||||
ReceiptTrieRoot = 6,
|
||||
/// The number of storage tries involved in these transactions. I.e. the number of values in
|
||||
/// `StorageTrieAddresses`, `StorageTriePointers` and `StorageTrieCheckpointPointers`.
|
||||
NumStorageTries = 7,
|
||||
|
||||
// The root digests of each Merkle trie before these transactions.
|
||||
StateTrieRootDigestBefore = 8,
|
||||
@ -38,7 +35,7 @@ pub(crate) enum GlobalMetadata {
|
||||
}
|
||||
|
||||
impl GlobalMetadata {
|
||||
pub(crate) const COUNT: usize = 15;
|
||||
pub(crate) const COUNT: usize = 14;
|
||||
|
||||
pub(crate) fn all() -> [Self; Self::COUNT] {
|
||||
[
|
||||
@ -49,7 +46,6 @@ impl GlobalMetadata {
|
||||
Self::StateTrieRoot,
|
||||
Self::TransactionTrieRoot,
|
||||
Self::ReceiptTrieRoot,
|
||||
Self::NumStorageTries,
|
||||
Self::StateTrieRootDigestBefore,
|
||||
Self::TransactionTrieRootDigestBefore,
|
||||
Self::ReceiptTrieRootDigestBefore,
|
||||
@ -70,7 +66,6 @@ impl GlobalMetadata {
|
||||
GlobalMetadata::StateTrieRoot => "GLOBAL_METADATA_STATE_TRIE_ROOT",
|
||||
GlobalMetadata::TransactionTrieRoot => "GLOBAL_METADATA_TXN_TRIE_ROOT",
|
||||
GlobalMetadata::ReceiptTrieRoot => "GLOBAL_METADATA_RECEIPT_TRIE_ROOT",
|
||||
GlobalMetadata::NumStorageTries => "GLOBAL_METADATA_NUM_STORAGE_TRIES",
|
||||
GlobalMetadata::StateTrieRootDigestBefore => "GLOBAL_METADATA_STATE_TRIE_DIGEST_BEFORE",
|
||||
GlobalMetadata::TransactionTrieRootDigestBefore => {
|
||||
"GLOBAL_METADATA_TXN_TRIE_DIGEST_BEFORE"
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
use anyhow::Result;
|
||||
use eth_trie_utils::partial_trie::PartialTrie;
|
||||
use ethereum_types::{BigEndianHash, H256, U256};
|
||||
use ethereum_types::{BigEndianHash, H256};
|
||||
|
||||
use super::nibbles;
|
||||
use crate::cpu::kernel::aggregator::KERNEL;
|
||||
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_rlp, test_account_2_rlp};
|
||||
use crate::generation::mpt::all_mpt_prover_inputs_reversed;
|
||||
use crate::generation::TrieInputs;
|
||||
|
||||
// TODO: Test with short leaf. Might need to be a storage trie.
|
||||
@ -24,73 +24,69 @@ fn mpt_hash_empty() -> Result<()> {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mpt_hash_leaf() -> 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)),
|
||||
fn mpt_hash_empty_branch() -> Result<()> {
|
||||
let children = std::array::from_fn(|_| PartialTrie::Empty.into());
|
||||
let state_trie = PartialTrie::Branch {
|
||||
children,
|
||||
value: vec![],
|
||||
};
|
||||
let account_rlp = rlp::encode(&account);
|
||||
|
||||
let state_trie = PartialTrie::Leaf {
|
||||
nibbles: nibbles(0xABC),
|
||||
value: account_rlp.to_vec(),
|
||||
};
|
||||
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie,
|
||||
transactions_trie: Default::default(),
|
||||
receipts_trie: Default::default(),
|
||||
storage_tries: vec![],
|
||||
};
|
||||
test_state_trie(trie_inputs)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mpt_hash_hash() -> Result<()> {
|
||||
let hash = H256::random();
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie: PartialTrie::Hash(hash),
|
||||
transactions_trie: Default::default(),
|
||||
receipts_trie: Default::default(),
|
||||
storage_tries: vec![],
|
||||
};
|
||||
|
||||
test_state_trie(trie_inputs)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mpt_hash_leaf() -> Result<()> {
|
||||
let state_trie = PartialTrie::Leaf {
|
||||
nibbles: nibbles(0xABC),
|
||||
value: test_account_1_rlp(),
|
||||
};
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie,
|
||||
transactions_trie: Default::default(),
|
||||
receipts_trie: Default::default(),
|
||||
storage_tries: vec![],
|
||||
};
|
||||
test_state_trie(trie_inputs)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mpt_hash_extension_to_leaf() -> 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);
|
||||
|
||||
let state_trie = extension_to_leaf(account_rlp.to_vec());
|
||||
|
||||
let state_trie = extension_to_leaf(test_account_1_rlp());
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie,
|
||||
transactions_trie: Default::default(),
|
||||
receipts_trie: Default::default(),
|
||||
storage_tries: vec![],
|
||||
};
|
||||
|
||||
test_state_trie(trie_inputs)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mpt_hash_branch_to_leaf() -> 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);
|
||||
|
||||
let leaf = PartialTrie::Leaf {
|
||||
nibbles: nibbles(0xABC),
|
||||
value: account_rlp.to_vec(),
|
||||
value: test_account_2_rlp(),
|
||||
}
|
||||
.into();
|
||||
let mut children = std::array::from_fn(|_| PartialTrie::Empty.into());
|
||||
children[5] = PartialTrie::Branch {
|
||||
children: children.clone(),
|
||||
value: vec![],
|
||||
}
|
||||
.into();
|
||||
children[3] = leaf;
|
||||
let state_trie = PartialTrie::Branch {
|
||||
children,
|
||||
|
||||
@ -6,13 +6,13 @@ use super::nibbles;
|
||||
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::{test_account_1_rlp, test_account_2_rlp};
|
||||
use crate::cpu::kernel::tests::mpt::{test_account_1_rlp, test_account_2};
|
||||
use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp};
|
||||
use crate::generation::TrieInputs;
|
||||
|
||||
#[test]
|
||||
fn mpt_insert_empty() -> Result<()> {
|
||||
test_state_trie(Default::default(), nibbles(0xABC), test_account_2_rlp())
|
||||
test_state_trie(Default::default(), nibbles(0xABC), test_account_2())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -22,7 +22,7 @@ fn mpt_insert_leaf_identical_keys() -> Result<()> {
|
||||
nibbles: key,
|
||||
value: test_account_1_rlp(),
|
||||
};
|
||||
test_state_trie(state_trie, key, test_account_2_rlp())
|
||||
test_state_trie(state_trie, key, test_account_2())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -31,7 +31,7 @@ fn mpt_insert_leaf_nonoverlapping_keys() -> Result<()> {
|
||||
nibbles: nibbles(0xABC),
|
||||
value: test_account_1_rlp(),
|
||||
};
|
||||
test_state_trie(state_trie, nibbles(0x123), test_account_2_rlp())
|
||||
test_state_trie(state_trie, nibbles(0x123), test_account_2())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -40,7 +40,7 @@ fn mpt_insert_leaf_overlapping_keys() -> Result<()> {
|
||||
nibbles: nibbles(0xABC),
|
||||
value: test_account_1_rlp(),
|
||||
};
|
||||
test_state_trie(state_trie, nibbles(0xADE), test_account_2_rlp())
|
||||
test_state_trie(state_trie, nibbles(0xADE), test_account_2())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -49,7 +49,7 @@ fn mpt_insert_leaf_insert_key_extends_leaf_key() -> Result<()> {
|
||||
nibbles: nibbles(0xABC),
|
||||
value: test_account_1_rlp(),
|
||||
};
|
||||
test_state_trie(state_trie, nibbles(0xABCDE), test_account_2_rlp())
|
||||
test_state_trie(state_trie, nibbles(0xABCDE), test_account_2())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -58,7 +58,7 @@ fn mpt_insert_leaf_leaf_key_extends_insert_key() -> Result<()> {
|
||||
nibbles: nibbles(0xABCDE),
|
||||
value: test_account_1_rlp(),
|
||||
};
|
||||
test_state_trie(state_trie, nibbles(0xABC), test_account_2_rlp())
|
||||
test_state_trie(state_trie, nibbles(0xABC), test_account_2())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -69,10 +69,13 @@ fn mpt_insert_branch_replacing_empty_child() -> Result<()> {
|
||||
value: vec![],
|
||||
};
|
||||
|
||||
test_state_trie(state_trie, nibbles(0xABC), test_account_2_rlp())
|
||||
test_state_trie(state_trie, nibbles(0xABC), test_account_2())
|
||||
}
|
||||
|
||||
#[test]
|
||||
// TODO: Not a valid test because branches state trie cannot have branch values.
|
||||
// We should change it to use a different trie.
|
||||
#[ignore]
|
||||
fn mpt_insert_extension_nonoverlapping_keys() -> Result<()> {
|
||||
// Existing keys are 0xABC, 0xABCDEF; inserted key is 0x12345.
|
||||
let mut children = std::array::from_fn(|_| PartialTrie::Empty.into());
|
||||
@ -89,10 +92,13 @@ fn mpt_insert_extension_nonoverlapping_keys() -> Result<()> {
|
||||
}
|
||||
.into(),
|
||||
};
|
||||
test_state_trie(state_trie, nibbles(0x12345), test_account_2_rlp())
|
||||
test_state_trie(state_trie, nibbles(0x12345), test_account_2())
|
||||
}
|
||||
|
||||
#[test]
|
||||
// TODO: Not a valid test because branches state trie cannot have branch values.
|
||||
// We should change it to use a different trie.
|
||||
#[ignore]
|
||||
fn mpt_insert_extension_insert_key_extends_node_key() -> Result<()> {
|
||||
// Existing keys are 0xA, 0xABCD; inserted key is 0xABCDEF.
|
||||
let mut children = std::array::from_fn(|_| PartialTrie::Empty.into());
|
||||
@ -109,7 +115,7 @@ fn mpt_insert_extension_insert_key_extends_node_key() -> Result<()> {
|
||||
}
|
||||
.into(),
|
||||
};
|
||||
test_state_trie(state_trie, nibbles(0xABCDEF), test_account_2_rlp())
|
||||
test_state_trie(state_trie, nibbles(0xABCDEF), test_account_2())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -126,10 +132,14 @@ fn mpt_insert_branch_to_leaf_same_key() -> Result<()> {
|
||||
value: vec![],
|
||||
};
|
||||
|
||||
test_state_trie(state_trie, nibbles(0xABCD), test_account_2_rlp())
|
||||
test_state_trie(state_trie, nibbles(0xABCD), test_account_2())
|
||||
}
|
||||
|
||||
fn test_state_trie(state_trie: PartialTrie, k: Nibbles, v: Vec<u8>) -> Result<()> {
|
||||
/// Note: The account's storage_root is ignored, as we can't insert a new storage_root without the
|
||||
/// accompanying trie data. An empty trie's storage_root is used instead.
|
||||
fn test_state_trie(state_trie: PartialTrie, k: Nibbles, mut account: AccountRlp) -> Result<()> {
|
||||
account.storage_root = PartialTrie::Empty.calc_hash();
|
||||
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie: state_trie.clone(),
|
||||
transactions_trie: Default::default(),
|
||||
@ -155,9 +165,13 @@ fn test_state_trie(state_trie: PartialTrie, k: Nibbles, v: Vec<u8>) -> Result<()
|
||||
trie_data.push(0.into());
|
||||
}
|
||||
let value_ptr = trie_data.len();
|
||||
let account: AccountRlp = rlp::decode(&v).expect("Decoding failed");
|
||||
let account_data = account.to_vec();
|
||||
trie_data.extend(account_data);
|
||||
trie_data.push(account.nonce);
|
||||
trie_data.push(account.balance);
|
||||
// In memory, storage_root gets interpreted as a pointer to a storage trie,
|
||||
// so we have to ensure the pointer is valid. It's easiest to set it to 0,
|
||||
// which works as an empty node, since trie_data[0] = 0 = MPT_TYPE_EMPTY.
|
||||
trie_data.push(H256::zero().into_uint());
|
||||
trie_data.push(account.code_hash.into_uint());
|
||||
let trie_data_len = trie_data.len().into();
|
||||
interpreter.set_global_metadata_field(GlobalMetadata::TrieDataSize, trie_data_len);
|
||||
interpreter.push(0xDEADBEEFu32.into());
|
||||
@ -186,7 +200,7 @@ fn test_state_trie(state_trie: PartialTrie, k: Nibbles, v: Vec<u8>) -> Result<()
|
||||
);
|
||||
let hash = H256::from_uint(&interpreter.stack()[0]);
|
||||
|
||||
let updated_trie = state_trie.insert(k, v);
|
||||
let updated_trie = state_trie.insert(k, rlp::encode(&account).to_vec());
|
||||
let expected_state_trie_hash = updated_trie.calc_hash();
|
||||
assert_eq!(hash, expected_state_trie_hash);
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use eth_trie_utils::partial_trie::PartialTrie;
|
||||
use ethereum_types::{BigEndianHash, U256};
|
||||
use ethereum_types::{BigEndianHash, H256, U256};
|
||||
|
||||
use crate::cpu::kernel::constants::global_metadata::GlobalMetadata;
|
||||
use crate::cpu::kernel::constants::trie_type::PartialTrieType;
|
||||
@ -42,11 +42,6 @@ fn load_all_mpts_empty() -> Result<()> {
|
||||
0.into()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::NumStorageTries),
|
||||
trie_inputs.storage_tries.len().into()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -81,8 +76,11 @@ fn load_all_mpts_leaf() -> Result<()> {
|
||||
5.into(), // value ptr
|
||||
test_account_1().nonce,
|
||||
test_account_1().balance,
|
||||
test_account_1().storage_root.into_uint(),
|
||||
9.into(), // pointer to storage trie root
|
||||
test_account_1().code_hash.into_uint(),
|
||||
// These last two elements encode the storage trie, which is a hash node.
|
||||
(PartialTrieType::Hash as u32).into(),
|
||||
test_account_1().storage_root.into_uint(),
|
||||
]
|
||||
);
|
||||
|
||||
@ -95,9 +93,40 @@ fn load_all_mpts_leaf() -> Result<()> {
|
||||
0.into()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_all_mpts_hash() -> Result<()> {
|
||||
let hash = H256::random();
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie: PartialTrie::Hash(hash),
|
||||
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_hash = U256::from(PartialTrieType::Hash as u32);
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::NumStorageTries),
|
||||
trie_inputs.storage_tries.len().into()
|
||||
interpreter.get_trie_data(),
|
||||
vec![0.into(), type_hash, 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()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@ -160,11 +189,6 @@ fn load_all_mpts_empty_branch() -> Result<()> {
|
||||
0.into()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::NumStorageTries),
|
||||
trie_inputs.storage_tries.len().into()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -201,15 +225,13 @@ fn load_all_mpts_ext_to_leaf() -> Result<()> {
|
||||
9.into(), // value pointer
|
||||
test_account_1().nonce,
|
||||
test_account_1().balance,
|
||||
test_account_1().storage_root.into_uint(),
|
||||
13.into(), // pointer to storage trie root
|
||||
test_account_1().code_hash.into_uint(),
|
||||
// These last two elements encode the storage trie, which is a hash node.
|
||||
(PartialTrieType::Hash as u32).into(),
|
||||
test_account_1().storage_root.into_uint(),
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_global_metadata_field(GlobalMetadata::NumStorageTries),
|
||||
trie_inputs.storage_tries.len().into()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,25 +1,17 @@
|
||||
use anyhow::Result;
|
||||
use ethereum_types::{BigEndianHash, H256, U256};
|
||||
use ethereum_types::BigEndianHash;
|
||||
|
||||
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;
|
||||
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 mpt_read() -> 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);
|
||||
|
||||
let trie_inputs = TrieInputs {
|
||||
state_trie: extension_to_leaf(account_rlp.to_vec()),
|
||||
state_trie: extension_to_leaf(test_account_1_rlp()),
|
||||
transactions_trie: Default::default(),
|
||||
receipts_trie: Default::default(),
|
||||
storage_tries: vec![],
|
||||
@ -45,10 +37,11 @@ fn mpt_read() -> Result<()> {
|
||||
assert_eq!(interpreter.stack().len(), 1);
|
||||
let result_ptr = interpreter.stack()[0].as_usize();
|
||||
let result = &interpreter.get_trie_data()[result_ptr..][..4];
|
||||
assert_eq!(result[0], account.nonce);
|
||||
assert_eq!(result[1], account.balance);
|
||||
assert_eq!(result[2], account.storage_root.into_uint());
|
||||
assert_eq!(result[3], account.code_hash.into_uint());
|
||||
assert_eq!(result[0], test_account_1().nonce);
|
||||
assert_eq!(result[1], test_account_1().balance);
|
||||
// result[2] is the storage root pointer. We won't check that it matches a
|
||||
// particular address, since that seems like over-specifying.
|
||||
assert_eq!(result[3], test_account_1().code_hash.into_uint());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use eth_trie_utils::partial_trie::PartialTrie;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use eth_trie_utils::partial_trie::{Nibbles, PartialTrie};
|
||||
use ethereum_types::{BigEndianHash, H256, U256};
|
||||
use keccak_hash::keccak;
|
||||
use rlp_derive::{RlpDecodable, RlpEncodable};
|
||||
|
||||
use crate::cpu::kernel::constants::trie_type::PartialTrieType;
|
||||
@ -13,17 +16,6 @@ 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();
|
||||
@ -34,10 +26,18 @@ pub(crate) fn all_mpt_prover_inputs_reversed(trie_inputs: &TrieInputs) -> Vec<U2
|
||||
pub(crate) fn all_mpt_prover_inputs(trie_inputs: &TrieInputs) -> Vec<U256> {
|
||||
let mut prover_inputs = vec![];
|
||||
|
||||
mpt_prover_inputs(&trie_inputs.state_trie, &mut prover_inputs, &|rlp| {
|
||||
let account: AccountRlp = rlp::decode(rlp).expect("Decoding failed");
|
||||
account.to_vec()
|
||||
});
|
||||
let storage_tries_by_state_key = trie_inputs
|
||||
.storage_tries
|
||||
.iter()
|
||||
.map(|(address, storage_trie)| (Nibbles::from(keccak(address)), storage_trie))
|
||||
.collect();
|
||||
|
||||
mpt_prover_inputs_state_trie(
|
||||
&trie_inputs.state_trie,
|
||||
empty_nibbles(),
|
||||
&mut prover_inputs,
|
||||
&storage_tries_by_state_key,
|
||||
);
|
||||
|
||||
mpt_prover_inputs(&trie_inputs.transactions_trie, &mut prover_inputs, &|rlp| {
|
||||
rlp::decode_list(rlp)
|
||||
@ -48,14 +48,6 @@ pub(crate) fn all_mpt_prover_inputs(trie_inputs: &TrieInputs) -> Vec<U256> {
|
||||
vec![]
|
||||
});
|
||||
|
||||
prover_inputs.push(trie_inputs.storage_tries.len().into());
|
||||
for (addr, storage_trie) in &trie_inputs.storage_tries {
|
||||
prover_inputs.push(addr.0.as_ref().into());
|
||||
mpt_prover_inputs(storage_trie, &mut prover_inputs, &|leaf_be| {
|
||||
vec![U256::from_big_endian(leaf_be)]
|
||||
});
|
||||
}
|
||||
|
||||
prover_inputs
|
||||
}
|
||||
|
||||
@ -66,7 +58,7 @@ pub(crate) fn all_mpt_prover_inputs(trie_inputs: &TrieInputs) -> Vec<U256> {
|
||||
pub(crate) fn mpt_prover_inputs<F>(
|
||||
trie: &PartialTrie,
|
||||
prover_inputs: &mut Vec<U256>,
|
||||
parse_leaf: &F,
|
||||
parse_value: &F,
|
||||
) where
|
||||
F: Fn(&[u8]) -> Vec<U256>,
|
||||
{
|
||||
@ -76,28 +68,108 @@ pub(crate) fn mpt_prover_inputs<F>(
|
||||
PartialTrie::Hash(h) => prover_inputs.push(U256::from_big_endian(h.as_bytes())),
|
||||
PartialTrie::Branch { children, value } => {
|
||||
if value.is_empty() {
|
||||
// There's no value, so length=0.
|
||||
// There's no value, so value_len = 0.
|
||||
prover_inputs.push(U256::zero());
|
||||
} else {
|
||||
let leaf = parse_leaf(value);
|
||||
prover_inputs.push(leaf.len().into());
|
||||
prover_inputs.extend(leaf);
|
||||
let parsed_value = parse_value(value);
|
||||
prover_inputs.push(parsed_value.len().into());
|
||||
prover_inputs.extend(parsed_value);
|
||||
}
|
||||
for child in children {
|
||||
mpt_prover_inputs(child, prover_inputs, parse_leaf);
|
||||
mpt_prover_inputs(child, prover_inputs, parse_value);
|
||||
}
|
||||
}
|
||||
PartialTrie::Extension { nibbles, child } => {
|
||||
prover_inputs.push(nibbles.count.into());
|
||||
prover_inputs.push(nibbles.packed);
|
||||
mpt_prover_inputs(child, prover_inputs, parse_leaf);
|
||||
mpt_prover_inputs(child, prover_inputs, parse_value);
|
||||
}
|
||||
PartialTrie::Leaf { nibbles, value } => {
|
||||
prover_inputs.push(nibbles.count.into());
|
||||
prover_inputs.push(nibbles.packed);
|
||||
let leaf = parse_leaf(value);
|
||||
prover_inputs.push(leaf.len().into());
|
||||
let leaf = parse_value(value);
|
||||
prover_inputs.extend(leaf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `mpt_prover_inputs`, but for the state trie, which is a bit unique since each value
|
||||
/// leads to a storage trie which we recursively traverse.
|
||||
pub(crate) fn mpt_prover_inputs_state_trie(
|
||||
trie: &PartialTrie,
|
||||
key: Nibbles,
|
||||
prover_inputs: &mut Vec<U256>,
|
||||
storage_tries_by_state_key: &HashMap<Nibbles, &PartialTrie>,
|
||||
) {
|
||||
prover_inputs.push((PartialTrieType::of(trie) as u32).into());
|
||||
match trie {
|
||||
PartialTrie::Empty => {}
|
||||
PartialTrie::Hash(h) => prover_inputs.push(U256::from_big_endian(h.as_bytes())),
|
||||
PartialTrie::Branch { children, value } => {
|
||||
assert!(value.is_empty(), "State trie should not have branch values");
|
||||
// There's no value, so value_len = 0.
|
||||
prover_inputs.push(U256::zero());
|
||||
|
||||
for (i, child) in children.iter().enumerate() {
|
||||
let extended_key = key.merge(&Nibbles {
|
||||
count: 1,
|
||||
packed: i.into(),
|
||||
});
|
||||
mpt_prover_inputs_state_trie(
|
||||
child,
|
||||
extended_key,
|
||||
prover_inputs,
|
||||
storage_tries_by_state_key,
|
||||
);
|
||||
}
|
||||
}
|
||||
PartialTrie::Extension { nibbles, child } => {
|
||||
prover_inputs.push(nibbles.count.into());
|
||||
prover_inputs.push(nibbles.packed);
|
||||
let extended_key = key.merge(nibbles);
|
||||
mpt_prover_inputs_state_trie(
|
||||
child,
|
||||
extended_key,
|
||||
prover_inputs,
|
||||
storage_tries_by_state_key,
|
||||
);
|
||||
}
|
||||
PartialTrie::Leaf { nibbles, value } => {
|
||||
let account: AccountRlp = rlp::decode(value).expect("Decoding failed");
|
||||
let AccountRlp {
|
||||
nonce,
|
||||
balance,
|
||||
storage_root,
|
||||
code_hash,
|
||||
} = account;
|
||||
|
||||
let storage_hash_only = PartialTrie::Hash(storage_root);
|
||||
let storage_trie: &PartialTrie = storage_tries_by_state_key
|
||||
.get(&key)
|
||||
.copied()
|
||||
.unwrap_or(&storage_hash_only);
|
||||
|
||||
assert_eq!(storage_trie.calc_hash(), storage_root,
|
||||
"In TrieInputs, an account's storage_root didn't match the associated storage trie hash");
|
||||
|
||||
prover_inputs.push(nibbles.count.into());
|
||||
prover_inputs.push(nibbles.packed);
|
||||
prover_inputs.push(nonce);
|
||||
prover_inputs.push(balance);
|
||||
mpt_prover_inputs(storage_trie, prover_inputs, &parse_storage_value);
|
||||
prover_inputs.push(code_hash.into_uint());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_storage_value(value_rlp: &[u8]) -> Vec<U256> {
|
||||
let value: U256 = rlp::decode(value_rlp).expect("Decoding failed");
|
||||
vec![value]
|
||||
}
|
||||
|
||||
fn empty_nibbles() -> Nibbles {
|
||||
Nibbles {
|
||||
count: 0,
|
||||
packed: U256::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,23 +29,14 @@ pub(crate) enum Segment {
|
||||
/// Contains all trie data. Tries are stored as immutable, copy-on-write trees, so this is an
|
||||
/// append-only buffer. It is owned by the kernel, so it only lives on context 0.
|
||||
TrieData = 12,
|
||||
/// The account address associated with the `i`th storage trie. Only lives on context 0.
|
||||
StorageTrieAddresses = 13,
|
||||
/// A pointer to the `i`th storage trie within the `TrieData` buffer. Only lives on context 0.
|
||||
StorageTriePointers = 14,
|
||||
/// Like `StorageTriePointers`, except that these pointers correspond to the version of each
|
||||
/// trie at the creation of a given context. This lets us easily revert a context by replacing
|
||||
/// `StorageTriePointers` with `StorageTrieCheckpointPointers`.
|
||||
/// See also `StateTrieCheckpointPointer`.
|
||||
StorageTrieCheckpointPointers = 15,
|
||||
/// A buffer used to store the encodings of a branch node's children.
|
||||
TrieEncodedChild = 16,
|
||||
TrieEncodedChild = 13,
|
||||
/// A buffer used to store the lengths of the encodings of a branch node's children.
|
||||
TrieEncodedChildLen = 17,
|
||||
TrieEncodedChildLen = 14,
|
||||
}
|
||||
|
||||
impl Segment {
|
||||
pub(crate) const COUNT: usize = 18;
|
||||
pub(crate) const COUNT: usize = 15;
|
||||
|
||||
pub(crate) fn all() -> [Self; Self::COUNT] {
|
||||
[
|
||||
@ -62,9 +53,6 @@ impl Segment {
|
||||
Self::TxnData,
|
||||
Self::RlpRaw,
|
||||
Self::TrieData,
|
||||
Self::StorageTrieAddresses,
|
||||
Self::StorageTriePointers,
|
||||
Self::StorageTrieCheckpointPointers,
|
||||
Self::TrieEncodedChild,
|
||||
Self::TrieEncodedChildLen,
|
||||
]
|
||||
@ -86,9 +74,6 @@ impl Segment {
|
||||
Segment::TxnData => "SEGMENT_TXN_DATA",
|
||||
Segment::RlpRaw => "SEGMENT_RLP_RAW",
|
||||
Segment::TrieData => "SEGMENT_TRIE_DATA",
|
||||
Segment::StorageTrieAddresses => "SEGMENT_STORAGE_TRIE_ADDRS",
|
||||
Segment::StorageTriePointers => "SEGMENT_STORAGE_TRIE_PTRS",
|
||||
Segment::StorageTrieCheckpointPointers => "SEGMENT_STORAGE_TRIE_CHECKPOINT_PTRS",
|
||||
Segment::TrieEncodedChild => "SEGMENT_TRIE_ENCODED_CHILD",
|
||||
Segment::TrieEncodedChildLen => "SEGMENT_TRIE_ENCODED_CHILD_LEN",
|
||||
}
|
||||
@ -110,9 +95,6 @@ impl Segment {
|
||||
Segment::TxnData => 256,
|
||||
Segment::RlpRaw => 8,
|
||||
Segment::TrieData => 256,
|
||||
Segment::StorageTrieAddresses => 160,
|
||||
Segment::StorageTriePointers => 32,
|
||||
Segment::StorageTrieCheckpointPointers => 32,
|
||||
Segment::TrieEncodedChild => 256,
|
||||
Segment::TrieEncodedChildLen => 6,
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user