diff --git a/Cargo.lock b/Cargo.lock index a59b12bb1..6c7b4e66a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2446,7 +2446,7 @@ dependencies = [ "bitflags 2.13.1", "cexpr", "clang-sys", - "itertools 0.13.0", + "itertools 0.10.5", "proc-macro2", "quote", "regex", @@ -5117,18 +5117,21 @@ dependencies = [ [[package]] name = "ethrex-blockchain" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "bytes", "crossbeam", "ethrex-common", "ethrex-crypto", + "ethrex-guest-program", "ethrex-metrics", "ethrex-rlp", "ethrex-storage", "ethrex-trie", "ethrex-vm", + "libssz", + "libssz-merkle", "rayon", "rustc-hash", "thiserror 2.0.20", @@ -5139,8 +5142,8 @@ dependencies = [ [[package]] name = "ethrex-common" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "bytes", "crc32fast", @@ -5154,9 +5157,12 @@ dependencies = [ "indexmap 2.14.0", "lazy_static", "libc", + "libssz", + "libssz-derive", + "libssz-merkle", + "libssz-types", "lru 0.16.4", "once_cell", - "rayon", "rkyv", "rustc-hash", "secp256k1 0.30.0", @@ -5169,8 +5175,8 @@ dependencies = [ [[package]] name = "ethrex-config" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "ethrex-common", "ethrex-p2p", @@ -5181,7 +5187,7 @@ dependencies = [ [[package]] name = "ethrex-crypto" -version = "20.0.0" +version = "26.0.0" dependencies = [ "ark-bn254", "ark-ec", @@ -5202,18 +5208,59 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "ethrex-guest-program" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" +dependencies = [ + "bytes", + "ethereum-types 0.15.1", + "ethrex-common", + "ethrex-crypto", + "ethrex-l2-common", + "ethrex-rlp", + "ethrex-vm", + "hex", + "libssz", + "libssz-derive", + "libssz-merkle", + "libssz-types", + "rkyv", + "serde", + "serde_with 3.22.0", + "thiserror 2.0.20", +] + +[[package]] +name = "ethrex-l2-common" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" +dependencies = [ + "bytes", + "ethereum-types 0.15.1", + "ethrex-common", + "ethrex-crypto", + "k256", + "lambdaworks-crypto", + "rkyv", + "serde", + "serde_with 3.22.0", + "thiserror 2.0.20", + "tracing", +] + [[package]] name = "ethrex-levm" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "bytes", "derive_more 1.0.0", "ethrex-common", "ethrex-crypto", "ethrex-rlp", + "libssz", "malachite", - "rayon", "rustc-hash", "serde", "strum 0.27.2", @@ -5222,8 +5269,8 @@ dependencies = [ [[package]] name = "ethrex-metrics" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "axum 0.8.9", "ethrex-common", @@ -5238,8 +5285,8 @@ dependencies = [ [[package]] name = "ethrex-p2p" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "aes", "aes-gcm", @@ -5282,8 +5329,8 @@ dependencies = [ [[package]] name = "ethrex-rlp" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "bytes", "ethereum-types 0.15.1", @@ -5292,8 +5339,8 @@ dependencies = [ [[package]] name = "ethrex-rpc" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "axum 0.8.9", "axum-extra", @@ -5332,8 +5379,8 @@ dependencies = [ [[package]] name = "ethrex-storage" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "anyhow", "bytes", @@ -5355,8 +5402,8 @@ dependencies = [ [[package]] name = "ethrex-trie" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "anyhow", "bytes", @@ -5364,18 +5411,19 @@ dependencies = [ "ethereum-types 0.15.1", "ethrex-crypto", "ethrex-rlp", - "lazy_static", + "hashbrown 0.15.5", "rayon", "rkyv", "rustc-hash", "serde", + "spin 0.9.9", "thiserror 2.0.20", ] [[package]] name = "ethrex-vm" -version = "20.0.0" -source = "git+https://github.com/lambdaclass/ethrex?rev=b4d5677812fdf58cb3e439c77906dda4d9b6f91a#b4d5677812fdf58cb3e439c77906dda4d9b6f91a" +version = "26.0.0" +source = "git+https://github.com/lambdaclass/ethrex?rev=34cf6c6258d3acb06e918e4308a3e571e19dfe05#34cf6c6258d3acb06e918e4308a3e571e19dfe05" dependencies = [ "bytes", "derive_more 1.0.0", @@ -5384,7 +5432,6 @@ dependencies = [ "ethrex-crypto", "ethrex-levm", "ethrex-rlp", - "rayon", "rustc-hash", "serde", "thiserror 2.0.20", @@ -8418,6 +8465,34 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "lambdaworks-crypto" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58b1a1c1102a5a7fbbda117b79fb3a01e033459c738a3c1642269603484fd1c1" +dependencies = [ + "lambdaworks-math", + "rand 0.8.7", + "rand_chacha 0.3.1", + "serde", + "sha2 0.10.9", + "sha3 0.10.9", +] + +[[package]] +name = "lambdaworks-math" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "018a95aa873eb49896a858dee0d925c33f3978d073c64b08dd4f2c9b35a017c6" +dependencies = [ + "getrandom 0.2.17", + "num-bigint 0.4.8", + "num-traits", + "rand 0.8.7", + "serde", + "serde_json", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -8811,6 +8886,47 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "libssz" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4bdd6d63ed811ae164966de20810be780e07de784a4834ccfe6be90480c369e" +dependencies = [ + "smallvec", +] + +[[package]] +name = "libssz-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeee1b9ac9200429f7e9830492765445989ea61c3fb9028ad5a96e1dd5f5e913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "libssz-merkle" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863eca32d1a43e5ec41106a515552efa8307768d37c68d26b7f21ff13cfee1a7" +dependencies = [ + "libssz", + "sha2 0.10.9", +] + +[[package]] +name = "libssz-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4231ac301726840a3fe111f11bd4619d3c97ed155cb94c88dbf92b70e04e017" +dependencies = [ + "libssz", + "libssz-merkle", + "smallvec", +] + [[package]] name = "libyaml-rs" version = "0.3.0" @@ -11224,7 +11340,7 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.12.1", + "itertools 0.10.5", "log", "multimap", "once_cell", @@ -11244,7 +11360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.119", @@ -11257,7 +11373,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.119", @@ -11270,7 +11386,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.119", diff --git a/Cargo.toml b/Cargo.toml index 38b59b576..d2d2d2796 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,20 +46,20 @@ ethers = "2.0.14" # ethrex-crypto's `aws-lc-rs` feature, whose cc >=1.2.26 requirement conflicts with # reth-mdbx-sys's exact `cc = 1.2.15` pin (via helix-simulator). The node is # assembled from the library crates instead. -ethrex-blockchain = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a", default-features = false, features = ["secp256k1", "c-kzg", "metrics"] } -ethrex-common = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a", default-features = false, features = ["secp256k1", "c-kzg"] } -ethrex-config = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a" } +ethrex-blockchain = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05", default-features = false, features = ["secp256k1", "c-kzg", "metrics"] } +ethrex-common = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05", default-features = false, features = ["secp256k1", "c-kzg"] } +ethrex-config = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05" } # default features minus `aws-lc-rs` (see note above); P-256 verify uses the portable fallback -ethrex-crypto = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a", default-features = false, features = ["std", "kzg-rs", "secp256k1", "blst", "c-kzg"] } +ethrex-crypto = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05", default-features = false, features = ["std", "kzg-rs", "secp256k1", "blst", "c-kzg"] } # Only for the EIP-8037 state-gas constants the payout reserve needs; already in # the tree via ethrex-vm. -ethrex-levm = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a", default-features = false, features = ["secp256k1", "c-kzg"] } -ethrex-metrics = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a" } -ethrex-p2p = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a", features = ["c-kzg", "rocksdb", "metrics"] } -ethrex-rlp = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a" } -ethrex-rpc = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a" } -ethrex-storage = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a", features = ["rocksdb"] } -ethrex-vm = { git = "https://github.com/lambdaclass/ethrex", rev = "b4d5677812fdf58cb3e439c77906dda4d9b6f91a", default-features = false, features = ["secp256k1", "c-kzg"] } +ethrex-levm = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05", default-features = false, features = ["secp256k1", "c-kzg"] } +ethrex-metrics = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05" } +ethrex-p2p = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05", features = ["c-kzg", "rocksdb", "metrics"] } +ethrex-rlp = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05" } +ethrex-rpc = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05" } +ethrex-storage = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05", features = ["rocksdb"] } +ethrex-vm = { git = "https://github.com/lambdaclass/ethrex", rev = "34cf6c6258d3acb06e918e4308a3e571e19dfe05", default-features = false, features = ["secp256k1", "c-kzg"] } eyre = "0.6.12" aws-sdk-s3 = "=1.35.0" diff --git a/crates/builder/README.md b/crates/builder/README.md index b69c0a535..085048e0f 100644 --- a/crates/builder/README.md +++ b/crates/builder/README.md @@ -176,6 +176,10 @@ On the relay side, add a merging builder to with `ssz_url` set to this role's `ssz_addr` (see the repo-root `config.example.yml`). +The embedded node is ethrex, pinned by rev in the workspace `Cargo.toml`. +Currently v26.0.0-rc.3, which supports glamsterdam-devnet-8 +(`--network plataberget`). + ## Limitations - Merging protocol v1 carries `ExecutionPayloadV3`; post-Amsterdam blocks diff --git a/crates/builder/src/cli.rs b/crates/builder/src/cli.rs index 041d5398b..f14bea04b 100644 --- a/crates/builder/src/cli.rs +++ b/crates/builder/src/cli.rs @@ -59,7 +59,7 @@ pub struct NodeOptions { #[arg( long = "rocksdb.block-cache-size", value_name = "BYTES", - default_value_t = ethrex_storage::DEFAULT_ROCKSDB_BLOCK_CACHE_SIZE_BYTES, + default_value_t = ethrex_storage::MAX_ROCKSDB_BLOCK_CACHE_SIZE_BYTES, help = "RocksDB shared block cache size in bytes.", env = "ETHREX_ROCKSDB_BLOCK_CACHE_SIZE", help_heading = "Storage options" diff --git a/crates/builder/src/node.rs b/crates/builder/src/node.rs index 83e3d954e..8d899771a 100644 --- a/crates/builder/src/node.rs +++ b/crates/builder/src/node.rs @@ -112,6 +112,13 @@ pub async fn start(opts: &NodeOptions) -> eyre::Result { let signer = get_signer(&datadir); let (local_p2p_node, network_config) = get_local_p2p_node(opts, &signer); let node_record = get_local_node_record(&datadir, &local_p2p_node, &signer); + // ethrex v26 threads one live identity through the RPC, discovery and + // shutdown paths instead of separate node/record copies. + let shared_local_node: ethrex_p2p::types::SharedLocalNode = + std::sync::Arc::new(std::sync::RwLock::new(ethrex_p2p::types::LocalNode { + node: local_p2p_node.clone(), + record: node_record.clone(), + })); let peer_table = PeerTableServer::spawn(local_p2p_node.node_id(), opts.target_peers, store.clone()); @@ -143,6 +150,13 @@ pub async fn start(opts: &NodeOptions) -> eyre::Result { blockchain.clone(), store.clone(), datadir.clone(), + // No historical backfill: the roles need the head and recent state + // only, and ethrex forces this off in dev mode for the same reason. + ethrex_p2p::sync::BackfillConfig { + mode: ethrex_p2p::sync::HistoryChain::Off, + tx_index_horizon: 0, + }, + tracker.clone(), ) .await; @@ -161,8 +175,7 @@ pub async fn start(opts: &NodeOptions) -> eyre::Result { store.clone(), blockchain.clone(), jwt_secret, - local_p2p_node.clone(), - node_record.clone(), + shared_local_node.clone(), syncer, peer_handler.clone(), client_version(), @@ -204,11 +217,16 @@ pub async fn start(opts: &NodeOptions) -> eyre::Result { let discovery_config = DiscoveryConfig { discv4_enabled: opts.discv4_enabled, discv5_enabled: opts.discv5_enabled, - ..Default::default() + nat_extip_set: opts.nat_extip.is_some(), }; - ethrex_p2p::start_network(p2p_context, bootnodes, discovery_config) - .await - .map_err(|e| eyre::eyre!("Network failed to start: {e}"))?; + ethrex_p2p::start_network( + p2p_context, + bootnodes, + discovery_config, + shared_local_node.clone(), + ) + .await + .map_err(|e| eyre::eyre!("Network failed to start: {e}"))?; tracker.spawn(ethrex_p2p::periodically_show_peer_stats( blockchain.clone(), peer_handler.peer_table.clone(), @@ -285,7 +303,7 @@ async fn spawn_head_watcher( } async fn read_head(store: &Store, blockchain: &Blockchain) -> eyre::Result { - let number = store.get_latest_block_number().await?; + let number = store.get_latest_block_number()?; let hash = store .get_canonical_block_hash(number) .await? @@ -298,7 +316,7 @@ async fn read_head(store: &Store, blockchain: &Blockchain) -> eyre::Result) -> eyre::Result<()> { - let head_block_number = store.get_latest_block_number().await?; + let head_block_number = store.get_latest_block_number()?; let Some(last_header) = store.get_block_header(head_block_number)? else { eyre::bail!("database is empty, genesis block should be present"); }; diff --git a/crates/builder/src/testing.rs b/crates/builder/src/testing.rs index f270f4af7..c487a79d8 100644 --- a/crates/builder/src/testing.rs +++ b/crates/builder/src/testing.rs @@ -87,23 +87,28 @@ pub fn deploy_payment_forwarder(genesis: &mut Genesis) { }); } -/// The EIP-8282 builder deposit and exit predeploys, from ethrex's -/// `fixtures/genesis/l1-bal.json`. Empty code at either address invalidates -/// every Amsterdam block, so an Amsterdam fixture cannot build without them. +/// The EIP-8282 builder deposit and exit predeploys. Empty code at either +/// address invalidates every Amsterdam block, so an Amsterdam fixture cannot +/// build without them. +/// +/// The addresses come from ethrex rather than a literal: they are Nick's-method +/// addresses and they moved between devnet-7 and devnet-8, so a hardcoded pair +/// silently breaks on an ethrex bump. The runtime bytecode is unchanged across +/// that move and is copied from `fixtures/genesis/l1-bal.json`. pub fn deploy_amsterdam_predeploys(genesis: &mut Genesis) { - for (address, code) in [ - ("0000884d2aa32eaa155f59a2f24efa73d9008282", BUILDER_DEPOSIT_CODE), - ("000014574a74c805590aff9499fc7a690f008282", BUILDER_EXIT_CODE), + use ethrex_vm::system_contracts::{ + BUILDER_DEPOSIT_CONTRACT_ADDRESS, BUILDER_EXIT_CONTRACT_ADDRESS, + }; + for (contract, code) in [ + (BUILDER_DEPOSIT_CONTRACT_ADDRESS, BUILDER_DEPOSIT_CODE), + (BUILDER_EXIT_CONTRACT_ADDRESS, BUILDER_EXIT_CODE), ] { - genesis.alloc.insert( - ethrex_common::Address::from_slice(&hex::decode(address).unwrap()), - GenesisAccount { - code: hex::decode(code).unwrap().into(), - storage: Default::default(), - balance: ethrex_common::U256::zero(), - nonce: 0, - }, - ); + genesis.alloc.insert(contract.address, GenesisAccount { + code: hex::decode(code).unwrap().into(), + storage: Default::default(), + balance: ethrex_common::U256::zero(), + nonce: 0, + }); } } @@ -181,7 +186,9 @@ pub fn signed_blob_transfer( nonce, gas_limit: 100_000, max_fee_per_gas: 100_000_000_000, - max_priority_fee_per_gas: 0, + // ethrex v26 rejects a zero-tip transaction from the mempool. The + // payout is unaffected: it bypasses the pool via `apply_tx_to_payload`. + max_priority_fee_per_gas: 1, to, value: U256::ZERO, access_list: Default::default(), diff --git a/crates/builder/src/validation/tests.rs b/crates/builder/src/validation/tests.rs index 43d470228..b2fcf7f8f 100644 --- a/crates/builder/src/validation/tests.rs +++ b/crates/builder/src/validation/tests.rs @@ -237,7 +237,8 @@ impl Fixture { let number = block.header.number; let timestamp = block.header.timestamp; self.blockchain.add_block(block).unwrap(); - apply_fork_choice(&self.store, parent, parent, parent).await.unwrap(); + // v26 added a reorg-depth bound; the fixture never reorgs. + apply_fork_choice(&self.store, parent, parent, parent, None).await.unwrap(); self.head.send_replace(HeadInfo { number, hash: parent, timestamp, is_synced: true }); } parent @@ -556,7 +557,7 @@ async fn validating_a_block_does_not_store_it() { ) .expect("a block the fixture built must validate"); - assert_eq!(fixture.store.get_latest_block_number().await.unwrap(), 0); + assert_eq!(fixture.store.get_latest_block_number().unwrap(), 0); assert!( fixture.store.get_block_header_by_hash(h256(message.block_hash)).unwrap().is_none(), "the validated block must not be in the store" diff --git a/crates/vendored/ethrex-crypto/Cargo.toml b/crates/vendored/ethrex-crypto/Cargo.toml index c1f940227..8e26eba71 100644 --- a/crates/vendored/ethrex-crypto/Cargo.toml +++ b/crates/vendored/ethrex-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ethrex-crypto" -version = "20.0.0" +version = "26.0.0" edition = "2024" license = "MIT OR Apache-2.0" description = "Cryptographic primitives and precompile backends for the ethrex Ethereum execution client" diff --git a/crates/vendored/ethrex-crypto/VENDORED.md b/crates/vendored/ethrex-crypto/VENDORED.md index 6b978cc0f..e89ff50c4 100644 --- a/crates/vendored/ethrex-crypto/VENDORED.md +++ b/crates/vendored/ethrex-crypto/VENDORED.md @@ -2,7 +2,7 @@ Copy of `crates/common/crypto` from [lambdaclass/ethrex](https://github.com/lambdaclass/ethrex) at rev -`b4d5677812fdf58cb3e439c77906dda4d9b6f91a` (MIT OR Apache-2.0), applied to the +`34cf6c6258d3acb06e918e4308a3e571e19dfe05` (v26.0.0-rc.3) (MIT OR Apache-2.0), applied to the workspace via `[patch]` in the root `Cargo.toml`. ## Why diff --git a/crates/vendored/ethrex-crypto/kzg.rs b/crates/vendored/ethrex-crypto/kzg.rs index 263a22acd..888eed408 100644 --- a/crates/vendored/ethrex-crypto/kzg.rs +++ b/crates/vendored/ethrex-crypto/kzg.rs @@ -220,6 +220,93 @@ pub fn blob_to_kzg_commitment_and_proof(blob: &Blob) -> Result<(Commitment, Proo Ok((commitment_bytes.into_inner(), proof_bytes.into_inner())) } +/// Reconstruct a blob from its cells. +/// +/// EIP-7594 lays the original blob data in the first `CELLS_PER_EXT_BLOB / 2` +/// cells (columns 0..63); the second half is the Reed-Solomon extension. +/// Concatenating the 64 data cells reproduces the blob's field elements 1:1, +/// so a full data-column set needs no KZG recovery. Verified empirically: +/// `compute_cells(blob)[0..64]` concatenated equals `blob` and yields the same +/// commitment. +/// +/// `all_cells[col]` must hold the cell bytes for column `col`; only columns +/// 0..63 are read, so callers must ensure those are present. +pub fn cells_to_blob( + all_cells: &[[u8; BYTES_PER_CELL]; CELLS_PER_EXT_BLOB], +) -> [u8; BYTES_PER_BLOB] { + let mut blob = [0u8; BYTES_PER_BLOB]; + for col in 0..CELLS_PER_EXT_BLOB / 2 { + let dst = &mut blob[col * BYTES_PER_CELL..(col + 1) * BYTES_PER_CELL]; + dst.copy_from_slice(&all_cells[col]); + } + blob +} + +/// Recover all 128 cells and their KZG proofs from a partial set of cells. +/// `cell_indices` and `cells` must have equal length (≥ 64 for successful recovery). +/// Returns `(all_cells, all_proofs)` each of length 128. +#[cfg(feature = "c-kzg")] +pub fn recover_cells_and_kzg_proofs( + cell_indices: &[u64], + cells: &[[u8; BYTES_PER_CELL]], +) -> Result<(Vec<[u8; BYTES_PER_CELL]>, Vec), KzgError> { + let c_kzg_settings = c_kzg::ethereum_kzg_settings(KZG_PRECOMPUTE); + let c_cells: Vec = cells.iter().map(|c| c_kzg::Cell::new(*c)).collect(); + let (recovered_cells, recovered_proofs) = + c_kzg_settings.recover_cells_and_kzg_proofs(cell_indices, &c_cells)?; + let out_cells: Vec<[u8; BYTES_PER_CELL]> = + recovered_cells.iter().map(|c| c.to_bytes()).collect(); + let out_proofs: Vec = recovered_proofs + .iter() + .map(|p| p.to_bytes().into_inner()) + .collect(); + Ok((out_cells, out_proofs)) +} + +/// Compute all `CELLS_PER_EXT_BLOB` cells for a blob. +/// Returns one `[u8; BYTES_PER_CELL]` per cell. +#[cfg(feature = "c-kzg")] +pub fn compute_cells(blob: &Blob) -> Result, KzgError> { + let c_kzg_settings = c_kzg::ethereum_kzg_settings(KZG_PRECOMPUTE); + let c_blob: c_kzg::Blob = (*blob).into(); + let boxed = c_kzg_settings + .compute_cells(&c_blob) + .map_err(KzgError::CKzg)?; + Ok(boxed.iter().map(|cell| cell.to_bytes()).collect()) +} + +/// Verify KZG cell proofs for a subset of cells (partial batch). +/// `commitments`, `cell_indices`, `cells`, and `proofs` must all have the same length. +#[allow(unused_variables)] +pub fn verify_cell_kzg_proof_batch_partial( + commitments: &[Commitment], + cell_indices: &[u64], + cells: &[[u8; BYTES_PER_CELL]], + proofs: &[Proof], +) -> Result { + #[cfg(not(feature = "c-kzg"))] + { + return Err(KzgError::Unimplemented( + "verify_cell_kzg_proof_batch_partial requires the c-kzg feature".into(), + )); + } + #[cfg(feature = "c-kzg")] + { + let c_kzg_settings = c_kzg::ethereum_kzg_settings(KZG_PRECOMPUTE); + let c_commitments: Vec = commitments.iter().map(|c| (*c).into()).collect(); + let c_cells: Vec = cells.iter().map(|c| c_kzg::Cell::new(*c)).collect(); + let c_proofs: Vec = proofs.iter().map(|p| (*p).into()).collect(); + c_kzg::KzgSettings::verify_cell_kzg_proof_batch( + c_kzg_settings, + &c_commitments, + cell_indices, + &c_cells, + &c_proofs, + ) + .map_err(KzgError::from) + } +} + #[cfg(feature = "c-kzg")] pub fn blob_to_commitment_and_cell_proofs( blob: &Blob, diff --git a/crates/vendored/ethrex-crypto/provider.rs b/crates/vendored/ethrex-crypto/provider.rs index 5eca02782..fbfdcd752 100644 --- a/crates/vendored/ethrex-crypto/provider.rs +++ b/crates/vendored/ethrex-crypto/provider.rs @@ -160,6 +160,42 @@ pub trait Crypto: Send + Sync + core::fmt::Debug { Ok(hash) } + /// Recover the signer's **uncompressed** secp256k1 public key (`0x04 || X || Y`). + /// + /// [`Self::recover_signer`] hashes this and keeps the last 20 bytes; the + /// stateless-validation wire format needs the key itself, so that a guest can + /// verify signatures against a supplied key instead of running `ecrecover`. + /// Applies the same EIP-2 low-s rejection, so the two agree on which + /// signatures are valid. + /// + /// Host-only: this exists to *produce* `SszStatelessInput::public_keys`. Guests + /// only ever consume them, so no zkVM provider needs to override it. + #[cfg(feature = "secp256k1")] + fn recover_public_key(&self, sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 65], CryptoError> { + // EIP-2: reject high-s signatures (s > secp256k1n/2), matching recover_signer. + const SECP256K1_N_HALF: [u8; 32] = + hex_literal::hex!("7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0"); + if sig[32..64] > SECP256K1_N_HALF[..] { + return Err(CryptoError::InvalidSignature); + } + + let recovery_id = secp256k1::ecdsa::RecoveryId::try_from(sig[64] as i32) + .map_err(|_| CryptoError::InvalidRecoveryId)?; + let recoverable_sig = secp256k1::ecdsa::RecoverableSignature::from_compact( + sig[..64] + .try_into() + .map_err(|_| CryptoError::InvalidSignature)?, + recovery_id, + ) + .map_err(|_| CryptoError::InvalidSignature)?; + + let public_key = recoverable_sig + .recover(&secp256k1::Message::from_digest(*msg)) + .map_err(|_| CryptoError::RecoveryFailed)?; + + Ok(public_key.serialize_uncompressed()) + } + /// Recover the signer address from a 65-byte signature (r||s||v) + 32-byte message hash. /// Used by transaction validation (tx.sender()) and EIP-7702 authority recovery. fn recover_signer(&self, sig: &[u8; 65], msg: &[u8; 32]) -> Result { diff --git a/docs/gloas-testnet.md b/docs/gloas-testnet.md index 9dc4b5a4e..bfe40cf3e 100644 --- a/docs/gloas-testnet.md +++ b/docs/gloas-testnet.md @@ -45,25 +45,58 @@ config). A submission whose shape cannot carry its block's list is refused before it is sent, because sending it would drop the list and every bid would die as an unexplained block hash mismatch. -## Execution layer genesis +## Execution layer -### The EIP-8282 predeploys are mandatory +### glamsterdam-devnet-8 (`plataberget`) -Amsterdam runs two system contracts — the EIP-8282 builder deposit and builder +The ethrex pin supports it by name: + +``` +--network plataberget +``` + +| | | +| --- | --- | +| chain id | `7091047534` | +| Amsterdam activation | timestamp `1787212224` (2026-08-20T07:50:24Z) | +| network configs | [ethpandaops/glamsterdam-devnets, `network-configs/devnet-8`](https://github.com/ethpandaops/glamsterdam-devnets/tree/master/network-configs/devnet-8) | + +An unrecognised `--network` value is **not** an error: ethrex falls back to +treating it as a path to a genesis file (`Network::GenesisPath`). A misspelling +therefore fails as a missing file rather than as an unknown network, so check +the spelling — it is `plataberget`, with an `l`. + +### The EIP-8282 predeploys + +Amsterdam runs two system contracts, the EIP-8282 builder deposit and builder exit predeploys. **Empty code at either address invalidates every Amsterdam -block**, with `SystemContractCallFailed: ... has no code after deployment`. Both -must be allocated in genesis: +block**, with `SystemContractCallFailed: ... has no code after deployment`. + +They are Nick's-method addresses, so on a real devnet they are deployed on +chain by an ordinary transaction before the fork activates — devnet-8's own +genesis does not allocate them. On a synced node there is nothing to do; if +Amsterdam blocks are failing, confirm with `eth_getCode` at both addresses +before looking anywhere else. + +**The addresses moved between devnet-7 and devnet-8**, so do not copy them from +older notes. Read them from the ethrex you are building against — +`ethrex_vm::system_contracts::{BUILDER_DEPOSIT_CONTRACT_ADDRESS, +BUILDER_EXIT_CONTRACT_ADDRESS}` — which is what +`crates/builder/src/testing.rs::deploy_amsterdam_predeploys` does, precisely so +a pin bump cannot silently invalidate every block. At v26.0.0-rc.3 they are: | address | contract | | --- | --- | -| `0x0000884d2AA32eAa155F59A2f24eFa73D9008282` | builder deposit | -| `0x000014574A74c805590AFF9499fc7A690f008282` | builder exit | +| `0x0000BFF46984E3725691FA540A8C7589300D8282` | builder deposit | +| `0x000064D678505AD48F8CCB093BC65613800E8282` | builder exit | + +The runtime bytecode did not change across that move. -Their runtime bytecode is in ethrex's own `fixtures/genesis/l1-bal.json`, and in -this repo in `crates/builder/src/testing.rs` -(`deploy_amsterdam_predeploys`), which is what the Amsterdam test fixtures use. +### A local genesis instead -### Fork activation +Only a genesis you build yourself needs the predeploys allocated, because it +has no pre-fork history in which to deploy them. Activate the fork and allocate +both contracts: ```json { @@ -208,9 +241,10 @@ above 204600 for any transfer to an address that does not exist yet. 5. **`get_payload` and publication complete**, which is the point of the whole exercise. -If step 1 fails with a block hash mismatch, suspect the genesis: a missing -Amsterdam predeploy, or an `amsterdamTime` that disagrees with the CL's Gloas -epoch. +If step 1 fails with a block hash mismatch, suspect fork disagreement first: an +`amsterdamTime` that does not line up with the CL's Gloas epoch. A missing +EIP-8282 predeploy shows up differently, as `SystemContractCallFailed` during +execution rather than as a hash mismatch. ## What is not supported