From 2ed29771f223e52931450e07e1c2610b689debcc Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Fri, 8 Apr 2022 15:35:16 +0200 Subject: [PATCH] Unittest for cost tracker after process_and_record_transactions --- core/src/banking_stage.rs | 125 ++++++++++++++++++++++++++++++++++++ runtime/src/cost_tracker.rs | 8 +++ 2 files changed, 133 insertions(+) diff --git a/core/src/banking_stage.rs b/core/src/banking_stage.rs index 5577f41e41..08540dc04d 100644 --- a/core/src/banking_stage.rs +++ b/core/src/banking_stage.rs @@ -2902,6 +2902,131 @@ mod tests { Blockstore::destroy(ledger_path.path()).unwrap(); } + #[test] + fn test_bank_process_and_record_transactions_cost_tracker() { + solana_logger::setup(); + let GenesisConfigInfo { + genesis_config, + mint_keypair, + .. + } = create_slow_genesis_config(10_000); + let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config)); + let pubkey = solana_sdk::pubkey::new_rand(); + + let ledger_path = get_tmp_ledger_path_auto_delete!(); + { + let blockstore = Blockstore::open(ledger_path.path()) + .expect("Expected to be able to open database ledger"); + let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new( + bank.tick_height(), + bank.last_blockhash(), + bank.clone(), + Some((4, 4)), + bank.ticks_per_slot(), + &pubkey, + &Arc::new(blockstore), + &Arc::new(LeaderScheduleCache::new_from_bank(&bank)), + &Arc::new(PohConfig::default()), + Arc::new(AtomicBool::default()), + ); + let recorder = poh_recorder.recorder(); + let poh_recorder = Arc::new(Mutex::new(poh_recorder)); + + let poh_simulator = simulate_poh(record_receiver, &poh_recorder); + + poh_recorder.lock().unwrap().set_bank(&bank); + let (gossip_vote_sender, _gossip_vote_receiver) = unbounded(); + + let qos_service = QosService::new(Arc::new(RwLock::new(CostModel::default())), 1); + + let get_block_cost = || bank.read_cost_tracker().unwrap().block_cost(); + let get_tx_count = || bank.read_cost_tracker().unwrap().transaction_count(); + assert_eq!(get_block_cost(), 0); + assert_eq!(get_tx_count(), 0); + + // + // TEST: cost tracker's block cost increases when successfully processing a tx + // + + let transactions = sanitize_transactions(vec![system_transaction::transfer( + &mint_keypair, + &pubkey, + 1, + genesis_config.hash(), + )]); + + let process_transactions_batch_output = BankingStage::process_and_record_transactions( + &bank, + &transactions, + &recorder, + 0, + None, + &gossip_vote_sender, + &qos_service, + ); + + let ExecuteAndCommitTransactionsOutput { + executed_with_successful_result_count, + commit_transactions_result, + .. + } = process_transactions_batch_output.execute_and_commit_transactions_output; + assert_eq!(executed_with_successful_result_count, 1); + assert!(commit_transactions_result.is_ok()); + + let single_transfer_cost = get_block_cost(); + assert_ne!(single_transfer_cost, 0); + assert_eq!(get_tx_count(), 1); + + // + // TEST: When a tx in a batch can't be executed (here because of account + // locks), then its cost does not affect the cost tracker. + // + + let allocate_keypair = Keypair::new(); + let transactions = sanitize_transactions(vec![ + system_transaction::transfer(&mint_keypair, &pubkey, 2, genesis_config.hash()), + // intentionally use a tx that has a different cost + system_transaction::allocate( + &mint_keypair, + &allocate_keypair, + genesis_config.hash(), + 1, + ), + ]); + + let process_transactions_batch_output = BankingStage::process_and_record_transactions( + &bank, + &transactions, + &recorder, + 0, + None, + &gossip_vote_sender, + &qos_service, + ); + + let ExecuteAndCommitTransactionsOutput { + executed_with_successful_result_count, + commit_transactions_result, + retryable_transaction_indexes, + .. + } = process_transactions_batch_output.execute_and_commit_transactions_output; + assert_eq!(executed_with_successful_result_count, 1); + assert!(commit_transactions_result.is_ok()); + assert_eq!(retryable_transaction_indexes, vec![1]); + + assert_eq!(get_block_cost(), 2 * single_transfer_cost); + assert_eq!(get_tx_count(), 2); + + poh_recorder + .lock() + .unwrap() + .is_exited + .store(true, Ordering::Relaxed); + let _ = poh_simulator.join(); + } + Blockstore::destroy(ledger_path.path()).unwrap(); + } + fn simulate_poh( record_receiver: CrossbeamReceiver, poh_recorder: &Arc>, diff --git a/runtime/src/cost_tracker.rs b/runtime/src/cost_tracker.rs index 64df73e513..9c418a9ab0 100644 --- a/runtime/src/cost_tracker.rs +++ b/runtime/src/cost_tracker.rs @@ -111,6 +111,14 @@ impl CostTracker { self.remove_transaction_cost(tx_cost); } + pub fn block_cost(&self) -> u64 { + self.block_cost + } + + pub fn transaction_count(&self) -> u64 { + self.transaction_count + } + pub fn report_stats(&self, bank_slot: Slot) { // skip reporting if block is empty if self.transaction_count == 0 {