reth_e2e_test_utils/
lib.rs

1//! Utilities for end-to-end tests.
2
3use node::NodeTestContext;
4use reth_chainspec::EthChainSpec;
5use reth_db::{test_utils::TempDatabase, DatabaseEnv};
6use reth_engine_local::LocalPayloadAttributesBuilder;
7use reth_network_api::test_utils::PeersHandleProvider;
8use reth_node_api::EngineValidator;
9use reth_node_builder::{
10    components::NodeComponentsBuilder,
11    rpc::{EngineValidatorAddOn, RethRpcAddOns},
12    EngineNodeLauncher, FullNodeTypesAdapter, Node, NodeAdapter, NodeBuilder, NodeComponents,
13    NodeConfig, NodeHandle, NodeTypesWithDBAdapter, NodeTypesWithEngine, PayloadAttributesBuilder,
14    PayloadTypes,
15};
16use reth_node_core::args::{DiscoveryArgs, NetworkArgs, RpcServerArgs};
17use reth_primitives::EthPrimitives;
18use reth_provider::providers::{
19    BlockchainProvider, BlockchainProvider2, NodeTypesForProvider, NodeTypesForTree,
20};
21use reth_rpc_server_types::RpcModuleSelection;
22use reth_tasks::TaskManager;
23use std::sync::Arc;
24use tracing::{span, Level};
25use wallet::Wallet;
26
27/// Wrapper type to create test nodes
28pub mod node;
29
30/// Helper for transaction operations
31pub mod transaction;
32
33/// Helper type to yield accounts from mnemonic
34pub mod wallet;
35
36/// Helper for payload operations
37mod payload;
38
39/// Helper for network operations
40mod network;
41
42/// Helper for engine api operations
43mod engine_api;
44/// Helper for rpc operations
45mod rpc;
46
47/// Helper traits
48mod traits;
49
50/// Creates the initial setup with `num_nodes` started and interconnected.
51pub async fn setup<N>(
52    num_nodes: usize,
53    chain_spec: Arc<N::ChainSpec>,
54    is_dev: bool,
55    attributes_generator: impl Fn(u64) -> <<N as NodeTypesWithEngine>::Engine as PayloadTypes>::PayloadBuilderAttributes + Copy + 'static,
56) -> eyre::Result<(Vec<NodeHelperType<N>>, TaskManager, Wallet)>
57where
58    N: Default + Node<TmpNodeAdapter<N>> + NodeTypesForTree + NodeTypesWithEngine,
59    N::ComponentsBuilder: NodeComponentsBuilder<
60        TmpNodeAdapter<N>,
61        Components: NodeComponents<TmpNodeAdapter<N>, Network: PeersHandleProvider>,
62    >,
63    N::AddOns: RethRpcAddOns<Adapter<N>>,
64{
65    let tasks = TaskManager::current();
66    let exec = tasks.executor();
67
68    let network_config = NetworkArgs {
69        discovery: DiscoveryArgs { disable_discovery: true, ..DiscoveryArgs::default() },
70        ..NetworkArgs::default()
71    };
72
73    // Create nodes and peer them
74    let mut nodes: Vec<NodeTestContext<_, _>> = Vec::with_capacity(num_nodes);
75
76    for idx in 0..num_nodes {
77        let node_config = NodeConfig::new(chain_spec.clone())
78            .with_network(network_config.clone())
79            .with_unused_ports()
80            .with_rpc(RpcServerArgs::default().with_unused_ports().with_http())
81            .set_dev(is_dev);
82
83        let span = span!(Level::INFO, "node", idx);
84        let _enter = span.enter();
85        let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config.clone())
86            .testing_node(exec.clone())
87            .node(Default::default())
88            .launch()
89            .await?;
90
91        let mut node = NodeTestContext::new(node, attributes_generator).await?;
92
93        // Connect each node in a chain.
94        if let Some(previous_node) = nodes.last_mut() {
95            previous_node.connect(&mut node).await;
96        }
97
98        // Connect last node with the first if there are more than two
99        if idx + 1 == num_nodes && num_nodes > 2 {
100            if let Some(first_node) = nodes.first_mut() {
101                node.connect(first_node).await;
102            }
103        }
104
105        nodes.push(node);
106    }
107
108    Ok((nodes, tasks, Wallet::default().with_chain_id(chain_spec.chain().into())))
109}
110
111/// Creates the initial setup with `num_nodes` started and interconnected.
112pub async fn setup_engine<N>(
113    num_nodes: usize,
114    chain_spec: Arc<N::ChainSpec>,
115    is_dev: bool,
116    attributes_generator: impl Fn(u64) -> <<N as NodeTypesWithEngine>::Engine as PayloadTypes>::PayloadBuilderAttributes + Copy + 'static,
117) -> eyre::Result<(
118    Vec<NodeHelperType<N, BlockchainProvider2<NodeTypesWithDBAdapter<N, TmpDB>>>>,
119    TaskManager,
120    Wallet,
121)>
122where
123    N: Default
124        + Node<TmpNodeAdapter<N, BlockchainProvider2<NodeTypesWithDBAdapter<N, TmpDB>>>>
125        + NodeTypesWithEngine<Primitives = EthPrimitives>
126        + NodeTypesForProvider,
127    N::ComponentsBuilder: NodeComponentsBuilder<
128        TmpNodeAdapter<N, BlockchainProvider2<NodeTypesWithDBAdapter<N, TmpDB>>>,
129        Components: NodeComponents<
130            TmpNodeAdapter<N, BlockchainProvider2<NodeTypesWithDBAdapter<N, TmpDB>>>,
131            Network: PeersHandleProvider,
132        >,
133    >,
134    N::AddOns: RethRpcAddOns<Adapter<N, BlockchainProvider2<NodeTypesWithDBAdapter<N, TmpDB>>>>
135        + EngineValidatorAddOn<
136            Adapter<N, BlockchainProvider2<NodeTypesWithDBAdapter<N, TmpDB>>>,
137            Validator: EngineValidator<N::Engine, Block = reth_primitives::Block>,
138        >,
139    LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
140        <<N as NodeTypesWithEngine>::Engine as PayloadTypes>::PayloadAttributes,
141    >,
142{
143    let tasks = TaskManager::current();
144    let exec = tasks.executor();
145
146    let network_config = NetworkArgs {
147        discovery: DiscoveryArgs { disable_discovery: true, ..DiscoveryArgs::default() },
148        ..NetworkArgs::default()
149    };
150
151    // Create nodes and peer them
152    let mut nodes: Vec<NodeTestContext<_, _>> = Vec::with_capacity(num_nodes);
153
154    for idx in 0..num_nodes {
155        let node_config = NodeConfig::new(chain_spec.clone())
156            .with_network(network_config.clone())
157            .with_unused_ports()
158            .with_rpc(
159                RpcServerArgs::default()
160                    .with_unused_ports()
161                    .with_http()
162                    .with_http_api(RpcModuleSelection::All),
163            )
164            .set_dev(is_dev);
165
166        let span = span!(Level::INFO, "node", idx);
167        let _enter = span.enter();
168        let node = N::default();
169        let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config.clone())
170            .testing_node(exec.clone())
171            .with_types_and_provider::<N, BlockchainProvider2<_>>()
172            .with_components(node.components_builder())
173            .with_add_ons(node.add_ons())
174            .launch_with_fn(|builder| {
175                let launcher = EngineNodeLauncher::new(
176                    builder.task_executor().clone(),
177                    builder.config().datadir(),
178                    Default::default(),
179                );
180                builder.launch_with(launcher)
181            })
182            .await?;
183
184        let mut node = NodeTestContext::new(node, attributes_generator).await?;
185
186        let genesis = node.block_hash(0);
187        node.engine_api.update_forkchoice(genesis, genesis).await?;
188
189        // Connect each node in a chain.
190        if let Some(previous_node) = nodes.last_mut() {
191            previous_node.connect(&mut node).await;
192        }
193
194        // Connect last node with the first if there are more than two
195        if idx + 1 == num_nodes && num_nodes > 2 {
196            if let Some(first_node) = nodes.first_mut() {
197                node.connect(first_node).await;
198            }
199        }
200
201        nodes.push(node);
202    }
203
204    Ok((nodes, tasks, Wallet::default().with_chain_id(chain_spec.chain().into())))
205}
206
207// Type aliases
208
209/// Testing database
210pub type TmpDB = Arc<TempDatabase<DatabaseEnv>>;
211type TmpNodeAdapter<N, Provider = BlockchainProvider<NodeTypesWithDBAdapter<N, TmpDB>>> =
212    FullNodeTypesAdapter<NodeTypesWithDBAdapter<N, TmpDB>, Provider>;
213
214/// Type alias for a `NodeAdapter`
215pub type Adapter<N, Provider = BlockchainProvider<NodeTypesWithDBAdapter<N, TmpDB>>> = NodeAdapter<
216    TmpNodeAdapter<N, Provider>,
217    <<N as Node<TmpNodeAdapter<N, Provider>>>::ComponentsBuilder as NodeComponentsBuilder<
218        TmpNodeAdapter<N, Provider>,
219    >>::Components,
220>;
221
222/// Type alias for a type of `NodeHelper`
223pub type NodeHelperType<N, Provider = BlockchainProvider<NodeTypesWithDBAdapter<N, TmpDB>>> =
224    NodeTestContext<Adapter<N, Provider>, <N as Node<TmpNodeAdapter<N, Provider>>>::AddOns>;