@@ -294,6 +294,70 @@ fn execute_batches_internal(
294
294
} )
295
295
}
296
296
297
+ // This fn diverts the code-path into two variants. Both must provide exactly the same set of
298
+ // validations. For this reason, this fn is deliberately inserted into the code path to be called
299
+ // inside process_entries(), so that Bank::prepare_sanitized_batch() has been called on all of
300
+ // batches already, while minimizing code duplication (thus divergent behavior risk) at the cost of
301
+ // acceptable overhead of meaningless buffering of batches for the scheduler variant.
302
+ //
303
+ // Also note that the scheduler variant can't implement the batch-level sanitization naively, due
304
+ // to the nature of individual tx processing. That's another reason of this particular placement of
305
+ // divergent point in the code-path (i.e. not one layer up with its own prepare_sanitized_batch()
306
+ // invocation).
307
+ fn process_batches (
308
+ bank : & BankWithScheduler ,
309
+ batches : & [ TransactionBatchWithIndexes ] ,
310
+ transaction_status_sender : Option < & TransactionStatusSender > ,
311
+ replay_vote_sender : Option < & ReplayVoteSender > ,
312
+ batch_execution_timing : & mut BatchExecutionTiming ,
313
+ log_messages_bytes_limit : Option < usize > ,
314
+ prioritization_fee_cache : & PrioritizationFeeCache ,
315
+ ) -> Result < ( ) > {
316
+ if bank. has_installed_scheduler ( ) {
317
+ debug ! (
318
+ "process_batches()/schedule_batches_for_execution({} batches)" ,
319
+ batches. len( )
320
+ ) ;
321
+ // scheduling always succeeds here without being blocked on actual transaction executions.
322
+ // The transaction execution errors will be collected via the blocking fn called
323
+ // BankWithScheduler::wait_for_completed_scheduler(), if any.
324
+ schedule_batches_for_execution ( bank, batches) ;
325
+ Ok ( ( ) )
326
+ } else {
327
+ debug ! (
328
+ "process_batches()/rebatch_and_execute_batches({} batches)" ,
329
+ batches. len( )
330
+ ) ;
331
+ rebatch_and_execute_batches (
332
+ bank,
333
+ batches,
334
+ transaction_status_sender,
335
+ replay_vote_sender,
336
+ batch_execution_timing,
337
+ log_messages_bytes_limit,
338
+ prioritization_fee_cache,
339
+ )
340
+ }
341
+ }
342
+
343
+ fn schedule_batches_for_execution (
344
+ bank : & BankWithScheduler ,
345
+ batches : & [ TransactionBatchWithIndexes ] ,
346
+ ) {
347
+ for TransactionBatchWithIndexes {
348
+ batch,
349
+ transaction_indexes,
350
+ } in batches
351
+ {
352
+ bank. schedule_transaction_executions (
353
+ batch
354
+ . sanitized_transactions ( )
355
+ . iter ( )
356
+ . zip ( transaction_indexes. iter ( ) ) ,
357
+ ) ;
358
+ }
359
+ }
360
+
297
361
fn rebatch_transactions < ' a > (
298
362
lock_results : & ' a [ Result < ( ) > ] ,
299
363
bank : & ' a Arc < Bank > ,
@@ -314,7 +378,7 @@ fn rebatch_transactions<'a>(
314
378
}
315
379
}
316
380
317
- fn execute_batches (
381
+ fn rebatch_and_execute_batches (
318
382
bank : & Arc < Bank > ,
319
383
batches : & [ TransactionBatchWithIndexes ] ,
320
384
transaction_status_sender : Option < & TransactionStatusSender > ,
@@ -488,7 +552,7 @@ fn process_entries(
488
552
if bank. is_block_boundary ( bank. tick_height ( ) + tick_hashes. len ( ) as u64 ) {
489
553
// If it's a tick that will cause a new blockhash to be created,
490
554
// execute the group and register the tick
491
- execute_batches (
555
+ process_batches (
492
556
bank,
493
557
& batches,
494
558
transaction_status_sender,
@@ -541,7 +605,7 @@ fn process_entries(
541
605
} else {
542
606
// else we have an entry that conflicts with a prior entry
543
607
// execute the current queue and try to process this entry again
544
- execute_batches (
608
+ process_batches (
545
609
bank,
546
610
& batches,
547
611
transaction_status_sender,
@@ -556,7 +620,7 @@ fn process_entries(
556
620
}
557
621
}
558
622
}
559
- execute_batches (
623
+ process_batches (
560
624
bank,
561
625
& batches,
562
626
transaction_status_sender,
@@ -1856,8 +1920,11 @@ pub mod tests {
1856
1920
rand:: { thread_rng, Rng } ,
1857
1921
solana_entry:: entry:: { create_ticks, next_entry, next_entry_mut} ,
1858
1922
solana_program_runtime:: declare_process_instruction,
1859
- solana_runtime:: genesis_utils:: {
1860
- self , create_genesis_config_with_vote_accounts, ValidatorVoteKeypairs ,
1923
+ solana_runtime:: {
1924
+ genesis_utils:: {
1925
+ self , create_genesis_config_with_vote_accounts, ValidatorVoteKeypairs ,
1926
+ } ,
1927
+ installed_scheduler_pool:: MockInstalledScheduler ,
1861
1928
} ,
1862
1929
solana_sdk:: {
1863
1930
account:: { AccountSharedData , WritableAccount } ,
@@ -4245,6 +4312,38 @@ pub mod tests {
4245
4312
)
4246
4313
}
4247
4314
4315
+ fn create_test_transactions (
4316
+ mint_keypair : & Keypair ,
4317
+ genesis_hash : & Hash ,
4318
+ ) -> Vec < SanitizedTransaction > {
4319
+ let pubkey = solana_sdk:: pubkey:: new_rand ( ) ;
4320
+ let keypair2 = Keypair :: new ( ) ;
4321
+ let pubkey2 = solana_sdk:: pubkey:: new_rand ( ) ;
4322
+ let keypair3 = Keypair :: new ( ) ;
4323
+ let pubkey3 = solana_sdk:: pubkey:: new_rand ( ) ;
4324
+
4325
+ vec ! [
4326
+ SanitizedTransaction :: from_transaction_for_tests( system_transaction:: transfer(
4327
+ mint_keypair,
4328
+ & pubkey,
4329
+ 1 ,
4330
+ * genesis_hash,
4331
+ ) ) ,
4332
+ SanitizedTransaction :: from_transaction_for_tests( system_transaction:: transfer(
4333
+ & keypair2,
4334
+ & pubkey2,
4335
+ 1 ,
4336
+ * genesis_hash,
4337
+ ) ) ,
4338
+ SanitizedTransaction :: from_transaction_for_tests( system_transaction:: transfer(
4339
+ & keypair3,
4340
+ & pubkey3,
4341
+ 1 ,
4342
+ * genesis_hash,
4343
+ ) ) ,
4344
+ ]
4345
+ }
4346
+
4248
4347
#[ test]
4249
4348
fn test_confirm_slot_entries_progress_num_txs_indexes ( ) {
4250
4349
let GenesisConfigInfo {
@@ -4368,34 +4467,7 @@ pub mod tests {
4368
4467
..
4369
4468
} = create_genesis_config_with_leader ( 500 , & dummy_leader_pubkey, 100 ) ;
4370
4469
let bank = Arc :: new ( Bank :: new_for_tests ( & genesis_config) ) ;
4371
-
4372
- let pubkey = solana_sdk:: pubkey:: new_rand ( ) ;
4373
- let keypair2 = Keypair :: new ( ) ;
4374
- let pubkey2 = solana_sdk:: pubkey:: new_rand ( ) ;
4375
- let keypair3 = Keypair :: new ( ) ;
4376
- let pubkey3 = solana_sdk:: pubkey:: new_rand ( ) ;
4377
-
4378
- let txs = vec ! [
4379
- SanitizedTransaction :: from_transaction_for_tests( system_transaction:: transfer(
4380
- & mint_keypair,
4381
- & pubkey,
4382
- 1 ,
4383
- genesis_config. hash( ) ,
4384
- ) ) ,
4385
- SanitizedTransaction :: from_transaction_for_tests( system_transaction:: transfer(
4386
- & keypair2,
4387
- & pubkey2,
4388
- 1 ,
4389
- genesis_config. hash( ) ,
4390
- ) ) ,
4391
- SanitizedTransaction :: from_transaction_for_tests( system_transaction:: transfer(
4392
- & keypair3,
4393
- & pubkey3,
4394
- 1 ,
4395
- genesis_config. hash( ) ,
4396
- ) ) ,
4397
- ] ;
4398
-
4470
+ let txs = create_test_transactions ( & mint_keypair, & genesis_config. hash ( ) ) ;
4399
4471
let batch = bank. prepare_sanitized_batch ( & txs) ;
4400
4472
assert ! ( batch. needs_unlock( ) ) ;
4401
4473
let transaction_indexes = vec ! [ 42 , 43 , 44 ] ;
@@ -4424,6 +4496,46 @@ pub mod tests {
4424
4496
assert_eq ! ( batch3. transaction_indexes, vec![ 43 , 44 ] ) ;
4425
4497
}
4426
4498
4499
+ #[ test]
4500
+ fn test_schedule_batches_for_execution ( ) {
4501
+ solana_logger:: setup ( ) ;
4502
+ let dummy_leader_pubkey = solana_sdk:: pubkey:: new_rand ( ) ;
4503
+ let GenesisConfigInfo {
4504
+ genesis_config,
4505
+ mint_keypair,
4506
+ ..
4507
+ } = create_genesis_config_with_leader ( 500 , & dummy_leader_pubkey, 100 ) ;
4508
+ let bank = Arc :: new ( Bank :: new_for_tests ( & genesis_config) ) ;
4509
+
4510
+ let txs = create_test_transactions ( & mint_keypair, & genesis_config. hash ( ) ) ;
4511
+
4512
+ let mut mocked_scheduler = MockInstalledScheduler :: new ( ) ;
4513
+ mocked_scheduler
4514
+ . expect_schedule_execution ( )
4515
+ . times ( txs. len ( ) )
4516
+ . returning ( |_| ( ) ) ;
4517
+ let bank = BankWithScheduler :: new ( bank, Some ( Box :: new ( mocked_scheduler) ) ) ;
4518
+
4519
+ let batch = bank. prepare_sanitized_batch ( & txs) ;
4520
+ let batch_with_indexes = TransactionBatchWithIndexes {
4521
+ batch,
4522
+ transaction_indexes : ( 0 ..txs. len ( ) ) . collect ( ) ,
4523
+ } ;
4524
+
4525
+ let mut batch_execution_timing = BatchExecutionTiming :: default ( ) ;
4526
+ let ignored_prioritization_fee_cache = PrioritizationFeeCache :: new ( 0u64 ) ;
4527
+ assert ! ( process_batches(
4528
+ & bank,
4529
+ & [ batch_with_indexes] ,
4530
+ None ,
4531
+ None ,
4532
+ & mut batch_execution_timing,
4533
+ None ,
4534
+ & ignored_prioritization_fee_cache
4535
+ )
4536
+ . is_ok( ) ) ;
4537
+ }
4538
+
4427
4539
#[ test]
4428
4540
fn test_confirm_slot_entries_with_fix ( ) {
4429
4541
const HASHES_PER_TICK : u64 = 10 ;
0 commit comments