cuprate_consensus/block/
free.rs

1//! Free functions for block verification
2use std::collections::HashMap;
3
4use monero_serai::block::Block;
5
6use cuprate_types::TransactionVerificationData;
7
8use crate::ExtendedConsensusError;
9
10/// Orders the [`TransactionVerificationData`] list the same as it appears in [`Block::transactions`]
11pub(crate) fn order_transactions(
12    block: &Block,
13    txs: &mut [TransactionVerificationData],
14) -> Result<(), ExtendedConsensusError> {
15    if block.transactions.len() != txs.len() {
16        return Err(ExtendedConsensusError::TxsIncludedWithBlockIncorrect);
17    }
18
19    for (i, tx_hash) in block.transactions.iter().enumerate() {
20        if tx_hash != &txs[i].tx_hash {
21            let at_index = txs[i..]
22                .iter()
23                .position(|tx| &tx.tx_hash == tx_hash)
24                .ok_or(ExtendedConsensusError::TxsIncludedWithBlockIncorrect)?;
25
26            // The above `position` will give an index from inside its view of the slice so we need to add the difference.
27            txs.swap(i, i + at_index);
28        }
29    }
30
31    debug_assert!(block
32        .transactions
33        .iter()
34        .zip(txs.iter())
35        .all(|(tx_hash, tx)| tx_hash == &tx.tx_hash));
36
37    Ok(())
38}
39
40/// Returns a list of transactions, pulled from `txs` in the order they are in the [`Block`].
41///
42/// Will error if a tx need is not in `txs` or if `txs` contain more txs than needed.
43pub(crate) fn pull_ordered_transactions(
44    block: &Block,
45    mut txs: HashMap<[u8; 32], TransactionVerificationData>,
46) -> Result<Vec<TransactionVerificationData>, ExtendedConsensusError> {
47    if block.transactions.len() != txs.len() {
48        return Err(ExtendedConsensusError::TxsIncludedWithBlockIncorrect);
49    }
50
51    let mut ordered_txs = Vec::with_capacity(txs.len());
52
53    if !block.transactions.is_empty() {
54        for tx_hash in &block.transactions {
55            let tx = txs
56                .remove(tx_hash)
57                .ok_or(ExtendedConsensusError::TxsIncludedWithBlockIncorrect)?;
58            ordered_txs.push(tx);
59        }
60        drop(txs);
61    }
62
63    Ok(ordered_txs)
64}