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, NsTableBuilder};
7use crate::{NamespaceId, 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<'de> Deserialize<'de> for NamespaceId {
22    fn deserialize<D>(deserializer: D) -> Result<NamespaceId, D::Error>
23    where
24        D: Deserializer<'de>,
25    {
26        use serde::de::Unexpected;
27
28        let ns_id = <u64 as Deserialize>::deserialize(deserializer)?;
29        if ns_id > u32::MAX as u64 {
30            Err(D::Error::invalid_value(
31                Unexpected::Unsigned(ns_id),
32                &"at most u32::MAX",
33            ))
34        } else {
35            Ok(NamespaceId(ns_id))
36        }
37    }
38}
39
40impl NamespaceId {
41    #[cfg(any(test, feature = "testing"))]
42    pub fn random(rng: &mut dyn rand::RngCore) -> Self {
43        Self(rng.next_u32() as u64)
44    }
45}
46
47impl Transaction {
48    pub fn new(namespace: NamespaceId, payload: Vec<u8>) -> Self {
49        Self { namespace, payload }
50    }
51
52    pub fn namespace(&self) -> NamespaceId {
53        self.namespace
54    }
55
56    pub fn payload(&self) -> &[u8] {
57        &self.payload
58    }
59
60    pub fn into_payload(self) -> Vec<u8> {
61        self.payload
62    }
63
64    pub fn size_in_block(&self, new_ns: bool) -> u64 {
65        if new_ns {
66            // each new namespace adds overhead
67            // here self.minimum_block_size() = `self.payload().len() + NsPayloadBuilder::tx_table_entry_byte_len() + NsTableBuilder::entry_byte_len() + NsPayloadBuilder::tx_table_header_byte_len()`
68            self.minimum_block_size()
69        } else {
70            (self.payload().len() + NsPayloadBuilder::tx_table_entry_byte_len()) as u64
71        }
72    }
73
74    #[cfg(any(test, feature = "testing"))]
75    pub fn random(rng: &mut dyn rand::RngCore) -> Self {
76        use rand::Rng;
77        let len = rng.gen_range(0..100);
78        Self::new(
79            NamespaceId::random(rng),
80            (0..len).map(|_| rand::random::<u8>()).collect::<Vec<_>>(),
81        )
82    }
83    #[cfg(any(test, feature = "testing"))]
84    /// Useful for when we want to test size of transaction(s)
85    pub fn of_size(len: usize) -> Self {
86        Self::new(
87            NamespaceId(1),
88            (0..len).map(|_| rand::random::<u8>()).collect::<Vec<_>>(),
89        )
90    }
91}
92
93impl HotShotTransaction for Transaction {
94    fn minimum_block_size(&self) -> u64 {
95        let len = self.payload().len()
96            + NsPayloadBuilder::tx_table_entry_byte_len()
97            + NsTableBuilder::entry_byte_len()
98            + NsPayloadBuilder::tx_table_header_byte_len();
99        len as u64
100    }
101}
102
103impl Committable for Transaction {
104    fn commit(&self) -> Commitment<Self> {
105        committable::RawCommitmentBuilder::new("Transaction")
106            .u64_field("namespace", self.namespace.0)
107            .var_size_bytes(&self.payload)
108            .finalize()
109    }
110
111    fn tag() -> String {
112        "TX".into()
113    }
114}
115
116impl ExplorerTransaction for Transaction {
117    type NamespaceId = NamespaceId;
118    fn namespace_id(&self) -> Self::NamespaceId {
119        self.namespace
120    }
121
122    fn payload_size(&self) -> u64 {
123        self.payload.len() as u64
124    }
125}