mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-05-23 10:19:27 +00:00
Merge pull request #747 from mir-protocol/mpt_hashing_2
MPT hashing logic, part 2
This commit is contained in:
commit
239ecedb0c
@ -99,9 +99,9 @@
|
|||||||
// stack: (empty)
|
// stack: (empty)
|
||||||
%endmacro
|
%endmacro
|
||||||
|
|
||||||
// Store a single value to @SEGMENT_KERNEL_GENERAL.
|
// Store a single byte to @SEGMENT_RLP_RAW.
|
||||||
%macro mstore_kernel_general
|
%macro mstore_rlp
|
||||||
// stack: offset, value
|
// stack: offset, value
|
||||||
%mstore_kernel(@SEGMENT_KERNEL_GENERAL)
|
%mstore_kernel(@SEGMENT_RLP_RAW)
|
||||||
// stack: (empty)
|
// stack: (empty)
|
||||||
%endmacro
|
%endmacro
|
||||||
|
|||||||
@ -1,4 +1,12 @@
|
|||||||
global mpt_hash:
|
// Computes the Merkle root of the given trie node.
|
||||||
|
//
|
||||||
|
// The encode_value function should take as input
|
||||||
|
// - the position withing @SEGMENT_RLP_RAW to write to,
|
||||||
|
// - the offset of a value within @SEGMENT_TRIE_DATA, and
|
||||||
|
// - a return address.
|
||||||
|
// It should serialize the value, write it to @SEGMENT_RLP_RAW starting at the
|
||||||
|
// given position, and return an updated position (the next unused offset).
|
||||||
|
%macro mpt_hash(encode_value)
|
||||||
// stack: node_ptr, retdest
|
// stack: node_ptr, retdest
|
||||||
DUP1
|
DUP1
|
||||||
%mload_trie_data
|
%mload_trie_data
|
||||||
@ -9,11 +17,57 @@ global mpt_hash:
|
|||||||
|
|
||||||
DUP1 %eq_const(@MPT_NODE_EMPTY) %jumpi(mpt_hash_empty)
|
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_HASH) %jumpi(mpt_hash_hash)
|
||||||
DUP1 %eq_const(@MPT_NODE_BRANCH) %jumpi(mpt_hash_branch)
|
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_EXTENSION) %jumpi(%%mpt_hash_extension)
|
||||||
DUP1 %eq_const(@MPT_NODE_LEAF) %jumpi(mpt_hash_leaf)
|
DUP1 %eq_const(@MPT_NODE_LEAF) %jumpi(%%mpt_hash_leaf)
|
||||||
PANIC // Invalid node type? Shouldn't get here.
|
PANIC // Invalid node type? Shouldn't get here.
|
||||||
|
|
||||||
|
%%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
|
||||||
|
PUSH %%mpt_hash_leaf_after_hex_prefix // retdest
|
||||||
|
PUSH 1 // terminated
|
||||||
|
// stack: terminated, %%mpt_hash_leaf_after_hex_prefix, node_payload_ptr, retdest
|
||||||
|
DUP3 %add_const(1) %mload_trie_data // Load the packed_nibbles field, which is at index 1.
|
||||||
|
// stack: packed_nibbles, terminated, %%mpt_hash_leaf_after_hex_prefix, node_payload_ptr, retdest
|
||||||
|
DUP4 %mload_trie_data // Load the num_nibbles field, which is at index 0.
|
||||||
|
// stack: num_nibbles, packed_nibbles, terminated, %%mpt_hash_leaf_after_hex_prefix, node_payload_ptr, retdest
|
||||||
|
PUSH 9 // We start at 9 to leave room to prepend the largest possible RLP list header.
|
||||||
|
// stack: rlp_start, num_nibbles, packed_nibbles, terminated, %%mpt_hash_leaf_after_hex_prefix, node_payload_ptr, retdest
|
||||||
|
%jump(hex_prefix)
|
||||||
|
%%mpt_hash_leaf_after_hex_prefix:
|
||||||
|
// stack: rlp_pos, node_payload_ptr, retdest
|
||||||
|
SWAP1
|
||||||
|
%add_const(2) // The value starts at index 2.
|
||||||
|
%stack (value_ptr, rlp_pos, retdest)
|
||||||
|
-> (rlp_pos, value_ptr, %%mpt_hash_leaf_after_encode_value, retdest)
|
||||||
|
%jump($encode_value)
|
||||||
|
%%mpt_hash_leaf_after_encode_value:
|
||||||
|
// stack: rlp_end_pos, retdest
|
||||||
|
%prepend_rlp_list_prefix
|
||||||
|
// stack: rlp_start_pos, rlp_len, retdest
|
||||||
|
PUSH $SEGMENT_RLP
|
||||||
|
PUSH 0 // kernel context
|
||||||
|
// stack: rlp_start_addr: 3, rlp_len, retdest
|
||||||
|
KECCAK_GENERAL
|
||||||
|
// stack: hash, retdest
|
||||||
|
SWAP
|
||||||
|
JUMP
|
||||||
|
%endmacro
|
||||||
|
|
||||||
mpt_hash_empty:
|
mpt_hash_empty:
|
||||||
%stack (node_type, node_payload_ptr, retdest) -> (retdest, @EMPTY_NODE_HASH)
|
%stack (node_type, node_payload_ptr, retdest) -> (retdest, @EMPTY_NODE_HASH)
|
||||||
JUMP
|
JUMP
|
||||||
@ -26,23 +80,3 @@ mpt_hash_hash:
|
|||||||
// stack: hash, retdest
|
// stack: hash, retdest
|
||||||
SWAP1
|
SWAP1
|
||||||
JUMP
|
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
|
|
||||||
|
|||||||
@ -1,51 +1,104 @@
|
|||||||
// Computes the hex-prefix encoding of the given nibble list and termination
|
// Computes the RLP encoding of the hex-prefix encoding of the given nibble list
|
||||||
// flag. Writes the result to the @KERNEL_GENERAL segment of memory, and returns
|
// and termination flag. Writes the result to @SEGMENT_RLP_RAW starting at the
|
||||||
// its length on the stack.
|
// given position, and returns the updated position, i.e. a pointer to the next
|
||||||
global hex_prefix:
|
// unused offset.
|
||||||
// stack: num_nibbles, packed_nibbles, terminated, retdest
|
//
|
||||||
// We will iterate backwards, from i = num_nibbles/2 to i=0, so that we can
|
// Pre stack: rlp_start_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
// take nibbles from the least-significant end of packed_nibbles.
|
// Post stack: rlp_end_pos
|
||||||
PUSH 2 DUP2 DIV // i = num_nibbles / 2
|
|
||||||
// stack: i, num_nibbles, packed_nibbles, terminated, retdest
|
global hex_prefix_rlp:
|
||||||
|
// stack: rlp_pos, 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 DUP3 DIV // i = num_nibbles / 2
|
||||||
|
// stack: i, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
|
|
||||||
|
// Compute the length of the hex-prefix string, in bytes:
|
||||||
|
// hp_len = num_nibbles / 2 + 1 = i + 1
|
||||||
|
DUP1 %add_const(1)
|
||||||
|
// stack: hp_len, i, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
|
|
||||||
|
// Write the RLP header.
|
||||||
|
DUP1 %gt_const(55) %jumpi(rlp_header_large)
|
||||||
|
DUP1 %gt_const(1) %jumpi(rlp_header_medium)
|
||||||
|
|
||||||
|
// The hex-prefix is a single byte. It must be <= 127, since its first
|
||||||
|
// nibble only has two bits. So this is the "small" RLP string case, where
|
||||||
|
// the byte is its own RLP encoding.
|
||||||
|
// stack: hp_len, i, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
|
%jump(start_loop)
|
||||||
|
|
||||||
|
rlp_header_medium:
|
||||||
|
// stack: hp_len, i, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
|
DUP1 // value = hp_len
|
||||||
|
DUP4 // offset = rlp_pos
|
||||||
|
%mstore_rlp
|
||||||
|
|
||||||
|
// rlp_pos += 1
|
||||||
|
SWAP2 %add_const(1) SWAP2
|
||||||
|
|
||||||
|
%jump(start_loop)
|
||||||
|
|
||||||
|
rlp_header_large:
|
||||||
|
// stack: hp_len, i, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
|
// In practice hex-prefix length will never exceed 256, so the length of the
|
||||||
|
// length will always be 1 byte in this case.
|
||||||
|
|
||||||
|
PUSH 1 // value = len_of_len = 1
|
||||||
|
DUP4 // offset = rlp_pos
|
||||||
|
%mstore_rlp
|
||||||
|
|
||||||
|
DUP1 // value = hp_len
|
||||||
|
DUP4 %add_const(1) // offset = rlp_pos + 1
|
||||||
|
%mstore_rlp
|
||||||
|
|
||||||
|
// rlp_pos += 2
|
||||||
|
SWAP2 %add_const(2) SWAP2
|
||||||
|
|
||||||
|
start_loop:
|
||||||
|
// stack: hp_len, i, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
|
SWAP1
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
|
// stack: i, hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
// If i == 0, break to first_byte.
|
// If i == 0, break to first_byte.
|
||||||
DUP1 ISZERO %jumpi(first_byte)
|
DUP1 ISZERO %jumpi(first_byte)
|
||||||
|
|
||||||
// stack: i, num_nibbles, packed_nibbles, terminated, retdest
|
// stack: i, hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
DUP3 // packed_nibbles
|
DUP5 // packed_nibbles
|
||||||
%and_const(0xFF)
|
%and_const(0xFF)
|
||||||
// stack: byte_i, i, num_nibbles, packed_nibbles, terminated, retdest
|
// stack: byte_i, i, hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
DUP2 // i
|
DUP4 // rlp_pos
|
||||||
%mstore_kernel_general
|
DUP3 // i
|
||||||
// stack: i, num_nibbles, packed_nibbles, terminated, retdest
|
ADD // We'll write to offset rlp_pos + i
|
||||||
|
%mstore_rlp
|
||||||
|
|
||||||
|
// stack: i, hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||||
%sub_const(1)
|
%sub_const(1)
|
||||||
SWAP2 %shr_const(8) SWAP2 // packed_nibbles >>= 8
|
SWAP4 %shr_const(8) SWAP4 // packed_nibbles >>= 8
|
||||||
// stack: i, num_nibbles, packed_nibbles, terminated, retdest
|
|
||||||
%jump(loop)
|
%jump(loop)
|
||||||
|
|
||||||
first_byte:
|
first_byte:
|
||||||
// stack: 0, num_nibbles, first_nibble_or_zero, terminated, retdest
|
// stack: 0, hp_len, rlp_pos, num_nibbles, first_nibble_or_zero, terminated, retdest
|
||||||
POP
|
POP
|
||||||
DUP1
|
// stack: hp_len, rlp_pos, num_nibbles, first_nibble_or_zero, terminated, retdest
|
||||||
// stack: num_nibbles, num_nibbles, first_nibble_or_zero, terminated, retdest
|
DUP2 ADD
|
||||||
%div_const(2)
|
// stack: rlp_end_pos, rlp_pos, num_nibbles, first_nibble_or_zero, terminated, retdest
|
||||||
%add_const(1)
|
SWAP4
|
||||||
// stack: result_len, num_nibbles, first_nibble_or_zero, terminated, retdest
|
// stack: terminated, rlp_pos, num_nibbles, first_nibble_or_zero, rlp_end_pos, retdest
|
||||||
SWAP3
|
|
||||||
// stack: terminated, num_nibbles, first_nibble_or_zero, result_len, retdest
|
|
||||||
%mul_const(2)
|
%mul_const(2)
|
||||||
SWAP1
|
// stack: terminated * 2, rlp_pos, num_nibbles, first_nibble_or_zero, rlp_end_pos, retdest
|
||||||
// stack: num_nibbles, terminated * 2, first_nibble_or_zero, result_len, retdest
|
%stack (terminated_x2, rlp_pos, num_nibbles, first_nibble_or_zero)
|
||||||
%mod_const(2)
|
-> (num_nibbles, terminated_x2, first_nibble_or_zero, rlp_pos)
|
||||||
|
// stack: num_nibbles, terminated * 2, first_nibble_or_zero, rlp_pos, rlp_end_pos, retdest
|
||||||
|
%mod_const(2) // parity
|
||||||
ADD
|
ADD
|
||||||
// stack: parity + terminated * 2, first_nibble_or_zero, result_len, retdest
|
// stack: parity + terminated * 2, first_nibble_or_zero, rlp_pos, rlp_end_pos, retdest
|
||||||
%mul_const(16)
|
%mul_const(16)
|
||||||
ADD
|
ADD
|
||||||
// stack: 16 * (parity + terminated * 2) + first_nibble_or_zero, result_len, retdest
|
// stack: first_byte, rlp_pos, rlp_end_pos, retdest
|
||||||
PUSH 0
|
SWAP1
|
||||||
%mstore_kernel_general
|
%mstore_rlp
|
||||||
|
// stack: rlp_end_pos, retdest
|
||||||
// stack: result_len, retdest
|
|
||||||
SWAP1
|
SWAP1
|
||||||
JUMP
|
JUMP
|
||||||
|
|||||||
@ -90,6 +90,73 @@ encode_rlp_fixed_finish:
|
|||||||
SWAP1
|
SWAP1
|
||||||
JUMP
|
JUMP
|
||||||
|
|
||||||
|
// Given an RLP list payload which starts at position 9 and ends at the given
|
||||||
|
// position, prepend the appropriate RLP list prefix. Returns the updated start
|
||||||
|
// position, as well as the length of the RLP data (including the newly-added
|
||||||
|
// prefix).
|
||||||
|
//
|
||||||
|
// (We sometimes start list payloads at position 9 because 9 is the length of
|
||||||
|
// the longest possible RLP list prefix.)
|
||||||
|
//
|
||||||
|
// Pre stack: end_pos, retdest
|
||||||
|
// Post stack: start_pos, rlp_len
|
||||||
|
global prepend_rlp_list_prefix:
|
||||||
|
// stack: end_pos, retdest
|
||||||
|
// Since the list payload starts at position 9, payload_len = end_pos - 9.
|
||||||
|
PUSH 9 DUP2 SUB
|
||||||
|
// stack: payload_len, end_pos, retdest
|
||||||
|
DUP1 %gt_const(55)
|
||||||
|
%jumpi(prepend_rlp_list_prefix_big)
|
||||||
|
|
||||||
|
// If we got here, we have a small list, so we prepend 0xc0 + len at position 8.
|
||||||
|
// stack: payload_len, end_pos, retdest
|
||||||
|
%add_const(0xc0)
|
||||||
|
// stack: prefix_byte, end_pos, retdest
|
||||||
|
PUSH 8 // offset
|
||||||
|
%mstore_rlp
|
||||||
|
// stack: end_pos, retdest
|
||||||
|
%sub_const(8)
|
||||||
|
// stack: rlp_len, retdest
|
||||||
|
PUSH 8 // start_pos
|
||||||
|
%stack (start_pos, rlp_len, retdest) -> (retdest, start_pos, rlp_len)
|
||||||
|
JUMP
|
||||||
|
|
||||||
|
prepend_rlp_list_prefix_big:
|
||||||
|
// We have a large list, so we prepend 0xf7 + len_of_len at position
|
||||||
|
// 8 - len_of_len, followed by the length itself.
|
||||||
|
// stack: payload_len, end_pos, retdest
|
||||||
|
DUP1 %num_bytes
|
||||||
|
// stack: len_of_len, payload_len, end_pos, retdest
|
||||||
|
DUP1
|
||||||
|
PUSH 8
|
||||||
|
SUB
|
||||||
|
// stack: start_pos, len_of_len, payload_len, end_pos, retdest
|
||||||
|
DUP2 DUP2 %mstore_rlp // rlp[start_pos] = len_of_len
|
||||||
|
DUP1 %add_const(1) // start_len_pos = start_pos + 1
|
||||||
|
%stack (start_len_pos, start_pos, len_of_len, payload_len, end_pos, retdest)
|
||||||
|
-> (len_of_len, start_len_pos, payload_len,
|
||||||
|
prepend_rlp_list_prefix_big_done_writing_len,
|
||||||
|
start_pos, end_pos, retdest)
|
||||||
|
%jump(encode_rlp_fixed)
|
||||||
|
prepend_rlp_list_prefix_big_done_writing_len:
|
||||||
|
// stack: start_payload_pos, start_pos, end_pos, retdest
|
||||||
|
POP
|
||||||
|
// stack: start_pos, end_pos, retdest
|
||||||
|
DUP1
|
||||||
|
SWAP2
|
||||||
|
// stack: end_pos, start_pos, start_pos, retdest
|
||||||
|
SUB
|
||||||
|
// stack: rlp_len, start_pos, retdest
|
||||||
|
%stack (rlp_len, start_pos, retdest) -> (retdest, start_pos, rlp_len)
|
||||||
|
JUMP
|
||||||
|
|
||||||
|
// Convenience macro to call prepend_rlp_list_prefix and return where we left off.
|
||||||
|
%macro prepend_rlp_list_prefix
|
||||||
|
%stack (start_pos) -> (start_pos, %%after)
|
||||||
|
%jump(prepend_rlp_list_prefix)
|
||||||
|
%%after:
|
||||||
|
%endmacro
|
||||||
|
|
||||||
// Get the number of bytes required to represent the given scalar.
|
// Get the number of bytes required to represent the given scalar.
|
||||||
// The scalar is assumed to be non-zero, as small scalars like zero should
|
// The scalar is assumed to be non-zero, as small scalars like zero should
|
||||||
// have already been handled with the small-scalar encoding.
|
// have already been handled with the small-scalar encoding.
|
||||||
|
|||||||
@ -161,10 +161,6 @@ impl<'a> Interpreter<'a> {
|
|||||||
&self.memory.context_memory[0].segments[Segment::TrieData as usize].content
|
&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> {
|
pub(crate) fn get_rlp_memory(&self) -> Vec<u8> {
|
||||||
self.memory.context_memory[self.context].segments[Segment::RlpRaw as usize]
|
self.memory.context_memory[self.context].segments[Segment::RlpRaw as usize]
|
||||||
.content
|
.content
|
||||||
|
|||||||
@ -5,20 +5,25 @@ use crate::cpu::kernel::interpreter::Interpreter;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hex_prefix_even_nonterminated() -> Result<()> {
|
fn hex_prefix_even_nonterminated() -> Result<()> {
|
||||||
let hex_prefix = KERNEL.global_labels["hex_prefix"];
|
let hex_prefix = KERNEL.global_labels["hex_prefix_rlp"];
|
||||||
|
|
||||||
let retdest = 0xDEADBEEFu32.into();
|
let retdest = 0xDEADBEEFu32.into();
|
||||||
let terminated = 0.into();
|
let terminated = 0.into();
|
||||||
let packed_nibbles = 0xABCDEF.into();
|
let packed_nibbles = 0xABCDEF.into();
|
||||||
let num_nibbles = 6.into();
|
let num_nibbles = 6.into();
|
||||||
let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles];
|
let rlp_pos = 0.into();
|
||||||
|
let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles, rlp_pos];
|
||||||
let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack);
|
let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack);
|
||||||
interpreter.run()?;
|
interpreter.run()?;
|
||||||
assert_eq!(interpreter.stack(), vec![4.into()]);
|
assert_eq!(interpreter.stack(), vec![5.into()]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpreter.get_kernel_general_data(),
|
interpreter.get_rlp_memory(),
|
||||||
vec![0.into(), 0xAB.into(), 0xCD.into(), 0xEF.into(),]
|
vec![
|
||||||
|
4, // length
|
||||||
|
0, // neither flag is set
|
||||||
|
0xAB, 0xCD, 0xEF
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -26,23 +31,53 @@ fn hex_prefix_even_nonterminated() -> Result<()> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hex_prefix_odd_terminated() -> Result<()> {
|
fn hex_prefix_odd_terminated() -> Result<()> {
|
||||||
let hex_prefix = KERNEL.global_labels["hex_prefix"];
|
let hex_prefix = KERNEL.global_labels["hex_prefix_rlp"];
|
||||||
|
|
||||||
let retdest = 0xDEADBEEFu32.into();
|
let retdest = 0xDEADBEEFu32.into();
|
||||||
let terminated = 1.into();
|
let terminated = 1.into();
|
||||||
let packed_nibbles = 0xABCDE.into();
|
let packed_nibbles = 0xABCDE.into();
|
||||||
let num_nibbles = 5.into();
|
let num_nibbles = 5.into();
|
||||||
let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles];
|
let rlp_pos = 0.into();
|
||||||
|
let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles, rlp_pos];
|
||||||
let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack);
|
let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack);
|
||||||
interpreter.run()?;
|
interpreter.run()?;
|
||||||
assert_eq!(interpreter.stack(), vec![3.into()]);
|
assert_eq!(interpreter.stack(), vec![4.into()]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpreter.get_kernel_general_data(),
|
interpreter.get_rlp_memory(),
|
||||||
vec![
|
vec![
|
||||||
(terminated * 2 + 1u32) * 16 + 0xAu32,
|
3, // length
|
||||||
0xBC.into(),
|
(2 + 1) * 16 + 0xA,
|
||||||
0xDE.into(),
|
0xBC,
|
||||||
|
0xDE,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hex_prefix_odd_terminated_tiny() -> Result<()> {
|
||||||
|
let hex_prefix = KERNEL.global_labels["hex_prefix_rlp"];
|
||||||
|
|
||||||
|
let retdest = 0xDEADBEEFu32.into();
|
||||||
|
let terminated = 1.into();
|
||||||
|
let packed_nibbles = 0xA.into();
|
||||||
|
let num_nibbles = 1.into();
|
||||||
|
let rlp_pos = 2.into();
|
||||||
|
let initial_stack = vec![retdest, terminated, packed_nibbles, num_nibbles, rlp_pos];
|
||||||
|
let mut interpreter = Interpreter::new_with_kernel(hex_prefix, initial_stack);
|
||||||
|
interpreter.run()?;
|
||||||
|
assert_eq!(interpreter.stack(), vec![3.into()]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
interpreter.get_rlp_memory(),
|
||||||
|
vec![
|
||||||
|
// Since rlp_pos = 2, we skipped over the first two bytes.
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
// No length prefix; this tiny string is its own RLP encoding.
|
||||||
|
(2 + 1) * 16 + 0xA,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -3,84 +3,6 @@ use anyhow::Result;
|
|||||||
use crate::cpu::kernel::aggregator::KERNEL;
|
use crate::cpu::kernel::aggregator::KERNEL;
|
||||||
use crate::cpu::kernel::interpreter::Interpreter;
|
use crate::cpu::kernel::interpreter::Interpreter;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_encode_rlp_scalar_small() -> Result<()> {
|
|
||||||
let encode_rlp_scalar = KERNEL.global_labels["encode_rlp_scalar"];
|
|
||||||
|
|
||||||
let retdest = 0xDEADBEEFu32.into();
|
|
||||||
let scalar = 42.into();
|
|
||||||
let pos = 2.into();
|
|
||||||
let initial_stack = vec![retdest, scalar, pos];
|
|
||||||
let mut interpreter = Interpreter::new_with_kernel(encode_rlp_scalar, initial_stack);
|
|
||||||
|
|
||||||
interpreter.run()?;
|
|
||||||
let expected_stack = vec![3.into()]; // pos' = pos + rlp_len = 2 + 1
|
|
||||||
let expected_rlp = vec![0, 0, 42];
|
|
||||||
assert_eq!(interpreter.stack(), expected_stack);
|
|
||||||
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_encode_rlp_scalar_medium() -> Result<()> {
|
|
||||||
let encode_rlp_scalar = KERNEL.global_labels["encode_rlp_scalar"];
|
|
||||||
|
|
||||||
let retdest = 0xDEADBEEFu32.into();
|
|
||||||
let scalar = 0x12345.into();
|
|
||||||
let pos = 2.into();
|
|
||||||
let initial_stack = vec![retdest, scalar, pos];
|
|
||||||
let mut interpreter = Interpreter::new_with_kernel(encode_rlp_scalar, initial_stack);
|
|
||||||
|
|
||||||
interpreter.run()?;
|
|
||||||
let expected_stack = vec![6.into()]; // pos' = pos + rlp_len = 2 + 4
|
|
||||||
let expected_rlp = vec![0, 0, 0x80 + 3, 0x01, 0x23, 0x45];
|
|
||||||
assert_eq!(interpreter.stack(), expected_stack);
|
|
||||||
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_encode_rlp_160() -> Result<()> {
|
|
||||||
let encode_rlp_160 = KERNEL.global_labels["encode_rlp_160"];
|
|
||||||
|
|
||||||
let retdest = 0xDEADBEEFu32.into();
|
|
||||||
let string = 0x12345.into();
|
|
||||||
let pos = 0.into();
|
|
||||||
let initial_stack = vec![retdest, string, pos];
|
|
||||||
let mut interpreter = Interpreter::new_with_kernel(encode_rlp_160, initial_stack);
|
|
||||||
|
|
||||||
interpreter.run()?;
|
|
||||||
let expected_stack = vec![(1 + 20).into()]; // pos'
|
|
||||||
#[rustfmt::skip]
|
|
||||||
let expected_rlp = vec![0x80 + 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x23, 0x45];
|
|
||||||
assert_eq!(interpreter.stack(), expected_stack);
|
|
||||||
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_encode_rlp_256() -> Result<()> {
|
|
||||||
let encode_rlp_256 = KERNEL.global_labels["encode_rlp_256"];
|
|
||||||
|
|
||||||
let retdest = 0xDEADBEEFu32.into();
|
|
||||||
let string = 0x12345.into();
|
|
||||||
let pos = 0.into();
|
|
||||||
let initial_stack = vec![retdest, string, pos];
|
|
||||||
let mut interpreter = Interpreter::new_with_kernel(encode_rlp_256, initial_stack);
|
|
||||||
|
|
||||||
interpreter.run()?;
|
|
||||||
let expected_stack = vec![(1 + 32).into()]; // pos'
|
|
||||||
#[rustfmt::skip]
|
|
||||||
let expected_rlp = vec![0x80 + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x23, 0x45];
|
|
||||||
assert_eq!(interpreter.stack(), expected_stack);
|
|
||||||
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_decode_rlp_string_len_short() -> Result<()> {
|
fn test_decode_rlp_string_len_short() -> Result<()> {
|
||||||
let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"];
|
let decode_rlp_string_len = KERNEL.global_labels["decode_rlp_string_len"];
|
||||||
110
evm/src/cpu/kernel/tests/rlp/encode.rs
Normal file
110
evm/src/cpu/kernel/tests/rlp/encode.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::cpu::kernel::aggregator::KERNEL;
|
||||||
|
use crate::cpu::kernel::interpreter::Interpreter;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode_rlp_scalar_small() -> Result<()> {
|
||||||
|
let encode_rlp_scalar = KERNEL.global_labels["encode_rlp_scalar"];
|
||||||
|
|
||||||
|
let retdest = 0xDEADBEEFu32.into();
|
||||||
|
let scalar = 42.into();
|
||||||
|
let pos = 2.into();
|
||||||
|
let initial_stack = vec![retdest, scalar, pos];
|
||||||
|
let mut interpreter = Interpreter::new_with_kernel(encode_rlp_scalar, initial_stack);
|
||||||
|
|
||||||
|
interpreter.run()?;
|
||||||
|
let expected_stack = vec![3.into()]; // pos' = pos + rlp_len = 2 + 1
|
||||||
|
let expected_rlp = vec![0, 0, 42];
|
||||||
|
assert_eq!(interpreter.stack(), expected_stack);
|
||||||
|
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode_rlp_scalar_medium() -> Result<()> {
|
||||||
|
let encode_rlp_scalar = KERNEL.global_labels["encode_rlp_scalar"];
|
||||||
|
|
||||||
|
let retdest = 0xDEADBEEFu32.into();
|
||||||
|
let scalar = 0x12345.into();
|
||||||
|
let pos = 2.into();
|
||||||
|
let initial_stack = vec![retdest, scalar, pos];
|
||||||
|
let mut interpreter = Interpreter::new_with_kernel(encode_rlp_scalar, initial_stack);
|
||||||
|
|
||||||
|
interpreter.run()?;
|
||||||
|
let expected_stack = vec![6.into()]; // pos' = pos + rlp_len = 2 + 4
|
||||||
|
let expected_rlp = vec![0, 0, 0x80 + 3, 0x01, 0x23, 0x45];
|
||||||
|
assert_eq!(interpreter.stack(), expected_stack);
|
||||||
|
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode_rlp_160() -> Result<()> {
|
||||||
|
let encode_rlp_160 = KERNEL.global_labels["encode_rlp_160"];
|
||||||
|
|
||||||
|
let retdest = 0xDEADBEEFu32.into();
|
||||||
|
let string = 0x12345.into();
|
||||||
|
let pos = 0.into();
|
||||||
|
let initial_stack = vec![retdest, string, pos];
|
||||||
|
let mut interpreter = Interpreter::new_with_kernel(encode_rlp_160, initial_stack);
|
||||||
|
|
||||||
|
interpreter.run()?;
|
||||||
|
let expected_stack = vec![(1 + 20).into()]; // pos'
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let expected_rlp = vec![0x80 + 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x23, 0x45];
|
||||||
|
assert_eq!(interpreter.stack(), expected_stack);
|
||||||
|
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode_rlp_256() -> Result<()> {
|
||||||
|
let encode_rlp_256 = KERNEL.global_labels["encode_rlp_256"];
|
||||||
|
|
||||||
|
let retdest = 0xDEADBEEFu32.into();
|
||||||
|
let string = 0x12345.into();
|
||||||
|
let pos = 0.into();
|
||||||
|
let initial_stack = vec![retdest, string, pos];
|
||||||
|
let mut interpreter = Interpreter::new_with_kernel(encode_rlp_256, initial_stack);
|
||||||
|
|
||||||
|
interpreter.run()?;
|
||||||
|
let expected_stack = vec![(1 + 32).into()]; // pos'
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let expected_rlp = vec![0x80 + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x23, 0x45];
|
||||||
|
assert_eq!(interpreter.stack(), expected_stack);
|
||||||
|
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_prepend_rlp_list_prefix_small() -> Result<()> {
|
||||||
|
let prepend_rlp_list_prefix = KERNEL.global_labels["prepend_rlp_list_prefix"];
|
||||||
|
|
||||||
|
let retdest = 0xDEADBEEFu32.into();
|
||||||
|
let end_pos = (9 + 5).into();
|
||||||
|
let initial_stack = vec![retdest, end_pos];
|
||||||
|
let mut interpreter = Interpreter::new_with_kernel(prepend_rlp_list_prefix, initial_stack);
|
||||||
|
interpreter.set_rlp_memory(vec![
|
||||||
|
// Nine 0s to leave room for the longest possible RLP list prefix.
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
// The actual RLP list payload, consisting of 5 tiny strings.
|
||||||
|
1, 2, 3, 4, 5,
|
||||||
|
]);
|
||||||
|
|
||||||
|
interpreter.run()?;
|
||||||
|
|
||||||
|
let expected_rlp_len = 6.into();
|
||||||
|
let expected_start_pos = 8.into();
|
||||||
|
let expected_stack = vec![expected_rlp_len, expected_start_pos];
|
||||||
|
let expected_rlp = vec![0, 0, 0, 0, 0, 0, 0, 0, 0xc0 + 5, 1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
assert_eq!(interpreter.stack(), expected_stack);
|
||||||
|
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
2
evm/src/cpu/kernel/tests/rlp/mod.rs
Normal file
2
evm/src/cpu/kernel/tests/rlp/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mod decode;
|
||||||
|
mod encode;
|
||||||
Loading…
x
Reference in New Issue
Block a user