snarkos_node_router_messages/
unconfirmed_transaction.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkOS library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18use snarkvm::{
19    ledger::narwhal::Data,
20    prelude::{FromBytes, ToBytes},
21};
22
23use std::borrow::Cow;
24
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct UnconfirmedTransaction<N: Network> {
27    pub transaction_id: N::TransactionID,
28    pub transaction: Data<Transaction<N>>,
29}
30
31impl<N: Network> From<Transaction<N>> for UnconfirmedTransaction<N> {
32    /// Initializes a new `UnconfirmedTransaction` message.
33    fn from(transaction: Transaction<N>) -> Self {
34        Self { transaction_id: transaction.id(), transaction: Data::Object(transaction) }
35    }
36}
37
38impl<N: Network> MessageTrait for UnconfirmedTransaction<N> {
39    /// Returns the message name.
40    #[inline]
41    fn name(&self) -> Cow<'static, str> {
42        "UnconfirmedTransaction".into()
43    }
44}
45
46impl<N: Network> ToBytes for UnconfirmedTransaction<N> {
47    fn write_le<W: io::Write>(&self, mut writer: W) -> io::Result<()> {
48        self.transaction_id.write_le(&mut writer)?;
49        self.transaction.write_le(&mut writer)?;
50        Ok(())
51    }
52}
53
54impl<N: Network> FromBytes for UnconfirmedTransaction<N> {
55    fn read_le<R: io::Read>(mut reader: R) -> io::Result<Self> {
56        Ok(Self { transaction_id: N::TransactionID::read_le(&mut reader)?, transaction: Data::read_le(reader)? })
57    }
58}
59
60#[cfg(test)]
61pub mod prop_tests {
62    use crate::{Transaction, UnconfirmedTransaction};
63    use snarkvm::{
64        ledger::{
65            narwhal::Data,
66            test_helpers::{sample_fee_public_transaction, sample_large_execution_transaction},
67        },
68        prelude::{FromBytes, TestRng, ToBytes},
69    };
70
71    use bytes::{Buf, BufMut, BytesMut};
72    use proptest::prelude::{BoxedStrategy, Strategy, any};
73    use test_strategy::proptest;
74
75    type CurrentNetwork = snarkvm::prelude::MainnetV0;
76
77    pub fn any_transaction() -> BoxedStrategy<Transaction<CurrentNetwork>> {
78        any::<u64>()
79            .prop_map(|seed| {
80                let mut rng = TestRng::fixed(seed);
81                sample_fee_public_transaction(&mut rng)
82            })
83            .boxed()
84    }
85
86    pub fn any_large_transaction() -> BoxedStrategy<Transaction<CurrentNetwork>> {
87        any::<u64>()
88            .prop_map(|seed| {
89                let mut rng = TestRng::fixed(seed);
90                sample_large_execution_transaction(&mut rng)
91            })
92            .boxed()
93    }
94
95    pub fn any_unconfirmed_transaction() -> BoxedStrategy<UnconfirmedTransaction<CurrentNetwork>> {
96        any_transaction()
97            .prop_map(|tx| UnconfirmedTransaction { transaction_id: tx.id(), transaction: Data::Object(tx) })
98            .boxed()
99    }
100
101    pub fn any_large_unconfirmed_transaction() -> BoxedStrategy<UnconfirmedTransaction<CurrentNetwork>> {
102        any_large_transaction()
103            .prop_map(|tx| UnconfirmedTransaction { transaction_id: tx.id(), transaction: Data::Object(tx) })
104            .boxed()
105    }
106
107    #[proptest]
108    fn unconfirmed_transaction_roundtrip(
109        #[strategy(any_unconfirmed_transaction())] original: UnconfirmedTransaction<CurrentNetwork>,
110    ) {
111        let mut buf = BytesMut::default().writer();
112        UnconfirmedTransaction::write_le(&original, &mut buf).unwrap();
113
114        let deserialized: UnconfirmedTransaction<CurrentNetwork> =
115            UnconfirmedTransaction::read_le(buf.into_inner().reader()).unwrap();
116        assert_eq!(original.transaction_id, deserialized.transaction_id);
117        assert_eq!(
118            original.transaction.deserialize_blocking().unwrap(),
119            deserialized.transaction.deserialize_blocking().unwrap(),
120        );
121    }
122}