diff --git a/src/blockchain/mod.rs b/src/blockchain/mod.rs index 8057183a8..807a91932 100644 --- a/src/blockchain/mod.rs +++ b/src/blockchain/mod.rs @@ -465,6 +465,17 @@ impl BlockchainOverlay { Ok(ret) } + /// Retrieve [`Block`]s by given hashes and return their transactions hashes. + pub fn get_blocks_txs_hashes(&self, hashes: &[blake3::Hash]) -> Result> { + let blocks = self.blocks.get(hashes, true)?; + let mut ret = vec![]; + for block in blocks { + ret.extend_from_slice(&block.unwrap().txs); + } + + Ok(ret) + } + /// Checkpoint overlay so we can revert to it, if needed. pub fn checkpoint(&self) { self.overlay.lock().unwrap().checkpoint(); diff --git a/src/validator/consensus.rs b/src/validator/consensus.rs index 4da06e593..b8ddaf693 100644 --- a/src/validator/consensus.rs +++ b/src/validator/consensus.rs @@ -38,7 +38,7 @@ use crate::{ }; // Consensus configuration -/// Block/proposal maximum transactions +/// Block/proposal maximum transactions, exluding producer transaction pub const TXS_CAP: usize = 50; /// This struct represents the information required by the consensus algorithm @@ -364,28 +364,44 @@ impl Fork { blockchain: &Blockchain, verifying_block_height: u64, ) -> Result> { - // Retrieve all mempool transactions - let mut unproposed_txs: Vec = blockchain - .pending_txs - .get(&self.mempool, true)? - .iter() - .map(|x| x.clone().unwrap()) - .collect(); + // Check if our mempool is not empty + if self.mempool.is_empty() { + return Ok(vec![]) + } - // Iterate over fork proposals to find already proposed transactions - // and remove them from the unproposed_txs vector. - let proposals = self.overlay.lock().unwrap().get_blocks_by_hash(&self.proposals)?; - for proposal in proposals { - for tx in &proposal.txs { - unproposed_txs.retain(|x| x != tx); + // Grab all current proposals transactions hashes + let proposals_txs = self.overlay.lock().unwrap().get_blocks_txs_hashes(&self.proposals)?; + + // Iterate through all pending transactions in the forks' mempool + let mut unproposed_txs = vec![]; + for tx in &self.mempool { + // If the hash is contained in the proposals transactions vec, skip it + if proposals_txs.contains(tx) { + continue + } + + // Push the tx hash into the unproposed transactions vector + unproposed_txs.push(*tx); + + // Check limit + if unproposed_txs.len() == TXS_CAP { + break } } - // Check if transactions exceed configured cap - if unproposed_txs.len() > TXS_CAP { - unproposed_txs = unproposed_txs[0..TXS_CAP].to_vec() + // Check if we have any unproposed transactions + if unproposed_txs.is_empty() { + return Ok(vec![]) } + // Retrieve the actual unproposed transactions + let mut unproposed_txs: Vec = blockchain + .pending_txs + .get(&unproposed_txs, true)? + .iter() + .map(|x| x.clone().unwrap()) + .collect(); + // Clone forks' overlay let overlay = self.overlay.lock().unwrap().full_clone()?; diff --git a/src/validator/verification.rs b/src/validator/verification.rs index 16bca906d..84b689c0c 100644 --- a/src/validator/verification.rs +++ b/src/validator/verification.rs @@ -695,7 +695,7 @@ pub async fn verify_proposal( } // Check that proposal transactions don't exceed limit (2) - if proposal.block.txs.len() > TXS_CAP { + if proposal.block.txs.len() > TXS_CAP + 1 { warn!( target: "validator::verification::verify_pow_proposal", "Received proposal transactions exceed configured cap: {} - {}", proposal.block.txs.len(),