/ ledger / block / src / transaction / bytes.rs
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  }