From 06d4c97bffcaa921d8cd2c16a8b7b84a32d1a189 Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Fri, 24 Apr 2026 10:00:16 +0800 Subject: [PATCH 01/10] add . --- Cargo.lock | 42 +++++++++++++++++++------------- Cargo.toml | 2 +- crates/stateless-core/Cargo.toml | 10 +++++--- crates/stateless-core/src/lib.rs | 5 +++- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0fe6509b..6f23bab4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1150,14 +1150,14 @@ checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" [[package]] name = "banderwagon" version = "0.1.0" -source = "git+https://github.com/megaeth-labs/salt.git?rev=v1.0.1#f15f1b2cac046c874656f16af10b00db3174e733" +source = "git+https://github.com/megaeth-labs/salt.git?rev=c8a3289bd3564018c831c062e761df04e512c2a4#c8a3289bd3564018c831c062e761df04e512c2a4" dependencies = [ "ark-ec 0.5.0 (git+https://github.com/megaeth-labs/algebra.git?rev=80ca69c37f79d5d00750edc1602af81b5f456695)", "ark-ed-on-bls12-381-bandersnatch", "ark-ff 0.5.0 (git+https://github.com/megaeth-labs/algebra.git?rev=80ca69c37f79d5d00750edc1602af81b5f456695)", "ark-serialize 0.5.0 (git+https://github.com/megaeth-labs/algebra.git?rev=80ca69c37f79d5d00750edc1602af81b5f456695)", - "hugepage-rs", "rayon", + "salt-macros", ] [[package]] @@ -2409,6 +2409,7 @@ dependencies = [ "allocator-api2", "equivalent", "foldhash 0.2.0", + "rayon", "serde", "serde_core", ] @@ -2494,16 +2495,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "hugepage-rs" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb5004049783b438b3559de8e1bf8c0739a4d61e0d91d78c97db31abb90a505" -dependencies = [ - "lazy_static", - "libc", -] - [[package]] name = "hyper" version = "1.8.1" @@ -2879,13 +2870,15 @@ dependencies = [ [[package]] name = "ipa-multipoint" version = "0.1.0" -source = "git+https://github.com/megaeth-labs/salt.git?rev=v1.0.1#f15f1b2cac046c874656f16af10b00db3174e733" +source = "git+https://github.com/megaeth-labs/salt.git?rev=c8a3289bd3564018c831c062e761df04e512c2a4#c8a3289bd3564018c831c062e761df04e512c2a4" dependencies = [ "banderwagon", + "hashbrown 0.16.1", "hex", "itertools 0.10.5", "rayon", "rustc-hash", + "salt-macros", "sha2 0.9.9", "thiserror 2.0.17", ] @@ -3113,7 +3106,7 @@ dependencies = [ "serde_arrays", "sha2 0.10.9", "sp1_bls12_381", - "spin", + "spin 0.9.8", ] [[package]] @@ -5121,23 +5114,33 @@ checksum = "dd29631678d6fb0903b69223673e122c32e9ae559d0960a38d574695ebc0ea15" [[package]] name = "salt" version = "1.0.1" -source = "git+https://github.com/megaeth-labs/salt.git?rev=v1.0.1#f15f1b2cac046c874656f16af10b00db3174e733" +source = "git+https://github.com/megaeth-labs/salt.git?rev=c8a3289bd3564018c831c062e761df04e512c2a4#c8a3289bd3564018c831c062e761df04e512c2a4" dependencies = [ "auto_impl", "banderwagon", "blake3", "derive_more", + "hashbrown 0.16.1", "hex", "ipa-multipoint", - "once_cell", "rayon", "rustc-hash", + "salt-macros", "serde", "serde_arrays", + "spin 0.10.0", "thiserror 2.0.17", "zerocopy 0.7.35", ] +[[package]] +name = "salt-macros" +version = "0.1.0" +source = "git+https://github.com/megaeth-labs/salt.git?rev=c8a3289bd3564018c831c062e761df04e512c2a4#c8a3289bd3564018c831c062e761df04e512c2a4" +dependencies = [ + "rayon", +] + [[package]] name = "schemars" version = "0.9.0" @@ -5552,6 +5555,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" + [[package]] name = "spki" version = "0.7.3" @@ -6757,7 +6766,6 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "byteorder", "zerocopy-derive 0.7.35", ] diff --git a/Cargo.toml b/Cargo.toml index a842fe0d..50e6c392 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ alloy-trie = { version = "0.9.0", default-features = false } # mega mega-evm = { git = "https://github.com/megaeth-labs/mega-evm.git", rev = "4e4d85cc8202ec4980ec4fa0b6f50666c9d7e92e" } -salt = { git = "https://github.com/megaeth-labs/salt.git", rev = "v1.0.1" } +salt = { git = "https://github.com/megaeth-labs/salt.git", rev = "c8a3289bd3564018c831c062e761df04e512c2a4" } # op op-alloy-network = "0.18.12" diff --git a/crates/stateless-core/Cargo.toml b/crates/stateless-core/Cargo.toml index 7d71f679..0d4d3210 100644 --- a/crates/stateless-core/Cargo.toml +++ b/crates/stateless-core/Cargo.toml @@ -42,14 +42,14 @@ revm.workspace = true # misc dyn-clone.workspace = true eyre.workspace = true -kanal.workspace = true -num_cpus.workspace = true +kanal = { workspace = true, optional = true } +num_cpus = { workspace = true, optional = true } rustc-hash.workspace = true serde.workspace = true serde_json.workspace = true thiserror.workspace = true -tokio.workspace = true -tokio-util.workspace = true +tokio = { workspace = true, optional = true } +tokio-util = { workspace = true, optional = true } tracing.workspace = true [dev-dependencies] @@ -60,4 +60,6 @@ stateless-test-utils = { path = "../stateless-test-utils" } bincode.workspace = true [features] +default = ["std"] +std = ["dep:kanal", "dep:num_cpus", "dep:tokio", "dep:tokio-util"] test-bucket-resize = ["salt/test-bucket-resize"] diff --git a/crates/stateless-core/src/lib.rs b/crates/stateless-core/src/lib.rs index 4457d613..fccb70f7 100644 --- a/crates/stateless-core/src/lib.rs +++ b/crates/stateless-core/src/lib.rs @@ -12,7 +12,8 @@ //! - [`db`]: Abstract storage traits (`ChainStore`, `ContractStore`, etc.) //! - [`data_types`]: SALT key/value encoding utilities //! - [`executor`]: Block validation via EVM replay -//! - [`pipeline`]: Generic three-stage chain sync pipeline (fetch → process → advance) +//! - [`pipeline`]: Generic three-stage chain sync pipeline (fetch → process → advance) — requires +//! `std` feature //! - [`withdrawals`]: MPT witness verification for L2→L1 withdrawals pub mod chain_spec; @@ -31,7 +32,9 @@ pub mod executor; pub use executor::{ ValidationError, ValidationResult, ValidationStats, replay_block, validate_block, }; +#[cfg(feature = "std")] pub mod pipeline; +#[cfg(feature = "std")] pub use pipeline::{ BlockFetcher, BlockProcessor, ErrorAction, PipelineConfig, PipelineHooks, PipelineOutcome, ProcessedBlock, ReorgEvent, block_fetcher, find_divergence_point, run_pipeline, From adb9a7e8c384cc07945b55005e265d128ec19677 Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Fri, 24 Apr 2026 13:27:21 +0800 Subject: [PATCH 02/10] add . --- Cargo.lock | 70 ++++++++++++---------- Cargo.toml | 19 +++--- bin/debug-trace-server/src/server_db.rs | 5 +- crates/stateless-core/Cargo.toml | 50 ++++++++++++---- crates/stateless-core/src/chain_spec.rs | 36 ++++++----- crates/stateless-core/src/data_types.rs | 2 +- crates/stateless-core/src/lib.rs | 15 ++++- crates/stateless-core/src/light_witness.rs | 12 ++-- crates/stateless-core/src/withdrawals.rs | 10 +++- 9 files changed, 138 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f23bab4..55eac203 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "ahash" version = "0.8.12" @@ -166,6 +172,7 @@ dependencies = [ "alloy-eips", "alloy-hardforks", "alloy-primitives", + "alloy-rpc-types-eth", "alloy-sol-types", "auto_impl", "derive_more", @@ -3359,6 +3366,15 @@ dependencies = [ "sketches-ddsketch", ] +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.2.0" @@ -4478,6 +4494,7 @@ dependencies = [ "alloy-primitives", "auto_impl", "once_cell", + "rustc-hash", ] [[package]] @@ -4500,6 +4517,7 @@ source = "git+https://github.com/paradigmxyz/reth?tag=v1.6.0#d8451e54e7267f9f163 dependencies = [ "alloy-primitives", "alloy-rlp", + "secp256k1 0.30.0", "serde_with", "thiserror 2.0.17", "url", @@ -4517,6 +4535,7 @@ dependencies = [ "alloy-hardforks", "alloy-primitives", "derive_more", + "miniz_oxide", "op-alloy-consensus", "op-alloy-rpc-types", "reth-chainspec", @@ -4525,7 +4544,9 @@ dependencies = [ "reth-optimism-forks", "reth-optimism-primitives", "reth-primitives-traits", + "serde", "serde_json", + "thiserror 2.0.17", ] [[package]] @@ -4548,8 +4569,13 @@ dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", + "bytes", "op-alloy-consensus", + "reth-codecs", "reth-primitives-traits", + "reth-zstd-compressors", + "serde", + "serde_with", ] [[package]] @@ -4562,6 +4588,7 @@ dependencies = [ "alloy-genesis", "alloy-primitives", "alloy-rlp", + "alloy-rpc-types-eth", "alloy-trie", "auto_impl", "bytes", @@ -4572,6 +4599,9 @@ dependencies = [ "revm-bytecode", "revm-primitives", "revm-state", + "secp256k1 0.30.0", + "serde", + "serde_with", "thiserror 2.0.17", ] @@ -4582,18 +4612,10 @@ source = "git+https://github.com/paradigmxyz/reth?tag=v1.6.0#d8451e54e7267f9f163 dependencies = [ "alloy-primitives", "derive_more", + "serde", "thiserror 2.0.17", ] -[[package]] -name = "reth-stages-types" -version = "1.6.0" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.6.0#d8451e54e7267f9f1634118d6d279b2216f7e2bb" -dependencies = [ - "alloy-primitives", - "reth-trie-common", -] - [[package]] name = "reth-static-file-types" version = "1.6.0" @@ -4621,28 +4643,6 @@ dependencies = [ "thiserror 2.0.17", ] -[[package]] -name = "reth-trie" -version = "1.6.0" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.6.0#d8451e54e7267f9f1634118d6d279b2216f7e2bb" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "alloy-rlp", - "alloy-trie", - "auto_impl", - "itertools 0.14.0", - "reth-execution-errors", - "reth-primitives-traits", - "reth-stages-types", - "reth-storage-errors", - "reth-trie-common", - "reth-trie-sparse", - "revm-database", - "tracing", -] - [[package]] name = "reth-trie-common" version = "1.6.0" @@ -4651,13 +4651,17 @@ dependencies = [ "alloy-consensus", "alloy-primitives", "alloy-rlp", + "alloy-rpc-types-eth", + "alloy-serde", "alloy-trie", + "bytes", "derive_more", "itertools 0.14.0", "nybbles", - "rayon", "reth-primitives-traits", "revm-database", + "serde", + "serde_with", ] [[package]] @@ -5634,6 +5638,7 @@ dependencies = [ "bincode 2.0.1", "dyn-clone", "eyre", + "hashbrown 0.16.1", "kanal", "mega-evm", "num_cpus", @@ -5641,7 +5646,6 @@ dependencies = [ "op-alloy-rpc-types", "reth-ethereum-forks", "reth-optimism-chainspec", - "reth-trie", "reth-trie-common", "reth-trie-sparse", "revm", diff --git a/Cargo.toml b/Cargo.toml index 50e6c392..e4396da7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,10 +23,10 @@ alloy-consensus = { version = "1.0.23", default-features = false } alloy-eips = { version = "1.0.23", default-features = false } alloy-evm = { version = "0.15.0", default-features = false } alloy-genesis = { version = "1.0.23", default-features = false } -alloy-hardforks = "0.2.7" +alloy-hardforks = { version = "0.2.7", default-features = false } alloy-network = "1.0.23" alloy-op-evm = { version = "0.15.0", default-features = false } -alloy-op-hardforks = "0.2.7" +alloy-op-hardforks = { version = "0.2.7", default-features = false } alloy-primitives = { version = "1.3.0", default-features = false } alloy-provider = { version = "1.0.23", features = [ "reqwest", @@ -40,11 +40,11 @@ alloy-signer-local = "1.0.23" alloy-trie = { version = "0.9.0", default-features = false } # mega -mega-evm = { git = "https://github.com/megaeth-labs/mega-evm.git", rev = "4e4d85cc8202ec4980ec4fa0b6f50666c9d7e92e" } -salt = { git = "https://github.com/megaeth-labs/salt.git", rev = "c8a3289bd3564018c831c062e761df04e512c2a4" } +mega-evm = { git = "https://github.com/megaeth-labs/mega-evm.git", rev = "4e4d85cc8202ec4980ec4fa0b6f50666c9d7e92e", default-features = false } +salt = { git = "https://github.com/megaeth-labs/salt.git", rev = "c8a3289bd3564018c831c062e761df04e512c2a4", default-features = false } # op -op-alloy-network = "0.18.12" +op-alloy-network = { version = "0.18.12", default-features = false } op-alloy-rpc-types = { version = "0.18.12", default-features = false } # reth @@ -69,6 +69,7 @@ dyn-clone = "1.0" eyre = { version = "0.6", features = ["auto-install"], default-features = false } fastrand = { version = "2.4", default-features = false } futures = { version = "0.3", default-features = false } +hashbrown = { version = "0.16", default-features = false } http = "1.4" http-body = "1.0" http-body-util = "0.1" @@ -87,11 +88,11 @@ rayon = "1.11" redb = "4.0" reqwest = { version = "0.13", features = ["json", "blocking"], default-features = false } rolling-file = "0.2" -rustc-hash = "2.1" -serde = { version = "1.0", default-features = false } -serde_json = { version = "1.0", default-features = false } +rustc-hash = { version = "2.1", default-features = false } +serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } +serde_json = { version = "1.0", default-features = false, features = ["alloc"] } tempfile = { version = "3.27", default-features = false } -thiserror = "2.0" +thiserror = { version = "2.0", default-features = false } tokio = { version = "1.51", features = ["rt-multi-thread", "signal"], default-features = false } tokio-util = { version = "0.7", default-features = false } tower = "0.5" diff --git a/bin/debug-trace-server/src/server_db.rs b/bin/debug-trace-server/src/server_db.rs index f89dd803..5a073344 100644 --- a/bin/debug-trace-server/src/server_db.rs +++ b/bin/debug-trace-server/src/server_db.rs @@ -292,10 +292,7 @@ mod tests { } fn empty_light_witness() -> LightWitness { - LightWitness { - kvs: std::collections::BTreeMap::new(), - levels: rustc_hash::FxHashMap::default(), - } + LightWitness { kvs: std::collections::BTreeMap::new(), levels: Default::default() } } #[test] diff --git a/crates/stateless-core/Cargo.toml b/crates/stateless-core/Cargo.toml index 0d4d3210..d96ab2c8 100644 --- a/crates/stateless-core/Cargo.toml +++ b/crates/stateless-core/Cargo.toml @@ -13,26 +13,25 @@ alloy-consensus.workspace = true alloy-eips.workspace = true alloy-evm.workspace = true alloy-genesis.workspace = true -alloy-hardforks.workspace = true +alloy-hardforks = { workspace = true, default-features = false } alloy-op-evm.workspace = true -alloy-op-hardforks.workspace = true +alloy-op-hardforks = { workspace = true, default-features = false } alloy-primitives.workspace = true alloy-rlp.workspace = true alloy-rpc-types-eth.workspace = true alloy-serde.workspace = true # mega -mega-evm.workspace = true -salt.workspace = true +mega-evm = { workspace = true, default-features = false } +salt = { workspace = true, default-features = false } # op -op-alloy-network.workspace = true +op-alloy-network = { workspace = true, default-features = false, optional = true } op-alloy-rpc-types.workspace = true # reth reth-ethereum-forks.workspace = true reth-optimism-chainspec.workspace = true -reth-trie.workspace = true reth-trie-common.workspace = true reth-trie-sparse.workspace = true @@ -41,13 +40,14 @@ revm.workspace = true # misc dyn-clone.workspace = true -eyre.workspace = true +eyre = { workspace = true, optional = true } +hashbrown.workspace = true kanal = { workspace = true, optional = true } num_cpus = { workspace = true, optional = true } -rustc-hash.workspace = true +rustc-hash = { workspace = true, default-features = false } serde.workspace = true serde_json.workspace = true -thiserror.workspace = true +thiserror = { workspace = true, default-features = false } tokio = { workspace = true, optional = true } tokio-util = { workspace = true, optional = true } tracing.workspace = true @@ -61,5 +61,35 @@ bincode.workspace = true [features] default = ["std"] -std = ["dep:kanal", "dep:num_cpus", "dep:tokio", "dep:tokio-util"] +std = [ + "dep:eyre", + "dep:kanal", + "dep:num_cpus", + "dep:op-alloy-network", + "dep:tokio", + "dep:tokio-util", + "alloy-consensus/std", + "alloy-eips/std", + "alloy-evm/std", + "alloy-genesis/std", + "alloy-op-evm/std", + "alloy-primitives/std", + "alloy-rlp/std", + "alloy-rpc-types-eth/std", + "alloy-serde/std", + "mega-evm/default", + "op-alloy-network/std", + "op-alloy-rpc-types/std", + "reth-ethereum-forks/std", + "reth-optimism-chainspec/std", + "reth-trie-common/std", + "reth-trie-sparse/std", + "revm/default", + "rustc-hash/std", + "salt/default", + "serde/std", + "serde_json/std", + "thiserror/std", + "tracing/std", +] test-bucket-resize = ["salt/test-bucket-resize"] diff --git a/crates/stateless-core/src/chain_spec.rs b/crates/stateless-core/src/chain_spec.rs index 729de2bd..997d15c8 100644 --- a/crates/stateless-core/src/chain_spec.rs +++ b/crates/stateless-core/src/chain_spec.rs @@ -1,5 +1,7 @@ //! Chain specification and hardfork activation logic. +use std::{boxed::Box, vec, vec::Vec}; + use alloy_genesis::Genesis; use alloy_hardforks::{EthereumHardfork, EthereumHardforks, ForkCondition, Hardfork}; use alloy_op_hardforks::{OpHardfork, OpHardforks}; @@ -71,9 +73,9 @@ impl ChainSpec { .map(|(f, b)| (dyn_clone::clone_box(f), b)) .collect(); - let hardfork_order = MEGA_MAINNET_HARDFORKS.forks_iter(); + let hardfork_order = mega_mainnet_hardforks(); let mut all_hardforks = Vec::with_capacity(op_hardforks.len() + megaeth_hardforks.len()); - for (order, _) in hardfork_order { + for (order, _) in hardfork_order.forks_iter() { if let Some(mega_hardfork_index) = megaeth_hardforks.iter().position(|(hardfork, _)| **hardfork == *order) { @@ -140,21 +142,25 @@ impl MegaethGenesisHardforks { } } +/// Build a fresh `ChainHardforks` describing MegaETH's canonical hardfork sequence. +pub fn mega_mainnet_hardforks() -> ChainHardforks { + ChainHardforks::new(vec![ + (MegaHardfork::MiniRex.boxed(), ForkCondition::Timestamp(0)), + (MegaHardfork::MiniRex1.boxed(), ForkCondition::Timestamp(0)), + (MegaHardfork::MiniRex2.boxed(), ForkCondition::Timestamp(0)), + (MegaHardfork::Rex.boxed(), ForkCondition::Timestamp(0)), + (MegaHardfork::Rex1.boxed(), ForkCondition::Timestamp(0)), + (MegaHardfork::Rex2.boxed(), ForkCondition::Timestamp(0)), + (MegaHardfork::Rex3.boxed(), ForkCondition::Timestamp(0)), + (MegaHardfork::Rex4.boxed(), ForkCondition::Timestamp(0)), + (MegaHardfork::Rex5.boxed(), ForkCondition::Timestamp(0)), + ]) +} + /// Hardforks configuration for MegaETH. +#[cfg(feature = "std")] pub static MEGA_MAINNET_HARDFORKS: std::sync::LazyLock = - std::sync::LazyLock::new(|| { - ChainHardforks::new(vec![ - (MegaHardfork::MiniRex.boxed(), ForkCondition::Timestamp(0)), - (MegaHardfork::MiniRex1.boxed(), ForkCondition::Timestamp(0)), - (MegaHardfork::MiniRex2.boxed(), ForkCondition::Timestamp(0)), - (MegaHardfork::Rex.boxed(), ForkCondition::Timestamp(0)), - (MegaHardfork::Rex1.boxed(), ForkCondition::Timestamp(0)), - (MegaHardfork::Rex2.boxed(), ForkCondition::Timestamp(0)), - (MegaHardfork::Rex3.boxed(), ForkCondition::Timestamp(0)), - (MegaHardfork::Rex4.boxed(), ForkCondition::Timestamp(0)), - (MegaHardfork::Rex5.boxed(), ForkCondition::Timestamp(0)), - ]) - }); + std::sync::LazyLock::new(mega_mainnet_hardforks); #[cfg(test)] mod tests { diff --git a/crates/stateless-core/src/data_types.rs b/crates/stateless-core/src/data_types.rs index 2313e825..edbd38ff 100644 --- a/crates/stateless-core/src/data_types.rs +++ b/crates/stateless-core/src/data_types.rs @@ -23,7 +23,7 @@ //! - Contract accounts: 72 bytes (8-byte nonce + 32-byte balance + 32-byte bytecode hash) //! - Storage values: 32 bytes (U256 value) -use std::collections::BTreeMap; +use std::{collections::BTreeMap, vec::Vec}; pub use alloy_primitives::Bytes; use alloy_primitives::{Address, B256, U256}; diff --git a/crates/stateless-core/src/lib.rs b/crates/stateless-core/src/lib.rs index fccb70f7..5bc98972 100644 --- a/crates/stateless-core/src/lib.rs +++ b/crates/stateless-core/src/lib.rs @@ -9,26 +9,37 @@ //! - [`chain_spec`]: Chain specification and hardfork activation //! - [`light_witness`]: Fast witness deserialization (skips proof validation) //! - [`evm_database`]: Witness-backed `DatabaseRef` for REVM -//! - [`db`]: Abstract storage traits (`ChainStore`, `ContractStore`, etc.) +//! - [`db`]: Abstract storage traits (`ChainStore`, `ContractStore`, etc.) — requires `std` feature //! - [`data_types`]: SALT key/value encoding utilities -//! - [`executor`]: Block validation via EVM replay +//! - [`executor`]: Block validation via EVM replay — requires `std` feature //! - [`pipeline`]: Generic three-stage chain sync pipeline (fetch → process → advance) — requires //! `std` feature //! - [`withdrawals`]: MPT witness verification for L2→L1 withdrawals +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc as std; + pub mod chain_spec; pub mod light_witness; pub use light_witness::{LightWitness, LightWitnessExecutor}; +#[cfg(feature = "std")] pub mod evm_database; +#[cfg(feature = "std")] pub use evm_database::{WitnessDatabase, WitnessDatabaseError, WitnessExternalEnv}; +#[cfg(feature = "std")] pub mod db; +#[cfg(feature = "std")] pub use db::{ BlockMeta, BlockStore, ChainStore, ContractStore, GenesisStore, MissingDataKind, PrunableChainStore, StoreError, StoreResult, StoreResultExt, }; pub mod data_types; pub use data_types::{PlainKey, PlainValue, iter_code_hashes}; +#[cfg(feature = "std")] pub mod executor; +#[cfg(feature = "std")] pub use executor::{ ValidationError, ValidationResult, ValidationStats, replay_block, validate_block, }; diff --git a/crates/stateless-core/src/light_witness.rs b/crates/stateless-core/src/light_witness.rs index fdba0a56..feeeb16d 100644 --- a/crates/stateless-core/src/light_witness.rs +++ b/crates/stateless-core/src/light_witness.rs @@ -14,12 +14,16 @@ //! - Standard `SaltWitness` deserialization: ~240ms (due to EC point validation) //! - `LightWitness` deserialization: ~10-20ms (skips EC point validation) -use std::{collections::BTreeMap, ops::RangeInclusive}; +use core::ops::RangeInclusive; +use std::{collections::BTreeMap, vec::Vec}; -use rustc_hash::FxHashMap; +use hashbrown::HashMap; +use rustc_hash::FxBuildHasher; use salt::{BucketId, BucketMeta, SaltKey, SaltValue, bucket_metadata_key, traits::StateReader}; use serde::{Deserialize, Serialize}; +type FxHashMap = HashMap; + /// Light witness that only contains data needed for execution. /// /// This struct mirrors `SaltWitness` but stores proof data as raw bytes @@ -120,14 +124,14 @@ impl StateReader for LightWitness { pub struct LightWitnessExecutor { /// Direct mapping from plain keys to their salt key locations. /// Only contains keys that exist. - direct_lookup_tbl: std::collections::HashMap, SaltKey>, + direct_lookup_tbl: HashMap, SaltKey>, /// The underlying fast witness light_witness: LightWitness, } impl From for LightWitnessExecutor { fn from(light_witness: LightWitness) -> Self { - let mut direct_lookup_tbl = std::collections::HashMap::new(); + let mut direct_lookup_tbl = HashMap::default(); for (salt_key, value) in &light_witness.kvs { if salt_key.is_in_meta_bucket() { continue; diff --git a/crates/stateless-core/src/withdrawals.rs b/crates/stateless-core/src/withdrawals.rs index c110a60f..21df306e 100644 --- a/crates/stateless-core/src/withdrawals.rs +++ b/crates/stateless-core/src/withdrawals.rs @@ -5,12 +5,16 @@ //! storage updates from block execution, it cryptographically proves the storage root //! transition is valid. +use std::{ + string::{String, ToString}, + vec::Vec, +}; + use alloy_consensus::constants::KECCAK_EMPTY; use alloy_primitives::{Address, B256, Bytes, U256, address, keccak256, map::B256Map}; use alloy_rlp::Encodable; use alloy_rpc_types_eth::Header; -use reth_trie::Nibbles; -use reth_trie_common::{EMPTY_ROOT_HASH, LeafNode, TrieAccount, TrieNode}; +use reth_trie_common::{EMPTY_ROOT_HASH, LeafNode, Nibbles, TrieAccount, TrieNode}; use reth_trie_sparse::{ SerialSparseTrie, SparseStateTrie, SparseTrie, provider::DefaultTrieNodeProviderFactory, }; @@ -155,7 +159,7 @@ impl MptWitness { /// Returns `(synthesized_state_root, witness_map, hashed_address)`. fn synthesize_state_witness(witness: &MptWitness) -> (B256, B256Map, B256) { let mut witness_map: B256Map = - witness.state.iter().map(|node| (keccak256(node), node.clone())).collect(); + witness.state.iter().map(|node: &Bytes| (keccak256(node.as_ref()), node.clone())).collect(); let hashed_address = keccak256(ADDRESS_L2_TO_L1_MESSAGE_PASSER); // `nonce`, `balance`, and `code_hash` are intentionally dummy values — they From fa0e718a9bd6d63e1d11a60b8646d1e3a91487da Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Fri, 24 Apr 2026 14:53:32 +0800 Subject: [PATCH 03/10] support no_std --- Cargo.lock | 12 ++--- Cargo.toml | 3 +- bin/debug-trace-server/src/chain_sync.rs | 4 +- bin/debug-trace-server/src/data_provider.rs | 5 +- bin/debug-trace-server/src/server_db.rs | 4 +- .../src/tracing_executor.rs | 4 +- bin/stateless-validator/src/validator_db.rs | 4 +- crates/stateless-core/Cargo.toml | 5 +- crates/stateless-core/src/chain_spec.rs | 10 ++-- crates/stateless-core/src/db.rs | 31 ++++++++---- crates/stateless-core/src/evm_database.rs | 13 +++-- crates/stateless-core/src/executor.rs | 48 ++++++++++++++----- crates/stateless-core/src/lib.rs | 10 +--- crates/stateless-core/src/pipeline/tests.rs | 34 ++++++------- crates/stateless-db/src/cache.rs | 8 ++-- crates/stateless-db/src/helpers.rs | 6 +-- crates/stateless-test-utils/src/fixtures.rs | 6 +-- 17 files changed, 118 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 55eac203..281a2612 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1157,7 +1157,7 @@ checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" [[package]] name = "banderwagon" version = "0.1.0" -source = "git+https://github.com/megaeth-labs/salt.git?rev=c8a3289bd3564018c831c062e761df04e512c2a4#c8a3289bd3564018c831c062e761df04e512c2a4" +source = "git+https://github.com/megaeth-labs/salt.git?rev=v1.0.2#2bb00254bbe9fd6671afac8a1bf3464614638b1c" dependencies = [ "ark-ec 0.5.0 (git+https://github.com/megaeth-labs/algebra.git?rev=80ca69c37f79d5d00750edc1602af81b5f456695)", "ark-ed-on-bls12-381-bandersnatch", @@ -2877,7 +2877,7 @@ dependencies = [ [[package]] name = "ipa-multipoint" version = "0.1.0" -source = "git+https://github.com/megaeth-labs/salt.git?rev=c8a3289bd3564018c831c062e761df04e512c2a4#c8a3289bd3564018c831c062e761df04e512c2a4" +source = "git+https://github.com/megaeth-labs/salt.git?rev=v1.0.2#2bb00254bbe9fd6671afac8a1bf3464614638b1c" dependencies = [ "banderwagon", "hashbrown 0.16.1", @@ -5117,8 +5117,8 @@ checksum = "dd29631678d6fb0903b69223673e122c32e9ae559d0960a38d574695ebc0ea15" [[package]] name = "salt" -version = "1.0.1" -source = "git+https://github.com/megaeth-labs/salt.git?rev=c8a3289bd3564018c831c062e761df04e512c2a4#c8a3289bd3564018c831c062e761df04e512c2a4" +version = "1.0.2" +source = "git+https://github.com/megaeth-labs/salt.git?rev=v1.0.2#2bb00254bbe9fd6671afac8a1bf3464614638b1c" dependencies = [ "auto_impl", "banderwagon", @@ -5140,7 +5140,7 @@ dependencies = [ [[package]] name = "salt-macros" version = "0.1.0" -source = "git+https://github.com/megaeth-labs/salt.git?rev=c8a3289bd3564018c831c062e761df04e512c2a4#c8a3289bd3564018c831c062e761df04e512c2a4" +source = "git+https://github.com/megaeth-labs/salt.git?rev=v1.0.2#2bb00254bbe9fd6671afac8a1bf3464614638b1c" dependencies = [ "rayon", ] @@ -5629,6 +5629,7 @@ dependencies = [ "alloy-evm", "alloy-genesis", "alloy-hardforks", + "alloy-network-primitives", "alloy-op-evm", "alloy-op-hardforks", "alloy-primitives", @@ -5642,7 +5643,6 @@ dependencies = [ "kanal", "mega-evm", "num_cpus", - "op-alloy-network", "op-alloy-rpc-types", "reth-ethereum-forks", "reth-optimism-chainspec", diff --git a/Cargo.toml b/Cargo.toml index e4396da7..66d42006 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ alloy-evm = { version = "0.15.0", default-features = false } alloy-genesis = { version = "1.0.23", default-features = false } alloy-hardforks = { version = "0.2.7", default-features = false } alloy-network = "1.0.23" +alloy-network-primitives = { version = "1.0.23", default-features = false } alloy-op-evm = { version = "0.15.0", default-features = false } alloy-op-hardforks = { version = "0.2.7", default-features = false } alloy-primitives = { version = "1.3.0", default-features = false } @@ -41,7 +42,7 @@ alloy-trie = { version = "0.9.0", default-features = false } # mega mega-evm = { git = "https://github.com/megaeth-labs/mega-evm.git", rev = "4e4d85cc8202ec4980ec4fa0b6f50666c9d7e92e", default-features = false } -salt = { git = "https://github.com/megaeth-labs/salt.git", rev = "c8a3289bd3564018c831c062e761df04e512c2a4", default-features = false } +salt = { git = "https://github.com/megaeth-labs/salt.git", rev = "v1.0.2", default-features = false } # op op-alloy-network = { version = "0.18.12", default-features = false } diff --git a/bin/debug-trace-server/src/chain_sync.rs b/bin/debug-trace-server/src/chain_sync.rs index dd402114..941f6020 100644 --- a/bin/debug-trace-server/src/chain_sync.rs +++ b/bin/debug-trace-server/src/chain_sync.rs @@ -169,9 +169,9 @@ impl PipelineHooks for TraceHooks { #[cfg(test)] mod tests { - use std::{collections::HashMap, sync::Arc}; + use std::sync::Arc; - use alloy_primitives::B256; + use alloy_primitives::{B256, map::HashMap}; use revm::state::Bytecode; use stateless_core::StoreResult; diff --git a/bin/debug-trace-server/src/data_provider.rs b/bin/debug-trace-server/src/data_provider.rs index b5be0faa..9fa5f08c 100644 --- a/bin/debug-trace-server/src/data_provider.rs +++ b/bin/debug-trace-server/src/data_provider.rs @@ -21,14 +21,13 @@ //! Response caching is handled at the HTTP layer by `ResponseCache`, not here. use std::{ - collections::HashMap, future::Future, pin::Pin, sync::Arc, time::{Duration, Instant}, }; -use alloy_primitives::B256; +use alloy_primitives::{B256, map::HashMap}; use alloy_rpc_types_eth::{Block, BlockId, BlockNumberOrTag}; use dashmap::DashMap; use futures::{FutureExt, future::Shared}; @@ -795,7 +794,7 @@ impl ContractStore for NoopContractStore { &self, hashes: &[B256], ) -> StoreResult<(HashMap>, Vec)> { - Ok((HashMap::new(), hashes.to_vec())) + Ok((HashMap::default(), hashes.to_vec())) } fn add_contracts(&self, _codes: &[(B256, Arc)]) -> StoreResult<()> { diff --git a/bin/debug-trace-server/src/server_db.rs b/bin/debug-trace-server/src/server_db.rs index 5a073344..1bad1ab6 100644 --- a/bin/debug-trace-server/src/server_db.rs +++ b/bin/debug-trace-server/src/server_db.rs @@ -3,9 +3,9 @@ //! Provides persistent storage of block data, witnesses, and canonical chain state //! for serving `debug_*` and `trace_*` RPC methods. -use std::{collections::HashMap, path::Path, sync::Arc}; +use std::{path::Path, sync::Arc}; -use alloy_primitives::{B256, BlockHash, BlockNumber}; +use alloy_primitives::{B256, BlockHash, BlockNumber, map::HashMap}; use alloy_rpc_types_eth::Block; use op_alloy_rpc_types::Transaction; use rayon::prelude::*; diff --git a/bin/debug-trace-server/src/tracing_executor.rs b/bin/debug-trace-server/src/tracing_executor.rs index 4007bc21..6ba7786a 100644 --- a/bin/debug-trace-server/src/tracing_executor.rs +++ b/bin/debug-trace-server/src/tracing_executor.rs @@ -24,12 +24,12 @@ //! ## Parity-style (trace_* methods) //! - `LocalizedTransactionTrace` - Flat call traces with block/tx context -use std::{collections::HashMap, sync::Arc}; +use std::sync::Arc; use alloy_consensus::Transaction; use alloy_evm::{Evm as EvmTrait, block::BlockExecutor}; use alloy_op_evm::block::OpAlloyReceiptBuilder; -use alloy_primitives::B256; +use alloy_primitives::{B256, map::HashMap}; use alloy_rpc_types_eth::{Block, BlockTransactions, TransactionInfo}; use alloy_rpc_types_trace::{ geth::{ diff --git a/bin/stateless-validator/src/validator_db.rs b/bin/stateless-validator/src/validator_db.rs index fcf2d406..0a81c7bd 100644 --- a/bin/stateless-validator/src/validator_db.rs +++ b/bin/stateless-validator/src/validator_db.rs @@ -6,10 +6,10 @@ //! CANONICAL_CHAIN is bounded to `max_chain_length` entries; older entries are //! pruned inline during [`ChainStore::advance_chain`]. -use std::{collections::HashMap, path::Path, sync::Arc}; +use std::{path::Path, sync::Arc}; use alloy_genesis::Genesis; -use alloy_primitives::{B256, BlockHash, BlockNumber}; +use alloy_primitives::{B256, BlockHash, BlockNumber, map::HashMap}; use redb::ReadableDatabase; use revm::state::Bytecode; use stateless_core::db::{ diff --git a/crates/stateless-core/Cargo.toml b/crates/stateless-core/Cargo.toml index d96ab2c8..41307173 100644 --- a/crates/stateless-core/Cargo.toml +++ b/crates/stateless-core/Cargo.toml @@ -14,6 +14,7 @@ alloy-eips.workspace = true alloy-evm.workspace = true alloy-genesis.workspace = true alloy-hardforks = { workspace = true, default-features = false } +alloy-network-primitives.workspace = true alloy-op-evm.workspace = true alloy-op-hardforks = { workspace = true, default-features = false } alloy-primitives.workspace = true @@ -26,7 +27,6 @@ mega-evm = { workspace = true, default-features = false } salt = { workspace = true, default-features = false } # op -op-alloy-network = { workspace = true, default-features = false, optional = true } op-alloy-rpc-types.workspace = true # reth @@ -65,20 +65,19 @@ std = [ "dep:eyre", "dep:kanal", "dep:num_cpus", - "dep:op-alloy-network", "dep:tokio", "dep:tokio-util", "alloy-consensus/std", "alloy-eips/std", "alloy-evm/std", "alloy-genesis/std", + "alloy-network-primitives/std", "alloy-op-evm/std", "alloy-primitives/std", "alloy-rlp/std", "alloy-rpc-types-eth/std", "alloy-serde/std", "mega-evm/default", - "op-alloy-network/std", "op-alloy-rpc-types/std", "reth-ethereum-forks/std", "reth-optimism-chainspec/std", diff --git a/crates/stateless-core/src/chain_spec.rs b/crates/stateless-core/src/chain_spec.rs index 997d15c8..d004ab03 100644 --- a/crates/stateless-core/src/chain_spec.rs +++ b/crates/stateless-core/src/chain_spec.rs @@ -49,8 +49,9 @@ impl ChainSpec { /// - [`OpChainSpec`] already yields Optimism/Ethereum hardforks in the correct order, so they /// do not require reordering. /// - MegaETH hardforks are extracted from the genesis `extra_fields` and explicitly ordered to - /// match the canonical sequence defined by [`MEGA_MAINNET_HARDFORKS`]. Any remaining, unknown - /// MegaETH hardforks are preserved and appended after the known ones so nothing is dropped. + /// match the canonical sequence defined by [`mega_mainnet_hardforks()`]. Any remaining, + /// unknown MegaETH hardforks are preserved and appended after the known ones so nothing is + /// dropped. /// - The MegaETH set is then merged with the Optimism/Ethereum set to build a single /// [`ChainHardforks`] that drives fork activation. /// @@ -157,11 +158,6 @@ pub fn mega_mainnet_hardforks() -> ChainHardforks { ]) } -/// Hardforks configuration for MegaETH. -#[cfg(feature = "std")] -pub static MEGA_MAINNET_HARDFORKS: std::sync::LazyLock = - std::sync::LazyLock::new(mega_mainnet_hardforks); - #[cfg(test)] mod tests { use alloy_serde::OtherFields; diff --git a/crates/stateless-core/src/db.rs b/crates/stateless-core/src/db.rs index 55dc7edf..97d15b76 100644 --- a/crates/stateless-core/src/db.rs +++ b/crates/stateless-core/src/db.rs @@ -9,10 +9,10 @@ //! Concrete implementations live in their respective binaries; //! shared redb helpers live in the `stateless-db` crate. -use std::{collections::HashMap, fmt, sync::Arc}; +use std::{boxed::Box, fmt, string::String, sync::Arc, vec::Vec}; use alloy_genesis::Genesis; -use alloy_primitives::{B256, BlockHash, BlockNumber}; +use alloy_primitives::{B256, BlockHash, BlockNumber, map::HashMap}; use alloy_rpc_types_eth::Block; use op_alloy_rpc_types::Transaction; use revm::state::Bytecode; @@ -39,12 +39,12 @@ pub struct BlockMeta { /// /// Backend errors (redb, bincode, serde_json, lz4, …) are wrapped as an opaque /// [`StoreError::Backend`] — the source chain is preserved via -/// [`std::error::Error::source`], so `%err` / `{:#}` logs show the root cause +/// [`core::error::Error::source`], so `%err` / `{:#}` logs show the root cause /// without the trait layer needing to know the concrete backend type. #[derive(Debug, Error)] pub enum StoreError { #[error(transparent)] - Backend(Box), + Backend(Box), #[error("missing {kind} for block {block_hash}")] MissingData { kind: MissingDataKind, block_hash: BlockHash }, @@ -53,7 +53,7 @@ pub enum StoreError { Corrupt(String), } -pub type StoreResult = std::result::Result; +pub type StoreResult = core::result::Result; /// Adapter for turning any concrete backend error into [`StoreError::Backend`]. /// @@ -63,8 +63,8 @@ pub trait StoreResultExt { fn store_err(self) -> StoreResult; } -impl StoreResultExt - for std::result::Result +impl StoreResultExt + for core::result::Result { fn store_err(self) -> StoreResult { self.map_err(|e| StoreError::Backend(Box::new(e))) @@ -138,6 +138,17 @@ pub trait BlockStore: PrunableChainStore { mod tests { use super::*; + /// Minimal `core::error::Error` impl for tests that exercise `Backend` wrapping + /// without pulling `std::io::Error` (which doesn't exist under no_std). + #[derive(Debug)] + struct TestErr(&'static str); + impl fmt::Display for TestErr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.0) + } + } + impl core::error::Error for TestErr {} + #[test] fn test_block_meta_equality() { let a = BlockMeta { @@ -188,15 +199,15 @@ mod tests { fn store_error_backend_display_forwards_transparently() { // `#[error(transparent)]` makes Backend's Display delegate to the wrapped error — // no prefix, just the inner message. - let io = std::io::Error::other("disk full"); - let err: StoreError = Err::<(), _>(io).store_err().unwrap_err(); + let inner = TestErr("disk full"); + let err: StoreError = Err::<(), _>(inner).store_err().unwrap_err(); assert_eq!(err.to_string(), "disk full"); assert!(matches!(err, StoreError::Backend(_))); } #[test] fn store_result_ext_passes_through_ok() { - let r: StoreResult = Ok::<_, std::io::Error>(42).store_err(); + let r: StoreResult = Ok::<_, TestErr>(42).store_err(); assert_eq!(r.unwrap(), 42); } } diff --git a/crates/stateless-core/src/evm_database.rs b/crates/stateless-core/src/evm_database.rs index 61073d35..820e8f30 100644 --- a/crates/stateless-core/src/evm_database.rs +++ b/crates/stateless-core/src/evm_database.rs @@ -4,10 +4,15 @@ //! a block witness rather than a full blockchain database, enabling stateless block //! validation. -use std::{collections::HashMap, sync::Arc}; +use std::{ + format, + string::{String, ToString}, + sync::Arc, + vec::Vec, +}; use alloy_eips::eip2935::{HISTORY_SERVE_WINDOW, HISTORY_STORAGE_ADDRESS}; -use alloy_primitives::{Address, B256, BlockNumber}; +use alloy_primitives::{Address, B256, BlockNumber, map::HashMap}; use alloy_rpc_types_eth::Header; use mega_evm::{ExternalEnvFactory, ExternalEnvs, OracleEnv, SaltEnv}; use revm::{ @@ -71,7 +76,7 @@ pub struct WitnessDatabase<'a, W> { impl<'a, W> WitnessDatabase<'a, W> where W: StateReader, - W::Error: std::fmt::Display, + W::Error: core::fmt::Display, { /// Get value from witness for the given plain key fn plain_value(&self, plain_key: &[u8]) -> Result>, WitnessDatabaseError> { @@ -84,7 +89,7 @@ where impl<'a, W> DatabaseRef for WitnessDatabase<'a, W> where W: StateReader, - W::Error: std::fmt::Display, + W::Error: core::fmt::Display, { type Error = WitnessDatabaseError; diff --git a/crates/stateless-core/src/executor.rs b/crates/stateless-core/src/executor.rs index cc9c3861..f94bd16e 100644 --- a/crates/stateless-core/src/executor.rs +++ b/crates/stateless-core/src/executor.rs @@ -23,37 +23,37 @@ //! The module integrates with the Salt witness system for state reconstruction //! and uses Revm for transaction execution. +use std::{boxed::Box, collections::BTreeMap, fmt::Debug, string::String, sync::Arc, vec::Vec}; +#[cfg(feature = "std")] use std::{ - collections::BTreeMap, - fmt::Debug, io::Write, - sync::Arc, time::{Instant, SystemTime}, }; use alloy_consensus::{TxReceipt, proofs::calculate_receipt_root, transaction::Recovered}; +use alloy_eips::eip2718::Encodable2718; use alloy_evm::{ EvmEnv, block::{BlockExecutor, ExecutableTx}, }; +use alloy_network_primitives::TransactionResponse; use alloy_op_evm::block::OpAlloyReceiptBuilder; use alloy_primitives::{ Address, BlockHash, BlockNumber, Bloom, keccak256, map::{B256Map, HashMap}, }; use alloy_rpc_types_eth::{Block, BlockTransactions, Header}; -use eyre::Result; use mega_evm::{ BlockLimits, ExternalEnvFactory, MegaBlockExecutionCtx, MegaBlockExecutorFactory, MegaEvmFactory, MegaHardforks, MegaSpecId, }; -use op_alloy_network::{TransactionResponse, eip2718::Encodable2718}; use op_alloy_rpc_types::Transaction as OpTransaction; +#[cfg(feature = "std")] +use revm::inspector::inspectors::TracerEip3155; use revm::{ DatabaseRef, context::{BlockEnv, CfgEnv}, database::states::{BundleAccount, StateBuilder, bundle_state::BundleRetention}, - inspector::inspectors::TracerEip3155, primitives::{B256, KECCAK_EMPTY, U256}, state::Bytecode, }; @@ -161,7 +161,8 @@ pub struct ValidationResult { pub success: bool, /// Any error message if validation failed pub error_message: Option, - /// Timestamp when validation completed + /// Timestamp when validation completed (only available with the `std` feature). + #[cfg(feature = "std")] pub completed_at: SystemTime, } @@ -277,12 +278,12 @@ pub fn replay_block( block: &Block, db: &DB, env_oracle: ENV, - trace_writer: Option>, + #[cfg(feature = "std")] trace_writer: Option>, ) -> Result<(HashMap, BlockExecutionOutput), ValidationError> where DB: DatabaseRef + Debug, ENV: ExternalEnvFactory + Clone, - E: std::error::Error + Send + Sync + 'static, + E: core::error::Error + Send + Sync + 'static, { // Extract full transaction data let BlockTransactions::Full(transactions) = &block.transactions else { @@ -317,6 +318,7 @@ where block_limits, ); + #[cfg(feature = "std")] let (receipts_root, logs_bloom, gas_used) = if let Some(writer) = trace_writer { let executor = executor_factory.create_executor_with_inspector( &mut state, @@ -329,6 +331,11 @@ where let executor = executor_factory.create_executor(&mut state, execution_context, evm_env); execute_transactions(executor, transactions)? }; + #[cfg(not(feature = "std"))] + let (receipts_root, logs_bloom, gas_used) = { + let executor = executor_factory.create_executor(&mut state, execution_context, evm_env); + execute_transactions(executor, transactions)? + }; // Merge transitions into bundle_state state.merge_transitions(BundleRetention::PlainState); @@ -426,23 +433,37 @@ pub fn validate_block( block: &Block, salt_witness: SaltWitness, mpt_witness: MptWitness, - contracts: &std::collections::HashMap>, - writer: Option>, + contracts: &HashMap>, + #[cfg(feature = "std")] writer: Option>, ) -> Result { // Create external environment oracle from salt witness let ext_env = WitnessExternalEnv::new(&salt_witness, block.header.number) .map_err(ValidationError::EnvOracleConstructionFailed)?; // Verify witness proof against the current state root + #[cfg(feature = "std")] let start = Instant::now(); let witness = Witness::from(salt_witness); witness.verify().map_err(ValidationError::WitnessVerificationFailed)?; + #[cfg(feature = "std")] let witness_verification_time = start.elapsed().as_secs_f64(); + #[cfg(not(feature = "std"))] + let witness_verification_time = 0.0_f64; // Replay block transactions let witness_db = WitnessDatabase { header: &block.header, witness: &witness, contracts }; - let (accounts, output) = replay_block(chain_spec, block, &witness_db, ext_env, writer)?; + let (accounts, output) = replay_block( + chain_spec, + block, + &witness_db, + ext_env, + #[cfg(feature = "std")] + writer, + )?; + #[cfg(feature = "std")] let block_replay_time = start.elapsed().as_secs_f64() - witness_verification_time; + #[cfg(not(feature = "std"))] + let block_replay_time = 0.0_f64; // Extract and hash storage updates (only changed values) let withdrawal_storage: B256Map = accounts @@ -518,8 +539,11 @@ pub fn validate_block( let (state_root, _) = StateRoot::new(&witness) .update_fin(&state_updates) .map_err(ValidationError::TrieUpdateFailed)?; + #[cfg(feature = "std")] let salt_update_time = start.elapsed().as_secs_f64() - witness_verification_time - block_replay_time; + #[cfg(not(feature = "std"))] + let salt_update_time = 0.0_f64; // Check if computed withdrawals root matches the claimed one mpt_witness diff --git a/crates/stateless-core/src/lib.rs b/crates/stateless-core/src/lib.rs index 5bc98972..f5b9760b 100644 --- a/crates/stateless-core/src/lib.rs +++ b/crates/stateless-core/src/lib.rs @@ -9,9 +9,9 @@ //! - [`chain_spec`]: Chain specification and hardfork activation //! - [`light_witness`]: Fast witness deserialization (skips proof validation) //! - [`evm_database`]: Witness-backed `DatabaseRef` for REVM -//! - [`db`]: Abstract storage traits (`ChainStore`, `ContractStore`, etc.) — requires `std` feature +//! - [`db`]: Abstract storage traits (`ChainStore`, `ContractStore`, etc.) //! - [`data_types`]: SALT key/value encoding utilities -//! - [`executor`]: Block validation via EVM replay — requires `std` feature +//! - [`executor`]: Block validation via EVM replay //! - [`pipeline`]: Generic three-stage chain sync pipeline (fetch → process → advance) — requires //! `std` feature //! - [`withdrawals`]: MPT witness verification for L2→L1 withdrawals @@ -24,22 +24,16 @@ extern crate alloc as std; pub mod chain_spec; pub mod light_witness; pub use light_witness::{LightWitness, LightWitnessExecutor}; -#[cfg(feature = "std")] pub mod evm_database; -#[cfg(feature = "std")] pub use evm_database::{WitnessDatabase, WitnessDatabaseError, WitnessExternalEnv}; -#[cfg(feature = "std")] pub mod db; -#[cfg(feature = "std")] pub use db::{ BlockMeta, BlockStore, ChainStore, ContractStore, GenesisStore, MissingDataKind, PrunableChainStore, StoreError, StoreResult, StoreResultExt, }; pub mod data_types; pub use data_types::{PlainKey, PlainValue, iter_code_hashes}; -#[cfg(feature = "std")] pub mod executor; -#[cfg(feature = "std")] pub use executor::{ ValidationError, ValidationResult, ValidationStats, replay_block, validate_block, }; diff --git a/crates/stateless-core/src/pipeline/tests.rs b/crates/stateless-core/src/pipeline/tests.rs index d792a181..5631c4ba 100644 --- a/crates/stateless-core/src/pipeline/tests.rs +++ b/crates/stateless-core/src/pipeline/tests.rs @@ -1,6 +1,6 @@ -use std::{collections::HashMap, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; -use alloy_primitives::{B256, BlockHash, BlockNumber}; +use alloy_primitives::{B256, BlockHash, BlockNumber, map::HashMap}; use eyre::{Result, anyhow}; use revm::state::Bytecode; use tokio_util::sync::CancellationToken; @@ -82,7 +82,7 @@ impl MockStore { impl crate::ContractStore for MockStore { fn get_contracts(&self, _: &[B256]) -> StoreResult<(HashMap>, Vec)> { - Ok((HashMap::new(), vec![])) + Ok((HashMap::default(), vec![])) } fn add_contracts(&self, _: &[(B256, Arc)]) -> StoreResult<()> { Ok(()) @@ -213,7 +213,7 @@ async fn test_chain_advancer_sequential() { Ok(make_block(12, make_hash(11))), Ok(make_block(13, make_hash(12))), ]; - let (result, store) = run_advancer(tip, HashMap::new(), blocks).await; + let (result, store) = run_advancer(tip, HashMap::default(), blocks).await; assert!(matches!(result.unwrap(), PipelineOutcome::Shutdown)); assert_eq!(store.get_canonical_tip().unwrap().unwrap().block_number, 13); } @@ -226,7 +226,7 @@ async fn test_chain_advancer_out_of_order() { Ok(make_block(12, make_hash(11))), Ok(make_block(11, make_hash(10))), ]; - let (result, store) = run_advancer(tip, HashMap::new(), blocks).await; + let (result, store) = run_advancer(tip, HashMap::default(), blocks).await; assert!(matches!(result.unwrap(), PipelineOutcome::Shutdown)); assert_eq!(store.get_canonical_tip().unwrap().unwrap().block_number, 13); } @@ -266,7 +266,7 @@ impl PipelineHooks for BadBlockHooks { /// a single test case. async fn run_bad_block_advancer(tip: BlockMeta, blocks: Vec) -> Result { let store = MockStore::new(tip.clone()); - let fetcher = MockFetcher { hashes: HashMap::new() }; + let fetcher = MockFetcher { hashes: HashMap::default() }; let hooks = BadBlockHooks; let (tx, rx) = kanal::bounded::< std::result::Result, ErrorAction)>, @@ -305,7 +305,7 @@ async fn test_chain_advancer_verify_continuity_failure_halts() { async fn test_chain_advancer_fatal_error_halts() { let tip = make_tip(10); let blocks = vec![Err(("state root mismatch".to_string(), ErrorAction::Halt))]; - let (result, _) = run_advancer(tip, HashMap::new(), blocks).await; + let (result, _) = run_advancer(tip, HashMap::default(), blocks).await; match result.unwrap() { PipelineOutcome::Fatal(msg) => assert!(msg.contains("state root mismatch")), other => panic!("Expected Fatal, got {other:?}"), @@ -316,7 +316,7 @@ async fn test_chain_advancer_fatal_error_halts() { async fn test_chain_advancer_transient_error_returns_retry_outcome() { let tip = make_tip(10); let blocks = vec![Err(("RPC timeout".to_string(), ErrorAction::Retry))]; - let (result, _) = run_advancer(tip, HashMap::new(), blocks).await; + let (result, _) = run_advancer(tip, HashMap::default(), blocks).await; // Retry errors are surfaced as `PipelineOutcome::Retry`, not `Err`. The outer // `run_pipeline` loop matches on the variant explicitly and runs the common // transient-restart recovery path. @@ -335,7 +335,7 @@ async fn test_chain_advancer_transient_error_returns_retry_outcome() { async fn test_chain_advancer_shutdown() { let tip = make_tip(10); let store = MockStore::new(tip.clone()); - let fetcher = MockFetcher { hashes: HashMap::new() }; + let fetcher = MockFetcher { hashes: HashMap::default() }; let hooks = NoopHooks; let (_tx, rx) = kanal::bounded::< std::result::Result, ErrorAction)>, @@ -350,7 +350,7 @@ async fn test_chain_advancer_shutdown() { #[tokio::test] async fn test_chain_advancer_reorg_detected() { let tip = make_tip(10); - let mut rpc_hashes = HashMap::new(); + let mut rpc_hashes = HashMap::default(); rpc_hashes.insert(10, make_hash(10)); let bad_block = MockBlock { @@ -375,7 +375,7 @@ async fn test_chain_advancer_reorg_detected() { #[tokio::test] async fn test_chain_advancer_reorg_mid_batch_uses_persisted_tip() { let tip = make_tip(10); - let mut rpc_hashes = HashMap::new(); + let mut rpc_hashes = HashMap::default(); rpc_hashes.insert(10, make_hash(10)); // Send block 12 before block 11 so they sit in the buffer together: the first recv only @@ -427,8 +427,8 @@ impl crate::pipeline::DivergenceLookups for MapLookups { #[tokio::test] async fn test_find_divergence_single_block_reorg() { - let mut local = HashMap::new(); - let mut remote = HashMap::new(); + let mut local = HashMap::default(); + let mut remote = HashMap::default(); for n in 1..=10 { local.insert(n, make_hash(n)); if n <= 9 { @@ -447,8 +447,8 @@ async fn test_find_divergence_single_block_reorg() { #[tokio::test] async fn test_find_divergence_multi_block_reorg() { - let mut local = HashMap::new(); - let mut remote = HashMap::new(); + let mut local = HashMap::default(); + let mut remote = HashMap::default(); for n in 1..=10 { if n <= 5 { let hash = make_hash(n); @@ -469,8 +469,8 @@ async fn test_find_divergence_multi_block_reorg() { #[tokio::test] async fn test_find_divergence_catastrophic() { - let mut local = HashMap::new(); - let mut remote = HashMap::new(); + let mut local = HashMap::default(); + let mut remote = HashMap::default(); for n in 1..=5 { local.insert(n, make_hash(n)); remote.insert(n, BlockHash::from([(n + 128) as u8; 32])); diff --git a/crates/stateless-db/src/cache.rs b/crates/stateless-db/src/cache.rs index 5d8bc29b..7aa436f4 100644 --- a/crates/stateless-db/src/cache.rs +++ b/crates/stateless-db/src/cache.rs @@ -1,7 +1,6 @@ //! In-memory write-through cache for contract bytecodes. use std::{ - collections::HashMap, hash::RandomState, sync::{ Arc, @@ -9,7 +8,7 @@ use std::{ }, }; -use alloy_primitives::B256; +use alloy_primitives::{B256, map::HashMap}; use quick_cache::{ Weighter, sync::{Cache, DefaultLifecycle}, @@ -121,7 +120,8 @@ impl ContractCache { /// caller should use a verified RPC fetch (`RpcClient::get_codes(.., verify=true)`) /// to populate the cache so all entries arrive pre-verified. pub fn get(&self, hashes: &[B256]) -> StoreResult { - let mut found = HashMap::with_capacity(hashes.len()); + let mut found: HashMap> = HashMap::default(); + found.reserve(hashes.len()); let mut not_in_memory = Vec::with_capacity(hashes.len()); for &hash in hashes { @@ -221,7 +221,7 @@ mod tests { hashes: &[B256], ) -> StoreResult<(HashMap>, Vec)> { self.get_calls.fetch_add(1, Ordering::Relaxed); - let mut found = HashMap::new(); + let mut found: HashMap> = HashMap::default(); let mut missing = Vec::new(); for &h in hashes { match self.data.get(&h) { diff --git a/crates/stateless-db/src/helpers.rs b/crates/stateless-db/src/helpers.rs index 5880e3ae..9d2fcff0 100644 --- a/crates/stateless-db/src/helpers.rs +++ b/crates/stateless-db/src/helpers.rs @@ -1,8 +1,8 @@ //! Shared redb read/write helpers used by both concrete database implementations. -use std::{collections::HashMap, sync::Arc}; +use std::sync::Arc; -use alloy_primitives::{B256, BlockHash, BlockNumber}; +use alloy_primitives::{B256, BlockHash, BlockNumber, map::HashMap}; use redb::{ReadableDatabase, ReadableTable}; use revm::state::Bytecode; use stateless_core::db::{BlockMeta, ContractLookup, StoreResult, StoreResultExt}; @@ -150,7 +150,7 @@ pub fn read_contracts(database: &Database, hashes: &[B256]) -> StoreResult> = HashMap::default(); let mut missing = Vec::new(); for &hash in hashes { diff --git a/crates/stateless-test-utils/src/fixtures.rs b/crates/stateless-test-utils/src/fixtures.rs index 9c59ff7b..7ad876f4 100644 --- a/crates/stateless-test-utils/src/fixtures.rs +++ b/crates/stateless-test-utils/src/fixtures.rs @@ -18,7 +18,7 @@ use std::{ }; use alloy_genesis::Genesis; -use alloy_primitives::{B256, BlockHash, BlockNumber}; +use alloy_primitives::{B256, BlockHash, BlockNumber, map::HashMap as AlloyHashMap}; use alloy_rpc_types_eth::Block; use eyre::{Context, Result}; use op_alloy_rpc_types::Transaction; @@ -49,7 +49,7 @@ pub struct TestFixtures { pub block_numbers: BTreeMap, pub salt_witnesses: HashMap, pub mpt_witness_bytes: HashMap>, - pub contracts: HashMap>, + pub contracts: AlloyHashMap>, } impl TestFixtures { @@ -167,7 +167,7 @@ pub fn load_json(path: impl AsRef) -> Result { } /// Loads contract bytecodes from a file (one `[hash, bytecode]` JSON per line). -pub fn load_contracts(path: impl AsRef) -> HashMap> { +pub fn load_contracts(path: impl AsRef) -> AlloyHashMap> { let path = path.as_ref(); let file = File::open(path).unwrap_or_else(|e| panic!("open {}: {e}", path.display())); BufReader::new(file) From 55a3f73f2bae77899658a29073b110ffb544d313 Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Fri, 24 Apr 2026 15:48:50 +0800 Subject: [PATCH 04/10] test: make stateless-core unit tests compile under --no-default-features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests hit three no_std gaps that only surfaced once the coverage script (`scripts/coverage_stateless_core.sh`) started building them with the `std` feature off: - `vec!` macro isn't in scope under no_std — add `use std::vec;` to the `withdrawals` and `data_types` test modules. - `ToString::to_string` needs the trait in scope — add `use std::string::ToString;` to the `chain_spec` and `db` test modules. - `validate_block`'s `trace_writer` param is `#[cfg(feature = "std")]`; cfg-gate the matching `None` argument in the executor mainnet-fixture test so the call compiles in both modes. No production code changed. Fixes the Coverage CI job. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/stateless-core/src/chain_spec.rs | 2 ++ crates/stateless-core/src/data_types.rs | 2 ++ crates/stateless-core/src/db.rs | 2 ++ crates/stateless-core/src/executor.rs | 1 + crates/stateless-core/src/withdrawals.rs | 2 ++ 5 files changed, 9 insertions(+) diff --git a/crates/stateless-core/src/chain_spec.rs b/crates/stateless-core/src/chain_spec.rs index d004ab03..dfef3720 100644 --- a/crates/stateless-core/src/chain_spec.rs +++ b/crates/stateless-core/src/chain_spec.rs @@ -160,6 +160,8 @@ pub fn mega_mainnet_hardforks() -> ChainHardforks { #[cfg(test)] mod tests { + use std::string::ToString; + use alloy_serde::OtherFields; use super::*; diff --git a/crates/stateless-core/src/data_types.rs b/crates/stateless-core/src/data_types.rs index edbd38ff..6476086e 100644 --- a/crates/stateless-core/src/data_types.rs +++ b/crates/stateless-core/src/data_types.rs @@ -210,6 +210,8 @@ pub fn iter_code_hashes( #[cfg(test)] mod tests { + use std::vec; + use super::*; fn account_kv(addr: u8, codehash: Option) -> SaltValue { diff --git a/crates/stateless-core/src/db.rs b/crates/stateless-core/src/db.rs index 97d15b76..be756e9c 100644 --- a/crates/stateless-core/src/db.rs +++ b/crates/stateless-core/src/db.rs @@ -136,6 +136,8 @@ pub trait BlockStore: PrunableChainStore { #[cfg(test)] mod tests { + use std::string::ToString; + use super::*; /// Minimal `core::error::Error` impl for tests that exercise `Backend` wrapping diff --git a/crates/stateless-core/src/executor.rs b/crates/stateless-core/src/executor.rs index f94bd16e..00351ae4 100644 --- a/crates/stateless-core/src/executor.rs +++ b/crates/stateless-core/src/executor.rs @@ -616,6 +616,7 @@ mod tests { fx.salt_witnesses[&hash].clone(), mpt, &fx.contracts, + #[cfg(feature = "std")] None, ) .unwrap_or_else(|e| panic!("validate_block failed for {number} ({hash}): {e:?}")); diff --git a/crates/stateless-core/src/withdrawals.rs b/crates/stateless-core/src/withdrawals.rs index 21df306e..d702e8bb 100644 --- a/crates/stateless-core/src/withdrawals.rs +++ b/crates/stateless-core/src/withdrawals.rs @@ -189,6 +189,8 @@ fn synthesize_state_witness(witness: &MptWitness) -> (B256, B256Map, B256 #[cfg(test)] mod tests { + use std::vec; + use WithdrawalValidationError::*; use alloy_primitives::{Sealable, b256}; From c9d3ad12493a18349b4572848b5abb7f278a4a64 Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Fri, 24 Apr 2026 19:41:09 +0800 Subject: [PATCH 05/10] refactor: dedup executor's plain-path branches via shared closure --- crates/stateless-core/src/executor.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/stateless-core/src/executor.rs b/crates/stateless-core/src/executor.rs index 00351ae4..410ee262 100644 --- a/crates/stateless-core/src/executor.rs +++ b/crates/stateless-core/src/executor.rs @@ -318,6 +318,14 @@ where block_limits, ); + // Plain execution path, shared by the non-tracer std branch and the no_std build. + // Extracted as a closure so the body lives in one place — any future change to the + // non-tracer path only needs to be made here. + let run_plain = |state: &mut _, ctx, env| { + let executor = executor_factory.create_executor(state, ctx, env); + execute_transactions(executor, transactions) + }; + #[cfg(feature = "std")] let (receipts_root, logs_bloom, gas_used) = if let Some(writer) = trace_writer { let executor = executor_factory.create_executor_with_inspector( @@ -328,14 +336,10 @@ where ); execute_transactions(executor, transactions)? } else { - let executor = executor_factory.create_executor(&mut state, execution_context, evm_env); - execute_transactions(executor, transactions)? + run_plain(&mut state, execution_context, evm_env)? }; #[cfg(not(feature = "std"))] - let (receipts_root, logs_bloom, gas_used) = { - let executor = executor_factory.create_executor(&mut state, execution_context, evm_env); - execute_transactions(executor, transactions)? - }; + let (receipts_root, logs_bloom, gas_used) = run_plain(&mut state, execution_context, evm_env)?; // Merge transitions into bundle_state state.merge_transitions(BundleRetention::PlainState); From 2dce247ef7ffc179f7371818bbc4c43cade47348 Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Fri, 24 Apr 2026 19:57:55 +0800 Subject: [PATCH 06/10] Update executor.rs --- crates/stateless-core/src/executor.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/stateless-core/src/executor.rs b/crates/stateless-core/src/executor.rs index 410ee262..7d22ba02 100644 --- a/crates/stateless-core/src/executor.rs +++ b/crates/stateless-core/src/executor.rs @@ -184,17 +184,21 @@ pub struct BlockExecutionOutput { } /// Statistics collected during block validation for metrics. +/// +/// The `*_time` fields are measured with `std::time::Instant` and are always `0.0` in +/// `no_std` builds (no monotonic clock available). Consumers that meter or log these +/// values should treat `0.0` as "not measured" when running without the `std` feature. #[derive(Debug, Clone, Default)] pub struct ValidationStats { /// Number of accounts/storage slots read during execution pub state_reads: usize, /// Number of accounts/storage slots changed pub state_writes: usize, - /// Time spent verifying the witness proof (seconds) + /// Time spent verifying the witness proof (seconds; `0.0` in `no_std` builds) pub witness_verification_time: f64, - /// Time spent replaying block transactions (seconds) + /// Time spent replaying block transactions (seconds; `0.0` in `no_std` builds) pub block_replay_time: f64, - /// Time spent updating SALT state (seconds) + /// Time spent updating SALT state (seconds; `0.0` in `no_std` builds) pub salt_update_time: f64, } @@ -452,7 +456,7 @@ pub fn validate_block( #[cfg(feature = "std")] let witness_verification_time = start.elapsed().as_secs_f64(); #[cfg(not(feature = "std"))] - let witness_verification_time = 0.0_f64; + let witness_verification_time = 0.0_f64; // no_std: timing unavailable // Replay block transactions let witness_db = WitnessDatabase { header: &block.header, witness: &witness, contracts }; @@ -467,7 +471,7 @@ pub fn validate_block( #[cfg(feature = "std")] let block_replay_time = start.elapsed().as_secs_f64() - witness_verification_time; #[cfg(not(feature = "std"))] - let block_replay_time = 0.0_f64; + let block_replay_time = 0.0_f64; // no_std: timing unavailable // Extract and hash storage updates (only changed values) let withdrawal_storage: B256Map = accounts @@ -547,7 +551,7 @@ pub fn validate_block( let salt_update_time = start.elapsed().as_secs_f64() - witness_verification_time - block_replay_time; #[cfg(not(feature = "std"))] - let salt_update_time = 0.0_f64; + let salt_update_time = 0.0_f64; // no_std: timing unavailable // Check if computed withdrawals root matches the claimed one mpt_witness From 3ee666a2cac25c7cc77c6fa2788c8e48138c7be2 Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Fri, 24 Apr 2026 20:15:21 +0800 Subject: [PATCH 07/10] Update fixtures.rs --- crates/stateless-test-utils/src/fixtures.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/stateless-test-utils/src/fixtures.rs b/crates/stateless-test-utils/src/fixtures.rs index 7ad876f4..960fb48e 100644 --- a/crates/stateless-test-utils/src/fixtures.rs +++ b/crates/stateless-test-utils/src/fixtures.rs @@ -10,7 +10,7 @@ //! `ChainSpec::from_genesis(fixtures.load_genesis().unwrap())`. use std::{ - collections::{BTreeMap, HashMap}, + collections::BTreeMap, fs::File, io::{BufRead, BufReader}, path::{Path, PathBuf}, @@ -18,7 +18,7 @@ use std::{ }; use alloy_genesis::Genesis; -use alloy_primitives::{B256, BlockHash, BlockNumber, map::HashMap as AlloyHashMap}; +use alloy_primitives::{B256, BlockHash, BlockNumber, map::HashMap}; use alloy_rpc_types_eth::Block; use eyre::{Context, Result}; use op_alloy_rpc_types::Transaction; @@ -49,13 +49,13 @@ pub struct TestFixtures { pub block_numbers: BTreeMap, pub salt_witnesses: HashMap, pub mpt_witness_bytes: HashMap>, - pub contracts: AlloyHashMap>, + pub contracts: HashMap>, } impl TestFixtures { /// Load fixtures from a directory following the `test_data/` layout. pub fn load(data_dir: &Path) -> Self { - let mut blocks = HashMap::new(); + let mut blocks = HashMap::default(); let mut block_numbers = BTreeMap::new(); for path in read_dir_paths(&data_dir.join("blocks")) { if path.extension().and_then(|s| s.to_str()) != Some("json") { @@ -75,8 +75,8 @@ impl TestFixtures { block_numbers.insert(number, hash); } - let mut salt_witnesses = HashMap::new(); - let mut mpt_witness_bytes = HashMap::new(); + let mut salt_witnesses = HashMap::default(); + let mut mpt_witness_bytes = HashMap::default(); for path in read_dir_paths(&data_dir.join("stateless/witness")) { let Some(ext) = path.extension().and_then(|s| s.to_str()) else { continue }; let stem = path.file_stem().unwrap().to_str().unwrap(); @@ -167,7 +167,7 @@ pub fn load_json(path: impl AsRef) -> Result { } /// Loads contract bytecodes from a file (one `[hash, bytecode]` JSON per line). -pub fn load_contracts(path: impl AsRef) -> AlloyHashMap> { +pub fn load_contracts(path: impl AsRef) -> HashMap> { let path = path.as_ref(); let file = File::open(path).unwrap_or_else(|e| panic!("open {}: {e}", path.display())); BufReader::new(file) From cff3df1b474283643931a5956a9c58297e652845 Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Fri, 24 Apr 2026 21:20:34 +0800 Subject: [PATCH 08/10] Update build-and-test.yml --- .github/workflows/build-and-test.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index bbe7a8a4..e0cce1bd 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -51,3 +51,23 @@ jobs: run: cargo build - name: Run Test run: cargo test + + no-std: + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install Rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + target: riscv64imac-unknown-none-elf,wasm32-unknown-unknown + - name: Check stateless-core (host no_std) + run: cargo check -p stateless-core --no-default-features + - name: Run stateless-core tests with --no-default-features + run: cargo test -p stateless-core --no-default-features --lib + - name: Build stateless-core for riscv64imac-unknown-none-elf + run: cargo build -p stateless-core --no-default-features --target riscv64imac-unknown-none-elf + - name: Build stateless-core for wasm32-unknown-unknown + run: cargo build -p stateless-core --no-default-features --target wasm32-unknown-unknown From 9fadeb8979b560271ec98c0e6af65e1641da2964 Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Fri, 24 Apr 2026 22:01:22 +0800 Subject: [PATCH 09/10] Update build-and-test.yml --- .github/workflows/build-and-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index e0cce1bd..6d3a86bd 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -63,6 +63,8 @@ jobs: uses: actions-rust-lang/setup-rust-toolchain@v1 with: target: riscv64imac-unknown-none-elf,wasm32-unknown-unknown + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 - name: Check stateless-core (host no_std) run: cargo check -p stateless-core --no-default-features - name: Run stateless-core tests with --no-default-features From cc8cf512ed502336e0569a90d8b5bb5a3e70a8a0 Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Mon, 27 Apr 2026 17:00:22 +0800 Subject: [PATCH 10/10] delete unused ValidationResult --- Cargo.lock | 1 - Cargo.toml | 1 - bin/debug-trace-server/Cargo.toml | 1 - crates/stateless-core/src/executor.rs | 34 +++------------------------ crates/stateless-core/src/lib.rs | 4 +--- 5 files changed, 4 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 281a2612..427aaf09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1844,7 +1844,6 @@ dependencies = [ "reqwest 0.13.2", "revm", "revm-inspectors", - "rustc-hash", "salt", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 66d42006..c75f2c1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,6 @@ op-alloy-rpc-types = { version = "0.18.12", default-features = false } # reth reth-ethereum-forks = { git = "https://github.com/paradigmxyz/reth", tag = "v1.6.0", default-features = false } reth-optimism-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.6.0", default-features = false } -reth-trie = { git = "https://github.com/paradigmxyz/reth", tag = "v1.6.0" } reth-trie-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.6.0", default-features = false } reth-trie-sparse = { git = "https://github.com/paradigmxyz/reth", tag = "v1.6.0", default-features = false } diff --git a/bin/debug-trace-server/Cargo.toml b/bin/debug-trace-server/Cargo.toml index 8a6745a8..7cd5ebe5 100644 --- a/bin/debug-trace-server/Cargo.toml +++ b/bin/debug-trace-server/Cargo.toml @@ -50,7 +50,6 @@ pin-project-lite.workspace = true quick_cache.workspace = true rayon.workspace = true redb.workspace = true -rustc-hash.workspace = true serde.workspace = true serde_json.workspace = true thiserror.workspace = true diff --git a/crates/stateless-core/src/executor.rs b/crates/stateless-core/src/executor.rs index 7d22ba02..c30d40a2 100644 --- a/crates/stateless-core/src/executor.rs +++ b/crates/stateless-core/src/executor.rs @@ -23,12 +23,9 @@ //! The module integrates with the Salt witness system for state reconstruction //! and uses Revm for transaction execution. -use std::{boxed::Box, collections::BTreeMap, fmt::Debug, string::String, sync::Arc, vec::Vec}; +use std::{boxed::Box, collections::BTreeMap, fmt::Debug, sync::Arc, vec::Vec}; #[cfg(feature = "std")] -use std::{ - io::Write, - time::{Instant, SystemTime}, -}; +use std::{io::Write, time::Instant}; use alloy_consensus::{TxReceipt, proofs::calculate_receipt_root, transaction::Recovered}; use alloy_eips::eip2718::Encodable2718; @@ -39,7 +36,7 @@ use alloy_evm::{ use alloy_network_primitives::TransactionResponse; use alloy_op_evm::block::OpAlloyReceiptBuilder; use alloy_primitives::{ - Address, BlockHash, BlockNumber, Bloom, keccak256, + Address, Bloom, keccak256, map::{B256Map, HashMap}, }; use alloy_rpc_types_eth::{Block, BlockTransactions, Header}; @@ -58,7 +55,6 @@ use revm::{ state::Bytecode, }; use salt::{EphemeralSaltState, SaltValue, SaltWitness, StateRoot, StateUpdates, Witness}; -use serde::{Deserialize, Serialize}; use thiserror::Error; use tracing::debug; @@ -142,30 +138,6 @@ pub enum ValidationError { }, } -/// Represents the result of a validation operation -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ValidationResult { - /// The pre-state root from the witness before block execution - pub pre_state_root: B256, - /// The post-state root after block execution (from block header) - pub post_state_root: B256, - /// The pre-withdrawl root from the mpt witness before block execution - pub pre_withdrawals_root: B256, - /// The post-withdrawal root after block execution (from block header) - pub post_withdrawals_root: B256, - /// The block number that was validated - pub block_number: BlockNumber, - /// The block hash that was validated - pub block_hash: BlockHash, - /// Whether the validation was successful - pub success: bool, - /// Any error message if validation failed - pub error_message: Option, - /// Timestamp when validation completed (only available with the `std` feature). - #[cfg(feature = "std")] - pub completed_at: SystemTime, -} - /// Results from executing block transactions. /// /// Contains the computed values needed to verify block header fields. diff --git a/crates/stateless-core/src/lib.rs b/crates/stateless-core/src/lib.rs index f5b9760b..c0c3dc3d 100644 --- a/crates/stateless-core/src/lib.rs +++ b/crates/stateless-core/src/lib.rs @@ -34,9 +34,7 @@ pub use db::{ pub mod data_types; pub use data_types::{PlainKey, PlainValue, iter_code_hashes}; pub mod executor; -pub use executor::{ - ValidationError, ValidationResult, ValidationStats, replay_block, validate_block, -}; +pub use executor::{ValidationError, ValidationStats, replay_block, validate_block}; #[cfg(feature = "std")] pub mod pipeline; #[cfg(feature = "std")]