reth_beacon_consensus/engine/hooks/
mod.rs

1use alloy_primitives::BlockNumber;
2use reth_errors::{RethError, RethResult};
3use std::{
4    fmt,
5    task::{Context, Poll},
6};
7
8mod controller;
9pub(crate) use controller::{EngineHooksController, PolledHook};
10
11mod prune;
12pub use prune::PruneHook;
13
14mod static_file;
15pub use static_file::StaticFileHook;
16
17/// Collection of [engine hooks][`EngineHook`].
18#[derive(Default)]
19pub struct EngineHooks {
20    inner: Vec<Box<dyn EngineHook>>,
21}
22
23impl fmt::Debug for EngineHooks {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        f.debug_struct("EngineHooks").field("inner", &self.inner.len()).finish()
26    }
27}
28
29impl EngineHooks {
30    /// Creates a new empty collection of [engine hooks][`EngineHook`].
31    pub fn new() -> Self {
32        Self { inner: Vec::new() }
33    }
34
35    /// Adds a new [engine hook][`EngineHook`] to the collection.
36    pub fn add<H: EngineHook>(&mut self, hook: H) {
37        self.inner.push(Box::new(hook))
38    }
39}
40
41/// Hook that will be run during the main loop of
42/// [consensus engine][`crate::engine::BeaconConsensusEngine`].
43pub trait EngineHook: Send + Sync + 'static {
44    /// Returns a human-readable name for the hook.
45    fn name(&self) -> &'static str;
46
47    /// Advances the hook execution, emitting an [event][`EngineHookEvent`].
48    fn poll(
49        &mut self,
50        cx: &mut Context<'_>,
51        ctx: EngineHookContext,
52    ) -> Poll<RethResult<EngineHookEvent>>;
53
54    /// Returns [db access level][`EngineHookDBAccessLevel`] the hook needs.
55    fn db_access_level(&self) -> EngineHookDBAccessLevel;
56}
57
58/// Engine context passed to the [hook polling function][`EngineHook::poll`].
59#[derive(Copy, Clone, Debug)]
60pub struct EngineHookContext {
61    /// Tip block number.
62    pub tip_block_number: BlockNumber,
63    /// Finalized block number, if known.
64    pub finalized_block_number: Option<BlockNumber>,
65}
66
67/// An event emitted when [hook][`EngineHook`] is polled.
68#[derive(Debug)]
69pub enum EngineHookEvent {
70    /// Hook is not ready.
71    ///
72    /// If this is returned, the hook is idle.
73    NotReady,
74    /// Hook started.
75    ///
76    /// If this is returned, the hook is running.
77    Started,
78    /// Hook finished.
79    ///
80    /// If this is returned, the hook is idle.
81    Finished(Result<(), EngineHookError>),
82}
83
84impl EngineHookEvent {
85    /// Returns `true` if the event is [`EngineHookEvent::Started`].
86    pub const fn is_started(&self) -> bool {
87        matches!(self, Self::Started)
88    }
89
90    /// Returns `true` if the event is [`EngineHookEvent::Finished`].
91    pub const fn is_finished(&self) -> bool {
92        matches!(self, Self::Finished(_))
93    }
94}
95
96/// An error returned by [hook][`EngineHook`].
97#[derive(Debug, thiserror::Error)]
98pub enum EngineHookError {
99    /// Hook channel closed.
100    #[error("hook channel closed")]
101    ChannelClosed,
102    /// Common error. Wrapper around [`RethError`].
103    #[error(transparent)]
104    Common(#[from] RethError),
105    /// An internal error occurred.
106    #[error(transparent)]
107    Internal(#[from] Box<dyn core::error::Error + Send + Sync>),
108}
109
110/// Level of database access the hook needs for execution.
111#[derive(Debug, Copy, Clone, Eq, PartialEq)]
112pub enum EngineHookDBAccessLevel {
113    /// Read-only database access.
114    ReadOnly,
115    /// Read-write database access.
116    ReadWrite,
117}
118
119impl EngineHookDBAccessLevel {
120    /// Returns `true` if the hook needs read-only access to the database.
121    pub const fn is_read_only(&self) -> bool {
122        matches!(self, Self::ReadOnly)
123    }
124
125    /// Returns `true` if the hook needs read-write access to the database.
126    pub const fn is_read_write(&self) -> bool {
127        matches!(self, Self::ReadWrite)
128    }
129}