From cec327695d9856750d9434db1434608cf485edf6 Mon Sep 17 00:00:00 2001 From: Rez Date: Sat, 6 Dec 2025 01:07:01 +1100 Subject: [PATCH 01/12] flashblocks integration correctly consume flashblocks from base correctly consume flashblocks from base Update mod.rs Update api.rs Update api.rs progress started --- Cargo.lock | 501 ++++++++++++++++++++++++++++----------- Cargo.toml | 98 ++++---- src/engine/mod.rs | 12 + src/flashblocks/mod.rs | 153 ++++++++++++ src/lib.rs | 1 + src/node/evm/config.rs | 16 ++ src/rpc/api.rs | 109 ++++++++- src/rpc/mod.rs | 72 +++++- tests/e2e/flashblocks.rs | 18 ++ tests/e2e/mod.rs | 1 + 10 files changed, 791 insertions(+), 190 deletions(-) create mode 100644 src/flashblocks/mod.rs create mode 100644 tests/e2e/flashblocks.rs diff --git a/Cargo.lock b/Cargo.lock index 911ed1b5..16f5ed52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -249,6 +249,7 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-hardforks", + "alloy-op-hardforks", "alloy-primitives", "alloy-rpc-types-engine", "alloy-rpc-types-eth", @@ -356,6 +357,36 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-op-evm" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231262d7e06000f3fb642d32d38ca75e09e78e04977c10be0a07a5ee2c869cfd" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-op-hardforks", + "alloy-primitives", + "auto_impl", + "op-alloy", + "op-revm", + "revm", + "thiserror 2.0.17", +] + +[[package]] +name = "alloy-op-hardforks" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f96fb2fce4024ada5b2c11d4076acf778a0d3e4f011c6dfd2ffce6d0fcf84ee9" +dependencies = [ + "alloy-chains", + "alloy-hardforks", + "alloy-primitives", + "auto_impl", +] + [[package]] name = "alloy-primitives" version = "1.4.1" @@ -1462,6 +1493,7 @@ dependencies = [ "clap", "derive_more", "eyre", + "futures-util", "jsonrpsee", "jsonrpsee-core", "jsonrpsee-proc-macros", @@ -1473,7 +1505,7 @@ dependencies = [ "reth-cli-commands", "reth-cli-util", "reth-codecs", - "reth-consensus-common", + "reth-consensus-common 1.9.3 (git+https://github.com/paradigmxyz/reth?rev=536bebfcd)", "reth-db", "reth-db-api", "reth-e2e-test-utils", @@ -1491,6 +1523,8 @@ dependencies = [ "reth-node-builder", "reth-node-core", "reth-node-ethereum", + "reth-optimism-flashblocks", + "reth-optimism-rpc", "reth-payload-primitives", "reth-payload-validator", "reth-primitives-traits", @@ -3999,7 +4033,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.57.0", ] [[package]] @@ -5375,6 +5409,12 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "op-alloy-flz" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a79f352fc3893dcd670172e615afef993a41798a1d3fc0db88a3e60ef2e70ecc" + [[package]] name = "op-alloy-network" version = "0.22.4" @@ -5406,6 +5446,16 @@ dependencies = [ "op-alloy-rpc-types-engine", ] +[[package]] +name = "op-alloy-rpc-jsonrpsee" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ef9114426b16172254555aad34a8ea96c01895e40da92f5d12ea680a1baeaa7" +dependencies = [ + "alloy-primitives", + "jsonrpsee", +] + [[package]] name = "op-alloy-rpc-types" version = "0.22.4" @@ -6466,7 +6516,6 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" [[package]] name = "reth" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-rpc-types", "aquamarine", @@ -6475,8 +6524,8 @@ dependencies = [ "reth-chainspec", "reth-cli-runner", "reth-cli-util", - "reth-consensus", - "reth-consensus-common", + "reth-consensus 1.9.3", + "reth-consensus-common 1.9.3", "reth-db", "reth-ethereum-cli", "reth-ethereum-payload-builder", @@ -6512,7 +6561,6 @@ dependencies = [ [[package]] name = "reth-basic-payload-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6536,7 +6584,6 @@ dependencies = [ [[package]] name = "reth-chain-state" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6567,7 +6614,6 @@ dependencies = [ [[package]] name = "reth-chainspec" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-chains", "alloy-consensus", @@ -6587,7 +6633,6 @@ dependencies = [ [[package]] name = "reth-cli" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-genesis", "clap", @@ -6601,7 +6646,6 @@ dependencies = [ [[package]] name = "reth-cli-commands" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-chains", "alloy-consensus", @@ -6627,7 +6671,7 @@ dependencies = [ "reth-cli-util", "reth-codecs", "reth-config", - "reth-consensus", + "reth-consensus 1.9.3", "reth-db", "reth-db-api", "reth-db-common", @@ -6676,7 +6720,6 @@ dependencies = [ [[package]] name = "reth-cli-runner" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "reth-tasks", "tokio", @@ -6686,7 +6729,6 @@ dependencies = [ [[package]] name = "reth-cli-util" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eips", "alloy-primitives", @@ -6704,7 +6746,6 @@ dependencies = [ [[package]] name = "reth-codecs" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6724,7 +6765,6 @@ dependencies = [ [[package]] name = "reth-codecs-derive" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "proc-macro2", "quote", @@ -6734,7 +6774,6 @@ dependencies = [ [[package]] name = "reth-config" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "eyre", "humantime-serde", @@ -6747,6 +6786,18 @@ dependencies = [ "url", ] +[[package]] +name = "reth-consensus" +version = "1.9.3" +dependencies = [ + "alloy-consensus", + "alloy-primitives", + "auto_impl", + "reth-execution-types", + "reth-primitives-traits", + "thiserror 2.0.17", +] + [[package]] name = "reth-consensus" version = "1.9.3" @@ -6760,6 +6811,17 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "reth-consensus-common" +version = "1.9.3" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "reth-chainspec", + "reth-consensus 1.9.3", + "reth-primitives-traits", +] + [[package]] name = "reth-consensus-common" version = "1.9.3" @@ -6768,14 +6830,13 @@ dependencies = [ "alloy-consensus", "alloy-eips", "reth-chainspec", - "reth-consensus", + "reth-consensus 1.9.3 (git+https://github.com/paradigmxyz/reth?rev=536bebfcd)", "reth-primitives-traits", ] [[package]] name = "reth-consensus-debug-client" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6801,7 +6862,6 @@ dependencies = [ [[package]] name = "reth-db" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "derive_more", @@ -6827,7 +6887,6 @@ dependencies = [ [[package]] name = "reth-db-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -6855,7 +6914,6 @@ dependencies = [ [[package]] name = "reth-db-common" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -6885,7 +6943,6 @@ dependencies = [ [[package]] name = "reth-db-models" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eips", "alloy-primitives", @@ -6900,7 +6957,6 @@ dependencies = [ [[package]] name = "reth-discv4" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -6925,7 +6981,6 @@ dependencies = [ [[package]] name = "reth-discv5" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -6949,7 +7004,6 @@ dependencies = [ [[package]] name = "reth-dns-discovery" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "data-encoding", @@ -6973,7 +7027,6 @@ dependencies = [ [[package]] name = "reth-downloaders" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6987,7 +7040,7 @@ dependencies = [ "pin-project", "rayon", "reth-config", - "reth-consensus", + "reth-consensus 1.9.3", "reth-ethereum-primitives", "reth-metrics", "reth-network-p2p", @@ -7008,7 +7061,6 @@ dependencies = [ [[package]] name = "reth-e2e-test-utils" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7027,7 +7079,7 @@ dependencies = [ "reth-chainspec", "reth-cli-commands", "reth-config", - "reth-consensus", + "reth-consensus 1.9.3", "reth-db", "reth-db-common", "reth-engine-local", @@ -7066,7 +7118,6 @@ dependencies = [ [[package]] name = "reth-ecies" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "aes", "alloy-primitives", @@ -7095,7 +7146,6 @@ dependencies = [ [[package]] name = "reth-engine-local" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7118,7 +7168,6 @@ dependencies = [ [[package]] name = "reth-engine-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7143,12 +7192,11 @@ dependencies = [ [[package]] name = "reth-engine-service" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "futures", "pin-project", "reth-chainspec", - "reth-consensus", + "reth-consensus 1.9.3", "reth-engine-primitives", "reth-engine-tree", "reth-ethereum-primitives", @@ -7165,7 +7213,6 @@ dependencies = [ [[package]] name = "reth-engine-tree" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7183,7 +7230,7 @@ dependencies = [ "rayon", "reth-chain-state", "reth-chainspec", - "reth-consensus", + "reth-consensus 1.9.3", "reth-db", "reth-engine-primitives", "reth-errors", @@ -7220,7 +7267,6 @@ dependencies = [ [[package]] name = "reth-engine-util" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -7248,7 +7294,6 @@ dependencies = [ [[package]] name = "reth-era" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7263,7 +7308,6 @@ dependencies = [ [[package]] name = "reth-era-downloader" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "bytes", @@ -7279,7 +7323,6 @@ dependencies = [ [[package]] name = "reth-era-utils" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7301,9 +7344,8 @@ dependencies = [ [[package]] name = "reth-errors" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ - "reth-consensus", + "reth-consensus 1.9.3", "reth-execution-errors", "reth-storage-errors", "thiserror 2.0.17", @@ -7312,7 +7354,6 @@ dependencies = [ [[package]] name = "reth-eth-wire" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-chains", "alloy-primitives", @@ -7340,7 +7381,6 @@ dependencies = [ [[package]] name = "reth-eth-wire-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-chains", "alloy-consensus", @@ -7361,7 +7401,6 @@ dependencies = [ [[package]] name = "reth-ethereum-cli" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "clap", "eyre", @@ -7383,14 +7422,13 @@ dependencies = [ [[package]] name = "reth-ethereum-consensus" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", "reth-chainspec", - "reth-consensus", - "reth-consensus-common", + "reth-consensus 1.9.3", + "reth-consensus-common 1.9.3", "reth-execution-types", "reth-primitives-traits", "tracing", @@ -7399,7 +7437,6 @@ dependencies = [ [[package]] name = "reth-ethereum-engine-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eips", "alloy-primitives", @@ -7417,7 +7454,6 @@ dependencies = [ [[package]] name = "reth-ethereum-forks" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eip2124", "alloy-hardforks", @@ -7430,7 +7466,6 @@ dependencies = [ [[package]] name = "reth-ethereum-payload-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7439,7 +7474,7 @@ dependencies = [ "alloy-rpc-types-engine", "reth-basic-payload-builder", "reth-chainspec", - "reth-consensus-common", + "reth-consensus-common 1.9.3", "reth-errors", "reth-ethereum-primitives", "reth-evm", @@ -7459,7 +7494,6 @@ dependencies = [ [[package]] name = "reth-ethereum-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7479,7 +7513,6 @@ dependencies = [ [[package]] name = "reth-etl" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "rayon", "reth-db-api", @@ -7489,7 +7522,6 @@ dependencies = [ [[package]] name = "reth-evm" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7512,7 +7544,6 @@ dependencies = [ [[package]] name = "reth-evm-ethereum" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7533,7 +7564,6 @@ dependencies = [ [[package]] name = "reth-execution-errors" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-evm", "alloy-primitives", @@ -7546,7 +7576,6 @@ dependencies = [ [[package]] name = "reth-execution-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7564,7 +7593,6 @@ dependencies = [ [[package]] name = "reth-exex" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7602,7 +7630,6 @@ dependencies = [ [[package]] name = "reth-exex-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eips", "alloy-primitives", @@ -7616,7 +7643,6 @@ dependencies = [ [[package]] name = "reth-fs-util" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "serde", "serde_json", @@ -7626,7 +7652,6 @@ dependencies = [ [[package]] name = "reth-invalid-block-hooks" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7654,7 +7679,6 @@ dependencies = [ [[package]] name = "reth-ipc" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "bytes", "futures", @@ -7674,7 +7698,6 @@ dependencies = [ [[package]] name = "reth-libmdbx" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "bitflags 2.10.0", "byteorder", @@ -7690,7 +7713,6 @@ dependencies = [ [[package]] name = "reth-mdbx-sys" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "bindgen 0.71.1", "cc", @@ -7699,7 +7721,6 @@ dependencies = [ [[package]] name = "reth-metrics" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "futures", "metrics", @@ -7711,7 +7732,6 @@ dependencies = [ [[package]] name = "reth-net-banlist" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "ipnet", @@ -7720,7 +7740,6 @@ dependencies = [ [[package]] name = "reth-net-nat" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "futures-util", "if-addrs", @@ -7734,7 +7753,6 @@ dependencies = [ [[package]] name = "reth-network" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7753,7 +7771,7 @@ dependencies = [ "rand 0.8.5", "rand 0.9.2", "reth-chainspec", - "reth-consensus", + "reth-consensus 1.9.3", "reth-discv4", "reth-discv5", "reth-dns-discovery", @@ -7789,7 +7807,6 @@ dependencies = [ [[package]] name = "reth-network-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7814,7 +7831,6 @@ dependencies = [ [[package]] name = "reth-network-p2p" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7823,7 +7839,7 @@ dependencies = [ "derive_more", "futures", "parking_lot", - "reth-consensus", + "reth-consensus 1.9.3", "reth-eth-wire-types", "reth-ethereum-primitives", "reth-network-peers", @@ -7837,7 +7853,6 @@ dependencies = [ [[package]] name = "reth-network-peers" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -7852,7 +7867,6 @@ dependencies = [ [[package]] name = "reth-network-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eip2124", "humantime-serde", @@ -7866,7 +7880,6 @@ dependencies = [ [[package]] name = "reth-nippy-jar" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "anyhow", "bincode 1.3.3", @@ -7883,12 +7896,11 @@ dependencies = [ [[package]] name = "reth-node-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-rpc-types-engine", "eyre", "reth-basic-payload-builder", - "reth-consensus", + "reth-consensus 1.9.3", "reth-db-api", "reth-engine-primitives", "reth-evm", @@ -7907,7 +7919,6 @@ dependencies = [ [[package]] name = "reth-node-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7925,7 +7936,7 @@ dependencies = [ "reth-chain-state", "reth-chainspec", "reth-config", - "reth-consensus", + "reth-consensus 1.9.3", "reth-consensus-debug-client", "reth-db", "reth-db-api", @@ -7974,7 +7985,6 @@ dependencies = [ [[package]] name = "reth-node-core" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7991,7 +8001,7 @@ dependencies = [ "reth-chainspec", "reth-cli-util", "reth-config", - "reth-consensus", + "reth-consensus 1.9.3", "reth-db", "reth-discv4", "reth-discv5", @@ -8030,7 +8040,6 @@ dependencies = [ [[package]] name = "reth-node-ethereum" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eips", "alloy-network", @@ -8068,7 +8077,6 @@ dependencies = [ [[package]] name = "reth-node-ethstats" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8092,7 +8100,6 @@ dependencies = [ [[package]] name = "reth-node-events" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8116,7 +8123,6 @@ dependencies = [ [[package]] name = "reth-node-metrics" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "eyre", "http", @@ -8138,7 +8144,6 @@ dependencies = [ [[package]] name = "reth-node-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "reth-chainspec", "reth-db-api", @@ -8147,10 +8152,168 @@ dependencies = [ "reth-primitives-traits", ] +[[package]] +name = "reth-optimism-chainspec" +version = "1.9.3" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-genesis", + "alloy-hardforks", + "alloy-primitives", + "derive_more", + "op-alloy-consensus", + "op-alloy-rpc-types", + "reth-chainspec", + "reth-ethereum-forks", + "reth-network-peers", + "reth-optimism-forks", + "reth-optimism-primitives", + "reth-primitives-traits", + "serde_json", +] + +[[package]] +name = "reth-optimism-consensus" +version = "1.9.3" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-trie", + "reth-chainspec", + "reth-consensus 1.9.3", + "reth-consensus-common 1.9.3", + "reth-execution-types", + "reth-optimism-chainspec", + "reth-optimism-forks", + "reth-optimism-primitives", + "reth-primitives-traits", + "reth-storage-api", + "reth-storage-errors", + "reth-trie-common", + "revm", + "thiserror 2.0.17", + "tracing", +] + +[[package]] +name = "reth-optimism-evm" +version = "1.9.3" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-op-evm", + "alloy-primitives", + "op-alloy-consensus", + "op-alloy-rpc-types-engine", + "op-revm", + "reth-chainspec", + "reth-evm", + "reth-execution-errors", + "reth-execution-types", + "reth-optimism-chainspec", + "reth-optimism-consensus", + "reth-optimism-forks", + "reth-optimism-primitives", + "reth-primitives-traits", + "reth-storage-errors", + "revm", + "thiserror 2.0.17", +] + +[[package]] +name = "reth-optimism-flashblocks" +version = "1.9.3" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rpc-types-engine", + "brotli", + "derive_more", + "eyre", + "futures-util", + "metrics", + "op-alloy-consensus", + "op-alloy-rpc-types-engine", + "reth-chain-state", + "reth-engine-primitives", + "reth-errors", + "reth-evm", + "reth-execution-types", + "reth-metrics", + "reth-optimism-payload-builder", + "reth-optimism-primitives", + "reth-payload-primitives", + "reth-primitives-traits", + "reth-revm", + "reth-rpc-eth-types", + "reth-storage-api", + "reth-tasks", + "ringbuffer", + "serde", + "serde_json", + "tokio", + "tokio-tungstenite", + "tracing", + "url", +] + +[[package]] +name = "reth-optimism-forks" +version = "1.9.3" +dependencies = [ + "alloy-op-hardforks", + "alloy-primitives", + "once_cell", + "reth-ethereum-forks", +] + +[[package]] +name = "reth-optimism-payload-builder" +version = "1.9.3" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-debug", + "alloy-rpc-types-engine", + "derive_more", + "either", + "op-alloy-consensus", + "op-alloy-rpc-types-engine", + "reth-basic-payload-builder", + "reth-chainspec", + "reth-evm", + "reth-execution-types", + "reth-optimism-evm", + "reth-optimism-forks", + "reth-optimism-primitives", + "reth-optimism-txpool", + "reth-payload-builder", + "reth-payload-builder-primitives", + "reth-payload-primitives", + "reth-payload-util", + "reth-payload-validator", + "reth-primitives-traits", + "reth-revm", + "reth-storage-api", + "reth-transaction-pool", + "revm", + "serde", + "sha2", + "thiserror 2.0.17", + "tracing", +] + [[package]] name = "reth-optimism-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8162,10 +8325,104 @@ dependencies = [ "serde_with", ] +[[package]] +name = "reth-optimism-rpc" +version = "1.9.3" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-debug", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-transport", + "alloy-transport-http", + "async-trait", + "derive_more", + "eyre", + "futures", + "jsonrpsee", + "jsonrpsee-core", + "jsonrpsee-types", + "metrics", + "op-alloy-consensus", + "op-alloy-network", + "op-alloy-rpc-jsonrpsee", + "op-alloy-rpc-types", + "op-alloy-rpc-types-engine", + "op-revm", + "reqwest", + "reth-chain-state", + "reth-chainspec", + "reth-evm", + "reth-metrics", + "reth-node-api", + "reth-node-builder", + "reth-optimism-evm", + "reth-optimism-flashblocks", + "reth-optimism-forks", + "reth-optimism-payload-builder", + "reth-optimism-primitives", + "reth-optimism-txpool", + "reth-primitives-traits", + "reth-rpc", + "reth-rpc-api", + "reth-rpc-engine-api", + "reth-rpc-eth-api", + "reth-rpc-eth-types", + "reth-rpc-server-types", + "reth-storage-api", + "reth-tasks", + "reth-transaction-pool", + "revm", + "serde_json", + "thiserror 2.0.17", + "tokio", + "tokio-stream", + "tower", + "tracing", +] + +[[package]] +name = "reth-optimism-txpool" +version = "1.9.3" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-serde", + "c-kzg", + "derive_more", + "futures-util", + "metrics", + "op-alloy-consensus", + "op-alloy-flz", + "op-alloy-rpc-types", + "op-revm", + "parking_lot", + "reth-chain-state", + "reth-chainspec", + "reth-metrics", + "reth-optimism-evm", + "reth-optimism-forks", + "reth-optimism-primitives", + "reth-primitives-traits", + "reth-storage-api", + "reth-transaction-pool", + "serde", + "thiserror 2.0.17", + "tokio", + "tracing", +] + [[package]] name = "reth-payload-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8186,7 +8443,6 @@ dependencies = [ [[package]] name = "reth-payload-builder-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "pin-project", "reth-payload-primitives", @@ -8198,7 +8454,6 @@ dependencies = [ [[package]] name = "reth-payload-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8218,10 +8473,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "reth-payload-util" +version = "1.9.3" +dependencies = [ + "alloy-consensus", + "alloy-primitives", + "reth-transaction-pool", +] + [[package]] name = "reth-payload-validator" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -8231,7 +8494,6 @@ dependencies = [ [[package]] name = "reth-primitives" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "once_cell", @@ -8244,7 +8506,6 @@ dependencies = [ [[package]] name = "reth-primitives-traits" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8277,7 +8538,6 @@ dependencies = [ [[package]] name = "reth-provider" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8321,7 +8581,6 @@ dependencies = [ [[package]] name = "reth-prune" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8349,7 +8608,6 @@ dependencies = [ [[package]] name = "reth-prune-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "arbitrary", @@ -8364,7 +8622,6 @@ dependencies = [ [[package]] name = "reth-ress-protocol" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8383,7 +8640,6 @@ dependencies = [ [[package]] name = "reth-ress-provider" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8410,7 +8666,6 @@ dependencies = [ [[package]] name = "reth-revm" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "reth-primitives-traits", @@ -8423,7 +8678,6 @@ dependencies = [ [[package]] name = "reth-rpc" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -8461,8 +8715,8 @@ dependencies = [ "pin-project", "reth-chain-state", "reth-chainspec", - "reth-consensus", - "reth-consensus-common", + "reth-consensus 1.9.3", + "reth-consensus-common 1.9.3", "reth-engine-primitives", "reth-errors", "reth-evm", @@ -8502,7 +8756,6 @@ dependencies = [ [[package]] name = "reth-rpc-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eips", "alloy-genesis", @@ -8530,7 +8783,6 @@ dependencies = [ [[package]] name = "reth-rpc-builder" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-network", "alloy-provider", @@ -8541,7 +8793,7 @@ dependencies = [ "pin-project", "reth-chain-state", "reth-chainspec", - "reth-consensus", + "reth-consensus 1.9.3", "reth-evm", "reth-ipc", "reth-metrics", @@ -8569,7 +8821,6 @@ dependencies = [ [[package]] name = "reth-rpc-convert" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-evm", @@ -8581,16 +8832,20 @@ dependencies = [ "auto_impl", "dyn-clone", "jsonrpsee-types", + "op-alloy-consensus", + "op-alloy-network", + "op-alloy-rpc-types", "reth-ethereum-primitives", "reth-evm", + "reth-optimism-primitives", "reth-primitives-traits", + "reth-storage-api", "thiserror 2.0.17", ] [[package]] name = "reth-rpc-engine-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8619,7 +8874,6 @@ dependencies = [ [[package]] name = "reth-rpc-eth-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -8663,7 +8917,6 @@ dependencies = [ [[package]] name = "reth-rpc-eth-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8710,7 +8963,6 @@ dependencies = [ [[package]] name = "reth-rpc-layer" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-rpc-types-engine", "http", @@ -8724,7 +8976,6 @@ dependencies = [ [[package]] name = "reth-rpc-server-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8740,7 +8991,6 @@ dependencies = [ [[package]] name = "reth-stages" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8755,7 +9005,7 @@ dependencies = [ "reth-chainspec", "reth-codecs", "reth-config", - "reth-consensus", + "reth-consensus 1.9.3", "reth-db", "reth-db-api", "reth-era", @@ -8788,7 +9038,6 @@ dependencies = [ [[package]] name = "reth-stages-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8796,7 +9045,7 @@ dependencies = [ "auto_impl", "futures-util", "metrics", - "reth-consensus", + "reth-consensus 1.9.3", "reth-errors", "reth-metrics", "reth-network-p2p", @@ -8815,7 +9064,6 @@ dependencies = [ [[package]] name = "reth-stages-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "arbitrary", @@ -8829,7 +9077,6 @@ dependencies = [ [[package]] name = "reth-static-file" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "parking_lot", @@ -8849,7 +9096,6 @@ dependencies = [ [[package]] name = "reth-static-file-types" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "clap", @@ -8861,7 +9107,6 @@ dependencies = [ [[package]] name = "reth-storage-api" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8885,7 +9130,6 @@ dependencies = [ [[package]] name = "reth-storage-errors" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8901,7 +9145,6 @@ dependencies = [ [[package]] name = "reth-tasks" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "auto_impl", "dyn-clone", @@ -8919,7 +9162,6 @@ dependencies = [ [[package]] name = "reth-testing-utils" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8935,7 +9177,6 @@ dependencies = [ [[package]] name = "reth-tokio-util" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "tokio", "tokio-stream", @@ -8945,7 +9186,6 @@ dependencies = [ [[package]] name = "reth-tracing" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "clap", "eyre", @@ -8961,7 +9201,6 @@ dependencies = [ [[package]] name = "reth-tracing-otlp" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "clap", "eyre", @@ -8978,7 +9217,6 @@ dependencies = [ [[package]] name = "reth-transaction-pool" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9019,7 +9257,6 @@ dependencies = [ [[package]] name = "reth-trie" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9045,7 +9282,6 @@ dependencies = [ [[package]] name = "reth-trie-common" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -9072,7 +9308,6 @@ dependencies = [ [[package]] name = "reth-trie-db" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "reth-db-api", @@ -9085,7 +9320,6 @@ dependencies = [ [[package]] name = "reth-trie-parallel" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -9110,7 +9344,6 @@ dependencies = [ [[package]] name = "reth-trie-sparse" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -9129,7 +9362,6 @@ dependencies = [ [[package]] name = "reth-trie-sparse-parallel" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -9147,7 +9379,6 @@ dependencies = [ [[package]] name = "reth-zstd-compressors" version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" dependencies = [ "zstd", ] @@ -11569,7 +11800,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 42935f9b..303f2b34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,8 @@ reth-node-api = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" reth-node-builder = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" } reth-node-core = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" } reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" } +reth-optimism-flashblocks = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" } +reth-optimism-rpc = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" } reth-payload-primitives = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" } reth-payload-validator = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" } reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" } @@ -80,6 +82,7 @@ reth-rpc-builder = { git = "https://github.com/paradigmxyz/reth", rev = "536bebf revm-inspectors = "0.33.0" serde_json = "1.0" test-fuzz = "7" +futures-util = { version = "0.3", default-features = false } [build-dependencies] vergen = { version = "9.0.4", features = ["build", "cargo", "emit_and_set"] } @@ -111,49 +114,52 @@ lto = "thin" [package.metadata.cargo-machete] ignored = ["modular-bitfield"] -# [patch."https://github.com/paradigmxyz/reth"] -# reth = { path = "../reth/bin/reth" } -# reth-rpc = { path = "../reth/crates/rpc/rpc" } -# reth-basic-payload-builder = { path = "../reth/crates/payload/basic" } -# reth-chainspec = { path = "../reth/crates/chainspec" } -# reth-cli = { path = "../reth/crates/cli/cli" } -# reth-cli-commands = { path = "../reth/crates/cli/commands" } -# reth-cli-util = { path = "../reth/crates/cli/util" } -# reth-db = { path = "../reth/crates/storage/db" } -# reth-engine-local = { path = "../reth/crates/engine/local" } -# reth-engine-primitives = { path = "../reth/crates/engine/primitives" } -# reth-ethereum-cli = { path = "../reth/crates/ethereum/cli" } -# reth-engine-tree = { path = "../reth/crates/engine/tree" } -# reth-ethereum-engine-primitives = { path = "../reth/crates/ethereum/engine-primitives" } -# reth-ethereum-payload-builder = { path = "../reth/crates/ethereum/payload" } -# reth-ethereum-primitives = { path = "../reth/crates/ethereum/primitives" } -# reth-evm = { path = "../reth/crates/evm/evm" } -# reth-evm-ethereum = { path = "../reth/crates/ethereum/evm" } -# reth-network-peers = { path = "../reth/crates/net/peers" } -# reth-node-api = { path = "../reth/crates/node/api" } -# reth-node-builder = { path = "../reth/crates/node/builder" } -# reth-node-core = { path = "../reth/crates/node/core" } -# reth-payload-validator = { path = "../reth/crates/payload/validator" } -# reth-node-ethereum = { path = "../reth/crates/ethereum/node" } -# reth-payload-primitives = { path = "../reth/crates/payload/primitives" } -# reth-primitives-traits = { path = "../reth/crates/primitives-traits" } -# reth-tracing = { path = "../reth/crates/tracing" } -# reth-codecs = { path = "../reth/crates/storage/codecs" } -# reth-db-api = { path = "../reth/crates/storage/db-api" } -# reth-rpc-engine-api = { path = "../reth/crates/rpc/rpc-engine-api" } -# reth-rpc-eth-api = { path = "../reth/crates/rpc/rpc-eth-api" } -# reth-rpc-eth-types = { path = "../reth/crates/rpc/rpc-eth-types" } -# reth-rpc-convert = { path = "../reth/crates/rpc/rpc-convert" } -# reth-transaction-pool = { path = "../reth/crates/transaction-pool" } -# reth-zstd-compressors = { path = "../reth/crates/storage/zstd-compressors" } -# reth-trie-common = { path = "../reth/crates/trie/common" } -# reth-trie-db = { path = "../reth/crates/trie/db" } -# reth-trie = { path = "../reth/crates/trie/trie" } -# reth-stages-types = { path = "../reth/crates/stages/types" } -# reth-execution-types = { path = "../reth/crates/evm/execution-types" } -# reth-execution-errors = { path = "../reth/crates/evm/execution-errors" } -# reth-storage-api = { path = "../reth/crates/storage/storage-api" } -# reth-provider = { path = "../reth/crates/storage/provider" } -# reth-storage-errors = { path = "../reth/crates/storage/errors" } -# reth-e2e-test-utils = { path = "../reth/crates/e2e-test-utils" } -# reth-rpc-builder = { path = "../reth/crates/rpc/rpc-builder" } +[patch."https://github.com/paradigmxyz/reth"] +reth = { path = "../reth/bin/reth" } +reth-rpc = { path = "../reth/crates/rpc/rpc" } +reth-basic-payload-builder = { path = "../reth/crates/payload/basic" } +reth-chainspec = { path = "../reth/crates/chainspec" } +reth-cli = { path = "../reth/crates/cli/cli" } +reth-cli-commands = { path = "../reth/crates/cli/commands" } +reth-cli-util = { path = "../reth/crates/cli/util" } +reth-db = { path = "../reth/crates/storage/db" } +reth-engine-local = { path = "../reth/crates/engine/local" } +reth-engine-primitives = { path = "../reth/crates/engine/primitives" } +reth-errors = { path = "../reth/crates/errors" } +reth-ethereum-cli = { path = "../reth/crates/ethereum/cli" } +reth-engine-tree = { path = "../reth/crates/engine/tree" } +reth-ethereum-engine-primitives = { path = "../reth/crates/ethereum/engine-primitives" } +reth-ethereum-payload-builder = { path = "../reth/crates/ethereum/payload" } +reth-ethereum-primitives = { path = "../reth/crates/ethereum/primitives" } +reth-evm = { path = "../reth/crates/evm/evm" } +reth-evm-ethereum = { path = "../reth/crates/ethereum/evm" } +reth-network-peers = { path = "../reth/crates/net/peers" } +reth-node-api = { path = "../reth/crates/node/api" } +reth-node-builder = { path = "../reth/crates/node/builder" } +reth-node-core = { path = "../reth/crates/node/core" } +reth-payload-validator = { path = "../reth/crates/payload/validator" } +reth-node-ethereum = { path = "../reth/crates/ethereum/node" } +reth-payload-primitives = { path = "../reth/crates/payload/primitives" } +reth-primitives-traits = { path = "../reth/crates/primitives-traits" } +reth-tracing = { path = "../reth/crates/tracing" } +reth-codecs = { path = "../reth/crates/storage/codecs" } +reth-db-api = { path = "../reth/crates/storage/db-api" } +reth-rpc-engine-api = { path = "../reth/crates/rpc/rpc-engine-api" } +reth-rpc-eth-api = { path = "../reth/crates/rpc/rpc-eth-api" } +reth-rpc-eth-types = { path = "../reth/crates/rpc/rpc-eth-types" } +reth-rpc-convert = { path = "../reth/crates/rpc/rpc-convert" } +reth-transaction-pool = { path = "../reth/crates/transaction-pool" } +reth-zstd-compressors = { path = "../reth/crates/storage/zstd-compressors" } +reth-trie-common = { path = "../reth/crates/trie/common" } +reth-trie-db = { path = "../reth/crates/trie/db" } +reth-trie = { path = "../reth/crates/trie/trie" } +reth-stages-types = { path = "../reth/crates/stages/types" } +reth-execution-types = { path = "../reth/crates/evm/execution-types" } +reth-execution-errors = { path = "../reth/crates/evm/execution-errors" } +reth-storage-api = { path = "../reth/crates/storage/storage-api" } +reth-provider = { path = "../reth/crates/storage/provider" } +reth-storage-errors = { path = "../reth/crates/storage/errors" } +reth-e2e-test-utils = { path = "../reth/crates/e2e-test-utils" } +reth-rpc-builder = { path = "../reth/crates/rpc/rpc-builder" } +reth-optimism-flashblocks = { path = "../reth/crates/optimism/flashblocks" } +reth-optimism-rpc = { path = "../reth/crates/optimism/rpc" } diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 56bc8765..ebdc8f32 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -20,6 +20,7 @@ use crate::{ engine::payload::{ BerachainBuiltPayload, BerachainPayloadAttributes, BerachainPayloadBuilderAttributes, }, + flashblocks::BerachainFlashblockPayload, hardforks::BerachainHardforks, node::evm::error::BerachainExecutionError, primitives::header::BlsPublicKey, @@ -39,6 +40,7 @@ use reth::{ api::{BuiltPayload, EngineTypes, NodePrimitives, PayloadTypes}, core::primitives::SealedBlock, }; +use reth_optimism_flashblocks::FlashBlockCompleteSequence; use reth_payload_primitives::ExecutionPayload as ExecutionPayloadTrait; use std::hash::Hash; @@ -270,6 +272,16 @@ impl From for BerachainExecutionData { } } +impl TryFrom<&FlashBlockCompleteSequence> for BerachainExecutionData { + type Error = &'static str; + + fn try_from( + _sequence: &FlashBlockCompleteSequence, + ) -> Result { + todo!("implement conversion from FlashBlockCompleteSequence to BerachainExecutionData") + } +} + /// Validates that the proposer pubkey is present after Prague1 and absent before Prague1 pub fn validate_proposer_pubkey_prague1( chain_spec: &ChainSpec, diff --git a/src/flashblocks/mod.rs b/src/flashblocks/mod.rs new file mode 100644 index 00000000..a2b31bc5 --- /dev/null +++ b/src/flashblocks/mod.rs @@ -0,0 +1,153 @@ +use crate::{primitives::header::BlsPublicKey, transaction::BerachainTxEnvelope}; +use alloy_consensus::{crypto::RecoveryError, transaction::Recovered}; +use alloy_eips::{ + eip2718::WithEncoded, + eip4895::{Withdrawal, Withdrawals}, +}; +use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; +use reth::rpc::types::engine::PayloadId; +use reth_optimism_flashblocks::{FlashblockDiff, FlashblockPayload, FlashblockPayloadBase}; + +#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct BerachainFlashblockPayloadBase { + /// Parent beacon block root. + pub parent_beacon_block_root: B256, + /// Hash of the parent block. + pub parent_hash: B256, + /// Address that receives fees for this block. + pub fee_recipient: Address, + /// The previous randao value. + pub prev_randao: B256, + /// Block number. + #[serde(with = "alloy_serde::quantity")] + pub block_number: u64, + /// Gas limit for this block. + #[serde(with = "alloy_serde::quantity")] + pub gas_limit: u64, + /// Block timestamp. + #[serde(with = "alloy_serde::quantity")] + pub timestamp: u64, + /// Extra data for the block. + pub extra_data: Bytes, + /// Base fee per gas for this block. + pub base_fee_per_gas: U256, + /// Berachain specific BlsPublicKey + pub prev_proposer_pubkey: Option, +} + +impl FlashblockPayloadBase for BerachainFlashblockPayloadBase { + fn parent_hash(&self) -> B256 { + self.parent_hash + } + + fn block_number(&self) -> u64 { + self.block_number + } + + fn timestamp(&self) -> u64 { + self.timestamp + } +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct BerachainFlashblockPayloadDiff { + /// The state root of the block. + pub state_root: B256, + /// The receipts root of the block. + pub receipts_root: B256, + /// The logs bloom of the block. + pub logs_bloom: Bloom, + /// The gas used of the block. + #[serde(with = "alloy_serde::quantity")] + pub gas_used: u64, + /// The block hash of the block. + pub block_hash: B256, + /// The transactions of the block. + pub transactions: Vec, + /// Array of [`Withdrawal`] enabled with V2 + pub withdrawals: Vec, + /// The withdrawals root of the block. + pub withdrawals_root: B256, + /// The estimated cumulative blob gas used for the block. Introduced in Jovian. + /// spec: + /// Defaults to 0 if not present (for pre-Jovian blocks). + #[serde(default, skip_serializing_if = "Option::is_none", with = "alloy_serde::quantity::opt")] + pub blob_gas_used: Option, +} + +impl FlashblockDiff for BerachainFlashblockPayloadDiff { + fn block_hash(&self) -> B256 { + self.block_hash + } + + fn state_root(&self) -> B256 { + self.state_root + } + + fn gas_used(&self) -> u64 { + self.gas_used + } + + fn logs_bloom(&self) -> &Bloom { + &self.logs_bloom + } + + fn receipts_root(&self) -> B256 { + self.receipts_root + } + + fn transactions_raw(&self) -> &[Bytes] { + &self.transactions + } + + fn withdrawals(&self) -> Option<&Withdrawals> { + None + } + + fn withdrawals_root(&self) -> Option { + None + } +} + +// Note: this uses mixed camel, snake case: + +#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct BerachainFlashblockPayload { + pub payload_id: PayloadId, + pub index: u64, + pub base: Option, + pub diff: BerachainFlashblockPayloadDiff, + // pub metadata: OpFlashblockPayloadMetadata, +} + +impl FlashblockPayload for BerachainFlashblockPayload { + type Base = BerachainFlashblockPayloadBase; + type Diff = BerachainFlashblockPayloadDiff; + type SignedTx = BerachainTxEnvelope; + + fn index(&self) -> u64 { + self.index + } + + fn payload_id(&self) -> PayloadId { + self.payload_id + } + + fn base(&self) -> Option { + self.base.clone() + } + + fn diff(&self) -> &Self::Diff { + &self.diff + } + + fn block_number(&self) -> u64 { + self.base.as_ref().map(|b| b.block_number()).unwrap_or(0) + } + + fn recover_transactions( + &self, + ) -> impl Iterator>, RecoveryError>> { + std::iter::from_fn(|| todo!("implement transaction recovery")) + } +} diff --git a/src/lib.rs b/src/lib.rs index 30b4118d..59e85b89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ pub mod chainspec; pub mod consensus; pub mod engine; pub mod evm; +pub mod flashblocks; pub mod genesis; pub mod hardforks; pub mod node; diff --git a/src/node/evm/config.rs b/src/node/evm/config.rs index f611cffe..e8be66d3 100644 --- a/src/node/evm/config.rs +++ b/src/node/evm/config.rs @@ -2,6 +2,7 @@ use crate::{ chainspec::BerachainChainSpec, engine::BerachainExecutionData, evm::BerachainEvmFactory, + flashblocks::BerachainFlashblockPayloadBase, node::evm::{ assembler::BerachainBlockAssembler, block_context::BerachainBlockExecutionCtx, builder::BerachainBlockBuilder, receipt::BerachainReceiptBuilder, @@ -358,3 +359,18 @@ impl ConfigureEngineEvm for BerachainEvmConfig { })) } } + +impl From for BerachainNextBlockEnvAttributes { + fn from(value: BerachainFlashblockPayloadBase) -> Self { + Self { + timestamp: value.timestamp, + suggested_fee_recipient: value.fee_recipient, + prev_randao: value.prev_randao, + gas_limit: value.gas_limit, + parent_beacon_block_root: Some(value.parent_beacon_block_root), + withdrawals: None, /* TODO: Add to BerachainFlashblockPayloadBase. Removed as using + * OP fields for starting parity tests */ + prev_proposer_pubkey: value.prev_proposer_pubkey, + } + } +} diff --git a/src/rpc/api.rs b/src/rpc/api.rs index 842bd958..0a1ef28e 100644 --- a/src/rpc/api.rs +++ b/src/rpc/api.rs @@ -1,9 +1,10 @@ use crate::{ + flashblocks::BerachainFlashblockPayload, primitives::BerachainHeader, rpc::receipt::BerachainReceiptEnvelope, transaction::{BerachainTxEnvelope, BerachainTxType, POL_TX_TYPE}, }; -use alloy_consensus::Transaction; +use alloy_consensus::{BlockHeader, Transaction}; use alloy_eips::eip2930::AccessList; use alloy_network::{ BuildResult, Network, NetworkWallet, TransactionBuilder, TransactionBuilderError, @@ -13,16 +14,17 @@ use alloy_rpc_types_eth::{Transaction as RpcTransaction, TransactionRequest}; use core::fmt; use derive_more::Deref; use reth::{ - providers::ProviderHeader, + providers::{BlockReaderIdExt, ProviderHeader}, rpc::compat::RpcConvert, tasks::{ TaskSpawner, pool::{BlockingTaskGuard, BlockingTaskPool}, }, }; +use reth_optimism_flashblocks::{FlashBlockBuildInfo, FlashblocksListeners, PendingFlashBlock}; use reth_primitives_traits::{Recovered, WithEncoded}; use reth_rpc_eth_api::{ - EthApiTypes, RpcNodeCore, RpcNodeCoreExt, + EthApiTypes, RpcNodeCore, RpcNodeCoreExt, RpcReceipt, helpers::{ Call, EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, LoadBlock, LoadFee, LoadPendingBlock, LoadReceipt, LoadState, LoadTransaction, SpawnBlocking, Trace, @@ -34,6 +36,8 @@ use reth_rpc_eth_types::{ builder::config::PendingBlockKind, error::FromEvmError, }; use reth_transaction_pool::PoolPooledTx; +use std::{sync::Arc, time::Duration}; +use tokio::time; impl fmt::Display for BerachainTxType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -327,6 +331,75 @@ pub struct BerachainApi { /// All nested fields bundled together. #[deref] pub(super) inner: reth_rpc::EthApi, + + /// Flashblocks listeners. + /// + /// If set, provides receivers for pending blocks, flashblock sequences, and build status. + pub flashblocks: Arc>>, +} + +/// Maximum duration to wait for a fresh flashblock when one is being built. +const MAX_FLASHBLOCK_WAIT_DURATION: Duration = Duration::from_millis(50); + +impl BerachainApi { + /// Returns information about the flashblock currently being built, if any. + fn flashblock_build_info(&self) -> Option { + self.flashblocks.as_ref().as_ref().and_then(|f| *f.in_progress_rx.borrow()) + } + + /// Extracts pending block if it matches the expected parent hash. + fn extract_matching_block( + &self, + block: Option<&PendingFlashBlock>, + parent_hash: B256, + ) -> Option> { + block.filter(|b| b.block().parent_hash() == parent_hash).map(|b| b.pending.clone()) + } + + /// Returns a [`PendingBlock`] that is built out of flashblocks. + /// + /// If flashblocks receiver is not set, then it always returns `None`. + /// + /// It may wait up to 50ms for a fresh flashblock if one is currently being built. + pub async fn pending_flashblock(&self) -> eyre::Result>> + where + // OpEthApiError: FromEvmError, + Rpc: RpcConvert, + { + let Some(latest) = self.provider().latest_header()? else { + return Ok(None); + }; + + self.flashblock(latest.hash()).await + } + + /// Awaits a fresh flashblock if one is being built, otherwise returns current. + async fn flashblock( + &self, + parent_hash: B256, + ) -> eyre::Result>> { + let Some(rx) = self.flashblocks.as_ref().as_ref().map(|f| &f.pending_block_rx) else { + return Ok(None) + }; + + // Check if a flashblock is being built + if let Some(build_info) = self.flashblock_build_info() { + let current_index = rx.borrow().as_ref().map(|b| b.last_flashblock_index); + + // Check if this is the first flashblock or the next consecutive index + let is_next_index = current_index.is_none_or(|idx| build_info.index == idx + 1); + + // Wait only for relevant flashblocks: matching parent and next in sequence + if build_info.parent_hash == parent_hash && is_next_index { + let mut rx_clone = rx.clone(); + // Wait up to MAX_FLASHBLOCK_WAIT_DURATION for a new flashblock to arrive + let _ = time::timeout(MAX_FLASHBLOCK_WAIT_DURATION, rx_clone.changed()).await; + } + } + + // Fall back to current block + Ok(self.extract_matching_block(rx.borrow().as_ref(), parent_hash)) + } } impl Clone for BerachainApi @@ -335,7 +408,7 @@ where Rpc: RpcConvert, { fn clone(&self) -> Self { - Self { inner: self.inner.clone() } + Self { inner: self.inner.clone(), flashblocks: self.flashblocks.clone() } } } @@ -445,6 +518,34 @@ where ) -> Result { EthTransactions::send_transaction(&self.inner, tx).await } + + /// Returns the transaction receipt for the given hash. + /// + /// With flashblocks, we should also lookup the pending block for the transaction + /// because this is considered confirmed/mined. + fn transaction_receipt( + &self, + hash: B256, + ) -> impl Future>, Self::Error>> + Send + { + let this = self.clone(); + async move { + // first attempt to fetch the mined transaction receipt data + let tx_receipt = this.load_transaction_and_receipt(hash).await?; + + if tx_receipt.is_none() { + // if flashblocks are supported, attempt to find id from the pending block + if let Ok(Some(pending_block)) = this.pending_flashblock().await && + let Some(Ok(receipt)) = pending_block + .find_and_convert_transaction_receipt(hash, this.converter()) + { + return Ok(Some(receipt)); + } + } + let Some((tx, meta, receipt)) = tx_receipt else { return Ok(None) }; + self.build_transaction_receipt(tx, meta, receipt).await.map(Some) + } + } } impl LoadTransaction for BerachainApi diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index f9b582ab..09170720 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -1,4 +1,6 @@ +use jsonrpsee::client_transport::ws::Url; use reth_rpc_eth_api::helpers::config::EthConfigApiServer; +use std::sync::Arc; pub mod api; pub mod config; pub mod receipt; @@ -9,6 +11,7 @@ use crate::{ BerachainExecutionData, rpc::BerachainEngineApiBuilder, validator::BerachainEngineValidatorBuilder, }, + flashblocks::{BerachainFlashblockPayload, BerachainFlashblockPayloadBase}, node::evm::config::{BerachainEvmConfig, BerachainNextBlockEnvAttributes}, primitives::BerachainPrimitives, rpc::{ @@ -35,12 +38,28 @@ use reth_node_builder::rpc::{ EthApiBuilder, EthApiCtx, PayloadValidatorBuilder, RethRpcAddOns, RethRpcMiddleware, RpcAddOns, RpcHandle, }; +use reth_optimism_flashblocks::{ + FlashBlockCompleteSequence, FlashBlockService, FlashblocksListeners, WsFlashBlockStream, +}; +use reth_optimism_rpc::OpRpcTypes; use reth_rpc_convert::{RpcConvert, RpcConverter}; use reth_rpc_eth_api::helpers::pending_block::BuildPendingEnv; +use tokio::sync::watch; +use tracing::info; /// Builds `BerachainEthApi` for Berachain. -#[derive(Debug, Default)] -pub struct BerachainEthApiBuilder; +#[derive(Debug)] +pub struct BerachainEthApiBuilder { + /// A URL pointing to a secure websocket connection (wss) that streams out flashblocks. + flashblocks_url: Option, +} + +impl Default for BerachainEthApiBuilder { + fn default() -> Self { + // TODO: hardcode value here + Self { flashblocks_url: None } + } +} pub type BerachainEthRpcConverterFor = RpcConverter< BerachainNetwork, @@ -48,14 +67,28 @@ pub type BerachainEthRpcConverterFor = RpcConverter< BerachainEthReceiptConverter<<::Provider as ChainSpecProvider>::ChainSpec>, >; +impl OpRpcTypes for BerachainNetwork { + type Flashblock = BerachainFlashblockPayload; +} + impl EthApiBuilder for BerachainEthApiBuilder where N: FullNodeComponents< Types: NodeTypes< ChainSpec: EthereumHardforks + Hardforks, Primitives = BerachainPrimitives, + Payload: reth_node_api::PayloadTypes< + ExecutionData: for<'a> TryFrom< + &'a FlashBlockCompleteSequence, + Error: std::fmt::Display, + >, + >, + >, + Evm: ConfigureEvm< + NextBlockEnvCtx: BuildPendingEnv> + + From + + Unpin, >, - Evm: ConfigureEvm>>, >, BerachainEthRpcConverterFor: RpcConvert< Primitives = PrimitivesTy, @@ -72,9 +105,38 @@ where BerachainEthReceiptConverter::new(ctx.components.provider().clone().chain_spec()), ); + let flashblocks = if let Some(ws_url) = self.flashblocks_url { + info!(target: "bera-reth:rpc", %ws_url, "Launching flashblocks service"); + + let (tx, pending_rx) = watch::channel(None); + let stream: WsFlashBlockStream<_, _, _, BerachainFlashblockPayload> = + WsFlashBlockStream::new(ws_url); + let service = FlashBlockService::new( + stream, + ctx.components.evm_config().clone(), + ctx.components.provider().clone(), + ctx.components.task_executor().clone(), + false, + ); + + let flashblocks_sequence = service.block_sequence_broadcaster().clone(); + let received_flashblocks = service.flashblocks_broadcaster().clone(); + let in_progress_rx = service.subscribe_in_progress(); + ctx.components.task_executor().spawn(Box::pin(service.run(tx))); + + Some(FlashblocksListeners::new( + pending_rx, + flashblocks_sequence, + in_progress_rx, + received_flashblocks, + )) + } else { + None + }; + let inner = ctx.eth_api_builder().with_rpc_converter(tx_resp_builder.clone()).build(); - Ok(BerachainApi { inner }) + Ok(BerachainApi { inner, flashblocks: Arc::new(flashblocks) }) } } @@ -99,7 +161,7 @@ where fn default() -> Self { Self { inner: RpcAddOns::new( - BerachainEthApiBuilder, + BerachainEthApiBuilder::default(), BerachainEngineValidatorBuilder::default(), BerachainEngineApiBuilder::::default(), BasicEngineValidatorBuilder::new(BerachainEngineValidatorBuilder::default()), diff --git a/tests/e2e/flashblocks.rs b/tests/e2e/flashblocks.rs new file mode 100644 index 00000000..c5e54d28 --- /dev/null +++ b/tests/e2e/flashblocks.rs @@ -0,0 +1,18 @@ +use bera_reth::flashblocks::BerachainFlashblockPayload; +use futures_util::stream::StreamExt; +use reth_optimism_flashblocks::WsFlashBlockStream; + +#[tokio::test] +async fn test_streaming_flashblocks_from_remote_source_is_successful() { + let items = 3; + let ws_url = "wss://sepolia.flashblocks.base.org/ws".parse().unwrap(); + let stream: WsFlashBlockStream<_, _, _, BerachainFlashblockPayload> = + WsFlashBlockStream::new(ws_url); + + let blocks: Vec<_> = stream.take(items).collect().await; + + for block in blocks { + println!("{:?}", block); + assert!(block.is_ok()); + } +} diff --git a/tests/e2e/mod.rs b/tests/e2e/mod.rs index 503dd071..31348eb1 100644 --- a/tests/e2e/mod.rs +++ b/tests/e2e/mod.rs @@ -18,6 +18,7 @@ use reth_payload_primitives::PayloadBuilderAttributes; use std::{str::FromStr, sync::Arc}; pub mod coinbase_system_state_change_test; +pub mod flashblocks; pub mod gas_limit_regression_test; pub mod pol_revert_test; pub mod transaction_tests; From f1786e57c19ed1de68ecd474ff43b670634c6f98 Mon Sep 17 00:00:00 2001 From: Rez Date: Mon, 22 Dec 2025 17:39:03 +1100 Subject: [PATCH 02/12] testing progress --- src/flashblocks/mod.rs | 346 ++++++++++++++++++++++++- src/flashblocks/test_utils.rs | 298 ++++++++++++++++++++++ tests/e2e/flashblocks.rs | 463 +++++++++++++++++++++++++++++++++- 3 files changed, 1103 insertions(+), 4 deletions(-) create mode 100644 src/flashblocks/test_utils.rs diff --git a/src/flashblocks/mod.rs b/src/flashblocks/mod.rs index a2b31bc5..1ef2e45d 100644 --- a/src/flashblocks/mod.rs +++ b/src/flashblocks/mod.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +pub mod test_utils; + use crate::{primitives::header::BlsPublicKey, transaction::BerachainTxEnvelope}; use alloy_consensus::{crypto::RecoveryError, transaction::Recovered}; use alloy_eips::{ @@ -109,7 +112,10 @@ impl FlashblockDiff for BerachainFlashblockPayloadDiff { } } -// Note: this uses mixed camel, snake case: +#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct BerachainFlashblockPayloadMetadata { + pub block_number: u64, +} #[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct BerachainFlashblockPayload { @@ -117,7 +123,13 @@ pub struct BerachainFlashblockPayload { pub index: u64, pub base: Option, pub diff: BerachainFlashblockPayloadDiff, - // pub metadata: OpFlashblockPayloadMetadata, + pub metadata: BerachainFlashblockPayloadMetadata, +} + +impl BerachainFlashblockPayload { + pub const fn block_number(&self) -> u64 { + self.metadata.block_number + } } impl FlashblockPayload for BerachainFlashblockPayload { @@ -142,7 +154,7 @@ impl FlashblockPayload for BerachainFlashblockPayload { } fn block_number(&self) -> u64 { - self.base.as_ref().map(|b| b.block_number()).unwrap_or(0) + Self::block_number(self) } fn recover_transactions( @@ -151,3 +163,331 @@ impl FlashblockPayload for BerachainFlashblockPayload { std::iter::from_fn(|| todo!("implement transaction recovery")) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::flashblocks::test_utils::BerachainTestFlashBlockFactory; + use reth_optimism_flashblocks::{FlashBlockCompleteSequence, FlashBlockPendingSequence}; + + mod serde_tests { + use super::*; + + #[test] + fn test_flashblock_payload_serde_roundtrip() { + let factory = BerachainTestFlashBlockFactory::new(); + let fb = + factory.flashblock_at(0).transactions(vec![Bytes::from_static(&[1, 2, 3])]).build(); + + let serialized = serde_json::to_string(&fb).expect("serialize"); + let deserialized: BerachainFlashblockPayload = + serde_json::from_str(&serialized).expect("deserialize"); + + assert_eq!(fb, deserialized); + } + + #[test] + fn test_flashblock_payload_base_serde_roundtrip() { + let base = BerachainFlashblockPayloadBase { + parent_beacon_block_root: B256::random(), + parent_hash: B256::random(), + fee_recipient: Address::random(), + prev_randao: B256::random(), + block_number: 100, + gas_limit: 30_000_000, + timestamp: 1_000_000, + extra_data: Bytes::from_static(&[0x42]), + base_fee_per_gas: U256::from(1_000_000_000u64), + prev_proposer_pubkey: Some(BlsPublicKey::random()), + }; + + let serialized = serde_json::to_string(&base).expect("serialize"); + let deserialized: BerachainFlashblockPayloadBase = + serde_json::from_str(&serialized).expect("deserialize"); + + assert_eq!(base, deserialized); + } + + #[test] + fn test_flashblock_payload_diff_serde_roundtrip() { + let diff = BerachainFlashblockPayloadDiff { + state_root: B256::random(), + receipts_root: B256::random(), + logs_bloom: Bloom::default(), + gas_used: 21000, + block_hash: B256::random(), + transactions: vec![Bytes::from_static(&[1, 2, 3])], + withdrawals: vec![], + withdrawals_root: B256::ZERO, + blob_gas_used: Some(131072), + }; + + let serialized = serde_json::to_string(&diff).expect("serialize"); + let deserialized: BerachainFlashblockPayloadDiff = + serde_json::from_str(&serialized).expect("deserialize"); + + assert_eq!(diff, deserialized); + } + + #[test] + fn test_flashblock_sequence_serde_roundtrip() { + let factory = BerachainTestFlashBlockFactory::new(); + let fb0 = factory.flashblock_at(0).build(); + let fb1 = factory.flashblock_after(&fb0).build(); + + let fbs = vec![fb0, fb1]; + let serialized = serde_json::to_string(&fbs).expect("serialize"); + let deserialized: Vec = + serde_json::from_str(&serialized).expect("deserialize"); + + assert_eq!(fbs.len(), deserialized.len()); + assert_eq!(fbs[0], deserialized[0]); + assert_eq!(fbs[1], deserialized[1]); + } + } + + mod pending_sequence_tests { + use super::*; + + #[test] + fn test_insert_index_zero_creates_new_sequence() { + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + let factory = BerachainTestFlashBlockFactory::new(); + let fb0 = factory.flashblock_at(0).build(); + let payload_id = fb0.payload_id; + + sequence.insert(fb0); + + assert_eq!(sequence.count(), 1); + assert_eq!(sequence.block_number(), Some(100)); + assert_eq!(sequence.payload_id(), Some(payload_id)); + } + + #[test] + fn test_insert_followup_same_block_and_payload() { + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + let factory = BerachainTestFlashBlockFactory::new(); + + let fb0 = factory.flashblock_at(0).build(); + sequence.insert(fb0.clone()); + + let fb1 = factory.flashblock_after(&fb0).build(); + sequence.insert(fb1.clone()); + + let fb2 = factory.flashblock_after(&fb1).build(); + sequence.insert(fb2); + + assert_eq!(sequence.count(), 3); + assert_eq!(sequence.index(), Some(2)); + } + + #[test] + fn test_insert_ignores_different_block_number() { + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + let factory = BerachainTestFlashBlockFactory::new(); + + let fb0 = factory.flashblock_at(0).build(); + sequence.insert(fb0.clone()); + + let fb1 = factory.flashblock_after(&fb0).block_number(101).build(); + sequence.insert(fb1); + + assert_eq!(sequence.count(), 1); + assert_eq!(sequence.block_number(), Some(100)); + } + + #[test] + fn test_insert_ignores_different_payload_id() { + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + let factory = BerachainTestFlashBlockFactory::new(); + + let fb0 = factory.flashblock_at(0).build(); + let payload_id1 = fb0.payload_id; + sequence.insert(fb0.clone()); + + let payload_id2 = PayloadId::new([2u8; 8]); + let fb1 = factory.flashblock_after(&fb0).payload_id(payload_id2).build(); + sequence.insert(fb1); + + assert_eq!(sequence.count(), 1); + assert_eq!(sequence.payload_id(), Some(payload_id1)); + } + + #[test] + fn test_finalize_empty_sequence_fails() { + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + let result = sequence.finalize(); + + assert!(result.is_err()); + } + + #[test] + fn test_finalize_clears_pending_state() { + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + let factory = BerachainTestFlashBlockFactory::new(); + + let fb0 = factory.flashblock_at(0).build(); + sequence.insert(fb0); + + assert_eq!(sequence.count(), 1); + + let _complete = sequence.finalize().unwrap(); + + assert_eq!(sequence.count(), 0); + assert_eq!(sequence.block_number(), None); + } + } + + mod complete_sequence_tests { + use super::*; + + #[test] + fn test_new_empty_sequence_fails() { + let result = + FlashBlockCompleteSequence::::new(vec![], None); + assert!(result.is_err()); + } + + #[test] + fn test_new_requires_base_at_index_zero() { + let factory = BerachainTestFlashBlockFactory::new(); + let mut fb0_no_base = factory.flashblock_at(1).build(); + fb0_no_base.index = 0; + fb0_no_base.base = None; + + let result = FlashBlockCompleteSequence::new(vec![fb0_no_base], None); + assert!(result.is_err()); + } + + #[test] + fn test_new_validates_successive_indices() { + let factory = BerachainTestFlashBlockFactory::new(); + + let fb0 = factory.flashblock_at(0).build(); + let fb2 = factory.flashblock_after(&fb0).index(2).build(); + + let result = FlashBlockCompleteSequence::new(vec![fb0, fb2], None); + assert!(result.is_err()); + } + + #[test] + fn test_new_valid_single_flashblock() { + let factory = BerachainTestFlashBlockFactory::new(); + let fb0 = factory.flashblock_at(0).build(); + + let result = FlashBlockCompleteSequence::new(vec![fb0], None); + assert!(result.is_ok()); + + let complete = result.unwrap(); + assert_eq!(complete.count(), 1); + assert_eq!(complete.block_number(), 100); + } + + #[test] + fn test_new_valid_multiple_flashblocks() { + let factory = BerachainTestFlashBlockFactory::new(); + + let fb0 = factory.flashblock_at(0).build(); + let fb1 = factory.flashblock_after(&fb0).build(); + let fb2 = factory.flashblock_after(&fb1).build(); + + let result = FlashBlockCompleteSequence::new(vec![fb0, fb1, fb2], None); + assert!(result.is_ok()); + + let complete = result.unwrap(); + assert_eq!(complete.count(), 3); + assert_eq!(complete.last().index(), 2); + } + + #[test] + fn test_all_transactions_aggregates_correctly() { + let factory = BerachainTestFlashBlockFactory::new(); + + let fb0 = factory + .flashblock_at(0) + .transactions(vec![Bytes::from_static(&[1, 2, 3]), Bytes::from_static(&[4, 5, 6])]) + .build(); + + let fb1 = factory + .flashblock_after(&fb0) + .transactions(vec![Bytes::from_static(&[7, 8, 9])]) + .build(); + + let complete = FlashBlockCompleteSequence::new(vec![fb0, fb1], None).unwrap(); + let all_txs = complete.all_transactions(); + + assert_eq!(all_txs.len(), 3); + assert_eq!(all_txs[0], Bytes::from_static(&[1, 2, 3])); + assert_eq!(all_txs[1], Bytes::from_static(&[4, 5, 6])); + assert_eq!(all_txs[2], Bytes::from_static(&[7, 8, 9])); + } + + #[test] + fn test_berachain_specific_payload_base_preserved() { + let factory = BerachainTestFlashBlockFactory::new(); + let pubkey = BlsPublicKey::random(); + + let fb0 = factory.flashblock_at(0).prev_proposer_pubkey(Some(pubkey)).build(); + + let complete = FlashBlockCompleteSequence::new(vec![fb0], None).unwrap(); + let base = complete.payload_base(); + + assert_eq!(base.prev_proposer_pubkey, Some(pubkey)); + } + } + + mod sequence_conversion_tests { + use super::*; + + #[test] + fn test_try_from_pending_to_complete_valid() { + let mut pending: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + let factory = BerachainTestFlashBlockFactory::new(); + + let fb0 = factory.flashblock_at(0).build(); + pending.insert(fb0); + + let complete: Result, _> = + pending.try_into(); + assert!(complete.is_ok()); + assert_eq!(complete.unwrap().count(), 1); + } + + #[test] + fn test_try_from_pending_to_complete_empty_fails() { + let pending: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + + let complete: Result, _> = + pending.try_into(); + assert!(complete.is_err()); + } + + #[test] + fn test_finalize_multiple_times_after_refill() { + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + let factory = BerachainTestFlashBlockFactory::new(); + + let fb0 = factory.flashblock_at(0).build(); + sequence.insert(fb0); + + let complete1 = sequence.finalize().unwrap(); + assert_eq!(complete1.count(), 1); + + let fb1 = factory.flashblock_for_next_block(&complete1.last().clone()).build(); + sequence.insert(fb1); + + let complete2 = sequence.finalize().unwrap(); + assert_eq!(complete2.count(), 1); + assert_eq!(complete2.block_number(), 101); + } + } +} diff --git a/src/flashblocks/test_utils.rs b/src/flashblocks/test_utils.rs new file mode 100644 index 00000000..fd01091d --- /dev/null +++ b/src/flashblocks/test_utils.rs @@ -0,0 +1,298 @@ +use crate::{ + flashblocks::{ + BerachainFlashblockPayload, BerachainFlashblockPayloadBase, BerachainFlashblockPayloadDiff, + BerachainFlashblockPayloadMetadata, + }, + primitives::header::BlsPublicKey, +}; +use alloy_eips::eip4895::Withdrawal; +use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; +use reth::rpc::types::engine::PayloadId; + +#[derive(Debug)] +pub struct BerachainTestFlashBlockFactory { + block_time: u64, + base_timestamp: u64, + current_block_number: u64, +} + +impl BerachainTestFlashBlockFactory { + pub fn new() -> Self { + Self { block_time: 2, base_timestamp: 1_000_000, current_block_number: 100 } + } + + pub fn with_block_time(mut self, block_time: u64) -> Self { + self.block_time = block_time; + self + } + + pub fn with_base_timestamp(mut self, timestamp: u64) -> Self { + self.base_timestamp = timestamp; + self + } + + pub fn with_block_number(mut self, block_number: u64) -> Self { + self.current_block_number = block_number; + self + } + + pub fn flashblock_at(&self, index: u64) -> BerachainTestFlashBlockBuilder { + self.builder().index(index).block_number(self.current_block_number) + } + + pub fn flashblock_after( + &self, + previous: &BerachainFlashblockPayload, + ) -> BerachainTestFlashBlockBuilder { + let parent_hash = + previous.base.as_ref().map(|b| b.parent_hash).unwrap_or(previous.diff.block_hash); + + self.builder() + .index(previous.index + 1) + .block_number(previous.metadata.block_number) + .payload_id(previous.payload_id) + .parent_hash(parent_hash) + .timestamp(previous.base.as_ref().map(|b| b.timestamp).unwrap_or(self.base_timestamp)) + } + + pub fn flashblock_for_next_block( + &self, + previous: &BerachainFlashblockPayload, + ) -> BerachainTestFlashBlockBuilder { + let prev_timestamp = + previous.base.as_ref().map(|b| b.timestamp).unwrap_or(self.base_timestamp); + let prev_block_number = previous.metadata.block_number; + + self.builder() + .index(0) + .block_number(prev_block_number + 1) + .payload_id(PayloadId::new(B256::random().0[0..8].try_into().unwrap())) + .parent_hash(previous.diff.block_hash) + .timestamp(prev_timestamp + self.block_time) + } + + pub fn builder(&self) -> BerachainTestFlashBlockBuilder { + BerachainTestFlashBlockBuilder { + index: 0, + block_number: self.current_block_number, + payload_id: PayloadId::new([1u8; 8]), + parent_hash: B256::random(), + timestamp: self.base_timestamp, + base: None, + block_hash: B256::random(), + state_root: B256::ZERO, + receipts_root: B256::ZERO, + logs_bloom: Bloom::default(), + gas_used: 0, + gas_limit: 30_000_000, + transactions: vec![], + withdrawals: vec![], + withdrawals_root: B256::ZERO, + blob_gas_used: None, + prev_proposer_pubkey: Some(BlsPublicKey::random()), + } + } +} + +impl Default for BerachainTestFlashBlockFactory { + fn default() -> Self { + Self::new() + } +} + +#[derive(Debug)] +pub struct BerachainTestFlashBlockBuilder { + index: u64, + block_number: u64, + payload_id: PayloadId, + parent_hash: B256, + timestamp: u64, + base: Option, + block_hash: B256, + state_root: B256, + receipts_root: B256, + logs_bloom: Bloom, + gas_used: u64, + gas_limit: u64, + transactions: Vec, + withdrawals: Vec, + withdrawals_root: B256, + blob_gas_used: Option, + prev_proposer_pubkey: Option, +} + +impl BerachainTestFlashBlockBuilder { + pub fn index(mut self, index: u64) -> Self { + self.index = index; + self + } + + pub fn block_number(mut self, block_number: u64) -> Self { + self.block_number = block_number; + self + } + + pub fn payload_id(mut self, payload_id: PayloadId) -> Self { + self.payload_id = payload_id; + self + } + + pub fn parent_hash(mut self, parent_hash: B256) -> Self { + self.parent_hash = parent_hash; + self + } + + pub fn timestamp(mut self, timestamp: u64) -> Self { + self.timestamp = timestamp; + self + } + + #[allow(dead_code)] + pub fn base(mut self, base: BerachainFlashblockPayloadBase) -> Self { + self.base = Some(base); + self + } + + #[allow(dead_code)] + pub fn block_hash(mut self, block_hash: B256) -> Self { + self.block_hash = block_hash; + self + } + + #[allow(dead_code)] + pub fn state_root(mut self, state_root: B256) -> Self { + self.state_root = state_root; + self + } + + #[allow(dead_code)] + pub fn receipts_root(mut self, receipts_root: B256) -> Self { + self.receipts_root = receipts_root; + self + } + + pub fn transactions(mut self, transactions: Vec) -> Self { + self.transactions = transactions; + self + } + + #[allow(dead_code)] + pub fn gas_used(mut self, gas_used: u64) -> Self { + self.gas_used = gas_used; + self + } + + #[allow(dead_code)] + pub fn gas_limit(mut self, gas_limit: u64) -> Self { + self.gas_limit = gas_limit; + self + } + + pub fn prev_proposer_pubkey(mut self, pubkey: Option) -> Self { + self.prev_proposer_pubkey = pubkey; + self + } + + pub fn build(mut self) -> BerachainFlashblockPayload { + if self.index == 0 && self.base.is_none() { + self.base = Some(BerachainFlashblockPayloadBase { + parent_hash: self.parent_hash, + parent_beacon_block_root: B256::random(), + fee_recipient: Address::default(), + prev_randao: B256::random(), + block_number: self.block_number, + gas_limit: self.gas_limit, + timestamp: self.timestamp, + extra_data: Default::default(), + base_fee_per_gas: U256::from(1_000_000_000u64), + prev_proposer_pubkey: self.prev_proposer_pubkey, + }); + } + + BerachainFlashblockPayload { + index: self.index, + payload_id: self.payload_id, + base: self.base, + diff: BerachainFlashblockPayloadDiff { + block_hash: self.block_hash, + state_root: self.state_root, + receipts_root: self.receipts_root, + logs_bloom: self.logs_bloom, + gas_used: self.gas_used, + transactions: self.transactions, + withdrawals: self.withdrawals, + withdrawals_root: self.withdrawals_root, + blob_gas_used: self.blob_gas_used, + }, + metadata: BerachainFlashblockPayloadMetadata { block_number: self.block_number }, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use reth_optimism_flashblocks::{FlashblockDiff, FlashblockPayload, FlashblockPayloadBase}; + + #[test] + fn test_factory_creates_valid_flashblock_at_index_0() { + let factory = BerachainTestFlashBlockFactory::new(); + let fb = factory.flashblock_at(0).build(); + + assert_eq!(fb.index, 0); + assert!(fb.base.is_some()); + assert_eq!(fb.base.as_ref().unwrap().block_number, 100); + } + + #[test] + fn test_factory_creates_followup_flashblock() { + let factory = BerachainTestFlashBlockFactory::new(); + let fb0 = factory.flashblock_at(0).build(); + let fb1 = factory.flashblock_after(&fb0).build(); + + assert_eq!(fb1.index, 1); + assert!(fb1.base.is_none()); + assert_eq!(fb1.payload_id, fb0.payload_id); + } + + #[test] + fn test_factory_creates_next_block_flashblock() { + let factory = BerachainTestFlashBlockFactory::new(); + let fb0 = factory.flashblock_at(0).build(); + let fb_next = factory.flashblock_for_next_block(&fb0).build(); + + assert_eq!(fb_next.index, 0); + assert!(fb_next.base.is_some()); + assert_eq!(fb_next.base.as_ref().unwrap().block_number, 101); + assert_eq!(fb_next.base.as_ref().unwrap().parent_hash, fb0.diff.block_hash); + assert_ne!(fb_next.payload_id, fb0.payload_id); + } + + #[test] + fn test_flashblock_trait_implementations() { + let factory = BerachainTestFlashBlockFactory::new(); + let fb = + factory.flashblock_at(0).transactions(vec![Bytes::from_static(&[1, 2, 3])]).build(); + + assert_eq!(fb.index(), 0); + assert_eq!(fb.block_number(), 100); + assert!(fb.base().is_some()); + + let base = fb.base().unwrap(); + assert_eq!(base.block_number(), 100); + assert_eq!(base.timestamp(), 1_000_000); + + let diff = fb.diff(); + assert_eq!(diff.transactions_raw().len(), 1); + assert_eq!(diff.gas_used(), 0); + } + + #[test] + fn test_berachain_specific_fields() { + let factory = BerachainTestFlashBlockFactory::new(); + let pubkey = BlsPublicKey::random(); + let fb = factory.flashblock_at(0).prev_proposer_pubkey(Some(pubkey)).build(); + + assert_eq!(fb.base.as_ref().unwrap().prev_proposer_pubkey, Some(pubkey)); + } +} diff --git a/tests/e2e/flashblocks.rs b/tests/e2e/flashblocks.rs index c5e54d28..0dfa3eda 100644 --- a/tests/e2e/flashblocks.rs +++ b/tests/e2e/flashblocks.rs @@ -1,8 +1,16 @@ -use bera_reth::flashblocks::BerachainFlashblockPayload; +use bera_reth::{ + flashblocks::{ + BerachainFlashblockPayload, BerachainFlashblockPayloadBase, BerachainFlashblockPayloadDiff, + BerachainFlashblockPayloadMetadata, + }, + node::BerachainNode, + primitives::header::BlsPublicKey, +}; use futures_util::stream::StreamExt; use reth_optimism_flashblocks::WsFlashBlockStream; #[tokio::test] +#[ignore = "requires external network access to Base sepolia"] async fn test_streaming_flashblocks_from_remote_source_is_successful() { let items = 3; let ws_url = "wss://sepolia.flashblocks.base.org/ws".parse().unwrap(); @@ -16,3 +24,456 @@ async fn test_streaming_flashblocks_from_remote_source_is_successful() { assert!(block.is_ok()); } } + +#[cfg(test)] +mod mock_stream_tests { + use super::*; + use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; + use futures_util::stream; + use reth::rpc::types::engine::PayloadId; + use reth_optimism_flashblocks::{ + FlashBlockPendingSequence, FlashblockPayload, FlashblockPayloadBase, + }; + + fn create_test_flashblock( + index: u64, + block_number: u64, + payload_id: PayloadId, + parent_hash: B256, + include_base: bool, + ) -> BerachainFlashblockPayload { + let base = if include_base { + Some(BerachainFlashblockPayloadBase { + parent_beacon_block_root: B256::random(), + parent_hash, + fee_recipient: Address::random(), + prev_randao: B256::random(), + block_number, + gas_limit: 30_000_000, + timestamp: 1_000_000 + block_number * 2, + extra_data: Bytes::default(), + base_fee_per_gas: U256::from(1_000_000_000u64), + prev_proposer_pubkey: Some(BlsPublicKey::random()), + }) + } else { + None + }; + + BerachainFlashblockPayload { + payload_id, + index, + base, + diff: BerachainFlashblockPayloadDiff { + state_root: B256::random(), + receipts_root: B256::random(), + logs_bloom: Bloom::default(), + gas_used: 21000 * (index + 1), + block_hash: B256::random(), + transactions: vec![Bytes::from_static(&[1, 2, 3])], + withdrawals: vec![], + withdrawals_root: B256::ZERO, + blob_gas_used: None, + }, + metadata: BerachainFlashblockPayloadMetadata { block_number }, + } + } + + fn create_flashblock_sequence(count: usize) -> Vec { + let payload_id = PayloadId::new([1u8; 8]); + let parent_hash = B256::random(); + + (0..count as u64) + .map(|i| create_test_flashblock(i, 100, payload_id, parent_hash, i == 0)) + .collect() + } + + #[tokio::test] + async fn test_mock_stream_produces_flashblocks() { + let flashblocks = create_flashblock_sequence(3); + let mut stream = stream::iter(flashblocks.clone().into_iter().map(Ok::<_, eyre::Error>)); + + let mut received = Vec::new(); + while let Some(result) = stream.next().await { + received.push(result.unwrap()); + } + + assert_eq!(received.len(), 3); + assert_eq!(received[0].index(), 0); + assert_eq!(received[1].index(), 1); + assert_eq!(received[2].index(), 2); + + assert!(received[0].base().is_some()); + assert!(received[1].base().is_none()); + assert!(received[2].base().is_none()); + } + + #[tokio::test] + async fn test_pending_sequence_processes_stream() { + let flashblocks = create_flashblock_sequence(5); + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + + for fb in flashblocks { + sequence.insert(fb); + } + + assert_eq!(sequence.count(), 5); + assert_eq!(sequence.block_number(), Some(100)); + assert_eq!(sequence.index(), Some(4)); + } + + #[tokio::test] + async fn test_complete_sequence_from_stream() { + let flashblocks = create_flashblock_sequence(3); + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + + for fb in flashblocks { + sequence.insert(fb); + } + + let complete = sequence.finalize().expect("should finalize"); + + assert_eq!(complete.count(), 3); + assert_eq!(complete.block_number(), 100); + + let all_txs = complete.all_transactions(); + assert_eq!(all_txs.len(), 3); + + let base = complete.payload_base(); + assert!(base.prev_proposer_pubkey.is_some()); + } + + #[tokio::test] + async fn test_stream_handles_new_block_sequence() { + let payload_id1 = PayloadId::new([1u8; 8]); + let payload_id2 = PayloadId::new([2u8; 8]); + let parent_hash1 = B256::random(); + + let fb0_block100 = create_test_flashblock(0, 100, payload_id1, parent_hash1, true); + let fb1_block100 = create_test_flashblock(1, 100, payload_id1, parent_hash1, false); + let block100_hash = fb1_block100.diff.block_hash; + + let fb0_block101 = create_test_flashblock(0, 101, payload_id2, block100_hash, true); + let fb1_block101 = create_test_flashblock(1, 101, payload_id2, block100_hash, false); + + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + + sequence.insert(fb0_block100); + sequence.insert(fb1_block100); + assert_eq!(sequence.count(), 2); + assert_eq!(sequence.block_number(), Some(100)); + + let complete_100 = sequence.finalize().expect("should finalize block 100"); + assert_eq!(complete_100.block_number(), 100); + + sequence.insert(fb0_block101); + sequence.insert(fb1_block101); + assert_eq!(sequence.count(), 2); + assert_eq!(sequence.block_number(), Some(101)); + + let complete_101 = sequence.finalize().expect("should finalize block 101"); + assert_eq!(complete_101.block_number(), 101); + } + + #[tokio::test] + async fn test_stream_rejects_out_of_order_flashblocks() { + let payload_id = PayloadId::new([1u8; 8]); + let parent_hash = B256::random(); + + let fb0 = create_test_flashblock(0, 100, payload_id, parent_hash, true); + let fb2_wrong_payload = + create_test_flashblock(2, 100, PayloadId::new([99u8; 8]), parent_hash, false); + + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + + sequence.insert(fb0); + sequence.insert(fb2_wrong_payload); + + assert_eq!(sequence.count(), 1); + } + + #[tokio::test] + async fn test_berachain_specific_fields_preserved() { + let pubkey = BlsPublicKey::random(); + let parent_hash = B256::random(); + let payload_id = PayloadId::new([1u8; 8]); + + let fb = BerachainFlashblockPayload { + payload_id, + index: 0, + base: Some(BerachainFlashblockPayloadBase { + parent_beacon_block_root: B256::random(), + parent_hash, + fee_recipient: Address::random(), + prev_randao: B256::random(), + block_number: 100, + gas_limit: 30_000_000, + timestamp: 1_000_000, + extra_data: Bytes::default(), + base_fee_per_gas: U256::from(1_000_000_000u64), + prev_proposer_pubkey: Some(pubkey), + }), + diff: BerachainFlashblockPayloadDiff { + state_root: B256::random(), + receipts_root: B256::random(), + logs_bloom: Bloom::default(), + gas_used: 21000, + block_hash: B256::random(), + transactions: vec![], + withdrawals: vec![], + withdrawals_root: B256::ZERO, + blob_gas_used: None, + }, + metadata: BerachainFlashblockPayloadMetadata { block_number: 100 }, + }; + + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + sequence.insert(fb); + + let complete = sequence.finalize().expect("should finalize"); + let base = complete.payload_base(); + + assert_eq!(base.prev_proposer_pubkey, Some(pubkey)); + assert_eq!(base.block_number(), 100); + assert_eq!(base.timestamp(), 1_000_000); + assert_eq!(base.parent_hash(), parent_hash); + } + + #[tokio::test] + async fn test_transaction_aggregation_across_flashblocks() { + let payload_id = PayloadId::new([1u8; 8]); + let parent_hash = B256::random(); + + let mut fb0 = create_test_flashblock(0, 100, payload_id, parent_hash, true); + fb0.diff.transactions = vec![Bytes::from_static(&[0xaa]), Bytes::from_static(&[0xbb])]; + + let mut fb1 = create_test_flashblock(1, 100, payload_id, parent_hash, false); + fb1.diff.transactions = vec![Bytes::from_static(&[0xcc])]; + + let mut fb2 = create_test_flashblock(2, 100, payload_id, parent_hash, false); + fb2.diff.transactions = vec![Bytes::from_static(&[0xdd]), Bytes::from_static(&[0xee])]; + + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + + sequence.insert(fb0); + sequence.insert(fb1); + sequence.insert(fb2); + + let complete = sequence.finalize().expect("should finalize"); + let all_txs = complete.all_transactions(); + + assert_eq!(all_txs.len(), 5); + assert_eq!(all_txs[0], Bytes::from_static(&[0xaa])); + assert_eq!(all_txs[1], Bytes::from_static(&[0xbb])); + assert_eq!(all_txs[2], Bytes::from_static(&[0xcc])); + assert_eq!(all_txs[3], Bytes::from_static(&[0xdd])); + assert_eq!(all_txs[4], Bytes::from_static(&[0xee])); + } +} + +#[cfg(test)] +mod service_integration_tests { + use super::*; + use crate::e2e::{berachain_payload_attributes_generator, setup_test_boilerplate}; + use alloy_consensus::BlockHeader; + use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; + use reth::{providers::BlockReaderIdExt, rpc::types::engine::PayloadId}; + use reth_e2e_test_utils::node::NodeTestContext; + use reth_node_builder::{NodeBuilder, NodeHandle}; + use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; + use reth_optimism_flashblocks::{FlashBlockPendingSequence, FlashblocksListeners}; + use std::sync::Arc; + use tokio::sync::{broadcast, watch}; + + fn create_test_flashblock_for_parent( + index: u64, + block_number: u64, + payload_id: PayloadId, + parent_hash: B256, + timestamp: u64, + ) -> BerachainFlashblockPayload { + let base = if index == 0 { + Some(BerachainFlashblockPayloadBase { + parent_beacon_block_root: B256::random(), + parent_hash, + fee_recipient: Address::random(), + prev_randao: B256::random(), + block_number, + gas_limit: 30_000_000, + timestamp, + extra_data: Bytes::default(), + base_fee_per_gas: U256::from(1_000_000_000u64), + prev_proposer_pubkey: Some(BlsPublicKey::random()), + }) + } else { + None + }; + + BerachainFlashblockPayload { + payload_id, + index, + base, + diff: BerachainFlashblockPayloadDiff { + state_root: B256::random(), + receipts_root: B256::random(), + logs_bloom: Bloom::default(), + gas_used: 21000, + block_hash: B256::random(), + transactions: vec![], + withdrawals: vec![], + withdrawals_root: B256::ZERO, + blob_gas_used: None, + }, + metadata: BerachainFlashblockPayloadMetadata { block_number }, + } + } + + #[tokio::test] + async fn test_flashblock_sequence_builds_with_node_context() -> eyre::Result<()> { + let (tasks, chain_spec) = setup_test_boilerplate().await?; + let executor = tasks.executor(); + + let node_config = NodeConfig::new(chain_spec.clone()) + .with_unused_ports() + .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) + .testing_node(executor.clone()) + .node(BerachainNode::default()) + .launch() + .await?; + + let ctx = NodeTestContext::new(node, berachain_payload_attributes_generator).await?; + + let provider = ctx.rpc.inner.eth_api().provider(); + let latest_header = provider.latest_header()?.expect("should have genesis"); + let latest_hash = latest_header.hash(); + let latest_number = latest_header.number(); + let latest_timestamp = latest_header.timestamp(); + + let payload_id = PayloadId::new([1u8; 8]); + let fb0 = create_test_flashblock_for_parent( + 0, + latest_number + 1, + payload_id, + latest_hash, + latest_timestamp + 2, + ); + let fb1 = create_test_flashblock_for_parent( + 1, + latest_number + 1, + payload_id, + latest_hash, + latest_timestamp + 2, + ); + + let mut sequence: FlashBlockPendingSequence = + FlashBlockPendingSequence::new(); + + sequence.insert(fb0); + sequence.insert(fb1); + + assert_eq!(sequence.count(), 2); + assert_eq!(sequence.block_number(), Some(latest_number + 1)); + + let complete = sequence.finalize()?; + assert_eq!(complete.count(), 2); + + let base = complete.payload_base(); + assert_eq!(base.parent_hash, latest_hash); + assert_eq!(base.block_number, latest_number + 1); + + Ok(()) + } + + #[tokio::test] + async fn test_flashblock_listeners_broadcast() -> eyre::Result<()> { + let (_pending_tx, pending_rx) = watch::channel(None); + let (sequence_tx, _) = broadcast::channel(128); + let (_in_progress_tx, in_progress_rx) = watch::channel(None); + let (received_tx, _) = broadcast::channel(128); + + let listeners: FlashblocksListeners< + bera_reth::primitives::BerachainPrimitives, + BerachainFlashblockPayload, + > = FlashblocksListeners::new( + pending_rx, + sequence_tx.clone(), + in_progress_rx, + received_tx.clone(), + ); + + let _sequence_rx = listeners.flashblocks_sequence.subscribe(); + let mut received_rx = listeners.received_flashblocks.subscribe(); + + let payload_id = PayloadId::new([1u8; 8]); + let parent_hash = B256::random(); + let fb = create_test_flashblock_for_parent(0, 100, payload_id, parent_hash, 1_000_000); + + received_tx.send(Arc::new(fb.clone()))?; + + let received = + tokio::time::timeout(std::time::Duration::from_millis(100), received_rx.recv()) + .await??; + + assert_eq!(received.index, 0); + assert_eq!(received.payload_id, payload_id); + + Ok(()) + } + + #[tokio::test] + async fn test_flashblock_sequence_validates_parent_hash() -> eyre::Result<()> { + let (tasks, chain_spec) = setup_test_boilerplate().await?; + let executor = tasks.executor(); + + let node_config = NodeConfig::new(chain_spec.clone()) + .with_unused_ports() + .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) + .testing_node(executor.clone()) + .node(BerachainNode::default()) + .launch() + .await?; + + let ctx = NodeTestContext::new(node, berachain_payload_attributes_generator).await?; + + let provider = ctx.rpc.inner.eth_api().provider(); + let latest_header = provider.latest_header()?.expect("should have genesis"); + let latest_hash = latest_header.hash(); + let latest_number = latest_header.number(); + let latest_timestamp = latest_header.timestamp(); + + let payload_id = PayloadId::new([1u8; 8]); + let fb_correct_parent = create_test_flashblock_for_parent( + 0, + latest_number + 1, + payload_id, + latest_hash, + latest_timestamp + 2, + ); + + let wrong_parent_hash = B256::random(); + let fb_wrong_parent = create_test_flashblock_for_parent( + 0, + latest_number + 1, + payload_id, + wrong_parent_hash, + latest_timestamp + 2, + ); + + let base_correct = fb_correct_parent.base.as_ref().unwrap(); + assert_eq!(base_correct.parent_hash, latest_hash); + + let base_wrong = fb_wrong_parent.base.as_ref().unwrap(); + assert_ne!(base_wrong.parent_hash, latest_hash); + + Ok(()) + } +} From a9c85c51287c89bee2f1e96782e7c6abf5b27137 Mon Sep 17 00:00:00 2001 From: Rez Date: Tue, 23 Dec 2025 00:52:20 +1100 Subject: [PATCH 03/12] test progress --- src/flashblocks/mod.rs | 11 +- tests/e2e/flashblocks.rs | 246 +++++++++++++++++++++++++++------------ 2 files changed, 184 insertions(+), 73 deletions(-) diff --git a/src/flashblocks/mod.rs b/src/flashblocks/mod.rs index 1ef2e45d..875818cc 100644 --- a/src/flashblocks/mod.rs +++ b/src/flashblocks/mod.rs @@ -160,7 +160,16 @@ impl FlashblockPayload for BerachainFlashblockPayload { fn recover_transactions( &self, ) -> impl Iterator>, RecoveryError>> { - std::iter::from_fn(|| todo!("implement transaction recovery")) + use alloy_consensus::transaction::SignerRecoverable; + use alloy_eips::Decodable2718; + + self.diff.transactions.clone().into_iter().map(|encoded| { + let tx = BerachainTxEnvelope::decode_2718(&mut encoded.as_ref()) + .map_err(RecoveryError::from_source)?; + let signer = tx.recover_signer()?; + let recovered = Recovered::new_unchecked(tx, signer); + Ok(WithEncoded::new(encoded, recovered)) + }) } } diff --git a/tests/e2e/flashblocks.rs b/tests/e2e/flashblocks.rs index 0dfa3eda..d43dc718 100644 --- a/tests/e2e/flashblocks.rs +++ b/tests/e2e/flashblocks.rs @@ -279,16 +279,21 @@ mod mock_stream_tests { #[cfg(test)] mod service_integration_tests { use super::*; - use crate::e2e::{berachain_payload_attributes_generator, setup_test_boilerplate}; + use crate::e2e::setup_test_boilerplate; use alloy_consensus::BlockHeader; use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; + use bera_reth::{ + evm::BerachainEvmFactory, node::evm::config::BerachainEvmConfig, + primitives::BerachainPrimitives, + }; use reth::{providers::BlockReaderIdExt, rpc::types::engine::PayloadId}; - use reth_e2e_test_utils::node::NodeTestContext; use reth_node_builder::{NodeBuilder, NodeHandle}; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; - use reth_optimism_flashblocks::{FlashBlockPendingSequence, FlashblocksListeners}; - use std::sync::Arc; - use tokio::sync::{broadcast, watch}; + use reth_optimism_flashblocks::{ + FlashBlockCompleteSequence, FlashBlockService, PendingFlashBlock, + }; + use std::{pin::Pin, task::Poll, time::Duration}; + use tokio::sync::watch; fn create_test_flashblock_for_parent( index: u64, @@ -333,8 +338,27 @@ mod service_integration_tests { } } + struct MockFlashblockStream { + rx: tokio::sync::mpsc::Receiver, + } + + impl futures_util::Stream for MockFlashblockStream { + type Item = eyre::Result; + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + match Pin::new(&mut self.rx).poll_recv(cx) { + Poll::Ready(Some(fb)) => Poll::Ready(Some(Ok(fb))), + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, + } + } + } + #[tokio::test] - async fn test_flashblock_sequence_builds_with_node_context() -> eyre::Result<()> { + async fn test_flashblock_service_receives_and_broadcasts() -> eyre::Result<()> { let (tasks, chain_spec) = setup_test_boilerplate().await?; let executor = tasks.executor(); @@ -348,87 +372,157 @@ mod service_integration_tests { .launch() .await?; - let ctx = NodeTestContext::new(node, berachain_payload_attributes_generator).await?; + let evm_config = BerachainEvmConfig::new_with_evm_factory( + chain_spec.clone(), + BerachainEvmFactory::default(), + ); + let provider = node.provider().clone(); + + let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); + let stream = MockFlashblockStream { rx: fb_rx }; - let provider = ctx.rpc.inner.eth_api().provider(); - let latest_header = provider.latest_header()?.expect("should have genesis"); - let latest_hash = latest_header.hash(); - let latest_number = latest_header.number(); - let latest_timestamp = latest_header.timestamp(); + let service = FlashBlockService::new(stream, evm_config, provider, executor.clone(), false); + + let mut received_rx = service.flashblocks_broadcaster().subscribe(); + let mut sequence_rx = service.subscribe_block_sequence(); + + let (pending_tx, _pending_rx) = watch::channel(None); + executor.spawn_critical( + "flashblock-service", + Box::pin(async move { + service.run(pending_tx).await; + }), + ); + + let latest = node.provider().latest_header()?.expect("should have genesis"); + let latest_hash = latest.hash(); + let next_block = latest.number() + 1; + let next_timestamp = latest.timestamp() + 2; let payload_id = PayloadId::new([1u8; 8]); let fb0 = create_test_flashblock_for_parent( 0, - latest_number + 1, + next_block, payload_id, latest_hash, - latest_timestamp + 2, + next_timestamp, ); + + fb_tx.send(fb0.clone()).await?; + + let received = + tokio::time::timeout(Duration::from_millis(500), received_rx.recv()).await??; + + assert_eq!(received.index, 0); + assert_eq!(received.payload_id, payload_id); + assert_eq!(received.metadata.block_number, next_block); + let fb1 = create_test_flashblock_for_parent( 1, - latest_number + 1, + next_block, payload_id, latest_hash, - latest_timestamp + 2, + next_timestamp, ); + fb_tx.send(fb1).await?; - let mut sequence: FlashBlockPendingSequence = - FlashBlockPendingSequence::new(); - - sequence.insert(fb0); - sequence.insert(fb1); + let received2 = + tokio::time::timeout(Duration::from_millis(500), received_rx.recv()).await??; + assert_eq!(received2.index, 1); - assert_eq!(sequence.count(), 2); - assert_eq!(sequence.block_number(), Some(latest_number + 1)); + let payload_id2 = PayloadId::new([2u8; 8]); + let fb_next_block = create_test_flashblock_for_parent( + 0, + next_block + 1, + payload_id2, + B256::random(), + next_timestamp + 2, + ); + fb_tx.send(fb_next_block).await?; - let complete = sequence.finalize()?; - assert_eq!(complete.count(), 2); + let sequence: FlashBlockCompleteSequence = + tokio::time::timeout(Duration::from_millis(500), sequence_rx.recv()).await??; - let base = complete.payload_base(); - assert_eq!(base.parent_hash, latest_hash); - assert_eq!(base.block_number, latest_number + 1); + assert_eq!(sequence.block_number(), next_block); + assert_eq!(sequence.count(), 2); Ok(()) } #[tokio::test] - async fn test_flashblock_listeners_broadcast() -> eyre::Result<()> { - let (_pending_tx, pending_rx) = watch::channel(None); - let (sequence_tx, _) = broadcast::channel(128); - let (_in_progress_tx, in_progress_rx) = watch::channel(None); - let (received_tx, _) = broadcast::channel(128); - - let listeners: FlashblocksListeners< - bera_reth::primitives::BerachainPrimitives, - BerachainFlashblockPayload, - > = FlashblocksListeners::new( - pending_rx, - sequence_tx.clone(), - in_progress_rx, - received_tx.clone(), + async fn test_flashblock_service_builds_pending_block() -> eyre::Result<()> { + let (tasks, chain_spec) = setup_test_boilerplate().await?; + let executor = tasks.executor(); + + let node_config = NodeConfig::new(chain_spec.clone()) + .with_unused_ports() + .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) + .testing_node(executor.clone()) + .node(BerachainNode::default()) + .launch() + .await?; + + let evm_config = BerachainEvmConfig::new_with_evm_factory( + chain_spec.clone(), + BerachainEvmFactory::default(), ); + let provider = node.provider().clone(); + + let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); + let stream = MockFlashblockStream { rx: fb_rx }; + + let service = + FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); - let _sequence_rx = listeners.flashblocks_sequence.subscribe(); - let mut received_rx = listeners.received_flashblocks.subscribe(); + let mut in_progress_rx = service.subscribe_in_progress(); + + let (pending_tx, mut pending_rx) = watch::channel(None); + executor.spawn_critical( + "flashblock-service", + Box::pin(async move { + service.run(pending_tx).await; + }), + ); + + let latest = node.provider().latest_header()?.expect("should have genesis"); + let latest_hash = latest.hash(); + let next_block = latest.number() + 1; + let next_timestamp = latest.timestamp() + 2; let payload_id = PayloadId::new([1u8; 8]); - let parent_hash = B256::random(); - let fb = create_test_flashblock_for_parent(0, 100, payload_id, parent_hash, 1_000_000); + let fb0 = create_test_flashblock_for_parent( + 0, + next_block, + payload_id, + latest_hash, + next_timestamp, + ); - received_tx.send(Arc::new(fb.clone()))?; + fb_tx.send(fb0).await?; - let received = - tokio::time::timeout(std::time::Duration::from_millis(100), received_rx.recv()) - .await??; + in_progress_rx.changed().await?; + let build_info = in_progress_rx.borrow().clone(); - assert_eq!(received.index, 0); - assert_eq!(received.payload_id, payload_id); + if let Some(info) = build_info { + assert_eq!(info.block_number, next_block); + assert_eq!(info.parent_hash, latest_hash); + } + + pending_rx.changed().await?; + let pending_block: Option> = + pending_rx.borrow().clone(); + + if let Some(pending) = pending_block { + assert_eq!(pending.parent_hash(), latest_hash); + } Ok(()) } #[tokio::test] - async fn test_flashblock_sequence_validates_parent_hash() -> eyre::Result<()> { + async fn test_flashblock_service_validates_parent_hash() -> eyre::Result<()> { let (tasks, chain_spec) = setup_test_boilerplate().await?; let executor = tasks.executor(); @@ -442,37 +536,45 @@ mod service_integration_tests { .launch() .await?; - let ctx = NodeTestContext::new(node, berachain_payload_attributes_generator).await?; + let evm_config = BerachainEvmConfig::new_with_evm_factory( + chain_spec.clone(), + BerachainEvmFactory::default(), + ); + let provider = node.provider().clone(); + + let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); + let stream = MockFlashblockStream { rx: fb_rx }; - let provider = ctx.rpc.inner.eth_api().provider(); - let latest_header = provider.latest_header()?.expect("should have genesis"); - let latest_hash = latest_header.hash(); - let latest_number = latest_header.number(); - let latest_timestamp = latest_header.timestamp(); + let service = + FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); - let payload_id = PayloadId::new([1u8; 8]); - let fb_correct_parent = create_test_flashblock_for_parent( - 0, - latest_number + 1, - payload_id, - latest_hash, - latest_timestamp + 2, + let (pending_tx, mut pending_rx) = watch::channel(None); + executor.spawn_critical( + "flashblock-service", + Box::pin(async move { + service.run(pending_tx).await; + }), ); + let latest = node.provider().latest_header()?.expect("should have genesis"); + let next_block = latest.number() + 1; + let next_timestamp = latest.timestamp() + 2; + let wrong_parent_hash = B256::random(); + let payload_id = PayloadId::new([1u8; 8]); let fb_wrong_parent = create_test_flashblock_for_parent( 0, - latest_number + 1, + next_block, payload_id, wrong_parent_hash, - latest_timestamp + 2, + next_timestamp, ); - let base_correct = fb_correct_parent.base.as_ref().unwrap(); - assert_eq!(base_correct.parent_hash, latest_hash); + fb_tx.send(fb_wrong_parent).await?; + + let result = tokio::time::timeout(Duration::from_millis(200), pending_rx.changed()).await; - let base_wrong = fb_wrong_parent.base.as_ref().unwrap(); - assert_ne!(base_wrong.parent_hash, latest_hash); + assert!(result.is_err(), "Should not build pending block with wrong parent hash"); Ok(()) } From 023daf01fc5ef7406bdbe6c311be4236ba934d94 Mon Sep 17 00:00:00 2001 From: Rez Date: Tue, 23 Dec 2025 01:16:52 +1100 Subject: [PATCH 04/12] more testing --- tests/e2e/flashblocks.rs | 291 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 289 insertions(+), 2 deletions(-) diff --git a/tests/e2e/flashblocks.rs b/tests/e2e/flashblocks.rs index d43dc718..6410280e 100644 --- a/tests/e2e/flashblocks.rs +++ b/tests/e2e/flashblocks.rs @@ -280,17 +280,21 @@ mod mock_stream_tests { mod service_integration_tests { use super::*; use crate::e2e::setup_test_boilerplate; - use alloy_consensus::BlockHeader; + use alloy_consensus::{ + BlockHeader, + transaction::{SignerRecoverable, TxHashRef}, + }; use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; use bera_reth::{ evm::BerachainEvmFactory, node::evm::config::BerachainEvmConfig, primitives::BerachainPrimitives, }; use reth::{providers::BlockReaderIdExt, rpc::types::engine::PayloadId}; + use reth_chainspec::EthChainSpec; use reth_node_builder::{NodeBuilder, NodeHandle}; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; use reth_optimism_flashblocks::{ - FlashBlockCompleteSequence, FlashBlockService, PendingFlashBlock, + FlashBlockCompleteSequence, FlashBlockService, FlashblockPayload, PendingFlashBlock, }; use std::{pin::Pin, task::Poll, time::Duration}; use tokio::sync::watch; @@ -578,4 +582,287 @@ mod service_integration_tests { Ok(()) } + + #[tokio::test] + async fn test_flashblock_service_with_real_transactions() -> eyre::Result<()> { + use crate::e2e::test_signer; + use alloy_eips::eip2718::Encodable2718; + use reth_e2e_test_utils::transaction::TransactionTestContext; + + let (tasks, chain_spec) = setup_test_boilerplate().await?; + let executor = tasks.executor(); + + let node_config = NodeConfig::new(chain_spec.clone()) + .with_unused_ports() + .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) + .testing_node(executor.clone()) + .node(BerachainNode::default()) + .launch() + .await?; + + let evm_config = BerachainEvmConfig::new_with_evm_factory( + chain_spec.clone(), + BerachainEvmFactory::default(), + ); + let provider = node.provider().clone(); + + let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); + let stream = MockFlashblockStream { rx: fb_rx }; + + let service = + FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); + + let (pending_tx, mut pending_rx) = watch::channel(None); + executor.spawn_critical( + "flashblock-service", + Box::pin(async move { + service.run(pending_tx).await; + }), + ); + + let latest = node.provider().latest_header()?.expect("should have genesis"); + let latest_hash = latest.hash(); + let next_block = latest.number() + 1; + let next_timestamp = latest.timestamp() + 2; + + let signer = test_signer()?; + let signer_address = signer.address(); + let chain_id = chain_spec.chain_id(); + let signed_tx = TransactionTestContext::transfer_tx(chain_id, signer).await; + let tx_bytes = Bytes::from(signed_tx.encoded_2718()); + let tx_hash = *signed_tx.tx_hash(); + + let payload_id = PayloadId::new([1u8; 8]); + let mut fb0 = create_test_flashblock_for_parent( + 0, + next_block, + payload_id, + latest_hash, + next_timestamp, + ); + fb0.diff.transactions = vec![tx_bytes.clone()]; + fb0.diff.gas_used = 21000; + + fb_tx.send(fb0).await?; + + pending_rx.changed().await?; + let pending_block: Option> = + pending_rx.borrow().clone(); + + let pending = pending_block.expect("should have pending block"); + assert_eq!(pending.parent_hash(), latest_hash); + + let block = pending.block(); + let block_txs = &block.body().transactions; + + assert!( + block_txs.len() >= 1, + "Block should contain at least 1 transaction, got {}", + block_txs.len() + ); + + let user_tx = block_txs + .iter() + .find(|tx| *tx.hash() == tx_hash) + .expect("User transaction should be in the block"); + + let recovered_sender = user_tx.recover_signer().expect("should recover signer"); + assert_eq!(recovered_sender, signer_address, "Recovered sender should match signer"); + + Ok(()) + } + + #[tokio::test] + async fn test_flashblock_pending_block_contains_correct_header_fields() -> eyre::Result<()> { + let (tasks, chain_spec) = setup_test_boilerplate().await?; + let executor = tasks.executor(); + + let node_config = NodeConfig::new(chain_spec.clone()) + .with_unused_ports() + .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) + .testing_node(executor.clone()) + .node(BerachainNode::default()) + .launch() + .await?; + + let evm_config = BerachainEvmConfig::new_with_evm_factory( + chain_spec.clone(), + BerachainEvmFactory::default(), + ); + let provider = node.provider().clone(); + + let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); + let stream = MockFlashblockStream { rx: fb_rx }; + + let service = + FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); + + let (pending_tx, mut pending_rx) = watch::channel(None); + executor.spawn_critical( + "flashblock-service", + Box::pin(async move { + service.run(pending_tx).await; + }), + ); + + let latest = node.provider().latest_header()?.expect("should have genesis"); + let latest_hash = latest.hash(); + let next_block = latest.number() + 1; + let next_timestamp = latest.timestamp() + 2; + + let payload_id = PayloadId::new([1u8; 8]); + let fb0 = create_test_flashblock_for_parent( + 0, + next_block, + payload_id, + latest_hash, + next_timestamp, + ); + + let expected_prev_proposer = fb0.base.as_ref().unwrap().prev_proposer_pubkey; + + fb_tx.send(fb0).await?; + + pending_rx.changed().await?; + let pending_block: Option> = + pending_rx.borrow().clone(); + + let pending = pending_block.expect("should have pending block"); + let block = pending.block(); + let header = block.header(); + + assert_eq!(header.number, next_block, "Block number mismatch"); + assert_eq!(header.timestamp, next_timestamp, "Timestamp mismatch"); + assert_eq!(header.parent_hash, latest_hash, "Parent hash mismatch"); + assert_eq!(header.gas_limit, 30_000_000, "Gas limit mismatch"); + assert_eq!( + header.prev_proposer_pubkey, expected_prev_proposer, + "prev_proposer_pubkey should be preserved" + ); + + Ok(()) + } + + #[tokio::test] + async fn test_flashblock_multiple_transactions_across_flashblocks() -> eyre::Result<()> { + use crate::e2e::test_signer; + use alloy_eips::eip2718::Encodable2718; + use alloy_signer_local::PrivateKeySigner; + use reth_e2e_test_utils::transaction::TransactionTestContext; + + let (tasks, chain_spec) = setup_test_boilerplate().await?; + let executor = tasks.executor(); + + let node_config = NodeConfig::new(chain_spec.clone()) + .with_unused_ports() + .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) + .testing_node(executor.clone()) + .node(BerachainNode::default()) + .launch() + .await?; + + let evm_config = BerachainEvmConfig::new_with_evm_factory( + chain_spec.clone(), + BerachainEvmFactory::default(), + ); + let provider = node.provider().clone(); + + let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); + let stream = MockFlashblockStream { rx: fb_rx }; + + let service = + FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); + + let mut sequence_rx = service.subscribe_block_sequence(); + + let (pending_tx, _pending_rx) = watch::channel(None); + executor.spawn_critical( + "flashblock-service", + Box::pin(async move { + service.run(pending_tx).await; + }), + ); + + let latest = node.provider().latest_header()?.expect("should have genesis"); + let latest_hash = latest.hash(); + let next_block = latest.number() + 1; + let next_timestamp = latest.timestamp() + 2; + + let signer1 = test_signer()?; + let signer1_address = signer1.address(); + let signer2 = PrivateKeySigner::random(); + let signer2_address = signer2.address(); + + let chain_id = chain_spec.chain_id(); + let tx1 = TransactionTestContext::transfer_tx(chain_id, signer1).await; + let tx1_bytes = Bytes::from(tx1.encoded_2718()); + let tx1_hash = *tx1.tx_hash(); + + let tx2 = TransactionTestContext::transfer_tx(chain_id, signer2).await; + let tx2_bytes = Bytes::from(tx2.encoded_2718()); + let tx2_hash = *tx2.tx_hash(); + + let payload_id = PayloadId::new([1u8; 8]); + + let mut fb0 = create_test_flashblock_for_parent( + 0, + next_block, + payload_id, + latest_hash, + next_timestamp, + ); + fb0.diff.transactions = vec![tx1_bytes]; + fb0.diff.gas_used = 21000; + + let mut fb1 = create_test_flashblock_for_parent( + 1, + next_block, + payload_id, + latest_hash, + next_timestamp, + ); + fb1.diff.transactions = vec![tx2_bytes]; + fb1.diff.gas_used = 42000; + + fb_tx.send(fb0).await?; + fb_tx.send(fb1).await?; + + let payload_id2 = PayloadId::new([2u8; 8]); + let fb_next = create_test_flashblock_for_parent( + 0, + next_block + 1, + payload_id2, + B256::random(), + next_timestamp + 2, + ); + fb_tx.send(fb_next).await?; + + let sequence: FlashBlockCompleteSequence = + tokio::time::timeout(Duration::from_millis(500), sequence_rx.recv()).await??; + + assert_eq!(sequence.count(), 2); + assert_eq!(sequence.block_number(), next_block); + + let all_txs = sequence.all_transactions(); + assert_eq!(all_txs.len(), 2, "Should have 2 transactions total"); + + let recovered_txs: Vec<_> = sequence + .iter() + .flat_map(|fb| fb.recover_transactions()) + .collect::, _>>()?; + + assert_eq!(recovered_txs.len(), 2); + assert_eq!(*recovered_txs[0].value().tx_hash(), tx1_hash); + assert_eq!(*recovered_txs[1].value().tx_hash(), tx2_hash); + assert_eq!(recovered_txs[0].value().signer(), signer1_address); + assert_eq!(recovered_txs[1].value().signer(), signer2_address); + + Ok(()) + } } From be54b61e0e01d4fc98c91b656ab4f8f4b560983f Mon Sep 17 00:00:00 2001 From: Rez Date: Tue, 23 Dec 2025 01:29:41 +1100 Subject: [PATCH 05/12] add depinjected flashblock listener --- src/rpc/mod.rs | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index 09170720..679c5aef 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -48,16 +48,46 @@ use tokio::sync::watch; use tracing::info; /// Builds `BerachainEthApi` for Berachain. -#[derive(Debug)] pub struct BerachainEthApiBuilder { /// A URL pointing to a secure websocket connection (wss) that streams out flashblocks. flashblocks_url: Option, + /// Pre-built flashblocks listeners (for testing/dependency injection). + flashblocks_listeners: + Option>, +} + +impl std::fmt::Debug for BerachainEthApiBuilder { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("BerachainEthApiBuilder") + .field("flashblocks_url", &self.flashblocks_url) + .field("has_flashblocks_listeners", &self.flashblocks_listeners.is_some()) + .finish() + } } impl Default for BerachainEthApiBuilder { fn default() -> Self { - // TODO: hardcode value here - Self { flashblocks_url: None } + Self { flashblocks_url: None, flashblocks_listeners: None } + } +} + +impl BerachainEthApiBuilder { + /// Configure flashblocks with a WebSocket URL. + pub fn with_flashblocks_url(mut self, url: Option) -> Self { + self.flashblocks_url = url; + self + } + + /// Configure flashblocks with pre-built listeners. + /// + /// This is primarily useful for testing, where you can build `FlashblocksListeners` + /// from a custom stream source instead of connecting to a real WebSocket server. + pub fn with_flashblocks_listeners( + mut self, + listeners: FlashblocksListeners, + ) -> Self { + self.flashblocks_listeners = Some(listeners); + self } } @@ -105,7 +135,10 @@ where BerachainEthReceiptConverter::new(ctx.components.provider().clone().chain_spec()), ); - let flashblocks = if let Some(ws_url) = self.flashblocks_url { + let flashblocks = if let Some(listeners) = self.flashblocks_listeners { + info!(target: "bera-reth:rpc", "Using pre-built flashblocks listeners"); + Some(listeners) + } else if let Some(ws_url) = self.flashblocks_url { info!(target: "bera-reth:rpc", %ws_url, "Launching flashblocks service"); let (tx, pending_rx) = watch::channel(None); From a715f224b481132dc77265641631565b98b152d0 Mon Sep 17 00:00:00 2001 From: Rez Date: Tue, 23 Dec 2025 01:44:12 +1100 Subject: [PATCH 06/12] compiling but failing --- src/rpc/api.rs | 4 +- src/rpc/mod.rs | 32 +++++-- tests/e2e/flashblocks.rs | 192 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+), 8 deletions(-) diff --git a/src/rpc/api.rs b/src/rpc/api.rs index 0a1ef28e..0793f2f2 100644 --- a/src/rpc/api.rs +++ b/src/rpc/api.rs @@ -335,7 +335,7 @@ pub struct BerachainApi { /// Flashblocks listeners. /// /// If set, provides receivers for pending blocks, flashblock sequences, and build status. - pub flashblocks: Arc>>, + pub flashblocks: Option>>, } /// Maximum duration to wait for a fresh flashblock when one is being built. @@ -344,7 +344,7 @@ const MAX_FLASHBLOCK_WAIT_DURATION: Duration = Duration::from_millis(50); impl BerachainApi { /// Returns information about the flashblock currently being built, if any. fn flashblock_build_info(&self) -> Option { - self.flashblocks.as_ref().as_ref().and_then(|f| *f.in_progress_rx.borrow()) + self.flashblocks.as_ref().and_then(|f| *f.in_progress_rx.borrow()) } /// Extracts pending block if it matches the expected parent hash. diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index 679c5aef..46c5be25 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -48,12 +48,14 @@ use tokio::sync::watch; use tracing::info; /// Builds `BerachainEthApi` for Berachain. +#[derive(Clone)] pub struct BerachainEthApiBuilder { /// A URL pointing to a secure websocket connection (wss) that streams out flashblocks. flashblocks_url: Option, /// Pre-built flashblocks listeners (for testing/dependency injection). + /// Wrapped in Arc for clonability. flashblocks_listeners: - Option>, + Option>>, } impl std::fmt::Debug for BerachainEthApiBuilder { @@ -86,7 +88,7 @@ impl BerachainEthApiBuilder { mut self, listeners: FlashblocksListeners, ) -> Self { - self.flashblocks_listeners = Some(listeners); + self.flashblocks_listeners = Some(Arc::new(listeners)); self } } @@ -157,19 +159,19 @@ where let in_progress_rx = service.subscribe_in_progress(); ctx.components.task_executor().spawn(Box::pin(service.run(tx))); - Some(FlashblocksListeners::new( + Some(Arc::new(FlashblocksListeners::new( pending_rx, flashblocks_sequence, in_progress_rx, received_flashblocks, - )) + ))) } else { None }; let inner = ctx.eth_api_builder().with_rpc_converter(tx_resp_builder.clone()).build(); - Ok(BerachainApi { inner, flashblocks: Arc::new(flashblocks) }) + Ok(BerachainApi { inner, flashblocks }) } } @@ -192,9 +194,27 @@ where BerachainEthApiBuilder: EthApiBuilder, { fn default() -> Self { + Self::new(BerachainEthApiBuilder::default()) + } +} + +impl BerachainAddOns +where + N: FullNodeComponents, + BerachainEthApiBuilder: EthApiBuilder, +{ + /// Creates new Berachain add-ons with a custom EthApiBuilder. + /// + /// This is useful for testing, where you can inject pre-built flashblocks listeners: + /// ```ignore + /// let eth_api_builder = BerachainEthApiBuilder::default() + /// .with_flashblocks_listeners(listeners); + /// let add_ons = BerachainAddOns::new(eth_api_builder); + /// ``` + pub fn new(eth_api_builder: BerachainEthApiBuilder) -> Self { Self { inner: RpcAddOns::new( - BerachainEthApiBuilder::default(), + eth_api_builder, BerachainEngineValidatorBuilder::default(), BerachainEngineApiBuilder::::default(), BasicEngineValidatorBuilder::new(BerachainEngineValidatorBuilder::default()), diff --git a/tests/e2e/flashblocks.rs b/tests/e2e/flashblocks.rs index 6410280e..e940f66e 100644 --- a/tests/e2e/flashblocks.rs +++ b/tests/e2e/flashblocks.rs @@ -866,3 +866,195 @@ mod service_integration_tests { Ok(()) } } + +#[cfg(test)] +mod rpc_integration_tests { + use super::*; + use crate::e2e::{setup_test_boilerplate, test_signer}; + use alloy_consensus::BlockHeader; + use alloy_eips::eip2718::Encodable2718; + use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; + use alloy_provider::Provider; + use bera_reth::{ + engine::validator::BerachainEngineValidatorBuilder, + evm::BerachainEvmFactory, + node::evm::config::BerachainEvmConfig, + primitives::BerachainPrimitives, + rpc::{BerachainAddOns, BerachainEthApiBuilder}, + }; + use reth::{providers::BlockReaderIdExt, rpc::types::engine::PayloadId}; + use reth_chainspec::EthChainSpec; + use reth_e2e_test_utils::transaction::TransactionTestContext; + use reth_node_builder::{Node, NodeBuilder, NodeHandle}; + use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; + use reth_optimism_flashblocks::{FlashBlockService, FlashblocksListeners}; + use std::{pin::Pin, sync::Arc, task::Poll, time::Duration}; + use tokio::sync::watch; + + fn create_test_flashblock_for_parent( + index: u64, + block_number: u64, + payload_id: PayloadId, + parent_hash: B256, + timestamp: u64, + ) -> BerachainFlashblockPayload { + let base = if index == 0 { + Some(BerachainFlashblockPayloadBase { + parent_beacon_block_root: B256::random(), + parent_hash, + fee_recipient: Address::random(), + prev_randao: B256::random(), + block_number, + gas_limit: 30_000_000, + timestamp, + extra_data: Bytes::default(), + base_fee_per_gas: U256::from(1_000_000_000u64), + prev_proposer_pubkey: Some(BlsPublicKey::random()), + }) + } else { + None + }; + + BerachainFlashblockPayload { + payload_id, + index, + base, + diff: BerachainFlashblockPayloadDiff { + state_root: B256::random(), + receipts_root: B256::random(), + logs_bloom: Bloom::default(), + gas_used: 21000, + block_hash: B256::random(), + transactions: vec![], + withdrawals: vec![], + withdrawals_root: B256::ZERO, + blob_gas_used: None, + }, + metadata: BerachainFlashblockPayloadMetadata { block_number }, + } + } + + struct MockFlashblockStream { + rx: tokio::sync::mpsc::Receiver, + } + + impl futures_util::Stream for MockFlashblockStream { + type Item = eyre::Result; + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + match Pin::new(&mut self.rx).poll_recv(cx) { + Poll::Ready(Some(fb)) => Poll::Ready(Some(Ok(fb))), + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, + } + } + } + + #[tokio::test] + async fn test_rpc_returns_flashblock_pending_receipt() -> eyre::Result<()> { + use reth_optimism_flashblocks::FlashBlockCompleteSequence; + use tokio::sync::broadcast; + + let (tasks, chain_spec) = setup_test_boilerplate().await?; + let executor = tasks.executor(); + + let (pending_tx, pending_rx) = watch::channel(None); + let (sequence_tx, _) = + broadcast::channel::>(16); + let (in_progress_tx, in_progress_rx) = watch::channel(None); + let (received_tx, _) = broadcast::channel::>(128); + + let listeners: FlashblocksListeners = + FlashblocksListeners::new(pending_rx, sequence_tx, in_progress_rx, received_tx); + + let eth_api_builder = + BerachainEthApiBuilder::default().with_flashblocks_listeners(listeners); + let add_ons = + BerachainAddOns::<_, _, BerachainEngineValidatorBuilder>::new(eth_api_builder); + + let node_config = NodeConfig::new(chain_spec.clone()) + .with_unused_ports() + .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) + .testing_node(executor.clone()) + .with_types::() + .with_components(BerachainNode::default().components_builder()) + .with_add_ons(add_ons) + .launch() + .await?; + + let evm_config = BerachainEvmConfig::new_with_evm_factory( + chain_spec.clone(), + BerachainEvmFactory::default(), + ); + let provider = node.provider().clone(); + + let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); + let stream = MockFlashblockStream { rx: fb_rx }; + + let service = + FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); + + let mut service_in_progress_rx = service.subscribe_in_progress(); + + executor.spawn_critical( + "flashblock-service", + Box::pin(async move { + service.run(pending_tx).await; + }), + ); + + let latest = node.provider().latest_header()?.expect("should have genesis"); + let latest_hash = latest.hash(); + let next_block = latest.number() + 1; + let next_timestamp = latest.timestamp() + 2; + + let signer = test_signer()?; + let chain_id = chain_spec.chain_id(); + let tx = TransactionTestContext::transfer_tx(chain_id, signer).await; + let tx_bytes = Bytes::from(tx.encoded_2718()); + let tx_hash = *tx.tx_hash(); + + let payload_id = PayloadId::new([1u8; 8]); + + let mut fb0 = create_test_flashblock_for_parent( + 0, + next_block, + payload_id, + latest_hash, + next_timestamp, + ); + fb0.diff.transactions = vec![tx_bytes]; + fb0.diff.gas_used = 21000; + + fb_tx.send(fb0).await?; + + tokio::time::timeout(Duration::from_millis(500), service_in_progress_rx.changed()) + .await??; + in_progress_tx.send(service_in_progress_rx.borrow().clone())?; + + tokio::time::sleep(Duration::from_millis(100)).await; + + let rpc_url = format!( + "http://127.0.0.1:{}", + node.rpc_server_handle().http_local_addr().unwrap().port() + ); + let rpc_client = alloy_provider::ProviderBuilder::new().connect(&rpc_url).await?; + + let receipt = rpc_client.get_transaction_receipt(tx_hash).await?; + + assert!( + receipt.is_some(), + "Transaction receipt should be available from flashblock pending state" + ); + + let receipt = receipt.unwrap(); + assert_eq!(receipt.transaction_hash, tx_hash); + + Ok(()) + } +} From be007ee87139dabdda2b46cc3238429480d0c198 Mon Sep 17 00:00:00 2001 From: Rez Date: Tue, 23 Dec 2025 02:08:12 +1100 Subject: [PATCH 07/12] cleanup test --- tests/e2e/flashblocks.rs | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/tests/e2e/flashblocks.rs b/tests/e2e/flashblocks.rs index e940f66e..5f6e6da5 100644 --- a/tests/e2e/flashblocks.rs +++ b/tests/e2e/flashblocks.rs @@ -877,8 +877,6 @@ mod rpc_integration_tests { use alloy_provider::Provider; use bera_reth::{ engine::validator::BerachainEngineValidatorBuilder, - evm::BerachainEvmFactory, - node::evm::config::BerachainEvmConfig, primitives::BerachainPrimitives, rpc::{BerachainAddOns, BerachainEthApiBuilder}, }; @@ -961,14 +959,26 @@ mod rpc_integration_tests { let (tasks, chain_spec) = setup_test_boilerplate().await?; let executor = tasks.executor(); + // Create channels that connect the FlashBlockService to the RPC layer's + // FlashblocksListeners. + // - pending_tx: service writes pending blocks here, RPC reads from pending_rx + // - in_progress_tx: we manually forward service state to RPC (see below) let (pending_tx, pending_rx) = watch::channel(None); - let (sequence_tx, _) = - broadcast::channel::>(16); let (in_progress_tx, in_progress_rx) = watch::channel(None); - let (received_tx, _) = broadcast::channel::>(128); + + // These channels are required by FlashblocksListeners but not used in this test. + // The service has its own internal broadcasters for these. + let (unused_sequence_tx, _) = + broadcast::channel::>(1); + let (unused_received_tx, _) = broadcast::channel::>(1); let listeners: FlashblocksListeners = - FlashblocksListeners::new(pending_rx, sequence_tx, in_progress_rx, received_tx); + FlashblocksListeners::new( + pending_rx, + unused_sequence_tx, + in_progress_rx, + unused_received_tx, + ); let eth_api_builder = BerachainEthApiBuilder::default().with_flashblocks_listeners(listeners); @@ -987,17 +997,16 @@ mod rpc_integration_tests { .launch() .await?; - let evm_config = BerachainEvmConfig::new_with_evm_factory( - chain_spec.clone(), - BerachainEvmFactory::default(), - ); - let provider = node.provider().clone(); - let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); let stream = MockFlashblockStream { rx: fb_rx }; - let service = - FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); + let service = FlashBlockService::new( + stream, + node.evm_config.clone(), + node.provider().clone(), + executor.clone(), + false, + ); let mut service_in_progress_rx = service.subscribe_in_progress(); From 5bbad35b427c6007680608370573b7294539d21f Mon Sep 17 00:00:00 2001 From: Rez Date: Tue, 23 Dec 2025 17:35:48 +1100 Subject: [PATCH 08/12] clippy --- tests/e2e/flashblocks.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/e2e/flashblocks.rs b/tests/e2e/flashblocks.rs index 5f6e6da5..78abdc83 100644 --- a/tests/e2e/flashblocks.rs +++ b/tests/e2e/flashblocks.rs @@ -507,7 +507,7 @@ mod service_integration_tests { fb_tx.send(fb0).await?; in_progress_rx.changed().await?; - let build_info = in_progress_rx.borrow().clone(); + let build_info = *in_progress_rx.borrow(); if let Some(info) = build_info { assert_eq!(info.block_number, next_block); @@ -658,7 +658,7 @@ mod service_integration_tests { let block_txs = &block.body().transactions; assert!( - block_txs.len() >= 1, + !block_txs.is_empty(), "Block should contain at least 1 transaction, got {}", block_txs.len() ); @@ -1044,7 +1044,7 @@ mod rpc_integration_tests { tokio::time::timeout(Duration::from_millis(500), service_in_progress_rx.changed()) .await??; - in_progress_tx.send(service_in_progress_rx.borrow().clone())?; + in_progress_tx.send(*service_in_progress_rx.borrow())?; tokio::time::sleep(Duration::from_millis(100)).await; From aee85f14a64a1f60c6ed5d524455d0b0c1db93a7 Mon Sep 17 00:00:00 2001 From: Rez Date: Tue, 23 Dec 2025 19:06:56 +1100 Subject: [PATCH 09/12] consolidate tests --- src/flashblocks/test_utils.rs | 167 +---- src/rpc/mod.rs | 7 + tests/e2e/flashblocks.rs | 1312 +++++++-------------------------- 3 files changed, 290 insertions(+), 1196 deletions(-) diff --git a/src/flashblocks/test_utils.rs b/src/flashblocks/test_utils.rs index fd01091d..3bdf53aa 100644 --- a/src/flashblocks/test_utils.rs +++ b/src/flashblocks/test_utils.rs @@ -1,3 +1,5 @@ +//! Test utilities for creating flashblock payloads. + use crate::{ flashblocks::{ BerachainFlashblockPayload, BerachainFlashblockPayloadBase, BerachainFlashblockPayloadDiff, @@ -5,7 +7,6 @@ use crate::{ }, primitives::header::BlsPublicKey, }; -use alloy_eips::eip4895::Withdrawal; use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; use reth::rpc::types::engine::PayloadId; @@ -21,16 +22,6 @@ impl BerachainTestFlashBlockFactory { Self { block_time: 2, base_timestamp: 1_000_000, current_block_number: 100 } } - pub fn with_block_time(mut self, block_time: u64) -> Self { - self.block_time = block_time; - self - } - - pub fn with_base_timestamp(mut self, timestamp: u64) -> Self { - self.base_timestamp = timestamp; - self - } - pub fn with_block_number(mut self, block_number: u64) -> Self { self.current_block_number = block_number; self @@ -71,24 +62,15 @@ impl BerachainTestFlashBlockFactory { .timestamp(prev_timestamp + self.block_time) } - pub fn builder(&self) -> BerachainTestFlashBlockBuilder { + fn builder(&self) -> BerachainTestFlashBlockBuilder { BerachainTestFlashBlockBuilder { index: 0, block_number: self.current_block_number, payload_id: PayloadId::new([1u8; 8]), parent_hash: B256::random(), timestamp: self.base_timestamp, - base: None, - block_hash: B256::random(), - state_root: B256::ZERO, - receipts_root: B256::ZERO, - logs_bloom: Bloom::default(), - gas_used: 0, gas_limit: 30_000_000, transactions: vec![], - withdrawals: vec![], - withdrawals_root: B256::ZERO, - blob_gas_used: None, prev_proposer_pubkey: Some(BlsPublicKey::random()), } } @@ -107,17 +89,8 @@ pub struct BerachainTestFlashBlockBuilder { payload_id: PayloadId, parent_hash: B256, timestamp: u64, - base: Option, - block_hash: B256, - state_root: B256, - receipts_root: B256, - logs_bloom: Bloom, - gas_used: u64, gas_limit: u64, transactions: Vec, - withdrawals: Vec, - withdrawals_root: B256, - blob_gas_used: Option, prev_proposer_pubkey: Option, } @@ -147,55 +120,19 @@ impl BerachainTestFlashBlockBuilder { self } - #[allow(dead_code)] - pub fn base(mut self, base: BerachainFlashblockPayloadBase) -> Self { - self.base = Some(base); - self - } - - #[allow(dead_code)] - pub fn block_hash(mut self, block_hash: B256) -> Self { - self.block_hash = block_hash; - self - } - - #[allow(dead_code)] - pub fn state_root(mut self, state_root: B256) -> Self { - self.state_root = state_root; - self - } - - #[allow(dead_code)] - pub fn receipts_root(mut self, receipts_root: B256) -> Self { - self.receipts_root = receipts_root; - self - } - pub fn transactions(mut self, transactions: Vec) -> Self { self.transactions = transactions; self } - #[allow(dead_code)] - pub fn gas_used(mut self, gas_used: u64) -> Self { - self.gas_used = gas_used; - self - } - - #[allow(dead_code)] - pub fn gas_limit(mut self, gas_limit: u64) -> Self { - self.gas_limit = gas_limit; - self - } - pub fn prev_proposer_pubkey(mut self, pubkey: Option) -> Self { self.prev_proposer_pubkey = pubkey; self } - pub fn build(mut self) -> BerachainFlashblockPayload { - if self.index == 0 && self.base.is_none() { - self.base = Some(BerachainFlashblockPayloadBase { + pub fn build(self) -> BerachainFlashblockPayload { + let base = if self.index == 0 { + Some(BerachainFlashblockPayloadBase { parent_hash: self.parent_hash, parent_beacon_block_root: B256::random(), fee_recipient: Address::default(), @@ -206,93 +143,27 @@ impl BerachainTestFlashBlockBuilder { extra_data: Default::default(), base_fee_per_gas: U256::from(1_000_000_000u64), prev_proposer_pubkey: self.prev_proposer_pubkey, - }); - } + }) + } else { + None + }; BerachainFlashblockPayload { index: self.index, payload_id: self.payload_id, - base: self.base, + base, diff: BerachainFlashblockPayloadDiff { - block_hash: self.block_hash, - state_root: self.state_root, - receipts_root: self.receipts_root, - logs_bloom: self.logs_bloom, - gas_used: self.gas_used, + block_hash: B256::random(), + state_root: B256::ZERO, + receipts_root: B256::ZERO, + logs_bloom: Bloom::default(), + gas_used: 0, transactions: self.transactions, - withdrawals: self.withdrawals, - withdrawals_root: self.withdrawals_root, - blob_gas_used: self.blob_gas_used, + withdrawals: vec![], + withdrawals_root: B256::ZERO, + blob_gas_used: None, }, metadata: BerachainFlashblockPayloadMetadata { block_number: self.block_number }, } } } - -#[cfg(test)] -mod tests { - use super::*; - use reth_optimism_flashblocks::{FlashblockDiff, FlashblockPayload, FlashblockPayloadBase}; - - #[test] - fn test_factory_creates_valid_flashblock_at_index_0() { - let factory = BerachainTestFlashBlockFactory::new(); - let fb = factory.flashblock_at(0).build(); - - assert_eq!(fb.index, 0); - assert!(fb.base.is_some()); - assert_eq!(fb.base.as_ref().unwrap().block_number, 100); - } - - #[test] - fn test_factory_creates_followup_flashblock() { - let factory = BerachainTestFlashBlockFactory::new(); - let fb0 = factory.flashblock_at(0).build(); - let fb1 = factory.flashblock_after(&fb0).build(); - - assert_eq!(fb1.index, 1); - assert!(fb1.base.is_none()); - assert_eq!(fb1.payload_id, fb0.payload_id); - } - - #[test] - fn test_factory_creates_next_block_flashblock() { - let factory = BerachainTestFlashBlockFactory::new(); - let fb0 = factory.flashblock_at(0).build(); - let fb_next = factory.flashblock_for_next_block(&fb0).build(); - - assert_eq!(fb_next.index, 0); - assert!(fb_next.base.is_some()); - assert_eq!(fb_next.base.as_ref().unwrap().block_number, 101); - assert_eq!(fb_next.base.as_ref().unwrap().parent_hash, fb0.diff.block_hash); - assert_ne!(fb_next.payload_id, fb0.payload_id); - } - - #[test] - fn test_flashblock_trait_implementations() { - let factory = BerachainTestFlashBlockFactory::new(); - let fb = - factory.flashblock_at(0).transactions(vec![Bytes::from_static(&[1, 2, 3])]).build(); - - assert_eq!(fb.index(), 0); - assert_eq!(fb.block_number(), 100); - assert!(fb.base().is_some()); - - let base = fb.base().unwrap(); - assert_eq!(base.block_number(), 100); - assert_eq!(base.timestamp(), 1_000_000); - - let diff = fb.diff(); - assert_eq!(diff.transactions_raw().len(), 1); - assert_eq!(diff.gas_used(), 0); - } - - #[test] - fn test_berachain_specific_fields() { - let factory = BerachainTestFlashBlockFactory::new(); - let pubkey = BlsPublicKey::random(); - let fb = factory.flashblock_at(0).prev_proposer_pubkey(Some(pubkey)).build(); - - assert_eq!(fb.base.as_ref().unwrap().prev_proposer_pubkey, Some(pubkey)); - } -} diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index 46c5be25..4a809c50 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -133,6 +133,13 @@ where type EthApi = BerachainApi>; async fn build_eth_api(self, ctx: EthApiCtx<'_, N>) -> eyre::Result { + if self.flashblocks_listeners.is_some() && self.flashblocks_url.is_some() { + return Err(eyre::eyre!( + "Cannot configure both flashblocks_listeners and flashblocks_url. \ + Use flashblocks_listeners for testing or flashblocks_url for production." + )); + } + let tx_resp_builder = BerachainEthRpcConverterFor::::new( BerachainEthReceiptConverter::new(ctx.components.provider().clone().chain_spec()), ); diff --git a/tests/e2e/flashblocks.rs b/tests/e2e/flashblocks.rs index 78abdc83..6b442d40 100644 --- a/tests/e2e/flashblocks.rs +++ b/tests/e2e/flashblocks.rs @@ -1,1069 +1,285 @@ +//! E2E tests for flashblock integration. +//! +//! These tests verify the complete flow: flashblock stream → FlashBlockService → +//! pending block construction → RPC receipt availability. + +use crate::e2e::{setup_test_boilerplate, test_signer}; +use alloy_consensus::BlockHeader; +use alloy_eips::eip2718::Encodable2718; +use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; +use alloy_provider::Provider; use bera_reth::{ + engine::validator::BerachainEngineValidatorBuilder, flashblocks::{ BerachainFlashblockPayload, BerachainFlashblockPayloadBase, BerachainFlashblockPayloadDiff, BerachainFlashblockPayloadMetadata, }, node::BerachainNode, - primitives::header::BlsPublicKey, + primitives::{BerachainPrimitives, header::BlsPublicKey}, + rpc::{BerachainAddOns, BerachainEthApiBuilder}, }; -use futures_util::stream::StreamExt; -use reth_optimism_flashblocks::WsFlashBlockStream; - -#[tokio::test] -#[ignore = "requires external network access to Base sepolia"] -async fn test_streaming_flashblocks_from_remote_source_is_successful() { - let items = 3; - let ws_url = "wss://sepolia.flashblocks.base.org/ws".parse().unwrap(); - let stream: WsFlashBlockStream<_, _, _, BerachainFlashblockPayload> = - WsFlashBlockStream::new(ws_url); - - let blocks: Vec<_> = stream.take(items).collect().await; - - for block in blocks { - println!("{:?}", block); - assert!(block.is_ok()); - } -} - -#[cfg(test)] -mod mock_stream_tests { - use super::*; - use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; - use futures_util::stream; - use reth::rpc::types::engine::PayloadId; - use reth_optimism_flashblocks::{ - FlashBlockPendingSequence, FlashblockPayload, FlashblockPayloadBase, +use reth::{providers::BlockReaderIdExt, rpc::types::engine::PayloadId}; +use reth_chainspec::EthChainSpec; +use reth_e2e_test_utils::transaction::TransactionTestContext; +use reth_node_builder::{Node, NodeBuilder, NodeHandle}; +use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; +use reth_optimism_flashblocks::{ + FlashBlockCompleteSequence, FlashBlockService, FlashblocksListeners, +}; +use std::{pin::Pin, sync::Arc, task::Poll, time::Duration}; +use tokio::sync::{broadcast, watch}; + +fn create_test_flashblock( + index: u64, + block_number: u64, + payload_id: PayloadId, + parent_hash: B256, + timestamp: u64, +) -> BerachainFlashblockPayload { + let base = if index == 0 { + Some(BerachainFlashblockPayloadBase { + parent_beacon_block_root: B256::random(), + parent_hash, + fee_recipient: Address::random(), + prev_randao: B256::random(), + block_number, + gas_limit: 30_000_000, + timestamp, + extra_data: Bytes::default(), + base_fee_per_gas: U256::from(1_000_000_000u64), + prev_proposer_pubkey: Some(BlsPublicKey::random()), + }) + } else { + None }; - fn create_test_flashblock( - index: u64, - block_number: u64, - payload_id: PayloadId, - parent_hash: B256, - include_base: bool, - ) -> BerachainFlashblockPayload { - let base = if include_base { - Some(BerachainFlashblockPayloadBase { - parent_beacon_block_root: B256::random(), - parent_hash, - fee_recipient: Address::random(), - prev_randao: B256::random(), - block_number, - gas_limit: 30_000_000, - timestamp: 1_000_000 + block_number * 2, - extra_data: Bytes::default(), - base_fee_per_gas: U256::from(1_000_000_000u64), - prev_proposer_pubkey: Some(BlsPublicKey::random()), - }) - } else { - None - }; - - BerachainFlashblockPayload { - payload_id, - index, - base, - diff: BerachainFlashblockPayloadDiff { - state_root: B256::random(), - receipts_root: B256::random(), - logs_bloom: Bloom::default(), - gas_used: 21000 * (index + 1), - block_hash: B256::random(), - transactions: vec![Bytes::from_static(&[1, 2, 3])], - withdrawals: vec![], - withdrawals_root: B256::ZERO, - blob_gas_used: None, - }, - metadata: BerachainFlashblockPayloadMetadata { block_number }, - } - } - - fn create_flashblock_sequence(count: usize) -> Vec { - let payload_id = PayloadId::new([1u8; 8]); - let parent_hash = B256::random(); - - (0..count as u64) - .map(|i| create_test_flashblock(i, 100, payload_id, parent_hash, i == 0)) - .collect() - } - - #[tokio::test] - async fn test_mock_stream_produces_flashblocks() { - let flashblocks = create_flashblock_sequence(3); - let mut stream = stream::iter(flashblocks.clone().into_iter().map(Ok::<_, eyre::Error>)); - - let mut received = Vec::new(); - while let Some(result) = stream.next().await { - received.push(result.unwrap()); - } - - assert_eq!(received.len(), 3); - assert_eq!(received[0].index(), 0); - assert_eq!(received[1].index(), 1); - assert_eq!(received[2].index(), 2); - - assert!(received[0].base().is_some()); - assert!(received[1].base().is_none()); - assert!(received[2].base().is_none()); - } - - #[tokio::test] - async fn test_pending_sequence_processes_stream() { - let flashblocks = create_flashblock_sequence(5); - let mut sequence: FlashBlockPendingSequence = - FlashBlockPendingSequence::new(); - - for fb in flashblocks { - sequence.insert(fb); - } - - assert_eq!(sequence.count(), 5); - assert_eq!(sequence.block_number(), Some(100)); - assert_eq!(sequence.index(), Some(4)); - } - - #[tokio::test] - async fn test_complete_sequence_from_stream() { - let flashblocks = create_flashblock_sequence(3); - let mut sequence: FlashBlockPendingSequence = - FlashBlockPendingSequence::new(); - - for fb in flashblocks { - sequence.insert(fb); - } - - let complete = sequence.finalize().expect("should finalize"); - - assert_eq!(complete.count(), 3); - assert_eq!(complete.block_number(), 100); - - let all_txs = complete.all_transactions(); - assert_eq!(all_txs.len(), 3); - - let base = complete.payload_base(); - assert!(base.prev_proposer_pubkey.is_some()); - } - - #[tokio::test] - async fn test_stream_handles_new_block_sequence() { - let payload_id1 = PayloadId::new([1u8; 8]); - let payload_id2 = PayloadId::new([2u8; 8]); - let parent_hash1 = B256::random(); - - let fb0_block100 = create_test_flashblock(0, 100, payload_id1, parent_hash1, true); - let fb1_block100 = create_test_flashblock(1, 100, payload_id1, parent_hash1, false); - let block100_hash = fb1_block100.diff.block_hash; - - let fb0_block101 = create_test_flashblock(0, 101, payload_id2, block100_hash, true); - let fb1_block101 = create_test_flashblock(1, 101, payload_id2, block100_hash, false); - - let mut sequence: FlashBlockPendingSequence = - FlashBlockPendingSequence::new(); - - sequence.insert(fb0_block100); - sequence.insert(fb1_block100); - assert_eq!(sequence.count(), 2); - assert_eq!(sequence.block_number(), Some(100)); - - let complete_100 = sequence.finalize().expect("should finalize block 100"); - assert_eq!(complete_100.block_number(), 100); - - sequence.insert(fb0_block101); - sequence.insert(fb1_block101); - assert_eq!(sequence.count(), 2); - assert_eq!(sequence.block_number(), Some(101)); - - let complete_101 = sequence.finalize().expect("should finalize block 101"); - assert_eq!(complete_101.block_number(), 101); - } - - #[tokio::test] - async fn test_stream_rejects_out_of_order_flashblocks() { - let payload_id = PayloadId::new([1u8; 8]); - let parent_hash = B256::random(); - - let fb0 = create_test_flashblock(0, 100, payload_id, parent_hash, true); - let fb2_wrong_payload = - create_test_flashblock(2, 100, PayloadId::new([99u8; 8]), parent_hash, false); - - let mut sequence: FlashBlockPendingSequence = - FlashBlockPendingSequence::new(); - - sequence.insert(fb0); - sequence.insert(fb2_wrong_payload); - - assert_eq!(sequence.count(), 1); - } - - #[tokio::test] - async fn test_berachain_specific_fields_preserved() { - let pubkey = BlsPublicKey::random(); - let parent_hash = B256::random(); - let payload_id = PayloadId::new([1u8; 8]); - - let fb = BerachainFlashblockPayload { - payload_id, - index: 0, - base: Some(BerachainFlashblockPayloadBase { - parent_beacon_block_root: B256::random(), - parent_hash, - fee_recipient: Address::random(), - prev_randao: B256::random(), - block_number: 100, - gas_limit: 30_000_000, - timestamp: 1_000_000, - extra_data: Bytes::default(), - base_fee_per_gas: U256::from(1_000_000_000u64), - prev_proposer_pubkey: Some(pubkey), - }), - diff: BerachainFlashblockPayloadDiff { - state_root: B256::random(), - receipts_root: B256::random(), - logs_bloom: Bloom::default(), - gas_used: 21000, - block_hash: B256::random(), - transactions: vec![], - withdrawals: vec![], - withdrawals_root: B256::ZERO, - blob_gas_used: None, - }, - metadata: BerachainFlashblockPayloadMetadata { block_number: 100 }, - }; - - let mut sequence: FlashBlockPendingSequence = - FlashBlockPendingSequence::new(); - sequence.insert(fb); - - let complete = sequence.finalize().expect("should finalize"); - let base = complete.payload_base(); - - assert_eq!(base.prev_proposer_pubkey, Some(pubkey)); - assert_eq!(base.block_number(), 100); - assert_eq!(base.timestamp(), 1_000_000); - assert_eq!(base.parent_hash(), parent_hash); - } - - #[tokio::test] - async fn test_transaction_aggregation_across_flashblocks() { - let payload_id = PayloadId::new([1u8; 8]); - let parent_hash = B256::random(); - - let mut fb0 = create_test_flashblock(0, 100, payload_id, parent_hash, true); - fb0.diff.transactions = vec![Bytes::from_static(&[0xaa]), Bytes::from_static(&[0xbb])]; - - let mut fb1 = create_test_flashblock(1, 100, payload_id, parent_hash, false); - fb1.diff.transactions = vec![Bytes::from_static(&[0xcc])]; - - let mut fb2 = create_test_flashblock(2, 100, payload_id, parent_hash, false); - fb2.diff.transactions = vec![Bytes::from_static(&[0xdd]), Bytes::from_static(&[0xee])]; - - let mut sequence: FlashBlockPendingSequence = - FlashBlockPendingSequence::new(); - - sequence.insert(fb0); - sequence.insert(fb1); - sequence.insert(fb2); - - let complete = sequence.finalize().expect("should finalize"); - let all_txs = complete.all_transactions(); - - assert_eq!(all_txs.len(), 5); - assert_eq!(all_txs[0], Bytes::from_static(&[0xaa])); - assert_eq!(all_txs[1], Bytes::from_static(&[0xbb])); - assert_eq!(all_txs[2], Bytes::from_static(&[0xcc])); - assert_eq!(all_txs[3], Bytes::from_static(&[0xdd])); - assert_eq!(all_txs[4], Bytes::from_static(&[0xee])); + BerachainFlashblockPayload { + payload_id, + index, + base, + diff: BerachainFlashblockPayloadDiff { + state_root: B256::random(), + receipts_root: B256::random(), + logs_bloom: Bloom::default(), + gas_used: 21000, + block_hash: B256::random(), + transactions: vec![], + withdrawals: vec![], + withdrawals_root: B256::ZERO, + blob_gas_used: None, + }, + metadata: BerachainFlashblockPayloadMetadata { block_number }, } } -#[cfg(test)] -mod service_integration_tests { - use super::*; - use crate::e2e::setup_test_boilerplate; - use alloy_consensus::{ - BlockHeader, - transaction::{SignerRecoverable, TxHashRef}, - }; - use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; - use bera_reth::{ - evm::BerachainEvmFactory, node::evm::config::BerachainEvmConfig, - primitives::BerachainPrimitives, - }; - use reth::{providers::BlockReaderIdExt, rpc::types::engine::PayloadId}; - use reth_chainspec::EthChainSpec; - use reth_node_builder::{NodeBuilder, NodeHandle}; - use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; - use reth_optimism_flashblocks::{ - FlashBlockCompleteSequence, FlashBlockService, FlashblockPayload, PendingFlashBlock, - }; - use std::{pin::Pin, task::Poll, time::Duration}; - use tokio::sync::watch; - - fn create_test_flashblock_for_parent( - index: u64, - block_number: u64, - payload_id: PayloadId, - parent_hash: B256, - timestamp: u64, - ) -> BerachainFlashblockPayload { - let base = if index == 0 { - Some(BerachainFlashblockPayloadBase { - parent_beacon_block_root: B256::random(), - parent_hash, - fee_recipient: Address::random(), - prev_randao: B256::random(), - block_number, - gas_limit: 30_000_000, - timestamp, - extra_data: Bytes::default(), - base_fee_per_gas: U256::from(1_000_000_000u64), - prev_proposer_pubkey: Some(BlsPublicKey::random()), - }) - } else { - None - }; - - BerachainFlashblockPayload { - payload_id, - index, - base, - diff: BerachainFlashblockPayloadDiff { - state_root: B256::random(), - receipts_root: B256::random(), - logs_bloom: Bloom::default(), - gas_used: 21000, - block_hash: B256::random(), - transactions: vec![], - withdrawals: vec![], - withdrawals_root: B256::ZERO, - blob_gas_used: None, - }, - metadata: BerachainFlashblockPayloadMetadata { block_number }, - } - } - - struct MockFlashblockStream { - rx: tokio::sync::mpsc::Receiver, - } - - impl futures_util::Stream for MockFlashblockStream { - type Item = eyre::Result; - - fn poll_next( - mut self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> Poll> { - match Pin::new(&mut self.rx).poll_recv(cx) { - Poll::Ready(Some(fb)) => Poll::Ready(Some(Ok(fb))), - Poll::Ready(None) => Poll::Ready(None), - Poll::Pending => Poll::Pending, - } - } - } - - #[tokio::test] - async fn test_flashblock_service_receives_and_broadcasts() -> eyre::Result<()> { - let (tasks, chain_spec) = setup_test_boilerplate().await?; - let executor = tasks.executor(); - - let node_config = NodeConfig::new(chain_spec.clone()) - .with_unused_ports() - .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); - - let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) - .testing_node(executor.clone()) - .node(BerachainNode::default()) - .launch() - .await?; - - let evm_config = BerachainEvmConfig::new_with_evm_factory( - chain_spec.clone(), - BerachainEvmFactory::default(), - ); - let provider = node.provider().clone(); - - let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); - let stream = MockFlashblockStream { rx: fb_rx }; - - let service = FlashBlockService::new(stream, evm_config, provider, executor.clone(), false); - - let mut received_rx = service.flashblocks_broadcaster().subscribe(); - let mut sequence_rx = service.subscribe_block_sequence(); - - let (pending_tx, _pending_rx) = watch::channel(None); - executor.spawn_critical( - "flashblock-service", - Box::pin(async move { - service.run(pending_tx).await; - }), - ); - - let latest = node.provider().latest_header()?.expect("should have genesis"); - let latest_hash = latest.hash(); - let next_block = latest.number() + 1; - let next_timestamp = latest.timestamp() + 2; - - let payload_id = PayloadId::new([1u8; 8]); - let fb0 = create_test_flashblock_for_parent( - 0, - next_block, - payload_id, - latest_hash, - next_timestamp, - ); - - fb_tx.send(fb0.clone()).await?; - - let received = - tokio::time::timeout(Duration::from_millis(500), received_rx.recv()).await??; - - assert_eq!(received.index, 0); - assert_eq!(received.payload_id, payload_id); - assert_eq!(received.metadata.block_number, next_block); - - let fb1 = create_test_flashblock_for_parent( - 1, - next_block, - payload_id, - latest_hash, - next_timestamp, - ); - fb_tx.send(fb1).await?; - - let received2 = - tokio::time::timeout(Duration::from_millis(500), received_rx.recv()).await??; - assert_eq!(received2.index, 1); - - let payload_id2 = PayloadId::new([2u8; 8]); - let fb_next_block = create_test_flashblock_for_parent( - 0, - next_block + 1, - payload_id2, - B256::random(), - next_timestamp + 2, - ); - fb_tx.send(fb_next_block).await?; - - let sequence: FlashBlockCompleteSequence = - tokio::time::timeout(Duration::from_millis(500), sequence_rx.recv()).await??; - - assert_eq!(sequence.block_number(), next_block); - assert_eq!(sequence.count(), 2); - - Ok(()) - } - - #[tokio::test] - async fn test_flashblock_service_builds_pending_block() -> eyre::Result<()> { - let (tasks, chain_spec) = setup_test_boilerplate().await?; - let executor = tasks.executor(); - - let node_config = NodeConfig::new(chain_spec.clone()) - .with_unused_ports() - .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); - - let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) - .testing_node(executor.clone()) - .node(BerachainNode::default()) - .launch() - .await?; - - let evm_config = BerachainEvmConfig::new_with_evm_factory( - chain_spec.clone(), - BerachainEvmFactory::default(), - ); - let provider = node.provider().clone(); - - let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); - let stream = MockFlashblockStream { rx: fb_rx }; - - let service = - FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); - - let mut in_progress_rx = service.subscribe_in_progress(); - - let (pending_tx, mut pending_rx) = watch::channel(None); - executor.spawn_critical( - "flashblock-service", - Box::pin(async move { - service.run(pending_tx).await; - }), - ); - - let latest = node.provider().latest_header()?.expect("should have genesis"); - let latest_hash = latest.hash(); - let next_block = latest.number() + 1; - let next_timestamp = latest.timestamp() + 2; - - let payload_id = PayloadId::new([1u8; 8]); - let fb0 = create_test_flashblock_for_parent( - 0, - next_block, - payload_id, - latest_hash, - next_timestamp, - ); - - fb_tx.send(fb0).await?; - - in_progress_rx.changed().await?; - let build_info = *in_progress_rx.borrow(); - - if let Some(info) = build_info { - assert_eq!(info.block_number, next_block); - assert_eq!(info.parent_hash, latest_hash); - } - - pending_rx.changed().await?; - let pending_block: Option> = - pending_rx.borrow().clone(); - - if let Some(pending) = pending_block { - assert_eq!(pending.parent_hash(), latest_hash); - } - - Ok(()) - } - - #[tokio::test] - async fn test_flashblock_service_validates_parent_hash() -> eyre::Result<()> { - let (tasks, chain_spec) = setup_test_boilerplate().await?; - let executor = tasks.executor(); - - let node_config = NodeConfig::new(chain_spec.clone()) - .with_unused_ports() - .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); - - let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) - .testing_node(executor.clone()) - .node(BerachainNode::default()) - .launch() - .await?; - - let evm_config = BerachainEvmConfig::new_with_evm_factory( - chain_spec.clone(), - BerachainEvmFactory::default(), - ); - let provider = node.provider().clone(); - - let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); - let stream = MockFlashblockStream { rx: fb_rx }; - - let service = - FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); - - let (pending_tx, mut pending_rx) = watch::channel(None); - executor.spawn_critical( - "flashblock-service", - Box::pin(async move { - service.run(pending_tx).await; - }), - ); - - let latest = node.provider().latest_header()?.expect("should have genesis"); - let next_block = latest.number() + 1; - let next_timestamp = latest.timestamp() + 2; - - let wrong_parent_hash = B256::random(); - let payload_id = PayloadId::new([1u8; 8]); - let fb_wrong_parent = create_test_flashblock_for_parent( - 0, - next_block, - payload_id, - wrong_parent_hash, - next_timestamp, - ); - - fb_tx.send(fb_wrong_parent).await?; - - let result = tokio::time::timeout(Duration::from_millis(200), pending_rx.changed()).await; - - assert!(result.is_err(), "Should not build pending block with wrong parent hash"); - - Ok(()) - } - - #[tokio::test] - async fn test_flashblock_service_with_real_transactions() -> eyre::Result<()> { - use crate::e2e::test_signer; - use alloy_eips::eip2718::Encodable2718; - use reth_e2e_test_utils::transaction::TransactionTestContext; - - let (tasks, chain_spec) = setup_test_boilerplate().await?; - let executor = tasks.executor(); - - let node_config = NodeConfig::new(chain_spec.clone()) - .with_unused_ports() - .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); - - let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) - .testing_node(executor.clone()) - .node(BerachainNode::default()) - .launch() - .await?; - - let evm_config = BerachainEvmConfig::new_with_evm_factory( - chain_spec.clone(), - BerachainEvmFactory::default(), - ); - let provider = node.provider().clone(); - - let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); - let stream = MockFlashblockStream { rx: fb_rx }; - - let service = - FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); - - let (pending_tx, mut pending_rx) = watch::channel(None); - executor.spawn_critical( - "flashblock-service", - Box::pin(async move { - service.run(pending_tx).await; - }), - ); - - let latest = node.provider().latest_header()?.expect("should have genesis"); - let latest_hash = latest.hash(); - let next_block = latest.number() + 1; - let next_timestamp = latest.timestamp() + 2; - - let signer = test_signer()?; - let signer_address = signer.address(); - let chain_id = chain_spec.chain_id(); - let signed_tx = TransactionTestContext::transfer_tx(chain_id, signer).await; - let tx_bytes = Bytes::from(signed_tx.encoded_2718()); - let tx_hash = *signed_tx.tx_hash(); - - let payload_id = PayloadId::new([1u8; 8]); - let mut fb0 = create_test_flashblock_for_parent( - 0, - next_block, - payload_id, - latest_hash, - next_timestamp, - ); - fb0.diff.transactions = vec![tx_bytes.clone()]; - fb0.diff.gas_used = 21000; - - fb_tx.send(fb0).await?; - - pending_rx.changed().await?; - let pending_block: Option> = - pending_rx.borrow().clone(); - - let pending = pending_block.expect("should have pending block"); - assert_eq!(pending.parent_hash(), latest_hash); - - let block = pending.block(); - let block_txs = &block.body().transactions; - - assert!( - !block_txs.is_empty(), - "Block should contain at least 1 transaction, got {}", - block_txs.len() - ); - - let user_tx = block_txs - .iter() - .find(|tx| *tx.hash() == tx_hash) - .expect("User transaction should be in the block"); - - let recovered_sender = user_tx.recover_signer().expect("should recover signer"); - assert_eq!(recovered_sender, signer_address, "Recovered sender should match signer"); - - Ok(()) - } - - #[tokio::test] - async fn test_flashblock_pending_block_contains_correct_header_fields() -> eyre::Result<()> { - let (tasks, chain_spec) = setup_test_boilerplate().await?; - let executor = tasks.executor(); - - let node_config = NodeConfig::new(chain_spec.clone()) - .with_unused_ports() - .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); - - let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) - .testing_node(executor.clone()) - .node(BerachainNode::default()) - .launch() - .await?; - - let evm_config = BerachainEvmConfig::new_with_evm_factory( - chain_spec.clone(), - BerachainEvmFactory::default(), - ); - let provider = node.provider().clone(); - - let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); - let stream = MockFlashblockStream { rx: fb_rx }; - - let service = - FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); - - let (pending_tx, mut pending_rx) = watch::channel(None); - executor.spawn_critical( - "flashblock-service", - Box::pin(async move { - service.run(pending_tx).await; - }), - ); - - let latest = node.provider().latest_header()?.expect("should have genesis"); - let latest_hash = latest.hash(); - let next_block = latest.number() + 1; - let next_timestamp = latest.timestamp() + 2; - - let payload_id = PayloadId::new([1u8; 8]); - let fb0 = create_test_flashblock_for_parent( - 0, - next_block, - payload_id, - latest_hash, - next_timestamp, - ); - - let expected_prev_proposer = fb0.base.as_ref().unwrap().prev_proposer_pubkey; - - fb_tx.send(fb0).await?; - - pending_rx.changed().await?; - let pending_block: Option> = - pending_rx.borrow().clone(); - - let pending = pending_block.expect("should have pending block"); - let block = pending.block(); - let header = block.header(); - - assert_eq!(header.number, next_block, "Block number mismatch"); - assert_eq!(header.timestamp, next_timestamp, "Timestamp mismatch"); - assert_eq!(header.parent_hash, latest_hash, "Parent hash mismatch"); - assert_eq!(header.gas_limit, 30_000_000, "Gas limit mismatch"); - assert_eq!( - header.prev_proposer_pubkey, expected_prev_proposer, - "prev_proposer_pubkey should be preserved" - ); - - Ok(()) - } - - #[tokio::test] - async fn test_flashblock_multiple_transactions_across_flashblocks() -> eyre::Result<()> { - use crate::e2e::test_signer; - use alloy_eips::eip2718::Encodable2718; - use alloy_signer_local::PrivateKeySigner; - use reth_e2e_test_utils::transaction::TransactionTestContext; - - let (tasks, chain_spec) = setup_test_boilerplate().await?; - let executor = tasks.executor(); - - let node_config = NodeConfig::new(chain_spec.clone()) - .with_unused_ports() - .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); - - let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) - .testing_node(executor.clone()) - .node(BerachainNode::default()) - .launch() - .await?; - - let evm_config = BerachainEvmConfig::new_with_evm_factory( - chain_spec.clone(), - BerachainEvmFactory::default(), - ); - let provider = node.provider().clone(); - - let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); - let stream = MockFlashblockStream { rx: fb_rx }; - - let service = - FlashBlockService::new(stream, evm_config, provider.clone(), executor.clone(), false); - - let mut sequence_rx = service.subscribe_block_sequence(); - - let (pending_tx, _pending_rx) = watch::channel(None); - executor.spawn_critical( - "flashblock-service", - Box::pin(async move { - service.run(pending_tx).await; - }), - ); - - let latest = node.provider().latest_header()?.expect("should have genesis"); - let latest_hash = latest.hash(); - let next_block = latest.number() + 1; - let next_timestamp = latest.timestamp() + 2; - - let signer1 = test_signer()?; - let signer1_address = signer1.address(); - let signer2 = PrivateKeySigner::random(); - let signer2_address = signer2.address(); - - let chain_id = chain_spec.chain_id(); - let tx1 = TransactionTestContext::transfer_tx(chain_id, signer1).await; - let tx1_bytes = Bytes::from(tx1.encoded_2718()); - let tx1_hash = *tx1.tx_hash(); - - let tx2 = TransactionTestContext::transfer_tx(chain_id, signer2).await; - let tx2_bytes = Bytes::from(tx2.encoded_2718()); - let tx2_hash = *tx2.tx_hash(); - - let payload_id = PayloadId::new([1u8; 8]); - - let mut fb0 = create_test_flashblock_for_parent( - 0, - next_block, - payload_id, - latest_hash, - next_timestamp, - ); - fb0.diff.transactions = vec![tx1_bytes]; - fb0.diff.gas_used = 21000; - - let mut fb1 = create_test_flashblock_for_parent( - 1, - next_block, - payload_id, - latest_hash, - next_timestamp, - ); - fb1.diff.transactions = vec![tx2_bytes]; - fb1.diff.gas_used = 42000; - - fb_tx.send(fb0).await?; - fb_tx.send(fb1).await?; - - let payload_id2 = PayloadId::new([2u8; 8]); - let fb_next = create_test_flashblock_for_parent( - 0, - next_block + 1, - payload_id2, - B256::random(), - next_timestamp + 2, - ); - fb_tx.send(fb_next).await?; - - let sequence: FlashBlockCompleteSequence = - tokio::time::timeout(Duration::from_millis(500), sequence_rx.recv()).await??; - - assert_eq!(sequence.count(), 2); - assert_eq!(sequence.block_number(), next_block); - - let all_txs = sequence.all_transactions(); - assert_eq!(all_txs.len(), 2, "Should have 2 transactions total"); - - let recovered_txs: Vec<_> = sequence - .iter() - .flat_map(|fb| fb.recover_transactions()) - .collect::, _>>()?; - - assert_eq!(recovered_txs.len(), 2); - assert_eq!(*recovered_txs[0].value().tx_hash(), tx1_hash); - assert_eq!(*recovered_txs[1].value().tx_hash(), tx2_hash); - assert_eq!(recovered_txs[0].value().signer(), signer1_address); - assert_eq!(recovered_txs[1].value().signer(), signer2_address); - - Ok(()) - } +struct MockFlashblockStream { + rx: tokio::sync::mpsc::Receiver, } -#[cfg(test)] -mod rpc_integration_tests { - use super::*; - use crate::e2e::{setup_test_boilerplate, test_signer}; - use alloy_consensus::BlockHeader; - use alloy_eips::eip2718::Encodable2718; - use alloy_primitives::{Address, B256, Bloom, Bytes, U256}; - use alloy_provider::Provider; - use bera_reth::{ - engine::validator::BerachainEngineValidatorBuilder, - primitives::BerachainPrimitives, - rpc::{BerachainAddOns, BerachainEthApiBuilder}, - }; - use reth::{providers::BlockReaderIdExt, rpc::types::engine::PayloadId}; - use reth_chainspec::EthChainSpec; - use reth_e2e_test_utils::transaction::TransactionTestContext; - use reth_node_builder::{Node, NodeBuilder, NodeHandle}; - use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; - use reth_optimism_flashblocks::{FlashBlockService, FlashblocksListeners}; - use std::{pin::Pin, sync::Arc, task::Poll, time::Duration}; - use tokio::sync::watch; - - fn create_test_flashblock_for_parent( - index: u64, - block_number: u64, - payload_id: PayloadId, - parent_hash: B256, - timestamp: u64, - ) -> BerachainFlashblockPayload { - let base = if index == 0 { - Some(BerachainFlashblockPayloadBase { - parent_beacon_block_root: B256::random(), - parent_hash, - fee_recipient: Address::random(), - prev_randao: B256::random(), - block_number, - gas_limit: 30_000_000, - timestamp, - extra_data: Bytes::default(), - base_fee_per_gas: U256::from(1_000_000_000u64), - prev_proposer_pubkey: Some(BlsPublicKey::random()), - }) - } else { - None - }; - - BerachainFlashblockPayload { - payload_id, - index, - base, - diff: BerachainFlashblockPayloadDiff { - state_root: B256::random(), - receipts_root: B256::random(), - logs_bloom: Bloom::default(), - gas_used: 21000, - block_hash: B256::random(), - transactions: vec![], - withdrawals: vec![], - withdrawals_root: B256::ZERO, - blob_gas_used: None, - }, - metadata: BerachainFlashblockPayloadMetadata { block_number }, +impl futures_util::Stream for MockFlashblockStream { + type Item = eyre::Result; + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + match Pin::new(&mut self.rx).poll_recv(cx) { + Poll::Ready(Some(fb)) => Poll::Ready(Some(Ok(fb))), + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, } } +} - struct MockFlashblockStream { - rx: tokio::sync::mpsc::Receiver, - } - - impl futures_util::Stream for MockFlashblockStream { - type Item = eyre::Result; - - fn poll_next( - mut self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> Poll> { - match Pin::new(&mut self.rx).poll_recv(cx) { - Poll::Ready(Some(fb)) => Poll::Ready(Some(Ok(fb))), - Poll::Ready(None) => Poll::Ready(None), - Poll::Pending => Poll::Pending, - } - } - } - - #[tokio::test] - async fn test_rpc_returns_flashblock_pending_receipt() -> eyre::Result<()> { - use reth_optimism_flashblocks::FlashBlockCompleteSequence; - use tokio::sync::broadcast; - - let (tasks, chain_spec) = setup_test_boilerplate().await?; - let executor = tasks.executor(); - - // Create channels that connect the FlashBlockService to the RPC layer's - // FlashblocksListeners. - // - pending_tx: service writes pending blocks here, RPC reads from pending_rx - // - in_progress_tx: we manually forward service state to RPC (see below) - let (pending_tx, pending_rx) = watch::channel(None); - let (in_progress_tx, in_progress_rx) = watch::channel(None); - - // These channels are required by FlashblocksListeners but not used in this test. - // The service has its own internal broadcasters for these. - let (unused_sequence_tx, _) = - broadcast::channel::>(1); - let (unused_received_tx, _) = broadcast::channel::>(1); - - let listeners: FlashblocksListeners = - FlashblocksListeners::new( - pending_rx, - unused_sequence_tx, - in_progress_rx, - unused_received_tx, - ); - - let eth_api_builder = - BerachainEthApiBuilder::default().with_flashblocks_listeners(listeners); - let add_ons = - BerachainAddOns::<_, _, BerachainEngineValidatorBuilder>::new(eth_api_builder); - - let node_config = NodeConfig::new(chain_spec.clone()) - .with_unused_ports() - .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); - - let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) - .testing_node(executor.clone()) - .with_types::() - .with_components(BerachainNode::default().components_builder()) - .with_add_ons(add_ons) - .launch() - .await?; - - let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); - let stream = MockFlashblockStream { rx: fb_rx }; - - let service = FlashBlockService::new( - stream, - node.evm_config.clone(), - node.provider().clone(), - executor.clone(), - false, - ); - - let mut service_in_progress_rx = service.subscribe_in_progress(); - - executor.spawn_critical( - "flashblock-service", - Box::pin(async move { - service.run(pending_tx).await; - }), - ); - - let latest = node.provider().latest_header()?.expect("should have genesis"); - let latest_hash = latest.hash(); - let next_block = latest.number() + 1; - let next_timestamp = latest.timestamp() + 2; - - let signer = test_signer()?; - let chain_id = chain_spec.chain_id(); - let tx = TransactionTestContext::transfer_tx(chain_id, signer).await; - let tx_bytes = Bytes::from(tx.encoded_2718()); - let tx_hash = *tx.tx_hash(); - - let payload_id = PayloadId::new([1u8; 8]); - - let mut fb0 = create_test_flashblock_for_parent( - 0, - next_block, - payload_id, - latest_hash, - next_timestamp, - ); - fb0.diff.transactions = vec![tx_bytes]; - fb0.diff.gas_used = 21000; - - fb_tx.send(fb0).await?; - - tokio::time::timeout(Duration::from_millis(500), service_in_progress_rx.changed()) - .await??; - in_progress_tx.send(*service_in_progress_rx.borrow())?; - - tokio::time::sleep(Duration::from_millis(100)).await; - - let rpc_url = format!( - "http://127.0.0.1:{}", - node.rpc_server_handle().http_local_addr().unwrap().port() - ); - let rpc_client = alloy_provider::ProviderBuilder::new().connect(&rpc_url).await?; - - let receipt = rpc_client.get_transaction_receipt(tx_hash).await?; - - assert!( - receipt.is_some(), - "Transaction receipt should be available from flashblock pending state" +/// Tests the complete flashblock → pending block → RPC receipt flow. +/// +/// # Data Flow +/// +/// This test wires together two separate systems that need to communicate: +/// +/// ```text +/// TEST HARNESS NODE (RPC) +/// ──────────── ────────── +/// +/// fb_tx ──────► MockFlashblockStream +/// │ +/// ▼ +/// FlashBlockService +/// │ │ +/// │ ▼ +/// │ service.subscribe_in_progress() +/// │ │ +/// ▼ │ (test manually bridges) +/// pending_tx ─────────┼──────────────────► pending_rx ──► RPC EthApi +/// │ (reads pending block) +/// ▼ +/// in_progress_tx ─────────► in_progress_rx ──► RPC EthApi +/// (knows build is active) +/// ``` +/// +/// The key insight is that `FlashblocksListeners` holds the rx ends of channels, which are +/// passed into the node at build time. The test harness holds the tx ends and must: +/// 1. Pass `pending_tx` to `service.run()` so the service can publish pending blocks +/// 2. Manually forward `in_progress` state from service → node (the service has its own internal +/// channel, so we subscribe and forward to the node's channel) +/// +/// When an RPC call like `eth_getTransactionReceipt` comes in, the EthApi checks +/// `pending_rx` for a flashblock-derived pending block containing that transaction. +#[tokio::test] +async fn test_rpc_returns_flashblock_pending_receipt() -> eyre::Result<()> { + let (tasks, chain_spec) = setup_test_boilerplate().await?; + let executor = tasks.executor(); + + // Channels that connect FlashBlockService (producer) to RPC EthApi (consumer). + // The service writes to pending_tx, the RPC reads from pending_rx. + let (pending_tx, pending_rx) = watch::channel(None); + + // in_progress channel tells RPC layer that a flashblock build is active. + // We manually bridge from service's internal channel to this one (see below). + let (in_progress_tx, in_progress_rx) = watch::channel(None); + + // These broadcast channels are for external listeners (e.g., websocket subscribers). + // Not used in this test but required by FlashblocksListeners constructor. + let (unused_sequence_tx, _) = + broadcast::channel::>(1); + let (unused_received_tx, _) = broadcast::channel::>(1); + + // FlashblocksListeners bundles the rx ends for the node's RPC layer. + let listeners: FlashblocksListeners = + FlashblocksListeners::new( + pending_rx, + unused_sequence_tx, + in_progress_rx, + unused_received_tx, ); - let receipt = receipt.unwrap(); - assert_eq!(receipt.transaction_hash, tx_hash); + let eth_api_builder = BerachainEthApiBuilder::default().with_flashblocks_listeners(listeners); + let add_ons = BerachainAddOns::<_, _, BerachainEngineValidatorBuilder>::new(eth_api_builder); + + let node_config = NodeConfig::new(chain_spec.clone()) + .with_unused_ports() + .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) + .testing_node(executor.clone()) + .with_types::() + .with_components(BerachainNode::default().components_builder()) + .with_add_ons(add_ons) + .launch() + .await?; + + // Create the flashblock input channel. Test sends flashblocks via fb_tx. + let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); + let stream = MockFlashblockStream { rx: fb_rx }; + + let service = FlashBlockService::new( + stream, + node.evm_config.clone(), + node.provider().clone(), + executor.clone(), + false, + ); + + // Subscribe to service's internal in_progress channel so we can forward to node's channel. + let mut service_in_progress_rx = service.subscribe_in_progress(); + + // Start the service, passing pending_tx so it can publish pending blocks to the RPC layer. + executor.spawn_critical( + "flashblock-service", + Box::pin(async move { + service.run(pending_tx).await; + }), + ); + + let latest = node.provider().latest_header()?.expect("should have genesis"); + let latest_hash = latest.hash(); + let next_block = latest.number() + 1; + let next_timestamp = latest.timestamp() + 2; + + let signer = test_signer()?; + let chain_id = chain_spec.chain_id(); + let tx = TransactionTestContext::transfer_tx(chain_id, signer).await; + let tx_bytes = Bytes::from(tx.encoded_2718()); + let tx_hash = *tx.tx_hash(); + + let payload_id = PayloadId::new([1u8; 8]); + let mut fb0 = create_test_flashblock(0, next_block, payload_id, latest_hash, next_timestamp); + fb0.diff.transactions = vec![tx_bytes]; + fb0.diff.gas_used = 21000; + + // Inject the flashblock into the service via our mock stream. + fb_tx.send(fb0).await?; + + // Wait for service to signal it's building, then forward that state to the node's channel. + tokio::time::timeout(Duration::from_millis(500), service_in_progress_rx.changed()).await??; + in_progress_tx.send(*service_in_progress_rx.borrow())?; + + // Give the service time to build and publish the pending block. + tokio::time::sleep(Duration::from_millis(100)).await; + + // Query the RPC - should find the transaction in the flashblock-derived pending block. + let rpc_url = + format!("http://127.0.0.1:{}", node.rpc_server_handle().http_local_addr().unwrap().port()); + let rpc_client = alloy_provider::ProviderBuilder::new().connect(&rpc_url).await?; + + let receipt = rpc_client.get_transaction_receipt(tx_hash).await?; + + assert!( + receipt.is_some(), + "Transaction receipt should be available from flashblock pending state" + ); + assert_eq!(receipt.unwrap().transaction_hash, tx_hash); + + Ok(()) +} - Ok(()) - } +/// Tests that flashblocks with invalid parent hashes are rejected. +#[tokio::test] +async fn test_flashblock_rejects_invalid_parent_hash() -> eyre::Result<()> { + let (tasks, chain_spec) = setup_test_boilerplate().await?; + let executor = tasks.executor(); + + let node_config = NodeConfig::new(chain_spec.clone()) + .with_unused_ports() + .with_rpc(RpcServerArgs::default().with_unused_ports().with_http()); + + let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config) + .testing_node(executor.clone()) + .node(BerachainNode::default()) + .launch() + .await?; + + let (fb_tx, fb_rx) = tokio::sync::mpsc::channel::(128); + let stream = MockFlashblockStream { rx: fb_rx }; + + let service = FlashBlockService::new( + stream, + node.evm_config.clone(), + node.provider().clone(), + executor.clone(), + false, + ); + + let (pending_tx, mut pending_rx) = watch::channel(None); + executor.spawn_critical( + "flashblock-service", + Box::pin(async move { + service.run(pending_tx).await; + }), + ); + + let latest = node.provider().latest_header()?.expect("should have genesis"); + let next_block = latest.number() + 1; + let next_timestamp = latest.timestamp() + 2; + + let wrong_parent_hash = B256::random(); + let payload_id = PayloadId::new([1u8; 8]); + let fb = create_test_flashblock(0, next_block, payload_id, wrong_parent_hash, next_timestamp); + + fb_tx.send(fb).await?; + + let result = tokio::time::timeout(Duration::from_millis(200), pending_rx.changed()).await; + assert!(result.is_err(), "Should not build pending block with wrong parent hash"); + + Ok(()) } From 5404de3216da7df1c477b0a234ab8845306d9ad3 Mon Sep 17 00:00:00 2001 From: Rez Date: Wed, 24 Dec 2025 00:15:58 +1100 Subject: [PATCH 10/12] cleanup and remove RPC bound which is only needed for OP consensus client --- src/engine/mod.rs | 12 ------------ src/flashblocks/mod.rs | 8 +++----- src/flashblocks/test_utils.rs | 4 ++-- src/rpc/mod.rs | 10 +--------- 4 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/engine/mod.rs b/src/engine/mod.rs index ebdc8f32..56bc8765 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -20,7 +20,6 @@ use crate::{ engine::payload::{ BerachainBuiltPayload, BerachainPayloadAttributes, BerachainPayloadBuilderAttributes, }, - flashblocks::BerachainFlashblockPayload, hardforks::BerachainHardforks, node::evm::error::BerachainExecutionError, primitives::header::BlsPublicKey, @@ -40,7 +39,6 @@ use reth::{ api::{BuiltPayload, EngineTypes, NodePrimitives, PayloadTypes}, core::primitives::SealedBlock, }; -use reth_optimism_flashblocks::FlashBlockCompleteSequence; use reth_payload_primitives::ExecutionPayload as ExecutionPayloadTrait; use std::hash::Hash; @@ -272,16 +270,6 @@ impl From for BerachainExecutionData { } } -impl TryFrom<&FlashBlockCompleteSequence> for BerachainExecutionData { - type Error = &'static str; - - fn try_from( - _sequence: &FlashBlockCompleteSequence, - ) -> Result { - todo!("implement conversion from FlashBlockCompleteSequence to BerachainExecutionData") - } -} - /// Validates that the proposer pubkey is present after Prague1 and absent before Prague1 pub fn validate_proposer_pubkey_prague1( chain_spec: &ChainSpec, diff --git a/src/flashblocks/mod.rs b/src/flashblocks/mod.rs index 875818cc..e581cd86 100644 --- a/src/flashblocks/mod.rs +++ b/src/flashblocks/mod.rs @@ -163,12 +163,10 @@ impl FlashblockPayload for BerachainFlashblockPayload { use alloy_consensus::transaction::SignerRecoverable; use alloy_eips::Decodable2718; - self.diff.transactions.clone().into_iter().map(|encoded| { - let tx = BerachainTxEnvelope::decode_2718(&mut encoded.as_ref()) + self.diff.transactions.clone().into_iter().map(|raw| { + let tx = BerachainTxEnvelope::decode_2718(&mut raw.as_ref()) .map_err(RecoveryError::from_source)?; - let signer = tx.recover_signer()?; - let recovered = Recovered::new_unchecked(tx, signer); - Ok(WithEncoded::new(encoded, recovered)) + tx.try_into_recovered().map(|tx| tx.into_encoded_with(raw.clone())) }) } } diff --git a/src/flashblocks/test_utils.rs b/src/flashblocks/test_utils.rs index 3bdf53aa..2648c370 100644 --- a/src/flashblocks/test_utils.rs +++ b/src/flashblocks/test_utils.rs @@ -154,8 +154,8 @@ impl BerachainTestFlashBlockBuilder { base, diff: BerachainFlashblockPayloadDiff { block_hash: B256::random(), - state_root: B256::ZERO, - receipts_root: B256::ZERO, + state_root: B256::random(), + receipts_root: B256::random(), logs_bloom: Bloom::default(), gas_used: 0, transactions: self.transactions, diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index 4a809c50..f929732d 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -38,9 +38,7 @@ use reth_node_builder::rpc::{ EthApiBuilder, EthApiCtx, PayloadValidatorBuilder, RethRpcAddOns, RethRpcMiddleware, RpcAddOns, RpcHandle, }; -use reth_optimism_flashblocks::{ - FlashBlockCompleteSequence, FlashBlockService, FlashblocksListeners, WsFlashBlockStream, -}; +use reth_optimism_flashblocks::{FlashBlockService, FlashblocksListeners, WsFlashBlockStream}; use reth_optimism_rpc::OpRpcTypes; use reth_rpc_convert::{RpcConvert, RpcConverter}; use reth_rpc_eth_api::helpers::pending_block::BuildPendingEnv; @@ -109,12 +107,6 @@ where Types: NodeTypes< ChainSpec: EthereumHardforks + Hardforks, Primitives = BerachainPrimitives, - Payload: reth_node_api::PayloadTypes< - ExecutionData: for<'a> TryFrom< - &'a FlashBlockCompleteSequence, - Error: std::fmt::Display, - >, - >, >, Evm: ConfigureEvm< NextBlockEnvCtx: BuildPendingEnv> From 88fe631a884f70b33c80f80442fb31427d1a6158 Mon Sep 17 00:00:00 2001 From: Rez Date: Wed, 24 Dec 2025 00:34:17 +1100 Subject: [PATCH 11/12] target rezbera reth --- Cargo.toml | 97 +++++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 303f2b34..c78ebfbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -115,51 +115,52 @@ lto = "thin" ignored = ["modular-bitfield"] [patch."https://github.com/paradigmxyz/reth"] -reth = { path = "../reth/bin/reth" } -reth-rpc = { path = "../reth/crates/rpc/rpc" } -reth-basic-payload-builder = { path = "../reth/crates/payload/basic" } -reth-chainspec = { path = "../reth/crates/chainspec" } -reth-cli = { path = "../reth/crates/cli/cli" } -reth-cli-commands = { path = "../reth/crates/cli/commands" } -reth-cli-util = { path = "../reth/crates/cli/util" } -reth-db = { path = "../reth/crates/storage/db" } -reth-engine-local = { path = "../reth/crates/engine/local" } -reth-engine-primitives = { path = "../reth/crates/engine/primitives" } -reth-errors = { path = "../reth/crates/errors" } -reth-ethereum-cli = { path = "../reth/crates/ethereum/cli" } -reth-engine-tree = { path = "../reth/crates/engine/tree" } -reth-ethereum-engine-primitives = { path = "../reth/crates/ethereum/engine-primitives" } -reth-ethereum-payload-builder = { path = "../reth/crates/ethereum/payload" } -reth-ethereum-primitives = { path = "../reth/crates/ethereum/primitives" } -reth-evm = { path = "../reth/crates/evm/evm" } -reth-evm-ethereum = { path = "../reth/crates/ethereum/evm" } -reth-network-peers = { path = "../reth/crates/net/peers" } -reth-node-api = { path = "../reth/crates/node/api" } -reth-node-builder = { path = "../reth/crates/node/builder" } -reth-node-core = { path = "../reth/crates/node/core" } -reth-payload-validator = { path = "../reth/crates/payload/validator" } -reth-node-ethereum = { path = "../reth/crates/ethereum/node" } -reth-payload-primitives = { path = "../reth/crates/payload/primitives" } -reth-primitives-traits = { path = "../reth/crates/primitives-traits" } -reth-tracing = { path = "../reth/crates/tracing" } -reth-codecs = { path = "../reth/crates/storage/codecs" } -reth-db-api = { path = "../reth/crates/storage/db-api" } -reth-rpc-engine-api = { path = "../reth/crates/rpc/rpc-engine-api" } -reth-rpc-eth-api = { path = "../reth/crates/rpc/rpc-eth-api" } -reth-rpc-eth-types = { path = "../reth/crates/rpc/rpc-eth-types" } -reth-rpc-convert = { path = "../reth/crates/rpc/rpc-convert" } -reth-transaction-pool = { path = "../reth/crates/transaction-pool" } -reth-zstd-compressors = { path = "../reth/crates/storage/zstd-compressors" } -reth-trie-common = { path = "../reth/crates/trie/common" } -reth-trie-db = { path = "../reth/crates/trie/db" } -reth-trie = { path = "../reth/crates/trie/trie" } -reth-stages-types = { path = "../reth/crates/stages/types" } -reth-execution-types = { path = "../reth/crates/evm/execution-types" } -reth-execution-errors = { path = "../reth/crates/evm/execution-errors" } -reth-storage-api = { path = "../reth/crates/storage/storage-api" } -reth-provider = { path = "../reth/crates/storage/provider" } -reth-storage-errors = { path = "../reth/crates/storage/errors" } -reth-e2e-test-utils = { path = "../reth/crates/e2e-test-utils" } -reth-rpc-builder = { path = "../reth/crates/rpc/rpc-builder" } -reth-optimism-flashblocks = { path = "../reth/crates/optimism/flashblocks" } -reth-optimism-rpc = { path = "../reth/crates/optimism/rpc" } +reth = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-rpc = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-basic-payload-builder = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-chainspec = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-cli = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-cli-commands = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-cli-util = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-db = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-engine-local = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-engine-primitives = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-errors = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-ethereum-cli = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-engine-tree = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-ethereum-engine-primitives = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-ethereum-payload-builder = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-ethereum-primitives = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-evm = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-evm-ethereum = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-network-peers = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-node-api = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-node-builder = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-node-core = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-payload-validator = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-node-ethereum = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-payload-primitives = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-primitives-traits = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-tracing = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-codecs = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-db-api = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-rpc-engine-api = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-rpc-eth-api = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-rpc-eth-types = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-rpc-convert = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-transaction-pool = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-zstd-compressors = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-trie-common = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-trie-db = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-trie = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-stages-types = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-execution-types = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-execution-errors = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-storage-api = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-provider = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-storage-errors = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-e2e-test-utils = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-rpc-builder = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-optimism-flashblocks = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-optimism-rpc = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } +reth-consensus-common = { git = "https://github.com/rezbera/reth", branch = "rezbera/modular-flashblocks" } From 86b62ae8cca79dc10684d4db0b9014c67dd92435 Mon Sep 17 00:00:00 2001 From: Rez Date: Fri, 26 Dec 2025 21:01:32 +1100 Subject: [PATCH 12/12] Update Cargo.toml and lint linty --- Cargo.lock | 212 +++++++++++++++++++++++++++++++++++-------------- Cargo.toml | 2 +- src/rpc/mod.rs | 8 +- 3 files changed, 156 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16f5ed52..ca5702ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -963,7 +963,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -974,7 +974,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1505,7 +1505,7 @@ dependencies = [ "reth-cli-commands", "reth-cli-util", "reth-codecs", - "reth-consensus-common 1.9.3 (git+https://github.com/paradigmxyz/reth?rev=536bebfcd)", + "reth-consensus-common", "reth-db", "reth-db-api", "reth-e2e-test-utils", @@ -2866,7 +2866,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3137,7 +3137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4033,7 +4033,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.57.0", + "windows-core 0.61.2", ] [[package]] @@ -5220,7 +5220,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -6516,6 +6516,7 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" [[package]] name = "reth" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-rpc-types", "aquamarine", @@ -6524,8 +6525,8 @@ dependencies = [ "reth-chainspec", "reth-cli-runner", "reth-cli-util", - "reth-consensus 1.9.3", - "reth-consensus-common 1.9.3", + "reth-consensus", + "reth-consensus-common", "reth-db", "reth-ethereum-cli", "reth-ethereum-payload-builder", @@ -6561,6 +6562,7 @@ dependencies = [ [[package]] name = "reth-basic-payload-builder" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6584,6 +6586,7 @@ dependencies = [ [[package]] name = "reth-chain-state" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6614,6 +6617,7 @@ dependencies = [ [[package]] name = "reth-chainspec" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-chains", "alloy-consensus", @@ -6633,6 +6637,7 @@ dependencies = [ [[package]] name = "reth-cli" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-genesis", "clap", @@ -6646,6 +6651,7 @@ dependencies = [ [[package]] name = "reth-cli-commands" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-chains", "alloy-consensus", @@ -6671,7 +6677,7 @@ dependencies = [ "reth-cli-util", "reth-codecs", "reth-config", - "reth-consensus 1.9.3", + "reth-consensus", "reth-db", "reth-db-api", "reth-db-common", @@ -6720,6 +6726,7 @@ dependencies = [ [[package]] name = "reth-cli-runner" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "reth-tasks", "tokio", @@ -6729,6 +6736,7 @@ dependencies = [ [[package]] name = "reth-cli-util" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eips", "alloy-primitives", @@ -6746,6 +6754,7 @@ dependencies = [ [[package]] name = "reth-codecs" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6765,6 +6774,7 @@ dependencies = [ [[package]] name = "reth-codecs-derive" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "proc-macro2", "quote", @@ -6774,6 +6784,7 @@ dependencies = [ [[package]] name = "reth-config" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "eyre", "humantime-serde", @@ -6789,19 +6800,7 @@ dependencies = [ [[package]] name = "reth-consensus" version = "1.9.3" -dependencies = [ - "alloy-consensus", - "alloy-primitives", - "auto_impl", - "reth-execution-types", - "reth-primitives-traits", - "thiserror 2.0.17", -] - -[[package]] -name = "reth-consensus" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -6814,29 +6813,19 @@ dependencies = [ [[package]] name = "reth-consensus-common" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", "reth-chainspec", - "reth-consensus 1.9.3", - "reth-primitives-traits", -] - -[[package]] -name = "reth-consensus-common" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=536bebfcd#536bebfcd7e8100ed69fe32c1122e18d6d6c3ff4" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "reth-chainspec", - "reth-consensus 1.9.3 (git+https://github.com/paradigmxyz/reth?rev=536bebfcd)", + "reth-consensus", "reth-primitives-traits", ] [[package]] name = "reth-consensus-debug-client" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6862,6 +6851,7 @@ dependencies = [ [[package]] name = "reth-db" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "derive_more", @@ -6887,6 +6877,7 @@ dependencies = [ [[package]] name = "reth-db-api" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -6914,6 +6905,7 @@ dependencies = [ [[package]] name = "reth-db-common" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -6943,6 +6935,7 @@ dependencies = [ [[package]] name = "reth-db-models" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eips", "alloy-primitives", @@ -6957,6 +6950,7 @@ dependencies = [ [[package]] name = "reth-discv4" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -6981,6 +6975,7 @@ dependencies = [ [[package]] name = "reth-discv5" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -7004,6 +6999,7 @@ dependencies = [ [[package]] name = "reth-dns-discovery" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "data-encoding", @@ -7027,6 +7023,7 @@ dependencies = [ [[package]] name = "reth-downloaders" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7040,7 +7037,7 @@ dependencies = [ "pin-project", "rayon", "reth-config", - "reth-consensus 1.9.3", + "reth-consensus", "reth-ethereum-primitives", "reth-metrics", "reth-network-p2p", @@ -7061,6 +7058,7 @@ dependencies = [ [[package]] name = "reth-e2e-test-utils" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7079,7 +7077,7 @@ dependencies = [ "reth-chainspec", "reth-cli-commands", "reth-config", - "reth-consensus 1.9.3", + "reth-consensus", "reth-db", "reth-db-common", "reth-engine-local", @@ -7118,6 +7116,7 @@ dependencies = [ [[package]] name = "reth-ecies" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "aes", "alloy-primitives", @@ -7146,6 +7145,7 @@ dependencies = [ [[package]] name = "reth-engine-local" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7168,6 +7168,7 @@ dependencies = [ [[package]] name = "reth-engine-primitives" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7192,11 +7193,12 @@ dependencies = [ [[package]] name = "reth-engine-service" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "futures", "pin-project", "reth-chainspec", - "reth-consensus 1.9.3", + "reth-consensus", "reth-engine-primitives", "reth-engine-tree", "reth-ethereum-primitives", @@ -7213,6 +7215,7 @@ dependencies = [ [[package]] name = "reth-engine-tree" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7230,7 +7233,7 @@ dependencies = [ "rayon", "reth-chain-state", "reth-chainspec", - "reth-consensus 1.9.3", + "reth-consensus", "reth-db", "reth-engine-primitives", "reth-errors", @@ -7267,6 +7270,7 @@ dependencies = [ [[package]] name = "reth-engine-util" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -7294,6 +7298,7 @@ dependencies = [ [[package]] name = "reth-era" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7308,6 +7313,7 @@ dependencies = [ [[package]] name = "reth-era-downloader" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "bytes", @@ -7323,6 +7329,7 @@ dependencies = [ [[package]] name = "reth-era-utils" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7344,8 +7351,9 @@ dependencies = [ [[package]] name = "reth-errors" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ - "reth-consensus 1.9.3", + "reth-consensus", "reth-execution-errors", "reth-storage-errors", "thiserror 2.0.17", @@ -7354,6 +7362,7 @@ dependencies = [ [[package]] name = "reth-eth-wire" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-chains", "alloy-primitives", @@ -7381,6 +7390,7 @@ dependencies = [ [[package]] name = "reth-eth-wire-types" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-chains", "alloy-consensus", @@ -7401,6 +7411,7 @@ dependencies = [ [[package]] name = "reth-ethereum-cli" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "clap", "eyre", @@ -7422,13 +7433,14 @@ dependencies = [ [[package]] name = "reth-ethereum-consensus" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", "reth-chainspec", - "reth-consensus 1.9.3", - "reth-consensus-common 1.9.3", + "reth-consensus", + "reth-consensus-common", "reth-execution-types", "reth-primitives-traits", "tracing", @@ -7437,6 +7449,7 @@ dependencies = [ [[package]] name = "reth-ethereum-engine-primitives" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eips", "alloy-primitives", @@ -7454,6 +7467,7 @@ dependencies = [ [[package]] name = "reth-ethereum-forks" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eip2124", "alloy-hardforks", @@ -7466,6 +7480,7 @@ dependencies = [ [[package]] name = "reth-ethereum-payload-builder" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7474,7 +7489,7 @@ dependencies = [ "alloy-rpc-types-engine", "reth-basic-payload-builder", "reth-chainspec", - "reth-consensus-common 1.9.3", + "reth-consensus-common", "reth-errors", "reth-ethereum-primitives", "reth-evm", @@ -7494,6 +7509,7 @@ dependencies = [ [[package]] name = "reth-ethereum-primitives" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7513,6 +7529,7 @@ dependencies = [ [[package]] name = "reth-etl" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "rayon", "reth-db-api", @@ -7522,6 +7539,7 @@ dependencies = [ [[package]] name = "reth-evm" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7544,6 +7562,7 @@ dependencies = [ [[package]] name = "reth-evm-ethereum" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7564,6 +7583,7 @@ dependencies = [ [[package]] name = "reth-execution-errors" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-evm", "alloy-primitives", @@ -7576,6 +7596,7 @@ dependencies = [ [[package]] name = "reth-execution-types" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7593,6 +7614,7 @@ dependencies = [ [[package]] name = "reth-exex" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7630,6 +7652,7 @@ dependencies = [ [[package]] name = "reth-exex-types" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eips", "alloy-primitives", @@ -7643,6 +7666,7 @@ dependencies = [ [[package]] name = "reth-fs-util" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "serde", "serde_json", @@ -7652,6 +7676,7 @@ dependencies = [ [[package]] name = "reth-invalid-block-hooks" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7679,6 +7704,7 @@ dependencies = [ [[package]] name = "reth-ipc" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "bytes", "futures", @@ -7698,6 +7724,7 @@ dependencies = [ [[package]] name = "reth-libmdbx" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "bitflags 2.10.0", "byteorder", @@ -7713,6 +7740,7 @@ dependencies = [ [[package]] name = "reth-mdbx-sys" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "bindgen 0.71.1", "cc", @@ -7721,6 +7749,7 @@ dependencies = [ [[package]] name = "reth-metrics" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "futures", "metrics", @@ -7732,6 +7761,7 @@ dependencies = [ [[package]] name = "reth-net-banlist" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "ipnet", @@ -7740,6 +7770,7 @@ dependencies = [ [[package]] name = "reth-net-nat" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "futures-util", "if-addrs", @@ -7753,6 +7784,7 @@ dependencies = [ [[package]] name = "reth-network" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7771,7 +7803,7 @@ dependencies = [ "rand 0.8.5", "rand 0.9.2", "reth-chainspec", - "reth-consensus 1.9.3", + "reth-consensus", "reth-discv4", "reth-discv5", "reth-dns-discovery", @@ -7807,6 +7839,7 @@ dependencies = [ [[package]] name = "reth-network-api" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7831,6 +7864,7 @@ dependencies = [ [[package]] name = "reth-network-p2p" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7839,7 +7873,7 @@ dependencies = [ "derive_more", "futures", "parking_lot", - "reth-consensus 1.9.3", + "reth-consensus", "reth-eth-wire-types", "reth-ethereum-primitives", "reth-network-peers", @@ -7853,6 +7887,7 @@ dependencies = [ [[package]] name = "reth-network-peers" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -7867,6 +7902,7 @@ dependencies = [ [[package]] name = "reth-network-types" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eip2124", "humantime-serde", @@ -7880,6 +7916,7 @@ dependencies = [ [[package]] name = "reth-nippy-jar" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "anyhow", "bincode 1.3.3", @@ -7896,11 +7933,12 @@ dependencies = [ [[package]] name = "reth-node-api" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-rpc-types-engine", "eyre", "reth-basic-payload-builder", - "reth-consensus 1.9.3", + "reth-consensus", "reth-db-api", "reth-engine-primitives", "reth-evm", @@ -7919,6 +7957,7 @@ dependencies = [ [[package]] name = "reth-node-builder" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7936,7 +7975,7 @@ dependencies = [ "reth-chain-state", "reth-chainspec", "reth-config", - "reth-consensus 1.9.3", + "reth-consensus", "reth-consensus-debug-client", "reth-db", "reth-db-api", @@ -7985,6 +8024,7 @@ dependencies = [ [[package]] name = "reth-node-core" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8001,7 +8041,7 @@ dependencies = [ "reth-chainspec", "reth-cli-util", "reth-config", - "reth-consensus 1.9.3", + "reth-consensus", "reth-db", "reth-discv4", "reth-discv5", @@ -8040,6 +8080,7 @@ dependencies = [ [[package]] name = "reth-node-ethereum" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eips", "alloy-network", @@ -8077,6 +8118,7 @@ dependencies = [ [[package]] name = "reth-node-ethstats" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8100,6 +8142,7 @@ dependencies = [ [[package]] name = "reth-node-events" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8123,6 +8166,7 @@ dependencies = [ [[package]] name = "reth-node-metrics" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "eyre", "http", @@ -8144,6 +8188,7 @@ dependencies = [ [[package]] name = "reth-node-types" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "reth-chainspec", "reth-db-api", @@ -8155,6 +8200,7 @@ dependencies = [ [[package]] name = "reth-optimism-chainspec" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-chains", "alloy-consensus", @@ -8177,14 +8223,15 @@ dependencies = [ [[package]] name = "reth-optimism-consensus" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-trie", "reth-chainspec", - "reth-consensus 1.9.3", - "reth-consensus-common 1.9.3", + "reth-consensus", + "reth-consensus-common", "reth-execution-types", "reth-optimism-chainspec", "reth-optimism-forks", @@ -8201,6 +8248,7 @@ dependencies = [ [[package]] name = "reth-optimism-evm" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8227,6 +8275,7 @@ dependencies = [ [[package]] name = "reth-optimism-flashblocks" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8265,6 +8314,7 @@ dependencies = [ [[package]] name = "reth-optimism-forks" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-op-hardforks", "alloy-primitives", @@ -8275,6 +8325,7 @@ dependencies = [ [[package]] name = "reth-optimism-payload-builder" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8314,6 +8365,7 @@ dependencies = [ [[package]] name = "reth-optimism-primitives" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8328,6 +8380,7 @@ dependencies = [ [[package]] name = "reth-optimism-rpc" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8388,6 +8441,7 @@ dependencies = [ [[package]] name = "reth-optimism-txpool" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8423,6 +8477,7 @@ dependencies = [ [[package]] name = "reth-payload-builder" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8443,6 +8498,7 @@ dependencies = [ [[package]] name = "reth-payload-builder-primitives" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "pin-project", "reth-payload-primitives", @@ -8454,6 +8510,7 @@ dependencies = [ [[package]] name = "reth-payload-primitives" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8476,6 +8533,7 @@ dependencies = [ [[package]] name = "reth-payload-util" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8485,6 +8543,7 @@ dependencies = [ [[package]] name = "reth-payload-validator" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -8494,6 +8553,7 @@ dependencies = [ [[package]] name = "reth-primitives" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "once_cell", @@ -8506,6 +8566,7 @@ dependencies = [ [[package]] name = "reth-primitives-traits" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8538,6 +8599,7 @@ dependencies = [ [[package]] name = "reth-provider" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8581,6 +8643,7 @@ dependencies = [ [[package]] name = "reth-prune" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8608,6 +8671,7 @@ dependencies = [ [[package]] name = "reth-prune-types" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "arbitrary", @@ -8622,6 +8686,7 @@ dependencies = [ [[package]] name = "reth-ress-protocol" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8640,6 +8705,7 @@ dependencies = [ [[package]] name = "reth-ress-provider" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8666,6 +8732,7 @@ dependencies = [ [[package]] name = "reth-revm" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "reth-primitives-traits", @@ -8678,6 +8745,7 @@ dependencies = [ [[package]] name = "reth-rpc" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -8715,8 +8783,8 @@ dependencies = [ "pin-project", "reth-chain-state", "reth-chainspec", - "reth-consensus 1.9.3", - "reth-consensus-common 1.9.3", + "reth-consensus", + "reth-consensus-common", "reth-engine-primitives", "reth-errors", "reth-evm", @@ -8756,6 +8824,7 @@ dependencies = [ [[package]] name = "reth-rpc-api" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eips", "alloy-genesis", @@ -8783,6 +8852,7 @@ dependencies = [ [[package]] name = "reth-rpc-builder" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-network", "alloy-provider", @@ -8793,7 +8863,7 @@ dependencies = [ "pin-project", "reth-chain-state", "reth-chainspec", - "reth-consensus 1.9.3", + "reth-consensus", "reth-evm", "reth-ipc", "reth-metrics", @@ -8821,6 +8891,7 @@ dependencies = [ [[package]] name = "reth-rpc-convert" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-evm", @@ -8846,6 +8917,7 @@ dependencies = [ [[package]] name = "reth-rpc-engine-api" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8874,6 +8946,7 @@ dependencies = [ [[package]] name = "reth-rpc-eth-api" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -8917,6 +8990,7 @@ dependencies = [ [[package]] name = "reth-rpc-eth-types" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8963,6 +9037,7 @@ dependencies = [ [[package]] name = "reth-rpc-layer" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-rpc-types-engine", "http", @@ -8976,6 +9051,7 @@ dependencies = [ [[package]] name = "reth-rpc-server-types" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8991,6 +9067,7 @@ dependencies = [ [[package]] name = "reth-stages" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9005,7 +9082,7 @@ dependencies = [ "reth-chainspec", "reth-codecs", "reth-config", - "reth-consensus 1.9.3", + "reth-consensus", "reth-db", "reth-db-api", "reth-era", @@ -9038,6 +9115,7 @@ dependencies = [ [[package]] name = "reth-stages-api" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eips", "alloy-primitives", @@ -9045,7 +9123,7 @@ dependencies = [ "auto_impl", "futures-util", "metrics", - "reth-consensus 1.9.3", + "reth-consensus", "reth-errors", "reth-metrics", "reth-network-p2p", @@ -9064,6 +9142,7 @@ dependencies = [ [[package]] name = "reth-stages-types" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "arbitrary", @@ -9077,6 +9156,7 @@ dependencies = [ [[package]] name = "reth-static-file" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "parking_lot", @@ -9096,6 +9176,7 @@ dependencies = [ [[package]] name = "reth-static-file-types" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "clap", @@ -9107,6 +9188,7 @@ dependencies = [ [[package]] name = "reth-storage-api" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9130,6 +9212,7 @@ dependencies = [ [[package]] name = "reth-storage-errors" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-eips", "alloy-primitives", @@ -9145,6 +9228,7 @@ dependencies = [ [[package]] name = "reth-tasks" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "auto_impl", "dyn-clone", @@ -9162,6 +9246,7 @@ dependencies = [ [[package]] name = "reth-testing-utils" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9177,6 +9262,7 @@ dependencies = [ [[package]] name = "reth-tokio-util" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "tokio", "tokio-stream", @@ -9186,6 +9272,7 @@ dependencies = [ [[package]] name = "reth-tracing" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "clap", "eyre", @@ -9201,6 +9288,7 @@ dependencies = [ [[package]] name = "reth-tracing-otlp" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "clap", "eyre", @@ -9217,6 +9305,7 @@ dependencies = [ [[package]] name = "reth-transaction-pool" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9257,6 +9346,7 @@ dependencies = [ [[package]] name = "reth-trie" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9282,6 +9372,7 @@ dependencies = [ [[package]] name = "reth-trie-common" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -9308,6 +9399,7 @@ dependencies = [ [[package]] name = "reth-trie-db" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "reth-db-api", @@ -9320,6 +9412,7 @@ dependencies = [ [[package]] name = "reth-trie-parallel" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -9344,6 +9437,7 @@ dependencies = [ [[package]] name = "reth-trie-sparse" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -9362,6 +9456,7 @@ dependencies = [ [[package]] name = "reth-trie-sparse-parallel" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -9379,6 +9474,7 @@ dependencies = [ [[package]] name = "reth-zstd-compressors" version = "1.9.3" +source = "git+https://github.com/rezbera/reth?branch=rezbera%2Fmodular-flashblocks#64b95481b3900c3d8986f7fee5a4f17f85ef871b" dependencies = [ "zstd", ] @@ -9810,7 +9906,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -10652,7 +10748,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix 1.1.2", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c78ebfbf..50ab389e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,12 +77,12 @@ alloy-provider = "1.1.2" alloy-rpc-client = "1.1.2" alloy-rpc-types-trace = "1.1.2" eyre = "0.6.12" +futures-util = { version = "0.3", default-features = false } reth-e2e-test-utils = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" } reth-rpc-builder = { git = "https://github.com/paradigmxyz/reth", rev = "536bebfcd" } revm-inspectors = "0.33.0" serde_json = "1.0" test-fuzz = "7" -futures-util = { version = "0.3", default-features = false } [build-dependencies] vergen = { version = "9.0.4", features = ["build", "cargo", "emit_and_set"] } diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index f929732d..682a1eec 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -46,7 +46,7 @@ use tokio::sync::watch; use tracing::info; /// Builds `BerachainEthApi` for Berachain. -#[derive(Clone)] +#[derive(Clone, Default)] pub struct BerachainEthApiBuilder { /// A URL pointing to a secure websocket connection (wss) that streams out flashblocks. flashblocks_url: Option, @@ -65,12 +65,6 @@ impl std::fmt::Debug for BerachainEthApiBuilder { } } -impl Default for BerachainEthApiBuilder { - fn default() -> Self { - Self { flashblocks_url: None, flashblocks_listeners: None } - } -} - impl BerachainEthApiBuilder { /// Configure flashblocks with a WebSocket URL. pub fn with_flashblocks_url(mut self, url: Option) -> Self {