Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
bank::calculate_fee returns both total_fee and max_units to streamlin…
Browse files Browse the repository at this point in the history
…e fee-per-cu computing;

avoid read-lock blockhash_queue when getting lamports-per-signature;
  • Loading branch information
tao-stones committed Mar 30, 2022
1 parent 1936a2f commit b040999
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 52 deletions.
25 changes: 11 additions & 14 deletions core/src/unprocessed_packet_batches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use {
retain_mut::RetainMut,
solana_gossip::weighted_shuffle::WeightedShuffle,
solana_perf::packet::{limited_deserialize, Packet, PacketBatch},
solana_program_runtime::compute_budget::ComputeBudget,
solana_runtime::bank::Bank,
solana_sdk::{
clock::Slot,
feature_set::tx_wide_compute_cap,
hash::Hash,
message::{
v0::{self},
Expand Down Expand Up @@ -33,7 +33,7 @@ struct FeePerCu {
impl FeePerCu {
fn too_old(&self, slot: &Slot) -> bool {
const MAX_SLOT_AGE: Slot = 1;
slot - &self.slot >= MAX_SLOT_AGE
slot - self.slot >= MAX_SLOT_AGE
}
}

Expand Down Expand Up @@ -245,11 +245,11 @@ impl UnprocessedPacketBatches {
let bank = bank.as_ref().unwrap();
let deserialized_packet = self.locate_packet_mut(locator)?;
if let Some(cached_fee_per_cu) =
Self::get_cached_fee_per_cu(&deserialized_packet, &bank.slot())
Self::get_cached_fee_per_cu(deserialized_packet, &bank.slot())
{
Some(cached_fee_per_cu)
} else {
let computed_fee_per_cu = Self::compute_fee_per_cu(&deserialized_packet, bank);
let computed_fee_per_cu = Self::compute_fee_per_cu(deserialized_packet, bank);
if let Some(computed_fee_per_cu) = computed_fee_per_cu {
deserialized_packet.fee_per_cu = Some(FeePerCu {
fee_per_cu: computed_fee_per_cu,
Expand Down Expand Up @@ -279,16 +279,13 @@ impl UnprocessedPacketBatches {
fn compute_fee_per_cu(deserialized_packet: &DeserializedPacket, bank: &Bank) -> Option<u64> {
let sanitized_message =
Self::sanitize_message(&deserialized_packet.versioned_transaction.message, bank)?;
let total_fee = bank.get_fee_for_message(&sanitized_message)?;

// TODO refactor `bank.get_fee_for_message()` to return both fee and CUs to avoid
// calling ComputeBudget twice.
let mut compute_budget = ComputeBudget::default();
let _ = compute_budget
.process_message(&sanitized_message, false)
.ok()?;

Some(total_fee / compute_budget.max_units)
let (total_fee, max_units) = Bank::calculate_fee(
&sanitized_message,
bank.get_lamports_per_signature(),
&bank.fee_structure,
bank.feature_set.is_active(&tx_wide_compute_cap::id()),
);
Some(total_fee / max_units)
}

fn get_cached_fee_per_cu(deserialized_packet: &DeserializedPacket, slot: &Slot) -> Option<u64> {
Expand Down
23 changes: 12 additions & 11 deletions runtime/src/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,16 +507,17 @@ impl Accounts {
.unwrap_or_else(|| {
hash_queue.get_lamports_per_signature(tx.message().recent_blockhash())
});
let fee = if let Some(lamports_per_signature) = lamports_per_signature {
Bank::calculate_fee(
tx.message(),
lamports_per_signature,
fee_structure,
feature_set.is_active(&tx_wide_compute_cap::id()),
)
} else {
return (Err(TransactionError::BlockhashNotFound), None);
};
let (fee, _max_units) =
if let Some(lamports_per_signature) = lamports_per_signature {
Bank::calculate_fee(
tx.message(),
lamports_per_signature,
fee_structure,
feature_set.is_active(&tx_wide_compute_cap::id()),
)
} else {
return (Err(TransactionError::BlockhashNotFound), None);
};

let loaded_transaction = match self.load_transaction(
ancestors,
Expand Down Expand Up @@ -1589,7 +1590,7 @@ mod tests {
instructions,
);

let fee = Bank::calculate_fee(
let (fee, _max_units) = Bank::calculate_fee(
&SanitizedMessage::try_from(tx.message().clone()).unwrap(),
10,
&FeeStructure::default(),
Expand Down
72 changes: 45 additions & 27 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3308,12 +3308,15 @@ impl Bank {
NoncePartial::new(address, account).lamports_per_signature()
})
})?;
Some(Self::calculate_fee(
message,
lamports_per_signature,
&self.fee_structure,
self.feature_set.is_active(&tx_wide_compute_cap::id()),
))
Some(
Self::calculate_fee(
message,
lamports_per_signature,
&self.fee_structure,
self.feature_set.is_active(&tx_wide_compute_cap::id()),
)
.0,
)
}

pub fn get_fee_for_message_with_lamports_per_signature(
Expand All @@ -3327,6 +3330,7 @@ impl Bank {
&self.fee_structure,
self.feature_set.is_active(&tx_wide_compute_cap::id()),
)
.0
}

#[deprecated(
Expand Down Expand Up @@ -4304,12 +4308,13 @@ impl Bank {
}

/// Calculate fee for `SanitizedMessage`
/// returns (total_fee, max_units)
pub fn calculate_fee(
message: &SanitizedMessage,
lamports_per_signature: u64,
fee_structure: &FeeStructure,
tx_wide_compute_cap: bool,
) -> u64 {
) -> (u64, u64) {
if tx_wide_compute_cap {
// Fee based on compute units and signatures
const BASE_CONGESTION: f64 = 5_000.0;
Expand Down Expand Up @@ -4341,15 +4346,21 @@ impl Bank {
.unwrap_or_default()
});

((additional_fee
.saturating_add(signature_fee)
.saturating_add(write_lock_fee)
.saturating_add(compute_fee) as f64)
* congestion_multiplier)
.round() as u64
(
((additional_fee
.saturating_add(signature_fee)
.saturating_add(write_lock_fee)
.saturating_add(compute_fee) as f64)
* congestion_multiplier)
.round() as u64,
compute_budget.max_units,
)
} else {
// Fee based only on signatures
lamports_per_signature.saturating_mul(Self::get_num_signatures_in_message(message))
(
lamports_per_signature.saturating_mul(Self::get_num_signatures_in_message(message)),
compute_budget::MAX_UNITS as u64,
)
}
}

Expand Down Expand Up @@ -4384,7 +4395,7 @@ impl Bank {

let lamports_per_signature =
lamports_per_signature.ok_or(TransactionError::BlockhashNotFound)?;
let fee = Self::calculate_fee(
let (fee, _units) = Self::calculate_fee(
tx.message(),
lamports_per_signature,
&self.fee_structure,
Expand Down Expand Up @@ -9537,7 +9548,7 @@ pub(crate) mod tests {
} = create_genesis_config_with_leader(mint, &leader, 3);
genesis_config.fee_rate_governor = FeeRateGovernor::new(4, 0); // something divisible by 2

let expected_fee_paid = Bank::calculate_fee(
let (expected_fee_paid, _max_units) = Bank::calculate_fee(
&SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap(),
genesis_config
.fee_rate_governor
Expand Down Expand Up @@ -9722,7 +9733,7 @@ pub(crate) mod tests {
let tx = system_transaction::transfer(&mint_keypair, &key.pubkey(), 1, cheap_blockhash);
assert_eq!(bank.process_transaction(&tx), Ok(()));
assert_eq!(bank.get_balance(&key.pubkey()), 1);
let cheap_fee = Bank::calculate_fee(
let (cheap_fee, _max_units) = Bank::calculate_fee(
&SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap(),
cheap_lamports_per_signature,
&FeeStructure::default(),
Expand All @@ -9739,7 +9750,7 @@ pub(crate) mod tests {
let tx = system_transaction::transfer(&mint_keypair, &key.pubkey(), 1, expensive_blockhash);
assert_eq!(bank.process_transaction(&tx), Ok(()));
assert_eq!(bank.get_balance(&key.pubkey()), 1);
let expensive_fee = Bank::calculate_fee(
let (expensive_fee, _max_units) = Bank::calculate_fee(
&SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap(),
expensive_lamports_per_signature,
&FeeStructure::default(),
Expand Down Expand Up @@ -9860,7 +9871,8 @@ pub(crate) mod tests {
.lamports_per_signature,
&FeeStructure::default(),
true,
) * 2
)
.0 * 2
)
.0
);
Expand Down Expand Up @@ -16152,13 +16164,13 @@ pub(crate) mod tests {
SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap();
assert_eq!(
Bank::calculate_fee(&message, 0, &FeeStructure::default(), false),
0
(0, compute_budget::MAX_UNITS as u64)
);

// One signature, a fee.
assert_eq!(
Bank::calculate_fee(&message, 1, &FeeStructure::default(), false),
1
(1, compute_budget::MAX_UNITS as u64)
);

// Two signatures, double the fee.
Expand All @@ -16169,7 +16181,7 @@ pub(crate) mod tests {
let message = SanitizedMessage::try_from(Message::new(&[ix0, ix1], Some(&key0))).unwrap();
assert_eq!(
Bank::calculate_fee(&message, 2, &FeeStructure::default(), false),
4
(4, compute_budget::MAX_UNITS as u64)
);
}

Expand All @@ -16185,7 +16197,10 @@ pub(crate) mod tests {
SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap();
assert_eq!(
Bank::calculate_fee(&message, 1, &fee_structure, true),
max_fee + lamports_per_signature
(
max_fee + lamports_per_signature,
compute_budget::MAX_UNITS as u64
)
);

// Three signatures, two instructions, no unit request
Expand All @@ -16197,7 +16212,10 @@ pub(crate) mod tests {
.unwrap();
assert_eq!(
Bank::calculate_fee(&message, 1, &fee_structure, true),
max_fee + 3 * lamports_per_signature
(
max_fee + 3 * lamports_per_signature,
compute_budget::MAX_UNITS as u64
)
);

// Explicit fee schedule
Expand All @@ -16223,7 +16241,7 @@ pub(crate) mod tests {
let message =
SanitizedMessage::try_from(Message::new(&[ix0, ix1], Some(&Pubkey::new_unique())))
.unwrap();
let fee = Bank::calculate_fee(&message, 1, &fee_structure, true);
let (fee, _units) = Bank::calculate_fee(&message, 1, &fee_structure, true);
assert_eq!(
fee,
sol_to_lamports(pair.1) + lamports_per_signature + ADDITIONAL_FEE
Expand Down Expand Up @@ -16259,7 +16277,7 @@ pub(crate) mod tests {
.unwrap();
assert_eq!(
Bank::calculate_fee(&message, 1, &FeeStructure::default(), false),
2
(2, compute_budget::MAX_UNITS as u64)
);

secp_instruction1.data = vec![0];
Expand All @@ -16271,7 +16289,7 @@ pub(crate) mod tests {
.unwrap();
assert_eq!(
Bank::calculate_fee(&message, 1, &FeeStructure::default(), false),
11
(11, compute_budget::MAX_UNITS as u64)
);
}

Expand Down

0 comments on commit b040999

Please sign in to comment.