From b52a65bf4f797ec1dc1a173c20d7ec9be56954ca Mon Sep 17 00:00:00 2001 From: frostburn Date: Tue, 13 Aug 2024 15:56:54 -0700 Subject: [PATCH] chore(reth-storage-errors): no_std support (#10011) --- Cargo.lock | 2 +- crates/storage/errors/Cargo.toml | 5 +- crates/storage/errors/src/db.rs | 80 +++++++++----- crates/storage/errors/src/lockfile.rs | 15 ++- crates/storage/errors/src/provider.rs | 144 ++++++++++++++++---------- crates/storage/errors/src/writer.rs | 29 +++++- 6 files changed, 177 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae87198135b6..655a244abed8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8679,9 +8679,9 @@ name = "reth-storage-errors" version = "1.0.5" dependencies = [ "alloy-rlp", + "derive_more", "reth-fs-util", "reth-primitives", - "thiserror-no-std", ] [[package]] diff --git a/crates/storage/errors/Cargo.toml b/crates/storage/errors/Cargo.toml index 5ef6f15771ef..c93adfbe1955 100644 --- a/crates/storage/errors/Cargo.toml +++ b/crates/storage/errors/Cargo.toml @@ -15,8 +15,9 @@ alloy-rlp.workspace = true reth-primitives.workspace = true reth-fs-util.workspace = true -thiserror-no-std = { workspace = true, default-features = false } +# misc +derive_more.workspace = true [features] default = ["std"] -std = ["thiserror-no-std/std"] \ No newline at end of file +std = [] \ No newline at end of file diff --git a/crates/storage/errors/src/db.rs b/crates/storage/errors/src/db.rs index 8b4896d23236..a2cbcba33ced 100644 --- a/crates/storage/errors/src/db.rs +++ b/crates/storage/errors/src/db.rs @@ -1,5 +1,5 @@ #[cfg(feature = "std")] -use std::{fmt::Display, str::FromStr, string::String}; +use std::{fmt, fmt::Display, str::FromStr, string::String}; #[cfg(not(feature = "std"))] use alloc::{ @@ -8,54 +8,66 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; - #[cfg(not(feature = "std"))] -use core::{fmt::Display, str::FromStr}; +use core::{ + fmt, + fmt::{Debug, Display}, + str::FromStr, +}; /// Database error type. -#[derive(Clone, Debug, PartialEq, Eq, thiserror_no_std::Error)] +#[derive(Clone, Debug, PartialEq, Eq, derive_more::Display)] pub enum DatabaseError { /// Failed to open the database. - #[error("failed to open the database: {0}")] + #[display(fmt = "failed to open the database: {_0}")] Open(DatabaseErrorInfo), /// Failed to create a table in the database. - #[error("failed to create a table: {0}")] + #[display(fmt = "failed to create a table: {_0}")] CreateTable(DatabaseErrorInfo), /// Failed to write a value into a table. - #[error(transparent)] - Write(#[from] Box), + Write(Box), /// Failed to read a value from a table. - #[error("failed to read a value from a database table: {0}")] + #[display(fmt = "failed to read a value from a database table: {_0}")] Read(DatabaseErrorInfo), /// Failed to delete a `(key, value)` pair from a table. - #[error("database delete error code: {0}")] + #[display(fmt = "database delete error code: {_0}")] Delete(DatabaseErrorInfo), /// Failed to commit transaction changes into the database. - #[error("failed to commit transaction changes: {0}")] + #[display(fmt = "failed to commit transaction changes: {_0}")] Commit(DatabaseErrorInfo), /// Failed to initiate a transaction. - #[error("failed to initialize a transaction: {0}")] + #[display(fmt = "failed to initialize a transaction: {_0}")] InitTx(DatabaseErrorInfo), /// Failed to initialize a cursor. - #[error("failed to initialize a cursor: {0}")] + #[display(fmt = "failed to initialize a cursor: {_0}")] InitCursor(DatabaseErrorInfo), /// Failed to decode a key from a table. - #[error("failed to decode a key from a table")] + #[display(fmt = "failed to decode a key from a table")] Decode, /// Failed to get database stats. - #[error("failed to get stats: {0}")] + #[display(fmt = "failed to get stats: {_0}")] Stats(DatabaseErrorInfo), /// Failed to use the specified log level, as it's not available. - #[error("log level {0:?} is not available")] + #[display(fmt = "log level {_0:?} is not available")] LogLevelUnavailable(LogLevel), /// Other unspecified error. - #[error("{0}")] + #[display(fmt = "{_0}")] Other(String), } +#[cfg(feature = "std")] +impl std::error::Error for DatabaseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Write(err) => std::error::Error::source(err), + _ => Option::None, + } + } +} + /// Common error struct to propagate implementation-specific error information. -#[derive(Debug, Clone, PartialEq, Eq, thiserror_no_std::Error)] -#[error("{message} ({code})")] +#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display)] +#[display(fmt = "{message} ({code})")] pub struct DatabaseErrorInfo { /// Human-readable error message. pub message: String, @@ -68,24 +80,20 @@ where E: Display + Into, { #[inline] - fn from(value: E) -> Self { - Self { message: value.to_string(), code: value.into() } + fn from(error: E) -> Self { + Self { message: error.to_string(), code: error.into() } } } impl From for DatabaseError { #[inline] - fn from(value: DatabaseWriteError) -> Self { - Self::Write(Box::new(value)) + fn from(error: DatabaseWriteError) -> Self { + Self::Write(Box::new(error)) } } /// Database write error. -#[derive(Clone, Debug, PartialEq, Eq, thiserror_no_std::Error)] -#[error( - "write operation {operation:?} failed for key \"{key}\" in table {table_name:?}: {info}", - key = reth_primitives::hex::encode(key), -)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct DatabaseWriteError { /// The error code and message. pub info: DatabaseErrorInfo, @@ -97,6 +105,22 @@ pub struct DatabaseWriteError { pub key: Vec, } +impl fmt::Display for DatabaseWriteError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "write operation {:?} failed for key \"{}\" in table {}: {}", + self.operation, + reth_primitives::hex::encode(&self.key), + self.table_name, + self.info + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for DatabaseWriteError {} + /// Database write operation type. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum DatabaseWriteOperation { diff --git a/crates/storage/errors/src/lockfile.rs b/crates/storage/errors/src/lockfile.rs index db27cb6e2e45..ede10401a20c 100644 --- a/crates/storage/errors/src/lockfile.rs +++ b/crates/storage/errors/src/lockfile.rs @@ -4,19 +4,24 @@ use reth_fs_util::FsPathError; use alloc::string::{String, ToString}; /// Storage lock error. -#[derive(Debug, Clone, PartialEq, Eq, thiserror_no_std::Error)] +#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display)] pub enum StorageLockError { /// Write lock taken - #[error("storage directory is currently in use as read-write by another process: PID {0}")] + #[display( + fmt = "storage directory is currently in use as read-write by another process: PID {_0}" + )] Taken(usize), /// Indicates other unspecified errors. - #[error("{0}")] + #[display(fmt = "{_0}")] Other(String), } +#[cfg(feature = "std")] +impl std::error::Error for StorageLockError {} + /// TODO: turn into variant once `ProviderError` impl From for StorageLockError { - fn from(source: FsPathError) -> Self { - Self::Other(source.to_string()) + fn from(error: FsPathError) -> Self { + Self::Other(error.to_string()) } } diff --git a/crates/storage/errors/src/provider.rs b/crates/storage/errors/src/provider.rs index 804d7693f50b..980e44c07ec2 100644 --- a/crates/storage/errors/src/provider.rs +++ b/crates/storage/errors/src/provider.rs @@ -1,3 +1,5 @@ +use crate::{db::DatabaseError, lockfile::StorageLockError, writer::UnifiedStorageWriterError}; +use derive_more::Display; use reth_primitives::{ Address, BlockHash, BlockHashOrNumber, BlockNumber, GotExpected, StaticFileSegment, TxHashOrNumber, TxNumber, B256, U256, @@ -7,44 +9,41 @@ use reth_primitives::{ use std::path::PathBuf; #[cfg(not(feature = "std"))] -use alloc::{ - boxed::Box, - string::{String, ToString}, -}; +use alloc::{boxed::Box, string::String}; /// Provider result type. pub type ProviderResult = Result; /// Bundled errors variants thrown by various providers. -#[derive(Clone, Debug, thiserror_no_std::Error, PartialEq, Eq)] +#[derive(Clone, Debug, Display, PartialEq, Eq)] pub enum ProviderError { /// Database error. - #[error(transparent)] - Database(#[from] crate::db::DatabaseError), + Database(DatabaseError), /// RLP error. - #[error(transparent)] - Rlp(#[from] alloy_rlp::Error), + Rlp(alloy_rlp::Error), /// Filesystem path error. - #[error("{0}")] + #[display(fmt = "{_0}")] FsPathError(String), /// Nippy jar error. - #[error("nippy jar error: {0}")] + #[display(fmt = "nippy jar error: {_0}")] NippyJar(String), /// Trie witness error. - #[error("trie witness error: {0}")] + #[display(fmt = "trie witness error: {_0}")] TrieWitnessError(String), /// Error when recovering the sender for a transaction - #[error("failed to recover sender for transaction")] + #[display(fmt = "failed to recover sender for transaction")] SenderRecoveryError, /// The header number was not found for the given block hash. - #[error("block hash {0} does not exist in Headers table")] + #[display(fmt = "block hash {_0} does not exist in Headers table")] BlockHashNotFound(BlockHash), /// A block body is missing. - #[error("block meta not found for block #{0}")] + #[display(fmt = "block meta not found for block #{_0}")] BlockBodyIndicesNotFound(BlockNumber), /// The transition ID was found for the given address and storage key, but the changeset was /// not found. - #[error("storage change set for address {address} and key {storage_key} at block #{block_number} does not exist")] + #[display( + fmt = "storage change set for address {address} and key {storage_key} at block #{block_number} does not exist" + )] StorageChangesetNotFound { /// The block number found for the address and storage key. block_number: BlockNumber, @@ -56,7 +55,9 @@ pub enum ProviderError { storage_key: Box, }, /// The block number was found for the given address, but the changeset was not found. - #[error("account change set for address {address} at block #{block_number} does not exist")] + #[display( + fmt = "account change set for address {address} at block #{block_number} does not exist" + )] AccountChangesetNotFound { /// Block number found for the address. block_number: BlockNumber, @@ -64,104 +65,133 @@ pub enum ProviderError { address: Address, }, /// The total difficulty for a block is missing. - #[error("total difficulty not found for block #{0}")] + #[display(fmt = "total difficulty not found for block #{_0}")] TotalDifficultyNotFound(BlockNumber), /// when required header related data was not found but was required. - #[error("no header found for {0:?}")] + #[display(fmt = "no header found for {_0:?}")] HeaderNotFound(BlockHashOrNumber), /// The specific transaction is missing. - #[error("no transaction found for {0:?}")] + #[display(fmt = "no transaction found for {_0:?}")] TransactionNotFound(TxHashOrNumber), /// The specific receipt is missing - #[error("no receipt found for {0:?}")] + #[display(fmt = "no receipt found for {_0:?}")] ReceiptNotFound(TxHashOrNumber), /// Unable to find the best block. - #[error("best block does not exist")] + #[display(fmt = "best block does not exist")] BestBlockNotFound, /// Unable to find the finalized block. - #[error("finalized block does not exist")] + #[display(fmt = "finalized block does not exist")] FinalizedBlockNotFound, /// Unable to find the safe block. - #[error("safe block does not exist")] + #[display(fmt = "safe block does not exist")] SafeBlockNotFound, /// Mismatch of sender and transaction. - #[error("mismatch of sender and transaction id {tx_id}")] + #[display(fmt = "mismatch of sender and transaction id {tx_id}")] MismatchOfTransactionAndSenderId { /// The transaction ID. tx_id: TxNumber, }, /// Block body wrong transaction count. - #[error("stored block indices does not match transaction count")] + #[display(fmt = "stored block indices does not match transaction count")] BlockBodyTransactionCount, /// Thrown when the cache service task dropped. - #[error("cache service task stopped")] + #[display(fmt = "cache service task stopped")] CacheServiceUnavailable, /// Thrown when we failed to lookup a block for the pending state. - #[error("unknown block {0}")] + #[display(fmt = "unknown block {_0}")] UnknownBlockHash(B256), /// Thrown when we were unable to find a state for a block hash. - #[error("no state found for block hash {0}")] + #[display(fmt = "no state found for block {_0}")] StateForHashNotFound(B256), /// Thrown when we were unable to find a state for a block number. - #[error("no state found for block number {0}")] + #[display(fmt = "no state found for block number {_0}")] StateForNumberNotFound(u64), /// Unable to find the block number for a given transaction index. - #[error("unable to find the block number for a given transaction index")] + #[display(fmt = "unable to find the block number for a given transaction index")] BlockNumberForTransactionIndexNotFound, /// Root mismatch. - #[error("merkle trie {0}")] + #[display(fmt = "merkle trie {_0}")] StateRootMismatch(Box), /// Root mismatch during unwind - #[error("unwind merkle trie {0}")] + #[display(fmt = "unwind merkle trie {_0}")] UnwindStateRootMismatch(Box), /// State is not available for the given block number because it is pruned. - #[error("state at block #{0} is pruned")] + #[display(fmt = "state at block #{_0} is pruned")] StateAtBlockPruned(BlockNumber), /// Provider does not support this particular request. - #[error("this provider does not support this request")] + #[display(fmt = "this provider does not support this request")] UnsupportedProvider, /// Static File is not found at specified path. #[cfg(feature = "std")] - #[error("not able to find {0} static file at {1}")] + #[display(fmt = "not able to find {_0} static file at {_1:?}")] MissingStaticFilePath(StaticFileSegment, PathBuf), /// Static File is not found for requested block. - #[error("not able to find {0} static file for block number {1}")] + #[display(fmt = "not able to find {_0} static file for block number {_1}")] MissingStaticFileBlock(StaticFileSegment, BlockNumber), /// Static File is not found for requested transaction. - #[error("unable to find {0} static file for transaction id {1}")] + #[display(fmt = "unable to find {_0} static file for transaction id {_1}")] MissingStaticFileTx(StaticFileSegment, TxNumber), /// Static File is finalized and cannot be written to. - #[error("unable to write block #{1} to finalized static file {0}")] + #[display(fmt = "unable to write block #{_1} to finalized static file {_0}")] FinalizedStaticFile(StaticFileSegment, BlockNumber), /// Trying to insert data from an unexpected block number. - #[error("trying to append data to {0} as block #{1} but expected block #{2}")] + #[display(fmt = "trying to append data to {_0} as block #{_1} but expected block #{_2}")] UnexpectedStaticFileBlockNumber(StaticFileSegment, BlockNumber, BlockNumber), /// Static File Provider was initialized as read-only. - #[error("cannot get a writer on a read-only environment.")] + #[display(fmt = "cannot get a writer on a read-only environment.")] ReadOnlyStaticFileAccess, /// Error encountered when the block number conversion from U256 to u64 causes an overflow. - #[error("failed to convert block number U256 to u64: {0}")] + #[display(fmt = "failed to convert block number U256 to u64: {_0}")] BlockNumberOverflow(U256), /// Consistent view error. - #[error("failed to initialize consistent view: {0}")] + #[display(fmt = "failed to initialize consistent view: {_0}")] ConsistentView(Box), /// Storage lock error. - #[error(transparent)] - StorageLockError(#[from] crate::lockfile::StorageLockError), + StorageLockError(StorageLockError), /// Storage writer error. - #[error(transparent)] - UnifiedStorageWriterError(#[from] crate::writer::UnifiedStorageWriterError), + UnifiedStorageWriterError(UnifiedStorageWriterError), +} + +impl From for ProviderError { + fn from(error: DatabaseError) -> Self { + Self::Database(error) + } +} + +impl From for ProviderError { + fn from(error: alloy_rlp::Error) -> Self { + Self::Rlp(error) + } } -impl From for ProviderError { - fn from(err: reth_fs_util::FsPathError) -> Self { - Self::FsPathError(err.to_string()) +impl From for ProviderError { + fn from(error: StorageLockError) -> Self { + Self::StorageLockError(error) + } +} + +impl From for ProviderError { + fn from(error: UnifiedStorageWriterError) -> Self { + Self::UnifiedStorageWriterError(error) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ProviderError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Database(source) => std::error::Error::source(source), + Self::Rlp(source) => std::error::Error::source(source), + Self::StorageLockError(source) => std::error::Error::source(source), + Self::UnifiedStorageWriterError(source) => std::error::Error::source(source), + _ => Option::None, + } } } /// A root mismatch error at a given block height. -#[derive(Clone, Debug, PartialEq, Eq, thiserror_no_std::Error)] -#[error("root mismatch at #{block_number} ({block_hash}): {root}")] +#[derive(Clone, Debug, PartialEq, Eq, Display)] +#[display(fmt = "root mismatch at #{block_number} ({block_hash}): {root}")] pub struct RootMismatch { /// The target block root diff. pub root: GotExpected, @@ -172,16 +202,16 @@ pub struct RootMismatch { } /// Consistent database view error. -#[derive(Clone, Debug, PartialEq, Eq, thiserror_no_std::Error)] +#[derive(Clone, Debug, PartialEq, Eq, Display)] pub enum ConsistentViewError { /// Error thrown on attempt to initialize provider while node is still syncing. - #[error("node is syncing. best block: {best_block:?}")] + #[display(fmt = "node is syncing. best block: {best_block:?}")] Syncing { /// Best block diff. best_block: GotExpected, }, /// Error thrown on inconsistent database view. - #[error("inconsistent database state: {tip:?}")] + #[display(fmt = "inconsistent database state: {tip:?}")] Inconsistent { /// The tip diff. tip: GotExpected>, @@ -189,7 +219,7 @@ pub enum ConsistentViewError { } impl From for ProviderError { - fn from(value: ConsistentViewError) -> Self { - Self::ConsistentView(Box::new(value)) + fn from(error: ConsistentViewError) -> Self { + Self::ConsistentView(Box::new(error)) } } diff --git a/crates/storage/errors/src/writer.rs b/crates/storage/errors/src/writer.rs index 362140da7b61..e5317043c8d4 100644 --- a/crates/storage/errors/src/writer.rs +++ b/crates/storage/errors/src/writer.rs @@ -2,15 +2,34 @@ use crate::db::DatabaseError; use reth_primitives::StaticFileSegment; /// `UnifiedStorageWriter` related errors -#[derive(Clone, Debug, thiserror_no_std::Error, PartialEq, Eq)] +/// `StorageWriter` related errors +#[derive(Clone, Debug, derive_more::Display, PartialEq, Eq)] pub enum UnifiedStorageWriterError { + /// Database writer is missing + #[display(fmt = "Database writer is missing")] + MissingDatabaseWriter, /// Static file writer is missing - #[error("Static file writer is missing")] + #[display(fmt = "Static file writer is missing")] MissingStaticFileWriter, /// Static file writer is of wrong segment - #[error("Static file writer is of wrong segment: got {0}, expected {1}")] + #[display(fmt = "Static file writer is of wrong segment: got {_0}, expected {_1}")] IncorrectStaticFileWriter(StaticFileSegment, StaticFileSegment), /// Database-related errors. - #[error(transparent)] - Database(#[from] DatabaseError), + Database(DatabaseError), +} + +#[cfg(feature = "std")] +impl std::error::Error for UnifiedStorageWriterError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Database(source) => std::error::Error::source(source), + _ => Option::None, + } + } +} + +impl From for UnifiedStorageWriterError { + fn from(error: DatabaseError) -> Self { + Self::Database(error) + } }