Skip to main content

arc_malachitebft_engine/
host.rs

1use bytes::Bytes;
2use std::ops::RangeInclusive;
3use std::time::Duration;
4
5use derive_where::derive_where;
6use ractor::{ActorRef, RpcReplyPort};
7
8use malachitebft_core_consensus::{MisbehaviorEvidence, Role, VoteExtensionError};
9use malachitebft_core_types::{CommitCertificate, Context, Round, ValueId, VoteExtensions};
10use malachitebft_sync::{PeerId, RawDecidedValue};
11
12use crate::util::streaming::StreamMessage;
13
14pub use malachitebft_core_consensus::{LocallyProposedValue, ProposedValue};
15pub use malachitebft_core_types::HeightParams;
16
17/// A reference to the host actor.
18pub type HostRef<Ctx> = ActorRef<HostMsg<Ctx>>;
19
20/// What to do next after a decision.
21#[derive_where(Debug)]
22pub enum Next<Ctx: Context> {
23    /// Start at the given height with the provided parameters.
24    Start(Ctx::Height, HeightParams<Ctx>),
25
26    /// Restart at the given height with the provided parameters.
27    Restart(Ctx::Height, HeightParams<Ctx>),
28}
29
30/// Messages that need to be handled by the host actor.
31#[derive_where(Debug)]
32pub enum HostMsg<Ctx: Context> {
33    /// Notifies the application that consensus is ready.
34    ///
35    /// The application MUST reply with a message to instruct
36    /// consensus to start at a given height.
37    ConsensusReady {
38        /// Use this reply port to instruct consensus to start the first height.
39        reply_to: RpcReplyPort<(Ctx::Height, HeightParams<Ctx>)>,
40    },
41
42    /// Consensus has started a new round.
43    StartedRound {
44        /// The height at which the round started.
45        height: Ctx::Height,
46        /// The round number that started.
47        round: Round,
48        /// The address of the proposer for this round.
49        proposer: Ctx::Address,
50        /// The role of the node in this round.
51        role: Role,
52        /// Use this reply port to send the undecided values that were already seen for this
53        /// round. This is needed when recovering from a crash.
54        ///
55        /// The application MUST reply immediately with the values it has, or with an empty vector.
56        reply_to: RpcReplyPort<Vec<ProposedValue<Ctx>>>,
57    },
58
59    /// Request to build a local value to propose
60    ///
61    /// The application MUST reply to this message with the requested value
62    /// within the specified timeout duration.
63    GetValue {
64        /// The height at which the value should be proposed.
65        height: Ctx::Height,
66        /// The round in which the value should be proposed.
67        round: Round,
68        /// The amount of time the application has to build the value.
69        timeout: Duration,
70        /// Use this reply port to send the value that was built.
71        reply_to: RpcReplyPort<LocallyProposedValue<Ctx>>,
72    },
73
74    /// ExtendVote allows the application to extend the pre-commit vote with arbitrary data.
75    ///
76    /// When consensus is preparing to send a pre-commit vote, it first calls `ExtendVote`.
77    /// The application then returns a blob of data called a vote extension.
78    /// This data is opaque to the consensus algorithm but can contain application-specific information.
79    /// The proposer of the next block will receive all vote extensions along with the commit certificate.
80    ExtendVote {
81        /// The height at which the vote is being extended.
82        height: Ctx::Height,
83        /// The round in which the vote is being extended.
84        round: Round,
85        /// The ID of the value that is being voted on.
86        value_id: ValueId<Ctx>,
87        /// The vote extension to be added to the vote, if any.
88        reply_to: RpcReplyPort<Option<Ctx::Extension>>,
89    },
90
91    /// Verify a vote extension
92    ///
93    /// If the vote extension is deemed invalid, the vote it was part of
94    /// will be discarded altogether.
95    VerifyVoteExtension {
96        /// The height for which the vote is.
97        height: Ctx::Height,
98        /// The round for which the vote is.
99        round: Round,
100        /// The ID of the value that the vote extension is for.
101        value_id: ValueId<Ctx>,
102        /// The vote extension to verify.
103        extension: Ctx::Extension,
104        /// Use this reply port to send the result of the verification.
105        reply_to: RpcReplyPort<Result<(), VoteExtensionError>>,
106    },
107
108    /// Requests the application to re-stream a proposal that it has already seen.
109    ///
110    /// The application MUST re-publish again all the proposal parts pertaining
111    /// to that value by sending [`NetworkMsg::PublishProposalPart`] messages through
112    /// the [`Channels::network`] channel.
113    RestreamValue {
114        /// The height at which the value was proposed.
115        height: Ctx::Height,
116        /// The round in which the value was proposed.
117        round: Round,
118        /// The round in which the value was valid.
119        valid_round: Round,
120        /// The address of the proposer of the value.
121        address: Ctx::Address,
122        /// The ID of the value to restream.
123        value_id: ValueId<Ctx>,
124    },
125
126    /// Requests the earliest height available in the history maintained by the application.
127    ///
128    /// The application MUST respond with its earliest available height.
129    GetHistoryMinHeight { reply_to: RpcReplyPort<Ctx::Height> },
130
131    /// Notifies the application that consensus has received a proposal part over the network.
132    ///
133    /// If this part completes the full proposal, the application MUST respond
134    /// with the complete proposed value. Otherwise, it MUST respond with `None`.
135    ReceivedProposalPart {
136        from: PeerId,
137        part: StreamMessage<Ctx::ProposalPart>,
138        reply_to: RpcReplyPort<ProposedValue<Ctx>>,
139    },
140
141    /// Notifies the application that consensus has decided on a value.
142    ///
143    /// This message includes a commit certificate containing the ID of
144    /// the value that was decided on, the height and round at which it was decided,
145    /// and the aggregated signatures of the validators that committed to it.
146    /// It also includes to the vote extensions received for that height.
147    Decided {
148        /// The commit certificate containing the ID of the value that was decided on,
149        /// the the height and round at which it was decided, and the aggregated signatures
150        /// of the validators that committed to it.
151        certificate: CommitCertificate<Ctx>,
152
153        /// Vote extensions that were received for this height.
154        extensions: VoteExtensions<Ctx>,
155    },
156
157    /// Notifies the application that consensus has finalized a height after collecting additional precommits.
158    ///
159    /// This message is sent when the target time for the height has been reached,
160    /// which may include a delay between `Decided` and `Finalized` messages.
161    /// During this delay, additional precommits may have been collected. The certificate may contain more
162    /// signatures than the one sent in the initial Decided message.
163    ///
164    /// In response to this message, the application MUST send a [`Next`]
165    /// message back to consensus, instructing it to either start the next height if
166    /// the application was able to commit the decided value, or to restart the current height
167    /// otherwise.
168    ///
169    /// If the application does not reply, consensus will stall.
170    Finalized {
171        /// The commit certificate with extended signatures collected during finalization period.
172        certificate: CommitCertificate<Ctx>,
173
174        /// Vote extensions that were received for this height (including additional ones).
175        extensions: VoteExtensions<Ctx>,
176
177        /// Misbehavior evidence collected since last height was decided.
178        evidence: MisbehaviorEvidence<Ctx>,
179
180        /// Use this reply port to instruct consensus to start the next height.
181        reply_to: RpcReplyPort<Next<Ctx>>,
182    },
183
184    /// Requests a range of previously decided values from the application's storage.
185    ///
186    /// The application MUST respond with those values if available, or `None` otherwise.
187    ///
188    /// ## Important
189    /// The range is NOT checked for validity by consensus. It is the application's responsibility
190    /// to ensure that the the range is within valid bounds.
191    GetDecidedValues {
192        /// Range of decided values to retrieve
193        range: RangeInclusive<Ctx::Height>,
194        /// Channel for sending back the decided value
195        reply_to: RpcReplyPort<Vec<RawDecidedValue<Ctx>>>,
196    },
197
198    /// Notifies the application that a value has been synced from the network.
199    /// This may happen when the node is catching up with the network.
200    ///
201    /// If a value can be decoded from the bytes provided, then the application MUST reply
202    /// to this message with the decoded value. Otherwise, it MUST reply with `None`.
203    ProcessSyncedValue {
204        /// Height of the synced value
205        height: Ctx::Height,
206        /// Round of the synced value
207        round: Round,
208        /// Address of the original proposer
209        proposer: Ctx::Address,
210        /// Raw encoded value data
211        value_bytes: Bytes,
212        /// Channel for sending back the proposed value, if successfully decoded
213        /// or `None` if the value could not be decoded
214        reply_to: RpcReplyPort<ProposedValue<Ctx>>,
215    },
216}