diff --git a/core/src/banking_stage/consume_worker.rs b/core/src/banking_stage/consume_worker.rs index 7e1449c5c7..b2428cfe4c 100644 --- a/core/src/banking_stage/consume_worker.rs +++ b/core/src/banking_stage/consume_worker.rs @@ -762,7 +762,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()) @@ -842,7 +847,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 { @@ -891,7 +896,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 { @@ -941,7 +946,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 @@ -1002,7 +1007,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 @@ -1056,6 +1061,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 @@ -1140,27 +1146,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 4798991e9f..e87b6374b9 100644 --- a/core/src/banking_stage/consumer.rs +++ b/core/src/banking_stage/consumer.rs @@ -448,7 +448,7 @@ impl Consumer { // This means that the transaction may cross and epoch boundary (not allowed), // or account lookup tables may have been closed. let pre_results = txs.iter().zip(max_ages).map(|(tx, max_age)| { - if bank.slot() > max_age.epoch_invalidation_slot { + if bank.epoch() != max_age.sanitized_epoch { // Epoch has rolled over. Need to fully re-verify the transaction. // Pre-compiles are verified here. // Attempt re-sanitization after epoch-cross. diff --git a/core/src/banking_stage/scheduler_messages.rs b/core/src/banking_stage/scheduler_messages.rs index 3c5da78838..9732f4fd83 100644 --- a/core/src/banking_stage/scheduler_messages.rs +++ b/core/src/banking_stage/scheduler_messages.rs @@ -1,6 +1,9 @@ use { super::immutable_deserialized_packet::ImmutableDeserializedPacket, - solana_sdk::{clock::Slot, transaction::SanitizedTransaction}, + solana_sdk::{ + clock::{Epoch, Slot}, + transaction::SanitizedTransaction, + }, std::{fmt::Display, sync::Arc}, }; @@ -38,10 +41,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 b31a3d60f5..c640e88a17 100644 --- a/core/src/banking_stage/transaction_scheduler/prio_graph_scheduler.rs +++ b/core/src/banking_stage/transaction_scheduler/prio_graph_scheduler.rs @@ -588,8 +588,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}, @@ -675,10 +675,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 08aaa6ac9c..136ad041b7 100644 --- a/core/src/banking_stage/transaction_scheduler/scheduler_controller.rs +++ b/core/src/banking_stage/transaction_scheduler/scheduler_controller.rs @@ -30,7 +30,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, @@ -506,9 +506,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(); @@ -531,7 +529,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)) }) @@ -554,7 +552,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, )); @@ -680,11 +678,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, @@ -697,13 +694,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, } } @@ -1213,13 +1210,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, } @@ -1227,9 +1224,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 efb59be1b8..2c633294c4 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 710b140ede..3a4bca8cfe 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)