diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index 024ffb24bee..30c377d452f 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -1592,7 +1592,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 04c717b992f..c7a2d5dd84b 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -2013,7 +2013,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 0aa745b93d5..f9f9e1d072f 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -3131,7 +3131,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 cb8d531393e..44769ef7859 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -2385,8 +2385,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 37e0e4ead40..5222bd9b88a 100644 --- a/runtime/src/snapshot_bank_utils.rs +++ b/runtime/src/snapshot_bank_utils.rs @@ -532,12 +532,10 @@ fn verify_slot_deltas( ) -> std::result::Result<(), VerifySlotDeltasError> { 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)?; - verify_slot_deltas_with_history( - &info.slots, - &bank.get_slot_history(), - 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) } /// Verify that the snapshot's slot deltas are not corrupt/invalid