Skip to content

Transaction.from_bytes() returns incomplete objects for most transaction types — missing _from_protobuf implementations #2179

@yuval99g

Description

@yuval99g

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.

Metadata

Metadata

Assignees

Labels

lang: pythonUses Python programming languagescope: DLTinvolves engineering for distributed ledger technology

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions