Skip to content

[Intermediate]: Pin receipt/record queries to submitting node by default #1686

@rwalworth

Description

@rwalworth

🧩 Intermediate Contributors

This issue is intended for contributors who already have some familiarity with the
Hiero Python SDK codebase and contribution workflow.

You should feel comfortable:

  • navigating existing source code and examples
  • understanding SDK concepts without step-by-step guidance
  • following the standard PR workflow without additional onboarding

If this is your very first contribution to the project, we recommend starting with a few
Good First Issues before working on this one.


🐞 Problem Description

The Python SDK's TransactionResponse.get_receipt() method does not pin the receipt query to the submitting node. Instead, it uses the default client node selection, which may query any node in the network.

This behavior differs from other Hiero SDKs (JavaScript, Java, Swift, C++, Go), which all explicitly pin receipt queries to the submitting node via set_node_account_ids([submitting_node]).

Why this matters:

When a transaction is rejected pre-consensus (non-billable — e.g., invalid payer, bad signature, insufficient balance), only the submitting node has visibility into that failure. The transaction is never propagated to other nodes. If the receipt query goes to a different node, it won't find the transaction and may return misleading results or errors.

Pinning receipt queries to the submitting node ensures consistent behavior for these edge cases.

Current implementation:

# src/hiero_sdk_python/transaction/transaction_response.py (lines 27-47)

def get_receipt(self, client):
    from hiero_sdk_python.query.transaction_get_receipt_query import TransactionGetReceiptQuery
    # TODO: Implement set_node_account_ids() to get failure reason for preHandle failures
    receipt = (
        TransactionGetReceiptQuery()
        .set_transaction_id(self.transaction_id)
        .execute(client)  # ← Does NOT pin to self.node_id
    )
    return receipt

Note: There's already a TODO comment acknowledging this gap.

Relevant files:

  • src/hiero_sdk_python/transaction/transaction_response.py
  • src/hiero_sdk_python/query/transaction_get_receipt_query.py
  • src/hiero_sdk_python/executable.py (contains set_node_account_ids())

💡 Expected Solution

Update TransactionResponse.get_receipt() to pin the receipt query to the submitting node by calling set_node_account_ids([self.node_id]).

The change should:

  • Pin receipt queries to the submitting node (self.node_id)
  • Preserve existing API behavior (no breaking changes)
  • Follow the same pattern used by other SDKs
  • Remove or update the existing TODO comment

Expected usage (unchanged):

response = transaction.execute(client)
receipt = response.get_receipt(client)
# Receipt query now explicitly targets the submitting node

Reference implementation (from JavaScript SDK):

// src/transaction/TransactionResponse.js
getReceiptQuery() {
    return new TransactionReceiptQuery()
        .setTransactionId(this.transactionId)
        .setNodeAccountIds([this.nodeId]);  // ← Pinned to submitting node
}

🧠 Implementation Notes

Likely steps:

  1. In TransactionResponse.get_receipt(), add .set_node_account_ids([self.node_id]) to the query chain
  2. Consider adding a get_receipt_query() method that returns the configured query object (for consistency with other SDKs)
  3. If get_record() exists, apply the same pinning logic there
  4. Remove or update the TODO comment on line 40
  5. Add or update tests to verify the node pinning behavior

The infrastructure already exists:

  • Executable.set_node_account_ids() is implemented in executable.py (line 83)
  • TransactionResponse already stores self.node_id (the submitting node)
  • TransactionGetReceiptQuery inherits from Query, which inherits from Executable

Similar patterns:

  • JavaScript SDK: TransactionResponse.getReceiptQuery() pins to this.nodeId
  • Java SDK: TransactionResponse.getReceiptQuery() uses Collections.singletonList(nodeId)
  • Swift SDK: TransactionResponse.getReceiptQuery() uses .nodeAccountIds([nodeAccountId])

Things to verify:

  • Ensure self.node_id is always populated when get_receipt() is called
  • Check if there's a get_record() method that needs the same treatment

✅ Acceptance Criteria

To merge this issue, the pull request must:

  • Pin receipt queries to the submitting node via set_node_account_ids([self.node_id])
  • Apply the same pinning to record queries if applicable (get_record())
  • Remove or update the existing TODO comment
  • Follow existing project conventions and patterns
  • Include tests verifying the node pinning behavior
  • Pass all CI checks
  • Include a valid changelog entry
  • Be DCO and GPG key signed as git commit -S -s -m "chore: my change" with a GPG key set up

📚 Additional Context or Resources

Related SDKs for reference:

Metadata

Metadata

Labels

Blockchain / DLTIssues engineering distributed ledger functionalityintermediaterequires some knowledge of the codebase with some defined steps to implement or examples

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions