diff --git a/crates/litesvm/src/lib.rs b/crates/litesvm/src/lib.rs index 5e88bdc2d..32059d392 100644 --- a/crates/litesvm/src/lib.rs +++ b/crates/litesvm/src/lib.rs @@ -279,7 +279,7 @@ use { create_program_runtime_environment_v1, create_program_runtime_environment_v2, }, solana_builtins::BUILTINS, - solana_clock::Clock, + solana_clock::{Clock, MAX_RECENT_BLOCKHASHES}, solana_compute_budget::{ compute_budget::ComputeBudget, compute_budget_limits::ComputeBudgetLimits, }, @@ -1234,11 +1234,28 @@ impl LiteSVM { pub fn expire_blockhash(&mut self) { self.latest_blockhash = create_blockhash(&self.latest_blockhash.to_bytes()); #[allow(deprecated)] - self.set_sysvar(&RecentBlockhashes::from_iter([IterItem( - 0, - &self.latest_blockhash, - self.fee_structure.lamports_per_signature, - )])); + { + let blockhashes = self.get_sysvar::(); + let max_entries_len = blockhashes.len().min(MAX_RECENT_BLOCKHASHES); + let mut entries = Vec::with_capacity(max_entries_len); + entries.push(IterItem( + 0, + &self.latest_blockhash, + self.fee_structure.lamports_per_signature, + )); + for (i, entry) in blockhashes.iter().enumerate() { + if i == MAX_RECENT_BLOCKHASHES - 1 { + break; + } + entries.push(IterItem( + i as u64 + 1, + &entry.blockhash, + entry.fee_calculator.lamports_per_signature, + )); + } + + self.set_sysvar(&RecentBlockhashes::from_iter(entries)); + } } /// Warps the clock to the specified slot. @@ -1275,7 +1292,7 @@ impl LiteSVM { tx: &SanitizedTransaction, ) -> solana_transaction_error::TransactionResult<()> { let recent_blockhash = tx.message().recent_blockhash(); - if recent_blockhash == &self.latest_blockhash + if self.check_blockhash_is_recent(recent_blockhash) || self.check_transaction_for_nonce( tx, &DurableNonce::from_blockhash(&self.latest_blockhash), @@ -1292,6 +1309,13 @@ impl LiteSVM { } } + fn check_blockhash_is_recent(&self, recent_blockhash: &Hash) -> bool { + #[allow(deprecated)] + self.get_sysvar::() + .iter() + .any(|entry| entry.blockhash == *recent_blockhash) + } + fn check_message_for_nonce(&self, message: &SanitizedMessage) -> bool { message .get_durable_nonce()