mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-03 14:23:07 +00:00
Merge pull request #787 from mir-protocol/mpt_storage
MPT storage logic
This commit is contained in:
commit
076fe521b3
@ -39,6 +39,7 @@ pub(crate) fn combined_kernel() -> Kernel {
|
||||
include_str!("asm/memory/metadata.asm"),
|
||||
include_str!("asm/memory/packing.asm"),
|
||||
include_str!("asm/memory/txn_fields.asm"),
|
||||
include_str!("asm/mpt/accounts.asm"),
|
||||
include_str!("asm/mpt/delete/delete.asm"),
|
||||
include_str!("asm/mpt/hash/hash.asm"),
|
||||
include_str!("asm/mpt/hash/hash_trie_specific.asm"),
|
||||
@ -50,8 +51,8 @@ pub(crate) fn combined_kernel() -> Kernel {
|
||||
include_str!("asm/mpt/load/load.asm"),
|
||||
include_str!("asm/mpt/load/load_trie_specific.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/storage/storage_read.asm"),
|
||||
include_str!("asm/mpt/storage/storage_write.asm"),
|
||||
include_str!("asm/mpt/util.asm"),
|
||||
include_str!("asm/ripemd/box.asm"),
|
||||
include_str!("asm/ripemd/compression.asm"),
|
||||
@ -77,6 +78,7 @@ pub(crate) fn combined_kernel() -> Kernel {
|
||||
include_str!("asm/transactions/type_2.asm"),
|
||||
include_str!("asm/util/assertions.asm"),
|
||||
include_str!("asm/util/basic_macros.asm"),
|
||||
include_str!("asm/util/keccak.asm"),
|
||||
];
|
||||
|
||||
let parsed_files = files.iter().map(|f| parse(f)).collect_vec();
|
||||
|
||||
53
evm/src/cpu/kernel/asm/mpt/accounts.asm
Normal file
53
evm/src/cpu/kernel/asm/mpt/accounts.asm
Normal file
@ -0,0 +1,53 @@
|
||||
// Return a pointer to the current account's data in the state trie.
|
||||
%macro current_account_data
|
||||
ADDRESS %mpt_read_state_trie
|
||||
// stack: account_ptr
|
||||
// account_ptr should be non-null as long as the prover provided the proper
|
||||
// Merkle data. But a bad prover may not have, and we don't want return a
|
||||
// null pointer for security reasons.
|
||||
DUP1 ISZERO %jumpi(panic)
|
||||
// stack: account_ptr
|
||||
%endmacro
|
||||
|
||||
// Returns a pointer to the root of the storage trie associated with the current account.
|
||||
%macro current_storage_trie
|
||||
// stack: (empty)
|
||||
%current_account_data
|
||||
// stack: account_ptr
|
||||
%add_const(2)
|
||||
// stack: storage_root_ptr_ptr
|
||||
%mload_trie_data
|
||||
// stack: storage_root_ptr
|
||||
%endmacro
|
||||
|
||||
global make_default_account:
|
||||
PANIC // TODO
|
||||
|
||||
// Create a copy of the given account. The copy can then safely be mutated as
|
||||
// needed, while leaving the original account data untouched.
|
||||
//
|
||||
// This writes the new account's data to MPT data, but does not register the new
|
||||
// account in the state trie.
|
||||
//
|
||||
// Pre stack: old_account_ptr, retdest
|
||||
// Post stack: new_account_ptr
|
||||
global make_account_copy:
|
||||
// stack: old_account_ptr, retdest
|
||||
%get_trie_data_size // pointer to new account we're about to create
|
||||
// stack: new_account_ptr, old_account_ptr, retdest
|
||||
|
||||
DUP2 %mload_trie_data %append_to_trie_data
|
||||
DUP2 %add_const(1) %mload_trie_data %append_to_trie_data
|
||||
DUP2 %add_const(3) %mload_trie_data %append_to_trie_data
|
||||
SWAP1 %add_const(4) %mload_trie_data %append_to_trie_data
|
||||
|
||||
// stack: new_account_ptr, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
// Convenience macro to call make_account_copy and return where we left off.
|
||||
%macro make_account_copy
|
||||
%stack (old_account_ptr) -> (old_account_ptr, %%after)
|
||||
%jump(make_account_copy)
|
||||
%%after:
|
||||
%endmacro
|
||||
@ -95,4 +95,4 @@ encode_receipt:
|
||||
PANIC // TODO
|
||||
|
||||
encode_storage_value:
|
||||
PANIC // TODO
|
||||
PANIC // TODO: RLP encode as variable-len scalar?
|
||||
|
||||
@ -3,26 +3,26 @@
|
||||
// state trie. Returns null if the address is not found.
|
||||
global mpt_read_state_trie:
|
||||
// stack: addr, retdest
|
||||
// The key is the hash of the address. Since KECCAK_GENERAL takes input from
|
||||
// memory, we will write addr bytes to SEGMENT_KERNEL_GENERAL[0..20] first.
|
||||
%stack (addr) -> (0, @SEGMENT_KERNEL_GENERAL, 0, addr, 20, mpt_read_state_trie_after_mstore)
|
||||
%jump(mstore_unpacking)
|
||||
mpt_read_state_trie_after_mstore:
|
||||
// stack: retdest
|
||||
%stack () -> (0, @SEGMENT_KERNEL_GENERAL, 0, 20) // context, segment, offset, len
|
||||
KECCAK_GENERAL
|
||||
%addr_to_state_key
|
||||
// stack: key, retdest
|
||||
PUSH 64 // num_nibbles
|
||||
%mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) // node_ptr
|
||||
// stack: node_ptr, num_nibbles, key, retdest
|
||||
%jump(mpt_read)
|
||||
|
||||
// Convenience macro to call mpt_read_state_trie and return where we left off.
|
||||
%macro mpt_read_state_trie
|
||||
%stack (addr) -> (addr, %%after)
|
||||
%jump(mpt_read_state_trie)
|
||||
%%after:
|
||||
%endmacro
|
||||
|
||||
// Read a value from a MPT.
|
||||
//
|
||||
// Arguments:
|
||||
// - the virtual address of the trie to search in
|
||||
// - the key, as a U256
|
||||
// - the number of nibbles in the key (should start at 64)
|
||||
// - the key, as a U256
|
||||
//
|
||||
// This function returns a pointer to the value, or 0 if the key is not found.
|
||||
global mpt_read:
|
||||
|
||||
28
evm/src/cpu/kernel/asm/mpt/storage/storage_read.asm
Normal file
28
evm/src/cpu/kernel/asm/mpt/storage/storage_read.asm
Normal file
@ -0,0 +1,28 @@
|
||||
// Read a word from the current account's storage trie.
|
||||
//
|
||||
// Pre stack: slot, retdest
|
||||
// Post stack: value
|
||||
|
||||
global storage_read:
|
||||
// stack: slot, retdest
|
||||
%stack (slot) -> (slot, after_storage_read)
|
||||
%slot_to_storage_key
|
||||
// stack: storage_key, after_storage_read, retdest
|
||||
PUSH 64 // storage_key has 64 nibbles
|
||||
%current_storage_trie
|
||||
// stack: storage_root_ptr, 64, storage_key, after_storage_read, retdest
|
||||
%jump(mpt_read)
|
||||
|
||||
after_storage_read:
|
||||
// stack: value_ptr, retdest
|
||||
DUP1 %jumpi(storage_key_exists)
|
||||
|
||||
// Storage key not found; return default value of 0.
|
||||
%stack (value_ptr, retdest) -> (retdest, 0)
|
||||
JUMP
|
||||
|
||||
storage_key_exists:
|
||||
// stack: value_ptr, retdest
|
||||
%mload_trie_data // TODO: If we end up not using value pointers in storage tries, remove this.
|
||||
SWAP1
|
||||
JUMP
|
||||
33
evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm
Normal file
33
evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm
Normal file
@ -0,0 +1,33 @@
|
||||
// Write a word to the current account's storage trie.
|
||||
//
|
||||
// Pre stack: slot, value, retdest
|
||||
// Post stack: (empty)
|
||||
|
||||
global storage_write:
|
||||
// stack: slot, value, retdest
|
||||
// TODO: If value = 0, delete the key instead of inserting 0?
|
||||
// TODO: Do we need to write value to MPT data and insert value_ptr? Currently some logic assumes all values are pointers, but could be relaxed so a value is any single word.
|
||||
%stack (slot, value) -> (slot, value, after_storage_insert)
|
||||
%slot_to_storage_key
|
||||
// stack: storage_key, value, after_storage_write, retdest
|
||||
PUSH 64 // storage_key has 64 nibbles
|
||||
%current_storage_trie
|
||||
// stack: storage_root_ptr, 64, storage_key, value, after_storage_insert, retdest
|
||||
%jump(mpt_insert)
|
||||
|
||||
after_storage_insert:
|
||||
// stack: new_storage_root_ptr, retdest
|
||||
%current_account_data
|
||||
// stack: old_account_ptr, new_storage_root_ptr, retdest
|
||||
%make_account_copy
|
||||
// stack: new_account_ptr, new_storage_root_ptr, retdest
|
||||
|
||||
// Update the copied account with our new storage root pointer.
|
||||
%stack (new_account_ptr, new_storage_root_ptr) -> (new_account_ptr, new_storage_root_ptr, new_account_ptr)
|
||||
%add_const(2)
|
||||
// stack: new_account_storage_root_ptr_ptr, new_storage_root_ptr, new_account_ptr, retdest
|
||||
%mstore_trie_data
|
||||
// stack: new_account_ptr, retdest
|
||||
|
||||
SWAP1
|
||||
JUMP
|
||||
@ -1,2 +0,0 @@
|
||||
global storage_read:
|
||||
// TODO
|
||||
@ -1,2 +0,0 @@
|
||||
global storage_write:
|
||||
// TODO
|
||||
@ -165,3 +165,14 @@
|
||||
SWAP4 %div_const(4) SWAP4 // bits_2 -> len_2 (in nibbles)
|
||||
// stack: len_common, key_common, len_1, key_1, len_2, key_2
|
||||
%endmacro
|
||||
|
||||
// Computes state_key = Keccak256(addr). Clobbers @SEGMENT_KERNEL_GENERAL.
|
||||
%macro addr_to_state_key
|
||||
%keccak256_word(20)
|
||||
%endmacro
|
||||
|
||||
// Given a storage slot (a 256-bit integer), computes storage_key = Keccak256(slot).
|
||||
// Clobbers @SEGMENT_KERNEL_GENERAL.
|
||||
%macro slot_to_storage_key
|
||||
%keccak256_word(32)
|
||||
%endmacro
|
||||
|
||||
14
evm/src/cpu/kernel/asm/util/keccak.asm
Normal file
14
evm/src/cpu/kernel/asm/util/keccak.asm
Normal file
@ -0,0 +1,14 @@
|
||||
// Computes Keccak256(input_word). Clobbers @SEGMENT_KERNEL_GENERAL.
|
||||
//
|
||||
// Pre stack: input_word
|
||||
// Post stack: hash
|
||||
%macro keccak256_word(num_bytes)
|
||||
// Since KECCAK_GENERAL takes its input from memory, we will first write
|
||||
// input_word's bytes to @SEGMENT_KERNEL_GENERAL[0..$num_bytes].
|
||||
%stack (word) -> (0, @SEGMENT_KERNEL_GENERAL, 0, word, $num_bytes, %%after_mstore)
|
||||
%jump(mstore_unpacking)
|
||||
%%after_mstore:
|
||||
// stack: (empty)
|
||||
%stack () -> (0, @SEGMENT_KERNEL_GENERAL, 0, $num_bytes) // context, segment, offset, len
|
||||
KECCAK_GENERAL
|
||||
%endmacro
|
||||
@ -68,11 +68,10 @@ 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 value_len = 0.
|
||||
prover_inputs.push(U256::zero());
|
||||
prover_inputs.push(U256::zero()); // value_present = 0
|
||||
} else {
|
||||
let parsed_value = parse_value(value);
|
||||
prover_inputs.push(parsed_value.len().into());
|
||||
prover_inputs.push(U256::one()); // value_present = 1
|
||||
prover_inputs.extend(parsed_value);
|
||||
}
|
||||
for child in children {
|
||||
@ -107,8 +106,7 @@ pub(crate) fn mpt_prover_inputs_state_trie(
|
||||
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());
|
||||
prover_inputs.push(U256::zero()); // value_present = 0
|
||||
|
||||
for (i, child) in children.iter().enumerate() {
|
||||
let extended_key = key.merge(&Nibbles {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user