cuprate_txpool/types.rs
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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
//! Tx-pool [table](crate::tables) types.
//!
//! This module contains all types used by the database tables,
//! and aliases for common types that use the same underlying
//! primitive type.
//!
//! <!-- FIXME: Add schema here or a link to it when complete -->
use bytemuck::{Pod, Zeroable};
use monero_serai::transaction::Timelock;
use cuprate_types::{CachedVerificationState, HardFork};
/// An inputs key image.
pub type KeyImage = [u8; 32];
/// A transaction hash.
pub type TransactionHash = [u8; 32];
/// A transaction blob hash.
pub type TransactionBlobHash = [u8; 32];
bitflags::bitflags! {
/// Flags representing the state of the transaction in the pool.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
#[repr(transparent)]
pub struct TxStateFlags: u8 {
/// A flag for if the transaction is in the stem state.
const STATE_STEM = 0b0000_0001;
/// A flag for if we have seen another tx double spending this tx.
const DOUBLE_SPENT = 0b0000_0010;
}
}
/// Information on a tx-pool transaction.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
#[repr(C)]
pub struct TransactionInfo {
/// The transaction's fee.
pub fee: u64,
/// The transaction's weight.
pub weight: usize,
/// [`TxStateFlags`] of this transaction.
pub flags: TxStateFlags,
#[expect(clippy::pub_underscore_fields)]
/// Explicit padding so that we have no implicit padding bytes in `repr(C)`.
///
/// Allows potential future expansion of this type.
pub _padding: [u8; 7],
}
/// [`CachedVerificationState`] in a format that can be stored into the database.
///
/// This type impls [`Into`] & [`From`] [`CachedVerificationState`].
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
#[repr(C)]
pub struct RawCachedVerificationState {
/// The raw hash, will be all `0`s if there is no block hash that this is valid for.
raw_valid_at_hash: [u8; 32],
/// The raw hard-fork, will be `0` if there is no hf this was validated at.
raw_hf: u8,
/// The raw [`u64`] timestamp as little endian bytes ([`u64::to_le_bytes`]).
///
/// This will be `0` if there is no timestamp that needs to be passed for this to
/// be valid.
///
/// Not a [`u64`] as if it was this type would have an alignment requirement.
raw_valid_past_timestamp: [u8; 8],
}
impl From<RawCachedVerificationState> for CachedVerificationState {
fn from(value: RawCachedVerificationState) -> Self {
// if the hash is all `0`s then there is no hash this is valid at.
if value.raw_valid_at_hash == [0; 32] {
return Self::NotVerified;
}
let raw_valid_past_timestamp = u64::from_le_bytes(value.raw_valid_past_timestamp);
// if the timestamp is 0, there is no timestamp that needs to be passed.
if raw_valid_past_timestamp == 0 {
return Self::ValidAtHashAndHF {
block_hash: value.raw_valid_at_hash,
hf: HardFork::from_version(value.raw_hf)
.expect("hard-fork values stored in the DB should always be valid"),
};
}
Self::ValidAtHashAndHFWithTimeBasedLock {
block_hash: value.raw_valid_at_hash,
hf: HardFork::from_version(value.raw_hf)
.expect("hard-fork values stored in the DB should always be valid"),
time_lock: Timelock::Time(raw_valid_past_timestamp),
}
}
}
#[expect(clippy::fallible_impl_from, reason = "only panics in invalid states")]
impl From<CachedVerificationState> for RawCachedVerificationState {
fn from(value: CachedVerificationState) -> Self {
match value {
CachedVerificationState::NotVerified => Self {
raw_valid_at_hash: [0; 32],
raw_hf: 0,
raw_valid_past_timestamp: [0; 8],
},
CachedVerificationState::ValidAtHashAndHF { block_hash, hf } => Self {
raw_valid_at_hash: block_hash,
raw_hf: hf.as_u8(),
raw_valid_past_timestamp: [0; 8],
},
CachedVerificationState::ValidAtHashAndHFWithTimeBasedLock {
block_hash,
hf,
time_lock,
} => {
let Timelock::Time(time) = time_lock else {
panic!("ValidAtHashAndHFWithTimeBasedLock timelock was not time-based");
};
Self {
raw_valid_at_hash: block_hash,
raw_hf: hf.as_u8(),
raw_valid_past_timestamp: time.to_le_bytes(),
}
}
}
}
}