1use core::fmt::Debug;
2
3use std::{
4 sync::Arc,
5 time::{SystemTime, Instant, Duration},
6 collections::VecDeque,
7};
8
9use log::debug;
10
11use parity_scale_codec::{Encode, Decode};
12
13use futures::{
14 FutureExt, StreamExt,
15 future::{self, Fuse},
16 channel::mpsc,
17};
18use tokio::time::sleep;
19
20mod time;
21use time::{sys_time, CanonicalInstant};
22
23mod round;
24
25mod block;
26use block::BlockData;
27
28pub(crate) mod message_log;
29
30pub mod ext;
32use ext::*;
33
34pub(crate) fn commit_msg(end_time: u64, id: &[u8]) -> Vec<u8> {
35 [&end_time.to_le_bytes(), id].concat().to_vec()
36}
37
38#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode)]
39enum Step {
40 Propose,
41 Prevote,
42 Precommit,
43}
44
45#[derive(Clone, Debug, Encode, Decode)]
46enum Data<B: Block, S: Signature> {
47 Proposal(Option<RoundNumber>, B),
48 Prevote(Option<B::Id>),
49 Precommit(Option<(B::Id, S)>),
50}
51
52impl<B: Block, S: Signature> PartialEq for Data<B, S> {
53 fn eq(&self, other: &Data<B, S>) -> bool {
54 match (self, other) {
55 (Data::Proposal(valid_round, block), Data::Proposal(valid_round2, block2)) => {
56 (valid_round == valid_round2) && (block == block2)
57 }
58 (Data::Prevote(id), Data::Prevote(id2)) => id == id2,
59 (Data::Precommit(None), Data::Precommit(None)) => true,
60 (Data::Precommit(Some((id, _))), Data::Precommit(Some((id2, _)))) => id == id2,
61 _ => false,
62 }
63 }
64}
65
66impl<B: Block, S: Signature> Data<B, S> {
67 fn step(&self) -> Step {
68 match self {
69 Data::Proposal(..) => Step::Propose,
70 Data::Prevote(..) => Step::Prevote,
71 Data::Precommit(..) => Step::Precommit,
72 }
73 }
74}
75
76#[derive(Clone, PartialEq, Debug, Encode, Decode)]
77struct Message<V: ValidatorId, B: Block, S: Signature> {
78 sender: V,
79
80 block: BlockNumber,
81 round: RoundNumber,
82
83 data: Data<B, S>,
84}
85
86#[derive(Clone, PartialEq, Debug, Encode, Decode)]
88pub struct SignedMessage<V: ValidatorId, B: Block, S: Signature> {
89 msg: Message<V, B, S>,
90 sig: S,
91}
92
93impl<V: ValidatorId, B: Block, S: Signature> SignedMessage<V, B, S> {
94 pub fn block(&self) -> BlockNumber {
96 self.msg.block
97 }
98
99 #[must_use]
100 pub fn verify_signature<Scheme: SignatureScheme<ValidatorId = V, Signature = S>>(
101 &self,
102 signer: &Scheme,
103 ) -> bool {
104 signer.verify(self.msg.sender, &self.msg.encode(), &self.sig)
105 }
106}
107
108#[derive(Clone, Copy, PartialEq, Eq, Debug)]
109enum TendermintError<V: ValidatorId> {
110 Malicious(V),
111 Temporal,
112}
113
114pub(crate) type DataFor<N> =
116 Data<<N as Network>::Block, <<N as Network>::SignatureScheme as SignatureScheme>::Signature>;
117pub(crate) type MessageFor<N> = Message<
118 <N as Network>::ValidatorId,
119 <N as Network>::Block,
120 <<N as Network>::SignatureScheme as SignatureScheme>::Signature,
121>;
122pub type SignedMessageFor<N> = SignedMessage<
124 <N as Network>::ValidatorId,
125 <N as Network>::Block,
126 <<N as Network>::SignatureScheme as SignatureScheme>::Signature,
127>;
128
129pub struct TendermintMachine<N: Network> {
131 network: N,
132 signer: <N::SignatureScheme as SignatureScheme>::Signer,
133 validators: N::SignatureScheme,
134 weights: Arc<N::Weights>,
135
136 queue: VecDeque<MessageFor<N>>,
137 msg_recv: mpsc::UnboundedReceiver<SignedMessageFor<N>>,
138 step_recv: mpsc::UnboundedReceiver<(BlockNumber, Commit<N::SignatureScheme>, N::Block)>,
139
140 block: BlockData<N>,
141}
142
143pub type StepSender<N> = mpsc::UnboundedSender<(
144 BlockNumber,
145 Commit<<N as Network>::SignatureScheme>,
146 <N as Network>::Block,
147)>;
148
149pub type MessageSender<N> = mpsc::UnboundedSender<SignedMessageFor<N>>;
150
151pub struct TendermintHandle<N: Network> {
153 pub step: StepSender<N>,
156 pub messages: MessageSender<N>,
158 pub machine: TendermintMachine<N>,
160}
161
162impl<N: Network + 'static> TendermintMachine<N> {
163 fn broadcast(&mut self, data: DataFor<N>) {
168 if let Some(msg) = self.block.message(data) {
169 self.queue.push_back(msg);
173 }
174 }
175
176 fn round(&mut self, round: RoundNumber, time: Option<CanonicalInstant>) -> bool {
178 if let Some(data) =
179 self.block.new_round(round, self.weights.proposer(self.block.number, round), time)
180 {
181 self.broadcast(data);
182 true
183 } else {
184 false
185 }
186 }
187
188 async fn reset(&mut self, end_round: RoundNumber, proposal: N::Block) {
190 self.block.populate_end_time(end_round);
192
193 let round_end = self.block.end_time[&end_round];
195 sleep(round_end.instant().saturating_duration_since(Instant::now())).await;
196
197 self.queue = VecDeque::new();
199
200 self.block = BlockData::new(
202 self.weights.clone(),
203 BlockNumber(self.block.number.0 + 1),
204 self.signer.validator_id().await,
205 proposal,
206 );
207
208 self.round(RoundNumber(0), Some(round_end));
210 }
211
212 async fn reset_by_commit(&mut self, commit: Commit<N::SignatureScheme>, proposal: N::Block) {
213 let mut round = self.block.round().number;
214 while self.block.end_time[&round].canonical() < commit.end_time {
216 round.0 += 1;
217 self.block.populate_end_time(round);
218 }
219 while self.block.end_time[&round].canonical() > commit.end_time {
221 if round.0 == 0 {
222 panic!("commit isn't for this machine's next block");
223 }
224 round.0 -= 1;
225 }
226 debug_assert_eq!(self.block.end_time[&round].canonical(), commit.end_time);
227
228 self.reset(round, proposal).await;
229 }
230
231 async fn slash(&mut self, validator: N::ValidatorId) {
232 if !self.block.slashes.contains(&validator) {
233 debug!(target: "tendermint", "Slashing validator {:?}", validator);
234 self.block.slashes.insert(validator);
235 self.network.slash(validator).await;
236 }
237 }
238
239 #[allow(clippy::new_ret_no_self)]
243 pub async fn new(
244 network: N,
245 last_block: BlockNumber,
246 last_time: u64,
247 proposal: N::Block,
248 ) -> TendermintHandle<N> {
249 let (msg_send, msg_recv) = mpsc::unbounded();
250 let (step_send, step_recv) = mpsc::unbounded();
251 TendermintHandle {
252 step: step_send,
253 messages: msg_send,
254 machine: {
255 let sys_time = sys_time(last_time);
256 sleep(sys_time.duration_since(SystemTime::now()).unwrap_or(Duration::ZERO)).await;
258
259 let signer = network.signer();
260 let validators = network.signature_scheme();
261 let weights = Arc::new(network.weights());
262 let validator_id = signer.validator_id().await;
263 let mut machine = TendermintMachine {
265 network,
266 signer,
267 validators,
268 weights: weights.clone(),
269
270 queue: VecDeque::new(),
271 msg_recv,
272 step_recv,
273
274 block: BlockData::new(weights, BlockNumber(last_block.0 + 1), validator_id, proposal),
275 };
276
277 machine.round(RoundNumber(0), Some(CanonicalInstant::new(last_time)));
285 machine
286 },
287 }
288 }
289
290 pub async fn run(mut self) {
291 loop {
292 let mut queue_future =
297 if self.queue.is_empty() { Fuse::terminated() } else { future::ready(()).fuse() };
298
299 if let Some((broadcast, msg)) = futures::select_biased! {
300 msg = self.step_recv.next() => {
303 if let Some((block_number, commit, proposal)) = msg {
304 if block_number != self.block.number {
306 continue;
307 }
308 self.reset_by_commit(commit, proposal).await;
309 None
310 } else {
311 break;
312 }
313 },
314
315 _ = queue_future => {
317 Some((true, self.queue.pop_front().unwrap()))
318 },
319
320 step = self.block.round().timeout_future().fuse() => {
322 self.block.round_mut().timeouts.remove(&step);
326 if self.block.round().step == step {
328 match step {
329 Step::Propose => {
330 debug!(target: "tendermint", "Validator didn't propose when they should have");
332 self.slash(
333 self.weights.proposer(self.block.number, self.block.round().number)
334 ).await;
335 self.broadcast(Data::Prevote(None));
336 },
337 Step::Prevote => self.broadcast(Data::Precommit(None)),
338 Step::Precommit => {
339 self.round(RoundNumber(self.block.round().number.0 + 1), None);
340 continue;
341 }
342 }
343 }
344 None
345 },
346
347 msg = self.msg_recv.next() => {
349 if let Some(msg) = msg {
350 if !msg.verify_signature(&self.validators) {
351 continue;
352 }
353 Some((false, msg.msg))
354 } else {
355 break;
356 }
357 }
358 } {
359 let res = self.message(msg.clone()).await;
360 if res.is_err() && broadcast {
361 panic!("honest node had invalid behavior");
362 }
363
364 match res {
365 Ok(None) => (),
366 Ok(Some(block)) => {
367 let mut validators = vec![];
368 let mut sigs = vec![];
369 for (validator, msgs) in &self.block.log.log[&msg.round] {
371 if let Some(Data::Precommit(Some((id, sig)))) = msgs.get(&Step::Precommit) {
372 if id == &block.id() {
374 validators.push(*validator);
375 sigs.push(sig.clone());
376 }
377 }
378 }
379
380 let commit = Commit {
381 end_time: self.block.end_time[&msg.round].canonical(),
382 validators,
383 signature: N::SignatureScheme::aggregate(&sigs),
384 };
385 debug_assert!(self.network.verify_commit(block.id(), &commit));
386
387 let proposal = self.network.add_block(block, commit).await;
388 self.reset(msg.round, proposal).await;
389 }
390 Err(TendermintError::Malicious(validator)) => self.slash(validator).await,
391 Err(TendermintError::Temporal) => (),
392 }
393
394 if broadcast {
395 let sig = self.signer.sign(&msg.encode()).await;
396 self.network.broadcast(SignedMessage { msg, sig }).await;
397 }
398 }
399 }
400 }
401
402 fn verify_precommit_signature(
406 &self,
407 sender: N::ValidatorId,
408 round: RoundNumber,
409 data: &DataFor<N>,
410 ) -> Result<bool, TendermintError<N::ValidatorId>> {
411 if let Data::Precommit(Some((id, sig))) = data {
412 if let Some(end_time) = self.block.end_time.get(&round) {
417 if !self.validators.verify(sender, &commit_msg(end_time.canonical(), id.as_ref()), sig) {
418 debug!(target: "tendermint", "Validator produced an invalid commit signature");
419 Err(TendermintError::Malicious(sender))?;
420 }
421 return Ok(true);
422 }
423 }
424 Ok(false)
425 }
426
427 async fn message(
428 &mut self,
429 msg: MessageFor<N>,
430 ) -> Result<Option<N::Block>, TendermintError<N::ValidatorId>> {
431 if msg.block != self.block.number {
432 Err(TendermintError::Temporal)?;
433 }
434
435 self.verify_precommit_signature(msg.sender, msg.round, &msg.data)?;
437
438 if matches!(msg.data, Data::Proposal(..)) &&
440 (msg.sender != self.weights.proposer(msg.block, msg.round))
441 {
442 debug!(target: "tendermint", "Validator who wasn't the proposer proposed");
443 Err(TendermintError::Malicious(msg.sender))?;
444 };
445
446 if !self.block.log.log(msg.clone())? {
447 return Ok(None);
448 }
449
450 if matches!(msg.data, Data::Proposal(..)) || matches!(msg.data, Data::Precommit(_)) {
455 let proposer = self.weights.proposer(self.block.number, msg.round);
456
457 if let Some(Data::Proposal(_, block)) = self.block.log.get(msg.round, proposer, Step::Propose)
459 {
460 if self.block.log.has_consensus(
463 msg.round,
464 Data::Precommit(Some((block.id(), self.signer.sign(&[]).await))),
465 ) {
466 return Ok(Some(block.clone()));
467 }
468 }
469 }
470
471 #[allow(clippy::comparison_chain)]
473 if msg.round.0 < self.block.round().number.0 {
474 return Ok(None);
476 } else if msg.round.0 > self.block.round().number.0 {
477 if self.block.log.round_participation(msg.round) > self.weights.fault_thresold() {
480 let round_msgs = self.block.log.log[&msg.round].clone();
482 for (validator, msgs) in &round_msgs {
483 if let Some(data) = msgs.get(&Step::Precommit) {
484 if let Ok(res) = self.verify_precommit_signature(*validator, msg.round, data) {
485 debug_assert!(res);
487 } else {
488 self
493 .block
494 .log
495 .log
496 .get_mut(&msg.round)
497 .unwrap()
498 .get_mut(validator)
499 .unwrap()
500 .remove(&Step::Precommit);
501 self.slash(*validator).await;
502 }
503 }
504 }
505 if self.round(msg.round, None) {
508 return Ok(None);
509 }
510 } else {
511 return Ok(None);
513 }
514 }
515
516 if (self.block.round().step == Step::Prevote) && matches!(msg.data, Data::Prevote(_)) {
520 let (participation, weight) =
521 self.block.log.message_instances(self.block.round().number, Data::Prevote(None));
522 if participation >= self.weights.threshold() {
524 self.block.round_mut().set_timeout(Step::Prevote);
525 }
526
527 if weight >= self.weights.threshold() {
529 self.broadcast(Data::Precommit(None));
530 return Ok(None);
531 }
532 }
533
534 if matches!(msg.data, Data::Precommit(_)) &&
536 self.block.log.has_participation(self.block.round().number, Step::Precommit)
537 {
538 self.block.round_mut().set_timeout(Step::Precommit);
539 }
540
541 let proposer = self.weights.proposer(self.block.number, self.block.round().number);
543 let (vr, block) = if let Some(Data::Proposal(vr, block)) =
544 self.block.log.get(self.block.round().number, proposer, Step::Propose)
545 {
546 (vr, block)
547 } else {
548 return Ok(None);
549 };
550
551 if self.block.round().step == Step::Propose {
553 let (valid, err) = match self.network.validate(block).await {
555 Ok(_) => (true, Ok(None)),
556 Err(BlockError::Temporal) => (false, Ok(None)),
557 Err(BlockError::Fatal) => (false, {
558 debug!(target: "tendermint", "Validator proposed a fatally invalid block");
559 Err(TendermintError::Malicious(proposer))
560 }),
561 };
562 let raw_vote = Some(block.id()).filter(|_| valid);
564
565 let locked = self.block.locked.as_ref().map(|(_, id)| id == &block.id()).unwrap_or(true);
570 let mut vote = raw_vote.filter(|_| locked);
571
572 if let Some(vr) = vr {
573 if vr.0 >= self.block.round().number.0 {
575 debug!(target: "tendermint", "Validator claimed a round from the future was valid");
576 Err(TendermintError::Malicious(msg.sender))?;
577 }
578
579 if self.block.log.has_consensus(*vr, Data::Prevote(Some(block.id()))) {
580 if let Some((locked_round, _)) = self.block.locked.as_ref() {
583 vote = vote.or_else(|| raw_vote.filter(|_| locked_round.0 <= vr.0));
584 }
585
586 self.broadcast(Data::Prevote(vote));
587 return err;
588 }
589 } else {
590 self.broadcast(Data::Prevote(vote));
591 return err;
592 }
593
594 return Ok(None);
595 }
596
597 if self
598 .block
599 .valid
600 .as_ref()
601 .map(|(round, _)| round != &self.block.round().number)
602 .unwrap_or(true)
603 {
604 if self.block.log.has_consensus(self.block.round().number, Data::Prevote(Some(block.id()))) {
610 match self.network.validate(block).await {
611 Ok(_) => (),
612 Err(BlockError::Temporal) => (),
613 Err(BlockError::Fatal) => {
614 debug!(target: "tendermint", "Validator proposed a fatally invalid block");
615 Err(TendermintError::Malicious(proposer))?
616 }
617 };
618
619 self.block.valid = Some((self.block.round().number, block.clone()));
620 if self.block.round().step == Step::Prevote {
621 self.block.locked = Some((self.block.round().number, block.id()));
622 self.broadcast(Data::Precommit(Some((
623 block.id(),
624 self
625 .signer
626 .sign(&commit_msg(
627 self.block.end_time[&self.block.round().number].canonical(),
628 block.id().as_ref(),
629 ))
630 .await,
631 ))));
632 }
633 }
634 }
635
636 Ok(None)
637 }
638}