From 05f6ae52fa7c4a454bb6005ecdf87d443e288c18 Mon Sep 17 00:00:00 2001 From: DoohyunCho Date: Wed, 7 Jan 2026 09:21:08 +0900 Subject: [PATCH 1/2] fix(database): return error instead of panic when block not found in AlloyDB - Change DBTransportError struct to AlloyDBError enum - Add BlockNotFound variant for missing block errors - Handle None case in block_hash_async_ref gracefully This fixes potential panics when: - Using pruned nodes with deleted block data - Using light clients without full block data - Requesting future or non-existent block numbers Closes #3278 --- crates/database/src/alloydb.rs | 45 +++++++++++++++++++++++++--------- crates/database/src/lib.rs | 2 +- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/crates/database/src/alloydb.rs b/crates/database/src/alloydb.rs index 5a0234ba72..f3efe077d1 100644 --- a/crates/database/src/alloydb.rs +++ b/crates/database/src/alloydb.rs @@ -12,23 +12,43 @@ use primitives::{Address, StorageKey, StorageValue, B256}; use state::{AccountInfo, Bytecode}; use std::fmt::Display; -/// Error type for transport-related database operations. +/// Error type for AlloyDB database operations. #[derive(Debug)] -pub struct DBTransportError(pub TransportError); +pub enum AlloyDBError { + /// Transport error from the underlying provider. + Transport(TransportError), + /// Block not found for the given block number. + /// + /// This can occur when: + /// - The block number is in the future + /// - The node has pruned the block data + /// - Using a light client that doesn't have the block + BlockNotFound(u64), +} -impl DBErrorMarker for DBTransportError {} +impl DBErrorMarker for AlloyDBError {} -impl Display for DBTransportError { +impl Display for AlloyDBError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Transport error: {}", self.0) + match self { + Self::Transport(err) => write!(f, "Transport error: {err}"), + Self::BlockNotFound(number) => write!(f, "Block not found: {number}"), + } } } -impl Error for DBTransportError {} +impl Error for AlloyDBError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + Self::Transport(err) => Some(err), + Self::BlockNotFound(_) => None, + } + } +} -impl From for DBTransportError { +impl From for AlloyDBError { fn from(e: TransportError) -> Self { - Self(e) + Self::Transport(e) } } @@ -61,7 +81,7 @@ impl> AlloyDB { } impl> DatabaseAsyncRef for AlloyDB { - type Error = DBTransportError; + type Error = AlloyDBError; async fn basic_async_ref(&self, address: Address) -> Result, Self::Error> { let nonce = self @@ -93,8 +113,11 @@ impl> DatabaseAsyncRef for AlloyDB { // SAFETY: We know number <= u64::MAX, so we can safely convert it to u64 .get_block_by_number(number.into()) .await?; - // SAFETY: If the number is given, the block is supposed to be finalized, so unwrapping is safe. - Ok(B256::new(*block.unwrap().header().hash())) + + match block { + Some(block) => Ok(B256::new(*block.header().hash())), + None => Err(AlloyDBError::BlockNotFound(number)), + } } async fn code_by_hash_async_ref(&self, _code_hash: B256) -> Result { diff --git a/crates/database/src/lib.rs b/crates/database/src/lib.rs index a1f6f5c543..ab1574a7c9 100644 --- a/crates/database/src/lib.rs +++ b/crates/database/src/lib.rs @@ -15,7 +15,7 @@ pub mod in_memory_db; pub mod states; #[cfg(feature = "alloydb")] -pub use alloydb::{AlloyDB, BlockId, DBTransportError}; +pub use alloydb::{AlloyDB, AlloyDBError, BlockId}; pub use in_memory_db::*; pub use states::{ From 3a61f56c26214085921bcf9228c2910145b327f0 Mon Sep 17 00:00:00 2001 From: rakita Date: Thu, 8 Jan 2026 12:15:44 +0100 Subject: [PATCH 2/2] Apply suggestion from @rakita --- crates/database/src/alloydb.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/database/src/alloydb.rs b/crates/database/src/alloydb.rs index f3efe077d1..06a75edf37 100644 --- a/crates/database/src/alloydb.rs +++ b/crates/database/src/alloydb.rs @@ -20,7 +20,6 @@ pub enum AlloyDBError { /// Block not found for the given block number. /// /// This can occur when: - /// - The block number is in the future /// - The node has pruned the block data /// - Using a light client that doesn't have the block BlockNotFound(u64),