diff --git a/core/src/banking_stage/consume_worker.rs b/core/src/banking_stage/consume_worker.rs index 349f5b8a9d8e6d..9375e733aae1c4 100644 --- a/core/src/banking_stage/consume_worker.rs +++ b/core/src/banking_stage/consume_worker.rs @@ -783,7 +783,12 @@ mod tests { .. } = create_slow_genesis_config(10_000); let (bank, bank_forks) = Bank::new_no_wallclock_throttle_for_tests(&genesis_config); - let bank = Arc::new(Bank::new_from_parent(bank, &Pubkey::new_unique(), 1)); + // Warp to next epoch for MaxAge tests. + let bank = Arc::new(Bank::new_from_parent( + bank.clone(), + &Pubkey::new_unique(), + bank.get_epoch_info().slots_in_epoch, + )); let ledger_path = get_tmp_ledger_path_auto_delete!(); let blockstore = Blockstore::open(ledger_path.path()) @@ -863,7 +868,7 @@ mod tests { let bid = TransactionBatchId::new(0); let id = TransactionId::new(0); let max_age = MaxAge { - epoch_invalidation_slot: bank.slot(), + sanitized_epoch: bank.epoch(), alt_invalidation_slot: bank.slot(), }; let work = ConsumeWork { @@ -912,7 +917,7 @@ mod tests { let bid = TransactionBatchId::new(0); let id = TransactionId::new(0); let max_age = MaxAge { - epoch_invalidation_slot: bank.slot(), + sanitized_epoch: bank.epoch(), alt_invalidation_slot: bank.slot(), }; let work = ConsumeWork { @@ -962,7 +967,7 @@ mod tests { let id1 = TransactionId::new(1); let id2 = TransactionId::new(0); let max_age = MaxAge { - epoch_invalidation_slot: bank.slot(), + sanitized_epoch: bank.epoch(), alt_invalidation_slot: bank.slot(), }; consume_sender @@ -1023,7 +1028,7 @@ mod tests { let id1 = TransactionId::new(1); let id2 = TransactionId::new(0); let max_age = MaxAge { - epoch_invalidation_slot: bank.slot(), + sanitized_epoch: bank.epoch(), alt_invalidation_slot: bank.slot(), }; consume_sender @@ -1077,6 +1082,7 @@ mod tests { .unwrap() .set_bank_for_test(bank.clone()); assert!(bank.slot() > 0); + assert!(bank.epoch() > 0); // No conflicts between transactions. Test 6 cases. // 1. Epoch expiration, before slot => still succeeds due to resanitizing @@ -1161,27 +1167,27 @@ mod tests { transactions: txs, max_ages: vec![ MaxAge { - epoch_invalidation_slot: bank.slot() - 1, + sanitized_epoch: bank.epoch() - 1, alt_invalidation_slot: Slot::MAX, }, MaxAge { - epoch_invalidation_slot: bank.slot(), + sanitized_epoch: bank.epoch(), alt_invalidation_slot: Slot::MAX, }, MaxAge { - epoch_invalidation_slot: bank.slot() + 1, + sanitized_epoch: bank.epoch() + 1, alt_invalidation_slot: Slot::MAX, }, MaxAge { - epoch_invalidation_slot: u64::MAX, + sanitized_epoch: bank.epoch(), alt_invalidation_slot: bank.slot() - 1, }, MaxAge { - epoch_invalidation_slot: u64::MAX, + sanitized_epoch: bank.epoch(), alt_invalidation_slot: bank.slot(), }, MaxAge { - epoch_invalidation_slot: u64::MAX, + sanitized_epoch: bank.epoch(), alt_invalidation_slot: bank.slot() + 1, }, ], diff --git a/core/src/banking_stage/consumer.rs b/core/src/banking_stage/consumer.rs index f2ae4dc905841c..bb76753d77951e 100644 --- a/core/src/banking_stage/consumer.rs +++ b/core/src/banking_stage/consumer.rs @@ -442,8 +442,8 @@ impl Consumer { let pre_results = txs.iter().zip(max_ages).map(|(tx, max_age)| { // If the transaction was sanitized before this bank's epoch, // additional checks are necessary. - if bank.slot() > max_age.epoch_invalidation_slot { - // Reserved key set may have cahnged, so we must verify that + if bank.epoch() != max_age.sanitized_epoch { + // Reserved key set may have changed, so we must verify that // no writable keys are reserved. bank.check_reserved_keys(tx)?; } diff --git a/core/src/banking_stage/scheduler_messages.rs b/core/src/banking_stage/scheduler_messages.rs index 29e9b99f50588a..c5bc74880bb8d7 100644 --- a/core/src/banking_stage/scheduler_messages.rs +++ b/core/src/banking_stage/scheduler_messages.rs @@ -1,5 +1,8 @@ use { - solana_sdk::{clock::Slot, transaction::SanitizedTransaction}, + solana_sdk::{ + clock::{Epoch, Slot}, + transaction::SanitizedTransaction, + }, std::fmt::Display, }; @@ -37,10 +40,17 @@ impl Display for TransactionId { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct MaxAge { - pub epoch_invalidation_slot: Slot, + pub sanitized_epoch: Epoch, pub alt_invalidation_slot: Slot, } +impl MaxAge { + pub const MAX: Self = Self { + sanitized_epoch: Epoch::MAX, + alt_invalidation_slot: Slot::MAX, + }; +} + /// Message: [Scheduler -> Worker] /// Transactions to be consumed (i.e. executed, recorded, and committed) pub struct ConsumeWork { diff --git a/core/src/banking_stage/transaction_scheduler/prio_graph_scheduler.rs b/core/src/banking_stage/transaction_scheduler/prio_graph_scheduler.rs index 2687c04d271991..14c4d8a62ff62d 100644 --- a/core/src/banking_stage/transaction_scheduler/prio_graph_scheduler.rs +++ b/core/src/banking_stage/transaction_scheduler/prio_graph_scheduler.rs @@ -618,8 +618,8 @@ mod tests { crossbeam_channel::{unbounded, Receiver}, itertools::Itertools, solana_sdk::{ - clock::Slot, compute_budget::ComputeBudgetInstruction, hash::Hash, message::Message, - packet::Packet, pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, + compute_budget::ComputeBudgetInstruction, hash::Hash, message::Message, packet::Packet, + pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, transaction::Transaction, }, std::{borrow::Borrow, sync::Arc}, @@ -705,10 +705,7 @@ mod tests { ); let transaction_ttl = SanitizedTransactionTTL { transaction, - max_age: MaxAge { - epoch_invalidation_slot: Slot::MAX, - alt_invalidation_slot: Slot::MAX, - }, + max_age: MaxAge::MAX, }; const TEST_TRANSACTION_COST: u64 = 5000; container.insert_new_transaction( diff --git a/core/src/banking_stage/transaction_scheduler/scheduler_controller.rs b/core/src/banking_stage/transaction_scheduler/scheduler_controller.rs index 0ca1ee562dc535..4e9cceba472acb 100644 --- a/core/src/banking_stage/transaction_scheduler/scheduler_controller.rs +++ b/core/src/banking_stage/transaction_scheduler/scheduler_controller.rs @@ -32,7 +32,7 @@ use { solana_sdk::{ self, address_lookup_table::state::estimate_last_valid_slot, - clock::{Slot, FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET, MAX_PROCESSING_AGE}, + clock::{Epoch, Slot, FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET, MAX_PROCESSING_AGE}, fee::FeeBudgetLimits, saturating_add_assign, transaction::SanitizedTransaction, @@ -509,9 +509,7 @@ impl SchedulerController { (root_bank, working_bank) }; let alt_resolved_slot = root_bank.slot(); - let last_slot_in_epoch = working_bank - .epoch_schedule() - .get_last_slot_in_epoch(working_bank.epoch()); + let sanitized_epoch = root_bank.epoch(); let transaction_account_lock_limit = working_bank.get_transaction_account_lock_limit(); let vote_only = working_bank.vote_only_bank(); @@ -533,7 +531,7 @@ impl SchedulerController { .build_sanitized_transaction( vote_only, root_bank.as_ref(), - working_bank.get_reserved_account_keys(), + root_bank.get_reserved_account_keys(), ) .map(|(tx, deactivation_slot)| (packet.clone(), tx, deactivation_slot)) }) @@ -556,7 +554,7 @@ impl SchedulerController { arc_packets.push(packet); transactions.push(tx); max_ages.push(calculate_max_age( - last_slot_in_epoch, + sanitized_epoch, deactivation_slot, alt_resolved_slot, )); @@ -683,11 +681,10 @@ impl SchedulerController { } } -/// Given the last slot in the epoch, the minimum deactivation slot, -/// and the current slot, return the `MaxAge` that should be used for -/// the transaction. This is used to determine the maximum slot that a -/// transaction will be considered valid for, without re-resolving addresses -/// or resanitizing. +/// Given the epoch, the minimum deactivation slot, and the current slot, +/// return the `MaxAge` that should be used for the transaction. This is used +/// to determine the maximum slot that a transaction will be considered valid +/// for, without re-resolving addresses or resanitizing. /// /// This function considers the deactivation period of Address Table /// accounts. If the deactivation period runs past the end of the epoch, @@ -700,13 +697,13 @@ impl SchedulerController { /// period, i.e. the transaction's address lookups are valid until /// AT LEAST this slot. fn calculate_max_age( - last_slot_in_epoch: Slot, + sanitized_epoch: Epoch, deactivation_slot: Slot, current_slot: Slot, ) -> MaxAge { let alt_min_expire_slot = estimate_last_valid_slot(deactivation_slot.min(current_slot)); MaxAge { - epoch_invalidation_slot: last_slot_in_epoch, + sanitized_epoch, alt_invalidation_slot: alt_min_expire_slot, } } @@ -1218,13 +1215,13 @@ mod tests { #[test] fn test_calculate_max_age() { let current_slot = 100; - let last_slot_in_epoch = 1000; + let sanitized_epoch = 10; // ALT deactivation slot is delayed assert_eq!( - calculate_max_age(last_slot_in_epoch, current_slot - 1, current_slot), + calculate_max_age(sanitized_epoch, current_slot - 1, current_slot), MaxAge { - epoch_invalidation_slot: last_slot_in_epoch, + sanitized_epoch, alt_invalidation_slot: current_slot - 1 + solana_sdk::slot_hashes::get_entries() as u64, } @@ -1232,9 +1229,9 @@ mod tests { // no deactivation slot assert_eq!( - calculate_max_age(last_slot_in_epoch, u64::MAX, current_slot), + calculate_max_age(sanitized_epoch, u64::MAX, current_slot), MaxAge { - epoch_invalidation_slot: last_slot_in_epoch, + sanitized_epoch, alt_invalidation_slot: current_slot + solana_sdk::slot_hashes::get_entries() as u64, } ); diff --git a/core/src/banking_stage/transaction_scheduler/transaction_state.rs b/core/src/banking_stage/transaction_scheduler/transaction_state.rs index efb59be1b8b5b5..2c633294c4643e 100644 --- a/core/src/banking_stage/transaction_scheduler/transaction_state.rs +++ b/core/src/banking_stage/transaction_scheduler/transaction_state.rs @@ -209,9 +209,8 @@ mod tests { use { super::*, solana_sdk::{ - clock::Slot, compute_budget::ComputeBudgetInstruction, hash::Hash, message::Message, - packet::Packet, signature::Keypair, signer::Signer, system_instruction, - transaction::Transaction, + compute_budget::ComputeBudgetInstruction, hash::Hash, message::Message, packet::Packet, + signature::Keypair, signer::Signer, system_instruction, transaction::Transaction, }, }; @@ -233,10 +232,7 @@ mod tests { ); let transaction_ttl = SanitizedTransactionTTL { transaction: SanitizedTransaction::from_transaction_for_tests(tx), - max_age: MaxAge { - epoch_invalidation_slot: Slot::MAX, - alt_invalidation_slot: Slot::MAX, - }, + max_age: MaxAge::MAX, }; const TEST_TRANSACTION_COST: u64 = 5000; TransactionState::new( @@ -327,13 +323,7 @@ mod tests { transaction_state, TransactionState::Unprocessed { .. } )); - assert_eq!( - transaction_ttl.max_age, - MaxAge { - epoch_invalidation_slot: Slot::MAX, - alt_invalidation_slot: Slot::MAX, - } - ); + assert_eq!(transaction_ttl.max_age, MaxAge::MAX); let _ = transaction_state.transition_to_pending(); assert!(matches!( @@ -351,13 +341,7 @@ mod tests { transaction_state, TransactionState::Unprocessed { .. } )); - assert_eq!( - transaction_ttl.max_age, - MaxAge { - epoch_invalidation_slot: Slot::MAX, - alt_invalidation_slot: Slot::MAX, - } - ); + assert_eq!(transaction_ttl.max_age, MaxAge::MAX); // ensure transaction_ttl is not lost through state transitions let transaction_ttl = transaction_state.transition_to_pending(); @@ -372,12 +356,6 @@ mod tests { transaction_state, TransactionState::Unprocessed { .. } )); - assert_eq!( - transaction_ttl.max_age, - MaxAge { - epoch_invalidation_slot: Slot::MAX, - alt_invalidation_slot: Slot::MAX, - } - ); + assert_eq!(transaction_ttl.max_age, MaxAge::MAX); } } diff --git a/core/src/banking_stage/transaction_scheduler/transaction_state_container.rs b/core/src/banking_stage/transaction_scheduler/transaction_state_container.rs index 7d40c66ec1b673..7f9a913457d4db 100644 --- a/core/src/banking_stage/transaction_scheduler/transaction_state_container.rs +++ b/core/src/banking_stage/transaction_scheduler/transaction_state_container.rs @@ -161,7 +161,6 @@ mod tests { packet::Packet, signature::Keypair, signer::Signer, - slot_history::Slot, system_instruction, transaction::{SanitizedTransaction, Transaction}, }, @@ -199,10 +198,7 @@ mod tests { ); let transaction_ttl = SanitizedTransactionTTL { transaction: tx, - max_age: MaxAge { - epoch_invalidation_slot: Slot::MAX, - alt_invalidation_slot: Slot::MAX, - }, + max_age: MaxAge::MAX, }; const TEST_TRANSACTION_COST: u64 = 5000; (transaction_ttl, packet, priority, TEST_TRANSACTION_COST)