22
33use hedera_proto:: services;
44use hedera_proto:: services:: util_service_client:: UtilServiceClient ;
5+ use prost:: Message ;
56use tonic:: transport:: Channel ;
67
78use crate :: ledger_id:: RefLedgerId ;
@@ -13,8 +14,6 @@ use crate::transaction::{
1314 TransactionData ,
1415 TransactionExecute ,
1516} ;
16- use prost:: Message ;
17-
1817use crate :: {
1918 AnyTransaction ,
2019 BoxGrpcFuture ,
@@ -27,38 +26,38 @@ use crate::{
2726
2827/// Execute multiple transactions in a single consensus event. This allows for atomic execution of multiple
2928/// transactions, where they either all succeed or all fail together.
30- ///
29+ ///
3130/// # Requirements
32- ///
31+ ///
3332/// - All inner transactions must be frozen before being added to the batch
3433/// - All inner transactions must have a batch key set (using `set_batch_key()` or `batchify()`)
3534/// - All inner transactions must be signed as required for each individual transaction
3635/// - The BatchTransaction must be signed by all batch keys of the inner transactions
3736/// - Certain transaction types (FreezeTransaction, BatchTransaction) are not allowed in a batch
38- ///
37+ ///
3938/// # Important notes
40- ///
39+ ///
4140/// - Fees are assessed for each inner transaction separately
4241/// - The maximum number of inner transactions in a batch is limited to 25
4342/// - Inner transactions cannot be scheduled transactions
44- ///
43+ ///
4544/// # Example usage
46- ///
45+ ///
4746/// ```rust,no_run
4847/// use hedera::{BatchTransaction, TransferTransaction, PrivateKey, Client, Hbar};
49- ///
48+ ///
5049/// # async fn example() -> hedera::Result<()> {
5150/// let client = Client::for_testnet();
5251/// let batch_key = PrivateKey::generate_ed25519();
53- ///
52+ ///
5453/// // Create and prepare inner transaction
5554/// let inner_transaction = TransferTransaction::new()
5655/// .hbar_transfer(sender, -amount)
5756/// .hbar_transfer(receiver, amount)
5857/// .freeze_with(&client)?
5958/// .set_batch_key(batch_key.public_key().into())
6059/// .sign(&operator_key)?;
61- ///
60+ ///
6261/// // Create and execute batch transaction
6362/// let response = BatchTransaction::new()
6463/// .add_inner_transaction(inner_transaction)?
@@ -78,50 +77,56 @@ pub struct BatchTransactionData {
7877
7978impl BatchTransaction {
8079 /// Append a transaction to the list of transactions this BatchTransaction will execute.
81- ///
80+ ///
8281 /// # Requirements for the inner transaction
83- ///
82+ ///
8483 /// - Must be frozen (use `freeze()` or `freeze_with(client)`)
8584 /// - Must have a batch key set (use `set_batch_key()` or `batchify()`)
8685 /// - Must not be a blacklisted transaction type
87- ///
86+ ///
8887 /// # Errors
89- ///
88+ ///
9089 /// Returns an error if:
9190 /// - The transaction is null
9291 /// - This transaction is frozen
9392 /// - The inner transaction is not frozen or missing a batch key
9493 /// - The transaction is of a blacklisted type (FreezeTransaction, BatchTransaction)
95- pub fn add_inner_transaction ( & mut self , transaction : AnyTransaction ) -> crate :: Result < & mut Self > {
94+ pub fn add_inner_transaction (
95+ & mut self ,
96+ transaction : AnyTransaction ,
97+ ) -> crate :: Result < & mut Self > {
9698 self . require_not_frozen ( ) ;
9799 self . validate_inner_transaction ( & transaction) ?;
98100 self . data_mut ( ) . inner_transactions . push ( transaction) ;
99101 Ok ( self )
100102 }
101103
102104 /// Set the list of transactions to be executed as part of this BatchTransaction.
103- ///
105+ ///
104106 /// # Requirements for each inner transaction
105- ///
107+ ///
106108 /// - Must be frozen (use `freeze()` or `freeze_with(client)`)
107109 /// - Must have a batch key set (use `set_batch_key()` or `batchify()`)
108110 /// - Must not be a blacklisted transaction type
109- ///
111+ ///
110112 /// Note: This method creates a defensive copy of the provided list.
111- ///
113+ ///
112114 /// # Errors
113- ///
115+ ///
114116 /// Returns an error if:
115117 /// - Any inner transaction is not frozen or missing a batch key
116118 /// - Any transaction is of a blacklisted type
117- pub fn set_inner_transactions ( & mut self , transactions : Vec < AnyTransaction > ) -> crate :: Result < & mut Self > {
119+ pub fn set_inner_transactions (
120+ & mut self ,
121+ transactions : Vec < AnyTransaction > ,
122+ ) -> crate :: Result < & mut Self > {
118123 self . require_not_frozen ( ) ;
119-
124+
120125 // Validate all transactions before setting
121126 for transaction in & transactions {
122127 self . validate_inner_transaction ( transaction) ?;
123128 }
124-
129+
125130 self . data_mut ( ) . inner_transactions = transactions;
126131 Ok ( self )
127132 }
@@ -132,24 +137,20 @@ impl BatchTransaction {
132137 }
133138
134139 /// Get the list of transaction IDs of each inner transaction of this BatchTransaction.
135- ///
140+ ///
136141 /// This method is particularly useful after execution to:
137142 /// - Track individual transaction results
138143 /// - Query receipts for specific inner transactions
139144 /// - Monitor the status of each transaction in the batch
140- ///
145+ ///
141146 /// **NOTE:** Transaction IDs will only be meaningful after the batch transaction has been
142147 /// executed or the IDs have been explicitly set on the inner transactions.
143148 pub fn get_inner_transaction_ids ( & self ) -> Vec < Option < TransactionId > > {
144- self . data ( )
145- . inner_transactions
146- . iter ( )
147- . map ( |tx| tx. get_transaction_id ( ) )
148- . collect ( )
149+ self . data ( ) . inner_transactions . iter ( ) . map ( |tx| tx. get_transaction_id ( ) ) . collect ( )
149150 }
150151
151152 /// Validates if a transaction is allowed in a batch transaction.
152- ///
153+ ///
153154 /// A transaction is valid if:
154155 /// - It is not a blacklisted type (FreezeTransaction or BatchTransaction)
155156 /// - It is frozen
@@ -159,12 +160,12 @@ impl BatchTransaction {
159160 match transaction. data ( ) {
160161 AnyTransactionData :: Freeze ( _) => {
161162 return Err ( Error :: basic_parse (
162- "Transaction type FreezeTransaction is not allowed in a batch transaction"
163+ "Transaction type FreezeTransaction is not allowed in a batch transaction" ,
163164 ) ) ;
164165 }
165166 AnyTransactionData :: Batch ( _) => {
166167 return Err ( Error :: basic_parse (
167- "Transaction type BatchTransaction is not allowed in a batch transaction"
168+ "Transaction type BatchTransaction is not allowed in a batch transaction" ,
168169 ) ) ;
169170 }
170171 _ => { }
@@ -196,11 +197,12 @@ impl ToTransactionDataProtobuf for BatchTransactionData {
196197 _chunk_info : & ChunkInfo ,
197198 ) -> services:: transaction_body:: Data {
198199 let mut builder = services:: AtomicBatchTransactionBody :: default ( ) ;
199-
200+
200201 for transaction in & self . inner_transactions {
201202 // Get the signed transaction bytes from each inner transaction
202203 // Note: This unwrap is OK because inner transactions should be frozen
203- let signed_transaction_bytes = transaction. to_signed_transaction_bytes ( )
204+ let signed_transaction_bytes = transaction
205+ . to_signed_transaction_bytes ( )
204206 . expect ( "Inner transaction should be frozen and serializable" ) ;
205207 builder. transactions . push ( signed_transaction_bytes) ;
206208 }
@@ -231,14 +233,12 @@ impl ValidateChecksums for BatchTransactionData {
231233impl FromProtobuf < services:: AtomicBatchTransactionBody > for BatchTransactionData {
232234 fn from_protobuf ( pb : services:: AtomicBatchTransactionBody ) -> crate :: Result < Self > {
233235 let mut inner_transactions = Vec :: new ( ) ;
234-
236+
235237 for signed_transaction_bytes in pb. transactions {
236238 // Create a transaction from the signed transaction bytes
237- let proto_transaction = services:: Transaction {
238- signed_transaction_bytes,
239- ..Default :: default ( )
240- } ;
241-
239+ let proto_transaction =
240+ services:: Transaction { signed_transaction_bytes, ..Default :: default ( ) } ;
241+
242242 let transaction = AnyTransaction :: from_bytes ( & proto_transaction. encode_to_vec ( ) ) ?;
243243 inner_transactions. push ( transaction) ;
244244 }
@@ -268,7 +268,7 @@ mod tests {
268268 fn test_validate_non_frozen_transaction ( ) {
269269 let mut batch = BatchTransaction :: new ( ) ;
270270 let inner_tx = TransferTransaction :: new ( ) ;
271-
271+
272272 let result = batch. add_inner_transaction ( inner_tx. into ( ) ) ;
273273 assert ! ( result. is_err( ) ) ;
274274 assert ! ( result. unwrap_err( ) . to_string( ) . contains( "Inner transaction should be frozen" ) ) ;
@@ -280,11 +280,11 @@ mod tests {
280280 let inner_tx = TransferTransaction :: new ( ) ;
281281 // Note: In a real scenario, you would freeze the transaction first,
282282 // then set a batch key, but this test just checks the validation logic
283-
283+
284284 let result = batch. add_inner_transaction ( inner_tx. into ( ) ) ;
285285 assert ! ( result. is_err( ) ) ;
286286 // The error will be about the transaction not being frozen first,
287287 // which comes before the batch key check
288288 assert ! ( result. unwrap_err( ) . to_string( ) . contains( "Inner transaction should be frozen" ) ) ;
289289 }
290- }
290+ }
0 commit comments