From f4f35af1662a604e680400f495a421727616da3f Mon Sep 17 00:00:00 2001 From: Davidson Souza <40968167+Davidson-Souza@users.noreply.github.com> Date: Sat, 20 May 2023 20:11:13 -0300 Subject: [PATCH] Reindex (#48) * Reindex chain if we go in an undefined state * Fix a bug during header download If we stopped the daemon while it's running, we'ld get a corrupted state, and header validation would loop forever --- src/blockchain/chain_state.rs | 76 ++++++++++++++++++--------- src/blockchain/p2p_blockchain/node.rs | 5 +- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/blockchain/chain_state.rs b/src/blockchain/chain_state.rs index 7f773b1..897c49b 100644 --- a/src/blockchain/chain_state.rs +++ b/src/blockchain/chain_state.rs @@ -649,22 +649,31 @@ impl ChainState { } Err(BlockchainError::BlockNotPresent) } - // fn reindex_chain(chainstore: &KvChainStore, network: Network) -> BestChain { - // let mut height = 0; - // let mut hash = genesis_block(network).block_hash(); - // while let Ok(Some(_hash)) = chainstore.get_block_hash(height) { - // height += 1; - // hash = _hash; - // } - // BestChain { - // best_block: hash, - // depth: height, - // validation_index: hash, - // rescan_index: None, - // alternative_tips: vec![], - // assume_valid_index: 0, - // } - // } + /// If we ever find ourselves in an undefined state, with one of our chain pointers + /// pointing to an invalid block, we'll find out what blocks do we have, and start from this + /// point. + fn reindex_chain(&self) -> BestChain { + let inner = read_lock!(self); + + let mut height = 0; + let mut hash = inner + .chainstore + .get_block_hash(0) + .expect("No genesis block") + .unwrap(); + while let Ok(Some(_hash)) = inner.chainstore.get_block_hash(height) { + height += 1; + hash = _hash; + } + BestChain { + best_block: hash, + depth: height, + validation_index: hash, + rescan_index: None, + alternative_tips: vec![], + assume_valid_index: 0, + } + } pub fn load_chain_state( chainstore: KvChainStore, network: Network, @@ -688,12 +697,15 @@ impl ChainState { assume_valid: (Self::get_assume_valid_value(network, assume_valid_hash), 0), }; info!( - "Chainstate loaded at height: {}", + "Chainstate loaded at height: {}, checking if we have all blocks", inner.best_block.best_block ); - Ok(ChainState { + let chainstate = ChainState { inner: RwLock::new(inner), - }) + }; + // Check the integrity of our chain + chainstate.reindex_chain(); + Ok(chainstate) } fn load_acc(data_storage: &Storage) -> Stump { @@ -932,11 +944,22 @@ impl BlockchainProviderInterface for ChainState BlockchainProviderInterface for ChainState BlockchainProviderInterface for ChainState Ok(height), DiskBlockHeader::FullyValid(_, height) => Ok(height), - _ => unreachable!( - "Validation index is in an invalid state, you should re-index your node" - ), + _ => { + self.reindex_chain(); + log::error!("Validation index is in an invalid state, re-indexing chainstate"); + Ok(0) + } } } diff --git a/src/blockchain/p2p_blockchain/node.rs b/src/blockchain/p2p_blockchain/node.rs index 9faa3b4..a2c1191 100644 --- a/src/blockchain/p2p_blockchain/node.rs +++ b/src/blockchain/p2p_blockchain/node.rs @@ -25,7 +25,7 @@ use bitcoin::{ }, BlockHash, BlockHeader, Network, OutPoint, Transaction, TxOut, Txid, }; -use log::{error, info, warn}; +use log::{error, info, trace, warn}; use rustreexo::accumulator::proof::Proof; use std::{ collections::{HashMap, HashSet}, @@ -242,7 +242,7 @@ impl UtreexoNode { return Ok(()); } self.last_headers_request = Instant::now(); - info!( + trace!( "Downloading headers at: {} hash: {}", self.chain.get_best_block()?.0, headers[0].block_hash() @@ -378,7 +378,6 @@ impl UtreexoNode { mempool_delta .extend(self._mempool.write().await.consume_block(&block.block)); } - match self.handle_block(block) { Ok(_) => {} Err(e) => {