MPT hashing logic, part 1

This commit is contained in:
Daniel Lubarov 2022-09-30 13:04:16 -07:00
parent a7b518003f
commit 12247047ae
10 changed files with 187 additions and 5 deletions

View File

@ -43,6 +43,7 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/rlp/decode.asm"),
include_str!("asm/rlp/read_to_memory.asm"),
include_str!("asm/mpt/hash.asm"),
include_str!("asm/mpt/hex_prefix.asm"),
include_str!("asm/mpt/load.asm"),
include_str!("asm/mpt/read.asm"),
include_str!("asm/mpt/storage_read.asm"),

View File

@ -1,8 +1,20 @@
global main:
// First, load all MPT data from the prover.
PUSH txn_loop
%jump(load_all_mpts)
hash_initial_tries:
// TODO: Hash each trie and set @GLOBAL_METADATA_STATE_TRIE_DIGEST_BEFORE, etc.
txn_loop:
// If the prover has no more txns for us to process, halt.
PROVER_INPUT(end_of_txns)
%jumpi(halt)
%jumpi(hash_final_tries)
// Call route_txn, returning to main to continue the loop.
PUSH main
// Call route_txn. When we return, continue the txn loop.
PUSH txn_loop
%jump(route_txn)
hash_final_tries:
// TODO: Hash each trie and set @GLOBAL_METADATA_STATE_TRIE_DIGEST_AFTER, etc.
%jump(halt)

View File

@ -98,3 +98,10 @@
%mstore_kernel(@SEGMENT_CODE)
// stack: (empty)
%endmacro
// Store a single value to @SEGMENT_KERNEL_GENERAL.
%macro mstore_kernel_general
// stack: offset, value
%mstore_kernel(@SEGMENT_KERNEL_GENERAL)
// stack: (empty)
%endmacro

View File

@ -1,2 +1,48 @@
global mpt_hash:
// TODO
// stack: node_ptr, retdest
DUP1
%mload_trie_data
// stack: node_type, node_ptr, retdest
// Increment node_ptr, so it points to the node payload instead of its type.
SWAP1 %add_const(1) SWAP1
// stack: node_type, node_payload_ptr, retdest
DUP1 %eq_const(@MPT_NODE_EMPTY) %jumpi(mpt_hash_empty)
DUP1 %eq_const(@MPT_NODE_HASH) %jumpi(mpt_hash_hash)
DUP1 %eq_const(@MPT_NODE_BRANCH) %jumpi(mpt_hash_branch)
DUP1 %eq_const(@MPT_NODE_EXTENSION) %jumpi(mpt_hash_extension)
DUP1 %eq_const(@MPT_NODE_LEAF) %jumpi(mpt_hash_leaf)
PANIC // Invalid node type? Shouldn't get here.
mpt_hash_empty:
%stack (node_type, node_payload_ptr, retdest) -> (retdest, @EMPTY_NODE_HASH)
JUMP
mpt_hash_hash:
// stack: node_type, node_payload_ptr, retdest
POP
// stack: node_payload_ptr, retdest
%mload_trie_data
// stack: hash, retdest
SWAP1
JUMP
mpt_hash_branch:
// stack: node_type, node_payload_ptr, retdest
POP
// stack: node_payload_ptr, retdest
PANIC // TODO
mpt_hash_extension:
// stack: node_type, node_payload_ptr, retdest
POP
// stack: node_payload_ptr, retdest
PANIC // TODO
mpt_hash_leaf:
// stack: node_type, node_payload_ptr, retdest
POP
// stack: node_payload_ptr, retdest
DUP1 %mload_trie_data
// stack: node_nibbles, node_payload_ptr, retdest
PANIC // TODO

View File

@ -0,0 +1,51 @@
// Computes the hex-prefix encoding of the given nibble list and termination
// flag. Writes the result to the @KERNEL_GENERAL segment of memory, and returns
// its length on the stack.
global hex_prefix:
// stack: num_nibbles, packed_nibbles, terminated, retdest
// We will iterate backwards, from i = num_nibbles/2 to i=0, so that we can
// take nibbles from the least-significant end of packed_nibbles.
PUSH 2 DUP2 DIV // i = num_nibbles / 2
// stack: i, num_nibbles, packed_nibbles, terminated, retdest
loop:
// If i == 0, break to first_byte.
DUP1 ISZERO %jumpi(first_byte)
// stack: i, num_nibbles, packed_nibbles, terminated, retdest
DUP3 // packed_nibbles
%and_const(0xFF)
// stack: byte_i, i, num_nibbles, packed_nibbles, terminated, retdest
DUP2 // i
%mstore_kernel_general
// stack: i, num_nibbles, packed_nibbles, terminated, retdest
%sub_const(1)
SWAP2 %shr_const(8) SWAP2 // packed_nibbles >>= 8
// stack: i, num_nibbles, packed_nibbles, terminated, retdest
%jump(loop)
first_byte:
// stack: 0, num_nibbles, first_nibble_or_zero, terminated, retdest
POP
DUP1
// stack: num_nibbles, num_nibbles, first_nibble_or_zero, terminated, retdest
%div_const(2)
%add_const(1)
// stack: result_len, num_nibbles, first_nibble_or_zero, terminated, retdest
SWAP3
// stack: terminated, num_nibbles, first_nibble_or_zero, result_len, retdest
%mul_const(2)
SWAP1
// stack: num_nibbles, terminated * 2, first_nibble_or_zero, result_len, retdest
%mod_const(2)
ADD
// stack: parity + terminated * 2, first_nibble_or_zero, result_len, retdest
%mul_const(16)
ADD
// stack: 16 * (parity + terminated * 2) + first_nibble_or_zero, result_len, retdest
PUSH 0
%mstore_kernel_general
// stack: result_len, retdest
SWAP1
JUMP

View File

@ -39,7 +39,6 @@ storage_trie_loop:
// stack: i, num_storage_tries, retdest
%jump(storage_trie_loop)
storage_trie_loop_end:
// TODO: Hash tries and set @GLOBAL_METADATA_STATE_TRIE_DIGEST_BEFORE, etc.
// stack: i, num_storage_tries, retdest
%pop2
// stack: retdest

View File

@ -18,6 +18,9 @@ pub fn evm_constants() -> HashMap<String, U256> {
for (name, value) in EC_CONSTANTS {
c.insert(name.into(), U256::from_big_endian(&value));
}
for (name, value) in HASH_CONSTANTS {
c.insert(name.into(), U256::from_big_endian(&value));
}
for (name, value) in GAS_CONSTANTS {
c.insert(name.into(), U256::from(value));
}
@ -43,6 +46,14 @@ pub fn evm_constants() -> HashMap<String, U256> {
c
}
const HASH_CONSTANTS: [(&str, [u8; 32]); 1] = [
// Hash of an empty node: keccak(rlp.encode(b'')).hex()
(
"EMPTY_NODE_HASH",
hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
),
];
const EC_CONSTANTS: [(&str, [u8; 32]); 3] = [
(
"BN_BASE",

View File

@ -161,6 +161,10 @@ impl<'a> Interpreter<'a> {
&self.memory.context_memory[0].segments[Segment::TrieData as usize].content
}
pub(crate) fn get_kernel_general_data(&self) -> &[U256] {
&self.memory.context_memory[0].segments[Segment::KernelGeneral as usize].content
}
pub(crate) fn get_rlp_memory(&self) -> Vec<u8> {
self.memory.context_memory[self.context].segments[Segment::RlpRaw as usize]
.content

View File

@ -0,0 +1,50 @@
use anyhow::Result;
use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::interpreter::Interpreter;
#[test]
fn hex_prefix_even_nonterminated() -> Result<()> {
let hex_prefix = KERNEL.global_labels["hex_prefix"];
let retdest = 0xDEADBEEFu32.into();
let terminated = 0.into();
let packed_nibbles = 0xABCDEF.into();
let num_nibbles = 6.into();
let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles];
let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack);
interpreter.run()?;
assert_eq!(interpreter.stack(), vec![4.into()]);
assert_eq!(
interpreter.get_kernel_general_data(),
vec![0.into(), 0xAB.into(), 0xCD.into(), 0xEF.into(),]
);
Ok(())
}
#[test]
fn hex_prefix_odd_terminated() -> Result<()> {
let hex_prefix = KERNEL.global_labels["hex_prefix"];
let retdest = 0xDEADBEEFu32.into();
let terminated = 1.into();
let packed_nibbles = 0xABCDE.into();
let num_nibbles = 5.into();
let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles];
let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack);
interpreter.run()?;
assert_eq!(interpreter.stack(), vec![3.into()]);
assert_eq!(
interpreter.get_kernel_general_data(),
vec![
(terminated * 2 + 1u32) * 16 + 0xAu32,
0xBC.into(),
0xDE.into(),
]
);
Ok(())
}

View File

@ -1,5 +1,6 @@
use eth_trie_utils::partial_trie::{Nibbles, PartialTrie};
mod hex_prefix;
mod load;
mod read;