catbuffer_rust/
aggregate_transaction_body_builder.rs

1/*
2 * // Copyright (c) 2016-2019, Jaguar0625, gimre, BloodyRookie, Tech Bureau, Corp.
3 * // Copyright (c) 2020-present, Jaguar0625, gimre, BloodyRookie.
4 * // All rights reserved.
5 * //
6 * // This file is part of Catapult.
7 * //
8 * // Catapult is free software: you can redistribute it and/or modify
9 * // it under the terms of the GNU Lesser General Public License as published by
10 * // the Free Software Foundation, either version 3 of the License, or
11 * // (at your option) any later version.
12 * //
13 * // Catapult is distributed in the hope that it will be useful,
14 * // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * // GNU Lesser General Public License for more details.
17 * //
18 * // You should have received a copy of the GNU Lesser General Public License
19 * // along with Catapult. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22use super::cosignature_builder::*;
23use super::embedded_transaction_builder::*;
24use super::embedded_transaction_helper::*;
25use super::generator_utils::*;
26use super::hash256_dto::*;
27
28/// Binary layout for an aggregate transaction.
29#[derive(Debug, Clone)]
30pub struct AggregateTransactionBodyBuilder {
31    /// Aggregate hash of an aggregate's transactions.
32    pub transactions_hash: Hash256Dto,
33    /// Sub-transaction data (transactions are variable sized and payload size is in bytes).
34    pub transactions: Vec<Box<dyn EmbeddedTransactionHelper + 'static>>,
35    /// Cosignatures data (fills remaining body space after transactions).
36    pub cosignatures: Vec<CosignatureBuilder>,
37}
38
39impl AggregateTransactionBodyBuilder {
40    fn load_embedded_transactions(transactions: &mut Vec<Box<dyn EmbeddedTransactionHelper + 'static>>, mut payload: Vec<u8>, payload_size: u32) -> Vec<u8> {
41        let mut remaining_byte_sizes = payload_size as usize;
42        while remaining_byte_sizes > 0 {
43            let item = load_from_binary(&payload);
44            transactions.push(item.clone());
45            let size = item.get_size();
46            let item_size = size + Self::get_padding_size(item.get_size(), 8);
47            remaining_byte_sizes -= item_size;
48            payload = (&payload[item_size..]).to_vec();
49        }
50        payload
51    }
52
53    fn load_cosignatures(transactions: &mut Vec<CosignatureBuilder>, mut payload: Vec<u8>, payload_size: usize) -> Vec<u8> {
54        let mut remaining_byte_sizes = payload_size;
55        while remaining_byte_sizes > 0 {
56            let item = CosignatureBuilder::from_binary(&payload);
57            transactions.push(item.clone());
58            let size = item.get_size();
59            let item_size = size + Self::get_padding_size(item.get_size(), 8);
60            remaining_byte_sizes -= item_size;
61            payload = (&payload[item_size..]).to_vec();
62        }
63        payload
64    }
65
66    /// Creates an instance of AggregateTransactionBodyBuilder from binary payload.
67    /// payload: Byte payload to use to serialize the object.
68    /// # Returns
69    /// A AggregateTransactionBodyBuilder.
70    pub fn from_binary(payload: &[u8]) -> Self {
71        let mut _bytes = payload.to_vec();
72        let transactions_hash = Hash256Dto::from_binary(&_bytes); // kind:CUSTOM1
73        _bytes = _bytes[transactions_hash.get_size()..].to_vec();
74        let buf = fixed_bytes::<4>(&_bytes);
75        let payload_size = u32::from_le_bytes(buf); // kind:SIZE_FIELD
76        _bytes = (&_bytes[4..]).to_vec();
77        let buf = fixed_bytes::<4>(&_bytes);
78        let _ = u32::from_le_bytes(buf); // kind:SIMPLE
79        _bytes = (&_bytes[4..]).to_vec();
80        let mut transactions: Vec<Box<dyn EmbeddedTransactionHelper + 'static>> = vec![];
81        _bytes = AggregateTransactionBodyBuilder::load_embedded_transactions(&mut transactions, _bytes, payload_size);
82        let mut cosignatures: Vec<CosignatureBuilder> = vec![];
83        let _ = Self::load_cosignatures(&mut cosignatures, _bytes.clone(), _bytes.clone().len());
84        // create object and call.
85        AggregateTransactionBodyBuilder { transactions_hash, transactions, cosignatures } // TransactionBody
86    }
87
88    /// Serializes an embeded transaction with correct padding.
89    /// # Returns
90    /// A Serialized embedded transaction.
91    pub fn serialize_aligned(transaction: &Box<dyn EmbeddedTransactionHelper>) -> Vec<u8> {
92        let txn_bytes = transaction.serializer();
93        let padding = vec![0u8; Self::get_padding_size(txn_bytes.len(), 8)];
94        [txn_bytes, padding].concat()
95    }
96
97    /// Serializes an embeded transaction with correct padding.
98    /// # Returns
99    /// A Serialized embedded transaction.
100    pub fn size_aligned(transaction: &Box<dyn EmbeddedTransactionHelper>) -> usize {
101        let txn_size = transaction.get_size();
102        let padding_size = Self::get_padding_size(txn_size, 8);
103        txn_size + padding_size
104    }
105
106    fn get_padding_size(size: usize, alignment: usize) -> usize {
107        if alignment == 0 {
108            return 0;
109        }
110
111        if size % alignment == 0 {
112            return 0;
113        }
114        alignment - size % alignment
115    }
116    /// Gets the size of the type.
117    ///
118    /// Returns:
119    /// A size in bytes.
120    pub fn get_size(&self) -> usize {
121        let mut size = 0;
122        size += self.transactions_hash.get_size(); // transactions_hash_size;
123        size += 4;  // payload_size;
124        size += 4;  // aggregate_transaction_header__reserved1;
125        for i in &self.transactions {
126            size += Self::size_aligned(i); // VAR_ARRAY
127        };
128        for i in &self.cosignatures {
129            size += i.get_size(); // FILL_ARRAY
130        };
131        size
132    }
133
134    /// Serializes self to bytes.
135    ///
136    /// # Returns
137    /// A Serialized bytes.
138    pub fn serializer(&self) -> Vec<u8> {
139        let mut buf: Vec<u8> = vec![];
140        buf.append(&mut self.transactions_hash.serializer()); // kind:CUSTOM
141        // calculate payload size
142        let mut size_value: u32 = 0;
143        for i in &self.transactions {
144            size_value += Self::size_aligned(i) as u32;
145        };
146        buf.append(&mut size_value.to_le_bytes().to_vec()); // kind:SIZE_FIELD
147        buf.append(&mut [0u8; 4].to_vec()); // kind:SIMPLE and is_reserved
148        for i in &self.transactions {
149            buf.append(&mut Self::serialize_aligned(i)); // kind:VAR_ARRAY
150        }
151        for i in &self.cosignatures {
152            buf.append(&mut i.serializer()); // kind:ARRAY|FILL_ARRAY
153        }
154        buf
155    }
156}
157