commonware_consensus/marshal/mod.rs
1//! Ordered delivery of finalized blocks.
2//!
3//! # Architecture
4//!
5//! The core of the module is the unified [`core::Actor`]. It marshals finalized blocks into order by:
6//!
7//! - Receiving uncertified blocks from a broadcast mechanism
8//! - Receiving notarizations and finalizations from consensus
9//! - Reconstructing a total order of finalized blocks
10//! - Providing a backfill mechanism for missing blocks
11//!
12//! The actor interacts with several components:
13//! - [`crate::Reporter`]: Receives ordered, finalized blocks at-least-once
14//! - [`crate::simplex`]: Provides consensus messages
15//! - Application: Provides verified blocks
16//! - [`commonware_broadcast::buffered`]: Provides uncertified blocks (standard mode)
17//! - [`coding::shards::Engine`]: Provides erasure-coded shards (coding mode)
18//! - [`resolver`]: Provides a backfill mechanism for missing blocks
19//!
20//! # Design
21//!
22//! ## Delivery
23//!
24//! The actor will deliver a block to the reporter at-least-once. The reporter should be prepared to
25//! handle duplicate deliveries. However the blocks will be in order.
26//!
27//! ## Finalization
28//!
29//! The actor uses a view-based model to track the state of the chain. Each view corresponds
30//! to a potential block in the chain. The actor will only finalize a block (and its ancestors)
31//! if it has a corresponding finalization from consensus.
32//!
33//! _It is possible that there may exist multiple finalizations for the same block in different views. Marshal
34//! only concerns itself with verifying a valid finalization exists for a block, not that a specific finalization
35//! exists. This means different Marshals may have different finalizations for the same block persisted to disk._
36//!
37//! ## Backfill
38//!
39//! The actor provides a backfill mechanism for missing blocks. If the actor notices a gap in its
40//! knowledge of finalized blocks, it will request the missing blocks from its peers. This ensures
41//! that the actor can catch up to the rest of the network if it falls behind.
42//!
43//! ## Storage
44//!
45//! The actor uses a combination of internal and external ([`store::Certificates`], [`store::Blocks`]) storage
46//! to store blocks and finalizations. Internal storage (in-memory caches) is used for data that is only
47//! needed for a short period of time, such as unverified blocks or notarizations. External storage
48//! (archive backends) is used to persist finalized blocks and certificates indefinitely.
49//!
50//! Marshal will store all blocks after a configurable starting height (or, floor) onward.
51//! This allows for state sync from a specific height rather than from genesis. When
52//! updating the starting height, marshal will attempt to prune blocks in external storage
53//! that are no longer needed, if the backing [`store::Blocks`] supports pruning.
54//!
55//! _Setting a configurable starting height will prevent others from backfilling blocks below said height. This
56//! feature is only recommended for applications that support state sync (i.e., those that don't require full
57//! block history to participate in consensus)._
58//!
59//! ## Limitations and Future Work
60//!
61//! - Only works with [crate::simplex] rather than general consensus.
62//! - Assumes at-most one notarization per view, incompatible with some consensus protocols.
63//! - Uses [`broadcast::buffered`](`commonware_broadcast::buffered`) for broadcasting and receiving
64//! uncertified blocks from the network.
65
66use crate::{
67 types::{Height, Round},
68 Block,
69};
70use commonware_cryptography::Digest;
71use commonware_storage::archive;
72use commonware_utils::{acknowledgement::Exact, Acknowledgement};
73
74mod config;
75pub use config::Config;
76
77pub mod ancestry;
78pub mod core;
79pub mod resolver;
80pub mod standard;
81pub mod store;
82
83commonware_macros::stability_scope!(ALPHA {
84 pub(crate) mod application;
85 pub mod coding;
86});
87
88#[cfg(test)]
89pub mod mocks;
90
91/// An identifier for a block request.
92pub enum Identifier<D: Digest> {
93 /// The height of the block to retrieve.
94 Height(Height),
95 /// The digest of the block to retrieve.
96 Digest(D),
97 /// The highest finalized block. It may be the case that marshal does not have some of the
98 /// blocks below this height.
99 Latest,
100}
101
102// Allows using u64 directly for convenience.
103impl<D: Digest> From<Height> for Identifier<D> {
104 fn from(src: Height) -> Self {
105 Self::Height(src)
106 }
107}
108
109// Allows using &Digest directly for convenience.
110impl<D: Digest> From<&D> for Identifier<D> {
111 fn from(src: &D) -> Self {
112 Self::Digest(*src)
113 }
114}
115
116// Allows using archive identifiers directly for convenience.
117impl<D: Digest> From<archive::Identifier<'_, D>> for Identifier<D> {
118 fn from(src: archive::Identifier<'_, D>) -> Self {
119 match src {
120 archive::Identifier::Index(index) => Self::Height(Height::new(index)),
121 archive::Identifier::Key(key) => Self::Digest(*key),
122 }
123 }
124}
125
126/// An update reported to the application, either a new finalized tip or a finalized block.
127///
128/// Finalized tips are reported as soon as known, whether or not we hold all blocks up to that height.
129/// Finalized blocks are reported to the application in monotonically increasing order (no gaps permitted).
130#[derive(Clone, Debug)]
131pub enum Update<B: Block, A: Acknowledgement = Exact> {
132 /// A new finalized tip and the finalization round.
133 Tip(Round, Height, B::Digest),
134 /// A new finalized block and an [Acknowledgement] for the application to signal once processed.
135 ///
136 /// To ensure all blocks are delivered at least once, marshal waits to mark a block as delivered
137 /// until the application explicitly acknowledges the update. If the [Acknowledgement] is dropped before
138 /// handling, marshal will exit (assuming the application is shutting down).
139 ///
140 /// Because the [Acknowledgement] is clonable, the application can pass [Update] to multiple consumers
141 /// (and marshal will only consider the block delivered once all consumers have acknowledged it).
142 Block(B, A),
143}