unconfirmed_transaction.rs
1 // Copyright (c) 2025 ADnet Contributors 2 // This file is part of the AlphaOS 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 16 use super::*; 17 18 use alphavm::{ 19 ledger::narwhal::Data, 20 prelude::{FromBytes, ToBytes}, 21 }; 22 23 use std::borrow::Cow; 24 25 #[derive(Clone, Debug, PartialEq, Eq)] 26 pub struct UnconfirmedTransaction<N: Network> { 27 pub transaction_id: N::TransactionID, 28 pub transaction: Data<Transaction<N>>, 29 } 30 31 impl<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 38 impl<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 46 impl<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 54 impl<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)] 61 pub mod prop_tests { 62 use crate::{Transaction, UnconfirmedTransaction}; 63 use alphavm::{ 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 = alphavm::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 }