Skip to main content

signet_test_utils/specs/
notif_spec.rs

1use crate::{chain::Chain, specs::HostBlockSpec};
2use alloy::consensus::BlobTransactionSidecar;
3use signet_types::primitives::TransactionSigned;
4use std::{collections::BTreeMap, sync::Arc};
5
6/// A shim for reth_exex::ExExNotification that allows us to use it in tests.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum ExExNotification {
9    /// Chain got committed without a reorg, and only the new chain is returned.
10    Committed {
11        /// The new chain after commit.
12        new: Arc<Chain>,
13    },
14    /// Chain got reorged, and both the old and the new chains are returned.
15    Reorged {
16        /// The old chain before reorg.
17        old: Arc<Chain>,
18        /// The new chain after reorg.
19        new: Arc<Chain>,
20    },
21    /// Chain got reverted, and only the old chain is returned.
22    Reverted {
23        /// The old chain before reversion.
24        old: Arc<Chain>,
25    },
26}
27
28impl ExExNotification {
29    /// Returns the committed chain, if any.
30    pub fn committed_chain(&self) -> Option<&Arc<Chain>> {
31        match self {
32            ExExNotification::Committed { new } => Some(new),
33            ExExNotification::Reorged { new, .. } => Some(new),
34            ExExNotification::Reverted { .. } => None,
35        }
36    }
37
38    /// Returns the reverted chain, if any.
39    pub fn reverted_chain(&self) -> Option<&Arc<Chain>> {
40        match self {
41            ExExNotification::Reorged { old, .. } => Some(old),
42            ExExNotification::Reverted { old } => Some(old),
43            ExExNotification::Committed { .. } => None,
44        }
45    }
46}
47
48/// A notification spec.
49#[derive(Debug, Default)]
50pub struct NotificationSpec {
51    /// The old blocks.
52    pub old: Vec<HostBlockSpec>,
53    /// The new blocks.
54    pub new: Vec<HostBlockSpec>,
55}
56
57impl NotificationSpec {
58    /// Make a new notification spec from a single block
59    pub fn commit_single_block(block: HostBlockSpec) -> Self {
60        Self { old: vec![], new: vec![block] }
61    }
62
63    /// Make a new notification spec from a single block
64    pub fn revert_single_block(block: HostBlockSpec) -> Self {
65        Self { old: vec![block], new: vec![] }
66    }
67
68    /// Commit a block to the spec.
69    pub fn commit(mut self, block: HostBlockSpec) -> Self {
70        self.new.push(block);
71        self
72    }
73
74    /// Add a block to revert to the spec.
75    pub fn revert(mut self, block: HostBlockSpec) -> Self {
76        self.old.push(block);
77        self
78    }
79
80    /// Convert to an exex notification.
81    pub fn to_exex_notification(&self) -> NotificationWithSidecars {
82        let mut sidecars = BTreeMap::new();
83
84        // we do not accumulate sidecars for the old chain.
85        let old_chain = if !self.old.is_empty() {
86            let num = self.old[0].block_number();
87            let (mut chain, _sidecar) = self.old[0].to_chain();
88
89            // we enumerate to ensure they're in block number order
90            for (i, block) in self.old.iter().enumerate().skip(1) {
91                block.set_block_number(num + i as u64);
92                chain.append_block(block.recovered_block(), block.execution_outcome());
93            }
94            Some(chain)
95        } else {
96            None
97        };
98
99        let new_chain = if !self.new.is_empty() {
100            let num = self.new[0].block_number();
101            let (mut chain, sidecar) = self.new[0].to_chain();
102            // accumulate sidecar if necessary
103            if let Some(sidecar) = sidecar {
104                let tx = self.new[0].sealed_block().transactions().last().unwrap().clone();
105                sidecars.insert(num, (sidecar, tx));
106            }
107
108            // we enumerate to ensure they're in block number order
109            for (i, block) in self.new.iter().enumerate().skip(1) {
110                block.set_block_number(num + i as u64);
111
112                let execution_outcome = block.execution_outcome();
113
114                // accumualate the sidecar here if necessary
115                if let Some(sidecar) = block.sidecar.clone() {
116                    let tx = block.sealed_block().transactions().last().unwrap().clone();
117                    sidecars.insert(block.block_number(), (sidecar, tx));
118                }
119
120                chain.append_block(block.recovered_block(), execution_outcome)
121            }
122
123            Some(chain)
124        } else {
125            None
126        };
127
128        match (old_chain, new_chain) {
129            (Some(old_chain), Some(new_chain)) => NotificationWithSidecars {
130                notification: ExExNotification::Reorged {
131                    old: Arc::new(old_chain),
132                    new: Arc::new(new_chain),
133                },
134                sidecars,
135            },
136            (Some(old_chain), None) => NotificationWithSidecars {
137                notification: ExExNotification::Reverted { old: Arc::new(old_chain) },
138                sidecars,
139            },
140            (None, Some(new_chain)) => NotificationWithSidecars {
141                notification: ExExNotification::Committed { new: Arc::new(new_chain) },
142                sidecars,
143            },
144            (None, None) => panic!("missing old and new chains"),
145        }
146    }
147}
148
149/// A notification with sidecars associated with the new chain.
150#[derive(Debug, Clone)]
151pub struct NotificationWithSidecars {
152    /// The notification.
153    pub notification: ExExNotification,
154    /// Sidecars associated with the new chain.
155    pub sidecars: BTreeMap<u64, (BlobTransactionSidecar, TransactionSigned)>,
156}
157
158impl NotificationWithSidecars {
159    /// Make a new notification from a single block
160    pub fn commit_single_block(block: HostBlockSpec) -> Self {
161        NotificationSpec::commit_single_block(block).to_exex_notification()
162    }
163
164    /// Make a new notification from a single block
165    pub fn revert_single_block(block: HostBlockSpec) -> Self {
166        NotificationSpec::revert_single_block(block).to_exex_notification()
167    }
168}