@@ -626,7 +626,6 @@ def to_bytes(self) -> bytes:
626626 Serializes the frozen transaction into its protobuf-encoded byte representation.
627627
628628 This method is equivalent to the TypeScript SDK's transaction.toBytes() method.
629- The transaction must be frozen before calling this method.
630629
631630 The transaction can be serialized with or without signatures:
632631 - **Unsigned**: Can be sent to external signing services or HSMs
@@ -652,43 +651,36 @@ def to_bytes(self) -> bytes:
652651
653652 Returns:
654653 bytes: The serialized transaction as bytes.
655-
656- Raises:
657- Exception: If the transaction has not been frozen yet.
658654 """
659655 transaction_list = TransactionList ()
660656
661- if len (self .node_account_ids ) == 0 :
662- transaction_body = self .build_transaction_body ()
663-
664- if self .transaction_id is not None :
665- transaction_body .transactionID .CopyFrom (self .transaction_id ._to_proto ())
657+ transaction_body = self .build_transaction_body ()
666658
667- transaction = transaction_contents_pb2 .SignedTransaction (bodyBytes = transaction_body .SerializeToString ())
659+ if self .transaction_id is not None :
660+ transaction_body .transactionID .CopyFrom (self .transaction_id ._to_proto ())
668661
669- transaction_list .transaction_list .append (
670- transaction_pb2 .Transaction (signedTransactionBytes = transaction .SerializeToString ())
671- )
662+ node_account_ids = self .node_account_ids or [None ]
672663
673- else :
674- transaction_body = self .build_transaction_body ()
664+ for node_account_id in node_account_ids :
665+ if node_account_id is not None :
666+ transaction_body .nodeAccountID .CopyFrom (node_account_id ._to_proto ())
675667
676- if self .transaction_id is not None :
677- transaction_body .transactionID .CopyFrom (self .transaction_id ._to_proto ())
668+ signed_transaction = transaction_contents_pb2 .SignedTransaction (
669+ bodyBytes = transaction_body .SerializeToString ()
670+ )
678671
679- for node_account_id in self .node_account_ids :
680- transaction_body .nodeAccountID .CopyFrom (node_account_id ._to_proto ())
681- transaction = transaction_contents_pb2 .SignedTransaction (bodyBytes = transaction_body .SerializeToString ())
672+ if self ._transaction_body_bytes :
673+ body_bytes = transaction_body .SerializeToString ()
682674
683- if self ._transaction_body_bytes :
684- if self . _signature_map and self . _signature_map [ transaction_body . SerializeToString ()] :
685- transaction .sigMap .CopyFrom (self . _signature_map [ transaction_body . SerializeToString ()] )
686- else :
687- transaction .sigMap .CopyFrom (basic_types_pb2 .SignatureMap (sigPair = []))
675+ signature_map = self ._signature_map . get ( body_bytes )
676+ if signature_map is not None :
677+ signed_transaction .sigMap .CopyFrom (signature_map )
678+ else :
679+ signed_transaction .sigMap .CopyFrom (basic_types_pb2 .SignatureMap (sigPair = []))
688680
689- transaction_list .transaction_list .append (
690- transaction_pb2 .Transaction (signedTransactionBytes = transaction .SerializeToString ())
691- )
681+ transaction_list .transaction_list .append (
682+ transaction_pb2 .Transaction (signedTransactionBytes = signed_transaction .SerializeToString ())
683+ )
692684
693685 return transaction_list .SerializeToString ()
694686
@@ -762,109 +754,116 @@ def from_bytes(transaction_bytes: bytes):
762754 return Transaction ._process_transaction_list_bytes (transaction_bytes )
763755 except Exception :
764756 try :
757+ # Backward compatibility
765758 return Transaction ._process_single_transaction_bytes (transaction_bytes )
766759 except Exception as e :
767760 raise ValueError (f"Failed to parse transaction_bytes { e } " ) from e
768761
769762 @staticmethod
770- def _process_base_transaction_bytes (transaction_proto : transaction_pb2 .Transaction ):
763+ def _process_base_transaction (transaction_proto : transaction_pb2 .Transaction ):
764+ """Parses a serialized Transaction protobuf."""
771765 try :
772766 signed_transaction = transaction_contents_pb2 .SignedTransaction ()
773767 signed_transaction .ParseFromString (transaction_proto .signedTransactionBytes )
774768 except Exception as e :
775769 raise ValueError (f"Failed to parse signed transaction: { e } " ) from e
770+
776771 try :
777772 transaction_body = transaction_pb2 .TransactionBody ()
778773 transaction_body .ParseFromString (signed_transaction .bodyBytes )
779774 except Exception as e :
780775 raise ValueError (f"Failed to parse transaction body: { e } " ) from e
776+
781777 transaction_type = transaction_body .WhichOneof ("data" )
782778 if transaction_type is None :
783779 raise ValueError ("Transaction body does not contain any transaction data" )
784780 transaction_class = Transaction ._get_transaction_class (transaction_type )
781+
785782 if transaction_class is None :
786783 raise ValueError (f"Unknown transaction type: { transaction_type } " )
787784
788785 return transaction_class , transaction_body , signed_transaction
789786
790787 # Deprecated, for backward compatiblity only
791788 @staticmethod
792- def _process_single_transaction_bytes (transaction_bytes ):
789+ def _process_single_transaction_bytes (transaction_bytes : bytes ):
790+ """Deserializes a single Transaction protobuf."""
793791 try :
794792 transaction_proto = transaction_pb2 .Transaction ()
795793 transaction_proto .ParseFromString (transaction_bytes )
796794 except Exception as e :
797795 raise ValueError (f"Failed to parse transaction bytes: { e } " ) from e
798796
799- transaction_class , transaction_body , signed_transaction = Transaction ._process_base_transaction_bytes (
797+ transaction_class , transaction_body , signed_transaction = Transaction ._process_base_transaction (
800798 transaction_proto
801799 )
802800
803- restore_transaction : Transaction = transaction_class ._from_protobuf (transaction_body )
801+ transaction : Transaction = transaction_class ._from_protobuf (transaction_body )
804802
805- if restore_transaction ._node_account_id is not None :
806- restore_transaction .set_node_account_id (restore_transaction ._node_account_id )
803+ if transaction ._node_account_id is not None :
804+ transaction .set_node_account_id (transaction ._node_account_id )
807805
808- if signed_transaction .HasField ("sigMap" ):
809- if signed_transaction .sigMap .sigPair :
810- restore_transaction ._signature_map [signed_transaction .bodyBytes ] = signed_transaction .sigMap
811-
812- restore_transaction ._transaction_body_bytes [restore_transaction ._node_account_id ] = (
813- signed_transaction .bodyBytes
814- )
806+ Transaction ._restore_signatures (
807+ transaction ,
808+ transaction ._node_account_id ,
809+ signed_transaction ,
810+ )
815811
816- return restore_transaction
812+ return transaction
817813
818814 @staticmethod
819815 def _process_transaction_list_bytes (transaction_bytes : bytes ):
820- transaction_list = TransactionList ()
821- transaction_list .ParseFromString (transaction_bytes )
816+ """Deserializes a TransactionList protobuf."""
817+ try :
818+ transaction_list = TransactionList ()
819+ transaction_list .ParseFromString (transaction_bytes )
820+ except Exception as e :
821+ raise ValueError (f"Failed to parse TransactionList: { e } " ) from e
822822
823823 if not transaction_list .transaction_list :
824824 raise ValueError ("TransactionList contains no transactions" )
825825
826826 restored_transaction : Transaction = None
827827
828828 for transaction_proto in transaction_list .transaction_list :
829- transaction_class , transaction_body , signed_transaction = Transaction ._process_base_transaction_bytes (
829+ transaction_class , transaction_body , signed_transaction = Transaction ._process_base_transaction (
830830 transaction_proto
831831 )
832832
833- tmp_transaction : Transaction = transaction_class ._from_protobuf (transaction_body )
834-
835- node_id = tmp_transaction ._node_account_id
833+ transaction : Transaction = transaction_class ._from_protobuf (transaction_body )
834+ node_account_id = transaction ._node_account_id
836835
837836 if restored_transaction is None :
838- restored_transaction = tmp_transaction
837+ restored_transaction = transaction
839838
840- if node_id is not None :
841- restored_transaction .node_account_ids = [node_id ]
842-
843- if tmp_transaction ._signature_map :
844- for key , value in tmp_transaction ._signature_map .items ():
845- restored_transaction ._signature_map [key ] = value
846- restored_transaction ._transaction_body_bytes [node_id ] = key
839+ if node_account_id is not None :
840+ restored_transaction .node_account_ids = [node_account_id ]
847841
848842 else :
849- if node_id is not None and node_id not in restored_transaction .node_account_ids :
850- restored_transaction .node_account_ids .append (node_id )
851-
852- if tmp_transaction ._signature_map :
853- for key , value in tmp_transaction ._signature_map .items ():
854- restored_transaction ._signature_map [key ] = value
855- restored_transaction ._transaction_body_bytes [node_id ] = key
856-
857- if signed_transaction .HasField ("sigMap" ):
858- if signed_transaction .sigMap .sigPair :
859- restored_transaction ._signature_map [signed_transaction .bodyBytes ] = signed_transaction .sigMap
843+ if node_account_id is not None and node_account_id not in restored_transaction .node_account_ids :
844+ restored_transaction .node_account_ids .append (node_account_id )
860845
861- restored_transaction ._transaction_body_bytes [node_id ] = signed_transaction .bodyBytes
862-
863- if restored_transaction is None :
864- raise ValueError ("No valid transactions could be parsed from the byte stream" )
846+ Transaction ._restore_signatures (
847+ restored_transaction ,
848+ node_account_id ,
849+ signed_transaction ,
850+ )
865851
866852 return restored_transaction
867853
854+ @staticmethod
855+ def _restore_signatures (
856+ transaction : Transaction ,
857+ node_account_id ,
858+ signed_transaction ,
859+ ):
860+ """Restores signature maps and body bytes."""
861+ if signed_transaction .HasField ("sigMap" ):
862+ if signed_transaction .sigMap .sigPair :
863+ transaction ._signature_map [signed_transaction .bodyBytes ] = signed_transaction .sigMap
864+ if node_account_id is not None :
865+ transaction ._transaction_body_bytes [node_account_id ] = signed_transaction .bodyBytes
866+
868867 @staticmethod
869868 def _get_transaction_class (transaction_type : str ):
870869 """
0 commit comments