espresso_types/v0/impls/
transaction.rs

1use committable::{Commitment, Committable};
2use hotshot_query_service::explorer::ExplorerTransaction;
3use hotshot_types::traits::block_contents::Transaction as HotShotTransaction;
4use serde::{de::Error, Deserialize, Deserializer};
5
6use super::NsPayloadBuilder;
7use crate::{NamespaceId, SeqTypes, Transaction};
8
9impl From<u32> for NamespaceId {
10    fn from(value: u32) -> Self {
11        Self(value as u64)
12    }
13}
14
15impl From<NamespaceId> for u32 {
16    fn from(value: NamespaceId) -> Self {
17        value.0 as Self
18    }
19}
20
21impl From<i64> for NamespaceId {
22    fn from(value: i64) -> Self {
23        Self(value as u64)
24    }
25}
26
27impl From<NamespaceId> for i64 {
28    fn from(value: NamespaceId) -> Self {
29        value.0 as Self
30    }
31}
32
33impl<'de> Deserialize<'de> for NamespaceId {
34    fn deserialize<D>(deserializer: D) -> Result<NamespaceId, D::Error>
35    where
36        D: Deserializer<'de>,
37    {
38        use serde::de::Unexpected;
39
40        let ns_id = <u64 as Deserialize>::deserialize(deserializer)?;
41        if ns_id > u32::MAX as u64 {
42            Err(D::Error::invalid_value(
43                Unexpected::Unsigned(ns_id),
44                &"at most u32::MAX",
45            ))
46        } else {
47            Ok(NamespaceId(ns_id))
48        }
49    }
50}
51
52impl NamespaceId {
53    #[cfg(any(test, feature = "testing"))]
54    pub fn random(rng: &mut dyn rand::RngCore) -> Self {
55        Self(rng.next_u32() as u64)
56    }
57}
58
59impl Transaction {
60    pub fn new(namespace: NamespaceId, payload: Vec<u8>) -> Self {
61        Self { namespace, payload }
62    }
63
64    pub fn namespace(&self) -> NamespaceId {
65        self.namespace
66    }
67
68    pub fn payload(&self) -> &[u8] {
69        &self.payload
70    }
71
72    pub fn into_payload(self) -> Vec<u8> {
73        self.payload
74    }
75
76    pub fn size_in_block(&self, new_ns: bool) -> u64 {
77        if new_ns {
78            // each new namespace adds overhead
79            self.minimum_block_size()
80        } else {
81            (self.payload().len() + NsPayloadBuilder::tx_table_entry_byte_len()) as u64
82        }
83    }
84
85    #[cfg(any(test, feature = "testing"))]
86    pub fn random(rng: &mut dyn rand::RngCore) -> Self {
87        use rand::Rng;
88        let len = rng.gen_range(0..100);
89        Self::new(
90            NamespaceId::random(rng),
91            (0..len).map(|_| rand::random::<u8>()).collect::<Vec<_>>(),
92        )
93    }
94    #[cfg(any(test, feature = "testing"))]
95    /// Useful for when we want to test size of transaction(s)
96    pub fn of_size(len: usize) -> Self {
97        Self::new(
98            NamespaceId(1),
99            (0..len).map(|_| rand::random::<u8>()).collect::<Vec<_>>(),
100        )
101    }
102}
103
104impl HotShotTransaction for Transaction {
105    fn minimum_block_size(&self) -> u64 {
106        // Any block containing this transaction will have at least:
107        let len =
108            // bytes for the payload of the transaction itself
109            self.payload().len()
110            // a transaction table entry in the transaction's namespace payload
111            + NsPayloadBuilder::tx_table_entry_byte_len()
112            // a header of the transaction table in the transaction's namespace payload
113            + NsPayloadBuilder::tx_table_header_byte_len();
114        // The block will also have an entry in the namespace table for the transaction's namespace;
115        // however this takes up space in the header, not the payload, so doesn't count against the
116        // size of the block.
117
118        len as u64
119    }
120}
121
122impl Committable for Transaction {
123    fn commit(&self) -> Commitment<Self> {
124        committable::RawCommitmentBuilder::new("Transaction")
125            .u64_field("namespace", self.namespace.0)
126            .var_size_bytes(&self.payload)
127            .finalize()
128    }
129
130    fn tag() -> String {
131        "TX".into()
132    }
133}
134
135impl ExplorerTransaction<SeqTypes> for Transaction {
136    fn namespace_id(&self) -> NamespaceId {
137        self.namespace
138    }
139
140    fn payload_size(&self) -> u64 {
141        self.payload.len() as u64
142    }
143}