Ver Fonte

validator/consensus: finalization check added

aggstam há 3 anos atrás
pai
commit
ff581982be
1 ficheiros alterados com 63 adições e 5 exclusões
  1. 63 5
      src/validator/consensus/mod.rs

+ 63 - 5
src/validator/consensus/mod.rs

@@ -22,7 +22,7 @@ use darkfi_sdk::{
     pasta::{group::ff::PrimeField, pallas},
 };
 use darkfi_serial::{serialize, SerialDecodable, SerialEncodable};
-use log::{error, warn};
+use log::{error, info, warn};
 use rand::rngs::OsRng;
 
 use crate::{
@@ -163,8 +163,7 @@ impl Consensus {
 
         // TODO: sign more stuff?
         // Sign block header using provided secret key
-        let signature =
-            SecretKey::from(secret_key).sign(&mut OsRng, &header.headerhash().as_bytes()[..]);
+        let signature = secret_key.sign(&mut OsRng, &header.headerhash().as_bytes()[..]);
 
         // Generate block producer info
         let block_producer = BlockProducer::new(signature, proposal_tx, slot.last_eta);
@@ -369,6 +368,65 @@ impl Consensus {
 
         Ok((fork, None))
     }
+
+    /// Node checks if any of the forks can be finalized.
+    /// Consensus finalization logic:
+    /// - If the node has observed the creation of a fork and no other forks exists at same or greater height,
+    ///   all proposals in that fork can be finalized (append to canonical blockchain).
+    /// When a fork can be finalized, blocks(proposals) should be appended to canonical,
+    /// and forks should be removed.
+    pub async fn forks_finalization(&mut self) -> Result<Vec<BlockInfo>> {
+        let slot = self.time_keeper.current_slot();
+        info!(target: "validator::consensus::forks_finalization", "Started finalization check for slot: {}", slot);
+        // Set last slot finalization check occured to current slot
+        self.checked_finalization = slot;
+
+        // First we find longest fork without any other forks at same height
+        let mut fork_index = -1;
+        let mut max_length = 0;
+        for (index, fork) in self.forks.iter().enumerate() {
+            let length = fork.proposals.len();
+            // Check if less than max
+            if length < max_length {
+                continue
+            }
+            // Check if same length as max
+            if length == max_length {
+                // Setting fork_index so we know we have multiple
+                // forks at same length.
+                fork_index = -2;
+                continue
+            }
+            // Set fork as max
+            fork_index = index as i64;
+            max_length = length;
+        }
+
+        // Check if we found any fork to finalize
+        match fork_index {
+            -2 => {
+                info!(target: "validator::consensus::forks_finalization", "Eligible forks with same height exist, nothing to finalize.");
+                return Ok(vec![])
+            }
+            -1 => {
+                info!(target: "validator::consensus::forks_finalization", "Nothing to finalize.");
+            }
+            _ => {
+                info!(target: "validator::consensus::forks_finalization", "Fork {} can be finalized!", fork_index)
+            }
+        }
+
+        if max_length == 0 {
+            return Ok(vec![])
+        }
+
+        // Starting finalization
+        let fork = &self.forks[fork_index as usize];
+        let finalized = fork.overlay.lock().unwrap().get_blocks_by_hash(&fork.proposals)?;
+        info!(target: "validator::consensus::forks_finalization", "Finalized blocks: {}", finalized.len());
+
+        Ok(finalized)
+    }
 }
 
 /// This struct represents a block proposal, used for consensus.
@@ -436,7 +494,7 @@ impl Fork {
         let hash = if self.proposals.is_empty() {
             self.overlay.lock().unwrap().last_block()?.blockhash()
         } else {
-            self.proposals.last().unwrap().clone()
+            *self.proposals.last().unwrap()
         };
 
         // Read first 240 bits
@@ -479,7 +537,7 @@ impl Fork {
         let overlay = self.overlay.lock().unwrap().full_clone()?;
 
         // Verify transactions
-        let erroneous_txs = verify_transactions(&overlay, &time_keeper, &unproposed_txs).await?;
+        let erroneous_txs = verify_transactions(&overlay, time_keeper, &unproposed_txs).await?;
         if !erroneous_txs.is_empty() {
             unproposed_txs.retain(|x| !erroneous_txs.contains(x));
         }