@@ -2192,6 +2192,56 @@ mod tests {
2192
2192
) ;
2193
2193
}
2194
2194
2195
+ #[ tokio:: test]
2196
+ async fn test_propose_batch_over_spend_limit ( ) {
2197
+ let mut rng = TestRng :: default ( ) ;
2198
+ // Create two primaries to test spend limit activation on V4.
2199
+ let ( accounts, committee) = sample_committee ( & mut rng) ;
2200
+ let primary_v3 = primary_with_committee (
2201
+ 0 ,
2202
+ & accounts,
2203
+ committee. clone ( ) ,
2204
+ CurrentNetwork :: CONSENSUS_HEIGHT ( ConsensusVersion :: V3 ) . unwrap ( ) ,
2205
+ ) ;
2206
+ let primary_v4 = primary_with_committee (
2207
+ 1 ,
2208
+ & accounts,
2209
+ committee,
2210
+ CurrentNetwork :: CONSENSUS_HEIGHT ( ConsensusVersion :: V4 ) . unwrap ( ) ,
2211
+ ) ;
2212
+
2213
+ // Check there is no batch currently proposed.
2214
+ assert ! ( primary_v3. proposed_batch. read( ) . is_none( ) ) ;
2215
+ assert ! ( primary_v4. proposed_batch. read( ) . is_none( ) ) ;
2216
+ // Check the workers are empty.
2217
+ primary_v3. workers ( ) . iter ( ) . for_each ( |worker| assert ! ( worker. transmissions( ) . is_empty( ) ) ) ;
2218
+ primary_v4. workers ( ) . iter ( ) . for_each ( |worker| assert ! ( worker. transmissions( ) . is_empty( ) ) ) ;
2219
+
2220
+ // Generate a solution and a transaction.
2221
+ let ( solution_id, solution) = sample_unconfirmed_solution ( & mut rng) ;
2222
+ primary_v3. workers [ 0 ] . process_unconfirmed_solution ( solution_id, solution. clone ( ) ) . await . unwrap ( ) ;
2223
+ primary_v4. workers [ 0 ] . process_unconfirmed_solution ( solution_id, solution) . await . unwrap ( ) ;
2224
+
2225
+ // At 10 credits per execution, 10 transactions should max out a batch, add a few more.
2226
+ for _i in 0 ..15 {
2227
+ let ( transaction_id, transaction) = sample_unconfirmed_transaction ( & mut rng) ;
2228
+ // Store it on one of the workers.
2229
+ primary_v3. workers [ 0 ] . process_unconfirmed_transaction ( transaction_id, transaction. clone ( ) ) . await . unwrap ( ) ;
2230
+ primary_v4. workers [ 0 ] . process_unconfirmed_transaction ( transaction_id, transaction) . await . unwrap ( ) ;
2231
+ }
2232
+
2233
+ // Try to propose a batch again. This time, it should succeed.
2234
+ assert ! ( primary_v3. propose_batch( ) . await . is_ok( ) ) ;
2235
+ assert ! ( primary_v4. propose_batch( ) . await . is_ok( ) ) ;
2236
+ // Expect 10/15 transactions to be included in the proposal, along with
2237
+ // the solution, for v3 consensus all 15 should be included.
2238
+ assert_eq ! ( primary_v3. proposed_batch. read( ) . as_ref( ) . unwrap( ) . transmissions( ) . len( ) , 16 ) ;
2239
+ assert_eq ! ( primary_v4. proposed_batch. read( ) . as_ref( ) . unwrap( ) . transmissions( ) . len( ) , 11 ) ;
2240
+ // Check the transactions were correctly drained from the workers (15 + 1 - 11).
2241
+ assert_eq ! ( primary_v3. workers( ) . iter( ) . map( |worker| worker. transmissions( ) . len( ) ) . sum:: <usize >( ) , 0 ) ;
2242
+ assert_eq ! ( primary_v4. workers( ) . iter( ) . map( |worker| worker. transmissions( ) . len( ) ) . sum:: <usize >( ) , 5 ) ;
2243
+ }
2244
+
2195
2245
#[ tokio:: test]
2196
2246
async fn test_batch_propose_from_peer ( ) {
2197
2247
let mut rng = TestRng :: default ( ) ;
@@ -2464,6 +2514,70 @@ mod tests {
2464
2514
) ;
2465
2515
}
2466
2516
2517
+ #[ tokio:: test]
2518
+ async fn test_batch_propose_from_peer_over_spend_limit ( ) {
2519
+ let mut rng = TestRng :: default ( ) ;
2520
+
2521
+ // Create two primaries to test spend limit activation on V4.
2522
+ let ( accounts, committee) = sample_committee ( & mut rng) ;
2523
+ let primary_v3 = primary_with_committee (
2524
+ 0 ,
2525
+ & accounts,
2526
+ committee. clone ( ) ,
2527
+ CurrentNetwork :: CONSENSUS_HEIGHT ( ConsensusVersion :: V3 ) . unwrap ( ) ,
2528
+ ) ;
2529
+ let primary_v4 = primary_with_committee (
2530
+ 1 ,
2531
+ & accounts,
2532
+ committee. clone ( ) ,
2533
+ CurrentNetwork :: CONSENSUS_HEIGHT ( ConsensusVersion :: V4 ) . unwrap ( ) ,
2534
+ ) ;
2535
+
2536
+ // Create a valid proposal with an author that isn't the primary.
2537
+ let round = 1 ;
2538
+ let peer_account = & accounts[ 1 ] ;
2539
+ let peer_ip = peer_account. 0 ;
2540
+ let timestamp = now ( ) + MIN_BATCH_DELAY_IN_SECS as i64 ;
2541
+ let proposal = create_test_proposal (
2542
+ & peer_account. 1 ,
2543
+ committee,
2544
+ round,
2545
+ Default :: default ( ) ,
2546
+ timestamp,
2547
+ // At 10 credits per execution, this should bring the batch above
2548
+ // the spend limit.
2549
+ 11 ,
2550
+ & mut rng,
2551
+ ) ;
2552
+
2553
+ // Make sure the primary is aware of the transmissions in the proposal.
2554
+ for ( transmission_id, transmission) in proposal. transmissions ( ) {
2555
+ primary_v3. workers [ 0 ] . process_transmission_from_peer ( peer_ip, * transmission_id, transmission. clone ( ) ) ;
2556
+ primary_v4. workers [ 0 ] . process_transmission_from_peer ( peer_ip, * transmission_id, transmission. clone ( ) ) ;
2557
+ }
2558
+
2559
+ // The author must be known to resolver to pass propose checks.
2560
+ primary_v3. gateway . resolver ( ) . insert_peer ( peer_ip, peer_ip, peer_account. 1 . address ( ) ) ;
2561
+ primary_v4. gateway . resolver ( ) . insert_peer ( peer_ip, peer_ip, peer_account. 1 . address ( ) ) ;
2562
+ // The primary must be considered synced.
2563
+ primary_v3. sync . block_sync ( ) . try_block_sync ( & primary_v3. gateway . clone ( ) ) . await ;
2564
+ primary_v4. sync . block_sync ( ) . try_block_sync ( & primary_v4. gateway . clone ( ) ) . await ;
2565
+
2566
+ // Check the spend limit is enforced from V4 onwards.
2567
+ assert ! (
2568
+ primary_v3
2569
+ . process_batch_propose_from_peer( peer_ip, ( * proposal. batch_header( ) ) . clone( ) . into( ) )
2570
+ . await
2571
+ . is_ok( )
2572
+ ) ;
2573
+ assert ! (
2574
+ primary_v4
2575
+ . process_batch_propose_from_peer( peer_ip, ( * proposal. batch_header( ) ) . clone( ) . into( ) )
2576
+ . await
2577
+ . is_err( )
2578
+ ) ;
2579
+ }
2580
+
2467
2581
#[ tokio:: test]
2468
2582
async fn test_propose_batch_with_storage_round_behind_proposal_lock ( ) {
2469
2583
let round = 3 ;
@@ -2527,47 +2641,6 @@ mod tests {
2527
2641
assert ! ( primary. proposed_batch. read( ) . as_ref( ) . unwrap( ) . round( ) > primary. current_round( ) ) ;
2528
2642
}
2529
2643
2530
- #[ tokio:: test]
2531
- async fn test_propose_batch_over_spend_limit ( ) {
2532
- let mut rng = TestRng :: default ( ) ;
2533
- // Instantiate two primaries to test spend limit activation on V4.
2534
- let ( primary_v3, _) =
2535
- primary_without_handlers ( & mut rng, CurrentNetwork :: CONSENSUS_HEIGHT ( ConsensusVersion :: V3 ) . unwrap ( ) ) . await ;
2536
- let ( primary_v4, _) =
2537
- primary_without_handlers ( & mut rng, CurrentNetwork :: CONSENSUS_HEIGHT ( ConsensusVersion :: V4 ) . unwrap ( ) ) . await ;
2538
-
2539
- // Check there is no batch currently proposed.
2540
- assert ! ( primary_v3. proposed_batch. read( ) . is_none( ) ) ;
2541
- assert ! ( primary_v4. proposed_batch. read( ) . is_none( ) ) ;
2542
- // Check the workers are empty.
2543
- primary_v3. workers ( ) . iter ( ) . for_each ( |worker| assert ! ( worker. transmissions( ) . is_empty( ) ) ) ;
2544
- primary_v4. workers ( ) . iter ( ) . for_each ( |worker| assert ! ( worker. transmissions( ) . is_empty( ) ) ) ;
2545
-
2546
- // Generate a solution and a transaction.
2547
- let ( solution_id, solution) = sample_unconfirmed_solution ( & mut rng) ;
2548
- primary_v3. workers [ 0 ] . process_unconfirmed_solution ( solution_id, solution. clone ( ) ) . await . unwrap ( ) ;
2549
- primary_v4. workers [ 0 ] . process_unconfirmed_solution ( solution_id, solution) . await . unwrap ( ) ;
2550
-
2551
- // At 10 credits per execution, 10 transactions should max out a batch, add a few more.
2552
- for _i in 0 ..15 {
2553
- let ( transaction_id, transaction) = sample_unconfirmed_transaction ( & mut rng) ;
2554
- // Store it on one of the workers.
2555
- primary_v3. workers [ 0 ] . process_unconfirmed_transaction ( transaction_id, transaction. clone ( ) ) . await . unwrap ( ) ;
2556
- primary_v4. workers [ 0 ] . process_unconfirmed_transaction ( transaction_id, transaction) . await . unwrap ( ) ;
2557
- }
2558
-
2559
- // Try to propose a batch again. This time, it should succeed.
2560
- assert ! ( primary_v3. propose_batch( ) . await . is_ok( ) ) ;
2561
- assert ! ( primary_v4. propose_batch( ) . await . is_ok( ) ) ;
2562
- // Expect 10/15 transactions to be included in the proposal, along with
2563
- // the solution, for v3 consensus all 15 should be included.
2564
- assert_eq ! ( primary_v3. proposed_batch. read( ) . as_ref( ) . unwrap( ) . transmissions( ) . len( ) , 16 ) ;
2565
- assert_eq ! ( primary_v4. proposed_batch. read( ) . as_ref( ) . unwrap( ) . transmissions( ) . len( ) , 11 ) ;
2566
- // Check the transactions were correctly drained from the workers (15 + 1 - 11).
2567
- assert_eq ! ( primary_v3. workers( ) . iter( ) . map( |worker| worker. transmissions( ) . len( ) ) . sum:: <usize >( ) , 0 ) ;
2568
- assert_eq ! ( primary_v4. workers( ) . iter( ) . map( |worker| worker. transmissions( ) . len( ) ) . sum:: <usize >( ) , 5 ) ;
2569
- }
2570
-
2571
2644
#[ tokio:: test( flavor = "multi_thread" ) ]
2572
2645
async fn test_batch_signature_from_peer ( ) {
2573
2646
let mut rng = TestRng :: default ( ) ;
0 commit comments