mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: --debug.etherscan for fake consensus client (#8082)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> Co-authored-by: Alexey Shekhirin <a.shekhirin@gmail.com>
This commit is contained in:
173
Cargo.lock
generated
173
Cargo.lock
generated
@ -317,11 +317,13 @@ dependencies = [
|
|||||||
"alloy-json-rpc",
|
"alloy-json-rpc",
|
||||||
"alloy-network",
|
"alloy-network",
|
||||||
"alloy-primitives",
|
"alloy-primitives",
|
||||||
|
"alloy-pubsub",
|
||||||
"alloy-rpc-client",
|
"alloy-rpc-client",
|
||||||
"alloy-rpc-types 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=cc68b93)",
|
"alloy-rpc-types 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=cc68b93)",
|
||||||
"alloy-rpc-types-trace",
|
"alloy-rpc-types-trace",
|
||||||
"alloy-transport",
|
"alloy-transport",
|
||||||
"alloy-transport-http",
|
"alloy-transport-http",
|
||||||
|
"alloy-transport-ws",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"auto_impl",
|
"auto_impl",
|
||||||
@ -338,6 +340,24 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alloy-pubsub"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/alloy-rs/alloy?rev=cc68b93#cc68b93605f4521c2b0bce1a7efaeff2046cf07c"
|
||||||
|
dependencies = [
|
||||||
|
"alloy-json-rpc",
|
||||||
|
"alloy-primitives",
|
||||||
|
"alloy-transport",
|
||||||
|
"bimap",
|
||||||
|
"futures",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
"tower",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-rlp"
|
name = "alloy-rlp"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@ -366,8 +386,11 @@ version = "0.1.0"
|
|||||||
source = "git+https://github.com/alloy-rs/alloy?rev=cc68b93#cc68b93605f4521c2b0bce1a7efaeff2046cf07c"
|
source = "git+https://github.com/alloy-rs/alloy?rev=cc68b93#cc68b93605f4521c2b0bce1a7efaeff2046cf07c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-json-rpc",
|
"alloy-json-rpc",
|
||||||
|
"alloy-primitives",
|
||||||
|
"alloy-pubsub",
|
||||||
"alloy-transport",
|
"alloy-transport",
|
||||||
"alloy-transport-http",
|
"alloy-transport-http",
|
||||||
|
"alloy-transport-ws",
|
||||||
"futures",
|
"futures",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"reqwest 0.12.4",
|
"reqwest 0.12.4",
|
||||||
@ -627,6 +650,22 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alloy-transport-ws"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/alloy-rs/alloy?rev=cc68b93#cc68b93605f4521c2b0bce1a7efaeff2046cf07c"
|
||||||
|
dependencies = [
|
||||||
|
"alloy-pubsub",
|
||||||
|
"alloy-transport",
|
||||||
|
"futures",
|
||||||
|
"http 0.2.12",
|
||||||
|
"serde_json",
|
||||||
|
"tokio",
|
||||||
|
"tokio-tungstenite",
|
||||||
|
"tracing",
|
||||||
|
"ws_stream_wasm",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloy-trie"
|
name = "alloy-trie"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@ -986,6 +1025,17 @@ dependencies = [
|
|||||||
"syn 2.0.66",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async_io_stream"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c"
|
||||||
|
dependencies = [
|
||||||
|
"futures",
|
||||||
|
"pharos",
|
||||||
|
"rustc_version 0.4.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic-waker"
|
name = "atomic-waker"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
@ -1127,6 +1177,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bimap"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "1.3.3"
|
version = "1.3.3"
|
||||||
@ -3124,7 +3180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
|
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gloo-timers",
|
"gloo-timers",
|
||||||
"send_wrapper",
|
"send_wrapper 0.4.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4147,7 +4203,7 @@ dependencies = [
|
|||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
"webpki-roots",
|
"webpki-roots 0.26.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5413,6 +5469,16 @@ dependencies = [
|
|||||||
"wyhash",
|
"wyhash",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pharos"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414"
|
||||||
|
dependencies = [
|
||||||
|
"futures",
|
||||||
|
"rustc_version 0.4.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
@ -6139,7 +6205,7 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"webpki-roots",
|
"webpki-roots 0.26.2",
|
||||||
"winreg 0.52.0",
|
"winreg 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -6446,6 +6512,28 @@ dependencies = [
|
|||||||
"reth-storage-api",
|
"reth-storage-api",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reth-consensus-debug-client"
|
||||||
|
version = "0.2.0-beta.9"
|
||||||
|
dependencies = [
|
||||||
|
"alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=cc68b93)",
|
||||||
|
"alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=cc68b93)",
|
||||||
|
"alloy-provider",
|
||||||
|
"auto_impl",
|
||||||
|
"eyre",
|
||||||
|
"futures",
|
||||||
|
"reqwest 0.12.4",
|
||||||
|
"reth-node-api",
|
||||||
|
"reth-node-core",
|
||||||
|
"reth-rpc-api",
|
||||||
|
"reth-rpc-builder",
|
||||||
|
"reth-rpc-types",
|
||||||
|
"reth-tracing",
|
||||||
|
"ringbuffer",
|
||||||
|
"serde",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reth-db"
|
name = "reth-db"
|
||||||
version = "0.2.0-beta.9"
|
version = "0.2.0-beta.9"
|
||||||
@ -7231,6 +7319,7 @@ dependencies = [
|
|||||||
"reth-blockchain-tree",
|
"reth-blockchain-tree",
|
||||||
"reth-config",
|
"reth-config",
|
||||||
"reth-consensus",
|
"reth-consensus",
|
||||||
|
"reth-consensus-debug-client",
|
||||||
"reth-db",
|
"reth-db",
|
||||||
"reth-db-api",
|
"reth-db-api",
|
||||||
"reth-db-common",
|
"reth-db-common",
|
||||||
@ -8271,6 +8360,12 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ringbuffer"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3df6368f71f205ff9c33c076d170dd56ebf68e8161c733c0caa07a7a5509ed53"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ripemd"
|
name = "ripemd"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@ -8739,6 +8834,12 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0"
|
checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "send_wrapper"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.203"
|
version = "1.0.203"
|
||||||
@ -9643,6 +9744,21 @@ dependencies = [
|
|||||||
"tokio-util",
|
"tokio-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-tungstenite"
|
||||||
|
version = "0.20.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c"
|
||||||
|
dependencies = [
|
||||||
|
"futures-util",
|
||||||
|
"log",
|
||||||
|
"rustls 0.21.12",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls 0.24.1",
|
||||||
|
"tungstenite",
|
||||||
|
"webpki-roots 0.25.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.11"
|
version = "0.7.11"
|
||||||
@ -9962,6 +10078,26 @@ dependencies = [
|
|||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tungstenite"
|
||||||
|
version = "0.20.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"bytes",
|
||||||
|
"data-encoding",
|
||||||
|
"http 0.2.12",
|
||||||
|
"httparse",
|
||||||
|
"log",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"rustls 0.21.12",
|
||||||
|
"sha1",
|
||||||
|
"thiserror",
|
||||||
|
"url",
|
||||||
|
"utf-8",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "txpool-tracing"
|
name = "txpool-tracing"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
@ -10101,6 +10237,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf-8"
|
||||||
|
version = "0.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf16_iter"
|
name = "utf16_iter"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@ -10301,6 +10443,12 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki-roots"
|
||||||
|
version = "0.25.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki-roots"
|
name = "webpki-roots"
|
||||||
version = "0.26.2"
|
version = "0.26.2"
|
||||||
@ -10620,6 +10768,25 @@ version = "0.5.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ws_stream_wasm"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5"
|
||||||
|
dependencies = [
|
||||||
|
"async_io_stream",
|
||||||
|
"futures",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"pharos",
|
||||||
|
"rustc_version 0.4.0",
|
||||||
|
"send_wrapper 0.6.0",
|
||||||
|
"thiserror",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wyhash"
|
name = "wyhash"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
|||||||
@ -18,6 +18,8 @@ members = [
|
|||||||
"crates/consensus/beacon/",
|
"crates/consensus/beacon/",
|
||||||
"crates/consensus/common/",
|
"crates/consensus/common/",
|
||||||
"crates/consensus/consensus/",
|
"crates/consensus/consensus/",
|
||||||
|
"crates/consensus/debug-client/",
|
||||||
|
"crates/ethereum-forks/",
|
||||||
"crates/e2e-test-utils/",
|
"crates/e2e-test-utils/",
|
||||||
"crates/engine-primitives/",
|
"crates/engine-primitives/",
|
||||||
"crates/errors/",
|
"crates/errors/",
|
||||||
@ -246,6 +248,7 @@ reth-codecs-derive = { path = "crates/storage/codecs/derive" }
|
|||||||
reth-config = { path = "crates/config" }
|
reth-config = { path = "crates/config" }
|
||||||
reth-consensus = { path = "crates/consensus/consensus" }
|
reth-consensus = { path = "crates/consensus/consensus" }
|
||||||
reth-consensus-common = { path = "crates/consensus/common" }
|
reth-consensus-common = { path = "crates/consensus/common" }
|
||||||
|
reth-consensus-debug-client = { path = "crates/consensus/debug-client" }
|
||||||
reth-db = { path = "crates/storage/db", default-features = false }
|
reth-db = { path = "crates/storage/db", default-features = false }
|
||||||
reth-db-api = { path = "crates/storage/db-api" }
|
reth-db-api = { path = "crates/storage/db-api" }
|
||||||
reth-db-common = { path = "crates/storage/db-common" }
|
reth-db-common = { path = "crates/storage/db-common" }
|
||||||
|
|||||||
6
book/cli/reth/node.md
vendored
6
book/cli/reth/node.md
vendored
@ -463,6 +463,12 @@ Debug:
|
|||||||
--debug.max-block <MAX_BLOCK>
|
--debug.max-block <MAX_BLOCK>
|
||||||
Runs the sync only up to the specified block
|
Runs the sync only up to the specified block
|
||||||
|
|
||||||
|
--debug.etherscan [<ETHERSCAN_API_URL>]
|
||||||
|
Runs a fake consensus client that advances the chain using recent block hashes on Etherscan. If specified, requires an `ETHERSCAN_API_KEY` environment variable
|
||||||
|
|
||||||
|
--debug.rpc-consensus-ws <RPC_CONSENSUS_WS>
|
||||||
|
Runs a fake consensus client using blocks fetched from an RPC `WebSocket` endpoint
|
||||||
|
|
||||||
--debug.skip-fcu <SKIP_FCU>
|
--debug.skip-fcu <SKIP_FCU>
|
||||||
If provided, the engine will skip `n` consecutive FCUs
|
If provided, the engine will skip `n` consecutive FCUs
|
||||||
|
|
||||||
|
|||||||
34
crates/consensus/debug-client/Cargo.toml
Normal file
34
crates/consensus/debug-client/Cargo.toml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[package]
|
||||||
|
name = "reth-consensus-debug-client"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# reth
|
||||||
|
reth-node-api.workspace = true
|
||||||
|
reth-node-core.workspace = true
|
||||||
|
reth-rpc-api.workspace = true
|
||||||
|
reth-rpc-types.workspace = true
|
||||||
|
reth-rpc-builder.workspace = true
|
||||||
|
reth-tracing.workspace = true
|
||||||
|
|
||||||
|
# ethereum
|
||||||
|
alloy-consensus = { workspace = true, features = ["serde"] }
|
||||||
|
alloy-eips.workspace = true
|
||||||
|
alloy-provider = { workspace = true, features = ["ws"] }
|
||||||
|
|
||||||
|
auto_impl.workspace = true
|
||||||
|
futures.workspace = true
|
||||||
|
eyre.workspace = true
|
||||||
|
reqwest = { workspace = true, features = ["rustls-tls", "json"] }
|
||||||
|
serde = { workspace = true, features = ["derive"] }
|
||||||
|
tokio = { workspace = true, features = ["time"] }
|
||||||
|
|
||||||
|
ringbuffer = "0.15.0"
|
||||||
224
crates/consensus/debug-client/src/client.rs
Normal file
224
crates/consensus/debug-client/src/client.rs
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
use alloy_consensus::TxEnvelope;
|
||||||
|
use alloy_eips::eip2718::Encodable2718;
|
||||||
|
use reth_node_api::EngineTypes;
|
||||||
|
use reth_node_core::{
|
||||||
|
primitives::B256,
|
||||||
|
rpc::types::{BlockTransactions, ExecutionPayloadV2, ExecutionPayloadV3, RichBlock},
|
||||||
|
};
|
||||||
|
use reth_rpc_builder::auth::AuthServerHandle;
|
||||||
|
use reth_rpc_types::ExecutionPayloadV1;
|
||||||
|
use reth_tracing::tracing::warn;
|
||||||
|
use ringbuffer::{AllocRingBuffer, RingBuffer};
|
||||||
|
use std::future::Future;
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
|
/// Supplies consensus client with new blocks sent in `tx` and a callback to find specific blocks
|
||||||
|
/// by number to fetch past finalized and safe blocks.
|
||||||
|
#[auto_impl::auto_impl(&, Arc, Box)]
|
||||||
|
pub trait BlockProvider: Send + Sync + 'static {
|
||||||
|
/// Runs a block provider to send new blocks to the given sender.
|
||||||
|
///
|
||||||
|
/// Note: This is expected to be spawned in a separate task.
|
||||||
|
fn subscribe_blocks(&self, tx: mpsc::Sender<RichBlock>) -> impl Future<Output = ()> + Send;
|
||||||
|
|
||||||
|
/// Get a past block by number.
|
||||||
|
fn get_block(&self, block_number: u64) -> impl Future<Output = eyre::Result<RichBlock>> + Send;
|
||||||
|
|
||||||
|
/// Get previous block hash using previous block hash buffer. If it isn't available (buffer
|
||||||
|
/// started more recently than `offset`), fetch it using `get_block`.
|
||||||
|
fn get_or_fetch_previous_block(
|
||||||
|
&self,
|
||||||
|
previous_block_hashes: &AllocRingBuffer<B256>,
|
||||||
|
current_block_number: u64,
|
||||||
|
offset: usize,
|
||||||
|
) -> impl Future<Output = eyre::Result<B256>> + Send {
|
||||||
|
async move {
|
||||||
|
let stored_hash = previous_block_hashes
|
||||||
|
.len()
|
||||||
|
.checked_sub(offset)
|
||||||
|
.and_then(|index| previous_block_hashes.get(index));
|
||||||
|
if let Some(hash) = stored_hash {
|
||||||
|
return Ok(*hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return zero hash if the chain isn't long enough to have the block at the offset.
|
||||||
|
let previous_block_number = match current_block_number.checked_sub(offset as u64) {
|
||||||
|
Some(number) => number,
|
||||||
|
None => return Ok(B256::default()),
|
||||||
|
};
|
||||||
|
let block = self.get_block(previous_block_number).await?;
|
||||||
|
block.header.hash.ok_or_else(|| eyre::eyre!("previous block does not have hash"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Debug consensus client that sends FCUs and new payloads using recent blocks from an external
|
||||||
|
/// provider like Etherscan or an RPC endpoint.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DebugConsensusClient<P: BlockProvider> {
|
||||||
|
/// Handle to execution client.
|
||||||
|
auth_server: AuthServerHandle,
|
||||||
|
/// Provider to get consensus blocks from.
|
||||||
|
block_provider: P,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: BlockProvider> DebugConsensusClient<P> {
|
||||||
|
/// Create a new debug consensus client with the given handle to execution
|
||||||
|
/// client and block provider.
|
||||||
|
pub const fn new(auth_server: AuthServerHandle, block_provider: P) -> Self {
|
||||||
|
Self { auth_server, block_provider }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: BlockProvider + Clone> DebugConsensusClient<P> {
|
||||||
|
/// Spawn the client to start sending FCUs and new payloads by periodically fetching recent
|
||||||
|
/// blocks.
|
||||||
|
pub async fn run<T: EngineTypes>(self) {
|
||||||
|
let execution_client = self.auth_server.http_client();
|
||||||
|
let mut previous_block_hashes = AllocRingBuffer::new(64);
|
||||||
|
|
||||||
|
let mut block_stream = {
|
||||||
|
let (tx, rx) = mpsc::channel::<RichBlock>(64);
|
||||||
|
let block_provider = self.block_provider.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
block_provider.subscribe_blocks(tx).await;
|
||||||
|
});
|
||||||
|
rx
|
||||||
|
};
|
||||||
|
|
||||||
|
while let Some(block) = block_stream.recv().await {
|
||||||
|
let payload = rich_block_to_execution_payload_v3(block);
|
||||||
|
|
||||||
|
let block_hash = payload.block_hash();
|
||||||
|
let block_number = payload.block_number();
|
||||||
|
|
||||||
|
// Send new events to execution client
|
||||||
|
reth_rpc_api::EngineApiClient::<T>::new_payload_v3(
|
||||||
|
&execution_client,
|
||||||
|
payload.execution_payload_v3,
|
||||||
|
payload.versioned_hashes,
|
||||||
|
payload.parent_beacon_block_root,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
previous_block_hashes.push(block_hash);
|
||||||
|
|
||||||
|
// Load previous block hashes. We're using (head - 32) and (head - 64) as the safe and
|
||||||
|
// finalized block hashes.
|
||||||
|
let safe_block_hash = self.block_provider.get_or_fetch_previous_block(
|
||||||
|
&previous_block_hashes,
|
||||||
|
block_number,
|
||||||
|
32,
|
||||||
|
);
|
||||||
|
let finalized_block_hash = self.block_provider.get_or_fetch_previous_block(
|
||||||
|
&previous_block_hashes,
|
||||||
|
block_number,
|
||||||
|
64,
|
||||||
|
);
|
||||||
|
let (safe_block_hash, finalized_block_hash) =
|
||||||
|
tokio::join!(safe_block_hash, finalized_block_hash);
|
||||||
|
let (safe_block_hash, finalized_block_hash) = match (
|
||||||
|
safe_block_hash,
|
||||||
|
finalized_block_hash,
|
||||||
|
) {
|
||||||
|
(Ok(safe_block_hash), Ok(finalized_block_hash)) => {
|
||||||
|
(safe_block_hash, finalized_block_hash)
|
||||||
|
}
|
||||||
|
(safe_block_hash, finalized_block_hash) => {
|
||||||
|
warn!(target: "consensus::debug-client", ?safe_block_hash, ?finalized_block_hash, "failed to fetch safe or finalized hash from etherscan");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reth_rpc_api::EngineApiClient::<T>::fork_choice_updated_v3(
|
||||||
|
&execution_client,
|
||||||
|
reth_rpc_types::engine::ForkchoiceState {
|
||||||
|
head_block_hash: block_hash,
|
||||||
|
safe_block_hash,
|
||||||
|
finalized_block_hash,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancun "new payload" event.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ExecutionNewPayload {
|
||||||
|
execution_payload_v3: ExecutionPayloadV3,
|
||||||
|
versioned_hashes: Vec<B256>,
|
||||||
|
parent_beacon_block_root: B256,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecutionNewPayload {
|
||||||
|
/// Get block hash from block in the payload
|
||||||
|
const fn block_hash(&self) -> B256 {
|
||||||
|
self.execution_payload_v3.payload_inner.payload_inner.block_hash
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get block number from block in the payload
|
||||||
|
const fn block_number(&self) -> u64 {
|
||||||
|
self.execution_payload_v3.payload_inner.payload_inner.block_number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a rich block from RPC / Etherscan to params for an execution client's "new payload"
|
||||||
|
/// method. Assumes that the block contains full transactions.
|
||||||
|
fn rich_block_to_execution_payload_v3(block: RichBlock) -> ExecutionNewPayload {
|
||||||
|
let transactions = match &block.transactions {
|
||||||
|
BlockTransactions::Full(txs) => txs.clone(),
|
||||||
|
// Empty array gets deserialized as BlockTransactions::Hashes.
|
||||||
|
BlockTransactions::Hashes(txs) if txs.is_empty() => vec![],
|
||||||
|
BlockTransactions::Hashes(_) | BlockTransactions::Uncle => {
|
||||||
|
panic!("Received uncle block or hash-only transactions from Etherscan API")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Concatenate all blob hashes from all transactions in order
|
||||||
|
// https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#specification
|
||||||
|
let versioned_hashes = transactions
|
||||||
|
.iter()
|
||||||
|
.flat_map(|tx| tx.blob_versioned_hashes.clone().unwrap_or_default())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let payload: ExecutionPayloadV3 = ExecutionPayloadV3 {
|
||||||
|
payload_inner: ExecutionPayloadV2 {
|
||||||
|
payload_inner: ExecutionPayloadV1 {
|
||||||
|
parent_hash: block.header.parent_hash,
|
||||||
|
fee_recipient: block.header.miner,
|
||||||
|
state_root: block.header.state_root,
|
||||||
|
receipts_root: block.header.receipts_root,
|
||||||
|
logs_bloom: block.header.logs_bloom,
|
||||||
|
prev_randao: block.header.mix_hash.unwrap(),
|
||||||
|
block_number: block.header.number.unwrap(),
|
||||||
|
gas_limit: block.header.gas_limit.try_into().unwrap(),
|
||||||
|
gas_used: block.header.gas_used.try_into().unwrap(),
|
||||||
|
timestamp: block.header.timestamp,
|
||||||
|
extra_data: block.header.extra_data.clone(),
|
||||||
|
base_fee_per_gas: block.header.base_fee_per_gas.unwrap().try_into().unwrap(),
|
||||||
|
block_hash: block.header.hash.unwrap(),
|
||||||
|
transactions: transactions
|
||||||
|
.into_iter()
|
||||||
|
.map(|tx| {
|
||||||
|
let envelope: TxEnvelope = tx.try_into().unwrap();
|
||||||
|
let mut buffer: Vec<u8> = vec![];
|
||||||
|
envelope.encode_2718(&mut buffer);
|
||||||
|
buffer.into()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
withdrawals: block.withdrawals.clone().unwrap_or_default(),
|
||||||
|
},
|
||||||
|
blob_gas_used: block.header.blob_gas_used.unwrap().try_into().unwrap(),
|
||||||
|
excess_blob_gas: block.header.excess_blob_gas.unwrap().try_into().unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
ExecutionNewPayload {
|
||||||
|
execution_payload_v3: payload,
|
||||||
|
versioned_hashes,
|
||||||
|
parent_beacon_block_root: block.header.parent_beacon_block_root.unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
19
crates/consensus/debug-client/src/lib.rs
Normal file
19
crates/consensus/debug-client/src/lib.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//! Debug consensus client.
|
||||||
|
//!
|
||||||
|
//! This is a worker that sends FCUs and new payloads by fetching recent blocks from an external
|
||||||
|
//! provider like Etherscan or an RPC endpoint. This allows to quickly test the execution client
|
||||||
|
//! without running a consensus node.
|
||||||
|
|
||||||
|
#![doc(
|
||||||
|
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
|
||||||
|
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
|
||||||
|
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
||||||
|
)]
|
||||||
|
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||||
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
|
|
||||||
|
mod client;
|
||||||
|
mod providers;
|
||||||
|
|
||||||
|
pub use client::{BlockProvider, DebugConsensusClient};
|
||||||
|
pub use providers::{EtherscanBlockProvider, RpcBlockProvider};
|
||||||
105
crates/consensus/debug-client/src/providers/etherscan.rs
Normal file
105
crates/consensus/debug-client/src/providers/etherscan.rs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
use crate::BlockProvider;
|
||||||
|
use alloy_eips::BlockNumberOrTag;
|
||||||
|
use reqwest::Client;
|
||||||
|
use reth_node_core::rpc::types::RichBlock;
|
||||||
|
use reth_tracing::tracing::warn;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::{sync::mpsc, time::interval};
|
||||||
|
|
||||||
|
/// Block provider that fetches new blocks from Etherscan API.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct EtherscanBlockProvider {
|
||||||
|
http_client: Client,
|
||||||
|
base_url: String,
|
||||||
|
api_key: String,
|
||||||
|
interval: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EtherscanBlockProvider {
|
||||||
|
/// Create a new Etherscan block provider with the given base URL and API key.
|
||||||
|
pub fn new(base_url: String, api_key: String) -> Self {
|
||||||
|
Self { http_client: Client::new(), base_url, api_key, interval: Duration::from_secs(3) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the interval at which the provider fetches new blocks.
|
||||||
|
pub const fn with_interval(mut self, interval: Duration) -> Self {
|
||||||
|
self.interval = interval;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockProvider for EtherscanBlockProvider {
|
||||||
|
async fn subscribe_blocks(&self, tx: mpsc::Sender<RichBlock>) {
|
||||||
|
let mut last_block_number: Option<u64> = None;
|
||||||
|
let mut interval = interval(self.interval);
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
let block = match load_etherscan_block(
|
||||||
|
&self.http_client,
|
||||||
|
&self.base_url,
|
||||||
|
&self.api_key,
|
||||||
|
BlockNumberOrTag::Latest,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(block) => block,
|
||||||
|
Err(err) => {
|
||||||
|
warn!(target: "consensus::debug-client", %err, "failed to fetch a block from Etherscan");
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let block_number = block.header.number.unwrap();
|
||||||
|
if Some(block_number) == last_block_number {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if tx.send(block).await.is_err() {
|
||||||
|
// channel closed
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_block_number = Some(block_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_block(&self, block_number: u64) -> eyre::Result<RichBlock> {
|
||||||
|
load_etherscan_block(
|
||||||
|
&self.http_client,
|
||||||
|
&self.base_url,
|
||||||
|
&self.api_key,
|
||||||
|
BlockNumberOrTag::Number(block_number),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct EtherscanBlockResponse {
|
||||||
|
result: RichBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load block using Etherscan API. Note: only `BlockNumberOrTag::Latest`,
|
||||||
|
/// `BlockNumberOrTag::Earliest`, `BlockNumberOrTag::Pending`, `BlockNumberOrTag::Number(u64)` are
|
||||||
|
/// supported.
|
||||||
|
async fn load_etherscan_block(
|
||||||
|
http_client: &Client,
|
||||||
|
base_url: &str,
|
||||||
|
api_key: &str,
|
||||||
|
block_number_or_tag: BlockNumberOrTag,
|
||||||
|
) -> eyre::Result<RichBlock> {
|
||||||
|
let block: EtherscanBlockResponse = http_client
|
||||||
|
.get(base_url)
|
||||||
|
.query(&[
|
||||||
|
("module", "proxy"),
|
||||||
|
("action", "eth_getBlockByNumber"),
|
||||||
|
("tag", &block_number_or_tag.to_string()),
|
||||||
|
("boolean", "true"),
|
||||||
|
("apikey", api_key),
|
||||||
|
])
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.json()
|
||||||
|
.await?;
|
||||||
|
Ok(block.result)
|
||||||
|
}
|
||||||
5
crates/consensus/debug-client/src/providers/mod.rs
Normal file
5
crates/consensus/debug-client/src/providers/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
mod etherscan;
|
||||||
|
mod rpc;
|
||||||
|
|
||||||
|
pub use etherscan::EtherscanBlockProvider;
|
||||||
|
pub use rpc::RpcBlockProvider;
|
||||||
58
crates/consensus/debug-client/src/providers/rpc.rs
Normal file
58
crates/consensus/debug-client/src/providers/rpc.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use crate::BlockProvider;
|
||||||
|
use alloy_eips::BlockNumberOrTag;
|
||||||
|
use alloy_provider::{Provider, ProviderBuilder};
|
||||||
|
use futures::StreamExt;
|
||||||
|
use reth_node_core::rpc::types::RichBlock;
|
||||||
|
use tokio::sync::mpsc::Sender;
|
||||||
|
|
||||||
|
/// Block provider that fetches new blocks from an RPC endpoint using a websocket connection.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct RpcBlockProvider {
|
||||||
|
ws_rpc_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RpcBlockProvider {
|
||||||
|
/// Create a new RPC block provider with the given WS RPC URL.
|
||||||
|
pub const fn new(ws_rpc_url: String) -> Self {
|
||||||
|
Self { ws_rpc_url }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockProvider for RpcBlockProvider {
|
||||||
|
async fn subscribe_blocks(&self, tx: Sender<RichBlock>) {
|
||||||
|
let ws_provider = ProviderBuilder::new()
|
||||||
|
.on_builtin(&self.ws_rpc_url)
|
||||||
|
.await
|
||||||
|
.expect("failed to create WS provider");
|
||||||
|
let mut stream = ws_provider
|
||||||
|
.subscribe_blocks()
|
||||||
|
.await
|
||||||
|
.expect("failed to subscribe on new blocks")
|
||||||
|
.into_stream();
|
||||||
|
|
||||||
|
while let Some(block) = stream.next().await {
|
||||||
|
let full_block = ws_provider
|
||||||
|
.get_block_by_hash(block.header.hash.unwrap(), true)
|
||||||
|
.await
|
||||||
|
.expect("failed to get block")
|
||||||
|
.expect("block not found");
|
||||||
|
if tx.send(full_block.into()).await.is_err() {
|
||||||
|
// channel closed
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_block(&self, block_number: u64) -> eyre::Result<RichBlock> {
|
||||||
|
let ws_provider = ProviderBuilder::new()
|
||||||
|
.on_builtin(&self.ws_rpc_url)
|
||||||
|
.await
|
||||||
|
.expect("failed to create WS provider");
|
||||||
|
let block: RichBlock = ws_provider
|
||||||
|
.get_block_by_number(BlockNumberOrTag::Number(block_number), true)
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| eyre::eyre!("block not found by number {}", block_number))?
|
||||||
|
.into();
|
||||||
|
Ok(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -28,6 +28,26 @@ pub struct DebugArgs {
|
|||||||
#[arg(long = "debug.max-block", help_heading = "Debug")]
|
#[arg(long = "debug.max-block", help_heading = "Debug")]
|
||||||
pub max_block: Option<u64>,
|
pub max_block: Option<u64>,
|
||||||
|
|
||||||
|
/// Runs a fake consensus client that advances the chain using recent block hashes
|
||||||
|
/// on Etherscan. If specified, requires an `ETHERSCAN_API_KEY` environment variable.
|
||||||
|
#[arg(
|
||||||
|
long = "debug.etherscan",
|
||||||
|
help_heading = "Debug",
|
||||||
|
conflicts_with = "tip",
|
||||||
|
conflicts_with = "rpc_consensus_ws",
|
||||||
|
value_name = "ETHERSCAN_API_URL"
|
||||||
|
)]
|
||||||
|
pub etherscan: Option<Option<String>>,
|
||||||
|
|
||||||
|
/// Runs a fake consensus client using blocks fetched from an RPC `WebSocket` endpoint.
|
||||||
|
#[arg(
|
||||||
|
long = "debug.rpc-consensus-ws",
|
||||||
|
help_heading = "Debug",
|
||||||
|
conflicts_with = "tip",
|
||||||
|
conflicts_with = "etherscan"
|
||||||
|
)]
|
||||||
|
pub rpc_consensus_ws: Option<String>,
|
||||||
|
|
||||||
/// If provided, the engine will skip `n` consecutive FCUs.
|
/// If provided, the engine will skip `n` consecutive FCUs.
|
||||||
#[arg(long = "debug.skip-fcu", help_heading = "Debug")]
|
#[arg(long = "debug.skip-fcu", help_heading = "Debug")]
|
||||||
pub skip_fcu: Option<usize>,
|
pub skip_fcu: Option<usize>,
|
||||||
|
|||||||
@ -41,7 +41,9 @@ reth-config.workspace = true
|
|||||||
reth-downloaders.workspace = true
|
reth-downloaders.workspace = true
|
||||||
reth-node-events.workspace = true
|
reth-node-events.workspace = true
|
||||||
reth-consensus.workspace = true
|
reth-consensus.workspace = true
|
||||||
|
reth-consensus-debug-client.workspace = true
|
||||||
reth-rpc-types.workspace = true
|
reth-rpc-types.workspace = true
|
||||||
|
|
||||||
## async
|
## async
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
tokio = { workspace = true, features = [
|
tokio = { workspace = true, features = [
|
||||||
|
|||||||
@ -18,6 +18,7 @@ use reth_blockchain_tree::{
|
|||||||
TreeExternals,
|
TreeExternals,
|
||||||
};
|
};
|
||||||
use reth_consensus::Consensus;
|
use reth_consensus::Consensus;
|
||||||
|
use reth_consensus_debug_client::{DebugConsensusClient, EtherscanBlockProvider, RpcBlockProvider};
|
||||||
use reth_exex::ExExManagerHandle;
|
use reth_exex::ExExManagerHandle;
|
||||||
use reth_network::NetworkEvents;
|
use reth_network::NetworkEvents;
|
||||||
use reth_node_api::{FullNodeComponents, FullNodeTypes};
|
use reth_node_api::{FullNodeComponents, FullNodeTypes};
|
||||||
@ -397,6 +398,48 @@ where
|
|||||||
let _ = tx.send(res);
|
let _ = tx.send(res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if let Some(maybe_custom_etherscan_url) = ctx.node_config().debug.etherscan.clone() {
|
||||||
|
info!(target: "reth::cli", "Using etherscan as consensus client");
|
||||||
|
|
||||||
|
let chain = ctx.node_config().chain.chain;
|
||||||
|
let etherscan_url = maybe_custom_etherscan_url.map(Ok).unwrap_or_else(|| {
|
||||||
|
// If URL isn't provided, use default Etherscan URL for the chain if it is known
|
||||||
|
chain
|
||||||
|
.etherscan_urls()
|
||||||
|
.map(|urls| urls.0.to_string())
|
||||||
|
.ok_or_else(|| eyre::eyre!("failed to get etherscan url for chain: {chain}"))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let block_provider = EtherscanBlockProvider::new(
|
||||||
|
etherscan_url,
|
||||||
|
chain.etherscan_api_key().ok_or_else(|| {
|
||||||
|
eyre::eyre!(
|
||||||
|
"etherscan api key not found for rpc consensus client for chain: {chain}"
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
);
|
||||||
|
let rpc_consensus_client = DebugConsensusClient::new(
|
||||||
|
rpc_server_handles.auth.clone(),
|
||||||
|
Arc::new(block_provider),
|
||||||
|
);
|
||||||
|
ctx.task_executor().spawn_critical("etherscan consensus client", async move {
|
||||||
|
rpc_consensus_client.run::<T::Engine>().await
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rpc_ws_url) = ctx.node_config().debug.rpc_consensus_ws.clone() {
|
||||||
|
info!(target: "reth::cli", "Using rpc provider as consensus client");
|
||||||
|
|
||||||
|
let block_provider = RpcBlockProvider::new(rpc_ws_url);
|
||||||
|
let rpc_consensus_client = DebugConsensusClient::new(
|
||||||
|
rpc_server_handles.auth.clone(),
|
||||||
|
Arc::new(block_provider),
|
||||||
|
);
|
||||||
|
ctx.task_executor().spawn_critical("rpc consensus client", async move {
|
||||||
|
rpc_consensus_client.run::<T::Engine>().await
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let full_node = FullNode {
|
let full_node = FullNode {
|
||||||
evm_config: node_adapter.components.evm_config().clone(),
|
evm_config: node_adapter.components.evm_config().clone(),
|
||||||
block_executor: node_adapter.components.block_executor().clone(),
|
block_executor: node_adapter.components.block_executor().clone(),
|
||||||
|
|||||||
Reference in New Issue
Block a user