From de1c490b09d04cc1e9cc83b5acb99412e5c0d377 Mon Sep 17 00:00:00 2001 From: Brooks Date: Wed, 20 May 2026 07:01:05 -0400 Subject: [PATCH 1/2] Bank::get_slot_history() is fallible (#12598) (cherry picked from commit ddb592b10e2adc9178cfc5d616be569cf049125e) # Conflicts: # runtime/src/snapshot_bank_utils.rs --- core/src/replay_stage.rs | 4 +++- core/src/validator.rs | 4 +++- rpc-client-api/src/custom_error.rs | 8 ++++++++ rpc/src/rpc.rs | 4 +++- runtime/src/bank.rs | 4 ++-- runtime/src/snapshot_bank_utils.rs | 9 +++++++++ 6 files changed, 28 insertions(+), 5 deletions(-) diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index 9bad2d2c4f2..1add3414e3a 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -1498,7 +1498,9 @@ impl ReplayStage { ) -> Result { let tower = Tower::restore(tower_storage, node_pubkey).and_then(|restored_tower| { let root_bank = bank_forks.read().unwrap().root_bank(); - let slot_history = root_bank.get_slot_history(); + let slot_history = root_bank + .get_slot_history() + .expect("slot history must exist"); restored_tower.adjust_lockouts_after_replay(root_bank.slot(), &slot_history) }); match tower { diff --git a/core/src/validator.rs b/core/src/validator.rs index fe520e76f0e..7c2500fd31d 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -2084,7 +2084,9 @@ fn post_process_restored_tower( let restored_tower = restored_tower.and_then(|tower| { let root_bank = bank_forks.root_bank(); - let slot_history = root_bank.get_slot_history(); + let slot_history = root_bank + .get_slot_history() + .expect("slot history must exist"); // make sure tower isn't corrupted first before the following hard fork check let tower = tower.adjust_lockouts_after_replay(root_bank.slot(), &slot_history); diff --git a/rpc-client-api/src/custom_error.rs b/rpc-client-api/src/custom_error.rs index 620ae497268..7f39d6c7a43 100644 --- a/rpc-client-api/src/custom_error.rs +++ b/rpc-client-api/src/custom_error.rs @@ -29,6 +29,7 @@ pub const JSON_RPC_SERVER_ERROR_EPOCH_REWARDS_PERIOD_ACTIVE: i64 = -32017; pub const JSON_RPC_SERVER_ERROR_SLOT_NOT_EPOCH_BOUNDARY: i64 = -32018; pub const JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_UNREACHABLE: i64 = -32019; pub const JSON_RPC_SERVER_ERROR_FILTER_TRANSACTION_NOT_FOUND: i64 = -32020; +pub const JSON_RPC_SERVER_ERROR_NO_SLOT_HISTORY: i64 = -32021; #[derive(Error, Debug)] #[allow(clippy::large_enum_variant)] @@ -83,6 +84,8 @@ pub enum RpcCustomError { LongTermStorageUnreachable, #[error("FilterTransactionNotFound")] FilterTransactionNotFound { signature: String }, + #[error("NoSlotHistory")] + NoSlotHistory, } #[derive(Debug, Serialize, Deserialize)] @@ -267,6 +270,11 @@ impl From for Error { message: format!("Transaction {signature} not found"), data: None, }, + RpcCustomError::NoSlotHistory => Self { + code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_NO_SLOT_HISTORY), + message: "No slot history".to_string(), + data: None, + }, } } } diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index d800f97dd2a..69d1dcc47e6 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -3121,7 +3121,9 @@ pub mod rpc_bank { } }; - let slot_history = bank.get_slot_history(); + let Some(slot_history) = bank.get_slot_history() else { + return Err(RpcCustomError::NoSlotHistory.into()); + }; if first_slot < slot_history.oldest() { return Err(Error::invalid_params(format!( "firstSlot, {}, is too small; min {}", diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 76cba28c09e..3340e7f4fc2 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -2326,8 +2326,8 @@ impl Bank { }); } - pub fn get_slot_history(&self) -> SlotHistory { - from_account(&self.get_account(&sysvar::slot_history::id()).unwrap()).unwrap() + pub fn get_slot_history(&self) -> Option { + from_account(&self.get_account(&sysvar::slot_history::id())?) } fn update_epoch_stakes(&mut self, leader_schedule_epoch: Epoch) { diff --git a/runtime/src/snapshot_bank_utils.rs b/runtime/src/snapshot_bank_utils.rs index 6d65013aaa2..aad8c201d10 100644 --- a/runtime/src/snapshot_bank_utils.rs +++ b/runtime/src/snapshot_bank_utils.rs @@ -509,8 +509,17 @@ fn verify_slot_deltas( slot_deltas: &[BankSlotDelta], bank: &Bank, ) -> std::result::Result<(), VerifySlotDeltasError> { +<<<<<<< HEAD let info = verify_slot_deltas_structural(slot_deltas, bank.slot())?; verify_slot_deltas_with_history(&info.slots, &bank.get_slot_history(), bank.slot()) +======= + let max_root_entries = bank.status_cache.read().unwrap().max_root_entries(); + let info = verify_slot_deltas_structural(slot_deltas, bank.slot(), max_root_entries)?; + let slot_history = bank + .get_slot_history() + .expect("snapshot bank must have slot history"); + verify_slot_deltas_with_history(&info.slots, &slot_history, bank.slot(), max_root_entries) +>>>>>>> ddb592b10 (Bank::get_slot_history() is fallible (#12598)) } /// Verify that the snapshot's slot deltas are not corrupt/invalid From 7db99419eb5cf3ef7ace886a6a763b0cbea3727d Mon Sep 17 00:00:00 2001 From: brooks Date: Wed, 20 May 2026 12:18:41 -0400 Subject: [PATCH 2/2] resolves merge conflicts --- runtime/src/snapshot_bank_utils.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/runtime/src/snapshot_bank_utils.rs b/runtime/src/snapshot_bank_utils.rs index aad8c201d10..3d0c18b2e52 100644 --- a/runtime/src/snapshot_bank_utils.rs +++ b/runtime/src/snapshot_bank_utils.rs @@ -509,17 +509,11 @@ fn verify_slot_deltas( slot_deltas: &[BankSlotDelta], bank: &Bank, ) -> std::result::Result<(), VerifySlotDeltasError> { -<<<<<<< HEAD let info = verify_slot_deltas_structural(slot_deltas, bank.slot())?; - verify_slot_deltas_with_history(&info.slots, &bank.get_slot_history(), bank.slot()) -======= - let max_root_entries = bank.status_cache.read().unwrap().max_root_entries(); - let info = verify_slot_deltas_structural(slot_deltas, bank.slot(), max_root_entries)?; let slot_history = bank .get_slot_history() .expect("snapshot bank must have slot history"); - verify_slot_deltas_with_history(&info.slots, &slot_history, bank.slot(), max_root_entries) ->>>>>>> ddb592b10 (Bank::get_slot_history() is fallible (#12598)) + verify_slot_deltas_with_history(&info.slots, &slot_history, bank.slot()) } /// Verify that the snapshot's slot deltas are not corrupt/invalid