diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 6898a7e14..a98b6102a 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -165,7 +165,7 @@ pub struct Chain { pow_verifier: fn(&BlockHeader) -> Result<(), pow::Error>, denylist: Arc>>, archive_mode: bool, - genesis: BlockHeader, + genesis: Block, } impl Chain { @@ -207,6 +207,7 @@ impl Chain { &mut header_pmmr, &mut sync_pmmr, &mut txhashset, + false, )?; // Initialize the output_pos index based on UTXO set @@ -231,7 +232,7 @@ impl Chain { pow_verifier, denylist: Arc::new(RwLock::new(vec![])), archive_mode, - genesis: genesis.header, + genesis: genesis, }; // If known bad block exists on "current chain" then rewind prior to this. @@ -300,6 +301,33 @@ impl Chain { Ok(()) } + /// wipes the chain head down to genesis, without attempting to rewind + /// Used upon PIBD failure, where we want to keep the header chain but + /// restart the output PMMRs from scratch + pub fn reset_chain_head_to_genesis(&self) -> Result<(), Error> { + let mut header_pmmr = self.header_pmmr.write(); + let mut txhashset = self.txhashset.write(); + let batch = self.store.batch()?; + + // Change head back to genesis + { + let head = Tip::from_header(&self.genesis.header); + batch.save_body_head(&head)?; + batch.commit()?; + } + + // Reinit + setup_head( + &self.genesis, + &self.store, + &mut header_pmmr, + &mut txhashset, + true, + )?; + + Ok(()) + } + /// Reset prune lists (when PIBD resets and rolls back the /// entire chain, the prune list needs to be manually wiped /// as it's currently not included as part of rewind) @@ -340,7 +368,7 @@ impl Chain { /// return genesis header pub fn genesis(&self) -> BlockHeader { - self.genesis.clone() + self.genesis.header.clone() } /// Shared store instance. @@ -891,7 +919,7 @@ impl Chain { txhashset::extending_readonly(&mut header_pmmr, &mut txhashset, |ext, batch| { self.rewind_and_apply_fork(&header, ext, batch)?; ext.extension.validate( - &self.genesis, + &self.genesis.header, fast_validation, &NoStatus, None, @@ -1132,7 +1160,7 @@ impl Chain { self.txhashset(), self.header_pmmr.clone(), header.clone(), - self.genesis.clone(), + self.genesis.header.clone(), self.store.clone(), )) } @@ -1329,7 +1357,13 @@ impl Chain { let header_pmmr = self.header_pmmr.read(); let batch = self.store.batch()?; - txhashset.verify_kernel_pos_index(&self.genesis, &header_pmmr, &batch, None, None)?; + txhashset.verify_kernel_pos_index( + &self.genesis.header, + &header_pmmr, + &batch, + None, + None, + )?; } // all good, prepare a new batch and update all the required records @@ -1347,8 +1381,15 @@ impl Chain { // Validate the extension, generating the utxo_sum and kernel_sum. // Full validation, including rangeproofs and kernel signature verification. - let (utxo_sum, kernel_sum) = - extension.validate(&self.genesis, false, status, None, None, &header, None)?; + let (utxo_sum, kernel_sum) = extension.validate( + &self.genesis.header, + false, + status, + None, + None, + &header, + None, + )?; // Save the block_sums (utxo_sum, kernel_sum) to the db for use later. batch.save_block_sums( @@ -1435,7 +1476,7 @@ impl Chain { let tail = match batch.tail() { Ok(tail) => tail, - Err(_) => Tip::from_header(&self.genesis), + Err(_) => Tip::from_header(&self.genesis.header), }; let mut cutoff = head.height.saturating_sub(horizon); @@ -1920,6 +1961,7 @@ fn setup_head( header_pmmr: &mut txhashset::PMMRHandle, sync_pmmr: &mut txhashset::PMMRHandle, txhashset: &mut txhashset::TxHashSet, + resetting_pibd: bool, ) -> Result<(), Error> { let mut batch = store.batch()?; @@ -1972,7 +2014,7 @@ fn setup_head( let head = batch.get_block_header(&head.last_block_h)?; let pibd_tip = store.pibd_head()?; let pibd_head = batch.get_block_header(&pibd_tip.last_block_h)?; - if pibd_head.height > head.height { + if pibd_head.height > head.height && !resetting_pibd { pibd_in_progress = true; pibd_head } else { diff --git a/servers/src/grin/sync/state_sync.rs b/servers/src/grin/sync/state_sync.rs index c7f870e07..47b970bd3 100644 --- a/servers/src/grin/sync/state_sync.rs +++ b/servers/src/grin/sync/state_sync.rs @@ -116,12 +116,12 @@ impl StateSync { if let Some(d) = desegmenter.write().as_mut() { d.reset(); }; - if let Err(e) = self.chain.reset_chain_head(self.chain.genesis(), false) { - error!("pibd_sync restart: chain reset error = {}", e); - } if let Err(e) = self.chain.reset_pibd_head() { error!("pibd_sync restart: reset pibd_head error = {}", e); } + if let Err(e) = self.chain.reset_chain_head_to_genesis() { + error!("pibd_sync restart: chain reset to genesis error = {}", e); + } if let Err(e) = self.chain.reset_prune_lists() { error!("pibd_sync restart: reset prune lists error = {}", e); }