Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 May 6, 2026
48e9322
feat: add HIP-1137 registered service endpoint models
danielmarv May 6, 2026
a7a0b37
Merge branch 'hiero-ledger:main' into hip-1137-br
danielmarv May 6, 2026
6c58126
feat: add HIP-1137 registered node transactions
danielmarv May 6, 2026
9ab77ab
Merge branch 'hip-1137-br' of https://github.com/danielmarv/hiero-sdk…
danielmarv May 6, 2026
cd2de39
feat: support associated registered nodes on node transactions
danielmarv May 6, 2026
0d76050
feat: add HIP-1137 registered node address book models
danielmarv May 6, 2026
87b9d90
test: harden HIP-1137 validation and status handling
danielmarv May 6, 2026
550ffdb
test: add HIP-1137 integration coverage and docs
danielmarv May 6, 2026
5fdbc50
test: add HIP-1137 integration coverage and docs
danielmarv May 6, 2026
2b9e6d3
test: add HIP-1137 integration coverage and docs
danielmarv May 6, 2026
b15ebd9
test: add HIP-1137 integration coverage and docs
danielmarv May 6, 2026
2025c27
Merge branch 'main' into hip-1137-br
danielmarv May 7, 2026
dca3d40
test: add HIP-1137 integration coverage and docs
danielmarv May 7, 2026
f47ed8b
Merge branch 'hip-1137-br' of https://github.com/danielmarv/hiero-sdk…
danielmarv May 7, 2026
54c5f31
test: add HIP-1137 integration coverage and docs
danielmarv May 7, 2026
1e86243
test: add HIP-1137 integration coverage and docs
danielmarv May 7, 2026
3b6ad9a
test: add HIP-1137 integration coverage and docs
danielmarv May 7, 2026
83cd770
Merge branch 'main' into hip-1137-br
danielmarv May 7, 2026
24212f4
Merge branch 'main' into hip-1137-br
danielmarv May 8, 2026
2bf5796
Merge branch 'main' into hip-1137-br
danielmarv May 11, 2026
7340544
feat: refactor registered node transactions and validation logic for …
danielmarv May 11, 2026
77aa5f8
Merge branch 'hip-1137-br' of https://github.com/danielmarv/hiero-sdk…
danielmarv May 11, 2026
c928195
feat: refactor registered node transactions and validation logic for …
danielmarv May 11, 2026
0be6eec
feat: refactor registered node transactions and validation logic for …
danielmarv May 11, 2026
d4f0fa0
feat: refactor registered node transactions and validation logic for …
danielmarv May 11, 2026
2345b42
Merge branch 'main' into hip-1137-br
danielmarv May 11, 2026
bb587da
Merge branch 'main' into hip-1137-br
danielmarv May 12, 2026
b267997
Merge branch 'main' into hip-1137-br
danielmarv May 13, 2026
b922cc9
test: Enhance NodeCreate and NodeUpdate tests for associated register…
danielmarv May 13, 2026
58ccff7
feat: Enhance registered node lifecycle example and add query functio…
danielmarv May 13, 2026
acfcf6f
Merge branch 'main' into hip-1137-br
danielmarv May 13, 2026
f100f5f
Merge branch 'main' into hip-1137-br
danielmarv May 14, 2026
c0dba0e
feat: Implement from_dict methods for service endpoints and enhance t…
danielmarv May 14, 2026
b69107b
Merge branch 'hip-1137-br' of https://github.com/danielmarv/hiero-sdk…
danielmarv May 14, 2026
c231de7
Merge branch 'main' into hip-1137-br
danielmarv May 14, 2026
dced5fd
feat: Implement from_dict methods for service endpoints and enhance t…
danielmarv May 14, 2026
7144c0e
feat: Implement from_dict methods for service endpoints and enhance t…
danielmarv May 14, 2026
9aa777a
Merge branch 'main' into hip-1137-br
danielmarv May 14, 2026
1206a86
feat: Implement from_dict methods for service endpoints and enhance t…
danielmarv May 14, 2026
51287f5
feat: Implement from_dict methods for service endpoints and enhance t…
danielmarv May 14, 2026
3bc52f8
Merge branch 'main' into hip-1137-br
danielmarv May 15, 2026
ad2a72e
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv May 15, 2026
fb7f464
Merge branch 'main' into hip-1137-br
danielmarv May 15, 2026
ad9ffe2
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv May 15, 2026
32d308e
Merge branch 'hip-1137-br' of https://github.com/danielmarv/hiero-sdk…
danielmarv May 15, 2026
fc186b9
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv May 16, 2026
bcfae47
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv May 16, 2026
0fbd578
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv May 16, 2026
366d56f
feat: Add setter methods for service endpoint attributes and enhance …
danielmarv May 16, 2026
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
208 changes: 208 additions & 0 deletions examples/nodes/registered_node_lifecycle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
"""
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. Query the registered node via the mirror node REST API
3. Update the registered node's description and service endpoints
4. Associate / disassociate the registered node with a consensus node
5. 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
import time

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.registered_node_address_book_query import RegisteredNodeAddressBookQuery
from hiero_sdk_python.exceptions import PrecheckError
from hiero_sdk_python.nodes.node_update_transaction import NodeUpdateTransaction
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"
Comment thread
aceppaluni marked this conversation as resolved.
)
client.set_operator(AccountId(0, 0, 2), original_operator_key)

return client


def registered_node_lifecycle():
"""Demonstrates create, query, update, associate, disassociate, 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--- Step 1: Creating registered node ---")

block_endpoint = BlockNodeServiceEndpoint(
ip_address=bytes([127, 0, 0, 1]),
port=443,
requires_tls=True,
endpoint_apis=[BlockNodeApi.STATUS, BlockNodeApi.SUBSCRIBE_STREAM],
)

try:
receipt = (
RegisteredNodeCreateTransaction()
.set_admin_key(admin_key.public_key())
.set_description("My 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: Query the registered node via mirror node ───────────
print("\n--- Step 2: Querying registered node via mirror node ---")

# Wait for mirror node ingestion
time.sleep(5)

try:
address_book = RegisteredNodeAddressBookQuery().set_registered_node_id(registered_node_id).execute(client)

if len(address_book) > 0:
node = address_book[0]
print(f"Fetched registered node: {node}")
print(f" Description: {node.description}")
print(f" Endpoints: {len(node.service_endpoints)}")
else:
print("No registered nodes returned (mirror may still be ingesting)")
except RuntimeError as e:
print(f"Query failed (mirror node may not support this endpoint): {e}")

# ── Step 3: Update the registered node ──────────────────────────
print("\n--- Step 3: Updating registered node ---")

update_endpoint = BlockNodeServiceEndpoint(
domain_name="block-node.example.com",
port=443,
requires_tls=True,
endpoint_apis=[BlockNodeApi.STATUS],
)

try:
receipt = (
RegisteredNodeUpdateTransaction()
.set_registered_node_id(registered_node_id)
.set_description("My Updated Block Node")
.set_service_endpoints([block_endpoint, update_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 4: Associate registered node with consensus node ───────
print("\n--- Step 4: Associating registered node with consensus node 0 ---")

try:
receipt = (
NodeUpdateTransaction()
.set_node_id(0)
.add_associated_registered_node(registered_node_id)
.freeze_with(client)
.execute(client)
)
except (PrecheckError, ValueError) as e:
print(f"Association failed: {e}")
sys.exit(1)

if receipt.status != ResponseCode.SUCCESS:
print(f"Association failed: {ResponseCode(receipt.status).name}")
sys.exit(1)

print(f"Registered node {registered_node_id} associated with consensus node 0")

# ── Step 5: Disassociate registered node from consensus node ────
print("\n--- Step 5: Disassociating registered node from consensus node 0 ---")

try:
receipt = (
NodeUpdateTransaction()
.set_node_id(0)
.clear_associated_registered_nodes()
.freeze_with(client)
.execute(client)
)
except (PrecheckError, ValueError) as e:
print(f"Disassociation failed: {e}")
sys.exit(1)

if receipt.status != ResponseCode.SUCCESS:
print(f"Disassociation failed: {ResponseCode(receipt.status).name}")
sys.exit(1)

print(f"Registered node {registered_node_id} disassociated from consensus node 0")

# ── Step 6: Delete the registered node ──────────────────────────
print("\n--- Step 6: 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()
Comment thread
aceppaluni marked this conversation as resolved.
2 changes: 1 addition & 1 deletion generate_proto.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from urllib.parse import urlparse


VERSION = "v0.72.1"
VERSION = "v0.73.0"
SOURCES = [
{
"name": "hedera-protobufs",
Expand Down
24 changes: 24 additions & 0 deletions src/hiero_sdk_python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,17 @@
from .account.account_update_transaction import AccountUpdateTransaction

# Address book
from .address_book.block_node_api import BlockNodeApi
from .address_book.block_node_service_endpoint import BlockNodeServiceEndpoint
from .address_book.endpoint import Endpoint
from .address_book.general_service_endpoint import GeneralServiceEndpoint
from .address_book.mirror_node_service_endpoint import MirrorNodeServiceEndpoint
from .address_book.node_address import NodeAddress
from .address_book.registered_node import RegisteredNode
from .address_book.registered_node_address_book import RegisteredNodeAddressBook
from .address_book.registered_node_address_book_query import RegisteredNodeAddressBookQuery
from .address_book.registered_service_endpoint import RegisteredServiceEndpoint
from .address_book.rpc_relay_service_endpoint import RpcRelayServiceEndpoint

# Client and Network
from .client.client import Client
Expand Down Expand Up @@ -77,6 +86,9 @@
from .nodes.node_create_transaction import NodeCreateTransaction
from .nodes.node_delete_transaction import NodeDeleteTransaction
from .nodes.node_update_transaction import NodeUpdateTransaction
from .nodes.registered_node_create_transaction import RegisteredNodeCreateTransaction
from .nodes.registered_node_delete_transaction import RegisteredNodeDeleteTransaction
from .nodes.registered_node_update_transaction import RegisteredNodeUpdateTransaction

# PRNG
from .prng_transaction import PrngTransaction
Expand Down Expand Up @@ -245,8 +257,17 @@
"TokenInfoQuery",
"AccountInfoQuery",
# Address book
"BlockNodeApi",
"BlockNodeServiceEndpoint",
"Endpoint",
"GeneralServiceEndpoint",
"MirrorNodeServiceEndpoint",
"NodeAddress",
"RegisteredNode",
"RegisteredNodeAddressBook",
"RegisteredNodeAddressBookQuery",
"RegisteredServiceEndpoint",
"RpcRelayServiceEndpoint",
# Logger
"Logger",
"LogLevel",
Expand Down Expand Up @@ -296,6 +317,9 @@
"NodeCreateTransaction",
"NodeUpdateTransaction",
"NodeDeleteTransaction",
"RegisteredNodeCreateTransaction",
"RegisteredNodeUpdateTransaction",
"RegisteredNodeDeleteTransaction",
# PRNG
"PrngTransaction",
# Custom Fees
Expand Down
13 changes: 13 additions & 0 deletions src/hiero_sdk_python/address_book/block_node_api.py
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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)
self.endpoint_apis: list[BlockNodeApi] = [BlockNodeApi(api) for api in (endpoint_apis or [])]

def set_endpoint_apis(self, endpoint_apis: list[BlockNodeApi]) -> BlockNodeServiceEndpoint:
"""Set the list of block node endpoint APIs."""
self.endpoint_apis = [BlockNodeApi(api) for api in endpoint_apis]
return self

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]
return cls(
ip_address=ip_address,
domain_name=domain_name,
port=port,
requires_tls=requires_tls,
endpoint_apis=apis,
)
Comment thread
aceppaluni marked this conversation as resolved.

@classmethod
def _from_dict_inner(cls, type_data: dict, **base_kwargs) -> BlockNodeServiceEndpoint:
"""Build from the ``block_node`` sub-dict of a mirror-node JSON endpoint."""
raw_apis = type_data.get("endpoint_apis") or []
apis = [BlockNodeApi[a.upper()] if isinstance(a, str) else BlockNodeApi(a) for a in raw_apis]
return cls(endpoint_apis=apis, **base_kwargs)
Loading
Loading