From d43c8e260c6cb6a98bb9eacf43108b4d35cc1630 Mon Sep 17 00:00:00 2001 From: Robin Salen <30937548+Nashtare@users.noreply.github.com> Date: Sun, 18 Feb 2024 09:48:24 -0500 Subject: [PATCH] Implement EIP-4788 for Cancun (#40) * Implement EIP-4788 * Cleanup test suite * Fix tests * Apply comments * Update PROVER_INPUT opcode value (#42) --- docs/arithmetization/cpulogic.tex | 4 +- evm_arithmetization/src/cpu/control_flow.rs | 8 +- evm_arithmetization/src/cpu/cpu_stark.rs | 13 +- evm_arithmetization/src/cpu/decode.rs | 15 +- evm_arithmetization/src/cpu/gas.rs | 16 +- .../src/cpu/kernel/aggregator.rs | 1 + .../src/cpu/kernel/asm/beacon_roots.asm | 48 ++++ .../src/cpu/kernel/asm/main.asm | 7 +- .../src/cpu/kernel/asm/memory/metadata.asm | 4 + .../src/cpu/kernel/asm/mpt/accounts.asm | 22 ++ .../src/cpu/kernel/asm/mpt/insert/insert.asm | 4 +- .../src/cpu/kernel/asm/mpt/read.asm | 6 +- .../cpu/kernel/constants/global_metadata.rs | 6 +- .../src/cpu/kernel/constants/mod.rs | 41 +++- .../src/cpu/kernel/interpreter.rs | 24 +- evm_arithmetization/src/cpu/kernel/mod.rs | 3 + evm_arithmetization/src/cpu/kernel/opcodes.rs | 2 +- .../src/cpu/kernel/tests/add11.rs | 102 +++++--- evm_arithmetization/src/generation/mod.rs | 4 + evm_arithmetization/src/get_challenges.rs | 2 + evm_arithmetization/src/lib.rs | 1 + evm_arithmetization/src/proof.rs | 30 ++- evm_arithmetization/src/recursive_verifier.rs | 16 +- evm_arithmetization/src/testing_utils.rs | 121 ++++++++++ evm_arithmetization/src/verifier.rs | 8 + evm_arithmetization/src/witness/operation.rs | 2 +- evm_arithmetization/src/witness/transition.rs | 2 +- evm_arithmetization/tests/add11_yml.rs | 31 ++- .../tests/basic_smart_contract.rs | 66 +++--- evm_arithmetization/tests/empty_txn_list.rs | 107 +++++++-- evm_arithmetization/tests/erc20.rs | 81 +++---- evm_arithmetization/tests/erc721.rs | 220 +++++++++--------- evm_arithmetization/tests/log_opcode.rs | 99 ++++++-- .../tests/self_balance_gas_cost.rs | 32 ++- evm_arithmetization/tests/selfdestruct.rs | 38 +-- evm_arithmetization/tests/simple_transfer.rs | 41 ++-- evm_arithmetization/tests/withdrawals.rs | 26 ++- 37 files changed, 865 insertions(+), 388 deletions(-) create mode 100644 evm_arithmetization/src/cpu/kernel/asm/beacon_roots.asm create mode 100644 evm_arithmetization/src/testing_utils.rs diff --git a/docs/arithmetization/cpulogic.tex b/docs/arithmetization/cpulogic.tex index 318e2db48..4f68faa7d 100644 --- a/docs/arithmetization/cpulogic.tex +++ b/docs/arithmetization/cpulogic.tex @@ -78,8 +78,6 @@ \subsection{Privileged instructions} \item[0x21.] \texttt{KECCAK\_GENERAL}. Pops 2 elements (a Memory address, followed by a length $\ell$) and pushes the hash of the memory portion starting at the constructed address and of length $\ell$. It is similar to KECCAK256 (0x20) instruction, but can be applied to any memory section (i.e. even privileged ones). - \item[0x49.] \texttt{PROVER\_INPUT}. Pushes a single prover input onto the stack. - \item[0xC0-0xDF.] \texttt{MSTORE\_32BYTES}. Pops 2 elements from the stack (a Memory address, and then a value), and pushes a new address' onto the stack. The value is being decomposed into bytes and written to memory, starting from the fetched address. The new address being pushed is computed as the initial address + the length of the byte sequence being written to memory. Note that similarly to PUSH (0x60-0x7F) instructions, there are 32 MSTORE\_32BYTES instructions, each @@ -87,6 +85,8 @@ \subsection{Privileged instructions} result in the integer being truncated. On the other hand, specifying a length $\ell$ greater than the byte size of the value being written will result in padding with zeroes. This process is heavily used when resetting memory sections (by calling MSTORE\_32BYTES\_32 with the value 0). + \item[0xEE.] \texttt{PROVER\_INPUT}. Pushes a single prover input onto the stack. + \item[0xF6.] \texttt{GET\_CONTEXT}. Pushes the current context onto the stack. The kernel always has context 0. \item[0xF7.] \texttt{SET\_CONTEXT}. Pops the top element of the stack and updates the current context to this value. It is usually used when calling another contract or precompile, diff --git a/evm_arithmetization/src/cpu/control_flow.rs b/evm_arithmetization/src/cpu/control_flow.rs index 832db1961..c4fcb91ec 100644 --- a/evm_arithmetization/src/cpu/control_flow.rs +++ b/evm_arithmetization/src/cpu/control_flow.rs @@ -72,7 +72,7 @@ pub(crate) fn eval_packed_generic( .constraint_transition(is_native_instruction * (lv.is_kernel_mode - nv.is_kernel_mode)); // Apply the same checks as before, for PROVER_INPUT. - let is_prover_input: P = lv.op.push_prover_input * (lv.opcode_bits[5] - P::ONES); + let is_prover_input: P = lv.op.push_prover_input * lv.opcode_bits[7]; yield_constr.constraint_transition( is_prover_input * (lv.program_counter - nv.program_counter + P::ONES), ); @@ -129,11 +129,7 @@ pub(crate) fn eval_ext_circuit, const D: usize>( yield_constr.constraint_transition(builder, kernel_constr); // Same constraints as before, for PROVER_INPUT. - let is_prover_input = builder.mul_sub_extension( - lv.op.push_prover_input, - lv.opcode_bits[5], - lv.op.push_prover_input, - ); + let is_prover_input = builder.mul_extension(lv.op.push_prover_input, lv.opcode_bits[7]); let pc_constr = builder.mul_add_extension(is_prover_input, pc_diff, is_prover_input); yield_constr.constraint_transition(builder, pc_constr); let kernel_constr = builder.mul_extension(is_prover_input, kernel_diff); diff --git a/evm_arithmetization/src/cpu/cpu_stark.rs b/evm_arithmetization/src/cpu/cpu_stark.rs index 4e60694b0..47a4b5e91 100644 --- a/evm_arithmetization/src/cpu/cpu_stark.rs +++ b/evm_arithmetization/src/cpu/cpu_stark.rs @@ -109,10 +109,7 @@ pub(crate) fn ctl_arithmetic_base_rows() -> TableWithColumns { // (also `ops` is used as the operation filter). The list of // operations includes binary operations which will simply ignore // the third input. - let col_bit = Column::linear_combination_with_constant( - vec![(COL_MAP.opcode_bits[5], F::NEG_ONE)], - F::ONE, - ); + let col_bit = Column::single(COL_MAP.opcode_bits[7]); TableWithColumns::new( *Table::Cpu, columns, @@ -263,9 +260,13 @@ pub(crate) fn ctl_data_byte_packing_push() -> Vec> { /// CTL filter for the `PUSH` operation. pub(crate) fn ctl_filter_byte_packing_push() -> Filter { - let bit_col = Column::single(COL_MAP.opcode_bits[5]); + let col_bit = Column::linear_combination_with_constant( + vec![(COL_MAP.opcode_bits[7], F::NEG_ONE)], + F::ONE, + ); + Filter::new( - vec![(Column::single(COL_MAP.op.push_prover_input), bit_col)], + vec![(Column::single(COL_MAP.op.push_prover_input), col_bit)], vec![], ) } diff --git a/evm_arithmetization/src/cpu/decode.rs b/evm_arithmetization/src/cpu/decode.rs index 081e3862c..f44d69fe3 100644 --- a/evm_arithmetization/src/cpu/decode.rs +++ b/evm_arithmetization/src/cpu/decode.rs @@ -197,12 +197,11 @@ pub(crate) fn eval_packed_generic( // Manually check PUSH and PROVER_INPUT. // PROVER_INPUT is a kernel-only instruction, but not PUSH. - let push_prover_input_constr = (opcode - P::Scalar::from_canonical_usize(0x49_usize)) + let push_prover_input_constr = (opcode - P::Scalar::from_canonical_usize(0xee_usize)) * (opcode_high_three - P::Scalar::from_canonical_usize(0x60_usize)) * lv.op.push_prover_input; yield_constr.constraint(push_prover_input_constr); - let prover_input_constr = - lv.op.push_prover_input * (lv.opcode_bits[5] - P::ONES) * (P::ONES - kernel_mode); + let prover_input_constr = lv.op.push_prover_input * lv.opcode_bits[7] * (P::ONES - kernel_mode); yield_constr.constraint(prover_input_constr); } @@ -389,8 +388,8 @@ pub(crate) fn eval_ext_circuit, const D: usize>( // Manually check PUSH and PROVER_INPUT. // PROVER_INPUT is a kernel-only instruction, but not PUSH. let prover_input_opcode = - builder.constant_extension(F::Extension::from_canonical_usize(0x49usize)); - let push_opcodes = builder.constant_extension(F::Extension::from_canonical_usize(0x60usize)); + builder.constant_extension(F::Extension::from_canonical_usize(0xee_usize)); + let push_opcodes = builder.constant_extension(F::Extension::from_canonical_usize(0x60_usize)); let push_constr = builder.sub_extension(opcode_high_three, push_opcodes); let prover_input_constr = builder.sub_extension(opcode, prover_input_opcode); @@ -398,11 +397,7 @@ pub(crate) fn eval_ext_circuit, const D: usize>( let push_prover_input_constr = builder.mul_many_extension([lv.op.push_prover_input, prover_input_constr, push_constr]); yield_constr.constraint(builder, push_prover_input_constr); - let prover_input_filter = builder.mul_sub_extension( - lv.op.push_prover_input, - lv.opcode_bits[5], - lv.op.push_prover_input, - ); + let prover_input_filter = builder.mul_extension(lv.op.push_prover_input, lv.opcode_bits[7]); let constr = builder.mul_extension(prover_input_filter, is_not_kernel_mode); yield_constr.constraint(builder, constr); } diff --git a/evm_arithmetization/src/cpu/gas.rs b/evm_arithmetization/src/cpu/gas.rs index 69ebf2c51..c3ec89089 100644 --- a/evm_arithmetization/src/cpu/gas.rs +++ b/evm_arithmetization/src/cpu/gas.rs @@ -114,11 +114,11 @@ fn eval_packed_accumulate( ); // For PROVER_INPUT and PUSH operations. - // PUSH operations are differentiated from PROVER_INPUT by their 6th bit set to + // PUSH operations are differentiated from PROVER_INPUT by their 8th bit set to // 1. - let push_prover_input_gas_cost = lv.opcode_bits[5] + let push_prover_input_gas_cost = (P::ONES - lv.opcode_bits[7]) * P::Scalar::from_canonical_u32(G_VERYLOW.unwrap()) - + (P::ONES - lv.opcode_bits[5]) * P::Scalar::from_canonical_u32(KERNEL_ONLY_INSTR.unwrap()); + + lv.opcode_bits[7] * P::Scalar::from_canonical_u32(KERNEL_ONLY_INSTR.unwrap()); yield_constr .constraint_transition(lv.op.push_prover_input * (gas_diff - push_prover_input_gas_cost)); } @@ -282,13 +282,13 @@ fn eval_ext_circuit_accumulate, const D: usize>( yield_constr.constraint_transition(builder, constr); // For PROVER_INPUT and PUSH operations. - // PUSH operations are differentiated from PROVER_INPUT by their 6th bit set to + // PUSH operations are differentiated from PROVER_INPUT by their 8th bit set to // 1. let push_prover_input_gas_cost = builder.arithmetic_extension( - F::from_canonical_u32(G_VERYLOW.unwrap()) - - F::from_canonical_u32(KERNEL_ONLY_INSTR.unwrap()), - F::from_canonical_u32(KERNEL_ONLY_INSTR.unwrap()), - lv.opcode_bits[5], + F::from_canonical_u32(KERNEL_ONLY_INSTR.unwrap()) + - F::from_canonical_u32(G_VERYLOW.unwrap()), + F::from_canonical_u32(G_VERYLOW.unwrap()), + lv.opcode_bits[7], one, one, ); diff --git a/evm_arithmetization/src/cpu/kernel/aggregator.rs b/evm_arithmetization/src/cpu/kernel/aggregator.rs index 637655255..b3b30ba93 100644 --- a/evm_arithmetization/src/cpu/kernel/aggregator.rs +++ b/evm_arithmetization/src/cpu/kernel/aggregator.rs @@ -13,6 +13,7 @@ pub(crate) fn combined_kernel() -> Kernel { let files = vec![ "global jumped_to_0: PANIC", "global jumped_to_1: PANIC", + include_str!("asm/beacon_roots.asm"), include_str!("asm/bignum/add.asm"), include_str!("asm/bignum/addmul.asm"), include_str!("asm/bignum/cmp.asm"), diff --git a/evm_arithmetization/src/cpu/kernel/asm/beacon_roots.asm b/evm_arithmetization/src/cpu/kernel/asm/beacon_roots.asm new file mode 100644 index 000000000..edcd53a3e --- /dev/null +++ b/evm_arithmetization/src/cpu/kernel/asm/beacon_roots.asm @@ -0,0 +1,48 @@ +/// EIP-4788: Beacon block root in the EVM +/// + +global set_beacon_root: + PUSH start_txn + %timestamp + // stack: timestamp, start_txns + PUSH @HISTORY_BUFFER_LENGTH + DUP2 + // stack: timestamp, 8191, timestamp, start_txns + MOD + // stack: timestamp_idx, timestamp, start_txns + PUSH write_beacon_roots_to_storage + %parent_beacon_block_root + // stack: calldata, write_beacon_roots_to_storage, timestamp_idx, timestamp, start_txns + DUP3 + %add_const(@HISTORY_BUFFER_LENGTH) + // stack: root_idx, calldata, write_beacon_roots_to_storage, timestamp_idx, timestamp, start_txns + +write_beacon_roots_to_storage: + // stack: slot, value, retdest + // First we write the value to MPT data, and get a pointer to it. + %get_trie_data_size + // stack: value_ptr, slot, value, retdest + SWAP2 + // stack: value, slot, value_ptr, retdest + %append_to_trie_data + // stack: slot, value_ptr, retdest + + // Next, call mpt_insert on the current account's storage root. + %stack (slot, value_ptr) -> (slot, value_ptr, after_beacon_roots_storage_insert) + %slot_to_storage_key + // stack: storage_key, value_ptr, after_beacon_roots_storage_insert, retdest + PUSH 64 // storage_key has 64 nibbles + %get_storage_trie(@BEACON_ROOTS_ADDRESS) + // stack: storage_root_ptr, 64, storage_key, value_ptr, after_beacon_roots_storage_insert, retdest + %jump(mpt_insert) + +after_beacon_roots_storage_insert: + // stack: new_storage_root_ptr, retdest + %get_account_data(@BEACON_ROOTS_ADDRESS) + // stack: account_ptr, new_storage_root_ptr, retdest + + // Update the copied account with our new storage root pointer. + %add_const(2) + // stack: account_storage_root_ptr_ptr, new_storage_root_ptr, retdest + %mstore_trie_data + JUMP diff --git a/evm_arithmetization/src/cpu/kernel/asm/main.asm b/evm_arithmetization/src/cpu/kernel/asm/main.asm index d78152f4b..1307f6d5d 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/main.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/main.asm @@ -41,10 +41,13 @@ global hash_initial_tries: // stack: trie_data_full_len %mstore_global_metadata(@GLOBAL_METADATA_TRIE_DATA_SIZE) + // If txn_idx == 0, update the beacon_root. + %mload_global_metadata(@GLOBAL_METADATA_TXN_NUMBER_BEFORE) + ISZERO + %jumpi(set_beacon_root) + global start_txn: // stack: (empty) - // The special case of an empty trie (i.e. for the first transaction) - // is handled outside of the kernel. %mload_global_metadata(@GLOBAL_METADATA_TXN_NUMBER_BEFORE) // stack: txn_nb DUP1 %scalar_to_rlp diff --git a/evm_arithmetization/src/cpu/kernel/asm/memory/metadata.asm b/evm_arithmetization/src/cpu/kernel/asm/memory/metadata.asm index f2dc897a1..8a7867118 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/memory/metadata.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/memory/metadata.asm @@ -447,3 +447,7 @@ global sys_prevrandao: %mload_global_metadata(@GLOBAL_METADATA_BLOCK_RANDOM) %stack (random, kexit_info) -> (kexit_info, random) EXIT_KERNEL + +%macro parent_beacon_block_root + %mload_global_metadata(@GLOBAL_METADATA_PARENT_BEACON_BLOCK_ROOT) +%endmacro diff --git a/evm_arithmetization/src/cpu/kernel/asm/mpt/accounts.asm b/evm_arithmetization/src/cpu/kernel/asm/mpt/accounts.asm index 0ee987b4c..cb8eede70 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/mpt/accounts.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/mpt/accounts.asm @@ -19,3 +19,25 @@ %mload_trie_data // stack: storage_root_ptr %endmacro + +// Return a pointer to the provided account's data in the state trie. +%macro get_account_data(addr) + PUSH $addr %mpt_read_state_trie + // stack: account_ptr + // account_ptr should be non-null as long as the prover provided the proper + // Merkle data. But a bad prover may not have, and we don't want return a + // null pointer for security reasons. + DUP1 ISZERO %jumpi(panic) + // stack: account_ptr +%endmacro + +// Returns a pointer to the root of the storage trie associated with the provided account. +%macro get_storage_trie(addr) + // stack: (empty) + %get_account_data($addr) + // stack: account_ptr + %add_const(2) + // stack: storage_root_ptr_ptr + %mload_trie_data + // stack: storage_root_ptr +%endmacro \ No newline at end of file diff --git a/evm_arithmetization/src/cpu/kernel/asm/mpt/insert/insert.asm b/evm_arithmetization/src/cpu/kernel/asm/mpt/insert/insert.asm index 34889a33f..33eadd755 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/mpt/insert/insert.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/mpt/insert/insert.asm @@ -20,7 +20,7 @@ global mpt_insert: global mpt_insert_hash_node: PANIC -mpt_insert_empty: +global mpt_insert_empty: // stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest %pop2 // stack: num_nibbles, key, value_ptr, retdest @@ -38,7 +38,7 @@ mpt_insert_empty: SWAP1 JUMP -mpt_insert_branch: +global mpt_insert_branch: // stack: node_type, node_payload_ptr, num_nibbles, key, value_ptr, retdest POP diff --git a/evm_arithmetization/src/cpu/kernel/asm/mpt/read.asm b/evm_arithmetization/src/cpu/kernel/asm/mpt/read.asm index 4a57dd4db..86926d130 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/mpt/read.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/mpt/read.asm @@ -106,7 +106,7 @@ global mpt_read_extension_not_found: // Not found; return 0. %stack (key_part, future_nibbles, key, node_payload_ptr, retdest) -> (retdest, 0) JUMP -mpt_read_extension_found: +global mpt_read_extension_found: // stack: key_part, future_nibbles, key, node_payload_ptr, retdest DUP2 %mul_const(4) SHL // key_part_shifted = (key_part << (future_nibbles * 4)) // stack: key_part_shifted, future_nibbles, key, node_payload_ptr, retdest @@ -121,7 +121,7 @@ mpt_read_extension_found: // stack: child_ptr, future_nibbles, key, retdest %jump(mpt_read) // recurse -mpt_read_leaf: +global mpt_read_leaf: // stack: node_type, node_payload_ptr, num_nibbles, key, retdest POP // stack: node_payload_ptr, num_nibbles, key, retdest @@ -142,7 +142,7 @@ global mpt_read_leaf_not_found: // Not found; return 0. %stack (node_payload_ptr, retdest) -> (retdest, 0) JUMP -mpt_read_leaf_found: +global mpt_read_leaf_found: // stack: node_payload_ptr, retdest %add_const(2) // The value pointer is located after num_nibbles and the key. // stack: value_ptr_ptr, retdest diff --git a/evm_arithmetization/src/cpu/kernel/constants/global_metadata.rs b/evm_arithmetization/src/cpu/kernel/constants/global_metadata.rs index 227ec5a16..8e866da16 100644 --- a/evm_arithmetization/src/cpu/kernel/constants/global_metadata.rs +++ b/evm_arithmetization/src/cpu/kernel/constants/global_metadata.rs @@ -56,6 +56,8 @@ pub(crate) enum GlobalMetadata { BlockGasUsedAfter, /// Current block header hash BlockCurrentHash, + /// EIP-4788: hash tree root of the beacon chain parent block. + ParentBeaconBlockRoot, /// Gas to refund at the end of the transaction. RefundCounter, @@ -101,7 +103,7 @@ pub(crate) enum GlobalMetadata { } impl GlobalMetadata { - pub(crate) const COUNT: usize = 49; + pub(crate) const COUNT: usize = 50; /// Unscales this virtual offset by their respective `Segment` value. pub(crate) const fn unscale(&self) -> usize { @@ -134,6 +136,7 @@ impl GlobalMetadata { Self::BlockGasUsed, Self::BlockGasUsedBefore, Self::BlockGasUsedAfter, + Self::ParentBeaconBlockRoot, Self::RefundCounter, Self::AccessedAddressesLen, Self::AccessedStorageKeysLen, @@ -190,6 +193,7 @@ impl GlobalMetadata { Self::BlockGasUsedBefore => "GLOBAL_METADATA_BLOCK_GAS_USED_BEFORE", Self::BlockGasUsedAfter => "GLOBAL_METADATA_BLOCK_GAS_USED_AFTER", Self::BlockCurrentHash => "GLOBAL_METADATA_BLOCK_CURRENT_HASH", + Self::ParentBeaconBlockRoot => "GLOBAL_METADATA_PARENT_BEACON_BLOCK_ROOT", Self::RefundCounter => "GLOBAL_METADATA_REFUND_COUNTER", Self::AccessedAddressesLen => "GLOBAL_METADATA_ACCESSED_ADDRESSES_LEN", Self::AccessedStorageKeysLen => "GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN", diff --git a/evm_arithmetization/src/cpu/kernel/constants/mod.rs b/evm_arithmetization/src/cpu/kernel/constants/mod.rs index 8aea84883..c85f061db 100644 --- a/evm_arithmetization/src/cpu/kernel/constants/mod.rs +++ b/evm_arithmetization/src/cpu/kernel/constants/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use ethereum_types::U256; +use ethereum_types::{H256, U256}; use hex_literal::hex; use crate::cpu::kernel::constants::context_metadata::ContextMetadata; @@ -8,6 +8,7 @@ use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; use crate::cpu::kernel::constants::journal_entry::JournalEntry; use crate::cpu::kernel::constants::trie_type::PartialTrieType; use crate::cpu::kernel::constants::txn_fields::NormalizedTxnField; +use crate::generation::mpt::AccountRlp; use crate::memory::segments::Segment; pub(crate) mod context_metadata; @@ -56,6 +57,14 @@ pub(crate) fn evm_constants() -> HashMap { c.insert(MAX_NONCE.0.into(), U256::from(MAX_NONCE.1)); c.insert(CALL_STACK_LIMIT.0.into(), U256::from(CALL_STACK_LIMIT.1)); + c.insert( + cancun_constants::BEACON_ROOTS_ADDRESS.0.into(), + U256::from_big_endian(&cancun_constants::BEACON_ROOTS_ADDRESS.1), + ); + c.insert( + cancun_constants::HISTORY_BUFFER_LENGTH.0.into(), + cancun_constants::HISTORY_BUFFER_LENGTH.1.into(), + ); for segment in Segment::all() { c.insert(segment.var_name().into(), (segment as usize).into()); @@ -285,3 +294,33 @@ const CODE_SIZE_LIMIT: [(&str, u64); 3] = [ const MAX_NONCE: (&str, u64) = ("MAX_NONCE", 0xffffffffffffffff); const CALL_STACK_LIMIT: (&str, u64) = ("CALL_STACK_LIMIT", 1024); + +/// Cancun-related constants +/// See . +pub mod cancun_constants { + use super::*; + + pub const BEACON_ROOTS_ADDRESS: (&str, [u8; 20]) = ( + "BEACON_ROOTS_ADDRESS", + hex!("000F3df6D732807Ef1319fB7B8bB8522d0Beac02"), + ); + + pub const HISTORY_BUFFER_LENGTH: (&str, u64) = ("HISTORY_BUFFER_LENGTH", 8191); + + pub const BEACON_ROOTS_CONTRACT_CODE: [u8; 106] = hex!("60618060095f395ff33373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500"); + pub const BEACON_ROOTS_CONTRACT_CODE_HASH: [u8; 32] = + hex!("468e991a328ab315e08296896adc222230a4960692e90cb6e096006ba6ae75d5"); + + pub const BEACON_ROOTS_CONTRACT_ADDRESS_HASHED: [u8; 32] = + hex!("37d65eaa92c6bc4c13a5ec45527f0c18ea8932588728769ec7aecfe6d9f32e42"); + + pub const BEACON_ROOTS_ACCOUNT: AccountRlp = AccountRlp { + nonce: U256::zero(), + balance: U256::zero(), + // Storage root for this account at genesis. + storage_root: H256(hex!( + "f58e5f1eae7ce386de44266ff0286a88dafe7e4269c1ffa97f79dbbcf4f59e5c" + )), + code_hash: H256(BEACON_ROOTS_CONTRACT_CODE_HASH), + }; +} diff --git a/evm_arithmetization/src/cpu/kernel/interpreter.rs b/evm_arithmetization/src/cpu/kernel/interpreter.rs index 6b8924c17..2b0718b55 100644 --- a/evm_arithmetization/src/cpu/kernel/interpreter.rs +++ b/evm_arithmetization/src/cpu/kernel/interpreter.rs @@ -841,7 +841,6 @@ impl<'a, F: Field> Interpreter<'a, F> { 0x46 => self.run_syscall(opcode, 0, true), // "CHAINID", 0x47 => self.run_syscall(opcode, 0, true), // SELFABALANCE, 0x48 => self.run_syscall(opcode, 0, true), // "BASEFEE", - 0x49 => self.run_prover_input(), // "PROVER_INPUT", 0x4a => self.run_syscall(opcode, 0, true), // "BLOBBASEFEE", 0x50 => self.run_pop(), // "POP", 0x51 => self.run_syscall(opcode, 1, false), // "MLOAD", @@ -874,19 +873,20 @@ impl<'a, F: Field> Interpreter<'a, F> { Err(ProgramError::KernelPanic) } // "PANIC", x if (0xc0..0xe0).contains(&x) => self.run_mstore_32bytes(x - 0xc0 + 1), /* "MSTORE_32BYTES", */ - 0xf0 => self.run_syscall(opcode, 3, false), // "CREATE", - 0xf1 => self.run_syscall(opcode, 7, false), // "CALL", - 0xf2 => self.run_syscall(opcode, 7, false), // "CALLCODE", - 0xf3 => self.run_syscall(opcode, 2, false), // "RETURN", + 0xee => self.run_prover_input(), // "PROVER_INPUT", + 0xf0 => self.run_syscall(opcode, 3, false), // "CREATE", + 0xf1 => self.run_syscall(opcode, 7, false), // "CALL", + 0xf2 => self.run_syscall(opcode, 7, false), // "CALLCODE", + 0xf3 => self.run_syscall(opcode, 2, false), // "RETURN", 0xf4 => self.run_syscall(opcode, 6, false), // "DELEGATECALL", 0xf5 => self.run_syscall(opcode, 4, false), // "CREATE2", - 0xf6 => self.run_get_context(), // "GET_CONTEXT", - 0xf7 => self.run_set_context(), // "SET_CONTEXT", - 0xf8 => self.run_mload_32bytes(), // "MLOAD_32BYTES", - 0xf9 => self.run_exit_kernel(), // "EXIT_KERNEL", + 0xf6 => self.run_get_context(), // "GET_CONTEXT", + 0xf7 => self.run_set_context(), // "SET_CONTEXT", + 0xf8 => self.run_mload_32bytes(), // "MLOAD_32BYTES", + 0xf9 => self.run_exit_kernel(), // "EXIT_KERNEL", 0xfa => self.run_syscall(opcode, 6, false), // "STATICCALL", - 0xfb => self.run_mload_general(), // "MLOAD_GENERAL", - 0xfc => self.run_mstore_general(), // "MSTORE_GENERAL", + 0xfb => self.run_mload_general(), // "MLOAD_GENERAL", + 0xfc => self.run_mstore_general(), // "MSTORE_GENERAL", 0xfd => self.run_syscall(opcode, 2, false), // "REVERT", 0xfe => { log::warn!( @@ -1604,7 +1604,6 @@ fn get_mnemonic(opcode: u8) -> &'static str { 0x45 => "GASLIMIT", 0x46 => "CHAINID", 0x48 => "BASEFEE", - 0x49 => "PROVER_INPUT", 0x4a => "BLOBBASEFEE", 0x50 => "POP", 0x51 => "MLOAD", @@ -1722,6 +1721,7 @@ fn get_mnemonic(opcode: u8) -> &'static str { 0xdd => "MSTORE_32BYTES_30", 0xde => "MSTORE_32BYTES_31", 0xdf => "MSTORE_32BYTES_32", + 0xee => "PROVER_INPUT", 0xf0 => "CREATE", 0xf1 => "CALL", 0xf2 => "CALLCODE", diff --git a/evm_arithmetization/src/cpu/kernel/mod.rs b/evm_arithmetization/src/cpu/kernel/mod.rs index 5a6717f21..d39b015cf 100644 --- a/evm_arithmetization/src/cpu/kernel/mod.rs +++ b/evm_arithmetization/src/cpu/kernel/mod.rs @@ -11,6 +11,9 @@ pub mod stack; mod utils; pub(crate) mod interpreter; + +pub use constants::cancun_constants; + #[cfg(test)] mod tests; diff --git a/evm_arithmetization/src/cpu/kernel/opcodes.rs b/evm_arithmetization/src/cpu/kernel/opcodes.rs index 59cc31754..cfa44e01f 100644 --- a/evm_arithmetization/src/cpu/kernel/opcodes.rs +++ b/evm_arithmetization/src/cpu/kernel/opcodes.rs @@ -63,7 +63,6 @@ pub fn get_opcode(mnemonic: &str) -> u8 { "GASLIMIT" => 0x45, "CHAINID" => 0x46, "BASEFEE" => 0x48, - "PROVER_INPUT" => 0x49, "BLOBBASEFEE" => 0x4a, "POP" => 0x50, "MLOAD" => 0x51, @@ -148,6 +147,7 @@ pub fn get_opcode(mnemonic: &str) -> u8 { "MSTORE_32BYTES_30" => 0xdd, "MSTORE_32BYTES_31" => 0xde, "MSTORE_32BYTES_32" => 0xdf, + "PROVER_INPUT" => 0xee, "CREATE" => 0xf0, "CALL" => 0xf1, "CALLCODE" => 0xf2, diff --git a/evm_arithmetization/src/cpu/kernel/tests/add11.rs b/evm_arithmetization/src/cpu/kernel/tests/add11.rs index 9d24bf00f..157fc1a13 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/add11.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/add11.rs @@ -14,6 +14,10 @@ use crate::cpu::kernel::interpreter::Interpreter; use crate::generation::mpt::{AccountRlp, LegacyReceiptRlp}; use crate::generation::TrieInputs; use crate::proof::{BlockHashes, BlockMetadata, TrieRoots}; +use crate::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, + initial_state_and_storage_tries_with_beacon_roots, update_beacon_roots_account_storage, +}; use crate::GenerationInputs; #[test] @@ -51,7 +55,9 @@ fn test_add11_yml() { ..AccountRlp::default() }; - let mut state_trie_before = HashedPartialTrie::from(Node::Empty); + let (mut state_trie_before, mut storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); state_trie_before.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_before).to_vec(), @@ -59,17 +65,33 @@ fn test_add11_yml() { 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()); + storage_tries.push((to_hashed, Node::Empty.into())); + let tries_before = TrieInputs { state_trie: state_trie_before, transactions_trie: Node::Empty.into(), receipts_trie: Node::Empty.into(), - storage_tries: vec![(to_hashed, Node::Empty.into())], + storage_tries, }; let txn = hex!("f863800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0ffb600e63115a7362e7811894a91d8ba4330e526f22121c994c4692035dfdfd5a06198379fcac8de3dbfac48b165df4bf88e2088f294b61efb9a65fe2281c76e16"); let gas_used = 0xa868u64.into(); + let block_metadata = BlockMetadata { + block_beneficiary: Address::from(beneficiary), + block_timestamp: 0x03e8.into(), + block_number: 1.into(), + block_difficulty: 0x020000.into(), + block_random: H256::from_uint(&0x020000.into()), + block_gaslimit: 0xff112233u32.into(), + block_chain_id: 1.into(), + block_base_fee: 0xa.into(), + block_gas_used: gas_used, + block_blob_base_fee: 0x2.into(), + ..Default::default() + }; + let expected_state_trie_after = { let beneficiary_account_after = AccountRlp { nonce: 1.into(), @@ -91,6 +113,13 @@ fn test_add11_yml() { .hash(), ..AccountRlp::default() }; + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty); expected_state_trie_after.insert( @@ -100,6 +129,10 @@ fn test_add11_yml() { 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()); + expected_state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); expected_state_trie_after }; let receipt_0 = LegacyReceiptRlp { @@ -125,20 +158,6 @@ fn test_add11_yml() { receipts_root: receipts_trie.hash(), }; - let block_metadata = BlockMetadata { - block_beneficiary: Address::from(beneficiary), - block_timestamp: 0x03e8.into(), - block_number: 1.into(), - block_difficulty: 0x020000.into(), - block_random: H256::from_uint(&0x020000.into()), - block_gaslimit: 0xff112233u32.into(), - block_chain_id: 1.into(), - block_base_fee: 0xa.into(), - block_gas_used: gas_used, - block_blob_base_fee: 0x2.into(), - block_bloom: [0.into(); 8], - }; - let tries_inputs = GenerationInputs { signed_txn: Some(txn.to_vec()), withdrawals: vec![], @@ -205,7 +224,9 @@ fn test_add11_yml_with_exception() { ..AccountRlp::default() }; - let mut state_trie_before = HashedPartialTrie::from(Node::Empty); + let (mut state_trie_before, mut storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); state_trie_before.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_before).to_vec(), @@ -213,19 +234,36 @@ fn test_add11_yml_with_exception() { 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()); + storage_tries.push((to_hashed, Node::Empty.into())); + let tries_before = TrieInputs { state_trie: state_trie_before, transactions_trie: Node::Empty.into(), receipts_trie: Node::Empty.into(), - storage_tries: vec![(to_hashed, Node::Empty.into())], + storage_tries, }; let txn = hex!("f863800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0ffb600e63115a7362e7811894a91d8ba4330e526f22121c994c4692035dfdfd5a06198379fcac8de3dbfac48b165df4bf88e2088f294b61efb9a65fe2281c76e16"); let txn_gas_limit = 400_000; let gas_price = 10; + let block_metadata = BlockMetadata { + block_beneficiary: Address::from(beneficiary), + block_timestamp: 0x03e8.into(), + block_number: 1.into(), + block_difficulty: 0x020000.into(), + block_random: H256::from_uint(&0x020000.into()), + block_gaslimit: 0xff112233u32.into(), + block_chain_id: 1.into(), + block_base_fee: 0xa.into(), + block_gas_used: txn_gas_limit.into(), + block_blob_base_fee: 0x2.into(), + ..Default::default() + }; + // Here, since the transaction fails, it consumes its gas limit, and does - // nothing else. + // nothing else. The beacon roots contract is still updated prior transaction + // execution. let expected_state_trie_after = { let beneficiary_account_after = beneficiary_account_before; // This is the only account that changes: the nonce and the balance are updated. @@ -236,6 +274,14 @@ fn test_add11_yml_with_exception() { }; let to_account_after = to_account_before; + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty); expected_state_trie_after.insert( beneficiary_nibbles, @@ -244,6 +290,10 @@ fn test_add11_yml_with_exception() { 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()); + expected_state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); expected_state_trie_after }; @@ -270,20 +320,6 @@ fn test_add11_yml_with_exception() { receipts_root: receipts_trie.hash(), }; - let block_metadata = BlockMetadata { - block_beneficiary: Address::from(beneficiary), - block_timestamp: 0x03e8.into(), - block_number: 1.into(), - block_difficulty: 0x020000.into(), - block_random: H256::from_uint(&0x020000.into()), - block_gaslimit: 0xff112233u32.into(), - block_chain_id: 1.into(), - block_base_fee: 0xa.into(), - block_gas_used: txn_gas_limit.into(), - block_blob_base_fee: 0x2.into(), - block_bloom: [0.into(); 8], - }; - let tries_inputs = GenerationInputs { signed_txn: Some(txn.to_vec()), withdrawals: vec![], diff --git a/evm_arithmetization/src/generation/mod.rs b/evm_arithmetization/src/generation/mod.rs index cf0557d66..138b87d47 100644 --- a/evm_arithmetization/src/generation/mod.rs +++ b/evm_arithmetization/src/generation/mod.rs @@ -131,6 +131,10 @@ fn apply_metadata_and_tries_memops, const D: usize> GlobalMetadata::BlockBlobBaseFee, metadata.block_blob_base_fee, ), + ( + GlobalMetadata::ParentBeaconBlockRoot, + h2u(metadata.parent_beacon_block_root), + ), (GlobalMetadata::BlockGasUsedBefore, inputs.gas_used_before), (GlobalMetadata::BlockGasUsedAfter, inputs.gas_used_after), (GlobalMetadata::TxnNumberBefore, inputs.txn_number_before), diff --git a/evm_arithmetization/src/get_challenges.rs b/evm_arithmetization/src/get_challenges.rs index 5cf8579b7..89b55ca93 100644 --- a/evm_arithmetization/src/get_challenges.rs +++ b/evm_arithmetization/src/get_challenges.rs @@ -68,6 +68,7 @@ fn observe_block_metadata< let blob_basefee = u256_to_u64(block_metadata.block_blob_base_fee)?; challenger.observe_element(blob_basefee.0); challenger.observe_element(blob_basefee.1); + challenger.observe_elements(&h256_limbs::(block_metadata.parent_beacon_block_root)); for i in 0..8 { challenger.observe_elements(&u256_limbs(block_metadata.block_bloom[i])); } @@ -95,6 +96,7 @@ fn observe_block_metadata_target< challenger.observe_elements(&block_metadata.block_base_fee); challenger.observe_element(block_metadata.block_gas_used); challenger.observe_elements(&block_metadata.block_blob_base_fee); + challenger.observe_elements(&block_metadata.parent_beacon_block_root); challenger.observe_elements(&block_metadata.block_bloom); } diff --git a/evm_arithmetization/src/lib.rs b/evm_arithmetization/src/lib.rs index b3cdc0e37..8bea00692 100644 --- a/evm_arithmetization/src/lib.rs +++ b/evm_arithmetization/src/lib.rs @@ -209,6 +209,7 @@ pub mod witness; // Utility modules pub mod curve_pairings; pub mod extension_tower; +pub mod testing_utils; pub mod util; // Set up Jemalloc diff --git a/evm_arithmetization/src/proof.rs b/evm_arithmetization/src/proof.rs index e5100b26e..4d96decd8 100644 --- a/evm_arithmetization/src/proof.rs +++ b/evm_arithmetization/src/proof.rs @@ -187,6 +187,8 @@ pub struct BlockMetadata { pub block_gas_used: U256, /// The blob base fee. It must fit in a `u64`. pub block_blob_base_fee: U256, + /// The hash tree root of the parent beacon block. + pub parent_beacon_block_root: H256, /// The block bloom of this block, represented as the consecutive /// 32-byte chunks of a block's final bloom filter string. pub block_bloom: [U256; 8], @@ -208,8 +210,9 @@ impl BlockMetadata { let block_gas_used = pis[20].to_canonical_u64().into(); let block_blob_base_fee = (pis[21].to_canonical_u64() + (pis[22].to_canonical_u64() << 32)).into(); + let parent_beacon_block_root = get_h256(&pis[23..31]); let block_bloom = - core::array::from_fn(|i| h2u(get_h256(&pis[23 + 8 * i..23 + 8 * (i + 1)]))); + core::array::from_fn(|i| h2u(get_h256(&pis[31 + 8 * i..31 + 8 * (i + 1)]))); Self { block_beneficiary, @@ -222,6 +225,7 @@ impl BlockMetadata { block_base_fee, block_gas_used, block_blob_base_fee, + parent_beacon_block_root, block_bloom, } } @@ -318,6 +322,7 @@ impl PublicValuesTarget { block_base_fee, block_gas_used, block_blob_base_fee, + parent_beacon_block_root, block_bloom, } = self.block_metadata; @@ -331,6 +336,7 @@ impl PublicValuesTarget { buffer.write_target_array(&block_base_fee)?; buffer.write_target(block_gas_used)?; buffer.write_target_array(&block_blob_base_fee)?; + buffer.write_target_array(&parent_beacon_block_root)?; buffer.write_target_array(&block_bloom)?; let BlockHashesTarget { @@ -381,6 +387,7 @@ impl PublicValuesTarget { block_base_fee: buffer.read_target_array()?, block_gas_used: buffer.read_target()?, block_blob_base_fee: buffer.read_target_array()?, + parent_beacon_block_root: buffer.read_target_array()?, block_bloom: buffer.read_target_array()?, }; @@ -583,13 +590,15 @@ pub struct BlockMetadataTarget { pub(crate) block_gas_used: Target, /// `Target`s for the blob base fee of this block. pub(crate) block_blob_base_fee: [Target; 2], + /// `Target`s for the parent beacon block root. + pub parent_beacon_block_root: [Target; 8], /// `Target`s for the block bloom of this block. pub(crate) block_bloom: [Target; 64], } impl BlockMetadataTarget { /// Number of `Target`s required for the block metadata. - pub(crate) const SIZE: usize = 87; + pub(crate) const SIZE: usize = 95; /// Extracts block metadata `Target`s from the provided public input /// `Target`s. The provided `pis` should start with the block metadata. @@ -604,7 +613,8 @@ impl BlockMetadataTarget { let block_base_fee = pis[18..20].try_into().unwrap(); let block_gas_used = pis[20]; let block_blob_base_fee = pis[21..23].try_into().unwrap(); - let block_bloom = pis[23..87].try_into().unwrap(); + let parent_beacon_block_root = pis[23..31].try_into().unwrap(); + let block_bloom = pis[31..95].try_into().unwrap(); Self { block_beneficiary, @@ -617,6 +627,7 @@ impl BlockMetadataTarget { block_base_fee, block_gas_used, block_blob_base_fee, + parent_beacon_block_root, block_bloom, } } @@ -656,6 +667,13 @@ impl BlockMetadataTarget { bm1.block_blob_base_fee[i], ) }), + parent_beacon_block_root: core::array::from_fn(|i| { + builder.select( + condition, + bm0.parent_beacon_block_root[i], + bm1.parent_beacon_block_root[i], + ) + }), block_bloom: core::array::from_fn(|i| { builder.select(condition, bm0.block_bloom[i], bm1.block_bloom[i]) }), @@ -686,6 +704,12 @@ impl BlockMetadataTarget { for i in 0..2 { builder.connect(bm0.block_blob_base_fee[i], bm1.block_blob_base_fee[i]) } + for i in 0..8 { + builder.connect( + bm0.parent_beacon_block_root[i], + bm1.parent_beacon_block_root[i], + ); + } for i in 0..64 { builder.connect(bm0.block_bloom[i], bm1.block_bloom[i]) } diff --git a/evm_arithmetization/src/recursive_verifier.rs b/evm_arithmetization/src/recursive_verifier.rs index e63d4731b..4cfcaee1c 100644 --- a/evm_arithmetization/src/recursive_verifier.rs +++ b/evm_arithmetization/src/recursive_verifier.rs @@ -377,8 +377,8 @@ pub(crate) fn get_memory_extra_looking_sum_circuit, ]; // This contains the `block_beneficiary`, `block_random`, `block_base_fee`, - // `block_blob_base_fee` as well as `cur_hash`. - let block_fields_arrays: [(GlobalMetadata, &[Target]); 5] = [ + // `block_blob_base_fee`, `parent_beacon_block_root` as well as `cur_hash`. + let block_fields_arrays: [(GlobalMetadata, &[Target]); 6] = [ ( GlobalMetadata::BlockBeneficiary, &public_values.block_metadata.block_beneficiary, @@ -395,6 +395,10 @@ pub(crate) fn get_memory_extra_looking_sum_circuit, GlobalMetadata::BlockBlobBaseFee, &public_values.block_metadata.block_blob_base_fee, ), + ( + GlobalMetadata::ParentBeaconBlockRoot, + &public_values.block_metadata.parent_beacon_block_root, + ), ( GlobalMetadata::BlockCurrentHash, &public_values.block_hashes.cur_hash, @@ -600,6 +604,7 @@ pub(crate) fn add_virtual_block_metadata, const D: let block_base_fee = builder.add_virtual_public_input_arr(); let block_gas_used = builder.add_virtual_public_input(); let block_blob_base_fee = builder.add_virtual_public_input_arr(); + let parent_beacon_block_root = builder.add_virtual_public_input_arr(); let block_bloom = builder.add_virtual_public_input_arr(); BlockMetadataTarget { block_beneficiary, @@ -612,6 +617,7 @@ pub(crate) fn add_virtual_block_metadata, const D: block_base_fee, block_gas_used, block_blob_base_fee, + parent_beacon_block_root, block_bloom, } } @@ -785,6 +791,12 @@ where let blob_basefee = u256_to_u64(block_metadata.block_blob_base_fee)?; witness.set_target(block_metadata_target.block_blob_base_fee[0], blob_basefee.0); witness.set_target(block_metadata_target.block_blob_base_fee[1], blob_basefee.1); + + witness.set_target_arr( + &block_metadata_target.parent_beacon_block_root, + &h256_limbs(block_metadata.parent_beacon_block_root), + ); + let mut block_bloom_limbs = [F::ZERO; 64]; for (i, limbs) in block_bloom_limbs.chunks_exact_mut(8).enumerate() { limbs.copy_from_slice(&u256_limbs(block_metadata.block_bloom[i])); diff --git a/evm_arithmetization/src/testing_utils.rs b/evm_arithmetization/src/testing_utils.rs new file mode 100644 index 000000000..c7371b4b6 --- /dev/null +++ b/evm_arithmetization/src/testing_utils.rs @@ -0,0 +1,121 @@ +//! A set of utility functions and constants to be used by `evm_arithmetization` +//! unit and integration tests. + +use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; +use ethereum_types::{H256, U256}; +use hex_literal::hex; +use keccak_hash::keccak; +use mpt_trie::{ + nibbles::Nibbles, + partial_trie::{HashedPartialTrie, Node, PartialTrie}, +}; + +pub use crate::cpu::kernel::cancun_constants::*; +use crate::{generation::mpt::AccountRlp, util::h2u}; + +pub const EMPTY_NODE_HASH: H256 = H256(hex!( + "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" +)); + +pub fn init_logger() { + let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); +} + +/// Converts a decimal string to a `U256`. +pub fn sd2u(s: &str) -> U256 { + U256::from_dec_str(s).unwrap() +} + +/// Converts an hexadecimal string to a `U256`. +pub fn sh2u(s: &str) -> U256 { + U256::from_str_radix(s, 16).unwrap() +} + +/// Inserts a new pair `(slot, value)` into the provided storage trie. +fn insert_storage(trie: &mut HashedPartialTrie, slot: U256, value: U256) { + let mut bytes = [0; 32]; + slot.to_big_endian(&mut bytes); + let key = keccak(bytes); + let nibbles = Nibbles::from_bytes_be(key.as_bytes()).unwrap(); + let r = rlp::encode(&value); + trie.insert(nibbles, r.freeze().to_vec()); +} + +/// Creates a storage trie for an account, given a list of `(slot, value)` +/// pairs. +pub fn create_account_storage(storage_pairs: &[(U256, U256)]) -> HashedPartialTrie { + let mut trie = HashedPartialTrie::from(Node::Empty); + for (slot, value) in storage_pairs { + insert_storage(&mut trie, *slot, *value); + } + trie +} + +/// Creates the storage trie of the beacon roots contract account at the +/// provided timestamp. Not passing any parent root will consider the parent +/// root at genesis, i.e. the empty hash. +fn beacon_roots_contract_storage(timestamp: U256, parent_root: H256) -> HashedPartialTrie { + let timestamp_idx = timestamp % HISTORY_BUFFER_LENGTH.1; + let root_idx = timestamp_idx + HISTORY_BUFFER_LENGTH.1; + + create_account_storage(&[(timestamp_idx, timestamp), (root_idx, h2u(parent_root))]) +} + +/// Updates the beacon roots account storage with the provided timestamp and +/// block parent root. +pub fn update_beacon_roots_account_storage( + storage_trie: &mut HashedPartialTrie, + timestamp: U256, + parent_root: H256, +) { + let timestamp_idx = timestamp % HISTORY_BUFFER_LENGTH.1; + let root_idx = timestamp_idx + HISTORY_BUFFER_LENGTH.1; + + insert_storage(storage_trie, timestamp_idx, timestamp); + insert_storage(storage_trie, root_idx, h2u(parent_root)); +} + +/// Returns the beacon roots contract account from its provided storage trie. +pub fn beacon_roots_contract_from_storage(storage_trie: &HashedPartialTrie) -> AccountRlp { + AccountRlp { + nonce: 0.into(), + balance: 0.into(), + storage_root: storage_trie.hash(), + code_hash: H256(BEACON_ROOTS_CONTRACT_CODE_HASH), + } +} + +/// Returns an initial state trie containing nothing but the beacon roots +/// contract, along with its storage trie. +pub fn initial_state_and_storage_tries_with_beacon_roots( +) -> (HashedPartialTrie, Vec<(H256, HashedPartialTrie)>) { + let state_trie = Node::Leaf { + nibbles: Nibbles::from_bytes_be(&BEACON_ROOTS_CONTRACT_ADDRESS_HASHED).unwrap(), + value: rlp::encode(&AccountRlp { + nonce: 0.into(), + balance: 0.into(), + storage_root: EMPTY_NODE_HASH, + code_hash: H256(BEACON_ROOTS_CONTRACT_CODE_HASH), + }) + .to_vec(), + } + .into(); + + let storage_tries = vec![( + H256(BEACON_ROOTS_CONTRACT_ADDRESS_HASHED), + Node::Empty.into(), + )]; + + (state_trie, storage_tries) +} + +/// Returns the `Nibbles` corresponding to the beacon roots contract account. +pub fn beacon_roots_account_nibbles() -> Nibbles { + Nibbles::from_bytes_be(&BEACON_ROOTS_CONTRACT_ADDRESS_HASHED).unwrap() +} + +/// Converts an amount in `ETH` to `wei` units. +pub fn eth_to_wei(eth: U256) -> U256 { + // 1 ether = 10^18 wei. + eth * U256::from(10).pow(18.into()) +} diff --git a/evm_arithmetization/src/verifier.rs b/evm_arithmetization/src/verifier.rs index 2e40a177c..d6e73fcad 100644 --- a/evm_arithmetization/src/verifier.rs +++ b/evm_arithmetization/src/verifier.rs @@ -182,6 +182,10 @@ where GlobalMetadata::BlockBaseFee, public_values.block_metadata.block_base_fee, ), + ( + GlobalMetadata::ParentBeaconBlockRoot, + h2u(public_values.block_metadata.parent_beacon_block_root), + ), ( GlobalMetadata::BlockCurrentHash, h2u(public_values.block_hashes.cur_hash), @@ -344,6 +348,10 @@ pub(crate) mod debug_utils { GlobalMetadata::BlockBlobBaseFee, public_values.block_metadata.block_blob_base_fee, ), + ( + GlobalMetadata::ParentBeaconBlockRoot, + h2u(public_values.block_metadata.parent_beacon_block_root), + ), ( GlobalMetadata::TxnNumberBefore, public_values.extra_block_data.txn_number_before, diff --git a/evm_arithmetization/src/witness/operation.rs b/evm_arithmetization/src/witness/operation.rs index 78e158ab2..17c3b157e 100644 --- a/evm_arithmetization/src/witness/operation.rs +++ b/evm_arithmetization/src/witness/operation.rs @@ -166,7 +166,7 @@ pub(crate) fn generate_prover_input( let pc = state.registers.program_counter; let input_fn = &KERNEL.prover_inputs[&pc]; let input = state.prover_input(input_fn)?; - let opcode = 0x49.into(); + let opcode = 0xee.into(); // `ArithmeticStark` range checks `mem_channels[0]`, which contains // the top of the stack, `mem_channels[1]`, `mem_channels[2]` and // next_row's `mem_channels[0]` which contains the next top of the stack. diff --git a/evm_arithmetization/src/witness/transition.rs b/evm_arithmetization/src/witness/transition.rs index d0215e3e3..67afcefb3 100644 --- a/evm_arithmetization/src/witness/transition.rs +++ b/evm_arithmetization/src/witness/transition.rs @@ -107,7 +107,6 @@ pub(crate) fn decode(registers: RegistersState, opcode: u8) -> Result Ok(Operation::Syscall(opcode, 0, true)), // CHAINID (0x47, _) => Ok(Operation::Syscall(opcode, 0, true)), // SELFBALANCE (0x48, _) => Ok(Operation::Syscall(opcode, 0, true)), // BASEFEE - (0x49, true) => Ok(Operation::ProverInput), (0x4a, _) => Ok(Operation::Syscall(opcode, 0, true)), // BLOBBASEFEE (0x50, _) => Ok(Operation::Pop), (0x51, _) => Ok(Operation::Syscall(opcode, 1, false)), // MLOAD @@ -138,6 +137,7 @@ pub(crate) fn decode(registers: RegistersState, opcode: u8) -> Result Ok(Operation::Mstore32Bytes(opcode - 0xc0 + 1)), + (0xee, true) => Ok(Operation::ProverInput), (0xf0, _) => Ok(Operation::Syscall(opcode, 3, false)), // CREATE (0xf1, _) => Ok(Operation::Syscall(opcode, 7, false)), // CALL (0xf2, _) => Ok(Operation::Syscall(opcode, 7, false)), // CALLCODE diff --git a/evm_arithmetization/tests/add11_yml.rs b/evm_arithmetization/tests/add11_yml.rs index 2f1b41c00..67b313ec8 100644 --- a/evm_arithmetization/tests/add11_yml.rs +++ b/evm_arithmetization/tests/add11_yml.rs @@ -2,12 +2,15 @@ use std::collections::HashMap; use std::str::FromStr; use std::time::Duration; -use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use ethereum_types::{Address, BigEndianHash, H256}; use evm_arithmetization::generation::mpt::{AccountRlp, LegacyReceiptRlp}; use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata, TrieRoots}; use evm_arithmetization::prover::prove; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, init_logger, + initial_state_and_storage_tries_with_beacon_roots, update_beacon_roots_account_storage, +}; use evm_arithmetization::verifier::verify_proof; use evm_arithmetization::{AllStark, Node, StarkConfig}; use hex_literal::hex; @@ -59,7 +62,9 @@ fn add11_yml() -> anyhow::Result<()> { ..AccountRlp::default() }; - let mut state_trie_before = HashedPartialTrie::from(Node::Empty); + let (mut state_trie_before, mut storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); state_trie_before.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_before).to_vec(), @@ -67,11 +72,13 @@ fn add11_yml() -> anyhow::Result<()> { 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()); + storage_tries.push((to_hashed, Node::Empty.into())); + let tries_before = TrieInputs { state_trie: state_trie_before, transactions_trie: Node::Empty.into(), receipts_trie: Node::Empty.into(), - storage_tries: vec![(to_hashed, Node::Empty.into())], + storage_tries, }; let txn = hex!("f863800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0ffb600e63115a7362e7811894a91d8ba4330e526f22121c994c4692035dfdfd5a06198379fcac8de3dbfac48b165df4bf88e2088f294b61efb9a65fe2281c76e16"); @@ -87,7 +94,7 @@ fn add11_yml() -> anyhow::Result<()> { block_base_fee: 0xa.into(), block_gas_used: 0xa868u64.into(), block_blob_base_fee: 0x2.into(), - block_bloom: [0.into(); 8], + ..Default::default() }; let mut contract_code = HashMap::new(); @@ -95,6 +102,14 @@ fn add11_yml() -> anyhow::Result<()> { contract_code.insert(code_hash, code.to_vec()); let expected_state_trie_after = { + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + let beneficiary_account_after = AccountRlp { nonce: 1.into(), ..AccountRlp::default() @@ -124,6 +139,10 @@ fn add11_yml() -> anyhow::Result<()> { 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()); + expected_state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); expected_state_trie_after }; @@ -172,7 +191,3 @@ fn add11_yml() -> anyhow::Result<()> { verify_proof(&all_stark, proof, &config) } - -fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); -} diff --git a/evm_arithmetization/tests/basic_smart_contract.rs b/evm_arithmetization/tests/basic_smart_contract.rs index b305e7628..06b83d711 100644 --- a/evm_arithmetization/tests/basic_smart_contract.rs +++ b/evm_arithmetization/tests/basic_smart_contract.rs @@ -2,13 +2,16 @@ use std::collections::HashMap; use std::str::FromStr; use std::time::Duration; -use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use ethereum_types::{Address, H256, U256}; use evm_arithmetization::cpu::kernel::opcodes::{get_opcode, get_push_opcode}; use evm_arithmetization::generation::mpt::{AccountRlp, LegacyReceiptRlp}; use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata, TrieRoots}; use evm_arithmetization::prover::prove; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, eth_to_wei, init_logger, + initial_state_and_storage_tries_with_beacon_roots, update_beacon_roots_account_storage, +}; use evm_arithmetization::verifier::verify_proof; use evm_arithmetization::{AllStark, Node, StarkConfig}; use hex_literal::hex; @@ -65,35 +68,22 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { ..AccountRlp::default() }; - let state_trie_before = { - let mut children = core::array::from_fn(|_| Node::Empty.into()); - children[beneficiary_nibbles.get_nibble(0) as usize] = Node::Leaf { - nibbles: beneficiary_nibbles.truncate_n_nibbles_front(1), - value: rlp::encode(&beneficiary_account_before).to_vec(), - } - .into(); - children[sender_nibbles.get_nibble(0) as usize] = Node::Leaf { - nibbles: sender_nibbles.truncate_n_nibbles_front(1), - value: rlp::encode(&sender_account_before).to_vec(), - } - .into(); - children[to_nibbles.get_nibble(0) as usize] = Node::Leaf { - nibbles: to_nibbles.truncate_n_nibbles_front(1), - value: rlp::encode(&to_account_before).to_vec(), - } - .into(); - Node::Branch { - children, - value: vec![], - } - } - .into(); + let (mut state_trie_before, storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); + + 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: Node::Empty.into(), receipts_trie: Node::Empty.into(), - storage_tries: vec![], + storage_tries, }; let txdata_gas = 2 * 16; @@ -111,10 +101,9 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { block_timestamp: 0x03e8.into(), block_gaslimit: 0xff112233u32.into(), block_gas_used: gas_used.into(), - block_bloom: [0.into(); 8], block_base_fee: 0xa.into(), block_blob_base_fee: 0x2.into(), - block_random: Default::default(), + ..Default::default() }; let mut contract_code = HashMap::new(); @@ -122,6 +111,14 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { contract_code.insert(code_hash, code.to_vec()); let expected_state_trie_after: HashedPartialTrie = { + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + let beneficiary_account_after = AccountRlp { nonce: 1.into(), ..AccountRlp::default() @@ -152,6 +149,12 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { value: rlp::encode(&to_account_after).to_vec(), } .into(); + children[beacon_roots_account_nibbles().get_nibble(0) as usize] = Node::Leaf { + nibbles: beacon_roots_account_nibbles().truncate_n_nibbles_front(1), + value: rlp::encode(&beacon_roots_account).to_vec(), + } + .into(); + Node::Branch { children, value: vec![], @@ -204,12 +207,3 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { verify_proof(&all_stark, proof, &config) } - -fn eth_to_wei(eth: U256) -> U256 { - // 1 ether = 10^18 wei. - eth * U256::from(10).pow(18.into()) -} - -fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); -} diff --git a/evm_arithmetization/tests/empty_txn_list.rs b/evm_arithmetization/tests/empty_txn_list.rs index 1205414f6..e343f7e53 100644 --- a/evm_arithmetization/tests/empty_txn_list.rs +++ b/evm_arithmetization/tests/empty_txn_list.rs @@ -2,11 +2,16 @@ use core::marker::PhantomData; use std::collections::HashMap; use std::time::Duration; -use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use ethereum_types::{BigEndianHash, H256}; use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata, PublicValues, TrieRoots}; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, init_logger, + initial_state_and_storage_tries_with_beacon_roots, update_beacon_roots_account_storage, + BEACON_ROOTS_CONTRACT_ADDRESS_HASHED, +}; use evm_arithmetization::{AllRecursiveCircuits, AllStark, Node, StarkConfig}; +use hex_literal::hex; use keccak_hash::keccak; use log::info; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; @@ -30,43 +35,62 @@ fn test_empty_txn_list() -> anyhow::Result<()> { let block_metadata = BlockMetadata { block_number: 1.into(), + parent_beacon_block_root: H256(hex!( + "44e2566c06c03b132e0ede3e90af477ebca74393b89dd6cb29f9c79cbcb6e963" + )), ..Default::default() }; - let state_trie = HashedPartialTrie::from(Node::Empty); + let (state_trie, storage_tries) = initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); let transactions_trie = HashedPartialTrie::from(Node::Empty); let receipts_trie = HashedPartialTrie::from(Node::Empty); - let storage_tries = vec![]; + + let state_trie_after: HashedPartialTrie = { + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + + Node::Leaf { + nibbles: beacon_roots_account_nibbles(), + value: rlp::encode(&beacon_roots_account).to_vec(), + } + .into() + }; let mut contract_code = HashMap::new(); contract_code.insert(keccak(vec![]), vec![]); - // No transactions, so no trie roots change. + // No transactions, but the beacon roots contract has been updated. let trie_roots_after = TrieRoots { - state_root: state_trie.hash(), + state_root: state_trie_after.hash(), transactions_root: transactions_trie.hash(), receipts_root: receipts_trie.hash(), }; let mut initial_block_hashes = vec![H256::default(); 256]; initial_block_hashes[255] = H256::from_uint(&0x200.into()); - let inputs = GenerationInputs { + let inputs1 = GenerationInputs { signed_txn: None, withdrawals: vec![], tries: TrieInputs { - state_trie, - transactions_trie, - receipts_trie, - storage_tries, + state_trie: state_trie.clone(), + transactions_trie: transactions_trie.clone(), + receipts_trie: receipts_trie.clone(), + storage_tries: storage_tries.clone(), }, trie_roots_after, - contract_code, - checkpoint_state_trie_root: HashedPartialTrie::from(Node::Empty).hash(), - block_metadata, + contract_code: contract_code.clone(), + checkpoint_state_trie_root: state_trie.hash(), + block_metadata: block_metadata.clone(), txn_number_before: 0.into(), gas_used_before: 0.into(), gas_used_after: 0.into(), block_hashes: BlockHashes { - prev_hashes: initial_block_hashes, + prev_hashes: initial_block_hashes.clone(), cur_hash: H256::default(), }, }; @@ -74,8 +98,8 @@ fn test_empty_txn_list() -> anyhow::Result<()> { // Initialize the preprocessed circuits for the zkEVM. let all_circuits = AllRecursiveCircuits::::new( &all_stark, - &[16..17, 9..11, 12..13, 14..15, 9..11, 12..13, 17..18], /* Minimal ranges to prove an - * empty list */ + // Minimal ranges to prove an empty list + &[16..17, 11..13, 13..15, 14..15, 9..10, 12..13, 17..18], &config, ); @@ -108,9 +132,9 @@ fn test_empty_txn_list() -> anyhow::Result<()> { assert_eq!(all_circuits, all_circuits_from_bytes); } - let mut timing = TimingTree::new("prove", log::Level::Info); + let mut timing = TimingTree::new("prove first dummy", log::Level::Info); let (root_proof, public_values) = - all_circuits.prove_root(&all_stark, &config, inputs, &mut timing, None)?; + all_circuits.prove_root(&all_stark, &config, inputs1, &mut timing, None)?; timing.filter(Duration::from_millis(100)).print(); all_circuits.verify_root(root_proof.clone())?; @@ -118,14 +142,51 @@ fn test_empty_txn_list() -> anyhow::Result<()> { let retrieved_public_values = PublicValues::from_public_inputs(&root_proof.public_inputs); assert_eq!(retrieved_public_values, public_values); - // We can duplicate the proofs here because the state hasn't mutated. + // We cannot duplicate the proof here because even though there weren't any + // transactions, the state has mutated when updating the beacon roots contract. + let trie_roots_after = TrieRoots { + state_root: state_trie_after.hash(), + transactions_root: transactions_trie.hash(), + receipts_root: receipts_trie.hash(), + }; + let inputs2 = GenerationInputs { + signed_txn: None, + withdrawals: vec![], + tries: TrieInputs { + state_trie: state_trie_after, + transactions_trie, + receipts_trie, + storage_tries: vec![( + H256(BEACON_ROOTS_CONTRACT_ADDRESS_HASHED), + beacon_roots_account_storage, + )], + }, + trie_roots_after, + contract_code, + checkpoint_state_trie_root: state_trie.hash(), + block_metadata, + txn_number_before: 0.into(), + gas_used_before: 0.into(), + gas_used_after: 0.into(), + block_hashes: BlockHashes { + prev_hashes: initial_block_hashes, + cur_hash: H256::default(), + }, + }; + + let mut timing = TimingTree::new("prove second dummy", log::Level::Info); + let (root_proof2, public_values2) = + all_circuits.prove_root(&all_stark, &config, inputs2, &mut timing, None)?; + timing.filter(Duration::from_millis(100)).print(); + all_circuits.verify_root(root_proof2.clone())?; + let (agg_proof, agg_public_values) = all_circuits.prove_aggregation( false, &root_proof, public_values.clone(), false, - &root_proof, - public_values, + &root_proof2, + public_values2, )?; all_circuits.verify_aggregation(&agg_proof)?; @@ -146,7 +207,3 @@ fn test_empty_txn_list() -> anyhow::Result<()> { let verifier = all_circuits.final_verifier_data(); verifier.verify(block_proof) } - -fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); -} diff --git a/evm_arithmetization/tests/erc20.rs b/evm_arithmetization/tests/erc20.rs index 119fb6ec1..c3235dd9b 100644 --- a/evm_arithmetization/tests/erc20.rs +++ b/evm_arithmetization/tests/erc20.rs @@ -1,12 +1,16 @@ use std::str::FromStr; use std::time::Duration; -use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use ethereum_types::{Address, BigEndianHash, H160, H256, U256}; use evm_arithmetization::generation::mpt::{AccountRlp, LegacyReceiptRlp, LogRlp}; use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata, TrieRoots}; use evm_arithmetization::prover::prove; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, create_account_storage, + init_logger, initial_state_and_storage_tries_with_beacon_roots, sd2u, + update_beacon_roots_account_storage, +}; use evm_arithmetization::verifier::verify_proof; use evm_arithmetization::{AllStark, Node, StarkConfig}; use hex_literal::hex; @@ -61,15 +65,17 @@ fn test_erc20() -> anyhow::Result<()> { let giver_nibbles = Nibbles::from_bytes_be(giver_state_key.as_bytes()).unwrap(); let token_nibbles = Nibbles::from_bytes_be(token_state_key.as_bytes()).unwrap(); - let mut state_trie_before = HashedPartialTrie::from(Node::Empty); + let (mut state_trie_before, mut storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); state_trie_before.insert(sender_nibbles, rlp::encode(&sender_account()).to_vec()); state_trie_before.insert(giver_nibbles, rlp::encode(&giver_account()).to_vec()); state_trie_before.insert(token_nibbles, rlp::encode(&token_account()).to_vec()); - let storage_tries = vec![ + storage_tries.extend([ (giver_state_key, giver_storage()), (token_state_key, token_storage()), - ]; + ]); let tries_before = TrieInputs { state_trie: state_trie_before, @@ -94,6 +100,7 @@ fn test_erc20() -> anyhow::Result<()> { block_gas_used: gas_used, block_blob_base_fee: 0x2.into(), block_bloom: bloom, + ..Default::default() }; let contract_code = [giver_bytecode(), token_bytecode(), vec![]] @@ -101,6 +108,14 @@ fn test_erc20() -> anyhow::Result<()> { .into(); let expected_state_trie_after: HashedPartialTrie = { + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + let mut state_trie_after = HashedPartialTrie::from(Node::Empty); let sender_account = sender_account(); let sender_account_after = AccountRlp { @@ -115,6 +130,10 @@ fn test_erc20() -> anyhow::Result<()> { ..token_account() }; state_trie_after.insert(token_nibbles, rlp::encode(&token_account_after).to_vec()); + state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); state_trie_after }; @@ -181,10 +200,6 @@ fn test_erc20() -> anyhow::Result<()> { verify_proof(&all_stark, proof, &config) } -fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); -} - fn giver_bytecode() -> Vec { hex!("608060405234801561001057600080fd5b50600436106100365760003560e01c8063a52c101e1461003b578063fc0c546a14610050575b600080fd5b61004e61004936600461010c565b61007f565b005b600054610063906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60005460405163a9059cbb60e01b8152731f9090aae28b8a3dceadf281b0f12828e676c3266004820152602481018390526001600160a01b039091169063a9059cbb906044016020604051808303816000875af11580156100e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101089190610125565b5050565b60006020828403121561011e57600080fd5b5035919050565b60006020828403121561013757600080fd5b8151801515811461014757600080fd5b939250505056fea264697066735822122050741efdbac11eb0bbb776ce3ac6004e596b7d7559658a12506164388c371cfd64736f6c63430008140033").into() } @@ -193,53 +208,31 @@ fn token_bytecode() -> Vec { hex!("608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce567146100fe57806370a082311461010d57806395d89b4114610136578063a9059cbb1461013e578063dd62ed3e1461015157600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100eb575b600080fd5b6100a061018a565b6040516100ad919061056a565b60405180910390f35b6100c96100c43660046105d4565b61021c565b60405190151581526020016100ad565b6002545b6040519081526020016100ad565b6100c96100f93660046105fe565b610236565b604051601281526020016100ad565b6100dd61011b36600461063a565b6001600160a01b031660009081526020819052604090205490565b6100a061025a565b6100c961014c3660046105d4565b610269565b6100dd61015f36600461065c565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6060600380546101999061068f565b80601f01602080910402602001604051908101604052809291908181526020018280546101c59061068f565b80156102125780601f106101e757610100808354040283529160200191610212565b820191906000526020600020905b8154815290600101906020018083116101f557829003601f168201915b5050505050905090565b60003361022a818585610277565b60019150505b92915050565b600033610244858285610289565b61024f85858561030c565b506001949350505050565b6060600480546101999061068f565b60003361022a81858561030c565b610284838383600161036b565b505050565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461030657818110156102f757604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064015b60405180910390fd5b6103068484848403600061036b565b50505050565b6001600160a01b03831661033657604051634b637e8f60e11b8152600060048201526024016102ee565b6001600160a01b0382166103605760405163ec442f0560e01b8152600060048201526024016102ee565b610284838383610440565b6001600160a01b0384166103955760405163e602df0560e01b8152600060048201526024016102ee565b6001600160a01b0383166103bf57604051634a1406b160e11b8152600060048201526024016102ee565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561030657826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161043291815260200190565b60405180910390a350505050565b6001600160a01b03831661046b57806002600082825461046091906106c9565b909155506104dd9050565b6001600160a01b038316600090815260208190526040902054818110156104be5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016102ee565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b0382166104f957600280548290039055610518565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161055d91815260200190565b60405180910390a3505050565b600060208083528351808285015260005b818110156105975785810183015185820160400152820161057b565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146105cf57600080fd5b919050565b600080604083850312156105e757600080fd5b6105f0836105b8565b946020939093013593505050565b60008060006060848603121561061357600080fd5b61061c846105b8565b925061062a602085016105b8565b9150604084013590509250925092565b60006020828403121561064c57600080fd5b610655826105b8565b9392505050565b6000806040838503121561066f57600080fd5b610678836105b8565b9150610686602084016105b8565b90509250929050565b600181811c908216806106a357607f821691505b6020821081036106c357634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561023057634e487b7160e01b600052601160045260246000fdfea2646970667358221220266a323ae4a816f6c6342a5be431fedcc0d45c44b02ea75f5474eb450b5d45b364736f6c63430008140033").into() } -fn insert_storage(trie: &mut HashedPartialTrie, slot: U256, value: U256) { - let mut bytes = [0; 32]; - slot.to_big_endian(&mut bytes); - let key = keccak(bytes); - let nibbles = Nibbles::from_bytes_be(key.as_bytes()).unwrap(); - let r = rlp::encode(&value); - let r = r.freeze().to_vec(); - trie.insert(nibbles, r); -} - -fn sd2u(s: &str) -> U256 { - U256::from_dec_str(s).unwrap() -} - fn giver_storage() -> HashedPartialTrie { - let mut trie = HashedPartialTrie::from(Node::Empty); - insert_storage( - &mut trie, + create_account_storage(&[( U256::zero(), sd2u("546584486846459126461364135121053344201067465379"), - ); - trie + )]) } fn token_storage() -> HashedPartialTrie { - let mut trie = HashedPartialTrie::from(Node::Empty); - insert_storage( - &mut trie, + create_account_storage(&[( sd2u("82183438603287090451672504949863617512989139203883434767553028632841710582583"), sd2u("1000000000000000000000"), - ); - trie + )]) } fn token_storage_after() -> HashedPartialTrie { - let mut trie = HashedPartialTrie::from(Node::Empty); - insert_storage( - &mut trie, - sd2u("82183438603287090451672504949863617512989139203883434767553028632841710582583"), - sd2u("900000000000000000000"), - ); - insert_storage( - &mut trie, - sd2u("53006154680716014998529145169423020330606407246856709517064848190396281160729"), - sd2u("100000000000000000000"), - ); - trie + create_account_storage(&[ + ( + sd2u("82183438603287090451672504949863617512989139203883434767553028632841710582583"), + sd2u("900000000000000000000"), + ), + ( + sd2u("53006154680716014998529145169423020330606407246856709517064848190396281160729"), + sd2u("100000000000000000000"), + ), + ]) } fn giver_account() -> AccountRlp { diff --git a/evm_arithmetization/tests/erc721.rs b/evm_arithmetization/tests/erc721.rs index 13ea05a79..29db8f1a8 100644 --- a/evm_arithmetization/tests/erc721.rs +++ b/evm_arithmetization/tests/erc721.rs @@ -1,12 +1,16 @@ use std::str::FromStr; use std::time::Duration; -use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use ethereum_types::{Address, BigEndianHash, H160, H256, U256}; use evm_arithmetization::generation::mpt::{AccountRlp, LegacyReceiptRlp, LogRlp}; use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata, TrieRoots}; use evm_arithmetization::prover::prove; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, create_account_storage, + init_logger, initial_state_and_storage_tries_with_beacon_roots, sd2u, sh2u, + update_beacon_roots_account_storage, +}; use evm_arithmetization::verifier::verify_proof; use evm_arithmetization::{AllStark, Node, StarkConfig}; use hex_literal::hex; @@ -61,11 +65,13 @@ fn test_erc721() -> anyhow::Result<()> { let owner_nibbles = Nibbles::from_bytes_be(owner_state_key.as_bytes()).unwrap(); let contract_nibbles = Nibbles::from_bytes_be(contract_state_key.as_bytes()).unwrap(); - let mut state_trie_before = HashedPartialTrie::from(Node::Empty); + let (mut state_trie_before, mut storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); state_trie_before.insert(owner_nibbles, rlp::encode(&owner_account()).to_vec()); state_trie_before.insert(contract_nibbles, rlp::encode(&contract_account()).to_vec()); - let storage_tries = vec![(contract_state_key, contract_storage())]; + storage_tries.push((contract_state_key, contract_storage())); let tries_before = TrieInputs { state_trie: state_trie_before, @@ -82,8 +88,55 @@ fn test_erc721() -> anyhow::Result<()> { .map(|v| (keccak(v.clone()), v)) .into(); + let logs = vec![LogRlp { + address: H160::from_str("0xf2B1114C644cBb3fF63Bf1dD284c8Cd716e95BE9").unwrap(), + topics: vec![ + H256::from_str("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") + .unwrap(), + H256::from_str("0x0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4") + .unwrap(), + H256::from_str("0x000000000000000000000000ab8483f64d9c6d1ecf9b849ae677dd3315835cb2") + .unwrap(), + H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000539") + .unwrap(), + ], + data: vec![].into(), + }]; + + let mut bloom_bytes = [0u8; 256]; + add_logs_to_bloom(&mut bloom_bytes, &logs); + + let bloom = bloom_bytes + .chunks_exact(32) + .map(U256::from_big_endian) + .collect::>(); + + let block_metadata = BlockMetadata { + block_beneficiary: Address::from(beneficiary), + block_timestamp: 0x03e8.into(), + block_number: 1.into(), + block_difficulty: 0x020000.into(), + block_random: H256::from_uint(&0x020000.into()), + block_gaslimit: 0xff112233u32.into(), + block_chain_id: 1.into(), + block_base_fee: 0xa.into(), + block_gas_used: gas_used, + block_blob_base_fee: 0x2.into(), + block_bloom: bloom.try_into().unwrap(), + ..Default::default() + }; + let expected_state_trie_after: HashedPartialTrie = { let mut state_trie_after = HashedPartialTrie::from(Node::Empty); + + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + let owner_account = owner_account(); let owner_account_after = AccountRlp { nonce: owner_account.nonce + 1, @@ -99,28 +152,14 @@ fn test_erc721() -> anyhow::Result<()> { contract_nibbles, rlp::encode(&contract_account_after).to_vec(), ); + state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); state_trie_after }; - let logs = vec![LogRlp { - address: H160::from_str("0xf2B1114C644cBb3fF63Bf1dD284c8Cd716e95BE9").unwrap(), - topics: vec![ - H256::from_str("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") - .unwrap(), - H256::from_str("0x0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4") - .unwrap(), - H256::from_str("0x000000000000000000000000ab8483f64d9c6d1ecf9b849ae677dd3315835cb2") - .unwrap(), - H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000539") - .unwrap(), - ], - data: vec![].into(), - }]; - - let mut bloom_bytes = [0u8; 256]; - add_logs_to_bloom(&mut bloom_bytes, &logs); - let receipt_0 = LegacyReceiptRlp { status: true, cum_gas_used: gas_used, @@ -141,25 +180,6 @@ fn test_erc721() -> anyhow::Result<()> { receipts_root: receipts_trie.hash(), }; - let bloom = bloom_bytes - .chunks_exact(32) - .map(U256::from_big_endian) - .collect::>(); - - let block_metadata = BlockMetadata { - block_beneficiary: Address::from(beneficiary), - block_timestamp: 0x03e8.into(), - block_number: 1.into(), - block_difficulty: 0x020000.into(), - block_random: H256::from_uint(&0x020000.into()), - block_gaslimit: 0xff112233u32.into(), - block_chain_id: 1.into(), - block_base_fee: 0xa.into(), - block_gas_used: gas_used, - block_blob_base_fee: 0x2.into(), - block_bloom: bloom.try_into().unwrap(), - }; - let inputs = GenerationInputs { signed_txn: Some(txn.to_vec()), withdrawals: vec![], @@ -184,90 +204,58 @@ fn test_erc721() -> anyhow::Result<()> { verify_proof(&all_stark, proof, &config) } -fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); -} - fn contract_bytecode() -> Vec { hex!("608060405234801561000f575f80fd5b5060043610610109575f3560e01c8063715018a6116100a0578063a22cb4651161006f578063a22cb465146102a1578063b88d4fde146102bd578063c87b56dd146102d9578063e985e9c514610309578063f2fde38b1461033957610109565b8063715018a61461023f5780638da5cb5b1461024957806395d89b4114610267578063a14481941461028557610109565b806323b872dd116100dc57806323b872dd146101a757806342842e0e146101c35780636352211e146101df57806370a082311461020f57610109565b806301ffc9a71461010d57806306fdde031461013d578063081812fc1461015b578063095ea7b31461018b575b5f80fd5b61012760048036038101906101229190611855565b610355565b604051610134919061189a565b60405180910390f35b610145610436565b604051610152919061193d565b60405180910390f35b61017560048036038101906101709190611990565b6104c5565b60405161018291906119fa565b60405180910390f35b6101a560048036038101906101a09190611a3d565b6104e0565b005b6101c160048036038101906101bc9190611a7b565b6104f6565b005b6101dd60048036038101906101d89190611a7b565b6105f5565b005b6101f960048036038101906101f49190611990565b610614565b60405161020691906119fa565b60405180910390f35b61022960048036038101906102249190611acb565b610625565b6040516102369190611b05565b60405180910390f35b6102476106db565b005b6102516106ee565b60405161025e91906119fa565b60405180910390f35b61026f610716565b60405161027c919061193d565b60405180910390f35b61029f600480360381019061029a9190611a3d565b6107a6565b005b6102bb60048036038101906102b69190611b48565b6107bc565b005b6102d760048036038101906102d29190611cb2565b6107d2565b005b6102f360048036038101906102ee9190611990565b6107ef565b604051610300919061193d565b60405180910390f35b610323600480360381019061031e9190611d32565b610855565b604051610330919061189a565b60405180910390f35b610353600480360381019061034e9190611acb565b6108e3565b005b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061041f57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061042f575061042e82610967565b5b9050919050565b60605f805461044490611d9d565b80601f016020809104026020016040519081016040528092919081815260200182805461047090611d9d565b80156104bb5780601f10610492576101008083540402835291602001916104bb565b820191905f5260205f20905b81548152906001019060200180831161049e57829003601f168201915b5050505050905090565b5f6104cf826109d0565b506104d982610a56565b9050919050565b6104f282826104ed610a8f565b610a96565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610566575f6040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161055d91906119fa565b60405180910390fd5b5f6105798383610574610a8f565b610aa8565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105ef578382826040517f64283d7b0000000000000000000000000000000000000000000000000000000081526004016105e693929190611dcd565b60405180910390fd5b50505050565b61060f83838360405180602001604052805f8152506107d2565b505050565b5f61061e826109d0565b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610696575f6040517f89c62b6400000000000000000000000000000000000000000000000000000000815260040161068d91906119fa565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6106e3610cb3565b6106ec5f610d3a565b565b5f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60606001805461072590611d9d565b80601f016020809104026020016040519081016040528092919081815260200182805461075190611d9d565b801561079c5780601f106107735761010080835404028352916020019161079c565b820191905f5260205f20905b81548152906001019060200180831161077f57829003601f168201915b5050505050905090565b6107ae610cb3565b6107b88282610dfd565b5050565b6107ce6107c7610a8f565b8383610e1a565b5050565b6107dd8484846104f6565b6107e984848484610f83565b50505050565b60606107fa826109d0565b505f610804611135565b90505f8151116108225760405180602001604052805f81525061084d565b8061082c8461114b565b60405160200161083d929190611e3c565b6040516020818303038152906040525b915050919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b6108eb610cb3565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361095b575f6040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260040161095291906119fa565b60405180910390fd5b61096481610d3a565b50565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f806109db83611215565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610a4d57826040517f7e273289000000000000000000000000000000000000000000000000000000008152600401610a449190611b05565b60405180910390fd5b80915050919050565b5f60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f33905090565b610aa3838383600161124e565b505050565b5f80610ab384611215565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610af457610af381848661140d565b5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610b7f57610b335f855f8061124e565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825403925050819055505b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614610bfe57600160035f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8460025f8681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4809150509392505050565b610cbb610a8f565b73ffffffffffffffffffffffffffffffffffffffff16610cd96106ee565b73ffffffffffffffffffffffffffffffffffffffff1614610d3857610cfc610a8f565b6040517f118cdaa7000000000000000000000000000000000000000000000000000000008152600401610d2f91906119fa565b60405180910390fd5b565b5f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160065f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b610e16828260405180602001604052805f8152506114d0565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610e8a57816040517f5b08ba18000000000000000000000000000000000000000000000000000000008152600401610e8191906119fa565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610f76919061189a565b60405180910390a3505050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b111561112f578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02610fc6610a8f565b8685856040518563ffffffff1660e01b8152600401610fe89493929190611eb1565b6020604051808303815f875af192505050801561102357506040513d601f19601f820116820180604052508101906110209190611f0f565b60015b6110a4573d805f8114611051576040519150601f19603f3d011682016040523d82523d5f602084013e611056565b606091505b505f81510361109c57836040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161109391906119fa565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461112d57836040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161112491906119fa565b60405180910390fd5b505b50505050565b606060405180602001604052805f815250905090565b60605f6001611159846114eb565b0190505f8167ffffffffffffffff81111561117757611176611b8e565b5b6040519080825280601f01601f1916602001820160405280156111a95781602001600182028036833780820191505090505b5090505f82602001820190505b60011561120a578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a85816111ff576111fe611f3a565b5b0494505f85036111b6575b819350505050919050565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b808061128657505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b156113b8575f611295846109d0565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156112ff57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561131257506113108184610855565b155b1561135457826040517fa9fbf51f00000000000000000000000000000000000000000000000000000000815260040161134b91906119fa565b60405180910390fd5b81156113b657838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b8360045f8581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b61141883838361163c565b6114cb575f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361148c57806040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016114839190611b05565b60405180910390fd5b81816040517f177e802f0000000000000000000000000000000000000000000000000000000081526004016114c2929190611f67565b60405180910390fd5b505050565b6114da83836116fc565b6114e65f848484610f83565b505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310611547577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161153d5761153c611f3a565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310611584576d04ee2d6d415b85acef8100000000838161157a57611579611f3a565b5b0492506020810190505b662386f26fc1000083106115b357662386f26fc1000083816115a9576115a8611f3a565b5b0492506010810190505b6305f5e10083106115dc576305f5e10083816115d2576115d1611f3a565b5b0492506008810190505b61271083106116015761271083816115f7576115f6611f3a565b5b0492506004810190505b60648310611624576064838161161a57611619611f3a565b5b0492506002810190505b600a8310611633576001810190505b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156116f357508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806116b457506116b38484610855565b5b806116f257508273ffffffffffffffffffffffffffffffffffffffff166116da83610a56565b73ffffffffffffffffffffffffffffffffffffffff16145b5b90509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361176c575f6040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161176391906119fa565b60405180910390fd5b5f61177883835f610aa8565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146117ea575f6040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081526004016117e191906119fa565b60405180910390fd5b505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61183481611800565b811461183e575f80fd5b50565b5f8135905061184f8161182b565b92915050565b5f6020828403121561186a576118696117f8565b5b5f61187784828501611841565b91505092915050565b5f8115159050919050565b61189481611880565b82525050565b5f6020820190506118ad5f83018461188b565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156118ea5780820151818401526020810190506118cf565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61190f826118b3565b61191981856118bd565b93506119298185602086016118cd565b611932816118f5565b840191505092915050565b5f6020820190508181035f8301526119558184611905565b905092915050565b5f819050919050565b61196f8161195d565b8114611979575f80fd5b50565b5f8135905061198a81611966565b92915050565b5f602082840312156119a5576119a46117f8565b5b5f6119b28482850161197c565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6119e4826119bb565b9050919050565b6119f4816119da565b82525050565b5f602082019050611a0d5f8301846119eb565b92915050565b611a1c816119da565b8114611a26575f80fd5b50565b5f81359050611a3781611a13565b92915050565b5f8060408385031215611a5357611a526117f8565b5b5f611a6085828601611a29565b9250506020611a718582860161197c565b9150509250929050565b5f805f60608486031215611a9257611a916117f8565b5b5f611a9f86828701611a29565b9350506020611ab086828701611a29565b9250506040611ac18682870161197c565b9150509250925092565b5f60208284031215611ae057611adf6117f8565b5b5f611aed84828501611a29565b91505092915050565b611aff8161195d565b82525050565b5f602082019050611b185f830184611af6565b92915050565b611b2781611880565b8114611b31575f80fd5b50565b5f81359050611b4281611b1e565b92915050565b5f8060408385031215611b5e57611b5d6117f8565b5b5f611b6b85828601611a29565b9250506020611b7c85828601611b34565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b611bc4826118f5565b810181811067ffffffffffffffff82111715611be357611be2611b8e565b5b80604052505050565b5f611bf56117ef565b9050611c018282611bbb565b919050565b5f67ffffffffffffffff821115611c2057611c1f611b8e565b5b611c29826118f5565b9050602081019050919050565b828183375f83830152505050565b5f611c56611c5184611c06565b611bec565b905082815260208101848484011115611c7257611c71611b8a565b5b611c7d848285611c36565b509392505050565b5f82601f830112611c9957611c98611b86565b5b8135611ca9848260208601611c44565b91505092915050565b5f805f8060808587031215611cca57611cc96117f8565b5b5f611cd787828801611a29565b9450506020611ce887828801611a29565b9350506040611cf98782880161197c565b925050606085013567ffffffffffffffff811115611d1a57611d196117fc565b5b611d2687828801611c85565b91505092959194509250565b5f8060408385031215611d4857611d476117f8565b5b5f611d5585828601611a29565b9250506020611d6685828601611a29565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611db457607f821691505b602082108103611dc757611dc6611d70565b5b50919050565b5f606082019050611de05f8301866119eb565b611ded6020830185611af6565b611dfa60408301846119eb565b949350505050565b5f81905092915050565b5f611e16826118b3565b611e208185611e02565b9350611e308185602086016118cd565b80840191505092915050565b5f611e478285611e0c565b9150611e538284611e0c565b91508190509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611e8382611e5f565b611e8d8185611e69565b9350611e9d8185602086016118cd565b611ea6816118f5565b840191505092915050565b5f608082019050611ec45f8301876119eb565b611ed160208301866119eb565b611ede6040830185611af6565b8181036060830152611ef08184611e79565b905095945050505050565b5f81519050611f098161182b565b92915050565b5f60208284031215611f2457611f236117f8565b5b5f611f3184828501611efb565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f604082019050611f7a5f8301856119eb565b611f876020830184611af6565b939250505056fea2646970667358221220432b30673e00c0eb009e1718c271f4cfdfbeded17345829703b06d322360990164736f6c63430008160033").into() } -fn insert_storage(trie: &mut HashedPartialTrie, slot: U256, value: U256) { - let mut bytes = [0; 32]; - slot.to_big_endian(&mut bytes); - let key = keccak(bytes); - let nibbles = Nibbles::from_bytes_be(key.as_bytes()).unwrap(); - let r = rlp::encode(&value); - let r = r.freeze().to_vec(); - trie.insert(nibbles, r); -} - -fn sd2u(s: &str) -> U256 { - U256::from_dec_str(s).unwrap() -} - -fn sh2u(s: &str) -> U256 { - U256::from_str_radix(s, 16).unwrap() -} - fn contract_storage() -> HashedPartialTrie { - let mut trie = HashedPartialTrie::from(Node::Empty); - insert_storage( - &mut trie, - U256::zero(), - sh2u("0x54657374546f6b656e0000000000000000000000000000000000000000000012"), - ); - insert_storage( - &mut trie, - U256::one(), - sh2u("0x5445535400000000000000000000000000000000000000000000000000000008"), - ); - insert_storage( - &mut trie, - sd2u("6"), - sh2u("0x5b38da6a701c568545dcfcb03fcb875f56beddc4"), - ); - insert_storage( - &mut trie, - sh2u("0x343ff8127bd64f680be4e996254dc3528603c6ecd54364b4cf956ebdd28f0028"), - sh2u("0x5b38da6a701c568545dcfcb03fcb875f56beddc4"), - ); - insert_storage( - &mut trie, - sh2u("0x118c1ea466562cb796e30ef705e4db752f5c39d773d22c5efd8d46f67194e78a"), - sd2u("1"), - ); - trie + create_account_storage(&[ + ( + U256::zero(), + sh2u("0x54657374546f6b656e0000000000000000000000000000000000000000000012"), + ), + ( + U256::one(), + sh2u("0x5445535400000000000000000000000000000000000000000000000000000008"), + ), + ( + sd2u("6"), + sh2u("0x5b38da6a701c568545dcfcb03fcb875f56beddc4"), + ), + ( + sh2u("0x343ff8127bd64f680be4e996254dc3528603c6ecd54364b4cf956ebdd28f0028"), + sh2u("0x5b38da6a701c568545dcfcb03fcb875f56beddc4"), + ), + ( + sh2u("0x118c1ea466562cb796e30ef705e4db752f5c39d773d22c5efd8d46f67194e78a"), + sd2u("1"), + ), + ]) } fn contract_storage_after() -> HashedPartialTrie { - let mut trie = HashedPartialTrie::from(Node::Empty); - insert_storage( - &mut trie, - U256::zero(), - sh2u("0x54657374546f6b656e0000000000000000000000000000000000000000000012"), - ); - insert_storage( - &mut trie, - U256::one(), - sh2u("0x5445535400000000000000000000000000000000000000000000000000000008"), - ); - insert_storage( - &mut trie, - sd2u("6"), - sh2u("0x5b38da6a701c568545dcfcb03fcb875f56beddc4"), - ); - insert_storage( - &mut trie, - sh2u("0x343ff8127bd64f680be4e996254dc3528603c6ecd54364b4cf956ebdd28f0028"), - sh2u("0xab8483f64d9c6d1ecf9b849ae677dd3315835cb2"), - ); - insert_storage( - &mut trie, - sh2u("0xf3aa6a8a9f7e3707e36cc99c499a27514922afe861ec3d80a1a314409cba92f9"), - sd2u("1"), - ); - trie + create_account_storage(&[ + ( + U256::zero(), + sh2u("0x54657374546f6b656e0000000000000000000000000000000000000000000012"), + ), + ( + U256::one(), + sh2u("0x5445535400000000000000000000000000000000000000000000000000000008"), + ), + ( + sd2u("6"), + sh2u("0x5b38da6a701c568545dcfcb03fcb875f56beddc4"), + ), + ( + sh2u("0x343ff8127bd64f680be4e996254dc3528603c6ecd54364b4cf956ebdd28f0028"), + sh2u("0xab8483f64d9c6d1ecf9b849ae677dd3315835cb2"), + ), + ( + sh2u("0xf3aa6a8a9f7e3707e36cc99c499a27514922afe861ec3d80a1a314409cba92f9"), + sd2u("1"), + ), + ]) } fn owner_account() -> AccountRlp { diff --git a/evm_arithmetization/tests/log_opcode.rs b/evm_arithmetization/tests/log_opcode.rs index c7326ef00..5d3735a6b 100644 --- a/evm_arithmetization/tests/log_opcode.rs +++ b/evm_arithmetization/tests/log_opcode.rs @@ -3,7 +3,6 @@ use std::str::FromStr; use std::time::Duration; use bytes::Bytes; -use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use ethereum_types::{Address, BigEndianHash, H256, U256}; use evm_arithmetization::generation::mpt::transaction_testing::{ AddressOption, LegacyTransactionRlp, @@ -12,6 +11,11 @@ use evm_arithmetization::generation::mpt::{AccountRlp, LegacyReceiptRlp, LogRlp} use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata, TrieRoots}; use evm_arithmetization::prover::prove; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, init_logger, + initial_state_and_storage_tries_with_beacon_roots, update_beacon_roots_account_storage, + BEACON_ROOTS_CONTRACT_ADDRESS_HASHED, +}; use evm_arithmetization::verifier::verify_proof; use evm_arithmetization::{AllRecursiveCircuits, AllStark, Node, StarkConfig}; use hex_literal::hex; @@ -84,7 +88,9 @@ fn test_log_opcodes() -> anyhow::Result<()> { }; // Initialize the state trie with three accounts. - let mut state_trie_before = HashedPartialTrie::from(Node::Empty); + let (mut state_trie_before, mut storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); state_trie_before.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_before).to_vec(), @@ -92,6 +98,8 @@ fn test_log_opcodes() -> anyhow::Result<()> { 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()); + storage_tries.push((to_hashed, Node::Empty.into())); + // We now add two receipts with logs and data. This updates the receipt trie as // well. let log_0 = LogRlp { @@ -125,7 +133,7 @@ fn test_log_opcodes() -> anyhow::Result<()> { state_trie: state_trie_before, transactions_trie: Node::Empty.into(), receipts_trie: receipts_trie.clone(), - storage_tries: vec![(to_hashed, Node::Empty.into())], + storage_tries, }; // Prove a transaction which carries out two LOG opcodes. @@ -141,9 +149,8 @@ fn test_log_opcodes() -> anyhow::Result<()> { block_gaslimit: 0xffffffffu32.into(), block_chain_id: 1.into(), block_base_fee: 0xa.into(), - block_gas_used: 0.into(), block_blob_base_fee: 0x2.into(), - block_bloom: [0.into(); 8], + ..Default::default() }; let mut contract_code = HashMap::new(); @@ -169,6 +176,13 @@ fn test_log_opcodes() -> anyhow::Result<()> { ..AccountRlp::default() }; + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = beacon_roots_contract_from_storage(&beacon_roots_account_storage); + // Update the receipt trie. let first_log = LogRlp { address: to.into(), @@ -204,6 +218,10 @@ fn test_log_opcodes() -> anyhow::Result<()> { ); 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()); + expected_state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), @@ -316,7 +334,9 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { // `to_account`. let gas_price = 10; let txn_value = 0xau64; - let mut state_trie_before = HashedPartialTrie::from(Node::Empty); + let (mut state_trie_before, storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); state_trie_before.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_before).to_vec(), @@ -333,7 +353,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { state_trie: state_trie_before, transactions_trie: Node::Empty.into(), receipts_trie: Node::Empty.into(), - storage_tries: vec![], + storage_tries, }; let txn = hex!("f85f800a82520894095e7baea6a6c7c4c2dfeb977efac326af552d870a8026a0122f370ed4023a6c253350c6bfb87d7d7eb2cd86447befee99e0a26b70baec20a07100ab1b3977f2b4571202b9f4b68850858caf5469222794600b5ce1cfb348ad"); @@ -364,7 +384,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { .unwrap(), U256::from_dec_str("2722259584404615024560450425766186844160").unwrap(), ], - block_random: Default::default(), + ..Default::default() }; let beneficiary_account_after = AccountRlp { @@ -383,6 +403,13 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { ..AccountRlp::default() }; + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_1_metadata.block_timestamp, + block_1_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = beacon_roots_contract_from_storage(&beacon_roots_account_storage); + let mut contract_code = HashMap::new(); contract_code.insert(keccak(vec![]), vec![]); contract_code.insert(code_hash, code.to_vec()); @@ -398,6 +425,10 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { to_second_nibbles, rlp::encode(&to_account_second_before).to_vec(), ); + expected_state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); // Compute new receipt trie. let mut receipts_trie = HashedPartialTrie::from(Node::Empty); @@ -547,6 +578,14 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { rlp::encode(&to_account_second_after).to_vec(), ); + // Copy without the beacon roots account for the next block. + let mut state_trie_after_block2 = expected_state_trie_after.clone(); + + expected_state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); + transactions_trie.insert(Nibbles::from_str("0x01").unwrap(), txn_2.to_vec()); let block_1_state_root = expected_state_trie_after.hash(); @@ -602,7 +641,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { let block_2_metadata = BlockMetadata { block_beneficiary: Address::from(beneficiary), - block_timestamp: 0x03e8.into(), + block_timestamp: 0x03e9.into(), block_number: 2.into(), block_difficulty: 0x020000.into(), block_gaslimit: 0x445566u32.into(), @@ -614,6 +653,19 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { let mut contract_code = HashMap::new(); contract_code.insert(keccak(vec![]), vec![]); + let initial_beacon_roots_account_storage = beacon_roots_account_storage.clone(); + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_2_metadata.block_timestamp, + block_2_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = beacon_roots_contract_from_storage(&beacon_roots_account_storage); + + state_trie_after_block2.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); + let inputs = GenerationInputs { signed_txn: None, withdrawals: vec![], @@ -621,10 +673,13 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { state_trie: expected_state_trie_after, transactions_trie: Node::Empty.into(), receipts_trie: Node::Empty.into(), - storage_tries: vec![], + storage_tries: vec![( + H256(BEACON_ROOTS_CONTRACT_ADDRESS_HASHED), + initial_beacon_roots_account_storage, + )], }, trie_roots_after: TrieRoots { - state_root: trie_roots_after.state_root, + state_root: state_trie_after_block2.hash(), transactions_root: HashedPartialTrie::from(Node::Empty).hash(), receipts_root: HashedPartialTrie::from(Node::Empty).hash(), }, @@ -639,19 +694,31 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { cur_hash: block_2_hash, }, }; + let mut inputs2 = inputs.clone(); let (root_proof, public_values) = all_circuits.prove_root(&all_stark, &config, inputs, &mut timing, None)?; all_circuits.verify_root(root_proof.clone())?; - // We can just duplicate the initial proof as the state didn't change. + // We cannot duplicate the proof here because even though there weren't any + // transactions, the state has mutated when updating the beacon roots contract. + inputs2.tries.storage_tries = vec![( + H256(BEACON_ROOTS_CONTRACT_ADDRESS_HASHED), + beacon_roots_account_storage, + )]; + inputs2.tries.state_trie = state_trie_after_block2; + + let (root_proof2, public_values2) = + all_circuits.prove_root(&all_stark, &config, inputs2, &mut timing, None)?; + all_circuits.verify_root(root_proof2.clone())?; + let (agg_proof, updated_agg_public_values) = all_circuits.prove_aggregation( false, &root_proof, public_values.clone(), false, - &root_proof, - public_values, + &root_proof2, + public_values2, )?; all_circuits.verify_aggregation(&agg_proof)?; @@ -777,7 +844,3 @@ fn test_txn_and_receipt_trie_hash() -> anyhow::Result<()> { Ok(()) } - -fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); -} diff --git a/evm_arithmetization/tests/self_balance_gas_cost.rs b/evm_arithmetization/tests/self_balance_gas_cost.rs index 40609a140..292c5f95e 100644 --- a/evm_arithmetization/tests/self_balance_gas_cost.rs +++ b/evm_arithmetization/tests/self_balance_gas_cost.rs @@ -2,12 +2,15 @@ use std::collections::HashMap; use std::str::FromStr; use std::time::Duration; -use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use ethereum_types::{Address, H256, U256}; use evm_arithmetization::generation::mpt::{AccountRlp, LegacyReceiptRlp}; use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata, TrieRoots}; use evm_arithmetization::prover::prove; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, init_logger, + initial_state_and_storage_tries_with_beacon_roots, update_beacon_roots_account_storage, +}; use evm_arithmetization::verifier::verify_proof; use evm_arithmetization::{AllStark, Node, StarkConfig}; use hex_literal::hex; @@ -73,7 +76,9 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { ..AccountRlp::default() }; - let mut state_trie_before = HashedPartialTrie::from(Node::Empty); + let (mut state_trie_before, mut storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); state_trie_before.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_before).to_vec(), @@ -81,11 +86,13 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { 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()); + storage_tries.push((to_hashed, Node::Empty.into())); + let tries_before = TrieInputs { state_trie: state_trie_before, transactions_trie: Node::Empty.into(), receipts_trie: Node::Empty.into(), - storage_tries: vec![(to_hashed, Node::Empty.into())], + storage_tries, }; let txn = hex!("f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b"); @@ -100,10 +107,9 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { block_timestamp: 0x03e8.into(), block_gaslimit: 0xff112233u32.into(), block_gas_used: gas_used.into(), - block_bloom: [0.into(); 8], block_base_fee: 0xa.into(), block_blob_base_fee: 0x2.into(), - block_random: Default::default(), + ..Default::default() }; let mut contract_code = HashMap::new(); @@ -135,6 +141,14 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { ..AccountRlp::default() }; + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty); expected_state_trie_after.insert( beneficiary_nibbles, @@ -143,6 +157,10 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { 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()); + expected_state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); expected_state_trie_after }; @@ -191,7 +209,3 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { verify_proof(&all_stark, proof, &config) } - -fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); -} diff --git a/evm_arithmetization/tests/selfdestruct.rs b/evm_arithmetization/tests/selfdestruct.rs index ebf01c8da..921852551 100644 --- a/evm_arithmetization/tests/selfdestruct.rs +++ b/evm_arithmetization/tests/selfdestruct.rs @@ -1,12 +1,15 @@ use std::str::FromStr; use std::time::Duration; -use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; -use ethereum_types::{Address, BigEndianHash, H256, U256}; +use ethereum_types::{Address, BigEndianHash, H256}; use evm_arithmetization::generation::mpt::{AccountRlp, LegacyReceiptRlp}; use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata, TrieRoots}; use evm_arithmetization::prover::prove; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, eth_to_wei, init_logger, + initial_state_and_storage_tries_with_beacon_roots, update_beacon_roots_account_storage, +}; use evm_arithmetization::verifier::verify_proof; use evm_arithmetization::{AllStark, Node, StarkConfig}; use hex_literal::hex; @@ -56,7 +59,9 @@ fn test_selfdestruct() -> anyhow::Result<()> { code_hash: keccak(&code), }; - let mut state_trie_before = HashedPartialTrie::from(Node::Empty); + let (mut state_trie_before, storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); 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()); @@ -64,7 +69,7 @@ fn test_selfdestruct() -> anyhow::Result<()> { state_trie: state_trie_before, transactions_trie: HashedPartialTrie::from(Node::Empty), receipts_trie: HashedPartialTrie::from(Node::Empty), - storage_tries: vec![], + storage_tries, }; // Generated using a little py-evm script. @@ -81,13 +86,22 @@ fn test_selfdestruct() -> anyhow::Result<()> { block_base_fee: 0xa.into(), block_gas_used: 26002.into(), block_blob_base_fee: 0x2.into(), - block_bloom: [0.into(); 8], + ..Default::default() }; let contract_code = [(keccak(&code), code.clone()), (keccak([]), vec![])].into(); let expected_state_trie_after: HashedPartialTrie = { let mut state_trie_after = HashedPartialTrie::from(Node::Empty); + + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + let sender_account_after = AccountRlp { nonce: 6.into(), balance: eth_to_wei(110_000.into()) - 26_002 * 0xa, @@ -105,6 +119,11 @@ fn test_selfdestruct() -> anyhow::Result<()> { code_hash: keccak(&code), }; state_trie_after.insert(to_nibbles, rlp::encode(&to_account_before).to_vec()); + state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); + state_trie_after }; @@ -153,12 +172,3 @@ fn test_selfdestruct() -> anyhow::Result<()> { verify_proof(&all_stark, proof, &config) } - -fn eth_to_wei(eth: U256) -> U256 { - // 1 ether = 10^18 wei. - eth * U256::from(10).pow(18.into()) -} - -fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); -} diff --git a/evm_arithmetization/tests/simple_transfer.rs b/evm_arithmetization/tests/simple_transfer.rs index 08928a076..812677516 100644 --- a/evm_arithmetization/tests/simple_transfer.rs +++ b/evm_arithmetization/tests/simple_transfer.rs @@ -2,12 +2,15 @@ use std::collections::HashMap; use std::str::FromStr; use std::time::Duration; -use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use ethereum_types::{Address, BigEndianHash, H256, U256}; use evm_arithmetization::generation::mpt::{AccountRlp, LegacyReceiptRlp}; use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata, TrieRoots}; use evm_arithmetization::prover::prove; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, eth_to_wei, init_logger, + initial_state_and_storage_tries_with_beacon_roots, update_beacon_roots_account_storage, +}; use evm_arithmetization::verifier::verify_proof; use evm_arithmetization::{AllStark, Node, StarkConfig}; use hex_literal::hex; @@ -48,17 +51,16 @@ fn test_simple_transfer() -> anyhow::Result<()> { }; let to_account_before = AccountRlp::default(); - let state_trie_before = Node::Leaf { - nibbles: sender_nibbles, - value: rlp::encode(&sender_account_before).to_vec(), - } - .into(); + let (mut state_trie_before, storage_tries) = + initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); + state_trie_before.insert(sender_nibbles, rlp::encode(&sender_account_before).to_vec()); let tries_before = TrieInputs { state_trie: state_trie_before, transactions_trie: HashedPartialTrie::from(Node::Empty), receipts_trie: HashedPartialTrie::from(Node::Empty), - storage_tries: vec![], + storage_tries, }; // Generated using a little py-evm script. @@ -76,7 +78,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { block_base_fee: 0xa.into(), block_gas_used: 21032.into(), block_blob_base_fee: 0x2.into(), - block_bloom: [0.into(); 8], + ..Default::default() }; let mut contract_code = HashMap::new(); @@ -86,6 +88,14 @@ fn test_simple_transfer() -> anyhow::Result<()> { let txdata_gas = 2 * 16; let gas_used = 21_000 + txdata_gas; + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + let sender_account_after = AccountRlp { balance: sender_account_before.balance - value - gas_used * 10, nonce: sender_account_before.nonce + 1, @@ -107,6 +117,12 @@ fn test_simple_transfer() -> anyhow::Result<()> { value: rlp::encode(&to_account_after).to_vec(), } .into(); + children[beacon_roots_account_nibbles().get_nibble(0) as usize] = Node::Leaf { + nibbles: beacon_roots_account_nibbles().truncate_n_nibbles_front(1), + value: rlp::encode(&beacon_roots_account).to_vec(), + } + .into(); + Node::Branch { children, value: vec![], @@ -159,12 +175,3 @@ fn test_simple_transfer() -> anyhow::Result<()> { verify_proof(&all_stark, proof, &config) } - -fn eth_to_wei(eth: U256) -> U256 { - // 1 ether = 10^18 wei. - eth * U256::from(10).pow(18.into()) -} - -fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); -} diff --git a/evm_arithmetization/tests/withdrawals.rs b/evm_arithmetization/tests/withdrawals.rs index 28dc6da59..56742be03 100644 --- a/evm_arithmetization/tests/withdrawals.rs +++ b/evm_arithmetization/tests/withdrawals.rs @@ -1,12 +1,15 @@ use std::collections::HashMap; use std::time::Duration; -use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use ethereum_types::{H160, H256, U256}; use evm_arithmetization::generation::mpt::AccountRlp; use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; use evm_arithmetization::proof::{BlockHashes, BlockMetadata, TrieRoots}; use evm_arithmetization::prover::prove; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, init_logger, + initial_state_and_storage_tries_with_beacon_roots, update_beacon_roots_account_storage, +}; use evm_arithmetization::verifier::verify_proof; use evm_arithmetization::{AllStark, Node, StarkConfig}; use keccak_hash::keccak; @@ -31,10 +34,10 @@ fn test_withdrawals() -> anyhow::Result<()> { let block_metadata = BlockMetadata::default(); - let state_trie_before = HashedPartialTrie::from(Node::Empty); + let (state_trie_before, storage_tries) = initial_state_and_storage_tries_with_beacon_roots(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); let transactions_trie = HashedPartialTrie::from(Node::Empty); let receipts_trie = HashedPartialTrie::from(Node::Empty); - let storage_tries = vec![]; let mut contract_code = HashMap::new(); contract_code.insert(keccak(vec![]), vec![]); @@ -44,6 +47,14 @@ fn test_withdrawals() -> anyhow::Result<()> { let state_trie_after = { let mut trie = HashedPartialTrie::from(Node::Empty); + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + 0.into(), + block_metadata.parent_beacon_block_root, + ); + let beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + let addr_state_key = keccak(withdrawals[0].0); let addr_nibbles = Nibbles::from_bytes_be(addr_state_key.as_bytes()).unwrap(); let account = AccountRlp { @@ -51,6 +62,11 @@ fn test_withdrawals() -> anyhow::Result<()> { ..AccountRlp::default() }; trie.insert(addr_nibbles, rlp::encode(&account).to_vec()); + trie.insert( + beacon_roots_account_nibbles(), + rlp::encode(&beacon_roots_account).to_vec(), + ); + trie }; @@ -88,7 +104,3 @@ fn test_withdrawals() -> anyhow::Result<()> { verify_proof(&all_stark, proof, &config) } - -fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); -}