Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
f694268
add tokenInfoQuery functionality
aceppaluni May 22, 2025
d5310c8
refactor: update TokenInfoQuery implementation
Dosik13 May 27, 2025
76b0d85
test: add unit tests
Dosik13 May 27, 2025
256e807
test: add integration tests
Dosik13 May 27, 2025
32443f1
docs: add examples for both non-fungible/fungible tokens
Dosik13 May 27, 2025
3c3a6ea
docs: update README in examples
Dosik13 May 27, 2025
1a453ee
chore: add TokenInfoQuery to __init__.py
Dosik13 May 27, 2025
1c6ac60
test: reduce test_token_info_query_execute function length
Dosik13 May 28, 2025
df1069c
test: fix incorrect integration test function names
Dosik13 May 28, 2025
67c9eb7
docs: change network from solo to testnet and some minor changes in e…
Dosik13 May 28, 2025
d7d6c18
test: address PR comments for integration/unit tests
Dosik13 May 30, 2025
79c1f10
docs: update examples for TokenInfoQuery to address PR comments
Dosik13 May 30, 2025
a4372ad
Merge branch 'hiero-ledger:main' into main
aceppaluni Jun 2, 2025
17ace16
Merge branch 'hiero-ledger:main' into main
aceppaluni Jun 4, 2025
090b2bb
Merge branch 'hiero-ledger:main' into main
aceppaluni Jun 16, 2025
854c0ca
Merge branch 'hiero-ledger:main' into main
aceppaluni Aug 6, 2025
168d706
Merge branch 'hiero-ledger:main' into main
aceppaluni Aug 7, 2025
143b727
Merge branch 'hiero-ledger:main' into main
aceppaluni Aug 15, 2025
ad6df88
Merge branch 'hiero-ledger:main' into main
aceppaluni Aug 20, 2025
fdcc0cb
Merge branch 'hiero-ledger:main' into main
aceppaluni Sep 3, 2025
b9ad245
Merge branch 'hiero-ledger:main' into main
aceppaluni Sep 8, 2025
7f4ee47
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 14, 2025
e17c504
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 19, 2025
22ba822
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 20, 2025
2741bde
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 21, 2025
9621065
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 22, 2025
9469f23
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 23, 2025
cfd8e1c
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 24, 2025
1cb2132
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 27, 2025
9328d1f
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 28, 2025
e594364
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 28, 2025
a5267b8
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 29, 2025
13b3573
Merge branch 'hiero-ledger:main' into main
aceppaluni Oct 30, 2025
177248e
Merge branch 'hiero-ledger:main' into main
aceppaluni Nov 4, 2025
7744971
Merge branch 'hiero-ledger:main' into main
aceppaluni Nov 9, 2025
277bf9d
Merge branch 'hiero-ledger:main' into main
aceppaluni Nov 11, 2025
1f4f5cf
Merge branch 'hiero-ledger:main' into main
aceppaluni Nov 17, 2025
91d86fb
Merge branch 'hiero-ledger:main' into main
aceppaluni Nov 19, 2025
fce4f9f
Merge branch 'hiero-ledger:main' into main
aceppaluni Nov 19, 2025
333f755
Merge branch 'hiero-ledger:main' into main
aceppaluni Nov 19, 2025
50f258e
Add set_node_account_id method
aceppaluni Sep 8, 2025
94c89d3
fix: add missing List import and update changelog
aceppaluni Oct 28, 2025
e83e701
style: add spacing in set_node_account_id method
aceppaluni Oct 28, 2025
cc7d9a8
feat: support selecting node account ID for execution flow
aceppaluni Oct 29, 2025
dac9cd2
Fix node selection to use _select_node instead of _get_node
aceppaluni Oct 30, 2025
13a542a
feat: add Network._get_node() and update executable to support node s…
aceppaluni Nov 4, 2025
7ffc7e4
feat: move node account ID selection to _Executable and update execut…
aceppaluni Nov 10, 2025
f521241
Fix imports for List and AccountId; update executable; sync with main
aceppaluni Nov 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
- Added expiration_time, auto_renew_period, auto_renew_account, fee_schedule_key, kyc_key in `TokenCreateTransaction`, `TokenUpdateTransaction` classes
- Added comprehensive Google-style docstrings to the `CustomFee` class and its methods in `custom_fee.py`.
- docs: Add `docs/sdk_developers/project_structure.md` to explain repository layout and import paths.
- Support selecting specific node account ID(s) for queries and transactions and added `Network._get_node()` with updated execution flow (#362)

### Changed
- chore: bumped solo action from 14.0 to 15.0 (#764)
Expand Down
15 changes: 15 additions & 0 deletions src/hiero_sdk_python/client/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,21 @@ def _select_node(self) -> _Node:
self._node_index = (self._node_index + 1) % len(self.nodes)
self.current_node = self.nodes[self._node_index]
return self.current_node

def _get_node(self, account_id: AccountId) -> Optional[_Node]:
"""
Get a node matching the given account ID.

Args:
account_id (AccountId): The account ID of the node to locate.

Returns:
Optional[_Node]: The matching node, or None if not found.
"""
for node in self.nodes:
if node._account_id == account_id:
return node
return None

def get_mirror_address(self) -> str:
"""
Expand Down
36 changes: 32 additions & 4 deletions src/hiero_sdk_python/executable.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from os import error
import time
from typing import Callable, Optional, Any, TYPE_CHECKING
from typing import Callable, Optional, Any, TYPE_CHECKING, List
import grpc
from abc import ABC, abstractmethod
from enum import IntEnum

from hiero_sdk_python.channels import _Channel
from hiero_sdk_python.exceptions import MaxAttemptsError
from hiero_sdk_python.account.account_id import AccountId
if TYPE_CHECKING:
from hiero_sdk_python.client.client import Client

Expand Down Expand Up @@ -75,6 +76,26 @@ def __init__(self):
self._grpc_deadline = DEFAULT_GRPC_DEADLINE
self.node_account_id = None

Copy link
Contributor

@nadineloepfe nadineloepfe Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here in the imports you need to add List to:

from typing import Callable, Optional, Any, TYPE_CHECKING, List

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and actually underL

 if TYPE_CHECKING:
    from hiero_sdk_python.client.client import Client

I'd also add AccountId

self.node_account_ids: Optional[List[AccountId]] = None
self._used_node_account_id: Optional[AccountId] = None

def set_node_account_ids(self, node_account_ids: List[AccountId]):
"""Select node account IDs for sending the request."""
self.node_account_ids = node_account_ids
return self

def set_node_account_id(self, node_account_id: AccountId):
"""Convenience wrapper to set a single node account ID."""
return self.set_node_account_ids([node_account_id])

def _select_node_account_id(self) -> Optional[AccountId]:
"""Pick the first preferred node if available, otherwise None."""
if self.node_account_ids:
selected = self.node_account_ids[0]
self._used_node_account_id = selected
return selected
return None

@abstractmethod
def _should_retry(self, response) -> _ExecutionState:
"""
Expand Down Expand Up @@ -176,10 +197,17 @@ def _execute(self, client: "Client"):
if attempt > 0 and current_backoff < self._max_backoff:
current_backoff *= 2

# Set the node account id to the client's node account id
node = client.network.current_node
# Select preferred node if provided, fallback to client's default
selected = self._select_node_account_id()

if selected is not None:
node = client.network._get_node(selected)
else:
node = client.network.current_node

#Store for logging and receipts
self.node_account_id = node._account_id

# Create a channel wrapper from the client's channel
channel = node._get_channel()

Expand Down
4 changes: 4 additions & 0 deletions src/hiero_sdk_python/query/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ def __init__(self) -> None:
self.node_index: int = 0
self.payment_amount: Optional[Hbar] = None

self.node_account_ids: Optional[List[AccountId]] = None
Copy link
Contributor

@nadineloepfe nadineloepfe Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just seen - this is duplicated
there;s another self.node_account_ids on line 57. Please remove!

I've also created a branch here to see if it all works with some minor changes, see here:
https://github.com/hiero-ledger/hiero-sdk-python/pull/853/files#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4ed

mostly wanted to fix the weird error in the pipeline, hard to see what's going on

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking the time to clean this up and address the CI issues. I’ve reviewed the changes in your branch and they all make sense. Everything looks good from my side.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @aceppaluni
The tests here are still failing, what's the next steps? @nadineloepfe will you be working on the new branch any further, or will @aceppaluni use that for reference to update this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @exploreriii, I’m currently awaiting @nadineloepfe 's guidance on how she’d like to proceed. My understanding is that the branch she created will address the test issue and allow us to finalize this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@exploreriii @aceppaluni: correct! the branch I've raised is passing, so if you'd like you can take inspiration there, and we can also jump on a call to walk through what has been done and why - bit easier than doing it here in writing :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nadineloepfe @exploreriii : Great! Let me know what days and times work for everyone!
I will be available at certain points today. I will not be available tomorrow. I will be available again on Friday :)

self._used_node_account_id: Optional[AccountId] = None

def _get_query_response(self, response: Any) -> query_pb2.Query:
"""
Extracts the query-specific response object from the full response.
Expand Down Expand Up @@ -379,3 +382,4 @@ def _is_payment_required(self) -> bool:
bool: True if payment is required, False otherwise
"""
return True

4 changes: 2 additions & 2 deletions src/hiero_sdk_python/transaction/transaction.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import hashlib
from typing import Optional
from typing import List, Optional

from typing import TYPE_CHECKING

Expand Down Expand Up @@ -59,7 +59,7 @@ def __init__(self) -> None:
# and ensures that the correct signatures are used when submitting transactions
self._signature_map: dict[bytes, basic_types_pb2.SignatureMap] = {}
self._default_transaction_fee = 2_000_000
self.operator_account_id = None
self.operator_account_id = None

def _make_request(self):
"""
Expand Down
31 changes: 31 additions & 0 deletions tests/unit/test_query_nodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pytest
from hiero_sdk_python.query.query import Query
from hiero_sdk_python.account.account_id import AccountId

def test_set_single_node_account_id():
q = Query()
node = AccountId(0, 0, 3)

q.set_node_account_id(node)

assert q.node_account_ids == [node]
assert q._used_node_account_id is None # not selected until execution

def test_set_multiple_node_account_ids():
q = Query()
nodes = [AccountId(0, 0, 3), AccountId(0, 0, 4)]

q.set_node_account_ids(nodes)

assert q.node_account_ids == nodes
assert q._used_node_account_id is None

def test_select_node_account_id():
q = Query()
nodes = [AccountId(0, 0, 3), AccountId(0, 0, 4)]
q.set_node_account_ids(nodes)

selected = q._select_node_account_id()

assert selected == nodes[0]
assert q._used_node_account_id == nodes[0]
52 changes: 52 additions & 0 deletions tests/unit/test_transaction_nodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import pytest
from hiero_sdk_python.transaction.transaction import Transaction
from hiero_sdk_python.account.account_id import AccountId


class DummyTransaction(Transaction):
"""
Minimal subclass of Transaction for testing.
Transaction is abstract (requires build methods), so we stub them out.
"""
def __init__(self):
super().__init__()

def build_base_transaction_body(self):
return None # stub

def _make_request(self):
return None # stub

def _get_method(self):
return None # stub


def test_set_single_node_account_id():
txn = DummyTransaction()
node = AccountId(0, 0, 3)

txn.set_node_account_id(node)

assert txn.node_account_ids == [node]
assert txn._used_node_account_id is None


def test_set_multiple_node_account_ids():
txn = DummyTransaction()
nodes = [AccountId(0, 0, 3), AccountId(0, 0, 4)]

txn.set_node_account_ids(nodes)

assert txn.node_account_ids == nodes
assert txn._used_node_account_id is None


def test_select_node_account_id():
txn = DummyTransaction()
nodes = [AccountId(0, 0, 3), AccountId(0, 0, 4)]
txn.set_node_account_ids(nodes)

selected = txn._select_node_account_id()

assert selected == nodes[0]
assert txn._used_node_account_id == nodes[0]
Loading