diff --git a/HIP/hip-869.md b/HIP/hip-869.md index 68537f192..be0f3956d 100644 --- a/HIP/hip-869.md +++ b/HIP/hip-869.md @@ -11,7 +11,7 @@ status: Accepted last-call-date-time: 2023-02-14T07:00:00Z created: 2024-01-22 discussions-to: https://github.com/hashgraph/hedera-improvement-proposal/pull/869 -updated: 2024-05-21 +updated: 2024-07-31 --- ## Abstract @@ -101,141 +101,273 @@ Adopting a two-phase strategy, this approach facilitated the earlier release of This HIP proposes the introduction of a new NodeService API that enables a node operator to create, delete, and update nodes. All of these transactions must be signed by the Hedera Council. ```protobuf -service NodeService { - /** - * Prepare to add a new node to the network. - * When a valid council member initiates a HAPI transaction to add a new node, - * then the network should acknowledge the transaction and update the network’s Address Book within 24 hours. - * The added node will not be active until the network is upgraded. +service AddressBookService { + /** + * A transaction to create a new consensus node in the network + * address book. + *

+ * This transaction, once complete, SHALL add a new consensus node to the + * network state.
+ * The new consensus node SHALL remain in state, but SHALL NOT participate + * in network consensus until the network updates the network configuration. + *

+ * Hedera governing council authorization is REQUIRED for this transaction. */ - rpc createNode (Transaction) returns (TransactionResponse); + rpc createNode (proto.Transaction) returns (proto.TransactionResponse); /** - * Prepare to delete the node to the network. - * The deleted node will not be deleted until the network is upgraded. - * Such a deleted node can never be reused. + * A transaction to remove a consensus node from the network address + * book. + *

+ * This transaction, once complete, SHALL remove the identified consensus + * node from the network state. + *

+ * Hedera governing council authorization is REQUIRED for this transaction. */ - rpc deleteNode (Transaction) returns (TransactionResponse); + rpc deleteNode (proto.Transaction) returns (proto.TransactionResponse); /** - * Prepare to update the node to the network. - * The node will not be updated until the network is upgraded. + * A transaction to update an existing consensus node from the network + * address book. + *

+ * This transaction, once complete, SHALL modify the identified consensus + * node state as requested. + *

+ * This transaction MUST be authorized by the node operator. */ - rpc updateNode (Transaction) returns (TransactionResponse); + rpc updateNode (proto.Transaction) returns (proto.TransactionResponse); } ``` A new Hedera API will be added called NodeCreate, which falls under the Node Service category. This function is used by the node operator to create a new node. To complete this transaction, both the node operator and a council member must sign it. ```protobuf -/** -* The council has to sign this transaction. This is a privileged transaction. -*/ message NodeCreateTransactionBody { + /** + * A Node account identifier. + *

+ * This account identifier MUST be in the "account number" form.
+ * This account identifier MUST NOT use the alias field.
+ * If the identified account does not exist, this transaction SHALL fail.
+ * Multiple nodes MAY share the same node account.
+ * This field is REQUIRED. + */ + proto.AccountID account_id = 1; - /** - * Node account id, mandatory field, ALIAS is not allowed, only ACCOUNT_NUM. - * If account_id does not exist, it will reject the transaction. - * Multiple nodes can have the same account_id. - */ - AccountID account_id = 1; - - /** - * Description of the node with UTF-8 encoding up to 100 bytes, optional field. - */ - string description = 2; - - /** - * Ip address and port, mandatory field. Fully qualified domain name is - * not allowed here. Maximum number of these endpoints is 10. - * The first in the list is used as the Internal IP address in config.txt, - * the second in the list is used as the External IP address in config.txt, - * the rest of IP addresses are ignored for DAB phase 2. - */ - repeated ServiceEndpoint gossip_endpoint = 3; - - /** - * A node's grpc service IP addresses and ports, IP:Port is mandatory, - * fully qualified domain name is optional. Maximum number of these endpoints is 8. - */ - repeated ServiceEndpoint service_endpoint = 4; - - /** - * The node's X509 RSA public key used to sign stream files (e.g., record stream - * files). Precisely, this field is the public key's DER encoding. - * This is a mandatory field. - */ - bytes public_key = 5; - - /** - * Hash of the node's TLS certificate. Precisely, this field is a string of - * hexadecimal characters which translated to binary, are the SHA-384 hash of - * the UTF-8 NFKD encoding of the node's TLS cert in PEM format. - * Its value can be used to verify the node's certificate it presents - * during TLS negotiations.node x509 certificate hash, optional field. - */ - bytes certificate_hash = 6; + /** + * A short description of the node. + *

+ * This value, if set, MUST NOT exceed 100 bytes when encoded as UTF-8.
+ * This field is OPTIONAL. + */ + string description = 2; + + /** + * A list of service endpoints for gossip. + *

+ * These endpoints SHALL represent the published endpoints to which other + * consensus nodes may _gossip_ transactions.
+ * These endpoints MUST specify a port.
+ * This list MUST NOT be empty.
+ * This list MUST NOT contain more than `10` entries.
+ * The first two entries in this list SHALL be the endpoints published to + * all consensus nodes.
+ * All other entries SHALL be reserved for future use. + *

+ * Each network may have additional requirements for these endpoints. + * A client MUST check network-specific documentation for those + * details.
+ * If the network configuration value `gossipFqdnRestricted` is set, then + * all endpoints in this list MUST supply only IP address.
+ * If the network configuration value `gossipFqdnRestricted` is _not_ set, + * then endpoints in this list MAY supply either IP address or FQDN, but + * MUST NOT supply both values for the same endpoint. + */ + repeated proto.ServiceEndpoint gossip_endpoint = 3; + + /** + * A list of service endpoints for gRPC calls. + *

+ * These endpoints SHALL represent the published gRPC endpoints to which + * clients may submit transactions.
+ * These endpoints MUST specify a port.
+ * Endpoints in this list MAY supply either IP address or FQDN, but MUST + * NOT supply both values for the same endpoint.
+ * This list MUST NOT be empty.
+ * This list MUST NOT contain more than `8` entries. + */ + repeated proto.ServiceEndpoint service_endpoint = 4; + + /** + * A certificate used to sign gossip events. + *

+ * This value MUST be a certificate of a type permitted for gossip + * signatures.
+ * This value MUST be the DER encoding of the certificate presented.
+ * This field is REQUIRED and MUST NOT be empty. + */ + bytes gossip_ca_certificate = 5; + + /** + * A hash of the node gRPC TLS certificate. + *

+ * This value MAY be used to verify the certificate presented by the node + * during TLS negotiation for gRPC.
+ * This value MUST be a SHA-384 hash.
+ * The TLS certificate to be hashed MUST first be in PEM format and MUST be + * encoded with UTF-8 NFKD encoding to a stream of bytes provided to + * the hash algorithm.
+ * This field is OPTIONAL. + */ + bytes grpc_certificate_hash = 6; + + /** + * An administrative key controlled by the node operator. + *

+ * This key MUST sign this transaction.
+ * This key MUST sign each transaction to update this node.
+ * This field MUST contain a valid `Key` value.
+ * This field is REQUIRED and MUST NOT be set to an empty `KeyList`. + */ + proto.Key admin_key = 7; } + ``` A new Hedera API called NodeDelete will be added under the Node Service. This API function is used by the node operator to delete a node. To perform this transaction, both the node operator and a council member need to sign it. ```protobuf -/** -/** -* The council has to sign this transaction. This is a privileged transaction. -*/ message NodeDeleteTransactionBody { - - /** - * The unique id of the node to be deleted. - */ - int64 node_id = 1; + /** + * A consensus node identifier in the network state. + *

+ * The node identified MUST exist in the network address book.
+ * The node identified MUST NOT be deleted.
+ * This value is REQUIRED. + */ + uint64 node_id = 1; } ``` A new Hedera API called NodeUpdate will be added under the Node Service. This function is used by the node operator to update a node. For this transaction, both the node operator and council member need to sign it. ```protobuf -/** -* Original node account ID has to sign this transaction. -*/ message NodeUpdateTransactionBody { + /** + * A consensus node identifier in the network state. + *

+ * The node identified MUST exist in the network address book.
+ * The node identified MUST NOT be deleted.
+ * This value is REQUIRED. + */ + uint64 node_id = 1; + + /** + * An account identifier. + *

+ * If set, this SHALL replace the node account identifier.
+ * If set, this transaction MUST be signed by the active `key` for _both_ + * the current node account _and_ the identified new node account. + */ + proto.AccountID account_id = 2; + + /** + * A short description of the node. + *

+ * This value, if set, MUST NOT exceed 100 bytes when encoded as UTF-8.
+ * If set, this value SHALL replace the previous value. + */ + google.protobuf.StringValue description = 3; + + /** + * A list of service endpoints for gossip. + *

+ * If set, this list MUST meet the following requirements. + *


+ * These endpoints SHALL represent the published endpoints to which other + * consensus nodes may _gossip_ transactions.
+ * These endpoints SHOULD NOT specify both address and DNS name.
+ * This list MUST NOT be empty.
+ * This list MUST NOT contain more than `10` entries.
+ * The first two entries in this list SHALL be the endpoints published to + * all consensus nodes.
+ * All other entries SHALL be reserved for future use. + *

+ * Each network may have additional requirements for these endpoints. + * A client MUST check network-specific documentation for those + * details.
+ *

Example
+ * Hedera Mainnet _requires_ that address be specified, and does not + * permit DNS name (FQDN) to be specified.
+ * Mainnet also requires that the first entry be an "internal" IP + * address and the second entry be an "external" IP address. + *
+ *
+ * Solo, however, _requires_ DNS name (FQDN) but also permits + * address. + *
+ *

+ * If set, the new list SHALL replace the existing list. + */ + repeated proto.ServiceEndpoint gossip_endpoint = 4; + + /** + * A list of service endpoints for gRPC calls. + *

+ * If set, this list MUST meet the following requirements. + *


+ * These endpoints SHALL represent the published endpoints to which clients + * may submit transactions.
+ * These endpoints SHOULD specify address and port.
+ * These endpoints MAY specify a DNS name.
+ * These endpoints SHOULD NOT specify both address and DNS name.
+ * This list MUST NOT be empty.
+ * This list MUST NOT contain more than `8` entries. + *

+ * Each network may have additional requirements for these endpoints. + * A client MUST check network-specific documentation for those + * details. + *

+ * If set, the new list SHALL replace the existing list. + */ + repeated proto.ServiceEndpoint service_endpoint = 5; + + /** + * A certificate used to sign gossip events. + *

+ * This value MUST be a certificate of a type permitted for gossip + * signatures.
+ * This value MUST be the DER encoding of the certificate presented. + *

+ * If set, the new value SHALL replace the existing bytes value. + */ + google.protobuf.BytesValue gossip_ca_certificate = 6; + + /** + * A hash of the node gRPC TLS certificate. + *

+ * This value MAY be used to verify the certificate presented by the node + * during TLS negotiation for gRPC.
+ * This value MUST be a SHA-384 hash.
+ * The TLS certificate to be hashed MUST first be in PEM format and MUST be + * encoded with UTF-8 NFKD encoding to a stream of bytes provided to + * the hash algorithm.
+ *

+ * If set, the new value SHALL replace the existing hash value. + */ + google.protobuf.BytesValue grpc_certificate_hash = 7; - /** - * The unique id of the Node to be updated. This must refer to an existing, non-deleted node. - */ - int64 node_id = 1; - - /** - * If set, the new node account_id. - */ - AccountID account_id = 2; - - /** - * If set, the new description to be associated with the node. - */ - google.protobuf.StringValue description = 3; - - /** - * If set, the new ip address or FQDN and port. - */ - repeated ServiceEndpoint gossip_endpoint = 4; - - /** - * If set, replace the current list of service_endpoints. - */ - repeated ServiceEndpoint service_endpoint = 5; - - /** - * If set, the new public_key to be associated with the node. - */ - google.protobuf.BytesValue public_key = 6; - - /** - * If set, the new node x509 certificate hash to be associated with the node. - */ - google.protobuf.BytesValue certificate_hash = 7; + /** + * An administrative key controlled by the node operator. + *

+ * This field is OPTIONAL.
+ * If set, this key MUST sign this transaction.
+ * If set, this key MUST sign each subsequent transaction to + * update this node.
+ * If set, this field MUST contain a valid `Key` value.
+ * If set, this field MUST NOT be set to an empty `KeyList`. + */ + proto.Key admin_key = 8; } ``` @@ -248,20 +380,20 @@ enum HederaFunctionality { [...] - /** + /** * Create a node */ - NodeCreate = 88; + NodeCreate = 89; /** * Update a node */ - NodeUpdate = 89; + NodeUpdate = 90; /** * Delete a node */ - NodeDelete = 90; + NodeDelete = 91; } ``` @@ -272,10 +404,15 @@ message ServiceEndpoint { [...] - /** - * The fully qualified domain name of the node, the maximum size is 253 characters. - */ - string domain_name = 3; + /** + * A node domain name.
+ * This MUST be the fully qualified domain(DNS) name of the node.
+ * This value MUST NOT be more than 253 characters. + * domain_name and ipAddressV4 are mutually exclusive. + * When the `domain_name` field is set, the `ipAddressV4` field MUST NOT be set.
+ * When the `ipAddressV4` field is set, the `domain_name` field MUST NOT be set. + */ + string domain_name = 3; } ``` @@ -286,34 +423,134 @@ message TransactionReceipt { [...] - /** - * In the receipt of a NodeCreate, the id of the newly created node. - */ - int64 node_id = 15; + /** + * In the receipt of a NodeCreate, NodeUpdate, NodeDelete, the id of the newly created node. + * An affected node identifier.
+ * This value SHALL be set following a `createNode` transaction.
+ * This value SHALL be set following a `updateNode` transaction.
+ * This value SHALL be set following a `deleteNode` transaction.
+ * This value SHALL NOT be set following any other transaction. + */ + uint64 node_id = 15; + } ``` -Added a couple of response codes. +Added a few response codes. ```protobuf enum ResponseCodeEnum { [...] - /** - * A node is already deleted - */ - NODE_DELETED = 333; + /** + * A transaction failed because the consensus node identified is + * deleted from the address book. + */ + NODE_DELETED = 338; + + /** + * A transaction failed because the consensus node identified is not valid or + * does not exist in state. + */ + INVALID_NODE_ID = 339; + + /** + * A transaction failed because one or more entries in the list of + * service endpoints for the `gossip_endpoint` field is invalid.
+ * The most common cause for this response is a service endpoint that has + * the domain name (DNS) set rather than address and port. + */ + INVALID_GOSSIP_ENDPOINT = 340; + + /** + * A transaction failed because the node account identifier provided + * does not exist or is not valid.
+ * One common source of this error is providing a node account identifier + * using the "alias" form rather than "numeric" form. + */ + INVALID_NODE_ACCOUNT_ID = 341; + + /** + * A transaction failed because the description field cannot be encoded + * as UTF-8 or is more than 100 bytes when encoded. + */ + INVALID_NODE_DESCRIPTION = 342; + + /** + * A transaction failed because one or more entries in the list of + * service endpoints for the `service_endpoint` field is invalid.
+ * The most common cause for this response is a service endpoint that has + * the domain name (DNS) set rather than address and port. + */ + INVALID_SERVICE_ENDPOINT = 343; + + /** + * A transaction failed because the TLS certificate provided for the + * node is missing or invalid.
+ * The certificate MUST be a TLS certificate of a type permitted for gossip + * signatures.
+ * The value presented MUST be a UTF-8 NFKD encoding of the TLS + * certificate.
+ * The certificate encoded MUST be in PEM format.
+ * The `gossip_ca_certificate` field is REQUIRED and MUST NOT be empty. + */ + INVALID_GOSSIP_CA_CERTIFICATE = 344; + + /** + * A transaction failed because the hash provided for the gRPC certificate + * is present but invalid.
+ * The `grpc_certificate_hash` MUST be a SHA-384 hash.
+ * The input hashed MUST be a UTF-8 NFKD encoding of the actual TLS + * certificate.
+ * The certificate to be encoded MUST be in PEM format. + */ + INVALID_GRPC_CERTIFICATE = 345; + + /** + * The maximum number of nodes allowed in the address book have been created. + */ + MAX_NODES_CREATED = 347; + + /** + * In ServiceEndpoint, domain_name and ipAddressV4 are mutually exclusive + */ + IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT = 348; + + /** + * Fully qualified domain name is not allowed in gossip_endpoint + */ + GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN = 349; + + /** + * In ServiceEndpoint, domain_name size too large + */ + FQDN_SIZE_TOO_LARGE = 350; + + /** + * ServiceEndpoint is invalid + */ + INVALID_ENDPOINT = 351; + + /** + * The number of gossip endpoints exceeds the limit + */ + GOSSIP_ENDPOINTS_EXCEEDED_LIMIT = 352; - /** - * A node is not found - */ - INVALID_NODE_ID = 334; + /** + * The number of service endpoints exceeds the limit + */ + SERVICE_ENDPOINTS_EXCEEDED_LIMIT = 356; - /** - * gossip_endpoint has a fully qualified domain name instead or ip - */ - INVALID_GOSSIP_ENDPOINT = 335; + /* + * The IPv4 address is invalid + */ + INVALID_IPV4_ADDRESS = 357; + + /* + * The node account is not allowed to be updated + */ + UPDATE_NODE_ACCOUNT_NOT_ALLOWED = 359; } ```