Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate vote cost #33230

Merged
merged 10 commits into from
Sep 25, 2023
6 changes: 4 additions & 2 deletions core/src/banking_stage/consumer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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 {
Expand Down
21 changes: 11 additions & 10 deletions core/src/banking_stage/qos_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,25 +318,25 @@ impl QosService {
Ok(cost) => {
saturating_add_assign!(
batched_transaction_details.costs.batched_signature_cost,
cost.signature_cost
cost.signature_cost()
);
saturating_add_assign!(
batched_transaction_details.costs.batched_write_lock_cost,
cost.write_lock_cost
cost.write_lock_cost()
);
saturating_add_assign!(
batched_transaction_details.costs.batched_data_bytes_cost,
cost.data_bytes_cost
cost.data_bytes_cost()
);
saturating_add_assign!(
batched_transaction_details
.costs
.batched_builtins_execute_cost,
cost.builtins_execution_cost
cost.builtins_execution_cost()
);
saturating_add_assign!(
batched_transaction_details.costs.batched_bpf_execute_cost,
cost.bpf_execution_cost
cost.bpf_execution_cost()
);
}
Err(transaction_error) => match transaction_error {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -734,7 +735,7 @@ mod tests {
let commited_status: Vec<CommitTransactionDetails> = 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();
Expand Down Expand Up @@ -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,
}
}
Expand Down Expand Up @@ -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)
}
Expand Down
103 changes: 57 additions & 46 deletions cost-model/src/cost_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//!

use {
crate::{block_cost_limits::*, transaction_cost::TransactionCost},
crate::{block_cost_limits::*, transaction_cost::*},
log::*,
solana_program_runtime::compute_budget::{
ComputeBudget, DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT, MAX_COMPUTE_UNIT_LIMIT,
Expand Down Expand Up @@ -36,16 +36,21 @@ impl CostModel {
transaction: &SanitizedTransaction,
feature_set: &FeatureSet,
) -> TransactionCost {
let mut tx_cost = TransactionCost::new_with_default_capacity();
if transaction.is_simple_vote_transaction() {
TransactionCost::SimpleVote {
writable_accounts: Self::get_writable_accounts(transaction),
}
} else {
let mut tx_cost = UsageCostDetails::new_with_default_capacity();

tx_cost.signature_cost = Self::get_signature_cost(transaction);
Self::get_write_lock_cost(&mut tx_cost, transaction);
Self::get_transaction_cost(&mut tx_cost, transaction, feature_set);
tx_cost.account_data_size = Self::calculate_account_data_size(transaction);
tx_cost.is_simple_vote = transaction.is_simple_vote_transaction();
tx_cost.signature_cost = Self::get_signature_cost(transaction);
Self::get_write_lock_cost(&mut tx_cost, transaction);
Self::get_transaction_cost(&mut tx_cost, transaction, feature_set);
tx_cost.account_data_size = Self::calculate_account_data_size(transaction);

debug!("transaction {:?} has cost {:?}", transaction, tx_cost);
tx_cost
debug!("transaction {:?} has cost {:?}", transaction, tx_cost);
TransactionCost::Transaction(tx_cost)
}
}

// Calculate cost of loaded accounts size in the same way heap cost is charged at
Expand All @@ -68,24 +73,30 @@ impl CostModel {
transaction.signatures().len() as u64 * SIGNATURE_COST
}

fn get_write_lock_cost(tx_cost: &mut TransactionCost, transaction: &SanitizedTransaction) {
fn get_writable_accounts(transaction: &SanitizedTransaction) -> Vec<Pubkey> {
let message = transaction.message();
message
.account_keys()
.iter()
.enumerate()
.for_each(|(i, k)| {
let is_writable = message.is_writable(i);

if is_writable {
tx_cost.writable_accounts.push(*k);
tx_cost.write_lock_cost += WRITE_LOCK_UNITS;
.filter_map(|(i, k)| {
if message.is_writable(i) {
Some(*k)
} else {
None
}
});
})
.collect()
}

fn get_write_lock_cost(tx_cost: &mut UsageCostDetails, transaction: &SanitizedTransaction) {
tx_cost.writable_accounts = Self::get_writable_accounts(transaction);
tx_cost.write_lock_cost =
WRITE_LOCK_UNITS.saturating_mul(tx_cost.writable_accounts.len() as u64);
}

fn get_transaction_cost(
tx_cost: &mut TransactionCost,
tx_cost: &mut UsageCostDetails,
transaction: &SanitizedTransaction,
feature_set: &FeatureSet,
) {
Expand Down Expand Up @@ -298,7 +309,7 @@ mod tests {
.get(&system_program::id())
.unwrap();

let mut tx_cost = TransactionCost::default();
let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(
&mut tx_cost,
&simple_transaction,
Expand Down Expand Up @@ -327,7 +338,7 @@ mod tests {
let token_transaction = SanitizedTransaction::from_transaction_for_tests(tx);
debug!("token_transaction {:?}", token_transaction);

let mut tx_cost = TransactionCost::default();
let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(
&mut tx_cost,
&token_transaction,
Expand Down Expand Up @@ -364,7 +375,7 @@ mod tests {
);
let token_transaction = SanitizedTransaction::from_transaction_for_tests(tx);

let mut tx_cost = TransactionCost::default();
let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(
&mut tx_cost,
&token_transaction,
Expand Down Expand Up @@ -414,7 +425,7 @@ mod tests {
);
let token_transaction = SanitizedTransaction::from_transaction_for_tests(tx);

let mut tx_cost = TransactionCost::default();
let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(
&mut tx_cost,
&token_transaction,
Expand Down Expand Up @@ -446,7 +457,7 @@ mod tests {
.unwrap();
let expected_cost = program_cost * 2;

let mut tx_cost = TransactionCost::default();
let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(&mut tx_cost, &tx, &FeatureSet::all_enabled());
assert_eq!(expected_cost, tx_cost.builtins_execution_cost);
assert_eq!(0, tx_cost.bpf_execution_cost);
Expand Down Expand Up @@ -478,7 +489,7 @@ mod tests {
debug!("many random transaction {:?}", tx);

let expected_cost = DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64 * 2;
let mut tx_cost = TransactionCost::default();
let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(&mut tx_cost, &tx, &FeatureSet::all_enabled());
assert_eq!(0, tx_cost.builtins_execution_cost);
assert_eq!(expected_cost, tx_cost.bpf_execution_cost);
Expand Down Expand Up @@ -509,11 +520,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]
Expand All @@ -539,12 +550,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()
);
}

Expand All @@ -568,12 +579,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()
);
}

Expand Down Expand Up @@ -607,12 +618,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()
);
}

Expand Down Expand Up @@ -640,12 +651,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()
);
}

Expand Down Expand Up @@ -705,7 +716,7 @@ mod tests {
.unwrap();
let expected_bpf_cost = DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT;

let mut tx_cost = TransactionCost::default();
let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(&mut tx_cost, &transaction, &FeatureSet::all_enabled());

assert_eq!(expected_builtin_cost, tx_cost.builtins_execution_cost);
Expand Down
Loading