1use crate::{ExExContextDyn, ExExEvent, ExExNotifications, ExExNotificationsStream};
2use alloy_eips::BlockNumHash;
3use reth_exex_types::ExExHead;
4use reth_node_api::{FullNodeComponents, NodeTypes, PrimitivesTy};
5use reth_node_core::node_config::NodeConfig;
6use reth_payload_builder::PayloadBuilderHandle;
7use reth_tasks::TaskExecutor;
8use std::fmt::Debug;
9use tokio::sync::mpsc::{error::SendError, UnboundedSender};
10
11pub struct ExExContext<Node: FullNodeComponents> {
15 pub head: BlockNumHash,
17 pub config: NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
19 pub reth_config: reth_config::Config,
21 pub events: UnboundedSender<ExExEvent>,
29 pub notifications: ExExNotifications<Node::Provider, Node::Evm>,
36
37 pub components: Node,
39}
40
41impl<Node> Debug for ExExContext<Node>
42where
43 Node: FullNodeComponents,
44{
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 f.debug_struct("ExExContext")
47 .field("head", &self.head)
48 .field("config", &self.config)
49 .field("reth_config", &self.reth_config)
50 .field("events", &self.events)
51 .field("notifications", &self.notifications)
52 .field("components", &"...")
53 .finish()
54 }
55}
56
57impl<Node> ExExContext<Node>
58where
59 Node: FullNodeComponents,
60{
61 pub fn into_dyn(self) -> ExExContextDyn<PrimitivesTy<Node::Types>> {
63 ExExContextDyn::from(self)
64 }
65}
66
67impl<Node> ExExContext<Node>
68where
69 Node: FullNodeComponents,
70{
71 pub fn pool(&self) -> &Node::Pool {
73 self.components.pool()
74 }
75
76 pub fn evm_config(&self) -> &Node::Evm {
78 self.components.evm_config()
79 }
80
81 pub fn provider(&self) -> &Node::Provider {
83 self.components.provider()
84 }
85
86 pub fn network(&self) -> &Node::Network {
88 self.components.network()
89 }
90
91 pub fn payload_builder_handle(
93 &self,
94 ) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
95 self.components.payload_builder_handle()
96 }
97
98 pub fn task_executor(&self) -> &TaskExecutor {
102 self.components.task_executor()
103 }
104
105 pub fn set_notifications_without_head(&mut self) {
108 self.notifications.set_without_head();
109 }
110
111 pub fn set_notifications_with_head(&mut self, head: ExExHead) {
114 self.notifications.set_with_head(head);
115 }
116
117 pub fn catch_up_notifications_with_head(&mut self, head: ExExHead) -> eyre::Result<()> {
120 self.notifications.catch_up_with_head(head)
121 }
122
123 pub fn send_finished_height(
128 &self,
129 height: BlockNumHash,
130 ) -> Result<(), SendError<BlockNumHash>> {
131 self.events.send(ExExEvent::FinishedHeight(height)).map_err(|_| SendError(height))
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use crate::ExExContext;
138 use reth_exex_types::ExExHead;
139 use reth_node_api::FullNodeComponents;
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 async fn _test_bounds(mut self) -> eyre::Result<()> {
151 self.ctx.pool();
152 self.ctx.evm_config();
153 self.ctx.provider();
154 self.ctx.network();
155 self.ctx.payload_builder_handle();
156 self.ctx.task_executor();
157 self.ctx.set_notifications_without_head();
158 self.ctx.set_notifications_with_head(ExExHead { block: Default::default() });
159 Ok(())
160 }
161 }
162 }
163}