diff --git a/linera-chain/src/lib.rs b/linera-chain/src/lib.rs index 66f9ab2d9e4..52c9a054ed7 100644 --- a/linera-chain/src/lib.rs +++ b/linera-chain/src/lib.rs @@ -18,7 +18,7 @@ use data_types::{MessageBundle, Origin, PostedMessage}; use linera_base::{ crypto::{CryptoError, CryptoHash}, data_types::{ArithmeticError, BlockHeight, Round, Timestamp}, - identifiers::{ApplicationId, ChainId}, + identifiers::{ApplicationId, BlobId, ChainId}, }; use linera_execution::ExecutionError; use linera_views::views::ViewError; @@ -32,7 +32,7 @@ pub enum ChainError { #[error("Arithmetic error: {0}")] ArithmeticError(#[from] ArithmeticError), #[error("Error in view operation: {0}")] - ViewError(#[from] ViewError), + ViewError(ViewError), #[error("Execution error: {0} during {1:?}")] ExecutionError(ExecutionError, ChainExecutionContext), @@ -150,6 +150,17 @@ pub enum ChainError { expected: CryptoHash, actual: CryptoHash, }, + #[error("Blobs not found: {0:?}")] + BlobsNotFound(Vec), +} + +impl From for ChainError { + fn from(error: ViewError) -> Self { + match error { + ViewError::BlobsNotFound(blob_ids) => ChainError::BlobsNotFound(blob_ids), + error => ChainError::ViewError(error), + } + } } #[derive(Copy, Clone, Debug)] diff --git a/linera-core/src/client/mod.rs b/linera-core/src/client/mod.rs index e4c535d2ee4..ca5b2e31988 100644 --- a/linera-core/src/client/mod.rs +++ b/linera-core/src/client/mod.rs @@ -446,10 +446,10 @@ where #[derive(Debug, Error)] pub enum ChainClientError { #[error("Local node operation failed: {0}")] - LocalNodeError(#[from] LocalNodeError), + LocalNodeError(LocalNodeError), #[error("Remote node operation failed: {0}")] - RemoteNodeError(#[from] NodeError), + RemoteNodeError(NodeError), #[error(transparent)] ArithmeticError(#[from] ArithmeticError), @@ -458,7 +458,7 @@ pub enum ChainClientError { JsonError(#[from] serde_json::Error), #[error("Chain operation failed: {0}")] - ChainError(#[from] ChainError), + ChainError(ChainError), #[error(transparent)] CommunicationError(#[from] CommunicationError), @@ -494,12 +494,51 @@ pub enum ChainClientError { FoundMultipleKeysForChain(ChainId), #[error(transparent)] - ViewError(#[from] ViewError), + ViewError(ViewError), #[error("Blobs not found: {0:?}")] BlobsNotFound(Vec), } +impl From for ChainClientError { + fn from(error: NodeError) -> Self { + match error { + NodeError::BlobsNotFound(blob_ids) => Self::BlobsNotFound(blob_ids), + error => Self::RemoteNodeError(error), + } + } +} + +impl From for ChainClientError { + fn from(error: ViewError) -> Self { + match error { + ViewError::BlobsNotFound(blob_ids) => Self::BlobsNotFound(blob_ids), + error => Self::ViewError(error), + } + } +} + +impl From for ChainClientError { + fn from(error: LocalNodeError) -> Self { + match error { + LocalNodeError::BlobsNotFound(blob_ids) => Self::BlobsNotFound(blob_ids), + error => Self::LocalNodeError(error), + } + } +} + +impl From for ChainClientError { + fn from(error: ChainError) -> Self { + match error { + ChainError::BlobsNotFound(blob_ids) + | ChainError::ExecutionError(ExecutionError::BlobsNotFound(blob_ids), _) => { + Self::BlobsNotFound(blob_ids) + } + error => Self::ChainError(error), + } + } +} + impl From for ChainClientError { fn from(infallible: Infallible) -> Self { match infallible {} @@ -1122,7 +1161,7 @@ where // necessary. if let Err(err) = self.process_certificate(certificate.clone(), vec![]).await { match &err { - LocalNodeError::WorkerError(WorkerError::BlobsNotFound(blob_ids)) => { + LocalNodeError::BlobsNotFound(blob_ids) => { let blobs = LocalNodeClient::::download_blobs(blob_ids, &nodes).await; ensure!(blobs.len() == blob_ids.len(), err); @@ -1623,8 +1662,8 @@ where .handle_block_proposal(*proposal.clone()) .await { - if let Some(blob_ids) = original_err.get_blobs_not_found() { - self.update_local_node_with_blobs_from(blob_ids, remote_node) + if let LocalNodeError::BlobsNotFound(blob_ids) = &original_err { + self.update_local_node_with_blobs_from(blob_ids.clone(), remote_node) .await?; continue; // We found the missing blobs: retry. } @@ -1641,9 +1680,7 @@ where let mut blobs = vec![]; while let Err(original_err) = self.client.handle_certificate(*cert.clone(), blobs).await { - if let LocalNodeError::WorkerError(WorkerError::BlobsNotFound(blob_ids)) = - &original_err - { + if let LocalNodeError::BlobsNotFound(blob_ids) = &original_err { blobs = remote_node .find_missing_blobs(blob_ids.clone(), chain_id) .await?; @@ -1792,11 +1829,10 @@ where .local_node .stage_block_execution(block.clone()) .await; - if let Err(err) = &result { - if let Some(blob_ids) = err.get_blobs_not_found() { - self.receive_certificates_for_blobs(blob_ids).await?; - continue; // We found the missing blob: retry. - } + if let Err(LocalNodeError::BlobsNotFound(blob_ids)) = &result { + self.receive_certificates_for_blobs(blob_ids.clone()) + .await?; + continue; // We found the missing blob: retry. } return Ok(result?); } diff --git a/linera-core/src/local_node.rs b/linera-core/src/local_node.rs index 44df6828f0e..5871a17f5fa 100644 --- a/linera-core/src/local_node.rs +++ b/linera-core/src/local_node.rs @@ -17,9 +17,9 @@ use linera_chain::{ data_types::{ Block, BlockProposal, Certificate, CertificateValue, ExecutedBlock, LiteCertificate, }, - ChainError, ChainStateView, + ChainStateView, }; -use linera_execution::{ExecutionError, Query, Response, SystemExecutionError}; +use linera_execution::{Query, Response}; use linera_storage::Storage; use linera_views::views::ViewError; use rand::{prelude::SliceRandom, thread_rng}; @@ -59,10 +59,10 @@ pub enum LocalNodeError { ArithmeticError(#[from] ArithmeticError), #[error(transparent)] - ViewError(#[from] linera_views::views::ViewError), + ViewError(ViewError), #[error("Local node operation failed: {0}")] - WorkerError(#[from] WorkerError), + WorkerError(WorkerError), #[error( "Failed to download certificates and update local node to the next height \ @@ -83,35 +83,35 @@ pub enum LocalNodeError { InvalidChainInfoResponse, #[error(transparent)] - NodeError(#[from] NodeError), + NodeError(NodeError), + + #[error("Blobs not found: {0:?}")] + BlobsNotFound(Vec), } -impl LocalNodeError { - pub fn get_blobs_not_found(&self) -> Option> { - match self { - LocalNodeError::WorkerError(WorkerError::ChainError(chain_error)) => { - match **chain_error { - ChainError::ExecutionError( - ExecutionError::SystemError(SystemExecutionError::BlobNotFoundOnRead( - blob_id, - )), - _, - ) - | ChainError::ExecutionError( - ExecutionError::ViewError(ViewError::BlobNotFoundOnRead(blob_id)), - _, - ) => Some(vec![blob_id]), - _ => None, - } - } - LocalNodeError::WorkerError(WorkerError::BlobsNotFound(blob_ids)) => { - Some(blob_ids.clone()) - } - LocalNodeError::NodeError(NodeError::BlobNotFoundOnRead(blob_id)) => { - Some(vec![*blob_id]) - } - LocalNodeError::NodeError(NodeError::BlobsNotFound(blob_ids)) => Some(blob_ids.clone()), - _ => None, +impl From for LocalNodeError { + fn from(error: WorkerError) -> Self { + match error { + WorkerError::BlobsNotFound(blob_ids) => LocalNodeError::BlobsNotFound(blob_ids), + error => LocalNodeError::WorkerError(error), + } + } +} + +impl From for LocalNodeError { + fn from(error: NodeError) -> Self { + match error { + NodeError::BlobsNotFound(blob_ids) => LocalNodeError::BlobsNotFound(blob_ids), + error => LocalNodeError::NodeError(error), + } + } +} + +impl From for LocalNodeError { + fn from(error: ViewError) -> Self { + match error { + ViewError::BlobsNotFound(blob_ids) => LocalNodeError::BlobsNotFound(blob_ids), + error => LocalNodeError::ViewError(error), } } } @@ -293,7 +293,7 @@ where result = match &result { Err(err) => { - if let Some(blob_ids) = err.get_blobs_not_found() { + if let LocalNodeError::BlobsNotFound(blob_ids) = &err { let blobs = remote_node.try_download_blobs(blob_ids.as_slice()).await; if blobs.len() != blob_ids.len() { result diff --git a/linera-core/src/node.rs b/linera-core/src/node.rs index dd4d99ad145..b2065172ebf 100644 --- a/linera-core/src/node.rs +++ b/linera-core/src/node.rs @@ -18,7 +18,7 @@ use linera_chain::{ }; use linera_execution::{ committee::{Committee, ValidatorName}, - ExecutionError, SystemExecutionError, + ExecutionError, }; use linera_version::VersionInfo; use linera_views::views::ViewError; @@ -178,7 +178,7 @@ pub enum NodeError { height: BlockHeight, }, - #[error("The following blobs are missing: {0:?}.")] + #[error("Blobs not found: {0:?}")] BlobsNotFound(Vec), // This error must be normalized during conversions. @@ -216,8 +216,6 @@ pub enum NodeError { #[error("Failed to make a chain info query on the local node: {error}")] LocalNodeQuery { error: String }, - #[error("Blob not found on storage read: {0}")] - BlobNotFoundOnRead(BlobId), #[error("Node failed to provide a 'last used by' certificate for the blob")] InvalidCertificateForBlob(BlobId), #[error("Local error handling validator response")] @@ -252,8 +250,11 @@ impl CrossChainMessageDelivery { impl From for NodeError { fn from(error: ViewError) -> Self { - Self::ViewError { - error: error.to_string(), + match error { + ViewError::BlobsNotFound(blob_ids) => Self::BlobsNotFound(blob_ids), + error => Self::ViewError { + error: error.to_string(), + }, } } } @@ -287,14 +288,10 @@ impl From for NodeError { height, }, ChainError::InactiveChain(chain_id) => Self::InactiveChain(chain_id), - ChainError::ExecutionError( - ExecutionError::SystemError(SystemExecutionError::BlobNotFoundOnRead(blob_id)), - _, - ) - | ChainError::ExecutionError( - ExecutionError::ViewError(ViewError::BlobNotFoundOnRead(blob_id)), - _, - ) => Self::BlobNotFoundOnRead(blob_id), + ChainError::BlobsNotFound(blob_ids) + | ChainError::ExecutionError(ExecutionError::BlobsNotFound(blob_ids), _) => { + Self::BlobsNotFound(blob_ids) + } error => Self::ChainError { error: error.to_string(), }, @@ -307,7 +304,7 @@ impl From for NodeError { match error { WorkerError::ChainError(error) => (*error).into(), WorkerError::MissingCertificateValue => Self::MissingCertificateValue, - WorkerError::BlobsNotFound(blob_ids) => NodeError::BlobsNotFound(blob_ids), + WorkerError::BlobsNotFound(blob_ids) => Self::BlobsNotFound(blob_ids), error => Self::WorkerError { error: error.to_string(), }, diff --git a/linera-core/src/unit_tests/test_utils.rs b/linera-core/src/unit_tests/test_utils.rs index dbaa6fa7ac7..198a40aacd4 100644 --- a/linera-core/src/unit_tests/test_utils.rs +++ b/linera-core/src/unit_tests/test_utils.rs @@ -262,7 +262,7 @@ where let handle_block_proposal_result = Self::handle_block_proposal(proposal, &mut validator).await; let result = match handle_block_proposal_result { - Some(Err(NodeError::BlobsNotFound(_) | NodeError::BlobNotFoundOnRead(_))) => { + Some(Err(NodeError::BlobsNotFound(_))) => { handle_block_proposal_result.expect("handle_block_proposal_result should be Some") } _ => match validator.fault_type { @@ -354,7 +354,7 @@ where let handle_certificate_result = Self::handle_certificate(certificate, validator, blobs).await; match handle_certificate_result { - Some(Err(NodeError::BlobsNotFound(_) | NodeError::BlobNotFoundOnRead(_))) => { + Some(Err(NodeError::BlobsNotFound(_))) => { handle_certificate_result.expect("handle_certificate_result should be Some") } _ => match validator.fault_type { diff --git a/linera-core/src/updater.rs b/linera-core/src/updater.rs index 14536891cc3..f5ed8b91f3b 100644 --- a/linera-core/src/updater.rs +++ b/linera-core/src/updater.rs @@ -274,8 +274,8 @@ where // synchronize them now and retry. self.send_chain_information_for_senders(chain_id).await?; } - Err(NodeError::BlobNotFoundOnRead(_)) if !blob_ids.is_empty() => { - // For `BlobNotFoundOnRead`, we assume that the local node should already be + Err(NodeError::BlobsNotFound(_)) if !blob_ids.is_empty() => { + // For `BlobsNotFound`, we assume that the local node should already be // updated with the needed blobs, so sending the chain information about the // certificates that last used the blobs to the validator node should be enough. let missing_blob_ids = stream::iter(mem::take(&mut blob_ids)) diff --git a/linera-core/src/worker.rs b/linera-core/src/worker.rs index cc34917b4ca..7b311dfba23 100644 --- a/linera-core/src/worker.rs +++ b/linera-core/src/worker.rs @@ -12,7 +12,7 @@ use std::{ #[cfg(with_testing)] use linera_base::crypto::PublicKey; use linera_base::{ - crypto::{CryptoHash, KeyPair}, + crypto::{CryptoError, CryptoHash, KeyPair}, data_types::{ ArithmeticError, Blob, BlockHeight, DecompressionError, Round, UserApplicationDescription, }, @@ -25,10 +25,11 @@ use linera_chain::{ Block, BlockExecutionOutcome, BlockProposal, Certificate, CertificateValue, ExecutedBlock, HashedCertificateValue, LiteCertificate, MessageBundle, Origin, Target, }, - ChainStateView, + ChainError, ChainStateView, }; -use linera_execution::{committee::Epoch, Query, Response}; +use linera_execution::{committee::Epoch, ExecutionError, Query, Response}; use linera_storage::Storage; +use linera_views::views::ViewError; use lru::LruCache; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -140,16 +141,16 @@ pub enum Reason { #[derive(Debug, Error)] pub enum WorkerError { #[error(transparent)] - CryptoError(#[from] linera_base::crypto::CryptoError), + CryptoError(#[from] CryptoError), #[error(transparent)] ArithmeticError(#[from] ArithmeticError), #[error(transparent)] - ViewError(#[from] linera_views::views::ViewError), + ViewError(ViewError), #[error(transparent)] - ChainError(#[from] Box), + ChainError(#[from] Box), // Chain access control #[error("Block was not signed by an authorized owner")] @@ -205,7 +206,7 @@ pub enum WorkerError { MissingExecutedBlockInProposal, #[error("Fast blocks cannot query oracles")] FastBlockUsingOracles, - #[error("The following blobs are missing: {0:?}.")] + #[error("Blobs not found: {0:?}")] BlobsNotFound(Vec), #[error("The block proposal is invalid: {0}")] InvalidBlockProposal(String), @@ -221,10 +222,25 @@ pub enum WorkerError { Decompression(#[from] DecompressionError), } -impl From for WorkerError { +impl From for WorkerError { #[instrument(level = "trace", skip(chain_error))] - fn from(chain_error: linera_chain::ChainError) -> Self { - WorkerError::ChainError(Box::new(chain_error)) + fn from(chain_error: ChainError) -> Self { + match chain_error { + ChainError::BlobsNotFound(blob_ids) + | ChainError::ExecutionError(ExecutionError::BlobsNotFound(blob_ids), _) => { + WorkerError::BlobsNotFound(blob_ids) + } + error => WorkerError::ChainError(Box::new(error)), + } + } +} + +impl From for WorkerError { + fn from(view_error: ViewError) -> Self { + match view_error { + ViewError::BlobsNotFound(blob_ids) => WorkerError::BlobsNotFound(blob_ids), + error => WorkerError::ViewError(error), + } } } diff --git a/linera-execution/src/execution_state_actor.rs b/linera-execution/src/execution_state_actor.rs index d11aba653fe..b8f36683470 100644 --- a/linera-execution/src/execution_state_actor.rs +++ b/linera-execution/src/execution_state_actor.rs @@ -306,11 +306,7 @@ where } ReadBlobContent { blob_id, callback } => { - let blob = self - .system - .read_blob_content(blob_id) - .await - .map_err(|_| SystemExecutionError::BlobNotFoundOnRead(blob_id))?; + let blob = self.system.read_blob_content(blob_id).await?; callback.respond(blob); } diff --git a/linera-execution/src/lib.rs b/linera-execution/src/lib.rs index a1c419c1b0d..2d2b9662c35 100644 --- a/linera-execution/src/lib.rs +++ b/linera-execution/src/lib.rs @@ -190,11 +190,11 @@ const _: () = { #[derive(Error, Debug)] pub enum ExecutionError { #[error(transparent)] - ViewError(#[from] ViewError), + ViewError(ViewError), #[error(transparent)] ArithmeticError(#[from] ArithmeticError), #[error(transparent)] - SystemError(#[from] SystemExecutionError), + SystemError(SystemExecutionError), #[error("User application reported an error: {0}")] UserError(String), #[cfg(any(with_wasmer, with_wasmtime))] @@ -264,6 +264,29 @@ pub enum ExecutionError { // and enforced limits for all oracles. #[error("Unstable oracles are disabled on this network.")] UnstableOracle, + + #[error("Blobs not found: {0:?}")] + BlobsNotFound(Vec), +} + +impl From for ExecutionError { + fn from(error: ViewError) -> Self { + match error { + ViewError::BlobsNotFound(blob_ids) => ExecutionError::BlobsNotFound(blob_ids), + error => ExecutionError::ViewError(error), + } + } +} + +impl From for ExecutionError { + fn from(error: SystemExecutionError) -> Self { + match error { + SystemExecutionError::BlobsNotFound(blob_ids) => { + ExecutionError::BlobsNotFound(blob_ids) + } + error => ExecutionError::SystemError(error), + } + } } /// The public entry points provided by the contract part of an application. @@ -346,7 +369,7 @@ pub trait ExecutionRuntimeContext { description: &UserApplicationDescription, ) -> Result; - async fn get_blob(&self, blob_id: BlobId) -> Result; + async fn get_blob(&self, blob_id: BlobId) -> Result; async fn contains_blob(&self, blob_id: BlobId) -> Result; } @@ -1018,11 +1041,11 @@ impl ExecutionRuntimeContext for TestExecutionRuntimeContext { .clone()) } - async fn get_blob(&self, blob_id: BlobId) -> Result { + async fn get_blob(&self, blob_id: BlobId) -> Result { Ok(self .blobs .get(&blob_id) - .ok_or_else(|| SystemExecutionError::BlobNotFoundOnRead(blob_id))? + .ok_or_else(|| ViewError::BlobsNotFound(vec![blob_id]))? .clone()) } diff --git a/linera-execution/src/system.rs b/linera-execution/src/system.rs index 61ac1254cf8..94cc631b139 100644 --- a/linera-execution/src/system.rs +++ b/linera-execution/src/system.rs @@ -336,7 +336,7 @@ pub enum SystemExecutionError { #[error(transparent)] ArithmeticError(#[from] ArithmeticError), #[error(transparent)] - ViewError(#[from] ViewError), + ViewError(ViewError), #[error("Invalid admin ID in new chain: {0}")] InvalidNewChainAdminId(ChainId), @@ -389,14 +389,23 @@ pub enum SystemExecutionError { #[error("Chain is not active yet.")] InactiveChain, - #[error("Blob not found on storage read: {0}")] - BlobNotFoundOnRead(BlobId), + #[error("Blobs not found: {0:?}")] + BlobsNotFound(Vec), #[error("Oracle response mismatch")] OracleResponseMismatch, #[error("No recorded response for oracle query")] MissingOracleResponse, } +impl From for SystemExecutionError { + fn from(error: ViewError) -> Self { + match error { + ViewError::BlobsNotFound(blob_ids) => SystemExecutionError::BlobsNotFound(blob_ids), + error => SystemExecutionError::ViewError(error), + } + } +} + impl SystemExecutionStateView where C: Context + Clone + Send + Sync + 'static, @@ -966,15 +975,11 @@ where Ok(messages) } - pub async fn read_blob_content( - &mut self, - blob_id: BlobId, - ) -> Result { + pub async fn read_blob_content(&mut self, blob_id: BlobId) -> Result { self.context() .extra() .get_blob(blob_id) .await - .map_err(|_| SystemExecutionError::BlobNotFoundOnRead(blob_id)) .map(Into::into) } @@ -985,7 +990,7 @@ where if self.context().extra().contains_blob(blob_id).await? { Ok(()) } else { - Err(SystemExecutionError::BlobNotFoundOnRead(blob_id)) + Err(SystemExecutionError::BlobsNotFound(vec![blob_id])) } } @@ -996,25 +1001,35 @@ where ) -> Result<(), SystemExecutionError> { let contract_bytecode_blob_id = BlobId::new(bytecode_id.contract_blob_hash, BlobType::ContractBytecode); - ensure!( - self.context() - .extra() - .contains_blob(contract_bytecode_blob_id) - .await?, - SystemExecutionError::BlobNotFoundOnRead(contract_bytecode_blob_id) - ); - txn_tracker.replay_oracle_response(OracleResponse::Blob(contract_bytecode_blob_id))?; + + let mut missing_blobs = Vec::new(); + if !self + .context() + .extra() + .contains_blob(contract_bytecode_blob_id) + .await? + { + missing_blobs.push(contract_bytecode_blob_id); + } + let service_bytecode_blob_id = BlobId::new(bytecode_id.service_blob_hash, BlobType::ServiceBytecode); - ensure!( - self.context() - .extra() - .contains_blob(service_bytecode_blob_id) - .await?, - SystemExecutionError::BlobNotFoundOnRead(service_bytecode_blob_id) - ); - txn_tracker.replay_oracle_response(OracleResponse::Blob(service_bytecode_blob_id))?; - Ok(()) + if !self + .context() + .extra() + .contains_blob(service_bytecode_blob_id) + .await? + { + missing_blobs.push(service_bytecode_blob_id); + } + + if missing_blobs.is_empty() { + txn_tracker.replay_oracle_response(OracleResponse::Blob(contract_bytecode_blob_id))?; + txn_tracker.replay_oracle_response(OracleResponse::Blob(service_bytecode_blob_id))?; + Ok(()) + } else { + Err(SystemExecutionError::BlobsNotFound(missing_blobs)) + } } } diff --git a/linera-rpc/tests/snapshots/format__format.yaml.snap b/linera-rpc/tests/snapshots/format__format.yaml.snap index 032ee89e0e7..1de66ecf376 100644 --- a/linera-rpc/tests/snapshots/format__format.yaml.snap +++ b/linera-rpc/tests/snapshots/format__format.yaml.snap @@ -597,14 +597,10 @@ NodeError: STRUCT: - error: STR 20: - BlobNotFoundOnRead: - NEWTYPE: - TYPENAME: BlobId - 21: InvalidCertificateForBlob: NEWTYPE: TYPENAME: BlobId - 22: + 21: LocalError: STRUCT: - error: STR diff --git a/linera-storage/src/db_storage.rs b/linera-storage/src/db_storage.rs index 8968b48dc5e..9d097a718d0 100644 --- a/linera-storage/src/db_storage.rs +++ b/linera-storage/src/db_storage.rs @@ -463,7 +463,7 @@ where let maybe_blob_bytes = self.store.read_value::>(&blob_key).await?; #[cfg(with_metrics)] READ_BLOB_COUNTER.with_label_values(&[]).inc(); - let blob_bytes = maybe_blob_bytes.ok_or_else(|| ViewError::BlobNotFoundOnRead(blob_id))?; + let blob_bytes = maybe_blob_bytes.ok_or_else(|| ViewError::BlobsNotFound(vec![blob_id]))?; Ok(Blob::new_with_id_unchecked(blob_id, blob_bytes)) } diff --git a/linera-storage/src/lib.rs b/linera-storage/src/lib.rs index 1b96ab5e546..0ef8d246139 100644 --- a/linera-storage/src/lib.rs +++ b/linera-storage/src/lib.rs @@ -403,8 +403,8 @@ where } } - async fn get_blob(&self, blob_id: BlobId) -> Result { - Ok(self.storage.read_blob(blob_id).await?) + async fn get_blob(&self, blob_id: BlobId) -> Result { + self.storage.read_blob(blob_id).await } async fn contains_blob(&self, blob_id: BlobId) -> Result { diff --git a/linera-views/src/views/mod.rs b/linera-views/src/views/mod.rs index 8dae9edffca..c7d8b52cfcd 100644 --- a/linera-views/src/views/mod.rs +++ b/linera-views/src/views/mod.rs @@ -155,9 +155,9 @@ pub enum ViewError { #[error("The value is too large for the client")] TooLargeValue, - /// Blob not found when trying to read it. - #[error("Blob not found on storage read: {0}")] - BlobNotFoundOnRead(BlobId), + /// Some blobs were not found. + #[error("Blobs not found: {0:?}")] + BlobsNotFound(Vec), } impl ViewError {