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 13, 2024
1 parent 5031885 commit a420bd8
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 148 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
52 changes: 30 additions & 22 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 @@ -6930,6 +6932,12 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() {
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 @@ -841,6 +841,10 @@ pub mod vote_only_retransmitter_signed_fec_sets {
solana_sdk::declare_id!("RfEcA95xnhuwooVAhUUksEJLZBF7xKCLuqrJoqk4Zph");
}

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

pub mod enable_turbine_extended_fanout_experiments {
solana_sdk::declare_id!("BZn14Liea52wtBwrXUxTv6vojuTTmfc7XGEDTXrvMD7b");
}
Expand Down Expand Up @@ -1050,6 +1054,7 @@ lazy_static! {
(move_stake_and_move_lamports_ixs::id(), "Enable MoveStake and MoveLamports stake program instructions #1610"),
(ed25519_precompile_verify_strict::id(), "Use strict verification in ed25519 precompile SIMD-0152"),
(vote_only_retransmitter_signed_fec_sets::id(), "vote only on retransmitter signed fec sets"),
(enable_transaction_failure_fees::id(), "Enable fees for some additional transaction failures SIMD-0082"),
(enable_turbine_extended_fanout_experiments::id(), "enable turbine extended fanout experiments #"),
/*************** ADD NEW FEATURES HERE ***************/
]
Expand Down
Loading

0 comments on commit a420bd8

Please sign in to comment.