mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
fix: set finalized & safe block information on startup (#9898)
Co-authored-by: Danyal Prout <me@dany.al>
This commit is contained in:
@ -17,10 +17,12 @@ pub struct ChainInfoTracker {
|
||||
}
|
||||
|
||||
impl ChainInfoTracker {
|
||||
/// Create a new chain info container for the given canonical head.
|
||||
pub fn new(head: SealedHeader) -> Self {
|
||||
let (finalized_block, _) = watch::channel(None);
|
||||
let (safe_block, _) = watch::channel(None);
|
||||
/// Create a new chain info container for the given canonical head and finalized header if it
|
||||
/// exists.
|
||||
pub fn new(head: SealedHeader, finalized: Option<SealedHeader>) -> Self {
|
||||
let (finalized_block, _) = watch::channel(finalized.clone());
|
||||
let (safe_block, _) = watch::channel(finalized);
|
||||
|
||||
Self {
|
||||
inner: Arc::new(ChainInfoInner {
|
||||
last_forkchoice_update: RwLock::new(None),
|
||||
|
||||
@ -112,11 +112,13 @@ pub struct CanonicalInMemoryState {
|
||||
}
|
||||
|
||||
impl CanonicalInMemoryState {
|
||||
/// Create a new in memory state with the given blocks, numbers, and pending state.
|
||||
/// Create a new in memory state with the given blocks, numbers, pending state and finalized
|
||||
/// header if it exists.
|
||||
pub fn new(
|
||||
blocks: HashMap<B256, Arc<BlockState>>,
|
||||
numbers: HashMap<u64, B256>,
|
||||
pending: Option<BlockState>,
|
||||
finalized: Option<SealedHeader>,
|
||||
) -> Self {
|
||||
let in_memory_state = InMemoryState::new(blocks, numbers, pending);
|
||||
let head_state = in_memory_state.head_state();
|
||||
@ -124,7 +126,7 @@ impl CanonicalInMemoryState {
|
||||
Some(state) => state.block().block().header.clone(),
|
||||
None => SealedHeader::default(),
|
||||
};
|
||||
let chain_info_tracker = ChainInfoTracker::new(header);
|
||||
let chain_info_tracker = ChainInfoTracker::new(header, finalized);
|
||||
let (canon_state_notification_sender, _canon_state_notification_receiver) =
|
||||
broadcast::channel(CANON_STATE_NOTIFICATION_CHANNEL_SIZE);
|
||||
|
||||
@ -137,9 +139,10 @@ impl CanonicalInMemoryState {
|
||||
Self { inner: Arc::new(inner) }
|
||||
}
|
||||
|
||||
/// Create a new in memory state with the given local head.
|
||||
pub fn with_head(head: SealedHeader) -> Self {
|
||||
let chain_info_tracker = ChainInfoTracker::new(head);
|
||||
/// Create a new in memory state with the given local head and finalized header
|
||||
/// if it exists.
|
||||
pub fn with_head(head: SealedHeader, finalized: Option<SealedHeader>) -> Self {
|
||||
let chain_info_tracker = ChainInfoTracker::new(head, finalized);
|
||||
let in_memory_state = InMemoryState::default();
|
||||
let (canon_state_notification_sender, _canon_state_notification_receiver) =
|
||||
broadcast::channel(CANON_STATE_NOTIFICATION_CHANNEL_SIZE);
|
||||
@ -889,7 +892,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_in_memory_state_chain_update() {
|
||||
let state = CanonicalInMemoryState::new(HashMap::new(), HashMap::new(), None);
|
||||
let state = CanonicalInMemoryState::new(HashMap::new(), HashMap::new(), None, None);
|
||||
let block1 = get_executed_block_with_number(0, B256::random());
|
||||
let block2 = get_executed_block_with_number(0, B256::random());
|
||||
let chain = NewCanonicalChain::Commit { new: vec![block1.clone()] };
|
||||
@ -925,7 +928,7 @@ mod tests {
|
||||
numbers.insert(2, block2.block().hash());
|
||||
numbers.insert(3, block3.block().hash());
|
||||
|
||||
let canonical_state = CanonicalInMemoryState::new(blocks, numbers, None);
|
||||
let canonical_state = CanonicalInMemoryState::new(blocks, numbers, None, None);
|
||||
|
||||
let historical: StateProviderBox = Box::new(MockStateProvider);
|
||||
|
||||
|
||||
@ -399,9 +399,10 @@ where
|
||||
)
|
||||
.expect("failed to create tree"),
|
||||
));
|
||||
let latest = self.base_config.chain_spec.genesis_header().seal_slow();
|
||||
let genesis_block = self.base_config.chain_spec.genesis_header().seal_slow();
|
||||
|
||||
let blockchain_provider =
|
||||
BlockchainProvider::with_latest(provider_factory.clone(), tree, latest);
|
||||
BlockchainProvider::with_blocks(provider_factory.clone(), tree, genesis_block, None);
|
||||
|
||||
let pruner = Pruner::<_, ProviderFactory<_>>::new(
|
||||
provider_factory.clone(),
|
||||
|
||||
@ -1736,7 +1736,7 @@ mod tests {
|
||||
|
||||
let header = chain_spec.genesis_header().seal_slow();
|
||||
let engine_api_tree_state = EngineApiTreeState::new(10, 10, header.num_hash());
|
||||
let canonical_in_memory_state = CanonicalInMemoryState::with_head(header);
|
||||
let canonical_in_memory_state = CanonicalInMemoryState::with_head(header, None);
|
||||
|
||||
let (to_payload_service, payload_command_rx) = unbounded_channel();
|
||||
let payload_builder = PayloadBuilderHandle::new(to_payload_service);
|
||||
@ -1797,7 +1797,7 @@ mod tests {
|
||||
let last_executed_block = blocks.last().unwrap().clone();
|
||||
let pending = Some(BlockState::new(last_executed_block));
|
||||
self.tree.canonical_in_memory_state =
|
||||
CanonicalInMemoryState::new(state_by_hash, hash_by_number, pending);
|
||||
CanonicalInMemoryState::new(state_by_hash, hash_by_number, pending, None);
|
||||
|
||||
self.blocks = blocks;
|
||||
self
|
||||
|
||||
@ -159,7 +159,8 @@ mod tests {
|
||||
let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone());
|
||||
|
||||
let blockchain_db =
|
||||
BlockchainProvider2::with_latest(provider_factory.clone(), SealedHeader::default());
|
||||
BlockchainProvider2::with_latest(provider_factory.clone(), SealedHeader::default())
|
||||
.unwrap();
|
||||
|
||||
let (_tx, rx) = watch::channel(FinishedExExHeight::NoExExs);
|
||||
let pruner =
|
||||
|
||||
@ -2,10 +2,10 @@ use crate::{
|
||||
providers::StaticFileProvider, AccountReader, BlockHashReader, BlockIdReader, BlockNumReader,
|
||||
BlockReader, BlockReaderIdExt, BlockSource, CanonChainTracker, CanonStateNotifications,
|
||||
CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, DatabaseProviderFactory,
|
||||
DatabaseProviderRO, EvmEnvProvider, HeaderProvider, ProviderError, ProviderFactory,
|
||||
PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, RequestsProvider,
|
||||
StageCheckpointReader, StateProviderBox, StateProviderFactory, StaticFileProviderFactory,
|
||||
TransactionVariant, TransactionsProvider, WithdrawalsProvider,
|
||||
DatabaseProviderRO, EvmEnvProvider, FinalizedBlockReader, HeaderProvider, ProviderError,
|
||||
ProviderFactory, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt,
|
||||
RequestsProvider, StageCheckpointReader, StateProviderBox, StateProviderFactory,
|
||||
StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider,
|
||||
};
|
||||
use alloy_rpc_types_engine::ForkchoiceState;
|
||||
use reth_chain_state::CanonicalInMemoryState;
|
||||
@ -55,14 +55,6 @@ impl<DB> Clone for BlockchainProvider2<DB> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> BlockchainProvider2<DB> {
|
||||
/// Create new provider instance that wraps the database and the blockchain tree, using the
|
||||
/// provided latest header to initialize the chain info tracker.
|
||||
pub fn with_latest(database: ProviderFactory<DB>, latest: SealedHeader) -> Self {
|
||||
Self { database, canonical_in_memory_state: CanonicalInMemoryState::with_head(latest) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> BlockchainProvider2<DB>
|
||||
where
|
||||
DB: Database,
|
||||
@ -75,12 +67,30 @@ where
|
||||
match provider.header_by_number(best.best_number)? {
|
||||
Some(header) => {
|
||||
drop(provider);
|
||||
Ok(Self::with_latest(database, header.seal(best.best_hash)))
|
||||
Ok(Self::with_latest(database, header.seal(best.best_hash))?)
|
||||
}
|
||||
None => Err(ProviderError::HeaderNotFound(best.best_number.into())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new provider instance that wraps the database and the blockchain tree, using the
|
||||
/// provided latest header to initialize the chain info tracker.
|
||||
///
|
||||
/// This returns a `ProviderResult` since it tries the retrieve the last finalized header from
|
||||
/// `database`.
|
||||
pub fn with_latest(
|
||||
database: ProviderFactory<DB>,
|
||||
latest: SealedHeader,
|
||||
) -> ProviderResult<Self> {
|
||||
let provider = database.provider()?;
|
||||
let finalized_block_number = provider.last_finalized_block_number()?;
|
||||
let finalized_header = provider.sealed_header(finalized_block_number)?;
|
||||
Ok(Self {
|
||||
database,
|
||||
canonical_in_memory_state: CanonicalInMemoryState::with_head(latest, finalized_header),
|
||||
})
|
||||
}
|
||||
|
||||
/// Gets a clone of `canonical_in_memory_state`.
|
||||
pub fn canonical_in_memory_state(&self) -> CanonicalInMemoryState {
|
||||
self.canonical_in_memory_state.clone()
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
use crate::{
|
||||
AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
|
||||
BlockSource, BlockchainTreePendingStateProvider, CanonChainTracker, ChainSpecProvider,
|
||||
ChangeSetReader, DatabaseProviderFactory, EvmEnvProvider, FullExecutionDataProvider,
|
||||
HeaderProvider, ProviderError, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt,
|
||||
RequestsProvider, StageCheckpointReader, StateProviderBox, StateProviderFactory,
|
||||
StaticFileProviderFactory, TransactionVariant, TransactionsProvider, TreeViewer,
|
||||
WithdrawalsProvider,
|
||||
BlockSource, BlockchainTreePendingStateProvider, CanonChainTracker, CanonStateNotifications,
|
||||
CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, DatabaseProviderFactory,
|
||||
EvmEnvProvider, FinalizedBlockReader, FullExecutionDataProvider, HeaderProvider, ProviderError,
|
||||
PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, RequestsProvider,
|
||||
StageCheckpointReader, StateProviderBox, StateProviderFactory, StaticFileProviderFactory,
|
||||
TransactionVariant, TransactionsProvider, TreeViewer, WithdrawalsProvider,
|
||||
};
|
||||
use reth_blockchain_tree_api::{
|
||||
error::{CanonicalError, InsertBlockError},
|
||||
BlockValidationKind, BlockchainTreeEngine, BlockchainTreeViewer, CanonicalOutcome,
|
||||
InsertPayloadOk,
|
||||
};
|
||||
use reth_chain_state::{CanonStateNotifications, CanonStateSubscriptions, ChainInfoTracker};
|
||||
use reth_chain_state::ChainInfoTracker;
|
||||
use reth_chainspec::{ChainInfo, ChainSpec};
|
||||
use reth_db_api::{
|
||||
database::Database,
|
||||
@ -88,16 +88,6 @@ impl<DB> Clone for BlockchainProvider<DB> {
|
||||
}
|
||||
|
||||
impl<DB> BlockchainProvider<DB> {
|
||||
/// Create new provider instance that wraps the database and the blockchain tree, using the
|
||||
/// provided latest header to initialize the chain info tracker.
|
||||
pub fn with_latest(
|
||||
database: ProviderFactory<DB>,
|
||||
tree: Arc<dyn TreeViewer>,
|
||||
latest: SealedHeader,
|
||||
) -> Self {
|
||||
Self { database, tree, chain_info: ChainInfoTracker::new(latest) }
|
||||
}
|
||||
|
||||
/// Sets the treeviewer for the provider.
|
||||
#[doc(hidden)]
|
||||
pub fn with_tree(mut self, tree: Arc<dyn TreeViewer>) -> Self {
|
||||
@ -110,18 +100,31 @@ impl<DB> BlockchainProvider<DB>
|
||||
where
|
||||
DB: Database,
|
||||
{
|
||||
/// Create new provider instance that wraps the database and the blockchain tree, using the
|
||||
/// provided latest header to initialize the chain info tracker, alongside the finalized header
|
||||
/// if it exists.
|
||||
pub fn with_blocks(
|
||||
database: ProviderFactory<DB>,
|
||||
tree: Arc<dyn TreeViewer>,
|
||||
latest: SealedHeader,
|
||||
finalized: Option<SealedHeader>,
|
||||
) -> Self {
|
||||
Self { database, tree, chain_info: ChainInfoTracker::new(latest, finalized) }
|
||||
}
|
||||
|
||||
/// Create a new provider using only the database and the tree, fetching the latest header from
|
||||
/// the database to initialize the provider.
|
||||
pub fn new(database: ProviderFactory<DB>, tree: Arc<dyn TreeViewer>) -> ProviderResult<Self> {
|
||||
let provider = database.provider()?;
|
||||
let best: ChainInfo = provider.chain_info()?;
|
||||
match provider.header_by_number(best.best_number)? {
|
||||
Some(header) => {
|
||||
drop(provider);
|
||||
Ok(Self::with_latest(database, tree, header.seal(best.best_hash)))
|
||||
}
|
||||
None => Err(ProviderError::HeaderNotFound(best.best_number.into())),
|
||||
}
|
||||
let latest_header = provider
|
||||
.header_by_number(best.best_number)?
|
||||
.ok_or(ProviderError::HeaderNotFound(best.best_number.into()))?;
|
||||
|
||||
let finalized_block_number = provider.last_finalized_block_number()?;
|
||||
let finalized_header = provider.sealed_header(finalized_block_number)?;
|
||||
|
||||
Ok(Self::with_blocks(database, tree, latest_header.seal(best.best_hash), finalized_header))
|
||||
}
|
||||
|
||||
/// Ensures that the given block number is canonical (synced)
|
||||
|
||||
Reference in New Issue
Block a user