reth_exex/
lib.rs

1//! Execution extensions (`ExEx`).
2//!
3//! An execution extension is a task that listens to state changes of the node.
4//!
5//! Some examples of such state derives are rollups, bridges, and indexers.
6//!
7//! An `ExEx` is a [`Future`] resolving to a `Result<()>` that is run indefinitely alongside the
8//! node.
9//!
10//! `ExEx`'s are initialized using an async closure that resolves to the `ExEx`; this closure gets
11//! passed an [`ExExContext`] where it is possible to spawn additional tasks and modify Reth.
12//!
13//! Most `ExEx`'s will want to derive their state from the [`CanonStateNotification`] channel given
14//! in [`ExExContext`]. A new notification is emitted whenever blocks are executed in live and
15//! historical sync.
16//!
17//! # Pruning
18//!
19//! `ExEx`'s **SHOULD** emit an `ExExEvent::FinishedHeight` event to signify what blocks have been
20//! processed. This event is used by Reth to determine what state can be pruned.
21//!
22//! An `ExEx` will only receive notifications for blocks greater than the block emitted in the
23//! event. To clarify: if the `ExEx` emits `ExExEvent::FinishedHeight(0)` it will receive
24//! notifications for any `block_number > 0`.
25//!
26//! # Examples, Assumptions, and Invariants
27//!
28//! ## Examples
29//!
30//! ### Simple Indexer ExEx
31//! ```no_run
32//! use alloy_consensus::BlockHeader;
33//! use futures::StreamExt;
34//! use reth_exex::ExExContext;
35//! use reth_node_api::FullNodeComponents;
36//! use reth_provider::CanonStateNotification;
37//!
38//! async fn my_indexer<N: FullNodeComponents>(
39//!     mut ctx: ExExContext<N>,
40//! ) -> Result<(), Box<dyn std::error::Error>> {
41//!     // Subscribe to canonical state notifications
42//!
43//!     while let Some(Ok(notification)) = ctx.notifications.next().await {
44//!         if let Some(committed) = notification.committed_chain() {
45//!             for block in committed.blocks_iter() {
46//!                 // Index or process block data
47//!                 println!("Processed block: {}", block.number());
48//!             }
49//!
50//!             // Signal completion for pruning
51//!             ctx.send_finished_height(committed.tip().num_hash());
52//!         }
53//!     }
54//!
55//!     Ok(())
56//! }
57//! ```
58//!
59//! ## Assumptions
60//!
61//! - `ExExs` run indefinitely alongside Reth
62//! - `ExExs` receive canonical state notifications for block execution
63//! - `ExExs` should handle potential network or database errors gracefully
64//! - `ExExs` must emit `FinishedHeight` events for proper state pruning
65//!
66//! ## Invariants
67//!
68//! - An ExEx must not block the main Reth execution
69//! - Notifications are processed in canonical order
70//! - `ExExs` should be able to recover from temporary failures
71//! - Memory and resource usage must be controlled
72//!
73//! ## Performance Considerations
74//!
75//! - Minimize blocking operations
76//! - Use efficient data structures for state tracking
77//! - Implement proper error handling and logging
78//! - Consider batching operations for better performance
79//!
80//! [`Future`]: std::future::Future
81//! [`ExExContext`]: crate::ExExContext
82//! [`CanonStateNotification`]: reth_provider::CanonStateNotification
83#![doc(
84    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
85    html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
86    issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
87)]
88#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
89#![cfg_attr(not(test), warn(unused_crate_dependencies))]
90
91mod backfill;
92pub use backfill::*;
93
94mod context;
95pub use context::*;
96
97mod dyn_context;
98pub use dyn_context::*;
99
100mod event;
101pub use event::*;
102
103mod manager;
104pub use manager::*;
105
106mod notifications;
107pub use notifications::*;
108
109mod wal;
110pub use wal::*;
111
112// Re-export exex types
113#[doc(inline)]
114pub use reth_exex_types::*;