cuprate_blockchain/
types.rs

1//! Blockchain [table](crate::tables) 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
43//---------------------------------------------------------------------------------------------------- Import
44use std::num::NonZero;
45
46use bytemuck::{Pod, Zeroable};
47#[cfg(feature = "serde")]
48use serde::{Deserialize, Serialize};
49
50use cuprate_database::{Key, StorableVec};
51use cuprate_types::{Chain, ChainId};
52
53//---------------------------------------------------------------------------------------------------- Aliases
54// These type aliases exist as many Monero-related types are the exact same.
55// For clarity, they're given type aliases as to not confuse them.
56
57/// An output's amount.
58pub type Amount = u64;
59
60/// The index of an [`Amount`] in a list of duplicate `Amount`s.
61pub type AmountIndex = u64;
62
63/// A list of [`AmountIndex`]s.
64pub type AmountIndices = StorableVec<AmountIndex>;
65
66/// A serialized block.
67pub type BlockBlob = StorableVec<u8>;
68
69/// A serialized block header
70pub type BlockHeaderBlob = StorableVec<u8>;
71
72/// A block transaction hashes
73pub type BlockTxHashes = StorableVec<[u8; 32]>;
74
75/// A block's hash.
76pub type BlockHash = [u8; 32];
77
78/// A block's height.
79pub type BlockHeight = usize;
80
81/// A key image.
82pub type KeyImage = [u8; 32];
83
84/// Pruned serialized bytes.
85pub type PrunedBlob = StorableVec<u8>;
86
87/// A prunable serialized bytes.
88pub type PrunableBlob = StorableVec<u8>;
89
90/// A prunable hash.
91pub type PrunableHash = [u8; 32];
92
93/// A serialized transaction.
94pub type TxBlob = StorableVec<u8>;
95
96/// A transaction's global index, or ID.
97pub type TxId = u64;
98
99/// A transaction's hash.
100pub type TxHash = [u8; 32];
101
102/// The unlock time value of an output.
103pub type UnlockTime = u64;
104
105//---------------------------------------------------------------------------------------------------- BlockInfoV1
106/// A identifier for a pre-RCT [`Output`].
107///
108/// This can also serve as an identifier for [`RctOutput`]'s
109/// when [`PreRctOutputId::amount`] is set to `0`, although,
110/// in that case, only [`AmountIndex`] needs to be known.
111///
112/// This is the key to the [`Outputs`](crate::tables::Outputs) table.
113///
114/// ```rust
115/// # use std::borrow::*;
116/// # use cuprate_blockchain::{*, types::*};
117/// use cuprate_database::Storable;
118///
119/// // Assert Storable is correct.
120/// let a = PreRctOutputId {
121///     amount: 1,
122///     amount_index: 123,
123/// };
124/// let b = Storable::as_bytes(&a);
125/// let c: PreRctOutputId = Storable::from_bytes(b);
126/// assert_eq!(a, c);
127/// ```
128///
129/// # Size & Alignment
130/// ```rust
131/// # use cuprate_blockchain::types::*;
132/// assert_eq!(size_of::<PreRctOutputId>(), 16);
133/// assert_eq!(align_of::<PreRctOutputId>(), 8);
134/// ```
135#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
136#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
137#[repr(C)]
138pub struct PreRctOutputId {
139    /// Amount of the output.
140    ///
141    /// This should be `0` if the output is an [`RctOutput`].
142    pub amount: Amount,
143    /// The index of the output with the same `amount`.
144    ///
145    /// In the case of [`Output`]'s, this is the index of the list
146    /// of outputs with the same clear amount.
147    ///
148    /// In the case of [`RctOutput`]'s, this is the
149    /// global index of _all_ `RctOutput`s
150    pub amount_index: AmountIndex,
151}
152
153impl Key for PreRctOutputId {}
154
155//---------------------------------------------------------------------------------------------------- BlockInfoV3
156/// Block information.
157///
158/// This is the value in the [`BlockInfos`](crate::tables::BlockInfos) table.
159///
160/// ```rust
161/// # use std::borrow::*;
162/// # use cuprate_blockchain::{*, types::*};
163/// use cuprate_database::Storable;
164///
165/// // Assert Storable is correct.
166/// let a = BlockInfo {
167///     timestamp: 1,
168///     cumulative_generated_coins: 123,
169///     weight: 321,
170///     cumulative_difficulty_low: 112,
171///     cumulative_difficulty_high: 112,
172///     block_hash: [54; 32],
173///     cumulative_rct_outs: 2389,
174///     long_term_weight: 2389,
175///     mining_tx_index: 23
176/// };
177/// let b = Storable::as_bytes(&a);
178/// let c: BlockInfo = Storable::from_bytes(b);
179/// assert_eq!(a, c);
180/// ```
181///
182/// # Size & Alignment
183/// ```rust
184/// # use cuprate_blockchain::types::*;
185/// assert_eq!(size_of::<BlockInfo>(), 96);
186/// assert_eq!(align_of::<BlockInfo>(), 8);
187/// ```
188#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
189#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
190#[repr(C)]
191pub struct BlockInfo {
192    /// The UNIX time at which the block was mined.
193    pub timestamp: u64,
194    /// The total amount of coins mined in all blocks so far, including this block's.
195    pub cumulative_generated_coins: u64,
196    /// The adjusted block size, in bytes.
197    ///
198    /// See [`block_weight`](https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#blocks-weight).
199    pub weight: usize,
200    /// Least-significant 64 bits of the 128-bit cumulative difficulty.
201    pub cumulative_difficulty_low: u64,
202    /// Most-significant 64 bits of the 128-bit cumulative difficulty.
203    pub cumulative_difficulty_high: u64,
204    /// The block's hash.
205    pub block_hash: [u8; 32],
206    /// The total amount of RCT outputs so far, including this block's.
207    pub cumulative_rct_outs: u64,
208    /// The long term block weight, based on the median weight of the preceding `100_000` blocks.
209    ///
210    /// See [`long_term_weight`](https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#long-term-block-weight).
211    pub long_term_weight: usize,
212    /// [`TxId`] (u64) of the block coinbase transaction.
213    pub mining_tx_index: TxId,
214}
215
216//---------------------------------------------------------------------------------------------------- OutputFlags
217bitflags::bitflags! {
218    /// Bit flags for [`Output`]s and [`RctOutput`]s,
219    ///
220    /// Currently only the first bit is used and, if set,
221    /// it means this output has a non-zero unlock time.
222    ///
223    /// ```rust
224    /// # use std::borrow::*;
225    /// # use cuprate_blockchain::{*, types::*};
226    /// use cuprate_database::Storable;
227    ///
228    /// // Assert Storable is correct.
229    /// let a = OutputFlags::NON_ZERO_UNLOCK_TIME;
230    /// let b = Storable::as_bytes(&a);
231    /// let c: OutputFlags = Storable::from_bytes(b);
232    /// assert_eq!(a, c);
233    /// ```
234    ///
235    /// # Size & Alignment
236    /// ```rust
237    /// # use cuprate_blockchain::types::*;
238    /// assert_eq!(size_of::<OutputFlags>(), 4);
239    /// assert_eq!(align_of::<OutputFlags>(), 4);
240    /// ```
241    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
242    #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
243    #[repr(transparent)]
244    pub struct OutputFlags: u32 {
245        /// This output has a non-zero unlock time.
246        const NON_ZERO_UNLOCK_TIME = 0b0000_0001;
247    }
248}
249
250//---------------------------------------------------------------------------------------------------- Output
251/// A pre-RCT (v1) output's data.
252///
253/// ```rust
254/// # use std::borrow::*;
255/// # use cuprate_blockchain::{*, types::*};
256/// use cuprate_database::Storable;
257///
258/// // Assert Storable is correct.
259/// let a = Output {
260///     key: [1; 32],
261///     height: 1,
262///     output_flags: OutputFlags::empty(),
263///     tx_idx: 3,
264/// };
265/// let b = Storable::as_bytes(&a);
266/// let c: Output = Storable::from_bytes(b);
267/// assert_eq!(a, c);
268/// ```
269///
270/// # Size & Alignment
271/// ```rust
272/// # use cuprate_blockchain::types::*;
273/// assert_eq!(size_of::<Output>(), 48);
274/// assert_eq!(align_of::<Output>(), 8);
275/// ```
276#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
277#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
278#[repr(C)]
279pub struct Output {
280    /// The public key of the output.
281    pub key: [u8; 32],
282    /// The block height this output belongs to.
283    // PERF: We could get this from the tx_idx with the `TxHeights`
284    // table but that would require another look up per out.
285    pub height: u32,
286    /// Bit flags for this output.
287    pub output_flags: OutputFlags,
288    /// The index of the transaction this output belongs to.
289    pub tx_idx: u64,
290}
291
292//---------------------------------------------------------------------------------------------------- RctOutput
293/// An RCT (v2+) output's data.
294///
295/// ```rust
296/// # use std::borrow::*;
297/// # use cuprate_blockchain::{*, types::*};
298/// use cuprate_database::Storable;
299///
300/// // Assert Storable is correct.
301/// let a = RctOutput {
302///     key: [1; 32],
303///     height: 1,
304///     output_flags: OutputFlags::empty(),
305///     tx_idx: 3,
306///     commitment: [3; 32],
307/// };
308/// let b = Storable::as_bytes(&a);
309/// let c: RctOutput = Storable::from_bytes(b);
310/// assert_eq!(a, c);
311/// ```
312///
313/// # Size & Alignment
314/// ```rust
315/// # use cuprate_blockchain::types::*;
316/// assert_eq!(size_of::<RctOutput>(), 80);
317/// assert_eq!(align_of::<RctOutput>(), 8);
318/// ```
319#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
320#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
321#[repr(C)]
322pub struct RctOutput {
323    /// The public key of the output.
324    pub key: [u8; 32],
325    /// The block height this output belongs to.
326    // PERF: We could get this from the tx_idx with the `TxHeights`
327    // table but that would require another look up per out.
328    pub height: u32,
329    /// Bit flags for this output, currently only the first bit is used and, if set, it means this output has a non-zero unlock time.
330    pub output_flags: OutputFlags,
331    /// The index of the transaction this output belongs to.
332    pub tx_idx: u64,
333    /// The amount commitment of this output.
334    pub commitment: [u8; 32],
335}
336// TODO: local_index?
337
338//---------------------------------------------------------------------------------------------------- RawChain
339/// [`Chain`] in a format which can be stored in the DB.
340///
341/// Implements [`Into`] and [`From`] for [`Chain`].
342///
343/// ```rust
344/// # use std::borrow::*;
345/// # use cuprate_blockchain::{*, types::*};
346/// use cuprate_database::Storable;
347/// use cuprate_types::Chain;
348///
349/// // Assert Storable is correct.
350/// let a: RawChain = Chain::Main.into();
351/// let b = Storable::as_bytes(&a);
352/// let c: RawChain = Storable::from_bytes(b);
353/// assert_eq!(a, c);
354/// ```
355///
356/// # Size & Alignment
357/// ```rust
358/// # use cuprate_blockchain::types::*;
359/// assert_eq!(size_of::<RawChain>(), 8);
360/// assert_eq!(align_of::<RawChain>(), 8);
361/// ```
362#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
363#[repr(transparent)]
364pub struct RawChain(u64);
365
366impl From<Chain> for RawChain {
367    fn from(value: Chain) -> Self {
368        match value {
369            Chain::Main => Self(0),
370            Chain::Alt(chain_id) => Self(chain_id.0.get()),
371        }
372    }
373}
374
375impl From<RawChain> for Chain {
376    fn from(value: RawChain) -> Self {
377        NonZero::new(value.0).map_or(Self::Main, |id| Self::Alt(ChainId(id)))
378    }
379}
380
381impl From<RawChainId> for RawChain {
382    fn from(value: RawChainId) -> Self {
383        // A [`ChainID`] with an inner value of `0` is invalid.
384        assert_ne!(value.0, 0);
385
386        Self(value.0)
387    }
388}
389
390//---------------------------------------------------------------------------------------------------- RawChainId
391/// [`ChainId`] in a format which can be stored in the DB.
392///
393/// Implements [`Into`] and [`From`] for [`ChainId`].
394///
395/// ```rust
396/// # use std::borrow::*;
397/// # use cuprate_blockchain::{*, types::*};
398/// use cuprate_database::Storable;
399/// use cuprate_types::ChainId;
400///
401/// // Assert Storable is correct.
402/// let a: RawChainId = ChainId(10.try_into().unwrap()).into();
403/// let b = Storable::as_bytes(&a);
404/// let c: RawChainId = Storable::from_bytes(b);
405/// assert_eq!(a, c);
406/// ```
407///
408/// # Size & Alignment
409/// ```rust
410/// # use cuprate_blockchain::types::*;
411/// assert_eq!(size_of::<RawChainId>(), 8);
412/// assert_eq!(align_of::<RawChainId>(), 8);
413/// ```
414#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
415#[repr(transparent)]
416pub struct RawChainId(u64);
417
418impl From<ChainId> for RawChainId {
419    fn from(value: ChainId) -> Self {
420        Self(value.0.get())
421    }
422}
423
424impl From<RawChainId> for ChainId {
425    fn from(value: RawChainId) -> Self {
426        Self(NonZero::new(value.0).expect("RawChainId cannot have a value of `0`"))
427    }
428}
429
430impl Key for RawChainId {}
431
432//---------------------------------------------------------------------------------------------------- AltChainInfo
433/// Information on an alternative chain.
434///
435/// ```rust
436/// # use std::borrow::*;
437/// # use cuprate_blockchain::{*, types::*};
438/// use cuprate_database::Storable;
439/// use cuprate_types::Chain;
440///
441/// // Assert Storable is correct.
442/// let a: AltChainInfo = AltChainInfo {
443///     parent_chain: Chain::Main.into(),
444///     common_ancestor_height: 0,
445///     chain_height: 1,
446/// };
447/// let b = Storable::as_bytes(&a);
448/// let c: AltChainInfo = Storable::from_bytes(b);
449/// assert_eq!(a, c);
450/// ```
451///
452/// # Size & Alignment
453/// ```rust
454/// # use cuprate_blockchain::types::*;
455/// assert_eq!(size_of::<AltChainInfo>(), 24);
456/// assert_eq!(align_of::<AltChainInfo>(), 8);
457/// ```
458#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
459#[repr(C)]
460pub struct AltChainInfo {
461    /// The chain this alt chain forks from.
462    pub parent_chain: RawChain,
463    /// The height of the first block we share with the parent chain.
464    pub common_ancestor_height: usize,
465    /// The chain height of the blocks in this alt chain.
466    pub chain_height: usize,
467}
468
469//---------------------------------------------------------------------------------------------------- AltBlockHeight
470/// Represents the height of a block on an alt-chain.
471///
472/// ```rust
473/// # use std::borrow::*;
474/// # use cuprate_blockchain::{*, types::*};
475/// use cuprate_database::Storable;
476/// use cuprate_types::ChainId;
477///
478/// // Assert Storable is correct.
479/// let a: AltBlockHeight = AltBlockHeight {
480///     chain_id: ChainId(1.try_into().unwrap()).into(),
481///     height: 1,
482/// };
483/// let b = Storable::as_bytes(&a);
484/// let c: AltBlockHeight = Storable::from_bytes(b);
485/// assert_eq!(a, c);
486/// ```
487///
488/// # Size & Alignment
489/// ```rust
490/// # use cuprate_blockchain::types::*;
491/// assert_eq!(size_of::<AltBlockHeight>(), 16);
492/// assert_eq!(align_of::<AltBlockHeight>(), 8);
493/// ```
494#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
495#[repr(C)]
496pub struct AltBlockHeight {
497    /// The [`ChainId`] of the chain this alt block is on, in raw form.
498    pub chain_id: RawChainId,
499    /// The height of this alt-block.
500    pub height: usize,
501}
502
503impl Key for AltBlockHeight {}
504
505//---------------------------------------------------------------------------------------------------- CompactAltBlockInfo
506/// Represents information on an alt-chain.
507///
508/// ```rust
509/// # use std::borrow::*;
510/// # use cuprate_blockchain::{*, types::*};
511/// use cuprate_database::Storable;
512///
513/// // Assert Storable is correct.
514/// let a: CompactAltBlockInfo = CompactAltBlockInfo {
515///     block_hash: [1; 32],
516///     pow_hash: [2; 32],
517///     height: 10,
518///     weight: 20,
519///     long_term_weight: 30,
520///     cumulative_difficulty_low: 40,
521///     cumulative_difficulty_high: 50,
522/// };
523///     
524/// let b = Storable::as_bytes(&a);
525/// let c: CompactAltBlockInfo = Storable::from_bytes(b);
526/// assert_eq!(a, c);
527/// ```
528///
529/// # Size & Alignment
530/// ```rust
531/// # use cuprate_blockchain::types::*;
532/// assert_eq!(size_of::<CompactAltBlockInfo>(), 104);
533/// assert_eq!(align_of::<CompactAltBlockInfo>(), 8);
534/// ```
535#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
536#[repr(C)]
537pub struct CompactAltBlockInfo {
538    /// The block's hash.
539    pub block_hash: [u8; 32],
540    /// The block's proof-of-work hash.
541    pub pow_hash: [u8; 32],
542    /// The block's height.
543    pub height: usize,
544    /// The adjusted block size, in bytes.
545    pub weight: usize,
546    /// The long term block weight, which is the weight factored in with previous block weights.
547    pub long_term_weight: usize,
548    /// The low 64 bits of the cumulative difficulty.
549    pub cumulative_difficulty_low: u64,
550    /// The high 64 bits of the cumulative difficulty.
551    pub cumulative_difficulty_high: u64,
552}
553
554//---------------------------------------------------------------------------------------------------- AltTransactionInfo
555/// Represents information on an alt transaction.
556///
557/// ```rust
558/// # use std::borrow::*;
559/// # use cuprate_blockchain::{*, types::*};
560/// use cuprate_database::Storable;
561///
562/// // Assert Storable is correct.
563/// let a: AltTransactionInfo = AltTransactionInfo {
564///     tx_weight: 1,
565///     fee: 6,
566///     tx_hash: [6; 32],
567/// };
568///     
569/// let b = Storable::as_bytes(&a);
570/// let c: AltTransactionInfo = Storable::from_bytes(b);
571/// assert_eq!(a, c);
572/// ```
573///
574/// # Size & Alignment
575/// ```rust
576/// # use cuprate_blockchain::types::*;
577/// assert_eq!(size_of::<AltTransactionInfo>(), 48);
578/// assert_eq!(align_of::<AltTransactionInfo>(), 8);
579/// ```
580#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Pod, Zeroable)]
581#[repr(C)]
582pub struct AltTransactionInfo {
583    /// The transaction's weight.
584    pub tx_weight: usize,
585    /// The transaction's total fees.
586    pub fee: u64,
587    /// The transaction's hash.
588    pub tx_hash: [u8; 32],
589}
590
591//---------------------------------------------------------------------------------------------------- Tests
592#[cfg(test)]
593mod test {
594    // use super::*;
595}