MPT hashing logic, part 2

This commit is contained in:
Daniel Lubarov 2022-10-01 10:33:05 -07:00
parent 6b8a18b3ef
commit f2f05952ab
9 changed files with 374 additions and 155 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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,
]
);

View File

@ -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"];

View 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(())
}

View File

@ -0,0 +1,2 @@
mod decode;
mod encode;