Skip to content

Commit

Permalink
feat: support committing fee-only transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry committed Aug 5, 2024
1 parent 919a5b5 commit 86dda02
Show file tree
Hide file tree
Showing 14 changed files with 353 additions and 175 deletions.
2 changes: 1 addition & 1 deletion core/src/banking_stage/committer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl Committer {
// transaction committed to block. qos_service uses these information to adjust
// reserved block space.
Ok(committed_tx) => CommitTransactionDetails::Committed {
compute_units: committed_tx.execution_details.executed_units,
compute_units: committed_tx.executed_units,
loaded_accounts_data_size: committed_tx
.loaded_account_stats
.loaded_accounts_data_size,
Expand Down
6 changes: 2 additions & 4 deletions ledger-tool/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,16 +708,14 @@ fn record_transactions(
.collect();

let is_simple_vote_tx = tx.is_simple_vote_transaction();
let execution_results = commit_result
.ok()
.map(|committed_tx| committed_tx.execution_details);
let commit_details = commit_result.ok().map(|committed_tx| committed_tx.into());

TransactionDetails {
signature: tx.signature().to_string(),
accounts,
instructions,
is_simple_vote_tx,
execution_results,
commit_details,
index,
}
})
Expand Down
5 changes: 1 addition & 4 deletions ledger/src/blockstore_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ fn check_block_cost_limits(
if let Ok(committed_tx) = commit_result {
Some(CostModel::calculate_cost_for_executed_transaction(
tx,
committed_tx.execution_details.executed_units,
committed_tx.executed_units,
committed_tx.loaded_account_stats.loaded_accounts_data_size,
&bank.feature_set,
))
Expand Down Expand Up @@ -2245,9 +2245,6 @@ pub mod tests {
},
solana_svm::{
transaction_commit_result::CommittedTransaction,
transaction_execution_result::{
TransactionExecutionDetails, TransactionLoadedAccountsStats,
},
transaction_processor::ExecutionRecordingConfig,
},
solana_vote::vote_account::VoteAccount,
Expand Down
19 changes: 6 additions & 13 deletions rpc/src/transaction_status_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ use {
blockstore::Blockstore,
blockstore_processor::{TransactionStatusBatch, TransactionStatusMessage},
},
solana_svm::{
transaction_commit_result::CommittedTransaction,
transaction_execution_result::TransactionExecutionDetails,
},
solana_svm::transaction_commit_result::CommittedTransaction,
solana_transaction_status::{
extract_and_fmt_memos, map_inner_instructions, Reward, TransactionStatusMeta,
},
Expand Down Expand Up @@ -96,15 +93,11 @@ impl TransactionStatusService {
) {
if let Ok(committed_tx) = commit_result {
let CommittedTransaction {
execution_details:
TransactionExecutionDetails {
status,
log_messages,
inner_instructions,
return_data,
executed_units,
..
},
status,
log_messages,
inner_instructions,
return_data,
executed_units,
fee_details,
rent_debits,
..
Expand Down
148 changes: 93 additions & 55 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ use {
},
solana_svm::{
account_loader::{
collect_rent_from_account, CheckedTransactionDetails, TransactionCheckResult,
collect_rent_from_account, CheckedTransactionDetails, LoadedTransaction,
TransactionCheckResult,
},
account_overrides::AccountOverrides,
account_saver::collect_accounts_to_store,
Expand All @@ -164,7 +165,8 @@ use {
},
transaction_processing_callback::TransactionProcessingCallback,
transaction_processing_result::{
TransactionProcessingResult, TransactionProcessingResultExtensions,
ProcessedTransaction, TransactionProcessingResult,
TransactionProcessingResultExtensions,
},
transaction_processor::{
ExecutionRecordingConfig, TransactionBatchProcessor, TransactionLogMessages,
Expand Down Expand Up @@ -3095,14 +3097,13 @@ impl Bank {
assert_eq!(sanitized_txs.len(), processing_results.len());
for (tx, processing_result) in sanitized_txs.iter().zip(processing_results) {
if let Ok(processed_tx) = &processing_result {
let details = &processed_tx.execution_details;
// Add the message hash to the status cache to ensure that this message
// won't be processed again with a different signature.
status_cache.insert(
tx.message().recent_blockhash(),
tx.message_hash(),
self.slot(),
details.status.clone(),
processed_tx.status(),
);
// Add the transaction signature to the status cache so that transaction status
// can be queried by transaction signature over RPC. In the future, this should
Expand All @@ -3111,7 +3112,7 @@ impl Bank {
tx.message().recent_blockhash(),
tx.signature(),
self.slot(),
details.status.clone(),
processed_tx.status(),
);
}
}
Expand Down Expand Up @@ -3363,30 +3364,35 @@ impl Bank {
let processing_result = processing_results
.pop()
.unwrap_or(Err(TransactionError::InvalidProgramForExecution));
let flattened_result = processing_result.flattened_result();
let (post_simulation_accounts, logs, return_data, inner_instructions) =
let (post_simulation_accounts, result, logs, return_data, inner_instructions) =
match processing_result {
Ok(processed_tx) => {
let details = processed_tx.execution_details;
let post_simulation_accounts = processed_tx
.loaded_transaction
.accounts
.into_iter()
.take(number_of_accounts)
.collect::<Vec<_>>();
(
post_simulation_accounts,
details.log_messages,
details.return_data,
details.inner_instructions,
)
}
Err(_) => (vec![], None, None, None),
Ok(processed_tx) => match processed_tx {
ProcessedTransaction::Executed(executed_tx) => {
let details = executed_tx.execution_details;
let post_simulation_accounts = executed_tx
.loaded_transaction
.accounts
.into_iter()
.take(number_of_accounts)
.collect::<Vec<_>>();
(
post_simulation_accounts,
details.status,
details.log_messages,
details.return_data,
details.inner_instructions,
)
}
ProcessedTransaction::FeesOnly(fees_only_tx) => {
(vec![], Err(fees_only_tx.load_error), None, None, None)
}
},
Err(error) => (vec![], Err(error), None, None, None),
};
let logs = logs.unwrap_or_default();

TransactionSimulationResult {
result: flattened_result,
result,
logs,
post_simulation_accounts,
units_consumed,
Expand Down Expand Up @@ -3699,7 +3705,8 @@ impl Bank {
.filter_map(|(processing_result, transaction)| {
// Skip log collection for unprocessed transactions
let processed_tx = processing_result.processed_transaction()?;
let execution_details = &processed_tx.execution_details;
// Skip log collection for unexecuted transactions
let execution_details = processed_tx.execution_details()?;
Self::collect_transaction_logs(
&transaction_log_collector_config,
transaction,
Expand Down Expand Up @@ -3849,7 +3856,7 @@ impl Bank {
.iter()
.for_each(|processing_result| match processing_result {
Ok(processed_tx) => {
fees += processed_tx.loaded_transaction.fee_details.total_fee();
fees += processed_tx.fee_details().total_fee();
}
Err(_) => {}
});
Expand All @@ -3868,8 +3875,7 @@ impl Bank {
.iter()
.for_each(|processing_result| match processing_result {
Ok(processed_tx) => {
accumulated_fee_details
.accumulate(&processed_tx.loaded_transaction.fee_details);
accumulated_fee_details.accumulate(&processed_tx.fee_details());
}
Err(_) => {}
});
Expand Down Expand Up @@ -3942,7 +3948,9 @@ impl Bank {
let ((), update_executors_us) = measure_us!({
let mut cache = None;
for processing_result in &processing_results {
if let Some(executed_tx) = processing_result.processed_transaction() {
if let Some(ProcessedTransaction::Executed(executed_tx)) =
processing_result.processed_transaction()
{
let programs_modified_by_tx = &executed_tx.programs_modified_by_tx;
if executed_tx.was_successful() && !programs_modified_by_tx.is_empty() {
cache
Expand All @@ -3958,7 +3966,7 @@ impl Bank {
let accounts_data_len_delta = processing_results
.iter()
.filter_map(|processing_result| processing_result.processed_transaction())
.map(|processed_tx| &processed_tx.execution_details)
.filter_map(|processed_tx| processed_tx.execution_details())
.filter_map(|details| {
details
.status
Expand Down Expand Up @@ -3996,29 +4004,54 @@ impl Bank {
) -> Vec<TransactionCommitResult> {
processing_results
.into_iter()
.map(|processing_result| match processing_result {
Ok(processed_tx) => {
let loaded_tx = &processed_tx.loaded_transaction;
let loaded_account_stats = TransactionLoadedAccountsStats {
loaded_accounts_data_size: loaded_tx.loaded_accounts_data_size,
loaded_accounts_count: loaded_tx.accounts.len(),
};

// Rent is only collected for successfully executed transactions
let rent_debits = if processed_tx.was_successful() {
processed_tx.loaded_transaction.rent_debits
} else {
RentDebits::default()
};

Ok(CommittedTransaction {
loaded_account_stats,
execution_details: processed_tx.execution_details,
fee_details: processed_tx.loaded_transaction.fee_details,
rent_debits,
})
.map(|processing_result| {
match processing_result? {
ProcessedTransaction::Executed(executed_tx) => {
let execution_details = executed_tx.execution_details;
let LoadedTransaction {
rent_debits,
accounts: loaded_accounts,
loaded_accounts_data_size,
fee_details,
..
} = executed_tx.loaded_transaction;

// Rent is only collected for successfully executed transactions
let rent_debits = if execution_details.was_successful() {
rent_debits
} else {
RentDebits::default()
};

Ok(CommittedTransaction {
status: execution_details.status,
log_messages: execution_details.log_messages,
inner_instructions: execution_details.inner_instructions,
return_data: execution_details.return_data,
executed_units: execution_details.executed_units,
fee_details,
rent_debits,
loaded_account_stats: TransactionLoadedAccountsStats {
loaded_accounts_count: loaded_accounts.len(),
loaded_accounts_data_size,
},
})
}
ProcessedTransaction::FeesOnly(fees_only_tx) => Ok(CommittedTransaction {
status: Err(fees_only_tx.load_error),
log_messages: None,
inner_instructions: None,
return_data: None,
executed_units: 0,
rent_debits: RentDebits::default(),
fee_details: fees_only_tx.fee_details,
loaded_account_stats: TransactionLoadedAccountsStats {
loaded_accounts_count: fees_only_tx.rollback_accounts.count(),
loaded_accounts_data_size: fees_only_tx.rollback_accounts.data_size()
as u32,
},
}),
}
Err(err) => Err(err),
})
.collect()
}
Expand All @@ -4027,6 +4060,7 @@ impl Bank {
let collected_rent = processing_results
.iter()
.filter_map(|processing_result| processing_result.processed_transaction())
.filter_map(|processed_tx| processed_tx.executed_transaction())
.filter(|executed_tx| executed_tx.was_successful())
.map(|executed_tx| executed_tx.loaded_transaction.rent)
.sum();
Expand Down Expand Up @@ -4752,7 +4786,7 @@ impl Bank {
pub fn process_transaction_with_metadata(
&self,
tx: impl Into<VersionedTransaction>,
) -> Result<TransactionExecutionDetails> {
) -> Result<CommittedTransaction> {
let txs = vec![tx.into()];
let batch = self.prepare_entry_batch(txs)?;

Expand All @@ -4769,8 +4803,7 @@ impl Bank {
Some(1000 * 1000),
);

let committed_tx = commit_results.remove(0)?;
Ok(committed_tx.execution_details)
commit_results.remove(0)
}

/// Process multiple transaction in a single batch. This is used for benches and unit tests.
Expand Down Expand Up @@ -5975,6 +6008,11 @@ impl Bank {
.processed_transaction()
.map(|processed_tx| (tx, processed_tx))
})
.filter_map(|(tx, processed_tx)| {
processed_tx
.executed_transaction()
.map(|executed_tx| (tx, executed_tx))
})
.filter(|(_, executed_tx)| executed_tx.was_successful())
.flat_map(|(tx, executed_tx)| {
let num_account_keys = tx.message().account_keys().len();
Expand Down
31 changes: 29 additions & 2 deletions runtime/src/bank/bank_hash_details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ use {
solana_sdk::{
account::{Account, AccountSharedData, ReadableAccount},
clock::{Epoch, Slot},
fee::FeeDetails,
hash::Hash,
inner_instruction::InnerInstructionsList,
pubkey::Pubkey,
transaction::Result as TransactionResult,
transaction_context::TransactionReturnData,
},
solana_svm::transaction_execution_result::TransactionExecutionDetails,
solana_svm::transaction_commit_result::CommittedTransaction,
solana_transaction_status::UiInstruction,
std::str::FromStr,
};
Expand Down Expand Up @@ -74,7 +78,30 @@ pub struct TransactionDetails {
pub accounts: Vec<String>,
pub instructions: Vec<UiInstruction>,
pub is_simple_vote_tx: bool,
pub execution_results: Option<TransactionExecutionDetails>,
pub commit_details: Option<TransactionCommitDetails>,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct TransactionCommitDetails {
pub status: TransactionResult<()>,
pub log_messages: Option<Vec<String>>,
pub inner_instructions: Option<InnerInstructionsList>,
pub return_data: Option<TransactionReturnData>,
pub executed_units: u64,
pub fee_details: FeeDetails,
}

impl From<CommittedTransaction> for TransactionCommitDetails {
fn from(committed_tx: CommittedTransaction) -> Self {
Self {
status: committed_tx.status,
log_messages: committed_tx.log_messages,
inner_instructions: committed_tx.inner_instructions,
return_data: committed_tx.return_data,
executed_units: committed_tx.executed_units,
fee_details: committed_tx.fee_details,
}
}
}

/// The components that go into a bank hash calculation for a single bank/slot.
Expand Down
Loading

0 comments on commit 86dda02

Please sign in to comment.