Transaction.from_bytes() returns incomplete objects for most transaction types — missing _from_protobuf implementations
Description
Transaction.from_bytes() silently returns an incomplete object for the vast majority of transaction types. The deserialization chain (from_bytes() → _get_transaction_class() → _from_protobuf()) works at the base class level, but almost all concrete subclasses never implemented _from_protobuf. The result is a correctly-typed instance (e.g. TokenMintTransaction) with all transaction-specific fields at their default None/empty values — no error, no warning.
Affected transaction types
- Account:
AccountCreateTransaction, AccountUpdateTransaction, AccountDeleteTransaction, AccountAllowanceApproveTransaction, AccountAllowanceDeleteTransaction
- Token:
TokenCreateTransaction, TokenUpdateTransaction, TokenMintTransaction, TokenBurnTransaction, TokenDeleteTransaction, TokenFreezeTransaction, TokenUnfreezeTransaction, TokenGrantKycTransaction, TokenRevokeKycTransaction, TokenWipeTransaction, TokenPauseTransaction, TokenUnpauseTransaction, TokenAssociateTransaction, TokenDissociateTransaction, TokenFeeScheduleUpdateTransaction, TokenAirdropTransaction, TokenClaimAirdropTransaction, TokenCancelAirdropTransaction, TokenRejectTransaction, TokenUpdateNftsTransaction
- Consensus:
TopicCreateTransaction, TopicUpdateTransaction, TopicDeleteTransaction, TopicMessageSubmitTransaction
- File:
FileCreateTransaction, FileAppendTransaction, FileUpdateTransaction, FileDeleteTransaction
- Schedule:
ScheduleCreateTransaction, ScheduleSignTransaction, ScheduleDeleteTransaction
- System:
FreezeTransaction
Additional bugs in _get_transaction_class map
The lookup map in transaction.py had several issues that caused some types to be deserialized as the wrong class:
- Wrong casing on keys —
WhichOneof("data") returns snake_case for newer proto fields (e.g. token_pause, token_unpause, token_fee_schedule_update, token_update_nfts) but the map had camelCase keys
- Missing entries for
tokenClaimAirdrop, token_fee_schedule_update, and freeze
- Incorrect module paths for some entries
Impact
Any code path that calls Transaction.from_bytes() — including mirror node queries, schedule transaction inspection, or round-trip serialization — returns a valid-looking but empty object. This is especially dangerous because it fails silently with no exception.
Expected behavior
Transaction.from_bytes(tx.to_bytes()) should round-trip correctly and return an object with all fields populated.
Proposed fix
Implement _from_protobuf for all affected transaction types, and correct the _get_transaction_class map keys and module paths to match what WhichOneof("data") actually returns.
Transaction.from_bytes()returns incomplete objects for most transaction types — missing_from_protobufimplementationsDescription
Transaction.from_bytes()silently returns an incomplete object for the vast majority of transaction types. The deserialization chain (from_bytes()→_get_transaction_class()→_from_protobuf()) works at the base class level, but almost all concrete subclasses never implemented_from_protobuf. The result is a correctly-typed instance (e.g.TokenMintTransaction) with all transaction-specific fields at their defaultNone/empty values — no error, no warning.Affected transaction types
AccountCreateTransaction,AccountUpdateTransaction,AccountDeleteTransaction,AccountAllowanceApproveTransaction,AccountAllowanceDeleteTransactionTokenCreateTransaction,TokenUpdateTransaction,TokenMintTransaction,TokenBurnTransaction,TokenDeleteTransaction,TokenFreezeTransaction,TokenUnfreezeTransaction,TokenGrantKycTransaction,TokenRevokeKycTransaction,TokenWipeTransaction,TokenPauseTransaction,TokenUnpauseTransaction,TokenAssociateTransaction,TokenDissociateTransaction,TokenFeeScheduleUpdateTransaction,TokenAirdropTransaction,TokenClaimAirdropTransaction,TokenCancelAirdropTransaction,TokenRejectTransaction,TokenUpdateNftsTransactionTopicCreateTransaction,TopicUpdateTransaction,TopicDeleteTransaction,TopicMessageSubmitTransactionFileCreateTransaction,FileAppendTransaction,FileUpdateTransaction,FileDeleteTransactionScheduleCreateTransaction,ScheduleSignTransaction,ScheduleDeleteTransactionFreezeTransactionAdditional bugs in
_get_transaction_classmapThe lookup map in
transaction.pyhad several issues that caused some types to be deserialized as the wrong class:WhichOneof("data")returns snake_case for newer proto fields (e.g.token_pause,token_unpause,token_fee_schedule_update,token_update_nfts) but the map had camelCase keystokenClaimAirdrop,token_fee_schedule_update, andfreezeImpact
Any code path that calls
Transaction.from_bytes()— including mirror node queries, schedule transaction inspection, or round-trip serialization — returns a valid-looking but empty object. This is especially dangerous because it fails silently with no exception.Expected behavior
Transaction.from_bytes(tx.to_bytes())should round-trip correctly and return an object with all fields populated.Proposed fix
Implement
_from_protobuffor all affected transaction types, and correct the_get_transaction_classmap keys and module paths to match whatWhichOneof("data")actually returns.