mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-02-03 19:45:20 -05:00
feat(provider): consistent database view (#6896)
This commit is contained in:
@@ -153,3 +153,20 @@ pub struct RootMismatch {
|
||||
/// The target block hash.
|
||||
pub block_hash: BlockHash,
|
||||
}
|
||||
|
||||
/// Consistent database view error.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ConsistentViewError {
|
||||
/// Error thrown on attempt to initialize provider while node is still syncing.
|
||||
#[error("node is syncing. best block: {0}")]
|
||||
Syncing(BlockNumber),
|
||||
/// Error thrown on inconsistent database view.
|
||||
#[error("inconsistent database state: {tip:?}")]
|
||||
InconsistentView {
|
||||
/// The tip diff.
|
||||
tip: GotExpected<Option<B256>>,
|
||||
},
|
||||
/// Underlying provider error.
|
||||
#[error(transparent)]
|
||||
Provider(#[from] ProviderError),
|
||||
}
|
||||
|
||||
71
crates/storage/provider/src/providers/consistent_view.rs
Normal file
71
crates/storage/provider/src/providers/consistent_view.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
use crate::{BlockNumReader, DatabaseProviderFactory, DatabaseProviderRO, ProviderError};
|
||||
use reth_db::{cursor::DbCursorRO, database::Database, tables, transaction::DbTx};
|
||||
use reth_interfaces::provider::{ConsistentViewError, ProviderResult};
|
||||
use reth_primitives::{GotExpected, B256};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// A consistent view over state in the database.
|
||||
///
|
||||
/// View gets initialized with the latest or provided tip.
|
||||
/// Upon every attempt to create a database provider, the view will
|
||||
/// perform a consistency check of current tip against the initial one.
|
||||
///
|
||||
/// ## Usage
|
||||
///
|
||||
/// The view should only be used outside of staged-sync.
|
||||
/// Otherwise, any attempt to create a provider will result in [ConsistentViewError::Syncing].
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ConsistentDbView<DB, Provider> {
|
||||
database: PhantomData<DB>,
|
||||
provider: Provider,
|
||||
tip: Option<B256>,
|
||||
}
|
||||
|
||||
impl<DB, Provider> ConsistentDbView<DB, Provider>
|
||||
where
|
||||
DB: Database,
|
||||
Provider: DatabaseProviderFactory<DB>,
|
||||
{
|
||||
/// Creates new consistent database view.
|
||||
pub fn new(provider: Provider) -> Self {
|
||||
Self { database: PhantomData, provider, tip: None }
|
||||
}
|
||||
|
||||
/// Initializes the view with provided tip.
|
||||
pub fn with_tip(mut self, tip: B256) -> Self {
|
||||
self.tip = Some(tip);
|
||||
self
|
||||
}
|
||||
|
||||
/// Initializes the view with latest tip.
|
||||
pub fn with_latest_tip(mut self) -> ProviderResult<Self> {
|
||||
let provider = self.provider.database_provider_ro()?;
|
||||
let tip = provider.tx_ref().cursor_read::<tables::CanonicalHeaders>()?.last()?;
|
||||
self.tip = tip.map(|(_, hash)| hash);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Creates new read-only provider and performs consistency checks on the current tip.
|
||||
pub fn provider_ro(&self) -> Result<DatabaseProviderRO<DB>, ConsistentViewError> {
|
||||
let provider_ro = self.provider.database_provider_ro()?;
|
||||
let last_entry = provider_ro
|
||||
.tx_ref()
|
||||
.cursor_read::<tables::CanonicalHeaders>()
|
||||
.and_then(|mut cursor| cursor.last())
|
||||
.map_err(ProviderError::Database)?;
|
||||
|
||||
let tip = last_entry.map(|(_, hash)| hash);
|
||||
if self.tip != tip {
|
||||
return Err(ConsistentViewError::InconsistentView {
|
||||
tip: GotExpected { got: tip, expected: self.tip },
|
||||
})
|
||||
}
|
||||
|
||||
let best_block_number = provider_ro.best_block_number()?;
|
||||
if last_entry.map(|(number, _)| number).unwrap_or_default() != best_block_number {
|
||||
return Err(ConsistentViewError::Syncing(best_block_number))
|
||||
}
|
||||
|
||||
Ok(provider_ro)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,20 @@
|
||||
use crate::{
|
||||
AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
|
||||
BlockchainTreePendingStateProvider, BundleStateDataProvider, CanonChainTracker,
|
||||
BlockSource, BlockchainTreePendingStateProvider, BundleStateDataProvider, CanonChainTracker,
|
||||
CanonStateNotifications, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader,
|
||||
DatabaseProviderFactory, EvmEnvProvider, HeaderProvider, ProviderError, PruneCheckpointReader,
|
||||
ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader, StateProviderBox,
|
||||
StateProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider,
|
||||
};
|
||||
use reth_db::{database::Database, models::StoredBlockBodyIndices};
|
||||
use reth_db::{
|
||||
database::Database,
|
||||
models::{AccountBeforeTx, StoredBlockBodyIndices},
|
||||
};
|
||||
use reth_interfaces::{
|
||||
blockchain_tree::{BlockchainTreeEngine, BlockchainTreeViewer},
|
||||
blockchain_tree::{
|
||||
error::InsertBlockError, BlockValidationKind, BlockchainTreeEngine, BlockchainTreeViewer,
|
||||
CanonicalOutcome, InsertPayloadOk,
|
||||
},
|
||||
consensus::ForkchoiceState,
|
||||
provider::ProviderResult,
|
||||
RethError, RethResult,
|
||||
@@ -31,27 +37,29 @@ use std::{
|
||||
};
|
||||
use tracing::trace;
|
||||
|
||||
mod database;
|
||||
pub use database::*;
|
||||
|
||||
mod static_file;
|
||||
pub use static_file::{
|
||||
StaticFileJarProvider, StaticFileProvider, StaticFileProviderRW, StaticFileProviderRWRefMut,
|
||||
StaticFileWriter,
|
||||
};
|
||||
|
||||
mod state;
|
||||
pub use state::{
|
||||
historical::{HistoricalStateProvider, HistoricalStateProviderRef},
|
||||
latest::{LatestStateProvider, LatestStateProviderRef},
|
||||
};
|
||||
|
||||
mod bundle_state_provider;
|
||||
mod chain_info;
|
||||
mod database;
|
||||
mod static_file;
|
||||
pub use static_file::{
|
||||
StaticFileJarProvider, StaticFileProvider, StaticFileProviderRW, StaticFileProviderRWRefMut,
|
||||
StaticFileWriter,
|
||||
};
|
||||
mod state;
|
||||
use crate::{providers::chain_info::ChainInfoTracker, traits::BlockSource};
|
||||
pub use bundle_state_provider::BundleStateProvider;
|
||||
pub use database::*;
|
||||
use reth_db::models::AccountBeforeTx;
|
||||
use reth_interfaces::blockchain_tree::{
|
||||
error::InsertBlockError, BlockValidationKind, CanonicalOutcome, InsertPayloadOk,
|
||||
};
|
||||
|
||||
mod chain_info;
|
||||
use chain_info::ChainInfoTracker;
|
||||
|
||||
mod consistent_view;
|
||||
pub use consistent_view::ConsistentDbView;
|
||||
|
||||
/// The main type for interacting with the blockchain.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user