diff --git a/src/consensus2/state.rs b/src/consensus2/state.rs index b47a64dbb..33f359661 100644 --- a/src/consensus2/state.rs +++ b/src/consensus2/state.rs @@ -160,8 +160,8 @@ impl ValidatorState { /// chain the node is holding. pub fn propose(&self) -> Result> { 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 { + /// Retrieve 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.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 { + /// 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),