Skip to content

Commit

Permalink
Add functions to collect executed transactions fee in details;
Browse files Browse the repository at this point in the history
  • Loading branch information
tao-stones committed Feb 29, 2024
1 parent 8ad125d commit 074d264
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 1 deletion.
90 changes: 89 additions & 1 deletion runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ use {
self, include_loaded_accounts_data_size_in_fee_calculation,
remove_rounding_in_fee_calculation, FeatureSet,
},
fee::FeeStructure,
fee::{FeeDetails, FeeStructure},
fee_calculator::{FeeCalculator, FeeRateGovernor},
genesis_config::{ClusterType, GenesisConfig},
hard_forks::HardForks,
Expand Down Expand Up @@ -252,6 +252,24 @@ impl AddAssign for SquashTiming {
}
}

#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
#[serde(rename_all = "camelCase")]
pub(crate) struct CollectorFeeDetails {
pub transaction_fee: u64,
pub priority_fee: u64,
}

impl CollectorFeeDetails {
pub(crate) fn add(&mut self, fee_details: &FeeDetails) {
self.transaction_fee = self
.transaction_fee
.saturating_add(fee_details.transaction_fee());
self.priority_fee = self
.priority_fee
.saturating_add(fee_details.prioritization_fee());
}
}

#[derive(Debug)]
pub struct BankRc {
/// where all the Accounts are stored
Expand Down Expand Up @@ -546,6 +564,7 @@ impl PartialEq for Bank {
loaded_programs_cache: _,
epoch_reward_status: _,
transaction_processor: _,
collector_fee_details,
// Ignore new fields explicitly if they do not impact PartialEq.
// Adding ".." will remove compile-time checks that if a new field
// is added to the struct, this PartialEq is accordingly updated.
Expand Down Expand Up @@ -579,6 +598,8 @@ impl PartialEq for Bank {
&& *stakes_cache.stakes() == *other.stakes_cache.stakes()
&& epoch_stakes == &other.epoch_stakes
&& is_delta.load(Relaxed) == other.is_delta.load(Relaxed)
&& *collector_fee_details.read().unwrap()
== *other.collector_fee_details.read().unwrap()
}
}

Expand Down Expand Up @@ -806,6 +827,9 @@ pub struct Bank {
epoch_reward_status: EpochRewardStatus,

transaction_processor: TransactionBatchProcessor<BankForks>,

/// Collected fee details
collector_fee_details: RwLock<CollectorFeeDetails>,
}

struct VoteWithStakeDelegations {
Expand Down Expand Up @@ -992,6 +1016,7 @@ impl Bank {
))),
epoch_reward_status: EpochRewardStatus::default(),
transaction_processor: TransactionBatchProcessor::default(),
collector_fee_details: RwLock::new(CollectorFeeDetails::default()),
};

bank.transaction_processor = TransactionBatchProcessor::new(
Expand Down Expand Up @@ -1310,6 +1335,7 @@ impl Bank {
loaded_programs_cache: parent.loaded_programs_cache.clone(),
epoch_reward_status: parent.epoch_reward_status.clone(),
transaction_processor: TransactionBatchProcessor::default(),
collector_fee_details: RwLock::new(CollectorFeeDetails::default()),
};

new.transaction_processor = TransactionBatchProcessor::new(
Expand Down Expand Up @@ -1827,6 +1853,8 @@ impl Bank {
))),
epoch_reward_status: fields.epoch_reward_status,
transaction_processor: TransactionBatchProcessor::default(),
// collector_fee_details is not serialized to snapshot
collector_fee_details: RwLock::new(CollectorFeeDetails::default()),
};

bank.transaction_processor = TransactionBatchProcessor::new(
Expand Down Expand Up @@ -4864,6 +4892,66 @@ impl Bank {
results
}

// Note: this function is not yet used; next PR will call it behind a feature gate
#[allow(dead_code)]
fn filter_program_errors_and_collect_fee_details(
&self,
txs: &[SanitizedTransaction],
execution_results: &[TransactionExecutionResult],
) -> Vec<Result<()>> {
let mut accumulated_fee_details = FeeDetails::default();

let results = txs
.iter()
.zip(execution_results)
.map(|(tx, execution_result)| {
let (execution_status, durable_nonce_fee) = match &execution_result {
TransactionExecutionResult::Executed { details, .. } => {
Ok((&details.status, details.durable_nonce_fee.as_ref()))
}
TransactionExecutionResult::NotExecuted(err) => Err(err.clone()),
}?;
let is_nonce = durable_nonce_fee.is_some();

let message = tx.message();
let fee_details = self.fee_structure.calculate_fee_details(
message,
&process_compute_budget_instructions(message.program_instructions_iter())
.unwrap_or_default()
.into(),
self.feature_set
.is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()),
);

// In case of instruction error, even though no accounts
// were stored we still need to charge the payer the
// fee.
//
//...except nonce accounts, which already have their
// post-load, fee deducted, pre-execute account state
// stored
if execution_status.is_err() && !is_nonce {
self.withdraw(
tx.message().fee_payer(),
fee_details.total_fee(
self.feature_set
.is_active(&remove_rounding_in_fee_calculation::id()),
),
)?;
}

accumulated_fee_details.accumulate(&fee_details);
Ok(())
})
.collect();

self.collector_fee_details
.write()
.unwrap()
.add(&accumulated_fee_details);
results
}

/// `committed_transactions_count` is the number of transactions out of `sanitized_txs`
/// that was executed. Of those, `committed_transactions_count`,
/// `committed_with_failure_result_count` is the number of executed transactions that returned
Expand Down
17 changes: 17 additions & 0 deletions sdk/src/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@ impl FeeDetails {
(total_fee as f64).round() as u64
}
}

pub fn accumulate(&mut self, fee_details: &FeeDetails) {
self.transaction_fee = self
.transaction_fee
.saturating_add(fee_details.transaction_fee);
self.prioritization_fee = self
.prioritization_fee
.saturating_add(fee_details.prioritization_fee)
}

pub fn transaction_fee(&self) -> u64 {
self.transaction_fee
}

pub fn prioritization_fee(&self) -> u64 {
self.prioritization_fee
}
}

pub const ACCOUNT_DATA_COST_PAGE_SIZE: u64 = 32_u64.saturating_mul(1024);
Expand Down

0 comments on commit 074d264

Please sign in to comment.