Răsfoiți Sursa

validator/consensus: handle same ranking forks

aggstam 2 ani în urmă
părinte
comite
4043e09330
2 a modificat fișierele cu 32 adăugiri și 14 ștergeri
  1. 1 0
      Cargo.toml
  2. 31 14
      src/validator/consensus.rs

+ 1 - 0
Cargo.toml

@@ -150,6 +150,7 @@ blockchain = [
     "blake3",
     "sled",
     "sled-overlay",
+    "num-bigint",
 
     "async-sdk",
     "async-serial",

+ 31 - 14
src/validator/consensus.rs

@@ -144,8 +144,8 @@ impl Consensus {
         secret_key: &SecretKey,
         proposal_tx: Transaction,
     ) -> Result<(Proposal, usize)> {
-        // Grab best fork and its last slot
-        let fork_index = self.best_fork_index()?;
+        // Grab best forks, pick the first and its last slot
+        let fork_index = self.best_forks_indexes()?[0];
         let fork = &self.forks[fork_index];
         let slot = fork.slots.last().unwrap();
 
@@ -231,27 +231,36 @@ impl Consensus {
         Ok(())
     }
 
-    /// Auxiliary function to find current best ranked fork index.
-    pub fn best_fork_index(&self) -> Result<usize> {
+    /// Auxiliary function to find current best ranked forks indexes.
+    pub fn best_forks_indexes(&self) -> Result<Vec<usize>> {
         // Check if node has any forks
         if self.forks.is_empty() {
             return Err(Error::ForksNotFound)
         }
 
-        // Find the best ranked fork
+        // Find the best ranked forks
         let mut best = 0;
-        let mut index = 0;
+        let mut indexes = vec![];
         for (f_index, fork) in self.forks.iter().enumerate() {
             let rank = fork.rank;
-            if rank <= best {
+
+            // Fork ranks lower that current best
+            if rank < best {
+                continue
+            }
+
+            // Fork has same rank as current best
+            if rank == best {
+                indexes.push(f_index);
                 continue
             }
 
+            // Fork ranks higher that current best
             best = rank;
-            index = f_index;
+            indexes = vec![f_index];
         }
 
-        Ok(index)
+        Ok(indexes)
     }
 
     /// Given a proposal, find the index of the fork chain it extends, along with the specific
@@ -365,8 +374,9 @@ impl Consensus {
     }
 
     /// Consensus finalization logic:
-    /// - If the current best fork has reached greater length than the security thresshold,
-    ///   all proposals excluding the last one in that fork can be finalized (append to canonical blockchain).
+    /// - If the current best fork has reached greater length than the security thresshold, and
+    ///   no other fork exist with same rank, all proposals excluding the last one in that fork
+    //    can be finalized (append to canonical blockchain).
     /// When best fork can be finalized, blocks(proposals) should be appended to canonical, excluding the
     /// last one, and fork should be rebuilt.
     pub async fn finalization(&mut self) -> Result<Vec<BlockInfo>> {
@@ -375,9 +385,16 @@ impl Consensus {
         debug!(target: "validator::consensus::finalization", "Started finalization check for slot: {}", slot);
         self.checked_finalization = slot;
 
-        // Grab best fork
-        let fork_index = self.best_fork_index()?;
-        let fork = &self.forks[fork_index];
+        // Grab best forks
+        let forks_indexes = self.best_forks_indexes()?;
+        // Check if multiple forks with same rank were found
+        if forks_indexes.len() > 1 {
+            debug!(target: "validator::consensus::finalization", "Multiple best ranked forks were found");
+            return Ok(vec![])
+        }
+
+        // Grag the actual best fork
+        let fork = &self.forks[forks_indexes[0]];
 
         // Check its length
         let length = fork.proposals.len();