reth_e2e_test_utils/testsuite/
mod.rs
1use crate::{
4 testsuite::actions::{Action, ActionBox},
5 NodeBuilderHelper, PayloadAttributesBuilder,
6};
7use alloy_primitives::B256;
8use eyre::Result;
9use jsonrpsee::http_client::{transport::HttpBackend, HttpClient};
10use reth_engine_local::LocalPayloadAttributesBuilder;
11use reth_node_api::{NodeTypes, PayloadTypes};
12use reth_payload_builder::PayloadId;
13use reth_rpc_layer::AuthClientService;
14use setup::Setup;
15use std::{collections::HashMap, marker::PhantomData};
16pub mod actions;
17pub mod setup;
18use alloy_rpc_types_engine::{ForkchoiceState, PayloadAttributes};
19
20#[cfg(test)]
21mod examples;
22
23#[derive(Debug)]
25pub struct NodeClient {
26 pub rpc: HttpClient,
28 pub engine: HttpClient<AuthClientService<HttpBackend>>,
30}
31
32#[derive(Debug, Clone)]
34pub struct LatestBlockInfo {
35 pub hash: B256,
37 pub number: u64,
39}
40#[derive(Debug)]
42pub struct Environment<I> {
43 pub node_clients: Vec<NodeClient>,
45 _phantom: PhantomData<I>,
47 pub latest_block_info: Option<LatestBlockInfo>,
49 pub last_producer_idx: Option<usize>,
51 pub payload_attributes: HashMap<u64, PayloadAttributes>,
53 pub latest_header_time: u64,
55 pub block_timestamp_increment: u64,
57 pub payload_id_history: HashMap<u64, PayloadId>,
59 pub next_payload_id: Option<PayloadId>,
61 pub latest_fork_choice_state: ForkchoiceState,
63 pub latest_payload_built: Option<PayloadAttributes>,
65 pub latest_payload_executed: Option<PayloadAttributes>,
67 pub slots_to_safe: u64,
69 pub slots_to_finalized: u64,
71}
72
73impl<I> Default for Environment<I> {
74 fn default() -> Self {
75 Self {
76 node_clients: vec![],
77 _phantom: Default::default(),
78 latest_block_info: None,
79 last_producer_idx: None,
80 payload_attributes: Default::default(),
81 latest_header_time: 0,
82 block_timestamp_increment: 2,
83 payload_id_history: HashMap::new(),
84 next_payload_id: None,
85 latest_fork_choice_state: ForkchoiceState::default(),
86 latest_payload_built: None,
87 latest_payload_executed: None,
88 slots_to_safe: 0,
89 slots_to_finalized: 0,
90 }
91 }
92}
93
94#[expect(missing_debug_implementations)]
96#[derive(Default)]
97pub struct TestBuilder<I> {
98 setup: Option<Setup<I>>,
99 actions: Vec<ActionBox<I>>,
100 env: Environment<I>,
101}
102
103impl<I: 'static> TestBuilder<I> {
104 pub fn new() -> Self {
106 Self { setup: None, actions: Vec::new(), env: Default::default() }
107 }
108
109 pub fn with_setup(mut self, setup: Setup<I>) -> Self {
111 self.setup = Some(setup);
112 self
113 }
114
115 pub fn with_action<A>(mut self, action: A) -> Self
117 where
118 A: Action<I>,
119 {
120 self.actions.push(ActionBox::<I>::new(action));
121 self
122 }
123
124 pub fn with_actions<II, A>(mut self, actions: II) -> Self
126 where
127 II: IntoIterator<Item = A>,
128 A: Action<I>,
129 {
130 self.actions.extend(actions.into_iter().map(ActionBox::new));
131 self
132 }
133
134 pub async fn run<N>(mut self) -> Result<()>
136 where
137 N: NodeBuilderHelper,
138 LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
139 <<N as NodeTypes>::Payload as PayloadTypes>::PayloadAttributes,
140 >,
141 {
142 let mut setup = self.setup.take();
143
144 if let Some(ref mut s) = setup {
145 s.apply::<N>(&mut self.env).await?;
146 }
147
148 let actions = std::mem::take(&mut self.actions);
149
150 for action in actions {
151 action.execute(&mut self.env).await?;
152 }
153
154 drop(setup);
157
158 Ok(())
159 }
160}