feat: check if blocknumber is latest block number (#2428)

This commit is contained in:
Matthias Seitz
2023-04-27 13:45:17 +02:00
committed by GitHub
parent a69b2e1600
commit e2bacdfad7
5 changed files with 50 additions and 10 deletions

View File

@@ -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,
}

View File

@@ -54,6 +54,10 @@ impl<DB: Database> ShareableDatabase<DB> {
) -> Result<StateProviderBox<'_>> {
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<DB: Database> ShareableDatabase<DB> {
.get::<tables::HeaderNumbers>(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<DB: Database> BlockIdProvider for ShareableDatabase<DB> {
}
fn best_block_number(&self) -> Result<BlockNumber> {
Ok(self
.db
.view(|tx| tx.get::<tables::SyncStage>("Finish".to_string()))?
.map_err(Into::<reth_interfaces::db::Error>::into)?
.unwrap_or_default())
Ok(self.db.view(|tx| best_block_number(tx))??.unwrap_or_default())
}
fn block_number(&self, hash: H256) -> Result<Option<BlockNumber>> {
@@ -452,6 +456,44 @@ impl<DB: Database> EvmEnvProvider for ShareableDatabase<DB> {
}
}
/// 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<bool, reth_interfaces::db::Error>
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<Option<BlockNumber>, reth_interfaces::db::Error>
where
TX: DbTx<'a> + Send + Sync,
{
tx.get::<tables::SyncStage>("Finish".to_string())
}
/// Fetches the last canonical header from the database.
#[inline]
fn last_canonical_header<'a, TX>(
tx: &TX,
) -> std::result::Result<Option<(BlockNumber, BlockHash)>, reth_interfaces::db::Error>
where
TX: DbTx<'a> + Send + Sync,
{
tx.cursor_read::<tables::CanonicalHeaders>()?.last()
}
#[cfg(test)]
mod tests {
use super::ShareableDatabase;

View File

@@ -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)
}

View File

@@ -94,6 +94,6 @@ impl<SP: StateProvider, PSDP: PostStateDataProvider> StateProvider for PostState
_address: Address,
_keys: &[H256],
) -> Result<(Vec<Bytes>, H256, Vec<Vec<Bytes>>)> {
Err(ProviderError::HistoryStateRoot.into())
Err(ProviderError::StateRootNotAvailableForHistoricalBlock.into())
}
}

View File

@@ -149,7 +149,7 @@ impl<'a, 'b, TX: DbTx<'a>> StateProvider for HistoricalStateProviderRef<'a, 'b,
_address: Address,
_keys: &[H256],
) -> Result<(Vec<Bytes>, H256, Vec<Vec<Bytes>>)> {
Err(ProviderError::HistoryStateRoot.into())
Err(ProviderError::StateRootNotAvailableForHistoricalBlock.into())
}
}