Skip to content

Commit

Permalink
loaded accounts data size cost does not apply to vote transaction (#3…
Browse files Browse the repository at this point in the history
…3235)

* loaded accounts data size cost does not apply to vote transaction

* add a test for vote cost

(cherry picked from commit dfaec78)

# Conflicts:
#	cost-model/src/transaction_cost.rs
  • Loading branch information
tao-stones authored and mergify[bot] committed Sep 14, 2023
1 parent 988641d commit fdbbf90
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 1 deletion.
146 changes: 146 additions & 0 deletions cost-model/src/transaction_cost.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use solana_sdk::pubkey::Pubkey;

const MAX_WRITABLE_ACCOUNTS: usize = 256;

// costs are stored in number of 'compute unit's
#[derive(Debug)]
pub struct TransactionCost {
pub writable_accounts: Vec<Pubkey>,
pub signature_cost: u64,
pub write_lock_cost: u64,
pub data_bytes_cost: u64,
pub builtins_execution_cost: u64,
pub bpf_execution_cost: u64,
pub loaded_accounts_data_size_cost: u64,
pub account_data_size: u64,
pub is_simple_vote: bool,
}

impl Default for TransactionCost {
fn default() -> Self {
Self {
writable_accounts: Vec::with_capacity(MAX_WRITABLE_ACCOUNTS),
signature_cost: 0u64,
write_lock_cost: 0u64,
data_bytes_cost: 0u64,
builtins_execution_cost: 0u64,
bpf_execution_cost: 0u64,
loaded_accounts_data_size_cost: 0u64,
account_data_size: 0u64,
is_simple_vote: false,
}
}
}

#[cfg(test)]
impl PartialEq for TransactionCost {
fn eq(&self, other: &Self) -> bool {
fn to_hash_set(v: &[Pubkey]) -> std::collections::HashSet<&Pubkey> {
v.iter().collect()
}

self.signature_cost == other.signature_cost
&& self.write_lock_cost == other.write_lock_cost
&& self.data_bytes_cost == other.data_bytes_cost
&& self.builtins_execution_cost == other.builtins_execution_cost
&& self.bpf_execution_cost == other.bpf_execution_cost
&& self.loaded_accounts_data_size_cost == other.loaded_accounts_data_size_cost
&& self.account_data_size == other.account_data_size
&& self.is_simple_vote == other.is_simple_vote
&& to_hash_set(&self.writable_accounts) == to_hash_set(&other.writable_accounts)
}
}

#[cfg(test)]
impl Eq for TransactionCost {}

impl TransactionCost {
pub fn new_with_capacity(capacity: usize) -> Self {
Self {
writable_accounts: Vec::with_capacity(capacity),
..Self::default()
}
}

pub fn new_with_default_capacity() -> Self {
Self::default()
}

pub fn sum(&self) -> u64 {
if self.is_simple_vote {
self.signature_cost
.saturating_add(self.write_lock_cost)
.saturating_add(self.data_bytes_cost)
.saturating_add(self.builtins_execution_cost)
} else {
self.signature_cost
.saturating_add(self.write_lock_cost)
.saturating_add(self.data_bytes_cost)
.saturating_add(self.builtins_execution_cost)
.saturating_add(self.bpf_execution_cost)
.saturating_add(self.loaded_accounts_data_size_cost)
}
}
}

#[cfg(test)]
mod tests {
use {
crate::cost_model::CostModel,
solana_sdk::{
feature_set::FeatureSet,
hash::Hash,
message::SimpleAddressLoader,
signer::keypair::Keypair,
transaction::{MessageHash, SanitizedTransaction, VersionedTransaction},
},
solana_vote_program::vote_transaction,
};

#[test]
fn test_vote_transaction_cost() {
solana_logger::setup();
let node_keypair = Keypair::new();
let vote_keypair = Keypair::new();
let auth_keypair = Keypair::new();
let transaction = vote_transaction::new_vote_transaction(
vec![],
Hash::default(),
Hash::default(),
&node_keypair,
&vote_keypair,
&auth_keypair,
None,
);

// create a sanitized vote transaction
let vote_transaction = SanitizedTransaction::try_create(
VersionedTransaction::from(transaction.clone()),
MessageHash::Compute,
Some(true),
SimpleAddressLoader::Disabled,
)
.unwrap();

// create a identical sanitized transaction, but identified as non-vote
let none_vote_transaction = SanitizedTransaction::try_create(
VersionedTransaction::from(transaction),
MessageHash::Compute,
Some(false),
SimpleAddressLoader::Disabled,
)
.unwrap();

// expected vote tx cost: 2 write locks, 2 sig, 1 vite ix, and 11 CU tx data cost
let expected_vote_cost = 4151;
// expected non-vote tx cost would include default loaded accounts size cost (16384) additionally
let expected_none_vote_cost = 20535;

let vote_cost = CostModel::calculate_cost(&vote_transaction, &FeatureSet::all_enabled());
let none_vote_cost =
CostModel::calculate_cost(&none_vote_transaction, &FeatureSet::all_enabled());

assert_eq!(expected_vote_cost, vote_cost.sum());
assert_eq!(expected_none_vote_cost, none_vote_cost.sum());
}
}
2 changes: 1 addition & 1 deletion runtime/src/cost_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ mod tests {
)
.unwrap();
let mut tx_cost = TransactionCost::new_with_capacity(1);
tx_cost.bpf_execution_cost = 10;
tx_cost.builtins_execution_cost = 10;
tx_cost.writable_accounts.push(mint_keypair.pubkey());
tx_cost.is_simple_vote = true;

Expand Down

0 comments on commit fdbbf90

Please sign in to comment.