cuprate_txpool/ops/
tx_write.rs

1//! Transaction writing ops.
2//!
3//! This module handles writing full transaction data, like removing or adding a transaction.
4use bytemuck::TransparentWrapper;
5use monero_serai::transaction::{NotPruned, Transaction};
6
7use cuprate_database::{DatabaseRw, DbResult, StorableVec};
8use cuprate_types::TransactionVerificationData;
9
10use crate::{
11    free::transaction_blob_hash,
12    ops::{
13        key_images::{add_tx_key_images, remove_tx_key_images},
14        TxPoolWriteError,
15    },
16    tables::TablesMut,
17    types::{TransactionHash, TransactionInfo, TxStateFlags},
18};
19
20/// Adds a transaction to the tx-pool.
21///
22/// This function fills in all tables necessary to add the transaction to the pool.
23///
24/// # Panics
25/// This function will panic if the transactions inputs are not all of type [`Input::ToKey`](monero_serai::transaction::Input::ToKey).
26pub fn add_transaction(
27    tx: &TransactionVerificationData,
28    state_stem: bool,
29    tables: &mut impl TablesMut,
30) -> Result<(), TxPoolWriteError> {
31    // Add the tx blob to table 0.
32    tables
33        .transaction_blobs_mut()
34        .put(&tx.tx_hash, StorableVec::wrap_ref(&tx.tx_blob))?;
35
36    let mut flags = TxStateFlags::empty();
37    flags.set(TxStateFlags::STATE_STEM, state_stem);
38
39    // Add the tx info to table 1.
40    tables.transaction_infos_mut().put(
41        &tx.tx_hash,
42        &TransactionInfo {
43            fee: tx.fee,
44            weight: tx.tx_weight,
45            flags,
46            _padding: [0; 7],
47        },
48    )?;
49
50    // Add the cached verification state to table 2.
51    let cached_verification_state = tx.cached_verification_state.into();
52    tables
53        .cached_verification_state_mut()
54        .put(&tx.tx_hash, &cached_verification_state)?;
55
56    // Add the tx key images to table 3.
57    let kis_table = tables.spent_key_images_mut();
58    add_tx_key_images(&tx.tx.prefix().inputs, &tx.tx_hash, kis_table)?;
59
60    // Add the blob hash to table 4.
61    let blob_hash = transaction_blob_hash(&tx.tx_blob);
62    tables
63        .known_blob_hashes_mut()
64        .put(&blob_hash, &tx.tx_hash)?;
65
66    Ok(())
67}
68
69/// Removes a transaction from the transaction pool.
70pub fn remove_transaction(tx_hash: &TransactionHash, tables: &mut impl TablesMut) -> DbResult<()> {
71    // Remove the tx blob from table 0.
72    let tx_blob = tables.transaction_blobs_mut().take(tx_hash)?.0;
73
74    // Remove the tx info from table 1.
75    tables.transaction_infos_mut().delete(tx_hash)?;
76
77    // Remove the cached verification state from table 2.
78    tables.cached_verification_state_mut().delete(tx_hash)?;
79
80    // Remove the tx key images from table 3.
81    let tx = Transaction::<NotPruned>::read(&mut tx_blob.as_slice())
82        .expect("Tx in the tx-pool must be parseable");
83    let kis_table = tables.spent_key_images_mut();
84    remove_tx_key_images(&tx.prefix().inputs, kis_table)?;
85
86    // Remove the blob hash from table 4.
87    let blob_hash = transaction_blob_hash(&tx_blob);
88    tables.known_blob_hashes_mut().delete(&blob_hash)?;
89
90    Ok(())
91}