1use crate::{ExExContextDyn, ExExEvent, ExExNotifications, ExExNotificationsStream};
2use alloy_eips::BlockNumHash;
3use reth_exex_types::ExExHead;
4use reth_node_api::{FullNodeComponents, NodePrimitives, NodeTypes, PrimitivesTy};
5use reth_node_core::node_config::NodeConfig;
6use reth_payload_builder::PayloadBuilderHandle;
7use reth_provider::BlockReader;
8use reth_tasks::TaskExecutor;
9use std::fmt::Debug;
10use tokio::sync::mpsc::{error::SendError, UnboundedSender};
11
12pub struct ExExContext<Node: FullNodeComponents> {
16    pub head: BlockNumHash,
18    pub config: NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
20    pub reth_config: reth_config::Config,
22    pub events: UnboundedSender<ExExEvent>,
30    pub notifications: ExExNotifications<Node::Provider, Node::Evm>,
37
38    pub components: Node,
40}
41
42impl<Node> Debug for ExExContext<Node>
43where
44    Node: FullNodeComponents,
45    Node::Provider: Debug,
46{
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        f.debug_struct("ExExContext")
49            .field("head", &self.head)
50            .field("config", &self.config)
51            .field("reth_config", &self.reth_config)
52            .field("events", &self.events)
53            .field("notifications", &self.notifications)
54            .field("components", &"...")
55            .finish()
56    }
57}
58
59impl<Node> ExExContext<Node>
60where
61    Node: FullNodeComponents,
62    Node::Provider: Debug + BlockReader,
63    Node::Types: NodeTypes<Primitives: NodePrimitives>,
64{
65    pub fn into_dyn(self) -> ExExContextDyn<PrimitivesTy<Node::Types>> {
67        ExExContextDyn::from(self)
68    }
69}
70
71impl<Node> ExExContext<Node>
72where
73    Node: FullNodeComponents,
74    Node::Types: NodeTypes<Primitives: NodePrimitives>,
75{
76    pub fn pool(&self) -> &Node::Pool {
78        self.components.pool()
79    }
80
81    pub fn evm_config(&self) -> &Node::Evm {
83        self.components.evm_config()
84    }
85
86    pub fn provider(&self) -> &Node::Provider {
88        self.components.provider()
89    }
90
91    pub fn network(&self) -> &Node::Network {
93        self.components.network()
94    }
95
96    pub fn payload_builder_handle(
98        &self,
99    ) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
100        self.components.payload_builder_handle()
101    }
102
103    pub fn task_executor(&self) -> &TaskExecutor {
107        self.components.task_executor()
108    }
109
110    pub fn set_notifications_without_head(&mut self) {
113        self.notifications.set_without_head();
114    }
115
116    pub fn set_notifications_with_head(&mut self, head: ExExHead) {
119        self.notifications.set_with_head(head);
120    }
121
122    pub fn send_finished_height(
127        &self,
128        height: BlockNumHash,
129    ) -> Result<(), SendError<BlockNumHash>> {
130        self.events.send(ExExEvent::FinishedHeight(height)).map_err(|_| SendError(height))
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use crate::ExExContext;
137    use reth_exex_types::ExExHead;
138    use reth_node_api::FullNodeComponents;
139    use reth_provider::BlockReader;
140
141    #[test]
143    const fn issue_12054() {
144        #[expect(dead_code)]
145        struct ExEx<Node: FullNodeComponents> {
146            ctx: ExExContext<Node>,
147        }
148
149        impl<Node: FullNodeComponents> ExEx<Node>
150        where
151            Node::Provider: BlockReader,
152        {
153            async fn _test_bounds(mut self) -> eyre::Result<()> {
154                self.ctx.pool();
155                self.ctx.evm_config();
156                self.ctx.provider();
157                self.ctx.network();
158                self.ctx.payload_builder_handle();
159                self.ctx.task_executor();
160                self.ctx.set_notifications_without_head();
161                self.ctx.set_notifications_with_head(ExExHead { block: Default::default() });
162                Ok(())
163            }
164        }
165    }
166}