diff --git a/src/consensus/state.rs b/src/consensus/state.rs index fc6299b6b..1f84d9e4d 100644 --- a/src/consensus/state.rs +++ b/src/consensus/state.rs @@ -164,8 +164,8 @@ impl ValidatorState { /// Proposal extends the longest notarized fork chain the node holds. pub fn propose(&self) -> Result> { let epoch = self.current_epoch(); - let previous_hash = self.longest_notarized_chain_last_hash().unwrap(); - let unproposed_txs = self.unproposed_txs(); + let (previous_hash, index) = self.longest_notarized_chain_last_hash().unwrap(); + let unproposed_txs = self.unproposed_txs(index); let metadata = Metadata::new( get_current_time(), String::from("proof"), @@ -189,30 +189,43 @@ impl ValidatorState { ))) } - /// Node retrieves all unconfiremd transactions not proposed in previous blocks. - pub fn unproposed_txs(&self) -> Vec { + /// Node retrieves all unconfirmed transactions not proposed + /// in previous blocks of provided index chain. + pub fn unproposed_txs(&self, index: i64) -> Vec { let mut unproposed_txs = self.unconfirmed_txs.clone(); - for chain in &self.consensus.proposals { - for proposal in &chain.proposals { - for tx in &proposal.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 chain will be generated, + // therefore all unproposed transactions can be included in the proposal. + if index == -1 { + return unproposed_txs + } + + // We iterate 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.txs { + if let Some(pos) = unproposed_txs.iter().position(|txs| *txs == *tx) { + unproposed_txs.remove(pos); } } } + unproposed_txs } - /// Finds the longest fully notarized blockchain the node holds and returns the last block hash. - pub fn longest_notarized_chain_last_hash(&self) -> Result { + /// Finds the longest fully notarized blockchain the node holds and 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: Option = None; let mut length = 0; + let mut index = -1; if !self.consensus.proposals.is_empty() { - for chain in &self.consensus.proposals[1..] { + for (i, chain) in self.consensus.proposals.iter().enumerate() { if chain.notarized() && chain.proposals.len() > length { longest_notarized_chain = Some(chain.clone()); length = chain.proposals.len(); + index = i as i64; } } } @@ -222,7 +235,7 @@ impl ValidatorState { None => self.blockchain.last()?.unwrap().1, }; - Ok(hash) + Ok((hash, index)) } /// Node receives the proposed block, verifies its sender(epoch leader),