From 71e9958e061493d7545bd28d4ac7a85aaed6ffbb Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 21 Jan 2021 21:40:47 -0700 Subject: [PATCH] Rpc: Add custom error for BigTable data not found (#14762) * Expose not-found bigtable error * Add custom rpc error for bigtable data not found * Return custom rpc error when bigtable block is not found * Generalize long-term storage --- client/src/rpc_custom_error.rs | 9 +++++++++ core/src/rpc.rs | 28 ++++++++++++++++++++++++---- storage-bigtable/src/lib.rs | 18 +++++++++++++++--- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/client/src/rpc_custom_error.rs b/client/src/rpc_custom_error.rs index 582872238b..ab14ca7a32 100644 --- a/client/src/rpc_custom_error.rs +++ b/client/src/rpc_custom_error.rs @@ -12,6 +12,7 @@ pub const JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY: i64 = -32005; pub const JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: i64 = -32006; pub const JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: i64 = -32007; pub const JSON_RPC_SERVER_ERROR_NO_SNAPSHOT: i64 = -32008; +pub const JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED: i64 = -32009; pub enum RpcCustomError { BlockCleanedUp { @@ -34,6 +35,9 @@ pub enum RpcCustomError { slot: Slot, }, NoSnapshot, + LongTermStorageSlotSkipped { + slot: Slot, + }, } #[derive(Debug, Serialize, Deserialize)] @@ -106,6 +110,11 @@ impl From for Error { message: "No snapshot".to_string(), data: None, }, + RpcCustomError::LongTermStorageSlotSkipped { slot } => Self { + code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED), + message: format!("Slot {} was skipped, or missing in long-term storage", slot), + data: None, + }, } } } diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 26552592ff..3883706017 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -670,6 +670,22 @@ impl JsonRpcRequestProcessor { Ok(()) } + fn check_bigtable_result( + &self, + result: &std::result::Result, + ) -> Result<()> + where + T: std::fmt::Debug, + { + if result.is_err() { + let err = result.as_ref().unwrap_err(); + if let solana_storage_bigtable::Error::BlockNotFound(slot) = err { + return Err(RpcCustomError::LongTermStorageSlotSkipped { slot: *slot }.into()); + } + } + Ok(()) + } + pub fn get_confirmed_block( &self, slot: Slot, @@ -688,9 +704,11 @@ impl JsonRpcRequestProcessor { self.check_blockstore_root(&result, slot)?; if result.is_err() { if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage { - return Ok(self + let bigtable_result = self .runtime_handle - .block_on(bigtable_ledger_storage.get_confirmed_block(slot)) + .block_on(bigtable_ledger_storage.get_confirmed_block(slot)); + self.check_bigtable_result(&bigtable_result)?; + return Ok(bigtable_result .ok() .map(|confirmed_block| confirmed_block.encode(encoding))); } @@ -803,9 +821,11 @@ impl JsonRpcRequestProcessor { self.check_blockstore_root(&result, slot)?; if result.is_err() || matches!(result, Ok(None)) { if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage { - return Ok(self + let bigtable_result = self .runtime_handle - .block_on(bigtable_ledger_storage.get_confirmed_block(slot)) + .block_on(bigtable_ledger_storage.get_confirmed_block(slot)); + self.check_bigtable_result(&bigtable_result)?; + return Ok(bigtable_result .ok() .and_then(|confirmed_block| confirmed_block.block_time)); } diff --git a/storage-bigtable/src/lib.rs b/storage-bigtable/src/lib.rs index f808bd0161..8ddae05f36 100644 --- a/storage-bigtable/src/lib.rs +++ b/storage-bigtable/src/lib.rs @@ -334,7 +334,11 @@ impl LedgerStorage { "blocks", slot_to_key(slot), ) - .await?; + .await + .map_err(|err| match err { + bigtable::Error::RowNotFound => Error::BlockNotFound(slot), + _ => err.into(), + })?; Ok(match block_cell_data { bigtable::CellData::Bincode(block) => block.into(), bigtable::CellData::Protobuf(block) => block.try_into().map_err(|_err| { @@ -347,7 +351,11 @@ impl LedgerStorage { let mut bigtable = self.connection.client(); let transaction_info = bigtable .get_bincode_cell::("tx", signature.to_string()) - .await?; + .await + .map_err(|err| match err { + bigtable::Error::RowNotFound => Error::SignatureNotFound, + _ => err.into(), + })?; Ok(transaction_info.into()) } @@ -361,7 +369,11 @@ impl LedgerStorage { // Figure out which block the transaction is located in let TransactionInfo { slot, index, .. } = bigtable .get_bincode_cell("tx", signature.to_string()) - .await?; + .await + .map_err(|err| match err { + bigtable::Error::RowNotFound => Error::SignatureNotFound, + _ => err.into(), + })?; // Load the block and return the transaction let block = self.get_confirmed_block(slot).await?;