diff --git a/core/src/banking_stage/consumer.rs b/core/src/banking_stage/consumer.rs index 0104792ccd4d4b..ba915bc767efc8 100644 --- a/core/src/banking_stage/consumer.rs +++ b/core/src/banking_stage/consumer.rs @@ -737,7 +737,7 @@ mod tests { unprocessed_transaction_storage::ThreadType, }, crossbeam_channel::{unbounded, Receiver}, - solana_cost_model::cost_model::CostModel, + solana_cost_model::{cost_model::CostModel, transaction_cost::TransactionCost}, solana_entry::entry::{next_entry, next_versioned_entry}, solana_ledger::{ blockstore::{entries_to_test_shreds, Blockstore}, @@ -1264,7 +1264,9 @@ mod tests { }; let mut cost = CostModel::calculate_cost(&transactions[0], &bank.feature_set); - cost.bpf_execution_cost = actual_bpf_execution_cost; + if let TransactionCost::Transaction(ref mut usage_cost) = cost { + usage_cost.bpf_execution_cost = actual_bpf_execution_cost; + } block_cost + cost.sum() } else { diff --git a/core/src/banking_stage/qos_service.rs b/core/src/banking_stage/qos_service.rs index a627acdf45dc30..abac9c70f854f1 100644 --- a/core/src/banking_stage/qos_service.rs +++ b/core/src/banking_stage/qos_service.rs @@ -589,6 +589,7 @@ mod tests { use { super::*, itertools::Itertools, + solana_cost_model::transaction_cost::UsageCostDetails, solana_runtime::genesis_utils::{create_genesis_config, GenesisConfigInfo}, solana_sdk::{ hash::Hash, @@ -734,7 +735,7 @@ mod tests { let commited_status: Vec = qos_cost_results .iter() .map(|tx_cost| CommitTransactionDetails::Committed { - compute_units: tx_cost.as_ref().unwrap().bpf_execution_cost + compute_units: tx_cost.as_ref().unwrap().bpf_execution_cost() + execute_units_adjustment, }) .collect(); @@ -861,7 +862,7 @@ mod tests { CommitTransactionDetails::NotCommitted } else { CommitTransactionDetails::Committed { - compute_units: tx_cost.as_ref().unwrap().bpf_execution_cost + compute_units: tx_cost.as_ref().unwrap().bpf_execution_cost() + execute_units_adjustment, } } @@ -904,14 +905,14 @@ mod tests { let tx_cost_results: Vec<_> = (0..num_txs) .map(|n| { if n % 2 == 0 { - Ok(TransactionCost { + Ok(TransactionCost::Transaction(UsageCostDetails { signature_cost, write_lock_cost, data_bytes_cost, builtins_execution_cost, bpf_execution_cost, - ..TransactionCost::default() - }) + ..UsageCostDetails::default() + })) } else { Err(TransactionError::WouldExceedMaxBlockCostLimit) } diff --git a/cost-model/src/cost_model.rs b/cost-model/src/cost_model.rs index a1f88db2f3febd..a7b0c57f08a6e1 100644 --- a/cost-model/src/cost_model.rs +++ b/cost-model/src/cost_model.rs @@ -528,11 +528,11 @@ mod tests { ); let tx_cost = CostModel::calculate_cost(&tx, &FeatureSet::all_enabled()); - assert_eq!(2 + 2, tx_cost.writable_accounts.len()); - assert_eq!(signer1.pubkey(), tx_cost.writable_accounts[0]); - assert_eq!(signer2.pubkey(), tx_cost.writable_accounts[1]); - assert_eq!(key1, tx_cost.writable_accounts[2]); - assert_eq!(key2, tx_cost.writable_accounts[3]); + assert_eq!(2 + 2, tx_cost.writable_accounts().len()); + assert_eq!(signer1.pubkey(), tx_cost.writable_accounts()[0]); + assert_eq!(signer2.pubkey(), tx_cost.writable_accounts()[1]); + assert_eq!(key1, tx_cost.writable_accounts()[2]); + assert_eq!(key2, tx_cost.writable_accounts()[3]); } #[test] @@ -558,12 +558,12 @@ mod tests { * DEFAULT_PAGE_COST; let tx_cost = CostModel::calculate_cost(&tx, &FeatureSet::all_enabled()); - assert_eq!(expected_account_cost, tx_cost.write_lock_cost); - assert_eq!(*expected_execution_cost, tx_cost.builtins_execution_cost); - assert_eq!(2, tx_cost.writable_accounts.len()); + assert_eq!(expected_account_cost, tx_cost.write_lock_cost()); + assert_eq!(*expected_execution_cost, tx_cost.builtins_execution_cost()); + assert_eq!(2, tx_cost.writable_accounts().len()); assert_eq!( expected_loaded_accounts_data_size_cost, - tx_cost.loaded_accounts_data_size_cost + tx_cost.loaded_accounts_data_size_cost() ); } @@ -587,12 +587,12 @@ mod tests { let expected_loaded_accounts_data_size_cost = 0; let tx_cost = CostModel::calculate_cost(&tx, &feature_set); - assert_eq!(expected_account_cost, tx_cost.write_lock_cost); - assert_eq!(*expected_execution_cost, tx_cost.builtins_execution_cost); - assert_eq!(2, tx_cost.writable_accounts.len()); + assert_eq!(expected_account_cost, tx_cost.write_lock_cost()); + assert_eq!(*expected_execution_cost, tx_cost.builtins_execution_cost()); + assert_eq!(2, tx_cost.writable_accounts().len()); assert_eq!( expected_loaded_accounts_data_size_cost, - tx_cost.loaded_accounts_data_size_cost + tx_cost.loaded_accounts_data_size_cost() ); } @@ -626,12 +626,12 @@ mod tests { let expected_loaded_accounts_data_size_cost = (data_limit as u64) / (32 * 1024) * 8; let tx_cost = CostModel::calculate_cost(&tx, &feature_set); - assert_eq!(expected_account_cost, tx_cost.write_lock_cost); - assert_eq!(expected_execution_cost, tx_cost.builtins_execution_cost); - assert_eq!(2, tx_cost.writable_accounts.len()); + assert_eq!(expected_account_cost, tx_cost.write_lock_cost()); + assert_eq!(expected_execution_cost, tx_cost.builtins_execution_cost()); + assert_eq!(2, tx_cost.writable_accounts().len()); assert_eq!( expected_loaded_accounts_data_size_cost, - tx_cost.loaded_accounts_data_size_cost + tx_cost.loaded_accounts_data_size_cost() ); } @@ -659,12 +659,12 @@ mod tests { let expected_loaded_accounts_data_size_cost = 0; let tx_cost = CostModel::calculate_cost(&tx, &feature_set); - assert_eq!(expected_account_cost, tx_cost.write_lock_cost); - assert_eq!(expected_execution_cost, tx_cost.builtins_execution_cost); - assert_eq!(2, tx_cost.writable_accounts.len()); + assert_eq!(expected_account_cost, tx_cost.write_lock_cost()); + assert_eq!(expected_execution_cost, tx_cost.builtins_execution_cost()); + assert_eq!(2, tx_cost.writable_accounts().len()); assert_eq!( expected_loaded_accounts_data_size_cost, - tx_cost.loaded_accounts_data_size_cost + tx_cost.loaded_accounts_data_size_cost() ); } diff --git a/cost-model/src/cost_tracker.rs b/cost-model/src/cost_tracker.rs index 82a0ed0f04703d..a795ac9e06e981 100644 --- a/cost-model/src/cost_tracker.rs +++ b/cost-model/src/cost_tracker.rs @@ -288,6 +288,7 @@ impl CostTracker { mod tests { use { super::*, + crate::transaction_cost::*, solana_sdk::{ hash::Hash, signature::{Keypair, Signer}, @@ -332,11 +333,11 @@ mod tests { let simple_transaction = SanitizedTransaction::from_transaction_for_tests( system_transaction::transfer(mint_keypair, &keypair.pubkey(), 2, *start_hash), ); - let mut tx_cost = TransactionCost::new_with_capacity(1); + let mut tx_cost = UsageCostDetails::new_with_capacity(1); tx_cost.bpf_execution_cost = 5; tx_cost.writable_accounts.push(mint_keypair.pubkey()); - (simple_transaction, tx_cost) + (simple_transaction, TransactionCost::Transaction(tx_cost)) } fn build_simple_vote_transaction( @@ -360,12 +361,12 @@ mod tests { SimpleAddressLoader::Disabled, ) .unwrap(); - let mut tx_cost = TransactionCost::new_with_capacity(1); - tx_cost.bpf_execution_cost = 10; - tx_cost.writable_accounts.push(mint_keypair.pubkey()); - tx_cost.is_simple_vote = true; - (vote_transaction, tx_cost) + let writable_accounts = vec![mint_keypair.pubkey()]; + ( + vote_transaction, + TransactionCost::Vote { writable_accounts }, + ) } #[test] @@ -414,7 +415,11 @@ mod tests { fn test_cost_tracker_add_data() { let (mint_keypair, start_hash) = test_setup(); let (_tx, mut tx_cost) = build_simple_transaction(&mint_keypair, &start_hash); - tx_cost.account_data_size = 1; + if let TransactionCost::Transaction(ref mut usage_cost) = tx_cost { + usage_cost.account_data_size = 1; + } else { + unreachable!(); + } let cost = tx_cost.sum(); // build testee to have capacity for one simple transaction @@ -569,8 +574,16 @@ mod tests { let second_account = Keypair::new(); let (_tx1, mut tx_cost1) = build_simple_transaction(&mint_keypair, &start_hash); let (_tx2, mut tx_cost2) = build_simple_transaction(&second_account, &start_hash); - tx_cost1.account_data_size = MAX_BLOCK_ACCOUNTS_DATA_SIZE_DELTA; - tx_cost2.account_data_size = MAX_BLOCK_ACCOUNTS_DATA_SIZE_DELTA + 1; + if let TransactionCost::Transaction(ref mut usage_cost) = tx_cost1 { + usage_cost.account_data_size = MAX_BLOCK_ACCOUNTS_DATA_SIZE_DELTA; + } else { + unreachable!(); + } + if let TransactionCost::Transaction(ref mut usage_cost) = tx_cost2 { + usage_cost.account_data_size = MAX_BLOCK_ACCOUNTS_DATA_SIZE_DELTA + 1; + } else { + unreachable!(); + } let cost1 = tx_cost1.sum(); let cost2 = tx_cost2.sum(); @@ -597,8 +610,16 @@ mod tests { let (_tx1, mut tx_cost1) = build_simple_transaction(&mint_keypair, &start_hash); let (_tx2, mut tx_cost2) = build_simple_transaction(&second_account, &start_hash); let remaining_account_data_size = 1234; - tx_cost1.account_data_size = remaining_account_data_size; - tx_cost2.account_data_size = remaining_account_data_size + 1; + if let TransactionCost::Transaction(ref mut usage_cost) = tx_cost1 { + usage_cost.account_data_size = remaining_account_data_size; + } else { + unreachable!(); + } + if let TransactionCost::Transaction(ref mut usage_cost) = tx_cost2 { + usage_cost.account_data_size = remaining_account_data_size + 1; + } else { + unreachable!(); + } let cost1 = tx_cost1.sum(); let cost2 = tx_cost2.sum(); @@ -662,11 +683,11 @@ mod tests { // | acct3 | $cost | // and block_cost = $cost { - let tx_cost = TransactionCost { + let tx_cost = TransactionCost::Transaction(UsageCostDetails { writable_accounts: vec![acct1, acct2, acct3], bpf_execution_cost: cost, - ..TransactionCost::default() - }; + ..UsageCostDetails::default() + }); assert!(testee.try_add(&tx_cost).is_ok()); let (_costliest_account, costliest_account_cost) = testee.find_costliest_account(); assert_eq!(cost, testee.block_cost); @@ -680,11 +701,11 @@ mod tests { // | acct3 | $cost | // and block_cost = $cost * 2 { - let tx_cost = TransactionCost { + let tx_cost = TransactionCost::Transaction(UsageCostDetails { writable_accounts: vec![acct2], bpf_execution_cost: cost, - ..TransactionCost::default() - }; + ..UsageCostDetails::default() + }); assert!(testee.try_add(&tx_cost).is_ok()); let (costliest_account, costliest_account_cost) = testee.find_costliest_account(); assert_eq!(cost * 2, testee.block_cost); @@ -700,11 +721,11 @@ mod tests { // | acct3 | $cost | // and block_cost = $cost * 2 { - let tx_cost = TransactionCost { + let tx_cost = TransactionCost::Transaction(UsageCostDetails { writable_accounts: vec![acct1, acct2], bpf_execution_cost: cost, - ..TransactionCost::default() - }; + ..UsageCostDetails::default() + }); assert!(testee.try_add(&tx_cost).is_err()); let (costliest_account, costliest_account_cost) = testee.find_costliest_account(); assert_eq!(cost * 2, testee.block_cost); @@ -724,11 +745,11 @@ mod tests { let block_max = account_max * 3; // for three accts let mut testee = CostTracker::new(account_max, block_max, block_max, None); - let tx_cost = TransactionCost { + let tx_cost = TransactionCost::Transaction(UsageCostDetails { writable_accounts: vec![acct1, acct2, acct3], bpf_execution_cost: cost, - ..TransactionCost::default() - }; + ..UsageCostDetails::default() + }); let mut expected_block_cost = tx_cost.sum(); let expected_tx_count = 1; assert!(testee.try_add(&tx_cost).is_ok()); @@ -811,11 +832,11 @@ mod tests { let acct3 = Pubkey::new_unique(); let cost = 100; - let tx_cost = TransactionCost { + let tx_cost = TransactionCost::Transaction(UsageCostDetails { writable_accounts: vec![acct1, acct2, acct3], bpf_execution_cost: cost, - ..TransactionCost::default() - }; + ..UsageCostDetails::default() + }); let mut cost_tracker = CostTracker::default(); @@ -858,11 +879,11 @@ mod tests { let mut cost_tracker = CostTracker::default(); let cost = 100u64; - let tx_cost = TransactionCost { + let tx_cost = TransactionCost::Transaction(UsageCostDetails { writable_accounts: vec![Pubkey::new_unique()], bpf_execution_cost: cost, - ..TransactionCost::default() - }; + ..UsageCostDetails::default() + }); cost_tracker.add_transaction_cost(&tx_cost); // assert cost_tracker is reverted to default diff --git a/cost-model/src/transaction_cost.rs b/cost-model/src/transaction_cost.rs index 477d5edaed2323..ba497a7f08877d 100644 --- a/cost-model/src/transaction_cost.rs +++ b/cost-model/src/transaction_cost.rs @@ -5,9 +5,8 @@ use {crate::block_cost_limits, solana_sdk::pubkey::Pubkey}; /// Resources required to process a regular transaction often include /// an array of variables, such as execution cost, loaded bytes, write /// lock and read lock etc. -/// Vote has a simple and pre-determined format, therefore can have -/// a constant cost, skipping transaction inspection as required for -/// non-vote transaction. +/// Vote has a simpler and pre-determined format, it's cost structure +/// can be simpler, calculation quicker. #[derive(Debug)] pub enum TransactionCost { Vote { writable_accounts: Vec }, @@ -60,6 +59,13 @@ impl TransactionCost { } } + pub fn loaded_accounts_data_size_cost(&self) -> u64 { + match self { + Self::Vote { .. } => 0, + Self::Transaction(usage_cost) => usage_cost.loaded_accounts_data_size_cost, + } + } + pub fn signature_cost(&self) -> u64 { match self { Self::Vote { writable_accounts } => { @@ -74,7 +80,7 @@ impl TransactionCost { Self::Vote { writable_accounts } => { block_cost_limits::WRITE_LOCK_UNITS.saturating_mul(writable_accounts.len() as u64) } - Self::Transaction(usage_cost) => usage_cost.signature_cost, + Self::Transaction(usage_cost) => usage_cost.write_lock_cost, } }