Browse Source

validator: check if proposal already exists when looking ofr its fork index

This also solves the bug where when appending a dublicated proposal, a new duplicate fork being created, resulting in never finalizing, as forks of same height existed
aggstam 2 năm trước cách đây
mục cha
commit
a318bb3d76
3 tập tin đã thay đổi với 34 bổ sung3 xóa
  1. 3 0
      src/error.rs
  2. 7 1
      src/validator/consensus.rs
  3. 24 2
      src/validator/utils.rs

+ 3 - 0
src/error.rs

@@ -339,6 +339,9 @@ pub enum Error {
     #[error("Proposal task stopped")]
     ProposalTaskStopped,
 
+    #[error("Proposal already exists")]
+    ProposalAlreadyExists,
+
     #[error("Miner task stopped")]
     MinerTaskStopped,
 

+ 7 - 1
src/validator/consensus.rs

@@ -208,7 +208,7 @@ impl Consensus {
     /// Given a proposal, the node verifys it and finds which fork it extends.
     /// If the proposal extends the canonical blockchain, a new fork chain is created.
     pub async fn append_proposal(&self, proposal: &Proposal) -> Result<()> {
-        info!(target: "validator::consensus::append_proposal", "Appending proposal {}", proposal.hash);
+        debug!(target: "validator::consensus::append_proposal", "Appending proposal {}", proposal.hash);
 
         // Verify proposal and grab corresponding fork
         let (mut fork, index) = verify_proposal(self, proposal).await?;
@@ -244,6 +244,8 @@ impl Consensus {
         }
         drop(lock);
 
+        info!(target: "validator::consensus::append_proposal", "Appended proposal {}", proposal.hash);
+
         Ok(())
     }
 
@@ -259,6 +261,10 @@ impl Consensus {
         // Check if proposal extends any fork
         let found = find_extended_fork_index(&forks, proposal);
         if found.is_err() {
+            if let Err(Error::ProposalAlreadyExists) = found {
+                return Err(Error::ProposalAlreadyExists)
+            }
+
             // Check if proposal extends canonical
             let (last_slot, last_block) = self.blockchain.last()?;
             if proposal.block.header.previous != last_block ||

+ 24 - 2
src/validator/utils.rs

@@ -254,17 +254,39 @@ pub fn previous_slot_info(
 }
 
 /// Given a proposal, find the index of the fork chain it extends, along with the specific
-/// extended proposal index.
+/// extended proposal index. Additionally, check that proposal doesn't already exists in any
+/// fork chain.
 pub fn find_extended_fork_index(forks: &[Fork], proposal: &Proposal) -> Result<(usize, usize)> {
+    // Grab provided proposal hash
+    let proposal_hash = proposal.block.hash()?;
+
+    // Keep track of fork and proposal indexes
+    let (mut fork_index, mut proposal_index) = (None, None);
+
+    // Loop through all the forks
     for (f_index, fork) in forks.iter().enumerate() {
         // Traverse fork proposals sequence in reverse
         for (p_index, p_hash) in fork.proposals.iter().enumerate().rev() {
+            // Check we haven't already seen that proposal
+            if &proposal_hash == p_hash {
+                return Err(Error::ProposalAlreadyExists)
+            }
+
+            // Check if proposal extends this fork
             if &proposal.block.header.previous == p_hash {
-                return Ok((f_index, p_index))
+                // Proposal must only extend a single fork
+                if fork_index.is_some() {
+                    return Err(Error::ProposalAlreadyExists)
+                }
+                (fork_index, proposal_index) = (Some(f_index), Some(p_index));
             }
         }
     }
 
+    if let (Some(f_index), Some(p_index)) = (fork_index, proposal_index) {
+        return Ok((f_index, p_index))
+    }
+
     Err(Error::ExtendedChainIndexNotFound)
 }