mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-09 09:13:09 +00:00
MPT hashing logic, part 2
This commit is contained in:
parent
6b8a18b3ef
commit
f2f05952ab
@ -99,9 +99,9 @@
|
||||
// stack: (empty)
|
||||
%endmacro
|
||||
|
||||
// Store a single value to @SEGMENT_KERNEL_GENERAL.
|
||||
%macro mstore_kernel_general
|
||||
// Store a single byte to @SEGMENT_RLP_RAW.
|
||||
%macro mstore_rlp
|
||||
// stack: offset, value
|
||||
%mstore_kernel(@SEGMENT_KERNEL_GENERAL)
|
||||
%mstore_kernel(@SEGMENT_RLP_RAW)
|
||||
// stack: (empty)
|
||||
%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
|
||||
DUP1
|
||||
%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_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)
|
||||
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_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:
|
||||
%stack (node_type, node_payload_ptr, retdest) -> (retdest, @EMPTY_NODE_HASH)
|
||||
JUMP
|
||||
@ -26,23 +80,3 @@ mpt_hash_hash:
|
||||
// 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
|
||||
|
||||
@ -1,51 +1,104 @@
|
||||
// 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
|
||||
// Computes the RLP encoding of the hex-prefix encoding of the given nibble list
|
||||
// and termination flag. Writes the result to @SEGMENT_RLP_RAW starting at the
|
||||
// given position, and returns the updated position, i.e. a pointer to the next
|
||||
// unused offset.
|
||||
//
|
||||
// Pre stack: rlp_start_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||
// Post stack: rlp_end_pos
|
||||
|
||||
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:
|
||||
// stack: i, hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||
// If i == 0, break to first_byte.
|
||||
DUP1 ISZERO %jumpi(first_byte)
|
||||
|
||||
// stack: i, num_nibbles, packed_nibbles, terminated, retdest
|
||||
DUP3 // packed_nibbles
|
||||
// stack: i, hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||
DUP5 // 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
|
||||
// stack: byte_i, i, hp_len, rlp_pos, num_nibbles, packed_nibbles, terminated, retdest
|
||||
DUP4 // rlp_pos
|
||||
DUP3 // i
|
||||
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)
|
||||
SWAP2 %shr_const(8) SWAP2 // packed_nibbles >>= 8
|
||||
// stack: i, num_nibbles, packed_nibbles, terminated, retdest
|
||||
SWAP4 %shr_const(8) SWAP4 // packed_nibbles >>= 8
|
||||
%jump(loop)
|
||||
|
||||
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
|
||||
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
|
||||
// stack: hp_len, rlp_pos, num_nibbles, first_nibble_or_zero, terminated, retdest
|
||||
DUP2 ADD
|
||||
// stack: rlp_end_pos, rlp_pos, num_nibbles, first_nibble_or_zero, terminated, retdest
|
||||
SWAP4
|
||||
// stack: terminated, rlp_pos, num_nibbles, first_nibble_or_zero, rlp_end_pos, retdest
|
||||
%mul_const(2)
|
||||
SWAP1
|
||||
// stack: num_nibbles, terminated * 2, first_nibble_or_zero, result_len, retdest
|
||||
%mod_const(2)
|
||||
// stack: terminated * 2, rlp_pos, num_nibbles, first_nibble_or_zero, rlp_end_pos, retdest
|
||||
%stack (terminated_x2, rlp_pos, num_nibbles, first_nibble_or_zero)
|
||||
-> (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
|
||||
// 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)
|
||||
ADD
|
||||
// stack: 16 * (parity + terminated * 2) + first_nibble_or_zero, result_len, retdest
|
||||
PUSH 0
|
||||
%mstore_kernel_general
|
||||
|
||||
// stack: result_len, retdest
|
||||
// stack: first_byte, rlp_pos, rlp_end_pos, retdest
|
||||
SWAP1
|
||||
%mstore_rlp
|
||||
// stack: rlp_end_pos, retdest
|
||||
SWAP1
|
||||
JUMP
|
||||
|
||||
@ -90,6 +90,73 @@ encode_rlp_fixed_finish:
|
||||
SWAP1
|
||||
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.
|
||||
// The scalar is assumed to be non-zero, as small scalars like zero should
|
||||
// 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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@ -5,20 +5,25 @@ use crate::cpu::kernel::interpreter::Interpreter;
|
||||
|
||||
#[test]
|
||||
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 terminated = 0.into();
|
||||
let packed_nibbles = 0xABCDEF.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);
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), vec![4.into()]);
|
||||
assert_eq!(interpreter.stack(), vec![5.into()]);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_kernel_general_data(),
|
||||
vec![0.into(), 0xAB.into(), 0xCD.into(), 0xEF.into(),]
|
||||
interpreter.get_rlp_memory(),
|
||||
vec![
|
||||
4, // length
|
||||
0, // neither flag is set
|
||||
0xAB, 0xCD, 0xEF
|
||||
]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@ -26,23 +31,53 @@ fn hex_prefix_even_nonterminated() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
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 terminated = 1.into();
|
||||
let packed_nibbles = 0xABCDE.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);
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), vec![3.into()]);
|
||||
assert_eq!(interpreter.stack(), vec![4.into()]);
|
||||
|
||||
assert_eq!(
|
||||
interpreter.get_kernel_general_data(),
|
||||
interpreter.get_rlp_memory(),
|
||||
vec![
|
||||
(terminated * 2 + 1u32) * 16 + 0xAu32,
|
||||
0xBC.into(),
|
||||
0xDE.into(),
|
||||
3, // length
|
||||
(2 + 1) * 16 + 0xA,
|
||||
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::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_decode_rlp_string_len_short() -> Result<()> {
|
||||
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