diff --git a/crates/interfaces/src/provider.rs b/crates/interfaces/src/provider.rs index c82116b2b1..54a5592efb 100644 --- a/crates/interfaces/src/provider.rs +++ b/crates/interfaces/src/provider.rs @@ -74,8 +74,6 @@ pub enum ProviderError { /// Some error occurred while interacting with the state tree. #[error("Unknown error occurred while interacting with the state trie.")] StateTrie, - #[error("History state root, can't be calculated")] - HistoryStateRoot, /// Thrown when required header related data was not found but was required. #[error("requested data not found")] HeaderNotFound, @@ -91,6 +89,7 @@ pub enum ProviderError { /// Thrown when we failed to lookup a block for the pending state #[error("Unknown block hash: {0:}")] UnknownBlockHash(H256), + /// Unable to compute state root on top of historical block #[error("Unable to compute state root on top of historical block")] StateRootNotAvailableForHistoricalBlock, } diff --git a/crates/storage/provider/src/providers/database.rs b/crates/storage/provider/src/providers/database.rs index 42a1d3d04f..d6ed3fe09d 100644 --- a/crates/storage/provider/src/providers/database.rs +++ b/crates/storage/provider/src/providers/database.rs @@ -54,6 +54,10 @@ impl ShareableDatabase { ) -> Result> { let tx = self.db.tx()?; + if is_latest_block_number(&tx, block_number)? { + return Ok(Box::new(LatestStateProvider::new(tx))) + } + // +1 as the changeset that we want is the one that was applied after this block. block_number += 1; @@ -68,6 +72,10 @@ impl ShareableDatabase { .get::(block_hash)? .ok_or(ProviderError::BlockHash { block_hash })?; + if is_latest_block_number(&tx, block_number)? { + return Ok(Box::new(LatestStateProvider::new(tx))) + } + // +1 as the changeset that we want is the one that was applied after this block. // as the changeset contains old values. block_number += 1; @@ -145,11 +153,7 @@ impl BlockIdProvider for ShareableDatabase { } fn best_block_number(&self) -> Result { - Ok(self - .db - .view(|tx| tx.get::("Finish".to_string()))? - .map_err(Into::::into)? - .unwrap_or_default()) + Ok(self.db.view(|tx| best_block_number(tx))??.unwrap_or_default()) } fn block_number(&self, hash: H256) -> Result> { @@ -452,6 +456,44 @@ impl EvmEnvProvider for ShareableDatabase { } } +/// Fetches checks if the block number is the latest block number. +#[inline] +fn is_latest_block_number<'a, TX>( + tx: &TX, + block_number: BlockNumber, +) -> std::result::Result +where + TX: DbTx<'a> + Send + Sync, +{ + // check if the block number is the best block number + // there's always at least one header in the database (genesis) + let best = best_block_number(tx)?.unwrap_or_default(); + let last = last_canonical_header(tx)?.map(|(last, _)| last).unwrap_or_default(); + Ok(block_number == best && block_number == last) +} + +/// Fetches the best block number from the database. +#[inline] +fn best_block_number<'a, TX>( + tx: &TX, +) -> std::result::Result, reth_interfaces::db::Error> +where + TX: DbTx<'a> + Send + Sync, +{ + tx.get::("Finish".to_string()) +} + +/// Fetches the last canonical header from the database. +#[inline] +fn last_canonical_header<'a, TX>( + tx: &TX, +) -> std::result::Result, reth_interfaces::db::Error> +where + TX: DbTx<'a> + Send + Sync, +{ + tx.cursor_read::()?.last() +} + #[cfg(test)] mod tests { use super::ShareableDatabase; diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index 2a2e68c7d3..0df7b46139 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -299,7 +299,6 @@ where if let Some(pending) = self.tree.find_pending_state_provider(block) { return self.pending_with_provider(pending) } - // not found in tree, check database self.history_by_block_hash(block) } diff --git a/crates/storage/provider/src/providers/post_state_provider.rs b/crates/storage/provider/src/providers/post_state_provider.rs index d69617c79e..8d0aedd27b 100644 --- a/crates/storage/provider/src/providers/post_state_provider.rs +++ b/crates/storage/provider/src/providers/post_state_provider.rs @@ -94,6 +94,6 @@ impl StateProvider for PostState _address: Address, _keys: &[H256], ) -> Result<(Vec, H256, Vec>)> { - Err(ProviderError::HistoryStateRoot.into()) + Err(ProviderError::StateRootNotAvailableForHistoricalBlock.into()) } } diff --git a/crates/storage/provider/src/providers/state/historical.rs b/crates/storage/provider/src/providers/state/historical.rs index 9c40d76127..3719313bd1 100644 --- a/crates/storage/provider/src/providers/state/historical.rs +++ b/crates/storage/provider/src/providers/state/historical.rs @@ -149,7 +149,7 @@ impl<'a, 'b, TX: DbTx<'a>> StateProvider for HistoricalStateProviderRef<'a, 'b, _address: Address, _keys: &[H256], ) -> Result<(Vec, H256, Vec>)> { - Err(ProviderError::HistoryStateRoot.into()) + Err(ProviderError::StateRootNotAvailableForHistoricalBlock.into()) } }