reth_beacon_consensus/engine/hooks/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use alloy_primitives::BlockNumber;
use reth_errors::{RethError, RethResult};
use std::{
    fmt,
    task::{Context, Poll},
};

mod controller;
pub(crate) use controller::{EngineHooksController, PolledHook};

mod prune;
pub use prune::PruneHook;

mod static_file;
pub use static_file::StaticFileHook;

/// Collection of [engine hooks][`EngineHook`].
#[derive(Default)]
pub struct EngineHooks {
    inner: Vec<Box<dyn EngineHook>>,
}

impl fmt::Debug for EngineHooks {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("EngineHooks").field("inner", &self.inner.len()).finish()
    }
}

impl EngineHooks {
    /// Creates a new empty collection of [engine hooks][`EngineHook`].
    pub fn new() -> Self {
        Self { inner: Vec::new() }
    }

    /// Adds a new [engine hook][`EngineHook`] to the collection.
    pub fn add<H: EngineHook>(&mut self, hook: H) {
        self.inner.push(Box::new(hook))
    }
}

/// Hook that will be run during the main loop of
/// [consensus engine][`crate::engine::BeaconConsensusEngine`].
pub trait EngineHook: Send + Sync + 'static {
    /// Returns a human-readable name for the hook.
    fn name(&self) -> &'static str;

    /// Advances the hook execution, emitting an [event][`EngineHookEvent`].
    fn poll(
        &mut self,
        cx: &mut Context<'_>,
        ctx: EngineHookContext,
    ) -> Poll<RethResult<EngineHookEvent>>;

    /// Returns [db access level][`EngineHookDBAccessLevel`] the hook needs.
    fn db_access_level(&self) -> EngineHookDBAccessLevel;
}

/// Engine context passed to the [hook polling function][`EngineHook::poll`].
#[derive(Copy, Clone, Debug)]
pub struct EngineHookContext {
    /// Tip block number.
    pub tip_block_number: BlockNumber,
    /// Finalized block number, if known.
    pub finalized_block_number: Option<BlockNumber>,
}

/// An event emitted when [hook][`EngineHook`] is polled.
#[derive(Debug)]
pub enum EngineHookEvent {
    /// Hook is not ready.
    ///
    /// If this is returned, the hook is idle.
    NotReady,
    /// Hook started.
    ///
    /// If this is returned, the hook is running.
    Started,
    /// Hook finished.
    ///
    /// If this is returned, the hook is idle.
    Finished(Result<(), EngineHookError>),
}

impl EngineHookEvent {
    /// Returns `true` if the event is [`EngineHookEvent::Started`].
    pub const fn is_started(&self) -> bool {
        matches!(self, Self::Started)
    }

    /// Returns `true` if the event is [`EngineHookEvent::Finished`].
    pub const fn is_finished(&self) -> bool {
        matches!(self, Self::Finished(_))
    }
}

/// An error returned by [hook][`EngineHook`].
#[derive(Debug, thiserror::Error)]
pub enum EngineHookError {
    /// Hook channel closed.
    #[error("hook channel closed")]
    ChannelClosed,
    /// Common error. Wrapper around [`RethError`].
    #[error(transparent)]
    Common(#[from] RethError),
    /// An internal error occurred.
    #[error(transparent)]
    Internal(#[from] Box<dyn core::error::Error + Send + Sync>),
}

/// Level of database access the hook needs for execution.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum EngineHookDBAccessLevel {
    /// Read-only database access.
    ReadOnly,
    /// Read-write database access.
    ReadWrite,
}

impl EngineHookDBAccessLevel {
    /// Returns `true` if the hook needs read-only access to the database.
    pub const fn is_read_only(&self) -> bool {
        matches!(self, Self::ReadOnly)
    }

    /// Returns `true` if the hook needs read-write access to the database.
    pub const fn is_read_write(&self) -> bool {
        matches!(self, Self::ReadWrite)
    }
}