Skip to content

[Advanced]: Implement HIP-1137 — Block Node discoverability via on-chain registry #1206

@rwalworth

Description

@rwalworth

🧠 Advanced

This issue is well-suited for contributors who are very familiar with the Hiero C++ SDK and enjoy working with its core abstractions and design patterns.

Advanced Issues often involve:

  • Exploring and shaping SDK architecture
  • Reasoning about trade-offs and long-term impact
  • Working across multiple modules or systems
  • Updating tests, examples, and documentation alongside code

The goal is to support thoughtful, high-impact contributions in a clear and collaborative way.

🐞 Problem Description

The Hiero C++ SDK does not currently support the registered node registry introduced by HIP-1137. This means SDK users cannot create, update, delete, or discover Block Nodes (or other registered node types such as mirror nodes and RPC relays) via on-chain data.

HIP-1137 adds three new transactions to the AddressBookService and extends several existing types. Without SDK support, developers must resort to raw protobuf construction to interact with the registered node registry — an experience that undermines the purpose of a typed, ergonomic SDK.

Key gaps:

  • No RegisteredNodeCreateTransaction, RegisteredNodeUpdateTransaction, or RegisteredNodeDeleteTransaction classes
  • No RegisteredServiceEndpoint hierarchy (BlockNodeServiceEndpoint, MirrorNodeServiceEndpoint, RpcRelayServiceEndpoint)
  • No BlockNodeApi enum
  • TransactionReceipt does not expose the registeredNodeId field
  • NodeCreateTransaction and NodeUpdateTransaction do not support the new associatedRegisteredNodes field
  • No RegisteredNode, RegisteredNodeAddressBook, or RegisteredNodeAddressBookQuery types

💡 Proposed / Expected Outcome

Implement full SDK support for HIP-1137 following the SDK design document and the patterns already established in the codebase for consensus node transactions (NodeCreateTransaction, NodeUpdateTransaction, NodeDeleteTransaction).

The implementation should deliver:

New transaction types

  • RegisteredNodeCreateTransaction — creates a registered node with an adminKey, optional description, optional nodeAccountId, and a list of service endpoints (1–50). On success the receipt contains the network-assigned registeredNodeId.
  • RegisteredNodeUpdateTransaction — updates an existing registered node by registeredNodeId. Supports changing adminKey (requires both old and new key signatures), description, nodeAccountId, and replacing the service endpoint list.
  • RegisteredNodeDeleteTransaction — removes a registered node by registeredNodeId. Must be signed by the node's adminKey or authorized by network governance.

All three transactions must be schedulable via ScheduleCreateTransaction.

New data types

  • BlockNodeApi enum — OTHER, STATUS, PUBLISH, SUBSCRIBE_STREAM, STATE_PROOF.
  • RegisteredServiceEndpoint — abstract base with ipAddress (bytes) or domainName (string), port, and requiresTls. Three concrete subtypes:
    • BlockNodeServiceEndpoint — adds endpointApi: BlockNodeApi
    • MirrorNodeServiceEndpoint — empty subtype (future-proofing)
    • RpcRelayServiceEndpoint — empty subtype (future-proofing)
  • RegisteredNode — immutable representation of a registered node as stored in network state.
  • RegisteredNodeAddressBook — collection of RegisteredNode objects.

New query type

  • RegisteredNodeAddressBookQuery — queries the mirror node for registered nodes and returns a RegisteredNodeAddressBook. Implementation should be deferred until the mirror node API is available, but the class skeleton should be defined.

Updates to existing types

  • TransactionReceipt — add nullable registeredNodeId: uint64 field.
  • NodeCreateTransaction — add associatedRegisteredNodes: list<uint64> and addAssociatedRegisteredNode(uint64).
  • NodeUpdateTransaction — add nullable associatedRegisteredNodes: list<uint64>,
    addAssociatedRegisteredNode(uint64), and clearAssociatedRegisteredNodes(). The protobuf uses a wrapper message for three-state semantics (not set / empty list / non-empty list).

Wiring

  • Add RegisteredNodeCreate, RegisteredNodeUpdate, RegisteredNodeDelete to the TransactionType enum.
  • Register the new transaction types in the Transaction.cc dispatch switch and add them to WrappedTransaction's variant.
  • Map to protobuf DataCase values (kRegisteredNodeCreate, kRegisteredNodeUpdate, kRegisteredNodeDelete) and schedulable body fields.

🧠 Implementation & Design Notes

Patterns to follow

The existing NodeCreateTransaction / NodeUpdateTransaction / NodeDeleteTransaction implementations serve as the primary reference. Each new registered node transaction should follow the same CRTP pattern:

class RegisteredNodeCreateTransaction : public Transaction<RegisteredNodeCreateTransaction>

Key methods to implement per transaction:

  • addToBody(proto::TransactionBody&) — set the allocated protobuf body
  • initFromSourceTransactionBody() — deserialize from protobuf
  • build() — construct and return the protobuf transaction body
  • submitRequest() — submit using the correct DataCase

Endpoint hierarchy

The design document specifies an inheritance-based endpoint hierarchy. In C++ this maps to:

  • A base RegisteredServiceEndpoint class (or struct) holding the shared fields (ipAddress, domainName, port, requiresTls)
  • Derived BlockNodeServiceEndpoint adding BlockNodeApi endpointApi
  • Derived MirrorNodeServiceEndpoint and RpcRelayServiceEndpoint as currently empty subtypes

Each subtype needs fromProtobuf() / toProtobuf() round-trip support, following the pattern in Endpoint.h / Endpoint.cc.

Key files to modify or create

New headers and sources (under src/sdk/main/include/ and src/sdk/main/src/):

  • RegisteredNodeCreateTransaction.h / .cc
  • RegisteredNodeUpdateTransaction.h / .cc
  • RegisteredNodeDeleteTransaction.h / .cc
  • RegisteredServiceEndpoint.h / .cc
  • BlockNodeServiceEndpoint.h / .cc
  • MirrorNodeServiceEndpoint.h / .cc
  • RpcRelayServiceEndpoint.h / .cc
  • BlockNodeApi.h
  • RegisteredNode.h / .cc
  • RegisteredNodeAddressBook.h / .cc
  • RegisteredNodeAddressBookQuery.h / .cc

Existing files to update:

  • TransactionReceipt.h / .cc — add registeredNodeId
  • NodeCreateTransaction.h / .cc — add associatedRegisteredNodes
  • NodeUpdateTransaction.h / .cc — add associatedRegisteredNodes with
    three-state wrapper semantics
  • TransactionType.h — add enum values
  • Transaction.cc — register new types in the DataCase switch
  • WrappedTransaction.h — add new types to the variant
  • CMake build files — add new source/header files

Protobuf dependencies

The implementation depends on new protobuf definitions from HIP-1137. Ensure the proto submodule or dependency includes:

  • registered_node_create.proto
  • registered_node_update.proto
  • registered_node_delete.proto
  • registered_service_endpoint.proto (or equivalent)
  • Updated transaction_body.proto (fields 78–80)
  • Updated schedulable_transaction_body.proto (fields 49–51)
  • Updated transaction_receipt.proto (field 16)

Testing strategy

  1. Unit tests — verify serialization round-trips (fromProtobuf / toProtobuf) for all new types, field validation (e.g. endpoint list bounds), and getter/setter correctness.
  2. Integration tests — execute the full registered node lifecycle against a test network:
    • Create a registered node with various endpoint types and verify the receipt contains a registeredNodeId
    • Update the node's description, endpoints, and admin key
    • Associate a registered node with a consensus node
    • Delete the registered node
    • Verify failure cases (missing admin key, empty endpoints, non-existent node ID, already-deleted node)
  3. TCK alignment — corresponding test cases should be defined in the TCK repository per the design document's 18-point test plan.

Schedulability

All three transactions must be schedulable. The SDK already has internal machinery for this — ensure each new transaction is included in SchedulableTransactionBody handling.

Response codes

HIP-1137 does not define new response codes at this time. If consensus node implementation introduces registered-node-specific response codes, the SDK's retry logic should be evaluated and updated.

✅ Acceptance Criteria

A pull request for this issue should:

  • Implement RegisteredNodeCreateTransaction, RegisteredNodeUpdateTransaction, and RegisteredNodeDeleteTransaction following existing transaction patterns
  • Implement the RegisteredServiceEndpoint hierarchy (BlockNodeServiceEndpoint, MirrorNodeServiceEndpoint, RpcRelayServiceEndpoint) and the BlockNodeApi enum
  • Implement RegisteredNode and RegisteredNodeAddressBook data types
  • Define the RegisteredNodeAddressBookQuery class skeleton
  • Update TransactionReceipt to expose registeredNodeId
  • Update NodeCreateTransaction and NodeUpdateTransaction with associatedRegisteredNodes support
  • Register new transaction types in TransactionType, Transaction.cc dispatch, and WrappedTransaction variant
  • Ensure all three new transactions are schedulable
  • Include unit tests for serialization, field validation, and getter/setter correctness
  • Include integration tests covering the registered node lifecycle (create, update, associate, delete, and failure cases)
  • Maintain backwards compatibility with existing APIs
  • Follow existing C++ conventions and architectural patterns
  • Pass all CI checks

📚 Additional Context, Links, or Prior Art

Metadata

Metadata

Assignees

Labels

priority: highImportant issue that should be prioritized in the current sprint/releasescope: apiRelated to the public SDK API surfacescope: examplesRelated to example projects or snippetsscope: grpcRelated to gRPC/protobuf/network layerskill: advancedRequires deep understanding of the SDK architecture and may span multiple modulesstatus: in progressSomeone is actively working on this issue

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions