@@ -17,9 +17,16 @@ use crate::{
1717} ;
1818
1919fn new_sim_config ( topology : RawTopology ) -> Arc < SimConfiguration > {
20- let params =
20+ let mut params: crate :: config :: RawParameters =
2121 serde_yaml:: from_slice ( include_bytes ! ( "../../../../parameters/config.default.yaml" ) )
2222 . unwrap ( ) ;
23+ params. leios_variant = crate :: config:: LeiosVariant :: LinearWithTxReferences ;
24+ // every transaction fills up exactly half of an RB
25+ let tx_size = params. rb_body_max_size_bytes / 2 ;
26+ params. tx_size_bytes_distribution = crate :: config:: DistributionConfig :: Constant {
27+ value : tx_size as f64 ,
28+ } ;
29+ params. tx_max_size_bytes = tx_size;
2330 let topology = topology. into ( ) ;
2431 Arc :: new ( SimConfiguration :: build ( params, topology) . unwrap ( ) )
2532}
@@ -154,6 +161,49 @@ impl TestDriver {
154161 }
155162 }
156163
164+ pub fn expect_tx_sent ( & mut self , from : NodeId , to : NodeId , tx : Arc < Transaction > ) {
165+ self . expect_message ( from, to, Message :: AnnounceTx ( tx. id ) ) ;
166+ self . expect_message ( to, from, Message :: RequestTx ( tx. id ) ) ;
167+ self . expect_message ( from, to, Message :: Tx ( tx. clone ( ) ) ) ;
168+ self . expect_cpu_task ( to, CpuTask :: TransactionValidated ( from, tx) ) ;
169+ }
170+
171+ pub fn expect_tx_not_sent ( & mut self , from : NodeId , to : NodeId , tx : Arc < Transaction > ) {
172+ self . expect_no_message ( from, to, Message :: AnnounceTx ( tx. id ) ) ;
173+ }
174+
175+ pub fn expect_rb_and_eb_sent (
176+ & mut self ,
177+ from : NodeId ,
178+ to : NodeId ,
179+ rb : Arc < LinearRankingBlock > ,
180+ eb : Option < Arc < LinearEndorserBlock > > ,
181+ ) {
182+ self . expect_message ( from, to, Message :: AnnounceRBHeader ( rb. header . id ) ) ;
183+ self . expect_message ( to, from, Message :: RequestRBHeader ( rb. header . id ) ) ;
184+ self . expect_message (
185+ from,
186+ to,
187+ Message :: RBHeader ( rb. header . clone ( ) , true , eb. is_some ( ) ) ,
188+ ) ;
189+ self . expect_cpu_task (
190+ to,
191+ CpuTask :: RBHeaderValidated ( from, rb. header . clone ( ) , true , eb. is_some ( ) ) ,
192+ ) ;
193+ self . expect_message ( to, from, Message :: RequestRB ( rb. header . id ) ) ;
194+ self . expect_message ( from, to, Message :: RB ( rb. clone ( ) ) ) ;
195+ self . expect_cpu_task ( to, CpuTask :: RBBlockValidated ( rb) ) ;
196+ if let Some ( eb) = eb {
197+ self . expect_message ( to, from, Message :: RequestEB ( eb. id ( ) ) ) ;
198+ self . expect_message ( from, to, Message :: EB ( eb. clone ( ) ) ) ;
199+ self . expect_cpu_task ( to, CpuTask :: EBHeaderValidated ( from, eb) ) ;
200+ }
201+ }
202+
203+ pub fn expect_eb_validated ( & mut self , node : NodeId , eb : Arc < LinearEndorserBlock > ) {
204+ self . expect_cpu_task ( node, CpuTask :: EBBlockValidated ( eb, self . time . now ( ) ) ) ;
205+ }
206+
157207 pub fn expect_message (
158208 & mut self ,
159209 from : NodeId ,
@@ -172,7 +222,12 @@ impl TestDriver {
172222 } ) ;
173223 assert ! (
174224 found,
175- "message {message:?} was not sent from {from} to {to}"
225+ "message {message:?} was not sent from {from} to {to}\n pending messages: {:?}" ,
226+ queued
227+ . messages
228+ . iter( )
229+ . filter( |( t, _) | t == & to)
230+ . collect:: <Vec <_>>( ) ,
176231 ) ;
177232 let events = self
178233 . nodes
@@ -182,6 +237,20 @@ impl TestDriver {
182237 self . queued . entry ( to) . or_default ( ) . merge ( events) ;
183238 }
184239
240+ pub fn expect_no_message (
241+ & mut self ,
242+ from : NodeId ,
243+ to : NodeId ,
244+ message : <LinearLeiosNode as NodeImpl >:: Message ,
245+ ) {
246+ let Some ( queued) = self . queued . get ( & from) else {
247+ return ;
248+ } ;
249+ for ( t, m) in & queued. messages {
250+ assert_ne ! ( ( t, m) , ( & to, & message) ) ;
251+ }
252+ }
253+
185254 pub fn expect_cpu_task ( & mut self , node : NodeId , task : <LinearLeiosNode as NodeImpl >:: Task ) {
186255 self . expect_cpu_task_matching ( node, |t| if * t == task { Some ( t. clone ( ) ) } else { None } ) ;
187256 }
@@ -212,11 +281,14 @@ impl TestDriver {
212281 }
213282}
214283
215- fn is_new_rb_task ( task : & CpuTask ) -> Option < ( LinearRankingBlock , Option < LinearEndorserBlock > ) > {
284+ fn is_new_rb_task (
285+ task : & CpuTask ,
286+ ) -> Option < ( Arc < LinearRankingBlock > , Option < Arc < LinearEndorserBlock > > ) > {
216287 match task {
217- CpuTask :: RBBlockGenerated ( rb, eb) => {
218- Some ( ( rb. clone ( ) , eb. as_ref ( ) . map ( |( eb, _) | eb. clone ( ) ) ) )
219- }
288+ CpuTask :: RBBlockGenerated ( rb, eb) => Some ( (
289+ Arc :: new ( rb. clone ( ) ) ,
290+ eb. as_ref ( ) . map ( |( eb, _) | Arc :: new ( eb. clone ( ) ) ) ,
291+ ) ) ,
220292 _ => None ,
221293 }
222294}
@@ -233,17 +305,11 @@ fn should_propagate_transactions() {
233305
234306 // Node 1 produces a transaction, node 2 should request it
235307 let tx1 = sim. produce_tx ( node1, false ) ;
236- sim. expect_message ( node1, node2, Message :: AnnounceTx ( tx1. id ) ) ;
237- sim. expect_message ( node2, node1, Message :: RequestTx ( tx1. id ) ) ;
238- sim. expect_message ( node1, node2, Message :: Tx ( tx1. clone ( ) ) ) ;
239- sim. expect_cpu_task ( node2, CpuTask :: TransactionValidated ( node1, tx1. clone ( ) ) ) ;
308+ sim. expect_tx_sent ( node1, node2, tx1. clone ( ) ) ;
240309
241310 // Node 2 produces a transaction, node 1 should request it
242311 let tx2 = sim. produce_tx ( node2, false ) ;
243- sim. expect_message ( node2, node1, Message :: AnnounceTx ( tx2. id ) ) ;
244- sim. expect_message ( node1, node2, Message :: RequestTx ( tx2. id ) ) ;
245- sim. expect_message ( node2, node1, Message :: Tx ( tx2. clone ( ) ) ) ;
246- sim. expect_cpu_task ( node1, CpuTask :: TransactionValidated ( node2, tx2. clone ( ) ) ) ;
312+ sim. expect_tx_sent ( node2, node1, tx2. clone ( ) ) ;
247313
248314 // When node 1 produces an RB, it should include both TXs
249315 sim. win_next_rb_lottery ( node1, 0 ) ;
@@ -252,3 +318,82 @@ fn should_propagate_transactions() {
252318 assert_eq ! ( new_rb. transactions, vec![ tx1, tx2] ) ;
253319 assert_eq ! ( new_eb, None ) ;
254320}
321+
322+ #[ test]
323+ fn should_not_propagate_conflicting_transactions ( ) {
324+ let topology = new_topology ( vec ! [
325+ ( "node-1" , new_node( Some ( 1000 ) , vec![ "node-2" ] ) ) ,
326+ ( "node-2" , new_node( Some ( 1000 ) , vec![ "node-1" ] ) ) ,
327+ ] ) ;
328+ let mut sim = TestDriver :: new ( topology) ;
329+ let node1 = sim. id_for ( "node-1" ) ;
330+ let node2 = sim. id_for ( "node-2" ) ;
331+
332+ // Node 1 and 2 produce conflicting transactions
333+ let tx1 = sim. produce_tx ( node1, false ) ;
334+ let tx2 = sim. produce_tx ( node2, true ) ;
335+
336+ // Each node should send its TX to the other node,
337+ sim. expect_tx_sent ( node1, node2, tx1. clone ( ) ) ;
338+ sim. expect_tx_sent ( node2, node1, tx2. clone ( ) ) ;
339+
340+ // When node 1 produces an RB, it should include only its own TX
341+ sim. win_next_rb_lottery ( node1, 0 ) ;
342+ sim. next_slot ( ) ;
343+ let ( new_rb, new_eb) = sim. expect_cpu_task_matching ( node1, is_new_rb_task) ;
344+ assert_eq ! ( new_rb. transactions, vec![ tx1] ) ;
345+ assert_eq ! ( new_eb, None ) ;
346+ }
347+
348+ #[ test]
349+ fn should_repropagate_conflicting_transactions_from_eb ( ) {
350+ let topology = new_topology ( vec ! [
351+ ( "node-1" , new_node( Some ( 1000 ) , vec![ "node-2" ] ) ) ,
352+ ( "node-2" , new_node( Some ( 1000 ) , vec![ "node-1" , "node-3" ] ) ) ,
353+ ( "node-3" , new_node( Some ( 1000 ) , vec![ "node-2" ] ) ) ,
354+ ] ) ;
355+ let mut sim = TestDriver :: new ( topology) ;
356+ let node1 = sim. id_for ( "node-1" ) ;
357+ let node2 = sim. id_for ( "node-2" ) ;
358+ let node3 = sim. id_for ( "node-3" ) ;
359+
360+ // Node 1 produces 3 transactions
361+ let tx1_1 = sim. produce_tx ( node1, false ) ;
362+ let tx1_2 = sim. produce_tx ( node1, false ) ;
363+ let tx1_3 = sim. produce_tx ( node1, false ) ;
364+
365+ // Node 2 produces a transaction which conflicts with Node 1's final transaction
366+ let tx2 = sim. produce_tx ( node2, true ) ;
367+ // Node 2 sends its transactions to nodes 1 and 3
368+ sim. expect_tx_sent ( node2, node1, tx2. clone ( ) ) ;
369+ sim. expect_tx_sent ( node2, node3, tx2. clone ( ) ) ;
370+
371+ // Node 1 sends all of its transactions to node 2
372+ sim. expect_tx_sent ( node1, node2, tx1_1. clone ( ) ) ;
373+ sim. expect_tx_sent ( node1, node2, tx1_2. clone ( ) ) ;
374+ sim. expect_tx_sent ( node1, node2, tx1_3. clone ( ) ) ;
375+
376+ // Node 2 sends the first two transactions to node 3, but not the conflicting third
377+ sim. expect_tx_sent ( node2, node3, tx1_1. clone ( ) ) ;
378+ sim. expect_tx_sent ( node2, node3, tx1_2. clone ( ) ) ;
379+ sim. expect_tx_not_sent ( node2, node3, tx1_3. clone ( ) ) ;
380+
381+ // Now, Node 1 produces an RB (with an EB, because there are enough transactions)
382+ sim. win_next_rb_lottery ( node1, 0 ) ;
383+ sim. next_slot ( ) ;
384+ let ( rb, eb) = sim. expect_cpu_task_matching ( node1, is_new_rb_task) ;
385+ let eb = eb. expect ( "node did not produce EB" ) ;
386+ assert_eq ! ( rb. transactions, vec![ tx1_1, tx1_2] ) ;
387+ assert_eq ! ( eb. txs, vec![ tx1_3. clone( ) ] ) ;
388+
389+ // That RB and EB propagate from node 1 to node 2
390+ sim. expect_rb_and_eb_sent ( node1, node2, rb. clone ( ) , Some ( eb. clone ( ) ) ) ;
391+ // Node 2 fully validates the EB, because node 1 has all TXs
392+ sim. expect_eb_validated ( node2, eb. clone ( ) ) ;
393+ // And Node 2 propagates it to Node 3
394+ sim. expect_rb_and_eb_sent ( node2, node3, rb. clone ( ) , Some ( eb. clone ( ) ) ) ;
395+
396+ // and NOW Node 2 will tell Node 3 about the EB's conflicting TX
397+ sim. expect_tx_sent ( node2, node3, tx1_3) ;
398+ sim. expect_eb_validated ( node3, eb) ;
399+ }
0 commit comments