diff --git a/core/src/banking_stage/consumer.rs b/core/src/banking_stage/consumer.rs index 57f1b1958b152c..675dfdd1ebadee 100644 --- a/core/src/banking_stage/consumer.rs +++ b/core/src/banking_stage/consumer.rs @@ -440,16 +440,8 @@ impl Consumer { // or account lookup tables may have been closed. let pre_results = txs.iter().zip(max_slot_ages).map(|(tx, max_slot_age)| { if *max_slot_age < bank.slot() { - // Pre-compiles are verified here. - // Attempt re-sanitization after epoch-cross. - // Re-sanitized transaction should be equal to the original transaction, - // but whether it will pass sanitization needs to be checked. - let resanitized_tx = - bank.fully_verify_transaction(tx.to_versioned_transaction())?; - if resanitized_tx != *tx { - // Sanitization before/after epoch give different transaction data - do not execute. - return Err(TransactionError::ResanitizationNeeded); - } + // Re-verify all state that depends on features or state. + bank.reverify_transaction(tx)?; } else { // Verify pre-compiles. if !move_precompile_verification_to_svm { diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index f881c548c89f1d..976d8bda795a39 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -5756,6 +5756,35 @@ impl Bank { self.verify_transaction(tx, TransactionVerificationMode::FullVerification) } + /// Re-performs **feature** or state dependent verification on the transaction. + pub fn reverify_transaction(&self, tx: &impl SVMMessage) -> Result<()> { + // Loaded addresses depend on address table account state. + // We need only verify that loading works correctly. + // Since the address table is append only there is no chance addresses + // are different than the first time this was resolved. + let _loaded_addresses = self.load_addresses_from_ref(tx.message_address_table_lookups())?; + + // Precompiles may be verified at this time if feature is not activated. + // Precompile verification can be dependent on features of the bank. + let move_precompile_verification_to_svm = self + .feature_set + .is_active(&feature_set::move_precompile_verification_to_svm::id()); + if !move_precompile_verification_to_svm { + verify_precompiles(tx, &self.feature_set)?; + } + + // Check keys against the reserved set - these failures simply require us + // to re-sanitize the transaction. We do not need to drop the transaction. + let reserved_keys = self.get_reserved_account_keys(); + for (index, key) in tx.account_keys().iter().enumerate() { + if tx.is_writable(index) && reserved_keys.contains(key) { + return Err(TransactionError::ResanitizationNeeded); + } + } + + Ok(()) + } + /// only called from ledger-tool or tests fn calculate_capitalization(&self, debug_verify: bool) -> u64 { let is_startup = true;