hiero-ledger / hiero-ledger/hiero-sdk-python

feat: implement _from_protobuf for token association & airdrop transactions (from_bytes round-trip)

Open
#2,619 4 comments 0 reactions 0 assignees View on GitHub
approved lang: python skill: intermediate
Dominant language
Python
Stars
63
Forks
298
Avg merge
3d 18h
Merged PRs (30d)
38

Description

### πŸ§‘β€πŸ’» Intermediate Issue

Welcome! This is an **[Intermediate Issue](https://github.com/issues?q=is%3Aopen%20is%3Aissue%20org%3Ahiero-ledger%20archived%3Afalse%20no%3Aassignee%20(label%3A%22intermediate%22%20OR%20label%3A%22skill%3A%20intermediate%22)%20(repo%3Ahiero-ledger%2Fhiero-sdk-cpp%20OR%20repo%3Ahiero-ledger%2Fhiero-sdk-swift%20OR%20repo%3Ahiero-ledger%2Fhiero-sdk-python%20OR%20repo%3Ahiero-ledger%2Fhiero-sdk-js%20OR%20repo%3Ahiero-ledger%2Fhiero-website))** touching core SDK architecture.

🏁 **When this issue is complete, you will have:**

βœ… Researched across multiple files and modules
βœ… Owned implementation decisions
βœ… Written thorough, meaningful tests
βœ… Delivered a clean, review-ready pull request

### 🐞 Problem Description

`Transaction.from_bytes()` returns a correctly-typed but **empty** instance for the transaction types below: they never override `_from_protobuf`, so every type-specific field is left at its default with no error or warning (common fields, signatures and the original body bytes *are* restored by the base class, so execution still works β€” inspection does not). Part of #2179; the dispatch-map fixes and the round-trip test harness land in #2614 first.

Affected classes:

- `TokenAssociateTransaction` (`src/hiero_sdk_python/tokens/token_associate_transaction.py`)
- `TokenDissociateTransaction` (`src/hiero_sdk_python/tokens/token_dissociate_transaction.py`)
- `TokenRejectTransaction` (`src/hiero_sdk_python/tokens/token_reject_transaction.py`)
- `TokenAirdropTransaction` (`src/hiero_sdk_python/tokens/token_airdrop_transaction.py`)
- `TokenCancelAirdropTransaction` (`src/hiero_sdk_python/tokens/token_cancel_airdrop_transaction.py`)
- `TokenClaimAirdropTransaction` (`src/hiero_sdk_python/tokens/token_airdrop_claim.py`)

### πŸ’‘ Expected Solution

Implement `_from_protobuf` for each affected class as the exact field-for-field inverse of its `build_transaction_body()`, then remove the `xfail` markers for these types in the round-trip harness from #2614.

- [ ] `TokenAssociateTransaction._from_protobuf`
- [ ] `TokenDissociateTransaction._from_protobuf`
- [ ] `TokenRejectTransaction._from_protobuf`
- [ ] `TokenAirdropTransaction._from_protobuf`
- [ ] `TokenCancelAirdropTransaction._from_protobuf`
- [ ] `TokenClaimAirdropTransaction._from_protobuf`
- [ ] Un-xfail these types in the #2614 round-trip harness

### πŸ” Background Research

This is inverse-serialization contract work β€” please research the pattern before coding; **do not code from this issue title alone**, and do not ship the first AI-generated attempt that runs. Reviewers check inverse fidelity per field.

1. Issue #2179 (context) and #2614 (the test harness your PR must satisfy β€” **do not start before it is merged**).
2. The reference implementations: `FileCreateTransaction._from_protobuf` (`src/hiero_sdk_python/file/file_create_transaction.py`) and `TransferTransaction._from_protobuf` (`src/hiero_sdk_python/transaction/transfer_transaction.py`). Your implementation must follow their structure exactly: call `super()._from_protobuf(...)`, then restore type-specific fields from the body.
3. Each affected class's `build_transaction_body()` β€” your `_from_protobuf` is its exact inverse. Reuse the SDK's existing `_from_proto` converters (`AccountId`, `TokenId`, keys, …); never hand-parse a submessage that already has one.
4. The generated proto message for each body (`src/hiero_sdk_python/hapi/services/`) β€” learn which fields are `optional` (guard with `HasField` so unset stays `None`) versus plain scalars/repeated.
5. [CONTRIBUTING.md](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/CONTRIBUTING.md) for test and PR conventions.

### πŸ› οΈ Implementation Notes

`TokenAirdropTransaction` reuses the `TokenTransfer` structures β€” research how `TransferTransaction._from_protobuf` (`src/hiero_sdk_python/transaction/transfer_transaction.py`) restores transfer lists and follow it. Cancel/claim restore repeated `PendingAirdropId` messages; reject distinguishes fungible token references from NFT references.

**Constraints / acceptance criteria:**

- For each class: build with all fields set β†’ freeze β†’ `to_bytes()` β†’ `from_bytes()` β†’ every type-specific field equals the original
- Unset optional fields come back as `None`/empty, not proto defaults
- `restored.to_bytes()` stays byte-identical to the original (no re-serialization of the body)
- No changes to public API signatures

Part of #2179. **Blocked by #2614.**

### πŸ”¬ Technical Domains

- [x] **Intermediate to Advanced Programming** (Object oriented design, inheritance, complex type systems)
- [x] **File Specific Knowledge** (request β†’ serialization β†’ execution β†’ response mapping)
- [x] **Backward Compatibility** (preserving method signatures, defaults, and return types)
- [x] **Protobuf Alignment** (reading `.proto` files, `_to_proto()` / `_from_proto()` correctness)
- [x] **Testing** (unit, integration, mocking, test coverage for edge cases and failure modes)

### 🧠 Intermediate Contributors β€” Prerequisites & Expectations

> [!CAUTION]
> **Intermediate issues are high-risk. We expect more than just a 'working solution' and will recommend beginner issues if the PR does not meet these standards.**

### 🏁 Concrete Prerequisites
- **Advanced Programming Language:** Higher level intermediate or advanced programming language.
- **Expertise:** Strong understanding of files related to this issue (research before claiming!).
- **Proven History:** Successfully completed **β‰₯ 5 beginner issues** in this repo.

If this feels like too big a step, that is completely fine β€” try a [Beginner Issue](https://github.com/issues?q=is%3Aopen%20is%3Aissue%20org%3Ahiero-ledger%20archived%3Afalse%20no%3Aassignee%20(label%3A%22beginner%22%20OR%20label%3A%22skill%3A%20beginner%22)%20(repo%3Ahiero-ledger%2Fhiero-sdk-cpp%20OR%20repo%3Ahiero-ledger%2Fhiero-sdk-swift%20OR%20repo%3Ahiero-ledger%2Fhiero-sdk-python%20OR%20repo%3Ahiero-ledger%2Fhiero-sdk-js%20OR%20repo%3Ahiero-ledger%2Fhiero-website)) first or a different **[Intermediate Issue](https://github.com/issues?q=is%3Aopen%20is%3Aissue%20org%3Ahiero-ledger%20archived%3Afalse%20no%3Aassignee%20(label%3A%22intermediate%22%20OR%20label%3A%22skill%3A%20intermediate%22)%20(repo%3Ahiero-ledger%2Fhiero-sdk-cpp%20OR%20repo%3Ahiero-ledger%2Fhiero-sdk-swift%20OR%20repo%3Ahiero-ledger%2Fhiero-sdk-python%20OR%20repo%3Ahiero-ledger%2Fhiero-sdk-js%20OR%20repo%3Ahiero-ledger%2Fhiero-website))**. You can always come back when you are ready.

### ⚠️ AI Usage Policy

- Using AI to generate code for Intermediate issues is **strictly discouraged**
- Using AI as the main source of research is **strictly discouraged**, refer to language and library documentation, protobuf definitions and other SDKs.

### ⏱️ Timeline & Workflow
- **Typical time:** ~2 weeks / ~25 hours.
- πŸ”΄ Completing an intermediate issue in 1–3 days is a **red flag**.

> [!TIP]
> **Suggested:** share your proposed implementation approach as a comment before writing code to get early feedback and avoid wasted effort.

### πŸ§ͺ Testing Requirements

> [!IMPORTANT]
> At the intermediate level, **testing is a major component**.
> Each `_from_protobuf` you implement must be verified field-by-field. Tests should cover happy paths, unset-optional edge cases, and error handling.

**Source code changes (in `src/`):**
- Un-xfail and pass the parametrized round-trip tests from #2614 for your types (build with all fields set β†’ freeze β†’ `to_bytes()` β†’ `from_bytes()` β†’ assert every type-specific field equals the original)
- Add explicit unset-optional cases: fields not set must come back as `None`/empty, not proto defaults
- Run tests locally: `uv run pytest tests/unit/_test.py -v`
- Verify naming, types, and field ordering match [protobuf definitions](https://github.com/hashgraph/hedera-protobufs/tree/main/services)
- Check consistency with similar classes already in the SDK β€” use the same patterns
- Integration tests will run automatically when you push

### πŸ›‘οΈ Quality & Review Standards

Intermediate PRs must be **"working, maintainable, and aligned with SDK architecture."**

1. **Working:** The implementation must solve the problem and meet the acceptance criteria.
2. **Maintainable:** Code should be clear and concise enough for others to understand and debug without your assistance.
3. **SDK Alignment:** The solution should fit well with existing SDK patterns and abstractions.
4. **Backward Compatibility:** Public API signatures must be preserved.
5. **Comprehensive Testing:** Must include unit and integration tests covering all new logic paths, edge cases, and failure modes. AI generated tests based on AI generated code is grounds for immediate rejection.

**⚠️ Breaking changes**
- Before changing any function signature, return type, or public API β€” stop and check
- If a breaking change is unavoidable: get explicit maintainer approval **before** implementing
- All existing tests should pass as-is.

### βœ… PR Quality Checklist

Before opening your PR, confirm:

- [ ] I have spent the majority of my time researching the problem and solution space extensively, including reviewing relevant code, documentation, and external resources.
- [ ] My implementation works but is also of high quality - including maintainability, readability, and architectural fit.
- [ ] I have checked for breaking changes - no public APIs regress.
- [ ] The system design fits with current Hiero SDK architectural approaches.
- [ ] Every line of code is personally understood and explainable.

Before requesting a review, confirm:
- [ ] I have reviewed the diff line by line.
- [ ] My implementation fully addresses the problem described above.
- [ ] I did not modify files unrelated to this issue
- [ ] Clean git history β€” no rebase artifacts, merge commits, or unrelated files
- [ ] My commits are signed: `git commit -S -s -m "chore: description"` β€” [Signing guide](https://github.com/hiero-ledger/sdk-collaboration-hub/blob/main/guides/issue-progression/for-developers/signing.md)
- [ ] I have verified naming, types, and field ordering against pinned Protobufs.
- [ ] I have applied appropriate linting, code quality, and formatting tools used in this repo.
- [ ] I have included appropriate tests and all CI checks pass.
- [ ] Double and triple check β€” intermediate PRs are time-consuming to review

### πŸ“‹ Workflow quick reference

You know the workflow β€” here are the links if you need them:

| Step | Guide |
|------|-------|
| Claim this issue | Comment `/assign` below |
| Sync with main | [Rebasing guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/rebasing.md) |
| Open a PR and link this issue | [PR guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/workflow/11_submit_pull_request.md) Β· [Linking guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/how_to_link_issues.md) |
| Resolve merge conflicts | [Merge conflicts guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/merge_conflicts.md) |
| Testing | [Testing guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/testing.md) |

### πŸ“š Resources & Support

**πŸ†˜ Stuck?**
> [!TIP]
> **Comment on this issue:** and describe what you have tried. A maintainer will respond.

**Project references:**
- [Project structure](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/training/setup/project_structure.md)
- [CONTRIBUTING.md](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/CONTRIBUTING.md)
- [Browse closed intermediate PRs](https://github.com/hiero-ledger/hiero-sdk-python/pulls?q=is%3Apr+is%3Amerged+label%3A%22skill%3A+intermediate%22) β€” see how others did it
- [Pylance guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/pylance.md)

**Protobuf references:**
- [Hedera Protobufs](https://github.com/hashgraph/hedera-protobufs/tree/main/services) β€” source of truth for field names, types, and ordering
- [Protobuf language guide](https://protobuf.dev/programming-guides/proto3/)

**Community:**
- [Community Calls](https://zoom-lfx.platform.linuxfoundation.org/meetings/hiero?view=week)
- [Discord](https://github.com/hiero-ledger/sdk-collaboration-hub/blob/main/guides/issue-progression/for-developers/discord.md)

Contributor guide

Open the contributing guide

Research direction

Wait for #2614, then read the six affected transaction files and their build_transaction_body() methods. Compare FileCreateTransaction._from_protobuf and TransferTransaction._from_protobuf, inspect generated protobuf definitions, and run the parametrized round-trip tests plus explicit unset-optional cases. Done means all type-specific fields restore field-for-field, byte output remains identical, and tests pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, blockchain
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.