1//! Free functions for block verification
2use std::collections::HashMap;
34use monero_serai::block::Block;
56use cuprate_types::TransactionVerificationData;
78use crate::ExtendedConsensusError;
910/// 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> {
15if block.transactions.len() != txs.len() {
16return Err(ExtendedConsensusError::TxsIncludedWithBlockIncorrect);
17 }
1819for (i, tx_hash) in block.transactions.iter().enumerate() {
20if tx_hash != &txs[i].tx_hash {
21let at_index = txs[i..]
22 .iter()
23 .position(|tx| &tx.tx_hash == tx_hash)
24 .ok_or(ExtendedConsensusError::TxsIncludedWithBlockIncorrect)?;
2526// The above `position` will give an index from inside its view of the slice so we need to add the difference.
27txs.swap(i, i + at_index);
28 }
29 }
3031debug_assert!(block
32 .transactions
33 .iter()
34 .zip(txs.iter())
35 .all(|(tx_hash, tx)| tx_hash == &tx.tx_hash));
3637Ok(())
38}
3940/// 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,
45mut txs: HashMap<[u8; 32], TransactionVerificationData>,
46) -> Result<Vec<TransactionVerificationData>, ExtendedConsensusError> {
47if block.transactions.len() != txs.len() {
48return Err(ExtendedConsensusError::TxsIncludedWithBlockIncorrect);
49 }
5051let mut ordered_txs = Vec::with_capacity(txs.len());
5253if !block.transactions.is_empty() {
54for tx_hash in &block.transactions {
55let tx = txs
56 .remove(tx_hash)
57 .ok_or(ExtendedConsensusError::TxsIncludedWithBlockIncorrect)?;
58 ordered_txs.push(tx);
59 }
60 drop(txs);
61 }
6263Ok(ordered_txs)
64}