From c162f07ad85b7d7fc92f8d3e4d2af64033f32e01 Mon Sep 17 00:00:00 2001 From: Stanimal Date: Mon, 1 Nov 2021 10:25:26 +0400 Subject: [PATCH] fix: header sync must allow transition to archival/pruned if tip is behind --- .../sync/header_sync/synchronizer.rs | 37 +++++++++++++------ base_layer/core/src/chain_storage/async_db.rs | 2 + .../src/chain_storage/blockchain_backend.rs | 2 + .../src/chain_storage/blockchain_database.rs | 5 +++ .../core/src/chain_storage/lmdb_db/lmdb_db.rs | 25 +++++++++++++ .../core/src/test_helpers/blockchain.rs | 4 ++ 6 files changed, 64 insertions(+), 11 deletions(-) diff --git a/base_layer/core/src/base_node/sync/header_sync/synchronizer.rs b/base_layer/core/src/base_node/sync/header_sync/synchronizer.rs index 16c7c41494..c5a69a4ea0 100644 --- a/base_layer/core/src/base_node/sync/header_sync/synchronizer.rs +++ b/base_layer/core/src/base_node/sync/header_sync/synchronizer.rs @@ -246,22 +246,37 @@ impl<'a, B: BlockchainBackend + 'static> HeaderSynchronizer<'a, B> { ); // Fetch the local tip header at the beginning of the sync process - let local_tip_header = self.db.fetch_tip_header().await?; + let local_tip_header = self.db.fetch_last_chain_header().await?; let local_total_accumulated_difficulty = local_tip_header.accumulated_data().total_accumulated_difficulty; + let header_tip_height = local_tip_header.height(); let sync_status = self .determine_sync_status(sync_peer, local_tip_header, &mut client) .await?; match sync_status { - SyncStatus::InSync => Err(BlockHeaderSyncError::PeerSentInaccurateChainMetadata { - claimed: sync_peer.claimed_chain_metadata().accumulated_difficulty(), - actual: None, - local: local_total_accumulated_difficulty, - }), - SyncStatus::WereAhead => Err(BlockHeaderSyncError::PeerSentInaccurateChainMetadata { - claimed: sync_peer.claimed_chain_metadata().accumulated_difficulty(), - actual: None, - local: local_total_accumulated_difficulty, - }), + SyncStatus::InSync | SyncStatus::WereAhead => { + let metadata = self.db.get_chain_metadata().await?; + if metadata.height_of_longest_chain() < header_tip_height { + debug!( + target: LOG_TARGET, + "Headers are in sync at height {} but tip is {}. Proceeding to archival/pruned block sync", + header_tip_height, + metadata.height_of_longest_chain() + ); + Ok(()) + } else { + debug!( + target: LOG_TARGET, + "Headers and block state are already in-sync (Header Tip: {}, Block tip: {})", + header_tip_height, + metadata.height_of_longest_chain() + ); + Err(BlockHeaderSyncError::PeerSentInaccurateChainMetadata { + claimed: sync_peer.claimed_chain_metadata().accumulated_difficulty(), + actual: None, + local: local_total_accumulated_difficulty, + }) + } + }, SyncStatus::Lagging(split_info) => { self.hooks.call_on_progress_header_hooks( split_info.local_tip_header.height(), diff --git a/base_layer/core/src/chain_storage/async_db.rs b/base_layer/core/src/chain_storage/async_db.rs index 0c1e743842..bf7c9b4a06 100644 --- a/base_layer/core/src/chain_storage/async_db.rs +++ b/base_layer/core/src/chain_storage/async_db.rs @@ -195,6 +195,8 @@ impl AsyncBlockchainDb { make_async_fn!(fetch_last_header() -> BlockHeader, "fetch_last_header"); + make_async_fn!(fetch_last_chain_header() -> ChainHeader, "fetch_last_chain_header"); + make_async_fn!(fetch_tip_header() -> ChainHeader, "fetch_tip_header"); make_async_fn!(insert_valid_headers(headers: Vec) -> (), "insert_valid_headers"); diff --git a/base_layer/core/src/chain_storage/blockchain_backend.rs b/base_layer/core/src/chain_storage/blockchain_backend.rs index 8c4612806a..bd1a3acdef 100644 --- a/base_layer/core/src/chain_storage/blockchain_backend.rs +++ b/base_layer/core/src/chain_storage/blockchain_backend.rs @@ -133,6 +133,8 @@ pub trait BlockchainBackend: Send + Sync { fn orphan_count(&self) -> Result; /// Returns the stored header with the highest corresponding height. fn fetch_last_header(&self) -> Result; + /// Returns the stored header and accumulated data with the highest height. + fn fetch_last_chain_header(&self) -> Result; /// Returns the stored header with the highest corresponding height. fn fetch_tip_header(&self) -> Result; /// Returns the stored chain metadata. diff --git a/base_layer/core/src/chain_storage/blockchain_database.rs b/base_layer/core/src/chain_storage/blockchain_database.rs index 4d7dbf5754..52c1ce2099 100644 --- a/base_layer/core/src/chain_storage/blockchain_database.rs +++ b/base_layer/core/src/chain_storage/blockchain_database.rs @@ -566,6 +566,11 @@ where B: BlockchainBackend db.fetch_last_header() } + pub fn fetch_last_chain_header(&self) -> Result { + let db = self.db_read_access()?; + db.fetch_last_chain_header() + } + /// Returns the sum of all kernels pub fn fetch_kernel_commitment_sum(&self, at_hash: &HashOutput) -> Result { Ok(self.fetch_block_accumulated_data(at_hash.clone())?.kernel_sum) diff --git a/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs b/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs index a4e3d4cea8..0b8e6333af 100644 --- a/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs +++ b/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs @@ -1942,6 +1942,31 @@ impl BlockchainBackend for LMDBDatabase { }) } + /// Finds and returns the last stored header. + fn fetch_last_chain_header(&self) -> Result { + let txn = self.read_transaction()?; + let header = self.fetch_last_header_in_txn(&txn)?.ok_or_else(|| { + ChainStorageError::InvalidOperation("Cannot fetch last header because database is empty".to_string()) + })?; + let height = header.height; + let accumulated_data = self + .fetch_header_accumulated_data_by_height(&txn, height)? + .ok_or_else(|| ChainStorageError::ValueNotFound { + entity: "BlockHeaderAccumulatedData", + field: "height", + value: height.to_string(), + })?; + + let chain_header = ChainHeader::try_construct(header, accumulated_data).ok_or_else(|| { + ChainStorageError::DataInconsistencyDetected { + function: "fetch_tip_header", + details: format!("Accumulated data mismatch at height #{}", height), + } + })?; + + Ok(chain_header) + } + fn fetch_tip_header(&self) -> Result { let txn = self.read_transaction()?; diff --git a/base_layer/core/src/test_helpers/blockchain.rs b/base_layer/core/src/test_helpers/blockchain.rs index 30c838cbf2..66afe677c9 100644 --- a/base_layer/core/src/test_helpers/blockchain.rs +++ b/base_layer/core/src/test_helpers/blockchain.rs @@ -314,6 +314,10 @@ impl BlockchainBackend for TempDatabase { self.db.as_ref().unwrap().fetch_last_header() } + fn fetch_last_chain_header(&self) -> Result { + self.db.as_ref().unwrap().fetch_last_chain_header() + } + fn fetch_tip_header(&self) -> Result { self.db.as_ref().unwrap().fetch_tip_header() }