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}