All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hedera.hashgraph.sdk.NodeUpdateTransaction Maven / Gradle / Ivy

The newest version!
/*-
 *
 * Hedera Java SDK
 *
 * Copyright (C) 2024 Hedera Hashgraph, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.hedera.hashgraph.sdk;

import com.google.protobuf.ByteString;
import com.google.protobuf.BytesValue;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.StringValue;
import com.hedera.hashgraph.sdk.proto.AddressBookServiceGrpc;
import com.hedera.hashgraph.sdk.proto.NodeUpdateTransactionBody;
import com.hedera.hashgraph.sdk.proto.SchedulableTransactionBody;
import com.hedera.hashgraph.sdk.proto.TransactionBody;
import com.hedera.hashgraph.sdk.proto.TransactionResponse;
import io.grpc.MethodDescriptor;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import javax.annotation.Nullable;
import org.bouncycastle.util.Arrays;

/**
 * A transaction to modify address book node attributes.
 *
 * - This transaction SHALL enable the node operator, as identified by the
 *   `admin_key`, to modify operational attributes of the node.
 * - This transaction MUST be signed by the active `admin_key` for the node.
 * - If this transaction sets a new value for the `admin_key`, then both the
 *   current `admin_key`, and the new `admin_key` MUST sign this transaction.
 * - This transaction SHALL NOT change any field that is not set (is null) in
 *   this transaction body.
 * - This SHALL create a pending update to the node, but the change SHALL NOT
 *   be immediately applied to the active configuration.
 * - All pending node updates SHALL be applied to the active network
 *   configuration during the next `freeze` transaction with the field
 *   `freeze_type` set to `PREPARE_UPGRADE`.
 *
 * ### Record Stream Effects
 * Upon completion the `node_id` for the updated entry SHALL be in the
 * transaction receipt.
 */
public class NodeUpdateTransaction extends Transaction {

    /**
     * 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. */ private long nodeId = 0; /** * 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. */ @Nullable private AccountId accountId = null; /** * 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. */ @Nullable private String description = null; /** * 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. */ private List gossipEndpoints = new ArrayList<>(); /** * 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. */ private List serviceEndpoints = new ArrayList<>(); /** * 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. */ @Nullable private byte[] gossipCaCertificate = null; /** * 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. */ @Nullable private byte[] grpcCertificateHash = null; /** * 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`. */ @Nullable private Key adminKey = null; /** * Constructor. */ public NodeUpdateTransaction() {} /** * Constructor. * * @param txs Compound list of transaction id's list of (AccountId, Transaction) records * @throws InvalidProtocolBufferException when there is an issue with the protobuf */ NodeUpdateTransaction( LinkedHashMap> txs) throws InvalidProtocolBufferException { super(txs); initFromTransactionBody(); } /** * Constructor. * * @param txBody protobuf TransactionBody */ NodeUpdateTransaction(com.hedera.hashgraph.sdk.proto.TransactionBody txBody) { super(txBody); initFromTransactionBody(); } /** * Extract the consensus node identifier in the network state. * @return the consensus node identifier in the network state. */ public long getNodeId() { return nodeId; } /** * Assign the consensus node identifier in the network state. * @param nodeId the consensus node identifier in the network state. * @return {@code this} */ public NodeUpdateTransaction setNodeId(long nodeId) { requireNotFrozen(); this.nodeId = nodeId; return this; } /** * Extract the Account ID of the Node. * @return the Account ID of the Node. */ public AccountId getAccountId() { return accountId; } /** * Assign the Account ID of the Node. * @param accountId the Account ID of the Node. * @return {@code this} */ public NodeUpdateTransaction setAccountId(AccountId accountId) { Objects.requireNonNull(accountId); requireNotFrozen(); this.accountId = accountId; return this; } /** * Extract the description of the node. * @return the node's description. */ @Nullable public String getDescription() { return description; } /** * Sets the description of the node. * @param description The String to be set as the description of the node. * @return {@code this} */ public NodeUpdateTransaction setDescription(String description) { requireNotFrozen(); Objects.requireNonNull(description); this.description = description; return this; } /** * Remove the description contents. * @return {@code this} */ public NodeUpdateTransaction clearDescription() { requireNotFrozen(); description = ""; return this; } /** * Extract the list of service endpoints for gossip. * @return the list of service endpoints for gossip. */ public List getGossipEndpoints() { return gossipEndpoints; } /** * Assign the list of service endpoints for gossip. * @param gossipEndpoints the list of service endpoints for gossip. * @return {@code this} */ public NodeUpdateTransaction setGossipEndpoints(List gossipEndpoints) { requireNotFrozen(); Objects.requireNonNull(gossipEndpoints); this.gossipEndpoints = new ArrayList<>(gossipEndpoints); return this; } /** * Add an endpoint for gossip to the list of service endpoints for gossip. * @param gossipEndpoint endpoints for gossip to add. * @return {@code this} */ public NodeUpdateTransaction addGossipEndpoint(Endpoint gossipEndpoint) { requireNotFrozen(); gossipEndpoints.add(gossipEndpoint); return this; } /** * Extract the list of service endpoints for gRPC calls. * @return the list of service endpoints for gRPC calls. */ public List getServiceEndpoints() { return serviceEndpoints; } /** * Assign the list of service endpoints for gRPC calls. * @param serviceEndpoints list of service endpoints for gRPC calls. * @return {@code this} */ public NodeUpdateTransaction setServiceEndpoints(List serviceEndpoints) { requireNotFrozen(); Objects.requireNonNull(serviceEndpoints); this.serviceEndpoints = new ArrayList<>(serviceEndpoints); return this; } /** * Add an endpoint for gRPC calls to the list of service endpoints for gRPC calls. * @param serviceEndpoint endpoints for gRPC calls to add. * @return {@code this} */ public NodeUpdateTransaction addServiceEndpoint(Endpoint serviceEndpoint) { requireNotFrozen(); serviceEndpoints.add(serviceEndpoint); return this; } /** * Extract the certificate used to sign gossip events. * @return the DER encoding of the certificate presented. */ @Nullable public byte[] getGossipCaCertificate() { return gossipCaCertificate != null ? Arrays.copyOf(gossipCaCertificate, gossipCaCertificate.length) : null; } /** * Sets the certificate used to sign gossip events. *
* This value MUST be the DER encoding of the certificate presented. * @param gossipCaCertificate the DER encoding of the certificate presented. * @return {@code this} */ public NodeUpdateTransaction setGossipCaCertificate(byte[] gossipCaCertificate) { Objects.requireNonNull(gossipCaCertificate); requireNotFrozen(); this.gossipCaCertificate = Arrays.copyOf(gossipCaCertificate, gossipCaCertificate.length); return this; } /** * Extract the hash of the node gRPC TLS certificate. * @return SHA-384 hash of the node gRPC TLS certificate. */ @Nullable public byte[] getGrpcCertificateHash() { return grpcCertificateHash != null ? Arrays.copyOf(grpcCertificateHash, grpcCertificateHash.length) : null; } /** * Sets the hash of the node gRPC TLS certificate. *
* This value MUST be a SHA-384 hash. * @param grpcCertificateHash SHA-384 hash of the node gRPC TLS certificate. * @return {@code this} */ public NodeUpdateTransaction setGrpcCertificateHash(byte[] grpcCertificateHash) { Objects.requireNonNull(grpcCertificateHash); requireNotFrozen(); this.grpcCertificateHash = Arrays.copyOf(grpcCertificateHash, grpcCertificateHash.length); return this; } /** * Get an administrative key controlled by the node operator. * @return an administrative key controlled by the node operator. */ @Nullable public Key getAdminKey() { return adminKey; } /** * Sets an administrative key controlled by the node operator. * @param adminKey an administrative key to be set. * @return {@code this} */ public NodeUpdateTransaction setAdminKey(Key adminKey) { Objects.requireNonNull(adminKey); requireNotFrozen(); this.adminKey = adminKey; return this; } /** * Build the transaction body. * * @return {@link com.hedera.hashgraph.sdk.proto.NodeUpdateTransactionBody} */ NodeUpdateTransactionBody.Builder build() { var builder = NodeUpdateTransactionBody.newBuilder(); builder.setNodeId(nodeId); if (accountId != null) { builder.setAccountId(accountId.toProtobuf()); } if (description != null) { builder.setDescription(StringValue.of(description)); } for (Endpoint gossipEndpoint : gossipEndpoints) { builder.addGossipEndpoint(gossipEndpoint.toProtobuf()); } for (Endpoint serviceEndpoint : serviceEndpoints) { builder.addServiceEndpoint(serviceEndpoint.toProtobuf()); } if (gossipCaCertificate != null) { builder.setGossipCaCertificate(BytesValue.of(ByteString.copyFrom(gossipCaCertificate))); } if (grpcCertificateHash != null) { builder.setGrpcCertificateHash(BytesValue.of(ByteString.copyFrom(grpcCertificateHash))); } if (adminKey != null) { builder.setAdminKey(adminKey.toProtobufKey()); } return builder; } /** * Initialize from the transaction body. */ void initFromTransactionBody() { var body = sourceTransactionBody.getNodeUpdate(); nodeId = body.getNodeId(); if (body.hasAccountId()) { accountId = AccountId.fromProtobuf(body.getAccountId()); } description = body.getDescription().getValue(); for (var gossipEndpoint : body.getGossipEndpointList()) { gossipEndpoints.add(Endpoint.fromProtobuf(gossipEndpoint)); } for (var serviceEndpoint : body.getServiceEndpointList()) { serviceEndpoints.add(Endpoint.fromProtobuf(serviceEndpoint)); } gossipCaCertificate = body.getGossipCaCertificate().getValue().toByteArray(); grpcCertificateHash = body.getGrpcCertificateHash().getValue().toByteArray(); if (body.hasAdminKey()) { adminKey = Key.fromProtobufKey(body.getAdminKey()); } } @Override void validateChecksums(Client client) throws BadEntityIdException { if (accountId != null) { accountId.validateChecksum(client); } } @Override MethodDescriptor getMethodDescriptor() { return AddressBookServiceGrpc.getUpdateNodeMethod(); } @Override void onFreeze(TransactionBody.Builder bodyBuilder) { bodyBuilder.setNodeUpdate(build()); } @Override void onScheduled(SchedulableTransactionBody.Builder scheduled) { scheduled.setNodeUpdate(build()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy