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    ///
95    /// # Warning
96    ///
97    /// This value is only valid when the tx is in an unpruned block. If the tx is not then the value
98    /// is unspecified.
99    pub prunable_blob_idx: u64,
100    /// The size of the transactions pruned blob.
101    pub pruned_size: usize,
102    /// The size of th transaction prunable blob.
103    pub prunable_size: usize,
104    /// The index of the first V2 output in this transaction.
105    ///
106    /// will be [`u64::MAX`] for V1 transactions.
107    pub rct_output_start_idx: u64,
108    /// The number of RCT outputs in this transaction.
109    ///
110    /// Undefined for V1 transactions.
111    pub numb_rct_outputs: usize,
112}
113
114impl TxInfo {
115    pub const fn is_v1_tx(&self) -> bool {
116        self.rct_output_start_idx == u64::MAX
117    }
118}
119
120//---------------------------------------------------------------------------------------------------- BlockInfoV1
121/// A identifier for a pre-RCT [`Output`].
122///
123/// This can also serve as an identifier for [`RctOutput`]'s
124/// when [`PreRctOutputId::amount`] is set to `0`, although,
125/// in that case, only [`AmountIndex`] needs to be known.
126///
127/// # Size & Alignment
128/// ```rust
129/// # use cuprate_blockchain::types::*;
130/// assert_eq!(size_of::<PreRctOutputId>(), 16);
131/// assert_eq!(align_of::<PreRctOutputId>(), 8);
132/// ```
133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
135#[repr(C)]
136pub struct PreRctOutputId {
137    /// Amount of the output.
138    ///
139    /// This should be `0` if the output is an [`RctOutput`].
140    pub amount: Amount,
141    /// The index of the output with the same `amount`.
142    ///
143    /// In the case of [`Output`]'s, this is the index of the list
144    /// of outputs with the same clear amount.
145    ///
146    /// In the case of [`RctOutput`]'s, this is the
147    /// global index of _all_ `RctOutput`s
148    pub amount_index: AmountIndex,
149}
150
151impl PreRctOutputId {
152    /// Serializes the [`PreRctOutputId`] into bytes.
153    pub fn to_bytes(&self) -> [u8; 16] {
154        // We use big endian here so that the outputs are sorted by their numeric values.
155        let mut buf = [0; 16];
156        buf[..8].copy_from_slice(&self.amount.to_be_bytes());
157        buf[8..].copy_from_slice(&self.amount_index.to_be_bytes());
158        buf
159    }
160
161    /// Deserializes the bytes into a [`PreRctOutputId`]
162    pub fn from_bytes(bytes: &[u8; 16]) -> Self {
163        Self {
164            amount: Amount::from_be_bytes(bytes[..8].try_into().unwrap()),
165            amount_index: AmountIndex::from_be_bytes(bytes[8..].try_into().unwrap()),
166        }
167    }
168}
169
170//---------------------------------------------------------------------------------------------------- BlockInfoV3
171/// Block information.
172///
173/// # Size & Alignment
174/// ```rust
175/// # use cuprate_blockchain::types::*;
176/// assert_eq!(size_of::<BlockInfo>(), 104);
177/// assert_eq!(align_of::<BlockInfo>(), 8);
178/// ```
179#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
180#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable, Default)]
181#[repr(C)]
182pub struct BlockInfo {
183    /// The total amount of coins mined in all blocks so far, including this block's.
184    pub cumulative_generated_coins: u64,
185    /// The adjusted block size, in bytes.
186    ///
187    /// See [`block_weight`](https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#blocks-weight).
188    pub weight: usize,
189    /// Least-significant 64 bits of the 128-bit cumulative difficulty.
190    pub cumulative_difficulty_low: u64,
191    /// Most-significant 64 bits of the 128-bit cumulative difficulty.
192    pub cumulative_difficulty_high: u64,
193    /// The block's hash.
194    pub block_hash: [u8; 32],
195    /// The total amount of RCT outputs so far, including this block's.
196    pub cumulative_rct_outs: u64,
197    /// The long term block weight, based on the median weight of the preceding `100_000` blocks.
198    ///
199    /// See [`long_term_weight`](https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#long-term-block-weight).
200    pub long_term_weight: usize,
201    /// [`TxId`] (u64) of the block coinbase transaction.
202    pub mining_tx_index: TxId,
203    /// The index of the block blob in the v1 prunable tape.
204    pub v1_prunable_blob_idx: u64,
205    /// The index of the block blob in the pruned tape.
206    pub pruned_blob_idx: u64,
207}
208
209//---------------------------------------------------------------------------------------------------- Output
210/// A pre-RCT (v1) output's data.
211///
212/// # Size & Alignment
213/// ```rust
214/// # use cuprate_blockchain::types::*;
215/// assert_eq!(size_of::<Output>(), 56);
216/// assert_eq!(align_of::<Output>(), 8);
217/// ```
218#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
219#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
220#[repr(C)]
221pub struct Output {
222    /// The public key of the output.
223    pub key: [u8; 32],
224    /// The block height this output belongs to.
225    // PERF: We could get this from the tx_idx with the `TxHeights`
226    // table but that would require another look up per out.
227    pub height: usize,
228    /// The time lock of this output.
229    pub timelock: u64,
230    /// The index of the transaction this output belongs to.
231    pub tx_idx: TxId,
232}
233
234//---------------------------------------------------------------------------------------------------- RctOutput
235/// An RCT (v2+) output's data.
236///
237/// # Size & Alignment
238/// ```rust
239/// # use cuprate_blockchain::types::*;
240/// assert_eq!(size_of::<RctOutput>(), 88);
241/// assert_eq!(align_of::<RctOutput>(), 8);
242/// ```
243#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
244#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
245#[repr(C)]
246pub struct RctOutput {
247    /// The public key of the output.
248    pub key: [u8; 32],
249    /// The block height this output belongs to.
250    // PERF: We could get this from the tx_idx with the `TxHeights`
251    // table but that would require another look up per out.
252    pub height: usize,
253    /// The time lock of this output.
254    pub timelock: u64,
255    /// The index of the transaction this output belongs to.
256    pub tx_idx: TxId,
257    /// The amount commitment of this output.
258    pub commitment: [u8; 32],
259}
260// TODO: local_index?
261
262//---------------------------------------------------------------------------------------------------- RawChain
263/// [`Chain`] in a format which can be stored in the DB.
264///
265/// Implements [`Into`] and [`From`] for [`Chain`].
266///
267/// # Size & Alignment
268/// ```rust
269/// # use cuprate_blockchain::types::*;
270/// assert_eq!(size_of::<RawChain>(), 8);
271/// assert_eq!(align_of::<RawChain>(), 8);
272/// ```
273#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
274#[repr(transparent)]
275pub struct RawChain(u64);
276
277impl From<Chain> for RawChain {
278    fn from(value: Chain) -> Self {
279        match value {
280            Chain::Main => Self(0),
281            Chain::Alt(chain_id) => Self(chain_id.0.get()),
282        }
283    }
284}
285
286impl From<RawChain> for Chain {
287    fn from(value: RawChain) -> Self {
288        NonZero::new(value.0).map_or(Self::Main, |id| Self::Alt(ChainId(id)))
289    }
290}
291
292impl From<RawChainId> for RawChain {
293    fn from(value: RawChainId) -> Self {
294        // A [`ChainID`] with an inner value of `0` is invalid.
295        assert_ne!(value.0, 0);
296
297        Self(value.0)
298    }
299}
300
301//---------------------------------------------------------------------------------------------------- RawChainId
302/// [`ChainId`] in a format which can be stored in the DB.
303///
304/// Implements [`Into`] and [`From`] for [`ChainId`].
305///
306/// # Size & Alignment
307/// ```rust
308/// # use cuprate_blockchain::types::*;
309/// assert_eq!(size_of::<RawChainId>(), 8);
310/// assert_eq!(align_of::<RawChainId>(), 8);
311/// ```
312#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
313#[repr(transparent)]
314pub struct RawChainId(pub(crate) u64);
315
316impl From<ChainId> for RawChainId {
317    fn from(value: ChainId) -> Self {
318        Self(value.0.get())
319    }
320}
321
322impl From<RawChainId> for ChainId {
323    fn from(value: RawChainId) -> Self {
324        Self(NonZero::new(value.0).expect("RawChainId cannot have a value of `0`"))
325    }
326}
327
328//---------------------------------------------------------------------------------------------------- AltChainInfo
329/// Information on an alternative chain.
330///
331/// # Size & Alignment
332/// ```rust
333/// # use cuprate_blockchain::types::*;
334/// assert_eq!(size_of::<AltChainInfo>(), 24);
335/// assert_eq!(align_of::<AltChainInfo>(), 8);
336/// ```
337#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
338#[repr(C)]
339pub struct AltChainInfo {
340    /// The chain this alt chain forks from.
341    pub parent_chain: RawChain,
342    /// The height of the first block we share with the parent chain.
343    pub common_ancestor_height: usize,
344    /// The chain height of the blocks in this alt chain.
345    pub chain_height: usize,
346}
347
348//---------------------------------------------------------------------------------------------------- AltBlockHeight
349/// Represents the height of a block on an alt-chain.
350///
351/// # Size & Alignment
352/// ```rust
353/// # use cuprate_blockchain::types::*;
354/// assert_eq!(size_of::<AltBlockHeight>(), 16);
355/// assert_eq!(align_of::<AltBlockHeight>(), 8);
356/// ```
357#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
358#[repr(C)]
359pub struct AltBlockHeight {
360    /// The [`ChainId`] of the chain this alt block is on, in raw form.
361    pub chain_id: RawChainId,
362    /// The height of this alt-block.
363    pub height: usize,
364}
365
366//---------------------------------------------------------------------------------------------------- CompactAltBlockInfo
367/// Represents information on an alt-chain.
368///
369/// # Size & Alignment
370/// ```rust
371/// # use cuprate_blockchain::types::*;
372/// assert_eq!(size_of::<CompactAltBlockInfo>(), 104);
373/// assert_eq!(align_of::<CompactAltBlockInfo>(), 8);
374/// ```
375#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
376#[repr(C)]
377pub struct CompactAltBlockInfo {
378    /// The block's hash.
379    pub block_hash: [u8; 32],
380    /// The block's proof-of-work hash.
381    pub pow_hash: [u8; 32],
382    /// The block's height.
383    pub height: usize,
384    /// The adjusted block size, in bytes.
385    pub weight: usize,
386    /// The long term block weight, which is the weight factored in with previous block weights.
387    pub long_term_weight: usize,
388    /// The low 64 bits of the cumulative difficulty.
389    pub cumulative_difficulty_low: u64,
390    /// The high 64 bits of the cumulative difficulty.
391    pub cumulative_difficulty_high: u64,
392}
393
394//---------------------------------------------------------------------------------------------------- AltTransactionInfo
395/// Represents information on an alt transaction.
396///
397/// # Size & Alignment
398/// ```rust
399/// # use cuprate_blockchain::types::*;
400/// assert_eq!(size_of::<AltTransactionInfo>(), 48);
401/// assert_eq!(align_of::<AltTransactionInfo>(), 8);
402/// ```
403#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
404#[repr(C)]
405pub struct AltTransactionInfo {
406    /// The transaction's weight.
407    pub tx_weight: usize,
408    /// The transaction's total fees.
409    pub fee: u64,
410    /// The transaction's hash.
411    pub tx_hash: [u8; 32],
412}
413
414//---------------------------------------------------------------------------------------------------- Tests
415#[cfg(test)]
416mod test {
417    // use super::*;
418}