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 9, 2024
1 parent f2facd4 commit f8c97b3
Show file tree
Hide file tree
Showing 10 changed files with 269 additions and 151 deletions.
142 changes: 85 additions & 57 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ use {
},
transaction_processing_callback::TransactionProcessingCallback,
transaction_processing_result::{
TransactionProcessingResult, TransactionProcessingResultExtensions,
ProcessedTransaction, TransactionProcessingResult,
TransactionProcessingResultExtensions,
},
transaction_processor::{
ExecutionRecordingConfig, TransactionBatchProcessor, TransactionLogMessages,
Expand Down Expand Up @@ -3091,14 +3092,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 @@ -3107,7 +3107,7 @@ impl Bank {
tx.message().recent_blockhash(),
tx.signature(),
self.slot(),
details.status.clone(),
processed_tx.status(),
);
}
}
Expand Down Expand Up @@ -3359,30 +3359,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 @@ -3562,7 +3567,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 @@ -3712,7 +3718,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 @@ -3731,8 +3737,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 @@ -3805,7 +3810,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 @@ -3821,7 +3828,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 @@ -3859,37 +3866,52 @@ impl Bank {
) -> Vec<TransactionCommitResult> {
processing_results
.into_iter()
.map(|processing_result| {
let processed_tx = processing_result?;
let execution_details = processed_tx.execution_details;
let LoadedTransaction {
rent_debits,
accounts: loaded_accounts,
loaded_accounts_data_size,
fee_details,
..
} = processed_tx.loaded_transaction;

// Rent is only collected for successfully executed transactions
let rent_debits = if execution_details.was_successful() {
rent_debits
} else {
RentDebits::default()
};
.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,
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: loaded_accounts.len(),
loaded_accounts_data_size,
loaded_accounts_count: fees_only_tx.rollback_accounts.count(),
loaded_accounts_data_size: fees_only_tx.rollback_accounts.data_size()
as u32,
},
})
}),
})
.collect()
}
Expand All @@ -3898,6 +3920,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 @@ -5845,6 +5868,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
54 changes: 31 additions & 23 deletions runtime/src/bank/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,21 +236,23 @@ fn new_processing_result(
status: Result<()>,
fee_details: FeeDetails,
) -> TransactionProcessingResult {
Ok(ExecutedTransaction {
loaded_transaction: LoadedTransaction {
fee_details,
..LoadedTransaction::default()
},
execution_details: TransactionExecutionDetails {
status,
log_messages: None,
inner_instructions: None,
return_data: None,
executed_units: 0,
accounts_data_len_delta: 0,
Ok(ProcessedTransaction::Executed(Box::new(
ExecutedTransaction {
loaded_transaction: LoadedTransaction {
fee_details,
..LoadedTransaction::default()
},
execution_details: TransactionExecutionDetails {
status,
log_messages: None,
inner_instructions: None,
return_data: None,
executed_units: 0,
accounts_data_len_delta: 0,
},
programs_modified_by_tx: HashMap::new(),
},
programs_modified_by_tx: HashMap::new(),
})
)))
}

impl Bank {
Expand Down Expand Up @@ -6924,12 +6926,18 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() {
Err(TransactionError::ProgramAccountNotFound),
);
{
// Make sure it is not in the cache because the account owner is not a loader
// Make sure it is not in the program cache because the account owner is not a loader
let program_cache = bank.transaction_processor.program_cache.read().unwrap();
let slot_versions = program_cache.get_slot_versions_for_tests(&program_keypair.pubkey());
assert!(slot_versions.is_empty());
}

// Advance bank to get a new last blockhash for duplicate transaction below
goto_end_of_slot(bank.clone());
let bank = bank_client
.advance_slot(1, bank_forks.as_ref(), &mint_keypair.pubkey())
.unwrap();

// Load program file
let mut file = File::open("../programs/bpf_loader/test_elfs/out/noop_aligned.so")
.expect("file open failed");
Expand Down Expand Up @@ -6995,8 +7003,8 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() {
let program_cache = bank.transaction_processor.program_cache.read().unwrap();
let slot_versions = program_cache.get_slot_versions_for_tests(&program_keypair.pubkey());
assert_eq!(slot_versions.len(), 1);
assert_eq!(slot_versions[0].deployment_slot, 0);
assert_eq!(slot_versions[0].effective_slot, 0);
assert_eq!(slot_versions[0].deployment_slot, bank.slot());
assert_eq!(slot_versions[0].effective_slot, bank.slot());
assert!(matches!(
slot_versions[0].program,
ProgramCacheEntryType::Closed,
Expand All @@ -7019,8 +7027,8 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() {
let program_cache = bank.transaction_processor.program_cache.read().unwrap();
let slot_versions = program_cache.get_slot_versions_for_tests(&buffer_address);
assert_eq!(slot_versions.len(), 1);
assert_eq!(slot_versions[0].deployment_slot, 0);
assert_eq!(slot_versions[0].effective_slot, 0);
assert_eq!(slot_versions[0].deployment_slot, bank.slot());
assert_eq!(slot_versions[0].effective_slot, bank.slot());
assert!(matches!(
slot_versions[0].program,
ProgramCacheEntryType::Closed,
Expand Down Expand Up @@ -7121,14 +7129,14 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() {
let program_cache = bank.transaction_processor.program_cache.read().unwrap();
let slot_versions = program_cache.get_slot_versions_for_tests(&program_keypair.pubkey());
assert_eq!(slot_versions.len(), 2);
assert_eq!(slot_versions[0].deployment_slot, 0);
assert_eq!(slot_versions[0].effective_slot, 0);
assert_eq!(slot_versions[0].deployment_slot, bank.slot() - 1);
assert_eq!(slot_versions[0].effective_slot, bank.slot() - 1);
assert!(matches!(
slot_versions[0].program,
ProgramCacheEntryType::Closed,
));
assert_eq!(slot_versions[1].deployment_slot, 0);
assert_eq!(slot_versions[1].effective_slot, 1);
assert_eq!(slot_versions[1].deployment_slot, bank.slot() - 1);
assert_eq!(slot_versions[1].effective_slot, bank.slot());
assert!(matches!(
slot_versions[1].program,
ProgramCacheEntryType::Loaded(_),
Expand Down
5 changes: 5 additions & 0 deletions sdk/src/feature_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,10 @@ pub mod disable_rent_fees_collection {
solana_sdk::declare_id!("CJzY83ggJHqPGDq8VisV3U91jDJLuEaALZooBrXtnnLU");
}

pub mod enable_transaction_failure_fees {
solana_sdk::declare_id!("My11111111111111111111111111111111111111111");
}

pub mod enable_zk_transfer_with_fee {
solana_sdk::declare_id!("zkNLP7EQALfC1TYeB3biDU7akDckj8iPkvh9y2Mt2K3");
}
Expand Down Expand Up @@ -1020,6 +1024,7 @@ lazy_static! {
(update_hashes_per_tick6::id(), "Update desired hashes per tick to 10M"),
(validate_fee_collector_account::id(), "validate fee collector account #33888"),
(disable_rent_fees_collection::id(), "Disable rent fees collection #33945"),
(enable_transaction_failure_fees::id(), "Enable fees for some additional transaction failures #XXXXX"),
(enable_zk_transfer_with_fee::id(), "enable Zk Token proof program transfer with fee"),
(drop_legacy_shreds::id(), "drops legacy shreds #34328"),
(allow_commission_decrease_at_any_time::id(), "Allow commission decrease at any time in epoch #33843"),
Expand Down
Loading

0 comments on commit f8c97b3

Please sign in to comment.