Fix clobbering of RLP data memory

This commit is contained in:
Daniel Lubarov 2023-03-18 09:29:31 -07:00
parent 2ac4fcdf84
commit a05ed9fc3a
10 changed files with 321 additions and 129 deletions

View File

@ -118,16 +118,19 @@ global encode_node_empty:
// stack: node_type, node_payload_ptr, encode_value, retdest
%pop3
// stack: retdest
// An empty node is encoded as a single byte, 0x80, which is the RLP
// encoding of the empty string. Write this byte to RLP[0] and return
// (0, 1).
// An empty node is encoded as a single byte, 0x80, which is the RLP encoding of the empty string.
// TODO: Write this byte just once to RLP memory, then we can always return (0, 1).
%alloc_rlp_block
// stack: rlp_pos, retdest
PUSH 0x80
PUSH 0
// stack: 0x80, rlp_pos, retdest
DUP2
// stack: rlp_pos, 0x80, rlp_pos, retdest
%mstore_rlp
%stack (retdest) -> (retdest, 0, 1)
%stack (rlp_pos, retdest) -> (retdest, rlp_pos, 1)
JUMP
encode_node_branch:
global encode_node_branch:
// stack: node_type, node_payload_ptr, encode_value, retdest
POP
// stack: node_payload_ptr, encode_value, retdest
@ -135,6 +138,7 @@ encode_node_branch:
// Get the next unused offset within the encoded child buffers.
// Then immediately increment the next unused offset by 16, so any
// recursive calls will use nonoverlapping offsets.
// TODO: Allocate a block of RLP memory instead?
%mload_global_metadata(@GLOBAL_METADATA_TRIE_ENCODED_CHILD_SIZE)
DUP1 %add_const(16)
%mstore_global_metadata(@GLOBAL_METADATA_TRIE_ENCODED_CHILD_SIZE)
@ -150,41 +154,41 @@ encode_node_branch:
// stack: base_offset, node_payload_ptr, encode_value, retdest
// Now, append each child to our RLP tape.
PUSH 9 // rlp_pos; we start at 9 to leave room to prepend a list prefix
%alloc_rlp_block DUP1
// stack: rlp_pos, rlp_start, base_offset, node_payload_ptr, encode_value, retdest
%append_child(0) %append_child(1) %append_child(2) %append_child(3)
%append_child(4) %append_child(5) %append_child(6) %append_child(7)
%append_child(8) %append_child(9) %append_child(10) %append_child(11)
%append_child(12) %append_child(13) %append_child(14) %append_child(15)
// stack: rlp_pos', base_offset, node_payload_ptr, encode_value, retdest
// stack: rlp_pos', rlp_start, base_offset, node_payload_ptr, encode_value, retdest
// We no longer need base_offset.
SWAP1
POP
// stack: rlp_pos', node_payload_ptr, encode_value, retdest
SWAP1
%stack (rlp_pos, rlp_start, base_offset, node_payload_ptr)
-> (node_payload_ptr, rlp_pos, rlp_start)
%add_const(16)
// stack: value_ptr_ptr, rlp_pos', encode_value, retdest
// stack: value_ptr_ptr, rlp_pos', rlp_start, encode_value, retdest
%mload_trie_data
// stack: value_ptr, rlp_pos', encode_value, retdest
// stack: value_ptr, rlp_pos', rlp_start, encode_value, retdest
DUP1 %jumpi(encode_node_branch_with_value)
// No value; append the empty string (0x80).
// stack: value_ptr, rlp_pos', encode_value, retdest
%stack (value_ptr, rlp_pos, encode_value) -> (rlp_pos, 0x80, rlp_pos)
// stack: value_ptr, rlp_pos', rlp_start, encode_value, retdest
%stack (value_ptr, rlp_pos, rlp_start, encode_value) -> (rlp_pos, 0x80, rlp_pos, rlp_start)
%mstore_rlp
// stack: rlp_pos', retdest
// stack: rlp_pos', rlp_start, retdest
%increment
// stack: rlp_pos'', retdest
// stack: rlp_pos'', rlp_start, retdest
%jump(encode_node_branch_prepend_prefix)
encode_node_branch_with_value:
// stack: value_ptr, rlp_pos', encode_value, retdest
%stack (value_ptr, rlp_pos, encode_value)
-> (encode_value, rlp_pos, value_ptr, encode_node_branch_prepend_prefix)
// stack: value_ptr, rlp_pos', rlp_start, encode_value, retdest
%stack (value_ptr, rlp_pos, rlp_start, encode_value)
-> (encode_value, rlp_pos, value_ptr, encode_node_branch_prepend_prefix, rlp_start)
JUMP // call encode_value
encode_node_branch_prepend_prefix:
// stack: rlp_pos'', retdest
// stack: rlp_pos'', rlp_start, retdest
%prepend_rlp_list_prefix
%stack (start_pos, rlp_len, retdest) -> (retdest, start_pos, rlp_len)
// stack: rlp_prefix_start, rlp_len, retdest
%stack (rlp_prefix_start, rlp_len, retdest)
-> (retdest, rlp_prefix_start, rlp_len)
JUMP
// Part of the encode_node_branch function. Encodes the i'th child.
@ -208,27 +212,28 @@ encode_node_branch_prepend_prefix:
// Part of the encode_node_branch function. Appends the i'th child's RLP.
%macro append_child(i)
// stack: rlp_pos, base_offset, node_payload_ptr, encode_value, retdest
DUP2 %add_const($i) %mload_kernel(@SEGMENT_TRIE_ENCODED_CHILD) // load result
DUP3 %add_const($i) %mload_kernel(@SEGMENT_TRIE_ENCODED_CHILD_LEN) // load result_len
// stack: result_len, result, rlp_pos, base_offset, node_payload_ptr, encode_value, retdest
// stack: rlp_pos, rlp_start, base_offset, node_payload_ptr, encode_value, retdest
DUP3 %add_const($i) %mload_kernel(@SEGMENT_TRIE_ENCODED_CHILD) // load result
DUP4 %add_const($i) %mload_kernel(@SEGMENT_TRIE_ENCODED_CHILD_LEN) // load result_len
// stack: result_len, result, rlp_pos, rlp_start, base_offset, node_payload_ptr, encode_value, retdest
// If result_len != 32, result is raw RLP, with an appropriate RLP prefix already.
DUP1 %sub_const(32) %jumpi(%%unpack)
// Otherwise, result is a hash, and we need to add the prefix 0x80 + 32 = 160.
// stack: result_len, result, rlp_pos, base_offset, node_payload_ptr, encode_value, retdest
// stack: result_len, result, rlp_pos, rlp_start, base_offset, node_payload_ptr, encode_value, retdest
PUSH 160
DUP4 // rlp_pos
%mstore_rlp
SWAP2 %increment SWAP2 // rlp_pos += 1
%%unpack:
%stack (result_len, result, rlp_pos, base_offset, node_payload_ptr, encode_value, retdest)
-> (rlp_pos, result, result_len, %%after_unpacking, base_offset, node_payload_ptr, encode_value, retdest)
%stack (result_len, result, rlp_pos, rlp_start, base_offset, node_payload_ptr, encode_value, retdest)
-> (rlp_pos, result, result_len, %%after_unpacking,
rlp_start, base_offset, node_payload_ptr, encode_value, retdest)
%jump(mstore_unpacking_rlp)
%%after_unpacking:
// stack: rlp_pos', base_offset, node_payload_ptr, encode_value, retdest
// stack: rlp_pos', rlp_start, base_offset, node_payload_ptr, encode_value, retdest
%endmacro
encode_node_extension:
global encode_node_extension:
// stack: node_type, node_payload_ptr, encode_value, retdest
%stack (node_type, node_payload_ptr, encode_value)
-> (node_payload_ptr, encode_value, encode_node_extension_after_encode_child, node_payload_ptr)
@ -237,61 +242,66 @@ encode_node_extension:
%jump(encode_or_hash_node)
encode_node_extension_after_encode_child:
// stack: result, result_len, node_payload_ptr, retdest
%alloc_rlp_block
// stack: rlp_start, result, result_len, node_payload_ptr, retdest
PUSH encode_node_extension_after_hex_prefix // retdest
PUSH 0 // terminated
// stack: terminated, encode_node_extension_after_hex_prefix, result, result_len, node_payload_ptr, retdest
DUP5 %increment %mload_trie_data // Load the packed_nibbles field, which is at index 1.
// stack: packed_nibbles, terminated, encode_node_extension_after_hex_prefix, result, result_len, node_payload_ptr, retdest
DUP6 %mload_trie_data // Load the num_nibbles field, which is at index 0.
// stack: num_nibbles, packed_nibbles, terminated, encode_node_extension_after_hex_prefix, result, result_len, 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, encode_node_extension_after_hex_prefix, result, result_len, node_payload_ptr, retdest
// stack: terminated, encode_node_extension_after_hex_prefix, rlp_start, result, result_len, node_payload_ptr, retdest
DUP6 %increment %mload_trie_data // Load the packed_nibbles field, which is at index 1.
// stack: packed_nibbles, terminated, encode_node_extension_after_hex_prefix, rlp_start, result, result_len, node_payload_ptr, retdest
DUP7 %mload_trie_data // Load the num_nibbles field, which is at index 0.
// stack: num_nibbles, packed_nibbles, terminated, encode_node_extension_after_hex_prefix, rlp_start, result, result_len, node_payload_ptr, retdest
DUP5
// stack: rlp_start, num_nibbles, packed_nibbles, terminated, encode_node_extension_after_hex_prefix, rlp_start, result, result_len, node_payload_ptr, retdest
%jump(hex_prefix_rlp)
encode_node_extension_after_hex_prefix:
// stack: rlp_pos, result, result_len, node_payload_ptr, retdest
// stack: rlp_pos, rlp_start, result, result_len, node_payload_ptr, retdest
// If result_len != 32, result is raw RLP, with an appropriate RLP prefix already.
DUP3 %sub_const(32) %jumpi(encode_node_extension_unpack)
DUP4 %sub_const(32) %jumpi(encode_node_extension_unpack)
// Otherwise, result is a hash, and we need to add the prefix 0x80 + 32 = 160.
PUSH 160
DUP2 // rlp_pos
%mstore_rlp
%increment // rlp_pos += 1
encode_node_extension_unpack:
%stack (rlp_pos, result, result_len, node_payload_ptr)
-> (rlp_pos, result, result_len, encode_node_extension_after_unpacking)
%stack (rlp_pos, rlp_start, result, result_len, node_payload_ptr)
-> (rlp_pos, result, result_len, encode_node_extension_after_unpacking, rlp_start)
%jump(mstore_unpacking_rlp)
encode_node_extension_after_unpacking:
// stack: rlp_end_pos, retdest
// stack: rlp_pos, rlp_start, retdest
%prepend_rlp_list_prefix
%stack (rlp_start_pos, rlp_len, retdest) -> (retdest, rlp_start_pos, rlp_len)
%stack (rlp_prefix_start_pos, rlp_len, retdest)
-> (retdest, rlp_prefix_start_pos, rlp_len)
JUMP
encode_node_leaf:
global encode_node_leaf:
// stack: node_type, node_payload_ptr, encode_value, retdest
POP
// stack: node_payload_ptr, encode_value, retdest
%alloc_rlp_block
PUSH encode_node_leaf_after_hex_prefix // retdest
PUSH 1 // terminated
// stack: terminated, encode_node_leaf_after_hex_prefix, node_payload_ptr, encode_value, retdest
DUP3 %increment %mload_trie_data // Load the packed_nibbles field, which is at index 1.
// stack: packed_nibbles, terminated, encode_node_leaf_after_hex_prefix, node_payload_ptr, encode_value, retdest
DUP4 %mload_trie_data // Load the num_nibbles field, which is at index 0.
// stack: num_nibbles, packed_nibbles, terminated, encode_node_leaf_after_hex_prefix, node_payload_ptr, encode_value, 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, encode_node_leaf_after_hex_prefix, node_payload_ptr, encode_value, retdest
// stack: terminated, encode_node_leaf_after_hex_prefix, rlp_start, node_payload_ptr, encode_value, retdest
DUP4 %increment %mload_trie_data // Load the packed_nibbles field, which is at index 1.
// stack: packed_nibbles, terminated, encode_node_leaf_after_hex_prefix, rlp_start, node_payload_ptr, encode_value, retdest
DUP5 %mload_trie_data // Load the num_nibbles field, which is at index 0.
// stack: num_nibbles, packed_nibbles, terminated, encode_node_leaf_after_hex_prefix, rlp_start, node_payload_ptr, encode_value, retdest
DUP5
// stack: rlp_start, num_nibbles, packed_nibbles, terminated, encode_node_leaf_after_hex_prefix, rlp_start, node_payload_ptr, encode_value, retdest
%jump(hex_prefix_rlp)
encode_node_leaf_after_hex_prefix:
// stack: rlp_pos, node_payload_ptr, encode_value, retdest
SWAP1
// stack: rlp_pos, rlp_start, node_payload_ptr, encode_value, retdest
SWAP2
%add_const(2) // The value pointer starts at index 3, after num_nibbles and packed_nibbles.
// stack: value_ptr_ptr, rlp_pos, encode_value, retdest
// stack: value_ptr_ptr, rlp_start, rlp_pos, encode_value, retdest
%mload_trie_data
// stack: value_ptr, rlp_pos, encode_value, retdest
%stack (value_ptr, rlp_pos, encode_value, retdest)
-> (encode_value, rlp_pos, value_ptr, encode_node_leaf_after_encode_value, retdest)
// stack: value_ptr, rlp_start, rlp_pos, encode_value, retdest
%stack (value_ptr, rlp_start, rlp_pos, encode_value, retdest)
-> (encode_value, rlp_pos, value_ptr, encode_node_leaf_after_encode_value, rlp_start, retdest)
JUMP
encode_node_leaf_after_encode_value:
// stack: rlp_end_pos, retdest
// stack: rlp_end_pos, rlp_start, retdest
%prepend_rlp_list_prefix
%stack (rlp_start_pos, rlp_len, retdest) -> (retdest, rlp_start_pos, rlp_len)
%stack (rlp_prefix_start_pos, rlp_len, retdest)
-> (retdest, rlp_prefix_start_pos, rlp_len)
JUMP

View File

@ -13,6 +13,17 @@ global mpt_hash_state_trie:
%%after:
%endmacro
global mpt_hash_storage_trie:
// stack: node_ptr, retdest
%stack (node_ptr) -> (node_ptr, encode_storage_value)
%jump(mpt_hash)
%macro mpt_hash_storage_trie
PUSH %%after
%jump(mpt_hash_storage_trie)
%%after:
%endmacro
global mpt_hash_txn_trie:
// stack: retdest
PUSH encode_txn
@ -96,6 +107,12 @@ global encode_receipt:
global encode_storage_value:
// stack: rlp_pos, value_ptr, retdest
SWAP1 %mload_trie_data SWAP1
// stack: rlp_pos, value, retdest
// The YP says storage trie is a map "... to the RLP-encoded 256-bit integer values"
// which seems to imply that this should be %encode_rlp_256. But %encode_rlp_scalar
// causes the tests to pass, so it seems storage values should be treated as variable-
// length after all.
%encode_rlp_scalar
// stack: rlp_pos', retdest
SWAP1

View File

@ -10,6 +10,23 @@
// stack: (empty)
%endmacro
%macro alloc_rlp_block
// stack: (empty)
%mload_global_metadata(@GLOBAL_METADATA_RLP_DATA_SIZE)
// stack: block_start
// In our model it's fine to use memory in a sparse way, as long as the gaps aren't larger than
// 2^16 or so. So instead of the caller specifying the size of the block they need, we'll just
// allocate 0x10000 = 2^16 bytes, much larger than any RLP blob the EVM could possibly create.
DUP1 %add_const(0x10000)
// stack: block_end, block_start
%mstore_global_metadata(@GLOBAL_METADATA_RLP_DATA_SIZE)
// stack: block_start
// We leave an extra 9 bytes, so that callers can later prepend a prefix before block_start.
// (9 is the length of the longest possible RLP list prefix.)
%add_const(9)
// stack: block_start
%endmacro
%macro get_trie_data_size
// stack: (empty)
%mload_global_metadata(@GLOBAL_METADATA_TRIE_DATA_SIZE)

View File

@ -196,66 +196,65 @@ encode_rlp_list_prefix_large_done_writing_len:
%%after:
%endmacro
// 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).
// Given an RLP list payload which starts and ends at the given positions,
// 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
// Pre stack: end_pos, start_pos, retdest
// Post stack: prefix_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
// stack: end_pos, start_pos, retdest
DUP2 DUP2 SUB // end_pos - start_pos
// stack: payload_len, end_pos, start_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
// stack: payload_len, end_pos, start_pos, retdest
DUP1 %add_const(0xc0)
// stack: prefix_byte, payload_len, end_pos, start_pos, retdest
DUP4 %decrement // offset of prefix
%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)
// stack: payload_len, end_pos, start_pos, retdest
%increment
// stack: rlp_len, end_pos, start_pos, retdest
SWAP2 %decrement
// stack: prefix_start_pos, end_pos, rlp_len, retdest
%stack (prefix_start_pos, end_pos, rlp_len, retdest) -> (retdest, prefix_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
// prefix_start_pos = start_pos - 1 - len_of_len
// followed by the length itself.
// stack: payload_len, end_pos, start_pos, retdest
DUP1 %num_bytes
// stack: len_of_len, payload_len, end_pos, retdest
// stack: len_of_len, payload_len, end_pos, start_pos, retdest
DUP1
PUSH 8
DUP5 %decrement // start_pos - 1
SUB
// stack: start_pos, len_of_len, payload_len, end_pos, retdest
DUP2 %add_const(0xf7) DUP2 %mstore_rlp // rlp[start_pos] = 0xf7 + len_of_len
DUP1 %increment // start_len_pos = start_pos + 1
%stack (start_len_pos, start_pos, len_of_len, payload_len, end_pos, retdest)
// stack: prefix_start_pos, len_of_len, payload_len, end_pos, start_pos, retdest
DUP2 %add_const(0xf7) DUP2 %mstore_rlp // rlp[prefix_start_pos] = 0xf7 + len_of_len
// stack: prefix_start_pos, len_of_len, payload_len, end_pos, start_pos, retdest
DUP1 %increment // start_len_pos = prefix_start_pos + 1
%stack (start_len_pos, prefix_start_pos, len_of_len, payload_len, end_pos, start_pos, retdest)
-> (start_len_pos, payload_len, len_of_len,
prepend_rlp_list_prefix_big_done_writing_len,
start_pos, end_pos, retdest)
prefix_start_pos, end_pos, retdest)
%jump(mstore_unpacking_rlp)
prepend_rlp_list_prefix_big_done_writing_len:
// stack: 9, start_pos, end_pos, retdest
%stack (_9, start_pos, end_pos) -> (end_pos, start_pos, start_pos)
// stack: end_pos, start_pos, start_pos, retdest
// stack: start_pos, prefix_start_pos, end_pos, retdest
%stack (start_pos, prefix_start_pos, end_pos)
-> (end_pos, prefix_start_pos, prefix_start_pos)
// stack: end_pos, prefix_start_pos, prefix_start_pos, retdest
SUB
// stack: rlp_len, start_pos, retdest
%stack (rlp_len, start_pos, retdest) -> (retdest, start_pos, rlp_len)
// stack: rlp_len, prefix_start_pos, retdest
%stack (rlp_len, prefix_start_pos, retdest) -> (retdest, prefix_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 (end_pos) -> (end_pos, %%after)
%stack (end_pos, start_pos) -> (end_pos, start_pos, %%after)
%jump(prepend_rlp_list_prefix)
%%after:
%endmacro

View File

@ -84,62 +84,64 @@ type_0_compute_signed_data:
// otherwise, it is
// keccak256(rlp([nonce, gas_price, gas_limit, to, value, data]))
%alloc_rlp_block
// stack: rlp_start, retdest
%mload_txn_field(@TXN_FIELD_NONCE)
// stack: nonce, retdest
PUSH 9 // We start at 9 to leave room to prepend the largest possible RLP list header.
// stack: rlp_pos, nonce, retdest
// stack: nonce, rlp_start, retdest
DUP2
// stack: rlp_pos, nonce, rlp_start, retdest
%encode_rlp_scalar
// stack: rlp_pos, retdest
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_MAX_FEE_PER_GAS)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_GAS_LIMIT)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_TO)
SWAP1 %encode_rlp_160
// stack: rlp_pos, retdest
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_VALUE)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
// stack: rlp_pos, rlp_start, retdest
// Encode txn data.
%mload_txn_field(@TXN_FIELD_DATA_LEN)
PUSH 0 // ADDR.virt
PUSH @SEGMENT_TXN_DATA
PUSH 0 // ADDR.context
// stack: ADDR: 3, len, rlp_pos, retdest
// stack: ADDR: 3, len, rlp_pos, rlp_start, retdest
PUSH after_serializing_txn_data
// stack: after_serializing_txn_data, ADDR: 3, len, rlp_pos, retdest
// stack: after_serializing_txn_data, ADDR: 3, len, rlp_pos, rlp_start, retdest
SWAP5
// stack: rlp_pos, ADDR: 3, len, after_serializing_txn_data, retdest
// stack: rlp_pos, ADDR: 3, len, after_serializing_txn_data, rlp_start, retdest
%jump(encode_rlp_string)
after_serializing_txn_data:
// stack: rlp_pos, retdest
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_CHAIN_ID_PRESENT)
ISZERO %jumpi(finish_rlp_list)
// stack: rlp_pos, retdest
// stack: rlp_pos, rlp_start, retdest
%mload_txn_field(@TXN_FIELD_CHAIN_ID)
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
// stack: rlp_pos, rlp_start, retdest
PUSH 0
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
// stack: rlp_pos, rlp_start, retdest
PUSH 0
SWAP1 %encode_rlp_scalar
// stack: rlp_pos, retdest
// stack: rlp_pos, rlp_start, retdest
finish_rlp_list:
%prepend_rlp_list_prefix
// stack: start_pos, rlp_len, retdest
// stack: prefix_start_pos, rlp_len, retdest
PUSH @SEGMENT_RLP_RAW
PUSH 0 // context
// stack: ADDR: 3, rlp_len, retdest

View File

@ -6,10 +6,13 @@ pub(crate) enum GlobalMetadata {
/// give each new context a unique ID, so that its memory will be zero-initialized.
LargestContext = 0,
/// The size of active memory, in bytes.
MemorySize = 2,
MemorySize = 1,
/// The size of the `TrieData` segment, in bytes. In other words, the next address available for
/// appending additional trie data.
TrieDataSize = 3,
TrieDataSize = 2,
/// The size of the `TrieData` segment, in bytes. In other words, the next address available for
/// appending additional trie data.
RlpDataSize = 3,
/// A pointer to the root of the state trie within the `TrieData` buffer.
StateTrieRoot = 4,
/// A pointer to the root of the transaction trie within the `TrieData` buffer.
@ -45,13 +48,14 @@ pub(crate) enum GlobalMetadata {
}
impl GlobalMetadata {
pub(crate) const COUNT: usize = 21;
pub(crate) const COUNT: usize = 22;
pub(crate) fn all() -> [Self; Self::COUNT] {
[
Self::LargestContext,
Self::MemorySize,
Self::TrieDataSize,
Self::RlpDataSize,
Self::StateTrieRoot,
Self::TransactionTrieRoot,
Self::ReceiptTrieRoot,
@ -79,6 +83,7 @@ impl GlobalMetadata {
Self::LargestContext => "GLOBAL_METADATA_LARGEST_CONTEXT",
Self::MemorySize => "GLOBAL_METADATA_MEMORY_SIZE",
Self::TrieDataSize => "GLOBAL_METADATA_TRIE_DATA_SIZE",
Self::RlpDataSize => "GLOBAL_METADATA_RLP_DATA_SIZE",
Self::StateTrieRoot => "GLOBAL_METADATA_STATE_TRIE_ROOT",
Self::TransactionTrieRoot => "GLOBAL_METADATA_TXN_TRIE_ROOT",
Self::ReceiptTrieRoot => "GLOBAL_METADATA_RECEIPT_TRIE_ROOT",

View File

@ -279,6 +279,7 @@ impl<'a> Interpreter<'a> {
.byte(0);
self.opcode_count[opcode as usize] += 1;
self.incr(1);
match opcode {
0x00 => self.run_stop(), // "STOP",
0x01 => self.run_add(), // "ADD",
@ -356,7 +357,7 @@ impl<'a> Interpreter<'a> {
0xa2 => todo!(), // "LOG2",
0xa3 => todo!(), // "LOG3",
0xa4 => todo!(), // "LOG4",
0xa5 => bail!("Executed PANIC"), // "PANIC",
0xa5 => bail!("Executed PANIC, stack={:?}", self.stack()), // "PANIC",
0xf0 => todo!(), // "CREATE",
0xf1 => todo!(), // "CALL",
0xf2 => todo!(), // "CALLCODE",

View File

@ -7,7 +7,7 @@ use crate::memory::segments::Segment;
#[test]
fn test_mload_packing_1_byte() -> Result<()> {
let mstore_unpacking = KERNEL.global_labels["mload_packing"];
let mload_packing = KERNEL.global_labels["mload_packing"];
let retdest = 0xDEADBEEFu32.into();
let len = 1.into();
@ -16,7 +16,7 @@ fn test_mload_packing_1_byte() -> Result<()> {
let context = 0.into();
let initial_stack = vec![retdest, len, offset, segment, context];
let mut interpreter = Interpreter::new_with_kernel(mstore_unpacking, initial_stack);
let mut interpreter = Interpreter::new_with_kernel(mload_packing, initial_stack);
interpreter.set_rlp_memory(vec![0, 0, 0xAB]);
interpreter.run()?;
@ -27,7 +27,7 @@ fn test_mload_packing_1_byte() -> Result<()> {
#[test]
fn test_mload_packing_3_bytes() -> Result<()> {
let mstore_unpacking = KERNEL.global_labels["mload_packing"];
let mload_packing = KERNEL.global_labels["mload_packing"];
let retdest = 0xDEADBEEFu32.into();
let len = 3.into();
@ -36,7 +36,7 @@ fn test_mload_packing_3_bytes() -> Result<()> {
let context = 0.into();
let initial_stack = vec![retdest, len, offset, segment, context];
let mut interpreter = Interpreter::new_with_kernel(mstore_unpacking, initial_stack);
let mut interpreter = Interpreter::new_with_kernel(mload_packing, initial_stack);
interpreter.set_rlp_memory(vec![0, 0, 0xAB, 0xCD, 0xEF]);
interpreter.run()?;
@ -47,7 +47,7 @@ fn test_mload_packing_3_bytes() -> Result<()> {
#[test]
fn test_mload_packing_32_bytes() -> Result<()> {
let mstore_unpacking = KERNEL.global_labels["mload_packing"];
let mload_packing = KERNEL.global_labels["mload_packing"];
let retdest = 0xDEADBEEFu32.into();
let len = 32.into();
@ -56,7 +56,7 @@ fn test_mload_packing_32_bytes() -> Result<()> {
let context = 0.into();
let initial_stack = vec![retdest, len, offset, segment, context];
let mut interpreter = Interpreter::new_with_kernel(mstore_unpacking, initial_stack);
let mut interpreter = Interpreter::new_with_kernel(mload_packing, initial_stack);
interpreter.set_rlp_memory(vec![0xFF; 32]);
interpreter.run()?;

View File

@ -86,8 +86,9 @@ 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 start_pos = 9.into();
let end_pos = (9 + 5).into();
let initial_stack = vec![retdest, end_pos];
let initial_stack = vec![retdest, start_pos, 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.
@ -114,8 +115,9 @@ fn test_prepend_rlp_list_prefix_large() -> Result<()> {
let prepend_rlp_list_prefix = KERNEL.global_labels["prepend_rlp_list_prefix"];
let retdest = 0xDEADBEEFu32.into();
let start_pos = 9.into();
let end_pos = (9 + 60).into();
let initial_stack = vec![retdest, end_pos];
let initial_stack = vec![retdest, start_pos, end_pos];
let mut interpreter = Interpreter::new_with_kernel(prepend_rlp_list_prefix, initial_stack);
#[rustfmt::skip]

139
evm/tests/add11_yml.rs Normal file
View File

@ -0,0 +1,139 @@
use std::collections::HashMap;
use std::time::Duration;
use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV};
use eth_trie_utils::partial_trie::{Nibbles, PartialTrie};
use ethereum_types::Address;
use hex_literal::hex;
use keccak_hash::keccak;
use plonky2::field::goldilocks_field::GoldilocksField;
use plonky2::plonk::config::PoseidonGoldilocksConfig;
use plonky2::util::timing::TimingTree;
use plonky2_evm::all_stark::AllStark;
use plonky2_evm::config::StarkConfig;
use plonky2_evm::generation::mpt::AccountRlp;
use plonky2_evm::generation::{GenerationInputs, TrieInputs};
use plonky2_evm::proof::BlockMetadata;
use plonky2_evm::prover::prove;
use plonky2_evm::verifier::verify_proof;
type F = GoldilocksField;
const D: usize = 2;
type C = PoseidonGoldilocksConfig;
/// Test a simple token transfer to a new address.
#[test]
fn add11_yml() -> anyhow::Result<()> {
init_logger();
let all_stark = AllStark::<F, D>::default();
let config = StarkConfig::standard_fast_config();
let beneficiary = hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba");
let sender = hex!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b");
let to = hex!("095e7baea6a6c7c4c2dfeb977efac326af552d87");
let beneficiary_state_key = keccak(beneficiary);
let sender_state_key = keccak(sender);
let to_state_key = keccak(to);
let beneficiary_nibbles = Nibbles::from_bytes_be(beneficiary_state_key.as_bytes()).unwrap();
let sender_nibbles = Nibbles::from_bytes_be(sender_state_key.as_bytes()).unwrap();
let to_nibbles = Nibbles::from_bytes_be(to_state_key.as_bytes()).unwrap();
let code = [0x60, 0x01, 0x60, 0x01, 0x01, 0x60, 0x00, 0x55, 0x00];
let code_hash = keccak(code);
let beneficiary_account_before = AccountRlp {
nonce: 1.into(),
..AccountRlp::default()
};
let sender_account_before = AccountRlp {
balance: 0x0de0b6b3a7640000u64.into(),
..AccountRlp::default()
};
let to_account_before = AccountRlp {
balance: 0x0de0b6b3a7640000u64.into(),
code_hash,
..AccountRlp::default()
};
let mut state_trie_before = PartialTrie::Empty;
state_trie_before.insert(
beneficiary_nibbles,
rlp::encode(&beneficiary_account_before).to_vec(),
);
state_trie_before.insert(sender_nibbles, rlp::encode(&sender_account_before).to_vec());
state_trie_before.insert(to_nibbles, rlp::encode(&to_account_before).to_vec());
let tries_before = TrieInputs {
state_trie: state_trie_before,
transactions_trie: PartialTrie::Empty,
receipts_trie: PartialTrie::Empty,
storage_tries: vec![(Address::from_slice(&to), PartialTrie::Empty)],
};
let txn = hex!("f863800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0ffb600e63115a7362e7811894a91d8ba4330e526f22121c994c4692035dfdfd5a06198379fcac8de3dbfac48b165df4bf88e2088f294b61efb9a65fe2281c76e16");
let block_metadata = BlockMetadata {
block_beneficiary: Address::from(beneficiary),
block_base_fee: 0xa.into(),
..BlockMetadata::default()
};
let mut contract_code = HashMap::new();
contract_code.insert(keccak(vec![]), vec![]);
contract_code.insert(code_hash, code.to_vec());
let inputs = GenerationInputs {
signed_txns: vec![txn.to_vec()],
tries: tries_before,
contract_code,
block_metadata,
addresses: vec![],
};
let mut timing = TimingTree::new("prove", log::Level::Debug);
let proof = prove::<F, C, D>(&all_stark, &config, inputs, &mut timing)?;
timing.filter(Duration::from_millis(100)).print();
let beneficiary_account_after = AccountRlp {
nonce: 1.into(),
..AccountRlp::default()
};
let sender_account_after = AccountRlp {
balance: 0xde0b6b3a75be550u64.into(),
nonce: 1.into(),
..AccountRlp::default()
};
let to_account_after = AccountRlp {
balance: 0xde0b6b3a76586a0u64.into(),
code_hash,
// Storage map: { 0 => 2 }
storage_root: PartialTrie::Leaf {
nibbles: Nibbles::from_h256_be(keccak([0u8; 32])),
value: vec![2],
}
.calc_hash(),
..AccountRlp::default()
};
let mut expected_state_trie_after = PartialTrie::Empty;
expected_state_trie_after.insert(
beneficiary_nibbles,
rlp::encode(&beneficiary_account_after).to_vec(),
);
expected_state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec());
expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec());
assert_eq!(
proof.public_values.trie_roots_after.state_root,
expected_state_trie_after.calc_hash()
);
verify_proof(&all_stark, proof, &config)
}
fn init_logger() {
let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info"));
}