bytes.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the deltavm 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 impl<N: Network> FromBytes for Transaction<N> { 19 /// Reads the transaction from the buffer. 20 #[inline] 21 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> { 22 // Read the version. 23 let version = u8::read_le(&mut reader)?; 24 // Ensure the version is valid. 25 if version != 1 { 26 return Err(error("Invalid transaction version")); 27 } 28 29 // Read the variant. 30 let variant = u8::read_le(&mut reader)?; 31 // Match the variant. 32 let (id, transaction) = match variant { 33 0 => { 34 // Read the ID. 35 let id = N::TransactionID::read_le(&mut reader)?; 36 // Read the owner. 37 let owner = ProgramOwner::read_le(&mut reader)?; 38 // Read the deployment. 39 let deployment = Deployment::read_le(&mut reader)?; 40 // Read the fee. 41 let fee = Fee::read_le(&mut reader)?; 42 43 // Initialize the transaction. 44 let transaction = Self::from_deployment(owner, deployment, fee).map_err(|e| error(e.to_string()))?; 45 // Return the ID and the transaction. 46 (id, transaction) 47 } 48 1 => { 49 // Read the ID. 50 let id = N::TransactionID::read_le(&mut reader)?; 51 // Read the execution. 52 let execution = Execution::read_le(&mut reader)?; 53 54 // Read the fee variant. 55 let fee_variant = u8::read_le(&mut reader)?; 56 // Read the fee. 57 let fee = match fee_variant { 58 0u8 => None, 59 1u8 => Some(Fee::read_le(&mut reader)?), 60 _ => return Err(error("Invalid fee variant")), 61 }; 62 63 // Initialize the transaction. 64 let transaction = Self::from_execution(execution, fee).map_err(|e| error(e.to_string()))?; 65 // Return the ID and the transaction. 66 (id, transaction) 67 } 68 2 => { 69 // Read the ID. 70 let id = N::TransactionID::read_le(&mut reader)?; 71 // Read the fee. 72 let fee = Fee::read_le(&mut reader)?; 73 74 // Initialize the transaction. 75 let transaction = Self::from_fee(fee).map_err(|e| error(e.to_string()))?; 76 // Return the ID and the transaction. 77 (id, transaction) 78 } 79 3.. => return Err(error("Invalid transaction variant")), 80 }; 81 82 // Ensure the transaction ID matches. 83 match transaction.id() == id { 84 // Return the transaction. 85 true => Ok(transaction), 86 false => Err(error("Transaction ID mismatch")), 87 } 88 } 89 } 90 91 impl<N: Network> ToBytes for Transaction<N> { 92 /// Writes the transaction to the buffer. 93 #[inline] 94 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> { 95 // Write the version. 96 1u8.write_le(&mut writer)?; 97 98 // Write the transaction. 99 // Note: We purposefully do not write out the deployment or execution ID, 100 // and instead recompute it when reconstructing the transaction, to ensure there was no malleability. 101 match self { 102 Self::Deploy(id, _, owner, deployment, fee) => { 103 // Write the variant. 104 0u8.write_le(&mut writer)?; 105 // Write the ID. 106 id.write_le(&mut writer)?; 107 // Write the owner. 108 owner.write_le(&mut writer)?; 109 // Write the deployment. 110 deployment.write_le(&mut writer)?; 111 // Write the fee. 112 fee.write_le(&mut writer) 113 } 114 Self::Execute(id, _, execution, fee) => { 115 // Write the variant. 116 1u8.write_le(&mut writer)?; 117 // Write the ID. 118 id.write_le(&mut writer)?; 119 // Write the execution. 120 execution.write_le(&mut writer)?; 121 // Write the fee. 122 match fee { 123 None => 0u8.write_le(&mut writer), 124 Some(fee) => { 125 1u8.write_le(&mut writer)?; 126 fee.write_le(&mut writer) 127 } 128 } 129 } 130 Self::Fee(id, fee) => { 131 // Write the variant. 132 2u8.write_le(&mut writer)?; 133 // Write the ID. 134 id.write_le(&mut writer)?; 135 // Write the fee. 136 fee.write_le(&mut writer) 137 } 138 } 139 } 140 } 141 142 #[cfg(test)] 143 mod tests { 144 use super::*; 145 146 #[test] 147 fn test_bytes() -> Result<()> { 148 let rng = &mut TestRng::default(); 149 150 for expected in [ 151 crate::transaction::test_helpers::sample_deployment_transaction(1, Uniform::rand(rng), true, rng), 152 crate::transaction::test_helpers::sample_deployment_transaction(1, Uniform::rand(rng), false, rng), 153 crate::transaction::test_helpers::sample_deployment_transaction(2, Uniform::rand(rng), true, rng), 154 crate::transaction::test_helpers::sample_deployment_transaction(2, Uniform::rand(rng), false, rng), 155 crate::transaction::test_helpers::sample_execution_transaction_with_fee(true, rng, 0), 156 crate::transaction::test_helpers::sample_execution_transaction_with_fee(false, rng, 0), 157 ] 158 .into_iter() 159 { 160 // Check the byte representation. 161 let expected_bytes = expected.to_bytes_le()?; 162 assert_eq!(expected, Transaction::read_le(&expected_bytes[..])?); 163 } 164 Ok(()) 165 } 166 }