From 88d75edfba7e3a8f7b2b9f7a580d13db444d8b8e Mon Sep 17 00:00:00 2001 From: BGluth Date: Fri, 19 Apr 2024 16:01:13 -0600 Subject: [PATCH 1/2] `main` --> `0.3.0` (#138) * Update plonky2 dependencies (#119) * Update plonky2 dependencies * Modify changelog * Charge gas before SLOAD and refactor `insert_accessed_storage_keys` (#117) * Charge gas before SLOAD and refactor `insert_accessed_storage_keys` * fmt * Only store value for cold access * PR feedback --------- Co-authored-by: BGluth * Increased the public interface for `trie_tools` (#123) - `trie_tools` needs to access a bit of currently private logic. Specifically, it needs to be able to process compact bytecode into `mpt_tries` directly. - I think this change is actually reasonable. I can see realistic use cases where we don't need to process an entire block trace but instead just want to decode some compact bytecode. - With the current public interface, the caller can only pass in an entire block trace to process. * Mpt trie panic refactor (#118) * refactor: refactoring mpt_trie to use more Results * fix: replace anyhow with this-error for mpt_trie * style: formatting * fix: fix results * fix: pr fixes * fix: fix error message * fix: format * fix: fix unusefull return type * fix: fix formatting * fix: pr fixes * fix: pr fixes * fix: pr fixes * tests: refactor some tests --------- Co-authored-by: Vladimir Trifonov * refactor: remove some reallocations from decoder (#126) Co-authored-by: Vladimir Trifonov * Charge cold access cost in *CALL* before accessing state (#124) * Charge cold access cost in CALL before accessing state * PR feedback --------- Co-authored-by: BGluth * chore: add debug function for better logging in development (#134) * chore: add debug function for better logging in development * chore: fix clippy issue --------- Co-authored-by: Vladimir Trifonov * Make test_receipt_encoding more meaningful. (#131) * Make test_receipt_encoding more meaningful. * Apply comment * Add a getter for the KERNEL codehash (#136) * Update CHANGELOG * Version bump for next release (#137) * Bumped sub-crate versions for a new release * Added in missing change log entries - Other PRs missed updating `CHANGELOG.md` * feat: swap out the internal U512 inside nibbles (#132) * feat: swap out the internal U512 inside nibbles * fix: comment fix * fix: fix clippy pr issues * fix: fix clippy issue * fix: fix pr comments * docs: update changelog * fix: update impl_to_nibbles --------- Co-authored-by: Vladimir Trifonov * Some clippy fixes (#149) * MAX fixes for clippy * fix transmut without annotations * please the fmt gods * Remove interpreter-specific preinialization logic from State trait (#139) * Remove interpreter specific methods from State trait * Changelog * Make some more functions constant (#154) * Make some more functions constant * Update changelog * fix(keccak-sponge): properly constrain padding bytes (#158) * fix(keccak-sponge): properly constrain padding bytes * fix: block bytes offset * fix: constrain zero padding bytes * fix: use collect_vec * feat: replace is_final_input_len with is_padding_byte * fix: remove unnecessary iterators * Update evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> * Update evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> * Update evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> * Update evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> * Update evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> * Update evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> * fix: remove redundant constraint * docs: define padding byte in comment --------- Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> * Reduce verbosity in logs (#160) * Reduce verbosity in logs * CHANGELOG * Add entry for 158 in CHANGELOG * Bump with latest starky (#161) * Bump with latest plonky2 * CHANGELOG * feat: decouple trace_decoder and proof_gen (#163) Co-authored-by: Vladimir Trifonov * Simplify withdrawals logic (#168) * Simplify withdrawals logic * Update CHANGELOG * Clippy * feat: extend trace decoder err info (#148) * feat: extend trace decoder err info * fix: fix clippy issue * feat: swap out the internal U512 inside nibbles (#132) * feat: swap out the internal U512 inside nibbles * fix: comment fix * fix: fix clippy pr issues * fix: fix clippy issue * fix: fix pr comments * docs: update changelog * fix: update impl_to_nibbles --------- Co-authored-by: Vladimir Trifonov * Some clippy fixes (#149) * MAX fixes for clippy * fix transmut without annotations * please the fmt gods * fix: add pr comments fixes * fix: add pr comments fix * fix: add pr comment fix * docs: update changelog --------- Co-authored-by: Vladimir Trifonov Co-authored-by: Ben * Moved `Unreleased` changes to `0.3.0` (#173) - Also added two missing PRs --------- Co-authored-by: Hamy Ratoanina Co-authored-by: wborgeaud Co-authored-by: Vladimir Trifonov Co-authored-by: Vladimir Trifonov Co-authored-by: Linda Guiga <101227802+LindaGuiga@users.noreply.github.com> Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> Co-authored-by: Robin Salen Co-authored-by: Ben Co-authored-by: Ayush Shukla --- CHANGELOG.md | 30 +- Cargo.toml | 4 +- evm_arithmetization/Cargo.toml | 4 +- evm_arithmetization/src/all_stark.rs | 45 +- .../src/arithmetic/arithmetic_stark.rs | 6 +- evm_arithmetization/src/arithmetic/modular.rs | 8 +- .../src/byte_packing/byte_packing_stark.rs | 2 +- evm_arithmetization/src/cpu/cpu_stark.rs | 4 +- .../src/cpu/kernel/asm/core/access_lists.asm | 79 ++-- .../src/cpu/kernel/asm/core/call_gas.asm | 18 +- .../kernel/asm/mpt/storage/storage_read.asm | 23 +- .../kernel/asm/mpt/storage/storage_write.asm | 21 +- .../asm/transactions/common_decoding.asm | 7 +- .../src/cpu/kernel/assembler.rs | 7 +- .../src/cpu/kernel/interpreter.rs | 28 +- .../src/cpu/kernel/tests/account_code.rs | 2 +- .../src/cpu/kernel/tests/balance.rs | 2 +- .../src/cpu/kernel/tests/core/access_lists.rs | 28 +- .../src/cpu/kernel/tests/mpt/delete.rs | 8 +- .../src/cpu/kernel/tests/mpt/insert.rs | 2 +- .../src/cpu/kernel/tests/receipt.rs | 10 +- .../src/fixed_recursive_verifier.rs | 5 +- evm_arithmetization/src/generation/mpt.rs | 12 +- .../src/generation/prover_input.rs | 4 +- evm_arithmetization/src/generation/state.rs | 16 - .../src/generation/trie_extractor.rs | 6 +- .../src/keccak/keccak_stark.rs | 2 +- .../src/keccak_sponge/columns.rs | 10 +- .../src/keccak_sponge/keccak_sponge_stark.rs | 192 ++++++-- evm_arithmetization/src/lib.rs | 2 + .../src/memory/memory_stark.rs | 7 +- evm_arithmetization/src/recursive_verifier.rs | 14 + evm_arithmetization/tests/add11_yml.rs | 14 +- .../tests/basic_smart_contract.rs | 2 +- evm_arithmetization/tests/erc20.rs | 63 +-- evm_arithmetization/tests/erc721.rs | 58 +-- evm_arithmetization/tests/log_opcode.rs | 57 +-- .../tests/self_balance_gas_cost.rs | 14 +- evm_arithmetization/tests/selfdestruct.rs | 8 +- evm_arithmetization/tests/simple_transfer.rs | 2 +- evm_arithmetization/tests/withdrawals.rs | 2 +- mpt_trie/Cargo.toml | 6 +- mpt_trie/examples/ethereum_trie.rs | 26 +- mpt_trie/examples/hash_nodes.rs | 19 +- mpt_trie/examples/simple.rs | 27 +- mpt_trie/src/debug_tools/diff.rs | 15 +- mpt_trie/src/debug_tools/query.rs | 6 +- mpt_trie/src/debug_tools/stats.rs | 41 +- mpt_trie/src/nibbles.rs | 387 +++++++++++++--- mpt_trie/src/partial_trie.rs | 48 +- mpt_trie/src/special_query.rs | 13 +- mpt_trie/src/testing_utils.rs | 22 +- mpt_trie/src/trie_hashing.rs | 40 +- mpt_trie/src/trie_ops.rs | 290 +++++++----- mpt_trie/src/trie_subsets.rs | 75 +-- mpt_trie/src/utils.rs | 21 +- proof_gen/Cargo.toml | 5 +- proof_gen/README.md | 2 +- proof_gen/src/lib.rs | 3 +- proof_gen/src/proof_gen.rs | 5 +- proof_gen/src/proof_types.rs | 7 +- proof_gen/src/prover_state.rs | 2 +- trace_decoder/Cargo.toml | 6 +- .../compact/compact_prestate_processing.rs | 117 +++-- .../src/compact/compact_to_partial_trie.rs | 18 +- .../src/compact/complex_test_payloads.rs | 25 +- trace_decoder/src/compact/mod.rs | 4 +- trace_decoder/src/decoding.rs | 430 ++++++++++++------ trace_decoder/src/lib.rs | 2 +- trace_decoder/src/processed_block_trace.rs | 30 +- trace_decoder/src/types.rs | 6 - trace_decoder/src/utils.rs | 11 +- 72 files changed, 1652 insertions(+), 885 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b60a5397..6eca93b5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,34 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + ## [Unreleased] +### Changed + +## [0.3.0] - 2024-04-19 + +### Changed +- Update plonky2 dependencies ([#119](https://github.com/0xPolygonZero/zk_evm/pull/119)) +- Swap out the internal U512 inside nibbles to [u64;5] ([#132](https://github.com/0xPolygonZero/zk_evm/pull/132)) +- Charge gas before SLOAD and refactor `insert_accessed_storage_keys` ([#117](https://github.com/0xPolygonZero/zk_evm/pull/117)) +- Increased the public interface for `trie_tools` ([#123](https://github.com/0xPolygonZero/zk_evm/pull/123)) +- Mpt trie panic refactor ([#118](https://github.com/0xPolygonZero/zk_evm/pull/118)) +- refactor: remove some reallocations from decoder ([#126](https://github.com/0xPolygonZero/zk_evm/pull/126)) +- Charge cold access cost in *CALL* before accessing state ([#124](https://github.com/0xPolygonZero/zk_evm/pull/124)) +- chore: add debug function for better logging in development ([#134](https://github.com/0xPolygonZero/zk_evm/pull/134)) +- Make test_receipt_encoding more meaningful. ([#131](https://github.com/0xPolygonZero/zk_evm/pull/131)) +- Add a getter for the KERNEL codehash ([#136](https://github.com/0xPolygonZero/zk_evm/pull/136)) +- Remove interpreter-specific preinialization logic from State trait ([#139](https://github.com/0xPolygonZero/zk_evm/pull/139)) +- Make some more functions constant ([#154](https://github.com/0xPolygonZero/zk_evm/pull/154)) +- fix(keccak-sponge): properly constrain padding bytes ([#158](https://github.com/0xPolygonZero/zk_evm/pull/158)) +- Reduce verbosity in logs ([#160](https://github.com/0xPolygonZero/zk_evm/pull/160)) +- Bump with latest starky ([#161](https://github.com/0xPolygonZero/zk_evm/pull/161)) +- Decouple trace_decoder and proof_gen ([#163](https://github.com/0xPolygonZero/zk_evm/pull/163)) +- Extend trace decoder err info ([#148](https://github.com/0xPolygonZero/zk_evm/pull/148)) +- Add debug function for better public values logging in development ([#134](https://github.com/0xPolygonZero/zk_evm/pull/134)) +- Simplify withdrawals logic ([#168](https://github.com/0xPolygonZero/zk_evm/pull/168)) + ## [0.2.0] - 2024-03-19 ### Changed @@ -18,8 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Reduce state trie size for dummy payloads ([#88](https://github.com/0xPolygonZero/zk_evm/pull/88)) - Fix post-txn trie debugging output for multi-logs receipts ([#86](https://github.com/0xPolygonZero/zk_evm/pull/86)) - Fixed *most* failing blocks caused by the merged in aggressive pruning changes ([#97](https://github.com/0xPolygonZero/zk_evm/pull/97)) -- Fixed trie hash collision issue when constructing storage tries [#75](https://github.com/0xPolygonZero/zk_evm/pull/75) -- Fix interpreter rollback by adding the clock to generation state checkpoints ([#109] https://github.com/0xPolygonZero/zk_evm/pull/109) +- Fixed trie hash collision issue when constructing storage tries ([#75](https://github.com/0xPolygonZero/zk_evm/pull/75)) +- Fix interpreter rollback by adding the clock to generation state checkpoints ([#109](https://github.com/0xPolygonZero/zk_evm/pull/109)) ## [0.1.1] - 2024-03-01 diff --git a/Cargo.toml b/Cargo.toml index ef8d457fc..61db35cd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,10 @@ serde_json = "1.0.96" thiserror = "1.0.49" # plonky2-related dependencies -plonky2 = "0.2.0" +plonky2 = "0.2.2" plonky2_maybe_rayon = "0.2.0" plonky2_util = "0.2.0" -starky = "0.2.1" +starky = "0.4.0" [workspace.package] diff --git a/evm_arithmetization/Cargo.toml b/evm_arithmetization/Cargo.toml index 12a3438a8..43e75b902 100644 --- a/evm_arithmetization/Cargo.toml +++ b/evm_arithmetization/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "evm_arithmetization" description = "Implementation of STARKs for the Ethereum Virtual Machine" -version = "0.1.2" +version = "0.1.3" authors = ["Daniel Lubarov ", "William Borgeaud "] readme = "README.md" categories = ["cryptography"] @@ -41,7 +41,7 @@ tiny-keccak = "2.0.2" serde_json = { workspace = true } # Local dependencies -mpt_trie = { version = "0.2.0", path = "../mpt_trie" } +mpt_trie = { version = "0.2.1", path = "../mpt_trie" } [target.'cfg(not(target_env = "msvc"))'.dependencies] jemallocator = "0.5.0" diff --git a/evm_arithmetization/src/all_stark.rs b/evm_arithmetization/src/all_stark.rs index 942b5cd2f..f8422b300 100644 --- a/evm_arithmetization/src/all_stark.rs +++ b/evm_arithmetization/src/all_stark.rs @@ -138,27 +138,27 @@ fn ctl_byte_packing() -> CrossTableLookup { let cpu_packing_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_byte_packing(), - Some(cpu_stark::ctl_filter_byte_packing()), + cpu_stark::ctl_filter_byte_packing(), ); let cpu_unpacking_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_byte_unpacking(), - Some(cpu_stark::ctl_filter_byte_unpacking()), + cpu_stark::ctl_filter_byte_unpacking(), ); let cpu_push_packing_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_byte_packing_push(), - Some(cpu_stark::ctl_filter_byte_packing_push()), + cpu_stark::ctl_filter_byte_packing_push(), ); let cpu_jumptable_read_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_jumptable_read(), - Some(cpu_stark::ctl_filter_syscall_exceptions()), + cpu_stark::ctl_filter_syscall_exceptions(), ); let byte_packing_looked = TableWithColumns::new( *Table::BytePacking, byte_packing_stark::ctl_looked_data(), - Some(byte_packing_stark::ctl_looked_filter()), + byte_packing_stark::ctl_looked_filter(), ); CrossTableLookup::new( vec![ @@ -179,12 +179,12 @@ fn ctl_keccak_inputs() -> CrossTableLookup { let keccak_sponge_looking = TableWithColumns::new( *Table::KeccakSponge, keccak_sponge_stark::ctl_looking_keccak_inputs(), - Some(keccak_sponge_stark::ctl_looking_keccak_filter()), + keccak_sponge_stark::ctl_looking_keccak_filter(), ); let keccak_looked = TableWithColumns::new( *Table::Keccak, keccak_stark::ctl_data_inputs(), - Some(keccak_stark::ctl_filter_inputs()), + keccak_stark::ctl_filter_inputs(), ); CrossTableLookup::new(vec![keccak_sponge_looking], keccak_looked) } @@ -196,12 +196,12 @@ fn ctl_keccak_outputs() -> CrossTableLookup { let keccak_sponge_looking = TableWithColumns::new( *Table::KeccakSponge, keccak_sponge_stark::ctl_looking_keccak_outputs(), - Some(keccak_sponge_stark::ctl_looking_keccak_filter()), + keccak_sponge_stark::ctl_looking_keccak_filter(), ); let keccak_looked = TableWithColumns::new( *Table::Keccak, keccak_stark::ctl_data_outputs(), - Some(keccak_stark::ctl_filter_outputs()), + keccak_stark::ctl_filter_outputs(), ); CrossTableLookup::new(vec![keccak_sponge_looking], keccak_looked) } @@ -212,12 +212,12 @@ fn ctl_keccak_sponge() -> CrossTableLookup { let cpu_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_keccak_sponge(), - Some(cpu_stark::ctl_filter_keccak_sponge()), + cpu_stark::ctl_filter_keccak_sponge(), ); let keccak_sponge_looked = TableWithColumns::new( *Table::KeccakSponge, keccak_sponge_stark::ctl_looked_data(), - Some(keccak_sponge_stark::ctl_looked_filter()), + keccak_sponge_stark::ctl_looked_filter(), ); CrossTableLookup::new(vec![cpu_looking], keccak_sponge_looked) } @@ -228,19 +228,18 @@ fn ctl_logic() -> CrossTableLookup { let cpu_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_logic(), - Some(cpu_stark::ctl_filter_logic()), + cpu_stark::ctl_filter_logic(), ); let mut all_lookers = vec![cpu_looking]; for i in 0..keccak_sponge_stark::num_logic_ctls() { let keccak_sponge_looking = TableWithColumns::new( *Table::KeccakSponge, keccak_sponge_stark::ctl_looking_logic(i), - Some(keccak_sponge_stark::ctl_looking_logic_filter()), + keccak_sponge_stark::ctl_looking_logic_filter(), ); all_lookers.push(keccak_sponge_looking); } - let logic_looked = - TableWithColumns::new(*Table::Logic, logic::ctl_data(), Some(logic::ctl_filter())); + let logic_looked = TableWithColumns::new(*Table::Logic, logic::ctl_data(), logic::ctl_filter()); CrossTableLookup::new(all_lookers, logic_looked) } @@ -250,42 +249,42 @@ fn ctl_memory() -> CrossTableLookup { let cpu_memory_code_read = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_code_memory(), - Some(cpu_stark::ctl_filter_code_memory()), + cpu_stark::ctl_filter_code_memory(), ); let cpu_memory_gp_ops = (0..NUM_GP_CHANNELS).map(|channel| { TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_gp_memory(channel), - Some(cpu_stark::ctl_filter_gp_memory(channel)), + cpu_stark::ctl_filter_gp_memory(channel), ) }); let cpu_push_write_ops = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_partial_memory::(), - Some(cpu_stark::ctl_filter_partial_memory()), + cpu_stark::ctl_filter_partial_memory(), ); let cpu_set_context_write = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_memory_old_sp_write_set_context::(), - Some(cpu_stark::ctl_filter_set_context()), + cpu_stark::ctl_filter_set_context(), ); let cpu_set_context_read = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_memory_new_sp_read_set_context::(), - Some(cpu_stark::ctl_filter_set_context()), + cpu_stark::ctl_filter_set_context(), ); let keccak_sponge_reads = (0..KECCAK_RATE_BYTES).map(|i| { TableWithColumns::new( *Table::KeccakSponge, keccak_sponge_stark::ctl_looking_memory(i), - Some(keccak_sponge_stark::ctl_looking_memory_filter(i)), + keccak_sponge_stark::ctl_looking_memory_filter(i), ) }); let byte_packing_ops = (0..32).map(|i| { TableWithColumns::new( *Table::BytePacking, byte_packing_stark::ctl_looking_memory(i), - Some(byte_packing_stark::ctl_looking_memory_filter(i)), + byte_packing_stark::ctl_looking_memory_filter(i), ) }); let all_lookers = vec![ @@ -302,7 +301,7 @@ fn ctl_memory() -> CrossTableLookup { let memory_looked = TableWithColumns::new( *Table::Memory, memory_stark::ctl_data(), - Some(memory_stark::ctl_filter()), + memory_stark::ctl_filter(), ); CrossTableLookup::new(all_lookers, memory_looked) } diff --git a/evm_arithmetization/src/arithmetic/arithmetic_stark.rs b/evm_arithmetization/src/arithmetic/arithmetic_stark.rs index f6877c95f..d0712a3bc 100644 --- a/evm_arithmetization/src/arithmetic/arithmetic_stark.rs +++ b/evm_arithmetization/src/arithmetic/arithmetic_stark.rs @@ -100,9 +100,7 @@ pub(crate) fn ctl_arithmetic_rows() -> TableWithColumns { let mut filter_cols = COMBINED_OPS.to_vec(); filter_cols.push((columns::IS_RANGE_CHECK, 0x01)); - let filter = Some(Filter::new_simple(Column::sum( - filter_cols.iter().map(|(c, _v)| *c), - ))); + let filter = Filter::new_simple(Column::sum(filter_cols.iter().map(|(c, _v)| *c))); let mut all_combined_cols = COMBINED_OPS.to_vec(); all_combined_cols.push((columns::OPCODE_COL, 0x01)); @@ -323,7 +321,7 @@ impl, const D: usize> Stark for ArithmeticSta columns: Column::singles(SHARED_COLS).collect(), table_column: Column::single(RANGE_COUNTER), frequencies_column: Column::single(RC_FREQUENCIES), - filter_columns: vec![None; NUM_SHARED_COLS], + filter_columns: vec![Default::default(); NUM_SHARED_COLS], }] } diff --git a/evm_arithmetization/src/arithmetic/modular.rs b/evm_arithmetization/src/arithmetic/modular.rs index 70761d4be..f91bebe99 100644 --- a/evm_arithmetization/src/arithmetic/modular.rs +++ b/evm_arithmetization/src/arithmetic/modular.rs @@ -307,7 +307,7 @@ pub(crate) fn generate_modular_op( let (lo, hi) = quot_limbs.split_at_mut(N_LIMBS); // Verify that the elements are in the expected range. - debug_assert!(lo.iter().all(|&c| c <= u16::max_value() as i64)); + debug_assert!(lo.iter().all(|&c| c <= u16::MAX as i64)); // Top half of quot_limbs should be zero. debug_assert!(hi.iter().all(|&d| d.is_zero())); @@ -318,7 +318,7 @@ pub(crate) fn generate_modular_op( // it's in the range [0, 2^16 - 1] which will correctly // range-check. for c in lo { - *c += u16::max_value() as i64; + *c += u16::MAX as i64; } // Store the sign of the quotient after the quotient. hi[0] = 1; @@ -522,7 +522,7 @@ pub(crate) fn submod_constr_poly( let sign = hi[0]; // sign must be 1 (negative) or 0 (positive) yield_constr.constraint(filter * sign * (sign - P::ONES)); - let offset = P::Scalar::from_canonical_u16(u16::max_value()); + let offset = P::Scalar::from_canonical_u16(u16::MAX); for c in lo { *c -= offset * sign; } @@ -723,7 +723,7 @@ pub(crate) fn submod_constr_poly_ext_circuit, const let t = builder.mul_extension(filter, t); // sign must be 1 (negative) or 0 (positive) yield_constr.constraint(builder, t); - let offset = F::from_canonical_u16(u16::max_value()); + let offset = F::from_canonical_u16(u16::MAX); for c in lo { let t = builder.mul_const_extension(offset, sign); *c = builder.sub_extension(*c, t); diff --git a/evm_arithmetization/src/byte_packing/byte_packing_stark.rs b/evm_arithmetization/src/byte_packing/byte_packing_stark.rs index 8708e2040..1a0acb51c 100644 --- a/evm_arithmetization/src/byte_packing/byte_packing_stark.rs +++ b/evm_arithmetization/src/byte_packing/byte_packing_stark.rs @@ -402,7 +402,7 @@ impl, const D: usize> Stark for BytePackingSt columns: Column::singles(value_bytes(0)..value_bytes(0) + NUM_BYTES).collect(), table_column: Column::single(RANGE_COUNTER), frequencies_column: Column::single(RC_FREQUENCIES), - filter_columns: vec![None; NUM_BYTES], + filter_columns: vec![Default::default(); NUM_BYTES], }] } diff --git a/evm_arithmetization/src/cpu/cpu_stark.rs b/evm_arithmetization/src/cpu/cpu_stark.rs index 4e60694b0..2c626584e 100644 --- a/evm_arithmetization/src/cpu/cpu_stark.rs +++ b/evm_arithmetization/src/cpu/cpu_stark.rs @@ -116,7 +116,7 @@ pub(crate) fn ctl_arithmetic_base_rows() -> TableWithColumns { TableWithColumns::new( *Table::Cpu, columns, - Some(Filter::new( + Filter::new( vec![(Column::single(COL_MAP.op.push_prover_input), col_bit)], vec![Column::sum([ COL_MAP.op.binary_op, @@ -126,7 +126,7 @@ pub(crate) fn ctl_arithmetic_base_rows() -> TableWithColumns { COL_MAP.op.syscall, COL_MAP.op.exception, ])], - )), + ), ) } diff --git a/evm_arithmetization/src/cpu/kernel/asm/core/access_lists.asm b/evm_arithmetization/src/cpu/kernel/asm/core/access_lists.asm index 76d183e5f..5d0512a12 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/core/access_lists.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/core/access_lists.asm @@ -199,15 +199,15 @@ global remove_accessed_addresses: %macro insert_accessed_storage_keys - %stack (addr, key, value) -> (addr, key, value, %%after) + %stack (addr, key) -> (addr, key, %%after) %jump(insert_accessed_storage_keys) %%after: - // stack: cold_access, original_value + // stack: cold_access, value_ptr %endmacro // Multiply the ptr at the top of the stack by 4 // and abort if 4*ptr - SEGMENT_ACCESSED_STORAGE_KEYS >= @GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN -// In this way ptr must be poiting to the begining of a node. +// In this way ptr must be pointing to the beginning of a node. %macro get_valid_storage_ptr // stack: ptr %mul_const(4) @@ -218,41 +218,41 @@ global remove_accessed_addresses: // stack: 2*ptr %endmacro -/// Inserts the storage key and value into the access list if it is not already present. -/// `value` should be the current storage value at the slot `(addr, key)`. -/// Return `1, value` if the storage key was inserted, `0, original_value` if it was already present. +/// Inserts the storage key into the access list if it is not already present. +/// Return `1, value_ptr` if the storage key was inserted, `0, value_ptr` if it was already present. +/// Callers to this function must ensure the original storage value is stored at `value_ptr`. global insert_accessed_storage_keys: - // stack: addr, key, value, retdest + // stack: addr, key, retdest PROVER_INPUT(access_lists::storage_insert) - // stack: pred_ptr/4, addr, key, value, retdest + // stack: pred_ptr/4, addr, key, retdest %get_valid_storage_ptr - // stack: pred_ptr, addr, key, value, retdest + // stack: pred_ptr, addr, key, retdest DUP1 MLOAD_GENERAL DUP1 - // stack: pred_addr, pred_addr, pred_ptr, addr, key, value, retdest + // stack: pred_addr, pred_addr, pred_ptr, addr, key, retdest DUP4 GT DUP3 %eq_const(@SEGMENT_ACCESSED_STORAGE_KEYS) ADD // OR %jumpi(insert_storage_key) - // stack: pred_addr, pred_ptr, addr, key, value, retdest + // stack: pred_addr, pred_ptr, addr, key, retdest // We know that addr <= pred_addr. It must hold that pred_addr == addr. DUP3 %assert_eq - // stack: pred_ptr, addr, key, value, retdest + // stack: pred_ptr, addr, key, retdest DUP1 %increment MLOAD_GENERAL - // stack: pred_key, pred_ptr, addr, key, value, retdest + // stack: pred_key, pred_ptr, addr, key, retdest DUP1 DUP5 GT - // stack: key > pred_key, pred_key, pred_ptr, addr, key, value, retdest + // stack: key > pred_key, pred_key, pred_ptr, addr, key, retdest %jumpi(insert_storage_key) - // stack: pred_key, pred_ptr, addr, key, value, retdest + // stack: pred_key, pred_ptr, addr, key, retdest DUP4 // We know that key <= pred_key. It must hold that pred_key == key. %assert_eq - // stack: pred_ptr, addr, key, value, retdest + // stack: pred_ptr, addr, key, retdest // Check that this is not a deleted node DUP1 %add_const(3) @@ -262,75 +262,78 @@ global insert_accessed_storage_keys: PANIC storage_key_found: // The address was already in the list - // stack: pred_ptr, addr, key, value, retdest + // stack: pred_ptr, addr, key, retdest %add_const(2) - MLOAD_GENERAL - %stack (original_value, addr, key, value, retdest) -> (retdest, 0, original_value) // Return 0 to indicate that the address was already present. + %stack (value_ptr, addr, key, retdest) -> (retdest, 0, value_ptr) // Return 0 to indicate that the address was already present. JUMP insert_storage_key: - // stack: pred_addr or pred_key, pred_ptr, addr, key, value, retdest + // stack: pred_addr or pred_key, pred_ptr, addr, key, retdest POP // Insert a new storage key - // stack: pred_ptr, addr, key, value, retdest + // stack: pred_ptr, addr, key, retdest // get the value of the next address %add_const(3) - // stack: next_ptr_ptr, addr, key, value, retdest + // stack: next_ptr_ptr, addr, key, retdest %mload_global_metadata(@GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN) DUP2 MLOAD_GENERAL - // stack: next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest + // stack: next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest // Check that this is not a deleted node DUP1 %eq_const(@U256_MAX) %assert_zero DUP1 MLOAD_GENERAL - // stack: next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest + // stack: next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest DUP5 // Check that addr < next_val OR (next_val == addr AND key < next_key) DUP2 DUP2 LT - // stack: addr < next_val, addr, next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest + // stack: addr < next_val, addr, next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest SWAP2 EQ - // stack: next_val == addr, addr < next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest + // stack: next_val == addr, addr < next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest DUP3 %increment MLOAD_GENERAL DUP8 LT - // stack: next_key > key, next_val == addr, addr < next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest + // stack: next_key > key, next_val == addr, addr < next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest AND OR %assert_nonzero - // stack: next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest + // stack: next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest SWAP2 DUP2 MSTORE_GENERAL - // stack: new_ptr, next_ptr, addr, key, value, retdest + // stack: new_ptr, next_ptr, addr, key, retdest DUP1 DUP4 MSTORE_GENERAL // store addr - // stack: new_ptr, next_ptr, addr, key, value, retdest + // stack: new_ptr, next_ptr, addr, key, retdest %increment DUP1 + // stack: new_ptr+1, new_ptr+1, next_ptr, addr, key, retdest DUP5 + // stack: key, new_ptr+1, new_ptr+1, next_ptr, addr, key, retdest MSTORE_GENERAL // store key + // stack: new_ptr+1, next_ptr, addr, key, retdest %increment DUP1 - DUP6 - MSTORE_GENERAL // store value - // stack: new_ptr + 2, next_ptr, addr, key, value, retdest + // stack: new_ptr+2, value_ptr, next_ptr, addr, key, retdest %increment DUP1 - // stack: new_next_ptr, new_next_ptr, next_ptr, addr, key, value, retdest - SWAP2 + // stack: new_next_ptr, new_next_ptr, value_ptr, next_ptr, addr, key, retdest + SWAP3 + // stack: next_ptr, new_next_ptr, value_ptr, new_next_ptr, addr, key, retdest MSTORE_GENERAL - // stack: new_next_ptr, addr, key, value, retdest + // stack: value_ptr, new_next_ptr, addr, key, retdest + SWAP1 + // stack: new_next_ptr, value_ptr, addr, key, retdest %increment %mstore_global_metadata(@GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN) - // stack: addr, key, value, retdest - %stack (addr, key, value, retdest) -> (addr, key, retdest, 1, value) + // stack: value_ptr, addr, key, retdest + %stack (value_ptr, addr, key, retdest) -> (addr, key, retdest, 1, value_ptr) %journal_add_storage_loaded JUMP diff --git a/evm_arithmetization/src/cpu/kernel/asm/core/call_gas.asm b/evm_arithmetization/src/cpu/kernel/asm/core/call_gas.asm index 396135213..5945c1e17 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/core/call_gas.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/core/call_gas.asm @@ -13,8 +13,10 @@ global call_charge_gas: // stack: is_call_or_callcode, is_call_or_staticcall, cold_access, address, gas, kexit_info, value, retdest SWAP2 // stack: cold_access, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest - %mul_const(@GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS) - %add_const(@GAS_WARMACCESS) + %jumpi(charge_cold_access_gas) + // stack: is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest +call_charge_gas_contd: + PUSH @GAS_WARMACCESS // stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest DUP3 // stack: is_call_or_callcode, cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest @@ -90,3 +92,15 @@ new_cost_nonzero: // stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest %add_const(@GAS_NEWACCOUNT) %jump(after_new_cost) + +charge_cold_access_gas: + // stack: is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest + SWAP4 + // stack: kexit_info, is_call_or_callcode, address, gas, is_call_or_staticcall, value, retdest + PUSH @GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS + // stack: cold_access_cost, kexit_info, is_call_or_callcode, address, gas, is_call_or_staticcall, value, retdest + %charge_gas + // stack: kexit_info, is_call_or_callcode, address, gas, is_call_or_staticcall, value, retdest + SWAP4 + // stack: is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest + %jump(call_charge_gas_contd) diff --git a/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_read.asm b/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_read.asm index 84d8d0efc..db9fe4222 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_read.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_read.asm @@ -39,18 +39,25 @@ global sys_sload: SWAP1 DUP1 // stack: slot, slot, kexit_info - %sload_current - - %stack (value, slot, kexit_info) -> (slot, value, kexit_info, value) %address - // stack: addr, slot, value, kexit_info, value + // stack: address, slot, slot, kexit_info %insert_accessed_storage_keys - // stack: cold_access, old_value, kexit_info, value - SWAP1 POP - // stack: cold_access, kexit_info, value + // stack: cold_access, value_ptr, slot, kexit_info + DUP1 %mul_const(@GAS_COLDSLOAD_MINUS_WARMACCESS) %add_const(@GAS_WARMACCESS) + %stack (gas, cold_access, value_ptr, slot, kexit_info) -> (gas, kexit_info, cold_access, value_ptr, slot) %charge_gas - // stack: kexit_info, value + + %stack (kexit_info, cold_access, value_ptr, slot) -> (slot, cold_access, value_ptr, kexit_info) + %sload_current + // stack: value, cold_access, value_ptr, kexit_info + SWAP1 %jumpi(sload_cold_access) + %stack (value, value_ptr, kexit_info) -> (kexit_info, value) EXIT_KERNEL +sload_cold_access: + // stack: value, value_ptr, kexit_info + %stack (value, value_ptr, kexit_info) -> (value, value_ptr, kexit_info, value) + MSTORE_GENERAL + EXIT_KERNEL diff --git a/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_write.asm b/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_write.asm index 08270dfa9..22c5d29de 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_write.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_write.asm @@ -9,11 +9,26 @@ global sys_sstore: %stack (kexit_info, slot, value) -> (slot, kexit_info, slot, value) %sload_current %address - %stack (addr, current_value, kexit_info, slot, value) -> (addr, slot, current_value, current_value, kexit_info, slot, value) + %stack (addr, current_value, kexit_info, slot, value) -> (addr, slot, current_value, kexit_info, slot, value) %insert_accessed_storage_keys - // stack: cold_access, original_value, current_value, kexit_info, slot, value - %mul_const(@GAS_COLDSLOAD) + // stack: cold_access, value_ptr, current_value, kexit_info, slot, value + %jumpi(sstore_cold_access) + // stack: value_ptr, current_value, kexit_info, slot, value + MLOAD_GENERAL + // stack: original_value, current_value, kexit_info, slot, value + PUSH 0 + // stack: gas, original_value, current_value, kexit_info, slot, value + %jump(sstore_after_cold_access_check) + +sstore_cold_access: + // stack: value_ptr, current_value, kexit_info, slot, value + DUP2 MSTORE_GENERAL + // stack: current_value, kexit_info, slot, value + DUP1 + PUSH @GAS_COLDSLOAD + // stack: gas, original_value, current_value, kexit_info, slot, value +sstore_after_cold_access_check: // Check for warm access. %stack (gas, original_value, current_value, kexit_info, slot, value) -> (value, current_value, current_value, original_value, gas, original_value, current_value, kexit_info, slot, value) diff --git a/evm_arithmetization/src/cpu/kernel/asm/transactions/common_decoding.asm b/evm_arithmetization/src/cpu/kernel/asm/transactions/common_decoding.asm index 4a8feccaa..223e0a62e 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/transactions/common_decoding.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/transactions/common_decoding.asm @@ -226,7 +226,12 @@ insert_accessed_storage_keys_with_original_value: after_read: %stack (value, addr, key, retdest) -> ( addr, key, value, retdest) %insert_accessed_storage_keys - %pop2 + // stack: cold_access, value_ptr, value, retdest + SWAP2 + // stack: value, value_ptr, cold_access, retdest + MSTORE_GENERAL + // stack: cold_access, retdest + POP JUMP diff --git a/evm_arithmetization/src/cpu/kernel/assembler.rs b/evm_arithmetization/src/cpu/kernel/assembler.rs index e28fc815b..7dfba09fc 100644 --- a/evm_arithmetization/src/cpu/kernel/assembler.rs +++ b/evm_arithmetization/src/cpu/kernel/assembler.rs @@ -27,7 +27,7 @@ pub(crate) const BYTES_PER_OFFSET: u8 = 3; pub struct Kernel { pub(crate) code: Vec, - /// Computed using `hash_kernel`. + /// Hash of the `Kernel` code. pub(crate) code_hash: H256, pub(crate) global_labels: HashMap, @@ -59,6 +59,11 @@ impl Kernel { } } + /// Outputs the Kernel code hash. + pub const fn hash(&self) -> H256 { + self.code_hash + } + pub fn to_file(&self, path: &str) { let kernel_serialized = serde_json::to_string(self).unwrap(); fs::write(path, kernel_serialized).expect("Unable to write kernel to file"); diff --git a/evm_arithmetization/src/cpu/kernel/interpreter.rs b/evm_arithmetization/src/cpu/kernel/interpreter.rs index 593b4a3f8..1e8ec7ccd 100644 --- a/evm_arithmetization/src/cpu/kernel/interpreter.rs +++ b/evm_arithmetization/src/cpu/kernel/interpreter.rs @@ -705,7 +705,7 @@ impl Interpreter { self.generation_state.registers.stack_len } - pub(crate) fn stack_top(&self) -> anyhow::Result { + pub(crate) const fn stack_top(&self) -> anyhow::Result { if self.stack_len() > 0 { Ok(self.generation_state.registers.stack_top) } else { @@ -738,6 +738,20 @@ impl Interpreter { .memory .set(MemoryAddress::new(0, Segment::RlpRaw, 0), 0x80.into()) } + + /// Inserts a preinitialized segment, given as a [Segment], + /// into the `preinitialized_segments` memory field. + fn insert_preinitialized_segment(&mut self, segment: Segment, values: MemorySegmentState) { + self.generation_state + .memory + .insert_preinitialized_segment(segment, values); + } + + fn is_preinitialized_segment(&self, segment: usize) -> bool { + self.generation_state + .memory + .is_preinitialized_segment(segment) + } } impl State for Interpreter { @@ -752,18 +766,6 @@ impl State for Interpreter { } } - fn insert_preinitialized_segment(&mut self, segment: Segment, values: MemorySegmentState) { - self.generation_state - .memory - .insert_preinitialized_segment(segment, values); - } - - fn is_preinitialized_segment(&self, segment: usize) -> bool { - self.generation_state - .memory - .is_preinitialized_segment(segment) - } - fn incr_gas(&mut self, n: u64) { self.generation_state.incr_gas(n); } diff --git a/evm_arithmetization/src/cpu/kernel/tests/account_code.rs b/evm_arithmetization/src/cpu/kernel/tests/account_code.rs index a8102f36c..5ad2d8485 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/account_code.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/account_code.rs @@ -115,7 +115,7 @@ fn prepare_interpreter( .push(value_ptr.into()) .expect("The stack should not overflow"); // value_ptr interpreter - .push(k.try_into_u256().unwrap()) + .push(k.try_into().unwrap()) .expect("The stack should not overflow"); // key interpreter.run()?; diff --git a/evm_arithmetization/src/cpu/kernel/tests/balance.rs b/evm_arithmetization/src/cpu/kernel/tests/balance.rs index 984772027..034df53a8 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/balance.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/balance.rs @@ -67,7 +67,7 @@ fn prepare_interpreter( .push(value_ptr.into()) .expect("The stack should not overflow"); // value_ptr interpreter - .push(k.try_into_u256().unwrap()) + .push(k.try_into().unwrap()) .expect("The stack should not overflow"); // key interpreter.run()?; diff --git a/evm_arithmetization/src/cpu/kernel/tests/core/access_lists.rs b/evm_arithmetization/src/cpu/kernel/tests/core/access_lists.rs index b2e8227fe..eab300ce2 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/core/access_lists.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/core/access_lists.rs @@ -208,12 +208,12 @@ fn test_insert_accessed_storage_keys() -> Result<()> { let mut rng = thread_rng(); let n = 10; let mut storage_keys = (0..n) - .map(|_| (rng.gen::
(), U256(rng.gen()), U256(rng.gen()))) + .map(|_| (rng.gen::
(), U256(rng.gen()))) .collect::>() .into_iter() - .collect::>(); + .collect::>(); let storage_key_in_list = storage_keys[rng.gen_range(0..n)]; - let storage_key_not_in_list = (rng.gen::
(), U256(rng.gen()), U256(rng.gen())); + let storage_key_not_in_list = (rng.gen::
(), U256(rng.gen())); assert!( !storage_keys.contains(&storage_key_not_in_list), "Cosmic luck or bad RNG?" @@ -223,28 +223,25 @@ fn test_insert_accessed_storage_keys() -> Result<()> { for i in 0..n { let addr = U256::from(storage_keys[i].0 .0.as_slice()); let key = storage_keys[i].1; - let value = storage_keys[i].2; interpreter.push(retaddr); - interpreter.push(value); interpreter.push(key); interpreter.push(addr); interpreter.generation_state.registers.program_counter = insert_accessed_storage_keys; interpreter.run()?; assert_eq!(interpreter.pop().unwrap(), U256::one()); - assert_eq!(interpreter.pop().unwrap(), value); + interpreter.pop().expect("Stack shouldn't be empty"); // Pop the value_ptr. } for i in 0..10 { // Test for storage key already in list. - let (addr, key, value) = storage_keys[i]; + let (addr, key) = storage_keys[i]; interpreter.push(retaddr); - interpreter.push(value); interpreter.push(key); interpreter.push(U256::from(addr.0.as_slice())); interpreter.generation_state.registers.program_counter = insert_accessed_storage_keys; interpreter.run()?; assert_eq!(interpreter.pop().unwrap(), U256::zero()); - assert_eq!(interpreter.pop().unwrap(), value); + interpreter.pop().expect("Stack shouldn't be empty"); // Pop the value_ptr. assert_eq!( interpreter.generation_state.memory.get_with_init( MemoryAddress::new_bundle(U256::from(AccessedStorageKeysLen as usize)).unwrap(), @@ -255,16 +252,12 @@ fn test_insert_accessed_storage_keys() -> Result<()> { // Test for storage key not in list. interpreter.push(retaddr); - interpreter.push(storage_key_not_in_list.2); interpreter.push(storage_key_not_in_list.1); interpreter.push(U256::from(storage_key_not_in_list.0 .0.as_slice())); interpreter.generation_state.registers.program_counter = insert_accessed_storage_keys; interpreter.run()?; - assert_eq!( - interpreter.stack(), - &[storage_key_not_in_list.2, U256::one()] - ); + assert_eq!(interpreter.stack()[1], U256::one()); assert_eq!( interpreter.generation_state.memory.get_with_init( MemoryAddress::new_bundle(U256::from(AccessedStorageKeysLen as usize)).unwrap(), @@ -285,13 +278,6 @@ fn test_insert_accessed_storage_keys() -> Result<()> { .get_with_init(MemoryAddress::new(0, AccessedStorageKeys, 4 * (n + 1) + 1),), storage_key_not_in_list.1 ); - assert_eq!( - interpreter - .generation_state - .memory - .get_with_init(MemoryAddress::new(0, AccessedStorageKeys, 4 * (n + 1) + 2),), - storage_key_not_in_list.2 - ); Ok(()) } diff --git a/evm_arithmetization/src/cpu/kernel/tests/mpt/delete.rs b/evm_arithmetization/src/cpu/kernel/tests/mpt/delete.rs index 3f9153cda..ef8830ae7 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/mpt/delete.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/mpt/delete.rs @@ -1,6 +1,6 @@ use anyhow::Result; use ethereum_types::{BigEndianHash, H256, U512}; -use mpt_trie::nibbles::Nibbles; +use mpt_trie::nibbles::{Nibbles, NibblesIntern}; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::random; @@ -70,7 +70,7 @@ fn test_after_mpt_delete_extension_branch() -> Result<()> { } .into(); let key = nibbles.merge_nibbles(&Nibbles { - packed: U512::zero(), + packed: NibblesIntern::zero(), count: 64 - nibbles.count, }); test_state_trie(state_trie, key, test_account_2()) @@ -130,7 +130,7 @@ fn test_state_trie( .push(value_ptr.into()) .expect("The stack should not overflow"); // value_ptr interpreter - .push(k.try_into_u256().unwrap()) + .push(k.try_into().unwrap()) .expect("The stack should not overflow"); // key interpreter.run()?; assert_eq!( @@ -147,7 +147,7 @@ fn test_state_trie( .push(0xDEADBEEFu32.into()) .expect("The stack should not overflow"); interpreter - .push(k.try_into_u256().unwrap()) + .push(k.try_into().unwrap()) .expect("The stack should not overflow"); interpreter .push(64.into()) diff --git a/evm_arithmetization/src/cpu/kernel/tests/mpt/insert.rs b/evm_arithmetization/src/cpu/kernel/tests/mpt/insert.rs index fcb2b5323..771921173 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/mpt/insert.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/mpt/insert.rs @@ -205,7 +205,7 @@ fn test_state_trie( .push(value_ptr.into()) .expect("The stack should not overflow"); // value_ptr interpreter - .push(k.try_into_u256().unwrap()) + .push(k.try_into().unwrap()) .expect("The stack should not overflow"); // key interpreter.run()?; diff --git a/evm_arithmetization/src/cpu/kernel/tests/receipt.rs b/evm_arithmetization/src/cpu/kernel/tests/receipt.rs index 3e34f640e..de6e7f1d4 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/receipt.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/receipt.rs @@ -11,7 +11,7 @@ use crate::cpu::kernel::constants::txn_fields::NormalizedTxnField; use crate::cpu::kernel::interpreter::Interpreter; use crate::cpu::kernel::tests::account_code::initialize_mpts; use crate::generation::mpt::{LegacyReceiptRlp, LogRlp}; -use crate::memory::segments::Segment; +use crate::memory::segments::{Segment, SEGMENT_SCALING_FACTOR}; #[test] fn test_process_receipt() -> Result<()> { @@ -129,7 +129,9 @@ fn test_receipt_encoding() -> Result<()> { // Get the expected RLP encoding. let expected_rlp = rlp::encode(&rlp::encode(&receipt_1)); - let initial_stack: Vec = vec![retdest, 0.into(), 0.into(), 0.into()]; + // Address at which the encoding is written. + let rlp_addr = U256::from(Segment::RlpRaw as usize); + let initial_stack: Vec = vec![retdest, 0.into(), 0.into(), rlp_addr]; let mut interpreter: Interpreter = Interpreter::new(encode_receipt, initial_stack); // Write data to memory. @@ -198,9 +200,9 @@ fn test_receipt_encoding() -> Result<()> { interpreter.run()?; let rlp_pos = interpreter.pop().expect("The stack should not be empty"); - let rlp_read: &[u8] = &interpreter.get_rlp_memory()[1..]; // skip empty_node + let rlp_read: &[u8] = &interpreter.get_rlp_memory(); - assert_eq!(rlp_pos.as_usize(), expected_rlp.len()); + assert_eq!((rlp_pos - rlp_addr).as_usize(), expected_rlp.len()); for i in 0..rlp_read.len() { assert_eq!(rlp_read[i], expected_rlp[i]); } diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index a60b9e7e3..be65eb413 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -399,7 +399,10 @@ where *table = MaybeUninit::new(value); } unsafe { - mem::transmute::<_, [RecursiveCircuitsForTable; NUM_TABLES]>(by_table) + mem::transmute::< + [std::mem::MaybeUninit>; NUM_TABLES], + [RecursiveCircuitsForTable; NUM_TABLES], + >(by_table) } } }; diff --git a/evm_arithmetization/src/generation/mpt.rs b/evm_arithmetization/src/generation/mpt.rs index 79e923068..febf2a2c1 100644 --- a/evm_arithmetization/src/generation/mpt.rs +++ b/evm_arithmetization/src/generation/mpt.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use bytes::Bytes; use ethereum_types::{Address, BigEndianHash, H256, U256, U512}; use keccak_hash::keccak; -use mpt_trie::nibbles::Nibbles; +use mpt_trie::nibbles::{Nibbles, NibblesIntern}; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use rlp::{Decodable, DecoderError, Encodable, PayloadInfo, Rlp, RlpStream}; use rlp_derive::{RlpDecodable, RlpEncodable}; @@ -120,7 +120,7 @@ fn parse_storage_value(value_rlp: &[u8]) -> Result, ProgramError> { const fn empty_nibbles() -> Nibbles { Nibbles { count: 0, - packed: U512::zero(), + packed: NibblesIntern::zero(), } } @@ -171,7 +171,7 @@ where trie_data.push(nibbles.count.into()); trie_data.push( nibbles - .try_into_u256() + .try_into() .map_err(|_| ProgramError::IntegerTooLarge)?, ); trie_data.push((trie_data.len() + 1).into()); @@ -187,7 +187,7 @@ where trie_data.push(nibbles.count.into()); trie_data.push( nibbles - .try_into_u256() + .try_into() .map_err(|_| ProgramError::IntegerTooLarge)?, ); @@ -250,7 +250,7 @@ fn load_state_trie( trie_data.push(nibbles.count.into()); trie_data.push( nibbles - .try_into_u256() + .try_into() .map_err(|_| ProgramError::IntegerTooLarge)?, ); // Set `value_ptr_ptr`. @@ -286,7 +286,7 @@ fn load_state_trie( trie_data.push(nibbles.count.into()); trie_data.push( nibbles - .try_into_u256() + .try_into() .map_err(|_| ProgramError::IntegerTooLarge)?, ); // Set `value_ptr_ptr`. diff --git a/evm_arithmetization/src/generation/prover_input.rs b/evm_arithmetization/src/generation/prover_input.rs index ebffadc8a..8e65e8db6 100644 --- a/evm_arithmetization/src/generation/prover_input.rs +++ b/evm_arithmetization/src/generation/prover_input.rs @@ -560,7 +560,7 @@ struct CodeIterator<'a> { } impl<'a> CodeIterator<'a> { - fn new(code: &'a [u8]) -> Self { + const fn new(code: &'a [u8]) -> Self { CodeIterator { end: code.len(), code, @@ -609,7 +609,7 @@ pub(crate) struct AccList<'a> { } impl<'a> AccList<'a> { - fn from_mem_and_segment( + const fn from_mem_and_segment( access_list_mem: &'a [Option], segment: Segment, ) -> Result { diff --git a/evm_arithmetization/src/generation/state.rs b/evm_arithmetization/src/generation/state.rs index e919eba80..5b3f5074b 100644 --- a/evm_arithmetization/src/generation/state.rs +++ b/evm_arithmetization/src/generation/state.rs @@ -138,12 +138,6 @@ pub(crate) trait State { /// Return the offsets at which execution must halt fn get_halt_offsets(&self) -> Vec; - /// Inserts a preinitialized segment, given as a [Segment], - /// into the `preinitialized_segments` memory field. - fn insert_preinitialized_segment(&mut self, segment: Segment, values: MemorySegmentState); - - fn is_preinitialized_segment(&self, segment: usize) -> bool; - /// Simulates the CPU. It only generates the traces if the `State` is a /// `GenerationState`. fn run_cpu(&mut self) -> anyhow::Result<()> @@ -428,16 +422,6 @@ impl State for GenerationState { } } - fn insert_preinitialized_segment(&mut self, segment: Segment, values: MemorySegmentState) { - panic!( - "A `GenerationState` cannot have a nonempty `preinitialized_segment` field in memory." - ) - } - - fn is_preinitialized_segment(&self, segment: usize) -> bool { - false - } - fn incr_gas(&mut self, n: u64) { self.registers.gas_used += n; } diff --git a/evm_arithmetization/src/generation/trie_extractor.rs b/evm_arithmetization/src/generation/trie_extractor.rs index dfea16234..0d825643f 100644 --- a/evm_arithmetization/src/generation/trie_extractor.rs +++ b/evm_arithmetization/src/generation/trie_extractor.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use ethereum_types::{BigEndianHash, H256, U256, U512}; -use mpt_trie::nibbles::Nibbles; +use mpt_trie::nibbles::{Nibbles, NibblesIntern}; use mpt_trie::partial_trie::{HashedPartialTrie, Node, PartialTrie, WrappedNode}; use super::mpt::{AccountRlp, LegacyReceiptRlp, LogRlp}; @@ -47,7 +47,7 @@ pub(crate) fn read_trie( let mut res = HashMap::new(); let empty_nibbles = Nibbles { count: 0, - packed: U512::zero(), + packed: NibblesIntern::zero(), }; read_trie_helper::(memory, ptr, read_value, empty_nibbles, &mut res)?; Ok(res) @@ -259,7 +259,7 @@ pub(crate) fn get_trie( ) -> Result { let empty_nibbles = Nibbles { count: 0, - packed: U512::zero(), + packed: NibblesIntern::zero(), }; Ok(N::new(get_trie_helper( memory, diff --git a/evm_arithmetization/src/keccak/keccak_stark.rs b/evm_arithmetization/src/keccak/keccak_stark.rs index e1a0484d6..5f505cf06 100644 --- a/evm_arithmetization/src/keccak/keccak_stark.rs +++ b/evm_arithmetization/src/keccak/keccak_stark.rs @@ -734,7 +734,7 @@ mod tests { gamma: F::ZERO, }, vec![], - vec![Some(Filter::new_simple(Column::constant(F::ZERO)))], + vec![Filter::new_simple(Column::constant(F::ZERO))], ); let ctl_data = CtlData { zs_columns: vec![ctl_z_data.clone(); config.num_challenges], diff --git a/evm_arithmetization/src/keccak_sponge/columns.rs b/evm_arithmetization/src/keccak_sponge/columns.rs index 6f602ab02..44c707bf2 100644 --- a/evm_arithmetization/src/keccak_sponge/columns.rs +++ b/evm_arithmetization/src/keccak_sponge/columns.rs @@ -47,12 +47,14 @@ pub(crate) struct KeccakSpongeColumnsView { /// block. pub already_absorbed_bytes: T, - /// If this row represents a final block row, the `i`th entry should be 1 if - /// the final chunk of input has length `i` (in other words if `len - - /// already_absorbed == i`), otherwise 0. + /// Indicates whether the byte at position `i` is a padding byte. + /// + /// For a final block, the `i`th entry should be 1 for all bytes that have + /// been padded, including the first `1` byte, all subsequent `0` bytes + /// and the last byte as per the 10*1 padding scheme. /// /// If this row represents a full input block, this should contain all 0s. - pub is_final_input_len: [T; KECCAK_RATE_BYTES], + pub is_padding_byte: [T; KECCAK_RATE_BYTES], /// The initial rate part of the sponge, at the start of this step. pub original_rate_u32s: [T; KECCAK_RATE_U32S], diff --git a/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs b/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs index 667d37ef8..d0f830fcf 100644 --- a/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs +++ b/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs @@ -45,14 +45,12 @@ pub(crate) fn ctl_looked_data() -> Vec> { outputs.push(cur_col); } - // The length of the inputs is `already_absorbed_bytes + is_final_input_len`. - let len_col = Column::linear_combination( - iter::once((cols.already_absorbed_bytes, F::ONE)).chain( - cols.is_final_input_len - .iter() - .enumerate() - .map(|(i, &elt)| (elt, F::from_canonical_usize(i))), - ), + // The length of the inputs is + // `already_absorbed_bytes + (RATE - Σi is_padding_byte[i])`. + let len_col = Column::linear_combination_with_constant( + iter::once((cols.already_absorbed_bytes, F::ONE)) + .chain((0..KECCAK_RATE_BYTES).map(|i| (cols.is_padding_byte[i], -F::ONE))), + F::from_canonical_usize(KECCAK_RATE_BYTES), ); let mut res: Vec> = @@ -191,7 +189,9 @@ pub(crate) fn ctl_looking_logic(i: usize) -> Vec> { pub(crate) fn ctl_looked_filter() -> Filter { // The CPU table is only interested in our final-block rows, since those contain // the final sponge output. - Filter::new_simple(Column::sum(KECCAK_SPONGE_COL_MAP.is_final_input_len)) + Filter::new_simple(Column::single( + KECCAK_SPONGE_COL_MAP.is_padding_byte[KECCAK_RATE_BYTES - 1], + )) } /// CTL filter for reading the `i`th byte of input from memory. @@ -203,26 +203,30 @@ pub(crate) fn ctl_looking_memory_filter(i: usize) -> Filter { if i == KECCAK_RATE_BYTES - 1 { Filter::new_simple(Column::single(cols.is_full_input_block)) } else { - Filter::new_simple(Column::sum( - once(&cols.is_full_input_block).chain(&cols.is_final_input_len[i + 1..]), - )) + Filter::new_simple(Column::linear_combination([ + (cols.is_full_input_block, F::ONE), + (cols.is_padding_byte[KECCAK_RATE_BYTES - 1], F::ONE), + (cols.is_padding_byte[i], -F::ONE), + ])) } } /// CTL filter for looking at XORs in the logic table. pub(crate) fn ctl_looking_logic_filter() -> Filter { let cols = KECCAK_SPONGE_COL_MAP; - Filter::new_simple(Column::sum( - once(&cols.is_full_input_block).chain(&cols.is_final_input_len), - )) + Filter::new_simple(Column::sum([ + cols.is_full_input_block, + cols.is_padding_byte[KECCAK_RATE_BYTES - 1], + ])) } /// CTL filter for looking at the input and output in the Keccak table. pub(crate) fn ctl_looking_keccak_filter() -> Filter { let cols = KECCAK_SPONGE_COL_MAP; - Filter::new_simple(Column::sum( - once(&cols.is_full_input_block).chain(&cols.is_final_input_len), - )) + Filter::new_simple(Column::sum([ + cols.is_full_input_block, + cols.is_padding_byte[KECCAK_RATE_BYTES - 1], + ])) } /// Information about a Keccak sponge operation needed for witness generation. @@ -373,8 +377,8 @@ impl, const D: usize> KeccakSpongeStark { /// Generates a row containing the last input bytes. /// On top of computing one absorption and padding the input, - /// we indicate the last non-padding input byte by setting - /// `row.is_final_input_len[final_inputs.len()]` to 1. + /// we indicate all the padding input bytes by setting the + /// corresponding indices in `row.is_padding_byte` to 1. fn generate_final_row( &self, op: &KeccakSpongeOp, @@ -399,7 +403,9 @@ impl, const D: usize> KeccakSpongeStark { row.block_bytes[KECCAK_RATE_BYTES - 1] = F::from_canonical_u8(0b10000000); } - row.is_final_input_len[final_inputs.len()] = F::ONE; + for i in final_inputs.len()..KECCAK_RATE_BYTES { + row.is_padding_byte[i] = F::ONE; + } Self::generate_common_fields(&mut row, op, already_absorbed_bytes, sponge_state); row @@ -561,16 +567,21 @@ impl, const D: usize> Stark for KeccakSpongeS let range_max = P::Scalar::from_canonical_u64((BYTE_RANGE_MAX - 1) as u64); yield_constr.constraint_last_row(rc1 - range_max); - // Each flag (full-input block, final block or implied dummy flag) must be + // Each flag (full-input block, padding byte or implied dummy flag) must be // boolean. let is_full_input_block = local_values.is_full_input_block; yield_constr.constraint(is_full_input_block * (is_full_input_block - P::ONES)); - let is_final_block: P = local_values.is_final_input_len.iter().copied().sum(); - yield_constr.constraint(is_final_block * (is_final_block - P::ONES)); + for &is_padding_byte in local_values.is_padding_byte.iter() { + yield_constr.constraint(is_padding_byte * (is_padding_byte - P::ONES)); + } + let is_final_block: P = local_values.is_padding_byte[KECCAK_RATE_BYTES - 1]; - for &is_final_len in local_values.is_final_input_len.iter() { - yield_constr.constraint(is_final_len * (is_final_len - P::ONES)); + // A padding byte is always followed by another padding byte. + for i in 1..KECCAK_RATE_BYTES { + yield_constr.constraint( + local_values.is_padding_byte[i - 1] * (local_values.is_padding_byte[i] - P::ONES), + ); } // Ensure that full-input block and final block flags are not set to 1 at the @@ -651,10 +662,51 @@ impl, const D: usize> Stark for KeccakSpongeS - next_values.already_absorbed_bytes), ); + // If the first padding byte is at the end of the block, then the block has a + // single padding byte. + let has_single_padding_byte = local_values.is_padding_byte[KECCAK_RATE_BYTES - 1] + - local_values.is_padding_byte[KECCAK_RATE_BYTES - 2]; + + // If the row has a single padding byte, then it must be the last byte with + // value 0b10000001. + yield_constr.constraint_transition( + has_single_padding_byte + * (local_values.block_bytes[KECCAK_RATE_BYTES - 1] + - P::from(FE::from_canonical_u8(0b10000001))), + ); + + for i in 0..KECCAK_RATE_BYTES - 1 { + let is_first_padding_byte = { + if i > 0 { + local_values.is_padding_byte[i] - local_values.is_padding_byte[i - 1] + } else { + local_values.is_padding_byte[i] + } + }; + // If the row has multiple padding bytes, the first padding byte must be 1. + yield_constr.constraint_transition( + is_first_padding_byte * (local_values.block_bytes[i] - P::ONES), + ); + // If the row has multiple padding bytes, the other padding bytes + // except the last one must be 0. + yield_constr.constraint_transition( + local_values.is_padding_byte[i] + * (is_first_padding_byte - P::ONES) + * local_values.block_bytes[i], + ); + } + // If the row has multiple padding bytes, then the last byte must be 0b10000000. + yield_constr.constraint_transition( + is_final_block + * (has_single_padding_byte - P::ONES) + * (local_values.block_bytes[KECCAK_RATE_BYTES - 1] + - P::from(FE::from_canonical_u8(0b10000000))), + ); + // A dummy row is always followed by another dummy row, so the prover can't put // dummy rows "in between" to avoid the above checks. let is_dummy = P::ONES - is_full_input_block - is_final_block; - let next_is_final_block: P = next_values.is_final_input_len.iter().copied().sum(); + let next_is_final_block: P = next_values.is_padding_byte[KECCAK_RATE_BYTES - 1]; yield_constr.constraint_transition( is_dummy * (next_values.is_full_input_block + next_is_final_block), ); @@ -689,8 +741,8 @@ impl, const D: usize> Stark for KeccakSpongeS let t = builder.sub_extension(rc1, range_max); yield_constr.constraint_last_row(builder, t); - // Each flag (full-input block, final block or implied dummy flag) must be - // boolean. + // Each flag (full-input block, final block, padding byte or implied dummy flag) + // must be boolean. let is_full_input_block = local_values.is_full_input_block; let constraint = builder.mul_sub_extension( is_full_input_block, @@ -699,12 +751,20 @@ impl, const D: usize> Stark for KeccakSpongeS ); yield_constr.constraint(builder, constraint); - let is_final_block = builder.add_many_extension(local_values.is_final_input_len); - let constraint = builder.mul_sub_extension(is_final_block, is_final_block, is_final_block); - yield_constr.constraint(builder, constraint); - - for &is_final_len in local_values.is_final_input_len.iter() { - let constraint = builder.mul_sub_extension(is_final_len, is_final_len, is_final_len); + for &is_padding_byte in local_values.is_padding_byte.iter() { + let constraint = + builder.mul_sub_extension(is_padding_byte, is_padding_byte, is_padding_byte); + yield_constr.constraint(builder, constraint); + } + let is_final_block = local_values.is_padding_byte[KECCAK_RATE_BYTES - 1]; + + // A padding byte is always followed by another padding byte. + for i in 1..KECCAK_RATE_BYTES { + let constraint = builder.mul_sub_extension( + local_values.is_padding_byte[i - 1], + local_values.is_padding_byte[i], + local_values.is_padding_byte[i - 1], + ); yield_constr.constraint(builder, constraint); } @@ -805,13 +865,71 @@ impl, const D: usize> Stark for KeccakSpongeS let constraint = builder.mul_extension(is_full_input_block, absorbed_diff); yield_constr.constraint_transition(builder, constraint); + // If the first padding byte is at the end of the block, then the block has a + // single padding byte. + let has_single_padding_byte = builder.sub_extension( + local_values.is_padding_byte[KECCAK_RATE_BYTES - 1], + local_values.is_padding_byte[KECCAK_RATE_BYTES - 2], + ); + + // If the row has a single padding byte, then it must be the last byte with + // value 0b10000001. + let padding_byte = builder.constant_extension(F::Extension::from_canonical_u8(0b10000001)); + let diff = builder.sub_extension( + local_values.block_bytes[KECCAK_RATE_BYTES - 1], + padding_byte, + ); + let constraint = builder.mul_extension(has_single_padding_byte, diff); + yield_constr.constraint_transition(builder, constraint); + + for i in 0..KECCAK_RATE_BYTES - 1 { + let is_first_padding_byte = { + if i > 0 { + builder.sub_extension( + local_values.is_padding_byte[i], + local_values.is_padding_byte[i - 1], + ) + } else { + local_values.is_padding_byte[i] + } + }; + // If the row has multiple padding bytes, the first padding byte must be 1. + let constraint = builder.mul_sub_extension( + is_first_padding_byte, + local_values.block_bytes[i], + is_first_padding_byte, + ); + yield_constr.constraint_transition(builder, constraint); + + // If the row has multiple padding bytes, the other padding bytes + // except the last one must be 0. + let sel = builder.mul_sub_extension( + local_values.is_padding_byte[i], + is_first_padding_byte, + local_values.is_padding_byte[i], + ); + let constraint = builder.mul_extension(sel, local_values.block_bytes[i]); + yield_constr.constraint_transition(builder, constraint); + } + + // If the row has multiple padding bytes, then the last byte must be 0b10000000. + let sel = + builder.mul_sub_extension(is_final_block, has_single_padding_byte, is_final_block); + let padding_byte = builder.constant_extension(F::Extension::from_canonical_u8(0b10000000)); + let diff = builder.sub_extension( + local_values.block_bytes[KECCAK_RATE_BYTES - 1], + padding_byte, + ); + let constraint = builder.mul_extension(sel, diff); + yield_constr.constraint_transition(builder, constraint); + // A dummy row is always followed by another dummy row, so the prover can't put // dummy rows "in between" to avoid the above checks. let is_dummy = { let tmp = builder.sub_extension(one, is_final_block); builder.sub_extension(tmp, is_full_input_block) }; - let next_is_final_block = builder.add_many_extension(next_values.is_final_input_len); + let next_is_final_block = next_values.is_padding_byte[KECCAK_RATE_BYTES - 1]; let constraint = { let tmp = builder.add_extension(next_is_final_block, next_values.is_full_input_block); builder.mul_extension(is_dummy, tmp) @@ -828,7 +946,7 @@ impl, const D: usize> Stark for KeccakSpongeS columns: Column::singles(get_block_bytes_range()).collect(), table_column: Column::single(RANGE_COUNTER), frequencies_column: Column::single(RC_FREQUENCIES), - filter_columns: vec![None; KECCAK_RATE_BYTES], + filter_columns: vec![Default::default(); KECCAK_RATE_BYTES], }] } diff --git a/evm_arithmetization/src/lib.rs b/evm_arithmetization/src/lib.rs index b3cdc0e37..bd4f20147 100644 --- a/evm_arithmetization/src/lib.rs +++ b/evm_arithmetization/src/lib.rs @@ -223,6 +223,8 @@ static GLOBAL: Jemalloc = Jemalloc; // Public definitions and re-exports pub type Node = mpt_trie::partial_trie::Node; +/// A type alias for `u64` of a block height. +pub type BlockHeight = u64; pub use all_stark::AllStark; pub use fixed_recursive_verifier::AllRecursiveCircuits; diff --git a/evm_arithmetization/src/memory/memory_stark.rs b/evm_arithmetization/src/memory/memory_stark.rs index 66f1ca42c..f788024fd 100644 --- a/evm_arithmetization/src/memory/memory_stark.rs +++ b/evm_arithmetization/src/memory/memory_stark.rs @@ -581,11 +581,8 @@ impl, const D: usize> Stark for MemoryStark, const D } } +pub(crate) fn debug_public_values(public_values: &PublicValues) { + log::debug!("Public Values:"); + log::debug!( + " Trie Roots Before: {:?}", + &public_values.trie_roots_before + ); + log::debug!(" Trie Roots After: {:?}", &public_values.trie_roots_after); + log::debug!(" Block Metadata: {:?}", &public_values.block_metadata); + log::debug!(" Block Hashes: {:?}", &public_values.block_hashes); + log::debug!(" Extra Block Data: {:?}", &public_values.extra_block_data); +} + pub fn set_public_value_targets( witness: &mut W, public_values_target: &PublicValuesTarget, @@ -644,6 +656,8 @@ where F: RichField + Extendable, W: Witness, { + debug_public_values(public_values); + set_trie_roots_target( witness, &public_values_target.trie_roots_before, diff --git a/evm_arithmetization/tests/add11_yml.rs b/evm_arithmetization/tests/add11_yml.rs index 772bd4774..00d7e56b4 100644 --- a/evm_arithmetization/tests/add11_yml.rs +++ b/evm_arithmetization/tests/add11_yml.rs @@ -63,9 +63,9 @@ fn add11_yml() -> anyhow::Result<()> { 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()); + )?; + 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, @@ -119,10 +119,10 @@ fn add11_yml() -> anyhow::Result<()> { expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), - ); + )?; expected_state_trie_after - .insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); - expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec()); + .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 }; @@ -136,7 +136,7 @@ fn add11_yml() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - ); + )?; let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), diff --git a/evm_arithmetization/tests/basic_smart_contract.rs b/evm_arithmetization/tests/basic_smart_contract.rs index 6f9bfc8d2..fd0948d80 100644 --- a/evm_arithmetization/tests/basic_smart_contract.rs +++ b/evm_arithmetization/tests/basic_smart_contract.rs @@ -168,7 +168,7 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - ); + )?; let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), diff --git a/evm_arithmetization/tests/erc20.rs b/evm_arithmetization/tests/erc20.rs index ef4b22878..609579af9 100644 --- a/evm_arithmetization/tests/erc20.rs +++ b/evm_arithmetization/tests/erc20.rs @@ -62,13 +62,13 @@ fn test_erc20() -> anyhow::Result<()> { let token_nibbles = Nibbles::from_bytes_be(token_state_key.as_bytes()).unwrap(); let mut state_trie_before = HashedPartialTrie::from(Node::Empty); - 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()); + 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![ - (giver_state_key, giver_storage()), - (token_state_key, token_storage()), + (giver_state_key, giver_storage()?), + (token_state_key, token_storage()?), ]; let tries_before = TrieInputs { @@ -107,13 +107,13 @@ fn test_erc20() -> anyhow::Result<()> { balance: sender_account.balance - gas_used * 0xa, ..sender_account }; - state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); - state_trie_after.insert(giver_nibbles, rlp::encode(&giver_account()).to_vec()); + state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec())?; + state_trie_after.insert(giver_nibbles, rlp::encode(&giver_account()?).to_vec())?; let token_account_after = AccountRlp { - storage_root: token_storage_after().hash(), - ..token_account() + storage_root: token_storage_after()?.hash(), + ..token_account()? }; - state_trie_after.insert(token_nibbles, rlp::encode(&token_account_after).to_vec()); + state_trie_after.insert(token_nibbles, rlp::encode(&token_account_after).to_vec())?; state_trie_after }; @@ -144,7 +144,7 @@ fn test_erc20() -> anyhow::Result<()> { }], }; let mut receipts_trie = HashedPartialTrie::from(Node::Empty); - receipts_trie.insert(Nibbles::from_str("0x80").unwrap(), receipt_0.encode(2)); + receipts_trie.insert(Nibbles::from_str("0x80").unwrap(), receipt_0.encode(2))?; let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), @@ -192,71 +192,72 @@ fn token_bytecode() -> Vec { hex!("608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce567146100fe57806370a082311461010d57806395d89b4114610136578063a9059cbb1461013e578063dd62ed3e1461015157600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100eb575b600080fd5b6100a061018a565b6040516100ad919061056a565b60405180910390f35b6100c96100c43660046105d4565b61021c565b60405190151581526020016100ad565b6002545b6040519081526020016100ad565b6100c96100f93660046105fe565b610236565b604051601281526020016100ad565b6100dd61011b36600461063a565b6001600160a01b031660009081526020819052604090205490565b6100a061025a565b6100c961014c3660046105d4565b610269565b6100dd61015f36600461065c565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6060600380546101999061068f565b80601f01602080910402602001604051908101604052809291908181526020018280546101c59061068f565b80156102125780601f106101e757610100808354040283529160200191610212565b820191906000526020600020905b8154815290600101906020018083116101f557829003601f168201915b5050505050905090565b60003361022a818585610277565b60019150505b92915050565b600033610244858285610289565b61024f85858561030c565b506001949350505050565b6060600480546101999061068f565b60003361022a81858561030c565b610284838383600161036b565b505050565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461030657818110156102f757604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064015b60405180910390fd5b6103068484848403600061036b565b50505050565b6001600160a01b03831661033657604051634b637e8f60e11b8152600060048201526024016102ee565b6001600160a01b0382166103605760405163ec442f0560e01b8152600060048201526024016102ee565b610284838383610440565b6001600160a01b0384166103955760405163e602df0560e01b8152600060048201526024016102ee565b6001600160a01b0383166103bf57604051634a1406b160e11b8152600060048201526024016102ee565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561030657826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161043291815260200190565b60405180910390a350505050565b6001600160a01b03831661046b57806002600082825461046091906106c9565b909155506104dd9050565b6001600160a01b038316600090815260208190526040902054818110156104be5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016102ee565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b0382166104f957600280548290039055610518565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161055d91815260200190565b60405180910390a3505050565b600060208083528351808285015260005b818110156105975785810183015185820160400152820161057b565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146105cf57600080fd5b919050565b600080604083850312156105e757600080fd5b6105f0836105b8565b946020939093013593505050565b60008060006060848603121561061357600080fd5b61061c846105b8565b925061062a602085016105b8565b9150604084013590509250925092565b60006020828403121561064c57600080fd5b610655826105b8565b9392505050565b6000806040838503121561066f57600080fd5b610678836105b8565b9150610686602084016105b8565b90509250929050565b600181811c908216806106a357607f821691505b6020821081036106c357634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561023057634e487b7160e01b600052601160045260246000fdfea2646970667358221220266a323ae4a816f6c6342a5be431fedcc0d45c44b02ea75f5474eb450b5d45b364736f6c63430008140033").into() } -fn insert_storage(trie: &mut HashedPartialTrie, slot: U256, value: U256) { +fn insert_storage(trie: &mut HashedPartialTrie, slot: U256, value: U256) -> anyhow::Result<()> { 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); + trie.insert(nibbles, r)?; + Ok(()) } fn sd2u(s: &str) -> U256 { U256::from_dec_str(s).unwrap() } -fn giver_storage() -> HashedPartialTrie { +fn giver_storage() -> anyhow::Result { let mut trie = HashedPartialTrie::from(Node::Empty); insert_storage( &mut trie, U256::zero(), sd2u("546584486846459126461364135121053344201067465379"), - ); - trie + )?; + Ok(trie) } -fn token_storage() -> HashedPartialTrie { +fn token_storage() -> anyhow::Result { let mut trie = HashedPartialTrie::from(Node::Empty); insert_storage( &mut trie, sd2u("82183438603287090451672504949863617512989139203883434767553028632841710582583"), sd2u("1000000000000000000000"), - ); - trie + )?; + Ok(trie) } -fn token_storage_after() -> HashedPartialTrie { +fn token_storage_after() -> anyhow::Result { let mut trie = HashedPartialTrie::from(Node::Empty); insert_storage( &mut trie, sd2u("82183438603287090451672504949863617512989139203883434767553028632841710582583"), sd2u("900000000000000000000"), - ); + )?; insert_storage( &mut trie, sd2u("53006154680716014998529145169423020330606407246856709517064848190396281160729"), sd2u("100000000000000000000"), - ); - trie + )?; + Ok(trie) } -fn giver_account() -> AccountRlp { - AccountRlp { +fn giver_account() -> anyhow::Result { + Ok(AccountRlp { nonce: 1.into(), balance: 0.into(), - storage_root: giver_storage().hash(), + storage_root: giver_storage()?.hash(), code_hash: keccak(giver_bytecode()), - } + }) } -fn token_account() -> AccountRlp { - AccountRlp { +fn token_account() -> anyhow::Result { + Ok(AccountRlp { nonce: 1.into(), balance: 0.into(), - storage_root: token_storage().hash(), + storage_root: token_storage()?.hash(), code_hash: keccak(token_bytecode()), - } + }) } fn sender_account() -> AccountRlp { diff --git a/evm_arithmetization/tests/erc721.rs b/evm_arithmetization/tests/erc721.rs index 207fa69db..86dd34002 100644 --- a/evm_arithmetization/tests/erc721.rs +++ b/evm_arithmetization/tests/erc721.rs @@ -62,10 +62,10 @@ fn test_erc721() -> anyhow::Result<()> { let contract_nibbles = Nibbles::from_bytes_be(contract_state_key.as_bytes()).unwrap(); let mut state_trie_before = HashedPartialTrie::from(Node::Empty); - state_trie_before.insert(owner_nibbles, rlp::encode(&owner_account()).to_vec()); - state_trie_before.insert(contract_nibbles, rlp::encode(&contract_account()).to_vec()); + 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())]; + let storage_tries = vec![(contract_state_key, contract_storage()?)]; let tries_before = TrieInputs { state_trie: state_trie_before, @@ -90,15 +90,15 @@ fn test_erc721() -> anyhow::Result<()> { balance: owner_account.balance - gas_used * 0xa, ..owner_account }; - state_trie_after.insert(owner_nibbles, rlp::encode(&owner_account_after).to_vec()); + state_trie_after.insert(owner_nibbles, rlp::encode(&owner_account_after).to_vec())?; let contract_account_after = AccountRlp { - storage_root: contract_storage_after().hash(), - ..contract_account() + storage_root: contract_storage_after()?.hash(), + ..contract_account()? }; state_trie_after.insert( contract_nibbles, rlp::encode(&contract_account_after).to_vec(), - ); + )?; state_trie_after }; @@ -128,7 +128,7 @@ fn test_erc721() -> anyhow::Result<()> { logs, }; let mut receipts_trie = HashedPartialTrie::from(Node::Empty); - receipts_trie.insert(Nibbles::from_str("0x80").unwrap(), receipt_0.encode(0)); + receipts_trie.insert(Nibbles::from_str("0x80").unwrap(), receipt_0.encode(0))?; let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), @@ -191,14 +191,16 @@ fn contract_bytecode() -> Vec { hex!("608060405234801561000f575f80fd5b5060043610610109575f3560e01c8063715018a6116100a0578063a22cb4651161006f578063a22cb465146102a1578063b88d4fde146102bd578063c87b56dd146102d9578063e985e9c514610309578063f2fde38b1461033957610109565b8063715018a61461023f5780638da5cb5b1461024957806395d89b4114610267578063a14481941461028557610109565b806323b872dd116100dc57806323b872dd146101a757806342842e0e146101c35780636352211e146101df57806370a082311461020f57610109565b806301ffc9a71461010d57806306fdde031461013d578063081812fc1461015b578063095ea7b31461018b575b5f80fd5b61012760048036038101906101229190611855565b610355565b604051610134919061189a565b60405180910390f35b610145610436565b604051610152919061193d565b60405180910390f35b61017560048036038101906101709190611990565b6104c5565b60405161018291906119fa565b60405180910390f35b6101a560048036038101906101a09190611a3d565b6104e0565b005b6101c160048036038101906101bc9190611a7b565b6104f6565b005b6101dd60048036038101906101d89190611a7b565b6105f5565b005b6101f960048036038101906101f49190611990565b610614565b60405161020691906119fa565b60405180910390f35b61022960048036038101906102249190611acb565b610625565b6040516102369190611b05565b60405180910390f35b6102476106db565b005b6102516106ee565b60405161025e91906119fa565b60405180910390f35b61026f610716565b60405161027c919061193d565b60405180910390f35b61029f600480360381019061029a9190611a3d565b6107a6565b005b6102bb60048036038101906102b69190611b48565b6107bc565b005b6102d760048036038101906102d29190611cb2565b6107d2565b005b6102f360048036038101906102ee9190611990565b6107ef565b604051610300919061193d565b60405180910390f35b610323600480360381019061031e9190611d32565b610855565b604051610330919061189a565b60405180910390f35b610353600480360381019061034e9190611acb565b6108e3565b005b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061041f57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061042f575061042e82610967565b5b9050919050565b60605f805461044490611d9d565b80601f016020809104026020016040519081016040528092919081815260200182805461047090611d9d565b80156104bb5780601f10610492576101008083540402835291602001916104bb565b820191905f5260205f20905b81548152906001019060200180831161049e57829003601f168201915b5050505050905090565b5f6104cf826109d0565b506104d982610a56565b9050919050565b6104f282826104ed610a8f565b610a96565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610566575f6040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161055d91906119fa565b60405180910390fd5b5f6105798383610574610a8f565b610aa8565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105ef578382826040517f64283d7b0000000000000000000000000000000000000000000000000000000081526004016105e693929190611dcd565b60405180910390fd5b50505050565b61060f83838360405180602001604052805f8152506107d2565b505050565b5f61061e826109d0565b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610696575f6040517f89c62b6400000000000000000000000000000000000000000000000000000000815260040161068d91906119fa565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6106e3610cb3565b6106ec5f610d3a565b565b5f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60606001805461072590611d9d565b80601f016020809104026020016040519081016040528092919081815260200182805461075190611d9d565b801561079c5780601f106107735761010080835404028352916020019161079c565b820191905f5260205f20905b81548152906001019060200180831161077f57829003601f168201915b5050505050905090565b6107ae610cb3565b6107b88282610dfd565b5050565b6107ce6107c7610a8f565b8383610e1a565b5050565b6107dd8484846104f6565b6107e984848484610f83565b50505050565b60606107fa826109d0565b505f610804611135565b90505f8151116108225760405180602001604052805f81525061084d565b8061082c8461114b565b60405160200161083d929190611e3c565b6040516020818303038152906040525b915050919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b6108eb610cb3565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361095b575f6040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260040161095291906119fa565b60405180910390fd5b61096481610d3a565b50565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f806109db83611215565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610a4d57826040517f7e273289000000000000000000000000000000000000000000000000000000008152600401610a449190611b05565b60405180910390fd5b80915050919050565b5f60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f33905090565b610aa3838383600161124e565b505050565b5f80610ab384611215565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610af457610af381848661140d565b5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610b7f57610b335f855f8061124e565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825403925050819055505b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614610bfe57600160035f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8460025f8681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4809150509392505050565b610cbb610a8f565b73ffffffffffffffffffffffffffffffffffffffff16610cd96106ee565b73ffffffffffffffffffffffffffffffffffffffff1614610d3857610cfc610a8f565b6040517f118cdaa7000000000000000000000000000000000000000000000000000000008152600401610d2f91906119fa565b60405180910390fd5b565b5f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160065f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b610e16828260405180602001604052805f8152506114d0565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610e8a57816040517f5b08ba18000000000000000000000000000000000000000000000000000000008152600401610e8191906119fa565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610f76919061189a565b60405180910390a3505050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b111561112f578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02610fc6610a8f565b8685856040518563ffffffff1660e01b8152600401610fe89493929190611eb1565b6020604051808303815f875af192505050801561102357506040513d601f19601f820116820180604052508101906110209190611f0f565b60015b6110a4573d805f8114611051576040519150601f19603f3d011682016040523d82523d5f602084013e611056565b606091505b505f81510361109c57836040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161109391906119fa565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461112d57836040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161112491906119fa565b60405180910390fd5b505b50505050565b606060405180602001604052805f815250905090565b60605f6001611159846114eb565b0190505f8167ffffffffffffffff81111561117757611176611b8e565b5b6040519080825280601f01601f1916602001820160405280156111a95781602001600182028036833780820191505090505b5090505f82602001820190505b60011561120a578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a85816111ff576111fe611f3a565b5b0494505f85036111b6575b819350505050919050565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b808061128657505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b156113b8575f611295846109d0565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156112ff57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561131257506113108184610855565b155b1561135457826040517fa9fbf51f00000000000000000000000000000000000000000000000000000000815260040161134b91906119fa565b60405180910390fd5b81156113b657838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b8360045f8581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b61141883838361163c565b6114cb575f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361148c57806040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016114839190611b05565b60405180910390fd5b81816040517f177e802f0000000000000000000000000000000000000000000000000000000081526004016114c2929190611f67565b60405180910390fd5b505050565b6114da83836116fc565b6114e65f848484610f83565b505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310611547577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161153d5761153c611f3a565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310611584576d04ee2d6d415b85acef8100000000838161157a57611579611f3a565b5b0492506020810190505b662386f26fc1000083106115b357662386f26fc1000083816115a9576115a8611f3a565b5b0492506010810190505b6305f5e10083106115dc576305f5e10083816115d2576115d1611f3a565b5b0492506008810190505b61271083106116015761271083816115f7576115f6611f3a565b5b0492506004810190505b60648310611624576064838161161a57611619611f3a565b5b0492506002810190505b600a8310611633576001810190505b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156116f357508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806116b457506116b38484610855565b5b806116f257508273ffffffffffffffffffffffffffffffffffffffff166116da83610a56565b73ffffffffffffffffffffffffffffffffffffffff16145b5b90509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361176c575f6040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161176391906119fa565b60405180910390fd5b5f61177883835f610aa8565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146117ea575f6040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081526004016117e191906119fa565b60405180910390fd5b505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61183481611800565b811461183e575f80fd5b50565b5f8135905061184f8161182b565b92915050565b5f6020828403121561186a576118696117f8565b5b5f61187784828501611841565b91505092915050565b5f8115159050919050565b61189481611880565b82525050565b5f6020820190506118ad5f83018461188b565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156118ea5780820151818401526020810190506118cf565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61190f826118b3565b61191981856118bd565b93506119298185602086016118cd565b611932816118f5565b840191505092915050565b5f6020820190508181035f8301526119558184611905565b905092915050565b5f819050919050565b61196f8161195d565b8114611979575f80fd5b50565b5f8135905061198a81611966565b92915050565b5f602082840312156119a5576119a46117f8565b5b5f6119b28482850161197c565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6119e4826119bb565b9050919050565b6119f4816119da565b82525050565b5f602082019050611a0d5f8301846119eb565b92915050565b611a1c816119da565b8114611a26575f80fd5b50565b5f81359050611a3781611a13565b92915050565b5f8060408385031215611a5357611a526117f8565b5b5f611a6085828601611a29565b9250506020611a718582860161197c565b9150509250929050565b5f805f60608486031215611a9257611a916117f8565b5b5f611a9f86828701611a29565b9350506020611ab086828701611a29565b9250506040611ac18682870161197c565b9150509250925092565b5f60208284031215611ae057611adf6117f8565b5b5f611aed84828501611a29565b91505092915050565b611aff8161195d565b82525050565b5f602082019050611b185f830184611af6565b92915050565b611b2781611880565b8114611b31575f80fd5b50565b5f81359050611b4281611b1e565b92915050565b5f8060408385031215611b5e57611b5d6117f8565b5b5f611b6b85828601611a29565b9250506020611b7c85828601611b34565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b611bc4826118f5565b810181811067ffffffffffffffff82111715611be357611be2611b8e565b5b80604052505050565b5f611bf56117ef565b9050611c018282611bbb565b919050565b5f67ffffffffffffffff821115611c2057611c1f611b8e565b5b611c29826118f5565b9050602081019050919050565b828183375f83830152505050565b5f611c56611c5184611c06565b611bec565b905082815260208101848484011115611c7257611c71611b8a565b5b611c7d848285611c36565b509392505050565b5f82601f830112611c9957611c98611b86565b5b8135611ca9848260208601611c44565b91505092915050565b5f805f8060808587031215611cca57611cc96117f8565b5b5f611cd787828801611a29565b9450506020611ce887828801611a29565b9350506040611cf98782880161197c565b925050606085013567ffffffffffffffff811115611d1a57611d196117fc565b5b611d2687828801611c85565b91505092959194509250565b5f8060408385031215611d4857611d476117f8565b5b5f611d5585828601611a29565b9250506020611d6685828601611a29565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611db457607f821691505b602082108103611dc757611dc6611d70565b5b50919050565b5f606082019050611de05f8301866119eb565b611ded6020830185611af6565b611dfa60408301846119eb565b949350505050565b5f81905092915050565b5f611e16826118b3565b611e208185611e02565b9350611e308185602086016118cd565b80840191505092915050565b5f611e478285611e0c565b9150611e538284611e0c565b91508190509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611e8382611e5f565b611e8d8185611e69565b9350611e9d8185602086016118cd565b611ea6816118f5565b840191505092915050565b5f608082019050611ec45f8301876119eb565b611ed160208301866119eb565b611ede6040830185611af6565b8181036060830152611ef08184611e79565b905095945050505050565b5f81519050611f098161182b565b92915050565b5f60208284031215611f2457611f236117f8565b5b5f611f3184828501611efb565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f604082019050611f7a5f8301856119eb565b611f876020830184611af6565b939250505056fea2646970667358221220432b30673e00c0eb009e1718c271f4cfdfbeded17345829703b06d322360990164736f6c63430008160033").into() } -fn insert_storage(trie: &mut HashedPartialTrie, slot: U256, value: U256) { +fn insert_storage(trie: &mut HashedPartialTrie, slot: U256, value: U256) -> anyhow::Result<()> { 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); + trie.insert(nibbles, r)?; + + Ok(()) } fn sd2u(s: &str) -> U256 { @@ -209,64 +211,64 @@ fn sh2u(s: &str) -> U256 { U256::from_str_radix(s, 16).unwrap() } -fn contract_storage() -> HashedPartialTrie { +fn contract_storage() -> anyhow::Result { 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 + )?; + Ok(trie) } -fn contract_storage_after() -> HashedPartialTrie { +fn contract_storage_after() -> anyhow::Result { 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 + )?; + Ok(trie) } fn owner_account() -> AccountRlp { @@ -278,13 +280,13 @@ fn owner_account() -> AccountRlp { } } -fn contract_account() -> AccountRlp { - AccountRlp { +fn contract_account() -> anyhow::Result { + Ok(AccountRlp { nonce: 0.into(), balance: 0.into(), - storage_root: contract_storage().hash(), + storage_root: contract_storage()?.hash(), code_hash: keccak(contract_bytecode()), - } + }) } fn signed_tx() -> Vec { diff --git a/evm_arithmetization/tests/log_opcode.rs b/evm_arithmetization/tests/log_opcode.rs index 56e5bbf6d..75cdd44f5 100644 --- a/evm_arithmetization/tests/log_opcode.rs +++ b/evm_arithmetization/tests/log_opcode.rs @@ -88,9 +88,9 @@ fn test_log_opcodes() -> anyhow::Result<()> { 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()); + )?; + 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())?; // We now add two receipts with logs and data. This updates the receipt trie as // well. @@ -119,7 +119,7 @@ fn test_log_opcodes() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x1337").unwrap(), rlp::encode(&receipt_0).to_vec(), - ); + )?; let tries_before = TrieInputs { state_trie: state_trie_before, @@ -193,16 +193,17 @@ fn test_log_opcodes() -> anyhow::Result<()> { let receipt_nibbles = Nibbles::from_str("0x80").unwrap(); // RLP(0) = 0x80 - receipts_trie.insert(receipt_nibbles, rlp::encode(&receipt).to_vec()); + receipts_trie.insert(receipt_nibbles, rlp::encode(&receipt).to_vec())?; // Update the state trie. let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty); expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), - ); - expected_state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); - expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec()); + )?; + 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())?; let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), @@ -319,13 +320,13 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { 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()); + )?; + 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())?; state_trie_before.insert( to_second_nibbles, rlp::encode(&to_account_second_before).to_vec(), - ); + )?; let checkpoint_state_trie_root = state_trie_before.hash(); let tries_before = TrieInputs { @@ -389,13 +390,14 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), - ); - expected_state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); - expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec()); + )?; + 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( to_second_nibbles, rlp::encode(&to_account_second_before).to_vec(), - ); + )?; // Compute new receipt trie. let mut receipts_trie = HashedPartialTrie::from(Node::Empty); @@ -408,7 +410,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - ); + )?; let mut transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), @@ -530,22 +532,23 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { let receipt_nibbles = Nibbles::from_str("0x01").unwrap(); // RLP(1) = 0x1 - receipts_trie.insert(receipt_nibbles, rlp::encode(&receipt).to_vec()); + receipts_trie.insert(receipt_nibbles, rlp::encode(&receipt).to_vec())?; // Update the state trie. let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty); expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), - ); - expected_state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); - expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec()); + )?; + 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( to_second_nibbles, rlp::encode(&to_account_second_after).to_vec(), - ); + )?; - transactions_trie.insert(Nibbles::from_str("0x01").unwrap(), txn_2.to_vec()); + transactions_trie.insert(Nibbles::from_str("0x01").unwrap(), txn_2.to_vec())?; let block_1_state_root = expected_state_trie_after.hash(); @@ -687,7 +690,7 @@ fn test_txn_and_receipt_trie_hash() -> anyhow::Result<()> { example_txn_trie.insert( Nibbles::from_str("0x80").unwrap(), // RLP(0) = 0x80 rlp::encode(&transaction_0).to_vec(), - ); + )?; let transaction_1 = LegacyTransactionRlp { nonce: 157824u64.into(), @@ -707,7 +710,7 @@ fn test_txn_and_receipt_trie_hash() -> anyhow::Result<()> { example_txn_trie.insert( Nibbles::from_str("0x01").unwrap(), rlp::encode(&transaction_1).to_vec(), - ); + )?; // Receipts: let mut example_receipt_trie = HashedPartialTrie::from(Node::Empty); @@ -735,7 +738,7 @@ fn test_txn_and_receipt_trie_hash() -> anyhow::Result<()> { example_receipt_trie.insert( Nibbles::from_str("0x80").unwrap(), // RLP(0) is 0x80 rlp::encode(&receipt_0).to_vec(), - ); + )?; let log_1 = LogRlp { address: hex!("7ef66b77759e12Caf3dDB3E4AFF524E577C59D8D").into(), @@ -760,7 +763,7 @@ fn test_txn_and_receipt_trie_hash() -> anyhow::Result<()> { example_receipt_trie.insert( Nibbles::from_str("0x01").unwrap(), rlp::encode(&receipt_1).to_vec(), - ); + )?; // Check that the trie hashes are correct. assert_eq!( diff --git a/evm_arithmetization/tests/self_balance_gas_cost.rs b/evm_arithmetization/tests/self_balance_gas_cost.rs index 979e43abd..510c33cb3 100644 --- a/evm_arithmetization/tests/self_balance_gas_cost.rs +++ b/evm_arithmetization/tests/self_balance_gas_cost.rs @@ -77,9 +77,9 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { 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()); + )?; + 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, @@ -138,10 +138,10 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), - ); + )?; expected_state_trie_after - .insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); - expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec()); + .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 }; @@ -155,7 +155,7 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - ); + )?; let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), diff --git a/evm_arithmetization/tests/selfdestruct.rs b/evm_arithmetization/tests/selfdestruct.rs index f48248f69..0ef48d2f4 100644 --- a/evm_arithmetization/tests/selfdestruct.rs +++ b/evm_arithmetization/tests/selfdestruct.rs @@ -57,8 +57,8 @@ fn test_selfdestruct() -> anyhow::Result<()> { }; let mut state_trie_before = HashedPartialTrie::from(Node::Empty); - 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()); + 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, @@ -93,7 +93,7 @@ fn test_selfdestruct() -> anyhow::Result<()> { storage_root: HashedPartialTrie::from(Node::Empty).hash(), code_hash: keccak([]), }; - state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); + state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec())?; state_trie_after }; @@ -107,7 +107,7 @@ fn test_selfdestruct() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - ); + )?; let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), diff --git a/evm_arithmetization/tests/simple_transfer.rs b/evm_arithmetization/tests/simple_transfer.rs index 3fb3b08f6..8adbc1c42 100644 --- a/evm_arithmetization/tests/simple_transfer.rs +++ b/evm_arithmetization/tests/simple_transfer.rs @@ -123,7 +123,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - ); + )?; let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), diff --git a/evm_arithmetization/tests/withdrawals.rs b/evm_arithmetization/tests/withdrawals.rs index 28dc6da59..7f133518b 100644 --- a/evm_arithmetization/tests/withdrawals.rs +++ b/evm_arithmetization/tests/withdrawals.rs @@ -50,7 +50,7 @@ fn test_withdrawals() -> anyhow::Result<()> { balance: withdrawals[0].1, ..AccountRlp::default() }; - trie.insert(addr_nibbles, rlp::encode(&account).to_vec()); + trie.insert(addr_nibbles, rlp::encode(&account).to_vec())?; trie }; diff --git a/mpt_trie/Cargo.toml b/mpt_trie/Cargo.toml index 41b4f704c..b4ef7ded2 100644 --- a/mpt_trie/Cargo.toml +++ b/mpt_trie/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "mpt_trie" description = "Types and utility functions for building/working with partial Ethereum tries." -version = "0.2.0" +version = "0.2.1" authors = ["Polygon Zero "] readme = "README.md" edition.workspace = true @@ -27,6 +27,10 @@ num-traits = "0.2.15" uint = "0.9.5" rlp = { workspace = true } serde = { workspace = true, features = ["derive", "rc"] } +impl-rlp = "0.3.0" +impl-codec = "0.6.0" +impl-serde = "0.4.0" +impl-num-traits = "0.1.2" [dev-dependencies] eth_trie = "0.4.0" diff --git a/mpt_trie/examples/ethereum_trie.rs b/mpt_trie/examples/ethereum_trie.rs index 53e3ad70e..d1aa1f799 100644 --- a/mpt_trie/examples/ethereum_trie.rs +++ b/mpt_trie/examples/ethereum_trie.rs @@ -13,6 +13,8 @@ use std::ops::RangeInclusive; use ethereum_types::{H160, H256, U256}; use keccak_hash::keccak; use mpt_trie::partial_trie::PartialTrie; +use mpt_trie::trie_ops::TrieOpResult; +use mpt_trie::utils::TryFromIterator; use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, StandardTrie}, @@ -36,34 +38,38 @@ struct StateTrieEntry { code_hash: H256, } -fn main() { +fn main() -> TrieOpResult<()> { let mut rng = StdRng::seed_from_u64(0); let (account_entries, account_storage_tries): (Vec<_>, Vec<_>) = (0..NUM_ACCOUNTS_TO_GEN) .map(|_| generate_fake_account_and_storage_trie(&mut rng)) + .collect::, _>>()? + .into_iter() .unzip(); - let _state_trie = StandardTrie::from_iter( + let _state_trie = StandardTrie::try_from_iter( account_entries .into_iter() .map(|(k, acc)| (Nibbles::from_h256_be(k), acc.rlp_bytes().to_vec())), - ); + )?; let _account_storage_tries: Vec<(AccountAddr, HashedPartialTrie)> = account_storage_tries; + Ok(()) + // TODO: Generate remaining tries... } fn generate_fake_account_and_storage_trie( rng: &mut StdRng, -) -> ( +) -> TrieOpResult<( (HashedAccountAddr, StateTrieEntry), (AccountAddr, HashedPartialTrie), -) { +)> { let account_addr: H160 = rng.gen(); let hashed_account_addr = keccak(account_addr.as_bytes()); - let account_storage_trie = generate_fake_account_storage_trie(rng); + let account_storage_trie = generate_fake_account_storage_trie(rng)?; let acc_entry = StateTrieEntry { nonce: gen_u256(rng), @@ -73,16 +79,16 @@ fn generate_fake_account_and_storage_trie( * "fake" it here. */ }; - ( + Ok(( (hashed_account_addr, acc_entry), (account_addr, account_storage_trie), - ) + )) } -fn generate_fake_account_storage_trie(rng: &mut StdRng) -> HashedPartialTrie { +fn generate_fake_account_storage_trie(rng: &mut StdRng) -> TrieOpResult { let num_storage_entries = rng.gen_range(RANGE_OF_STORAGE_ENTRIES_AN_ACCOUNT_CAN_HAVE); - HashedPartialTrie::from_iter((0..num_storage_entries).map(|_| { + HashedPartialTrie::try_from_iter((0..num_storage_entries).map(|_| { let hashed_storage_addr = Nibbles::from_h256_be(rng.gen::()); let storage_data = gen_u256(rng).rlp_bytes().to_vec(); diff --git a/mpt_trie/examples/hash_nodes.rs b/mpt_trie/examples/hash_nodes.rs index 0a27dd72d..2b18d33fc 100644 --- a/mpt_trie/examples/hash_nodes.rs +++ b/mpt_trie/examples/hash_nodes.rs @@ -54,9 +54,10 @@ use mpt_trie::partial_trie::PartialTrie; use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, Node}, + trie_ops::TrieOpResult, }; -fn main() { +fn main() -> TrieOpResult<()> { pretty_env_logger::try_init().unwrap(); // Lets build the (binary) tries in the module-level docs. Since the example @@ -66,10 +67,10 @@ fn main() { // Note the nibbles read the most significant nibble first (eg. `0x12` reads `1` // first). - full_trie.insert(Nibbles::from_str("0x00").unwrap(), large_val(1)); // 1st from left. - full_trie.insert(Nibbles::from_str("0x01").unwrap(), large_val(2)); // 2nd from left. - full_trie.insert(Nibbles::from(0x10_u64), large_val(3)); // 3rd from left. - full_trie.insert(Nibbles::from(0x11_u64), large_val(4)); // 4th from left. + full_trie.insert(Nibbles::from_str("0x00").unwrap(), large_val(1))?; // 1st from left. + full_trie.insert(Nibbles::from_str("0x01").unwrap(), large_val(2))?; // 2nd from left. + full_trie.insert(Nibbles::from(0x10_u64), large_val(3))?; // 3rd from left. + full_trie.insert(Nibbles::from(0x11_u64), large_val(4))?; // 4th from left. let full_trie_hash = full_trie.hash(); @@ -83,14 +84,16 @@ fn main() { // Hash version. `0` branch is replaced with a `Hash` node. let mut hash_trie = HashedPartialTrie::default(); - hash_trie.insert(Nibbles::from_str("0x0").unwrap(), left_side_hash); // Hash node - hash_trie.insert(0x10_u64, large_val(3)); // 3rd from left. - hash_trie.insert(0x11_u64, large_val(4)); // 4th from left. + hash_trie.insert(Nibbles::from_str("0x0").unwrap(), left_side_hash)?; // Hash node + hash_trie.insert(0x10_u64, large_val(3))?; // 3rd from left. + hash_trie.insert(0x11_u64, large_val(4))?; // 4th from left. let hash_trie_hash = hash_trie.hash(); // Hashes should be equal. assert_eq!(full_trie_hash, hash_trie_hash); + + Ok(()) } /// We want to ensure that all leafs are >= 32 bytes when RLP encoded in order diff --git a/mpt_trie/examples/simple.rs b/mpt_trie/examples/simple.rs index 15917e843..eb70a52b1 100644 --- a/mpt_trie/examples/simple.rs +++ b/mpt_trie/examples/simple.rs @@ -3,13 +3,14 @@ use std::iter::once; use mpt_trie::partial_trie::PartialTrie; +use mpt_trie::utils::TryFromIterator; use mpt_trie::{ nibbles::{Nibbles, ToNibbles}, partial_trie::{HashedPartialTrie, StandardTrie}, - trie_ops::ValOrHash, + trie_ops::{TrieOpResult, ValOrHash}, }; -fn main() { +fn main() -> TrieOpResult<()> { // Construct an empty trie: let mut trie = StandardTrie::default(); @@ -17,13 +18,13 @@ fn main() { trie.insert( Nibbles::from_bytes_be(b"hello").unwrap(), b"world!".to_vec(), - ); + )?; // Or by initializing the trie with an iterator of key value pairs: - let mut trie = StandardTrie::from_iter(vec![ + let mut trie = StandardTrie::try_from_iter(vec![ (0x1234_u32, b"some data".to_vec()), (9001_u32, vec![1, 2, 3]), - ]); + ])?; // Tries can be queried: assert_eq!(trie.get(0x1234_u32), Some(b"some data".as_slice())); @@ -43,8 +44,8 @@ fn main() { ); // Values can be deleted: - let del_val = trie.delete(0x1234_u32); - assert_eq!(del_val, Some(b"some data".to_vec())); + let del_val = trie.delete(0x1234_u32)?; + assert_eq!(del_val.unwrap(), b"some data".to_vec()); assert_eq!(trie.get(0x1234_u32), None); // It's important to note how types are converted to `Nibbles`. This is @@ -59,11 +60,13 @@ fn main() { // Note that `From` just calls `to_nibbles` by default instead of // `to_nibbles_byte_padded`. - let hash_1 = - HashedPartialTrie::from_iter(once((0x19002_u32.to_nibbles_byte_padded(), vec![4, 5, 6]))) - .hash(); + let hash_1 = HashedPartialTrie::try_from_iter(once(( + 0x19002_u32.to_nibbles_byte_padded(), + vec![4, 5, 6], + )))? + .hash(); let hash_2 = - HashedPartialTrie::from_iter(once((0x19002_u32.to_nibbles(), vec![4, 5, 6]))).hash(); + HashedPartialTrie::try_from_iter(once((0x19002_u32.to_nibbles(), vec![4, 5, 6])))?.hash(); assert_ne!(hash_1, hash_2); // Finally note that `Nibbles` which are constructed from bytes are always @@ -76,4 +79,6 @@ fn main() { format!("{:x}", Nibbles::from_bytes_le(&[69, 35, 1]).unwrap()), "0x012345" ); + + Ok(()) } diff --git a/mpt_trie/src/debug_tools/diff.rs b/mpt_trie/src/debug_tools/diff.rs index fd280c749..3a4318c23 100644 --- a/mpt_trie/src/debug_tools/diff.rs +++ b/mpt_trie/src/debug_tools/diff.rs @@ -65,7 +65,7 @@ enum DiffDetectionState { } impl DiffDetectionState { - fn pick_most_significant_state(&self, other: &Self) -> Self { + const fn pick_most_significant_state(&self, other: &Self) -> Self { match self.get_int_repr() > other.get_int_repr() { false => *other, true => *self, @@ -73,7 +73,7 @@ impl DiffDetectionState { } /// The integer representation also indicates the more "significant" state. - fn get_int_repr(self) -> usize { + const fn get_int_repr(self) -> usize { self as usize } } @@ -403,7 +403,7 @@ fn create_diff_detection_state_based_from_hashes( /// If the node type contains a value (without looking at the children), then /// return it. -fn get_value_from_node(n: &Node) -> Option<&Vec> { +const fn get_value_from_node(n: &Node) -> Option<&Vec> { match n { Node::Empty | Node::Hash(_) | Node::Extension { .. } => None, Node::Branch { value, .. } | Node::Leaf { nibbles: _, value } => Some(value), @@ -416,18 +416,19 @@ mod tests { use crate::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, PartialTrie}, + trie_ops::TrieOpResult, utils::TrieNodeType, }; #[test] - fn depth_single_node_hash_diffs_work() { + fn depth_single_node_hash_diffs_work() -> TrieOpResult<()> { // TODO: Reduce duplication once we identify common structures across tests... let mut a = HashedPartialTrie::default(); - a.insert(0x1234, vec![0]); + a.insert(0x1234, vec![0])?; let a_hash = a.hash(); let mut b = a.clone(); - b.insert(0x1234, vec![1]); + b.insert(0x1234, vec![1])?; let b_hash = b.hash(); let diff = create_diff_between_tries(&a, &b); @@ -455,6 +456,8 @@ mod tests { }; assert_eq!(diff.latest_diff_res, Some(expected)); + + Ok(()) } // TODO: Will finish these tests later (low-priority). diff --git a/mpt_trie/src/debug_tools/query.rs b/mpt_trie/src/debug_tools/query.rs index 20edf6a3b..e6a988cee 100644 --- a/mpt_trie/src/debug_tools/query.rs +++ b/mpt_trie/src/debug_tools/query.rs @@ -49,19 +49,19 @@ pub struct DebugQueryParamsBuilder { impl DebugQueryParamsBuilder { /// Defaults to `true`. - pub fn print_key_pieces(mut self, enabled: bool) -> Self { + pub const fn print_key_pieces(mut self, enabled: bool) -> Self { self.params.include_key_piece_per_node = enabled; self } /// Defaults to `true`. - pub fn print_node_type(mut self, enabled: bool) -> Self { + pub const fn print_node_type(mut self, enabled: bool) -> Self { self.params.include_node_type = enabled; self } /// Defaults to `false`. - pub fn print_node_specific_values(mut self, enabled: bool) -> Self { + pub const fn print_node_specific_values(mut self, enabled: bool) -> Self { self.params.include_node_specific_values = enabled; self } diff --git a/mpt_trie/src/debug_tools/stats.rs b/mpt_trie/src/debug_tools/stats.rs index 6a23ab496..1f2762936 100644 --- a/mpt_trie/src/debug_tools/stats.rs +++ b/mpt_trie/src/debug_tools/stats.rs @@ -34,7 +34,7 @@ impl Display for TrieStats { impl TrieStats { /// Compares with the statistics of another trie. - pub fn compare(&self, other: &Self) -> TrieComparison { + pub const fn compare(&self, other: &Self) -> TrieComparison { TrieComparison { node_comp: self.counts.compare(&other.counts), depth_comp: self.depth_stats.compare(&other.depth_stats), @@ -77,19 +77,19 @@ impl NodeCounts { } impl NodeCounts { - fn total_nodes(&self) -> usize { + const fn total_nodes(&self) -> usize { self.empty + self.total_node_non_empty() } - fn total_node_non_empty(&self) -> usize { + const fn total_node_non_empty(&self) -> usize { self.branch + self.extension + self.hash_and_leaf_node_count() } - fn hash_and_leaf_node_count(&self) -> usize { + const fn hash_and_leaf_node_count(&self) -> usize { self.hash + self.leaf } - fn compare(&self, other: &Self) -> NodeComparison { + const fn compare(&self, other: &Self) -> NodeComparison { NodeComparison { tot_node_rat: RatioStat::new(self.total_nodes(), other.total_nodes()), non_empty_rat: RatioStat::new( @@ -184,7 +184,7 @@ impl Display for RatioStat { impl RatioStat { /// `new` doesn't have any logic, but this will reduce a lot of line lengths /// since this is called so many times. - fn new(a: T, b: T) -> Self { + const fn new(a: T, b: T) -> Self { Self { a, b } } @@ -234,7 +234,7 @@ impl Display for DepthStats { } impl DepthStats { - fn compare(&self, other: &Self) -> DepthComparison { + const fn compare(&self, other: &Self) -> DepthComparison { DepthComparison { lowest_depth_rat: RatioStat::new(self.lowest_depth, other.lowest_depth), avg_leaf_depth_rat: RatioStat::new(self.avg_leaf_depth, other.avg_leaf_depth), @@ -317,13 +317,14 @@ mod tests { generate_n_random_fixed_trie_hash_entries, generate_n_random_fixed_trie_value_entries, handmade_trie_1, }, + trie_ops::TrieOpResult, }; const MASSIVE_TRIE_SIZE: usize = 100_000; #[test] - fn hand_made_trie_has_correct_node_stats() { - let (trie, _) = handmade_trie_1(); + fn hand_made_trie_has_correct_node_stats() -> TrieOpResult<()> { + let (trie, _) = handmade_trie_1()?; let stats = get_trie_stats(&trie); assert_eq!(stats.counts.leaf, 4); @@ -333,6 +334,8 @@ mod tests { // empty = (n_branch * 4) - n_leaf - (n_branch - 1) assert_eq!(stats.counts.empty, 57); + + Ok(()) } // TODO: Low-priority. Finish later. @@ -343,40 +346,42 @@ mod tests { } #[test] - fn massive_leaf_trie_has_correct_leaf_node_stats() { - create_trie_and_stats_from_entries_and_assert(MASSIVE_TRIE_SIZE, 0, 9522); + fn massive_leaf_trie_has_correct_leaf_node_stats() -> TrieOpResult<()> { + create_trie_and_stats_from_entries_and_assert(MASSIVE_TRIE_SIZE, 0, 9522) } #[test] - fn massive_hash_trie_has_correct_hash_node_stats() { - create_trie_and_stats_from_entries_and_assert(0, MASSIVE_TRIE_SIZE, 9855); + fn massive_hash_trie_has_correct_hash_node_stats() -> TrieOpResult<()> { + create_trie_and_stats_from_entries_and_assert(0, MASSIVE_TRIE_SIZE, 9855) } #[test] - fn massive_mixed_trie_has_correct_hash_node_stats() { + fn massive_mixed_trie_has_correct_hash_node_stats() -> TrieOpResult<()> { create_trie_and_stats_from_entries_and_assert( MASSIVE_TRIE_SIZE / 2, MASSIVE_TRIE_SIZE / 2, 1992, - ); + ) } fn create_trie_and_stats_from_entries_and_assert( n_leaf_nodes: usize, n_hash_nodes: usize, seed: u64, - ) { + ) -> TrieOpResult<()> { let val_entries = generate_n_random_fixed_trie_value_entries(n_leaf_nodes, seed); let hash_entries = generate_n_random_fixed_trie_hash_entries(n_hash_nodes, seed + 1); let mut trie = HashedPartialTrie::default(); - trie.extend(val_entries); - trie.extend(hash_entries); + trie.extend(val_entries)?; + trie.extend(hash_entries)?; let stats = get_trie_stats(&trie); assert_eq!(stats.counts.leaf, n_leaf_nodes); assert_eq!(stats.counts.hash, n_hash_nodes); + + Ok(()) } // TODO: Low-priority. Finish later. diff --git a/mpt_trie/src/nibbles.rs b/mpt_trie/src/nibbles.rs index d2426dad2..d7422a93d 100644 --- a/mpt_trie/src/nibbles.rs +++ b/mpt_trie/src/nibbles.rs @@ -1,6 +1,7 @@ +#![allow(clippy::assign_op_pattern)] + //! Define [`Nibbles`] and how to convert bytes, hex prefix encodings and //! strings into nibbles. - use std::mem::size_of; use std::{ fmt::{self, Debug}, @@ -13,9 +14,14 @@ use std::{ }; use bytes::{Bytes, BytesMut}; -use ethereum_types::{H256, U128, U256, U512}; +use ethereum_types::{H256, U128, U256}; +use impl_codec::impl_uint_codec; +use impl_num_traits::impl_uint_num_traits; +use impl_rlp::impl_uint_rlp; +use impl_serde::impl_uint_serde; use serde::{Deserialize, Serialize}; use thiserror::Error; +use uint::construct_uint; use uint::FromHexError; use crate::utils::{create_mask_of_1s, is_even}; @@ -23,8 +29,19 @@ use crate::utils::{create_mask_of_1s, is_even}; // Use a whole byte for a Nibble just for convenience /// A Nibble has 4 bits and is stored as `u8`. pub type Nibble = u8; -/// Used for the internal representation of a sequence of nibbles. -pub type NibblesIntern = U512; + +construct_uint! { + /// Used for the internal representation of a sequence of nibbles. + /// The choice of [u64; 5] accommodates the 260-bit key requirement efficiently by + /// leveraging 64-bit instructions for performance, while providing an additional u64 + /// to handle the overflow case beyond the 256-bit capacity of [u64; 4]. + pub struct NibblesIntern(5); +} + +impl_uint_num_traits!(NibblesIntern, 5); +impl_uint_serde!(NibblesIntern, 5); +impl_uint_codec!(NibblesIntern, 5); +impl_uint_rlp!(NibblesIntern, 5); const MULTIPLE_NIBBLES_APPEND_ASSERT_ERR_MSG: &str = "Attempted to create a nibbles sequence longer than 64!"; @@ -74,11 +91,56 @@ pub enum FromHexPrefixError { /// The hex prefix encoding flag is invalid. InvalidFlags(Nibble), - #[error("Tried to convert a hex prefix byte string into `Nibbles` that was longer than 64 bytes: (length: {0}, bytes: {1})")] + #[error("Tried to convert a hex prefix byte string into `Nibbles` that was longer than 40 bytes: (length: {0}, bytes: {1})")] /// The hex prefix encoding is too large. TooLong(String, usize), } +/// Error type for conversion. +#[derive(Debug, Error)] +pub enum NibblesToTypeError { + #[error("Overflow encountered when converting to U256: {0}")] + /// Overflow encountered. + Overflow(NibblesIntern), +} + +trait AsU64s { + fn as_u64s(&self) -> impl Iterator + '_; +} + +macro_rules! impl_as_u64s_for_primitive { + ($type:ty) => { + impl AsU64s for $type { + fn as_u64s(&self) -> impl Iterator + '_ { + std::iter::once(*self as u64) + } + } + }; +} + +impl_as_u64s_for_primitive!(u8); +impl_as_u64s_for_primitive!(u16); +impl_as_u64s_for_primitive!(u32); +impl_as_u64s_for_primitive!(u64); + +impl AsU64s for U128 { + fn as_u64s(&self) -> impl Iterator + '_ { + self.0.iter().copied() + } +} + +impl AsU64s for U256 { + fn as_u64s(&self) -> impl Iterator + '_ { + self.0.iter().copied() + } +} + +impl AsU64s for NibblesIntern { + fn as_u64s(&self) -> impl Iterator + '_ { + self.0.iter().copied() + } +} + #[derive(Debug, Error)] #[error(transparent)] /// An error encountered when converting a string to a sequence of nibbles. @@ -103,11 +165,14 @@ macro_rules! impl_to_nibbles { #[allow(clippy::manual_bits)] let size_bits = size_of::() * 8; let count = (size_bits - self.leading_zeros() as usize + 3) / 4; + let mut packed = NibblesIntern::zero(); - Nibbles { - count, - packed: self.into(), + let parts = self.as_u64s(); + for (i, part) in parts.enumerate().take(packed.0.len()) { + packed.0[i] = part; } + + Nibbles { count, packed } } } }; @@ -119,7 +184,60 @@ impl_to_nibbles!(u32); impl_to_nibbles!(u64); impl_to_nibbles!(U128); impl_to_nibbles!(U256); -impl_to_nibbles!(U512); +impl_to_nibbles!(NibblesIntern); + +impl<'a> TryFrom<&'a Nibbles> for U256 { + type Error = NibblesToTypeError; + + fn try_from(value: &'a Nibbles) -> Result { + let NibblesIntern(ref arr) = value.packed; + if arr[4] != 0 { + return Err(NibblesToTypeError::Overflow(value.packed)); + } + + let ret = [arr[0], arr[1], arr[2], arr[3]]; + Ok(U256(ret)) + } +} + +impl<'a> TryFrom<&'a NibblesIntern> for U256 { + type Error = NibblesToTypeError; + + fn try_from(value: &'a NibblesIntern) -> Result { + if value.0[4] != 0 { + return Err(NibblesToTypeError::Overflow(*value)); + } + + let ret = [value.0[0], value.0[1], value.0[2], value.0[3]]; + Ok(U256(ret)) + } +} + +impl TryInto for Nibbles { + type Error = NibblesToTypeError; + + fn try_into(self) -> Result { + let arr = self.packed; + if arr.0[4] != 0 { + return Err(NibblesToTypeError::Overflow(arr)); + } + + let ret = [arr.0[0], arr.0[1], arr.0[2], arr.0[3]]; + Ok(U256(ret)) + } +} + +impl From for NibblesIntern { + fn from(val: U256) -> Self { + let arr = val.as_u64s(); + + let mut ret = NibblesIntern::zero(); + for (i, part) in arr.enumerate() { + ret.0[i] = part; + } + ret + } +} #[derive(Copy, Clone, Deserialize, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] /// A sequence of nibbles which is used as the key type into @@ -190,7 +308,6 @@ impl Debug for Nibbles { } } -// TODO: This impl is going to need to change once we move away from `U256`s... impl FromStr for Nibbles { type Err = StrToNibblesError; @@ -201,7 +318,7 @@ impl FromStr for Nibbles { .chars() .position(|c| c != '0') .unwrap_or(stripped_str.len()); - let packed = U512::from_str(s)?; + let packed = NibblesIntern::from_str(s)?; Ok(Self { count: leading_zeros + Self::get_num_nibbles_in_key(&packed), @@ -228,7 +345,7 @@ impl Nibbles { /// Returns an error if the byte slice is empty or is longer than `32` /// bytes. pub fn from_bytes_be(bytes: &[u8]) -> Result { - Self::from_bytes(bytes, U512::from_big_endian) + Self::from_bytes(bytes, NibblesIntern::from_big_endian) } /// Creates `Nibbles` from little endian bytes. @@ -236,7 +353,7 @@ impl Nibbles { /// Returns an error if the byte slice is empty or is longer than `32` /// bytes. pub fn from_bytes_le(bytes: &[u8]) -> Result { - Self::from_bytes(bytes, U512::from_little_endian) + Self::from_bytes(bytes, NibblesIntern::from_little_endian) } fn from_bytes(bytes: &[u8], conv_f: F) -> Result @@ -350,7 +467,7 @@ impl Nibbles { let shift_amt = 4 * self.count; self.count += 1; - self.packed |= U512::from(n) << shift_amt; + self.packed |= NibblesIntern::from(n) << shift_amt; } /// Pushes a nibble to the back. @@ -462,7 +579,7 @@ impl Nibbles { self.packed = (self.packed & truncate_mask) >> shift_amt; } - fn get_min_truncate_amount_to_prevent_over_truncating(&self, n: usize) -> usize { + const fn get_min_truncate_amount_to_prevent_over_truncating(&self, n: usize) -> usize { match self.count >= n { false => self.count, true => n, @@ -471,7 +588,7 @@ impl Nibbles { /// Returns whether or not this `Nibbles` contains actual nibbles. (If /// `count` is set to `0`) - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.count == 0 } @@ -564,8 +681,8 @@ impl Nibbles { /// Reverses the `Nibbles` such that the last `Nibble` is now the first /// `Nibble`. pub fn reverse(&self) -> Nibbles { - let mut mask = U512::from(0xf); - let mut reversed_packed = U512::zero(); + let mut mask = NibblesIntern::from(0xf); + let mut reversed_packed = NibblesIntern::zero(); for i in 0..self.count { reversed_packed <<= 4; @@ -615,7 +732,7 @@ impl Nibbles { return n1.count; } - let mut curr_mask: U512 = (U512::from(0xf)) << ((n1.count - 1) * 4); + let mut curr_mask: NibblesIntern = (NibblesIntern::from(0xf)) << ((n1.count - 1) * 4); for i in 0..n1.count { if n1.packed & curr_mask != n2.packed & curr_mask { return i; @@ -632,11 +749,11 @@ impl Nibbles { where F: Fn(&[u8]) -> String, { - let mut byte_buf = [0; 64]; + let mut byte_buf = [0; 40]; self.packed.to_big_endian(&mut byte_buf); let count_bytes = self.min_bytes(); - let hex_string_raw = hex_encode_f(&byte_buf[(64 - count_bytes)..64]); + let hex_string_raw = hex_encode_f(&byte_buf[(40 - count_bytes)..40]); let hex_char_iter_raw = hex_string_raw.chars(); // We need this skip to make both match arms have the same type. @@ -656,10 +773,10 @@ impl Nibbles { pub fn to_hex_prefix_encoding(&self, is_leaf: bool) -> Bytes { let num_nibbles = self.count + 1; let num_bytes = (num_nibbles + 1) / 2; - let flag_byte_idx = 65 - num_bytes; + let flag_byte_idx = 41 - num_bytes; // Needed because `to_big_endian` always writes `32` bytes. - let mut bytes = BytesMut::zeroed(65); + let mut bytes = BytesMut::zeroed(41); let is_even = is_even(self.count); let odd_bit = match is_even { @@ -673,10 +790,10 @@ impl Nibbles { }; let flags: u8 = (odd_bit | (term_bit << 1)) << 4; - self.packed.to_big_endian(&mut bytes[1..65]); + self.packed.to_big_endian(&mut bytes[1..41]); bytes[flag_byte_idx] |= flags; - Bytes::copy_from_slice(&bytes[flag_byte_idx..65]) + Bytes::copy_from_slice(&bytes[flag_byte_idx..41]) } /// Converts a hex prefix byte string ("AKA "compact") into `Nibbles`. @@ -710,7 +827,7 @@ impl Nibbles { let hex_prefix_byes_iter = hex_prefix_bytes.iter().skip(1).take(32).cloned(); let mut i = 0; - let mut nibbles_raw = [0; 64]; + let mut nibbles_raw = [0; 40]; if odd_nib_count { Self::write_byte_iter_to_byte_buf( @@ -730,7 +847,7 @@ impl Nibbles { let x = Self { count, - packed: U512::from_big_endian(&nibbles_raw[..tot_bytes]), + packed: NibblesIntern::from_big_endian(&nibbles_raw[..tot_bytes]), }; Ok(x) @@ -744,43 +861,41 @@ impl Nibbles { } /// Returns the minimum number of bytes needed to represent these `Nibbles`. - pub fn min_bytes(&self) -> usize { + pub const fn min_bytes(&self) -> usize { (self.count + 1) / 2 } /// Returns the minimum number of nibbles needed to represent a `U256` key. - pub fn get_num_nibbles_in_key(k: &U512) -> usize { + pub fn get_num_nibbles_in_key(k: &NibblesIntern) -> usize { (k.bits() + 3) / 4 } - // TODO: Make not terrible at some point... Consider moving away from `U256` - // internally? /// Returns the nibbles bytes in big-endian format. pub fn bytes_be(&self) -> Vec { - let mut byte_buf = [0; 64]; + let mut byte_buf = [0; 40]; self.packed.to_big_endian(&mut byte_buf); - byte_buf[64 - self.min_bytes()..64].to_vec() + byte_buf[40 - self.min_bytes()..40].to_vec() } /// Creates `Nibbles` from a big endian `H256`. pub fn from_h256_be(v: H256) -> Self { - Self::from_h256_common(|v| U512::from_big_endian(v.as_bytes()), v) + Self::from_h256_common(|v| NibblesIntern::from_big_endian(v.as_bytes()), v) } /// Creates `Nibbles` from a little endian `H256`. pub fn from_h256_le(v: H256) -> Self { - Self::from_h256_common(|v| U512::from_little_endian(v.as_bytes()), v) + Self::from_h256_common(|v| NibblesIntern::from_little_endian(v.as_bytes()), v) } - fn from_h256_common U512>(conv_f: F, v: H256) -> Self { + fn from_h256_common NibblesIntern>(conv_f: F, v: H256) -> Self { Self { count: 64, packed: conv_f(v), } } - fn nibble_append_safety_asserts(&self, n: Nibble) { + const fn nibble_append_safety_asserts(&self, n: Nibble) { assert!( self.count < 64, "{}", @@ -789,25 +904,13 @@ impl Nibbles { assert!(n < 16, "{}", SINGLE_NIBBLE_APPEND_ASSERT_ERR_MSG); } - fn nibbles_append_safety_asserts(&self, new_count: usize) { + const fn nibbles_append_safety_asserts(&self, new_count: usize) { assert!( new_count <= 64, "{}", MULTIPLE_NIBBLES_APPEND_ASSERT_ERR_MSG ); } - - // TODO: REMOVE BEFORE NEXT CRATE VERSION! THIS IS A TEMP HACK! - /// Converts to u256 returning an error if not possible. - pub fn try_into_u256(&self) -> Result { - match self.count <= 64 { - false => Err(format!( - "Tried getting a U256 from Nibbles that were too big! ({:?})", - self - )), - true => Ok(self.packed.try_into().unwrap()), - } - } } #[cfg(test)] @@ -816,7 +919,7 @@ mod tests { use ethereum_types::{H256, U256}; - use super::{Nibble, Nibbles, ToNibbles}; + use super::{Nibble, Nibbles, StrToNibblesError, ToNibbles}; use crate::nibbles::FromHexPrefixError; const ZERO_NIBS_63: &str = "0x000000000000000000000000000000000000000000000000000000000000000"; @@ -827,23 +930,42 @@ mod tests { "0x0000000000000000000000000000000000000000000000000000000000000001"; #[test] - fn get_nibble_works() { + fn get_nibble_works() -> Result<(), StrToNibblesError> { let n = Nibbles::from(0x1234); - assert_eq!(n.get_nibble(0), 0x1); assert_eq!(n.get_nibble(3), 0x4); + + let n = Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", + )?; + assert_eq!(n.get_nibble(30), 0x1); + assert_eq!(n.get_nibble(33), 0xc); + + Ok(()) } #[test] fn pop_nibble_front_works() { pop_and_assert_nibbles(0x1, 0x0, 1, Nibbles::pop_next_nibble_front); pop_and_assert_nibbles(0x1234, 0x234, 1, Nibbles::pop_next_nibble_front); + pop_and_assert_nibbles( + 0x1234567890123, + 0x234567890123, + 1, + Nibbles::pop_next_nibble_front, + ); } #[test] fn pop_nibble_back_works() { pop_and_assert_nibbles(0x1, 0x0, 1, Nibbles::pop_next_nibble_back); pop_and_assert_nibbles(0x1234, 0x123, 4, Nibbles::pop_next_nibble_back); + pop_and_assert_nibbles( + 0x1234567890123, + 0x123456789012, + 3, + Nibbles::pop_next_nibble_back, + ); } fn pop_and_assert_nibbles Nibble>( @@ -868,7 +990,7 @@ mod tests { } #[test] - fn pop_nibbles_front_works() { + fn pop_nibbles_front_works() -> Result<(), StrToNibblesError> { let nib = 0x1234.into(); assert_pop_nibbles( @@ -899,10 +1021,30 @@ mod tests { 0x1234.into(), Nibbles::pop_nibbles_front, ); + assert_pop_nibbles( + &nib, + 4, + 0x0.into(), + 0x1234.into(), + Nibbles::pop_nibbles_front, + ); + + let nib = Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", + )?; + assert_pop_nibbles( + &nib, + 24, + Nibbles::from_str("0x0ffd1e165c754b28a41a95922f9f70682c581353")?, + Nibbles::from_str("0x3ab76c381c0f8ea617ea9678")?, + Nibbles::pop_nibbles_front, + ); + + Ok(()) } #[test] - fn pop_nibbles_back_works() { + fn pop_nibbles_back_works() -> Result<(), StrToNibblesError> { let nib = 0x1234.into(); assert_pop_nibbles( @@ -921,6 +1063,19 @@ mod tests { 0x4321.into(), Nibbles::pop_nibbles_back, ); + + let nib = Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", + )?; + assert_pop_nibbles( + &nib, + 24, + Nibbles::from_str("0x3ab76c381c0f8ea617ea96780ffd1e165c754b28")?, + Nibbles::from_str("0x353185c28607f9f22959a14a")?, + Nibbles::pop_nibbles_back, + ); + + Ok(()) } fn assert_pop_nibbles Nibbles>( @@ -997,7 +1152,7 @@ mod tests { } #[test] - fn get_next_nibbles_works() { + fn get_next_nibbles_works() -> Result<(), StrToNibblesError> { let n: Nibbles = 0x1234.into(); assert_eq!(n.get_next_nibbles(0), Nibbles::default()); @@ -1007,20 +1162,37 @@ mod tests { assert_eq!(n.get_next_nibbles(4), Nibbles::from(0x1234)); assert_eq!(Nibbles::from(0x0).get_next_nibbles(0), Nibbles::default()); + + let n = Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", + )?; + assert_eq!( + n.get_next_nibbles(24), + Nibbles::from_str("0x3ab76c381c0f8ea617ea9678")? + ); + + Ok(()) } #[test] - fn get_nibble_range_works() { + fn get_nibble_range_works() -> Result<(), StrToNibblesError> { let n: Nibbles = 0x1234.into(); assert_eq!(n.get_nibble_range(0..0), 0x0.into()); assert_eq!(n.get_nibble_range(0..1), 0x1.into()); assert_eq!(n.get_nibble_range(0..2), 0x12.into()); assert_eq!(n.get_nibble_range(0..4), 0x1234.into()); + + let n = Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", + )?; + assert_eq!(n.get_nibble_range(16..24), Nibbles::from_str("0x17ea9678")?); + + Ok(()) } #[test] - fn truncate_nibbles_works() { + fn truncate_nibbles_works() -> Result<(), StrToNibblesError> { let n: Nibbles = 0x1234.into(); assert_eq!(n.truncate_n_nibbles_front(0), n); @@ -1036,16 +1208,43 @@ mod tests { assert_eq!(n.truncate_n_nibbles_back(3), 0x1.into()); assert_eq!(n.truncate_n_nibbles_back(4), 0x0.into()); assert_eq!(n.truncate_n_nibbles_back(8), 0x0.into()); + + let n = Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", + )?; + assert_eq!( + n.truncate_n_nibbles_front(16), + Nibbles::from_str("0x17ea96780ffd1e165c754b28a41a95922f9f70682c581353")? + ); + assert_eq!( + n.truncate_n_nibbles_back(16), + Nibbles::from_str("0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a9592")? + ); + + Ok(()) } #[test] - fn split_at_idx_works() { + fn split_at_idx_works() -> Result<(), StrToNibblesError> { let n: Nibbles = 0x1234.into(); assert_eq!(n.split_at_idx(0), (0x0.into(), 0x1234.into())); assert_eq!(n.split_at_idx(1), (0x1.into(), 0x234.into())); assert_eq!(n.split_at_idx(2), (0x12.into(), 0x34.into())); assert_eq!(n.split_at_idx(3), (0x123.into(), 0x4.into())); + + let n = Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", + )?; + assert_eq!( + n.split_at_idx(24), + ( + Nibbles::from_str("0x3ab76c381c0f8ea617ea9678")?, + Nibbles::from_str("0x0ffd1e165c754b28a41a95922f9f70682c581353")? + ) + ); + + Ok(()) } #[test] @@ -1055,31 +1254,60 @@ mod tests { } #[test] - fn split_at_idx_prefix_works() { + fn split_at_idx_prefix_works() -> Result<(), StrToNibblesError> { let n: Nibbles = 0x1234.into(); assert_eq!(n.split_at_idx_prefix(0), 0x0.into()); assert_eq!(n.split_at_idx_prefix(1), 0x1.into()); assert_eq!(n.split_at_idx_prefix(3), 0x123.into()); + + let n = Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", + )?; + assert_eq!( + n.split_at_idx_prefix(24), + Nibbles::from_str("0x3ab76c381c0f8ea617ea9678")? + ); + + Ok(()) } #[test] - fn split_at_idx_postfix_works() { + fn split_at_idx_postfix_works() -> Result<(), StrToNibblesError> { let n: Nibbles = 0x1234.into(); assert_eq!(n.split_at_idx_postfix(0), 0x1234.into()); assert_eq!(n.split_at_idx_postfix(1), 0x234.into()); assert_eq!(n.split_at_idx_postfix(3), 0x4.into()); + + let n = Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", + )?; + assert_eq!( + n.split_at_idx_postfix(24), + Nibbles::from_str("0x0ffd1e165c754b28a41a95922f9f70682c581353")? + ); + + Ok(()) } #[test] - fn merge_nibble_works() { + fn merge_nibble_works() -> Result<(), StrToNibblesError> { assert_eq!(Nibbles::from(0x0).merge_nibble(1), 0x1.into()); assert_eq!(Nibbles::from(0x1234).merge_nibble(5), 0x12345.into()); + assert_eq!( + Nibbles::from_str("0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c58135")? + .merge_nibble(3), + Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353" + )? + ); + + Ok(()) } #[test] - fn merge_nibbles_works() { + fn merge_nibbles_works() -> Result<(), StrToNibblesError> { assert_eq!( Nibbles::from(0x12).merge_nibbles(&(0x34.into())), 0x1234.into() @@ -1093,18 +1321,34 @@ mod tests { 0x34.into() ); assert_eq!(Nibbles::from(0x0).merge_nibbles(&(0x0).into()), 0x0.into()); + assert_eq!( + Nibbles::from_str("0x3ab76c381c0f8ea617ea96780ffd1e1")? + .merge_nibbles(&Nibbles::from_str("0x65c754b28a41a95922f9f70682c581353")?), + Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353" + )? + ); + + Ok(()) } #[test] - fn reverse_works() { + fn reverse_works() -> Result<(), StrToNibblesError> { assert_eq!(Nibbles::from(0x0).reverse(), Nibbles::from(0x0_u64)); assert_eq!(Nibbles::from(0x1).reverse(), Nibbles::from(0x1_u64)); assert_eq!(Nibbles::from(0x12).reverse(), Nibbles::from(0x21_u64)); assert_eq!(Nibbles::from(0x1234).reverse(), Nibbles::from(0x4321_u64)); + assert_eq!( + Nibbles::from_str("0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c58135")? + .reverse(), + Nibbles::from_str("0x53185c28607f9f22959a14a82b457c561e1dff08769ae716ae8f0c183c67ba3")? + ); + + Ok(()) } #[test] - fn find_nibble_idx_that_differs_between_nibbles_works() { + fn find_nibble_idx_that_differs_between_nibbles_works() -> Result<(), StrToNibblesError> { assert_eq!( Nibbles::find_nibble_idx_that_differs_between_nibbles_equal_lengths( &(0x1234.into()), @@ -1140,6 +1384,19 @@ mod tests { ), 4 ); + assert_eq!( + Nibbles::find_nibble_idx_that_differs_between_nibbles_different_lengths( + &(Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c58135" + )?), + &(Nibbles::from_str( + "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41ae716ae8f0c183c67ba3" + )?), + ), + 44 + ); + + Ok(()) } #[test] diff --git a/mpt_trie/src/partial_trie.rs b/mpt_trie/src/partial_trie.rs index c1a04c4bf..3d29e8c05 100644 --- a/mpt_trie/src/partial_trie.rs +++ b/mpt_trie/src/partial_trie.rs @@ -13,8 +13,8 @@ use serde::{Deserialize, Serialize}; use crate::{ nibbles::Nibbles, trie_hashing::{hash_trie, rlp_encode_and_hash_node, EncodedNode}, - trie_ops::ValOrHash, - utils::bytes_to_h256, + trie_ops::{TrieOpResult, ValOrHash}, + utils::{bytes_to_h256, TryFromIterator}, }; macro_rules! impl_from_for_trie_type { @@ -58,13 +58,13 @@ pub trait PartialTrie: fn new(n: Node) -> Self; /// Inserts a node into the trie. - fn insert(&mut self, k: K, v: V) + fn insert(&mut self, k: K, v: V) -> TrieOpResult<()> where K: Into, V: Into; /// Add more nodes to the trie through an iterator - fn extend(&mut self, nodes: I) + fn extend(&mut self, nodes: I) -> TrieOpResult<()> where K: Into, V: Into, @@ -89,7 +89,7 @@ pub trait PartialTrie: /// are meant for parts of the trie that are not relevant, traversing one /// means that a `Hash` node was created that potentially should not have /// been. - fn delete(&mut self, k: K) -> Option> + fn delete(&mut self, k: K) -> TrieOpResult>> where K: Into; @@ -214,15 +214,16 @@ impl PartialTrie for StandardTrie { Self(n) } - fn insert(&mut self, k: K, v: V) + fn insert(&mut self, k: K, v: V) -> TrieOpResult<()> where K: Into, V: Into, { - self.0.trie_insert(k, v); + self.0.trie_insert(k, v)?; + Ok(()) } - fn extend(&mut self, nodes: I) + fn extend(&mut self, nodes: I) -> TrieOpResult<()> where K: Into, V: Into, @@ -238,7 +239,7 @@ impl PartialTrie for StandardTrie { self.0.trie_get(k) } - fn delete(&mut self, k: K) -> Option> + fn delete(&mut self, k: K) -> TrieOpResult>> where K: Into, { @@ -282,12 +283,12 @@ impl DerefMut for StandardTrie { } } -impl FromIterator<(K, V)> for StandardTrie +impl TryFromIterator<(K, V)> for StandardTrie where K: Into, V: Into, { - fn from_iter>(nodes: T) -> Self { + fn try_from_iter>(nodes: T) -> TrieOpResult { from_iter_common(nodes) } } @@ -327,23 +328,25 @@ impl PartialTrie for HashedPartialTrie { } } - fn insert(&mut self, k: K, v: V) + fn insert(&mut self, k: K, v: V) -> TrieOpResult<()> where K: Into, V: Into, { - self.node.trie_insert(k, v); + self.node.trie_insert(k, v)?; self.set_hash(None); + Ok(()) } - fn extend(&mut self, nodes: I) + fn extend(&mut self, nodes: I) -> TrieOpResult<()> where K: Into, V: Into, I: IntoIterator, { - self.node.trie_extend(nodes); + self.node.trie_extend(nodes)?; self.set_hash(None); + Ok(()) } fn get(&self, k: K) -> Option<&[u8]> @@ -353,7 +356,7 @@ impl PartialTrie for HashedPartialTrie { self.node.trie_get(k) } - fn delete(&mut self, k: K) -> Option> + fn delete(&mut self, k: K) -> TrieOpResult>> where K: Into, { @@ -418,23 +421,24 @@ impl PartialEq for HashedPartialTrie { } } -impl FromIterator<(K, V)> for HashedPartialTrie +impl TryFromIterator<(K, V)> for HashedPartialTrie where K: Into, V: Into, { - fn from_iter>(nodes: T) -> Self { + fn try_from_iter>(nodes: T) -> TrieOpResult { from_iter_common(nodes) } } -fn from_iter_common, K, V>(nodes: T) -> N +fn from_iter_common, K, V>( + nodes: T, +) -> TrieOpResult where K: Into, V: Into, { let mut root = N::new(Node::Empty); - root.extend(nodes); - - root + root.extend(nodes)?; + Ok(root) } diff --git a/mpt_trie/src/special_query.rs b/mpt_trie/src/special_query.rs index 5c74cbab8..c133a6091 100644 --- a/mpt_trie/src/special_query.rs +++ b/mpt_trie/src/special_query.rs @@ -125,13 +125,14 @@ mod test { use crate::{ nibbles::Nibbles, testing_utils::{common_setup, handmade_trie_1}, + trie_ops::TrieOpResult, utils::TrieSegment, }; #[test] - fn query_iter_works_no_last_node() { + fn query_iter_works_no_last_node() -> TrieOpResult<()> { common_setup(); - let (trie, ks) = handmade_trie_1(); + let (trie, ks) = handmade_trie_1()?; // ks --> vec![0x1234, 0x1324, 0x132400005_u64, 0x2001, 0x2002]; let res = vec![ @@ -170,12 +171,14 @@ mod test { let res: Vec<_> = path_for_query(&trie.node, q, false).collect(); assert_eq!(res, expected) } + + Ok(()) } #[test] - fn query_iter_works_with_last_node() { + fn query_iter_works_with_last_node() -> TrieOpResult<()> { common_setup(); - let (trie, _) = handmade_trie_1(); + let (trie, _) = handmade_trie_1()?; let extension_expected = vec![ TrieSegment::Branch(1), @@ -212,5 +215,7 @@ mod test { path_for_query(&trie, 0x132400, true).collect::>(), leaf_expected ); + + Ok(()) } } diff --git a/mpt_trie/src/testing_utils.rs b/mpt_trie/src/testing_utils.rs index 51b40e541..cc8a0daef 100644 --- a/mpt_trie/src/testing_utils.rs +++ b/mpt_trie/src/testing_utils.rs @@ -3,14 +3,14 @@ use std::{ iter::{once, repeat}, }; -use ethereum_types::{H256, U256, U512}; +use ethereum_types::{H256, U256}; use log::info; use rand::{rngs::StdRng, seq::IteratorRandom, Rng, RngCore, SeedableRng}; use crate::{ - nibbles::Nibbles, + nibbles::{Nibbles, NibblesIntern}, partial_trie::{HashedPartialTrie, Node, PartialTrie}, - trie_ops::ValOrHash, + trie_ops::{TrieOpResult, ValOrHash}, utils::is_even, }; @@ -29,7 +29,7 @@ type TestInsertEntry = (Nibbles, T); // Don't want this exposed publicly, but it is useful for testing. impl From for Nibbles { fn from(k: i32) -> Self { - let packed = U512::from(k); + let packed = NibblesIntern::from(k); Self { count: Self::get_num_nibbles_in_key(&packed), @@ -192,19 +192,21 @@ fn gen_rand_u256_bytes(rng: &mut StdRng) -> Vec { /// Initializes a trie with keys large enough to force hashing (nodes less than /// 32 bytes are not hashed). -pub(crate) fn create_trie_with_large_entry_nodes + Copy>(keys: &[T]) -> TrieType { +pub(crate) fn create_trie_with_large_entry_nodes + Copy>( + keys: &[T], +) -> TrieOpResult { let mut trie = TrieType::default(); for (k, v) in keys.iter().map(|k| (*k).into()).map(large_entry) { - trie.insert(k, v.clone()); + trie.insert(k, v.clone())?; } - trie + Ok(trie) } -pub(crate) fn handmade_trie_1() -> (TrieType, Vec) { +pub(crate) fn handmade_trie_1() -> TrieOpResult<(TrieType, Vec)> { let ks = vec![0x1234, 0x1324, 0x132400005_u64, 0x2001, 0x2002]; let ks_nibbles: Vec = ks.into_iter().map(|k| k.into()).collect(); - let trie = create_trie_with_large_entry_nodes(&ks_nibbles); + let trie = create_trie_with_large_entry_nodes(&ks_nibbles)?; // Branch (0x) --> 1, 2 // Branch (0x1) --> 2, 3 @@ -219,5 +221,5 @@ pub(crate) fn handmade_trie_1() -> (TrieType, Vec) { // Leaf (0x2001) --> (n: 0x1, v: [3]) // Leaf (0x2002) --> (n: 0x2, v: [4]) - (trie, ks_nibbles) + Ok((trie, ks_nibbles)) } diff --git a/mpt_trie/src/trie_hashing.rs b/mpt_trie/src/trie_hashing.rs index b6dc864eb..9502ebe1c 100644 --- a/mpt_trie/src/trie_hashing.rs +++ b/mpt_trie/src/trie_hashing.rs @@ -113,6 +113,8 @@ mod tests { generate_n_random_variable_trie_value_entries, large_entry, TestInsertValEntry, }, trie_hashing::hash_bytes, + trie_ops::TrieOpResult, + utils::TryFromIterator, }; const PYEVM_TRUTH_VALS_JSON_PATH: &str = "test_data/pyevm_account_ground_truth.json"; @@ -185,7 +187,7 @@ mod tests { } impl PyEvmTrueValEntry { - fn account_entry(&self) -> AccountEntry { + const fn account_entry(&self) -> AccountEntry { AccountEntry { nonce: self.nonce, balance: self.balance, @@ -232,7 +234,7 @@ mod tests { let mut trie = HashedPartialTrie::new(Node::Empty); entries.map(move |(k, v)| { - trie.insert(k, v); + trie.insert(k, v).unwrap(); trie.get_hash() }) } @@ -257,7 +259,7 @@ mod tests { } #[test] - fn single_account_leaf_hash_is_correct() { + fn single_account_leaf_hash_is_correct() -> TrieOpResult<()> { common_setup(); let acc_and_hash_entry = &load_pyevm_truth_vals()[0]; @@ -274,10 +276,12 @@ mod tests { get_lib_trie_root_hashes_after_each_insert(once(ins_entry.clone())) .next() .unwrap(); - let our_hash = HashedPartialTrie::from_iter(once(ins_entry)).get_hash(); + let our_hash = HashedPartialTrie::try_from_iter(once(ins_entry))?.get_hash(); assert_eq!(py_evm_truth_val, our_hash); assert_eq!(eth_trie_lib_truth_val, our_hash); + + Ok(()) } #[test] @@ -357,7 +361,7 @@ mod tests { } #[test] - fn massive_trie_data_deletion_agrees_with_eth_trie() { + fn massive_trie_data_deletion_agrees_with_eth_trie() -> Result<(), Box> { common_setup(); let entries: Vec<_> = generate_n_random_fixed_even_nibble_padded_trie_value_entries( @@ -366,32 +370,34 @@ mod tests { ) .collect(); - let mut our_trie = HashedPartialTrie::from_iter(entries.iter().cloned()); + let mut our_trie = HashedPartialTrie::try_from_iter(entries.iter().cloned())?; let mut truth_trie = create_truth_trie(); for (k, v) in entries.iter() { - truth_trie.insert(&k.bytes_be(), v).unwrap(); + truth_trie.insert(&k.bytes_be(), v)?; } let half_entries = entries.len() / 2; let entries_to_delete = entries.into_iter().take(half_entries); for (k, _) in entries_to_delete { - our_trie.delete(k); - truth_trie.remove(&k.bytes_be()).unwrap(); + our_trie.delete(k)?; + truth_trie.remove(&k.bytes_be())?; - let truth_root_hash = H256(truth_trie.root_hash().unwrap().0); + let truth_root_hash = H256(truth_trie.root_hash()?.0); assert_eq!(our_trie.get_hash(), truth_root_hash); } + + Ok(()) } #[test] - fn replacing_branch_of_leaves_with_hash_nodes_produced_same_hash() { - let mut trie = HashedPartialTrie::from_iter([ + fn replacing_branch_of_leaves_with_hash_nodes_produced_same_hash() -> TrieOpResult<()> { + let mut trie = HashedPartialTrie::try_from_iter([ large_entry(0x1), large_entry(0x2), large_entry(0x3), large_entry(0x4), - ]); + ])?; let orig_hash = trie.hash(); @@ -401,6 +407,8 @@ mod tests { let new_hash = trie.hash(); assert_eq!(orig_hash, new_hash); + + Ok(()) } fn get_branch_children_expected( @@ -413,7 +421,7 @@ mod tests { } #[test] - fn replacing_part_of_a_trie_with_a_hash_node_produces_same_hash() { + fn replacing_part_of_a_trie_with_a_hash_node_produces_same_hash() -> TrieOpResult<()> { let entries = (0..16).flat_map(|i| { generate_n_random_variable_trie_value_entries( NODES_PER_BRANCH_FOR_HASH_REPLACEMENT_TEST, @@ -428,7 +436,7 @@ mod tests { }) }); - let mut trie = HashedPartialTrie::from_iter(entries); + let mut trie = HashedPartialTrie::try_from_iter(entries)?; let orig_hash = trie.get_hash(); let root_branch_children = match &mut *trie { @@ -444,5 +452,7 @@ mod tests { let new_hash = trie.get_hash(); assert_eq!(orig_hash, new_hash); + + Ok(()) } } diff --git a/mpt_trie/src/trie_ops.rs b/mpt_trie/src/trie_ops.rs index 1208be70e..64f7f70b4 100644 --- a/mpt_trie/src/trie_ops.rs +++ b/mpt_trie/src/trie_ops.rs @@ -6,6 +6,7 @@ use std::{fmt::Display, mem::size_of}; use enum_as_inner::EnumAsInner; use ethereum_types::{H256, U128, U256, U512}; use log::trace; +use thiserror::Error; use crate::{ nibbles::{Nibble, Nibbles}, @@ -13,6 +14,33 @@ use crate::{ utils::TrieNodeType, }; +/// Stores the result of trie operations. Returns a [TrieOpError] upon +/// failure. +pub type TrieOpResult = Result; + +/// An error type for trie operation. +#[derive(Debug, Error)] +pub enum TrieOpError { + /// An error that occurs when a hash node is found during an insert + /// operation. + #[error("Found a `Hash` node during an insert in a `PartialTrie`! These should not be able to be traversed during an insert! (hash: {0})")] + HashNodeInsertError(H256), + + /// An error that occurs when a hash node is found during a delete + /// operation. + #[error("Attempted to delete a value that ended up inside a hash node! (hash: {0})")] + HashNodeDeleteError(H256), + + /// An error that occurs when encontered an unexisting type of node during + /// an extension node collapse. + #[error("Extension managed to get an unexisting child node type! (child: {0})")] + HashNodeExtError(TrieNodeType), + + /// Failed to insert a hash node into the trie. + #[error("Attempted to place a hash node on an existing node! (hash: {0})")] + ExistingHashNodeError(H256), +} + /// A entry to be inserted into a `PartialTrie`. #[derive(Clone, Debug, Eq, Hash, PartialEq)] struct InsertEntry { @@ -263,7 +291,7 @@ impl Iterator for PartialTrieIter { } impl Node { - pub(crate) fn trie_insert(&mut self, k: K, v: V) + pub(crate) fn trie_insert(&mut self, k: K, v: V) -> TrieOpResult<()> where K: Into, V: Into, @@ -272,19 +300,21 @@ impl Node { trace!("Inserting new node {:?}...", ins_entry); // Inserts are guaranteed to update the root node. - let node_ref: &Node = &insert_into_trie_rec(self, ins_entry).unwrap(); + let node_ref: &Node = &insert_into_trie_rec(self, ins_entry)?.unwrap(); *self = node_ref.clone(); + Ok(()) } - pub(crate) fn trie_extend(&mut self, nodes: I) + pub(crate) fn trie_extend(&mut self, nodes: I) -> TrieOpResult<()> where K: Into, V: Into, I: IntoIterator, { for (k, v) in nodes { - self.trie_insert(k, v); + self.trie_insert(k, v)?; } + Ok(()) } pub(crate) fn trie_get(&self, k: K) -> Option<&[u8]> @@ -330,19 +360,20 @@ impl Node { } } - pub(crate) fn trie_delete(&mut self, k: K) -> Option> + pub(crate) fn trie_delete(&mut self, k: K) -> TrieOpResult>> where K: Into, { let k = k.into(); trace!("Deleting a leaf node with key {} if it exists", k); - delete_intern(&self.clone(), k).map(|(updated_root, deleted_val)| { + delete_intern(&self.clone(), k)?.map_or(Ok(None), |(updated_root, deleted_val)| { // Final check at the root if we have an extension node - let node_ref: &Node = &try_collapse_if_extension(updated_root); + let wrapped_node = try_collapse_if_extension(updated_root)?; + let node_ref: &Node = &wrapped_node; *self = node_ref.clone(); - deleted_val + Ok(Some(deleted_val)) }) } @@ -365,32 +396,35 @@ impl Node { fn insert_into_trie_rec( node: &Node, mut new_node: InsertEntry, -) -> Option> { +) -> TrieOpResult>> { match node { Node::Empty => { trace!("Insert traversed Empty"); - Some(create_node_from_insert_val(new_node.nibbles, new_node.v)) + Ok(Some(create_node_from_insert_val( + new_node.nibbles, + new_node.v, + ))) } - Node::Hash(_) => { + Node::Hash(h) => { trace!("Insert traversed {:?}", node); - panic!( - "Found a `Hash` node during an insert in a `PartialTrie`! These should not be able to be traversed during an insert!" - ) + Err(TrieOpError::HashNodeInsertError(*h)) } Node::Branch { children, value } => { if new_node.nibbles.count == 0 { trace!("Insert traversed branch and placed value in node"); - return Some(branch_from_insert_val(children.clone(), new_node.v)); + return Ok(Some(branch_from_insert_val(children.clone(), new_node.v)?)); } let nibble = new_node.nibbles.pop_next_nibble_front(); trace!("Insert traversed Branch (nibble: {:x})", nibble); - insert_into_trie_rec(&children[nibble as usize], new_node).map(|updated_child| { - let mut updated_children = children.clone(); - updated_children[nibble as usize] = updated_child; - branch(updated_children, value.clone()) - }) + Ok( + insert_into_trie_rec(&children[nibble as usize], new_node)?.map(|updated_child| { + let mut updated_children = children.clone(); + updated_children[nibble as usize] = updated_child; + branch(updated_children, value.clone()) + }), + ) } Node::Extension { nibbles, child } => { trace!("Insert traversed Extension (nibbles: {:?})", nibbles); @@ -402,8 +436,9 @@ fn insert_into_trie_rec( if nibbles.nibbles_are_identical_up_to_smallest_count(&new_node.nibbles) { new_node.truncate_n_nibbles(nibbles.count); - return insert_into_trie_rec(child, new_node) - .map(|updated_child| extension(*nibbles, updated_child)); + return insert_into_trie_rec(child, new_node)?.map_or(Ok(None), |updated_child| { + Ok(Some(extension(*nibbles, updated_child))) + }); } // Drop one since branch will cover one nibble. @@ -418,18 +453,18 @@ fn insert_into_trie_rec( _ => extension(existing_postfix_adjusted_for_branch, child.clone()), }; - Some(place_branch_and_potentially_ext_prefix( + Ok(Some(place_branch_and_potentially_ext_prefix( &info, updated_existing_node, new_node, - )) + ))) } Node::Leaf { nibbles, value } => { trace!("Insert traversed Leaf (nibbles: {:?})", nibbles); // Update existing node value if already present. if *nibbles == new_node.nibbles { - return Some(leaf_from_insert_val(*nibbles, new_node.v)); + return Ok(Some(leaf_from_insert_val(*nibbles, new_node.v)?)); } let info = get_pre_and_postfixes_for_existing_and_new_nodes(nibbles, &new_node.nibbles); @@ -441,11 +476,11 @@ fn insert_into_trie_rec( value.clone(), ); - Some(place_branch_and_potentially_ext_prefix( + Ok(Some(place_branch_and_potentially_ext_prefix( &info, existing_node_truncated, new_node, - )) + ))) } } } @@ -453,24 +488,23 @@ fn insert_into_trie_rec( fn delete_intern( node: &Node, mut curr_k: Nibbles, -) -> Option<(WrappedNode, Vec)> { +) -> TrieOpResult, Vec)>> { match node { Node::Empty => { trace!("Delete traversed Empty"); - None + Ok(None) } - Node::Hash(_) => { - panic!("Attempted to delete a value that ended up inside a hash node") - } // TODO: Find a nice way to get the full key path... + Node::Hash(h) => Err(TrieOpError::HashNodeDeleteError(*h)), + // TODO: Find a nice way to get the full key path... Node::Branch { children, value } => { if curr_k.is_empty() { - return Some((branch(children.clone(), Vec::new()), value.clone())); + return Ok(Some((branch(children.clone(), Vec::new()), value.clone()))); } let nibble = curr_k.pop_next_nibble_front(); trace!("Delete traversed Branch nibble {:x}", nibble); - delete_intern(&children[nibble as usize], curr_k).map( + delete_intern(&children[nibble as usize], curr_k)?.map_or(Ok(None), |(updated_child, value_deleted)| { // If the child we recursively called is deleted, then we may need to reduce // this branch to an extension/leaf. @@ -481,7 +515,7 @@ fn delete_intern( // Branch stays. let mut updated_children = children.clone(); updated_children[nibble as usize] = - try_collapse_if_extension(updated_child); + try_collapse_if_extension(updated_child)?; branch(updated_children, value.clone()) } true => { @@ -499,7 +533,7 @@ fn delete_intern( } }; - (updated_node, value_deleted) + Ok(Some((updated_node, value_deleted))) }, ) } @@ -513,34 +547,38 @@ fn delete_intern( .nibbles_are_identical_up_to_smallest_count(&curr_k) .then(|| { curr_k.truncate_n_nibbles_front_mut(ext_nibbles.count); - delete_intern(child, curr_k).map(|(updated_child, value_deleted)| { - let updated_node = collapse_ext_node_if_needed(ext_nibbles, &updated_child); - (updated_node, value_deleted) + + delete_intern(child, curr_k).and_then(|res| { + res.map_or(Ok(None), |(updated_child, value_deleted)| { + let updated_node = + collapse_ext_node_if_needed(ext_nibbles, &updated_child)?; + Ok(Some((updated_node, value_deleted))) + }) }) }) - .flatten() + .unwrap_or(Ok(None)) } Node::Leaf { nibbles, value } => { trace!("Delete traversed Leaf (nibbles: {:?})", nibbles); - (*nibbles == curr_k).then(|| { + Ok((*nibbles == curr_k).then(|| { trace!("Deleting leaf ({:x})", nibbles); (Node::Empty.into(), value.clone()) - }) + })) } } } -fn try_collapse_if_extension(node: WrappedNode) -> WrappedNode { +fn try_collapse_if_extension(node: WrappedNode) -> TrieOpResult> { match node.as_ref() { Node::Extension { nibbles, child } => collapse_ext_node_if_needed(nibbles, child), - _ => node, + _ => Ok(node), } } fn collapse_ext_node_if_needed( ext_nibbles: &Nibbles, child: &WrappedNode, -) -> WrappedNode { +) -> TrieOpResult> { trace!( "Collapsing extension node ({:x}) with child {}...", ext_nibbles, @@ -548,23 +586,20 @@ fn collapse_ext_node_if_needed( ); match child.as_ref() { - Node::Branch { .. } => extension(*ext_nibbles, child.clone()), + Node::Branch { .. } => Ok(extension(*ext_nibbles, child.clone())), Node::Extension { nibbles: other_ext_nibbles, child: other_ext_child, - } => extension( + } => Ok(extension( ext_nibbles.merge_nibbles(other_ext_nibbles), other_ext_child.clone(), - ), + )), Node::Leaf { nibbles: leaf_nibbles, value, - } => leaf(ext_nibbles.merge_nibbles(leaf_nibbles), value.clone()), - Node::Hash(_) => extension(*ext_nibbles, child.clone()), - _ => panic!( - "Extension managed to get a child node type that is impossible! (child: {})", - TrieNodeType::from(child) - ), + } => Ok(leaf(ext_nibbles.merge_nibbles(leaf_nibbles), value.clone())), + Node::Hash(_) => Ok(extension(*ext_nibbles, child.clone())), + _ => Err(TrieOpError::HashNodeExtError(TrieNodeType::from(child))), } } @@ -717,7 +752,7 @@ pub(crate) fn branch( fn branch_from_insert_val( children: [WrappedNode; 16], value: ValOrHash, -) -> WrappedNode { +) -> TrieOpResult> { create_node_if_ins_val_not_hash(value, |value| Node::Branch { children, value }.into()) } @@ -729,7 +764,10 @@ fn leaf(nibbles: Nibbles, value: Vec) -> WrappedNode { Node::Leaf { nibbles, value }.into() } -fn leaf_from_insert_val(nibbles: Nibbles, value: ValOrHash) -> WrappedNode { +fn leaf_from_insert_val( + nibbles: Nibbles, + value: ValOrHash, +) -> TrieOpResult> { create_node_if_ins_val_not_hash(value, |value| Node::Leaf { nibbles, value }.into()) } @@ -759,12 +797,10 @@ fn create_node_from_insert_val( fn create_node_if_ins_val_not_hash) -> WrappedNode>( value: ValOrHash, create_node_f: F, -) -> WrappedNode { +) -> TrieOpResult> { match value { - ValOrHash::Val(leaf_v) => create_node_f(leaf_v), - ValOrHash::Hash(h) => { - panic!("Attempted to place a hash node on an existing node! (hash: {h})") - } + ValOrHash::Val(leaf_v) => Ok(create_node_f(leaf_v)), + ValOrHash::Hash(h) => Err(TrieOpError::ExistingHashNodeError(h)), } } @@ -785,15 +821,20 @@ mod tests { generate_n_random_variable_trie_value_entries, get_non_hash_values_in_trie, unwrap_iter_item_to_val, TestInsertValEntry, }, - utils::create_mask_of_1s, + trie_ops::TrieOpResult, + utils::{create_mask_of_1s, TryFromIterator}, }; const MASSIVE_TRIE_SIZE: usize = 100000; const COW_TEST_TRIE_SIZE: usize = 500; - fn insert_entries_and_assert_all_exist_in_trie_with_no_extra(entries: &[TestInsertValEntry]) { - let trie = StandardTrie::from_iter(entries.iter().cloned()); - assert_all_entries_in_trie(entries, &trie) + fn insert_entries_and_assert_all_exist_in_trie_with_no_extra( + entries: &[TestInsertValEntry], + ) -> TrieOpResult<()> { + let trie = StandardTrie::try_from_iter(entries.iter().cloned())?; + assert_all_entries_in_trie(entries, &trie); + + Ok(()) } fn assert_all_entries_in_trie(entries: &[TestInsertValEntry], trie: &Node) { @@ -831,105 +872,112 @@ mod tests { } #[test] - fn single_insert() { + fn single_insert() -> TrieOpResult<()> { common_setup(); - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&[entry(0x1234)]); + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&[entry(0x1234)]) } #[test] - fn two_disjoint_inserts_works() { + fn two_disjoint_inserts_works() -> TrieOpResult<()> { common_setup(); let entries = [entry(0x1234), entry(0x5678)]; - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) } #[test] - fn two_inserts_that_share_one_nibble_works() { + fn two_inserts_that_share_one_nibble_works() -> TrieOpResult<()> { common_setup(); let entries = [entry(0x1234), entry(0x1567)]; - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) } #[test] - fn two_inserts_that_differ_on_last_nibble_works() { + fn two_inserts_that_differ_on_last_nibble_works() -> TrieOpResult<()> { common_setup(); let entries = [entry(0x1234), entry(0x1235)]; - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) } #[test] - fn diagonal_inserts_to_base_of_trie_works() { + fn diagonal_inserts_to_base_of_trie_works() -> TrieOpResult<()> { common_setup(); let entries: Vec<_> = (0..=64).map(|i| entry(create_mask_of_1s(i * 4))).collect(); - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) } #[test] - fn updating_an_existing_node_works() { + fn updating_an_existing_node_works() -> TrieOpResult<()> { common_setup(); let mut entries = [entry(0x1234), entry(0x1234)]; entries[1].1 = vec![100]; - let trie = StandardTrie::from_iter(entries); + let trie = StandardTrie::try_from_iter(entries)?; assert_eq!(trie.get(0x1234), Some([100].as_slice())); + + Ok(()) } #[test] - fn cloning_a_trie_creates_two_separate_tries() { + fn cloning_a_trie_creates_two_separate_tries() -> TrieOpResult<()> { common_setup(); - assert_cloning_works_for_tries::(); - assert_cloning_works_for_tries::(); + assert_cloning_works_for_tries::()?; + assert_cloning_works_for_tries::()?; + + Ok(()) } - fn assert_cloning_works_for_tries() + fn assert_cloning_works_for_tries() -> TrieOpResult<()> where - T: FromIterator<(Nibbles, Vec)> + PartialTrie, + T: TryFromIterator<(Nibbles, Vec)> + PartialTrie, { - let trie = T::from_iter(once(entry(0x1234))); + let trie = T::try_from_iter(once(entry(0x1234)))?; let mut cloned_trie = trie.clone(); - cloned_trie.extend(once(entry(0x5678))); + cloned_trie.extend(once(entry(0x5678)))?; assert_ne!(trie, cloned_trie); assert_ne!(trie.hash(), cloned_trie.hash()); + + Ok(()) } #[test] - fn mass_inserts_fixed_sized_keys_all_entries_are_retrievable() { + fn mass_inserts_fixed_sized_keys_all_entries_are_retrievable() -> TrieOpResult<()> { common_setup(); let entries: Vec<_> = generate_n_random_fixed_trie_value_entries(MASSIVE_TRIE_SIZE, 0).collect(); - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) } #[test] - fn mass_inserts_variable_sized_keys_all_entries_are_retrievable() { + fn mass_inserts_variable_sized_keys_all_entries_are_retrievable() -> TrieOpResult<()> { common_setup(); let entries: Vec<_> = generate_n_random_variable_trie_value_entries(MASSIVE_TRIE_SIZE, 0).collect(); - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) } #[test] - fn mass_inserts_variable_sized_keys_with_hash_nodes_all_entries_are_retrievable() { + fn mass_inserts_variable_sized_keys_with_hash_nodes_all_entries_are_retrievable( + ) -> TrieOpResult<()> { common_setup(); let non_hash_entries: Vec<_> = generate_n_random_variable_trie_value_entries(MASSIVE_TRIE_SIZE, 0).collect(); - let mut trie = StandardTrie::from_iter(non_hash_entries.iter().cloned()); + let mut trie = StandardTrie::try_from_iter(non_hash_entries.iter().cloned())?; let extra_hash_entries = generate_n_hash_nodes_entries_for_empty_slots_in_trie( &trie, MASSIVE_TRIE_SIZE / 10, 51, ); - trie.extend(extra_hash_entries.iter().cloned()); + assert!(trie.extend(extra_hash_entries.iter().cloned()).is_ok()); let all_nodes: HashSet<_> = trie.items().collect(); @@ -941,10 +989,12 @@ mod tests { assert!(extra_hash_entries .into_iter() .all(|(k, h)| all_nodes.contains(&(k, ValOrHash::Hash(h))))); + + Ok(()) } #[test] - fn equivalency_check_works() { + fn equivalency_check_works() -> TrieOpResult<()> { common_setup(); assert_eq!( @@ -953,33 +1003,37 @@ mod tests { ); let entries = generate_n_random_fixed_trie_value_entries(MASSIVE_TRIE_SIZE, 0); - let big_trie_1 = StandardTrie::from_iter(entries); + let big_trie_1 = StandardTrie::try_from_iter(entries)?; assert_eq!(big_trie_1, big_trie_1); let entries = generate_n_random_fixed_trie_value_entries(MASSIVE_TRIE_SIZE, 1); - let big_trie_2 = StandardTrie::from_iter(entries); + let big_trie_2 = StandardTrie::try_from_iter(entries)?; + + assert_ne!(big_trie_1, big_trie_2); - assert_ne!(big_trie_1, big_trie_2) + Ok(()) } #[test] - fn two_variable_length_keys_with_overlap_are_queryable() { + fn two_variable_length_keys_with_overlap_are_queryable() -> TrieOpResult<()> { common_setup(); let entries = [entry_with_value(0x1234, 1), entry_with_value(0x12345678, 2)]; - let trie = StandardTrie::from_iter(entries.iter().cloned()); + let trie = StandardTrie::try_from_iter(entries.iter().cloned())?; assert_eq!(trie.get(0x1234), Some([1].as_slice())); assert_eq!(trie.get(0x12345678), Some([2].as_slice())); + + Ok(()) } #[test] - fn get_massive_trie_works() { + fn get_massive_trie_works() -> TrieOpResult<()> { common_setup(); let random_entries: Vec<_> = generate_n_random_fixed_trie_value_entries(MASSIVE_TRIE_SIZE, 9001).collect(); - let trie = StandardTrie::from_iter(random_entries.iter().cloned()); + let trie = StandardTrie::try_from_iter(random_entries.iter().cloned())?; for (k, v) in random_entries.into_iter() { debug!("Attempting to retrieve {:?}...", (k, &v)); @@ -987,10 +1041,12 @@ mod tests { assert_eq!(res, Some(v.as_slice())); } + + Ok(()) } #[test] - fn held_trie_cow_references_do_not_change_as_trie_changes() { + fn held_trie_cow_references_do_not_change_as_trie_changes() -> TrieOpResult<()> { common_setup(); let entries = generate_n_random_variable_trie_value_entries(COW_TEST_TRIE_SIZE, 9002); @@ -1000,7 +1056,7 @@ mod tests { let mut trie = StandardTrie::default(); for (k, v) in entries { - trie.insert(k, v); + trie.insert(k, v)?; all_nodes_in_trie_after_each_insert.push(get_non_hash_values_in_trie(&trie)); root_node_after_each_insert.push(trie.clone()); @@ -1013,15 +1069,17 @@ mod tests { let nodes_retrieved = get_non_hash_values_in_trie(&old_root_node); assert_eq!(old_trie_nodes_truth, nodes_retrieved) } + + Ok(()) } #[test] - fn trie_iter_works() { + fn trie_iter_works() -> TrieOpResult<()> { common_setup(); let entries: HashSet<_> = generate_n_random_variable_trie_value_entries(MASSIVE_TRIE_SIZE, 9003).collect(); - let trie = StandardTrie::from_iter(entries.iter().cloned()); + let trie = StandardTrie::try_from_iter(entries.iter().cloned())?; let trie_items: HashSet<_> = trie .items() @@ -1030,40 +1088,48 @@ mod tests { assert!(entries.iter().all(|e| trie_items.contains(e))); assert!(trie_items.iter().all(|item| entries.contains(item))); + + Ok(()) } #[test] - fn deleting_a_non_existent_node_returns_none() { + fn deleting_a_non_existent_node_returns_none() -> TrieOpResult<()> { common_setup(); let mut trie = StandardTrie::default(); - trie.insert(0x1234, vec![91]); + trie.insert(0x1234, vec![91])?; - assert!(trie.delete(0x5678).is_none()) + let res = trie.delete(0x5678)?; + assert!(res.is_none()); + + Ok(()) } #[test] - fn deleting_from_an_empty_trie_returns_none() { + fn deleting_from_an_empty_trie_returns_none() -> TrieOpResult<()> { common_setup(); let mut trie = StandardTrie::default(); - assert!(trie.delete(0x1234).is_none()); + let res = trie.delete(0x1234)?; + assert!(res.is_none()); + + Ok(()) } #[test] - fn deletion_massive_trie() { + fn deletion_massive_trie() -> TrieOpResult<()> { common_setup(); let entries: Vec<_> = generate_n_random_variable_trie_value_entries(MASSIVE_TRIE_SIZE, 7).collect(); - let mut trie = StandardTrie::from_iter(entries.iter().cloned()); + let mut trie = StandardTrie::try_from_iter(entries.iter().cloned())?; // Delete half of the elements let half_entries = entries.len() / 2; let entries_to_delete = entries.iter().take(half_entries); for (k, v) in entries_to_delete { - let res = trie.delete(*k); + let res = trie.delete(*k)?; assert!(trie.get(*k).is_none()); assert_eq!(res.as_ref(), Some(v)); @@ -1073,5 +1139,7 @@ mod tests { for (k, v) in entries_that_still_should_exist { assert_eq!(trie.get(k), Some(v.as_slice())); } + + Ok(()) } } diff --git a/mpt_trie/src/trie_subsets.rs b/mpt_trie/src/trie_subsets.rs index 483c86baf..0f1ff138a 100644 --- a/mpt_trie/src/trie_subsets.rs +++ b/mpt_trie/src/trie_subsets.rs @@ -163,7 +163,7 @@ struct TrackedNodeInfo { } impl TrackedNodeInfo { - fn new(underlying_node: N) -> Self { + const fn new(underlying_node: N) -> Self { Self { underlying_node, touched: false, @@ -396,8 +396,8 @@ mod tests { common_setup, create_trie_with_large_entry_nodes, generate_n_random_fixed_trie_value_entries, handmade_trie_1, TrieType, }, - trie_ops::ValOrHash, - utils::TrieNodeType, + trie_ops::{TrieOpResult, ValOrHash}, + utils::{TrieNodeType, TryFromIterator}, }; const MASSIVE_TEST_NUM_SUB_TRIES: usize = 10; @@ -503,7 +503,7 @@ mod tests { common_setup(); let mut trie = TrieType::default(); - trie.insert(0x1234, vec![0, 1, 2]); + assert!(trie.insert(0x1234, vec![0, 1, 2]).is_ok()); let res = create_trie_subset(&trie, once(0x5678)); assert!(res.is_ok()); @@ -520,35 +520,39 @@ mod tests { } #[test] - fn single_node_trie_is_queryable() { + fn single_node_trie_is_queryable() -> Result<(), Box> { common_setup(); let mut trie = TrieType::default(); - trie.insert(0x1234, vec![0, 1, 2]); - let trie_subset = create_trie_subset(&trie, once(0x1234)).unwrap(); + trie.insert(0x1234, vec![0, 1, 2])?; + let trie_subset = create_trie_subset(&trie, once(0x1234))?; assert_eq!(trie, trie_subset); + + Ok(()) } #[test] - fn multi_node_trie_returns_proper_subset() { + fn multi_node_trie_returns_proper_subset() -> Result<(), Box> { common_setup(); - let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x56, 0x12345_u64]); + let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x56, 0x12345_u64])?; - let trie_subset = create_trie_subset(&trie, vec![0x1234, 0x56]).unwrap(); + let trie_subset = create_trie_subset(&trie, vec![0x1234, 0x56])?; let leaf_keys = get_all_nibbles_of_leaf_nodes_in_trie(&trie_subset); assert!(leaf_keys.contains(&(Nibbles::from(0x1234)))); assert!(leaf_keys.contains(&(Nibbles::from(0x56)))); assert!(!leaf_keys.contains(&Nibbles::from(0x12345))); + + Ok(()) } #[test] fn intermediate_nodes_are_included_in_subset() { common_setup(); - let (trie, ks_nibbles) = handmade_trie_1(); + let (trie, ks_nibbles) = handmade_trie_1().unwrap(); let trie_subset_all = create_trie_subset(&trie, ks_nibbles.iter().cloned()).unwrap(); let subset_keys = get_all_nibbles_of_leaf_nodes_in_trie(&trie_subset_all); @@ -690,20 +694,23 @@ mod tests { } #[test] - fn all_leafs_of_keys_to_create_subset_are_included_in_subset_for_giant_trie() { + fn all_leafs_of_keys_to_create_subset_are_included_in_subset_for_giant_trie() -> TrieOpResult<()> + { common_setup(); - let (_, trie_subsets, keys_of_subsets) = create_massive_trie_and_subsets(9009); + let (_, trie_subsets, keys_of_subsets) = create_massive_trie_and_subsets(9009)?; for (sub_trie, ks_used) in trie_subsets.into_iter().zip(keys_of_subsets.into_iter()) { let leaf_nibbles = get_all_nibbles_of_leaf_nodes_in_trie(&sub_trie); assert!(ks_used.into_iter().all(|k| leaf_nibbles.contains(&k))); } + + Ok(()) } #[test] fn hash_of_single_leaf_trie_partial_trie_matches_original_trie() { - let trie = create_trie_with_large_entry_nodes(&[0x0]); + let trie = create_trie_with_large_entry_nodes(&[0x0]).unwrap(); let base_hash = trie.hash(); let partial_trie = create_trie_subset(&trie, [0x1234]).unwrap(); @@ -715,27 +722,31 @@ mod tests { fn sub_trie_that_includes_branch_but_not_children_hashes_out_children() { common_setup(); - let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x12345, 0x12346, 0x1234f]); + let trie = + create_trie_with_large_entry_nodes(&[0x1234, 0x12345, 0x12346, 0x1234f]).unwrap(); let partial_trie = create_trie_subset(&trie, [0x1234f]).unwrap(); assert_nodes_are_hash_nodes(&partial_trie, [0x12345, 0x12346]); } #[test] - fn sub_trie_for_non_existent_key_that_hits_branch_leaf_does_not_hash_out_leaf() { + fn sub_trie_for_non_existent_key_that_hits_branch_leaf_does_not_hash_out_leaf( + ) -> TrieOpResult<()> { common_setup(); - let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x1234589, 0x12346]); + let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x1234589, 0x12346])?; let partial_trie = create_trie_subset(&trie, [0x1234567]).unwrap(); // Note that `0x1234589` gets hashed at the branch slot at `0x12345`. assert_nodes_are_hash_nodes(&partial_trie, Vec::::default()); + + Ok(()) } #[test] - fn hash_of_branch_partial_tries_matches_original_trie() { + fn hash_of_branch_partial_tries_matches_original_trie() -> TrieOpResult<()> { common_setup(); - let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x56, 0x12345]); + let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x56, 0x12345])?; let base_hash: H256 = trie.hash(); let partial_tries = vec![ @@ -747,26 +758,30 @@ mod tests { ]; assert!(partial_tries .into_iter() - .all(|p_tree| p_tree.hash() == base_hash)) + .all(|p_tree| p_tree.hash() == base_hash)); + + Ok(()) } #[test] - fn hash_of_giant_random_partial_tries_matches_original_trie() { + fn hash_of_giant_random_partial_tries_matches_original_trie() -> TrieOpResult<()> { common_setup(); - let (base_trie, trie_subsets, _) = create_massive_trie_and_subsets(9010); + let (base_trie, trie_subsets, _) = create_massive_trie_and_subsets(9010)?; let base_hash = base_trie.hash(); assert!(trie_subsets .into_iter() - .all(|p_tree| p_tree.hash() == base_hash)) + .all(|p_tree| p_tree.hash() == base_hash)); + + Ok(()) } #[test] - fn giant_random_partial_tries_hashes_leaves_correctly() { + fn giant_random_partial_tries_hashes_leaves_correctly() -> TrieOpResult<()> { common_setup(); - let (base_trie, trie_subsets, leaf_keys_per_trie) = create_massive_trie_and_subsets(9011); + let (base_trie, trie_subsets, leaf_keys_per_trie) = create_massive_trie_and_subsets(9011)?; let all_keys: Vec = base_trie.keys().collect(); for (partial_trie, leaf_trie_keys) in @@ -785,6 +800,8 @@ mod tests { // over a `Hash` node, we return `None`.) assert_all_keys_do_not_exist(&partial_trie, keys_of_hash_nodes); } + + Ok(()) } fn assert_all_keys_do_not_exist(trie: &TrieType, ks: impl Iterator) { @@ -793,13 +810,15 @@ mod tests { } } - fn create_massive_trie_and_subsets(seed: u64) -> (TrieType, Vec, Vec>) { + fn create_massive_trie_and_subsets( + seed: u64, + ) -> TrieOpResult<(TrieType, Vec, Vec>)> { let trie_size = MASSIVE_TEST_NUM_SUB_TRIES * MASSIVE_TEST_NUM_SUB_TRIE_SIZE; let random_entries: Vec<_> = generate_n_random_fixed_trie_value_entries(trie_size, seed).collect(); let entry_keys: Vec<_> = random_entries.iter().map(|(k, _)| k).cloned().collect(); - let trie = TrieType::from_iter(random_entries); + let trie = TrieType::try_from_iter(random_entries)?; let keys_of_subsets: Vec> = (0..MASSIVE_TEST_NUM_SUB_TRIES) .map(|i| { @@ -812,6 +831,6 @@ mod tests { let trie_subsets = create_trie_subsets(&trie, keys_of_subsets.iter().map(|v| v.iter().cloned())).unwrap(); - (trie, trie_subsets, keys_of_subsets) + Ok((trie, trie_subsets, keys_of_subsets)) } } diff --git a/mpt_trie/src/utils.rs b/mpt_trie/src/utils.rs index 8c457f07a..c38c78a94 100644 --- a/mpt_trie/src/utils.rs +++ b/mpt_trie/src/utils.rs @@ -7,12 +7,13 @@ use std::{ sync::Arc, }; -use ethereum_types::{H256, U512}; +use ethereum_types::H256; use num_traits::PrimInt; use crate::{ - nibbles::{Nibble, Nibbles}, + nibbles::{Nibble, Nibbles, NibblesIntern}, partial_trie::{Node, PartialTrie}, + trie_ops::TrieOpResult, }; #[derive(Clone, Debug, Eq, Hash, PartialEq)] @@ -70,8 +71,8 @@ pub(crate) fn is_even>(num: T) -> bool { (num & T::one()) == T::zero() } -pub(crate) fn create_mask_of_1s(amt: usize) -> U512 { - (U512::one() << amt) - 1 +pub(crate) fn create_mask_of_1s(amt: usize) -> NibblesIntern { + (NibblesIntern::one() << amt) - 1 } pub(crate) fn bytes_to_h256(b: &[u8; 32]) -> H256 { @@ -205,7 +206,7 @@ impl Display for TrieSegment { impl TrieSegment { /// Get the node type of the [`TrieSegment`]. - pub fn node_type(&self) -> TrieNodeType { + pub const fn node_type(&self) -> TrieNodeType { match self { TrieSegment::Empty => TrieNodeType::Empty, TrieSegment::Hash => TrieNodeType::Hash, @@ -243,6 +244,16 @@ pub(crate) fn get_segment_from_node_and_key_piece( } } +/// Conversion from an [`Iterator`] within an allocator. +/// +/// By implementing `TryFromIteratorIn` for a type, you define how it will be +/// created from an iterator. This is common for types which describe a +/// collection of some kind. +pub trait TryFromIterator: Sized { + /// Creates a value from an iterator within an allocator. + fn try_from_iter>(iter: T) -> TrieOpResult; +} + #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/proof_gen/Cargo.toml b/proof_gen/Cargo.toml index 9a613bcc9..b0f6b680e 100644 --- a/proof_gen/Cargo.toml +++ b/proof_gen/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "proof_gen" description = "Generates block proofs from zero proof IR." -version = "0.1.2" +version = "0.1.3" authors = ["Polygon Zero "] edition.workspace = true license.workspace = true @@ -17,5 +17,4 @@ plonky2 = { workspace = true } serde = { workspace = true } # Local dependencies -trace_decoder = { version = "0.2.0", path = "../trace_decoder" } -evm_arithmetization = { version = "0.1.2", path = "../evm_arithmetization" } +evm_arithmetization = { version = "0.1.3", path = "../evm_arithmetization" } diff --git a/proof_gen/README.md b/proof_gen/README.md index 03bb6cfa1..09730359a 100644 --- a/proof_gen/README.md +++ b/proof_gen/README.md @@ -22,7 +22,7 @@ pub struct BlockHashes { ``` Note that `prev_hashes` is going to be `256` elements long (!) most of the time. -`generate_txn_proof` takes in the output from the parser lib (`TxnProofGenIR`). +`generate_txn_proof` takes in the output from the parser lib (`GenerationInputs`). `generate_agg_proof` takes in the two child proofs (wrapped in `AggregatableProof`` to support txn or agg proofs). diff --git a/proof_gen/src/lib.rs b/proof_gen/src/lib.rs index 7907ae3b9..2599f6360 100644 --- a/proof_gen/src/lib.rs +++ b/proof_gen/src/lib.rs @@ -53,7 +53,8 @@ //! ```compile_fail //! pub fn generate_txn_proof( //! p_state: &ProverState, -//! start_info: TxnProofGenIR, +//! gen_inputs: GenerationInputs, +//! abort_signal: Option>, //! ) -> ProofGenResult { ... } //! ``` //! diff --git a/proof_gen/src/proof_gen.rs b/proof_gen/src/proof_gen.rs index 58435d0dc..f41167490 100644 --- a/proof_gen/src/proof_gen.rs +++ b/proof_gen/src/proof_gen.rs @@ -3,14 +3,13 @@ use std::sync::{atomic::AtomicBool, Arc}; -use evm_arithmetization::{AllStark, StarkConfig}; +use evm_arithmetization::{AllStark, GenerationInputs, StarkConfig}; use plonky2::{ gates::noop::NoopGate, iop::witness::PartialWitness, plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig}, util::timing::TimingTree, }; -use trace_decoder::types::TxnProofGenIR; use crate::{ proof_types::{AggregatableProof, GeneratedAggProof, GeneratedBlockProof, GeneratedTxnProof}, @@ -44,7 +43,7 @@ impl From for ProofGenError { /// Generates a transaction proof from some IR data. pub fn generate_txn_proof( p_state: &ProverState, - gen_inputs: TxnProofGenIR, + gen_inputs: GenerationInputs, abort_signal: Option>, ) -> ProofGenResult { let (intern, p_vals) = p_state diff --git a/proof_gen/src/proof_types.rs b/proof_gen/src/proof_types.rs index acac783a8..49d3b25f3 100644 --- a/proof_gen/src/proof_types.rs +++ b/proof_gen/src/proof_types.rs @@ -1,9 +1,8 @@ //! This module defines the various proof types used throughout the block proof //! generation process. -use evm_arithmetization::proof::PublicValues; +use evm_arithmetization::{proof::PublicValues, BlockHeight}; use serde::{Deserialize, Serialize}; -use trace_decoder::types::BlockHeight; use crate::types::PlonkyProofIntern; @@ -59,14 +58,14 @@ impl AggregatableProof { } } - pub(crate) fn is_agg(&self) -> bool { + pub(crate) const fn is_agg(&self) -> bool { match self { AggregatableProof::Txn(_) => false, AggregatableProof::Agg(_) => true, } } - pub(crate) fn intern(&self) -> &PlonkyProofIntern { + pub(crate) const fn intern(&self) -> &PlonkyProofIntern { match self { AggregatableProof::Txn(info) => &info.intern, AggregatableProof::Agg(info) => &info.intern, diff --git a/proof_gen/src/prover_state.rs b/proof_gen/src/prover_state.rs index efb3413f4..338cb52c7 100644 --- a/proof_gen/src/prover_state.rs +++ b/proof_gen/src/prover_state.rs @@ -57,7 +57,7 @@ macro_rules! define_set_circuit_size_method { paste! { /// Specifies a range of degrees to be supported for this STARK /// table's associated recursive circuits. - pub fn [](mut self, size: Range) -> Self { + pub const fn [](mut self, size: Range) -> Self { self.[<$name _circuit_size>] = size; self } diff --git a/trace_decoder/Cargo.toml b/trace_decoder/Cargo.toml index 2d4dab80f..bd25704c9 100644 --- a/trace_decoder/Cargo.toml +++ b/trace_decoder/Cargo.toml @@ -2,7 +2,7 @@ name = "trace_decoder" description = "Processes trace payloads into Intermediate Representation (IR) format." authors = ["Polygon Zero "] -version = "0.2.0" +version = "0.3.0" edition.workspace = true license.workspace = true repository.workspace = true @@ -27,8 +27,8 @@ serde_with = "3.4.0" thiserror = { workspace = true } # Local dependencies -mpt_trie = { version = "0.2.0", path = "../mpt_trie" } -evm_arithmetization = { version = "0.1.2", path = "../evm_arithmetization" } +mpt_trie = { version = "0.2.1", path = "../mpt_trie" } +evm_arithmetization = { version = "0.1.3", path = "../evm_arithmetization" } [dev-dependencies] pretty_env_logger = "0.5.0" diff --git a/trace_decoder/src/compact/compact_prestate_processing.rs b/trace_decoder/src/compact/compact_prestate_processing.rs index 59efdd6c5..f44c2b30a 100644 --- a/trace_decoder/src/compact/compact_prestate_processing.rs +++ b/trace_decoder/src/compact/compact_prestate_processing.rs @@ -29,6 +29,8 @@ use crate::{ types::{CodeHash, HashedAccountAddr, TrieRootHash}, }; +/// Result alias for any error that can occur when processing encoded compact +/// prestate. pub type CompactParsingResult = Result; type BranchMask = u32; @@ -46,20 +48,29 @@ const MAX_WITNESS_ENTRIES_NEEDED_TO_MATCH_A_RULE: usize = 3; const BRANCH_MAX_CHILDREN: usize = 16; const CURSOR_ERROR_BYTES_MAX_LEN: usize = 10; +/// An error from processing Erigon's compact witness format. #[derive(Debug, Error)] pub enum CompactParsingError { + /// The header in the compact payload was missing. This is just a single + /// byte that is used for versioning. #[error("Missing header")] MissingHeader, + /// Encountered a byte representing an opcode that does not represent any + /// known opcode #[error("Invalid opcode operator (\"{0:x}\")")] - InvalidOperator(u8), + InvalidOpcode(u8), + /// Encountered the end of the byte stream when we were still expecting more + /// data. #[error("Reached the end of the byte stream when we still expected more data")] UnexpectedEndOfStream, + /// Failed to decode a byte vector from CBOR. #[error("Unable to parse an expected byte vector (field name: {0}) (error: {1}). Cursor error info: {2}")] InvalidByteVector(&'static str, String, CursorBytesErrorInfo), + /// Failed to decode a given type from CBOR. #[error( "Unable to parse the type \"{0}\" (field name: {1}) from bytes {2}. Cursor error info: {3} (err: {4})" )] @@ -71,32 +82,48 @@ pub enum CompactParsingError { String, ), + /// Encountered a sequence of instructions of nodes that should not be able + /// to occur. #[error("Invalid block witness entries: {0:?}")] InvalidWitnessFormat(Vec), + /// Multiple entries were remaining after we were unable to apply any more + /// rules. There should always only be one remaining entry after we can not + /// apply any more rules. #[error("There were multiple entries remaining after the compact block witness was processed (Remaining entries: {0:#?})")] NonSingleEntryAfterProcessing(WitnessEntries), + /// A branch was found that had an unexpected number of child nodes trailing + /// it than expected. #[error("Branch mask {0:#b} stated there should be {1} preceding nodes but instead found {2} (nodes: {3:?})")] IncorrectNumberOfNodesPrecedingBranch(BranchMask, usize, usize, Vec), + /// Found a branch that had claimed to have `n` children but instead had a + /// different amount. #[error( "Expected a branch to have {0} preceding nodes but only had {1} (mask: {2}, nodes: {3:?})" )] MissingExpectedNodesPrecedingBranch(usize, usize, BranchMask, Vec), + /// Expected a preceding node to be of a given type but instead found one of + /// a different type. + #[error("Expected the entry preceding {0} positions behind a {1} entry to be a node of type but instead found a {2} node. (nodes: {3:?})")] + UnexpectedPrecedingNodeFoundWhenProcessingRule(usize, &'static str, String, Vec), + + /// Expected a compact node type that should not be present in the given + /// type of trie. #[error("Found an unexpected compact node type ({0:?}) during processing compact into a `mpt_trie` {1} partial trie.")] UnexpectedNodeForTrieType(UnexpectedCompactNodeType, TrieType), - #[error("Expected the entry preceding {0} positions behind a {1} entry to be a node but instead found a {2}. (nodes: {3:?})")] - PrecedingNonNodeEntryFoundWhenProcessingRule(usize, &'static str, String, Vec), - + // TODO: No constructors for this, but I think there should be one in + // [`key_bytes_to_nibbles`]... + /// Error when constructing a key from bytes. #[error("Unable to create key nibbles from bytes {0}")] KeyError(#[from] FromHexPrefixError), } #[derive(Debug)] -pub struct CursorBytesErrorInfo { +pub(crate) struct CursorBytesErrorInfo { error_start_pos: usize, bad_bytes_hex: String, } @@ -141,7 +168,7 @@ enum Opcode { } #[derive(Clone, Debug, EnumAsInner)] -pub enum WitnessEntry { +pub(crate) enum WitnessEntry { Instruction(Instruction), Node(NodeEntry), } @@ -258,7 +285,7 @@ pub(super) struct AccountNodeData { } impl AccountNodeData { - fn new( + const fn new( nonce: Nonce, balance: Balance, storage_trie: Option, @@ -285,16 +312,16 @@ impl Display for Header { } impl Header { - pub(crate) fn version_is_compatible(&self, target_ver: u8) -> bool { + pub(crate) const fn version_is_compatible(&self, target_ver: u8) -> bool { self.version == target_ver } } -#[derive(Debug)] -pub(crate) struct WitnessOutput { - pub(crate) tries: PartialTriePreImages, - pub(crate) code: Option>>, -} +// #[derive(Debug)] +// pub struct CompactWitnessDecodingOutput { +// pub tries: PartialTriePreImages, +// pub code: Option>>, +// } #[derive(Debug)] struct ParserState { @@ -325,7 +352,7 @@ impl ParserState { Ok((header, p_state)) } - fn parse(mut self) -> CompactParsingResult { + fn parse(mut self) -> CompactParsingResult { let mut entry_buf = Vec::new(); loop { @@ -346,15 +373,7 @@ impl ParserState { )), }?; - let tries = PartialTriePreImages { - state: res.trie, - storage: res.storage_tries, - }; - - // Replace with a none if there are no entries. - let code = (!res.code.is_empty()).then_some(res.code); - - Ok(WitnessOutput { tries, code }) + Ok(res) } fn apply_rules_to_witness_entries( @@ -384,10 +403,6 @@ impl ParserState { ) -> CompactParsingResult { traverser.get_next_n_elems_into_buf(MAX_WITNESS_ENTRIES_NEEDED_TO_MATCH_A_RULE, buf); - // TODO: There is a decent amount of code duplication with the matches and the - // calls to `invalid_witness_err`. We should condense this... - - // TODO: These clones are really bad, but we will clean this up once it works. match buf[0].clone() { WitnessEntry::Instruction(Instruction::EmptyRoot) => { Self::traverser_replace_prev_n_nodes_entry_helper(1, traverser, NodeEntry::Empty) @@ -399,13 +414,13 @@ impl ParserState { Self::traverser_replace_prev_n_nodes_entry_helper( 1, traverser, - NodeEntry::Leaf(k, LeafNodeData::Value(v.clone().into())), + NodeEntry::Leaf(k, LeafNodeData::Value(v.into())), ) } WitnessEntry::Instruction(Instruction::Extension(k)) => { traverser.get_prev_n_elems_into_buf(1, buf); - match buf[0].clone() { + match &buf[0] { WitnessEntry::Node(node) => Self::traverser_replace_prev_n_nodes_entry_helper( 2, traverser, @@ -415,11 +430,7 @@ impl ParserState { } } WitnessEntry::Instruction(Instruction::Code(c)) => { - Self::traverser_replace_prev_n_nodes_entry_helper( - 1, - traverser, - NodeEntry::Code(c.clone()), - ) + Self::traverser_replace_prev_n_nodes_entry_helper(1, traverser, NodeEntry::Code(c)) } WitnessEntry::Instruction(Instruction::AccountLeaf(k, n, b, has_code, has_storage)) => { let (n_nodes_to_replace, account_node_code, s_trie) = match (has_code, has_storage) @@ -484,7 +495,7 @@ impl ParserState { let n_entries_behind_cursor = number_available_preceding_elems - curr_traverser_node_idx; - CompactParsingError::PrecedingNonNodeEntryFoundWhenProcessingRule( + CompactParsingError::UnexpectedPrecedingNodeFoundWhenProcessingRule( n_entries_behind_cursor, "Branch", entry_to_check.to_string(), @@ -516,14 +527,14 @@ impl ParserState { } // ... Because we can't do `[None; 16]` without implementing `Copy`. - fn create_empty_branch_node_entry() -> [Option>; 16] { + const fn create_empty_branch_node_entry() -> [Option>; 16] { [ None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, ] } - fn match_account_leaf_no_code_and_no_storage( + const fn match_account_leaf_no_code_and_no_storage( ) -> CompactParsingResult<(usize, Option, Option)> { Ok((1, None, None)) } @@ -722,7 +733,7 @@ impl WitnessBytes { let opcode_byte = self.byte_cursor.read_byte()?; let opcode = - Opcode::n(opcode_byte).ok_or(CompactParsingError::InvalidOperator(opcode_byte))?; + Opcode::n(opcode_byte).ok_or(CompactParsingError::InvalidOpcode(opcode_byte))?; trace!("Processed \"{:?}\" opcode", opcode); @@ -1203,7 +1214,7 @@ impl<'a> CollapsableWitnessEntryTraverser<'a> { } } -fn try_get_node_entry_from_witness_entry(entry: &WitnessEntry) -> Option<&NodeEntry> { +const fn try_get_node_entry_from_witness_entry(entry: &WitnessEntry) -> Option<&NodeEntry> { match entry { WitnessEntry::Node(n_entry) => Some(n_entry), _ => None, @@ -1219,24 +1230,38 @@ enum TraverserDirection { #[derive(Debug, Default)] pub(crate) struct PartialTriePreImages { - pub(crate) state: HashedPartialTrie, - pub(crate) storage: HashMap, + pub state: HashedPartialTrie, + pub storage: HashMap, } +/// The output we get from processing prestate compact into the trie format of +/// `mpt_trie`. +/// +/// Note that this format contains storage tries embedded within the state trie, +/// so there may be multiple tries inside this output. Also note that the +/// bytecode (instead of just the code hash) may be embedded directly in this +/// format. #[derive(Debug)] -pub(crate) struct ProcessedCompactOutput { - pub(crate) header: Header, - pub(crate) witness_out: WitnessOutput, +pub struct ProcessedCompactOutput { + /// The header of the compact. + pub header: Header, + + /// The actual processed `mpt_trie` tries and additional code hash mappings + /// from the compact. + pub witness_out: StateTrieExtractionOutput, } -pub(crate) fn process_compact_prestate( +/// Processes the compact prestate into the trie format of `mpt_trie`. +pub fn process_compact_prestate( state: TrieCompact, ) -> CompactParsingResult { process_compact_prestate_common(state, ParserState::create_and_extract_header) } +/// Processes the compact prestate into the trie format of `mpt_trie`. Also +/// enables heavy debug traces during processing. // TODO: Move behind a feature flag... -pub(crate) fn process_compact_prestate_debug( +pub fn process_compact_prestate_debug( state: TrieCompact, ) -> CompactParsingResult { process_compact_prestate_common(state, ParserState::create_and_extract_header_debug) diff --git a/trace_decoder/src/compact/compact_to_partial_trie.rs b/trace_decoder/src/compact/compact_to_partial_trie.rs index ec6c77b34..d7fac0644 100644 --- a/trace_decoder/src/compact/compact_to_partial_trie.rs +++ b/trace_decoder/src/compact/compact_to_partial_trie.rs @@ -104,10 +104,16 @@ pub(super) enum UnexpectedCompactNodeType { /// Output from constructing a state trie from compact. #[derive(Debug, Default)] -pub(super) struct StateTrieExtractionOutput { - pub(super) trie: HashedPartialTrie, - pub(super) code: HashMap>, - pub(super) storage_tries: HashMap, +pub struct StateTrieExtractionOutput { + /// The state trie of the compact. + pub state_trie: HashedPartialTrie, + + /// Any embedded contract bytecode that appears in the compact will be + /// present here. + pub code: HashMap>, + + /// All storage tries present in the compact. + pub storage_tries: HashMap, } impl CompactToPartialTrieExtractionOutput for StateTrieExtractionOutput { @@ -125,7 +131,7 @@ impl CompactToPartialTrieExtractionOutput for StateTrieExtractionOutput { leaf_node_data: &LeafNodeData, ) -> CompactParsingResult<()> { process_leaf_common( - &mut self.trie, + &mut self.state_trie, curr_key, leaf_key, leaf_node_data, @@ -140,7 +146,7 @@ impl CompactToPartialTrieExtractionOutput for StateTrieExtractionOutput { ) } fn trie(&mut self) -> &mut HashedPartialTrie { - &mut self.trie + &mut self.state_trie } } diff --git a/trace_decoder/src/compact/complex_test_payloads.rs b/trace_decoder/src/compact/complex_test_payloads.rs index 89febd736..2f1f4bd32 100644 --- a/trace_decoder/src/compact/complex_test_payloads.rs +++ b/trace_decoder/src/compact/complex_test_payloads.rs @@ -1,9 +1,12 @@ use evm_arithmetization::generation::mpt::AccountRlp; use mpt_trie::partial_trie::PartialTrie; -use super::compact_prestate_processing::{ - process_compact_prestate, process_compact_prestate_debug, CompactParsingResult, - PartialTriePreImages, ProcessedCompactOutput, +use super::{ + compact_prestate_processing::{ + process_compact_prestate, process_compact_prestate_debug, CompactParsingResult, + PartialTriePreImages, ProcessedCompactOutput, + }, + compact_to_partial_trie::StateTrieExtractionOutput, }; use crate::{ trace_protocol::TrieCompact, @@ -56,23 +59,23 @@ impl TestProtocolInputAndRoot { Ok(x) => x, Err(err) => panic!("{}", err.to_string()), }; - let trie_hash = out.witness_out.tries.state.hash(); + let trie_hash = out.witness_out.state_trie.hash(); - print_value_and_hash_nodes_of_trie(&out.witness_out.tries.state); + print_value_and_hash_nodes_of_trie(&out.witness_out.state_trie); - for (hashed_addr, s_trie) in out.witness_out.tries.storage.iter() { + for (hashed_addr, s_trie) in out.witness_out.storage_tries.iter() { print_value_and_hash_nodes_of_storage_trie(hashed_addr, s_trie); } assert!(out.header.version_is_compatible(1)); assert_eq!(trie_hash, expected_hash); - Self::assert_non_all_storage_roots_exist_in_storage_trie_map(&out.witness_out.tries); + Self::assert_non_all_storage_roots_exist_in_storage_trie_map(&out.witness_out); } - fn assert_non_all_storage_roots_exist_in_storage_trie_map(images: &PartialTriePreImages) { - let non_empty_account_s_roots = images - .state + fn assert_non_all_storage_roots_exist_in_storage_trie_map(out: &StateTrieExtractionOutput) { + let non_empty_account_s_roots = out + .state_trie .items() .filter_map(|(addr, data)| { data.as_val().map(|data| { @@ -86,7 +89,7 @@ impl TestProtocolInputAndRoot { .map(|(addr, _)| addr); for account_with_non_empty_root in non_empty_account_s_roots { - assert!(images.storage.contains_key(&account_with_non_empty_root)); + assert!(out.storage_tries.contains_key(&account_with_non_empty_root)); } } } diff --git a/trace_decoder/src/compact/mod.rs b/trace_decoder/src/compact/mod.rs index 4fe23ab33..a07930735 100644 --- a/trace_decoder/src/compact/mod.rs +++ b/trace_decoder/src/compact/mod.rs @@ -1,5 +1,5 @@ -pub(crate) mod compact_prestate_processing; -mod compact_to_partial_trie; +pub mod compact_prestate_processing; +pub mod compact_to_partial_trie; #[cfg(test)] pub(crate) mod complex_test_payloads; diff --git a/trace_decoder/src/decoding.rs b/trace_decoder/src/decoding.rs index b697fcaac..c0128bb54 100644 --- a/trace_decoder/src/decoding.rs +++ b/trace_decoder/src/decoding.rs @@ -4,7 +4,7 @@ use std::{ iter::{self, empty, once}, }; -use ethereum_types::{Address, H256, U256}; +use ethereum_types::{Address, H256, U256, U512}; use evm_arithmetization::{ generation::{mpt::AccountRlp, GenerationInputs, TrieInputs}, proof::{ExtraBlockData, TrieRoots}, @@ -14,28 +14,133 @@ use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, Node, PartialTrie}, special_query::path_for_query, + trie_ops::TrieOpError, trie_subsets::{create_trie_subset, SubsetTrieError}, utils::{IntoTrieKey, TriePath, TrieSegment}, }; use thiserror::Error; use crate::{ - processed_block_trace::{NodesUsedByTxn, ProcessedBlockTrace, StateTrieWrites, TxnMetaState}, + processed_block_trace::{ + NodesUsedByTxn, ProcessedBlockTrace, ProcessedTxnInfo, StateTrieWrites, TxnMetaState, + }, types::{ HashedAccountAddr, HashedNodeAddr, HashedStorageAddr, HashedStorageAddrNibbles, - OtherBlockData, TriePathIter, TrieRootHash, TxnIdx, TxnProofGenIR, - EMPTY_ACCOUNT_BYTES_RLPED, ZERO_STORAGE_SLOT_VAL_RLPED, + OtherBlockData, TriePathIter, TrieRootHash, TxnIdx, EMPTY_ACCOUNT_BYTES_RLPED, + ZERO_STORAGE_SLOT_VAL_RLPED, }, - utils::{hash, update_val_if_some}, + utils::{hash, optional_field, optional_field_hex, update_val_if_some}, }; /// Stores the result of parsing tries. Returns a [TraceParsingError] upon /// failure. -pub type TraceParsingResult = Result; +pub type TraceParsingResult = Result>; + +/// Represents errors that can occur during the processing of a block trace. +/// +/// This struct is intended to encapsulate various kinds of errors that might +/// arise when parsing, validating, or otherwise processing the trace data of +/// blockchain blocks. It could include issues like malformed trace data, +/// inconsistencies found during processing, or any other condition that +/// prevents successful completion of the trace processing task. +#[derive(Debug)] +pub struct TraceParsingError { + block_num: Option, + block_chain_id: Option, + txn_idx: Option, + addr: Option
, + h_addr: Option, + slot: Option, + slot_value: Option, + reason: TraceParsingErrorReason, // The original error type +} + +impl std::fmt::Display for TraceParsingError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let h_slot = self.slot.map(|slot| { + let mut buf = [0u8; 64]; + slot.to_big_endian(&mut buf); + hash(&buf) + }); + write!( + f, + "Error processing trace: {}\n{}{}{}{}{}{}{}{}", + self.reason, + optional_field("Block num", self.block_num), + optional_field("Block chain id", self.block_chain_id), + optional_field("Txn idx", self.txn_idx), + optional_field("Address", self.addr.as_ref()), + optional_field("Hashed address", self.h_addr.as_ref()), + optional_field_hex("Slot", self.slot), + optional_field("Hashed Slot", h_slot), + optional_field_hex("Slot value", self.slot_value), + ) + } +} + +impl std::error::Error for TraceParsingError {} + +impl TraceParsingError { + /// Function to create a new TraceParsingError with mandatory fields + pub(crate) fn new(reason: TraceParsingErrorReason) -> Self { + Self { + block_num: None, + block_chain_id: None, + txn_idx: None, + addr: None, + h_addr: None, + slot: None, + slot_value: None, + reason, + } + } + + /// Builder method to set block_num + pub(crate) fn block_num(&mut self, block_num: U256) -> &mut Self { + self.block_num = Some(block_num); + self + } + + /// Builder method to set block_chain_id + pub(crate) fn block_chain_id(&mut self, block_chain_id: U256) -> &mut Self { + self.block_chain_id = Some(block_chain_id); + self + } + + /// Builder method to set txn_idx + pub fn txn_idx(&mut self, txn_idx: usize) -> &mut Self { + self.txn_idx = Some(txn_idx); + self + } + + /// Builder method to set addr + pub fn addr(&mut self, addr: Address) -> &mut Self { + self.addr = Some(addr); + self + } -/// An error type for trie parsing. + /// Builder method to set h_addr + pub fn h_addr(&mut self, h_addr: H256) -> &mut Self { + self.h_addr = Some(h_addr); + self + } + + /// Builder method to set slot + pub fn slot(&mut self, slot: U512) -> &mut Self { + self.slot = Some(slot); + self + } + + /// Builder method to set slot_value + pub fn slot_value(&mut self, slot_value: U512) -> &mut Self { + self.slot_value = Some(slot_value); + self + } +} + +/// An error reason for trie parsing. #[derive(Debug, Error)] -pub enum TraceParsingError { +pub enum TraceParsingErrorReason { /// Failure to decode an Ethereum [Account]. #[error("Failed to decode RLP bytes ({0}) as an Ethereum account due to the error: {1}")] AccountDecode(String, String), @@ -56,6 +161,17 @@ pub enum TraceParsingError { /// Failure due to trying to withdraw from a missing account #[error("No account present at {0:x} (hashed: {1:x}) to withdraw {2} Gwei from!")] MissingWithdrawalAccount(Address, HashedAccountAddr, U256), + + /// Failure due to a trie operation error. + #[error("Trie operation error: {0}")] + TrieOpError(TrieOpError), +} + +impl From for TraceParsingError { + fn from(err: TrieOpError) -> Self { + // Convert TrieOpError into TraceParsingError + TraceParsingError::new(TraceParsingErrorReason::TrieOpError(err)) + } } /// An enum to cover all Ethereum trie types (see https://ethereum.github.io/yellowpaper/paper.pdf for details). @@ -105,7 +221,7 @@ impl ProcessedBlockTrace { pub(crate) fn into_txn_proof_gen_ir( self, other_data: OtherBlockData, - ) -> TraceParsingResult> { + ) -> TraceParsingResult> { let mut curr_block_tries = PartialTrieState { state: self.tries.state.clone(), storage: self.tries.storage.clone(), @@ -135,70 +251,24 @@ impl ProcessedBlockTrace { .into_iter() .enumerate() .map(|(txn_idx, txn_info)| { - trace!("Generating proof IR for txn {}...", txn_idx); - - Self::init_any_needed_empty_storage_tries( - &mut curr_block_tries.storage, - txn_info - .nodes_used_by_txn - .storage_accesses - .iter() - .map(|(k, _)| k), - &txn_info - .nodes_used_by_txn - .state_accounts_with_no_accesses_but_storage_tries, - ); - // For each non-dummy txn, we increment `txn_number_after` by 1, and - // update `gas_used_after` accordingly. - extra_data.txn_number_after += U256::one(); - extra_data.gas_used_after += txn_info.meta.gas_used.into(); - - // Because we need to run delta application before creating the minimal - // sub-tries (we need to detect if deletes collapsed any branches), we need to - // do this clone every iteration. - let tries_at_start_of_txn = curr_block_tries.clone(); - - Self::update_txn_and_receipt_tries(&mut curr_block_tries, &txn_info.meta, txn_idx); - - let delta_out = Self::apply_deltas_to_trie_state( - &mut curr_block_tries, - &txn_info.nodes_used_by_txn, - &txn_info.meta, - )?; - - let tries = Self::create_minimal_partial_tries_needed_by_txn( - &tries_at_start_of_txn, - &txn_info.nodes_used_by_txn, + Self::process_txn_info( txn_idx, - delta_out, - &other_data.b_data.b_meta.block_beneficiary, - )?; - - let trie_roots_after = calculate_trie_input_hashes(&curr_block_tries); - let gen_inputs = GenerationInputs { - txn_number_before: extra_data.txn_number_before, - gas_used_before: extra_data.gas_used_before, - gas_used_after: extra_data.gas_used_after, - signed_txn: txn_info.meta.txn_bytes, - withdrawals: Vec::default(), /* Only ever set in a dummy txn at the end of - * the block (see `[add_withdrawals_to_txns]` - * for more info). */ - tries, - trie_roots_after, - checkpoint_state_trie_root: extra_data.checkpoint_state_trie_root, - contract_code: txn_info.contract_code_accessed, - block_metadata: other_data.b_data.b_meta.clone(), - block_hashes: other_data.b_data.b_hashes.clone(), - }; - - // After processing a transaction, we update the remaining accumulators - // for the next transaction. - extra_data.txn_number_before += U256::one(); - extra_data.gas_used_before = extra_data.gas_used_after; - - Ok(gen_inputs) + txn_info, + &mut curr_block_tries, + &mut extra_data, + &other_data, + ) + .map_err(|mut e| { + e.txn_idx(txn_idx); + e + }) }) - .collect::>>()?; + .collect::>>() + .map_err(|mut e| { + e.block_num(other_data.b_data.b_meta.block_number); + e.block_chain_id(other_data.b_data.b_meta.block_chain_id); + e + })?; let dummies_added = Self::pad_gen_inputs_with_dummy_inputs_if_needed( &mut txn_gen_inputs, @@ -213,11 +283,8 @@ impl ProcessedBlockTrace { if !self.withdrawals.is_empty() { Self::add_withdrawals_to_txns( &mut txn_gen_inputs, - &other_data, - &extra_data, &mut curr_block_tries, self.withdrawals, - dummies_added, )?; } @@ -306,9 +373,15 @@ impl ProcessedBlockTrace { let mut out = TrieDeltaApplicationOutput::default(); for (hashed_acc_addr, storage_writes) in deltas.storage_writes.iter() { - let mut storage_trie = trie_state.storage.get_mut(hashed_acc_addr).ok_or( - TraceParsingError::MissingAccountStorageTrie(*hashed_acc_addr), - )?; + let mut storage_trie = + trie_state.storage.get_mut(hashed_acc_addr).ok_or_else(|| { + let hashed_acc_addr = *hashed_acc_addr; + let mut e = TraceParsingError::new( + TraceParsingErrorReason::MissingAccountStorageTrie(hashed_acc_addr), + ); + e.h_addr(hashed_acc_addr); + e + })?; for (slot, val) in storage_writes .iter() @@ -316,7 +389,13 @@ impl ProcessedBlockTrace { { // If we are writing a zero, then we actually need to perform a delete. match val == &ZERO_STORAGE_SLOT_VAL_RLPED { - false => storage_trie.insert(slot, val.clone()), + false => storage_trie.insert(slot, val.clone()).map_err(|err| { + let mut e = + TraceParsingError::new(TraceParsingErrorReason::TrieOpError(err)); + e.slot(U512::from_big_endian(slot.bytes_be().as_slice())); + e.slot_value(U512::from_big_endian(val.as_slice())); + e + })?, true => { if let Some(remaining_slot_key) = Self::delete_node_and_report_remaining_key_if_branch_collapsed( @@ -361,10 +440,14 @@ impl ProcessedBlockTrace { for hashed_addr in deltas.self_destructed_accounts.iter() { let k = Nibbles::from_h256_be(*hashed_addr); - trie_state - .storage - .remove(hashed_addr) - .ok_or(TraceParsingError::MissingAccountStorageTrie(*hashed_addr))?; + trie_state.storage.remove(hashed_addr).ok_or_else(|| { + let hashed_addr = *hashed_addr; + let mut e = TraceParsingError::new( + TraceParsingErrorReason::MissingAccountStorageTrie(hashed_addr), + ); + e.h_addr(hashed_addr); + e + })?; // TODO: Once the mechanism for resolving code hashes settles, we probably want // to also delete the code hash mapping here as well... @@ -437,7 +520,7 @@ impl ProcessedBlockTrace { /// `[add_withdrawals_to_txns]`), where the final one will mutate the /// state trie. fn pad_gen_inputs_with_dummy_inputs_if_needed( - gen_inputs: &mut Vec, + gen_inputs: &mut Vec, other_data: &OtherBlockData, final_extra_data: &ExtraBlockData, initial_extra_data: &ExtraBlockData, @@ -492,64 +575,27 @@ impl ProcessedBlockTrace { /// - If no dummy proofs are already present, then a dummy proof that just /// contains the withdrawals is appended to the end of the IR vec. fn add_withdrawals_to_txns( - txn_ir: &mut Vec, - other_data: &OtherBlockData, - extra_data: &ExtraBlockData, + txn_ir: &mut [GenerationInputs], final_trie_state: &mut PartialTrieState, withdrawals: Vec<(Address, U256)>, - dummies_already_added: bool, ) -> TraceParsingResult<()> { - let withdrawals_with_hashed_addrs_iter = withdrawals - .iter() - .map(|(addr, v)| (*addr, hash(addr.as_bytes()), *v)); - - match dummies_already_added { - // If we have no actual dummy proofs, then we create one and append it to the - // end of the block. - false => { - // TODO: Decide if we want this allocation... - // To avoid double hashing the addrs, but I don't know if the extra `Vec` - // allocation is worth it. - let withdrawals_with_hashed_addrs: Vec<_> = - withdrawals_with_hashed_addrs_iter.collect(); - - // Dummy state will be the state after the final txn. Also need to include the - // account nodes that were accessed by the withdrawals. - let withdrawal_addrs = withdrawals_with_hashed_addrs - .iter() - .cloned() - .map(|(_, h_addr, _)| h_addr); - let mut withdrawal_dummy = create_dummy_gen_input_with_state_addrs_accessed( - other_data, - extra_data, - final_trie_state, - withdrawal_addrs, - )?; - - Self::update_trie_state_from_withdrawals( - withdrawals_with_hashed_addrs, - &mut final_trie_state.state, - )?; + let withdrawals_with_hashed_addrs_iter = || { + withdrawals + .iter() + .map(|(addr, v)| (*addr, hash(addr.as_bytes()), *v)) + }; - withdrawal_dummy.withdrawals = withdrawals; + Self::update_trie_state_from_withdrawals( + withdrawals_with_hashed_addrs_iter(), + &mut final_trie_state.state, + )?; - // Only the state root hash needs to be updated from the withdrawals. - withdrawal_dummy.trie_roots_after.state_root = final_trie_state.state.hash(); + let last_inputs = txn_ir + .last_mut() + .expect("We cannot have an empty list of payloads."); - txn_ir.push(withdrawal_dummy); - } - true => { - Self::update_trie_state_from_withdrawals( - withdrawals_with_hashed_addrs_iter, - &mut final_trie_state.state, - )?; - - // If we have dummy proofs (note: `txn_ir[1]` is always a dummy txn in this - // case), then this dummy will get the withdrawals. - txn_ir[1].withdrawals = withdrawals; - txn_ir[1].trie_roots_after.state_root = final_trie_state.state.hash(); - } - } + last_inputs.withdrawals = withdrawals; + last_inputs.trie_roots_after.state_root = final_trie_state.state.hash(); Ok(()) } @@ -563,12 +609,14 @@ impl ProcessedBlockTrace { for (addr, h_addr, amt) in withdrawals { let h_addr_nibs = Nibbles::from_h256_be(h_addr); - let acc_bytes = - state - .get(h_addr_nibs) - .ok_or(TraceParsingError::MissingWithdrawalAccount( - addr, h_addr, amt, - ))?; + let acc_bytes = state.get(h_addr_nibs).ok_or_else(|| { + let mut e = TraceParsingError::new( + TraceParsingErrorReason::MissingWithdrawalAccount(addr, h_addr, amt), + ); + e.addr(addr); + e.h_addr(h_addr); + e + })?; let mut acc_data = account_from_rlped_bytes(acc_bytes)?; acc_data.balance += amt; @@ -578,6 +626,78 @@ impl ProcessedBlockTrace { Ok(()) } + + /// Processes a single transaction in the trace. + fn process_txn_info( + txn_idx: usize, + txn_info: ProcessedTxnInfo, + curr_block_tries: &mut PartialTrieState, + extra_data: &mut ExtraBlockData, + other_data: &OtherBlockData, + ) -> TraceParsingResult { + trace!("Generating proof IR for txn {}...", txn_idx); + + Self::init_any_needed_empty_storage_tries( + &mut curr_block_tries.storage, + txn_info + .nodes_used_by_txn + .storage_accesses + .iter() + .map(|(k, _)| k), + &txn_info + .nodes_used_by_txn + .state_accounts_with_no_accesses_but_storage_tries, + ); + // For each non-dummy txn, we increment `txn_number_after` by 1, and + // update `gas_used_after` accordingly. + extra_data.txn_number_after += U256::one(); + extra_data.gas_used_after += txn_info.meta.gas_used.into(); + + // Because we need to run delta application before creating the minimal + // sub-tries (we need to detect if deletes collapsed any branches), we need to + // do this clone every iteration. + let tries_at_start_of_txn = curr_block_tries.clone(); + + Self::update_txn_and_receipt_tries(curr_block_tries, &txn_info.meta, txn_idx); + + let delta_out = Self::apply_deltas_to_trie_state( + curr_block_tries, + &txn_info.nodes_used_by_txn, + &txn_info.meta, + )?; + + let tries = Self::create_minimal_partial_tries_needed_by_txn( + &tries_at_start_of_txn, + &txn_info.nodes_used_by_txn, + txn_idx, + delta_out, + &other_data.b_data.b_meta.block_beneficiary, + )?; + + let trie_roots_after = calculate_trie_input_hashes(curr_block_tries); + let gen_inputs = GenerationInputs { + txn_number_before: extra_data.txn_number_before, + gas_used_before: extra_data.gas_used_before, + gas_used_after: extra_data.gas_used_after, + signed_txn: txn_info.meta.txn_bytes, + withdrawals: Vec::default(), /* Only ever set in a dummy txn at the end of + * the block (see `[add_withdrawals_to_txns]` + * for more info). */ + tries, + trie_roots_after, + checkpoint_state_trie_root: extra_data.checkpoint_state_trie_root, + contract_code: txn_info.contract_code_accessed, + block_metadata: other_data.b_data.b_meta.clone(), + block_hashes: other_data.b_data.b_hashes.clone(), + }; + + // After processing a transaction, we update the remaining accumulators + // for the next transaction. + extra_data.txn_number_before += U256::one(); + extra_data.gas_used_before = extra_data.gas_used_after; + + Ok(gen_inputs) + } } impl StateTrieWrites { @@ -590,9 +710,14 @@ impl StateTrieWrites { let storage_root_hash_change = match self.storage_trie_change { false => None, true => { - let storage_trie = acc_storage_tries - .get(h_addr) - .ok_or(TraceParsingError::MissingAccountStorageTrie(*h_addr))?; + let storage_trie = acc_storage_tries.get(h_addr).ok_or_else(|| { + let h_addr = *h_addr; + let mut e = TraceParsingError::new( + TraceParsingErrorReason::MissingAccountStorageTrie(h_addr), + ); + e.h_addr(h_addr); + e + })?; Some(storage_trie.hash()) } @@ -626,7 +751,7 @@ fn create_dummy_txn_pair_for_empty_block( other_data: &OtherBlockData, extra_data: &ExtraBlockData, final_tries: &PartialTrieState, -) -> [TxnProofGenIR; 2] { +) -> [GenerationInputs; 2] { [ create_dummy_gen_input(other_data, extra_data, final_tries), create_dummy_gen_input(other_data, extra_data, final_tries), @@ -637,7 +762,7 @@ fn create_dummy_gen_input( other_data: &OtherBlockData, extra_data: &ExtraBlockData, final_tries: &PartialTrieState, -) -> TxnProofGenIR { +) -> GenerationInputs { let sub_tries = create_dummy_proof_trie_inputs( final_tries, create_fully_hashed_out_sub_partial_trie(&final_tries.state), @@ -650,7 +775,7 @@ fn create_dummy_gen_input_with_state_addrs_accessed( extra_data: &ExtraBlockData, final_tries: &PartialTrieState, account_addrs_accessed: impl Iterator, -) -> TraceParsingResult { +) -> TraceParsingResult { let sub_tries = create_dummy_proof_trie_inputs( final_tries, create_minimal_state_partial_trie( @@ -784,13 +909,18 @@ fn create_trie_subset_wrapped( SubsetTrieError::UnexpectedKey(key, _) => key, }; - TraceParsingError::MissingKeysCreatingSubPartialTrie(key, trie_type) + Box::new(TraceParsingError::new( + TraceParsingErrorReason::MissingKeysCreatingSubPartialTrie(key, trie_type), + )) }) } fn account_from_rlped_bytes(bytes: &[u8]) -> TraceParsingResult { - rlp::decode(bytes) - .map_err(|err| TraceParsingError::AccountDecode(hex::encode(bytes), err.to_string())) + rlp::decode(bytes).map_err(|err| { + Box::new(TraceParsingError::new( + TraceParsingErrorReason::AccountDecode(hex::encode(bytes), err.to_string()), + )) + }) } impl TxnMetaState { diff --git a/trace_decoder/src/lib.rs b/trace_decoder/src/lib.rs index e52948c9f..90eea0844 100644 --- a/trace_decoder/src/lib.rs +++ b/trace_decoder/src/lib.rs @@ -80,7 +80,7 @@ //! p_meta: &ProcessingMeta, //! // Extra data needed for proof generation. //! other_data: OtherBlockData, -//! ) -> TraceParsingResult> +//! ) -> TraceParsingResult> //! ``` //! //! It first preprocesses the [BlockTrace] to provide transaction, diff --git a/trace_decoder/src/processed_block_trace.rs b/trace_decoder/src/processed_block_trace.rs index 31e1613cc..ab0ec85c2 100644 --- a/trace_decoder/src/processed_block_trace.rs +++ b/trace_decoder/src/processed_block_trace.rs @@ -4,11 +4,12 @@ use std::iter::once; use ethereum_types::{Address, H256, U256}; use evm_arithmetization::generation::mpt::{AccountRlp, LegacyReceiptRlp}; +use evm_arithmetization::GenerationInputs; use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use crate::compact::compact_prestate_processing::{ - process_compact_prestate_debug, PartialTriePreImages, + process_compact_prestate_debug, PartialTriePreImages, ProcessedCompactOutput, }; use crate::decoding::TraceParsingResult; use crate::trace_protocol::{ @@ -18,8 +19,7 @@ use crate::trace_protocol::{ }; use crate::types::{ CodeHash, CodeHashResolveFunc, HashedAccountAddr, HashedNodeAddr, HashedStorageAddr, - HashedStorageAddrNibbles, OtherBlockData, TrieRootHash, TxnProofGenIR, EMPTY_CODE_HASH, - EMPTY_TRIE_HASH, + HashedStorageAddrNibbles, OtherBlockData, TrieRootHash, EMPTY_CODE_HASH, EMPTY_TRIE_HASH, }; use crate::utils::{ h_addr_nibs_to_h256, hash, print_value_and_hash_nodes_of_storage_trie, @@ -42,7 +42,7 @@ impl BlockTrace { self, p_meta: &ProcessingMeta, other_data: OtherBlockData, - ) -> TraceParsingResult> + ) -> TraceParsingResult> where F: CodeHashResolveFunc, { @@ -109,6 +109,21 @@ struct ProcessedBlockTracePreImages { extra_code_hash_mappings: Option>>, } +impl From for ProcessedBlockTracePreImages { + fn from(v: ProcessedCompactOutput) -> Self { + let tries = PartialTriePreImages { + state: v.witness_out.state_trie, + storage: v.witness_out.storage_tries, + }; + + Self { + tries, + extra_code_hash_mappings: (!v.witness_out.code.is_empty()) + .then_some(v.witness_out.code), + } + } +} + fn process_block_trace_trie_pre_images( block_trace_pre_images: BlockTraceTriePreImages, ) -> ProcessedBlockTracePreImages { @@ -169,10 +184,7 @@ fn process_compact_trie(trie: TrieCompact) -> ProcessedBlockTracePreImages { // TODO: Make this into a result... assert!(out.header.version_is_compatible(COMPATIBLE_HEADER_VERSION)); - ProcessedBlockTracePreImages { - tries: out.witness_out.tries, - extra_code_hash_mappings: out.witness_out.code, - } + out.into() } /// Structure storing a function turning a `CodeHash` into bytes. @@ -190,7 +202,7 @@ where { /// Returns a `ProcessingMeta` given the provided code hash resolving /// function. - pub fn new(resolve_code_hash_fn: F) -> Self { + pub const fn new(resolve_code_hash_fn: F) -> Self { Self { resolve_code_hash_fn, } diff --git a/trace_decoder/src/types.rs b/trace_decoder/src/types.rs index def6f02f1..b1e2da5ca 100644 --- a/trace_decoder/src/types.rs +++ b/trace_decoder/src/types.rs @@ -7,8 +7,6 @@ use mpt_trie::{nibbles::Nibbles, partial_trie::HashedPartialTrie}; use serde::{Deserialize, Serialize}; // TODO: Make these types in the doc comments point to the actual types... -/// A type alias for `u64` of a block height. -pub type BlockHeight = u64; /// A type alias for `[U256; 8]` of a bloom filter. pub type Bloom = [U256; 8]; /// A type alias for `H256` of a code hash. @@ -61,10 +59,6 @@ pub(crate) const EMPTY_ACCOUNT_BYTES_RLPED: [u8; 70] = [ // This is just `rlp(0)`. pub(crate) const ZERO_STORAGE_SLOT_VAL_RLPED: [u8; 1] = [128]; -/// An `IR` (Intermediate Representation) for a given txn in a block that we can -/// use to generate a proof for that txn. -pub type TxnProofGenIR = GenerationInputs; - /// Other data that is needed for proof gen. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct OtherBlockData { diff --git a/trace_decoder/src/utils.rs b/trace_decoder/src/utils.rs index 678fcc064..ee48e770f 100644 --- a/trace_decoder/src/utils.rs +++ b/trace_decoder/src/utils.rs @@ -1,5 +1,6 @@ use ethereum_types::H256; use keccak_hash::keccak; +use log::debug; use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, PartialTrie}, @@ -30,7 +31,7 @@ pub(crate) fn print_value_and_hash_nodes_of_storage_trie( trie: &HashedPartialTrie, ) { let trie_elems = print_value_and_hash_nodes_of_trie_common(trie); - println!("Storage trie for {:x}: {:#?}", s_trie_addr, trie_elems); + debug!("Storage trie for {:x}: {:#?}", s_trie_addr, trie_elems); } // TODO: Move under a feature flag... @@ -57,3 +58,11 @@ pub(crate) fn h_addr_nibs_to_h256(h_addr_nibs: &Nibbles) -> H256 { H256::from_slice(&nib_bytes) } + +pub(crate) fn optional_field(label: &str, value: Option) -> String { + value.map_or(String::new(), |v| format!("{}: {:?}\n", label, v)) +} + +pub(crate) fn optional_field_hex(label: &str, value: Option) -> String { + value.map_or(String::new(), |v| format!("{}: 0x{:064X}\n", label, v)) +} From 4769a2bd7a9fe40ac3f21ca01eb72c3dbdac8d78 Mon Sep 17 00:00:00 2001 From: BGluth Date: Mon, 22 Apr 2024 14:06:03 -0600 Subject: [PATCH 2/2] Revert "`main` --> `0.3.0` (#138)" (#179) This reverts commit 88d75edfba7e3a8f7b2b9f7a580d13db444d8b8e. --- CHANGELOG.md | 30 +- Cargo.toml | 4 +- evm_arithmetization/Cargo.toml | 4 +- evm_arithmetization/src/all_stark.rs | 45 +- .../src/arithmetic/arithmetic_stark.rs | 6 +- evm_arithmetization/src/arithmetic/modular.rs | 8 +- .../src/byte_packing/byte_packing_stark.rs | 2 +- evm_arithmetization/src/cpu/cpu_stark.rs | 4 +- .../src/cpu/kernel/asm/core/access_lists.asm | 79 ++-- .../src/cpu/kernel/asm/core/call_gas.asm | 18 +- .../kernel/asm/mpt/storage/storage_read.asm | 23 +- .../kernel/asm/mpt/storage/storage_write.asm | 21 +- .../asm/transactions/common_decoding.asm | 7 +- .../src/cpu/kernel/assembler.rs | 7 +- .../src/cpu/kernel/interpreter.rs | 28 +- .../src/cpu/kernel/tests/account_code.rs | 2 +- .../src/cpu/kernel/tests/balance.rs | 2 +- .../src/cpu/kernel/tests/core/access_lists.rs | 28 +- .../src/cpu/kernel/tests/mpt/delete.rs | 8 +- .../src/cpu/kernel/tests/mpt/insert.rs | 2 +- .../src/cpu/kernel/tests/receipt.rs | 10 +- .../src/fixed_recursive_verifier.rs | 5 +- evm_arithmetization/src/generation/mpt.rs | 12 +- .../src/generation/prover_input.rs | 4 +- evm_arithmetization/src/generation/state.rs | 16 + .../src/generation/trie_extractor.rs | 6 +- .../src/keccak/keccak_stark.rs | 2 +- .../src/keccak_sponge/columns.rs | 10 +- .../src/keccak_sponge/keccak_sponge_stark.rs | 192 ++------ evm_arithmetization/src/lib.rs | 2 - .../src/memory/memory_stark.rs | 7 +- evm_arithmetization/src/recursive_verifier.rs | 14 - evm_arithmetization/tests/add11_yml.rs | 14 +- .../tests/basic_smart_contract.rs | 2 +- evm_arithmetization/tests/erc20.rs | 63 ++- evm_arithmetization/tests/erc721.rs | 58 ++- evm_arithmetization/tests/log_opcode.rs | 57 ++- .../tests/self_balance_gas_cost.rs | 14 +- evm_arithmetization/tests/selfdestruct.rs | 8 +- evm_arithmetization/tests/simple_transfer.rs | 2 +- evm_arithmetization/tests/withdrawals.rs | 2 +- mpt_trie/Cargo.toml | 6 +- mpt_trie/examples/ethereum_trie.rs | 26 +- mpt_trie/examples/hash_nodes.rs | 19 +- mpt_trie/examples/simple.rs | 27 +- mpt_trie/src/debug_tools/diff.rs | 15 +- mpt_trie/src/debug_tools/query.rs | 6 +- mpt_trie/src/debug_tools/stats.rs | 41 +- mpt_trie/src/nibbles.rs | 387 +++------------- mpt_trie/src/partial_trie.rs | 48 +- mpt_trie/src/special_query.rs | 13 +- mpt_trie/src/testing_utils.rs | 22 +- mpt_trie/src/trie_hashing.rs | 40 +- mpt_trie/src/trie_ops.rs | 290 +++++------- mpt_trie/src/trie_subsets.rs | 75 ++- mpt_trie/src/utils.rs | 21 +- proof_gen/Cargo.toml | 5 +- proof_gen/README.md | 2 +- proof_gen/src/lib.rs | 3 +- proof_gen/src/proof_gen.rs | 5 +- proof_gen/src/proof_types.rs | 7 +- proof_gen/src/prover_state.rs | 2 +- trace_decoder/Cargo.toml | 6 +- .../compact/compact_prestate_processing.rs | 117 ++--- .../src/compact/compact_to_partial_trie.rs | 18 +- .../src/compact/complex_test_payloads.rs | 25 +- trace_decoder/src/compact/mod.rs | 4 +- trace_decoder/src/decoding.rs | 430 ++++++------------ trace_decoder/src/lib.rs | 2 +- trace_decoder/src/processed_block_trace.rs | 30 +- trace_decoder/src/types.rs | 6 + trace_decoder/src/utils.rs | 11 +- 72 files changed, 885 insertions(+), 1652 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6eca93b5a..1b60a5397 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,34 +5,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - ## [Unreleased] -### Changed - -## [0.3.0] - 2024-04-19 - -### Changed -- Update plonky2 dependencies ([#119](https://github.com/0xPolygonZero/zk_evm/pull/119)) -- Swap out the internal U512 inside nibbles to [u64;5] ([#132](https://github.com/0xPolygonZero/zk_evm/pull/132)) -- Charge gas before SLOAD and refactor `insert_accessed_storage_keys` ([#117](https://github.com/0xPolygonZero/zk_evm/pull/117)) -- Increased the public interface for `trie_tools` ([#123](https://github.com/0xPolygonZero/zk_evm/pull/123)) -- Mpt trie panic refactor ([#118](https://github.com/0xPolygonZero/zk_evm/pull/118)) -- refactor: remove some reallocations from decoder ([#126](https://github.com/0xPolygonZero/zk_evm/pull/126)) -- Charge cold access cost in *CALL* before accessing state ([#124](https://github.com/0xPolygonZero/zk_evm/pull/124)) -- chore: add debug function for better logging in development ([#134](https://github.com/0xPolygonZero/zk_evm/pull/134)) -- Make test_receipt_encoding more meaningful. ([#131](https://github.com/0xPolygonZero/zk_evm/pull/131)) -- Add a getter for the KERNEL codehash ([#136](https://github.com/0xPolygonZero/zk_evm/pull/136)) -- Remove interpreter-specific preinialization logic from State trait ([#139](https://github.com/0xPolygonZero/zk_evm/pull/139)) -- Make some more functions constant ([#154](https://github.com/0xPolygonZero/zk_evm/pull/154)) -- fix(keccak-sponge): properly constrain padding bytes ([#158](https://github.com/0xPolygonZero/zk_evm/pull/158)) -- Reduce verbosity in logs ([#160](https://github.com/0xPolygonZero/zk_evm/pull/160)) -- Bump with latest starky ([#161](https://github.com/0xPolygonZero/zk_evm/pull/161)) -- Decouple trace_decoder and proof_gen ([#163](https://github.com/0xPolygonZero/zk_evm/pull/163)) -- Extend trace decoder err info ([#148](https://github.com/0xPolygonZero/zk_evm/pull/148)) -- Add debug function for better public values logging in development ([#134](https://github.com/0xPolygonZero/zk_evm/pull/134)) -- Simplify withdrawals logic ([#168](https://github.com/0xPolygonZero/zk_evm/pull/168)) - ## [0.2.0] - 2024-03-19 ### Changed @@ -44,8 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Reduce state trie size for dummy payloads ([#88](https://github.com/0xPolygonZero/zk_evm/pull/88)) - Fix post-txn trie debugging output for multi-logs receipts ([#86](https://github.com/0xPolygonZero/zk_evm/pull/86)) - Fixed *most* failing blocks caused by the merged in aggressive pruning changes ([#97](https://github.com/0xPolygonZero/zk_evm/pull/97)) -- Fixed trie hash collision issue when constructing storage tries ([#75](https://github.com/0xPolygonZero/zk_evm/pull/75)) -- Fix interpreter rollback by adding the clock to generation state checkpoints ([#109](https://github.com/0xPolygonZero/zk_evm/pull/109)) +- Fixed trie hash collision issue when constructing storage tries [#75](https://github.com/0xPolygonZero/zk_evm/pull/75) +- Fix interpreter rollback by adding the clock to generation state checkpoints ([#109] https://github.com/0xPolygonZero/zk_evm/pull/109) ## [0.1.1] - 2024-03-01 diff --git a/Cargo.toml b/Cargo.toml index 61db35cd5..ef8d457fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,10 @@ serde_json = "1.0.96" thiserror = "1.0.49" # plonky2-related dependencies -plonky2 = "0.2.2" +plonky2 = "0.2.0" plonky2_maybe_rayon = "0.2.0" plonky2_util = "0.2.0" -starky = "0.4.0" +starky = "0.2.1" [workspace.package] diff --git a/evm_arithmetization/Cargo.toml b/evm_arithmetization/Cargo.toml index 43e75b902..12a3438a8 100644 --- a/evm_arithmetization/Cargo.toml +++ b/evm_arithmetization/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "evm_arithmetization" description = "Implementation of STARKs for the Ethereum Virtual Machine" -version = "0.1.3" +version = "0.1.2" authors = ["Daniel Lubarov ", "William Borgeaud "] readme = "README.md" categories = ["cryptography"] @@ -41,7 +41,7 @@ tiny-keccak = "2.0.2" serde_json = { workspace = true } # Local dependencies -mpt_trie = { version = "0.2.1", path = "../mpt_trie" } +mpt_trie = { version = "0.2.0", path = "../mpt_trie" } [target.'cfg(not(target_env = "msvc"))'.dependencies] jemallocator = "0.5.0" diff --git a/evm_arithmetization/src/all_stark.rs b/evm_arithmetization/src/all_stark.rs index f8422b300..942b5cd2f 100644 --- a/evm_arithmetization/src/all_stark.rs +++ b/evm_arithmetization/src/all_stark.rs @@ -138,27 +138,27 @@ fn ctl_byte_packing() -> CrossTableLookup { let cpu_packing_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_byte_packing(), - cpu_stark::ctl_filter_byte_packing(), + Some(cpu_stark::ctl_filter_byte_packing()), ); let cpu_unpacking_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_byte_unpacking(), - cpu_stark::ctl_filter_byte_unpacking(), + Some(cpu_stark::ctl_filter_byte_unpacking()), ); let cpu_push_packing_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_byte_packing_push(), - cpu_stark::ctl_filter_byte_packing_push(), + Some(cpu_stark::ctl_filter_byte_packing_push()), ); let cpu_jumptable_read_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_jumptable_read(), - cpu_stark::ctl_filter_syscall_exceptions(), + Some(cpu_stark::ctl_filter_syscall_exceptions()), ); let byte_packing_looked = TableWithColumns::new( *Table::BytePacking, byte_packing_stark::ctl_looked_data(), - byte_packing_stark::ctl_looked_filter(), + Some(byte_packing_stark::ctl_looked_filter()), ); CrossTableLookup::new( vec![ @@ -179,12 +179,12 @@ fn ctl_keccak_inputs() -> CrossTableLookup { let keccak_sponge_looking = TableWithColumns::new( *Table::KeccakSponge, keccak_sponge_stark::ctl_looking_keccak_inputs(), - keccak_sponge_stark::ctl_looking_keccak_filter(), + Some(keccak_sponge_stark::ctl_looking_keccak_filter()), ); let keccak_looked = TableWithColumns::new( *Table::Keccak, keccak_stark::ctl_data_inputs(), - keccak_stark::ctl_filter_inputs(), + Some(keccak_stark::ctl_filter_inputs()), ); CrossTableLookup::new(vec![keccak_sponge_looking], keccak_looked) } @@ -196,12 +196,12 @@ fn ctl_keccak_outputs() -> CrossTableLookup { let keccak_sponge_looking = TableWithColumns::new( *Table::KeccakSponge, keccak_sponge_stark::ctl_looking_keccak_outputs(), - keccak_sponge_stark::ctl_looking_keccak_filter(), + Some(keccak_sponge_stark::ctl_looking_keccak_filter()), ); let keccak_looked = TableWithColumns::new( *Table::Keccak, keccak_stark::ctl_data_outputs(), - keccak_stark::ctl_filter_outputs(), + Some(keccak_stark::ctl_filter_outputs()), ); CrossTableLookup::new(vec![keccak_sponge_looking], keccak_looked) } @@ -212,12 +212,12 @@ fn ctl_keccak_sponge() -> CrossTableLookup { let cpu_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_keccak_sponge(), - cpu_stark::ctl_filter_keccak_sponge(), + Some(cpu_stark::ctl_filter_keccak_sponge()), ); let keccak_sponge_looked = TableWithColumns::new( *Table::KeccakSponge, keccak_sponge_stark::ctl_looked_data(), - keccak_sponge_stark::ctl_looked_filter(), + Some(keccak_sponge_stark::ctl_looked_filter()), ); CrossTableLookup::new(vec![cpu_looking], keccak_sponge_looked) } @@ -228,18 +228,19 @@ fn ctl_logic() -> CrossTableLookup { let cpu_looking = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_logic(), - cpu_stark::ctl_filter_logic(), + Some(cpu_stark::ctl_filter_logic()), ); let mut all_lookers = vec![cpu_looking]; for i in 0..keccak_sponge_stark::num_logic_ctls() { let keccak_sponge_looking = TableWithColumns::new( *Table::KeccakSponge, keccak_sponge_stark::ctl_looking_logic(i), - keccak_sponge_stark::ctl_looking_logic_filter(), + Some(keccak_sponge_stark::ctl_looking_logic_filter()), ); all_lookers.push(keccak_sponge_looking); } - let logic_looked = TableWithColumns::new(*Table::Logic, logic::ctl_data(), logic::ctl_filter()); + let logic_looked = + TableWithColumns::new(*Table::Logic, logic::ctl_data(), Some(logic::ctl_filter())); CrossTableLookup::new(all_lookers, logic_looked) } @@ -249,42 +250,42 @@ fn ctl_memory() -> CrossTableLookup { let cpu_memory_code_read = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_code_memory(), - cpu_stark::ctl_filter_code_memory(), + Some(cpu_stark::ctl_filter_code_memory()), ); let cpu_memory_gp_ops = (0..NUM_GP_CHANNELS).map(|channel| { TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_gp_memory(channel), - cpu_stark::ctl_filter_gp_memory(channel), + Some(cpu_stark::ctl_filter_gp_memory(channel)), ) }); let cpu_push_write_ops = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_partial_memory::(), - cpu_stark::ctl_filter_partial_memory(), + Some(cpu_stark::ctl_filter_partial_memory()), ); let cpu_set_context_write = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_memory_old_sp_write_set_context::(), - cpu_stark::ctl_filter_set_context(), + Some(cpu_stark::ctl_filter_set_context()), ); let cpu_set_context_read = TableWithColumns::new( *Table::Cpu, cpu_stark::ctl_data_memory_new_sp_read_set_context::(), - cpu_stark::ctl_filter_set_context(), + Some(cpu_stark::ctl_filter_set_context()), ); let keccak_sponge_reads = (0..KECCAK_RATE_BYTES).map(|i| { TableWithColumns::new( *Table::KeccakSponge, keccak_sponge_stark::ctl_looking_memory(i), - keccak_sponge_stark::ctl_looking_memory_filter(i), + Some(keccak_sponge_stark::ctl_looking_memory_filter(i)), ) }); let byte_packing_ops = (0..32).map(|i| { TableWithColumns::new( *Table::BytePacking, byte_packing_stark::ctl_looking_memory(i), - byte_packing_stark::ctl_looking_memory_filter(i), + Some(byte_packing_stark::ctl_looking_memory_filter(i)), ) }); let all_lookers = vec![ @@ -301,7 +302,7 @@ fn ctl_memory() -> CrossTableLookup { let memory_looked = TableWithColumns::new( *Table::Memory, memory_stark::ctl_data(), - memory_stark::ctl_filter(), + Some(memory_stark::ctl_filter()), ); CrossTableLookup::new(all_lookers, memory_looked) } diff --git a/evm_arithmetization/src/arithmetic/arithmetic_stark.rs b/evm_arithmetization/src/arithmetic/arithmetic_stark.rs index d0712a3bc..f6877c95f 100644 --- a/evm_arithmetization/src/arithmetic/arithmetic_stark.rs +++ b/evm_arithmetization/src/arithmetic/arithmetic_stark.rs @@ -100,7 +100,9 @@ pub(crate) fn ctl_arithmetic_rows() -> TableWithColumns { let mut filter_cols = COMBINED_OPS.to_vec(); filter_cols.push((columns::IS_RANGE_CHECK, 0x01)); - let filter = Filter::new_simple(Column::sum(filter_cols.iter().map(|(c, _v)| *c))); + let filter = Some(Filter::new_simple(Column::sum( + filter_cols.iter().map(|(c, _v)| *c), + ))); let mut all_combined_cols = COMBINED_OPS.to_vec(); all_combined_cols.push((columns::OPCODE_COL, 0x01)); @@ -321,7 +323,7 @@ impl, const D: usize> Stark for ArithmeticSta columns: Column::singles(SHARED_COLS).collect(), table_column: Column::single(RANGE_COUNTER), frequencies_column: Column::single(RC_FREQUENCIES), - filter_columns: vec![Default::default(); NUM_SHARED_COLS], + filter_columns: vec![None; NUM_SHARED_COLS], }] } diff --git a/evm_arithmetization/src/arithmetic/modular.rs b/evm_arithmetization/src/arithmetic/modular.rs index f91bebe99..70761d4be 100644 --- a/evm_arithmetization/src/arithmetic/modular.rs +++ b/evm_arithmetization/src/arithmetic/modular.rs @@ -307,7 +307,7 @@ pub(crate) fn generate_modular_op( let (lo, hi) = quot_limbs.split_at_mut(N_LIMBS); // Verify that the elements are in the expected range. - debug_assert!(lo.iter().all(|&c| c <= u16::MAX as i64)); + debug_assert!(lo.iter().all(|&c| c <= u16::max_value() as i64)); // Top half of quot_limbs should be zero. debug_assert!(hi.iter().all(|&d| d.is_zero())); @@ -318,7 +318,7 @@ pub(crate) fn generate_modular_op( // it's in the range [0, 2^16 - 1] which will correctly // range-check. for c in lo { - *c += u16::MAX as i64; + *c += u16::max_value() as i64; } // Store the sign of the quotient after the quotient. hi[0] = 1; @@ -522,7 +522,7 @@ pub(crate) fn submod_constr_poly( let sign = hi[0]; // sign must be 1 (negative) or 0 (positive) yield_constr.constraint(filter * sign * (sign - P::ONES)); - let offset = P::Scalar::from_canonical_u16(u16::MAX); + let offset = P::Scalar::from_canonical_u16(u16::max_value()); for c in lo { *c -= offset * sign; } @@ -723,7 +723,7 @@ pub(crate) fn submod_constr_poly_ext_circuit, const let t = builder.mul_extension(filter, t); // sign must be 1 (negative) or 0 (positive) yield_constr.constraint(builder, t); - let offset = F::from_canonical_u16(u16::MAX); + let offset = F::from_canonical_u16(u16::max_value()); for c in lo { let t = builder.mul_const_extension(offset, sign); *c = builder.sub_extension(*c, t); diff --git a/evm_arithmetization/src/byte_packing/byte_packing_stark.rs b/evm_arithmetization/src/byte_packing/byte_packing_stark.rs index 1a0acb51c..8708e2040 100644 --- a/evm_arithmetization/src/byte_packing/byte_packing_stark.rs +++ b/evm_arithmetization/src/byte_packing/byte_packing_stark.rs @@ -402,7 +402,7 @@ impl, const D: usize> Stark for BytePackingSt columns: Column::singles(value_bytes(0)..value_bytes(0) + NUM_BYTES).collect(), table_column: Column::single(RANGE_COUNTER), frequencies_column: Column::single(RC_FREQUENCIES), - filter_columns: vec![Default::default(); NUM_BYTES], + filter_columns: vec![None; NUM_BYTES], }] } diff --git a/evm_arithmetization/src/cpu/cpu_stark.rs b/evm_arithmetization/src/cpu/cpu_stark.rs index 2c626584e..4e60694b0 100644 --- a/evm_arithmetization/src/cpu/cpu_stark.rs +++ b/evm_arithmetization/src/cpu/cpu_stark.rs @@ -116,7 +116,7 @@ pub(crate) fn ctl_arithmetic_base_rows() -> TableWithColumns { TableWithColumns::new( *Table::Cpu, columns, - Filter::new( + Some(Filter::new( vec![(Column::single(COL_MAP.op.push_prover_input), col_bit)], vec![Column::sum([ COL_MAP.op.binary_op, @@ -126,7 +126,7 @@ pub(crate) fn ctl_arithmetic_base_rows() -> TableWithColumns { COL_MAP.op.syscall, COL_MAP.op.exception, ])], - ), + )), ) } diff --git a/evm_arithmetization/src/cpu/kernel/asm/core/access_lists.asm b/evm_arithmetization/src/cpu/kernel/asm/core/access_lists.asm index 5d0512a12..76d183e5f 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/core/access_lists.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/core/access_lists.asm @@ -199,15 +199,15 @@ global remove_accessed_addresses: %macro insert_accessed_storage_keys - %stack (addr, key) -> (addr, key, %%after) + %stack (addr, key, value) -> (addr, key, value, %%after) %jump(insert_accessed_storage_keys) %%after: - // stack: cold_access, value_ptr + // stack: cold_access, original_value %endmacro // Multiply the ptr at the top of the stack by 4 // and abort if 4*ptr - SEGMENT_ACCESSED_STORAGE_KEYS >= @GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN -// In this way ptr must be pointing to the beginning of a node. +// In this way ptr must be poiting to the begining of a node. %macro get_valid_storage_ptr // stack: ptr %mul_const(4) @@ -218,41 +218,41 @@ global remove_accessed_addresses: // stack: 2*ptr %endmacro -/// Inserts the storage key into the access list if it is not already present. -/// Return `1, value_ptr` if the storage key was inserted, `0, value_ptr` if it was already present. -/// Callers to this function must ensure the original storage value is stored at `value_ptr`. +/// Inserts the storage key and value into the access list if it is not already present. +/// `value` should be the current storage value at the slot `(addr, key)`. +/// Return `1, value` if the storage key was inserted, `0, original_value` if it was already present. global insert_accessed_storage_keys: - // stack: addr, key, retdest + // stack: addr, key, value, retdest PROVER_INPUT(access_lists::storage_insert) - // stack: pred_ptr/4, addr, key, retdest + // stack: pred_ptr/4, addr, key, value, retdest %get_valid_storage_ptr - // stack: pred_ptr, addr, key, retdest + // stack: pred_ptr, addr, key, value, retdest DUP1 MLOAD_GENERAL DUP1 - // stack: pred_addr, pred_addr, pred_ptr, addr, key, retdest + // stack: pred_addr, pred_addr, pred_ptr, addr, key, value, retdest DUP4 GT DUP3 %eq_const(@SEGMENT_ACCESSED_STORAGE_KEYS) ADD // OR %jumpi(insert_storage_key) - // stack: pred_addr, pred_ptr, addr, key, retdest + // stack: pred_addr, pred_ptr, addr, key, value, retdest // We know that addr <= pred_addr. It must hold that pred_addr == addr. DUP3 %assert_eq - // stack: pred_ptr, addr, key, retdest + // stack: pred_ptr, addr, key, value, retdest DUP1 %increment MLOAD_GENERAL - // stack: pred_key, pred_ptr, addr, key, retdest + // stack: pred_key, pred_ptr, addr, key, value, retdest DUP1 DUP5 GT - // stack: key > pred_key, pred_key, pred_ptr, addr, key, retdest + // stack: key > pred_key, pred_key, pred_ptr, addr, key, value, retdest %jumpi(insert_storage_key) - // stack: pred_key, pred_ptr, addr, key, retdest + // stack: pred_key, pred_ptr, addr, key, value, retdest DUP4 // We know that key <= pred_key. It must hold that pred_key == key. %assert_eq - // stack: pred_ptr, addr, key, retdest + // stack: pred_ptr, addr, key, value, retdest // Check that this is not a deleted node DUP1 %add_const(3) @@ -262,78 +262,75 @@ global insert_accessed_storage_keys: PANIC storage_key_found: // The address was already in the list - // stack: pred_ptr, addr, key, retdest + // stack: pred_ptr, addr, key, value, retdest %add_const(2) - %stack (value_ptr, addr, key, retdest) -> (retdest, 0, value_ptr) // Return 0 to indicate that the address was already present. + MLOAD_GENERAL + %stack (original_value, addr, key, value, retdest) -> (retdest, 0, original_value) // Return 0 to indicate that the address was already present. JUMP insert_storage_key: - // stack: pred_addr or pred_key, pred_ptr, addr, key, retdest + // stack: pred_addr or pred_key, pred_ptr, addr, key, value, retdest POP // Insert a new storage key - // stack: pred_ptr, addr, key, retdest + // stack: pred_ptr, addr, key, value, retdest // get the value of the next address %add_const(3) - // stack: next_ptr_ptr, addr, key, retdest + // stack: next_ptr_ptr, addr, key, value, retdest %mload_global_metadata(@GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN) DUP2 MLOAD_GENERAL - // stack: next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest + // stack: next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest // Check that this is not a deleted node DUP1 %eq_const(@U256_MAX) %assert_zero DUP1 MLOAD_GENERAL - // stack: next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest + // stack: next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest DUP5 // Check that addr < next_val OR (next_val == addr AND key < next_key) DUP2 DUP2 LT - // stack: addr < next_val, addr, next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest + // stack: addr < next_val, addr, next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest SWAP2 EQ - // stack: next_val == addr, addr < next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest + // stack: next_val == addr, addr < next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest DUP3 %increment MLOAD_GENERAL DUP8 LT - // stack: next_key > key, next_val == addr, addr < next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest + // stack: next_key > key, next_val == addr, addr < next_val, next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest AND OR %assert_nonzero - // stack: next_ptr, new_ptr, next_ptr_ptr, addr, key, retdest + // stack: next_ptr, new_ptr, next_ptr_ptr, addr, key, value, retdest SWAP2 DUP2 MSTORE_GENERAL - // stack: new_ptr, next_ptr, addr, key, retdest + // stack: new_ptr, next_ptr, addr, key, value, retdest DUP1 DUP4 MSTORE_GENERAL // store addr - // stack: new_ptr, next_ptr, addr, key, retdest + // stack: new_ptr, next_ptr, addr, key, value, retdest %increment DUP1 - // stack: new_ptr+1, new_ptr+1, next_ptr, addr, key, retdest DUP5 - // stack: key, new_ptr+1, new_ptr+1, next_ptr, addr, key, retdest MSTORE_GENERAL // store key - // stack: new_ptr+1, next_ptr, addr, key, retdest %increment DUP1 - // stack: new_ptr+2, value_ptr, next_ptr, addr, key, retdest + DUP6 + MSTORE_GENERAL // store value + // stack: new_ptr + 2, next_ptr, addr, key, value, retdest %increment DUP1 - // stack: new_next_ptr, new_next_ptr, value_ptr, next_ptr, addr, key, retdest - SWAP3 - // stack: next_ptr, new_next_ptr, value_ptr, new_next_ptr, addr, key, retdest + // stack: new_next_ptr, new_next_ptr, next_ptr, addr, key, value, retdest + SWAP2 MSTORE_GENERAL - // stack: value_ptr, new_next_ptr, addr, key, retdest - SWAP1 - // stack: new_next_ptr, value_ptr, addr, key, retdest + // stack: new_next_ptr, addr, key, value, retdest %increment %mstore_global_metadata(@GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN) - // stack: value_ptr, addr, key, retdest - %stack (value_ptr, addr, key, retdest) -> (addr, key, retdest, 1, value_ptr) + // stack: addr, key, value, retdest + %stack (addr, key, value, retdest) -> (addr, key, retdest, 1, value) %journal_add_storage_loaded JUMP diff --git a/evm_arithmetization/src/cpu/kernel/asm/core/call_gas.asm b/evm_arithmetization/src/cpu/kernel/asm/core/call_gas.asm index 5945c1e17..396135213 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/core/call_gas.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/core/call_gas.asm @@ -13,10 +13,8 @@ global call_charge_gas: // stack: is_call_or_callcode, is_call_or_staticcall, cold_access, address, gas, kexit_info, value, retdest SWAP2 // stack: cold_access, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest - %jumpi(charge_cold_access_gas) - // stack: is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest -call_charge_gas_contd: - PUSH @GAS_WARMACCESS + %mul_const(@GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS) + %add_const(@GAS_WARMACCESS) // stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest DUP3 // stack: is_call_or_callcode, cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest @@ -92,15 +90,3 @@ new_cost_nonzero: // stack: cost, is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest %add_const(@GAS_NEWACCOUNT) %jump(after_new_cost) - -charge_cold_access_gas: - // stack: is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest - SWAP4 - // stack: kexit_info, is_call_or_callcode, address, gas, is_call_or_staticcall, value, retdest - PUSH @GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS - // stack: cold_access_cost, kexit_info, is_call_or_callcode, address, gas, is_call_or_staticcall, value, retdest - %charge_gas - // stack: kexit_info, is_call_or_callcode, address, gas, is_call_or_staticcall, value, retdest - SWAP4 - // stack: is_call_or_staticcall, is_call_or_callcode, address, gas, kexit_info, value, retdest - %jump(call_charge_gas_contd) diff --git a/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_read.asm b/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_read.asm index db9fe4222..84d8d0efc 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_read.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_read.asm @@ -39,25 +39,18 @@ global sys_sload: SWAP1 DUP1 // stack: slot, slot, kexit_info + %sload_current + + %stack (value, slot, kexit_info) -> (slot, value, kexit_info, value) %address - // stack: address, slot, slot, kexit_info + // stack: addr, slot, value, kexit_info, value %insert_accessed_storage_keys - // stack: cold_access, value_ptr, slot, kexit_info - DUP1 + // stack: cold_access, old_value, kexit_info, value + SWAP1 POP + // stack: cold_access, kexit_info, value %mul_const(@GAS_COLDSLOAD_MINUS_WARMACCESS) %add_const(@GAS_WARMACCESS) - %stack (gas, cold_access, value_ptr, slot, kexit_info) -> (gas, kexit_info, cold_access, value_ptr, slot) %charge_gas - - %stack (kexit_info, cold_access, value_ptr, slot) -> (slot, cold_access, value_ptr, kexit_info) - %sload_current - // stack: value, cold_access, value_ptr, kexit_info - SWAP1 %jumpi(sload_cold_access) - %stack (value, value_ptr, kexit_info) -> (kexit_info, value) + // stack: kexit_info, value EXIT_KERNEL -sload_cold_access: - // stack: value, value_ptr, kexit_info - %stack (value, value_ptr, kexit_info) -> (value, value_ptr, kexit_info, value) - MSTORE_GENERAL - EXIT_KERNEL diff --git a/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_write.asm b/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_write.asm index 22c5d29de..08270dfa9 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_write.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/mpt/storage/storage_write.asm @@ -9,26 +9,11 @@ global sys_sstore: %stack (kexit_info, slot, value) -> (slot, kexit_info, slot, value) %sload_current %address - %stack (addr, current_value, kexit_info, slot, value) -> (addr, slot, current_value, kexit_info, slot, value) + %stack (addr, current_value, kexit_info, slot, value) -> (addr, slot, current_value, current_value, kexit_info, slot, value) %insert_accessed_storage_keys - // stack: cold_access, value_ptr, current_value, kexit_info, slot, value - %jumpi(sstore_cold_access) - // stack: value_ptr, current_value, kexit_info, slot, value - MLOAD_GENERAL - // stack: original_value, current_value, kexit_info, slot, value - PUSH 0 - // stack: gas, original_value, current_value, kexit_info, slot, value - %jump(sstore_after_cold_access_check) - -sstore_cold_access: - // stack: value_ptr, current_value, kexit_info, slot, value - DUP2 MSTORE_GENERAL - // stack: current_value, kexit_info, slot, value - DUP1 - PUSH @GAS_COLDSLOAD - // stack: gas, original_value, current_value, kexit_info, slot, value + // stack: cold_access, original_value, current_value, kexit_info, slot, value + %mul_const(@GAS_COLDSLOAD) -sstore_after_cold_access_check: // Check for warm access. %stack (gas, original_value, current_value, kexit_info, slot, value) -> (value, current_value, current_value, original_value, gas, original_value, current_value, kexit_info, slot, value) diff --git a/evm_arithmetization/src/cpu/kernel/asm/transactions/common_decoding.asm b/evm_arithmetization/src/cpu/kernel/asm/transactions/common_decoding.asm index 223e0a62e..4a8feccaa 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/transactions/common_decoding.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/transactions/common_decoding.asm @@ -226,12 +226,7 @@ insert_accessed_storage_keys_with_original_value: after_read: %stack (value, addr, key, retdest) -> ( addr, key, value, retdest) %insert_accessed_storage_keys - // stack: cold_access, value_ptr, value, retdest - SWAP2 - // stack: value, value_ptr, cold_access, retdest - MSTORE_GENERAL - // stack: cold_access, retdest - POP + %pop2 JUMP diff --git a/evm_arithmetization/src/cpu/kernel/assembler.rs b/evm_arithmetization/src/cpu/kernel/assembler.rs index 7dfba09fc..e28fc815b 100644 --- a/evm_arithmetization/src/cpu/kernel/assembler.rs +++ b/evm_arithmetization/src/cpu/kernel/assembler.rs @@ -27,7 +27,7 @@ pub(crate) const BYTES_PER_OFFSET: u8 = 3; pub struct Kernel { pub(crate) code: Vec, - /// Hash of the `Kernel` code. + /// Computed using `hash_kernel`. pub(crate) code_hash: H256, pub(crate) global_labels: HashMap, @@ -59,11 +59,6 @@ impl Kernel { } } - /// Outputs the Kernel code hash. - pub const fn hash(&self) -> H256 { - self.code_hash - } - pub fn to_file(&self, path: &str) { let kernel_serialized = serde_json::to_string(self).unwrap(); fs::write(path, kernel_serialized).expect("Unable to write kernel to file"); diff --git a/evm_arithmetization/src/cpu/kernel/interpreter.rs b/evm_arithmetization/src/cpu/kernel/interpreter.rs index 1e8ec7ccd..593b4a3f8 100644 --- a/evm_arithmetization/src/cpu/kernel/interpreter.rs +++ b/evm_arithmetization/src/cpu/kernel/interpreter.rs @@ -705,7 +705,7 @@ impl Interpreter { self.generation_state.registers.stack_len } - pub(crate) const fn stack_top(&self) -> anyhow::Result { + pub(crate) fn stack_top(&self) -> anyhow::Result { if self.stack_len() > 0 { Ok(self.generation_state.registers.stack_top) } else { @@ -738,20 +738,6 @@ impl Interpreter { .memory .set(MemoryAddress::new(0, Segment::RlpRaw, 0), 0x80.into()) } - - /// Inserts a preinitialized segment, given as a [Segment], - /// into the `preinitialized_segments` memory field. - fn insert_preinitialized_segment(&mut self, segment: Segment, values: MemorySegmentState) { - self.generation_state - .memory - .insert_preinitialized_segment(segment, values); - } - - fn is_preinitialized_segment(&self, segment: usize) -> bool { - self.generation_state - .memory - .is_preinitialized_segment(segment) - } } impl State for Interpreter { @@ -766,6 +752,18 @@ impl State for Interpreter { } } + fn insert_preinitialized_segment(&mut self, segment: Segment, values: MemorySegmentState) { + self.generation_state + .memory + .insert_preinitialized_segment(segment, values); + } + + fn is_preinitialized_segment(&self, segment: usize) -> bool { + self.generation_state + .memory + .is_preinitialized_segment(segment) + } + fn incr_gas(&mut self, n: u64) { self.generation_state.incr_gas(n); } diff --git a/evm_arithmetization/src/cpu/kernel/tests/account_code.rs b/evm_arithmetization/src/cpu/kernel/tests/account_code.rs index 5ad2d8485..a8102f36c 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/account_code.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/account_code.rs @@ -115,7 +115,7 @@ fn prepare_interpreter( .push(value_ptr.into()) .expect("The stack should not overflow"); // value_ptr interpreter - .push(k.try_into().unwrap()) + .push(k.try_into_u256().unwrap()) .expect("The stack should not overflow"); // key interpreter.run()?; diff --git a/evm_arithmetization/src/cpu/kernel/tests/balance.rs b/evm_arithmetization/src/cpu/kernel/tests/balance.rs index 034df53a8..984772027 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/balance.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/balance.rs @@ -67,7 +67,7 @@ fn prepare_interpreter( .push(value_ptr.into()) .expect("The stack should not overflow"); // value_ptr interpreter - .push(k.try_into().unwrap()) + .push(k.try_into_u256().unwrap()) .expect("The stack should not overflow"); // key interpreter.run()?; diff --git a/evm_arithmetization/src/cpu/kernel/tests/core/access_lists.rs b/evm_arithmetization/src/cpu/kernel/tests/core/access_lists.rs index eab300ce2..b2e8227fe 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/core/access_lists.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/core/access_lists.rs @@ -208,12 +208,12 @@ fn test_insert_accessed_storage_keys() -> Result<()> { let mut rng = thread_rng(); let n = 10; let mut storage_keys = (0..n) - .map(|_| (rng.gen::
(), U256(rng.gen()))) + .map(|_| (rng.gen::
(), U256(rng.gen()), U256(rng.gen()))) .collect::>() .into_iter() - .collect::>(); + .collect::>(); let storage_key_in_list = storage_keys[rng.gen_range(0..n)]; - let storage_key_not_in_list = (rng.gen::
(), U256(rng.gen())); + let storage_key_not_in_list = (rng.gen::
(), U256(rng.gen()), U256(rng.gen())); assert!( !storage_keys.contains(&storage_key_not_in_list), "Cosmic luck or bad RNG?" @@ -223,25 +223,28 @@ fn test_insert_accessed_storage_keys() -> Result<()> { for i in 0..n { let addr = U256::from(storage_keys[i].0 .0.as_slice()); let key = storage_keys[i].1; + let value = storage_keys[i].2; interpreter.push(retaddr); + interpreter.push(value); interpreter.push(key); interpreter.push(addr); interpreter.generation_state.registers.program_counter = insert_accessed_storage_keys; interpreter.run()?; assert_eq!(interpreter.pop().unwrap(), U256::one()); - interpreter.pop().expect("Stack shouldn't be empty"); // Pop the value_ptr. + assert_eq!(interpreter.pop().unwrap(), value); } for i in 0..10 { // Test for storage key already in list. - let (addr, key) = storage_keys[i]; + let (addr, key, value) = storage_keys[i]; interpreter.push(retaddr); + interpreter.push(value); interpreter.push(key); interpreter.push(U256::from(addr.0.as_slice())); interpreter.generation_state.registers.program_counter = insert_accessed_storage_keys; interpreter.run()?; assert_eq!(interpreter.pop().unwrap(), U256::zero()); - interpreter.pop().expect("Stack shouldn't be empty"); // Pop the value_ptr. + assert_eq!(interpreter.pop().unwrap(), value); assert_eq!( interpreter.generation_state.memory.get_with_init( MemoryAddress::new_bundle(U256::from(AccessedStorageKeysLen as usize)).unwrap(), @@ -252,12 +255,16 @@ fn test_insert_accessed_storage_keys() -> Result<()> { // Test for storage key not in list. interpreter.push(retaddr); + interpreter.push(storage_key_not_in_list.2); interpreter.push(storage_key_not_in_list.1); interpreter.push(U256::from(storage_key_not_in_list.0 .0.as_slice())); interpreter.generation_state.registers.program_counter = insert_accessed_storage_keys; interpreter.run()?; - assert_eq!(interpreter.stack()[1], U256::one()); + assert_eq!( + interpreter.stack(), + &[storage_key_not_in_list.2, U256::one()] + ); assert_eq!( interpreter.generation_state.memory.get_with_init( MemoryAddress::new_bundle(U256::from(AccessedStorageKeysLen as usize)).unwrap(), @@ -278,6 +285,13 @@ fn test_insert_accessed_storage_keys() -> Result<()> { .get_with_init(MemoryAddress::new(0, AccessedStorageKeys, 4 * (n + 1) + 1),), storage_key_not_in_list.1 ); + assert_eq!( + interpreter + .generation_state + .memory + .get_with_init(MemoryAddress::new(0, AccessedStorageKeys, 4 * (n + 1) + 2),), + storage_key_not_in_list.2 + ); Ok(()) } diff --git a/evm_arithmetization/src/cpu/kernel/tests/mpt/delete.rs b/evm_arithmetization/src/cpu/kernel/tests/mpt/delete.rs index ef8830ae7..3f9153cda 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/mpt/delete.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/mpt/delete.rs @@ -1,6 +1,6 @@ use anyhow::Result; use ethereum_types::{BigEndianHash, H256, U512}; -use mpt_trie::nibbles::{Nibbles, NibblesIntern}; +use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::random; @@ -70,7 +70,7 @@ fn test_after_mpt_delete_extension_branch() -> Result<()> { } .into(); let key = nibbles.merge_nibbles(&Nibbles { - packed: NibblesIntern::zero(), + packed: U512::zero(), count: 64 - nibbles.count, }); test_state_trie(state_trie, key, test_account_2()) @@ -130,7 +130,7 @@ fn test_state_trie( .push(value_ptr.into()) .expect("The stack should not overflow"); // value_ptr interpreter - .push(k.try_into().unwrap()) + .push(k.try_into_u256().unwrap()) .expect("The stack should not overflow"); // key interpreter.run()?; assert_eq!( @@ -147,7 +147,7 @@ fn test_state_trie( .push(0xDEADBEEFu32.into()) .expect("The stack should not overflow"); interpreter - .push(k.try_into().unwrap()) + .push(k.try_into_u256().unwrap()) .expect("The stack should not overflow"); interpreter .push(64.into()) diff --git a/evm_arithmetization/src/cpu/kernel/tests/mpt/insert.rs b/evm_arithmetization/src/cpu/kernel/tests/mpt/insert.rs index 771921173..fcb2b5323 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/mpt/insert.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/mpt/insert.rs @@ -205,7 +205,7 @@ fn test_state_trie( .push(value_ptr.into()) .expect("The stack should not overflow"); // value_ptr interpreter - .push(k.try_into().unwrap()) + .push(k.try_into_u256().unwrap()) .expect("The stack should not overflow"); // key interpreter.run()?; diff --git a/evm_arithmetization/src/cpu/kernel/tests/receipt.rs b/evm_arithmetization/src/cpu/kernel/tests/receipt.rs index de6e7f1d4..3e34f640e 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/receipt.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/receipt.rs @@ -11,7 +11,7 @@ use crate::cpu::kernel::constants::txn_fields::NormalizedTxnField; use crate::cpu::kernel::interpreter::Interpreter; use crate::cpu::kernel::tests::account_code::initialize_mpts; use crate::generation::mpt::{LegacyReceiptRlp, LogRlp}; -use crate::memory::segments::{Segment, SEGMENT_SCALING_FACTOR}; +use crate::memory::segments::Segment; #[test] fn test_process_receipt() -> Result<()> { @@ -129,9 +129,7 @@ fn test_receipt_encoding() -> Result<()> { // Get the expected RLP encoding. let expected_rlp = rlp::encode(&rlp::encode(&receipt_1)); - // Address at which the encoding is written. - let rlp_addr = U256::from(Segment::RlpRaw as usize); - let initial_stack: Vec = vec![retdest, 0.into(), 0.into(), rlp_addr]; + let initial_stack: Vec = vec![retdest, 0.into(), 0.into(), 0.into()]; let mut interpreter: Interpreter = Interpreter::new(encode_receipt, initial_stack); // Write data to memory. @@ -200,9 +198,9 @@ fn test_receipt_encoding() -> Result<()> { interpreter.run()?; let rlp_pos = interpreter.pop().expect("The stack should not be empty"); - let rlp_read: &[u8] = &interpreter.get_rlp_memory(); + let rlp_read: &[u8] = &interpreter.get_rlp_memory()[1..]; // skip empty_node - assert_eq!((rlp_pos - rlp_addr).as_usize(), expected_rlp.len()); + assert_eq!(rlp_pos.as_usize(), expected_rlp.len()); for i in 0..rlp_read.len() { assert_eq!(rlp_read[i], expected_rlp[i]); } diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index be65eb413..a60b9e7e3 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -399,10 +399,7 @@ where *table = MaybeUninit::new(value); } unsafe { - mem::transmute::< - [std::mem::MaybeUninit>; NUM_TABLES], - [RecursiveCircuitsForTable; NUM_TABLES], - >(by_table) + mem::transmute::<_, [RecursiveCircuitsForTable; NUM_TABLES]>(by_table) } } }; diff --git a/evm_arithmetization/src/generation/mpt.rs b/evm_arithmetization/src/generation/mpt.rs index febf2a2c1..79e923068 100644 --- a/evm_arithmetization/src/generation/mpt.rs +++ b/evm_arithmetization/src/generation/mpt.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use bytes::Bytes; use ethereum_types::{Address, BigEndianHash, H256, U256, U512}; use keccak_hash::keccak; -use mpt_trie::nibbles::{Nibbles, NibblesIntern}; +use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use rlp::{Decodable, DecoderError, Encodable, PayloadInfo, Rlp, RlpStream}; use rlp_derive::{RlpDecodable, RlpEncodable}; @@ -120,7 +120,7 @@ fn parse_storage_value(value_rlp: &[u8]) -> Result, ProgramError> { const fn empty_nibbles() -> Nibbles { Nibbles { count: 0, - packed: NibblesIntern::zero(), + packed: U512::zero(), } } @@ -171,7 +171,7 @@ where trie_data.push(nibbles.count.into()); trie_data.push( nibbles - .try_into() + .try_into_u256() .map_err(|_| ProgramError::IntegerTooLarge)?, ); trie_data.push((trie_data.len() + 1).into()); @@ -187,7 +187,7 @@ where trie_data.push(nibbles.count.into()); trie_data.push( nibbles - .try_into() + .try_into_u256() .map_err(|_| ProgramError::IntegerTooLarge)?, ); @@ -250,7 +250,7 @@ fn load_state_trie( trie_data.push(nibbles.count.into()); trie_data.push( nibbles - .try_into() + .try_into_u256() .map_err(|_| ProgramError::IntegerTooLarge)?, ); // Set `value_ptr_ptr`. @@ -286,7 +286,7 @@ fn load_state_trie( trie_data.push(nibbles.count.into()); trie_data.push( nibbles - .try_into() + .try_into_u256() .map_err(|_| ProgramError::IntegerTooLarge)?, ); // Set `value_ptr_ptr`. diff --git a/evm_arithmetization/src/generation/prover_input.rs b/evm_arithmetization/src/generation/prover_input.rs index 8e65e8db6..ebffadc8a 100644 --- a/evm_arithmetization/src/generation/prover_input.rs +++ b/evm_arithmetization/src/generation/prover_input.rs @@ -560,7 +560,7 @@ struct CodeIterator<'a> { } impl<'a> CodeIterator<'a> { - const fn new(code: &'a [u8]) -> Self { + fn new(code: &'a [u8]) -> Self { CodeIterator { end: code.len(), code, @@ -609,7 +609,7 @@ pub(crate) struct AccList<'a> { } impl<'a> AccList<'a> { - const fn from_mem_and_segment( + fn from_mem_and_segment( access_list_mem: &'a [Option], segment: Segment, ) -> Result { diff --git a/evm_arithmetization/src/generation/state.rs b/evm_arithmetization/src/generation/state.rs index 5b3f5074b..e919eba80 100644 --- a/evm_arithmetization/src/generation/state.rs +++ b/evm_arithmetization/src/generation/state.rs @@ -138,6 +138,12 @@ pub(crate) trait State { /// Return the offsets at which execution must halt fn get_halt_offsets(&self) -> Vec; + /// Inserts a preinitialized segment, given as a [Segment], + /// into the `preinitialized_segments` memory field. + fn insert_preinitialized_segment(&mut self, segment: Segment, values: MemorySegmentState); + + fn is_preinitialized_segment(&self, segment: usize) -> bool; + /// Simulates the CPU. It only generates the traces if the `State` is a /// `GenerationState`. fn run_cpu(&mut self) -> anyhow::Result<()> @@ -422,6 +428,16 @@ impl State for GenerationState { } } + fn insert_preinitialized_segment(&mut self, segment: Segment, values: MemorySegmentState) { + panic!( + "A `GenerationState` cannot have a nonempty `preinitialized_segment` field in memory." + ) + } + + fn is_preinitialized_segment(&self, segment: usize) -> bool { + false + } + fn incr_gas(&mut self, n: u64) { self.registers.gas_used += n; } diff --git a/evm_arithmetization/src/generation/trie_extractor.rs b/evm_arithmetization/src/generation/trie_extractor.rs index 0d825643f..dfea16234 100644 --- a/evm_arithmetization/src/generation/trie_extractor.rs +++ b/evm_arithmetization/src/generation/trie_extractor.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use ethereum_types::{BigEndianHash, H256, U256, U512}; -use mpt_trie::nibbles::{Nibbles, NibblesIntern}; +use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, Node, PartialTrie, WrappedNode}; use super::mpt::{AccountRlp, LegacyReceiptRlp, LogRlp}; @@ -47,7 +47,7 @@ pub(crate) fn read_trie( let mut res = HashMap::new(); let empty_nibbles = Nibbles { count: 0, - packed: NibblesIntern::zero(), + packed: U512::zero(), }; read_trie_helper::(memory, ptr, read_value, empty_nibbles, &mut res)?; Ok(res) @@ -259,7 +259,7 @@ pub(crate) fn get_trie( ) -> Result { let empty_nibbles = Nibbles { count: 0, - packed: NibblesIntern::zero(), + packed: U512::zero(), }; Ok(N::new(get_trie_helper( memory, diff --git a/evm_arithmetization/src/keccak/keccak_stark.rs b/evm_arithmetization/src/keccak/keccak_stark.rs index 5f505cf06..e1a0484d6 100644 --- a/evm_arithmetization/src/keccak/keccak_stark.rs +++ b/evm_arithmetization/src/keccak/keccak_stark.rs @@ -734,7 +734,7 @@ mod tests { gamma: F::ZERO, }, vec![], - vec![Filter::new_simple(Column::constant(F::ZERO))], + vec![Some(Filter::new_simple(Column::constant(F::ZERO)))], ); let ctl_data = CtlData { zs_columns: vec![ctl_z_data.clone(); config.num_challenges], diff --git a/evm_arithmetization/src/keccak_sponge/columns.rs b/evm_arithmetization/src/keccak_sponge/columns.rs index 44c707bf2..6f602ab02 100644 --- a/evm_arithmetization/src/keccak_sponge/columns.rs +++ b/evm_arithmetization/src/keccak_sponge/columns.rs @@ -47,14 +47,12 @@ pub(crate) struct KeccakSpongeColumnsView { /// block. pub already_absorbed_bytes: T, - /// Indicates whether the byte at position `i` is a padding byte. - /// - /// For a final block, the `i`th entry should be 1 for all bytes that have - /// been padded, including the first `1` byte, all subsequent `0` bytes - /// and the last byte as per the 10*1 padding scheme. + /// If this row represents a final block row, the `i`th entry should be 1 if + /// the final chunk of input has length `i` (in other words if `len - + /// already_absorbed == i`), otherwise 0. /// /// If this row represents a full input block, this should contain all 0s. - pub is_padding_byte: [T; KECCAK_RATE_BYTES], + pub is_final_input_len: [T; KECCAK_RATE_BYTES], /// The initial rate part of the sponge, at the start of this step. pub original_rate_u32s: [T; KECCAK_RATE_U32S], diff --git a/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs b/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs index d0f830fcf..667d37ef8 100644 --- a/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs +++ b/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs @@ -45,12 +45,14 @@ pub(crate) fn ctl_looked_data() -> Vec> { outputs.push(cur_col); } - // The length of the inputs is - // `already_absorbed_bytes + (RATE - Σi is_padding_byte[i])`. - let len_col = Column::linear_combination_with_constant( - iter::once((cols.already_absorbed_bytes, F::ONE)) - .chain((0..KECCAK_RATE_BYTES).map(|i| (cols.is_padding_byte[i], -F::ONE))), - F::from_canonical_usize(KECCAK_RATE_BYTES), + // The length of the inputs is `already_absorbed_bytes + is_final_input_len`. + let len_col = Column::linear_combination( + iter::once((cols.already_absorbed_bytes, F::ONE)).chain( + cols.is_final_input_len + .iter() + .enumerate() + .map(|(i, &elt)| (elt, F::from_canonical_usize(i))), + ), ); let mut res: Vec> = @@ -189,9 +191,7 @@ pub(crate) fn ctl_looking_logic(i: usize) -> Vec> { pub(crate) fn ctl_looked_filter() -> Filter { // The CPU table is only interested in our final-block rows, since those contain // the final sponge output. - Filter::new_simple(Column::single( - KECCAK_SPONGE_COL_MAP.is_padding_byte[KECCAK_RATE_BYTES - 1], - )) + Filter::new_simple(Column::sum(KECCAK_SPONGE_COL_MAP.is_final_input_len)) } /// CTL filter for reading the `i`th byte of input from memory. @@ -203,30 +203,26 @@ pub(crate) fn ctl_looking_memory_filter(i: usize) -> Filter { if i == KECCAK_RATE_BYTES - 1 { Filter::new_simple(Column::single(cols.is_full_input_block)) } else { - Filter::new_simple(Column::linear_combination([ - (cols.is_full_input_block, F::ONE), - (cols.is_padding_byte[KECCAK_RATE_BYTES - 1], F::ONE), - (cols.is_padding_byte[i], -F::ONE), - ])) + Filter::new_simple(Column::sum( + once(&cols.is_full_input_block).chain(&cols.is_final_input_len[i + 1..]), + )) } } /// CTL filter for looking at XORs in the logic table. pub(crate) fn ctl_looking_logic_filter() -> Filter { let cols = KECCAK_SPONGE_COL_MAP; - Filter::new_simple(Column::sum([ - cols.is_full_input_block, - cols.is_padding_byte[KECCAK_RATE_BYTES - 1], - ])) + Filter::new_simple(Column::sum( + once(&cols.is_full_input_block).chain(&cols.is_final_input_len), + )) } /// CTL filter for looking at the input and output in the Keccak table. pub(crate) fn ctl_looking_keccak_filter() -> Filter { let cols = KECCAK_SPONGE_COL_MAP; - Filter::new_simple(Column::sum([ - cols.is_full_input_block, - cols.is_padding_byte[KECCAK_RATE_BYTES - 1], - ])) + Filter::new_simple(Column::sum( + once(&cols.is_full_input_block).chain(&cols.is_final_input_len), + )) } /// Information about a Keccak sponge operation needed for witness generation. @@ -377,8 +373,8 @@ impl, const D: usize> KeccakSpongeStark { /// Generates a row containing the last input bytes. /// On top of computing one absorption and padding the input, - /// we indicate all the padding input bytes by setting the - /// corresponding indices in `row.is_padding_byte` to 1. + /// we indicate the last non-padding input byte by setting + /// `row.is_final_input_len[final_inputs.len()]` to 1. fn generate_final_row( &self, op: &KeccakSpongeOp, @@ -403,9 +399,7 @@ impl, const D: usize> KeccakSpongeStark { row.block_bytes[KECCAK_RATE_BYTES - 1] = F::from_canonical_u8(0b10000000); } - for i in final_inputs.len()..KECCAK_RATE_BYTES { - row.is_padding_byte[i] = F::ONE; - } + row.is_final_input_len[final_inputs.len()] = F::ONE; Self::generate_common_fields(&mut row, op, already_absorbed_bytes, sponge_state); row @@ -567,21 +561,16 @@ impl, const D: usize> Stark for KeccakSpongeS let range_max = P::Scalar::from_canonical_u64((BYTE_RANGE_MAX - 1) as u64); yield_constr.constraint_last_row(rc1 - range_max); - // Each flag (full-input block, padding byte or implied dummy flag) must be + // Each flag (full-input block, final block or implied dummy flag) must be // boolean. let is_full_input_block = local_values.is_full_input_block; yield_constr.constraint(is_full_input_block * (is_full_input_block - P::ONES)); - for &is_padding_byte in local_values.is_padding_byte.iter() { - yield_constr.constraint(is_padding_byte * (is_padding_byte - P::ONES)); - } - let is_final_block: P = local_values.is_padding_byte[KECCAK_RATE_BYTES - 1]; + let is_final_block: P = local_values.is_final_input_len.iter().copied().sum(); + yield_constr.constraint(is_final_block * (is_final_block - P::ONES)); - // A padding byte is always followed by another padding byte. - for i in 1..KECCAK_RATE_BYTES { - yield_constr.constraint( - local_values.is_padding_byte[i - 1] * (local_values.is_padding_byte[i] - P::ONES), - ); + for &is_final_len in local_values.is_final_input_len.iter() { + yield_constr.constraint(is_final_len * (is_final_len - P::ONES)); } // Ensure that full-input block and final block flags are not set to 1 at the @@ -662,51 +651,10 @@ impl, const D: usize> Stark for KeccakSpongeS - next_values.already_absorbed_bytes), ); - // If the first padding byte is at the end of the block, then the block has a - // single padding byte. - let has_single_padding_byte = local_values.is_padding_byte[KECCAK_RATE_BYTES - 1] - - local_values.is_padding_byte[KECCAK_RATE_BYTES - 2]; - - // If the row has a single padding byte, then it must be the last byte with - // value 0b10000001. - yield_constr.constraint_transition( - has_single_padding_byte - * (local_values.block_bytes[KECCAK_RATE_BYTES - 1] - - P::from(FE::from_canonical_u8(0b10000001))), - ); - - for i in 0..KECCAK_RATE_BYTES - 1 { - let is_first_padding_byte = { - if i > 0 { - local_values.is_padding_byte[i] - local_values.is_padding_byte[i - 1] - } else { - local_values.is_padding_byte[i] - } - }; - // If the row has multiple padding bytes, the first padding byte must be 1. - yield_constr.constraint_transition( - is_first_padding_byte * (local_values.block_bytes[i] - P::ONES), - ); - // If the row has multiple padding bytes, the other padding bytes - // except the last one must be 0. - yield_constr.constraint_transition( - local_values.is_padding_byte[i] - * (is_first_padding_byte - P::ONES) - * local_values.block_bytes[i], - ); - } - // If the row has multiple padding bytes, then the last byte must be 0b10000000. - yield_constr.constraint_transition( - is_final_block - * (has_single_padding_byte - P::ONES) - * (local_values.block_bytes[KECCAK_RATE_BYTES - 1] - - P::from(FE::from_canonical_u8(0b10000000))), - ); - // A dummy row is always followed by another dummy row, so the prover can't put // dummy rows "in between" to avoid the above checks. let is_dummy = P::ONES - is_full_input_block - is_final_block; - let next_is_final_block: P = next_values.is_padding_byte[KECCAK_RATE_BYTES - 1]; + let next_is_final_block: P = next_values.is_final_input_len.iter().copied().sum(); yield_constr.constraint_transition( is_dummy * (next_values.is_full_input_block + next_is_final_block), ); @@ -741,8 +689,8 @@ impl, const D: usize> Stark for KeccakSpongeS let t = builder.sub_extension(rc1, range_max); yield_constr.constraint_last_row(builder, t); - // Each flag (full-input block, final block, padding byte or implied dummy flag) - // must be boolean. + // Each flag (full-input block, final block or implied dummy flag) must be + // boolean. let is_full_input_block = local_values.is_full_input_block; let constraint = builder.mul_sub_extension( is_full_input_block, @@ -751,20 +699,12 @@ impl, const D: usize> Stark for KeccakSpongeS ); yield_constr.constraint(builder, constraint); - for &is_padding_byte in local_values.is_padding_byte.iter() { - let constraint = - builder.mul_sub_extension(is_padding_byte, is_padding_byte, is_padding_byte); - yield_constr.constraint(builder, constraint); - } - let is_final_block = local_values.is_padding_byte[KECCAK_RATE_BYTES - 1]; - - // A padding byte is always followed by another padding byte. - for i in 1..KECCAK_RATE_BYTES { - let constraint = builder.mul_sub_extension( - local_values.is_padding_byte[i - 1], - local_values.is_padding_byte[i], - local_values.is_padding_byte[i - 1], - ); + let is_final_block = builder.add_many_extension(local_values.is_final_input_len); + let constraint = builder.mul_sub_extension(is_final_block, is_final_block, is_final_block); + yield_constr.constraint(builder, constraint); + + for &is_final_len in local_values.is_final_input_len.iter() { + let constraint = builder.mul_sub_extension(is_final_len, is_final_len, is_final_len); yield_constr.constraint(builder, constraint); } @@ -865,71 +805,13 @@ impl, const D: usize> Stark for KeccakSpongeS let constraint = builder.mul_extension(is_full_input_block, absorbed_diff); yield_constr.constraint_transition(builder, constraint); - // If the first padding byte is at the end of the block, then the block has a - // single padding byte. - let has_single_padding_byte = builder.sub_extension( - local_values.is_padding_byte[KECCAK_RATE_BYTES - 1], - local_values.is_padding_byte[KECCAK_RATE_BYTES - 2], - ); - - // If the row has a single padding byte, then it must be the last byte with - // value 0b10000001. - let padding_byte = builder.constant_extension(F::Extension::from_canonical_u8(0b10000001)); - let diff = builder.sub_extension( - local_values.block_bytes[KECCAK_RATE_BYTES - 1], - padding_byte, - ); - let constraint = builder.mul_extension(has_single_padding_byte, diff); - yield_constr.constraint_transition(builder, constraint); - - for i in 0..KECCAK_RATE_BYTES - 1 { - let is_first_padding_byte = { - if i > 0 { - builder.sub_extension( - local_values.is_padding_byte[i], - local_values.is_padding_byte[i - 1], - ) - } else { - local_values.is_padding_byte[i] - } - }; - // If the row has multiple padding bytes, the first padding byte must be 1. - let constraint = builder.mul_sub_extension( - is_first_padding_byte, - local_values.block_bytes[i], - is_first_padding_byte, - ); - yield_constr.constraint_transition(builder, constraint); - - // If the row has multiple padding bytes, the other padding bytes - // except the last one must be 0. - let sel = builder.mul_sub_extension( - local_values.is_padding_byte[i], - is_first_padding_byte, - local_values.is_padding_byte[i], - ); - let constraint = builder.mul_extension(sel, local_values.block_bytes[i]); - yield_constr.constraint_transition(builder, constraint); - } - - // If the row has multiple padding bytes, then the last byte must be 0b10000000. - let sel = - builder.mul_sub_extension(is_final_block, has_single_padding_byte, is_final_block); - let padding_byte = builder.constant_extension(F::Extension::from_canonical_u8(0b10000000)); - let diff = builder.sub_extension( - local_values.block_bytes[KECCAK_RATE_BYTES - 1], - padding_byte, - ); - let constraint = builder.mul_extension(sel, diff); - yield_constr.constraint_transition(builder, constraint); - // A dummy row is always followed by another dummy row, so the prover can't put // dummy rows "in between" to avoid the above checks. let is_dummy = { let tmp = builder.sub_extension(one, is_final_block); builder.sub_extension(tmp, is_full_input_block) }; - let next_is_final_block = next_values.is_padding_byte[KECCAK_RATE_BYTES - 1]; + let next_is_final_block = builder.add_many_extension(next_values.is_final_input_len); let constraint = { let tmp = builder.add_extension(next_is_final_block, next_values.is_full_input_block); builder.mul_extension(is_dummy, tmp) @@ -946,7 +828,7 @@ impl, const D: usize> Stark for KeccakSpongeS columns: Column::singles(get_block_bytes_range()).collect(), table_column: Column::single(RANGE_COUNTER), frequencies_column: Column::single(RC_FREQUENCIES), - filter_columns: vec![Default::default(); KECCAK_RATE_BYTES], + filter_columns: vec![None; KECCAK_RATE_BYTES], }] } diff --git a/evm_arithmetization/src/lib.rs b/evm_arithmetization/src/lib.rs index bd4f20147..b3cdc0e37 100644 --- a/evm_arithmetization/src/lib.rs +++ b/evm_arithmetization/src/lib.rs @@ -223,8 +223,6 @@ static GLOBAL: Jemalloc = Jemalloc; // Public definitions and re-exports pub type Node = mpt_trie::partial_trie::Node; -/// A type alias for `u64` of a block height. -pub type BlockHeight = u64; pub use all_stark::AllStark; pub use fixed_recursive_verifier::AllRecursiveCircuits; diff --git a/evm_arithmetization/src/memory/memory_stark.rs b/evm_arithmetization/src/memory/memory_stark.rs index f788024fd..66f1ca42c 100644 --- a/evm_arithmetization/src/memory/memory_stark.rs +++ b/evm_arithmetization/src/memory/memory_stark.rs @@ -581,8 +581,11 @@ impl, const D: usize> Stark for MemoryStark, const D } } -pub(crate) fn debug_public_values(public_values: &PublicValues) { - log::debug!("Public Values:"); - log::debug!( - " Trie Roots Before: {:?}", - &public_values.trie_roots_before - ); - log::debug!(" Trie Roots After: {:?}", &public_values.trie_roots_after); - log::debug!(" Block Metadata: {:?}", &public_values.block_metadata); - log::debug!(" Block Hashes: {:?}", &public_values.block_hashes); - log::debug!(" Extra Block Data: {:?}", &public_values.extra_block_data); -} - pub fn set_public_value_targets( witness: &mut W, public_values_target: &PublicValuesTarget, @@ -656,8 +644,6 @@ where F: RichField + Extendable, W: Witness, { - debug_public_values(public_values); - set_trie_roots_target( witness, &public_values_target.trie_roots_before, diff --git a/evm_arithmetization/tests/add11_yml.rs b/evm_arithmetization/tests/add11_yml.rs index 00d7e56b4..772bd4774 100644 --- a/evm_arithmetization/tests/add11_yml.rs +++ b/evm_arithmetization/tests/add11_yml.rs @@ -63,9 +63,9 @@ fn add11_yml() -> anyhow::Result<()> { 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())?; + ); + 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, @@ -119,10 +119,10 @@ fn add11_yml() -> anyhow::Result<()> { expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), - )?; + ); expected_state_trie_after - .insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec())?; - expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec())?; + .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 }; @@ -136,7 +136,7 @@ fn add11_yml() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - )?; + ); let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), diff --git a/evm_arithmetization/tests/basic_smart_contract.rs b/evm_arithmetization/tests/basic_smart_contract.rs index fd0948d80..6f9bfc8d2 100644 --- a/evm_arithmetization/tests/basic_smart_contract.rs +++ b/evm_arithmetization/tests/basic_smart_contract.rs @@ -168,7 +168,7 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - )?; + ); let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), diff --git a/evm_arithmetization/tests/erc20.rs b/evm_arithmetization/tests/erc20.rs index 609579af9..ef4b22878 100644 --- a/evm_arithmetization/tests/erc20.rs +++ b/evm_arithmetization/tests/erc20.rs @@ -62,13 +62,13 @@ fn test_erc20() -> anyhow::Result<()> { let token_nibbles = Nibbles::from_bytes_be(token_state_key.as_bytes()).unwrap(); let mut state_trie_before = HashedPartialTrie::from(Node::Empty); - 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())?; + 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![ - (giver_state_key, giver_storage()?), - (token_state_key, token_storage()?), + (giver_state_key, giver_storage()), + (token_state_key, token_storage()), ]; let tries_before = TrieInputs { @@ -107,13 +107,13 @@ fn test_erc20() -> anyhow::Result<()> { balance: sender_account.balance - gas_used * 0xa, ..sender_account }; - state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec())?; - state_trie_after.insert(giver_nibbles, rlp::encode(&giver_account()?).to_vec())?; + state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); + state_trie_after.insert(giver_nibbles, rlp::encode(&giver_account()).to_vec()); let token_account_after = AccountRlp { - storage_root: token_storage_after()?.hash(), - ..token_account()? + storage_root: token_storage_after().hash(), + ..token_account() }; - state_trie_after.insert(token_nibbles, rlp::encode(&token_account_after).to_vec())?; + state_trie_after.insert(token_nibbles, rlp::encode(&token_account_after).to_vec()); state_trie_after }; @@ -144,7 +144,7 @@ fn test_erc20() -> anyhow::Result<()> { }], }; let mut receipts_trie = HashedPartialTrie::from(Node::Empty); - receipts_trie.insert(Nibbles::from_str("0x80").unwrap(), receipt_0.encode(2))?; + receipts_trie.insert(Nibbles::from_str("0x80").unwrap(), receipt_0.encode(2)); let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), @@ -192,72 +192,71 @@ fn token_bytecode() -> Vec { hex!("608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce567146100fe57806370a082311461010d57806395d89b4114610136578063a9059cbb1461013e578063dd62ed3e1461015157600080fd5b806306fdde0314610098578063095ea7b3146100b657806318160ddd146100d957806323b872dd146100eb575b600080fd5b6100a061018a565b6040516100ad919061056a565b60405180910390f35b6100c96100c43660046105d4565b61021c565b60405190151581526020016100ad565b6002545b6040519081526020016100ad565b6100c96100f93660046105fe565b610236565b604051601281526020016100ad565b6100dd61011b36600461063a565b6001600160a01b031660009081526020819052604090205490565b6100a061025a565b6100c961014c3660046105d4565b610269565b6100dd61015f36600461065c565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6060600380546101999061068f565b80601f01602080910402602001604051908101604052809291908181526020018280546101c59061068f565b80156102125780601f106101e757610100808354040283529160200191610212565b820191906000526020600020905b8154815290600101906020018083116101f557829003601f168201915b5050505050905090565b60003361022a818585610277565b60019150505b92915050565b600033610244858285610289565b61024f85858561030c565b506001949350505050565b6060600480546101999061068f565b60003361022a81858561030c565b610284838383600161036b565b505050565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461030657818110156102f757604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064015b60405180910390fd5b6103068484848403600061036b565b50505050565b6001600160a01b03831661033657604051634b637e8f60e11b8152600060048201526024016102ee565b6001600160a01b0382166103605760405163ec442f0560e01b8152600060048201526024016102ee565b610284838383610440565b6001600160a01b0384166103955760405163e602df0560e01b8152600060048201526024016102ee565b6001600160a01b0383166103bf57604051634a1406b160e11b8152600060048201526024016102ee565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561030657826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161043291815260200190565b60405180910390a350505050565b6001600160a01b03831661046b57806002600082825461046091906106c9565b909155506104dd9050565b6001600160a01b038316600090815260208190526040902054818110156104be5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016102ee565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b0382166104f957600280548290039055610518565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161055d91815260200190565b60405180910390a3505050565b600060208083528351808285015260005b818110156105975785810183015185820160400152820161057b565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146105cf57600080fd5b919050565b600080604083850312156105e757600080fd5b6105f0836105b8565b946020939093013593505050565b60008060006060848603121561061357600080fd5b61061c846105b8565b925061062a602085016105b8565b9150604084013590509250925092565b60006020828403121561064c57600080fd5b610655826105b8565b9392505050565b6000806040838503121561066f57600080fd5b610678836105b8565b9150610686602084016105b8565b90509250929050565b600181811c908216806106a357607f821691505b6020821081036106c357634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561023057634e487b7160e01b600052601160045260246000fdfea2646970667358221220266a323ae4a816f6c6342a5be431fedcc0d45c44b02ea75f5474eb450b5d45b364736f6c63430008140033").into() } -fn insert_storage(trie: &mut HashedPartialTrie, slot: U256, value: U256) -> anyhow::Result<()> { +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)?; - Ok(()) + trie.insert(nibbles, r); } fn sd2u(s: &str) -> U256 { U256::from_dec_str(s).unwrap() } -fn giver_storage() -> anyhow::Result { +fn giver_storage() -> HashedPartialTrie { let mut trie = HashedPartialTrie::from(Node::Empty); insert_storage( &mut trie, U256::zero(), sd2u("546584486846459126461364135121053344201067465379"), - )?; - Ok(trie) + ); + trie } -fn token_storage() -> anyhow::Result { +fn token_storage() -> HashedPartialTrie { let mut trie = HashedPartialTrie::from(Node::Empty); insert_storage( &mut trie, sd2u("82183438603287090451672504949863617512989139203883434767553028632841710582583"), sd2u("1000000000000000000000"), - )?; - Ok(trie) + ); + trie } -fn token_storage_after() -> anyhow::Result { +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"), - )?; - Ok(trie) + ); + trie } -fn giver_account() -> anyhow::Result { - Ok(AccountRlp { +fn giver_account() -> AccountRlp { + AccountRlp { nonce: 1.into(), balance: 0.into(), - storage_root: giver_storage()?.hash(), + storage_root: giver_storage().hash(), code_hash: keccak(giver_bytecode()), - }) + } } -fn token_account() -> anyhow::Result { - Ok(AccountRlp { +fn token_account() -> AccountRlp { + AccountRlp { nonce: 1.into(), balance: 0.into(), - storage_root: token_storage()?.hash(), + storage_root: token_storage().hash(), code_hash: keccak(token_bytecode()), - }) + } } fn sender_account() -> AccountRlp { diff --git a/evm_arithmetization/tests/erc721.rs b/evm_arithmetization/tests/erc721.rs index 86dd34002..207fa69db 100644 --- a/evm_arithmetization/tests/erc721.rs +++ b/evm_arithmetization/tests/erc721.rs @@ -62,10 +62,10 @@ fn test_erc721() -> anyhow::Result<()> { let contract_nibbles = Nibbles::from_bytes_be(contract_state_key.as_bytes()).unwrap(); let mut state_trie_before = HashedPartialTrie::from(Node::Empty); - state_trie_before.insert(owner_nibbles, rlp::encode(&owner_account()).to_vec())?; - state_trie_before.insert(contract_nibbles, rlp::encode(&contract_account()?).to_vec())?; + 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()?)]; + let storage_tries = vec![(contract_state_key, contract_storage())]; let tries_before = TrieInputs { state_trie: state_trie_before, @@ -90,15 +90,15 @@ fn test_erc721() -> anyhow::Result<()> { balance: owner_account.balance - gas_used * 0xa, ..owner_account }; - state_trie_after.insert(owner_nibbles, rlp::encode(&owner_account_after).to_vec())?; + state_trie_after.insert(owner_nibbles, rlp::encode(&owner_account_after).to_vec()); let contract_account_after = AccountRlp { - storage_root: contract_storage_after()?.hash(), - ..contract_account()? + storage_root: contract_storage_after().hash(), + ..contract_account() }; state_trie_after.insert( contract_nibbles, rlp::encode(&contract_account_after).to_vec(), - )?; + ); state_trie_after }; @@ -128,7 +128,7 @@ fn test_erc721() -> anyhow::Result<()> { logs, }; let mut receipts_trie = HashedPartialTrie::from(Node::Empty); - receipts_trie.insert(Nibbles::from_str("0x80").unwrap(), receipt_0.encode(0))?; + receipts_trie.insert(Nibbles::from_str("0x80").unwrap(), receipt_0.encode(0)); let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), @@ -191,16 +191,14 @@ fn contract_bytecode() -> Vec { hex!("608060405234801561000f575f80fd5b5060043610610109575f3560e01c8063715018a6116100a0578063a22cb4651161006f578063a22cb465146102a1578063b88d4fde146102bd578063c87b56dd146102d9578063e985e9c514610309578063f2fde38b1461033957610109565b8063715018a61461023f5780638da5cb5b1461024957806395d89b4114610267578063a14481941461028557610109565b806323b872dd116100dc57806323b872dd146101a757806342842e0e146101c35780636352211e146101df57806370a082311461020f57610109565b806301ffc9a71461010d57806306fdde031461013d578063081812fc1461015b578063095ea7b31461018b575b5f80fd5b61012760048036038101906101229190611855565b610355565b604051610134919061189a565b60405180910390f35b610145610436565b604051610152919061193d565b60405180910390f35b61017560048036038101906101709190611990565b6104c5565b60405161018291906119fa565b60405180910390f35b6101a560048036038101906101a09190611a3d565b6104e0565b005b6101c160048036038101906101bc9190611a7b565b6104f6565b005b6101dd60048036038101906101d89190611a7b565b6105f5565b005b6101f960048036038101906101f49190611990565b610614565b60405161020691906119fa565b60405180910390f35b61022960048036038101906102249190611acb565b610625565b6040516102369190611b05565b60405180910390f35b6102476106db565b005b6102516106ee565b60405161025e91906119fa565b60405180910390f35b61026f610716565b60405161027c919061193d565b60405180910390f35b61029f600480360381019061029a9190611a3d565b6107a6565b005b6102bb60048036038101906102b69190611b48565b6107bc565b005b6102d760048036038101906102d29190611cb2565b6107d2565b005b6102f360048036038101906102ee9190611990565b6107ef565b604051610300919061193d565b60405180910390f35b610323600480360381019061031e9190611d32565b610855565b604051610330919061189a565b60405180910390f35b610353600480360381019061034e9190611acb565b6108e3565b005b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061041f57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061042f575061042e82610967565b5b9050919050565b60605f805461044490611d9d565b80601f016020809104026020016040519081016040528092919081815260200182805461047090611d9d565b80156104bb5780601f10610492576101008083540402835291602001916104bb565b820191905f5260205f20905b81548152906001019060200180831161049e57829003601f168201915b5050505050905090565b5f6104cf826109d0565b506104d982610a56565b9050919050565b6104f282826104ed610a8f565b610a96565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610566575f6040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161055d91906119fa565b60405180910390fd5b5f6105798383610574610a8f565b610aa8565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105ef578382826040517f64283d7b0000000000000000000000000000000000000000000000000000000081526004016105e693929190611dcd565b60405180910390fd5b50505050565b61060f83838360405180602001604052805f8152506107d2565b505050565b5f61061e826109d0565b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610696575f6040517f89c62b6400000000000000000000000000000000000000000000000000000000815260040161068d91906119fa565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6106e3610cb3565b6106ec5f610d3a565b565b5f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60606001805461072590611d9d565b80601f016020809104026020016040519081016040528092919081815260200182805461075190611d9d565b801561079c5780601f106107735761010080835404028352916020019161079c565b820191905f5260205f20905b81548152906001019060200180831161077f57829003601f168201915b5050505050905090565b6107ae610cb3565b6107b88282610dfd565b5050565b6107ce6107c7610a8f565b8383610e1a565b5050565b6107dd8484846104f6565b6107e984848484610f83565b50505050565b60606107fa826109d0565b505f610804611135565b90505f8151116108225760405180602001604052805f81525061084d565b8061082c8461114b565b60405160200161083d929190611e3c565b6040516020818303038152906040525b915050919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b6108eb610cb3565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361095b575f6040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260040161095291906119fa565b60405180910390fd5b61096481610d3a565b50565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f806109db83611215565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610a4d57826040517f7e273289000000000000000000000000000000000000000000000000000000008152600401610a449190611b05565b60405180910390fd5b80915050919050565b5f60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f33905090565b610aa3838383600161124e565b505050565b5f80610ab384611215565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610af457610af381848661140d565b5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610b7f57610b335f855f8061124e565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825403925050819055505b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614610bfe57600160035f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8460025f8681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4809150509392505050565b610cbb610a8f565b73ffffffffffffffffffffffffffffffffffffffff16610cd96106ee565b73ffffffffffffffffffffffffffffffffffffffff1614610d3857610cfc610a8f565b6040517f118cdaa7000000000000000000000000000000000000000000000000000000008152600401610d2f91906119fa565b60405180910390fd5b565b5f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160065f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b610e16828260405180602001604052805f8152506114d0565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610e8a57816040517f5b08ba18000000000000000000000000000000000000000000000000000000008152600401610e8191906119fa565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610f76919061189a565b60405180910390a3505050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b111561112f578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02610fc6610a8f565b8685856040518563ffffffff1660e01b8152600401610fe89493929190611eb1565b6020604051808303815f875af192505050801561102357506040513d601f19601f820116820180604052508101906110209190611f0f565b60015b6110a4573d805f8114611051576040519150601f19603f3d011682016040523d82523d5f602084013e611056565b606091505b505f81510361109c57836040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161109391906119fa565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461112d57836040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161112491906119fa565b60405180910390fd5b505b50505050565b606060405180602001604052805f815250905090565b60605f6001611159846114eb565b0190505f8167ffffffffffffffff81111561117757611176611b8e565b5b6040519080825280601f01601f1916602001820160405280156111a95781602001600182028036833780820191505090505b5090505f82602001820190505b60011561120a578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a85816111ff576111fe611f3a565b5b0494505f85036111b6575b819350505050919050565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b808061128657505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b156113b8575f611295846109d0565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156112ff57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561131257506113108184610855565b155b1561135457826040517fa9fbf51f00000000000000000000000000000000000000000000000000000000815260040161134b91906119fa565b60405180910390fd5b81156113b657838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b8360045f8581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b61141883838361163c565b6114cb575f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361148c57806040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016114839190611b05565b60405180910390fd5b81816040517f177e802f0000000000000000000000000000000000000000000000000000000081526004016114c2929190611f67565b60405180910390fd5b505050565b6114da83836116fc565b6114e65f848484610f83565b505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310611547577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161153d5761153c611f3a565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310611584576d04ee2d6d415b85acef8100000000838161157a57611579611f3a565b5b0492506020810190505b662386f26fc1000083106115b357662386f26fc1000083816115a9576115a8611f3a565b5b0492506010810190505b6305f5e10083106115dc576305f5e10083816115d2576115d1611f3a565b5b0492506008810190505b61271083106116015761271083816115f7576115f6611f3a565b5b0492506004810190505b60648310611624576064838161161a57611619611f3a565b5b0492506002810190505b600a8310611633576001810190505b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156116f357508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806116b457506116b38484610855565b5b806116f257508273ffffffffffffffffffffffffffffffffffffffff166116da83610a56565b73ffffffffffffffffffffffffffffffffffffffff16145b5b90509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361176c575f6040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161176391906119fa565b60405180910390fd5b5f61177883835f610aa8565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146117ea575f6040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081526004016117e191906119fa565b60405180910390fd5b505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61183481611800565b811461183e575f80fd5b50565b5f8135905061184f8161182b565b92915050565b5f6020828403121561186a576118696117f8565b5b5f61187784828501611841565b91505092915050565b5f8115159050919050565b61189481611880565b82525050565b5f6020820190506118ad5f83018461188b565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156118ea5780820151818401526020810190506118cf565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61190f826118b3565b61191981856118bd565b93506119298185602086016118cd565b611932816118f5565b840191505092915050565b5f6020820190508181035f8301526119558184611905565b905092915050565b5f819050919050565b61196f8161195d565b8114611979575f80fd5b50565b5f8135905061198a81611966565b92915050565b5f602082840312156119a5576119a46117f8565b5b5f6119b28482850161197c565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6119e4826119bb565b9050919050565b6119f4816119da565b82525050565b5f602082019050611a0d5f8301846119eb565b92915050565b611a1c816119da565b8114611a26575f80fd5b50565b5f81359050611a3781611a13565b92915050565b5f8060408385031215611a5357611a526117f8565b5b5f611a6085828601611a29565b9250506020611a718582860161197c565b9150509250929050565b5f805f60608486031215611a9257611a916117f8565b5b5f611a9f86828701611a29565b9350506020611ab086828701611a29565b9250506040611ac18682870161197c565b9150509250925092565b5f60208284031215611ae057611adf6117f8565b5b5f611aed84828501611a29565b91505092915050565b611aff8161195d565b82525050565b5f602082019050611b185f830184611af6565b92915050565b611b2781611880565b8114611b31575f80fd5b50565b5f81359050611b4281611b1e565b92915050565b5f8060408385031215611b5e57611b5d6117f8565b5b5f611b6b85828601611a29565b9250506020611b7c85828601611b34565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b611bc4826118f5565b810181811067ffffffffffffffff82111715611be357611be2611b8e565b5b80604052505050565b5f611bf56117ef565b9050611c018282611bbb565b919050565b5f67ffffffffffffffff821115611c2057611c1f611b8e565b5b611c29826118f5565b9050602081019050919050565b828183375f83830152505050565b5f611c56611c5184611c06565b611bec565b905082815260208101848484011115611c7257611c71611b8a565b5b611c7d848285611c36565b509392505050565b5f82601f830112611c9957611c98611b86565b5b8135611ca9848260208601611c44565b91505092915050565b5f805f8060808587031215611cca57611cc96117f8565b5b5f611cd787828801611a29565b9450506020611ce887828801611a29565b9350506040611cf98782880161197c565b925050606085013567ffffffffffffffff811115611d1a57611d196117fc565b5b611d2687828801611c85565b91505092959194509250565b5f8060408385031215611d4857611d476117f8565b5b5f611d5585828601611a29565b9250506020611d6685828601611a29565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611db457607f821691505b602082108103611dc757611dc6611d70565b5b50919050565b5f606082019050611de05f8301866119eb565b611ded6020830185611af6565b611dfa60408301846119eb565b949350505050565b5f81905092915050565b5f611e16826118b3565b611e208185611e02565b9350611e308185602086016118cd565b80840191505092915050565b5f611e478285611e0c565b9150611e538284611e0c565b91508190509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611e8382611e5f565b611e8d8185611e69565b9350611e9d8185602086016118cd565b611ea6816118f5565b840191505092915050565b5f608082019050611ec45f8301876119eb565b611ed160208301866119eb565b611ede6040830185611af6565b8181036060830152611ef08184611e79565b905095945050505050565b5f81519050611f098161182b565b92915050565b5f60208284031215611f2457611f236117f8565b5b5f611f3184828501611efb565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f604082019050611f7a5f8301856119eb565b611f876020830184611af6565b939250505056fea2646970667358221220432b30673e00c0eb009e1718c271f4cfdfbeded17345829703b06d322360990164736f6c63430008160033").into() } -fn insert_storage(trie: &mut HashedPartialTrie, slot: U256, value: U256) -> anyhow::Result<()> { +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)?; - - Ok(()) + trie.insert(nibbles, r); } fn sd2u(s: &str) -> U256 { @@ -211,64 +209,64 @@ fn sh2u(s: &str) -> U256 { U256::from_str_radix(s, 16).unwrap() } -fn contract_storage() -> anyhow::Result { +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"), - )?; - Ok(trie) + ); + trie } -fn contract_storage_after() -> anyhow::Result { +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"), - )?; - Ok(trie) + ); + trie } fn owner_account() -> AccountRlp { @@ -280,13 +278,13 @@ fn owner_account() -> AccountRlp { } } -fn contract_account() -> anyhow::Result { - Ok(AccountRlp { +fn contract_account() -> AccountRlp { + AccountRlp { nonce: 0.into(), balance: 0.into(), - storage_root: contract_storage()?.hash(), + storage_root: contract_storage().hash(), code_hash: keccak(contract_bytecode()), - }) + } } fn signed_tx() -> Vec { diff --git a/evm_arithmetization/tests/log_opcode.rs b/evm_arithmetization/tests/log_opcode.rs index 75cdd44f5..56e5bbf6d 100644 --- a/evm_arithmetization/tests/log_opcode.rs +++ b/evm_arithmetization/tests/log_opcode.rs @@ -88,9 +88,9 @@ fn test_log_opcodes() -> anyhow::Result<()> { 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())?; + ); + 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()); // We now add two receipts with logs and data. This updates the receipt trie as // well. @@ -119,7 +119,7 @@ fn test_log_opcodes() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x1337").unwrap(), rlp::encode(&receipt_0).to_vec(), - )?; + ); let tries_before = TrieInputs { state_trie: state_trie_before, @@ -193,17 +193,16 @@ fn test_log_opcodes() -> anyhow::Result<()> { let receipt_nibbles = Nibbles::from_str("0x80").unwrap(); // RLP(0) = 0x80 - receipts_trie.insert(receipt_nibbles, rlp::encode(&receipt).to_vec())?; + receipts_trie.insert(receipt_nibbles, rlp::encode(&receipt).to_vec()); // Update the state trie. let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty); expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), - )?; - expected_state_trie_after - .insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec())?; - expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec())?; + ); + 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()); let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), @@ -320,13 +319,13 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { 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())?; + ); + 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()); state_trie_before.insert( to_second_nibbles, rlp::encode(&to_account_second_before).to_vec(), - )?; + ); let checkpoint_state_trie_root = state_trie_before.hash(); let tries_before = TrieInputs { @@ -390,14 +389,13 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), - )?; - expected_state_trie_after - .insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec())?; - expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec())?; + ); + 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( to_second_nibbles, rlp::encode(&to_account_second_before).to_vec(), - )?; + ); // Compute new receipt trie. let mut receipts_trie = HashedPartialTrie::from(Node::Empty); @@ -410,7 +408,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - )?; + ); let mut transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), @@ -532,23 +530,22 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { let receipt_nibbles = Nibbles::from_str("0x01").unwrap(); // RLP(1) = 0x1 - receipts_trie.insert(receipt_nibbles, rlp::encode(&receipt).to_vec())?; + receipts_trie.insert(receipt_nibbles, rlp::encode(&receipt).to_vec()); // Update the state trie. let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty); expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), - )?; - expected_state_trie_after - .insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec())?; - expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec())?; + ); + 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( to_second_nibbles, rlp::encode(&to_account_second_after).to_vec(), - )?; + ); - transactions_trie.insert(Nibbles::from_str("0x01").unwrap(), txn_2.to_vec())?; + transactions_trie.insert(Nibbles::from_str("0x01").unwrap(), txn_2.to_vec()); let block_1_state_root = expected_state_trie_after.hash(); @@ -690,7 +687,7 @@ fn test_txn_and_receipt_trie_hash() -> anyhow::Result<()> { example_txn_trie.insert( Nibbles::from_str("0x80").unwrap(), // RLP(0) = 0x80 rlp::encode(&transaction_0).to_vec(), - )?; + ); let transaction_1 = LegacyTransactionRlp { nonce: 157824u64.into(), @@ -710,7 +707,7 @@ fn test_txn_and_receipt_trie_hash() -> anyhow::Result<()> { example_txn_trie.insert( Nibbles::from_str("0x01").unwrap(), rlp::encode(&transaction_1).to_vec(), - )?; + ); // Receipts: let mut example_receipt_trie = HashedPartialTrie::from(Node::Empty); @@ -738,7 +735,7 @@ fn test_txn_and_receipt_trie_hash() -> anyhow::Result<()> { example_receipt_trie.insert( Nibbles::from_str("0x80").unwrap(), // RLP(0) is 0x80 rlp::encode(&receipt_0).to_vec(), - )?; + ); let log_1 = LogRlp { address: hex!("7ef66b77759e12Caf3dDB3E4AFF524E577C59D8D").into(), @@ -763,7 +760,7 @@ fn test_txn_and_receipt_trie_hash() -> anyhow::Result<()> { example_receipt_trie.insert( Nibbles::from_str("0x01").unwrap(), rlp::encode(&receipt_1).to_vec(), - )?; + ); // Check that the trie hashes are correct. assert_eq!( diff --git a/evm_arithmetization/tests/self_balance_gas_cost.rs b/evm_arithmetization/tests/self_balance_gas_cost.rs index 510c33cb3..979e43abd 100644 --- a/evm_arithmetization/tests/self_balance_gas_cost.rs +++ b/evm_arithmetization/tests/self_balance_gas_cost.rs @@ -77,9 +77,9 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { 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())?; + ); + 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, @@ -138,10 +138,10 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), - )?; + ); expected_state_trie_after - .insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec())?; - expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec())?; + .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 }; @@ -155,7 +155,7 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - )?; + ); let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), diff --git a/evm_arithmetization/tests/selfdestruct.rs b/evm_arithmetization/tests/selfdestruct.rs index 0ef48d2f4..f48248f69 100644 --- a/evm_arithmetization/tests/selfdestruct.rs +++ b/evm_arithmetization/tests/selfdestruct.rs @@ -57,8 +57,8 @@ fn test_selfdestruct() -> anyhow::Result<()> { }; let mut state_trie_before = HashedPartialTrie::from(Node::Empty); - 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())?; + 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, @@ -93,7 +93,7 @@ fn test_selfdestruct() -> anyhow::Result<()> { storage_root: HashedPartialTrie::from(Node::Empty).hash(), code_hash: keccak([]), }; - state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec())?; + state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); state_trie_after }; @@ -107,7 +107,7 @@ fn test_selfdestruct() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - )?; + ); let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), diff --git a/evm_arithmetization/tests/simple_transfer.rs b/evm_arithmetization/tests/simple_transfer.rs index 8adbc1c42..3fb3b08f6 100644 --- a/evm_arithmetization/tests/simple_transfer.rs +++ b/evm_arithmetization/tests/simple_transfer.rs @@ -123,7 +123,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { receipts_trie.insert( Nibbles::from_str("0x80").unwrap(), rlp::encode(&receipt_0).to_vec(), - )?; + ); let transactions_trie: HashedPartialTrie = Node::Leaf { nibbles: Nibbles::from_str("0x80").unwrap(), value: txn.to_vec(), diff --git a/evm_arithmetization/tests/withdrawals.rs b/evm_arithmetization/tests/withdrawals.rs index 7f133518b..28dc6da59 100644 --- a/evm_arithmetization/tests/withdrawals.rs +++ b/evm_arithmetization/tests/withdrawals.rs @@ -50,7 +50,7 @@ fn test_withdrawals() -> anyhow::Result<()> { balance: withdrawals[0].1, ..AccountRlp::default() }; - trie.insert(addr_nibbles, rlp::encode(&account).to_vec())?; + trie.insert(addr_nibbles, rlp::encode(&account).to_vec()); trie }; diff --git a/mpt_trie/Cargo.toml b/mpt_trie/Cargo.toml index b4ef7ded2..41b4f704c 100644 --- a/mpt_trie/Cargo.toml +++ b/mpt_trie/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "mpt_trie" description = "Types and utility functions for building/working with partial Ethereum tries." -version = "0.2.1" +version = "0.2.0" authors = ["Polygon Zero "] readme = "README.md" edition.workspace = true @@ -27,10 +27,6 @@ num-traits = "0.2.15" uint = "0.9.5" rlp = { workspace = true } serde = { workspace = true, features = ["derive", "rc"] } -impl-rlp = "0.3.0" -impl-codec = "0.6.0" -impl-serde = "0.4.0" -impl-num-traits = "0.1.2" [dev-dependencies] eth_trie = "0.4.0" diff --git a/mpt_trie/examples/ethereum_trie.rs b/mpt_trie/examples/ethereum_trie.rs index d1aa1f799..53e3ad70e 100644 --- a/mpt_trie/examples/ethereum_trie.rs +++ b/mpt_trie/examples/ethereum_trie.rs @@ -13,8 +13,6 @@ use std::ops::RangeInclusive; use ethereum_types::{H160, H256, U256}; use keccak_hash::keccak; use mpt_trie::partial_trie::PartialTrie; -use mpt_trie::trie_ops::TrieOpResult; -use mpt_trie::utils::TryFromIterator; use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, StandardTrie}, @@ -38,38 +36,34 @@ struct StateTrieEntry { code_hash: H256, } -fn main() -> TrieOpResult<()> { +fn main() { let mut rng = StdRng::seed_from_u64(0); let (account_entries, account_storage_tries): (Vec<_>, Vec<_>) = (0..NUM_ACCOUNTS_TO_GEN) .map(|_| generate_fake_account_and_storage_trie(&mut rng)) - .collect::, _>>()? - .into_iter() .unzip(); - let _state_trie = StandardTrie::try_from_iter( + let _state_trie = StandardTrie::from_iter( account_entries .into_iter() .map(|(k, acc)| (Nibbles::from_h256_be(k), acc.rlp_bytes().to_vec())), - )?; + ); let _account_storage_tries: Vec<(AccountAddr, HashedPartialTrie)> = account_storage_tries; - Ok(()) - // TODO: Generate remaining tries... } fn generate_fake_account_and_storage_trie( rng: &mut StdRng, -) -> TrieOpResult<( +) -> ( (HashedAccountAddr, StateTrieEntry), (AccountAddr, HashedPartialTrie), -)> { +) { let account_addr: H160 = rng.gen(); let hashed_account_addr = keccak(account_addr.as_bytes()); - let account_storage_trie = generate_fake_account_storage_trie(rng)?; + let account_storage_trie = generate_fake_account_storage_trie(rng); let acc_entry = StateTrieEntry { nonce: gen_u256(rng), @@ -79,16 +73,16 @@ fn generate_fake_account_and_storage_trie( * "fake" it here. */ }; - Ok(( + ( (hashed_account_addr, acc_entry), (account_addr, account_storage_trie), - )) + ) } -fn generate_fake_account_storage_trie(rng: &mut StdRng) -> TrieOpResult { +fn generate_fake_account_storage_trie(rng: &mut StdRng) -> HashedPartialTrie { let num_storage_entries = rng.gen_range(RANGE_OF_STORAGE_ENTRIES_AN_ACCOUNT_CAN_HAVE); - HashedPartialTrie::try_from_iter((0..num_storage_entries).map(|_| { + HashedPartialTrie::from_iter((0..num_storage_entries).map(|_| { let hashed_storage_addr = Nibbles::from_h256_be(rng.gen::()); let storage_data = gen_u256(rng).rlp_bytes().to_vec(); diff --git a/mpt_trie/examples/hash_nodes.rs b/mpt_trie/examples/hash_nodes.rs index 2b18d33fc..0a27dd72d 100644 --- a/mpt_trie/examples/hash_nodes.rs +++ b/mpt_trie/examples/hash_nodes.rs @@ -54,10 +54,9 @@ use mpt_trie::partial_trie::PartialTrie; use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, Node}, - trie_ops::TrieOpResult, }; -fn main() -> TrieOpResult<()> { +fn main() { pretty_env_logger::try_init().unwrap(); // Lets build the (binary) tries in the module-level docs. Since the example @@ -67,10 +66,10 @@ fn main() -> TrieOpResult<()> { // Note the nibbles read the most significant nibble first (eg. `0x12` reads `1` // first). - full_trie.insert(Nibbles::from_str("0x00").unwrap(), large_val(1))?; // 1st from left. - full_trie.insert(Nibbles::from_str("0x01").unwrap(), large_val(2))?; // 2nd from left. - full_trie.insert(Nibbles::from(0x10_u64), large_val(3))?; // 3rd from left. - full_trie.insert(Nibbles::from(0x11_u64), large_val(4))?; // 4th from left. + full_trie.insert(Nibbles::from_str("0x00").unwrap(), large_val(1)); // 1st from left. + full_trie.insert(Nibbles::from_str("0x01").unwrap(), large_val(2)); // 2nd from left. + full_trie.insert(Nibbles::from(0x10_u64), large_val(3)); // 3rd from left. + full_trie.insert(Nibbles::from(0x11_u64), large_val(4)); // 4th from left. let full_trie_hash = full_trie.hash(); @@ -84,16 +83,14 @@ fn main() -> TrieOpResult<()> { // Hash version. `0` branch is replaced with a `Hash` node. let mut hash_trie = HashedPartialTrie::default(); - hash_trie.insert(Nibbles::from_str("0x0").unwrap(), left_side_hash)?; // Hash node - hash_trie.insert(0x10_u64, large_val(3))?; // 3rd from left. - hash_trie.insert(0x11_u64, large_val(4))?; // 4th from left. + hash_trie.insert(Nibbles::from_str("0x0").unwrap(), left_side_hash); // Hash node + hash_trie.insert(0x10_u64, large_val(3)); // 3rd from left. + hash_trie.insert(0x11_u64, large_val(4)); // 4th from left. let hash_trie_hash = hash_trie.hash(); // Hashes should be equal. assert_eq!(full_trie_hash, hash_trie_hash); - - Ok(()) } /// We want to ensure that all leafs are >= 32 bytes when RLP encoded in order diff --git a/mpt_trie/examples/simple.rs b/mpt_trie/examples/simple.rs index eb70a52b1..15917e843 100644 --- a/mpt_trie/examples/simple.rs +++ b/mpt_trie/examples/simple.rs @@ -3,14 +3,13 @@ use std::iter::once; use mpt_trie::partial_trie::PartialTrie; -use mpt_trie::utils::TryFromIterator; use mpt_trie::{ nibbles::{Nibbles, ToNibbles}, partial_trie::{HashedPartialTrie, StandardTrie}, - trie_ops::{TrieOpResult, ValOrHash}, + trie_ops::ValOrHash, }; -fn main() -> TrieOpResult<()> { +fn main() { // Construct an empty trie: let mut trie = StandardTrie::default(); @@ -18,13 +17,13 @@ fn main() -> TrieOpResult<()> { trie.insert( Nibbles::from_bytes_be(b"hello").unwrap(), b"world!".to_vec(), - )?; + ); // Or by initializing the trie with an iterator of key value pairs: - let mut trie = StandardTrie::try_from_iter(vec![ + let mut trie = StandardTrie::from_iter(vec![ (0x1234_u32, b"some data".to_vec()), (9001_u32, vec![1, 2, 3]), - ])?; + ]); // Tries can be queried: assert_eq!(trie.get(0x1234_u32), Some(b"some data".as_slice())); @@ -44,8 +43,8 @@ fn main() -> TrieOpResult<()> { ); // Values can be deleted: - let del_val = trie.delete(0x1234_u32)?; - assert_eq!(del_val.unwrap(), b"some data".to_vec()); + let del_val = trie.delete(0x1234_u32); + assert_eq!(del_val, Some(b"some data".to_vec())); assert_eq!(trie.get(0x1234_u32), None); // It's important to note how types are converted to `Nibbles`. This is @@ -60,13 +59,11 @@ fn main() -> TrieOpResult<()> { // Note that `From` just calls `to_nibbles` by default instead of // `to_nibbles_byte_padded`. - let hash_1 = HashedPartialTrie::try_from_iter(once(( - 0x19002_u32.to_nibbles_byte_padded(), - vec![4, 5, 6], - )))? - .hash(); + let hash_1 = + HashedPartialTrie::from_iter(once((0x19002_u32.to_nibbles_byte_padded(), vec![4, 5, 6]))) + .hash(); let hash_2 = - HashedPartialTrie::try_from_iter(once((0x19002_u32.to_nibbles(), vec![4, 5, 6])))?.hash(); + HashedPartialTrie::from_iter(once((0x19002_u32.to_nibbles(), vec![4, 5, 6]))).hash(); assert_ne!(hash_1, hash_2); // Finally note that `Nibbles` which are constructed from bytes are always @@ -79,6 +76,4 @@ fn main() -> TrieOpResult<()> { format!("{:x}", Nibbles::from_bytes_le(&[69, 35, 1]).unwrap()), "0x012345" ); - - Ok(()) } diff --git a/mpt_trie/src/debug_tools/diff.rs b/mpt_trie/src/debug_tools/diff.rs index 3a4318c23..fd280c749 100644 --- a/mpt_trie/src/debug_tools/diff.rs +++ b/mpt_trie/src/debug_tools/diff.rs @@ -65,7 +65,7 @@ enum DiffDetectionState { } impl DiffDetectionState { - const fn pick_most_significant_state(&self, other: &Self) -> Self { + fn pick_most_significant_state(&self, other: &Self) -> Self { match self.get_int_repr() > other.get_int_repr() { false => *other, true => *self, @@ -73,7 +73,7 @@ impl DiffDetectionState { } /// The integer representation also indicates the more "significant" state. - const fn get_int_repr(self) -> usize { + fn get_int_repr(self) -> usize { self as usize } } @@ -403,7 +403,7 @@ fn create_diff_detection_state_based_from_hashes( /// If the node type contains a value (without looking at the children), then /// return it. -const fn get_value_from_node(n: &Node) -> Option<&Vec> { +fn get_value_from_node(n: &Node) -> Option<&Vec> { match n { Node::Empty | Node::Hash(_) | Node::Extension { .. } => None, Node::Branch { value, .. } | Node::Leaf { nibbles: _, value } => Some(value), @@ -416,19 +416,18 @@ mod tests { use crate::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, PartialTrie}, - trie_ops::TrieOpResult, utils::TrieNodeType, }; #[test] - fn depth_single_node_hash_diffs_work() -> TrieOpResult<()> { + fn depth_single_node_hash_diffs_work() { // TODO: Reduce duplication once we identify common structures across tests... let mut a = HashedPartialTrie::default(); - a.insert(0x1234, vec![0])?; + a.insert(0x1234, vec![0]); let a_hash = a.hash(); let mut b = a.clone(); - b.insert(0x1234, vec![1])?; + b.insert(0x1234, vec![1]); let b_hash = b.hash(); let diff = create_diff_between_tries(&a, &b); @@ -456,8 +455,6 @@ mod tests { }; assert_eq!(diff.latest_diff_res, Some(expected)); - - Ok(()) } // TODO: Will finish these tests later (low-priority). diff --git a/mpt_trie/src/debug_tools/query.rs b/mpt_trie/src/debug_tools/query.rs index e6a988cee..20edf6a3b 100644 --- a/mpt_trie/src/debug_tools/query.rs +++ b/mpt_trie/src/debug_tools/query.rs @@ -49,19 +49,19 @@ pub struct DebugQueryParamsBuilder { impl DebugQueryParamsBuilder { /// Defaults to `true`. - pub const fn print_key_pieces(mut self, enabled: bool) -> Self { + pub fn print_key_pieces(mut self, enabled: bool) -> Self { self.params.include_key_piece_per_node = enabled; self } /// Defaults to `true`. - pub const fn print_node_type(mut self, enabled: bool) -> Self { + pub fn print_node_type(mut self, enabled: bool) -> Self { self.params.include_node_type = enabled; self } /// Defaults to `false`. - pub const fn print_node_specific_values(mut self, enabled: bool) -> Self { + pub fn print_node_specific_values(mut self, enabled: bool) -> Self { self.params.include_node_specific_values = enabled; self } diff --git a/mpt_trie/src/debug_tools/stats.rs b/mpt_trie/src/debug_tools/stats.rs index 1f2762936..6a23ab496 100644 --- a/mpt_trie/src/debug_tools/stats.rs +++ b/mpt_trie/src/debug_tools/stats.rs @@ -34,7 +34,7 @@ impl Display for TrieStats { impl TrieStats { /// Compares with the statistics of another trie. - pub const fn compare(&self, other: &Self) -> TrieComparison { + pub fn compare(&self, other: &Self) -> TrieComparison { TrieComparison { node_comp: self.counts.compare(&other.counts), depth_comp: self.depth_stats.compare(&other.depth_stats), @@ -77,19 +77,19 @@ impl NodeCounts { } impl NodeCounts { - const fn total_nodes(&self) -> usize { + fn total_nodes(&self) -> usize { self.empty + self.total_node_non_empty() } - const fn total_node_non_empty(&self) -> usize { + fn total_node_non_empty(&self) -> usize { self.branch + self.extension + self.hash_and_leaf_node_count() } - const fn hash_and_leaf_node_count(&self) -> usize { + fn hash_and_leaf_node_count(&self) -> usize { self.hash + self.leaf } - const fn compare(&self, other: &Self) -> NodeComparison { + fn compare(&self, other: &Self) -> NodeComparison { NodeComparison { tot_node_rat: RatioStat::new(self.total_nodes(), other.total_nodes()), non_empty_rat: RatioStat::new( @@ -184,7 +184,7 @@ impl Display for RatioStat { impl RatioStat { /// `new` doesn't have any logic, but this will reduce a lot of line lengths /// since this is called so many times. - const fn new(a: T, b: T) -> Self { + fn new(a: T, b: T) -> Self { Self { a, b } } @@ -234,7 +234,7 @@ impl Display for DepthStats { } impl DepthStats { - const fn compare(&self, other: &Self) -> DepthComparison { + fn compare(&self, other: &Self) -> DepthComparison { DepthComparison { lowest_depth_rat: RatioStat::new(self.lowest_depth, other.lowest_depth), avg_leaf_depth_rat: RatioStat::new(self.avg_leaf_depth, other.avg_leaf_depth), @@ -317,14 +317,13 @@ mod tests { generate_n_random_fixed_trie_hash_entries, generate_n_random_fixed_trie_value_entries, handmade_trie_1, }, - trie_ops::TrieOpResult, }; const MASSIVE_TRIE_SIZE: usize = 100_000; #[test] - fn hand_made_trie_has_correct_node_stats() -> TrieOpResult<()> { - let (trie, _) = handmade_trie_1()?; + fn hand_made_trie_has_correct_node_stats() { + let (trie, _) = handmade_trie_1(); let stats = get_trie_stats(&trie); assert_eq!(stats.counts.leaf, 4); @@ -334,8 +333,6 @@ mod tests { // empty = (n_branch * 4) - n_leaf - (n_branch - 1) assert_eq!(stats.counts.empty, 57); - - Ok(()) } // TODO: Low-priority. Finish later. @@ -346,42 +343,40 @@ mod tests { } #[test] - fn massive_leaf_trie_has_correct_leaf_node_stats() -> TrieOpResult<()> { - create_trie_and_stats_from_entries_and_assert(MASSIVE_TRIE_SIZE, 0, 9522) + fn massive_leaf_trie_has_correct_leaf_node_stats() { + create_trie_and_stats_from_entries_and_assert(MASSIVE_TRIE_SIZE, 0, 9522); } #[test] - fn massive_hash_trie_has_correct_hash_node_stats() -> TrieOpResult<()> { - create_trie_and_stats_from_entries_and_assert(0, MASSIVE_TRIE_SIZE, 9855) + fn massive_hash_trie_has_correct_hash_node_stats() { + create_trie_and_stats_from_entries_and_assert(0, MASSIVE_TRIE_SIZE, 9855); } #[test] - fn massive_mixed_trie_has_correct_hash_node_stats() -> TrieOpResult<()> { + fn massive_mixed_trie_has_correct_hash_node_stats() { create_trie_and_stats_from_entries_and_assert( MASSIVE_TRIE_SIZE / 2, MASSIVE_TRIE_SIZE / 2, 1992, - ) + ); } fn create_trie_and_stats_from_entries_and_assert( n_leaf_nodes: usize, n_hash_nodes: usize, seed: u64, - ) -> TrieOpResult<()> { + ) { let val_entries = generate_n_random_fixed_trie_value_entries(n_leaf_nodes, seed); let hash_entries = generate_n_random_fixed_trie_hash_entries(n_hash_nodes, seed + 1); let mut trie = HashedPartialTrie::default(); - trie.extend(val_entries)?; - trie.extend(hash_entries)?; + trie.extend(val_entries); + trie.extend(hash_entries); let stats = get_trie_stats(&trie); assert_eq!(stats.counts.leaf, n_leaf_nodes); assert_eq!(stats.counts.hash, n_hash_nodes); - - Ok(()) } // TODO: Low-priority. Finish later. diff --git a/mpt_trie/src/nibbles.rs b/mpt_trie/src/nibbles.rs index d7422a93d..d2426dad2 100644 --- a/mpt_trie/src/nibbles.rs +++ b/mpt_trie/src/nibbles.rs @@ -1,7 +1,6 @@ -#![allow(clippy::assign_op_pattern)] - //! Define [`Nibbles`] and how to convert bytes, hex prefix encodings and //! strings into nibbles. + use std::mem::size_of; use std::{ fmt::{self, Debug}, @@ -14,14 +13,9 @@ use std::{ }; use bytes::{Bytes, BytesMut}; -use ethereum_types::{H256, U128, U256}; -use impl_codec::impl_uint_codec; -use impl_num_traits::impl_uint_num_traits; -use impl_rlp::impl_uint_rlp; -use impl_serde::impl_uint_serde; +use ethereum_types::{H256, U128, U256, U512}; use serde::{Deserialize, Serialize}; use thiserror::Error; -use uint::construct_uint; use uint::FromHexError; use crate::utils::{create_mask_of_1s, is_even}; @@ -29,19 +23,8 @@ use crate::utils::{create_mask_of_1s, is_even}; // Use a whole byte for a Nibble just for convenience /// A Nibble has 4 bits and is stored as `u8`. pub type Nibble = u8; - -construct_uint! { - /// Used for the internal representation of a sequence of nibbles. - /// The choice of [u64; 5] accommodates the 260-bit key requirement efficiently by - /// leveraging 64-bit instructions for performance, while providing an additional u64 - /// to handle the overflow case beyond the 256-bit capacity of [u64; 4]. - pub struct NibblesIntern(5); -} - -impl_uint_num_traits!(NibblesIntern, 5); -impl_uint_serde!(NibblesIntern, 5); -impl_uint_codec!(NibblesIntern, 5); -impl_uint_rlp!(NibblesIntern, 5); +/// Used for the internal representation of a sequence of nibbles. +pub type NibblesIntern = U512; const MULTIPLE_NIBBLES_APPEND_ASSERT_ERR_MSG: &str = "Attempted to create a nibbles sequence longer than 64!"; @@ -91,56 +74,11 @@ pub enum FromHexPrefixError { /// The hex prefix encoding flag is invalid. InvalidFlags(Nibble), - #[error("Tried to convert a hex prefix byte string into `Nibbles` that was longer than 40 bytes: (length: {0}, bytes: {1})")] + #[error("Tried to convert a hex prefix byte string into `Nibbles` that was longer than 64 bytes: (length: {0}, bytes: {1})")] /// The hex prefix encoding is too large. TooLong(String, usize), } -/// Error type for conversion. -#[derive(Debug, Error)] -pub enum NibblesToTypeError { - #[error("Overflow encountered when converting to U256: {0}")] - /// Overflow encountered. - Overflow(NibblesIntern), -} - -trait AsU64s { - fn as_u64s(&self) -> impl Iterator + '_; -} - -macro_rules! impl_as_u64s_for_primitive { - ($type:ty) => { - impl AsU64s for $type { - fn as_u64s(&self) -> impl Iterator + '_ { - std::iter::once(*self as u64) - } - } - }; -} - -impl_as_u64s_for_primitive!(u8); -impl_as_u64s_for_primitive!(u16); -impl_as_u64s_for_primitive!(u32); -impl_as_u64s_for_primitive!(u64); - -impl AsU64s for U128 { - fn as_u64s(&self) -> impl Iterator + '_ { - self.0.iter().copied() - } -} - -impl AsU64s for U256 { - fn as_u64s(&self) -> impl Iterator + '_ { - self.0.iter().copied() - } -} - -impl AsU64s for NibblesIntern { - fn as_u64s(&self) -> impl Iterator + '_ { - self.0.iter().copied() - } -} - #[derive(Debug, Error)] #[error(transparent)] /// An error encountered when converting a string to a sequence of nibbles. @@ -165,14 +103,11 @@ macro_rules! impl_to_nibbles { #[allow(clippy::manual_bits)] let size_bits = size_of::() * 8; let count = (size_bits - self.leading_zeros() as usize + 3) / 4; - let mut packed = NibblesIntern::zero(); - let parts = self.as_u64s(); - for (i, part) in parts.enumerate().take(packed.0.len()) { - packed.0[i] = part; + Nibbles { + count, + packed: self.into(), } - - Nibbles { count, packed } } } }; @@ -184,60 +119,7 @@ impl_to_nibbles!(u32); impl_to_nibbles!(u64); impl_to_nibbles!(U128); impl_to_nibbles!(U256); -impl_to_nibbles!(NibblesIntern); - -impl<'a> TryFrom<&'a Nibbles> for U256 { - type Error = NibblesToTypeError; - - fn try_from(value: &'a Nibbles) -> Result { - let NibblesIntern(ref arr) = value.packed; - if arr[4] != 0 { - return Err(NibblesToTypeError::Overflow(value.packed)); - } - - let ret = [arr[0], arr[1], arr[2], arr[3]]; - Ok(U256(ret)) - } -} - -impl<'a> TryFrom<&'a NibblesIntern> for U256 { - type Error = NibblesToTypeError; - - fn try_from(value: &'a NibblesIntern) -> Result { - if value.0[4] != 0 { - return Err(NibblesToTypeError::Overflow(*value)); - } - - let ret = [value.0[0], value.0[1], value.0[2], value.0[3]]; - Ok(U256(ret)) - } -} - -impl TryInto for Nibbles { - type Error = NibblesToTypeError; - - fn try_into(self) -> Result { - let arr = self.packed; - if arr.0[4] != 0 { - return Err(NibblesToTypeError::Overflow(arr)); - } - - let ret = [arr.0[0], arr.0[1], arr.0[2], arr.0[3]]; - Ok(U256(ret)) - } -} - -impl From for NibblesIntern { - fn from(val: U256) -> Self { - let arr = val.as_u64s(); - - let mut ret = NibblesIntern::zero(); - for (i, part) in arr.enumerate() { - ret.0[i] = part; - } - ret - } -} +impl_to_nibbles!(U512); #[derive(Copy, Clone, Deserialize, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] /// A sequence of nibbles which is used as the key type into @@ -308,6 +190,7 @@ impl Debug for Nibbles { } } +// TODO: This impl is going to need to change once we move away from `U256`s... impl FromStr for Nibbles { type Err = StrToNibblesError; @@ -318,7 +201,7 @@ impl FromStr for Nibbles { .chars() .position(|c| c != '0') .unwrap_or(stripped_str.len()); - let packed = NibblesIntern::from_str(s)?; + let packed = U512::from_str(s)?; Ok(Self { count: leading_zeros + Self::get_num_nibbles_in_key(&packed), @@ -345,7 +228,7 @@ impl Nibbles { /// Returns an error if the byte slice is empty or is longer than `32` /// bytes. pub fn from_bytes_be(bytes: &[u8]) -> Result { - Self::from_bytes(bytes, NibblesIntern::from_big_endian) + Self::from_bytes(bytes, U512::from_big_endian) } /// Creates `Nibbles` from little endian bytes. @@ -353,7 +236,7 @@ impl Nibbles { /// Returns an error if the byte slice is empty or is longer than `32` /// bytes. pub fn from_bytes_le(bytes: &[u8]) -> Result { - Self::from_bytes(bytes, NibblesIntern::from_little_endian) + Self::from_bytes(bytes, U512::from_little_endian) } fn from_bytes(bytes: &[u8], conv_f: F) -> Result @@ -467,7 +350,7 @@ impl Nibbles { let shift_amt = 4 * self.count; self.count += 1; - self.packed |= NibblesIntern::from(n) << shift_amt; + self.packed |= U512::from(n) << shift_amt; } /// Pushes a nibble to the back. @@ -579,7 +462,7 @@ impl Nibbles { self.packed = (self.packed & truncate_mask) >> shift_amt; } - const fn get_min_truncate_amount_to_prevent_over_truncating(&self, n: usize) -> usize { + fn get_min_truncate_amount_to_prevent_over_truncating(&self, n: usize) -> usize { match self.count >= n { false => self.count, true => n, @@ -588,7 +471,7 @@ impl Nibbles { /// Returns whether or not this `Nibbles` contains actual nibbles. (If /// `count` is set to `0`) - pub const fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.count == 0 } @@ -681,8 +564,8 @@ impl Nibbles { /// Reverses the `Nibbles` such that the last `Nibble` is now the first /// `Nibble`. pub fn reverse(&self) -> Nibbles { - let mut mask = NibblesIntern::from(0xf); - let mut reversed_packed = NibblesIntern::zero(); + let mut mask = U512::from(0xf); + let mut reversed_packed = U512::zero(); for i in 0..self.count { reversed_packed <<= 4; @@ -732,7 +615,7 @@ impl Nibbles { return n1.count; } - let mut curr_mask: NibblesIntern = (NibblesIntern::from(0xf)) << ((n1.count - 1) * 4); + let mut curr_mask: U512 = (U512::from(0xf)) << ((n1.count - 1) * 4); for i in 0..n1.count { if n1.packed & curr_mask != n2.packed & curr_mask { return i; @@ -749,11 +632,11 @@ impl Nibbles { where F: Fn(&[u8]) -> String, { - let mut byte_buf = [0; 40]; + let mut byte_buf = [0; 64]; self.packed.to_big_endian(&mut byte_buf); let count_bytes = self.min_bytes(); - let hex_string_raw = hex_encode_f(&byte_buf[(40 - count_bytes)..40]); + let hex_string_raw = hex_encode_f(&byte_buf[(64 - count_bytes)..64]); let hex_char_iter_raw = hex_string_raw.chars(); // We need this skip to make both match arms have the same type. @@ -773,10 +656,10 @@ impl Nibbles { pub fn to_hex_prefix_encoding(&self, is_leaf: bool) -> Bytes { let num_nibbles = self.count + 1; let num_bytes = (num_nibbles + 1) / 2; - let flag_byte_idx = 41 - num_bytes; + let flag_byte_idx = 65 - num_bytes; // Needed because `to_big_endian` always writes `32` bytes. - let mut bytes = BytesMut::zeroed(41); + let mut bytes = BytesMut::zeroed(65); let is_even = is_even(self.count); let odd_bit = match is_even { @@ -790,10 +673,10 @@ impl Nibbles { }; let flags: u8 = (odd_bit | (term_bit << 1)) << 4; - self.packed.to_big_endian(&mut bytes[1..41]); + self.packed.to_big_endian(&mut bytes[1..65]); bytes[flag_byte_idx] |= flags; - Bytes::copy_from_slice(&bytes[flag_byte_idx..41]) + Bytes::copy_from_slice(&bytes[flag_byte_idx..65]) } /// Converts a hex prefix byte string ("AKA "compact") into `Nibbles`. @@ -827,7 +710,7 @@ impl Nibbles { let hex_prefix_byes_iter = hex_prefix_bytes.iter().skip(1).take(32).cloned(); let mut i = 0; - let mut nibbles_raw = [0; 40]; + let mut nibbles_raw = [0; 64]; if odd_nib_count { Self::write_byte_iter_to_byte_buf( @@ -847,7 +730,7 @@ impl Nibbles { let x = Self { count, - packed: NibblesIntern::from_big_endian(&nibbles_raw[..tot_bytes]), + packed: U512::from_big_endian(&nibbles_raw[..tot_bytes]), }; Ok(x) @@ -861,41 +744,43 @@ impl Nibbles { } /// Returns the minimum number of bytes needed to represent these `Nibbles`. - pub const fn min_bytes(&self) -> usize { + pub fn min_bytes(&self) -> usize { (self.count + 1) / 2 } /// Returns the minimum number of nibbles needed to represent a `U256` key. - pub fn get_num_nibbles_in_key(k: &NibblesIntern) -> usize { + pub fn get_num_nibbles_in_key(k: &U512) -> usize { (k.bits() + 3) / 4 } + // TODO: Make not terrible at some point... Consider moving away from `U256` + // internally? /// Returns the nibbles bytes in big-endian format. pub fn bytes_be(&self) -> Vec { - let mut byte_buf = [0; 40]; + let mut byte_buf = [0; 64]; self.packed.to_big_endian(&mut byte_buf); - byte_buf[40 - self.min_bytes()..40].to_vec() + byte_buf[64 - self.min_bytes()..64].to_vec() } /// Creates `Nibbles` from a big endian `H256`. pub fn from_h256_be(v: H256) -> Self { - Self::from_h256_common(|v| NibblesIntern::from_big_endian(v.as_bytes()), v) + Self::from_h256_common(|v| U512::from_big_endian(v.as_bytes()), v) } /// Creates `Nibbles` from a little endian `H256`. pub fn from_h256_le(v: H256) -> Self { - Self::from_h256_common(|v| NibblesIntern::from_little_endian(v.as_bytes()), v) + Self::from_h256_common(|v| U512::from_little_endian(v.as_bytes()), v) } - fn from_h256_common NibblesIntern>(conv_f: F, v: H256) -> Self { + fn from_h256_common U512>(conv_f: F, v: H256) -> Self { Self { count: 64, packed: conv_f(v), } } - const fn nibble_append_safety_asserts(&self, n: Nibble) { + fn nibble_append_safety_asserts(&self, n: Nibble) { assert!( self.count < 64, "{}", @@ -904,13 +789,25 @@ impl Nibbles { assert!(n < 16, "{}", SINGLE_NIBBLE_APPEND_ASSERT_ERR_MSG); } - const fn nibbles_append_safety_asserts(&self, new_count: usize) { + fn nibbles_append_safety_asserts(&self, new_count: usize) { assert!( new_count <= 64, "{}", MULTIPLE_NIBBLES_APPEND_ASSERT_ERR_MSG ); } + + // TODO: REMOVE BEFORE NEXT CRATE VERSION! THIS IS A TEMP HACK! + /// Converts to u256 returning an error if not possible. + pub fn try_into_u256(&self) -> Result { + match self.count <= 64 { + false => Err(format!( + "Tried getting a U256 from Nibbles that were too big! ({:?})", + self + )), + true => Ok(self.packed.try_into().unwrap()), + } + } } #[cfg(test)] @@ -919,7 +816,7 @@ mod tests { use ethereum_types::{H256, U256}; - use super::{Nibble, Nibbles, StrToNibblesError, ToNibbles}; + use super::{Nibble, Nibbles, ToNibbles}; use crate::nibbles::FromHexPrefixError; const ZERO_NIBS_63: &str = "0x000000000000000000000000000000000000000000000000000000000000000"; @@ -930,42 +827,23 @@ mod tests { "0x0000000000000000000000000000000000000000000000000000000000000001"; #[test] - fn get_nibble_works() -> Result<(), StrToNibblesError> { + fn get_nibble_works() { let n = Nibbles::from(0x1234); + assert_eq!(n.get_nibble(0), 0x1); assert_eq!(n.get_nibble(3), 0x4); - - let n = Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", - )?; - assert_eq!(n.get_nibble(30), 0x1); - assert_eq!(n.get_nibble(33), 0xc); - - Ok(()) } #[test] fn pop_nibble_front_works() { pop_and_assert_nibbles(0x1, 0x0, 1, Nibbles::pop_next_nibble_front); pop_and_assert_nibbles(0x1234, 0x234, 1, Nibbles::pop_next_nibble_front); - pop_and_assert_nibbles( - 0x1234567890123, - 0x234567890123, - 1, - Nibbles::pop_next_nibble_front, - ); } #[test] fn pop_nibble_back_works() { pop_and_assert_nibbles(0x1, 0x0, 1, Nibbles::pop_next_nibble_back); pop_and_assert_nibbles(0x1234, 0x123, 4, Nibbles::pop_next_nibble_back); - pop_and_assert_nibbles( - 0x1234567890123, - 0x123456789012, - 3, - Nibbles::pop_next_nibble_back, - ); } fn pop_and_assert_nibbles Nibble>( @@ -990,7 +868,7 @@ mod tests { } #[test] - fn pop_nibbles_front_works() -> Result<(), StrToNibblesError> { + fn pop_nibbles_front_works() { let nib = 0x1234.into(); assert_pop_nibbles( @@ -1021,30 +899,10 @@ mod tests { 0x1234.into(), Nibbles::pop_nibbles_front, ); - assert_pop_nibbles( - &nib, - 4, - 0x0.into(), - 0x1234.into(), - Nibbles::pop_nibbles_front, - ); - - let nib = Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", - )?; - assert_pop_nibbles( - &nib, - 24, - Nibbles::from_str("0x0ffd1e165c754b28a41a95922f9f70682c581353")?, - Nibbles::from_str("0x3ab76c381c0f8ea617ea9678")?, - Nibbles::pop_nibbles_front, - ); - - Ok(()) } #[test] - fn pop_nibbles_back_works() -> Result<(), StrToNibblesError> { + fn pop_nibbles_back_works() { let nib = 0x1234.into(); assert_pop_nibbles( @@ -1063,19 +921,6 @@ mod tests { 0x4321.into(), Nibbles::pop_nibbles_back, ); - - let nib = Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", - )?; - assert_pop_nibbles( - &nib, - 24, - Nibbles::from_str("0x3ab76c381c0f8ea617ea96780ffd1e165c754b28")?, - Nibbles::from_str("0x353185c28607f9f22959a14a")?, - Nibbles::pop_nibbles_back, - ); - - Ok(()) } fn assert_pop_nibbles Nibbles>( @@ -1152,7 +997,7 @@ mod tests { } #[test] - fn get_next_nibbles_works() -> Result<(), StrToNibblesError> { + fn get_next_nibbles_works() { let n: Nibbles = 0x1234.into(); assert_eq!(n.get_next_nibbles(0), Nibbles::default()); @@ -1162,37 +1007,20 @@ mod tests { assert_eq!(n.get_next_nibbles(4), Nibbles::from(0x1234)); assert_eq!(Nibbles::from(0x0).get_next_nibbles(0), Nibbles::default()); - - let n = Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", - )?; - assert_eq!( - n.get_next_nibbles(24), - Nibbles::from_str("0x3ab76c381c0f8ea617ea9678")? - ); - - Ok(()) } #[test] - fn get_nibble_range_works() -> Result<(), StrToNibblesError> { + fn get_nibble_range_works() { let n: Nibbles = 0x1234.into(); assert_eq!(n.get_nibble_range(0..0), 0x0.into()); assert_eq!(n.get_nibble_range(0..1), 0x1.into()); assert_eq!(n.get_nibble_range(0..2), 0x12.into()); assert_eq!(n.get_nibble_range(0..4), 0x1234.into()); - - let n = Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", - )?; - assert_eq!(n.get_nibble_range(16..24), Nibbles::from_str("0x17ea9678")?); - - Ok(()) } #[test] - fn truncate_nibbles_works() -> Result<(), StrToNibblesError> { + fn truncate_nibbles_works() { let n: Nibbles = 0x1234.into(); assert_eq!(n.truncate_n_nibbles_front(0), n); @@ -1208,43 +1036,16 @@ mod tests { assert_eq!(n.truncate_n_nibbles_back(3), 0x1.into()); assert_eq!(n.truncate_n_nibbles_back(4), 0x0.into()); assert_eq!(n.truncate_n_nibbles_back(8), 0x0.into()); - - let n = Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", - )?; - assert_eq!( - n.truncate_n_nibbles_front(16), - Nibbles::from_str("0x17ea96780ffd1e165c754b28a41a95922f9f70682c581353")? - ); - assert_eq!( - n.truncate_n_nibbles_back(16), - Nibbles::from_str("0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a9592")? - ); - - Ok(()) } #[test] - fn split_at_idx_works() -> Result<(), StrToNibblesError> { + fn split_at_idx_works() { let n: Nibbles = 0x1234.into(); assert_eq!(n.split_at_idx(0), (0x0.into(), 0x1234.into())); assert_eq!(n.split_at_idx(1), (0x1.into(), 0x234.into())); assert_eq!(n.split_at_idx(2), (0x12.into(), 0x34.into())); assert_eq!(n.split_at_idx(3), (0x123.into(), 0x4.into())); - - let n = Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", - )?; - assert_eq!( - n.split_at_idx(24), - ( - Nibbles::from_str("0x3ab76c381c0f8ea617ea9678")?, - Nibbles::from_str("0x0ffd1e165c754b28a41a95922f9f70682c581353")? - ) - ); - - Ok(()) } #[test] @@ -1254,60 +1055,31 @@ mod tests { } #[test] - fn split_at_idx_prefix_works() -> Result<(), StrToNibblesError> { + fn split_at_idx_prefix_works() { let n: Nibbles = 0x1234.into(); assert_eq!(n.split_at_idx_prefix(0), 0x0.into()); assert_eq!(n.split_at_idx_prefix(1), 0x1.into()); assert_eq!(n.split_at_idx_prefix(3), 0x123.into()); - - let n = Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", - )?; - assert_eq!( - n.split_at_idx_prefix(24), - Nibbles::from_str("0x3ab76c381c0f8ea617ea9678")? - ); - - Ok(()) } #[test] - fn split_at_idx_postfix_works() -> Result<(), StrToNibblesError> { + fn split_at_idx_postfix_works() { let n: Nibbles = 0x1234.into(); assert_eq!(n.split_at_idx_postfix(0), 0x1234.into()); assert_eq!(n.split_at_idx_postfix(1), 0x234.into()); assert_eq!(n.split_at_idx_postfix(3), 0x4.into()); - - let n = Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353", - )?; - assert_eq!( - n.split_at_idx_postfix(24), - Nibbles::from_str("0x0ffd1e165c754b28a41a95922f9f70682c581353")? - ); - - Ok(()) } #[test] - fn merge_nibble_works() -> Result<(), StrToNibblesError> { + fn merge_nibble_works() { assert_eq!(Nibbles::from(0x0).merge_nibble(1), 0x1.into()); assert_eq!(Nibbles::from(0x1234).merge_nibble(5), 0x12345.into()); - assert_eq!( - Nibbles::from_str("0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c58135")? - .merge_nibble(3), - Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353" - )? - ); - - Ok(()) } #[test] - fn merge_nibbles_works() -> Result<(), StrToNibblesError> { + fn merge_nibbles_works() { assert_eq!( Nibbles::from(0x12).merge_nibbles(&(0x34.into())), 0x1234.into() @@ -1321,34 +1093,18 @@ mod tests { 0x34.into() ); assert_eq!(Nibbles::from(0x0).merge_nibbles(&(0x0).into()), 0x0.into()); - assert_eq!( - Nibbles::from_str("0x3ab76c381c0f8ea617ea96780ffd1e1")? - .merge_nibbles(&Nibbles::from_str("0x65c754b28a41a95922f9f70682c581353")?), - Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c581353" - )? - ); - - Ok(()) } #[test] - fn reverse_works() -> Result<(), StrToNibblesError> { + fn reverse_works() { assert_eq!(Nibbles::from(0x0).reverse(), Nibbles::from(0x0_u64)); assert_eq!(Nibbles::from(0x1).reverse(), Nibbles::from(0x1_u64)); assert_eq!(Nibbles::from(0x12).reverse(), Nibbles::from(0x21_u64)); assert_eq!(Nibbles::from(0x1234).reverse(), Nibbles::from(0x4321_u64)); - assert_eq!( - Nibbles::from_str("0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c58135")? - .reverse(), - Nibbles::from_str("0x53185c28607f9f22959a14a82b457c561e1dff08769ae716ae8f0c183c67ba3")? - ); - - Ok(()) } #[test] - fn find_nibble_idx_that_differs_between_nibbles_works() -> Result<(), StrToNibblesError> { + fn find_nibble_idx_that_differs_between_nibbles_works() { assert_eq!( Nibbles::find_nibble_idx_that_differs_between_nibbles_equal_lengths( &(0x1234.into()), @@ -1384,19 +1140,6 @@ mod tests { ), 4 ); - assert_eq!( - Nibbles::find_nibble_idx_that_differs_between_nibbles_different_lengths( - &(Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41a95922f9f70682c58135" - )?), - &(Nibbles::from_str( - "0x3ab76c381c0f8ea617ea96780ffd1e165c754b28a41ae716ae8f0c183c67ba3" - )?), - ), - 44 - ); - - Ok(()) } #[test] diff --git a/mpt_trie/src/partial_trie.rs b/mpt_trie/src/partial_trie.rs index 3d29e8c05..c1a04c4bf 100644 --- a/mpt_trie/src/partial_trie.rs +++ b/mpt_trie/src/partial_trie.rs @@ -13,8 +13,8 @@ use serde::{Deserialize, Serialize}; use crate::{ nibbles::Nibbles, trie_hashing::{hash_trie, rlp_encode_and_hash_node, EncodedNode}, - trie_ops::{TrieOpResult, ValOrHash}, - utils::{bytes_to_h256, TryFromIterator}, + trie_ops::ValOrHash, + utils::bytes_to_h256, }; macro_rules! impl_from_for_trie_type { @@ -58,13 +58,13 @@ pub trait PartialTrie: fn new(n: Node) -> Self; /// Inserts a node into the trie. - fn insert(&mut self, k: K, v: V) -> TrieOpResult<()> + fn insert(&mut self, k: K, v: V) where K: Into, V: Into; /// Add more nodes to the trie through an iterator - fn extend(&mut self, nodes: I) -> TrieOpResult<()> + fn extend(&mut self, nodes: I) where K: Into, V: Into, @@ -89,7 +89,7 @@ pub trait PartialTrie: /// are meant for parts of the trie that are not relevant, traversing one /// means that a `Hash` node was created that potentially should not have /// been. - fn delete(&mut self, k: K) -> TrieOpResult>> + fn delete(&mut self, k: K) -> Option> where K: Into; @@ -214,16 +214,15 @@ impl PartialTrie for StandardTrie { Self(n) } - fn insert(&mut self, k: K, v: V) -> TrieOpResult<()> + fn insert(&mut self, k: K, v: V) where K: Into, V: Into, { - self.0.trie_insert(k, v)?; - Ok(()) + self.0.trie_insert(k, v); } - fn extend(&mut self, nodes: I) -> TrieOpResult<()> + fn extend(&mut self, nodes: I) where K: Into, V: Into, @@ -239,7 +238,7 @@ impl PartialTrie for StandardTrie { self.0.trie_get(k) } - fn delete(&mut self, k: K) -> TrieOpResult>> + fn delete(&mut self, k: K) -> Option> where K: Into, { @@ -283,12 +282,12 @@ impl DerefMut for StandardTrie { } } -impl TryFromIterator<(K, V)> for StandardTrie +impl FromIterator<(K, V)> for StandardTrie where K: Into, V: Into, { - fn try_from_iter>(nodes: T) -> TrieOpResult { + fn from_iter>(nodes: T) -> Self { from_iter_common(nodes) } } @@ -328,25 +327,23 @@ impl PartialTrie for HashedPartialTrie { } } - fn insert(&mut self, k: K, v: V) -> TrieOpResult<()> + fn insert(&mut self, k: K, v: V) where K: Into, V: Into, { - self.node.trie_insert(k, v)?; + self.node.trie_insert(k, v); self.set_hash(None); - Ok(()) } - fn extend(&mut self, nodes: I) -> TrieOpResult<()> + fn extend(&mut self, nodes: I) where K: Into, V: Into, I: IntoIterator, { - self.node.trie_extend(nodes)?; + self.node.trie_extend(nodes); self.set_hash(None); - Ok(()) } fn get(&self, k: K) -> Option<&[u8]> @@ -356,7 +353,7 @@ impl PartialTrie for HashedPartialTrie { self.node.trie_get(k) } - fn delete(&mut self, k: K) -> TrieOpResult>> + fn delete(&mut self, k: K) -> Option> where K: Into, { @@ -421,24 +418,23 @@ impl PartialEq for HashedPartialTrie { } } -impl TryFromIterator<(K, V)> for HashedPartialTrie +impl FromIterator<(K, V)> for HashedPartialTrie where K: Into, V: Into, { - fn try_from_iter>(nodes: T) -> TrieOpResult { + fn from_iter>(nodes: T) -> Self { from_iter_common(nodes) } } -fn from_iter_common, K, V>( - nodes: T, -) -> TrieOpResult +fn from_iter_common, K, V>(nodes: T) -> N where K: Into, V: Into, { let mut root = N::new(Node::Empty); - root.extend(nodes)?; - Ok(root) + root.extend(nodes); + + root } diff --git a/mpt_trie/src/special_query.rs b/mpt_trie/src/special_query.rs index c133a6091..5c74cbab8 100644 --- a/mpt_trie/src/special_query.rs +++ b/mpt_trie/src/special_query.rs @@ -125,14 +125,13 @@ mod test { use crate::{ nibbles::Nibbles, testing_utils::{common_setup, handmade_trie_1}, - trie_ops::TrieOpResult, utils::TrieSegment, }; #[test] - fn query_iter_works_no_last_node() -> TrieOpResult<()> { + fn query_iter_works_no_last_node() { common_setup(); - let (trie, ks) = handmade_trie_1()?; + let (trie, ks) = handmade_trie_1(); // ks --> vec![0x1234, 0x1324, 0x132400005_u64, 0x2001, 0x2002]; let res = vec![ @@ -171,14 +170,12 @@ mod test { let res: Vec<_> = path_for_query(&trie.node, q, false).collect(); assert_eq!(res, expected) } - - Ok(()) } #[test] - fn query_iter_works_with_last_node() -> TrieOpResult<()> { + fn query_iter_works_with_last_node() { common_setup(); - let (trie, _) = handmade_trie_1()?; + let (trie, _) = handmade_trie_1(); let extension_expected = vec![ TrieSegment::Branch(1), @@ -215,7 +212,5 @@ mod test { path_for_query(&trie, 0x132400, true).collect::>(), leaf_expected ); - - Ok(()) } } diff --git a/mpt_trie/src/testing_utils.rs b/mpt_trie/src/testing_utils.rs index cc8a0daef..51b40e541 100644 --- a/mpt_trie/src/testing_utils.rs +++ b/mpt_trie/src/testing_utils.rs @@ -3,14 +3,14 @@ use std::{ iter::{once, repeat}, }; -use ethereum_types::{H256, U256}; +use ethereum_types::{H256, U256, U512}; use log::info; use rand::{rngs::StdRng, seq::IteratorRandom, Rng, RngCore, SeedableRng}; use crate::{ - nibbles::{Nibbles, NibblesIntern}, + nibbles::Nibbles, partial_trie::{HashedPartialTrie, Node, PartialTrie}, - trie_ops::{TrieOpResult, ValOrHash}, + trie_ops::ValOrHash, utils::is_even, }; @@ -29,7 +29,7 @@ type TestInsertEntry = (Nibbles, T); // Don't want this exposed publicly, but it is useful for testing. impl From for Nibbles { fn from(k: i32) -> Self { - let packed = NibblesIntern::from(k); + let packed = U512::from(k); Self { count: Self::get_num_nibbles_in_key(&packed), @@ -192,21 +192,19 @@ fn gen_rand_u256_bytes(rng: &mut StdRng) -> Vec { /// Initializes a trie with keys large enough to force hashing (nodes less than /// 32 bytes are not hashed). -pub(crate) fn create_trie_with_large_entry_nodes + Copy>( - keys: &[T], -) -> TrieOpResult { +pub(crate) fn create_trie_with_large_entry_nodes + Copy>(keys: &[T]) -> TrieType { let mut trie = TrieType::default(); for (k, v) in keys.iter().map(|k| (*k).into()).map(large_entry) { - trie.insert(k, v.clone())?; + trie.insert(k, v.clone()); } - Ok(trie) + trie } -pub(crate) fn handmade_trie_1() -> TrieOpResult<(TrieType, Vec)> { +pub(crate) fn handmade_trie_1() -> (TrieType, Vec) { let ks = vec![0x1234, 0x1324, 0x132400005_u64, 0x2001, 0x2002]; let ks_nibbles: Vec = ks.into_iter().map(|k| k.into()).collect(); - let trie = create_trie_with_large_entry_nodes(&ks_nibbles)?; + let trie = create_trie_with_large_entry_nodes(&ks_nibbles); // Branch (0x) --> 1, 2 // Branch (0x1) --> 2, 3 @@ -221,5 +219,5 @@ pub(crate) fn handmade_trie_1() -> TrieOpResult<(TrieType, Vec)> { // Leaf (0x2001) --> (n: 0x1, v: [3]) // Leaf (0x2002) --> (n: 0x2, v: [4]) - Ok((trie, ks_nibbles)) + (trie, ks_nibbles) } diff --git a/mpt_trie/src/trie_hashing.rs b/mpt_trie/src/trie_hashing.rs index 9502ebe1c..b6dc864eb 100644 --- a/mpt_trie/src/trie_hashing.rs +++ b/mpt_trie/src/trie_hashing.rs @@ -113,8 +113,6 @@ mod tests { generate_n_random_variable_trie_value_entries, large_entry, TestInsertValEntry, }, trie_hashing::hash_bytes, - trie_ops::TrieOpResult, - utils::TryFromIterator, }; const PYEVM_TRUTH_VALS_JSON_PATH: &str = "test_data/pyevm_account_ground_truth.json"; @@ -187,7 +185,7 @@ mod tests { } impl PyEvmTrueValEntry { - const fn account_entry(&self) -> AccountEntry { + fn account_entry(&self) -> AccountEntry { AccountEntry { nonce: self.nonce, balance: self.balance, @@ -234,7 +232,7 @@ mod tests { let mut trie = HashedPartialTrie::new(Node::Empty); entries.map(move |(k, v)| { - trie.insert(k, v).unwrap(); + trie.insert(k, v); trie.get_hash() }) } @@ -259,7 +257,7 @@ mod tests { } #[test] - fn single_account_leaf_hash_is_correct() -> TrieOpResult<()> { + fn single_account_leaf_hash_is_correct() { common_setup(); let acc_and_hash_entry = &load_pyevm_truth_vals()[0]; @@ -276,12 +274,10 @@ mod tests { get_lib_trie_root_hashes_after_each_insert(once(ins_entry.clone())) .next() .unwrap(); - let our_hash = HashedPartialTrie::try_from_iter(once(ins_entry))?.get_hash(); + let our_hash = HashedPartialTrie::from_iter(once(ins_entry)).get_hash(); assert_eq!(py_evm_truth_val, our_hash); assert_eq!(eth_trie_lib_truth_val, our_hash); - - Ok(()) } #[test] @@ -361,7 +357,7 @@ mod tests { } #[test] - fn massive_trie_data_deletion_agrees_with_eth_trie() -> Result<(), Box> { + fn massive_trie_data_deletion_agrees_with_eth_trie() { common_setup(); let entries: Vec<_> = generate_n_random_fixed_even_nibble_padded_trie_value_entries( @@ -370,34 +366,32 @@ mod tests { ) .collect(); - let mut our_trie = HashedPartialTrie::try_from_iter(entries.iter().cloned())?; + let mut our_trie = HashedPartialTrie::from_iter(entries.iter().cloned()); let mut truth_trie = create_truth_trie(); for (k, v) in entries.iter() { - truth_trie.insert(&k.bytes_be(), v)?; + truth_trie.insert(&k.bytes_be(), v).unwrap(); } let half_entries = entries.len() / 2; let entries_to_delete = entries.into_iter().take(half_entries); for (k, _) in entries_to_delete { - our_trie.delete(k)?; - truth_trie.remove(&k.bytes_be())?; + our_trie.delete(k); + truth_trie.remove(&k.bytes_be()).unwrap(); - let truth_root_hash = H256(truth_trie.root_hash()?.0); + let truth_root_hash = H256(truth_trie.root_hash().unwrap().0); assert_eq!(our_trie.get_hash(), truth_root_hash); } - - Ok(()) } #[test] - fn replacing_branch_of_leaves_with_hash_nodes_produced_same_hash() -> TrieOpResult<()> { - let mut trie = HashedPartialTrie::try_from_iter([ + fn replacing_branch_of_leaves_with_hash_nodes_produced_same_hash() { + let mut trie = HashedPartialTrie::from_iter([ large_entry(0x1), large_entry(0x2), large_entry(0x3), large_entry(0x4), - ])?; + ]); let orig_hash = trie.hash(); @@ -407,8 +401,6 @@ mod tests { let new_hash = trie.hash(); assert_eq!(orig_hash, new_hash); - - Ok(()) } fn get_branch_children_expected( @@ -421,7 +413,7 @@ mod tests { } #[test] - fn replacing_part_of_a_trie_with_a_hash_node_produces_same_hash() -> TrieOpResult<()> { + fn replacing_part_of_a_trie_with_a_hash_node_produces_same_hash() { let entries = (0..16).flat_map(|i| { generate_n_random_variable_trie_value_entries( NODES_PER_BRANCH_FOR_HASH_REPLACEMENT_TEST, @@ -436,7 +428,7 @@ mod tests { }) }); - let mut trie = HashedPartialTrie::try_from_iter(entries)?; + let mut trie = HashedPartialTrie::from_iter(entries); let orig_hash = trie.get_hash(); let root_branch_children = match &mut *trie { @@ -452,7 +444,5 @@ mod tests { let new_hash = trie.get_hash(); assert_eq!(orig_hash, new_hash); - - Ok(()) } } diff --git a/mpt_trie/src/trie_ops.rs b/mpt_trie/src/trie_ops.rs index 64f7f70b4..1208be70e 100644 --- a/mpt_trie/src/trie_ops.rs +++ b/mpt_trie/src/trie_ops.rs @@ -6,7 +6,6 @@ use std::{fmt::Display, mem::size_of}; use enum_as_inner::EnumAsInner; use ethereum_types::{H256, U128, U256, U512}; use log::trace; -use thiserror::Error; use crate::{ nibbles::{Nibble, Nibbles}, @@ -14,33 +13,6 @@ use crate::{ utils::TrieNodeType, }; -/// Stores the result of trie operations. Returns a [TrieOpError] upon -/// failure. -pub type TrieOpResult = Result; - -/// An error type for trie operation. -#[derive(Debug, Error)] -pub enum TrieOpError { - /// An error that occurs when a hash node is found during an insert - /// operation. - #[error("Found a `Hash` node during an insert in a `PartialTrie`! These should not be able to be traversed during an insert! (hash: {0})")] - HashNodeInsertError(H256), - - /// An error that occurs when a hash node is found during a delete - /// operation. - #[error("Attempted to delete a value that ended up inside a hash node! (hash: {0})")] - HashNodeDeleteError(H256), - - /// An error that occurs when encontered an unexisting type of node during - /// an extension node collapse. - #[error("Extension managed to get an unexisting child node type! (child: {0})")] - HashNodeExtError(TrieNodeType), - - /// Failed to insert a hash node into the trie. - #[error("Attempted to place a hash node on an existing node! (hash: {0})")] - ExistingHashNodeError(H256), -} - /// A entry to be inserted into a `PartialTrie`. #[derive(Clone, Debug, Eq, Hash, PartialEq)] struct InsertEntry { @@ -291,7 +263,7 @@ impl Iterator for PartialTrieIter { } impl Node { - pub(crate) fn trie_insert(&mut self, k: K, v: V) -> TrieOpResult<()> + pub(crate) fn trie_insert(&mut self, k: K, v: V) where K: Into, V: Into, @@ -300,21 +272,19 @@ impl Node { trace!("Inserting new node {:?}...", ins_entry); // Inserts are guaranteed to update the root node. - let node_ref: &Node = &insert_into_trie_rec(self, ins_entry)?.unwrap(); + let node_ref: &Node = &insert_into_trie_rec(self, ins_entry).unwrap(); *self = node_ref.clone(); - Ok(()) } - pub(crate) fn trie_extend(&mut self, nodes: I) -> TrieOpResult<()> + pub(crate) fn trie_extend(&mut self, nodes: I) where K: Into, V: Into, I: IntoIterator, { for (k, v) in nodes { - self.trie_insert(k, v)?; + self.trie_insert(k, v); } - Ok(()) } pub(crate) fn trie_get(&self, k: K) -> Option<&[u8]> @@ -360,20 +330,19 @@ impl Node { } } - pub(crate) fn trie_delete(&mut self, k: K) -> TrieOpResult>> + pub(crate) fn trie_delete(&mut self, k: K) -> Option> where K: Into, { let k = k.into(); trace!("Deleting a leaf node with key {} if it exists", k); - delete_intern(&self.clone(), k)?.map_or(Ok(None), |(updated_root, deleted_val)| { + delete_intern(&self.clone(), k).map(|(updated_root, deleted_val)| { // Final check at the root if we have an extension node - let wrapped_node = try_collapse_if_extension(updated_root)?; - let node_ref: &Node = &wrapped_node; + let node_ref: &Node = &try_collapse_if_extension(updated_root); *self = node_ref.clone(); - Ok(Some(deleted_val)) + deleted_val }) } @@ -396,35 +365,32 @@ impl Node { fn insert_into_trie_rec( node: &Node, mut new_node: InsertEntry, -) -> TrieOpResult>> { +) -> Option> { match node { Node::Empty => { trace!("Insert traversed Empty"); - Ok(Some(create_node_from_insert_val( - new_node.nibbles, - new_node.v, - ))) + Some(create_node_from_insert_val(new_node.nibbles, new_node.v)) } - Node::Hash(h) => { + Node::Hash(_) => { trace!("Insert traversed {:?}", node); - Err(TrieOpError::HashNodeInsertError(*h)) + panic!( + "Found a `Hash` node during an insert in a `PartialTrie`! These should not be able to be traversed during an insert!" + ) } Node::Branch { children, value } => { if new_node.nibbles.count == 0 { trace!("Insert traversed branch and placed value in node"); - return Ok(Some(branch_from_insert_val(children.clone(), new_node.v)?)); + return Some(branch_from_insert_val(children.clone(), new_node.v)); } let nibble = new_node.nibbles.pop_next_nibble_front(); trace!("Insert traversed Branch (nibble: {:x})", nibble); - Ok( - insert_into_trie_rec(&children[nibble as usize], new_node)?.map(|updated_child| { - let mut updated_children = children.clone(); - updated_children[nibble as usize] = updated_child; - branch(updated_children, value.clone()) - }), - ) + insert_into_trie_rec(&children[nibble as usize], new_node).map(|updated_child| { + let mut updated_children = children.clone(); + updated_children[nibble as usize] = updated_child; + branch(updated_children, value.clone()) + }) } Node::Extension { nibbles, child } => { trace!("Insert traversed Extension (nibbles: {:?})", nibbles); @@ -436,9 +402,8 @@ fn insert_into_trie_rec( if nibbles.nibbles_are_identical_up_to_smallest_count(&new_node.nibbles) { new_node.truncate_n_nibbles(nibbles.count); - return insert_into_trie_rec(child, new_node)?.map_or(Ok(None), |updated_child| { - Ok(Some(extension(*nibbles, updated_child))) - }); + return insert_into_trie_rec(child, new_node) + .map(|updated_child| extension(*nibbles, updated_child)); } // Drop one since branch will cover one nibble. @@ -453,18 +418,18 @@ fn insert_into_trie_rec( _ => extension(existing_postfix_adjusted_for_branch, child.clone()), }; - Ok(Some(place_branch_and_potentially_ext_prefix( + Some(place_branch_and_potentially_ext_prefix( &info, updated_existing_node, new_node, - ))) + )) } Node::Leaf { nibbles, value } => { trace!("Insert traversed Leaf (nibbles: {:?})", nibbles); // Update existing node value if already present. if *nibbles == new_node.nibbles { - return Ok(Some(leaf_from_insert_val(*nibbles, new_node.v)?)); + return Some(leaf_from_insert_val(*nibbles, new_node.v)); } let info = get_pre_and_postfixes_for_existing_and_new_nodes(nibbles, &new_node.nibbles); @@ -476,11 +441,11 @@ fn insert_into_trie_rec( value.clone(), ); - Ok(Some(place_branch_and_potentially_ext_prefix( + Some(place_branch_and_potentially_ext_prefix( &info, existing_node_truncated, new_node, - ))) + )) } } } @@ -488,23 +453,24 @@ fn insert_into_trie_rec( fn delete_intern( node: &Node, mut curr_k: Nibbles, -) -> TrieOpResult, Vec)>> { +) -> Option<(WrappedNode, Vec)> { match node { Node::Empty => { trace!("Delete traversed Empty"); - Ok(None) + None } - Node::Hash(h) => Err(TrieOpError::HashNodeDeleteError(*h)), - // TODO: Find a nice way to get the full key path... + Node::Hash(_) => { + panic!("Attempted to delete a value that ended up inside a hash node") + } // TODO: Find a nice way to get the full key path... Node::Branch { children, value } => { if curr_k.is_empty() { - return Ok(Some((branch(children.clone(), Vec::new()), value.clone()))); + return Some((branch(children.clone(), Vec::new()), value.clone())); } let nibble = curr_k.pop_next_nibble_front(); trace!("Delete traversed Branch nibble {:x}", nibble); - delete_intern(&children[nibble as usize], curr_k)?.map_or(Ok(None), + delete_intern(&children[nibble as usize], curr_k).map( |(updated_child, value_deleted)| { // If the child we recursively called is deleted, then we may need to reduce // this branch to an extension/leaf. @@ -515,7 +481,7 @@ fn delete_intern( // Branch stays. let mut updated_children = children.clone(); updated_children[nibble as usize] = - try_collapse_if_extension(updated_child)?; + try_collapse_if_extension(updated_child); branch(updated_children, value.clone()) } true => { @@ -533,7 +499,7 @@ fn delete_intern( } }; - Ok(Some((updated_node, value_deleted))) + (updated_node, value_deleted) }, ) } @@ -547,38 +513,34 @@ fn delete_intern( .nibbles_are_identical_up_to_smallest_count(&curr_k) .then(|| { curr_k.truncate_n_nibbles_front_mut(ext_nibbles.count); - - delete_intern(child, curr_k).and_then(|res| { - res.map_or(Ok(None), |(updated_child, value_deleted)| { - let updated_node = - collapse_ext_node_if_needed(ext_nibbles, &updated_child)?; - Ok(Some((updated_node, value_deleted))) - }) + delete_intern(child, curr_k).map(|(updated_child, value_deleted)| { + let updated_node = collapse_ext_node_if_needed(ext_nibbles, &updated_child); + (updated_node, value_deleted) }) }) - .unwrap_or(Ok(None)) + .flatten() } Node::Leaf { nibbles, value } => { trace!("Delete traversed Leaf (nibbles: {:?})", nibbles); - Ok((*nibbles == curr_k).then(|| { + (*nibbles == curr_k).then(|| { trace!("Deleting leaf ({:x})", nibbles); (Node::Empty.into(), value.clone()) - })) + }) } } } -fn try_collapse_if_extension(node: WrappedNode) -> TrieOpResult> { +fn try_collapse_if_extension(node: WrappedNode) -> WrappedNode { match node.as_ref() { Node::Extension { nibbles, child } => collapse_ext_node_if_needed(nibbles, child), - _ => Ok(node), + _ => node, } } fn collapse_ext_node_if_needed( ext_nibbles: &Nibbles, child: &WrappedNode, -) -> TrieOpResult> { +) -> WrappedNode { trace!( "Collapsing extension node ({:x}) with child {}...", ext_nibbles, @@ -586,20 +548,23 @@ fn collapse_ext_node_if_needed( ); match child.as_ref() { - Node::Branch { .. } => Ok(extension(*ext_nibbles, child.clone())), + Node::Branch { .. } => extension(*ext_nibbles, child.clone()), Node::Extension { nibbles: other_ext_nibbles, child: other_ext_child, - } => Ok(extension( + } => extension( ext_nibbles.merge_nibbles(other_ext_nibbles), other_ext_child.clone(), - )), + ), Node::Leaf { nibbles: leaf_nibbles, value, - } => Ok(leaf(ext_nibbles.merge_nibbles(leaf_nibbles), value.clone())), - Node::Hash(_) => Ok(extension(*ext_nibbles, child.clone())), - _ => Err(TrieOpError::HashNodeExtError(TrieNodeType::from(child))), + } => leaf(ext_nibbles.merge_nibbles(leaf_nibbles), value.clone()), + Node::Hash(_) => extension(*ext_nibbles, child.clone()), + _ => panic!( + "Extension managed to get a child node type that is impossible! (child: {})", + TrieNodeType::from(child) + ), } } @@ -752,7 +717,7 @@ pub(crate) fn branch( fn branch_from_insert_val( children: [WrappedNode; 16], value: ValOrHash, -) -> TrieOpResult> { +) -> WrappedNode { create_node_if_ins_val_not_hash(value, |value| Node::Branch { children, value }.into()) } @@ -764,10 +729,7 @@ fn leaf(nibbles: Nibbles, value: Vec) -> WrappedNode { Node::Leaf { nibbles, value }.into() } -fn leaf_from_insert_val( - nibbles: Nibbles, - value: ValOrHash, -) -> TrieOpResult> { +fn leaf_from_insert_val(nibbles: Nibbles, value: ValOrHash) -> WrappedNode { create_node_if_ins_val_not_hash(value, |value| Node::Leaf { nibbles, value }.into()) } @@ -797,10 +759,12 @@ fn create_node_from_insert_val( fn create_node_if_ins_val_not_hash) -> WrappedNode>( value: ValOrHash, create_node_f: F, -) -> TrieOpResult> { +) -> WrappedNode { match value { - ValOrHash::Val(leaf_v) => Ok(create_node_f(leaf_v)), - ValOrHash::Hash(h) => Err(TrieOpError::ExistingHashNodeError(h)), + ValOrHash::Val(leaf_v) => create_node_f(leaf_v), + ValOrHash::Hash(h) => { + panic!("Attempted to place a hash node on an existing node! (hash: {h})") + } } } @@ -821,20 +785,15 @@ mod tests { generate_n_random_variable_trie_value_entries, get_non_hash_values_in_trie, unwrap_iter_item_to_val, TestInsertValEntry, }, - trie_ops::TrieOpResult, - utils::{create_mask_of_1s, TryFromIterator}, + utils::create_mask_of_1s, }; const MASSIVE_TRIE_SIZE: usize = 100000; const COW_TEST_TRIE_SIZE: usize = 500; - fn insert_entries_and_assert_all_exist_in_trie_with_no_extra( - entries: &[TestInsertValEntry], - ) -> TrieOpResult<()> { - let trie = StandardTrie::try_from_iter(entries.iter().cloned())?; - assert_all_entries_in_trie(entries, &trie); - - Ok(()) + fn insert_entries_and_assert_all_exist_in_trie_with_no_extra(entries: &[TestInsertValEntry]) { + let trie = StandardTrie::from_iter(entries.iter().cloned()); + assert_all_entries_in_trie(entries, &trie) } fn assert_all_entries_in_trie(entries: &[TestInsertValEntry], trie: &Node) { @@ -872,112 +831,105 @@ mod tests { } #[test] - fn single_insert() -> TrieOpResult<()> { + fn single_insert() { common_setup(); - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&[entry(0x1234)]) + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&[entry(0x1234)]); } #[test] - fn two_disjoint_inserts_works() -> TrieOpResult<()> { + fn two_disjoint_inserts_works() { common_setup(); let entries = [entry(0x1234), entry(0x5678)]; - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); } #[test] - fn two_inserts_that_share_one_nibble_works() -> TrieOpResult<()> { + fn two_inserts_that_share_one_nibble_works() { common_setup(); let entries = [entry(0x1234), entry(0x1567)]; - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); } #[test] - fn two_inserts_that_differ_on_last_nibble_works() -> TrieOpResult<()> { + fn two_inserts_that_differ_on_last_nibble_works() { common_setup(); let entries = [entry(0x1234), entry(0x1235)]; - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); } #[test] - fn diagonal_inserts_to_base_of_trie_works() -> TrieOpResult<()> { + fn diagonal_inserts_to_base_of_trie_works() { common_setup(); let entries: Vec<_> = (0..=64).map(|i| entry(create_mask_of_1s(i * 4))).collect(); - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); } #[test] - fn updating_an_existing_node_works() -> TrieOpResult<()> { + fn updating_an_existing_node_works() { common_setup(); let mut entries = [entry(0x1234), entry(0x1234)]; entries[1].1 = vec![100]; - let trie = StandardTrie::try_from_iter(entries)?; + let trie = StandardTrie::from_iter(entries); assert_eq!(trie.get(0x1234), Some([100].as_slice())); - - Ok(()) } #[test] - fn cloning_a_trie_creates_two_separate_tries() -> TrieOpResult<()> { + fn cloning_a_trie_creates_two_separate_tries() { common_setup(); - assert_cloning_works_for_tries::()?; - assert_cloning_works_for_tries::()?; - - Ok(()) + assert_cloning_works_for_tries::(); + assert_cloning_works_for_tries::(); } - fn assert_cloning_works_for_tries() -> TrieOpResult<()> + fn assert_cloning_works_for_tries() where - T: TryFromIterator<(Nibbles, Vec)> + PartialTrie, + T: FromIterator<(Nibbles, Vec)> + PartialTrie, { - let trie = T::try_from_iter(once(entry(0x1234)))?; + let trie = T::from_iter(once(entry(0x1234))); let mut cloned_trie = trie.clone(); - cloned_trie.extend(once(entry(0x5678)))?; + cloned_trie.extend(once(entry(0x5678))); assert_ne!(trie, cloned_trie); assert_ne!(trie.hash(), cloned_trie.hash()); - - Ok(()) } #[test] - fn mass_inserts_fixed_sized_keys_all_entries_are_retrievable() -> TrieOpResult<()> { + fn mass_inserts_fixed_sized_keys_all_entries_are_retrievable() { common_setup(); let entries: Vec<_> = generate_n_random_fixed_trie_value_entries(MASSIVE_TRIE_SIZE, 0).collect(); - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); } #[test] - fn mass_inserts_variable_sized_keys_all_entries_are_retrievable() -> TrieOpResult<()> { + fn mass_inserts_variable_sized_keys_all_entries_are_retrievable() { common_setup(); let entries: Vec<_> = generate_n_random_variable_trie_value_entries(MASSIVE_TRIE_SIZE, 0).collect(); - insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries) + insert_entries_and_assert_all_exist_in_trie_with_no_extra(&entries); } #[test] - fn mass_inserts_variable_sized_keys_with_hash_nodes_all_entries_are_retrievable( - ) -> TrieOpResult<()> { + fn mass_inserts_variable_sized_keys_with_hash_nodes_all_entries_are_retrievable() { common_setup(); let non_hash_entries: Vec<_> = generate_n_random_variable_trie_value_entries(MASSIVE_TRIE_SIZE, 0).collect(); - let mut trie = StandardTrie::try_from_iter(non_hash_entries.iter().cloned())?; + let mut trie = StandardTrie::from_iter(non_hash_entries.iter().cloned()); let extra_hash_entries = generate_n_hash_nodes_entries_for_empty_slots_in_trie( &trie, MASSIVE_TRIE_SIZE / 10, 51, ); - assert!(trie.extend(extra_hash_entries.iter().cloned()).is_ok()); + trie.extend(extra_hash_entries.iter().cloned()); let all_nodes: HashSet<_> = trie.items().collect(); @@ -989,12 +941,10 @@ mod tests { assert!(extra_hash_entries .into_iter() .all(|(k, h)| all_nodes.contains(&(k, ValOrHash::Hash(h))))); - - Ok(()) } #[test] - fn equivalency_check_works() -> TrieOpResult<()> { + fn equivalency_check_works() { common_setup(); assert_eq!( @@ -1003,37 +953,33 @@ mod tests { ); let entries = generate_n_random_fixed_trie_value_entries(MASSIVE_TRIE_SIZE, 0); - let big_trie_1 = StandardTrie::try_from_iter(entries)?; + let big_trie_1 = StandardTrie::from_iter(entries); assert_eq!(big_trie_1, big_trie_1); let entries = generate_n_random_fixed_trie_value_entries(MASSIVE_TRIE_SIZE, 1); - let big_trie_2 = StandardTrie::try_from_iter(entries)?; - - assert_ne!(big_trie_1, big_trie_2); + let big_trie_2 = StandardTrie::from_iter(entries); - Ok(()) + assert_ne!(big_trie_1, big_trie_2) } #[test] - fn two_variable_length_keys_with_overlap_are_queryable() -> TrieOpResult<()> { + fn two_variable_length_keys_with_overlap_are_queryable() { common_setup(); let entries = [entry_with_value(0x1234, 1), entry_with_value(0x12345678, 2)]; - let trie = StandardTrie::try_from_iter(entries.iter().cloned())?; + let trie = StandardTrie::from_iter(entries.iter().cloned()); assert_eq!(trie.get(0x1234), Some([1].as_slice())); assert_eq!(trie.get(0x12345678), Some([2].as_slice())); - - Ok(()) } #[test] - fn get_massive_trie_works() -> TrieOpResult<()> { + fn get_massive_trie_works() { common_setup(); let random_entries: Vec<_> = generate_n_random_fixed_trie_value_entries(MASSIVE_TRIE_SIZE, 9001).collect(); - let trie = StandardTrie::try_from_iter(random_entries.iter().cloned())?; + let trie = StandardTrie::from_iter(random_entries.iter().cloned()); for (k, v) in random_entries.into_iter() { debug!("Attempting to retrieve {:?}...", (k, &v)); @@ -1041,12 +987,10 @@ mod tests { assert_eq!(res, Some(v.as_slice())); } - - Ok(()) } #[test] - fn held_trie_cow_references_do_not_change_as_trie_changes() -> TrieOpResult<()> { + fn held_trie_cow_references_do_not_change_as_trie_changes() { common_setup(); let entries = generate_n_random_variable_trie_value_entries(COW_TEST_TRIE_SIZE, 9002); @@ -1056,7 +1000,7 @@ mod tests { let mut trie = StandardTrie::default(); for (k, v) in entries { - trie.insert(k, v)?; + trie.insert(k, v); all_nodes_in_trie_after_each_insert.push(get_non_hash_values_in_trie(&trie)); root_node_after_each_insert.push(trie.clone()); @@ -1069,17 +1013,15 @@ mod tests { let nodes_retrieved = get_non_hash_values_in_trie(&old_root_node); assert_eq!(old_trie_nodes_truth, nodes_retrieved) } - - Ok(()) } #[test] - fn trie_iter_works() -> TrieOpResult<()> { + fn trie_iter_works() { common_setup(); let entries: HashSet<_> = generate_n_random_variable_trie_value_entries(MASSIVE_TRIE_SIZE, 9003).collect(); - let trie = StandardTrie::try_from_iter(entries.iter().cloned())?; + let trie = StandardTrie::from_iter(entries.iter().cloned()); let trie_items: HashSet<_> = trie .items() @@ -1088,48 +1030,40 @@ mod tests { assert!(entries.iter().all(|e| trie_items.contains(e))); assert!(trie_items.iter().all(|item| entries.contains(item))); - - Ok(()) } #[test] - fn deleting_a_non_existent_node_returns_none() -> TrieOpResult<()> { + fn deleting_a_non_existent_node_returns_none() { common_setup(); let mut trie = StandardTrie::default(); - trie.insert(0x1234, vec![91])?; + trie.insert(0x1234, vec![91]); - let res = trie.delete(0x5678)?; - assert!(res.is_none()); - - Ok(()) + assert!(trie.delete(0x5678).is_none()) } #[test] - fn deleting_from_an_empty_trie_returns_none() -> TrieOpResult<()> { + fn deleting_from_an_empty_trie_returns_none() { common_setup(); let mut trie = StandardTrie::default(); - let res = trie.delete(0x1234)?; - assert!(res.is_none()); - - Ok(()) + assert!(trie.delete(0x1234).is_none()); } #[test] - fn deletion_massive_trie() -> TrieOpResult<()> { + fn deletion_massive_trie() { common_setup(); let entries: Vec<_> = generate_n_random_variable_trie_value_entries(MASSIVE_TRIE_SIZE, 7).collect(); - let mut trie = StandardTrie::try_from_iter(entries.iter().cloned())?; + let mut trie = StandardTrie::from_iter(entries.iter().cloned()); // Delete half of the elements let half_entries = entries.len() / 2; let entries_to_delete = entries.iter().take(half_entries); for (k, v) in entries_to_delete { - let res = trie.delete(*k)?; + let res = trie.delete(*k); assert!(trie.get(*k).is_none()); assert_eq!(res.as_ref(), Some(v)); @@ -1139,7 +1073,5 @@ mod tests { for (k, v) in entries_that_still_should_exist { assert_eq!(trie.get(k), Some(v.as_slice())); } - - Ok(()) } } diff --git a/mpt_trie/src/trie_subsets.rs b/mpt_trie/src/trie_subsets.rs index 0f1ff138a..483c86baf 100644 --- a/mpt_trie/src/trie_subsets.rs +++ b/mpt_trie/src/trie_subsets.rs @@ -163,7 +163,7 @@ struct TrackedNodeInfo { } impl TrackedNodeInfo { - const fn new(underlying_node: N) -> Self { + fn new(underlying_node: N) -> Self { Self { underlying_node, touched: false, @@ -396,8 +396,8 @@ mod tests { common_setup, create_trie_with_large_entry_nodes, generate_n_random_fixed_trie_value_entries, handmade_trie_1, TrieType, }, - trie_ops::{TrieOpResult, ValOrHash}, - utils::{TrieNodeType, TryFromIterator}, + trie_ops::ValOrHash, + utils::TrieNodeType, }; const MASSIVE_TEST_NUM_SUB_TRIES: usize = 10; @@ -503,7 +503,7 @@ mod tests { common_setup(); let mut trie = TrieType::default(); - assert!(trie.insert(0x1234, vec![0, 1, 2]).is_ok()); + trie.insert(0x1234, vec![0, 1, 2]); let res = create_trie_subset(&trie, once(0x5678)); assert!(res.is_ok()); @@ -520,39 +520,35 @@ mod tests { } #[test] - fn single_node_trie_is_queryable() -> Result<(), Box> { + fn single_node_trie_is_queryable() { common_setup(); let mut trie = TrieType::default(); - trie.insert(0x1234, vec![0, 1, 2])?; - let trie_subset = create_trie_subset(&trie, once(0x1234))?; + trie.insert(0x1234, vec![0, 1, 2]); + let trie_subset = create_trie_subset(&trie, once(0x1234)).unwrap(); assert_eq!(trie, trie_subset); - - Ok(()) } #[test] - fn multi_node_trie_returns_proper_subset() -> Result<(), Box> { + fn multi_node_trie_returns_proper_subset() { common_setup(); - let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x56, 0x12345_u64])?; + let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x56, 0x12345_u64]); - let trie_subset = create_trie_subset(&trie, vec![0x1234, 0x56])?; + let trie_subset = create_trie_subset(&trie, vec![0x1234, 0x56]).unwrap(); let leaf_keys = get_all_nibbles_of_leaf_nodes_in_trie(&trie_subset); assert!(leaf_keys.contains(&(Nibbles::from(0x1234)))); assert!(leaf_keys.contains(&(Nibbles::from(0x56)))); assert!(!leaf_keys.contains(&Nibbles::from(0x12345))); - - Ok(()) } #[test] fn intermediate_nodes_are_included_in_subset() { common_setup(); - let (trie, ks_nibbles) = handmade_trie_1().unwrap(); + let (trie, ks_nibbles) = handmade_trie_1(); let trie_subset_all = create_trie_subset(&trie, ks_nibbles.iter().cloned()).unwrap(); let subset_keys = get_all_nibbles_of_leaf_nodes_in_trie(&trie_subset_all); @@ -694,23 +690,20 @@ mod tests { } #[test] - fn all_leafs_of_keys_to_create_subset_are_included_in_subset_for_giant_trie() -> TrieOpResult<()> - { + fn all_leafs_of_keys_to_create_subset_are_included_in_subset_for_giant_trie() { common_setup(); - let (_, trie_subsets, keys_of_subsets) = create_massive_trie_and_subsets(9009)?; + let (_, trie_subsets, keys_of_subsets) = create_massive_trie_and_subsets(9009); for (sub_trie, ks_used) in trie_subsets.into_iter().zip(keys_of_subsets.into_iter()) { let leaf_nibbles = get_all_nibbles_of_leaf_nodes_in_trie(&sub_trie); assert!(ks_used.into_iter().all(|k| leaf_nibbles.contains(&k))); } - - Ok(()) } #[test] fn hash_of_single_leaf_trie_partial_trie_matches_original_trie() { - let trie = create_trie_with_large_entry_nodes(&[0x0]).unwrap(); + let trie = create_trie_with_large_entry_nodes(&[0x0]); let base_hash = trie.hash(); let partial_trie = create_trie_subset(&trie, [0x1234]).unwrap(); @@ -722,31 +715,27 @@ mod tests { fn sub_trie_that_includes_branch_but_not_children_hashes_out_children() { common_setup(); - let trie = - create_trie_with_large_entry_nodes(&[0x1234, 0x12345, 0x12346, 0x1234f]).unwrap(); + let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x12345, 0x12346, 0x1234f]); let partial_trie = create_trie_subset(&trie, [0x1234f]).unwrap(); assert_nodes_are_hash_nodes(&partial_trie, [0x12345, 0x12346]); } #[test] - fn sub_trie_for_non_existent_key_that_hits_branch_leaf_does_not_hash_out_leaf( - ) -> TrieOpResult<()> { + fn sub_trie_for_non_existent_key_that_hits_branch_leaf_does_not_hash_out_leaf() { common_setup(); - let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x1234589, 0x12346])?; + let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x1234589, 0x12346]); let partial_trie = create_trie_subset(&trie, [0x1234567]).unwrap(); // Note that `0x1234589` gets hashed at the branch slot at `0x12345`. assert_nodes_are_hash_nodes(&partial_trie, Vec::::default()); - - Ok(()) } #[test] - fn hash_of_branch_partial_tries_matches_original_trie() -> TrieOpResult<()> { + fn hash_of_branch_partial_tries_matches_original_trie() { common_setup(); - let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x56, 0x12345])?; + let trie = create_trie_with_large_entry_nodes(&[0x1234, 0x56, 0x12345]); let base_hash: H256 = trie.hash(); let partial_tries = vec![ @@ -758,30 +747,26 @@ mod tests { ]; assert!(partial_tries .into_iter() - .all(|p_tree| p_tree.hash() == base_hash)); - - Ok(()) + .all(|p_tree| p_tree.hash() == base_hash)) } #[test] - fn hash_of_giant_random_partial_tries_matches_original_trie() -> TrieOpResult<()> { + fn hash_of_giant_random_partial_tries_matches_original_trie() { common_setup(); - let (base_trie, trie_subsets, _) = create_massive_trie_and_subsets(9010)?; + let (base_trie, trie_subsets, _) = create_massive_trie_and_subsets(9010); let base_hash = base_trie.hash(); assert!(trie_subsets .into_iter() - .all(|p_tree| p_tree.hash() == base_hash)); - - Ok(()) + .all(|p_tree| p_tree.hash() == base_hash)) } #[test] - fn giant_random_partial_tries_hashes_leaves_correctly() -> TrieOpResult<()> { + fn giant_random_partial_tries_hashes_leaves_correctly() { common_setup(); - let (base_trie, trie_subsets, leaf_keys_per_trie) = create_massive_trie_and_subsets(9011)?; + let (base_trie, trie_subsets, leaf_keys_per_trie) = create_massive_trie_and_subsets(9011); let all_keys: Vec = base_trie.keys().collect(); for (partial_trie, leaf_trie_keys) in @@ -800,8 +785,6 @@ mod tests { // over a `Hash` node, we return `None`.) assert_all_keys_do_not_exist(&partial_trie, keys_of_hash_nodes); } - - Ok(()) } fn assert_all_keys_do_not_exist(trie: &TrieType, ks: impl Iterator) { @@ -810,15 +793,13 @@ mod tests { } } - fn create_massive_trie_and_subsets( - seed: u64, - ) -> TrieOpResult<(TrieType, Vec, Vec>)> { + fn create_massive_trie_and_subsets(seed: u64) -> (TrieType, Vec, Vec>) { let trie_size = MASSIVE_TEST_NUM_SUB_TRIES * MASSIVE_TEST_NUM_SUB_TRIE_SIZE; let random_entries: Vec<_> = generate_n_random_fixed_trie_value_entries(trie_size, seed).collect(); let entry_keys: Vec<_> = random_entries.iter().map(|(k, _)| k).cloned().collect(); - let trie = TrieType::try_from_iter(random_entries)?; + let trie = TrieType::from_iter(random_entries); let keys_of_subsets: Vec> = (0..MASSIVE_TEST_NUM_SUB_TRIES) .map(|i| { @@ -831,6 +812,6 @@ mod tests { let trie_subsets = create_trie_subsets(&trie, keys_of_subsets.iter().map(|v| v.iter().cloned())).unwrap(); - Ok((trie, trie_subsets, keys_of_subsets)) + (trie, trie_subsets, keys_of_subsets) } } diff --git a/mpt_trie/src/utils.rs b/mpt_trie/src/utils.rs index c38c78a94..8c457f07a 100644 --- a/mpt_trie/src/utils.rs +++ b/mpt_trie/src/utils.rs @@ -7,13 +7,12 @@ use std::{ sync::Arc, }; -use ethereum_types::H256; +use ethereum_types::{H256, U512}; use num_traits::PrimInt; use crate::{ - nibbles::{Nibble, Nibbles, NibblesIntern}, + nibbles::{Nibble, Nibbles}, partial_trie::{Node, PartialTrie}, - trie_ops::TrieOpResult, }; #[derive(Clone, Debug, Eq, Hash, PartialEq)] @@ -71,8 +70,8 @@ pub(crate) fn is_even>(num: T) -> bool { (num & T::one()) == T::zero() } -pub(crate) fn create_mask_of_1s(amt: usize) -> NibblesIntern { - (NibblesIntern::one() << amt) - 1 +pub(crate) fn create_mask_of_1s(amt: usize) -> U512 { + (U512::one() << amt) - 1 } pub(crate) fn bytes_to_h256(b: &[u8; 32]) -> H256 { @@ -206,7 +205,7 @@ impl Display for TrieSegment { impl TrieSegment { /// Get the node type of the [`TrieSegment`]. - pub const fn node_type(&self) -> TrieNodeType { + pub fn node_type(&self) -> TrieNodeType { match self { TrieSegment::Empty => TrieNodeType::Empty, TrieSegment::Hash => TrieNodeType::Hash, @@ -244,16 +243,6 @@ pub(crate) fn get_segment_from_node_and_key_piece( } } -/// Conversion from an [`Iterator`] within an allocator. -/// -/// By implementing `TryFromIteratorIn` for a type, you define how it will be -/// created from an iterator. This is common for types which describe a -/// collection of some kind. -pub trait TryFromIterator: Sized { - /// Creates a value from an iterator within an allocator. - fn try_from_iter>(iter: T) -> TrieOpResult; -} - #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/proof_gen/Cargo.toml b/proof_gen/Cargo.toml index b0f6b680e..9a613bcc9 100644 --- a/proof_gen/Cargo.toml +++ b/proof_gen/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "proof_gen" description = "Generates block proofs from zero proof IR." -version = "0.1.3" +version = "0.1.2" authors = ["Polygon Zero "] edition.workspace = true license.workspace = true @@ -17,4 +17,5 @@ plonky2 = { workspace = true } serde = { workspace = true } # Local dependencies -evm_arithmetization = { version = "0.1.3", path = "../evm_arithmetization" } +trace_decoder = { version = "0.2.0", path = "../trace_decoder" } +evm_arithmetization = { version = "0.1.2", path = "../evm_arithmetization" } diff --git a/proof_gen/README.md b/proof_gen/README.md index 09730359a..03bb6cfa1 100644 --- a/proof_gen/README.md +++ b/proof_gen/README.md @@ -22,7 +22,7 @@ pub struct BlockHashes { ``` Note that `prev_hashes` is going to be `256` elements long (!) most of the time. -`generate_txn_proof` takes in the output from the parser lib (`GenerationInputs`). +`generate_txn_proof` takes in the output from the parser lib (`TxnProofGenIR`). `generate_agg_proof` takes in the two child proofs (wrapped in `AggregatableProof`` to support txn or agg proofs). diff --git a/proof_gen/src/lib.rs b/proof_gen/src/lib.rs index 2599f6360..7907ae3b9 100644 --- a/proof_gen/src/lib.rs +++ b/proof_gen/src/lib.rs @@ -53,8 +53,7 @@ //! ```compile_fail //! pub fn generate_txn_proof( //! p_state: &ProverState, -//! gen_inputs: GenerationInputs, -//! abort_signal: Option>, +//! start_info: TxnProofGenIR, //! ) -> ProofGenResult { ... } //! ``` //! diff --git a/proof_gen/src/proof_gen.rs b/proof_gen/src/proof_gen.rs index f41167490..58435d0dc 100644 --- a/proof_gen/src/proof_gen.rs +++ b/proof_gen/src/proof_gen.rs @@ -3,13 +3,14 @@ use std::sync::{atomic::AtomicBool, Arc}; -use evm_arithmetization::{AllStark, GenerationInputs, StarkConfig}; +use evm_arithmetization::{AllStark, StarkConfig}; use plonky2::{ gates::noop::NoopGate, iop::witness::PartialWitness, plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig}, util::timing::TimingTree, }; +use trace_decoder::types::TxnProofGenIR; use crate::{ proof_types::{AggregatableProof, GeneratedAggProof, GeneratedBlockProof, GeneratedTxnProof}, @@ -43,7 +44,7 @@ impl From for ProofGenError { /// Generates a transaction proof from some IR data. pub fn generate_txn_proof( p_state: &ProverState, - gen_inputs: GenerationInputs, + gen_inputs: TxnProofGenIR, abort_signal: Option>, ) -> ProofGenResult { let (intern, p_vals) = p_state diff --git a/proof_gen/src/proof_types.rs b/proof_gen/src/proof_types.rs index 49d3b25f3..acac783a8 100644 --- a/proof_gen/src/proof_types.rs +++ b/proof_gen/src/proof_types.rs @@ -1,8 +1,9 @@ //! This module defines the various proof types used throughout the block proof //! generation process. -use evm_arithmetization::{proof::PublicValues, BlockHeight}; +use evm_arithmetization::proof::PublicValues; use serde::{Deserialize, Serialize}; +use trace_decoder::types::BlockHeight; use crate::types::PlonkyProofIntern; @@ -58,14 +59,14 @@ impl AggregatableProof { } } - pub(crate) const fn is_agg(&self) -> bool { + pub(crate) fn is_agg(&self) -> bool { match self { AggregatableProof::Txn(_) => false, AggregatableProof::Agg(_) => true, } } - pub(crate) const fn intern(&self) -> &PlonkyProofIntern { + pub(crate) fn intern(&self) -> &PlonkyProofIntern { match self { AggregatableProof::Txn(info) => &info.intern, AggregatableProof::Agg(info) => &info.intern, diff --git a/proof_gen/src/prover_state.rs b/proof_gen/src/prover_state.rs index 338cb52c7..efb3413f4 100644 --- a/proof_gen/src/prover_state.rs +++ b/proof_gen/src/prover_state.rs @@ -57,7 +57,7 @@ macro_rules! define_set_circuit_size_method { paste! { /// Specifies a range of degrees to be supported for this STARK /// table's associated recursive circuits. - pub const fn [](mut self, size: Range) -> Self { + pub fn [](mut self, size: Range) -> Self { self.[<$name _circuit_size>] = size; self } diff --git a/trace_decoder/Cargo.toml b/trace_decoder/Cargo.toml index bd25704c9..2d4dab80f 100644 --- a/trace_decoder/Cargo.toml +++ b/trace_decoder/Cargo.toml @@ -2,7 +2,7 @@ name = "trace_decoder" description = "Processes trace payloads into Intermediate Representation (IR) format." authors = ["Polygon Zero "] -version = "0.3.0" +version = "0.2.0" edition.workspace = true license.workspace = true repository.workspace = true @@ -27,8 +27,8 @@ serde_with = "3.4.0" thiserror = { workspace = true } # Local dependencies -mpt_trie = { version = "0.2.1", path = "../mpt_trie" } -evm_arithmetization = { version = "0.1.3", path = "../evm_arithmetization" } +mpt_trie = { version = "0.2.0", path = "../mpt_trie" } +evm_arithmetization = { version = "0.1.2", path = "../evm_arithmetization" } [dev-dependencies] pretty_env_logger = "0.5.0" diff --git a/trace_decoder/src/compact/compact_prestate_processing.rs b/trace_decoder/src/compact/compact_prestate_processing.rs index f44c2b30a..59efdd6c5 100644 --- a/trace_decoder/src/compact/compact_prestate_processing.rs +++ b/trace_decoder/src/compact/compact_prestate_processing.rs @@ -29,8 +29,6 @@ use crate::{ types::{CodeHash, HashedAccountAddr, TrieRootHash}, }; -/// Result alias for any error that can occur when processing encoded compact -/// prestate. pub type CompactParsingResult = Result; type BranchMask = u32; @@ -48,29 +46,20 @@ const MAX_WITNESS_ENTRIES_NEEDED_TO_MATCH_A_RULE: usize = 3; const BRANCH_MAX_CHILDREN: usize = 16; const CURSOR_ERROR_BYTES_MAX_LEN: usize = 10; -/// An error from processing Erigon's compact witness format. #[derive(Debug, Error)] pub enum CompactParsingError { - /// The header in the compact payload was missing. This is just a single - /// byte that is used for versioning. #[error("Missing header")] MissingHeader, - /// Encountered a byte representing an opcode that does not represent any - /// known opcode #[error("Invalid opcode operator (\"{0:x}\")")] - InvalidOpcode(u8), + InvalidOperator(u8), - /// Encountered the end of the byte stream when we were still expecting more - /// data. #[error("Reached the end of the byte stream when we still expected more data")] UnexpectedEndOfStream, - /// Failed to decode a byte vector from CBOR. #[error("Unable to parse an expected byte vector (field name: {0}) (error: {1}). Cursor error info: {2}")] InvalidByteVector(&'static str, String, CursorBytesErrorInfo), - /// Failed to decode a given type from CBOR. #[error( "Unable to parse the type \"{0}\" (field name: {1}) from bytes {2}. Cursor error info: {3} (err: {4})" )] @@ -82,48 +71,32 @@ pub enum CompactParsingError { String, ), - /// Encountered a sequence of instructions of nodes that should not be able - /// to occur. #[error("Invalid block witness entries: {0:?}")] InvalidWitnessFormat(Vec), - /// Multiple entries were remaining after we were unable to apply any more - /// rules. There should always only be one remaining entry after we can not - /// apply any more rules. #[error("There were multiple entries remaining after the compact block witness was processed (Remaining entries: {0:#?})")] NonSingleEntryAfterProcessing(WitnessEntries), - /// A branch was found that had an unexpected number of child nodes trailing - /// it than expected. #[error("Branch mask {0:#b} stated there should be {1} preceding nodes but instead found {2} (nodes: {3:?})")] IncorrectNumberOfNodesPrecedingBranch(BranchMask, usize, usize, Vec), - /// Found a branch that had claimed to have `n` children but instead had a - /// different amount. #[error( "Expected a branch to have {0} preceding nodes but only had {1} (mask: {2}, nodes: {3:?})" )] MissingExpectedNodesPrecedingBranch(usize, usize, BranchMask, Vec), - /// Expected a preceding node to be of a given type but instead found one of - /// a different type. - #[error("Expected the entry preceding {0} positions behind a {1} entry to be a node of type but instead found a {2} node. (nodes: {3:?})")] - UnexpectedPrecedingNodeFoundWhenProcessingRule(usize, &'static str, String, Vec), - - /// Expected a compact node type that should not be present in the given - /// type of trie. #[error("Found an unexpected compact node type ({0:?}) during processing compact into a `mpt_trie` {1} partial trie.")] UnexpectedNodeForTrieType(UnexpectedCompactNodeType, TrieType), - // TODO: No constructors for this, but I think there should be one in - // [`key_bytes_to_nibbles`]... - /// Error when constructing a key from bytes. + #[error("Expected the entry preceding {0} positions behind a {1} entry to be a node but instead found a {2}. (nodes: {3:?})")] + PrecedingNonNodeEntryFoundWhenProcessingRule(usize, &'static str, String, Vec), + #[error("Unable to create key nibbles from bytes {0}")] KeyError(#[from] FromHexPrefixError), } #[derive(Debug)] -pub(crate) struct CursorBytesErrorInfo { +pub struct CursorBytesErrorInfo { error_start_pos: usize, bad_bytes_hex: String, } @@ -168,7 +141,7 @@ enum Opcode { } #[derive(Clone, Debug, EnumAsInner)] -pub(crate) enum WitnessEntry { +pub enum WitnessEntry { Instruction(Instruction), Node(NodeEntry), } @@ -285,7 +258,7 @@ pub(super) struct AccountNodeData { } impl AccountNodeData { - const fn new( + fn new( nonce: Nonce, balance: Balance, storage_trie: Option, @@ -312,16 +285,16 @@ impl Display for Header { } impl Header { - pub(crate) const fn version_is_compatible(&self, target_ver: u8) -> bool { + pub(crate) fn version_is_compatible(&self, target_ver: u8) -> bool { self.version == target_ver } } -// #[derive(Debug)] -// pub struct CompactWitnessDecodingOutput { -// pub tries: PartialTriePreImages, -// pub code: Option>>, -// } +#[derive(Debug)] +pub(crate) struct WitnessOutput { + pub(crate) tries: PartialTriePreImages, + pub(crate) code: Option>>, +} #[derive(Debug)] struct ParserState { @@ -352,7 +325,7 @@ impl ParserState { Ok((header, p_state)) } - fn parse(mut self) -> CompactParsingResult { + fn parse(mut self) -> CompactParsingResult { let mut entry_buf = Vec::new(); loop { @@ -373,7 +346,15 @@ impl ParserState { )), }?; - Ok(res) + let tries = PartialTriePreImages { + state: res.trie, + storage: res.storage_tries, + }; + + // Replace with a none if there are no entries. + let code = (!res.code.is_empty()).then_some(res.code); + + Ok(WitnessOutput { tries, code }) } fn apply_rules_to_witness_entries( @@ -403,6 +384,10 @@ impl ParserState { ) -> CompactParsingResult { traverser.get_next_n_elems_into_buf(MAX_WITNESS_ENTRIES_NEEDED_TO_MATCH_A_RULE, buf); + // TODO: There is a decent amount of code duplication with the matches and the + // calls to `invalid_witness_err`. We should condense this... + + // TODO: These clones are really bad, but we will clean this up once it works. match buf[0].clone() { WitnessEntry::Instruction(Instruction::EmptyRoot) => { Self::traverser_replace_prev_n_nodes_entry_helper(1, traverser, NodeEntry::Empty) @@ -414,13 +399,13 @@ impl ParserState { Self::traverser_replace_prev_n_nodes_entry_helper( 1, traverser, - NodeEntry::Leaf(k, LeafNodeData::Value(v.into())), + NodeEntry::Leaf(k, LeafNodeData::Value(v.clone().into())), ) } WitnessEntry::Instruction(Instruction::Extension(k)) => { traverser.get_prev_n_elems_into_buf(1, buf); - match &buf[0] { + match buf[0].clone() { WitnessEntry::Node(node) => Self::traverser_replace_prev_n_nodes_entry_helper( 2, traverser, @@ -430,7 +415,11 @@ impl ParserState { } } WitnessEntry::Instruction(Instruction::Code(c)) => { - Self::traverser_replace_prev_n_nodes_entry_helper(1, traverser, NodeEntry::Code(c)) + Self::traverser_replace_prev_n_nodes_entry_helper( + 1, + traverser, + NodeEntry::Code(c.clone()), + ) } WitnessEntry::Instruction(Instruction::AccountLeaf(k, n, b, has_code, has_storage)) => { let (n_nodes_to_replace, account_node_code, s_trie) = match (has_code, has_storage) @@ -495,7 +484,7 @@ impl ParserState { let n_entries_behind_cursor = number_available_preceding_elems - curr_traverser_node_idx; - CompactParsingError::UnexpectedPrecedingNodeFoundWhenProcessingRule( + CompactParsingError::PrecedingNonNodeEntryFoundWhenProcessingRule( n_entries_behind_cursor, "Branch", entry_to_check.to_string(), @@ -527,14 +516,14 @@ impl ParserState { } // ... Because we can't do `[None; 16]` without implementing `Copy`. - const fn create_empty_branch_node_entry() -> [Option>; 16] { + fn create_empty_branch_node_entry() -> [Option>; 16] { [ None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, ] } - const fn match_account_leaf_no_code_and_no_storage( + fn match_account_leaf_no_code_and_no_storage( ) -> CompactParsingResult<(usize, Option, Option)> { Ok((1, None, None)) } @@ -733,7 +722,7 @@ impl WitnessBytes { let opcode_byte = self.byte_cursor.read_byte()?; let opcode = - Opcode::n(opcode_byte).ok_or(CompactParsingError::InvalidOpcode(opcode_byte))?; + Opcode::n(opcode_byte).ok_or(CompactParsingError::InvalidOperator(opcode_byte))?; trace!("Processed \"{:?}\" opcode", opcode); @@ -1214,7 +1203,7 @@ impl<'a> CollapsableWitnessEntryTraverser<'a> { } } -const fn try_get_node_entry_from_witness_entry(entry: &WitnessEntry) -> Option<&NodeEntry> { +fn try_get_node_entry_from_witness_entry(entry: &WitnessEntry) -> Option<&NodeEntry> { match entry { WitnessEntry::Node(n_entry) => Some(n_entry), _ => None, @@ -1230,38 +1219,24 @@ enum TraverserDirection { #[derive(Debug, Default)] pub(crate) struct PartialTriePreImages { - pub state: HashedPartialTrie, - pub storage: HashMap, + pub(crate) state: HashedPartialTrie, + pub(crate) storage: HashMap, } -/// The output we get from processing prestate compact into the trie format of -/// `mpt_trie`. -/// -/// Note that this format contains storage tries embedded within the state trie, -/// so there may be multiple tries inside this output. Also note that the -/// bytecode (instead of just the code hash) may be embedded directly in this -/// format. #[derive(Debug)] -pub struct ProcessedCompactOutput { - /// The header of the compact. - pub header: Header, - - /// The actual processed `mpt_trie` tries and additional code hash mappings - /// from the compact. - pub witness_out: StateTrieExtractionOutput, +pub(crate) struct ProcessedCompactOutput { + pub(crate) header: Header, + pub(crate) witness_out: WitnessOutput, } -/// Processes the compact prestate into the trie format of `mpt_trie`. -pub fn process_compact_prestate( +pub(crate) fn process_compact_prestate( state: TrieCompact, ) -> CompactParsingResult { process_compact_prestate_common(state, ParserState::create_and_extract_header) } -/// Processes the compact prestate into the trie format of `mpt_trie`. Also -/// enables heavy debug traces during processing. // TODO: Move behind a feature flag... -pub fn process_compact_prestate_debug( +pub(crate) fn process_compact_prestate_debug( state: TrieCompact, ) -> CompactParsingResult { process_compact_prestate_common(state, ParserState::create_and_extract_header_debug) diff --git a/trace_decoder/src/compact/compact_to_partial_trie.rs b/trace_decoder/src/compact/compact_to_partial_trie.rs index d7fac0644..ec6c77b34 100644 --- a/trace_decoder/src/compact/compact_to_partial_trie.rs +++ b/trace_decoder/src/compact/compact_to_partial_trie.rs @@ -104,16 +104,10 @@ pub(super) enum UnexpectedCompactNodeType { /// Output from constructing a state trie from compact. #[derive(Debug, Default)] -pub struct StateTrieExtractionOutput { - /// The state trie of the compact. - pub state_trie: HashedPartialTrie, - - /// Any embedded contract bytecode that appears in the compact will be - /// present here. - pub code: HashMap>, - - /// All storage tries present in the compact. - pub storage_tries: HashMap, +pub(super) struct StateTrieExtractionOutput { + pub(super) trie: HashedPartialTrie, + pub(super) code: HashMap>, + pub(super) storage_tries: HashMap, } impl CompactToPartialTrieExtractionOutput for StateTrieExtractionOutput { @@ -131,7 +125,7 @@ impl CompactToPartialTrieExtractionOutput for StateTrieExtractionOutput { leaf_node_data: &LeafNodeData, ) -> CompactParsingResult<()> { process_leaf_common( - &mut self.state_trie, + &mut self.trie, curr_key, leaf_key, leaf_node_data, @@ -146,7 +140,7 @@ impl CompactToPartialTrieExtractionOutput for StateTrieExtractionOutput { ) } fn trie(&mut self) -> &mut HashedPartialTrie { - &mut self.state_trie + &mut self.trie } } diff --git a/trace_decoder/src/compact/complex_test_payloads.rs b/trace_decoder/src/compact/complex_test_payloads.rs index 2f1f4bd32..89febd736 100644 --- a/trace_decoder/src/compact/complex_test_payloads.rs +++ b/trace_decoder/src/compact/complex_test_payloads.rs @@ -1,12 +1,9 @@ use evm_arithmetization::generation::mpt::AccountRlp; use mpt_trie::partial_trie::PartialTrie; -use super::{ - compact_prestate_processing::{ - process_compact_prestate, process_compact_prestate_debug, CompactParsingResult, - PartialTriePreImages, ProcessedCompactOutput, - }, - compact_to_partial_trie::StateTrieExtractionOutput, +use super::compact_prestate_processing::{ + process_compact_prestate, process_compact_prestate_debug, CompactParsingResult, + PartialTriePreImages, ProcessedCompactOutput, }; use crate::{ trace_protocol::TrieCompact, @@ -59,23 +56,23 @@ impl TestProtocolInputAndRoot { Ok(x) => x, Err(err) => panic!("{}", err.to_string()), }; - let trie_hash = out.witness_out.state_trie.hash(); + let trie_hash = out.witness_out.tries.state.hash(); - print_value_and_hash_nodes_of_trie(&out.witness_out.state_trie); + print_value_and_hash_nodes_of_trie(&out.witness_out.tries.state); - for (hashed_addr, s_trie) in out.witness_out.storage_tries.iter() { + for (hashed_addr, s_trie) in out.witness_out.tries.storage.iter() { print_value_and_hash_nodes_of_storage_trie(hashed_addr, s_trie); } assert!(out.header.version_is_compatible(1)); assert_eq!(trie_hash, expected_hash); - Self::assert_non_all_storage_roots_exist_in_storage_trie_map(&out.witness_out); + Self::assert_non_all_storage_roots_exist_in_storage_trie_map(&out.witness_out.tries); } - fn assert_non_all_storage_roots_exist_in_storage_trie_map(out: &StateTrieExtractionOutput) { - let non_empty_account_s_roots = out - .state_trie + fn assert_non_all_storage_roots_exist_in_storage_trie_map(images: &PartialTriePreImages) { + let non_empty_account_s_roots = images + .state .items() .filter_map(|(addr, data)| { data.as_val().map(|data| { @@ -89,7 +86,7 @@ impl TestProtocolInputAndRoot { .map(|(addr, _)| addr); for account_with_non_empty_root in non_empty_account_s_roots { - assert!(out.storage_tries.contains_key(&account_with_non_empty_root)); + assert!(images.storage.contains_key(&account_with_non_empty_root)); } } } diff --git a/trace_decoder/src/compact/mod.rs b/trace_decoder/src/compact/mod.rs index a07930735..4fe23ab33 100644 --- a/trace_decoder/src/compact/mod.rs +++ b/trace_decoder/src/compact/mod.rs @@ -1,5 +1,5 @@ -pub mod compact_prestate_processing; -pub mod compact_to_partial_trie; +pub(crate) mod compact_prestate_processing; +mod compact_to_partial_trie; #[cfg(test)] pub(crate) mod complex_test_payloads; diff --git a/trace_decoder/src/decoding.rs b/trace_decoder/src/decoding.rs index c0128bb54..b697fcaac 100644 --- a/trace_decoder/src/decoding.rs +++ b/trace_decoder/src/decoding.rs @@ -4,7 +4,7 @@ use std::{ iter::{self, empty, once}, }; -use ethereum_types::{Address, H256, U256, U512}; +use ethereum_types::{Address, H256, U256}; use evm_arithmetization::{ generation::{mpt::AccountRlp, GenerationInputs, TrieInputs}, proof::{ExtraBlockData, TrieRoots}, @@ -14,133 +14,28 @@ use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, Node, PartialTrie}, special_query::path_for_query, - trie_ops::TrieOpError, trie_subsets::{create_trie_subset, SubsetTrieError}, utils::{IntoTrieKey, TriePath, TrieSegment}, }; use thiserror::Error; use crate::{ - processed_block_trace::{ - NodesUsedByTxn, ProcessedBlockTrace, ProcessedTxnInfo, StateTrieWrites, TxnMetaState, - }, + processed_block_trace::{NodesUsedByTxn, ProcessedBlockTrace, StateTrieWrites, TxnMetaState}, types::{ HashedAccountAddr, HashedNodeAddr, HashedStorageAddr, HashedStorageAddrNibbles, - OtherBlockData, TriePathIter, TrieRootHash, TxnIdx, EMPTY_ACCOUNT_BYTES_RLPED, - ZERO_STORAGE_SLOT_VAL_RLPED, + OtherBlockData, TriePathIter, TrieRootHash, TxnIdx, TxnProofGenIR, + EMPTY_ACCOUNT_BYTES_RLPED, ZERO_STORAGE_SLOT_VAL_RLPED, }, - utils::{hash, optional_field, optional_field_hex, update_val_if_some}, + utils::{hash, update_val_if_some}, }; /// Stores the result of parsing tries. Returns a [TraceParsingError] upon /// failure. -pub type TraceParsingResult = Result>; - -/// Represents errors that can occur during the processing of a block trace. -/// -/// This struct is intended to encapsulate various kinds of errors that might -/// arise when parsing, validating, or otherwise processing the trace data of -/// blockchain blocks. It could include issues like malformed trace data, -/// inconsistencies found during processing, or any other condition that -/// prevents successful completion of the trace processing task. -#[derive(Debug)] -pub struct TraceParsingError { - block_num: Option, - block_chain_id: Option, - txn_idx: Option, - addr: Option
, - h_addr: Option, - slot: Option, - slot_value: Option, - reason: TraceParsingErrorReason, // The original error type -} - -impl std::fmt::Display for TraceParsingError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let h_slot = self.slot.map(|slot| { - let mut buf = [0u8; 64]; - slot.to_big_endian(&mut buf); - hash(&buf) - }); - write!( - f, - "Error processing trace: {}\n{}{}{}{}{}{}{}{}", - self.reason, - optional_field("Block num", self.block_num), - optional_field("Block chain id", self.block_chain_id), - optional_field("Txn idx", self.txn_idx), - optional_field("Address", self.addr.as_ref()), - optional_field("Hashed address", self.h_addr.as_ref()), - optional_field_hex("Slot", self.slot), - optional_field("Hashed Slot", h_slot), - optional_field_hex("Slot value", self.slot_value), - ) - } -} - -impl std::error::Error for TraceParsingError {} - -impl TraceParsingError { - /// Function to create a new TraceParsingError with mandatory fields - pub(crate) fn new(reason: TraceParsingErrorReason) -> Self { - Self { - block_num: None, - block_chain_id: None, - txn_idx: None, - addr: None, - h_addr: None, - slot: None, - slot_value: None, - reason, - } - } - - /// Builder method to set block_num - pub(crate) fn block_num(&mut self, block_num: U256) -> &mut Self { - self.block_num = Some(block_num); - self - } - - /// Builder method to set block_chain_id - pub(crate) fn block_chain_id(&mut self, block_chain_id: U256) -> &mut Self { - self.block_chain_id = Some(block_chain_id); - self - } - - /// Builder method to set txn_idx - pub fn txn_idx(&mut self, txn_idx: usize) -> &mut Self { - self.txn_idx = Some(txn_idx); - self - } - - /// Builder method to set addr - pub fn addr(&mut self, addr: Address) -> &mut Self { - self.addr = Some(addr); - self - } +pub type TraceParsingResult = Result; - /// Builder method to set h_addr - pub fn h_addr(&mut self, h_addr: H256) -> &mut Self { - self.h_addr = Some(h_addr); - self - } - - /// Builder method to set slot - pub fn slot(&mut self, slot: U512) -> &mut Self { - self.slot = Some(slot); - self - } - - /// Builder method to set slot_value - pub fn slot_value(&mut self, slot_value: U512) -> &mut Self { - self.slot_value = Some(slot_value); - self - } -} - -/// An error reason for trie parsing. +/// An error type for trie parsing. #[derive(Debug, Error)] -pub enum TraceParsingErrorReason { +pub enum TraceParsingError { /// Failure to decode an Ethereum [Account]. #[error("Failed to decode RLP bytes ({0}) as an Ethereum account due to the error: {1}")] AccountDecode(String, String), @@ -161,17 +56,6 @@ pub enum TraceParsingErrorReason { /// Failure due to trying to withdraw from a missing account #[error("No account present at {0:x} (hashed: {1:x}) to withdraw {2} Gwei from!")] MissingWithdrawalAccount(Address, HashedAccountAddr, U256), - - /// Failure due to a trie operation error. - #[error("Trie operation error: {0}")] - TrieOpError(TrieOpError), -} - -impl From for TraceParsingError { - fn from(err: TrieOpError) -> Self { - // Convert TrieOpError into TraceParsingError - TraceParsingError::new(TraceParsingErrorReason::TrieOpError(err)) - } } /// An enum to cover all Ethereum trie types (see https://ethereum.github.io/yellowpaper/paper.pdf for details). @@ -221,7 +105,7 @@ impl ProcessedBlockTrace { pub(crate) fn into_txn_proof_gen_ir( self, other_data: OtherBlockData, - ) -> TraceParsingResult> { + ) -> TraceParsingResult> { let mut curr_block_tries = PartialTrieState { state: self.tries.state.clone(), storage: self.tries.storage.clone(), @@ -251,24 +135,70 @@ impl ProcessedBlockTrace { .into_iter() .enumerate() .map(|(txn_idx, txn_info)| { - Self::process_txn_info( - txn_idx, - txn_info, + trace!("Generating proof IR for txn {}...", txn_idx); + + Self::init_any_needed_empty_storage_tries( + &mut curr_block_tries.storage, + txn_info + .nodes_used_by_txn + .storage_accesses + .iter() + .map(|(k, _)| k), + &txn_info + .nodes_used_by_txn + .state_accounts_with_no_accesses_but_storage_tries, + ); + // For each non-dummy txn, we increment `txn_number_after` by 1, and + // update `gas_used_after` accordingly. + extra_data.txn_number_after += U256::one(); + extra_data.gas_used_after += txn_info.meta.gas_used.into(); + + // Because we need to run delta application before creating the minimal + // sub-tries (we need to detect if deletes collapsed any branches), we need to + // do this clone every iteration. + let tries_at_start_of_txn = curr_block_tries.clone(); + + Self::update_txn_and_receipt_tries(&mut curr_block_tries, &txn_info.meta, txn_idx); + + let delta_out = Self::apply_deltas_to_trie_state( &mut curr_block_tries, - &mut extra_data, - &other_data, - ) - .map_err(|mut e| { - e.txn_idx(txn_idx); - e - }) + &txn_info.nodes_used_by_txn, + &txn_info.meta, + )?; + + let tries = Self::create_minimal_partial_tries_needed_by_txn( + &tries_at_start_of_txn, + &txn_info.nodes_used_by_txn, + txn_idx, + delta_out, + &other_data.b_data.b_meta.block_beneficiary, + )?; + + let trie_roots_after = calculate_trie_input_hashes(&curr_block_tries); + let gen_inputs = GenerationInputs { + txn_number_before: extra_data.txn_number_before, + gas_used_before: extra_data.gas_used_before, + gas_used_after: extra_data.gas_used_after, + signed_txn: txn_info.meta.txn_bytes, + withdrawals: Vec::default(), /* Only ever set in a dummy txn at the end of + * the block (see `[add_withdrawals_to_txns]` + * for more info). */ + tries, + trie_roots_after, + checkpoint_state_trie_root: extra_data.checkpoint_state_trie_root, + contract_code: txn_info.contract_code_accessed, + block_metadata: other_data.b_data.b_meta.clone(), + block_hashes: other_data.b_data.b_hashes.clone(), + }; + + // After processing a transaction, we update the remaining accumulators + // for the next transaction. + extra_data.txn_number_before += U256::one(); + extra_data.gas_used_before = extra_data.gas_used_after; + + Ok(gen_inputs) }) - .collect::>>() - .map_err(|mut e| { - e.block_num(other_data.b_data.b_meta.block_number); - e.block_chain_id(other_data.b_data.b_meta.block_chain_id); - e - })?; + .collect::>>()?; let dummies_added = Self::pad_gen_inputs_with_dummy_inputs_if_needed( &mut txn_gen_inputs, @@ -283,8 +213,11 @@ impl ProcessedBlockTrace { if !self.withdrawals.is_empty() { Self::add_withdrawals_to_txns( &mut txn_gen_inputs, + &other_data, + &extra_data, &mut curr_block_tries, self.withdrawals, + dummies_added, )?; } @@ -373,15 +306,9 @@ impl ProcessedBlockTrace { let mut out = TrieDeltaApplicationOutput::default(); for (hashed_acc_addr, storage_writes) in deltas.storage_writes.iter() { - let mut storage_trie = - trie_state.storage.get_mut(hashed_acc_addr).ok_or_else(|| { - let hashed_acc_addr = *hashed_acc_addr; - let mut e = TraceParsingError::new( - TraceParsingErrorReason::MissingAccountStorageTrie(hashed_acc_addr), - ); - e.h_addr(hashed_acc_addr); - e - })?; + let mut storage_trie = trie_state.storage.get_mut(hashed_acc_addr).ok_or( + TraceParsingError::MissingAccountStorageTrie(*hashed_acc_addr), + )?; for (slot, val) in storage_writes .iter() @@ -389,13 +316,7 @@ impl ProcessedBlockTrace { { // If we are writing a zero, then we actually need to perform a delete. match val == &ZERO_STORAGE_SLOT_VAL_RLPED { - false => storage_trie.insert(slot, val.clone()).map_err(|err| { - let mut e = - TraceParsingError::new(TraceParsingErrorReason::TrieOpError(err)); - e.slot(U512::from_big_endian(slot.bytes_be().as_slice())); - e.slot_value(U512::from_big_endian(val.as_slice())); - e - })?, + false => storage_trie.insert(slot, val.clone()), true => { if let Some(remaining_slot_key) = Self::delete_node_and_report_remaining_key_if_branch_collapsed( @@ -440,14 +361,10 @@ impl ProcessedBlockTrace { for hashed_addr in deltas.self_destructed_accounts.iter() { let k = Nibbles::from_h256_be(*hashed_addr); - trie_state.storage.remove(hashed_addr).ok_or_else(|| { - let hashed_addr = *hashed_addr; - let mut e = TraceParsingError::new( - TraceParsingErrorReason::MissingAccountStorageTrie(hashed_addr), - ); - e.h_addr(hashed_addr); - e - })?; + trie_state + .storage + .remove(hashed_addr) + .ok_or(TraceParsingError::MissingAccountStorageTrie(*hashed_addr))?; // TODO: Once the mechanism for resolving code hashes settles, we probably want // to also delete the code hash mapping here as well... @@ -520,7 +437,7 @@ impl ProcessedBlockTrace { /// `[add_withdrawals_to_txns]`), where the final one will mutate the /// state trie. fn pad_gen_inputs_with_dummy_inputs_if_needed( - gen_inputs: &mut Vec, + gen_inputs: &mut Vec, other_data: &OtherBlockData, final_extra_data: &ExtraBlockData, initial_extra_data: &ExtraBlockData, @@ -575,27 +492,64 @@ impl ProcessedBlockTrace { /// - If no dummy proofs are already present, then a dummy proof that just /// contains the withdrawals is appended to the end of the IR vec. fn add_withdrawals_to_txns( - txn_ir: &mut [GenerationInputs], + txn_ir: &mut Vec, + other_data: &OtherBlockData, + extra_data: &ExtraBlockData, final_trie_state: &mut PartialTrieState, withdrawals: Vec<(Address, U256)>, + dummies_already_added: bool, ) -> TraceParsingResult<()> { - let withdrawals_with_hashed_addrs_iter = || { - withdrawals - .iter() - .map(|(addr, v)| (*addr, hash(addr.as_bytes()), *v)) - }; + let withdrawals_with_hashed_addrs_iter = withdrawals + .iter() + .map(|(addr, v)| (*addr, hash(addr.as_bytes()), *v)); + + match dummies_already_added { + // If we have no actual dummy proofs, then we create one and append it to the + // end of the block. + false => { + // TODO: Decide if we want this allocation... + // To avoid double hashing the addrs, but I don't know if the extra `Vec` + // allocation is worth it. + let withdrawals_with_hashed_addrs: Vec<_> = + withdrawals_with_hashed_addrs_iter.collect(); + + // Dummy state will be the state after the final txn. Also need to include the + // account nodes that were accessed by the withdrawals. + let withdrawal_addrs = withdrawals_with_hashed_addrs + .iter() + .cloned() + .map(|(_, h_addr, _)| h_addr); + let mut withdrawal_dummy = create_dummy_gen_input_with_state_addrs_accessed( + other_data, + extra_data, + final_trie_state, + withdrawal_addrs, + )?; - Self::update_trie_state_from_withdrawals( - withdrawals_with_hashed_addrs_iter(), - &mut final_trie_state.state, - )?; + Self::update_trie_state_from_withdrawals( + withdrawals_with_hashed_addrs, + &mut final_trie_state.state, + )?; - let last_inputs = txn_ir - .last_mut() - .expect("We cannot have an empty list of payloads."); + withdrawal_dummy.withdrawals = withdrawals; - last_inputs.withdrawals = withdrawals; - last_inputs.trie_roots_after.state_root = final_trie_state.state.hash(); + // Only the state root hash needs to be updated from the withdrawals. + withdrawal_dummy.trie_roots_after.state_root = final_trie_state.state.hash(); + + txn_ir.push(withdrawal_dummy); + } + true => { + Self::update_trie_state_from_withdrawals( + withdrawals_with_hashed_addrs_iter, + &mut final_trie_state.state, + )?; + + // If we have dummy proofs (note: `txn_ir[1]` is always a dummy txn in this + // case), then this dummy will get the withdrawals. + txn_ir[1].withdrawals = withdrawals; + txn_ir[1].trie_roots_after.state_root = final_trie_state.state.hash(); + } + } Ok(()) } @@ -609,14 +563,12 @@ impl ProcessedBlockTrace { for (addr, h_addr, amt) in withdrawals { let h_addr_nibs = Nibbles::from_h256_be(h_addr); - let acc_bytes = state.get(h_addr_nibs).ok_or_else(|| { - let mut e = TraceParsingError::new( - TraceParsingErrorReason::MissingWithdrawalAccount(addr, h_addr, amt), - ); - e.addr(addr); - e.h_addr(h_addr); - e - })?; + let acc_bytes = + state + .get(h_addr_nibs) + .ok_or(TraceParsingError::MissingWithdrawalAccount( + addr, h_addr, amt, + ))?; let mut acc_data = account_from_rlped_bytes(acc_bytes)?; acc_data.balance += amt; @@ -626,78 +578,6 @@ impl ProcessedBlockTrace { Ok(()) } - - /// Processes a single transaction in the trace. - fn process_txn_info( - txn_idx: usize, - txn_info: ProcessedTxnInfo, - curr_block_tries: &mut PartialTrieState, - extra_data: &mut ExtraBlockData, - other_data: &OtherBlockData, - ) -> TraceParsingResult { - trace!("Generating proof IR for txn {}...", txn_idx); - - Self::init_any_needed_empty_storage_tries( - &mut curr_block_tries.storage, - txn_info - .nodes_used_by_txn - .storage_accesses - .iter() - .map(|(k, _)| k), - &txn_info - .nodes_used_by_txn - .state_accounts_with_no_accesses_but_storage_tries, - ); - // For each non-dummy txn, we increment `txn_number_after` by 1, and - // update `gas_used_after` accordingly. - extra_data.txn_number_after += U256::one(); - extra_data.gas_used_after += txn_info.meta.gas_used.into(); - - // Because we need to run delta application before creating the minimal - // sub-tries (we need to detect if deletes collapsed any branches), we need to - // do this clone every iteration. - let tries_at_start_of_txn = curr_block_tries.clone(); - - Self::update_txn_and_receipt_tries(curr_block_tries, &txn_info.meta, txn_idx); - - let delta_out = Self::apply_deltas_to_trie_state( - curr_block_tries, - &txn_info.nodes_used_by_txn, - &txn_info.meta, - )?; - - let tries = Self::create_minimal_partial_tries_needed_by_txn( - &tries_at_start_of_txn, - &txn_info.nodes_used_by_txn, - txn_idx, - delta_out, - &other_data.b_data.b_meta.block_beneficiary, - )?; - - let trie_roots_after = calculate_trie_input_hashes(curr_block_tries); - let gen_inputs = GenerationInputs { - txn_number_before: extra_data.txn_number_before, - gas_used_before: extra_data.gas_used_before, - gas_used_after: extra_data.gas_used_after, - signed_txn: txn_info.meta.txn_bytes, - withdrawals: Vec::default(), /* Only ever set in a dummy txn at the end of - * the block (see `[add_withdrawals_to_txns]` - * for more info). */ - tries, - trie_roots_after, - checkpoint_state_trie_root: extra_data.checkpoint_state_trie_root, - contract_code: txn_info.contract_code_accessed, - block_metadata: other_data.b_data.b_meta.clone(), - block_hashes: other_data.b_data.b_hashes.clone(), - }; - - // After processing a transaction, we update the remaining accumulators - // for the next transaction. - extra_data.txn_number_before += U256::one(); - extra_data.gas_used_before = extra_data.gas_used_after; - - Ok(gen_inputs) - } } impl StateTrieWrites { @@ -710,14 +590,9 @@ impl StateTrieWrites { let storage_root_hash_change = match self.storage_trie_change { false => None, true => { - let storage_trie = acc_storage_tries.get(h_addr).ok_or_else(|| { - let h_addr = *h_addr; - let mut e = TraceParsingError::new( - TraceParsingErrorReason::MissingAccountStorageTrie(h_addr), - ); - e.h_addr(h_addr); - e - })?; + let storage_trie = acc_storage_tries + .get(h_addr) + .ok_or(TraceParsingError::MissingAccountStorageTrie(*h_addr))?; Some(storage_trie.hash()) } @@ -751,7 +626,7 @@ fn create_dummy_txn_pair_for_empty_block( other_data: &OtherBlockData, extra_data: &ExtraBlockData, final_tries: &PartialTrieState, -) -> [GenerationInputs; 2] { +) -> [TxnProofGenIR; 2] { [ create_dummy_gen_input(other_data, extra_data, final_tries), create_dummy_gen_input(other_data, extra_data, final_tries), @@ -762,7 +637,7 @@ fn create_dummy_gen_input( other_data: &OtherBlockData, extra_data: &ExtraBlockData, final_tries: &PartialTrieState, -) -> GenerationInputs { +) -> TxnProofGenIR { let sub_tries = create_dummy_proof_trie_inputs( final_tries, create_fully_hashed_out_sub_partial_trie(&final_tries.state), @@ -775,7 +650,7 @@ fn create_dummy_gen_input_with_state_addrs_accessed( extra_data: &ExtraBlockData, final_tries: &PartialTrieState, account_addrs_accessed: impl Iterator, -) -> TraceParsingResult { +) -> TraceParsingResult { let sub_tries = create_dummy_proof_trie_inputs( final_tries, create_minimal_state_partial_trie( @@ -909,18 +784,13 @@ fn create_trie_subset_wrapped( SubsetTrieError::UnexpectedKey(key, _) => key, }; - Box::new(TraceParsingError::new( - TraceParsingErrorReason::MissingKeysCreatingSubPartialTrie(key, trie_type), - )) + TraceParsingError::MissingKeysCreatingSubPartialTrie(key, trie_type) }) } fn account_from_rlped_bytes(bytes: &[u8]) -> TraceParsingResult { - rlp::decode(bytes).map_err(|err| { - Box::new(TraceParsingError::new( - TraceParsingErrorReason::AccountDecode(hex::encode(bytes), err.to_string()), - )) - }) + rlp::decode(bytes) + .map_err(|err| TraceParsingError::AccountDecode(hex::encode(bytes), err.to_string())) } impl TxnMetaState { diff --git a/trace_decoder/src/lib.rs b/trace_decoder/src/lib.rs index 90eea0844..e52948c9f 100644 --- a/trace_decoder/src/lib.rs +++ b/trace_decoder/src/lib.rs @@ -80,7 +80,7 @@ //! p_meta: &ProcessingMeta, //! // Extra data needed for proof generation. //! other_data: OtherBlockData, -//! ) -> TraceParsingResult> +//! ) -> TraceParsingResult> //! ``` //! //! It first preprocesses the [BlockTrace] to provide transaction, diff --git a/trace_decoder/src/processed_block_trace.rs b/trace_decoder/src/processed_block_trace.rs index ab0ec85c2..31e1613cc 100644 --- a/trace_decoder/src/processed_block_trace.rs +++ b/trace_decoder/src/processed_block_trace.rs @@ -4,12 +4,11 @@ use std::iter::once; use ethereum_types::{Address, H256, U256}; use evm_arithmetization::generation::mpt::{AccountRlp, LegacyReceiptRlp}; -use evm_arithmetization::GenerationInputs; use mpt_trie::nibbles::Nibbles; use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use crate::compact::compact_prestate_processing::{ - process_compact_prestate_debug, PartialTriePreImages, ProcessedCompactOutput, + process_compact_prestate_debug, PartialTriePreImages, }; use crate::decoding::TraceParsingResult; use crate::trace_protocol::{ @@ -19,7 +18,8 @@ use crate::trace_protocol::{ }; use crate::types::{ CodeHash, CodeHashResolveFunc, HashedAccountAddr, HashedNodeAddr, HashedStorageAddr, - HashedStorageAddrNibbles, OtherBlockData, TrieRootHash, EMPTY_CODE_HASH, EMPTY_TRIE_HASH, + HashedStorageAddrNibbles, OtherBlockData, TrieRootHash, TxnProofGenIR, EMPTY_CODE_HASH, + EMPTY_TRIE_HASH, }; use crate::utils::{ h_addr_nibs_to_h256, hash, print_value_and_hash_nodes_of_storage_trie, @@ -42,7 +42,7 @@ impl BlockTrace { self, p_meta: &ProcessingMeta, other_data: OtherBlockData, - ) -> TraceParsingResult> + ) -> TraceParsingResult> where F: CodeHashResolveFunc, { @@ -109,21 +109,6 @@ struct ProcessedBlockTracePreImages { extra_code_hash_mappings: Option>>, } -impl From for ProcessedBlockTracePreImages { - fn from(v: ProcessedCompactOutput) -> Self { - let tries = PartialTriePreImages { - state: v.witness_out.state_trie, - storage: v.witness_out.storage_tries, - }; - - Self { - tries, - extra_code_hash_mappings: (!v.witness_out.code.is_empty()) - .then_some(v.witness_out.code), - } - } -} - fn process_block_trace_trie_pre_images( block_trace_pre_images: BlockTraceTriePreImages, ) -> ProcessedBlockTracePreImages { @@ -184,7 +169,10 @@ fn process_compact_trie(trie: TrieCompact) -> ProcessedBlockTracePreImages { // TODO: Make this into a result... assert!(out.header.version_is_compatible(COMPATIBLE_HEADER_VERSION)); - out.into() + ProcessedBlockTracePreImages { + tries: out.witness_out.tries, + extra_code_hash_mappings: out.witness_out.code, + } } /// Structure storing a function turning a `CodeHash` into bytes. @@ -202,7 +190,7 @@ where { /// Returns a `ProcessingMeta` given the provided code hash resolving /// function. - pub const fn new(resolve_code_hash_fn: F) -> Self { + pub fn new(resolve_code_hash_fn: F) -> Self { Self { resolve_code_hash_fn, } diff --git a/trace_decoder/src/types.rs b/trace_decoder/src/types.rs index b1e2da5ca..def6f02f1 100644 --- a/trace_decoder/src/types.rs +++ b/trace_decoder/src/types.rs @@ -7,6 +7,8 @@ use mpt_trie::{nibbles::Nibbles, partial_trie::HashedPartialTrie}; use serde::{Deserialize, Serialize}; // TODO: Make these types in the doc comments point to the actual types... +/// A type alias for `u64` of a block height. +pub type BlockHeight = u64; /// A type alias for `[U256; 8]` of a bloom filter. pub type Bloom = [U256; 8]; /// A type alias for `H256` of a code hash. @@ -59,6 +61,10 @@ pub(crate) const EMPTY_ACCOUNT_BYTES_RLPED: [u8; 70] = [ // This is just `rlp(0)`. pub(crate) const ZERO_STORAGE_SLOT_VAL_RLPED: [u8; 1] = [128]; +/// An `IR` (Intermediate Representation) for a given txn in a block that we can +/// use to generate a proof for that txn. +pub type TxnProofGenIR = GenerationInputs; + /// Other data that is needed for proof gen. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct OtherBlockData { diff --git a/trace_decoder/src/utils.rs b/trace_decoder/src/utils.rs index ee48e770f..678fcc064 100644 --- a/trace_decoder/src/utils.rs +++ b/trace_decoder/src/utils.rs @@ -1,6 +1,5 @@ use ethereum_types::H256; use keccak_hash::keccak; -use log::debug; use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, PartialTrie}, @@ -31,7 +30,7 @@ pub(crate) fn print_value_and_hash_nodes_of_storage_trie( trie: &HashedPartialTrie, ) { let trie_elems = print_value_and_hash_nodes_of_trie_common(trie); - debug!("Storage trie for {:x}: {:#?}", s_trie_addr, trie_elems); + println!("Storage trie for {:x}: {:#?}", s_trie_addr, trie_elems); } // TODO: Move under a feature flag... @@ -58,11 +57,3 @@ pub(crate) fn h_addr_nibs_to_h256(h_addr_nibs: &Nibbles) -> H256 { H256::from_slice(&nib_bytes) } - -pub(crate) fn optional_field(label: &str, value: Option) -> String { - value.map_or(String::new(), |v| format!("{}: {:?}\n", label, v)) -} - -pub(crate) fn optional_field_hex(label: &str, value: Option) -> String { - value.map_or(String::new(), |v| format!("{}: 0x{:064X}\n", label, v)) -}