Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: header sync must allow transition to archival/pruned if tip is behind #3520

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 26 additions & 11 deletions base_layer/core/src/base_node/sync/header_sync/synchronizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
2 changes: 2 additions & 0 deletions base_layer/core/src/chain_storage/async_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ impl<B: BlockchainBackend + 'static> AsyncBlockchainDb<B> {

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<ChainHeader>) -> (), "insert_valid_headers");
Expand Down
2 changes: 2 additions & 0 deletions base_layer/core/src/chain_storage/blockchain_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ pub trait BlockchainBackend: Send + Sync {
fn orphan_count(&self) -> Result<usize, ChainStorageError>;
/// Returns the stored header with the highest corresponding height.
fn fetch_last_header(&self) -> Result<BlockHeader, ChainStorageError>;
/// Returns the stored header and accumulated data with the highest height.
fn fetch_last_chain_header(&self) -> Result<ChainHeader, ChainStorageError>;
/// Returns the stored header with the highest corresponding height.
fn fetch_tip_header(&self) -> Result<ChainHeader, ChainStorageError>;
/// Returns the stored chain metadata.
Expand Down
5 changes: 5 additions & 0 deletions base_layer/core/src/chain_storage/blockchain_database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,11 @@ where B: BlockchainBackend
db.fetch_last_header()
}

pub fn fetch_last_chain_header(&self) -> Result<ChainHeader, ChainStorageError> {
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<Commitment, ChainStorageError> {
Ok(self.fetch_block_accumulated_data(at_hash.clone())?.kernel_sum)
Expand Down
25 changes: 25 additions & 0 deletions base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1942,6 +1942,31 @@ impl BlockchainBackend for LMDBDatabase {
})
}

/// Finds and returns the last stored header.
fn fetch_last_chain_header(&self) -> Result<ChainHeader, ChainStorageError> {
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<ChainHeader, ChainStorageError> {
let txn = self.read_transaction()?;

Expand Down
4 changes: 4 additions & 0 deletions base_layer/core/src/test_helpers/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,10 @@ impl BlockchainBackend for TempDatabase {
self.db.as_ref().unwrap().fetch_last_header()
}

fn fetch_last_chain_header(&self) -> Result<ChainHeader, ChainStorageError> {
self.db.as_ref().unwrap().fetch_last_chain_header()
}

fn fetch_tip_header(&self) -> Result<ChainHeader, ChainStorageError> {
self.db.as_ref().unwrap().fetch_tip_header()
}
Expand Down