TransactionState: add TransactionCost (#34881)

This commit is contained in:
Andrew Fitzgerald 2024-01-22 16:21:06 -08:00 committed by GitHub
parent 2f744f1639
commit 45a2a701de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 69 additions and 12 deletions

View File

@ -191,9 +191,7 @@ impl PrioGraphScheduler {
saturating_add_assign!(num_scheduled, 1);
let sanitized_transaction_ttl = transaction_state.transition_to_pending();
let cu_limit = transaction_state
.transaction_priority_details()
.compute_unit_limit;
let cost = transaction_state.transaction_cost().sum();
let SanitizedTransactionTTL {
transaction,
@ -203,7 +201,7 @@ impl PrioGraphScheduler {
batches.transactions[thread_id].push(transaction);
batches.ids[thread_id].push(id.id);
batches.max_age_slots[thread_id].push(max_age_slot);
saturating_add_assign!(batches.total_cus[thread_id], cu_limit);
saturating_add_assign!(batches.total_cus[thread_id], cost);
// If target batch size is reached, send only this batch.
if batches.ids[thread_id].len() >= TARGET_NUM_TRANSACTIONS_PER_BATCH {
@ -492,10 +490,12 @@ mod tests {
crate::banking_stage::consumer::TARGET_NUM_TRANSACTIONS_PER_BATCH,
crossbeam_channel::{unbounded, Receiver},
itertools::Itertools,
solana_cost_model::cost_model::CostModel,
solana_runtime::transaction_priority_details::TransactionPriorityDetails,
solana_sdk::{
compute_budget::ComputeBudgetInstruction, hash::Hash, message::Message, pubkey::Pubkey,
signature::Keypair, signer::Signer, system_instruction, transaction::Transaction,
compute_budget::ComputeBudgetInstruction, feature_set::FeatureSet, hash::Hash,
message::Message, pubkey::Pubkey, signature::Keypair, signer::Signer,
system_instruction, transaction::Transaction,
},
std::borrow::Borrow,
};
@ -568,6 +568,7 @@ mod tests {
let id = TransactionId::new(index as u64);
let transaction =
prioritized_tranfers(from_keypair.borrow(), to_pubkeys, lamports, priority);
let transaction_cost = CostModel::calculate_cost(&transaction, &FeatureSet::default());
let transaction_ttl = SanitizedTransactionTTL {
transaction,
max_age_slot: Slot::MAX,
@ -579,6 +580,7 @@ mod tests {
priority,
compute_unit_limit: 1,
},
transaction_cost,
);
}

View File

@ -18,6 +18,7 @@ use {
},
crossbeam_channel::RecvTimeoutError,
solana_accounts_db::transaction_error_metrics::TransactionErrorMetrics,
solana_cost_model::cost_model::CostModel,
solana_measure::measure_us,
solana_runtime::{bank::Bank, bank_forks::BankForks},
solana_sdk::{
@ -342,6 +343,8 @@ impl SchedulerController {
{
saturating_add_assign!(post_transaction_check_count, 1);
let transaction_id = self.transaction_id_generator.next();
let transaction_cost = CostModel::calculate_cost(&transaction, &bank.feature_set);
let transaction_ttl = SanitizedTransactionTTL {
transaction,
max_age_slot: last_slot_in_epoch,
@ -351,6 +354,7 @@ impl SchedulerController {
transaction_id,
transaction_ttl,
priority_details,
transaction_cost,
) {
saturating_add_assign!(self.count_metrics.num_dropped_on_capacity, 1);
}

View File

@ -1,4 +1,5 @@
use {
solana_cost_model::transaction_cost::TransactionCost,
solana_runtime::transaction_priority_details::TransactionPriorityDetails,
solana_sdk::{slot_history::Slot, transaction::SanitizedTransaction},
};
@ -34,11 +35,13 @@ pub(crate) enum TransactionState {
Unprocessed {
transaction_ttl: SanitizedTransactionTTL,
transaction_priority_details: TransactionPriorityDetails,
transaction_cost: TransactionCost,
forwarded: bool,
},
/// The transaction is currently scheduled or being processed.
Pending {
transaction_priority_details: TransactionPriorityDetails,
transaction_cost: TransactionCost,
forwarded: bool,
},
}
@ -48,10 +51,12 @@ impl TransactionState {
pub(crate) fn new(
transaction_ttl: SanitizedTransactionTTL,
transaction_priority_details: TransactionPriorityDetails,
transaction_cost: TransactionCost,
) -> Self {
Self::Unprocessed {
transaction_ttl,
transaction_priority_details,
transaction_cost,
forwarded: false,
}
}
@ -70,6 +75,18 @@ impl TransactionState {
}
}
/// Returns a reference to the transaction cost of the transaction.
pub(crate) fn transaction_cost(&self) -> &TransactionCost {
match self {
Self::Unprocessed {
transaction_cost, ..
} => transaction_cost,
Self::Pending {
transaction_cost, ..
} => transaction_cost,
}
}
/// Returns the priority of the transaction.
pub(crate) fn priority(&self) -> u64 {
self.transaction_priority_details().priority
@ -103,10 +120,12 @@ impl TransactionState {
TransactionState::Unprocessed {
transaction_ttl,
transaction_priority_details,
transaction_cost,
forwarded,
} => {
*self = TransactionState::Pending {
transaction_priority_details,
transaction_cost,
forwarded,
};
transaction_ttl
@ -128,11 +147,13 @@ impl TransactionState {
TransactionState::Unprocessed { .. } => panic!("already unprocessed"),
TransactionState::Pending {
transaction_priority_details,
transaction_cost,
forwarded,
} => {
*self = Self::Unprocessed {
transaction_ttl,
transaction_priority_details,
transaction_cost,
forwarded,
}
}
@ -162,6 +183,9 @@ impl TransactionState {
priority: 0,
compute_unit_limit: 0,
},
transaction_cost: TransactionCost::SimpleVote {
writable_accounts: vec![],
},
forwarded: false,
},
)
@ -172,6 +196,7 @@ impl TransactionState {
mod tests {
use {
super::*,
solana_cost_model::transaction_cost::UsageCostDetails,
solana_sdk::{
compute_budget::ComputeBudgetInstruction, hash::Hash, message::Message,
signature::Keypair, signer::Signer, system_instruction, transaction::Transaction,
@ -190,6 +215,10 @@ mod tests {
];
let message = Message::new(&ixs, Some(&from_keypair.pubkey()));
let tx = Transaction::new(&[&from_keypair], message, Hash::default());
let transaction_cost = TransactionCost::Transaction(UsageCostDetails {
signature_cost: 5000,
..UsageCostDetails::default()
});
let transaction_ttl = SanitizedTransactionTTL {
transaction: SanitizedTransaction::from_transaction_for_tests(tx),
@ -202,6 +231,7 @@ mod tests {
priority,
compute_unit_limit: 0,
},
transaction_cost,
)
}

View File

@ -5,6 +5,7 @@ use {
},
crate::banking_stage::scheduler_messages::TransactionId,
min_max_heap::MinMaxHeap,
solana_cost_model::transaction_cost::TransactionCost,
solana_runtime::transaction_priority_details::TransactionPriorityDetails,
std::collections::HashMap,
};
@ -125,12 +126,17 @@ impl TransactionStateContainer {
transaction_id: TransactionId,
transaction_ttl: SanitizedTransactionTTL,
transaction_priority_details: TransactionPriorityDetails,
transaction_cost: TransactionCost,
) -> bool {
let priority_id =
TransactionPriorityId::new(transaction_priority_details.priority, transaction_id);
self.id_to_transaction_state.insert(
transaction_id,
TransactionState::new(transaction_ttl, transaction_priority_details),
TransactionState::new(
transaction_ttl,
transaction_priority_details,
transaction_cost,
),
);
self.push_id_into_queue(priority_id)
}
@ -176,8 +182,10 @@ impl TransactionStateContainer {
mod tests {
use {
super::*,
solana_cost_model::cost_model::CostModel,
solana_sdk::{
compute_budget::ComputeBudgetInstruction,
feature_set::FeatureSet,
hash::Hash,
message::Message,
signature::Keypair,
@ -188,7 +196,13 @@ mod tests {
},
};
fn test_transaction(priority: u64) -> (SanitizedTransactionTTL, TransactionPriorityDetails) {
fn test_transaction(
priority: u64,
) -> (
SanitizedTransactionTTL,
TransactionPriorityDetails,
TransactionCost,
) {
let from_keypair = Keypair::new();
let ixs = vec![
system_instruction::transfer(
@ -199,10 +213,14 @@ mod tests {
ComputeBudgetInstruction::set_compute_unit_price(priority),
];
let message = Message::new(&ixs, Some(&from_keypair.pubkey()));
let tx = Transaction::new(&[&from_keypair], message, Hash::default());
let tx = SanitizedTransaction::from_transaction_for_tests(Transaction::new(
&[&from_keypair],
message,
Hash::default(),
));
let transaction_cost = CostModel::calculate_cost(&tx, &FeatureSet::default());
let transaction_ttl = SanitizedTransactionTTL {
transaction: SanitizedTransaction::from_transaction_for_tests(tx),
transaction: tx,
max_age_slot: Slot::MAX,
};
(
@ -211,17 +229,20 @@ mod tests {
priority,
compute_unit_limit: 0,
},
transaction_cost,
)
}
fn push_to_container(container: &mut TransactionStateContainer, num: usize) {
for id in 0..num as u64 {
let priority = id;
let (transaction_ttl, transaction_priority_details) = test_transaction(priority);
let (transaction_ttl, transaction_priority_details, transaction_cost) =
test_transaction(priority);
container.insert_new_transaction(
TransactionId::new(id),
transaction_ttl,
transaction_priority_details,
transaction_cost,
);
}
}