reth_e2e_test_utils/
lib.rs

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