1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use bytemuck::TransparentWrapper;
use monero_serai::transaction::Transaction;

use cuprate_database::{DatabaseRo, DatabaseRw, RuntimeError, StorableVec};
use cuprate_types::VerifiedTransactionInformation;

use crate::{
    ops::macros::{doc_add_alt_block_inner_invariant, doc_error},
    tables::{Tables, TablesMut},
    types::{AltTransactionInfo, TxHash},
};

/// Adds a [`VerifiedTransactionInformation`] from an alt-block
/// if it is not already in the DB.
///
/// If the transaction is in the main-chain this function will still fill in the
/// [`AltTransactionInfos`](crate::tables::AltTransactionInfos) table, as that
/// table holds data which we don't keep around for main-chain txs.
///
#[doc = doc_add_alt_block_inner_invariant!()]
#[doc = doc_error!()]
pub fn add_alt_transaction_blob(
    tx: &VerifiedTransactionInformation,
    tables: &mut impl TablesMut,
) -> Result<(), RuntimeError> {
    tables.alt_transaction_infos_mut().put(
        &tx.tx_hash,
        &AltTransactionInfo {
            tx_weight: tx.tx_weight,
            fee: tx.fee,
            tx_hash: tx.tx_hash,
        },
    )?;

    if tables.tx_ids().get(&tx.tx_hash).is_ok()
        || tables.alt_transaction_blobs().get(&tx.tx_hash).is_ok()
    {
        return Ok(());
    }

    tables
        .alt_transaction_blobs_mut()
        .put(&tx.tx_hash, StorableVec::wrap_ref(&tx.tx_blob))?;

    Ok(())
}

/// Retrieve a [`VerifiedTransactionInformation`] from the database.
///
#[doc = doc_error!()]
pub fn get_alt_transaction(
    tx_hash: &TxHash,
    tables: &impl Tables,
) -> Result<VerifiedTransactionInformation, RuntimeError> {
    let tx_info = tables.alt_transaction_infos().get(tx_hash)?;

    let tx_blob = match tables.alt_transaction_blobs().get(tx_hash) {
        Ok(blob) => blob.0,
        Err(RuntimeError::KeyNotFound) => {
            let tx_id = tables.tx_ids().get(tx_hash)?;

            let blob = tables.tx_blobs().get(&tx_id)?;

            blob.0
        }
        Err(e) => return Err(e),
    };

    Ok(VerifiedTransactionInformation {
        tx: Transaction::read(&mut tx_blob.as_slice()).unwrap(),
        tx_blob,
        tx_weight: tx_info.tx_weight,
        fee: tx_info.fee,
        tx_hash: tx_info.tx_hash,
    })
}