11use std:: {
22 collections:: { BTreeMap , HashMap } ,
33 sync:: Arc ,
4+ time:: Duration ,
45} ;
56
67use rand:: { RngCore , SeedableRng } ;
@@ -30,6 +31,8 @@ fn new_sim_config(topology: RawTopology) -> Arc<SimConfiguration> {
3031 value : tx_size as f64 ,
3132 } ;
3233 params. tx_max_size_bytes = tx_size;
34+ // it takes two votes to certify an EB
35+ params. vote_threshold = 2 ;
3336 let topology = topology. into ( ) ;
3437 Arc :: new ( SimConfiguration :: build ( params, topology) . unwrap ( ) )
3538}
@@ -154,6 +157,14 @@ impl TestDriver {
154157 tx
155158 }
156159
160+ pub fn produce_txs < const N : usize > (
161+ & mut self ,
162+ node_id : NodeId ,
163+ conflict : bool ,
164+ ) -> [ Arc < Transaction > ; N ] {
165+ [ ( ) ; N ] . map ( |_| self . produce_tx ( node_id, conflict) )
166+ }
167+
157168 pub fn win_next_rb_lottery ( & mut self , node_id : NodeId , result : u64 ) {
158169 self . lottery
159170 . get ( & node_id)
@@ -249,6 +260,13 @@ impl TestDriver {
249260 self . expect_cpu_task ( node, CpuTask :: EBBlockValidated ( eb, self . time . now ( ) ) ) ;
250261 }
251262
263+ pub fn expect_vote_bundle_sent ( & mut self , from : NodeId , to : NodeId , votes : Arc < VoteBundle > ) {
264+ self . expect_message ( from, to, Message :: AnnounceVotes ( votes. id ) ) ;
265+ self . expect_message ( to, from, Message :: RequestVotes ( votes. id ) ) ;
266+ self . expect_message ( from, to, Message :: Votes ( votes. clone ( ) ) ) ;
267+ self . expect_cpu_task ( to, CpuTask :: VTBundleValidated ( from, votes) ) ;
268+ }
269+
252270 pub fn expect_message (
253271 & mut self ,
254272 from : NodeId ,
@@ -394,12 +412,10 @@ fn should_produce_rbs_and_ebs() {
394412 let node2 = sim. id_for ( "node-2" ) ;
395413
396414 // Node 1 produces three transactions, Node 2 should request them all
397- let tx1_1 = sim. produce_tx ( node1, false ) ;
398- sim. expect_tx_sent ( node1, node2, tx1_1. clone ( ) ) ;
399- let tx1_2 = sim. produce_tx ( node1, false ) ;
400- sim. expect_tx_sent ( node1, node2, tx1_2. clone ( ) ) ;
401- let tx1_3 = sim. produce_tx ( node1, false ) ;
402- sim. expect_tx_sent ( node1, node2, tx1_3. clone ( ) ) ;
415+ let [ tx1_1, tx1_2, tx1_3] = sim. produce_txs ( node1, false ) ;
416+ for tx in [ & tx1_1, & tx1_2, & tx1_3] {
417+ sim. expect_tx_sent ( node1, node2, tx. clone ( ) ) ;
418+ }
403419
404420 sim. win_next_rb_lottery ( node1, 0 ) ;
405421 sim. next_slot ( ) ;
@@ -451,9 +467,7 @@ fn should_repropagate_conflicting_transactions_from_eb() {
451467 let node3 = sim. id_for ( "node-3" ) ;
452468
453469 // Node 1 produces 3 transactions
454- let tx1_1 = sim. produce_tx ( node1, false ) ;
455- let tx1_2 = sim. produce_tx ( node1, false ) ;
456- let tx1_3 = sim. produce_tx ( node1, false ) ;
470+ let [ tx1_1, tx1_2, tx1_3] = sim. produce_txs ( node1, false ) ;
457471
458472 // Node 2 produces a transaction which conflicts with Node 1's final transaction
459473 let tx2 = sim. produce_tx ( node2, true ) ;
@@ -501,9 +515,7 @@ fn should_vote_for_eb() {
501515 let node1 = sim. id_for ( "node-1" ) ;
502516 let node2 = sim. id_for ( "node-2" ) ;
503517
504- let txs = ( 0 ..3 )
505- . map ( |_| sim. produce_tx ( node1, false ) )
506- . collect :: < Vec < _ > > ( ) ;
518+ let txs: [ _ ; 3 ] = sim. produce_txs ( node1, false ) ;
507519 for tx in & txs {
508520 sim. expect_tx_sent ( node1, node2, tx. clone ( ) ) ;
509521 }
@@ -521,3 +533,57 @@ fn should_vote_for_eb() {
521533 let vote = sim. expect_cpu_task_matching ( node2, is_new_vote_task) ;
522534 assert_eq ! ( * vote. ebs. first_key_value( ) . unwrap( ) . 0 , eb. id( ) ) ;
523535}
536+
537+ #[ test]
538+ fn should_not_include_tx_twice ( ) {
539+ let topology = new_topology ( vec ! [
540+ ( "node-1" , new_node( Some ( 1000 ) , vec![ "node-2" ] ) ) ,
541+ ( "node-2" , new_node( Some ( 1000 ) , vec![ "node-1" ] ) ) ,
542+ ] ) ;
543+ let mut sim = TestDriver :: new ( topology) ;
544+ let node1 = sim. id_for ( "node-1" ) ;
545+ let node2 = sim. id_for ( "node-2" ) ;
546+
547+ let [ rb_tx1, rb_tx2, eb_tx] = sim. produce_txs ( node1, false ) ;
548+ for tx in [ & rb_tx1, & rb_tx2, & eb_tx] {
549+ sim. expect_tx_sent ( node1, node2, tx. clone ( ) ) ;
550+ }
551+
552+ sim. win_next_vote_lottery ( node1, 0 ) ;
553+ sim. win_next_vote_lottery ( node2, 0 ) ;
554+
555+ // Node 1 produces an RB containing two transactions, and an EB containing a third
556+ sim. win_next_rb_lottery ( node1, 0 ) ;
557+ sim. next_slot ( ) ;
558+ let ( rb, eb) = sim. expect_cpu_task_matching ( node1, is_new_rb_task) ;
559+ let eb = eb. expect ( "node did not produce EB" ) ;
560+ assert ! ( eb. txs. contains( & eb_tx) ) ;
561+
562+ // Node 2 receives and validates the RB and EB
563+ sim. expect_rb_and_eb_sent ( node1, node2, rb. clone ( ) , Some ( eb. clone ( ) ) ) ;
564+ sim. expect_eb_validated ( node2, eb. clone ( ) ) ;
565+
566+ // Nodes 1 and 2 both vote for the EB
567+ sim. advance_time_to ( sim. now ( ) + ( sim. config . header_diffusion_time * 3 ) ) ;
568+ let votes_1 = sim. expect_cpu_task_matching ( node1, is_new_vote_task) ;
569+ sim. expect_vote_bundle_sent ( node1, node2, votes_1) ;
570+ let votes_2 = sim. expect_cpu_task_matching ( node2, is_new_vote_task) ;
571+ sim. expect_vote_bundle_sent ( node2, node1, votes_2) ;
572+
573+ // After enough time has elapsed to include the EB in a new RB, Node 2 mints a new RB
574+ sim. advance_time_to (
575+ sim. now ( )
576+ + Duration :: from_secs ( sim. config . linear_diffuse_stage_length )
577+ + Duration :: from_secs ( sim. config . linear_vote_stage_length ) ,
578+ ) ;
579+ sim. win_next_rb_lottery ( node2, 0 ) ;
580+ sim. next_slot ( ) ;
581+ let ( rb, new_eb) = sim. expect_cpu_task_matching ( node2, is_new_rb_task) ;
582+
583+ // This RB endorses the previous EB (including its transaction on the chain)
584+ assert_eq ! ( rb. endorsement. as_ref( ) . map( |e| e. eb) , Some ( eb. id( ) ) ) ;
585+
586+ // And it does not include any transactions of its own
587+ assert ! ( rb. transactions. is_empty( ) ) ;
588+ assert_eq ! ( new_eb, None ) ;
589+ }
0 commit comments