reth_e2e_test_utils/testsuite/actions/
reorg.rs1use crate::testsuite::{
4 actions::{produce_blocks::BroadcastLatestForkchoice, Action, Sequence},
5 BlockInfo, Environment,
6};
7use alloy_primitives::B256;
8use alloy_rpc_types_engine::{ForkchoiceState, PayloadAttributes};
9use eyre::Result;
10use futures_util::future::BoxFuture;
11use reth_node_api::{EngineTypes, PayloadTypes};
12use std::marker::PhantomData;
13use tracing::debug;
14
15#[derive(Debug, Clone)]
17pub enum ReorgTarget {
18 Hash(B256),
20 Tag(String),
22}
23
24#[derive(Debug)]
26pub struct ReorgTo<Engine> {
27 pub target: ReorgTarget,
29 _phantom: PhantomData<Engine>,
31}
32
33impl<Engine> ReorgTo<Engine> {
34 pub const fn new(target_hash: B256) -> Self {
36 Self { target: ReorgTarget::Hash(target_hash), _phantom: PhantomData }
37 }
38
39 pub fn new_from_tag(tag: impl Into<String>) -> Self {
41 Self { target: ReorgTarget::Tag(tag.into()), _phantom: PhantomData }
42 }
43}
44
45impl<Engine> Action<Engine> for ReorgTo<Engine>
46where
47 Engine: EngineTypes + PayloadTypes,
48 Engine::PayloadAttributes: From<PayloadAttributes> + Clone,
49 Engine::ExecutionPayloadEnvelopeV3:
50 Into<alloy_rpc_types_engine::payload::ExecutionPayloadEnvelopeV3>,
51{
52 fn execute<'a>(&'a mut self, env: &'a mut Environment<Engine>) -> BoxFuture<'a, Result<()>> {
53 Box::pin(async move {
54 let target_block_info = match &self.target {
56 ReorgTarget::Hash(_hash) => {
57 return Err(eyre::eyre!(
58 "Direct hash reorgs are not supported. Use CaptureBlock to tag the target block first, then use ReorgTo::new_from_tag()"
59 ));
60 }
61 ReorgTarget::Tag(tag) => {
62 let (block_info, _node_idx) =
63 env.block_registry.get(tag).copied().ok_or_else(|| {
64 eyre::eyre!("Block tag '{}' not found in registry", tag)
65 })?;
66 block_info
67 }
68 };
69
70 let mut sequence = Sequence::new(vec![
71 Box::new(SetReorgTarget::new(target_block_info)),
72 Box::new(BroadcastLatestForkchoice::default()),
73 ]);
74
75 sequence.execute(env).await
76 })
77 }
78}
79
80#[derive(Debug)]
82pub struct SetReorgTarget {
83 pub target_block_info: BlockInfo,
85}
86
87impl SetReorgTarget {
88 pub const fn new(target_block_info: BlockInfo) -> Self {
90 Self { target_block_info }
91 }
92}
93
94impl<Engine> Action<Engine> for SetReorgTarget
95where
96 Engine: EngineTypes,
97{
98 fn execute<'a>(&'a mut self, env: &'a mut Environment<Engine>) -> BoxFuture<'a, Result<()>> {
99 Box::pin(async move {
100 let block_info = self.target_block_info;
101
102 debug!(
103 "Setting reorg target to block {} (hash: {})",
104 block_info.number, block_info.hash
105 );
106
107 let active_node_state = env.active_node_state_mut()?;
109 active_node_state.current_block_info = Some(block_info);
110 active_node_state.latest_header_time = block_info.timestamp;
111
112 active_node_state.latest_fork_choice_state = ForkchoiceState {
114 head_block_hash: block_info.hash,
115 safe_block_hash: block_info.hash,
116 finalized_block_hash: block_info.hash,
117 };
118
119 debug!("Set reorg target to block {}", block_info.hash);
120 Ok(())
121 })
122 }
123}