Skip to main content

cuprate_blockchain/
types.rs

1//! Blockchain types.
2//!
3//! This module contains all types used by the database tables,
4//! and aliases for common Monero-related types that use the
5//! same underlying primitive type.
6//!
7//! <!-- FIXME: Add schema here or a link to it when complete -->
8
9/*
10 * <============================================> VERY BIG SCARY SAFETY MESSAGE <============================================>
11 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
12 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
13 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
14 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
15 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
16 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
17 *
18 *
19 *
20 *                                We use `bytemuck` to (de)serialize data types in the database.
21 *                          We are SAFELY casting bytes, but to do so, we must uphold some invariants.
22 *                          When editing this file, there is only 1 commandment that MUST be followed:
23 *
24 *                                   1. Thou shall only utilize `bytemuck`'s derive macros
25 *
26 *                             The derive macros will fail at COMPILE time if something is incorrect.
27 *                                  <https://docs.rs/bytemuck/latest/bytemuck/derive.Pod.html>
28 *                                 If you submit a PR that breaks this I will come and find you.
29 *
30 *
31 *
32 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
33 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
34 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
35 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
36 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
37 * DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE --- DO NOT IGNORE
38 * <============================================> VERY BIG SCARY SAFETY MESSAGE <============================================>
39 */
40// actually i still don't trust you. no unsafe.
41#![forbid(unsafe_code)] // if you remove this line i will steal your monero
42
43use std::num::NonZero;
44
45use bytemuck::{Pod, Zeroable};
46#[cfg(feature = "serde")]
47use serde::{Deserialize, Serialize};
48
49use cuprate_types::{Chain, ChainId};
50
51//---------------------------------------------------------------------------------------------------- Aliases
52// These type aliases exist as many Monero-related types are the exact same.
53// For clarity, they're given type aliases as to not confuse them.
54
55/// An output's amount.
56pub type Amount = u64;
57
58/// The index of an [`Amount`] in a list of duplicate `Amount`s.
59pub type AmountIndex = u64;
60
61/// A list of [`AmountIndex`]s.
62pub type AmountIndices = Vec<AmountIndex>;
63
64/// A block's hash.
65pub type BlockHash = [u8; 32];
66
67/// A block's height.
68pub type BlockHeight = usize;
69
70/// A key image.
71pub type KeyImage = [u8; 32];
72
73/// A prunable hash.
74pub type PrunableHash = [u8; 32];
75
76/// A transaction's global index, or ID.
77pub type TxId = u64;
78
79/// A transaction's hash.
80pub type TxHash = [u8; 32];
81
82/// The unlock time value of an output.
83pub type UnlockTime = u64;
84
85/// Information on a transaction in the blockchain.
86#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
87#[repr(C)]
88pub struct TxInfo {
89    /// The height of this transaction.
90    pub height: usize,
91    /// The index of the transactions pruned blob in the pruned tape.
92    pub pruned_blob_idx: u64,
93    /// The index of the transactions prunable blob in the corresponding prunable tape.
94    pub prunable_blob_idx: u64,
95    /// The size of the transactions pruned blob.
96    pub pruned_size: usize,
97    /// The size of th transaction prunable blob.
98    pub prunable_size: usize,
99    /// The index of the first V2 output in this transaction.
100    ///
101    /// will be [`u64::MAX`] for V1 transactions.
102    pub rct_output_start_idx: u64,
103    /// The number of RCT outputs in this transaction.
104    ///
105    /// Undefined for V1 transactions.
106    pub numb_rct_outputs: usize,
107}
108
109impl TxInfo {
110    pub const fn is_v1_tx(&self) -> bool {
111        self.rct_output_start_idx == u64::MAX
112    }
113}
114
115//---------------------------------------------------------------------------------------------------- BlockInfoV1
116/// A identifier for a pre-RCT [`Output`].
117///
118/// This can also serve as an identifier for [`RctOutput`]'s
119/// when [`PreRctOutputId::amount`] is set to `0`, although,
120/// in that case, only [`AmountIndex`] needs to be known.
121///
122/// # Size & Alignment
123/// ```rust
124/// # use cuprate_blockchain::types::*;
125/// assert_eq!(size_of::<PreRctOutputId>(), 16);
126/// assert_eq!(align_of::<PreRctOutputId>(), 8);
127/// ```
128#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
129#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
130#[repr(C)]
131pub struct PreRctOutputId {
132    /// Amount of the output.
133    ///
134    /// This should be `0` if the output is an [`RctOutput`].
135    pub amount: Amount,
136    /// The index of the output with the same `amount`.
137    ///
138    /// In the case of [`Output`]'s, this is the index of the list
139    /// of outputs with the same clear amount.
140    ///
141    /// In the case of [`RctOutput`]'s, this is the
142    /// global index of _all_ `RctOutput`s
143    pub amount_index: AmountIndex,
144}
145
146impl PreRctOutputId {
147    /// Serializes the [`PreRctOutputId`] into bytes.
148    pub fn to_bytes(&self) -> [u8; 16] {
149        // We use big endian here so that the outputs are sorted by their numeric values.
150        let mut buf = [0; 16];
151        buf[..8].copy_from_slice(&self.amount.to_be_bytes());
152        buf[8..].copy_from_slice(&self.amount_index.to_be_bytes());
153        buf
154    }
155
156    /// Deserializes the bytes into a [`PreRctOutputId`]
157    pub fn from_bytes(bytes: &[u8; 16]) -> Self {
158        Self {
159            amount: Amount::from_be_bytes(bytes[..8].try_into().unwrap()),
160            amount_index: AmountIndex::from_be_bytes(bytes[8..].try_into().unwrap()),
161        }
162    }
163}
164
165//---------------------------------------------------------------------------------------------------- BlockInfoV3
166/// Block information.
167///
168/// # Size & Alignment
169/// ```rust
170/// # use cuprate_blockchain::types::*;
171/// assert_eq!(size_of::<BlockInfo>(), 112);
172/// assert_eq!(align_of::<BlockInfo>(), 8);
173/// ```
174#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
175#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable, Default)]
176#[repr(C)]
177pub struct BlockInfo {
178    /// The total amount of coins mined in all blocks so far, including this block's.
179    pub cumulative_generated_coins: u64,
180    /// The adjusted block size, in bytes.
181    ///
182    /// See [`block_weight`](https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#blocks-weight).
183    pub weight: usize,
184    /// Least-significant 64 bits of the 128-bit cumulative difficulty.
185    pub cumulative_difficulty_low: u64,
186    /// Most-significant 64 bits of the 128-bit cumulative difficulty.
187    pub cumulative_difficulty_high: u64,
188    /// The block's hash.
189    pub block_hash: [u8; 32],
190    /// The total amount of RCT outputs so far, including this block's.
191    pub cumulative_rct_outs: u64,
192    /// The long term block weight, based on the median weight of the preceding `100_000` blocks.
193    ///
194    /// See [`long_term_weight`](https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#long-term-block-weight).
195    pub long_term_weight: usize,
196    /// [`TxId`] (u64) of the block coinbase transaction.
197    pub mining_tx_index: TxId,
198    /// The index of the block blob in the v2 prunable tape.
199    pub prunable_blob_idx: u64,
200    /// The index of the block blob in the v1 prunable tape.
201    pub v1_prunable_blob_idx: u64,
202    /// The index of the block blob in the pruned tape.
203    pub pruned_blob_idx: u64,
204}
205
206//---------------------------------------------------------------------------------------------------- Output
207/// A pre-RCT (v1) output's data.
208///
209/// # Size & Alignment
210/// ```rust
211/// # use cuprate_blockchain::types::*;
212/// assert_eq!(size_of::<Output>(), 56);
213/// assert_eq!(align_of::<Output>(), 8);
214/// ```
215#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
216#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
217#[repr(C)]
218pub struct Output {
219    /// The public key of the output.
220    pub key: [u8; 32],
221    /// The block height this output belongs to.
222    // PERF: We could get this from the tx_idx with the `TxHeights`
223    // table but that would require another look up per out.
224    pub height: usize,
225    /// The time lock of this output.
226    pub timelock: u64,
227    /// The index of the transaction this output belongs to.
228    pub tx_idx: TxId,
229}
230
231//---------------------------------------------------------------------------------------------------- RctOutput
232/// An RCT (v2+) output's data.
233///
234/// # Size & Alignment
235/// ```rust
236/// # use cuprate_blockchain::types::*;
237/// assert_eq!(size_of::<RctOutput>(), 88);
238/// assert_eq!(align_of::<RctOutput>(), 8);
239/// ```
240#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
241#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
242#[repr(C)]
243pub struct RctOutput {
244    /// The public key of the output.
245    pub key: [u8; 32],
246    /// The block height this output belongs to.
247    // PERF: We could get this from the tx_idx with the `TxHeights`
248    // table but that would require another look up per out.
249    pub height: usize,
250    /// The time lock of this output.
251    pub timelock: u64,
252    /// The index of the transaction this output belongs to.
253    pub tx_idx: TxId,
254    /// The amount commitment of this output.
255    pub commitment: [u8; 32],
256}
257// TODO: local_index?
258
259//---------------------------------------------------------------------------------------------------- RawChain
260/// [`Chain`] in a format which can be stored in the DB.
261///
262/// Implements [`Into`] and [`From`] for [`Chain`].
263///
264/// # Size & Alignment
265/// ```rust
266/// # use cuprate_blockchain::types::*;
267/// assert_eq!(size_of::<RawChain>(), 8);
268/// assert_eq!(align_of::<RawChain>(), 8);
269/// ```
270#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
271#[repr(transparent)]
272pub struct RawChain(u64);
273
274impl From<Chain> for RawChain {
275    fn from(value: Chain) -> Self {
276        match value {
277            Chain::Main => Self(0),
278            Chain::Alt(chain_id) => Self(chain_id.0.get()),
279        }
280    }
281}
282
283impl From<RawChain> for Chain {
284    fn from(value: RawChain) -> Self {
285        NonZero::new(value.0).map_or(Self::Main, |id| Self::Alt(ChainId(id)))
286    }
287}
288
289impl From<RawChainId> for RawChain {
290    fn from(value: RawChainId) -> Self {
291        // A [`ChainID`] with an inner value of `0` is invalid.
292        assert_ne!(value.0, 0);
293
294        Self(value.0)
295    }
296}
297
298//---------------------------------------------------------------------------------------------------- RawChainId
299/// [`ChainId`] in a format which can be stored in the DB.
300///
301/// Implements [`Into`] and [`From`] for [`ChainId`].
302///
303/// # Size & Alignment
304/// ```rust
305/// # use cuprate_blockchain::types::*;
306/// assert_eq!(size_of::<RawChainId>(), 8);
307/// assert_eq!(align_of::<RawChainId>(), 8);
308/// ```
309#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
310#[repr(transparent)]
311pub struct RawChainId(pub(crate) u64);
312
313impl From<ChainId> for RawChainId {
314    fn from(value: ChainId) -> Self {
315        Self(value.0.get())
316    }
317}
318
319impl From<RawChainId> for ChainId {
320    fn from(value: RawChainId) -> Self {
321        Self(NonZero::new(value.0).expect("RawChainId cannot have a value of `0`"))
322    }
323}
324
325//---------------------------------------------------------------------------------------------------- AltChainInfo
326/// Information on an alternative chain.
327///
328/// # Size & Alignment
329/// ```rust
330/// # use cuprate_blockchain::types::*;
331/// assert_eq!(size_of::<AltChainInfo>(), 24);
332/// assert_eq!(align_of::<AltChainInfo>(), 8);
333/// ```
334#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
335#[repr(C)]
336pub struct AltChainInfo {
337    /// The chain this alt chain forks from.
338    pub parent_chain: RawChain,
339    /// The height of the first block we share with the parent chain.
340    pub common_ancestor_height: usize,
341    /// The chain height of the blocks in this alt chain.
342    pub chain_height: usize,
343}
344
345//---------------------------------------------------------------------------------------------------- AltBlockHeight
346/// Represents the height of a block on an alt-chain.
347///
348/// # Size & Alignment
349/// ```rust
350/// # use cuprate_blockchain::types::*;
351/// assert_eq!(size_of::<AltBlockHeight>(), 16);
352/// assert_eq!(align_of::<AltBlockHeight>(), 8);
353/// ```
354#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
355#[repr(C)]
356pub struct AltBlockHeight {
357    /// The [`ChainId`] of the chain this alt block is on, in raw form.
358    pub chain_id: RawChainId,
359    /// The height of this alt-block.
360    pub height: usize,
361}
362
363//---------------------------------------------------------------------------------------------------- CompactAltBlockInfo
364/// Represents information on an alt-chain.
365///
366/// # Size & Alignment
367/// ```rust
368/// # use cuprate_blockchain::types::*;
369/// assert_eq!(size_of::<CompactAltBlockInfo>(), 104);
370/// assert_eq!(align_of::<CompactAltBlockInfo>(), 8);
371/// ```
372#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
373#[repr(C)]
374pub struct CompactAltBlockInfo {
375    /// The block's hash.
376    pub block_hash: [u8; 32],
377    /// The block's proof-of-work hash.
378    pub pow_hash: [u8; 32],
379    /// The block's height.
380    pub height: usize,
381    /// The adjusted block size, in bytes.
382    pub weight: usize,
383    /// The long term block weight, which is the weight factored in with previous block weights.
384    pub long_term_weight: usize,
385    /// The low 64 bits of the cumulative difficulty.
386    pub cumulative_difficulty_low: u64,
387    /// The high 64 bits of the cumulative difficulty.
388    pub cumulative_difficulty_high: u64,
389}
390
391//---------------------------------------------------------------------------------------------------- AltTransactionInfo
392/// Represents information on an alt transaction.
393///
394/// # Size & Alignment
395/// ```rust
396/// # use cuprate_blockchain::types::*;
397/// assert_eq!(size_of::<AltTransactionInfo>(), 48);
398/// assert_eq!(align_of::<AltTransactionInfo>(), 8);
399/// ```
400#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
401#[repr(C)]
402pub struct AltTransactionInfo {
403    /// The transaction's weight.
404    pub tx_weight: usize,
405    /// The transaction's total fees.
406    pub fee: u64,
407    /// The transaction's hash.
408    pub tx_hash: [u8; 32],
409}
410
411//---------------------------------------------------------------------------------------------------- Tests
412#[cfg(test)]
413mod test {
414    // use super::*;
415}