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

consensus/state: unproposed txs from extending chain only.

Fix an index bug when generating a new fork chain.
aggstam 4 лет назад
Родитель
Сommit
72f6ad0e59
1 измененных файлов с 28 добавлено и 16 удалено
  1. 28 16
      src/consensus2/state.rs

+ 28 - 16
src/consensus2/state.rs

@@ -160,8 +160,8 @@ impl ValidatorState {
     /// chain the node is holding.
     pub fn propose(&self) -> Result<Option<BlockProposal>> {
         let epoch = self.current_epoch();
-        let prev_hash = self.longest_notarized_chain_last_hash().unwrap();
-        let unproposed_txs = self.unproposed_txs();
+        let (prev_hash, index) = self.longest_notarized_chain_last_hash().unwrap();
+        let unproposed_txs = self.unproposed_txs(index);
 
         let metadata = Metadata::new(
             Timestamp::current_time(),
@@ -186,15 +186,24 @@ impl ValidatorState {
         )))
     }
 
-    /// Retrieve all unconfirmed transactions not proposed in previous blocks.
-    pub fn unproposed_txs(&self) -> Vec<Tx> {
+    /// Retrieve all unconfirmed transactions not proposed in previous blocks
+    /// of provided index chain.
+    pub fn unproposed_txs(&self, index: i64) -> Vec<Tx> {
         let mut unproposed_txs = self.unconfirmed_txs.clone();
-        for chain in &self.consensus.proposals {
-            for proposal in &chain.proposals {
-                for tx in &proposal.block.txs {
-                    if let Some(pos) = unproposed_txs.iter().position(|txs| *txs == *tx) {
-                        unproposed_txs.remove(pos);
-                    }
+
+        // If index is -1 (canonical blockchain) a new fork will be generated,
+        // therefore all unproposed transactions can be included in the proposal.
+        if index == -1 {
+            return unproposed_txs
+        }
+
+        // We iterate over the fork chain proposals to find already proposed
+        // transactions and remove them from the local unproposed_txs vector.
+        let chain = &self.consensus.proposals[index as usize];
+        for proposal in &chain.proposals {
+            for tx in &proposal.block.txs {
+                if let Some(pos) = unproposed_txs.iter().position(|txs| *txs == *tx) {
+                    unproposed_txs.remove(pos);
                 }
             }
         }
@@ -203,16 +212,19 @@ impl ValidatorState {
     }
 
     /// Finds the longest fully notarized blockchain the node holds and
-    /// returns the last block hash.
-    pub fn longest_notarized_chain_last_hash(&self) -> Result<blake3::Hash> {
+    /// returns the last block hash and the chain index.
+    pub fn longest_notarized_chain_last_hash(&self) -> Result<(blake3::Hash, i64)> {
+        let mut longest_notarized_chain = &self.consensus.proposals[0];
+        let mut length = longest_notarized_chain.proposals.len();
+        let mut index = -1;
+
         let hash = if !self.consensus.proposals.is_empty() {
-            let mut longest_notarized_chain = &self.consensus.proposals[0];
-            let mut length = longest_notarized_chain.proposals.len();
             if self.consensus.proposals.len() > 1 {
-                for chain in &self.consensus.proposals[1..] {
+                for (i, chain) in self.consensus.proposals.iter().enumerate() {
                     if chain.notarized() && chain.proposals.len() > length {
                         length = chain.proposals.len();
                         longest_notarized_chain = chain;
+                        index = i as i64;
                     }
                 }
             }
@@ -222,7 +234,7 @@ impl ValidatorState {
             self.blockchain.last()?.unwrap().1
         };
 
-        Ok(hash)
+        Ok((hash, index))
     }
 
     /// Receive the proposed block, verify its sender (epoch leader),