cuprate_txpool/ops/
key_images.rs

1//! Tx-pool key image ops.
2use monero_serai::transaction::Input;
3
4use cuprate_database::{DatabaseRw, DbResult};
5
6use crate::{ops::TxPoolWriteError, tables::SpentKeyImages, types::TransactionHash};
7
8/// Adds the transaction key images to the [`SpentKeyImages`] table.
9///
10/// This function will return an error if any of the key images are already spent.
11///
12/// # Panics
13/// This function will panic if any of the [`Input`]s are not [`Input::ToKey`]
14pub(super) fn add_tx_key_images(
15    inputs: &[Input],
16    tx_hash: &TransactionHash,
17    kis_table: &mut impl DatabaseRw<SpentKeyImages>,
18) -> Result<(), TxPoolWriteError> {
19    for ki in inputs.iter().map(ki_from_input) {
20        if let Ok(double_spend_tx_hash) = kis_table.get(&ki) {
21            return Err(TxPoolWriteError::DoubleSpend(double_spend_tx_hash));
22        }
23
24        kis_table.put(&ki, tx_hash)?;
25    }
26
27    Ok(())
28}
29
30/// Removes key images from the [`SpentKeyImages`] table.
31///
32/// # Panics
33/// This function will panic if any of the [`Input`]s are not [`Input::ToKey`]
34pub(super) fn remove_tx_key_images(
35    inputs: &[Input],
36    kis_table: &mut impl DatabaseRw<SpentKeyImages>,
37) -> DbResult<()> {
38    for ki in inputs.iter().map(ki_from_input) {
39        kis_table.delete(&ki)?;
40    }
41
42    Ok(())
43}
44
45/// Maps an input to a key image.
46///
47/// # Panics
48/// This function will panic if the [`Input`] is not [`Input::ToKey`]
49fn ki_from_input(input: &Input) -> [u8; 32] {
50    match input {
51        Input::ToKey { key_image, .. } => key_image.0,
52        Input::Gen(_) => panic!("miner tx cannot be added to the txpool"),
53    }
54}