Просмотр исходного кода

validator: reset to height functionality added, using blocks reverese diffs

skoupidi 1 год назад
Родитель
Сommit
66dfc9c95d

+ 14 - 1
bin/darkfid/src/main.rs

@@ -32,7 +32,7 @@ use darkfi::{
         encoding::base64,
         path::{expand_path, get_config_path},
     },
-    validator::ValidatorConfig,
+    validator::{Validator, ValidatorConfig},
     Error, Result,
 };
 use darkfi_serial::deserialize_async;
@@ -60,6 +60,10 @@ struct Args {
     /// Blockchain network to use
     network: String,
 
+    #[structopt(short, long)]
+    /// Reset validator state to given block height
+    reset: Option<u32>,
+
     #[structopt(short, long)]
     /// Set log file to ouput into
     log: Option<String>,
@@ -190,6 +194,15 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
         verify_fees: !blockchain_config.skip_fees,
     };
 
+    // Check if reset was requested
+    if let Some(height) = args.reset {
+        info!(target: "darkfid", "Node will reset validator state to height: {}", height);
+        let validator = Validator::new(&sled_db, &config).await?;
+        validator.reset_to_height(height).await?;
+        info!(target: "darkfid", "Validator state reset successfully!");
+        return Ok(())
+    }
+
     // Generate the daemon
     let daemon = Darkfid::init(
         &sled_db,

+ 1 - 1
contrib/localnet/darkfid-small/darkfid2.toml

@@ -21,7 +21,7 @@ database = "darkfid2"
 threshold = 6
 
 # minerd JSON-RPC endpoint
-minerd_endpoint = "tcp://127.0.0.1:28467"
+#minerd_endpoint = "tcp://127.0.0.1:28467"
 
 # PoW block production target, in seconds
 pow_target = 20

+ 34 - 0
src/blockchain/mod.rs

@@ -332,6 +332,40 @@ impl Blockchain {
 
         Ok(blocks)
     }
+
+    /// Auxiliary function to reset the blockchain and consensus state
+    /// to the provided block height.
+    pub fn reset_to_height(&self, height: u32) -> Result<()> {
+        // First we grab the last block height
+        let (last, _) = self.last()?;
+
+        // Check if request height is after our last height
+        if height >= last {
+            return Ok(())
+        }
+
+        // Grab all state diffs until requested height going backwards
+        let heights: Vec<u32> = (height + 1..=last).rev().collect();
+        let diffs = self.blocks.get_state_diff(&heights, true)?;
+
+        // Create an overlay to apply the reverse diffs
+        let overlay = BlockchainOverlay::new(self)?;
+
+        // Apply the inverse diffs sequence
+        let overlay_lock = overlay.lock().unwrap();
+        let mut lock = overlay_lock.overlay.lock().unwrap();
+        for diff in diffs {
+            // Since we used strict retrieval it's safe to unwrap here
+            let inverse_diff = diff.unwrap().inverse();
+            lock.add_diff(&inverse_diff)?;
+            lock.apply_diff(&inverse_diff)?;
+            self.sled_db.flush()?;
+        }
+        drop(lock);
+        drop(overlay_lock);
+
+        Ok(())
+    }
 }
 
 /// Atomic pointer to sled db overlay.

+ 14 - 0
src/validator/consensus.rs

@@ -563,6 +563,20 @@ impl Consensus {
         debug!(target: "validator::consensus::purge_forks", "Forks purged!");
         Ok(())
     }
+
+    /// Auxiliary function to reset PoW module.
+    pub async fn reset_pow_module(&self) -> Result<()> {
+        debug!(target: "validator::consensus::reset_pow_module", "Resetting PoW module...");
+        let mut module = self.module.write().await;
+        *module = PoWModule::new(
+            self.blockchain.clone(),
+            module.target,
+            module.fixed_difficulty.clone(),
+        )?;
+        drop(module);
+        debug!(target: "validator::consensus::reset_pow_module", "PoW module reset successfully!");
+        Ok(())
+    }
 }
 
 /// This struct represents a block proposal, used for consensus.

+ 24 - 0
src/validator/mod.rs

@@ -774,4 +774,28 @@ impl Validator {
 
         Ok(next_block_height)
     }
+
+    /// Auxiliary function to reset the validator blockchain and consensus states
+    /// to the provided block height.
+    pub async fn reset_to_height(&self, height: u32) -> Result<()> {
+        info!(target: "validator::reset_to_height", "Resetting validator to height: {height}");
+        // Grab append lock so no new proposals can be appended while we execute a reset
+        let append_lock = self.consensus.append_lock.write().await;
+
+        // Reset our databasse to provided height
+        self.blockchain.reset_to_height(height)?;
+
+        // Reset consensus PoW module
+        self.consensus.reset_pow_module().await?;
+
+        // Purge current forks
+        self.consensus.purge_forks().await?;
+
+        // Release append lock
+        drop(append_lock);
+
+        info!(target: "validator::reset_to_height", "Validator reset successfully!");
+
+        Ok(())
+    }
 }