casper_node/
components.rs

1//! Components subsystem.
2//!
3//! Components are the building blocks for the application and wired together inside a
4//! [reactor](crate::reactor). Each component has a unified interface, expressed by the
5//! [`Component`] trait.
6//!
7//! # Events
8//!
9//! Every component defines a set of events it can process, expressed through the
10//! [`Component::Event`] associated type. If an event that originated outside the component is to be
11//! handled (e.g. a request or announcement being handled), a `From<OutsideEvent> for
12//! ComponentEvent` implementation must be added (see component vs reactor event section below).
13//!
14//! A typical cycle for components is to receive an event, either originating from the outside, or
15//! as the result of an effect created by the component. This event is processed in the
16//! [`handle_event`](Component::handle_event) function, potentially returning effects that may
17//! produce new events.
18//!
19//! # Error and halting states
20//!
21//! Components in general are expected to be able to handle every input (that is every
22//! [`Component::Event`]) in every state. Unexpected inputs should usually be logged and discarded,
23//! if possible, and the component is expected to recover from error states by itself.
24//!
25//! When a recovery is not possible, the [`fatal!`](crate::fatal!) macro should be used to produce
26//! an effect that will shut down the system.
27//!
28//! # Component events and reactor events
29//!
30//! It is easy to confuse the components own associated event ([`Component::Event`]) and the
31//! so-called "reactor event", often written `REv` (see [`effects`](crate::effect) for details on
32//! the distinctions).
33//!
34//! A component's own event defines what sort of events it produces purely for internal use, and
35//! also which unbound events it can accept. **Acceptance of external events** is expressed by
36//! implementing a `From` implementation for the unbound, i.e. a component that can process
37//! `FooAnnouncement` and a `BarRequest` will have to `impl From<FooAnnouncement> for Event` and
38//! `impl From<BarRequest>`, with `Event` being the event named as [`Component::Event`].
39//!
40//! Since components are usually not specific to only a single reactor, they have to implement
41//! `Component<REv>` for a variety of reactor events (`REv`). A component can **demand that the
42//! reactor provides a set of capabilities** by requiring `From`-implementations on the `REv`, e.g.
43//! by restricting the `impl Component<REv>` by `where REv: From<Baz>`. The concrete requirement
44//! will usually be dictated by a restriction on a method on an
45//! [`EffectBuilder`](crate::effect::EffectBuilder).
46
47pub(crate) mod binary_port;
48pub(crate) mod block_accumulator;
49pub(crate) mod block_synchronizer;
50pub(crate) mod block_validator;
51pub mod consensus;
52pub mod contract_runtime;
53pub(crate) mod diagnostics_port;
54pub(crate) mod event_stream_server;
55pub(crate) mod fetcher;
56pub(crate) mod gossiper;
57pub(crate) mod transaction_buffer;
58// The `in_memory_network` is public for use in doctests.
59#[cfg(test)]
60pub mod in_memory_network;
61pub(crate) mod metrics;
62pub(crate) mod network;
63pub(crate) mod rest_server;
64pub(crate) mod shutdown_trigger;
65pub mod storage;
66pub(crate) mod sync_leaper;
67pub(crate) mod transaction_acceptor;
68pub(crate) mod upgrade_watcher;
69
70use datasize::DataSize;
71use serde::Deserialize;
72use std::fmt::{Debug, Display};
73use tracing::info;
74
75use crate::{
76    effect::{EffectBuilder, Effects},
77    failpoints::FailpointActivation,
78    NodeRng,
79};
80
81#[cfg_attr(doc, aquamarine::aquamarine)]
82/// ```mermaid
83/// flowchart TD
84///     style Start fill:#66ccff,stroke:#333,stroke-width:4px
85///     style End fill:#66ccff,stroke:#333,stroke-width:4px
86///
87///     Start --> Uninitialized
88///     Uninitialized --> Initializing
89///     Initializing --> Initialized
90///     Initializing --> Fatal
91///     Initialized --> End
92///     Fatal --> End
93/// ```
94#[derive(Clone, PartialEq, Eq, DataSize, Debug, Deserialize, Default)]
95pub(crate) enum ComponentState {
96    #[default]
97    Uninitialized,
98    Initializing,
99    Initialized,
100    Fatal(String),
101}
102
103/// Core Component.
104///
105/// Every component process a set of events it defines itself
106/// Its inputs are `Event`s, allowing it to perform work whenever an event is received, outputting
107/// `Effect`s each time it is called.
108///
109/// # Error and halting states
110///
111/// Components in general are expected to be able to handle every input (`Event`) in every state.
112/// Invalid inputs are supposed to be discarded, and the machine is expected to recover from any
113/// recoverable error states by itself.
114///
115/// If a fatal error occurs that is not recoverable, the reactor should be notified instead.
116///
117/// # Component events and reactor events
118///
119/// Each component has two events related to it: An associated `Event` and a reactor event (`REv`).
120/// The `Event` type indicates what type of event a component accepts, these are typically event
121/// types specific to the component.
122///
123/// Components place restrictions on reactor events (`REv`s), indicating what kind of effects they
124/// need to be able to produce to operate.
125pub(crate) trait Component<REv> {
126    /// Event associated with `Component`.
127    ///
128    /// The event type that is handled by the component.
129    type Event;
130
131    /// Name of the component.
132    fn name(&self) -> &str;
133
134    /// Activate/deactivate a failpoint.
135    fn activate_failpoint(&mut self, _activation: &FailpointActivation) {
136        // Default is to ignore failpoints.
137    }
138
139    /// Processes an event, outputting zero or more effects.
140    ///
141    /// This function must not ever perform any blocking or CPU intensive work, as it is expected
142    /// to return very quickly -- it will usually be called from an `async` function context.
143    fn handle_event(
144        &mut self,
145        effect_builder: EffectBuilder<REv>,
146        rng: &mut NodeRng,
147        event: Self::Event,
148    ) -> Effects<Self::Event>;
149}
150
151pub(crate) trait InitializedComponent<REv>: Component<REv> {
152    fn state(&self) -> &ComponentState;
153
154    fn is_uninitialized(&self) -> bool {
155        self.state() == &ComponentState::Uninitialized
156    }
157
158    fn is_fatal(&self) -> bool {
159        matches!(self.state(), ComponentState::Fatal(_))
160    }
161
162    fn start_initialization(&mut self) {
163        if self.is_uninitialized() {
164            self.set_state(ComponentState::Initializing);
165        } else {
166            info!(name = self.name(), "component must be uninitialized");
167        }
168    }
169
170    fn set_state(&mut self, new_state: ComponentState);
171}
172
173pub(crate) trait PortBoundComponent<REv>: InitializedComponent<REv> {
174    type Error: Display + Debug;
175    type ComponentEvent;
176
177    fn bind(
178        &mut self,
179        enabled: bool,
180        effect_builder: EffectBuilder<REv>,
181    ) -> (Effects<Self::ComponentEvent>, ComponentState) {
182        if !enabled {
183            return (Effects::new(), ComponentState::Initialized);
184        }
185
186        match self.listen(effect_builder) {
187            Ok(effects) => (effects, ComponentState::Initialized),
188            Err(error) => (Effects::new(), ComponentState::Fatal(format!("{}", error))),
189        }
190    }
191
192    fn listen(
193        &mut self,
194        effect_builder: EffectBuilder<REv>,
195    ) -> Result<Effects<Self::ComponentEvent>, Self::Error>;
196}
197
198pub(crate) trait ValidatorBoundComponent<REv>: Component<REv> {
199    fn handle_validators(
200        &mut self,
201        effect_builder: EffectBuilder<REv>,
202        rng: &mut NodeRng,
203    ) -> Effects<Self::Event>;
204}