1mod context;
18
19use context::{Context, Vote, VoteNode};
20
21#[cfg(feature = "derive-codec")]
22use parity_scale_codec::{Decode, Encode};
23
24use crate::{
25 std::{
26 self,
27 collections::btree_map::{BTreeMap, Entry},
28 fmt,
29 vec::Vec,
30 },
31 vote_graph::VoteGraph,
32 voter_set::{VoterInfo, VoterSet},
33 weights::{VoteWeight, VoterWeight},
34};
35
36use super::{
37 BlockNumberOps, Chain, Equivocation, HistoricalVotes, Message, Precommit, Prevote,
38 SignedMessage,
39};
40
41#[derive(PartialEq, Eq, Copy, Clone, Debug)]
44pub enum Phase {
45 Prevote,
47 Precommit,
49}
50
51enum VoteMultiplicity<Vote, Signature> {
53 Single(Vote, Signature),
55 Equivocated((Vote, Signature), (Vote, Signature)),
58}
59
60impl<Vote: Eq, Signature: Eq> VoteMultiplicity<Vote, Signature> {
61 fn contains(&self, vote: &Vote, signature: &Signature) -> bool {
62 match self {
63 VoteMultiplicity::Single(v, s) => v == vote && s == signature,
64 VoteMultiplicity::Equivocated((v1, s1), (v2, s2)) =>
65 v1 == vote && s1 == signature || v2 == vote && s2 == signature,
66 }
67 }
68}
69
70struct VoteTracker<Id: Ord + Eq, Vote, Signature> {
71 votes: BTreeMap<Id, VoteMultiplicity<Vote, Signature>>,
72 current_weight: VoteWeight,
73}
74
75pub(crate) struct AddVoteResult<'a, Vote, Signature> {
77 multiplicity: Option<&'a VoteMultiplicity<Vote, Signature>>,
78 duplicated: bool,
79}
80
81impl<Id: Ord + Eq + Clone, Vote: Clone + Eq, Signature: Clone + Eq>
82 VoteTracker<Id, Vote, Signature>
83{
84 fn new() -> Self {
85 VoteTracker { votes: BTreeMap::new(), current_weight: VoteWeight(0) }
86 }
87
88 fn add_vote(
99 &mut self,
100 id: Id,
101 vote: Vote,
102 signature: Signature,
103 weight: VoterWeight,
104 ) -> AddVoteResult<Vote, Signature> {
105 match self.votes.entry(id) {
106 Entry::Vacant(vacant) => {
107 self.current_weight = self.current_weight + weight;
108 let multiplicity = vacant.insert(VoteMultiplicity::Single(vote, signature));
109
110 AddVoteResult { multiplicity: Some(multiplicity), duplicated: false }
111 },
112 Entry::Occupied(mut occupied) => {
113 if occupied.get().contains(&vote, &signature) {
114 return AddVoteResult { multiplicity: None, duplicated: true }
115 }
116
117 let new_val = match *occupied.get_mut() {
119 VoteMultiplicity::Single(ref v, ref s) =>
120 VoteMultiplicity::Equivocated((v.clone(), s.clone()), (vote, signature)),
121 VoteMultiplicity::Equivocated(_, _) =>
122 return AddVoteResult { multiplicity: None, duplicated: false },
123 };
124
125 *occupied.get_mut() = new_val;
126
127 AddVoteResult { multiplicity: Some(&*occupied.into_mut()), duplicated: false }
128 },
129 }
130 }
131
132 fn votes(&self) -> Vec<(Id, Vote, Signature)> {
134 let mut votes = Vec::new();
135
136 for (id, vote) in &self.votes {
137 match vote {
138 VoteMultiplicity::Single(v, s) => votes.push((id.clone(), v.clone(), s.clone())),
139 VoteMultiplicity::Equivocated((v1, s1), (v2, s2)) => {
140 votes.push((id.clone(), v1.clone(), s1.clone()));
141 votes.push((id.clone(), v2.clone(), s2.clone()));
142 },
143 }
144 }
145
146 votes
147 }
148
149 fn participation(&self) -> (VoteWeight, usize) {
151 (self.current_weight, self.votes.len())
152 }
153}
154
155#[derive(PartialEq, Clone)]
157#[cfg_attr(any(feature = "std", test), derive(Debug))]
158#[cfg_attr(feature = "derive-codec", derive(Encode, Decode, scale_info::TypeInfo))]
159pub struct State<H, N> {
160 pub prevote_ghost: Option<(H, N)>,
162 pub finalized: Option<(H, N)>,
164 pub estimate: Option<(H, N)>,
166 pub completable: bool,
168}
169
170impl<H: Clone, N: Clone> State<H, N> {
171 pub fn genesis(genesis: (H, N)) -> Self {
173 State {
174 prevote_ghost: Some(genesis.clone()),
175 finalized: Some(genesis.clone()),
176 estimate: Some(genesis),
177 completable: true,
178 }
179 }
180}
181
182pub struct RoundParams<Id: Ord + Eq, H, N> {
184 pub round_number: u64,
186 pub voters: VoterSet<Id>,
188 pub base: (H, N),
190}
191
192pub struct Round<Id: Ord + Eq, H: Ord + Eq, N, Signature> {
194 round_number: u64,
195 context: Context<Id>,
196 graph: VoteGraph<H, N, VoteNode>, prevote: VoteTracker<Id, Prevote<H, N>, Signature>, precommit: VoteTracker<Id, Precommit<H, N>, Signature>, historical_votes: HistoricalVotes<H, N, Signature, Id>,
200 prevote_ghost: Option<(H, N)>, precommit_ghost: Option<(H, N)>, finalized: Option<(H, N)>, estimate: Option<(H, N)>, completable: bool, }
206
207pub(crate) struct ImportResult<Id, P, Signature> {
209 pub(crate) valid_voter: bool,
211 pub(crate) duplicated: bool,
213 pub(crate) equivocation: Option<Equivocation<Id, P, Signature>>,
215}
216
217impl<Id, P, Signature> Default for ImportResult<Id, P, Signature> {
218 fn default() -> Self {
219 ImportResult { valid_voter: false, duplicated: false, equivocation: None }
220 }
221}
222
223impl<Id, H, N, Signature> Round<Id, H, N, Signature>
224where
225 Id: Ord + Clone + Eq + fmt::Debug,
226 H: Ord + Clone + Eq + Ord + fmt::Debug,
227 N: Copy + fmt::Debug + BlockNumberOps,
228 Signature: Eq + Clone,
229{
230 pub fn new(round_params: RoundParams<Id, H, N>) -> Self {
232 let (base_hash, base_number) = round_params.base;
233
234 Round {
235 round_number: round_params.round_number,
236 context: Context::new(round_params.voters),
237 graph: VoteGraph::new(base_hash, base_number, VoteNode::default()),
238 prevote: VoteTracker::new(),
239 precommit: VoteTracker::new(),
240 historical_votes: HistoricalVotes::new(),
241 prevote_ghost: None,
242 precommit_ghost: None,
243 finalized: None,
244 estimate: None,
245 completable: false,
246 }
247 }
248
249 pub fn number(&self) -> u64 {
251 self.round_number
252 }
253
254 #[cfg_attr(not(feature = "std"), allow(unused))]
259 pub(crate) fn import_prevote<C: Chain<H, N>>(
260 &mut self,
261 chain: &C,
262 prevote: Prevote<H, N>,
263 signer: Id,
264 signature: Signature,
265 ) -> Result<ImportResult<Id, Prevote<H, N>, Signature>, crate::Error> {
266 let mut import_result = ImportResult::default();
267
268 let info = match self.context.voters().get(&signer) {
269 Some(info) => info.clone(),
270 None => return Ok(import_result),
271 };
272
273 import_result.valid_voter = true;
274 let weight = info.weight();
275
276 let equivocation = {
277 let multiplicity = match self.prevote.add_vote(
278 signer.clone(),
279 prevote.clone(),
280 signature.clone(),
281 weight,
282 ) {
283 AddVoteResult { multiplicity: Some(m), .. } => m,
284 AddVoteResult { duplicated, .. } => {
285 import_result.duplicated = duplicated;
286 return Ok(import_result)
287 },
288 };
289 let round_number = self.round_number;
290
291 match multiplicity {
292 VoteMultiplicity::Single(single_vote, _) => {
293 let vote = Vote::new(&info, Phase::Prevote);
294
295 self.graph.insert(
296 single_vote.target_hash.clone(),
297 single_vote.target_number,
298 vote,
299 chain,
300 )?;
301
302 let message = Message::Prevote(prevote);
304 let signed_message = SignedMessage { id: signer, signature, message };
305 self.historical_votes.push_vote(signed_message);
306
307 None
308 },
309 VoteMultiplicity::Equivocated(ref first, ref second) => {
310 self.context.equivocated(&info, Phase::Prevote);
312
313 let message = Message::Prevote(prevote);
315 let signed_message = SignedMessage { id: signer.clone(), signature, message };
316 self.historical_votes.push_vote(signed_message);
317
318 Some(Equivocation {
319 round_number,
320 identity: signer,
321 first: first.clone(),
322 second: second.clone(),
323 })
324 },
325 }
326 };
327
328 let threshold = self.threshold();
330 if self.prevote.current_weight >= threshold {
331 self.prevote_ghost = self.graph.find_ghost(self.prevote_ghost.take(), |v| {
332 self.context.weight(v, Phase::Prevote) >= threshold
333 });
334 }
335
336 self.update();
337 import_result.equivocation = equivocation;
338 Ok(import_result)
339 }
340
341 pub(crate) fn import_precommit<C: Chain<H, N>>(
346 &mut self,
347 chain: &C,
348 precommit: Precommit<H, N>,
349 signer: Id,
350 signature: Signature,
351 ) -> Result<ImportResult<Id, Precommit<H, N>, Signature>, crate::Error> {
352 let mut import_result = ImportResult::default();
353
354 let info = match self.context.voters().get(&signer) {
355 Some(info) => info.clone(),
356 None => return Ok(import_result),
357 };
358 import_result.valid_voter = true;
359 let weight = info.weight();
360
361 let equivocation = {
362 let multiplicity = match self.precommit.add_vote(
363 signer.clone(),
364 precommit.clone(),
365 signature.clone(),
366 weight,
367 ) {
368 AddVoteResult { multiplicity: Some(m), .. } => m,
369 AddVoteResult { duplicated, .. } => {
370 import_result.duplicated = duplicated;
371 return Ok(import_result)
372 },
373 };
374
375 let round_number = self.round_number;
376
377 match multiplicity {
378 VoteMultiplicity::Single(single_vote, _) => {
379 let vote = Vote::new(&info, Phase::Precommit);
380
381 self.graph.insert(
382 single_vote.target_hash.clone(),
383 single_vote.target_number,
384 vote,
385 chain,
386 )?;
387
388 let message = Message::Precommit(precommit);
389 let signed_message = SignedMessage { id: signer, signature, message };
390 self.historical_votes.push_vote(signed_message);
391
392 None
393 },
394 VoteMultiplicity::Equivocated(ref first, ref second) => {
395 self.context.equivocated(&info, Phase::Precommit);
397
398 let message = Message::Precommit(precommit);
400 let signed_message = SignedMessage { id: signer.clone(), signature, message };
401 self.historical_votes.push_vote(signed_message);
402
403 Some(Equivocation {
404 round_number,
405 identity: signer,
406 first: first.clone(),
407 second: second.clone(),
408 })
409 },
410 }
411 };
412
413 self.update();
414 import_result.equivocation = equivocation;
415 Ok(import_result)
416 }
417
418 pub fn state(&self) -> State<H, N> {
420 State {
421 prevote_ghost: self.prevote_ghost.clone(),
422 finalized: self.finalized.clone(),
423 estimate: self.estimate.clone(),
424 completable: self.completable,
425 }
426 }
427
428 pub fn precommit_ghost(&mut self) -> Option<(H, N)> {
430 let threshold = self.threshold();
432 if self.precommit.current_weight >= threshold {
433 self.precommit_ghost = self.graph.find_ghost(self.precommit_ghost.take(), |v| {
434 self.context.weight(v, Phase::Precommit) >= threshold
435 });
436 }
437
438 self.precommit_ghost.clone()
439 }
440
441 pub fn finalizing_precommits<'a, C: 'a + Chain<H, N>>(
445 &'a mut self,
446 chain: &'a C,
447 ) -> Option<impl Iterator<Item = crate::SignedPrecommit<H, N, Signature, Id>> + 'a> {
448 struct YieldVotes<'b, V: 'b, S: 'b> {
449 yielded: usize,
450 multiplicity: &'b VoteMultiplicity<V, S>,
451 }
452
453 impl<'b, V: 'b + Clone, S: 'b + Clone> Iterator for YieldVotes<'b, V, S> {
454 type Item = (V, S);
455
456 fn next(&mut self) -> Option<(V, S)> {
457 match self.multiplicity {
458 VoteMultiplicity::Single(ref v, ref s) =>
459 if self.yielded == 0 {
460 self.yielded += 1;
461 Some((v.clone(), s.clone()))
462 } else {
463 None
464 },
465 VoteMultiplicity::Equivocated(ref a, ref b) => {
466 let res = match self.yielded {
467 0 => Some(a.clone()),
468 1 => Some(b.clone()),
469 _ => None,
470 };
471
472 self.yielded += 1;
473 res
474 },
475 }
476 }
477 }
478
479 let (f_hash, _f_num) = self.finalized.clone()?;
480 let find_valid_precommits = self
481 .precommit
482 .votes
483 .iter()
484 .filter(move |&(_id, multiplicity)| {
485 if let VoteMultiplicity::Single(ref v, _) = *multiplicity {
486 chain.is_equal_or_descendent_of(f_hash.clone(), v.target_hash.clone())
489 } else {
490 true
492 }
493 })
494 .flat_map(|(id, multiplicity)| {
495 let yield_votes = YieldVotes { yielded: 0, multiplicity };
496
497 yield_votes.map(move |(v, s)| crate::SignedPrecommit {
498 precommit: v,
499 signature: s,
500 id: id.clone(),
501 })
502 });
503
504 Some(find_valid_precommits)
505 }
506
507 fn update(&mut self) {
509 let threshold = self.threshold();
510
511 if self.prevote.current_weight < threshold {
512 return
513 }
514
515 let (g_hash, g_num) = match self.prevote_ghost.clone() {
516 None => return,
517 Some(x) => x,
518 };
519
520 let ctx = &self.context;
521
522 let current_precommits = self.precommit.current_weight;
525 if current_precommits >= self.threshold() {
526 self.finalized = self.graph.find_ancestor(g_hash.clone(), g_num, |v| {
527 ctx.weight(v, Phase::Precommit) >= threshold
528 });
529 };
530
531 let possible_to_precommit = {
536 let tolerated_equivocations = ctx.voters().total_weight() - threshold;
542 let current_equivocations = ctx.equivocation_weight(Phase::Precommit);
543 let additional_equiv = tolerated_equivocations - current_equivocations;
544 let remaining_commit_votes =
545 ctx.voters().total_weight() - self.precommit.current_weight;
546
547 move |node: &VoteNode| {
548 let precommitted_for = ctx.weight(node, Phase::Precommit);
550
551 let possible_equivocations =
554 std::cmp::min(current_precommits - precommitted_for, additional_equiv);
555
556 let full_possible_weight =
560 precommitted_for + remaining_commit_votes + possible_equivocations;
561
562 full_possible_weight >= threshold
563 }
564 };
565
566 if self.precommit.current_weight >= threshold {
577 self.estimate = self.graph.find_ancestor(g_hash.clone(), g_num, possible_to_precommit);
578 } else {
579 self.estimate = Some((g_hash, g_num));
580 return
581 }
582
583 self.completable = self.estimate.clone().map_or(false, |(b_hash, b_num)| {
584 b_hash != g_hash || {
585 self.graph
589 .find_ghost(Some((b_hash, b_num)), possible_to_precommit)
590 .map_or(true, |x| x == (g_hash, g_num))
591 }
592 })
593 }
594
595 pub fn estimate(&self) -> Option<&(H, N)> {
601 self.estimate.as_ref()
602 }
603
604 pub fn finalized(&self) -> Option<&(H, N)> {
606 self.finalized.as_ref()
607 }
608
609 pub fn completable(&self) -> bool {
615 self.completable
616 }
617
618 pub fn threshold(&self) -> VoterWeight {
620 self.context.voters().threshold()
621 }
622
623 pub fn base(&self) -> (H, N) {
625 self.graph.base()
626 }
627
628 pub fn voters(&self) -> &VoterSet<Id> {
630 self.context.voters()
631 }
632
633 pub fn primary_voter(&self) -> (&Id, &VoterInfo) {
635 self.context.voters().nth_mod(self.round_number as usize)
636 }
637
638 pub fn prevote_participation(&self) -> (VoteWeight, usize) {
640 self.prevote.participation()
641 }
642
643 pub fn precommit_participation(&self) -> (VoteWeight, usize) {
645 self.precommit.participation()
646 }
647
648 pub fn prevotes(&self) -> Vec<(Id, Prevote<H, N>, Signature)> {
650 self.prevote.votes()
651 }
652
653 pub fn precommits(&self) -> Vec<(Id, Precommit<H, N>, Signature)> {
655 self.precommit.votes()
656 }
657
658 pub fn historical_votes(&self) -> &HistoricalVotes<H, N, Signature, Id> {
663 &self.historical_votes
664 }
665
666 pub fn set_prevoted_index(&mut self) {
669 self.historical_votes.set_prevoted_idx()
670 }
671
672 pub fn set_precommitted_index(&mut self) {
675 self.historical_votes.set_precommitted_idx()
676 }
677
678 pub fn prevoted_index(&self) -> Option<u64> {
681 self.historical_votes.prevote_idx
682 }
683
684 pub fn precommitted_index(&self) -> Option<u64> {
687 self.historical_votes.precommit_idx
688 }
689}
690
691#[cfg(test)]
692mod tests {
693 use super::*;
694 use crate::testing::chain::{DummyChain, GENESIS_HASH};
695
696 fn voters() -> VoterSet<&'static str> {
697 VoterSet::new([("Alice", 4), ("Bob", 7), ("Eve", 3)].iter().cloned()).expect("nonempty")
698 }
699
700 #[derive(PartialEq, Eq, Clone, Debug)]
701 struct Signature(&'static str);
702
703 #[test]
704 fn estimate_is_valid() {
705 let mut chain = DummyChain::new();
706 chain.push_blocks(GENESIS_HASH, &["A", "B", "C", "D", "E", "F"]);
707 chain.push_blocks("E", &["EA", "EB", "EC", "ED"]);
708 chain.push_blocks("F", &["FA", "FB", "FC"]);
709
710 let mut round =
711 Round::new(RoundParams { round_number: 1, voters: voters(), base: ("C", 4) });
712
713 round
714 .import_prevote(&chain, Prevote::new("FC", 10), "Alice", Signature("Alice"))
715 .unwrap();
716
717 round
718 .import_prevote(&chain, Prevote::new("ED", 10), "Bob", Signature("Bob"))
719 .unwrap();
720
721 assert_eq!(round.prevote_ghost, Some(("E", 6)));
722 assert_eq!(round.estimate(), Some(&("E", 6)));
723 assert!(!round.completable());
724
725 round
726 .import_prevote(&chain, Prevote::new("F", 7), "Eve", Signature("Eve"))
727 .unwrap();
728
729 assert_eq!(round.prevote_ghost, Some(("E", 6)));
730 assert_eq!(round.estimate(), Some(&("E", 6)));
731 }
732
733 #[test]
734 fn finalization() {
735 let mut chain = DummyChain::new();
736 chain.push_blocks(GENESIS_HASH, &["A", "B", "C", "D", "E", "F"]);
737 chain.push_blocks("E", &["EA", "EB", "EC", "ED"]);
738 chain.push_blocks("F", &["FA", "FB", "FC"]);
739
740 let mut round =
741 Round::new(RoundParams { round_number: 1, voters: voters(), base: ("C", 4) });
742
743 round
744 .import_precommit(&chain, Precommit::new("FC", 10), "Alice", Signature("Alice"))
745 .unwrap();
746
747 round
748 .import_precommit(&chain, Precommit::new("ED", 10), "Bob", Signature("Bob"))
749 .unwrap();
750
751 assert_eq!(round.finalized, None);
752
753 {
755 round
756 .import_prevote(&chain, Prevote::new("FC", 10), "Alice", Signature("Alice"))
757 .unwrap();
758
759 round
760 .import_prevote(&chain, Prevote::new("ED", 10), "Bob", Signature("Bob"))
761 .unwrap();
762
763 round
764 .import_prevote(&chain, Prevote::new("EA", 7), "Eve", Signature("Eve"))
765 .unwrap();
766
767 assert_eq!(round.finalized, Some(("E", 6)));
768 }
769
770 round
771 .import_precommit(&chain, Precommit::new("EA", 7), "Eve", Signature("Eve"))
772 .unwrap();
773
774 assert_eq!(round.finalized, Some(("EA", 7)));
775 }
776
777 #[test]
778 fn equivocate_does_not_double_count() {
779 let mut chain = DummyChain::new();
780 chain.push_blocks(GENESIS_HASH, &["A", "B", "C", "D", "E", "F"]);
781 chain.push_blocks("E", &["EA", "EB", "EC", "ED"]);
782 chain.push_blocks("F", &["FA", "FB", "FC"]);
783
784 let mut round =
785 Round::new(RoundParams { round_number: 1, voters: voters(), base: ("C", 4) });
786
787 assert!(round
789 .import_prevote(
790 &chain,
791 Prevote::new("FC", 10),
792 "Eve", Signature("Eve-1"),
794 )
795 .unwrap()
796 .equivocation
797 .is_none());
798
799 assert!(round.prevote_ghost.is_none());
800
801 assert!(round
803 .import_prevote(
804 &chain,
805 Prevote::new("ED", 10),
806 "Eve", Signature("Eve-2"),
808 )
809 .unwrap()
810 .equivocation
811 .is_some());
812
813 assert!(round
815 .import_prevote(
816 &chain,
817 Prevote::new("F", 7),
818 "Eve", Signature("Eve-2"),
820 )
821 .unwrap()
822 .equivocation
823 .is_none());
824
825 assert!(round.prevote_ghost.is_none());
828
829 assert!(round
830 .import_prevote(
831 &chain,
832 Prevote::new("FA", 8),
833 "Bob", Signature("Bob-1"),
835 )
836 .unwrap()
837 .equivocation
838 .is_none());
839
840 assert_eq!(round.prevote_ghost, Some(("FA", 8)));
841 }
842
843 #[test]
844 fn historical_votes_works() {
845 let mut chain = DummyChain::new();
846 chain.push_blocks(GENESIS_HASH, &["A", "B", "C", "D", "E", "F"]);
847 chain.push_blocks("E", &["EA", "EB", "EC", "ED"]);
848 chain.push_blocks("F", &["FA", "FB", "FC"]);
849
850 let mut round =
851 Round::new(RoundParams { round_number: 1, voters: voters(), base: ("C", 4) });
852
853 round
854 .import_prevote(&chain, Prevote::new("FC", 10), "Alice", Signature("Alice"))
855 .unwrap();
856
857 round.set_prevoted_index();
858
859 round
860 .import_prevote(&chain, Prevote::new("EA", 7), "Eve", Signature("Eve"))
861 .unwrap();
862
863 round
864 .import_precommit(&chain, Precommit::new("EA", 7), "Eve", Signature("Eve"))
865 .unwrap();
866
867 round
868 .import_prevote(&chain, Prevote::new("EC", 10), "Alice", Signature("Alice"))
869 .unwrap();
870
871 round.set_precommitted_index();
872
873 assert_eq!(
874 round.historical_votes(),
875 &HistoricalVotes::new_with(
876 vec![
877 SignedMessage {
878 message: Message::Prevote(Prevote { target_hash: "FC", target_number: 10 }),
879 signature: Signature("Alice"),
880 id: "Alice"
881 },
882 SignedMessage {
883 message: Message::Prevote(Prevote { target_hash: "EA", target_number: 7 }),
884 signature: Signature("Eve"),
885 id: "Eve"
886 },
887 SignedMessage {
888 message: Message::Precommit(Precommit {
889 target_hash: "EA",
890 target_number: 7
891 }),
892 signature: Signature("Eve"),
893 id: "Eve"
894 },
895 SignedMessage {
896 message: Message::Prevote(Prevote { target_hash: "EC", target_number: 10 }),
897 signature: Signature("Alice"),
898 id: "Alice"
899 },
900 ],
901 Some(1),
902 Some(4),
903 )
904 );
905 }
906}