Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update location of ENCODED_EMPTY_NODE #62

Merged
merged 6 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Refactor accessed lists as sorted linked lists ([#30](https://github.com/0xPolygonZero/zk_evm/pull/30))
- Change visibility of `compact` mod ([#57](https://github.com/0xPolygonZero/zk_evm/pull/57))
- Change position of empty node encoding in RLP segment ([#62](https://github.com/0xPolygonZero/zk_evm/pull/62))

## [0.1.0] - 2024-02-21
* Initial release.
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ process_receipt_after_bloom:
// Now we can write the receipt in MPT_TRIE_DATA.
%get_trie_data_size
// stack: receipt_ptr, payload_len, status, new_cum_gas, txn_nb, new_cum_gas, txn_nb, num_nibbles, retdest
// Write transaction type if necessary. RLP_RAW contains, at index 0, the current transaction type.
PUSH @SEGMENT_RLP_RAW // ctx == virt == 0
// Write transaction type if necessary. The address INITIAL_TXN_RLP_ADDR contains the current transaction type.
PUSH @INITIAL_TXN_RLP_ADDR
MLOAD_GENERAL
// stack: first_txn_byte, receipt_ptr, payload_len, status, new_cum_gas, txn_nb, new_cum_gas, txn_nb, num_nibbles, retdest
DUP1 %eq_const(1) %jumpi(receipt_nonzero_type)
Expand Down
5 changes: 3 additions & 2 deletions evm_arithmetization/src/cpu/kernel/asm/main.asm
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ global main:
// Initialize accessed addresses and storage keys lists
%init_access_lists

// Initialize the RLP DATA pointer to its initial position (ctx == virt == 0, segment = RLP)
PUSH @SEGMENT_RLP_RAW
// Initialize the RLP DATA pointer to its initial position,
// skipping over the preinitialized empty node.
PUSH @INITIAL_TXN_RLP_ADDR
%mstore_global_metadata(@GLOBAL_METADATA_RLP_DATA_SIZE)

// Encode constant nodes
Expand Down
2 changes: 1 addition & 1 deletion evm_arithmetization/src/cpu/kernel/asm/mpt/hash/hash.asm
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ encode_node:
global encode_node_empty:
// stack: node_type, node_payload_ptr, encode_value, cur_len, retdest
%pop3
%stack (cur_len, retdest) -> (retdest, @ENCODED_EMPTY_NODE_POS, 1, cur_len)
%stack (cur_len, retdest) -> (retdest, @ENCODED_EMPTY_NODE_ADDR, 1, cur_len)
JUMP

global encode_node_branch:
Expand Down
2 changes: 1 addition & 1 deletion evm_arithmetization/src/cpu/kernel/asm/mpt/util.asm
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
%endmacro

%macro initialize_rlp_segment
PUSH @ENCODED_EMPTY_NODE_POS
PUSH @ENCODED_EMPTY_NODE_ADDR
PUSH 0x80
MSTORE_GENERAL
%endmacro
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ global read_rlp_to_memory:
// stack: retdest
PROVER_INPUT(rlp) // Read the RLP blob length from the prover tape.
// stack: len, retdest
PUSH @SEGMENT_RLP_RAW
PUSH @INITIAL_TXN_RLP_ADDR
%build_kernel_address

PUSH @SEGMENT_RLP_RAW // ctx == virt == 0
PUSH @INITIAL_TXN_RLP_ADDR
// stack: addr, final_addr, retdest
read_rlp_to_memory_loop:
// stack: addr, final_addr, retdest
Expand All @@ -31,7 +31,7 @@ read_rlp_to_memory_loop:
read_rlp_to_memory_finish:
// stack: addr, final_addr, retdest
// we recover the offset here
PUSH @SEGMENT_RLP_RAW // ctx == virt == 0
PUSH @INITIAL_TXN_RLP_ADDR
DUP3 SUB
// stack: pos, addr, final_addr, retdest
%stack(pos, addr, final_addr, retdest) -> (retdest, pos)
Expand Down
11 changes: 5 additions & 6 deletions evm_arithmetization/src/cpu/kernel/asm/transactions/router.asm
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ read_txn_from_memory:
// Type 0 (legacy) transactions have no such prefix, but their RLP will have a
// first byte >= 0xc0, so there is no overlap.

PUSH @SEGMENT_RLP_RAW // ctx == virt == 0
PUSH @INITIAL_TXN_RLP_ADDR
MLOAD_GENERAL
%eq_const(1)
// stack: first_byte == 1, retdest
%jumpi(process_type_1_txn)
// stack: retdest

PUSH @SEGMENT_RLP_RAW // ctx == virt == 0
PUSH @INITIAL_TXN_RLP_ADDR
MLOAD_GENERAL
%eq_const(2)
// stack: first_byte == 2, retdest
Expand All @@ -47,15 +47,14 @@ global update_txn_trie:
// stack: txn_rlp_len, value_ptr, txn_counter, num_nibbles, ret_dest
DUP2 %increment
// stack: rlp_start=value_ptr+1, txn_rlp_len, value_ptr, txn_counter, num_nibbles, retdest


// and now copy txn_rlp to the new block
%stack (rlp_start, txn_rlp_len, value_ptr, txn_counter, num_nibbles) -> (
@SEGMENT_RLP_RAW, // src addr. ctx == virt == 0
rlp_start, @SEGMENT_TRIE_DATA, // swapped dest addr, ctx == 0
@SEGMENT_TRIE_DATA, rlp_start, // dest addr, ctx == 0
@INITIAL_TXN_RLP_ADDR, // src addr
txn_rlp_len, // mcpy len
txn_rlp_len, rlp_start, txn_counter, num_nibbles, value_ptr)
SWAP2 %build_kernel_address
%build_kernel_address
// stack: DST, SRC, txn_rlp_len, txn_rlp_len, rlp_start, txn_counter, num_nibbles, value_ptr
%memcpy_bytes
ADD
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

global process_type_0_txn:
// stack: retdest
PUSH @SEGMENT_RLP_RAW // ctx == virt == 0
PUSH @INITIAL_TXN_RLP_ADDR
// stack: rlp_addr, retdest
%decode_rlp_list_len
// We don't actually need the length.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ global process_type_1_txn:
// stack: retdest
// Initial rlp address offset of 1 (skipping over the 0x01 byte)
PUSH 1
PUSH @SEGMENT_RLP_RAW
PUSH @INITIAL_TXN_RLP_ADDR
%build_kernel_address
// stack: rlp_addr, retdest
%decode_rlp_list_len
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ global process_type_2_txn:
// stack: retdest
// Initial rlp address offset of 1 (skipping over the 0x02 byte)
PUSH 1
PUSH @SEGMENT_RLP_RAW
PUSH @INITIAL_TXN_RLP_ADDR
%build_kernel_address
// stack: rlp_addr, retdest
%decode_rlp_list_len
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ pub(crate) enum GlobalMetadata {
/// The size of the `TrieData` segment, in bytes. In other words, the next
/// address available for appending additional trie data.
TrieDataSize,
/// The size of the `TrieData` segment, in bytes, represented as a whole
/// The size of the `RLP` segment, in bytes, represented as a whole
/// address. In other words, the next address available for appending
/// additional trie data.
/// additional RLP data.
RlpDataSize,
/// A pointer to the root of the state trie within the `TrieData` buffer.
StateTrieRoot,
Expand Down
18 changes: 13 additions & 5 deletions evm_arithmetization/src/cpu/kernel/constants/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,23 +89,31 @@ pub(crate) fn evm_constants() -> HashMap<String, U256> {
c
}

const MISC_CONSTANTS: [(&str, [u8; 32]); 3] = [
const MISC_CONSTANTS: [(&str, [u8; 32]); 4] = [
// Base for limbs used in bignum arithmetic.
(
"BIGNUM_LIMB_BASE",
hex!("0000000000000000000000000000000100000000000000000000000000000000"),
),
// Position in SEGMENT_RLP_RAW where the empty node encoding is stored. It is
// equal to u32::MAX + @SEGMENT_RLP_RAW so that all rlp pointers are much smaller than that.
// Address where the empty node encoding is stored.
// It is at the offset 0 within SEGMENT_RLP_RAW.
// *Note*: Changing this will break some tests.
(
"ENCODED_EMPTY_NODE_POS",
hex!("0000000000000000000000000000000000000000000000000000000CFFFFFFFF"),
"ENCODED_EMPTY_NODE_ADDR",
hex!("0000000000000000000000000000000000000000000000000000000c00000000"),
),
// 0x10000 = 2^16 bytes, much larger than any RLP blob the EVM could possibly create.
(
"MAX_RLP_BLOB_SIZE",
hex!("0000000000000000000000000000000000000000000000000000000000010000"),
),
// Address where the txn RLP encoding starts.
// It is the offset 1 within SEGMENT_RLP_RAW.
// *Note*: Changing this will break some tests.
(
"INITIAL_TXN_RLP_ADDR",
hex!("0000000000000000000000000000000000000000000000000000000c00000001"),
),
];

const HASH_CONSTANTS: [(&str, [u8; 32]); 2] = [
Expand Down
21 changes: 16 additions & 5 deletions evm_arithmetization/src/cpu/kernel/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,18 @@ impl<'a, F: Field> Interpreter<'a, F> {
memory.into_iter().map(U256::from).collect();
}

pub(crate) fn extend_memory_segment(&mut self, segment: Segment, memory: &[U256]) {
self.generation_state.memory.contexts[0].segments[segment.unscale()]
.content
.extend(memory);
}

pub(crate) fn extend_memory_segment_bytes(&mut self, segment: Segment, memory: Vec<u8>) {
self.generation_state.memory.contexts[0].segments[segment.unscale()]
.content
.extend(memory.into_iter().map(U256::from).collect::<Vec<_>>());
}

pub(crate) fn set_rlp_memory(&mut self, rlp: Vec<u8>) {
self.set_memory_segment_bytes(Segment::RlpRaw, rlp)
}
Expand Down Expand Up @@ -1504,12 +1516,11 @@ impl<'a, F: Field> Interpreter<'a, F> {
self.generation_state.registers.context = context;
}

/// Writes the encoding of 0 to position @ENCODED_EMPTY_NODE_POS.
/// Writes the encoding of 0 at @ENCODED_EMPTY_NODE_ADDR.
pub(crate) fn initialize_rlp_segment(&mut self) {
self.generation_state.memory.set(
MemoryAddress::new(0, Segment::RlpRaw, 0xFFFFFFFF),
128.into(),
)
self.generation_state
.memory
.set(MemoryAddress::new(0, Segment::RlpRaw, 0), 0x80.into())
}
}

Expand Down
5 changes: 3 additions & 2 deletions evm_arithmetization/src/cpu/kernel/tests/mpt/hex_prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@ fn hex_prefix_odd_terminated_tiny() -> Result<()> {
assert_eq!(
interpreter.get_rlp_memory(),
vec![
// Since rlp_pos = 2, we skipped over the first two bytes.
0,
// The two first values of the RLP segment are the hardcoded 0x80 for an empty
// node, and 0 (i.e. unset).
0x80,
0,
// No length prefix; this tiny string is its own RLP encoding.
(2 + 1) * 16 + 0xA,
Expand Down
5 changes: 3 additions & 2 deletions evm_arithmetization/src/cpu/kernel/tests/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ fn test_receipt_encoding() -> Result<()> {
interpreter.run()?;
let rlp_pos = interpreter.pop().expect("The stack should not be empty");

let rlp_read: Vec<u8> = interpreter.get_rlp_memory();
let rlp_read: &[u8] = &interpreter.get_rlp_memory()[1..]; // skip empty_node

assert_eq!(rlp_pos.as_usize(), expected_rlp.len());
for i in 0..rlp_read.len() {
Expand Down Expand Up @@ -513,7 +513,8 @@ fn test_mpt_insert_receipt() -> Result<()> {
// Set memory.
interpreter.generation_state.registers.program_counter = mpt_insert;
interpreter.set_memory_segment(Segment::TrieData, cur_trie_data.clone());
interpreter.set_global_metadata_field(GlobalMetadata::TrieDataSize, cur_trie_data.len().into());
let trie_data_len = cur_trie_data.len().into();
interpreter.set_global_metadata_field(GlobalMetadata::TrieDataSize, trie_data_len);
interpreter.run()?;

// Finally, check that the hashes correspond.
Expand Down
12 changes: 10 additions & 2 deletions evm_arithmetization/src/cpu/kernel/tests/rlp/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ fn test_encode_rlp_scalar_small() -> Result<()> {

interpreter.run()?;
let expected_stack = vec![pos + U256::from(1)]; // pos' = pos + rlp_len = 2 + 1
let expected_rlp = vec![0, 0, 42];

// The two first values of the RLP segment are the hardcoded 0x80 for an empty
// node, and 0 (i.e. unset).
let expected_rlp = vec![0x80, 0, 42];

assert_eq!(interpreter.stack(), expected_stack);
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);

Expand All @@ -39,7 +43,11 @@ fn test_encode_rlp_scalar_medium() -> Result<()> {

interpreter.run()?;
let expected_stack = vec![pos + U256::from(4)]; // pos' = pos + rlp_len = 2 + 4
let expected_rlp = vec![0, 0, 0x80 + 3, 0x01, 0x23, 0x45];

// The two first values of the RLP segment are the hardcoded 0x80 for an empty
// node, and 0 (i.e. unset).
let expected_rlp = vec![0x80, 0, 0x80 + 3, 0x01, 0x23, 0x45];

assert_eq!(interpreter.stack(), expected_stack);
assert_eq!(interpreter.get_rlp_memory(), expected_rlp);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use NormalizedTxnField::*;
use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::constants::txn_fields::NormalizedTxnField;
use crate::cpu::kernel::interpreter::Interpreter;
use crate::memory::segments::Segment;

#[test]
fn process_type_0_txn() -> Result<()> {
Expand Down Expand Up @@ -38,7 +39,7 @@ fn process_type_0_txn() -> Result<()> {
// 4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318'))
// signed_txn = unsigned_txn.as_signed_transaction(sk)
// rlp.encode(signed_txn).hex()
interpreter.set_rlp_memory(hex!("f861050a8255f0940000000000000000000000000000000000000000648242421ca07c5c61ed975ebd286f6b027b8c504842e50a47d318e1e801719dd744fe93e6c6a01e7b5119b57dd54e175ff2f055c91f3ab1b53eba0b2c184f347cdff0e745aca2").to_vec());
interpreter.extend_memory_segment_bytes(Segment::RlpRaw, hex!("f861050a8255f0940000000000000000000000000000000000000000648242421ca07c5c61ed975ebd286f6b027b8c504842e50a47d318e1e801719dd744fe93e6c6a01e7b5119b57dd54e175ff2f055c91f3ab1b53eba0b2c184f347cdff0e745aca2").to_vec());

interpreter.run()?;

Expand Down