@@ -13,7 +13,7 @@ use crate::{
1313 test_utils:: placeholder_ledger_info,
1414} ;
1515use aptos_consensus_types:: common:: Author ;
16- use aptos_infallible:: RwLock ;
16+ use aptos_infallible:: { Mutex , RwLock } ;
1717use aptos_types:: {
1818 aggregate_signature:: AggregateSignature , epoch_state:: EpochState ,
1919 validator_verifier:: random_validator_verifier,
@@ -23,25 +23,50 @@ use proptest::prelude::*;
2323use std:: sync:: Arc ;
2424
2525/// Generate a virtual dag that first layer represents round
26- /// second layer represents nodes
27- /// third layer is a bitmask that represents strong links (true => linked, false => not linked)
26+ /// second layer represents nodes, Some => node exist, None => not exist
27+ /// third layer is a bitmask that represents compressed strong links (true => linked, false => not linked),
28+ /// the bitmask ignores non-existing nodes
2829fn generate_virtual_dag (
29- num_validators : usize ,
30+ num_nodes : usize ,
31+ num_holes : usize ,
3032 round : u64 ,
31- ) -> impl Strategy < Value = Vec < Vec < Vec < bool > > > > {
32- let f = ( num_validators - 1 ) / 3 ;
33- let bitmask: Vec < bool > = std:: iter:: repeat ( false )
34- . take ( f)
35- . chain ( std:: iter:: repeat ( true ) . take ( num_validators - f) )
33+ ) -> impl Strategy < Value = Vec < Vec < Option < Vec < bool > > > > > {
34+ let num_strong_links = num_nodes * 2 / 3 + 1 ;
35+ assert ! ( num_holes <= num_nodes - num_strong_links) ;
36+ // This only has length of num_nodes - num_holes which ignores holes
37+ let strong_links: Vec < bool > = std:: iter:: repeat ( false )
38+ . take ( num_nodes - num_holes - num_strong_links)
39+ . chain ( std:: iter:: repeat ( true ) . take ( num_strong_links) )
3640 . collect ( ) ;
41+ // This has length of num_nodes
42+ let nodes: Vec < bool > = std:: iter:: repeat ( false )
43+ . take ( num_holes)
44+ . chain ( std:: iter:: repeat ( true ) . take ( num_nodes - num_holes) )
45+ . collect ( ) ;
46+ // For every round, we shuffle the nodes bitmask to generate holes
47+ // For every node, we shuffle the compressed strong links if the node is not a hole
3748 proptest:: collection:: vec (
38- proptest:: collection:: vec ( Just ( bitmask) . prop_shuffle ( ) , num_validators) ,
49+ Just ( nodes) . prop_shuffle ( ) . prop_flat_map ( move |nodes| {
50+ nodes
51+ . into_iter ( )
52+ . map ( |exist| {
53+ if exist {
54+ Just ( strong_links. clone ( ) )
55+ . prop_shuffle ( )
56+ . prop_map ( Some )
57+ . boxed ( )
58+ } else {
59+ Just ( None ) . boxed ( )
60+ }
61+ } )
62+ . collect :: < Vec < _ > > ( )
63+ } ) ,
3964 round as usize ,
4065 )
4166}
4267
43- /// Generate `num_per ` random permutations of how nodes are processed by the order rule
44- /// Imagine we have 4 nodes, this generates a permutation of [0, 1, 2, 3]
68+ /// Generate `num_perm ` random permutations of how nodes are processed by the order rule
69+ /// Imagine we have 4 nodes, this generates `num_perm` permutations of [0, 1, 2, 3]
4570fn generate_permutations (
4671 num_perm : usize ,
4772 total_number : usize ,
@@ -52,25 +77,39 @@ fn generate_permutations(
5277 )
5378}
5479
55- fn generate_dag_nodes ( dag : & [ Vec < Vec < bool > > ] , validators : & [ Author ] ) -> Vec < Vec < CertifiedNode > > {
80+ /// Generate certified nodes for dag given the virtual dag
81+ fn generate_dag_nodes (
82+ dag : & [ Vec < Option < Vec < bool > > > ] ,
83+ validators : & [ Author ] ,
84+ ) -> Vec < Vec < Option < CertifiedNode > > > {
5685 let mut nodes = vec ! [ ] ;
57- let mut previous_round: Vec < CertifiedNode > = vec ! [ ] ;
86+ let mut previous_round: Vec < Option < CertifiedNode > > = vec ! [ ] ;
5887 for ( round, round_nodes) in dag. iter ( ) . enumerate ( ) {
5988 let mut nodes_at_round = vec ! [ ] ;
6089 for ( idx, author) in validators. iter ( ) . enumerate ( ) {
61- let bitmask = & round_nodes[ idx] ;
62- let parents: Vec < _ > = previous_round
63- . iter ( )
64- . enumerate ( )
65- . filter ( |( idx, _) | bitmask[ * idx] )
66- . map ( |( _, node) | {
67- NodeCertificate :: new ( node. metadata ( ) . clone ( ) , AggregateSignature :: empty ( ) )
68- } )
69- . collect ( ) ;
70- if round > 1 {
71- assert_eq ! ( parents. len( ) , NUM_VALIDATORS * 2 / 3 + 1 ) ;
90+ if let Some ( bitmask) = & round_nodes[ idx] {
91+ // the bitmask is compressed (without the holes), we need to flatten the previous round nodes
92+ // to match the index
93+ let parents: Vec < _ > = previous_round
94+ . iter ( )
95+ . flatten ( )
96+ . enumerate ( )
97+ . filter ( |( idx, _) | * bitmask. get ( * idx) . unwrap_or ( & false ) )
98+ . map ( |( _, node) | {
99+ NodeCertificate :: new ( node. metadata ( ) . clone ( ) , AggregateSignature :: empty ( ) )
100+ } )
101+ . collect ( ) ;
102+ if round > 1 {
103+ assert_eq ! ( parents. len( ) , NUM_VALIDATORS * 2 / 3 + 1 ) ;
104+ }
105+ nodes_at_round. push ( Some ( new_certified_node (
106+ ( round + 1 ) as u64 ,
107+ * author,
108+ parents,
109+ ) ) ) ;
110+ } else {
111+ nodes_at_round. push ( None ) ;
72112 }
73- nodes_at_round. push ( new_certified_node ( ( round + 1 ) as u64 , * author, parents) ) ;
74113 }
75114 previous_round = nodes_at_round. clone ( ) ;
76115 nodes. push ( nodes_at_round) ;
@@ -93,49 +132,56 @@ fn create_order_rule(
93132 )
94133}
95134
135+ const NUM_HOLES : usize = 1 ;
96136const NUM_VALIDATORS : usize = 4 ;
97137const NUM_ROUNDS : u64 = 50 ;
98138const NUM_PERMUTATION : usize = 100 ;
99139
100140proptest ! {
101141 #[ test]
102142 fn test_order_rule(
103- dag in generate_virtual_dag( NUM_VALIDATORS , NUM_ROUNDS ) ,
104- sequences in generate_permutations( NUM_PERMUTATION , NUM_VALIDATORS * NUM_ROUNDS as usize )
143+ mut dag_with_holes in generate_virtual_dag( NUM_VALIDATORS , NUM_HOLES , NUM_ROUNDS ) ,
144+ mut dag in generate_virtual_dag( NUM_VALIDATORS , 0 , NUM_ROUNDS ) ,
145+ sequences in generate_permutations( NUM_PERMUTATION , ( NUM_VALIDATORS - NUM_HOLES ) * NUM_ROUNDS as usize )
105146 ) {
106147 let ( _, validator_verifier) = random_validator_verifier( NUM_VALIDATORS , None , false ) ;
107148 let validators = validator_verifier. get_ordered_account_addresses( ) ;
108149 let author_indexes = validator_verifier. address_to_validator_index( ) . clone( ) ;
150+ dag. append( & mut dag_with_holes) ;
109151 let nodes = generate_dag_nodes( & dag, & validators) ;
110152 let epoch_state = Arc :: new( EpochState {
111153 epoch: 1 ,
112154 verifier: validator_verifier,
113155 } ) ;
114156 let mut dag = Dag :: new( epoch_state. clone( ) , Arc :: new( MockStorage :: new( ) ) ) ;
115157 for round_nodes in & nodes {
116- for node in round_nodes {
158+ for node in round_nodes. iter ( ) . flatten ( ) {
117159 dag. add_node( node. clone( ) ) . unwrap( ) ;
118160 }
119161 }
120- let flatten_nodes: Vec <_> = nodes. into_iter( ) . flatten( ) . collect( ) ;
121- let mut all_ordered = vec![ ] ;
122- for seq in sequences {
123- let dag = Arc :: new( RwLock :: new( dag. clone( ) ) ) ;
124- let ( mut order_rule, mut receiver) = create_order_rule( epoch_state. clone( ) , dag. clone( ) ) ;
125- for idx in seq {
126- order_rule. process_new_node( & flatten_nodes[ idx] ) ;
162+ let flatten_nodes: Vec <_> = nodes. into_iter( ) . flatten( ) . flatten( ) . collect( ) ;
163+ let all_ordered = Arc :: new( Mutex :: new( vec![ ] ) ) ;
164+ rayon:: scope( |s| {
165+ for seq in sequences {
166+ s. spawn( |_| {
167+ let dag = Arc :: new( RwLock :: new( dag. clone( ) ) ) ;
168+ let ( mut order_rule, mut receiver) = create_order_rule( epoch_state. clone( ) , dag) ;
169+ for idx in seq {
170+ order_rule. process_new_node( & flatten_nodes[ idx] ) ;
171+ }
172+ let mut ordered = vec![ ] ;
173+ while let Ok ( Some ( mut ordered_nodes) ) = receiver. try_next( ) {
174+ ordered. append( & mut ordered_nodes) ;
175+ }
176+ all_ordered. lock( ) . push( ordered) ;
177+ } ) ;
127178 }
128- let mut ordered = vec![ ] ;
129- while let Ok ( Some ( mut ordered_nodes) ) = receiver. try_next( ) {
130- ordered. append( & mut ordered_nodes) ;
131- }
132- all_ordered. push( ordered) ;
133- }
179+ } ) ;
134180 let display = |node: & Arc <CertifiedNode >| {
135181 ( node. metadata( ) . round( ) , * author_indexes. get( node. metadata( ) . author( ) ) . unwrap( ) )
136182 } ;
137- let longest: Vec <_> = all_ordered. iter( ) . max_by( |v1, v2| v1. len( ) . cmp( & v2. len( ) ) ) . unwrap( ) . iter( ) . map( display) . collect( ) ;
138- for ordered in all_ordered {
183+ let longest: Vec <_> = all_ordered. lock ( ) . iter( ) . max_by( |v1, v2| v1. len( ) . cmp( & v2. len( ) ) ) . unwrap( ) . iter( ) . map( display) . collect( ) ;
184+ for ordered in all_ordered. lock ( ) . iter ( ) {
139185 let a: Vec <_> = ordered. iter( ) . map( display) . collect( ) ;
140186 assert_eq!( a, longest[ ..a. len( ) ] ) ;
141187 }
0 commit comments