1mod blame_verifier;
6pub mod confirmation_meter;
7pub mod consensus_executor;
8pub mod consensus_new_block_handler;
9use cfxcore_errors::ProviderBlockError;
10use cfxcore_pow as pow;
11
12use pow::{PowComputer, ProofOfWorkConfig};
13
14use crate::{
15 block_data_manager::{
16 BlockDataManager, BlockExecutionResultWithEpoch, DataVersionTuple,
17 EpochExecutionContext,
18 },
19 consensus::{
20 anticone_cache::AnticoneCache,
21 consensus_inner::consensus_executor::ConsensusExecutor,
22 debug_recompute::log_invalid_state_root, pastset_cache::PastSetCache,
23 pos_handler::PosVerifier,
24 },
25 pos::pow_handler::POS_TERM_EPOCHS,
26 state_exposer::{ConsensusGraphBlockExecutionState, STATE_EXPOSER},
27 verification::VerificationConfig,
28};
29use cfx_internal_common::{
30 consensus_api::StateMaintenanceTrait, EpochExecutionCommitment,
31};
32use cfx_parameters::{consensus::*, consensus_internal::*};
33use cfx_types::{H256, U256, U512};
34use dag::{
35 get_future, topological_sort, Graph, RichDAG, RichTreeGraph, TreeGraph, DAG,
36};
37use hashbrown::HashMap as FastHashMap;
38use hibitset::{BitSet, BitSetLike, DrainableBitSet};
39use link_cut_tree::{CaterpillarMinLinkCutTree, SizeMinLinkCutTree};
40use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
41use malloc_size_of_derive::MallocSizeOf as DeriveMallocSizeOf;
42use metrics::{Counter, CounterUsize};
43use primitives::{
44 pos::PosBlockId, Block, BlockHeader, BlockHeaderBuilder, EpochId,
45};
46use slab::Slab;
47use std::{
48 cmp::{max, min},
49 collections::{BinaryHeap, HashMap, HashSet, VecDeque},
50 convert::TryFrom,
51 mem,
52 sync::Arc,
53};
54lazy_static! {
55 static ref INVALID_BLAME_OR_STATE_ROOT_COUNTER: Arc<dyn Counter<usize>> =
56 CounterUsize::register_with_group(
57 "system_metrics",
58 "invalid_blame_or_state_root_count"
59 );
60}
61
62#[derive(Clone)]
63pub struct ConsensusInnerConfig {
64 pub adaptive_weight_beta: u64,
66 pub heavy_block_difficulty_ratio: u64,
68 pub timer_chain_block_difficulty_ratio: u64,
70 pub timer_chain_beta: u64,
72 pub era_epoch_count: u64,
76 pub enable_optimistic_execution: bool,
81 pub enable_state_expose: bool,
83 pub pos_pivot_decision_defer_epoch_count: u64,
85
86 pub cip113_pivot_decision_defer_epoch_count: u64,
87 pub cip113_transition_height: u64,
88
89 pub debug_dump_dir_invalid_state_root: Option<String>,
92 pub debug_invalid_state_root_epoch: Option<H256>,
93 pub force_recompute_height_during_construct_pivot: Option<u64>,
94 pub recovery_latest_mpt_snapshot: bool,
95 pub use_isolated_db_for_mpt_table: bool,
96}
97
98impl ConsensusInnerConfig {
99 pub fn pos_pivot_decision_defer_epoch_count(
100 &self, confirmed_height: u64,
101 ) -> u64 {
102 if confirmed_height >= self.cip113_transition_height {
103 self.cip113_pivot_decision_defer_epoch_count
104 } else {
105 self.pos_pivot_decision_defer_epoch_count
106 }
107 }
108}
109
110#[derive(Copy, Clone, DeriveMallocSizeOf)]
111pub struct StateBlameInfo {
112 pub blame: u32,
113 pub state_vec_root: H256,
114 pub receipts_vec_root: H256,
115 pub logs_bloom_vec_root: H256,
116}
117
118#[derive(DeriveMallocSizeOf)]
124pub struct ConsensusGraphNodeData {
125 pub epoch_number: u64,
128 partial_invalid: bool,
132 pending: bool,
136 inactive_dependency_cnt: usize,
142 activated: bool,
147 force_confirm: usize,
149 blockset_in_own_view_of_epoch: Vec<usize>,
153 ordered_executable_epoch_blocks: Vec<usize>,
159 skipped_epoch_blocks: Vec<H256>,
166 blockset_cleared: bool,
169 sequence_number: u64,
174 past_view_timer_longest_difficulty: i128,
176 past_view_last_timer_block_arena_index: usize,
178 ledger_view_timer_chain_height: u64,
182 vote_valid_lca_height: u64,
185 vote_valid: bool,
188 last_pivot_in_past: u64,
191 pub state_valid: Option<bool>,
195 blame_info: Option<StateBlameInfo>,
198}
199
200impl ConsensusGraphNodeData {
201 fn new(
202 epoch_number: u64, sequence_number: u64, inactive_dependency_cnt: usize,
203 ) -> Self {
204 ConsensusGraphNodeData {
205 epoch_number,
206 partial_invalid: false,
207 pending: false,
208 inactive_dependency_cnt,
209 activated: false,
210 force_confirm: NULL,
211 blockset_in_own_view_of_epoch: Default::default(),
212 ordered_executable_epoch_blocks: Default::default(),
213 skipped_epoch_blocks: Default::default(),
214 blockset_cleared: true,
215 sequence_number,
216 past_view_timer_longest_difficulty: 0,
217 past_view_last_timer_block_arena_index: NULL,
218 ledger_view_timer_chain_height: 0,
219 vote_valid_lca_height: NULLU64,
220 vote_valid: true,
221 last_pivot_in_past: 0,
222 state_valid: None,
223 blame_info: None,
224 }
225 }
226}
227
228#[derive(DeriveMallocSizeOf)]
229struct ConsensusGraphPivotData {
230 last_pivot_in_past_blocks: HashSet<usize>,
233 past_weight: i128,
236}
237
238impl Default for ConsensusGraphPivotData {
239 fn default() -> Self {
240 ConsensusGraphPivotData {
241 last_pivot_in_past_blocks: HashSet::new(),
242 past_weight: 0,
243 }
244 }
245}
246
247pub struct ConsensusGraphInner {
453 pub data_man: Arc<BlockDataManager>,
455 pub pos_verifier: Arc<PosVerifier>,
456 pub inner_conf: ConsensusInnerConfig,
457 pub pow_config: ProofOfWorkConfig,
458 pub pow: Arc<PowComputer>,
459 pub arena: Slab<ConsensusGraphNode>,
463 pub hash_to_arena_indices: FastHashMap<H256, usize>,
465 pivot_chain: Vec<usize>,
467 pivot_chain_metadata: Vec<ConsensusGraphPivotData>,
469 timer_chain: Vec<usize>,
471 timer_chain_accumulative_lca: Vec<usize>,
473 terminal_hashes: HashSet<H256>,
476 cur_era_genesis_block_arena_index: usize,
480 cur_era_genesis_height: u64,
482 cur_era_stable_height: u64,
485 cur_era_stable_block_hash: H256,
489 initial_stable_future: Option<BitSet>,
493 cur_era_genesis_timer_chain_height: u64,
495 best_timer_chain_difficulty: i128,
497 best_timer_chain_hash: H256,
498
499 best_pos_pivot_decision: (H256, u64),
504
505 weight_tree: SizeMinLinkCutTree,
507 adaptive_tree: CaterpillarMinLinkCutTree,
510 invalid_block_queue: BinaryHeap<(i128, usize)>,
513 pub current_difficulty: U256,
515 anticone_cache: AnticoneCache,
518 pastset_cache: PastSetCache,
519 sequence_number_of_block_entrance: u64,
520
521 best_terminals_lca_height_cache: FastHashMap<usize, u64>,
526 best_terminals_reorg_height: u64,
529 has_timer_block_in_anticone_cache: HashSet<usize>,
532
533 header_only: bool,
536}
537
538impl MallocSizeOf for ConsensusGraphInner {
539 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
540 self.arena.size_of(ops)
541 + self.hash_to_arena_indices.size_of(ops)
542 + self.pivot_chain.size_of(ops)
543 + self.pivot_chain_metadata.size_of(ops)
544 + self.timer_chain.size_of(ops)
545 + self.timer_chain_accumulative_lca.size_of(ops)
546 + self.terminal_hashes.size_of(ops)
547 + self.initial_stable_future.size_of(ops)
548 + self.weight_tree.size_of(ops)
549 + self.adaptive_tree.size_of(ops)
550 + self.invalid_block_queue.size_of(ops)
551 + self.pow_config.size_of(ops)
552 + self.data_man.size_of(ops)
553 + self.anticone_cache.size_of(ops)
554 + self.pastset_cache.size_of(ops)
555 + self.best_terminals_lca_height_cache.size_of(ops)
556 + self.best_terminals_reorg_height.size_of(ops)
557 }
558}
559
560#[derive(DeriveMallocSizeOf)]
561pub struct ConsensusGraphNode {
562 pub hash: H256,
563 pub height: u64,
564 pub parent: usize,
565 difficulty: U256,
566 is_heavy: bool,
567 is_timer: bool,
568 past_num_blocks: u64,
570 adaptive: bool,
571
572 era_block: usize,
576 children: Vec<usize>,
577 referrers: Vec<usize>,
578 referees: Vec<usize>,
579 pub data: ConsensusGraphNodeData,
584}
585
586impl ConsensusGraphNode {
587 pub fn past_num_blocks(&self) -> u64 { self.past_num_blocks }
588
589 pub fn adaptive(&self) -> bool { self.adaptive }
590
591 pub fn pending(&self) -> bool { self.data.pending }
592
593 pub fn partial_invalid(&self) -> bool { self.data.partial_invalid }
594
595 pub fn era_block(&self) -> usize { self.era_block }
596}
597
598impl ConsensusGraphInner {
599 pub fn with_era_genesis(
600 pow_config: ProofOfWorkConfig, pow: Arc<PowComputer>,
601 pos_verifier: Arc<PosVerifier>, data_man: Arc<BlockDataManager>,
602 inner_conf: ConsensusInnerConfig, cur_era_genesis_block_hash: &H256,
603 cur_era_stable_block_hash: &H256,
604 ) -> Self {
605 let genesis_block_header = data_man
606 .block_header_by_hash(cur_era_genesis_block_hash)
607 .expect("genesis block header should exist here");
608 let cur_era_genesis_height = genesis_block_header.height();
609 let stable_block_header = data_man
610 .block_header_by_hash(cur_era_stable_block_hash)
611 .expect("stable genesis block header should exist here");
612 let cur_era_stable_height = stable_block_header.height();
613 let initial_difficulty = pow_config.initial_difficulty;
614 let mut inner = ConsensusGraphInner {
615 arena: Slab::new(),
616 hash_to_arena_indices: FastHashMap::new(),
617 pivot_chain: Vec::new(),
618 pivot_chain_metadata: Vec::new(),
619 timer_chain: Vec::new(),
620 timer_chain_accumulative_lca: Vec::new(),
621 terminal_hashes: Default::default(),
622 cur_era_genesis_block_arena_index: NULL,
623 cur_era_genesis_height,
624 cur_era_stable_height,
625 cur_era_stable_block_hash: cur_era_stable_block_hash.clone(),
628 initial_stable_future: Some(BitSet::new()),
629 cur_era_genesis_timer_chain_height: 0,
630 best_timer_chain_difficulty: 0,
631 best_timer_chain_hash: Default::default(),
632 best_pos_pivot_decision: (
633 *cur_era_genesis_block_hash,
634 cur_era_genesis_height,
635 ),
636 weight_tree: SizeMinLinkCutTree::new(),
637 adaptive_tree: CaterpillarMinLinkCutTree::new(),
638 invalid_block_queue: BinaryHeap::new(),
639 pow_config,
640 pow,
641 current_difficulty: initial_difficulty.into(),
642 data_man: data_man.clone(),
643 pos_verifier,
644 inner_conf,
645 anticone_cache: AnticoneCache::new(),
646 pastset_cache: Default::default(),
647 sequence_number_of_block_entrance: 0,
648 best_terminals_lca_height_cache: Default::default(),
649 best_terminals_reorg_height: NULLU64,
650 has_timer_block_in_anticone_cache: Default::default(),
651 header_only: true,
652 };
653
654 let (genesis_arena_index, _) = inner.insert(&genesis_block_header);
659 if cur_era_genesis_block_hash == cur_era_stable_block_hash {
660 inner
661 .initial_stable_future
662 .as_mut()
663 .unwrap()
664 .add(genesis_arena_index as u32);
665 }
666 inner.arena[genesis_arena_index].data.blockset_cleared = false;
667 if genesis_block_header.height() == 0 {
668 inner.arena[genesis_arena_index].data.state_valid = Some(true);
669 }
670 inner.cur_era_genesis_block_arena_index = genesis_arena_index;
671 inner.arena[genesis_arena_index].data.activated = true;
672 let genesis_block_weight = genesis_block_header.difficulty().low_u128();
673 inner
674 .weight_tree
675 .make_tree(inner.cur_era_genesis_block_arena_index);
676 inner.weight_tree.path_apply(
677 inner.cur_era_genesis_block_arena_index,
678 genesis_block_weight as i128,
679 );
680 inner
681 .adaptive_tree
682 .make_tree(inner.cur_era_genesis_block_arena_index);
683 inner
686 .adaptive_tree
687 .set(inner.cur_era_genesis_block_arena_index, 0);
688 inner.arena[inner.cur_era_genesis_block_arena_index]
689 .data
690 .epoch_number = cur_era_genesis_height;
691 let genesis_epoch_size = inner
692 .data_man
693 .executed_epoch_set_hashes_from_db(cur_era_genesis_height)
694 .expect("Genesis epoch set should be in data manager.")
695 .len();
696 inner.arena[inner.cur_era_genesis_block_arena_index].past_num_blocks =
697 inner
698 .data_man
699 .get_epoch_execution_context(cur_era_genesis_block_hash)
700 .expect("ExecutionContext for cur_era_genesis exists")
701 .start_block_number
702 + genesis_epoch_size as u64
703 - 1;
704 inner.arena[inner.cur_era_genesis_block_arena_index]
705 .data
706 .last_pivot_in_past = cur_era_genesis_height;
707 inner
708 .pivot_chain
709 .push(inner.cur_era_genesis_block_arena_index);
710 let mut last_pivot_in_past_blocks = HashSet::new();
711 last_pivot_in_past_blocks
712 .insert(inner.cur_era_genesis_block_arena_index);
713 inner.pivot_chain_metadata.push(ConsensusGraphPivotData {
714 last_pivot_in_past_blocks,
715 past_weight: genesis_block_weight as i128,
716 });
717 if inner.arena[inner.cur_era_genesis_block_arena_index].is_timer {
718 inner
719 .timer_chain
720 .push(inner.cur_era_genesis_block_arena_index);
721 }
722 inner.arena[inner.cur_era_genesis_block_arena_index]
723 .data
724 .ledger_view_timer_chain_height = 0;
725 inner.best_timer_chain_difficulty =
726 inner.get_timer_difficulty(inner.cur_era_genesis_block_arena_index);
727
728 inner
729 .anticone_cache
730 .update(inner.cur_era_genesis_block_arena_index, &BitSet::new());
731
732 inner
733 }
734
735 fn persist_epoch_set_hashes(&mut self, pivot_index: usize) {
736 let height = self.pivot_index_to_height(pivot_index);
737 let arena_index = self.pivot_chain[pivot_index];
738 let epoch_set_hashes = self
739 .get_ordered_executable_epoch_blocks(arena_index)
740 .iter()
741 .map(|arena_index| self.arena[*arena_index].hash)
742 .collect();
743 let skipped_set_hashes = self
744 .get_or_compute_skipped_epoch_blocks(arena_index)
745 .clone();
746 self.data_man
747 .insert_executed_epoch_set_hashes_to_db(height, &epoch_set_hashes);
748 self.data_man
749 .insert_skipped_epoch_set_hashes_to_db(height, &skipped_set_hashes);
750 }
751
752 #[inline]
753 pub fn current_era_genesis_seq_num(&self) -> u64 {
754 self.arena[self.cur_era_genesis_block_arena_index]
755 .data
756 .sequence_number
757 }
758
759 #[inline]
760 pub fn get_pivot_block_arena_index(&self, height: u64) -> usize {
763 let pivot_index = (height - self.cur_era_genesis_height) as usize;
764 assert!(pivot_index < self.pivot_chain.len());
765 self.pivot_chain[pivot_index]
766 }
767
768 #[inline]
769 pub fn get_pivot_height(&self) -> u64 {
770 self.cur_era_genesis_height + self.pivot_chain.len() as u64
771 }
772
773 #[inline]
774 pub fn height_to_pivot_index(&self, height: u64) -> usize {
775 (height - self.cur_era_genesis_height) as usize
776 }
777
778 #[inline]
779 pub fn pivot_index_to_height(&self, pivot_index: usize) -> u64 {
780 self.cur_era_genesis_height + pivot_index as u64
781 }
782
783 #[inline]
784 fn get_next_sequence_number(&mut self) -> u64 {
785 let sn = self.sequence_number_of_block_entrance;
786 self.sequence_number_of_block_entrance += 1;
787 sn
788 }
789
790 #[inline]
791 pub fn set_initial_sequence_number(&mut self, initial_sn: u64) {
792 self.arena[self.cur_era_genesis_block_arena_index]
793 .data
794 .sequence_number = initial_sn;
795 self.sequence_number_of_block_entrance = initial_sn + 1;
796 }
797
798 #[inline]
799 fn is_heavier(a: (i128, &H256), b: (i128, &H256)) -> bool {
800 (a.0 > b.0) || ((a.0 == b.0) && (*a.1 > *b.1))
801 }
802
803 #[inline]
804 fn ancestor_at(&self, me: usize, height: u64) -> usize {
805 let height_index = self.height_to_pivot_index(height);
806 self.weight_tree.ancestor_at(me, height_index)
807 }
808
809 #[inline]
810 fn lca(&self, me: usize, v: usize) -> usize {
812 if self.arena[v].era_block == NULL || self.arena[me].era_block == NULL {
813 return NULL;
814 }
815 self.weight_tree.lca(me, v)
816 }
817
818 #[inline]
819 fn get_era_genesis_height(&self, parent_height: u64) -> u64 {
820 parent_height / self.inner_conf.era_epoch_count
821 * self.inner_conf.era_epoch_count
822 }
823
824 #[inline]
825 pub fn get_cur_era_genesis_height(&self) -> u64 {
826 self.cur_era_genesis_height
827 }
828
829 #[inline]
830 fn get_era_genesis_block_with_parent(&self, parent: usize) -> usize {
831 if parent == NULL {
832 return 0;
833 }
834 let height = self.arena[parent].height;
835 let era_genesis_height = self.get_era_genesis_height(height);
836 trace!(
837 "height={} era_height={} era_genesis_height={}",
838 height,
839 era_genesis_height,
840 self.cur_era_genesis_height
841 );
842 self.ancestor_at(parent, era_genesis_height)
843 }
844
845 #[inline]
846 pub fn get_epoch_block_hashes(
847 &self, epoch_arena_index: usize,
848 ) -> Vec<H256> {
849 self.get_ordered_executable_epoch_blocks(epoch_arena_index)
850 .iter()
851 .map(|idx| self.arena[*idx].hash)
852 .collect()
853 }
854
855 #[inline]
856 fn get_epoch_start_block_number(&self, epoch_arena_index: usize) -> u64 {
857 let parent = self.arena[epoch_arena_index].parent;
858
859 return self.arena[parent].past_num_blocks + 1;
860 }
861
862 #[inline]
863 fn is_legacy_block(&self, index: usize) -> bool {
864 self.arena[index].era_block == NULL
865 }
866
867 fn compute_blockset_in_own_view_of_epoch_impl(
882 &mut self, lca: usize, pivot: usize,
883 ) {
884 let pastset = self.pastset_cache.get(lca).unwrap();
885 let mut path_to_lca = Vec::new();
886 let mut cur = pivot;
887 while cur != lca {
888 path_to_lca.push(cur);
889 cur = self.arena[cur].parent;
890 }
891 path_to_lca.reverse();
892 let mut visited = BitSet::new();
893 for ancestor_arena_index in path_to_lca {
894 visited.add(ancestor_arena_index as u32);
895 if ancestor_arena_index == pivot
896 || self.arena[ancestor_arena_index].data.blockset_cleared
897 {
898 let mut queue = VecDeque::new();
899 for referee in &self.arena[ancestor_arena_index].referees {
900 if !pastset.contains(*referee as u32)
901 && !visited.contains(*referee as u32)
902 {
903 visited.add(*referee as u32);
904 queue.push_back(*referee);
905 }
906 }
907 while let Some(index) = queue.pop_front() {
908 if ancestor_arena_index == pivot {
909 self.arena[pivot]
910 .data
911 .blockset_in_own_view_of_epoch
912 .push(index);
913 }
914 let parent = self.arena[index].parent;
915 if parent != NULL
916 && !pastset.contains(parent as u32)
917 && !visited.contains(parent as u32)
918 {
919 visited.add(parent as u32);
920 queue.push_back(parent);
921 }
922 for referee in &self.arena[index].referees {
923 if !pastset.contains(*referee as u32)
924 && !visited.contains(*referee as u32)
925 {
926 visited.add(*referee as u32);
927 queue.push_back(*referee);
928 }
929 }
930 }
931 } else {
932 for index in &self.arena[ancestor_arena_index]
933 .data
934 .blockset_in_own_view_of_epoch
935 {
936 visited.add(*index as u32);
937 }
938 }
939 }
940 }
941
942 fn compute_blockset_in_own_view_of_epoch(&mut self, pivot: usize) {
952 if !self.arena[pivot].data.blockset_cleared {
953 return;
954 }
955 let parent = self.arena[pivot].parent;
957 if parent != NULL {
958 let last = *self.pivot_chain.last().unwrap();
959 let lca = self.lca(last, parent);
960 assert!(lca != NULL);
961 if self.pastset_cache.get_and_update_cache(lca).is_none() {
962 let pastset = self.compute_pastset_brutal(lca);
963 self.pastset_cache.update(lca, pastset);
964 }
965 self.compute_blockset_in_own_view_of_epoch_impl(lca, pivot);
966 }
967
968 let mut filtered_blockset = HashSet::new();
969 let mut different_era_blocks = Vec::new();
970 for idx in &self.arena[pivot].data.blockset_in_own_view_of_epoch {
971 if self.is_same_era(*idx, pivot) {
972 filtered_blockset.insert(*idx);
973 } else {
974 different_era_blocks.push(*idx);
975 }
976 }
977
978 let mut ordered_executable_epoch_blocks = self
979 .topological_sort_with_order_indicator(filtered_blockset, |i| {
980 self.arena[i].hash
981 });
982 ordered_executable_epoch_blocks.push(pivot);
983 let skipped_epoch_block_indices = if ordered_executable_epoch_blocks
984 .len()
985 > EPOCH_EXECUTED_BLOCK_BOUND
986 {
987 let cut_off = ordered_executable_epoch_blocks.len()
988 - EPOCH_EXECUTED_BLOCK_BOUND;
989 let mut skipped_epoch_block_indices =
990 ordered_executable_epoch_blocks;
991 ordered_executable_epoch_blocks =
992 skipped_epoch_block_indices.split_off(cut_off);
993 skipped_epoch_block_indices.append(&mut different_era_blocks);
994 skipped_epoch_block_indices
995 } else {
996 different_era_blocks
997 };
998
999 self.arena[pivot].data.skipped_epoch_blocks =
1000 skipped_epoch_block_indices
1001 .into_iter()
1002 .map(|i| self.arena[i].hash)
1003 .collect();
1004 self.arena[pivot].data.ordered_executable_epoch_blocks =
1005 ordered_executable_epoch_blocks;
1006 self.arena[pivot].data.blockset_cleared = false;
1007 }
1008
1009 #[inline]
1010 fn exchange_or_compute_blockset_in_own_view_of_epoch(
1011 &mut self, index: usize, blockset_opt: Option<Vec<usize>>,
1012 ) -> Vec<usize> {
1013 if let Some(blockset) = blockset_opt {
1014 mem::replace(
1015 &mut self.arena[index].data.blockset_in_own_view_of_epoch,
1016 blockset,
1017 )
1018 } else {
1019 if self.arena[index].data.blockset_cleared {
1020 self.compute_blockset_in_own_view_of_epoch(index);
1021 }
1022 mem::replace(
1023 &mut self.arena[index].data.blockset_in_own_view_of_epoch,
1024 Default::default(),
1025 )
1026 }
1027 }
1028
1029 #[inline]
1030 pub fn get_ordered_executable_epoch_blocks(
1031 &self, index: usize,
1032 ) -> &Vec<usize> {
1033 &self.arena[index].data.ordered_executable_epoch_blocks
1034 }
1035
1036 #[inline]
1037 pub fn get_or_compute_skipped_epoch_blocks(
1038 &mut self, index: usize,
1039 ) -> &Vec<H256> {
1040 if self.arena[index].data.blockset_cleared {
1041 self.compute_blockset_in_own_view_of_epoch(index);
1042 }
1043 &self.arena[index].data.skipped_epoch_blocks
1044 }
1045
1046 #[inline]
1047 pub fn get_skipped_epoch_blocks(&self, index: usize) -> Option<&Vec<H256>> {
1048 if self.arena[index].data.blockset_cleared {
1049 None
1050 } else {
1051 Some(&self.arena[index].data.skipped_epoch_blocks)
1052 }
1053 }
1054
1055 fn get_blame(&self, arena_index: usize) -> u32 {
1056 let block_header = self
1057 .data_man
1058 .block_header_by_hash(&self.arena[arena_index].hash)
1059 .unwrap();
1060 block_header.blame()
1061 }
1062
1063 fn get_blame_with_pivot_index(&self, pivot_index: usize) -> u32 {
1064 let arena_index = self.pivot_chain[pivot_index];
1065 self.get_blame(arena_index)
1066 }
1067
1068 fn prev_trusted_pivot_index(
1073 trusted_index: usize, blame: u32, from: usize,
1074 ) -> Option<usize> {
1075 match trusted_index
1076 .checked_sub(blame as usize)
1077 .and_then(|v| v.checked_sub(1))
1078 {
1079 Some(prev) if prev >= from => Some(prev),
1080 _ => None,
1081 }
1082 }
1083
1084 fn blame_covered_start_height(height: u64, blame: u32) -> Option<u64> {
1089 height.checked_sub(blame as u64 + 1)
1090 }
1091
1092 pub fn find_first_index_with_correct_state_of(
1093 &self, pivot_index: usize, blame_bound: Option<u32>,
1094 min_vote_count: usize,
1095 ) -> Option<usize> {
1096 let from = pivot_index + DEFERRED_STATE_EPOCH_COUNT as usize;
1099
1100 self.find_first_trusted_starting_from(from, blame_bound, min_vote_count)
1101 }
1102
1103 pub fn find_first_trusted_starting_from(
1104 &self, from: usize, blame_bound: Option<u32>, min_vote_count: usize,
1105 ) -> Option<usize> {
1106 let mut trusted_index = match self
1107 .find_first_with_trusted_blame_starting_from(
1108 from,
1109 blame_bound,
1110 min_vote_count,
1111 ) {
1112 None => return None,
1113 Some(index) => index,
1114 };
1115
1116 while trusted_index != from {
1119 let blame = self.get_blame_with_pivot_index(trusted_index);
1120 match Self::prev_trusted_pivot_index(trusted_index, blame, from) {
1121 Some(prev_trusted) => trusted_index = prev_trusted,
1122 None => break,
1123 }
1124 }
1125
1126 Some(trusted_index)
1127 }
1128
1129 fn find_first_with_trusted_blame_starting_from(
1130 &self, pivot_index: usize, blame_bound: Option<u32>,
1131 min_vote_count: usize,
1132 ) -> Option<usize> {
1133 trace!(
1134 "find_first_with_trusted_blame_starting_from pivot_index={:?}",
1135 pivot_index
1136 );
1137 let mut cur_pivot_index = pivot_index;
1138 while cur_pivot_index < self.pivot_chain.len() {
1139 let arena_index = self.pivot_chain[cur_pivot_index];
1140 let blame_ratio = self.compute_blame_ratio(
1141 arena_index,
1142 blame_bound,
1143 min_vote_count,
1144 );
1145 trace!(
1146 "blame_ratio for {:?} is {}",
1147 self.arena[arena_index].hash,
1148 blame_ratio
1149 );
1150 if blame_ratio < MAX_BLAME_RATIO_FOR_TRUST {
1151 return Some(cur_pivot_index);
1152 }
1153 cur_pivot_index += 1;
1154 }
1155
1156 None
1157 }
1158
1159 fn compute_blame_ratio(
1161 &self, arena_index: usize, blame_bound: Option<u32>,
1162 min_vote_count: usize,
1163 ) -> f64 {
1164 let blame_bound = if let Some(bound) = blame_bound {
1165 bound
1166 } else {
1167 u32::max_value()
1168 };
1169 let mut total_blame_count = 0 as u64;
1170 let mut queue = VecDeque::new();
1171 let mut votes = HashMap::new();
1172 queue.push_back((arena_index, 0 as u32));
1173 while let Some((index, step)) = queue.pop_front() {
1174 if index == arena_index {
1175 votes.insert(index, true);
1176 } else {
1177 let mut my_blame = self.get_blame(index);
1178 let mut parent = index;
1179 loop {
1180 parent = self.arena[parent].parent;
1181 if my_blame == 0 {
1182 let parent_vote = *votes.get(&parent).unwrap();
1183 votes.insert(index, parent_vote);
1184 if !parent_vote {
1185 total_blame_count += 1;
1186 }
1187 break;
1188 } else if parent == arena_index {
1189 votes.insert(index, false);
1190 total_blame_count += 1;
1191 break;
1192 }
1193 my_blame -= 1;
1194 }
1195 }
1196
1197 if step == blame_bound {
1198 continue;
1199 }
1200
1201 let next_step = step + 1;
1202 for child in &self.arena[index].children {
1203 queue.push_back((*child, next_step));
1204 }
1205 }
1206
1207 let total_vote_count = votes.len();
1208
1209 if total_vote_count < min_vote_count {
1210 return 1.0;
1212 }
1213
1214 total_blame_count as f64 / total_vote_count as f64
1217 }
1218
1219 pub fn check_mining_adaptive_block(
1220 &mut self, parent_arena_index: usize, referee_indices: Vec<usize>,
1221 difficulty: U256, pos_reference: Option<PosBlockId>,
1222 ) -> bool {
1223 let parent_anticone_opt = self.anticone_cache.get(parent_arena_index);
1225 let mut anticone;
1226 if parent_anticone_opt.is_none() {
1227 anticone = consensus_new_block_handler::ConsensusNewBlockHandler::compute_anticone_bruteforce(
1228 self, parent_arena_index,
1229 );
1230 for i in self.compute_future_bitset(parent_arena_index) {
1231 anticone.add(i);
1232 }
1233 } else {
1234 anticone = self.compute_future_bitset(parent_arena_index);
1235 for index in parent_anticone_opt.unwrap() {
1236 anticone.add(*index as u32);
1237 }
1238 }
1239 let mut my_past = BitSet::new();
1240 let mut queue: VecDeque<usize> = VecDeque::new();
1241 for index in &referee_indices {
1242 queue.push_back(*index);
1243 }
1244 while let Some(index) = queue.pop_front() {
1245 if my_past.contains(index as u32) {
1246 continue;
1247 }
1248 my_past.add(index as u32);
1249 let idx_parent = self.arena[index].parent;
1250 if idx_parent != NULL {
1251 if anticone.contains(idx_parent as u32)
1252 || self.arena[idx_parent].era_block == NULL
1253 {
1254 queue.push_back(idx_parent);
1255 }
1256 }
1257 for referee in &self.arena[index].referees {
1258 if anticone.contains(*referee as u32)
1259 || self.arena[*referee].era_block == NULL
1260 {
1261 queue.push_back(*referee);
1262 }
1263 }
1264 }
1265 for index in my_past.drain() {
1266 anticone.remove(index);
1267 }
1268
1269 let mut anticone_barrier = BitSet::new();
1270 for index in (&anticone).iter() {
1271 let parent = self.arena[index as usize].parent as u32;
1272 if self.arena[index as usize].era_block != NULL
1273 && !anticone.contains(parent)
1274 {
1275 anticone_barrier.add(index);
1276 }
1277 }
1278
1279 let timer_chain_tuple = self.compute_timer_chain_tuple(
1280 parent_arena_index,
1281 &referee_indices,
1282 Some(&anticone),
1283 );
1284
1285 self.adaptive_weight_impl(
1286 parent_arena_index,
1287 &anticone_barrier,
1288 None,
1289 &timer_chain_tuple,
1290 i128::try_from(difficulty.low_u128()).unwrap(),
1291 pos_reference,
1292 )
1293 }
1294
1295 fn compute_subtree_weights(
1315 &self, me: usize, anticone_barrier: &BitSet,
1316 ) -> Vec<i128> {
1317 let mut subtree_weight = Vec::new();
1318 let n = self.arena.capacity();
1319 subtree_weight.resize_with(n, Default::default);
1320 let mut stack = Vec::new();
1321 stack.push((0, self.cur_era_genesis_block_arena_index));
1322 while let Some((stage, index)) = stack.pop() {
1323 if stage == 0 {
1324 stack.push((1, index));
1325 subtree_weight[index] = 0;
1326 for child in &self.arena[index].children {
1327 if !anticone_barrier.contains(*child as u32) && *child != me
1328 {
1329 stack.push((0, *child));
1330 }
1331 }
1332 } else {
1333 let weight = self.block_weight(index);
1334 subtree_weight[index] += weight;
1335 let parent = self.arena[index].parent;
1336 if parent != NULL {
1337 subtree_weight[parent] += subtree_weight[index];
1338 }
1339 }
1340 }
1341 subtree_weight
1342 }
1343
1344 fn get_best_timer_tick(
1345 &self,
1346 timer_chain_tuple: &(u64, HashMap<usize, u64>, Vec<usize>, Vec<usize>),
1347 ) -> u64 {
1348 let (fork_at, _, _, c) = timer_chain_tuple;
1349 *fork_at + c.len() as u64
1350 }
1351
1352 fn get_timer_tick(
1353 &self, me: usize,
1354 timer_chain_tuple: &(u64, HashMap<usize, u64>, Vec<usize>, Vec<usize>),
1355 ) -> u64 {
1356 let (fork_at, m, _, _) = timer_chain_tuple;
1357 if let Some(t) = m.get(&me) {
1358 return *t;
1359 } else {
1360 assert!(
1361 self.arena[me].data.ledger_view_timer_chain_height <= *fork_at
1362 );
1363 }
1364 return self.arena[me].data.ledger_view_timer_chain_height;
1365 }
1366
1367 fn adaptive_weight_impl_brutal(
1368 &self, parent_0: usize, subtree_weight: &Vec<i128>,
1369 timer_chain_tuple: &(u64, HashMap<usize, u64>, Vec<usize>, Vec<usize>),
1370 force_confirm: usize, difficulty: i128,
1371 ) -> bool {
1372 let mut parent = parent_0;
1373
1374 let force_confirm_height = self.arena[force_confirm].height;
1375 let timer_me = self.get_best_timer_tick(timer_chain_tuple);
1376
1377 let adjusted_beta =
1378 (self.inner_conf.adaptive_weight_beta as i128) * difficulty;
1379
1380 let mut adaptive = false;
1381 while self.arena[parent].height != force_confirm_height {
1382 let grandparent = self.arena[parent].parent;
1383 let timer_parent = self.get_timer_tick(parent, timer_chain_tuple);
1384 assert!(timer_me >= timer_parent);
1385 if timer_me - timer_parent >= self.inner_conf.timer_chain_beta {
1386 let w = 2 * subtree_weight[parent]
1387 - subtree_weight[grandparent]
1388 + self.block_weight(grandparent);
1389 if w < adjusted_beta {
1390 adaptive = true;
1391 break;
1392 }
1393 }
1394 parent = grandparent;
1395 }
1396
1397 adaptive
1398 }
1399
1400 fn adaptive_weight_impl(
1401 &mut self, parent_0: usize, anticone_barrier: &BitSet,
1402 weight_tuple: Option<&Vec<i128>>,
1403 timer_chain_tuple: &(u64, HashMap<usize, u64>, Vec<usize>, Vec<usize>),
1404 difficulty: i128, pos_reference: Option<PosBlockId>,
1405 ) -> bool {
1406 let mut parent = parent_0;
1407 let force_confirm =
1408 self.compute_block_force_confirm(timer_chain_tuple, pos_reference);
1409 let force_confirm_height = self.arena[force_confirm].height;
1410 if self.arena[parent].height < force_confirm_height
1413 || self.ancestor_at(parent, force_confirm_height) != force_confirm
1414 {
1415 return false;
1416 }
1417 if let Some(subtree_weight) = weight_tuple {
1418 return self.adaptive_weight_impl_brutal(
1419 parent_0,
1420 subtree_weight,
1421 timer_chain_tuple,
1422 force_confirm,
1423 difficulty,
1424 );
1425 }
1426
1427 let mut weight_delta = HashMap::new();
1428
1429 for index in anticone_barrier.iter() {
1430 assert!(!self.is_legacy_block(index as usize));
1431 weight_delta
1432 .insert(index as usize, self.weight_tree.get(index as usize));
1433 }
1434
1435 for (index, delta) in &weight_delta {
1436 self.weight_tree.path_apply(*index, -*delta);
1437 let parent = self.arena[*index].parent;
1438 assert!(parent != NULL);
1439 self.adaptive_tree.caterpillar_apply(parent, *delta);
1440 self.adaptive_tree.path_apply(*index, -*delta * 2);
1441 }
1442
1443 let timer_me = self.get_best_timer_tick(timer_chain_tuple);
1444 let adjusted_beta = self.inner_conf.timer_chain_beta;
1445
1446 let mut high = self.arena[parent].height;
1447 let mut low = force_confirm_height + 1;
1448 let mut best = force_confirm_height;
1450
1451 while low <= high {
1452 let mid = (low + high) / 2;
1453 let p = self.ancestor_at(parent, mid);
1454 let timer_mid = self.get_timer_tick(p, timer_chain_tuple);
1455 assert!(timer_me >= timer_mid);
1456 if timer_me - timer_mid >= adjusted_beta {
1457 best = mid;
1458 low = mid + 1;
1459 } else {
1460 high = mid - 1;
1461 }
1462 }
1463
1464 let adaptive = if best != force_confirm_height {
1465 parent = self.ancestor_at(parent, best);
1466
1467 let a = self
1468 .adaptive_tree
1469 .path_aggregate_chop(parent, force_confirm);
1470 let b = self.inner_conf.adaptive_weight_beta as i128 * difficulty;
1471
1472 if a < b {
1473 debug!("block is adaptive: {:?} < {:?}!", a, b);
1474 } else {
1475 debug!("block is not adaptive: {:?} >= {:?}!", a, b);
1476 }
1477 a < b
1478 } else {
1479 debug!(
1480 "block is not adaptive: too close to genesis, timer tick {:?}",
1481 timer_me
1482 );
1483 false
1484 };
1485
1486 for (index, delta) in &weight_delta {
1487 self.weight_tree.path_apply(*index, *delta);
1488 let parent = self.arena[*index].parent;
1489 self.adaptive_tree.caterpillar_apply(parent, -*delta);
1490 self.adaptive_tree.path_apply(*index, *delta * 2)
1491 }
1492
1493 adaptive
1494 }
1495
1496 fn adaptive_weight(
1499 &mut self, me: usize, anticone_barrier: &BitSet,
1500 weight_tuple: Option<&Vec<i128>>,
1501 timer_chain_tuple: &(u64, HashMap<usize, u64>, Vec<usize>, Vec<usize>),
1502 ) -> bool {
1503 let parent = self.arena[me].parent;
1504 assert!(parent != NULL);
1505
1506 let difficulty =
1507 i128::try_from(self.arena[me].difficulty.low_u128()).unwrap();
1508
1509 self.adaptive_weight_impl(
1510 parent,
1511 anticone_barrier,
1512 weight_tuple,
1513 timer_chain_tuple,
1514 difficulty,
1515 self.data_man
1516 .pos_reference_by_hash(&self.arena[me].hash)
1517 .expect("header exist"),
1518 )
1519 }
1520
1521 #[inline]
1522 fn is_same_era(&self, me: usize, pivot: usize) -> bool {
1523 self.arena[me].era_block == self.arena[pivot].era_block
1524 }
1525
1526 fn compute_pastset_brutal(&mut self, me: usize) -> BitSet {
1527 let mut path = Vec::new();
1528 let mut cur = me;
1529 while cur != NULL && self.pastset_cache.get(cur).is_none() {
1530 path.push(cur);
1531 cur = self.arena[cur].parent;
1532 }
1533 path.reverse();
1534 let mut result = self
1535 .pastset_cache
1536 .get(cur)
1537 .unwrap_or(&BitSet::new())
1538 .clone();
1539 for ancestor_arena_index in path {
1540 result.add(ancestor_arena_index as u32);
1541 if self.arena[ancestor_arena_index].data.blockset_cleared {
1542 let mut queue = VecDeque::new();
1543 queue.push_back(ancestor_arena_index);
1544 while let Some(index) = queue.pop_front() {
1545 let parent = self.arena[index].parent;
1546 if parent != NULL && !result.contains(parent as u32) {
1547 result.add(parent as u32);
1548 queue.push_back(parent);
1549 }
1550 for referee in &self.arena[index].referees {
1551 if !result.contains(*referee as u32) {
1552 result.add(*referee as u32);
1553 queue.push_back(*referee);
1554 }
1555 }
1556 }
1557 } else {
1558 let blockset = self
1559 .exchange_or_compute_blockset_in_own_view_of_epoch(
1560 ancestor_arena_index,
1561 None,
1562 );
1563 for index in &blockset {
1564 result.add(*index as u32);
1565 }
1566 self.exchange_or_compute_blockset_in_own_view_of_epoch(
1567 ancestor_arena_index,
1568 Some(blockset),
1569 );
1570 }
1571 }
1572 result
1573 }
1574
1575 fn insert_referee_if_not_duplicate(
1582 &self, referees: &mut Vec<usize>, me: usize,
1583 ) {
1584 for i in 0..referees.len() {
1585 let x = referees[i];
1586 let lca = self.lca(x, me);
1587 if lca == me {
1588 return;
1590 } else if lca == x {
1591 referees[i] = me;
1593 return;
1594 }
1595 }
1596 referees.push(me)
1597 }
1598
1599 pub fn insert_out_era_block(
1603 &mut self, block_header: &BlockHeader, partial_invalid: bool,
1604 ) -> (u64, usize) {
1605 let sn = self.get_next_sequence_number();
1606 let hash = block_header.hash();
1607 let parent = self
1609 .hash_to_arena_indices
1610 .get(block_header.parent_hash())
1611 .cloned()
1612 .unwrap_or(NULL);
1613
1614 let mut referees: Vec<usize> = Vec::new();
1615 for hash in block_header.referee_hashes().iter() {
1616 if let Some(x) = self.hash_to_arena_indices.get(hash) {
1617 self.insert_referee_if_not_duplicate(&mut referees, *x);
1618 }
1619 }
1620
1621 if parent == NULL && referees.is_empty() {
1622 return (sn, NULL);
1623 }
1624
1625 let mut inactive_dependency_cnt = 0;
1626 for referee in &referees {
1627 if !self.arena[*referee].data.activated {
1628 inactive_dependency_cnt += 1;
1629 }
1630 }
1631
1632 let index = self.arena.insert(ConsensusGraphNode {
1635 hash,
1636 height: block_header.height(),
1637 is_heavy: true,
1638 difficulty: *block_header.difficulty(),
1639 past_num_blocks: 0,
1640 is_timer: false,
1641 adaptive: block_header.adaptive(),
1644 parent,
1645 era_block: NULL,
1646 children: Vec::new(),
1647 referees,
1648 referrers: Vec::new(),
1649 data: ConsensusGraphNodeData::new(
1650 NULLU64,
1651 sn,
1652 inactive_dependency_cnt,
1653 ),
1654 });
1655 self.arena[index].data.pending = true;
1656 self.arena[index].data.activated = false;
1657 self.arena[index].data.partial_invalid = partial_invalid;
1658 self.hash_to_arena_indices.insert(hash, index);
1659
1660 let referees = self.arena[index].referees.clone();
1661 for referee in referees {
1662 self.arena[referee].referrers.push(index);
1663 }
1664 if parent != NULL {
1665 self.arena[parent].children.push(index);
1666 }
1667
1668 self.weight_tree.make_tree(index);
1669 self.adaptive_tree.make_tree(index);
1670
1671 (sn, index)
1672 }
1673
1674 fn get_timer_difficulty(&self, me: usize) -> i128 {
1675 if self.arena[me].is_timer && !self.arena[me].data.partial_invalid {
1676 i128::try_from(self.arena[me].difficulty.low_u128()).unwrap()
1677 } else {
1678 0
1679 }
1680 }
1681
1682 fn compute_global_force_confirm(&self) -> usize {
1683 let timer_chain_choice =
1684 if let Some(x) = self.timer_chain_accumulative_lca.last() {
1685 *x
1686 } else {
1687 self.cur_era_genesis_block_arena_index
1688 };
1689 self.compute_force_confirm(
1690 timer_chain_choice,
1691 &self.best_pos_pivot_decision,
1692 )
1693 }
1694
1695 fn compute_block_force_confirm(
1696 &self,
1697 timer_chain_tuple: &(u64, HashMap<usize, u64>, Vec<usize>, Vec<usize>),
1698 pos_reference: Option<PosBlockId>,
1699 ) -> usize {
1700 let (fork_at, _, extra_lca, tmp_chain) = timer_chain_tuple;
1701 let fork_end_index =
1702 (*fork_at - self.cur_era_genesis_timer_chain_height) as usize
1703 + tmp_chain.len();
1704 let acc_lca_ref = extra_lca;
1705 let timer_chain_choice = if let Some(x) = acc_lca_ref.last() {
1706 *x
1707 } else if fork_end_index > self.inner_conf.timer_chain_beta as usize {
1708 self.timer_chain_accumulative_lca
1709 [fork_end_index - self.inner_conf.timer_chain_beta as usize - 1]
1710 } else {
1711 self.cur_era_genesis_block_arena_index
1712 };
1713 match pos_reference {
1714 None => timer_chain_choice,
1715 Some(pos_reference) => {
1716 let pos_pivot_decision = self
1717 .pos_verifier
1718 .get_pivot_decision(&pos_reference)
1719 .expect("pos_reference checked");
1720 self.compute_force_confirm(
1721 timer_chain_choice,
1722 &(
1723 pos_pivot_decision,
1724 self.data_man
1725 .block_height_by_hash(&pos_pivot_decision)
1726 .expect("pos pivot decision checked"),
1727 ),
1728 )
1729 }
1730 }
1731 }
1732
1733 fn compute_force_confirm(
1734 &self, timer_chain_choice: usize, pos_pivot_decision: &(H256, u64),
1735 ) -> usize {
1736 if let Some(arena_index) =
1737 self.hash_to_arena_indices.get(&pos_pivot_decision.0)
1738 {
1739 if self.arena[timer_chain_choice].height > pos_pivot_decision.1
1740 && self.lca(timer_chain_choice, *arena_index) == *arena_index
1741 {
1742 timer_chain_choice
1745 } else {
1746 *arena_index
1749 }
1750 } else {
1751 timer_chain_choice
1754 }
1755 }
1756
1757 fn insert(&mut self, block_header: &BlockHeader) -> (usize, usize) {
1758 let hash = block_header.hash();
1759
1760 let pow_quality =
1761 U512::from(VerificationConfig::get_or_compute_header_pow_quality(
1762 &self.pow,
1763 block_header,
1764 ));
1765 let is_heavy = pow_quality
1766 >= U512::from(self.inner_conf.heavy_block_difficulty_ratio)
1767 * U512::from(block_header.difficulty());
1768 let is_timer = pow_quality
1769 >= U512::from(self.inner_conf.timer_chain_block_difficulty_ratio)
1770 * U512::from(block_header.difficulty());
1771
1772 let parent =
1773 if hash != self.data_man.get_cur_consensus_era_genesis_hash() {
1774 self.hash_to_arena_indices
1775 .get(block_header.parent_hash())
1776 .cloned()
1777 .unwrap()
1778 } else {
1779 NULL
1780 };
1781
1782 let mut referees: Vec<usize> = Vec::new();
1783 for hash in block_header.referee_hashes().iter() {
1784 if let Some(x) = self.hash_to_arena_indices.get(hash) {
1785 self.insert_referee_if_not_duplicate(&mut referees, *x);
1786 }
1787 }
1788
1789 let mut inactive_dependency_cnt =
1790 if parent != NULL && !self.arena[parent].data.activated {
1791 1
1792 } else {
1793 0
1794 };
1795 for referee in &referees {
1796 if !self.arena[*referee].data.activated {
1797 inactive_dependency_cnt += 1;
1798 }
1799 }
1800
1801 let my_height = block_header.height();
1802 let sn = self.get_next_sequence_number();
1803 let index = self.arena.insert(ConsensusGraphNode {
1804 hash,
1805 height: my_height,
1806 is_heavy,
1807 difficulty: *block_header.difficulty(),
1808 past_num_blocks: 0,
1809 is_timer,
1810 adaptive: block_header.adaptive(),
1813 parent,
1814 era_block: self.get_era_genesis_block_with_parent(parent),
1815 children: Vec::new(),
1816 referees,
1817 referrers: Vec::new(),
1818 data: ConsensusGraphNodeData::new(
1819 NULLU64,
1820 sn,
1821 inactive_dependency_cnt,
1822 ),
1823 });
1824 self.hash_to_arena_indices.insert(hash, index);
1825
1826 if parent != NULL {
1827 self.arena[parent].children.push(index);
1828 }
1829 let referees = self.arena[index].referees.clone();
1830 for referee in referees {
1831 self.arena[referee].referrers.push(index);
1832 }
1833
1834 self.compute_blockset_in_own_view_of_epoch(index);
1835 let executed_epoch_len =
1836 self.get_ordered_executable_epoch_blocks(index).len();
1837
1838 if parent != NULL {
1839 let past_num_blocks =
1840 self.arena[parent].past_num_blocks + executed_epoch_len as u64;
1841
1842 self.data_man.insert_epoch_execution_context(
1843 hash.clone(),
1844 EpochExecutionContext {
1845 start_block_number: self
1846 .get_epoch_start_block_number(index),
1847 },
1848 true, );
1850
1851 self.arena[index].past_num_blocks = past_num_blocks;
1852 }
1853
1854 debug!(
1855 "Block {} inserted into Consensus with index={}",
1856 hash, index
1857 );
1858
1859 (index, self.hash_to_arena_indices.len())
1860 }
1861
1862 fn compute_future_bitset(&self, me: usize) -> BitSet {
1863 let mut queue: VecDeque<usize> = VecDeque::new();
1865 let mut visited = BitSet::with_capacity(self.arena.len() as u32);
1866 queue.push_back(me);
1867 visited.add(me as u32);
1868 while let Some(index) = queue.pop_front() {
1869 for child in &self.arena[index].children {
1870 if !visited.contains(*child as u32)
1871 && (self.arena[*child].data.activated
1872 || self.arena[*child].data.inactive_dependency_cnt
1873 == NULL)
1874 {
1876 visited.add(*child as u32);
1877 queue.push_back(*child);
1878 }
1879 }
1880 for referrer in &self.arena[index].referrers {
1881 if !visited.contains(*referrer as u32)
1882 && (self.arena[*referrer].data.activated
1883 || self.arena[*referrer].data.inactive_dependency_cnt
1884 == NULL)
1885 {
1887 visited.add(*referrer as u32);
1888 queue.push_back(*referrer);
1889 }
1890 }
1891 }
1892 visited.remove(me as u32);
1893 visited
1894 }
1895
1896 pub fn get_pivot_reward_index(
1922 &self, epoch_arena_index: usize,
1923 ) -> Option<(usize, usize)> {
1924 if self.arena[epoch_arena_index].height <= REWARD_EPOCH_COUNT {
1926 return None;
1927 }
1928 let parent_index = self.arena[epoch_arena_index].parent;
1929 let anticone_cut_height =
1931 REWARD_EPOCH_COUNT - ANTICONE_PENALTY_UPPER_EPOCH_COUNT;
1932 let mut anticone_penalty_cutoff_epoch_block = parent_index;
1933 for _i in 1..anticone_cut_height {
1934 if anticone_penalty_cutoff_epoch_block == NULL {
1935 break;
1936 }
1937 anticone_penalty_cutoff_epoch_block =
1938 self.arena[anticone_penalty_cutoff_epoch_block].parent;
1939 }
1940 let mut reward_epoch_block = anticone_penalty_cutoff_epoch_block;
1941 for _i in 0..ANTICONE_PENALTY_UPPER_EPOCH_COUNT {
1942 if reward_epoch_block == NULL {
1943 break;
1944 }
1945 reward_epoch_block = self.arena[reward_epoch_block].parent;
1946 }
1947 if reward_epoch_block != NULL {
1948 while !self.is_same_era(
1950 reward_epoch_block,
1951 anticone_penalty_cutoff_epoch_block,
1952 ) {
1953 anticone_penalty_cutoff_epoch_block =
1954 self.arena[anticone_penalty_cutoff_epoch_block].parent;
1955 }
1956 }
1957 let reward_index = if reward_epoch_block == NULL {
1958 None
1959 } else {
1960 Some((reward_epoch_block, anticone_penalty_cutoff_epoch_block))
1961 };
1962 reward_index
1963 }
1964
1965 fn get_executable_epoch_blocks(
1966 &self, epoch_arena_index: usize,
1967 ) -> Vec<Arc<Block>> {
1968 let mut epoch_blocks = Vec::new();
1969 for idx in self.get_ordered_executable_epoch_blocks(epoch_arena_index) {
1970 let block = self
1971 .data_man
1972 .block_by_hash(
1973 &self.arena[*idx].hash,
1974 true, )
1976 .expect("Exist");
1977 epoch_blocks.push(block);
1978 }
1979 epoch_blocks
1980 }
1981
1982 pub fn expected_difficulty(&self, parent_hash: &H256) -> U256 {
2001 let parent_arena_index =
2002 *self.hash_to_arena_indices.get(parent_hash).unwrap();
2003 let parent_epoch = self.arena[parent_arena_index].height;
2004 if parent_epoch
2005 < self
2006 .pow_config
2007 .difficulty_adjustment_epoch_period(parent_epoch)
2008 {
2009 self.pow_config.initial_difficulty.into()
2011 } else {
2012 let last_period_upper = (parent_epoch
2013 / self
2014 .pow_config
2015 .difficulty_adjustment_epoch_period(parent_epoch))
2016 * self
2017 .pow_config
2018 .difficulty_adjustment_epoch_period(parent_epoch);
2019 if last_period_upper != parent_epoch {
2020 self.arena[parent_arena_index].difficulty
2021 } else {
2022 self.data_man.target_difficulty_manager.target_difficulty(
2023 self,
2024 &self.pow_config,
2026 &self.arena[parent_arena_index].hash,
2027 )
2028 }
2029 }
2030 }
2031
2032 fn adjust_difficulty(&mut self, new_best_arena_index: usize) {
2033 let new_best_hash = self.arena[new_best_arena_index].hash.clone();
2034 let new_best_difficulty = self.arena[new_best_arena_index].difficulty;
2035 let old_best_arena_index = *self.pivot_chain.last().expect("not empty");
2036 if old_best_arena_index == self.arena[new_best_arena_index].parent {
2037 assert!(self.current_difficulty == new_best_difficulty);
2039 }
2040
2041 let epoch = self.arena[new_best_arena_index].height;
2042 if epoch == 0 {
2043 self.current_difficulty = self.pow_config.initial_difficulty.into();
2046 } else if epoch
2047 == (epoch
2048 / self.pow_config.difficulty_adjustment_epoch_period(epoch))
2049 * self.pow_config.difficulty_adjustment_epoch_period(epoch)
2050 {
2051 let this: &ConsensusGraphInner = self;
2052 self.current_difficulty = self
2053 .data_man
2054 .target_difficulty_manager
2055 .target_difficulty(this, &self.pow_config, &new_best_hash);
2056 } else {
2057 self.current_difficulty = new_best_difficulty;
2058 }
2059 }
2060
2061 pub fn best_block_hash(&self) -> H256 {
2062 self.arena[*self.pivot_chain.last().unwrap()].hash
2063 }
2064
2065 pub fn best_block_number(&self) -> u64 {
2066 self.arena[*self.pivot_chain.last().unwrap()].past_num_blocks
2067 }
2068
2069 pub fn best_state_epoch_number(&self) -> u64 {
2074 let pivot_height = self.pivot_index_to_height(self.pivot_chain.len());
2075 if pivot_height < DEFERRED_STATE_EPOCH_COUNT {
2076 0
2077 } else {
2078 pivot_height - DEFERRED_STATE_EPOCH_COUNT
2079 }
2080 }
2081
2082 fn best_state_arena_index(&self) -> usize {
2083 self.get_pivot_block_arena_index(self.best_state_epoch_number())
2084 }
2085
2086 pub fn best_state_block_hash(&self) -> H256 {
2087 self.arena[self.best_state_arena_index()].hash
2088 }
2089
2090 pub fn get_state_block_with_delay(
2091 &self, block_hash: &H256, delay: usize,
2092 ) -> Result<&H256, String> {
2093 let idx_opt = self.hash_to_arena_indices.get(block_hash);
2094 if idx_opt == None {
2095 return Err(
2096 "Parent hash is too old for computing the deferred state"
2097 .to_owned(),
2098 );
2099 }
2100 let mut idx = *idx_opt.unwrap();
2101 for _i in 0..delay {
2102 trace!(
2103 "get_state_block_with_delay: idx={}, height={}",
2104 idx,
2105 self.arena[idx].height
2106 );
2107 if idx == self.cur_era_genesis_block_arena_index {
2108 if self.arena[self.cur_era_genesis_block_arena_index].height
2110 == 0
2111 {
2112 break;
2113 } else {
2114 return Err(
2115 "Parent is too old for computing the deferred state"
2116 .to_owned(),
2117 );
2118 }
2119 }
2120 idx = self.arena[idx].parent;
2121 }
2122 Ok(&self.arena[idx].hash)
2123 }
2124
2125 pub fn best_epoch_number(&self) -> u64 {
2126 self.cur_era_genesis_height + self.pivot_chain.len() as u64 - 1
2127 }
2128
2129 pub fn best_timer_chain_height(&self) -> u64 {
2130 self.cur_era_genesis_timer_chain_height + self.timer_chain.len() as u64
2131 - 1
2132 }
2133
2134 fn get_arena_index_from_epoch_number(
2135 &self, epoch_number: u64,
2136 ) -> Result<usize, String> {
2137 if epoch_number >= self.cur_era_genesis_height {
2138 let pivot_index =
2139 (epoch_number - self.cur_era_genesis_height) as usize;
2140 if pivot_index >= self.pivot_chain.len() {
2141 Err("Epoch number larger than the current pivot chain tip"
2142 .into())
2143 } else {
2144 Ok(self.get_pivot_block_arena_index(epoch_number))
2145 }
2146 } else {
2147 Err("Invalid params: epoch number is too old and not maintained by consensus graph".to_owned())
2148 }
2149 }
2150
2151 pub fn get_pivot_hash_from_epoch_number(
2155 &self, epoch_number: u64,
2156 ) -> Result<EpochId, ProviderBlockError> {
2157 let height = epoch_number;
2158 if height >= self.cur_era_genesis_height {
2159 let pivot_index = (height - self.cur_era_genesis_height) as usize;
2160 if pivot_index >= self.pivot_chain.len() {
2161 Err("Epoch number larger than the current pivot chain tip"
2162 .into())
2163 } else {
2164 Ok(self.arena[self.get_pivot_block_arena_index(height)].hash)
2165 }
2166 } else {
2167 self.data_man.executed_epoch_set_hashes_from_db(epoch_number).ok_or(
2168 format!("get_hash_from_epoch_number: Epoch hash set not in db, epoch_number={}", epoch_number).into()
2169 ).and_then(|epoch_hashes|
2170 epoch_hashes.last().map(Clone::clone).ok_or("Epoch set is empty".into())
2171 )
2172 }
2173 }
2174
2175 pub fn epoch_hash(&self, epoch_number: u64) -> Option<H256> {
2178 let pivot_index = self.height_to_pivot_index(epoch_number);
2179 self.pivot_chain
2180 .get(pivot_index)
2181 .map(|idx| self.arena[*idx].hash)
2182 }
2183
2184 pub fn block_hashes_by_epoch(
2185 &self, epoch_number: u64,
2186 ) -> Result<Vec<H256>, ProviderBlockError> {
2187 debug!(
2188 "block_hashes_by_epoch epoch_number={:?} pivot_chain.len={:?}",
2189 epoch_number,
2190 self.pivot_chain.len()
2191 );
2192
2193 let e;
2194 match self.get_arena_index_from_epoch_number(epoch_number) {
2198 Ok(pivot_arena_index) => {
2199 if pivot_arena_index != self.cur_era_genesis_block_arena_index {
2200 return Ok(self
2201 .get_ordered_executable_epoch_blocks(pivot_arena_index)
2202 .iter()
2203 .map(|index| self.arena[*index].hash)
2204 .collect());
2205 }
2206 e = "Epoch set of the current genesis is not maintained".into();
2207 }
2208 Err(err) => e = err,
2209 }
2210
2211 self.data_man
2212 .executed_epoch_set_hashes_from_db(epoch_number)
2213 .ok_or(
2214 format!(
2215 "Epoch set not in db epoch_number={}, in mem err={:?}",
2216 epoch_number, e
2217 )
2218 .into(),
2219 )
2220 }
2221
2222 pub fn skipped_block_hashes_by_epoch(
2223 &self, epoch_number: u64,
2224 ) -> Result<Vec<H256>, ProviderBlockError> {
2225 debug!(
2226 "skipped_block_hashes_by_epoch epoch_number={:?} pivot_chain.len={:?}",
2227 epoch_number,
2228 self.pivot_chain.len()
2229 );
2230
2231 let e;
2232 match self.get_arena_index_from_epoch_number(epoch_number) {
2236 Ok(pivot_arena_index) => {
2237 if pivot_arena_index != self.cur_era_genesis_block_arena_index {
2238 if let Some(skipped_block_set) =
2239 self.get_skipped_epoch_blocks(pivot_arena_index)
2240 {
2241 return Ok(skipped_block_set.clone());
2242 }
2243 }
2244 e = "Skipped epoch set of the current genesis is not maintained".into();
2245 }
2246 Err(err) => e = err,
2247 }
2248
2249 self.data_man
2250 .skipped_epoch_set_hashes_from_db(epoch_number)
2251 .ok_or(
2252 format!(
2253 "Skipped epoch set not in db epoch_number={}, in mem err={:?}",
2254 epoch_number, e
2255 )
2256 .into(),
2257 )
2258 }
2259
2260 fn get_epoch_hash_for_block(&self, hash: &H256) -> Option<H256> {
2261 self.get_block_epoch_number(&hash)
2262 .and_then(|epoch_number| self.epoch_hash(epoch_number))
2263 }
2264
2265 pub fn bounded_terminal_block_hashes(
2266 &mut self, referee_bound: usize,
2267 ) -> Vec<H256> {
2268 let best_block_arena_index = *self.pivot_chain.last().unwrap();
2269 if self.terminal_hashes.len() > referee_bound {
2270 self.best_terminals(best_block_arena_index, referee_bound)
2271 } else {
2272 self.terminal_hashes
2273 .iter()
2274 .map(|hash| hash.clone())
2275 .collect()
2276 }
2277 }
2278
2279 pub fn get_block_epoch_number(&self, hash: &H256) -> Option<u64> {
2280 self.hash_to_arena_indices.get(hash).and_then(|index| {
2281 match self.arena[*index].data.epoch_number {
2282 NULLU64 => None,
2283 epoch => Some(epoch),
2284 }
2285 })
2286 }
2287
2288 pub fn all_blocks_with_topo_order(&self) -> Vec<H256> {
2289 let epoch_number = self.best_epoch_number();
2290 let mut current_number = 0;
2291 let mut hashes = Vec::new();
2292 while current_number <= epoch_number {
2293 let epoch_hashes =
2294 self.block_hashes_by_epoch(current_number.into()).unwrap();
2295 for hash in epoch_hashes {
2296 hashes.push(hash);
2297 }
2298 current_number += 1;
2299 }
2300 hashes
2301 }
2302
2303 pub fn block_execution_results_by_hash(
2306 &self, hash: &H256, update_cache: bool,
2307 ) -> Option<BlockExecutionResultWithEpoch> {
2308 match self.get_epoch_hash_for_block(hash) {
2309 Some(epoch) => {
2310 trace!("Block {} is in epoch {}", hash, epoch);
2311 let execution_result =
2312 self.data_man.block_execution_result_by_hash_with_epoch(
2313 hash,
2314 &epoch,
2315 false, update_cache,
2317 )?;
2318 Some(DataVersionTuple(epoch, execution_result))
2319 }
2320 None => {
2321 debug!("Block {:?} not in mem, try to read from db", hash);
2322
2323 let res = match self
2326 .data_man
2327 .block_execution_result_by_hash_from_db(hash)
2328 {
2329 None => return None,
2330 Some(res) => res,
2331 };
2332
2333 let execution_pivot_hash = res.0;
2334 let epoch_number = self
2335 .data_man
2336 .block_header_by_hash(&execution_pivot_hash)?
2337 .height();
2338
2339 match self.get_pivot_hash_from_epoch_number(epoch_number) {
2340 Ok(h) if h == execution_pivot_hash => Some(res),
2342
2343 _ => None,
2345 }
2346 }
2347 }
2348 }
2349
2350 pub fn is_timer_block(&self, block_hash: &H256) -> Option<bool> {
2351 self.hash_to_arena_indices
2352 .get(block_hash)
2353 .and_then(|index| Some(self.arena[*index].is_timer))
2354 }
2355
2356 pub fn is_adaptive(&self, block_hash: &H256) -> Option<bool> {
2357 self.hash_to_arena_indices
2358 .get(block_hash)
2359 .and_then(|index| Some(self.arena[*index].adaptive))
2360 }
2361
2362 pub fn is_partial_invalid(&self, block_hash: &H256) -> Option<bool> {
2363 self.hash_to_arena_indices
2364 .get(block_hash)
2365 .and_then(|index| Some(self.arena[*index].data.partial_invalid))
2366 }
2367
2368 pub fn is_pending(&self, block_hash: &H256) -> Option<bool> {
2369 self.hash_to_arena_indices
2370 .get(block_hash)
2371 .and_then(|index| Some(self.arena[*index].data.pending))
2372 }
2373
2374 pub fn check_block_pivot_assumption(
2375 &self, pivot_hash: &H256, epoch: u64,
2376 ) -> Result<(), ProviderBlockError> {
2377 let last_number = self.best_epoch_number();
2378 let hash = self.get_pivot_hash_from_epoch_number(epoch)?;
2379 if epoch > last_number || hash != *pivot_hash {
2380 return Err("Error: pivot chain assumption failed".into());
2381 }
2382 Ok(())
2383 }
2384
2385 fn block_weight(&self, me: usize) -> i128 {
2390 if !self.arena[me].data.activated || self.arena[me].era_block == NULL {
2391 return 0 as i128;
2392 }
2393 let is_heavy = self.arena[me].is_heavy;
2394 let is_adaptive = self.arena[me].adaptive;
2395 if is_adaptive {
2396 if is_heavy {
2397 self.inner_conf.heavy_block_difficulty_ratio as i128
2398 * i128::try_from(self.arena[me].difficulty.low_u128())
2399 .unwrap()
2400 } else {
2401 0 as i128
2402 }
2403 } else {
2404 i128::try_from(self.arena[me].difficulty.low_u128()).unwrap()
2405 }
2406 }
2407
2408 fn compute_blame_and_state_with_execution_result(
2468 &mut self, parent: usize, state_root_hash: H256,
2469 receipts_root_hash: H256, logs_bloom_hash: H256,
2470 ) -> Result<StateBlameInfo, String> {
2471 let mut cur = parent;
2472 let mut blame_cnt: u32 = 0;
2473 let mut state_blame_vec = Vec::new();
2474 let mut receipt_blame_vec = Vec::new();
2475 let mut bloom_blame_vec = Vec::new();
2476 let mut blame_info_to_fill = Vec::new();
2477 state_blame_vec.push(state_root_hash);
2478 receipt_blame_vec.push(receipts_root_hash);
2479 bloom_blame_vec.push(logs_bloom_hash);
2480 loop {
2481 if self.arena[cur]
2482 .data
2483 .state_valid
2484 .expect("computed by the caller")
2485 {
2486 if let Some(last_blame_info) = blame_info_to_fill.pop() {
2490 self.arena[last_blame_info].data.blame_info =
2491 Some(StateBlameInfo {
2492 blame: 0,
2493 state_vec_root: state_blame_vec
2494 .last()
2495 .unwrap()
2496 .clone(),
2497 receipts_vec_root: receipt_blame_vec
2498 .last()
2499 .unwrap()
2500 .clone(),
2501 logs_bloom_vec_root: bloom_blame_vec
2502 .last()
2503 .unwrap()
2504 .clone(),
2505 });
2506 blame_cnt = 1;
2507 }
2508 break;
2509 }
2510
2511 debug!("compute_blame_and_state_with_execution_result: cur={} height={}", cur, self.arena[cur].height);
2512 let deferred_arena_index =
2517 self.get_deferred_state_arena_index(cur)?;
2518 let deferred_block_commitment = self
2519 .data_man
2520 .get_epoch_execution_commitment(
2521 &self.arena[deferred_arena_index].hash,
2522 )
2523 .ok_or("State block commitment missing")?;
2524 if let Some(blame_info) = self.arena[cur].data.blame_info {
2526 blame_cnt = blame_info.blame + 1;
2527 state_blame_vec.push(blame_info.state_vec_root);
2528 receipt_blame_vec.push(blame_info.receipts_vec_root);
2529 bloom_blame_vec.push(blame_info.logs_bloom_vec_root);
2530 break;
2531 }
2532 blame_info_to_fill.push(cur);
2533 if self.arena[cur].height == self.cur_era_genesis_height {
2534 return Err(
2540 "Failed to compute blame and state due to out of era. The blockchain data is probably corrupted."
2541 .to_owned(),
2542 );
2543 }
2544 state_blame_vec.push(
2545 deferred_block_commitment
2546 .state_root_with_aux_info
2547 .aux_info
2548 .state_root_hash,
2549 );
2550 receipt_blame_vec
2551 .push(deferred_block_commitment.receipts_root.clone());
2552 bloom_blame_vec
2553 .push(deferred_block_commitment.logs_bloom_hash.clone());
2554 cur = self.arena[cur].parent;
2555 }
2556 let blame = blame_cnt + blame_info_to_fill.len() as u32;
2557
2558 if blame > 0 {
2569 let mut accumulated_state_root =
2570 state_blame_vec.last().unwrap().clone();
2571 let mut accumulated_receipts_root =
2572 receipt_blame_vec.last().unwrap().clone();
2573 let mut accumulated_logs_bloom_root =
2574 bloom_blame_vec.last().unwrap().clone();
2575 for i in (0..blame_info_to_fill.len()).rev() {
2576 accumulated_state_root =
2577 BlockHeaderBuilder::compute_blame_state_root_incremental(
2578 state_blame_vec[i + 1],
2579 accumulated_state_root,
2580 );
2581 accumulated_receipts_root =
2582 BlockHeaderBuilder::compute_blame_state_root_incremental(
2583 receipt_blame_vec[i + 1],
2584 accumulated_receipts_root,
2585 );
2586 accumulated_logs_bloom_root =
2587 BlockHeaderBuilder::compute_blame_state_root_incremental(
2588 bloom_blame_vec[i + 1],
2589 accumulated_logs_bloom_root,
2590 );
2591 self.arena[blame_info_to_fill[i]].data.blame_info =
2592 Some(StateBlameInfo {
2593 blame: blame_cnt,
2594 state_vec_root: accumulated_state_root,
2595 receipts_vec_root: accumulated_receipts_root,
2596 logs_bloom_vec_root: accumulated_logs_bloom_root,
2597 });
2598 blame_cnt += 1;
2599 }
2600 let state_vec_root =
2601 BlockHeaderBuilder::compute_blame_state_root_incremental(
2602 state_blame_vec[0],
2603 accumulated_state_root,
2604 );
2605 let receipts_vec_root =
2606 BlockHeaderBuilder::compute_blame_state_root_incremental(
2607 receipt_blame_vec[0],
2608 accumulated_receipts_root,
2609 );
2610 let logs_bloom_vec_root =
2611 BlockHeaderBuilder::compute_blame_state_root_incremental(
2612 bloom_blame_vec[0],
2613 accumulated_logs_bloom_root,
2614 );
2615 Ok(StateBlameInfo {
2616 blame,
2617 state_vec_root,
2618 receipts_vec_root,
2619 logs_bloom_vec_root,
2620 })
2621 } else {
2622 Ok(StateBlameInfo {
2623 blame: 0,
2624 state_vec_root: state_blame_vec.pop().unwrap(),
2625 receipts_vec_root: receipt_blame_vec.pop().unwrap(),
2626 logs_bloom_vec_root: bloom_blame_vec.pop().unwrap(),
2627 })
2628 }
2629 }
2630
2631 fn compute_state_valid_and_blame_info_for_block(
2637 &mut self, me: usize, executor: &ConsensusExecutor,
2638 ) -> Result<(), String> {
2639 let block_height = self.arena[me].height;
2640 let block_hash = self.arena[me].hash;
2641 debug!("compute_state_valid: me={} height={}", me, block_height);
2642 let deferred_state_arena_index =
2643 self.get_deferred_state_arena_index(me)?;
2644 let exec_commitment = self
2645 .data_man
2646 .get_epoch_execution_commitment(
2647 &self.arena[deferred_state_arena_index].hash,
2648 )
2649 .expect("Commitment exist");
2650 let parent = self.arena[me].parent;
2651 let original_deferred_state_root =
2652 exec_commitment.state_root_with_aux_info.clone();
2653 let original_deferred_receipt_root =
2654 exec_commitment.receipts_root.clone();
2655 let original_deferred_logs_bloom_hash =
2656 exec_commitment.logs_bloom_hash.clone();
2657
2658 let state_blame_info = self
2659 .compute_blame_and_state_with_execution_result(
2660 parent,
2661 original_deferred_state_root
2662 .aux_info
2663 .state_root_hash
2664 .clone(),
2665 original_deferred_receipt_root.clone(),
2666 original_deferred_logs_bloom_hash.clone(),
2667 )?;
2668 let block_header = self
2669 .data_man
2670 .block_header_by_hash(&self.arena[me].hash)
2671 .unwrap();
2672 let state_valid = block_header.blame() == state_blame_info.blame
2673 && *block_header.deferred_state_root()
2674 == state_blame_info.state_vec_root
2675 && *block_header.deferred_receipts_root()
2676 == state_blame_info.receipts_vec_root
2677 && *block_header.deferred_logs_bloom_hash()
2678 == state_blame_info.logs_bloom_vec_root;
2679
2680 let mut debug_recompute = false;
2681 if state_valid {
2682 debug!(
2683 "compute_state_valid_for_block(): Block {} state/blame is valid.",
2684 block_hash,
2685 );
2686 } else {
2687 warn!(
2688 "compute_state_valid_for_block(): Block {:?} state/blame is invalid! \
2689 header blame {:?}, our blame {:?}, header state_root {:?}, \
2690 our state root {:?}, header receipt_root {:?}, our receipt root {:?}, \
2691 header logs_bloom_hash {:?}, our logs_bloom_hash {:?}.",
2692 block_hash, block_header.blame(), state_blame_info.blame,
2693 block_header.deferred_state_root(), state_blame_info.state_vec_root,
2694 block_header.deferred_receipts_root(), state_blame_info.receipts_vec_root,
2695 block_header.deferred_logs_bloom_hash(), state_blame_info.logs_bloom_vec_root,
2696 );
2697 INVALID_BLAME_OR_STATE_ROOT_COUNTER.inc(1);
2698
2699 if self.inner_conf.debug_dump_dir_invalid_state_root.is_some() {
2700 debug_recompute = true;
2701 }
2702 }
2703 if let Some(debug_epoch) =
2704 &self.inner_conf.debug_invalid_state_root_epoch
2705 {
2706 if block_hash.eq(debug_epoch) {
2707 debug_recompute = true;
2708 }
2709 }
2710 if debug_recompute {
2711 if let Ok(epoch_arena_index) =
2712 self.get_deferred_state_arena_index(me)
2713 {
2714 let state_availability_lower_bound = self
2715 .data_man
2716 .state_availability_boundary
2717 .read()
2718 .lower_bound;
2719 if state_availability_lower_bound < block_height {
2722 log_invalid_state_root(
2724 epoch_arena_index,
2725 self,
2726 executor,
2727 block_hash,
2728 block_height,
2729 &original_deferred_state_root,
2730 )
2731 .ok();
2732
2733 let header_blame = block_header.blame() as u64;
2737 let mut block_arena_index = self.arena[me].parent;
2738 let mut earliest_mismatch_arena_index = me;
2739 for i in 1..header_blame {
2740 if block_height - i <= state_availability_lower_bound {
2741 break;
2742 }
2743 if self.arena[block_arena_index].data.state_valid
2744 != Some(false)
2745 {
2746 earliest_mismatch_arena_index = block_arena_index;
2747 }
2748 block_arena_index =
2749 self.arena[block_arena_index].parent;
2750 }
2751 if earliest_mismatch_arena_index != me {
2752 if let Ok(state_epoch_arena_index) = self
2753 .get_deferred_state_arena_index(
2754 earliest_mismatch_arena_index,
2755 )
2756 {
2757 let block_hash =
2758 self.arena[earliest_mismatch_arena_index].hash;
2759 let block_height = self.arena
2760 [earliest_mismatch_arena_index]
2761 .height;
2762 let state_root = self
2763 .data_man
2764 .get_epoch_execution_commitment(
2765 &self.arena[state_epoch_arena_index].hash,
2766 )
2767 .expect("Commitment exist")
2768 .state_root_with_aux_info
2769 .clone();
2770 log_invalid_state_root(
2771 state_epoch_arena_index,
2772 self,
2773 executor,
2774 block_hash,
2775 block_height,
2776 &state_root,
2777 )
2778 .ok();
2779 }
2780 }
2781 }
2782 }
2783 }
2784
2785 self.arena[me].data.state_valid = Some(state_valid);
2786 if !state_valid {
2787 self.arena[me].data.blame_info = Some(state_blame_info);
2788 }
2789
2790 if self.inner_conf.enable_state_expose {
2791 STATE_EXPOSER
2792 .consensus_graph
2793 .lock()
2794 .block_execution_state_vec
2795 .push(ConsensusGraphBlockExecutionState {
2796 block_hash,
2797 deferred_state_root: original_deferred_state_root
2798 .aux_info
2799 .state_root_hash,
2800 deferred_receipt_root: original_deferred_receipt_root,
2801 deferred_logs_bloom_hash: original_deferred_logs_bloom_hash,
2802 state_valid: self.arena[me]
2803 .data
2804 .state_valid
2805 .unwrap_or(true),
2806 })
2807 }
2808
2809 Ok(())
2810 }
2811
2812 fn compute_vote_valid_for_pivot_block(
2813 &mut self, me: usize, pivot_arena_index: usize,
2814 ) -> bool {
2815 let lca = self.lca(me, pivot_arena_index);
2816 let lca_height = self.arena[lca].height;
2817 debug!(
2818 "compute_vote_valid_for_pivot_block: lca={}, lca_height={}",
2819 lca, lca_height
2820 );
2821 let mut stack = Vec::new();
2822 stack.push((0, me, 0));
2823 while !stack.is_empty() {
2824 let (stage, index, a) = stack.pop().unwrap();
2825 if stage == 0 {
2826 if self.arena[index].data.vote_valid_lca_height != lca_height {
2827 let header = self
2828 .data_man
2829 .block_header_by_hash(&self.arena[index].hash)
2830 .unwrap();
2831 let blame = header.blame();
2832 if self.arena[index].height > lca_height + 1 + blame as u64
2833 {
2834 let ancestor = self.ancestor_at(
2835 index,
2836 self.arena[index].height - blame as u64 - 1,
2837 );
2838 stack.push((1, index, ancestor));
2839 stack.push((0, ancestor, 0));
2840 } else {
2841 let vote_valid = match Self::blame_covered_start_height(
2845 self.arena[index].height,
2846 blame,
2847 ) {
2848 Some(start_height) => {
2849 let mut cur_height = lca_height;
2850 let mut cur = lca;
2851 let mut vote_valid = true;
2852 while cur_height > start_height {
2853 if self.arena[cur].data.state_valid
2854 .expect("state_valid for me has been computed in \
2855 wait_and_compute_state_valid_locked by the caller, \
2856 so the precedents should have state_valid") {
2857 vote_valid = false;
2858 break;
2859 }
2860 cur_height -= 1;
2861 cur = self.arena[cur].parent;
2862 }
2863 vote_valid
2864 && self.arena[cur].data.state_valid.expect(
2865 "state_valid for me has been computed in \
2866 wait_and_compute_state_valid_locked by the caller, \
2867 so the precedents should have state_valid",
2868 )
2869 }
2870 None => false,
2871 };
2872 self.arena[index].data.vote_valid_lca_height =
2873 lca_height;
2874 self.arena[index].data.vote_valid = vote_valid;
2875 }
2876 }
2877 } else {
2878 self.arena[index].data.vote_valid_lca_height = lca_height;
2879 self.arena[index].data.vote_valid =
2880 self.arena[a].data.vote_valid;
2881 }
2882 }
2883 self.arena[me].data.vote_valid
2884 }
2885
2886 fn total_weight_in_own_epoch(
2889 &self, blockset_in_own_epoch: &Vec<usize>, genesis: usize,
2890 ) -> i128 {
2891 let gen_arena_index = if genesis != NULL {
2892 genesis
2893 } else {
2894 self.cur_era_genesis_block_arena_index
2895 };
2896 let gen_height = self.arena[gen_arena_index].height;
2897 let mut total_weight = 0 as i128;
2898 for index in blockset_in_own_epoch.iter() {
2899 if gen_arena_index != self.cur_era_genesis_block_arena_index {
2900 let height = self.arena[*index].height;
2901 if height < gen_height {
2902 continue;
2903 }
2904 let era_arena_index = self.ancestor_at(*index, gen_height);
2905 if gen_arena_index != era_arena_index {
2906 continue;
2907 }
2908 }
2909 total_weight += self.block_weight(*index);
2910 }
2911 total_weight
2912 }
2913
2914 fn recompute_metadata(
2916 &mut self, start_at: u64, mut to_update: HashSet<usize>,
2917 ) {
2918 self.pivot_chain_metadata
2919 .resize_with(self.pivot_chain.len(), Default::default);
2920 let pivot_height = self.get_pivot_height();
2921 for i in start_at..pivot_height {
2922 let me = self.get_pivot_block_arena_index(i);
2923 self.arena[me].data.last_pivot_in_past = i;
2924 let i_pivot_index = self.height_to_pivot_index(i);
2925 self.pivot_chain_metadata[i_pivot_index]
2926 .last_pivot_in_past_blocks
2927 .clear();
2928 self.pivot_chain_metadata[i_pivot_index]
2929 .last_pivot_in_past_blocks
2930 .insert(me);
2931 self.pivot_chain_metadata[i_pivot_index].past_weight =
2932 if i_pivot_index > 0 {
2933 let blockset = self
2934 .exchange_or_compute_blockset_in_own_view_of_epoch(
2935 me, None,
2936 );
2937 let blockset_weight = self.total_weight_in_own_epoch(
2938 &blockset,
2939 self.cur_era_genesis_block_arena_index,
2940 );
2941 self.exchange_or_compute_blockset_in_own_view_of_epoch(
2942 me,
2943 Some(blockset),
2944 );
2945 self.pivot_chain_metadata[i_pivot_index - 1].past_weight
2946 + blockset_weight
2947 + self.block_weight(me)
2948 } else {
2949 self.block_weight(me)
2950 };
2951 to_update.remove(&me);
2952 }
2953 let mut stack = Vec::new();
2954 let to_visit = to_update.clone();
2955 for i in &to_update {
2956 stack.push((0, *i));
2957 }
2958 while !stack.is_empty() {
2959 let (stage, me) = stack.pop().unwrap();
2960 if !to_visit.contains(&me) {
2961 continue;
2962 }
2963 let parent = self.arena[me].parent;
2964 if stage == 0 {
2965 if to_update.contains(&me) {
2966 to_update.remove(&me);
2967 stack.push((1, me));
2968 stack.push((0, parent));
2969 for referee in &self.arena[me].referees {
2970 stack.push((0, *referee));
2971 }
2972 }
2973 } else if stage == 1 && me != self.cur_era_genesis_block_arena_index
2974 {
2975 let mut last_pivot = if parent == NULL {
2976 0
2977 } else {
2978 self.arena[parent].data.last_pivot_in_past
2979 };
2980 for referee in &self.arena[me].referees {
2981 let x = self.arena[*referee].data.last_pivot_in_past;
2982 last_pivot = max(last_pivot, x);
2983 }
2984 self.arena[me].data.last_pivot_in_past = last_pivot;
2985 let last_pivot_index = self.height_to_pivot_index(last_pivot);
2986 self.pivot_chain_metadata[last_pivot_index]
2987 .last_pivot_in_past_blocks
2988 .insert(me);
2989 }
2990 }
2991 }
2992
2993 fn get_timer_chain_index(&self, me: usize) -> usize {
2994 if !self.arena[me].is_timer || self.arena[me].data.partial_invalid {
2995 return NULL;
2996 }
2997 if self.arena[me].data.ledger_view_timer_chain_height
2998 < self.cur_era_genesis_timer_chain_height
2999 {
3000 return NULL;
3003 }
3004 let timer_chain_index =
3005 (self.arena[me].data.ledger_view_timer_chain_height
3006 - self.cur_era_genesis_timer_chain_height) as usize;
3007 if self.timer_chain.len() > timer_chain_index
3008 && self.timer_chain[timer_chain_index] == me
3009 {
3010 timer_chain_index
3011 } else {
3012 NULL
3013 }
3014 }
3015
3016 fn compute_timer_chain_past_view_info(
3017 &self, parent: usize, referees: &Vec<usize>,
3018 ) -> (i128, usize) {
3019 let mut timer_longest_difficulty = 0;
3020 let mut longest_referee = parent;
3021 if parent != NULL {
3022 timer_longest_difficulty =
3023 self.arena[parent].data.past_view_timer_longest_difficulty
3024 + self.get_timer_difficulty(parent);
3025 }
3026 for referee in referees {
3027 let timer_difficulty =
3028 self.arena[*referee].data.past_view_timer_longest_difficulty
3029 + self.get_timer_difficulty(*referee);
3030 if longest_referee == NULL
3031 || ConsensusGraphInner::is_heavier(
3032 (timer_difficulty, &self.arena[*referee].hash),
3033 (
3034 timer_longest_difficulty,
3035 &self.arena[longest_referee].hash,
3036 ),
3037 )
3038 {
3039 timer_longest_difficulty = timer_difficulty;
3040 longest_referee = *referee;
3041 }
3042 }
3043 let last_timer_block_arena_index = if longest_referee == NULL
3044 || self.arena[longest_referee].is_timer
3045 && !self.arena[longest_referee].data.partial_invalid
3046 {
3047 longest_referee
3048 } else {
3049 self.arena[longest_referee]
3050 .data
3051 .past_view_last_timer_block_arena_index
3052 };
3053 (timer_longest_difficulty, last_timer_block_arena_index)
3054 }
3055
3056 fn compute_timer_chain_tuple(
3057 &self, parent: usize, referees: &Vec<usize>,
3058 anticone_opt: Option<&BitSet>,
3059 ) -> (u64, HashMap<usize, u64>, Vec<usize>, Vec<usize>) {
3060 let empty_set = BitSet::new();
3061 let anticone = if let Some(a) = anticone_opt {
3062 a
3063 } else {
3064 &empty_set
3065 };
3066 let mut tmp_chain = Vec::new();
3067 let mut tmp_chain_set = HashSet::new();
3068 let (_, past_view_last_timer_block_arena_index) =
3069 self.compute_timer_chain_past_view_info(parent, referees);
3070 let mut i = past_view_last_timer_block_arena_index;
3071 while i != NULL && self.get_timer_chain_index(i) == NULL {
3072 tmp_chain.push(i);
3073 tmp_chain_set.insert(i);
3074 i = self.arena[i].data.past_view_last_timer_block_arena_index;
3075 }
3076 tmp_chain.reverse();
3077 let fork_at;
3078 let fork_at_index;
3079 if i != NULL {
3080 fork_at = self.arena[i].data.ledger_view_timer_chain_height + 1;
3081 assert!(fork_at >= self.cur_era_genesis_timer_chain_height);
3082 fork_at_index =
3083 (fork_at - self.cur_era_genesis_timer_chain_height) as usize;
3084 } else {
3085 fork_at = self.cur_era_genesis_timer_chain_height;
3086 fork_at_index = 0;
3087 }
3088
3089 let mut res = HashMap::new();
3090 if fork_at_index < self.timer_chain.len() {
3091 debug!("New block parent = {} referees = {:?} not extending timer chain (len = {}), fork at timer chain height {}, timer chain index {}", parent, referees, self.timer_chain.len(), fork_at, fork_at_index);
3092 let start_point = if i == NULL {
3095 self.cur_era_genesis_block_arena_index
3096 } else {
3097 self.timer_chain[fork_at_index - 1]
3098 };
3099 let mut start_set = HashSet::new();
3100 start_set.insert(start_point);
3101 let visited: BitSet = get_future(
3102 start_set,
3103 |i| self.successor_edges(i as usize),
3105 |i| anticone.contains(i as u32),
3106 );
3107 let visited_in_order: Vec<usize> = topological_sort(
3108 visited,
3109 |i| {
3110 self.predecessor_edges(i as usize)
3111 .into_iter()
3112 .map(|i| i as u32)
3113 .collect()
3114 },
3115 |_| true,
3116 );
3117 for x in visited_in_order {
3118 let x = x as usize;
3119 let mut timer_chain_height = 0;
3120 for pred in &self.predecessor_edges(x) {
3121 let mut height = if let Some(v) = res.get(pred) {
3122 *v
3123 } else {
3124 self.arena[*pred].data.ledger_view_timer_chain_height
3125 };
3126 if tmp_chain_set.contains(pred)
3127 || self.get_timer_chain_index(*pred) < fork_at_index
3128 {
3129 height += 1;
3130 }
3131 if height > timer_chain_height {
3132 timer_chain_height = height;
3133 }
3134 }
3135 res.insert(x, timer_chain_height);
3136 }
3137 }
3138
3139 let mut tmp_lca = Vec::new();
3141 if tmp_chain.len() > self.timer_chain.len() - fork_at_index
3142 && self.timer_chain.len() - fork_at_index
3143 < self.inner_conf.timer_chain_beta as usize
3144 {
3145 let mut last_lca = match self.timer_chain_accumulative_lca.last() {
3146 Some(last_lca) => *last_lca,
3147 None => self.cur_era_genesis_block_arena_index,
3148 };
3149 let s = max(
3150 self.timer_chain.len(),
3151 self.inner_conf.timer_chain_beta as usize,
3152 );
3153 let e =
3154 min(tmp_chain.len(), self.inner_conf.timer_chain_beta as usize);
3155 for i in s..(fork_at_index + e) {
3156 let end = i - self.inner_conf.timer_chain_beta as usize;
3160 if end < self.inner_conf.timer_chain_beta as usize {
3161 tmp_lca.push(self.cur_era_genesis_block_arena_index);
3162 continue;
3163 }
3164 let mut lca = self.timer_chain[end];
3165 for j in
3166 (end - self.inner_conf.timer_chain_beta as usize + 1)..end
3167 {
3168 if lca == NULL {
3173 break;
3174 }
3175 lca = self.lca(lca, self.timer_chain[j]);
3176 }
3177 if lca != NULL
3187 && self.arena[last_lca].height < self.arena[lca].height
3188 {
3189 last_lca = lca;
3190 }
3191 tmp_lca.push(last_lca);
3192 }
3193 }
3194 if tmp_chain.len() > self.inner_conf.timer_chain_beta as usize {
3195 let mut last_lca = if let Some(lca) = tmp_lca.last() {
3196 *lca
3197 } else if fork_at_index == 0 {
3198 self.cur_era_genesis_block_arena_index
3199 } else {
3200 self.timer_chain_accumulative_lca[fork_at_index - 1]
3206 };
3207 for i in 0..(tmp_chain.len()
3208 - (self.inner_conf.timer_chain_beta as usize))
3209 {
3210 if fork_at_index + i + 1
3211 < self.inner_conf.timer_chain_beta as usize
3212 {
3213 tmp_lca.push(self.cur_era_genesis_block_arena_index)
3214 } else {
3215 let mut lca = tmp_chain[i];
3216 let s = if i < self.inner_conf.timer_chain_beta as usize - 1
3218 {
3219 0
3220 } else {
3221 i + 1 - self.inner_conf.timer_chain_beta as usize
3222 };
3223 for j in s..i {
3224 if lca == NULL {
3229 break;
3230 }
3231 lca = self.lca(lca, tmp_chain[j]);
3232 }
3233 for j in (fork_at_index + i + 1
3234 - self.inner_conf.timer_chain_beta as usize)
3235 ..fork_at_index
3236 {
3237 if lca == NULL {
3242 break;
3243 }
3244 lca = self.lca(lca, self.timer_chain[j]);
3245 }
3246 if lca != NULL
3256 && self.arena[last_lca].height < self.arena[lca].height
3257 {
3258 last_lca = lca;
3259 }
3260 tmp_lca.push(last_lca);
3261 }
3262 }
3263 }
3264
3265 (fork_at, res, tmp_lca, tmp_chain)
3266 }
3267
3268 fn update_timer_chain(&mut self, me: usize) {
3269 let (fork_at, res, extra_lca, tmp_chain) = self
3270 .compute_timer_chain_tuple(
3271 self.arena[me].parent,
3272 &self.arena[me].referees,
3273 None,
3274 );
3275
3276 let fork_at_index =
3277 (fork_at - self.cur_era_genesis_timer_chain_height) as usize;
3278 self.timer_chain.resize(fork_at_index + tmp_chain.len(), 0);
3279 let new_chain_lca_size = if self.timer_chain.len()
3280 > self.inner_conf.timer_chain_beta as usize
3281 {
3282 self.timer_chain.len() - self.inner_conf.timer_chain_beta as usize
3283 } else {
3284 0
3285 };
3286 self.timer_chain_accumulative_lca
3287 .resize(new_chain_lca_size, 0);
3288 for i in 0..tmp_chain.len() {
3289 self.timer_chain[fork_at_index + i] = tmp_chain[i];
3290 }
3291 for i in 0..extra_lca.len() {
3292 self.timer_chain_accumulative_lca
3293 [new_chain_lca_size - extra_lca.len() + i] = extra_lca[i];
3294 }
3295 if !res.contains_key(&me) {
3298 assert!(
3299 self.cur_era_genesis_timer_chain_height
3300 + self.timer_chain.len() as u64
3301 == fork_at
3302 );
3303 self.arena[me].data.ledger_view_timer_chain_height = fork_at;
3304 }
3305 for (k, v) in res {
3306 self.arena[k].data.ledger_view_timer_chain_height = v;
3307 }
3308 if self.arena[me].is_timer && !self.arena[me].data.partial_invalid {
3309 self.timer_chain.push(me);
3310 if self.timer_chain.len()
3311 >= 2 * self.inner_conf.timer_chain_beta as usize
3312 {
3313 let s = self.timer_chain.len()
3314 - 2 * self.inner_conf.timer_chain_beta as usize;
3315 let e = self.timer_chain.len()
3316 - self.inner_conf.timer_chain_beta as usize;
3317 let mut lca = self.timer_chain[e - 1];
3318 for i in s..(e - 1) {
3319 if lca == NULL {
3324 break;
3325 }
3326 lca = self.lca(lca, self.timer_chain[i]);
3327 }
3328 let last_lca =
3329 if let Some(x) = self.timer_chain_accumulative_lca.last() {
3330 *x
3331 } else {
3332 self.cur_era_genesis_block_arena_index
3333 };
3334 if lca != NULL
3344 && self.arena[last_lca].height < self.arena[lca].height
3345 {
3346 self.timer_chain_accumulative_lca.push(lca);
3347 } else {
3348 self.timer_chain_accumulative_lca.push(last_lca);
3349 }
3350 assert_eq!(
3351 self.timer_chain_accumulative_lca.len(),
3352 self.timer_chain.len()
3353 - self.inner_conf.timer_chain_beta as usize
3354 );
3355 } else if self.timer_chain.len()
3356 > self.inner_conf.timer_chain_beta as usize
3357 {
3358 self.timer_chain_accumulative_lca
3359 .push(self.cur_era_genesis_block_arena_index);
3360 }
3361 }
3362 debug!(
3363 "Timer chain updated to {:?} accumulated lca {:?}",
3364 self.timer_chain, self.timer_chain_accumulative_lca
3365 );
3366 }
3367
3368 pub fn total_processed_block_count(&self) -> u64 {
3369 self.sequence_number_of_block_entrance
3370 }
3371
3372 pub fn get_trusted_blame_block(
3373 &self, checkpoint_hash: &H256, plus_depth: usize,
3374 ) -> Option<H256> {
3375 let arena_index_opt = self.hash_to_arena_indices.get(checkpoint_hash);
3376 if arena_index_opt.is_none() {
3378 debug!(
3379 "get_trusted_blame_block: block {:?} not in consensus",
3380 checkpoint_hash
3381 );
3382 return None;
3383 }
3384 let arena_index = *arena_index_opt.unwrap();
3385 let pivot_index =
3386 self.height_to_pivot_index(self.arena[arena_index].height);
3387 if pivot_index >= self.pivot_chain.len()
3389 || self.pivot_chain[pivot_index] != arena_index
3390 {
3391 debug!(
3392 "get_trusted_blame_block: block {:?} not on pivot chain",
3393 checkpoint_hash
3394 );
3395 return None;
3396 }
3397 self.find_first_index_with_correct_state_of(
3398 pivot_index + plus_depth,
3399 None, 0, )
3402 .and_then(|index| Some(self.arena[self.pivot_chain[index]].hash))
3403 }
3404
3405 pub fn get_trusted_blame_block_for_snapshot(
3407 &self, snapshot_epoch_id: &EpochId,
3408 ) -> Option<H256> {
3409 self.get_trusted_blame_block(
3410 snapshot_epoch_id,
3411 self.data_man.get_snapshot_blame_plus_depth(),
3412 )
3413 }
3414
3415 pub fn get_to_sync_epoch_id(&self) -> EpochId {
3417 let height_to_sync = self.latest_snapshot_height();
3418 let epoch_to_sync = self.arena
3420 [self.pivot_chain[self.height_to_pivot_index(height_to_sync)]]
3421 .hash;
3422 epoch_to_sync
3423 }
3424
3425 fn latest_snapshot_height(&self) -> u64 { self.cur_era_stable_height }
3428
3429 fn collect_defer_blocks_missing_execution_commitments(
3430 &self, me: usize,
3431 ) -> Result<Vec<H256>, String> {
3432 let mut cur = self.get_deferred_state_arena_index(me)?;
3433 let mut waiting_blocks = Vec::new();
3434 debug!(
3435 "collect_blocks_missing_execution_commitments: me={}, height={}",
3436 me, self.arena[me].height
3437 );
3438 let state_boundary_height =
3441 self.data_man.state_availability_boundary.read().lower_bound;
3442 loop {
3443 let deferred_block_hash = self.arena[cur].hash;
3444
3445 if self
3446 .data_man
3447 .get_epoch_execution_commitment(&deferred_block_hash)
3448 .is_some()
3449 || self.arena[cur].height <= state_boundary_height
3450 {
3451 break;
3454 }
3455 waiting_blocks.push(deferred_block_hash);
3456 cur = self.arena[cur].parent;
3457 }
3458 waiting_blocks.reverse();
3459 Ok(waiting_blocks)
3460 }
3461
3462 fn compute_state_valid_and_blame_info(
3464 &mut self, me: usize, executor: &ConsensusExecutor,
3465 ) -> Result<(), String> {
3466 let mut blocks_to_compute = Vec::new();
3469 let mut cur = me;
3470 loop {
3475 if self.arena[cur].data.state_valid.is_some() {
3476 break;
3477 }
3478 blocks_to_compute.push(cur);
3484 cur = self.arena[cur].parent;
3485 }
3486 blocks_to_compute.reverse();
3487
3488 for index in blocks_to_compute {
3489 self.compute_state_valid_and_blame_info_for_block(index, executor)?;
3490 }
3491 Ok(())
3492 }
3493
3494 fn split_root(&mut self, me: usize) {
3495 let parent = self.arena[me].parent;
3496 assert!(parent != NULL);
3497 self.weight_tree.split_root(parent, me);
3498 self.adaptive_tree.split_root(parent, me);
3499 self.arena[me].parent = NULL;
3500 }
3501
3502 pub fn reset_epoch_number_in_epoch(&mut self, pivot_arena_index: usize) {
3503 self.set_epoch_number_in_epoch(pivot_arena_index, NULLU64);
3504 }
3505
3506 fn set_epoch_number_in_epoch(
3507 &mut self, pivot_arena_index: usize, epoch_number: u64,
3508 ) {
3509 assert!(!self.arena[pivot_arena_index].data.blockset_cleared);
3510 let block_set = self.exchange_or_compute_blockset_in_own_view_of_epoch(
3511 pivot_arena_index,
3512 None,
3513 );
3514 for idx in &block_set {
3515 self.arena[*idx].data.epoch_number = epoch_number
3516 }
3517 self.exchange_or_compute_blockset_in_own_view_of_epoch(
3518 pivot_arena_index,
3519 Some(block_set),
3520 );
3521 self.arena[pivot_arena_index].data.epoch_number = epoch_number;
3522 }
3523
3524 fn get_deferred_state_arena_index(
3525 &self, me: usize,
3526 ) -> Result<usize, String> {
3527 let height = self.arena[me].height;
3528 if height <= DEFERRED_STATE_EPOCH_COUNT {
3532 return Ok(self.cur_era_genesis_block_arena_index);
3533 }
3534 if self.cur_era_genesis_height + DEFERRED_STATE_EPOCH_COUNT > height {
3536 return Err(
3537 "Parent is too old for computing the deferred state".to_owned()
3538 );
3539 }
3540 let target_height = height - DEFERRED_STATE_EPOCH_COUNT;
3541 let pivot_idx = self.height_to_pivot_index(height);
3542 if pivot_idx < self.pivot_chain.len()
3544 && self.pivot_chain[pivot_idx] == me
3545 {
3546 return Ok(
3547 self.pivot_chain[self.height_to_pivot_index(target_height)]
3548 );
3549 } else {
3550 return Ok(self.ancestor_at(me, target_height));
3551 }
3552 }
3553
3554 pub fn recover_state_valid(&mut self) {
3558 let start_pivot_index =
3561 (self.data_man.state_availability_boundary.read().lower_bound
3562 - self.cur_era_genesis_height) as usize;
3563 if start_pivot_index >= self.pivot_chain.len() {
3564 return;
3567 }
3568 let start_epoch_hash =
3569 self.arena[self.pivot_chain[start_pivot_index]].hash;
3570 let maybe_trusted_blame_block =
3574 self.get_trusted_blame_block(&start_epoch_hash, 0);
3575 debug!("recover_state_valid: checkpoint={:?}, maybe_trusted_blame_block={:?}", start_epoch_hash, maybe_trusted_blame_block);
3576
3577 if let Some(trusted_blame_block) = maybe_trusted_blame_block {
3580 let mut cur = *self
3581 .hash_to_arena_indices
3582 .get(&trusted_blame_block)
3583 .unwrap();
3584 while cur != NULL {
3585 let blame = self
3586 .data_man
3587 .block_header_by_hash(&self.arena[cur].hash)
3588 .unwrap()
3589 .blame();
3590 for i in 0..=blame {
3596 self.arena[cur].data.state_valid = Some(i == 0);
3597 trace!(
3598 "recover_state_valid: index={} hash={} state_valid={}",
3599 cur,
3600 self.arena[cur].hash,
3601 i == 0
3602 );
3603 cur = self.arena[cur].parent;
3604 if cur == NULL {
3605 break;
3606 }
3607 }
3608 }
3609 } else {
3610 if start_epoch_hash != self.data_man.true_genesis.hash() {
3611 error!(
3612 "Fail to recover state_valid: start_epoch_hash={:?}",
3613 start_epoch_hash
3614 );
3615 }
3616 }
3617 }
3618
3619 pub fn block_node(&self, block_hash: &H256) -> Option<&ConsensusGraphNode> {
3620 self.hash_to_arena_indices
3621 .get(block_hash)
3622 .and_then(|arena_index| self.arena.get(*arena_index))
3623 }
3624
3625 pub fn best_terminals(
3630 &mut self, best_index: usize, ref_bound: usize,
3631 ) -> Vec<H256> {
3632 let pastset_tmp;
3633 let pastset = if let Some(s) = self.pastset_cache.get(best_index) {
3634 s
3635 } else {
3636 pastset_tmp = self.compute_pastset_brutal(best_index);
3637 &pastset_tmp
3638 };
3639
3640 let lca_height_cache = mem::replace(
3641 &mut self.best_terminals_lca_height_cache,
3642 Default::default(),
3643 );
3644
3645 let mut counter_map = FastHashMap::new();
3648 let mut queue = BinaryHeap::new();
3649 for hash in self.terminal_hashes.iter() {
3650 let a_idx = self.hash_to_arena_indices.get(hash).unwrap();
3651 let mut a_lca_height = NULLU64;
3652 if let Some(h) = lca_height_cache.get(a_idx) {
3653 if *h < self.best_terminals_reorg_height {
3654 a_lca_height = *h;
3655 }
3656 }
3657 if a_lca_height == NULLU64 {
3658 let a_lca = self.lca(*a_idx, best_index);
3659 a_lca_height = self.arena[a_lca].height;
3660 }
3661 self.best_terminals_lca_height_cache
3662 .insert(*a_idx, a_lca_height);
3663 queue.push((-(a_lca_height as i128), *a_idx));
3664 }
3665
3666 while queue.len() > ref_bound
3678 || queue
3679 .peek()
3680 .map_or(false, |(v, _)| *v == -(NULLU64 as i128))
3681 {
3682 let (_, idx) = queue.pop().unwrap();
3683 let parent = self.arena[idx].parent;
3684 if parent != NULL {
3685 if let Some(p) = counter_map.get_mut(&parent) {
3686 *p = *p + 1;
3687 } else if !pastset.contains(parent as u32) {
3688 counter_map.insert(parent, 1);
3689 }
3690 if let Some(p) = counter_map.get(&parent) {
3691 if *p
3692 == self.arena[parent].children.len()
3693 + self.arena[parent].referrers.len()
3694 {
3695 if self.arena[parent].era_block == NULL {
3700 queue.push((-(NULLU64 as i128), parent));
3701 } else {
3702 let mut a_lca_height = NULLU64;
3703 if let Some(h) = lca_height_cache.get(&parent) {
3704 if *h < self.best_terminals_reorg_height {
3705 a_lca_height = *h;
3706 }
3707 }
3708 if a_lca_height == NULLU64 {
3709 let a_lca = self.lca(parent, best_index);
3710 a_lca_height = self.arena[a_lca].height;
3711 }
3712 self.best_terminals_lca_height_cache
3713 .insert(parent, a_lca_height);
3714 queue.push((-(a_lca_height as i128), parent));
3715 }
3716 }
3717 }
3718 }
3719 for referee in &self.arena[idx].referees {
3720 if let Some(p) = counter_map.get_mut(referee) {
3721 *p = *p + 1;
3722 } else if !pastset.contains(*referee as u32) {
3723 counter_map.insert(*referee, 1);
3724 }
3725 if let Some(p) = counter_map.get(referee) {
3726 if *p
3727 == self.arena[*referee].children.len()
3728 + self.arena[*referee].referrers.len()
3729 {
3730 if self.arena[*referee].era_block == NULL {
3735 queue.push((-(NULLU64 as i128), *referee));
3736 } else {
3737 let mut a_lca_height = NULLU64;
3738 if let Some(h) = lca_height_cache.get(referee) {
3739 if *h < self.best_terminals_reorg_height {
3740 a_lca_height = *h;
3741 }
3742 }
3743 if a_lca_height == NULLU64 {
3744 let a_lca = self.lca(*referee, best_index);
3745 a_lca_height = self.arena[a_lca].height;
3746 }
3747 self.best_terminals_lca_height_cache
3748 .insert(*referee, a_lca_height);
3749 queue.push((-(a_lca_height as i128), *referee));
3750 }
3751 }
3752 }
3753 }
3754 }
3755 self.best_terminals_reorg_height = NULLU64;
3756 let bounded_hashes =
3757 queue.iter().map(|(_, b)| self.arena[*b].hash).collect();
3758 bounded_hashes
3759 }
3760
3761 pub fn finish_block_recovery(&mut self) { self.header_only = false; }
3762
3763 pub fn get_pivot_chain_and_weight(
3764 &self, height_range: Option<(u64, u64)>,
3765 ) -> Result<Vec<(H256, U256)>, String> {
3766 let min_height = self.get_cur_era_genesis_height();
3767 let max_height = self.arena[*self.pivot_chain.last().unwrap()].height;
3768 let (start, end) = height_range.unwrap_or((min_height, max_height));
3769 if start < min_height || end > max_height {
3770 bail!(
3771 "height_range out of bound: requested={:?} min={} max={}",
3772 height_range,
3773 min_height,
3774 max_height
3775 );
3776 }
3777
3778 let mut chain = Vec::new();
3779 for i in start..=end {
3780 let pivot_arena_index = self.get_pivot_block_arena_index(i);
3781 chain.push((
3782 self.arena[pivot_arena_index].hash.into(),
3783 (self.weight_tree.get(pivot_arena_index) as u64).into(),
3784 ));
3785 }
3786 Ok(chain)
3787 }
3788
3789 pub fn get_subtree(&self, root_block: &H256) -> Option<Vec<H256>> {
3791 let root_arena_index = *self.hash_to_arena_indices.get(root_block)?;
3792 let mut queue = VecDeque::new();
3793 let mut subtree = Vec::new();
3794 queue.push_back(root_arena_index);
3795 while let Some(i) = queue.pop_front() {
3796 subtree.push(self.arena[i].hash);
3797 for child in &self.arena[i].children {
3798 queue.push_back(*child);
3799 }
3800 }
3801 Some(subtree)
3802 }
3803
3804 pub fn get_next_pivot_decision(
3805 &self, parent_decision_hash: &H256, confirmed_height: u64,
3806 ) -> Option<(u64, H256)> {
3807 let r = match self.hash_to_arena_indices.get(parent_decision_hash) {
3808 None => {
3809 let new_decision_height = (confirmed_height.saturating_sub(
3813 self.inner_conf
3814 .pos_pivot_decision_defer_epoch_count(confirmed_height),
3815 )) / POS_TERM_EPOCHS
3816 * POS_TERM_EPOCHS;
3817 if new_decision_height <= self.cur_era_genesis_height {
3818 None
3819 } else {
3820 let new_decision_arena_index =
3821 self.get_pivot_block_arena_index(new_decision_height);
3822 Some((
3823 self.arena[new_decision_arena_index].height,
3824 self.arena[new_decision_arena_index].hash,
3825 ))
3826 }
3827 }
3828 Some(parent_decision) => {
3829 let parent_decision_height =
3830 self.arena[*parent_decision].height;
3831 assert_eq!(parent_decision_height % POS_TERM_EPOCHS, 0);
3832 if self.get_pivot_block_arena_index(parent_decision_height)
3834 == *parent_decision
3835 {
3836 let new_decision_height =
3839 (confirmed_height.saturating_sub(
3840 self.inner_conf
3841 .pos_pivot_decision_defer_epoch_count(
3842 confirmed_height,
3843 ),
3844 )) / POS_TERM_EPOCHS
3845 * POS_TERM_EPOCHS;
3846 if new_decision_height <= parent_decision_height {
3847 None
3848 } else {
3849 let new_decision_arena_index = self
3850 .get_pivot_block_arena_index(new_decision_height);
3851 Some((
3852 self.arena[new_decision_arena_index].height,
3853 self.arena[new_decision_arena_index].hash,
3854 ))
3855 }
3856 } else {
3857 None
3858 }
3859 }
3860 };
3861 debug!(
3862 "next_pivot_decision: parent={:?} return={:?}",
3863 parent_decision_hash, r
3864 );
3865 r
3866 }
3867
3868 pub fn validate_pivot_decision(
3869 &self, ancestor_hash: &H256, me_hash: &H256,
3870 ) -> bool {
3871 if ancestor_hash == me_hash {
3872 return true;
3873 }
3874 debug!(
3875 "validate_pivot_decision: ancestor={:?}, me={:?}",
3876 ancestor_hash, me_hash
3877 );
3878 match (
3879 self.hash_to_arena_indices.get(ancestor_hash),
3880 self.hash_to_arena_indices.get(me_hash),
3881 ) {
3882 (Some(ancestor), Some(me)) => {
3883 if self.arena[*me].height % POS_TERM_EPOCHS != 0 {
3884 return false;
3885 }
3886 self.ancestor_at(*me, self.arena[*ancestor].height) == *ancestor
3888 }
3889 (_, Some(_me)) => {
3895 if !self.header_only {
3897 warn!(
3898 "ancestor not in consensus graph: processed={}",
3899 self.pivot_block_processed(ancestor_hash)
3900 );
3901 }
3902 true
3905 }
3906 (_, _) => {
3907 if !self.header_only {
3909 warn!("ancestor and me are both not in consensus graph, processed={} {}", self.pivot_block_processed(ancestor_hash), self.pivot_block_processed(me_hash));
3910 }
3911 true
3912 }
3913 }
3914 }
3915
3916 fn get_pos_reference_pivot_decision(
3919 &self, block_hash: &H256,
3920 ) -> Result<H256, String> {
3921 let pos_reference = self
3922 .data_man
3923 .pos_reference_by_hash(block_hash)
3924 .ok_or("header exist".to_string())?
3925 .ok_or("pos reference checked in sync graph".to_string())?;
3926 self.pos_verifier
3927 .get_pivot_decision(&pos_reference)
3928 .ok_or("pos validity checked in sync graph".to_string())
3929 }
3930
3931 fn update_pos_pivot_decision(&mut self, me: usize) {
3932 let h = self.arena[me].hash;
3933 if let Ok(pivot_decision) = self.get_pos_reference_pivot_decision(&h) {
3934 let pivot_decision_height = self
3935 .data_man
3936 .block_height_by_hash(&pivot_decision)
3937 .expect("pos_reference checked");
3938 if pivot_decision_height > self.best_pos_pivot_decision.1 {
3939 self.best_pos_pivot_decision =
3940 (pivot_decision, pivot_decision_height);
3941 }
3942 }
3943 }
3944
3945 pub fn choose_correct_parent(
3948 &mut self, parent_arena_index: usize, referee_indices: Vec<usize>,
3949 pos_reference: Option<PosBlockId>,
3950 ) -> usize {
3951 let parent_anticone_opt = self.anticone_cache.get(parent_arena_index);
3953 let mut anticone;
3954 if parent_anticone_opt.is_none() {
3955 anticone = consensus_new_block_handler::ConsensusNewBlockHandler::compute_anticone_bruteforce(
3956 self, parent_arena_index,
3957 );
3958 for i in self.compute_future_bitset(parent_arena_index) {
3959 anticone.add(i);
3960 }
3961 } else {
3962 anticone = self.compute_future_bitset(parent_arena_index);
3963 for index in parent_anticone_opt.unwrap() {
3964 anticone.add(*index as u32);
3965 }
3966 }
3967 let mut my_past = BitSet::new();
3968 let mut queue: VecDeque<usize> = VecDeque::new();
3969 for index in &referee_indices {
3970 queue.push_back(*index);
3971 }
3972 while let Some(index) = queue.pop_front() {
3973 if my_past.contains(index as u32) {
3974 continue;
3975 }
3976 my_past.add(index as u32);
3977 let idx_parent = self.arena[index].parent;
3978 if idx_parent != NULL {
3979 if anticone.contains(idx_parent as u32)
3980 || self.arena[idx_parent].era_block == NULL
3981 {
3982 queue.push_back(idx_parent);
3983 }
3984 }
3985 for referee in &self.arena[index].referees {
3986 if anticone.contains(*referee as u32)
3987 || self.arena[*referee].era_block == NULL
3988 {
3989 queue.push_back(*referee);
3990 }
3991 }
3992 }
3993 for index in my_past.drain() {
3994 anticone.remove(index);
3995 }
3996
3997 let mut anticone_barrier = BitSet::new();
3998 for index in (&anticone).iter() {
3999 let parent = self.arena[index as usize].parent as u32;
4000 if self.arena[index as usize].era_block != NULL
4001 && !anticone.contains(parent)
4002 {
4003 anticone_barrier.add(index);
4004 }
4005 }
4006
4007 let timer_chain_tuple = self.compute_timer_chain_tuple(
4008 parent_arena_index,
4009 &referee_indices,
4010 Some(&anticone),
4011 );
4012
4013 self.choose_correct_parent_impl(
4014 parent_arena_index,
4015 &anticone_barrier,
4016 &timer_chain_tuple,
4017 pos_reference,
4018 )
4019 }
4020
4021 fn choose_correct_parent_impl(
4022 &mut self, parent: usize, anticone_barrier: &BitSet,
4023 timer_chain_tuple: &(u64, HashMap<usize, u64>, Vec<usize>, Vec<usize>),
4024 pos_reference: Option<PosBlockId>,
4025 ) -> usize {
4026 let force_confirm =
4027 self.compute_block_force_confirm(timer_chain_tuple, pos_reference);
4028 let force_confirm_height = self.arena[force_confirm].height;
4029
4030 if self.ancestor_at(parent, force_confirm_height) == force_confirm {
4031 return parent;
4033 }
4034
4035 let mut weight_delta = HashMap::new();
4036
4037 for index in anticone_barrier.iter() {
4038 assert!(!self.is_legacy_block(index as usize));
4039 weight_delta
4040 .insert(index as usize, self.weight_tree.get(index as usize));
4041 }
4042
4043 for (index, delta) in &weight_delta {
4044 self.weight_tree.path_apply(*index, -*delta);
4045 }
4046
4047 let mut new_parent = force_confirm;
4048 while !self.arena[new_parent].children.is_empty() {
4051 let mut children = self.arena[new_parent].children.clone();
4052 let mut pivot = children.pop().expect("non-empty");
4053 for child in children {
4054 if ConsensusGraphInner::is_heavier(
4055 (self.weight_tree.get(child), &self.arena[child].hash),
4056 (self.weight_tree.get(pivot), &self.arena[pivot].hash),
4057 ) {
4058 pivot = child;
4059 }
4060 }
4061 new_parent = pivot;
4062 }
4063
4064 for (index, delta) in &weight_delta {
4065 self.weight_tree.path_apply(*index, *delta);
4066 }
4067
4068 new_parent
4069 }
4070
4071 pub fn pivot_block_processed(&self, pivot_hash: &H256) -> bool {
4072 if let Some(height) = self.data_man.block_height_by_hash(pivot_hash) {
4073 if let Ok(epoch_hash) =
4074 self.get_pivot_hash_from_epoch_number(height)
4075 {
4076 if epoch_hash == *pivot_hash {
4077 return true;
4078 } else {
4079 debug!(
4080 "pivot_block_processed: {:?} is not on pivot chain",
4081 pivot_hash
4082 );
4083 }
4084 } else {
4085 debug!("pivot_block_processed: epoch not processed height={:?} pivot={:?}", height, pivot_hash);
4086 }
4087 } else {
4088 debug!("pivot_block_processed: {:?} is not processed", pivot_hash);
4089 }
4090 false
4091 }
4092
4093 pub fn is_confirmed_by_pos(&self, block_hash: &H256) -> bool {
4101 let epoch_number = match self.get_block_epoch_number(block_hash) {
4102 Some(epoch_number) => epoch_number,
4103 None => match self
4104 .data_man
4105 .block_execution_result_by_hash_from_db(block_hash)
4106 {
4107 Some(r) => {
4108 let epoch_hash = r.0;
4109 self.data_man
4110 .block_height_by_hash(&epoch_hash)
4111 .expect("executed header exists")
4112 }
4113 None => return false,
4115 },
4116 };
4117 epoch_number <= self.best_pos_pivot_decision.1
4119 }
4120
4121 pub fn latest_epoch_confirmed_by_pos(&self) -> &(H256, u64) {
4123 &self.best_pos_pivot_decision
4124 }
4125
4126 pub fn confirmed_height_for_state_maintenance(
4130 &self, confirmed_height: u64,
4131 ) -> u64 {
4132 std::cmp::min(confirmed_height, self.best_pos_pivot_decision.1)
4133 }
4134}
4135
4136impl pow::ConsensusProvider for &ConsensusGraphInner {
4137 fn num_blocks_in_epoch(&self, h: &H256) -> u64 {
4138 let index = self.hash_to_arena_indices.get(h).unwrap(); let parent = self.arena[*index].parent;
4140 (self.arena[*index].past_num_blocks
4141 - self.arena[parent].past_num_blocks) as u64
4142 }
4143
4144 fn block_header_by_hash(&self, hash: &H256) -> Option<Arc<BlockHeader>> {
4145 self.data_man.block_header_by_hash(hash)
4146 }
4147}
4148
4149impl Graph for ConsensusGraphInner {
4150 type NodeIndex = usize;
4151}
4152
4153impl TreeGraph for ConsensusGraphInner {
4154 fn parent(&self, node_index: Self::NodeIndex) -> Option<Self::NodeIndex> {
4155 if self.arena[node_index].parent != NULL {
4156 Some(self.arena[node_index].parent)
4157 } else {
4158 None
4159 }
4160 }
4161
4162 fn referees(&self, node_index: Self::NodeIndex) -> Vec<Self::NodeIndex> {
4163 self.arena[node_index].referees.clone()
4164 }
4165}
4166
4167impl RichTreeGraph for ConsensusGraphInner {
4168 fn children(&self, node_index: Self::NodeIndex) -> Vec<Self::NodeIndex> {
4169 self.arena[node_index].children.clone()
4170 }
4171
4172 fn referrers(&self, node_index: Self::NodeIndex) -> Vec<Self::NodeIndex> {
4173 self.arena[node_index].referrers.clone()
4174 }
4175}
4176
4177impl StateMaintenanceTrait for ConsensusGraphInner {
4178 fn get_pivot_hash_from_epoch_number(
4179 &self, epoch_number: u64,
4180 ) -> Result<EpochId, String> {
4181 ConsensusGraphInner::get_pivot_hash_from_epoch_number(
4182 self,
4183 epoch_number,
4184 )
4185 .map_err(|e| e.to_string())
4186 }
4187
4188 fn get_epoch_execution_commitment_with_db(
4189 &self, block_hash: &EpochId,
4190 ) -> Option<EpochExecutionCommitment> {
4191 self.data_man
4192 .get_epoch_execution_commitment_with_db(block_hash)
4193 }
4194}
4195
4196#[cfg(test)]
4197mod blame_underflow_tests {
4198 use super::ConsensusGraphInner;
4199
4200 fn naive_prev(
4203 trusted_index: usize, blame: u32, from: usize,
4204 ) -> Option<usize> {
4205 let prev = trusted_index - blame as usize - 1;
4206 if prev >= from {
4207 Some(prev)
4208 } else {
4209 None
4210 }
4211 }
4212
4213 #[test]
4214 fn blame_prev_trusted_pivot_index_matches_naive_on_honest_inputs() {
4215 for &(trusted_index, blame, from) in &[
4216 (100usize, 0u32, 10usize),
4217 (100, 3, 10),
4218 (100, 89, 10), (100, 90, 10), ] {
4221 assert_eq!(
4222 ConsensusGraphInner::prev_trusted_pivot_index(
4223 trusted_index,
4224 blame,
4225 from
4226 ),
4227 naive_prev(trusted_index, blame, from),
4228 "trusted_index={trusted_index} blame={blame} from={from}",
4229 );
4230 }
4231 }
4232
4233 #[test]
4234 fn blame_prev_trusted_pivot_index_no_panic_on_malicious_blame() {
4235 assert_eq!(
4238 ConsensusGraphInner::prev_trusted_pivot_index(5, 5, 0),
4239 None
4240 );
4241 assert_eq!(
4242 ConsensusGraphInner::prev_trusted_pivot_index(5, 10, 0),
4243 None
4244 );
4245 assert_eq!(
4246 ConsensusGraphInner::prev_trusted_pivot_index(0, u32::MAX, 0),
4247 None
4248 );
4249 assert_eq!(
4250 ConsensusGraphInner::prev_trusted_pivot_index(3, u32::MAX, 0),
4251 None
4252 );
4253 }
4254
4255 #[test]
4256 fn blame_covered_start_height_matches_naive_on_honest_inputs() {
4257 for &(height, blame) in &[(100u64, 0u32), (100, 3), (100, 94)] {
4258 assert_eq!(
4259 ConsensusGraphInner::blame_covered_start_height(height, blame),
4260 Some(height - blame as u64 - 1),
4261 "height={height} blame={blame}",
4262 );
4263 }
4264 }
4265
4266 #[test]
4267 fn blame_covered_start_height_no_panic_on_malicious_blame() {
4268 assert_eq!(ConsensusGraphInner::blame_covered_start_height(5, 5), None);
4270 assert_eq!(
4271 ConsensusGraphInner::blame_covered_start_height(5, 10),
4272 None
4273 );
4274 assert_eq!(ConsensusGraphInner::blame_covered_start_height(0, 0), None);
4275 assert_eq!(
4276 ConsensusGraphInner::blame_covered_start_height(3, u32::MAX),
4277 None
4278 );
4279 }
4280}