Skip to main content

cuprate_types/
block_complete_entry.rs

1//! Contains [`BlockCompleteEntry`] and the related types.
2
3//---------------------------------------------------------------------------------------------------- Import
4use bytes::Bytes;
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use cuprate_fixed_bytes::ByteArray;
10
11#[cfg(feature = "epee")]
12use cuprate_epee_encoding::{
13    epee_object,
14    macros::bytes::{Buf, BufMut},
15    EpeeValue, InnerMarker,
16};
17
18//---------------------------------------------------------------------------------------------------- BlockCompleteEntry
19/// A block that can contain transactions.
20///
21/// # Warning
22///
23/// This struct has a large in-memory size compared to its smallest valid encoding.
24/// You will need to add safety limits if this is stored in a Vec.
25#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
26#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27pub struct BlockCompleteEntry {
28    /// `true` if transaction data is pruned.
29    pub pruned: bool,
30    /// The block.
31    pub block: Bytes,
32    /// The block weight/size.
33    pub block_weight: u64,
34    /// The block's transactions.
35    pub txs: TransactionBlobs,
36}
37
38#[cfg(feature = "epee")]
39epee_object!(
40    BlockCompleteEntry,
41    pruned: bool = false,
42    block: Bytes,
43    block_weight: u64 = 0_u64,
44    txs: TransactionBlobs = TransactionBlobs::None =>
45        TransactionBlobs::tx_blob_read,
46        TransactionBlobs::tx_blob_write,
47        TransactionBlobs::should_write_tx_blobs,
48);
49
50//---------------------------------------------------------------------------------------------------- TransactionBlobs
51/// Transaction blobs within [`BlockCompleteEntry`].
52#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
53#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
54pub enum TransactionBlobs {
55    /// Pruned transaction blobs.
56    Pruned(Vec<PrunedTxBlobEntry>),
57    /// Normal transaction blobs.
58    Normal(Vec<Bytes>),
59    #[default]
60    /// No transactions.
61    None,
62}
63
64impl TransactionBlobs {
65    /// Returns [`Some`] if `self` is [`Self::Pruned`].
66    pub fn take_pruned(self) -> Option<Vec<PrunedTxBlobEntry>> {
67        match self {
68            Self::Normal(_) => None,
69            Self::Pruned(txs) => Some(txs),
70            Self::None => Some(vec![]),
71        }
72    }
73
74    /// Returns [`Some`] if `self` is [`Self::Normal`].
75    pub fn take_normal(self) -> Option<Vec<Bytes>> {
76        match self {
77            Self::Normal(txs) => Some(txs),
78            Self::Pruned(_) => None,
79            Self::None => Some(vec![]),
80        }
81    }
82
83    /// Returns the byte length of the blob.
84    pub const fn len(&self) -> usize {
85        match self {
86            Self::Normal(txs) => txs.len(),
87            Self::Pruned(txs) => txs.len(),
88            Self::None => 0,
89        }
90    }
91
92    /// Returns `true` if the byte length of the blob is `0`.
93    pub const fn is_empty(&self) -> bool {
94        self.len() == 0
95    }
96
97    /// Epee read function.
98    #[cfg(feature = "epee")]
99    fn tx_blob_read<B: Buf>(
100        b: &mut B,
101        _: cuprate_epee_encoding::EpeeValueLimits,
102    ) -> cuprate_epee_encoding::Result<Self> {
103        let limits = cuprate_epee_encoding::EpeeValueLimits {
104            // This is the size of `Bytes` on the stack, no tx can be this small. We could set a limit
105            // higher than 32 but 32 gives us enough protection.
106            min_element_size: 32,
107            // TODO: set to max txs in a block, but for now this is safe.
108            max_sequence_len: usize::MAX,
109        };
110
111        let marker = cuprate_epee_encoding::read_marker(b)?;
112        match marker.inner_marker {
113            InnerMarker::Object => Ok(Self::Pruned(Vec::read(b, &marker, limits)?)),
114            InnerMarker::String => Ok(Self::Normal(Vec::read(b, &marker, limits)?)),
115            InnerMarker::I64
116            | InnerMarker::I32
117            | InnerMarker::I16
118            | InnerMarker::I8
119            | InnerMarker::U64
120            | InnerMarker::U32
121            | InnerMarker::U16
122            | InnerMarker::U8
123            | InnerMarker::F64
124            | InnerMarker::Bool => Err(cuprate_epee_encoding::Error::Value(
125                "Invalid marker for tx blobs".to_string(),
126            )),
127        }
128    }
129
130    /// Epee write function.
131    #[cfg(feature = "epee")]
132    fn tx_blob_write<B: BufMut>(
133        self,
134        field_name: &str,
135        w: &mut B,
136    ) -> cuprate_epee_encoding::Result<()> {
137        if self.should_write_tx_blobs() {
138            match self {
139                Self::Normal(bytes) => {
140                    cuprate_epee_encoding::write_field(bytes, field_name, w)?;
141                }
142                Self::Pruned(obj) => {
143                    cuprate_epee_encoding::write_field(obj, field_name, w)?;
144                }
145                Self::None => (),
146            }
147        }
148        Ok(())
149    }
150
151    /// Epee should write function.
152    #[cfg(feature = "epee")]
153    const fn should_write_tx_blobs(&self) -> bool {
154        !self.is_empty()
155    }
156}
157
158//---------------------------------------------------------------------------------------------------- PrunedTxBlobEntry
159/// A pruned transaction with the hash of the missing prunable data
160#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
161#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
162pub struct PrunedTxBlobEntry {
163    /// The transaction.
164    pub blob: Bytes,
165    /// The prunable transaction hash.
166    pub prunable_hash: ByteArray<32>,
167}
168
169#[cfg(feature = "epee")]
170epee_object!(
171    PrunedTxBlobEntry,
172    blob: Bytes,
173    prunable_hash: ByteArray<32>,
174);
175
176//---------------------------------------------------------------------------------------------------- Import
177#[cfg(test)]
178mod tests {}