From ea51663f9c5988af9a7376e8726bf0ea1bea9a94 Mon Sep 17 00:00:00 2001 From: Antioch Peverell Date: Wed, 26 Dec 2018 21:33:01 +0000 Subject: [PATCH] Remember to reset sync head on first transition to header sync (#2222) Also cleanup reset_sync_head code --- chain/src/chain.rs | 17 +++++++++++++++++ servers/src/grin/sync/header_sync.rs | 14 +++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 0358dc6a7..af10ed4e2 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -213,6 +213,11 @@ impl Chain { self.txhashset.clone() } + /// Shared store instance. + pub fn store(&self) -> Arc { + self.store.clone() + } + fn log_heads(store: &store::ChainStore) -> Result<(), Error> { let head = store.head()?; debug!( @@ -241,6 +246,18 @@ impl Chain { Ok(()) } + /// Reset sync_head to current header_head. + /// We do this when we first transition to header_sync to ensure we extend + /// the "sync" header MMR from a known consistent state and to ensure we track + /// the header chain correctly at the fork point. + pub fn reset_sync_head(&self) -> Result { + let batch = self.store.batch()?; + batch.reset_sync_head()?; + let head = batch.get_sync_head()?; + batch.commit()?; + Ok(head) + } + /// Processes a single block, then checks for orphans, processing /// those as well if they're found pub fn process_block(&self, b: Block, opts: Options) -> Result, Error> { diff --git a/servers/src/grin/sync/header_sync.rs b/servers/src/grin/sync/header_sync.rs index ee3696e28..7e21190dd 100644 --- a/servers/src/grin/sync/header_sync.rs +++ b/servers/src/grin/sync/header_sync.rs @@ -55,17 +55,25 @@ impl HeaderSync { | SyncStatus::HeaderSync { .. } | SyncStatus::TxHashsetDone => true, SyncStatus::NoSync | SyncStatus::Initial | SyncStatus::AwaitingPeers(_) => { - // Reset sync_head to header_head on transition to HeaderSync, - // but ONLY on initial transition to HeaderSync state. let sync_head = self.chain.get_sync_head().unwrap(); debug!( - "sync: initial transition to HeaderSync. sync_head: {} at {}, reset to: {} at {}", + "sync: initial transition to HeaderSync. sync_head: {} at {}, resetting to: {} at {}", sync_head.hash(), sync_head.height, header_head.hash(), header_head.height, ); + // Reset sync_head to header_head on transition to HeaderSync, + // but ONLY on initial transition to HeaderSync state. + // + // The header_head and sync_head may diverge here in the presence of a fork + // in the header chain. Ensure we track the new advertised header chain here + // correctly, so reset any previous (and potentially stale) sync_head to match + // our last known "good" header_head. + // + self.chain.reset_sync_head().unwrap(); + // Rebuild the sync MMR to match our updated sync_head. self.chain.rebuild_sync_mmr(&header_head).unwrap();