mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-08 23:08:19 -05:00
feat: add helpers for testing rpc requests with prestate (#19790)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
22
Cargo.lock
generated
22
Cargo.lock
generated
@@ -3049,7 +3049,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"option-ext",
|
"option-ext",
|
||||||
"redox_users 0.5.2",
|
"redox_users 0.5.2",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3379,7 +3379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4728,7 +4728,7 @@ dependencies = [
|
|||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-core 0.62.2",
|
"windows-core 0.57.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5073,7 +5073,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5982,7 +5982,7 @@ version = "0.50.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7013,7 +7013,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"socket2 0.6.1",
|
"socket2 0.6.1",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -9185,6 +9185,7 @@ dependencies = [
|
|||||||
"alloy-rpc-types-beacon",
|
"alloy-rpc-types-beacon",
|
||||||
"alloy-rpc-types-engine",
|
"alloy-rpc-types-engine",
|
||||||
"alloy-rpc-types-eth",
|
"alloy-rpc-types-eth",
|
||||||
|
"alloy-rpc-types-trace",
|
||||||
"alloy-signer",
|
"alloy-signer",
|
||||||
"alloy-sol-types",
|
"alloy-sol-types",
|
||||||
"eyre",
|
"eyre",
|
||||||
@@ -9217,10 +9218,13 @@ dependencies = [
|
|||||||
"reth-rpc-eth-types",
|
"reth-rpc-eth-types",
|
||||||
"reth-rpc-server-types",
|
"reth-rpc-server-types",
|
||||||
"reth-tasks",
|
"reth-tasks",
|
||||||
|
"reth-testing-utils",
|
||||||
"reth-tracing",
|
"reth-tracing",
|
||||||
"reth-transaction-pool",
|
"reth-transaction-pool",
|
||||||
"revm",
|
"revm",
|
||||||
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"similar-asserts",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -11459,7 +11463,7 @@ dependencies = [
|
|||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.11.0",
|
"linux-raw-sys 0.11.0",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -12350,7 +12354,7 @@ dependencies = [
|
|||||||
"getrandom 0.3.4",
|
"getrandom 0.3.4",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.2",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -13565,7 +13569,7 @@ version = "0.1.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -496,7 +496,7 @@ alloy-genesis = { version = "1.0.41", default-features = false }
|
|||||||
alloy-json-rpc = { version = "1.0.41", default-features = false }
|
alloy-json-rpc = { version = "1.0.41", default-features = false }
|
||||||
alloy-network = { version = "1.0.41", default-features = false }
|
alloy-network = { version = "1.0.41", default-features = false }
|
||||||
alloy-network-primitives = { version = "1.0.41", default-features = false }
|
alloy-network-primitives = { version = "1.0.41", default-features = false }
|
||||||
alloy-provider = { version = "1.0.41", features = ["reqwest"], default-features = false }
|
alloy-provider = { version = "1.0.41", features = ["reqwest", "debug-api"], default-features = false }
|
||||||
alloy-pubsub = { version = "1.0.41", default-features = false }
|
alloy-pubsub = { version = "1.0.41", default-features = false }
|
||||||
alloy-rpc-client = { version = "1.0.41", default-features = false }
|
alloy-rpc-client = { version = "1.0.41", default-features = false }
|
||||||
alloy-rpc-types = { version = "1.0.41", features = ["eth"], default-features = false }
|
alloy-rpc-types = { version = "1.0.41", features = ["eth"], default-features = false }
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ reth-exex.workspace = true
|
|||||||
reth-node-core.workspace = true
|
reth-node-core.workspace = true
|
||||||
reth-e2e-test-utils.workspace = true
|
reth-e2e-test-utils.workspace = true
|
||||||
reth-tasks.workspace = true
|
reth-tasks.workspace = true
|
||||||
|
reth-testing-utils.workspace = true
|
||||||
|
|
||||||
alloy-primitives.workspace = true
|
alloy-primitives.workspace = true
|
||||||
alloy-provider.workspace = true
|
alloy-provider.workspace = true
|
||||||
@@ -74,6 +75,9 @@ futures.workspace = true
|
|||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
alloy-rpc-types-trace.workspace = true
|
||||||
|
similar-asserts.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ mod dev;
|
|||||||
mod eth;
|
mod eth;
|
||||||
mod p2p;
|
mod p2p;
|
||||||
mod pool;
|
mod pool;
|
||||||
|
mod prestate;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
|||||||
132
crates/ethereum/node/tests/e2e/prestate.rs
Normal file
132
crates/ethereum/node/tests/e2e/prestate.rs
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
use alloy_eips::BlockId;
|
||||||
|
use alloy_genesis::{Genesis, GenesisAccount};
|
||||||
|
use alloy_primitives::address;
|
||||||
|
use alloy_provider::ext::DebugApi;
|
||||||
|
use alloy_rpc_types_eth::{Transaction, TransactionRequest};
|
||||||
|
use alloy_rpc_types_trace::geth::{
|
||||||
|
AccountState, GethDebugTracingOptions, PreStateConfig, PreStateFrame,
|
||||||
|
};
|
||||||
|
use eyre::{eyre, Result};
|
||||||
|
use reth_chainspec::{ChainSpecBuilder, MAINNET};
|
||||||
|
use reth_node_builder::{NodeBuilder, NodeHandle};
|
||||||
|
use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig};
|
||||||
|
use reth_node_ethereum::EthereumNode;
|
||||||
|
use reth_rpc_server_types::RpcModuleSelection;
|
||||||
|
use reth_tasks::TaskManager;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
const PRESTATE_SNAPSHOT: &str =
|
||||||
|
include_str!("../../../../../testing/prestate/tx-selfdestruct-prestate.json");
|
||||||
|
|
||||||
|
/// Replays the selfdestruct transaction via `debug_traceCall` and ensures Reth's prestate matches
|
||||||
|
/// Geth's captured snapshot.
|
||||||
|
// <https://github.com/paradigmxyz/reth/issues/19703>
|
||||||
|
#[tokio::test]
|
||||||
|
async fn debug_trace_call_matches_geth_prestate_snapshot() -> Result<()> {
|
||||||
|
reth_tracing::init_test_tracing();
|
||||||
|
|
||||||
|
let mut genesis: Genesis = MAINNET.genesis().clone();
|
||||||
|
genesis.coinbase = address!("0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5");
|
||||||
|
|
||||||
|
let exec = TaskManager::current();
|
||||||
|
let exec = exec.executor();
|
||||||
|
|
||||||
|
let expected_frame = expected_snapshot_frame()?;
|
||||||
|
let prestate_mode = match &expected_frame {
|
||||||
|
PreStateFrame::Default(mode) => mode.clone(),
|
||||||
|
_ => return Err(eyre!("snapshot must contain default prestate frame")),
|
||||||
|
};
|
||||||
|
|
||||||
|
genesis.alloc.extend(
|
||||||
|
prestate_mode
|
||||||
|
.0
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(addr, state)| (addr, account_state_to_genesis(state))),
|
||||||
|
);
|
||||||
|
|
||||||
|
let chain_spec = Arc::new(
|
||||||
|
ChainSpecBuilder::default()
|
||||||
|
.chain(MAINNET.chain)
|
||||||
|
.genesis(genesis)
|
||||||
|
.cancun_activated()
|
||||||
|
.prague_activated()
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let node_config = NodeConfig::test().with_chain(chain_spec).with_rpc(
|
||||||
|
RpcServerArgs::default()
|
||||||
|
.with_unused_ports()
|
||||||
|
.with_http()
|
||||||
|
.with_http_api(RpcModuleSelection::all_modules().into()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config)
|
||||||
|
.testing_node(exec)
|
||||||
|
.node(EthereumNode::default())
|
||||||
|
.launch()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let provider = node.rpc_server_handle().eth_http_provider().unwrap();
|
||||||
|
|
||||||
|
// <https://etherscan.io/tx/0x391f4b6a382d3bcc3120adc2ea8c62003e604e487d97281129156fd284a1a89d>
|
||||||
|
let tx = r#"{
|
||||||
|
"type": "0x2",
|
||||||
|
"chainId": "0x1",
|
||||||
|
"nonce": "0x39af8",
|
||||||
|
"gas": "0x249f0",
|
||||||
|
"maxFeePerGas": "0xc6432e2d7",
|
||||||
|
"maxPriorityFeePerGas": "0x68889c2b",
|
||||||
|
"to": "0xc77ad0a71008d7094a62cfbd250a2eb2afdf2776",
|
||||||
|
"value": "0x0",
|
||||||
|
"accessList": [],
|
||||||
|
"input": "0xf3fef3a3000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000000f6b64",
|
||||||
|
"r": "0x40ab901a8262d5e6fe9b6513996cd5df412526580cab7410c13acc9dd9f6ec93",
|
||||||
|
"s": "0x6b76354c8cb1c1d6dbebfd555be9053170f02a648c4b36740e3fd7c6e9499572",
|
||||||
|
"yParity": "0x1",
|
||||||
|
"v": "0x1",
|
||||||
|
"hash": "0x391f4b6a382d3bcc3120adc2ea8c62003e604e487d97281129156fd284a1a89d",
|
||||||
|
"blockHash": "0xf9b77bcf8c69544304dff34129f3bdc71f00fdf766c1522ed6ac1382726ead82",
|
||||||
|
"blockNumber": "0x1294fd2",
|
||||||
|
"transactionIndex": "0x3a",
|
||||||
|
"from": "0xa7fb5ca286fc3fd67525629048a4de3ba24cba2e",
|
||||||
|
"gasPrice": "0x7c5bcc0e0"
|
||||||
|
}"#;
|
||||||
|
let tx = serde_json::from_str::<Transaction>(tx).unwrap();
|
||||||
|
let request = TransactionRequest::from_recovered_transaction(tx.into_recovered());
|
||||||
|
|
||||||
|
let trace: PreStateFrame = provider
|
||||||
|
.debug_trace_call_prestate(
|
||||||
|
request,
|
||||||
|
BlockId::latest(),
|
||||||
|
GethDebugTracingOptions::prestate_tracer(PreStateConfig::default()).into(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
similar_asserts::assert_eq!(trace, expected_frame);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expected_snapshot_frame() -> Result<PreStateFrame> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Snapshot {
|
||||||
|
result: serde_json::Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
let snapshot: Snapshot = serde_json::from_str(PRESTATE_SNAPSHOT)?;
|
||||||
|
Ok(serde_json::from_value(snapshot.result)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn account_state_to_genesis(value: AccountState) -> GenesisAccount {
|
||||||
|
let balance = value.balance.unwrap_or_default();
|
||||||
|
let code = value.code.filter(|code| !code.is_empty());
|
||||||
|
let storage = (!value.storage.is_empty()).then_some(value.storage);
|
||||||
|
|
||||||
|
GenesisAccount::default()
|
||||||
|
.with_balance(balance)
|
||||||
|
.with_nonce(value.nonce)
|
||||||
|
.with_code(code)
|
||||||
|
.with_storage(storage)
|
||||||
|
}
|
||||||
43
testing/prestate/tx-selfdestruct-prestate.json
Normal file
43
testing/prestate/tx-selfdestruct-prestate.json
Normal file
File diff suppressed because one or more lines are too long
@@ -8,8 +8,7 @@
|
|||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||||
|
|
||||||
|
pub mod generators;
|
||||||
pub mod genesis_allocator;
|
pub mod genesis_allocator;
|
||||||
|
|
||||||
pub use genesis_allocator::GenesisAllocator;
|
pub use genesis_allocator::GenesisAllocator;
|
||||||
|
|
||||||
pub mod generators;
|
|
||||||
|
|||||||
Reference in New Issue
Block a user