-
Notifications
You must be signed in to change notification settings - Fork 298
Implements HIP-1137 registered node support in the Python SDK. #2248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 30 commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
209bf5c
feat: update protobufs to v0.73.0 for HIP-1137
danielmarv 48e9322
feat: add HIP-1137 registered service endpoint models
danielmarv a7a0b37
Merge branch 'hiero-ledger:main' into hip-1137-br
danielmarv 6c58126
feat: add HIP-1137 registered node transactions
danielmarv 9ab77ab
Merge branch 'hip-1137-br' of https://github.com/danielmarv/hiero-sdk…
danielmarv cd2de39
feat: support associated registered nodes on node transactions
danielmarv 0d76050
feat: add HIP-1137 registered node address book models
danielmarv 87b9d90
test: harden HIP-1137 validation and status handling
danielmarv 550ffdb
test: add HIP-1137 integration coverage and docs
danielmarv 5fdbc50
test: add HIP-1137 integration coverage and docs
danielmarv 2b9e6d3
test: add HIP-1137 integration coverage and docs
danielmarv b15ebd9
test: add HIP-1137 integration coverage and docs
danielmarv 2025c27
Merge branch 'main' into hip-1137-br
danielmarv dca3d40
test: add HIP-1137 integration coverage and docs
danielmarv f47ed8b
Merge branch 'hip-1137-br' of https://github.com/danielmarv/hiero-sdk…
danielmarv 54c5f31
test: add HIP-1137 integration coverage and docs
danielmarv 1e86243
test: add HIP-1137 integration coverage and docs
danielmarv 3b6ad9a
test: add HIP-1137 integration coverage and docs
danielmarv 83cd770
Merge branch 'main' into hip-1137-br
danielmarv 24212f4
Merge branch 'main' into hip-1137-br
danielmarv 2bf5796
Merge branch 'main' into hip-1137-br
danielmarv 7340544
feat: refactor registered node transactions and validation logic for …
danielmarv 77aa5f8
Merge branch 'hip-1137-br' of https://github.com/danielmarv/hiero-sdk…
danielmarv c928195
feat: refactor registered node transactions and validation logic for …
danielmarv 0be6eec
feat: refactor registered node transactions and validation logic for …
danielmarv d4f0fa0
feat: refactor registered node transactions and validation logic for …
danielmarv 2345b42
Merge branch 'main' into hip-1137-br
danielmarv bb587da
Merge branch 'main' into hip-1137-br
danielmarv b267997
Merge branch 'main' into hip-1137-br
danielmarv b922cc9
test: Enhance NodeCreate and NodeUpdate tests for associated register…
danielmarv 58ccff7
feat: Enhance registered node lifecycle example and add query functio…
danielmarv acfcf6f
Merge branch 'main' into hip-1137-br
danielmarv f100f5f
Merge branch 'main' into hip-1137-br
danielmarv c0dba0e
feat: Implement from_dict methods for service endpoints and enhance t…
danielmarv b69107b
Merge branch 'hip-1137-br' of https://github.com/danielmarv/hiero-sdk…
danielmarv c231de7
Merge branch 'main' into hip-1137-br
danielmarv dced5fd
feat: Implement from_dict methods for service endpoints and enhance t…
danielmarv 7144c0e
feat: Implement from_dict methods for service endpoints and enhance t…
danielmarv 9aa777a
Merge branch 'main' into hip-1137-br
danielmarv 1206a86
feat: Implement from_dict methods for service endpoints and enhance t…
danielmarv 51287f5
feat: Implement from_dict methods for service endpoints and enhance t…
danielmarv 3bc52f8
Merge branch 'main' into hip-1137-br
danielmarv ad2a72e
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv fb7f464
Merge branch 'main' into hip-1137-br
danielmarv ad9ffe2
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv 32d308e
Merge branch 'hip-1137-br' of https://github.com/danielmarv/hiero-sdk…
danielmarv fc186b9
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv bcfae47
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv 0fbd578
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv 366d56f
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| """ | ||
| Demonstrates the full lifecycle of a registered node on the Hedera network. | ||
|
|
||
| This example shows how to: | ||
| 1. Create a registered node with BlockNodeServiceEndpoint and multiple endpoint APIs | ||
| 2. Update the registered node's description and service endpoints | ||
| 3. Delete the registered node | ||
|
|
||
| NOTE: This is a privileged transaction. Regular developers do not have the required | ||
| permissions to manage registered nodes on testnet or mainnet as this operation | ||
| requires special authorization. | ||
|
|
||
| This example is provided to demonstrate the API for educational purposes or for use | ||
| in private network deployments where you have the necessary administrative privileges. | ||
| """ | ||
|
|
||
| import sys | ||
|
|
||
| from dotenv import load_dotenv | ||
|
|
||
| from hiero_sdk_python import AccountId, Client, Network, PrivateKey | ||
| from hiero_sdk_python.address_book.block_node_api import BlockNodeApi | ||
| from hiero_sdk_python.address_book.block_node_service_endpoint import BlockNodeServiceEndpoint | ||
| from hiero_sdk_python.address_book.mirror_node_service_endpoint import MirrorNodeServiceEndpoint | ||
| from hiero_sdk_python.exceptions import PrecheckError | ||
| from hiero_sdk_python.nodes.registered_node_create_transaction import RegisteredNodeCreateTransaction | ||
| from hiero_sdk_python.nodes.registered_node_delete_transaction import RegisteredNodeDeleteTransaction | ||
| from hiero_sdk_python.nodes.registered_node_update_transaction import RegisteredNodeUpdateTransaction | ||
| from hiero_sdk_python.response_code import ResponseCode | ||
|
|
||
|
|
||
| def setup_client(): | ||
| """Initialize and set up the client with operator account.""" | ||
| load_dotenv() | ||
| network = Network(network="solo") | ||
| client = Client(network) | ||
| print(f"Connecting to Hedera {network} network!") | ||
|
|
||
| # Account 0.0.2 is a special administrative account with | ||
| # elevated privileges for network management operations. | ||
| # The private key is intentionally public for local development. | ||
| # Note: This setup only works on solo network and will not work on testnet/mainnet. | ||
| original_operator_key = PrivateKey.from_string_der( | ||
| "302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137" | ||
| ) | ||
| client.set_operator(AccountId(0, 0, 2), original_operator_key) | ||
|
|
||
| return client | ||
|
|
||
|
|
||
| def registered_node_lifecycle(): | ||
| """Demonstrates create, update, and delete of a registered node.""" | ||
| client = setup_client() | ||
|
|
||
| # Generate an admin key for the registered node | ||
| admin_key = PrivateKey.generate_ed25519() | ||
|
|
||
| # ── Step 1: Create a registered node ──────────────────────────── | ||
| print("\n--- Creating registered node ---") | ||
|
|
||
| block_endpoint = BlockNodeServiceEndpoint( | ||
| domain_name="block.example.com", | ||
| port=443, | ||
| requires_tls=True, | ||
| endpoint_apis=[BlockNodeApi.STATUS, BlockNodeApi.SUBSCRIBE_STREAM], | ||
| ) | ||
|
|
||
| try: | ||
| receipt = ( | ||
| RegisteredNodeCreateTransaction() | ||
| .set_admin_key(admin_key.public_key()) | ||
| .set_description("Example block node") | ||
| .set_service_endpoints([block_endpoint]) | ||
| .freeze_with(client) | ||
| .sign(admin_key) | ||
| .execute(client) | ||
| ) | ||
| except (PrecheckError, ValueError) as e: | ||
| print(f"Registered node creation failed: {e}") | ||
| sys.exit(1) | ||
|
|
||
| if receipt.status != ResponseCode.SUCCESS: | ||
| print(f"Registered node creation failed: {ResponseCode(receipt.status).name}") | ||
| sys.exit(1) | ||
|
|
||
| registered_node_id = receipt.registered_node_id | ||
| print(f"Registered node created with ID: {registered_node_id}") | ||
|
|
||
| # ── Step 2: Update the registered node ────────────────────────── | ||
| print("\n--- Updating registered node ---") | ||
|
|
||
| mirror_endpoint = MirrorNodeServiceEndpoint( | ||
| domain_name="mirror.example.com", | ||
| port=5600, | ||
| requires_tls=True, | ||
| ) | ||
|
|
||
| try: | ||
| receipt = ( | ||
| RegisteredNodeUpdateTransaction() | ||
| .set_registered_node_id(registered_node_id) | ||
| .set_description("Updated block + mirror node") | ||
| .set_service_endpoints([block_endpoint, mirror_endpoint]) | ||
| .freeze_with(client) | ||
| .sign(admin_key) | ||
| .execute(client) | ||
| ) | ||
| except (PrecheckError, ValueError) as e: | ||
| print(f"Registered node update failed: {e}") | ||
| sys.exit(1) | ||
|
|
||
| if receipt.status != ResponseCode.SUCCESS: | ||
| print(f"Registered node update failed: {ResponseCode(receipt.status).name}") | ||
| sys.exit(1) | ||
|
|
||
| print("Registered node updated successfully") | ||
|
|
||
| # ── Step 3: Delete the registered node ────────────────────────── | ||
| print("\n--- Deleting registered node ---") | ||
|
|
||
| try: | ||
| receipt = ( | ||
| RegisteredNodeDeleteTransaction() | ||
| .set_registered_node_id(registered_node_id) | ||
| .freeze_with(client) | ||
| .sign(admin_key) | ||
| .execute(client) | ||
| ) | ||
| except (PrecheckError, ValueError) as e: | ||
| print(f"Registered node deletion failed: {e}") | ||
| sys.exit(1) | ||
|
|
||
| if receipt.status != ResponseCode.SUCCESS: | ||
| print(f"Registered node deletion failed: {ResponseCode(receipt.status).name}") | ||
| sys.exit(1) | ||
|
|
||
| print("Registered node deleted successfully") | ||
| print("\n--- Registered node lifecycle complete ---") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| registered_node_lifecycle() | ||
|
aceppaluni marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from enum import IntEnum | ||
|
|
||
|
|
||
| class BlockNodeApi(IntEnum): | ||
| """Maps to the BlockNodeApi enum defined inside RegisteredServiceEndpoint.BlockNodeEndpoint.""" | ||
|
|
||
| OTHER = 0 | ||
| STATUS = 1 | ||
| PUBLISH = 2 | ||
| SUBSCRIBE_STREAM = 3 | ||
| STATE_PROOF = 4 |
49 changes: 49 additions & 0 deletions
49
src/hiero_sdk_python/address_book/block_node_service_endpoint.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from hiero_sdk_python.address_book.block_node_api import BlockNodeApi | ||
| from hiero_sdk_python.address_book.registered_service_endpoint import RegisteredServiceEndpoint | ||
| from hiero_sdk_python.hapi.services.registered_service_endpoint_pb2 import ( | ||
| RegisteredServiceEndpoint as RegisteredServiceEndpointProto, | ||
| ) | ||
|
|
||
|
|
||
| class BlockNodeServiceEndpoint(RegisteredServiceEndpoint): | ||
| """A registered service endpoint for a block node.""" | ||
|
|
||
| def __init__( | ||
| self, | ||
| ip_address: bytes | None = None, | ||
| domain_name: str | None = None, | ||
| port: int = 0, | ||
| requires_tls: bool = False, | ||
| endpoint_apis: list[BlockNodeApi] | None = None, | ||
| ) -> None: | ||
| super().__init__(ip_address=ip_address, domain_name=domain_name, port=port, requires_tls=requires_tls) | ||
| if endpoint_apis is None or len(endpoint_apis) == 0: | ||
| raise ValueError("endpoint_apis must be non-empty") | ||
| self.endpoint_apis: list[BlockNodeApi] = [BlockNodeApi(api) for api in endpoint_apis] | ||
|
|
||
|
danielmarv marked this conversation as resolved.
Outdated
|
||
| def _set_endpoint_type(self, proto: RegisteredServiceEndpointProto) -> None: | ||
| block_node = proto.block_node | ||
| for api in self.endpoint_apis: | ||
| block_node.endpoint_api.append(api.value) | ||
|
|
||
| @classmethod | ||
| def _from_proto_inner( | ||
| cls, | ||
| proto: RegisteredServiceEndpointProto, | ||
| ip_address: bytes | None, | ||
| domain_name: str | None, | ||
| port: int, | ||
| requires_tls: bool, | ||
| ) -> BlockNodeServiceEndpoint: | ||
| apis = [BlockNodeApi(v) for v in proto.block_node.endpoint_api] | ||
| if not apis: | ||
|
danielmarv marked this conversation as resolved.
Outdated
|
||
| apis = [BlockNodeApi.OTHER] | ||
| return cls( | ||
| ip_address=ip_address, | ||
| domain_name=domain_name, | ||
| port=port, | ||
| requires_tls=requires_tls, | ||
| endpoint_apis=apis, | ||
| ) | ||
|
aceppaluni marked this conversation as resolved.
|
||
47 changes: 47 additions & 0 deletions
47
src/hiero_sdk_python/address_book/general_service_endpoint.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from hiero_sdk_python.address_book.registered_service_endpoint import RegisteredServiceEndpoint | ||
| from hiero_sdk_python.hapi.services.registered_service_endpoint_pb2 import ( | ||
| RegisteredServiceEndpoint as RegisteredServiceEndpointProto, | ||
| ) | ||
|
|
||
|
|
||
| class GeneralServiceEndpoint(RegisteredServiceEndpoint): | ||
| """A registered service endpoint for a general service.""" | ||
|
|
||
| def __init__( | ||
| self, | ||
| ip_address: bytes | None = None, | ||
| domain_name: str | None = None, | ||
| port: int = 0, | ||
| requires_tls: bool = False, | ||
| description: str | None = None, | ||
| ) -> None: | ||
| super().__init__(ip_address=ip_address, domain_name=domain_name, port=port, requires_tls=requires_tls) | ||
| if description is not None and len(description.encode("utf-8")) > 100: | ||
| raise ValueError("description must be 100 UTF-8 bytes or fewer") | ||
| self.description: str | None = description | ||
|
|
||
| def _set_endpoint_type(self, proto: RegisteredServiceEndpointProto) -> None: | ||
| if self.description is not None: | ||
| proto.general_service.description = self.description | ||
| else: | ||
| proto.general_service.SetInParent() | ||
|
|
||
| @classmethod | ||
| def _from_proto_inner( | ||
| cls, | ||
| proto: RegisteredServiceEndpointProto, | ||
| ip_address: bytes | None, | ||
| domain_name: str | None, | ||
| port: int, | ||
| requires_tls: bool, | ||
| ) -> GeneralServiceEndpoint: | ||
| desc = proto.general_service.description or None | ||
| return cls( | ||
| ip_address=ip_address, | ||
| domain_name=domain_name, | ||
| port=port, | ||
| requires_tls=requires_tls, | ||
| description=desc, | ||
| ) |
30 changes: 30 additions & 0 deletions
30
src/hiero_sdk_python/address_book/mirror_node_service_endpoint.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from hiero_sdk_python.address_book.registered_service_endpoint import RegisteredServiceEndpoint | ||
| from hiero_sdk_python.hapi.services.registered_service_endpoint_pb2 import ( | ||
| RegisteredServiceEndpoint as RegisteredServiceEndpointProto, | ||
| ) | ||
|
|
||
|
|
||
| class MirrorNodeServiceEndpoint(RegisteredServiceEndpoint): | ||
| """A registered service endpoint for a mirror node.""" | ||
|
|
||
| def _set_endpoint_type(self, proto: RegisteredServiceEndpointProto) -> None: | ||
| # Accessing the field initializes the oneof to mirror_node | ||
| proto.mirror_node.SetInParent() | ||
|
|
||
| @classmethod | ||
| def _from_proto_inner( | ||
| cls, | ||
| _proto: RegisteredServiceEndpointProto, | ||
| ip_address: bytes | None, | ||
| domain_name: str | None, | ||
| port: int, | ||
| requires_tls: bool, | ||
| ) -> MirrorNodeServiceEndpoint: | ||
| return cls( | ||
| ip_address=ip_address, | ||
| domain_name=domain_name, | ||
| port=port, | ||
| requires_tls=requires_tls, | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.