[PIBD] Fix to restart of PIBD download on corrupted data or mismatched roots (#3775)

* process restart

* remove trace statements

* remove further debug statement

* remove further debug statement
This commit is contained in:
Yeastplume 2023-10-31 12:18:17 +00:00 committed by GitHub
parent 213dfd4f19
commit 05ec6fda38
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 14 deletions

View file

@ -158,7 +158,7 @@ pub struct Chain {
pow_verifier: fn(&BlockHeader) -> Result<(), pow::Error>, pow_verifier: fn(&BlockHeader) -> Result<(), pow::Error>,
denylist: Arc<RwLock<Vec<Hash>>>, denylist: Arc<RwLock<Vec<Hash>>>,
archive_mode: bool, archive_mode: bool,
genesis: BlockHeader, genesis: Block,
} }
impl Chain { impl Chain {
@ -184,7 +184,7 @@ impl Chain {
None, None,
)?; )?;
setup_head(&genesis, &store, &mut header_pmmr, &mut txhashset)?; setup_head(&genesis, &store, &mut header_pmmr, &mut txhashset, false)?;
// Initialize the output_pos index based on UTXO set // Initialize the output_pos index based on UTXO set
// and NRD kernel_pos index based recent kernel history. // and NRD kernel_pos index based recent kernel history.
@ -207,7 +207,7 @@ impl Chain {
pow_verifier, pow_verifier,
denylist: Arc::new(RwLock::new(vec![])), denylist: Arc::new(RwLock::new(vec![])),
archive_mode, archive_mode,
genesis: genesis.header, genesis: genesis,
}; };
chain.log_heads()?; chain.log_heads()?;
@ -269,6 +269,33 @@ impl Chain {
Ok(()) 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 /// Reset prune lists (when PIBD resets and rolls back the
/// entire chain, the prune list needs to be manually wiped /// entire chain, the prune list needs to be manually wiped
/// as it's currently not included as part of rewind) /// as it's currently not included as part of rewind)
@ -309,7 +336,7 @@ impl Chain {
/// return genesis header /// return genesis header
pub fn genesis(&self) -> BlockHeader { pub fn genesis(&self) -> BlockHeader {
self.genesis.clone() self.genesis.header.clone()
} }
/// Shared store instance. /// Shared store instance.
@ -703,7 +730,7 @@ impl Chain {
txhashset::extending_readonly(&mut header_pmmr, &mut txhashset, |ext, batch| { txhashset::extending_readonly(&mut header_pmmr, &mut txhashset, |ext, batch| {
self.rewind_and_apply_fork(&header, ext, batch)?; self.rewind_and_apply_fork(&header, ext, batch)?;
ext.extension.validate( ext.extension.validate(
&self.genesis, &self.genesis.header,
fast_validation, fast_validation,
&NoStatus, &NoStatus,
None, None,
@ -943,7 +970,7 @@ impl Chain {
self.txhashset(), self.txhashset(),
self.header_pmmr.clone(), self.header_pmmr.clone(),
header.clone(), header.clone(),
self.genesis.clone(), self.genesis.header.clone(),
self.store.clone(), self.store.clone(),
)) ))
} }
@ -1125,7 +1152,13 @@ impl Chain {
let header_pmmr = self.header_pmmr.read(); let header_pmmr = self.header_pmmr.read();
let batch = self.store.batch()?; 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 // all good, prepare a new batch and update all the required records
@ -1143,8 +1176,15 @@ impl Chain {
// Validate the extension, generating the utxo_sum and kernel_sum. // Validate the extension, generating the utxo_sum and kernel_sum.
// Full validation, including rangeproofs and kernel signature verification. // Full validation, including rangeproofs and kernel signature verification.
let (utxo_sum, kernel_sum) = let (utxo_sum, kernel_sum) = extension.validate(
extension.validate(&self.genesis, false, status, None, None, &header, None)?; &self.genesis.header,
false,
status,
None,
None,
&header,
None,
)?;
// Save the block_sums (utxo_sum, kernel_sum) to the db for use later. // Save the block_sums (utxo_sum, kernel_sum) to the db for use later.
batch.save_block_sums( batch.save_block_sums(
@ -1231,7 +1271,7 @@ impl Chain {
let tail = match batch.tail() { let tail = match batch.tail() {
Ok(tail) => 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); let mut cutoff = head.height.saturating_sub(horizon);
@ -1643,6 +1683,7 @@ fn setup_head(
store: &store::ChainStore, store: &store::ChainStore,
header_pmmr: &mut txhashset::PMMRHandle<BlockHeader>, header_pmmr: &mut txhashset::PMMRHandle<BlockHeader>,
txhashset: &mut txhashset::TxHashSet, txhashset: &mut txhashset::TxHashSet,
resetting_pibd: bool,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut batch = store.batch()?; let mut batch = store.batch()?;
@ -1689,7 +1730,7 @@ fn setup_head(
let head = batch.get_block_header(&head.last_block_h)?; let head = batch.get_block_header(&head.last_block_h)?;
let pibd_tip = store.pibd_head()?; let pibd_tip = store.pibd_head()?;
let pibd_head = batch.get_block_header(&pibd_tip.last_block_h)?; 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_in_progress = true;
pibd_head pibd_head
} else { } else {

View file

@ -111,12 +111,12 @@ impl StateSync {
if let Some(d) = desegmenter.write().as_mut() { if let Some(d) = desegmenter.write().as_mut() {
d.reset(); 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() { if let Err(e) = self.chain.reset_pibd_head() {
error!("pibd_sync restart: reset pibd_head error = {}", e); 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() { if let Err(e) = self.chain.reset_prune_lists() {
error!("pibd_sync restart: reset prune lists error = {}", e); error!("pibd_sync restart: reset prune lists error = {}", e);
} }