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..3d0c18b2e52 100644 --- a/runtime/src/snapshot_bank_utils.rs +++ b/runtime/src/snapshot_bank_utils.rs @@ -510,7 +510,10 @@ fn verify_slot_deltas( bank: &Bank, ) -> std::result::Result<(), VerifySlotDeltasError> { let info = verify_slot_deltas_structural(slot_deltas, bank.slot())?; - verify_slot_deltas_with_history(&info.slots, &bank.get_slot_history(), bank.slot()) + 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()) } /// Verify that the snapshot's slot deltas are not corrupt/invalid