diff --git a/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/AddressBookServiceImpl.java b/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/AddressBookServiceImpl.java index c75069bab736..3580c6c3e666 100644 --- a/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/AddressBookServiceImpl.java +++ b/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/AddressBookServiceImpl.java @@ -26,7 +26,6 @@ * Standard implementation of the {@link AddressBookService} {@link RpcService}. */ public final class AddressBookServiceImpl implements AddressBookService { - public static final String NODES_KEY = "NODES"; @Override public void registerSchemas(@NonNull SchemaRegistry registry) { diff --git a/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/ReadableNodeStoreImpl.java b/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/ReadableNodeStoreImpl.java index be2b9f4fd029..671c04b18afa 100644 --- a/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/ReadableNodeStoreImpl.java +++ b/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/ReadableNodeStoreImpl.java @@ -16,7 +16,7 @@ package com.hedera.node.app.service.addressbook.impl; -import static com.hedera.node.app.service.addressbook.impl.AddressBookServiceImpl.NODES_KEY; +import static com.hedera.node.app.service.addressbook.AddressBookHelper.NODES_KEY; import static java.util.Objects.requireNonNull; import com.hedera.hapi.node.state.addressbook.Node; diff --git a/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/WritableNodeStore.java b/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/WritableNodeStore.java index 574cadccc095..9444eb988b3c 100644 --- a/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/WritableNodeStore.java +++ b/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/WritableNodeStore.java @@ -27,7 +27,6 @@ import com.swirlds.state.spi.WritableKVState; import com.swirlds.state.spi.WritableStates; import edu.umd.cs.findbugs.annotations.NonNull; -import java.util.Iterator; import java.util.Set; /** @@ -98,14 +97,4 @@ public long sizeOfState() { public Set modifiedNodes() { return nodesState().modifiedKeys(); } - - /** - * Returns an iterator over the keys in the state. - * @return - */ - @Override - @NonNull - public Iterator keys() { - return nodesState().keys(); - } } diff --git a/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/handlers/NodeCreateHandler.java b/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/handlers/NodeCreateHandler.java index 0c2227923a9e..57ce366e06c7 100644 --- a/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/handlers/NodeCreateHandler.java +++ b/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/handlers/NodeCreateHandler.java @@ -22,6 +22,7 @@ import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_NODE_ACCOUNT_ID; import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_SERVICE_ENDPOINT; import static com.hedera.hapi.node.base.ResponseCodeEnum.MAX_NODES_CREATED; +import static com.hedera.node.app.service.addressbook.AddressBookHelper.getNextNodeID; import static com.hedera.node.app.spi.workflows.HandleException.validateFalse; import static com.hedera.node.app.spi.workflows.HandleException.validateTrue; import static com.hedera.node.app.spi.workflows.PreCheckException.validateFalsePreCheck; @@ -45,7 +46,6 @@ import com.hedera.node.config.data.NodesConfig; import com.hedera.pbj.runtime.io.buffer.Bytes; import edu.umd.cs.findbugs.annotations.NonNull; -import java.util.concurrent.atomic.AtomicLong; import javax.inject.Inject; import javax.inject.Singleton; @@ -114,8 +114,6 @@ public void handle(@NonNull final HandleContext handleContext) { .description(op.description()) .gossipEndpoint(op.gossipEndpoint()) .serviceEndpoint(op.serviceEndpoint()) - .gossipEndpoint(op.gossipEndpoint()) - .serviceEndpoint(op.serviceEndpoint()) .gossipCaCertificate(op.gossipCaCertificate()) .grpcCertificateHash(op.grpcCertificateHash()) .adminKey(op.adminKey()); @@ -139,12 +137,4 @@ public Fees calculateFees(@NonNull final FeeContext feeContext) { calculator.addVerificationsPerTransaction(Math.max(0, feeContext.numTxnSignatures() - 1)); return calculator.calculate(); } - - private long getNextNodeID(@NonNull final WritableNodeStore nodeStore) { - requireNonNull(nodeStore); - final var nodeIds = nodeStore.keys(); - AtomicLong max = new AtomicLong(-1); - nodeIds.forEachRemaining(nodeId -> max.set(Math.max(max.get(), nodeId.number()))); - return max.get() + 1; - } } diff --git a/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/schemas/V053AddressBookSchema.java b/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/schemas/V053AddressBookSchema.java index 66ddb9bd6fc4..29808701c19b 100644 --- a/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/schemas/V053AddressBookSchema.java +++ b/hedera-node/hedera-addressbook-service-impl/src/main/java/com/hedera/node/app/service/addressbook/impl/schemas/V053AddressBookSchema.java @@ -16,17 +16,21 @@ package com.hedera.node.app.service.addressbook.impl.schemas; -import static com.hedera.node.app.service.addressbook.impl.AddressBookServiceImpl.NODES_KEY; +import static com.hedera.node.app.service.addressbook.AddressBookHelper.NODES_KEY; import static java.util.Objects.requireNonNull; +import com.hedera.hapi.node.base.AccountID; import com.hedera.hapi.node.base.Key; import com.hedera.hapi.node.base.SemanticVersion; import com.hedera.hapi.node.base.ServiceEndpoint; import com.hedera.hapi.node.state.addressbook.Node; import com.hedera.hapi.node.state.common.EntityNumber; +import com.hedera.hapi.node.state.token.Account; +import com.hedera.node.config.data.AccountsConfig; import com.hedera.node.config.data.BootstrapConfig; import com.hedera.pbj.runtime.io.buffer.Bytes; import com.swirlds.state.spi.MigrationContext; +import com.swirlds.state.spi.ReadableKVState; import com.swirlds.state.spi.Schema; import com.swirlds.state.spi.StateDefinition; import com.swirlds.state.spi.WritableKVState; @@ -49,6 +53,7 @@ public class V053AddressBookSchema extends Schema { private static final long MAX_NODES = 100L; private static final SemanticVersion VERSION = SemanticVersion.newBuilder().major(0).minor(53).patch(0).build(); + public static final String ACCOUNTS_KEY = "ACCOUNTS"; public V053AddressBookSchema() { super(VERSION); @@ -65,13 +70,30 @@ public void migrate(@NonNull final MigrationContext ctx) { requireNonNull(ctx); final WritableKVState writableNodes = ctx.newStates().get(NODES_KEY); + ReadableKVState readableAccounts = null; + try { + readableAccounts = ctx.newStates().get(ACCOUNTS_KEY); + } catch (IllegalArgumentException e) { + log.info("AccountStore is not found, can be ignored."); + } final var networkInfo = ctx.networkInfo(); final var addressBook = networkInfo.addressBook(); final var bootstrapConfig = ctx.configuration().getConfigData(BootstrapConfig.class); - final var adminKey = - Key.newBuilder().ed25519(bootstrapConfig.genesisPublicKey()).build(); + final var accountConfig = ctx.configuration().getConfigData(AccountsConfig.class); + var adminKey = Key.DEFAULT; + if (readableAccounts != null) { + final var adminAccount = readableAccounts.get(AccountID.newBuilder() + .accountNum(accountConfig.addressBookAdmin()) + .build()); + if (adminAccount != null) { + adminKey = adminAccount.keyOrElse(Key.DEFAULT); + } + } log.info("Started migrating nodes from address book"); + Key finalAdminKey = adminKey == null || adminKey.equals(Key.DEFAULT) + ? Key.newBuilder().ed25519(bootstrapConfig.genesisPublicKey()).build() + : adminKey; addressBook.forEach(nodeInfo -> { final var node = Node.newBuilder() .nodeId(nodeInfo.nodeId()) @@ -82,7 +104,7 @@ public void migrate(@NonNull final MigrationContext ctx) { endpointFor(nodeInfo.externalHostName(), nodeInfo.externalPort()))) .gossipCaCertificate(nodeInfo.sigCertBytes()) .weight(nodeInfo.stake()) - .adminKey(adminKey) + .adminKey(finalAdminKey) .build(); writableNodes.put( EntityNumber.newBuilder().number(nodeInfo.nodeId()).build(), node); diff --git a/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/ReadableNodeStoreImplTest.java b/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/ReadableNodeStoreImplTest.java index f27666637b10..4605323af37f 100644 --- a/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/ReadableNodeStoreImplTest.java +++ b/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/ReadableNodeStoreImplTest.java @@ -17,7 +17,7 @@ package com.hedera.node.app.service.addressbook.impl.test; import static com.hedera.node.app.hapi.utils.CommonPbjConverters.asBytes; -import static com.hedera.node.app.service.addressbook.impl.AddressBookServiceImpl.NODES_KEY; +import static com.hedera.node.app.service.addressbook.AddressBookHelper.NODES_KEY; import static java.util.stream.Collectors.toSet; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertArrayEquals; diff --git a/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/handlers/AddressBookTestBase.java b/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/handlers/AddressBookTestBase.java index 49be8967e921..4047ce90a77a 100644 --- a/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/handlers/AddressBookTestBase.java +++ b/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/handlers/AddressBookTestBase.java @@ -17,7 +17,7 @@ package com.hedera.node.app.service.addressbook.impl.test.handlers; import static com.hedera.node.app.hapi.utils.CommonPbjConverters.asBytes; -import static com.hedera.node.app.service.addressbook.impl.AddressBookServiceImpl.NODES_KEY; +import static com.hedera.node.app.service.addressbook.AddressBookHelper.NODES_KEY; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; diff --git a/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/handlers/NodeDeleteHandlerTest.java b/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/handlers/NodeDeleteHandlerTest.java index 86b6de856d1d..940f3b31eed8 100644 --- a/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/handlers/NodeDeleteHandlerTest.java +++ b/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/handlers/NodeDeleteHandlerTest.java @@ -17,7 +17,7 @@ package com.hedera.node.app.service.addressbook.impl.test.handlers; import static com.hedera.hapi.node.base.ResponseCodeEnum.INVALID_NODE_ID; -import static com.hedera.node.app.service.addressbook.impl.AddressBookServiceImpl.NODES_KEY; +import static com.hedera.node.app.service.addressbook.AddressBookHelper.NODES_KEY; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; diff --git a/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/schemas/V053AddressBookSchemaTest.java b/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/schemas/V053AddressBookSchemaTest.java index 0c137d80fc7a..1c401945f30e 100644 --- a/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/schemas/V053AddressBookSchemaTest.java +++ b/hedera-node/hedera-addressbook-service-impl/src/test/java/com/hedera/node/app/service/addressbook/impl/test/schemas/V053AddressBookSchemaTest.java @@ -16,15 +16,22 @@ package com.hedera.node.app.service.addressbook.impl.test.schemas; -import static com.hedera.node.app.service.addressbook.impl.AddressBookServiceImpl.NODES_KEY; +import static com.hedera.node.app.service.addressbook.AddressBookHelper.NODES_KEY; +import static com.hedera.node.app.service.addressbook.impl.schemas.V053AddressBookSchema.ACCOUNTS_KEY; +import static com.hedera.node.app.service.addressbook.impl.schemas.V053AddressBookSchema.endpointFor; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.BDDMockito.given; +import com.hedera.hapi.node.base.AccountID; +import com.hedera.hapi.node.state.addressbook.Node; +import com.hedera.hapi.node.state.common.EntityNumber; +import com.hedera.hapi.node.state.token.Account; import com.hedera.node.app.info.NodeInfoImpl; import com.hedera.node.app.service.addressbook.impl.schemas.V053AddressBookSchema; import com.hedera.node.app.service.addressbook.impl.test.handlers.AddressBookTestBase; +import com.hedera.node.app.spi.fixtures.state.MapWritableStates; import com.hedera.node.app.spi.fixtures.util.LogCaptor; import com.hedera.node.app.spi.fixtures.util.LogCaptureExtension; import com.hedera.node.app.spi.fixtures.util.LoggingSubject; @@ -33,10 +40,11 @@ import com.hedera.pbj.runtime.io.buffer.Bytes; import com.swirlds.state.spi.MigrationContext; import com.swirlds.state.spi.StateDefinition; -import com.swirlds.state.spi.WritableKVStateBase; -import com.swirlds.state.spi.WritableStates; import com.swirlds.state.spi.info.NetworkInfo; +import com.swirlds.state.test.fixtures.MapWritableKVState; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -51,18 +59,21 @@ class V053AddressBookSchemaTest extends AddressBookTestBase { @Mock private MigrationContext migrationContext; - @Mock - private WritableStates writableStates; - @Mock private NetworkInfo networkInfo; - @Mock - private WritableKVStateBase writableKVState; - @LoggingSubject private V053AddressBookSchema subject; + private final Map accounts = new HashMap<>(); + private final MapWritableKVState writableAccounts = + new MapWritableKVState<>(ACCOUNTS_KEY, accounts); + + private final Map nodes = new HashMap<>(); + private final MapWritableKVState writableNodes = new MapWritableKVState<>(NODES_KEY, nodes); + + private MapWritableStates writableStates = null; + @BeforeEach void setUp() { subject = new V053AddressBookSchema(); @@ -81,14 +92,46 @@ void registersExpectedSchema() { void migrateAsExpected() { setupMigrationContext(); + assertThatCode(() -> subject.migrate(migrationContext)).doesNotThrowAnyException(); + assertThat(logCaptor.infoLogs()).contains("Started migrating nodes from address book"); + assertThat(logCaptor.infoLogs()).contains("AccountStore is not found, can be ignored."); + assertThat(logCaptor.infoLogs()).contains("Migrated 2 nodes from address book"); + } + + @Test + void migrateAsExpected2() { + setupMigrationContext2(); + assertThatCode(() -> subject.migrate(migrationContext)).doesNotThrowAnyException(); assertThat(logCaptor.infoLogs()).contains("Started migrating nodes from address book"); assertThat(logCaptor.infoLogs()).contains("Migrated 2 nodes from address book"); + assertEquals( + Node.newBuilder() + .nodeId(1) + .accountId(payerId) + .description("memo1") + .gossipEndpoint(List.of(endpointFor("127.0.0.1", 123), endpointFor("23.45.34.245", 22))) + .gossipCaCertificate(Bytes.wrap(gossipCaCertificate)) + .weight(0) + .adminKey(anotherKey) + .build(), + writableNodes.get(EntityNumber.newBuilder().number(1).build())); + assertEquals( + Node.newBuilder() + .nodeId(2) + .accountId(accountId) + .description("memo2") + .gossipEndpoint(List.of(endpointFor("127.0.0.2", 123), endpointFor("23.45.34.240", 23))) + .gossipCaCertificate(Bytes.wrap(grpcCertificateHash)) + .weight(1) + .adminKey(anotherKey) + .build(), + writableNodes.get(EntityNumber.newBuilder().number(2).build())); } private void setupMigrationContext() { + writableStates = MapWritableStates.builder().state(writableNodes).build(); given(migrationContext.newStates()).willReturn(writableStates); - given(writableStates.get(NODES_KEY)).willReturn(writableKVState); final var nodeInfo1 = new NodeInfoImpl( 1, @@ -101,7 +144,7 @@ private void setupMigrationContext() { "pubKey1", "memo1", Bytes.wrap(gossipCaCertificate), - "memo2"); + "memo1"); final var nodeInfo2 = new NodeInfoImpl( 2, accountId, @@ -121,4 +164,22 @@ private void setupMigrationContext() { .getOrCreateConfig(); given(migrationContext.configuration()).willReturn(config); } + + private void setupMigrationContext2() { + setupMigrationContext(); + accounts.put( + AccountID.newBuilder().accountNum(55).build(), + Account.newBuilder().key(anotherKey).build()); + writableStates = MapWritableStates.builder() + .state(writableAccounts) + .state(writableNodes) + .build(); + given(migrationContext.newStates()).willReturn(writableStates); + + final var config = HederaTestConfigBuilder.create() + .withValue("bootstrap.genesisPublicKey", defauleAdminKeyBytes) + .withValue("accounts.addressBookAdmin", "55") + .getOrCreateConfig(); + given(migrationContext.configuration()).willReturn(config); + } } diff --git a/hedera-node/hedera-addressbook-service/src/main/java/com/hedera/node/app/service/addressbook/AddressBookHelper.java b/hedera-node/hedera-addressbook-service/src/main/java/com/hedera/node/app/service/addressbook/AddressBookHelper.java new file mode 100644 index 000000000000..d1fc343e0a0a --- /dev/null +++ b/hedera-node/hedera-addressbook-service/src/main/java/com/hedera/node/app/service/addressbook/AddressBookHelper.java @@ -0,0 +1,47 @@ +/* + * 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.node.app.service.addressbook; + +import static java.util.Objects.requireNonNull; +import static java.util.Spliterator.DISTINCT; + +import com.hedera.hapi.node.state.common.EntityNumber; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Spliterators; +import java.util.stream.StreamSupport; + +/** + * Utility class that provides static methods and constants to facilitate the Address Book Services functions. + */ +public class AddressBookHelper { + public static final String NODES_KEY = "NODES"; + + /** + * Get the next Node ID number from the reaReadableNodeStore + * @param nodeStore + * @return nextNodeId + */ + public static long getNextNodeID(@NonNull final ReadableNodeStore nodeStore) { + requireNonNull(nodeStore); + final long maxNodeId = StreamSupport.stream( + Spliterators.spliterator(nodeStore.keys(), nodeStore.sizeOfState(), DISTINCT), false) + .mapToLong(EntityNumber::number) + .max() + .orElse(-1L); + return maxNodeId + 1; + } +} diff --git a/hedera-node/hedera-network-admin-service-impl/src/main/java/com/hedera/node/app/service/networkadmin/impl/handlers/ReadableFreezeUpgradeActions.java b/hedera-node/hedera-network-admin-service-impl/src/main/java/com/hedera/node/app/service/networkadmin/impl/handlers/ReadableFreezeUpgradeActions.java index b0c208d85f98..79816b579f99 100644 --- a/hedera-node/hedera-network-admin-service-impl/src/main/java/com/hedera/node/app/service/networkadmin/impl/handlers/ReadableFreezeUpgradeActions.java +++ b/hedera-node/hedera-network-admin-service-impl/src/main/java/com/hedera/node/app/service/networkadmin/impl/handlers/ReadableFreezeUpgradeActions.java @@ -43,7 +43,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; -import java.util.Comparator; import java.util.List; import java.util.Spliterators; import java.util.concurrent.CompletableFuture; @@ -197,9 +196,9 @@ private List allActiveNodes() { return StreamSupport.stream( Spliterators.spliterator(nodeStore.keys(), nodeStore.sizeOfState(), DISTINCT), false) .mapToLong(EntityNumber::number) + .sorted() .mapToObj(nodeStore::get) .filter(node -> node != null && !node.deleted()) - .sorted(Comparator.comparing(Node::nodeId)) .map(node -> new ActiveNode(node, stakingInfoStore.get(node.nodeId()))) .toList(); } @@ -220,13 +219,12 @@ private void extractAndReplaceArtifacts( FileUtils.cleanDirectory(artifactsDir); UnzipUtility.unzip(archiveData.toByteArray(), artifactsLoc); log.info("Finished unzipping {} bytes for {} update into {}", size, desc, artifactsLoc); - if (desc.equals(PREPARE_UPGRADE_DESC)) { - requireNonNull(nodes, "Cannot generate config.txt without a valid list of active nodes"); + if (nodes != null) { generateConfigPem(artifactsLoc, nodes); log.info("Finished generating config.txt and pem files into {}", artifactsLoc); } writeSecondMarker(marker, now); - } catch (final Throwable t) { + } catch (final Exception t) { // catch and log instead of throwing because upgrade process looks at the presence or absence // of marker files to determine whether to proceed with the upgrade // if second marker is present, that means the zip file was successfully extracted @@ -235,6 +233,13 @@ private void extractAndReplaceArtifacts( } } + private long getNextNodeID(@NonNull List nodes) { + requireNonNull(nodes); + final long maxNodeId = + nodes.stream().mapToLong(a -> a.node.nodeId()).max().orElse(-1L); + return maxNodeId + 1; + } + private void generateConfigPem(@NonNull final Path artifactsLoc, @NonNull final List activeNodes) { requireNonNull(artifactsLoc, "Cannot generate config.txt without a valid artifacts location"); requireNonNull(activeNodes, "Cannot generate config.txt without a valid list of active nodes"); @@ -245,32 +250,17 @@ private void generateConfigPem(@NonNull final Path artifactsLoc, @NonNull final return; } + final var nextNodeId = getNextNodeID(activeNodes); try (final var fw = new FileWriter(configTxt.toFile()); final var bw = new BufferedWriter(fw)) { activeNodes.forEach(node -> writeConfigLineAndPem(node, bw, artifactsLoc)); - writeNextNodeId(activeNodes, bw); + bw.write("nextNodeId, " + nextNodeId); bw.flush(); } catch (final IOException e) { log.error("Failed to generate {} with exception : {}", configTxt, e); } } - private void writeNextNodeId(final List activeNodes, final BufferedWriter bw) { - requireNonNull(activeNodes); - requireNonNull(bw); - // find max nodeId of all nodes and write nextNodeId as maxNodeId + 1 - final var maxNodeId = activeNodes.stream() - .map(ActiveNode::node) - .map(Node::nodeId) - .max(Long::compareTo) - .orElseThrow(); - try { - bw.write("nextNodeId, " + (maxNodeId + 1)); - } catch (IOException e) { - log.error("Failed to write nextNodeId {} with exception : {}", maxNodeId, e); - } - } - private void writeConfigLineAndPem( @NonNull final ActiveNode activeNode, @NonNull final BufferedWriter bw, @NonNull final Path pathToWrite) { requireNonNull(activeNode); @@ -280,7 +270,8 @@ private void writeConfigLineAndPem( var line = new StringBuilder(); int weight = 0; final var node = activeNode.node(); - final var alias = nameToAlias(node.description()); + final var name = "node" + (node.nodeId() + 1); + final var alias = nameToAlias(name); final var pemFile = pathToWrite.resolve("s-public-" + alias + ".pem"); final int INT = 0; final int EXT = 1; @@ -297,7 +288,7 @@ private void writeConfigLineAndPem( .append(", ") .append(node.nodeId()) .append(", ") - .append(node.description()) + .append(name) .append(", ") .append(weight) .append(", ") diff --git a/hedera-node/hedera-network-admin-service-impl/src/test/java/com/hedera/node/app/service/networkadmin/impl/test/handlers/FreezeHandlerTest.java b/hedera-node/hedera-network-admin-service-impl/src/test/java/com/hedera/node/app/service/networkadmin/impl/test/handlers/FreezeHandlerTest.java index 5c71513018ef..16728937bf72 100644 --- a/hedera-node/hedera-network-admin-service-impl/src/test/java/com/hedera/node/app/service/networkadmin/impl/test/handlers/FreezeHandlerTest.java +++ b/hedera-node/hedera-network-admin-service-impl/src/test/java/com/hedera/node/app/service/networkadmin/impl/test/handlers/FreezeHandlerTest.java @@ -395,6 +395,7 @@ void happyPathPrepareUpgradeFile150() throws IOException { .willReturn(File.newBuilder().build()); given(upgradeFileStore.getFull(fileUpgradeFileId)).willReturn(Bytes.wrap("Upgrade file bytes")); given(nodeStore.keys()).willReturn(List.of(new EntityNumber(0)).iterator()); + given(nodeStore.sizeOfState()).willReturn(1L); TransactionID txnId = TransactionID.newBuilder() .accountID(nonAdminAccount) @@ -424,6 +425,7 @@ void happyPathPrepareUpgradeFile157() throws IOException { .willReturn(File.newBuilder().build()); given(upgradeFileStore.getFull(anotherFileUpgradeFileId)).willReturn(Bytes.wrap("Upgrade file bytes")); given(nodeStore.keys()).willReturn(List.of(new EntityNumber(0)).iterator()); + given(nodeStore.sizeOfState()).willReturn(1L); TransactionID txnId = TransactionID.newBuilder() .accountID(nonAdminAccount) diff --git a/hedera-node/hedera-network-admin-service-impl/src/test/java/com/hedera/node/app/service/networkadmin/impl/test/handlers/ReadableFreezeUpgradeActionsTest.java b/hedera-node/hedera-network-admin-service-impl/src/test/java/com/hedera/node/app/service/networkadmin/impl/test/handlers/ReadableFreezeUpgradeActionsTest.java index f380c0a8ed1c..76cc5cbd2398 100644 --- a/hedera-node/hedera-network-admin-service-impl/src/test/java/com/hedera/node/app/service/networkadmin/impl/test/handlers/ReadableFreezeUpgradeActionsTest.java +++ b/hedera-node/hedera-network-admin-service-impl/src/test/java/com/hedera/node/app/service/networkadmin/impl/test/handlers/ReadableFreezeUpgradeActionsTest.java @@ -16,6 +16,7 @@ package com.hedera.node.app.service.networkadmin.impl.test.handlers; +import static com.hedera.node.app.service.addressbook.AddressBookHelper.NODES_KEY; import static com.hedera.node.app.service.networkadmin.impl.handlers.FreezeUpgradeActions.EXEC_IMMEDIATE_MARKER; import static com.hedera.node.app.service.networkadmin.impl.handlers.FreezeUpgradeActions.EXEC_TELEMETRY_MARKER; import static com.hedera.node.app.service.networkadmin.impl.handlers.FreezeUpgradeActions.NOW_FROZEN_MARKER; @@ -40,6 +41,7 @@ import com.hedera.hapi.node.state.common.EntityNumber; import com.hedera.hapi.node.state.token.StakingNodeInfo; import com.hedera.node.app.service.addressbook.ReadableNodeStore; +import com.hedera.node.app.service.addressbook.impl.ReadableNodeStoreImpl; import com.hedera.node.app.service.addressbook.impl.schemas.V053AddressBookSchema; import com.hedera.node.app.service.file.impl.WritableUpgradeFileStore; import com.hedera.node.app.service.networkadmin.impl.WritableFreezeStore; @@ -54,6 +56,7 @@ import com.hedera.pbj.runtime.io.buffer.Bytes; import com.swirlds.platform.state.PlatformState; import com.swirlds.platform.system.address.AddressBook; +import com.swirlds.state.spi.ReadableStates; import com.swirlds.state.test.fixtures.MapReadableKVState; import edu.umd.cs.findbugs.annotations.Nullable; import java.io.File; @@ -66,7 +69,6 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; -import java.util.Collections; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.ForkJoinPool; @@ -135,17 +137,26 @@ class ReadableFreezeUpgradeActionsTest { private WritableUpgradeFileStore upgradeFileStore; @Mock - private ReadableNodeStore nodeStore; + private ReadableStakingInfoStore stakingInfoStore; @Mock - private ReadableStakingInfoStore stakingInfoStore; + protected ReadableStates readableStates; + + private ReadableNodeStore nodeStore; + + private Executor freezeExecutor; @BeforeEach void setUp() throws IOException { noiseFileLoc = zipOutputDir.toPath().resolve("forgotten.cfg"); noiseSubFileLoc = zipOutputDir.toPath().resolve("edargpu"); - final Executor freezeExecutor = new ForkJoinPool( + final var readableNodeState = + MapReadableKVState.builder(NODES_KEY).build(); + given(readableStates.get(NODES_KEY)).willReturn(readableNodeState); + nodeStore = new ReadableNodeStoreImpl(readableStates); + + freezeExecutor = new ForkJoinPool( 1, ForkJoinPool.defaultForkJoinWorkerThreadFactory, Thread.getDefaultUncaughtExceptionHandler(), true); subject = new FreezeUpgradeActions( adminServiceConfig, writableFreezeStore, freezeExecutor, upgradeFileStore, nodeStore, stakingInfoStore); @@ -169,7 +180,6 @@ void complainsLoudlyWhenUnableToUnzipArchive() { rmIfPresent(EXEC_IMMEDIATE_MARKER); given(adminServiceConfig.upgradeArtifactsPath()).willReturn(zipOutputDir.toString()); - given(nodeStore.keys()).willReturn(Collections.emptyIterator()); final Bytes invalidArchive = Bytes.wrap("Not a valid zip archive".getBytes(StandardCharsets.UTF_8)); subject.extractSoftwareUpgrade(invalidArchive).join(); @@ -185,7 +195,6 @@ void complainsLoudlyWhenUnableToUnzipArchive() { @Test void preparesForUpgrade() throws IOException { setupNoiseFiles(); - given(nodeStore.keys()).willReturn(Collections.emptyIterator()); rmIfPresent(EXEC_IMMEDIATE_MARKER); given(adminServiceConfig.upgradeArtifactsPath()).willReturn(zipOutputDir.toString()); @@ -423,17 +432,16 @@ private void setupNodes() { 8, false, A_COMPLEX_KEY); - final var readableNodeState = MapReadableKVState.builder("NODES") + final var readableNodeState = MapReadableKVState.builder(NODES_KEY) .value(new EntityNumber(4), node4) .value(new EntityNumber(2), node2) .value(new EntityNumber(3), node3) .value(new EntityNumber(1), node1) .build(); - given(nodeStore.keys()).willReturn(readableNodeState.keys()); - given(nodeStore.get(1)).willReturn(node1); - given(nodeStore.get(2)).willReturn(node2); - given(nodeStore.get(3)).willReturn(node3); - given(nodeStore.get(4)).willReturn(node4); + given(readableStates.get(NODES_KEY)).willReturn(readableNodeState); + nodeStore = new ReadableNodeStoreImpl(readableStates); + subject = new FreezeUpgradeActions( + adminServiceConfig, writableFreezeStore, freezeExecutor, upgradeFileStore, nodeStore, stakingInfoStore); var stakingNodeInfo1 = mock(StakingNodeInfo.class); var stakingNodeInfo2 = mock(StakingNodeInfo.class); var stakingNodeInfo4 = mock(StakingNodeInfo.class); diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/junit/hedera/utils/AddressBookUtils.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/junit/hedera/utils/AddressBookUtils.java index 1a220cdab2cc..0ffcb2623d37 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/junit/hedera/utils/AddressBookUtils.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/junit/hedera/utils/AddressBookUtils.java @@ -39,10 +39,8 @@ */ public class AddressBookUtils { public static final long CLASSIC_FIRST_NODE_ACCOUNT_NUM = 3; - public static final String[] CLASSIC_NODE_NAMES = new String[] { - "Alice", "Bob", "Carol", "Dave", "Eve", "Faythe", "Grace", "Heidi", "Ivy", "Judy", "Kathy", "Lana", - "Mallory", "Nadia", "Olivia", "Peggy", "Quinn", "Rita", "Sue", "Tina", "Ursula", "Vera", "Wendy", "Xena", - }; + public static final String[] CLASSIC_NODE_NAMES = + new String[] {"node1", "node2", "node3", "node4", "node5", "node6", "node7", "node8"}; private AddressBookUtils() { throw new UnsupportedOperationException("Utility Class"); @@ -143,7 +141,7 @@ public static Stream nodeIdsFrom(AddressBook addressBook) { /** * Returns service end point base on the host and port. - used for hapi path for ServiceEndPoint * - * @param host is an ip or domain name + * @param host is an ip or domain name, do not pass in an invalid ip such as "130.0.0.1", will set it as domain name otherwise. * @param port * @return ServiceEndpoint */ diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/HapiSpec.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/HapiSpec.java index 5a9e6606300b..f02522b18cc9 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/HapiSpec.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/HapiSpec.java @@ -16,7 +16,7 @@ package com.hedera.services.bdd.spec; -import static com.hedera.node.app.service.addressbook.impl.AddressBookServiceImpl.NODES_KEY; +import static com.hedera.node.app.service.addressbook.AddressBookHelper.NODES_KEY; import static com.hedera.node.app.service.token.impl.schemas.V0490TokenSchema.ACCOUNTS_KEY; import static com.hedera.services.bdd.junit.SharedNetworkLauncherSessionListener.repeatableModeRequested; import static com.hedera.services.bdd.junit.extensions.NetworkTargetingExtension.REPEATABLE_KEY_GENERATOR; diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/infrastructure/HapiSpecRegistry.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/infrastructure/HapiSpecRegistry.java index 29160d5d1610..f125d9920591 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/infrastructure/HapiSpecRegistry.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/infrastructure/HapiSpecRegistry.java @@ -877,7 +877,8 @@ public void saveNodeMeta(String name, NodeUpdateTransactionBody txn) { if (txn.hasGrpcCertificateHash()) { builder.setGrpcCertificateHash(txn.getGossipCaCertificate().toByteString()); } - // TODO builder.setGossipEndpoint() + builder.addAllGossipEndpoint(txn.getGossipEndpointList()); + builder.addAllServiceEndpoint(txn.getServiceEndpointList()); put(name, builder.build()); } } diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/transactions/node/HapiNodeCreate.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/transactions/node/HapiNodeCreate.java index 45a91bb78d5f..d7b9b28a7630 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/transactions/node/HapiNodeCreate.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/transactions/node/HapiNodeCreate.java @@ -170,7 +170,7 @@ protected Consumer opBodyDef(@NonNull final HapiSpec sp NodeCreateTransactionBody.class, builder -> { accountId.ifPresent(builder::setAccountId); description.ifPresent(builder::setDescription); - if (adminKey != null) builder.setAdminKey(adminKey); + builder.setAdminKey(adminKey); builder.clearGossipEndpoint().addAllGossipEndpoint(gossipEndpoints); builder.clearServiceEndpoint().addAllServiceEndpoint(grpcEndpoints); gossipCaCertificate.ifPresent(s -> builder.setGossipCaCertificate(ByteString.copyFrom(s))); @@ -212,4 +212,8 @@ protected MoreObjects.ToStringHelper toStringHelper() { Optional.ofNullable(lastReceipt).ifPresent(receipt -> helper.add("created", receipt.getNodeId())); return helper; } + + public Key getAdminKey() { + return adminKey; + } } diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/transactions/node/HapiNodeUpdate.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/transactions/node/HapiNodeUpdate.java index 9ecc4d0dc869..1bc98977932c 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/transactions/node/HapiNodeUpdate.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/transactions/node/HapiNodeUpdate.java @@ -218,4 +218,8 @@ protected MoreObjects.ToStringHelper toStringHelper() { newDescription.ifPresent(d -> helper.add("description", d)); return helper; } + + public Key getAdminKey() { + return newAdminKey.orElse(null); + } } diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/utilops/embedded/ViewNodeOp.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/utilops/embedded/ViewNodeOp.java index 2fd8069c4025..b4c0f61c50ea 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/utilops/embedded/ViewNodeOp.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/spec/utilops/embedded/ViewNodeOp.java @@ -17,8 +17,8 @@ package com.hedera.services.bdd.spec.utilops.embedded; import static com.hedera.node.app.hapi.utils.CommonPbjConverters.toPbj; +import static com.hedera.node.app.service.addressbook.AddressBookHelper.NODES_KEY; import static com.hedera.node.app.service.addressbook.AddressBookService.NAME; -import static com.hedera.node.app.service.addressbook.impl.AddressBookServiceImpl.NODES_KEY; import static java.util.Objects.requireNonNull; import com.hedera.hapi.node.state.addressbook.Node; diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/hip869/NodeCreateTest.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/hip869/NodeCreateTest.java index 13e2023d5610..4c4e3ce20f66 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/hip869/NodeCreateTest.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/hip869/NodeCreateTest.java @@ -16,6 +16,7 @@ package com.hedera.services.bdd.suites.hip869; +import static com.hedera.node.app.hapi.utils.CommonPbjConverters.toPbj; import static com.hedera.services.bdd.junit.EmbeddedReason.MUST_SKIP_INGEST; import static com.hedera.services.bdd.junit.EmbeddedReason.NEEDS_STATE_ACCESS; import static com.hedera.services.bdd.junit.hedera.utils.AddressBookUtils.endpointFor; @@ -36,12 +37,16 @@ import static com.hedera.services.bdd.suites.HapiSuite.ONE_HUNDRED_HBARS; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.BUSY; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.GOSSIP_ENDPOINTS_EXCEEDED_LIMIT; +import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INSUFFICIENT_TX_FEE; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_ADMIN_KEY; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_GOSSIP_CA_CERTIFICATE; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_GOSSIP_ENDPOINT; +import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_NODE_ACCOUNT_ID; +import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_NODE_DESCRIPTION; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.INVALID_SERVICE_ENDPOINT; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.KEY_REQUIRED; +import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.MAX_NODES_CREATED; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.OK; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.SERVICE_ENDPOINTS_EXCEEDED_LIMIT; import static com.hederahashgraph.api.proto.java.ResponseCodeEnum.SUCCESS; @@ -53,11 +58,14 @@ import com.hedera.services.bdd.junit.EmbeddedHapiTest; import com.hedera.services.bdd.junit.HapiTest; import com.hedera.services.bdd.junit.LeakyEmbeddedHapiTest; +import com.hedera.services.bdd.junit.LeakyHapiTest; import com.hedera.services.bdd.spec.keys.KeyShape; +import com.hederahashgraph.api.proto.java.AccountID; import com.hederahashgraph.api.proto.java.ServiceEndpoint; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DynamicTest; public class NodeCreateTest { @@ -256,21 +264,20 @@ final Stream failOnTooManyServiceEndpoints() { } /** - * Check that node creation succeeds with gossip and service endpoints using domain names and all optional fields are recorded. + * Check that node creation succeeds with gossip and service endpoints using ips and all optional fields are recorded. * @see HIP-869 */ @EmbeddedHapiTest(NEEDS_STATE_ACCESS) - final Stream allFieldsSetHappyCaseForDomains() { + final Stream allFieldsSetHappyCaseForIps() { return hapiTest( newKeyNamed(ED_25519_KEY).shape(KeyShape.ED25519), - overriding("nodes.gossipFqdnRestricted", "false"), nodeCreate("nodeCreate") .description("hello") .gossipCaCertificate("gossip".getBytes()) .grpcCertificateHash("hash".getBytes()) .accountId(asAccount("0.0.100")) - .gossipEndpoint(GOSSIP_ENDPOINTS) - .serviceEndpoint(SERVICES_ENDPOINTS) + .gossipEndpoint(GOSSIP_ENDPOINTS_IPS) + .serviceEndpoint(SERVICES_ENDPOINTS_IPS) .adminKey(ED_25519_KEY) .hasPrecheck(OK) .hasKnownStatus(SUCCESS), @@ -285,33 +292,34 @@ final Stream allFieldsSetHappyCaseForDomains() { ByteString.copyFrom(node.grpcCertificateHash().toByteArray()), "GRPC hash invalid"); assertEquals(100, node.accountId().accountNum(), "Account ID invalid"); - assertEqualServiceEndpoints(GOSSIP_ENDPOINTS, node.gossipEndpoint()); - assertEqualServiceEndpoints(SERVICES_ENDPOINTS, node.serviceEndpoint()); + assertEqualServiceEndpoints(GOSSIP_ENDPOINTS_IPS, node.gossipEndpoint()); + assertEqualServiceEndpoints(SERVICES_ENDPOINTS_IPS, node.serviceEndpoint()); assertNotNull(node.adminKey(), "Admin key invalid"); })); } /** - * Check that node creation succeeds with gossip and service endpoints using IPs and all optional fields are recorded. + * Check that node creation succeeds with gossip and service endpoints using domain names and all optional fields are recorded. * @see HIP-869 */ @LeakyEmbeddedHapiTest( reason = NEEDS_STATE_ACCESS, overrides = {"nodes.gossipFqdnRestricted"}) - final Stream allFieldsSetHappyCaseForIps() { + final Stream allFieldsSetHappyCaseForDomains() { + final var nodeCreate = nodeCreate("nodeCreate") + .description("hello") + .gossipCaCertificate("gossip".getBytes()) + .grpcCertificateHash("hash".getBytes()) + .accountId(asAccount("0.0.100")) + .gossipEndpoint(GOSSIP_ENDPOINTS) + .serviceEndpoint(SERVICES_ENDPOINTS) + .adminKey(ED_25519_KEY) + .hasPrecheck(OK) + .hasKnownStatus(SUCCESS); return hapiTest( newKeyNamed(ED_25519_KEY).shape(KeyShape.ED25519), overriding("nodes.gossipFqdnRestricted", "false"), - nodeCreate("nodeCreate") - .description("hello") - .gossipCaCertificate("gossip".getBytes()) - .grpcCertificateHash("hash".getBytes()) - .accountId(asAccount("0.0.100")) - .gossipEndpoint(GOSSIP_ENDPOINTS_IPS) - .serviceEndpoint(SERVICES_ENDPOINTS_IPS) - .adminKey(ED_25519_KEY) - .hasPrecheck(OK) - .hasKnownStatus(SUCCESS), + nodeCreate, viewNode("nodeCreate", node -> { assertEquals("hello", node.description(), "Description invalid"); assertEquals( @@ -323,9 +331,9 @@ final Stream allFieldsSetHappyCaseForIps() { ByteString.copyFrom(node.grpcCertificateHash().toByteArray()), "GRPC hash invalid"); assertEquals(100, node.accountId().accountNum(), "Account ID invalid"); - assertEqualServiceEndpoints(GOSSIP_ENDPOINTS_IPS, node.gossipEndpoint()); - assertEqualServiceEndpoints(SERVICES_ENDPOINTS_IPS, node.serviceEndpoint()); - assertNotNull(node.adminKey(), "Admin key invalid"); + assertEqualServiceEndpoints(GOSSIP_ENDPOINTS, node.gossipEndpoint()); + assertEqualServiceEndpoints(SERVICES_ENDPOINTS, node.serviceEndpoint()); + assertEquals(toPbj(nodeCreate.getAdminKey()), node.adminKey(), "Admin key invalid"); })); } @@ -443,6 +451,37 @@ final Stream failsAtIngestForUnAuthorizedTxns() { .via("nodeCreation")); } + @LeakyHapiTest(overrides = {"nodes.maxNumber"}) + @DisplayName("check error code MAX_NODES_CREATED is returned correctly") + final Stream maxNodesReachedFail() { + return hapiTest( + overriding("nodes.maxNumber", "1"), nodeCreate("testNode").hasKnownStatus(MAX_NODES_CREATED)); + } + + @HapiTest + @DisplayName("Not existing account as accountId during nodeCreate failed") + final Stream notExistingAccountFail() { + return hapiTest(nodeCreate("testNode") + .accountId(AccountID.newBuilder().setAccountNum(50000).build()) + .hasKnownStatus(INVALID_NODE_ACCOUNT_ID)); + } + + @LeakyHapiTest(overrides = {"nodes.nodeMaxDescriptionUtf8Bytes"}) + @DisplayName("Check the max description size") + final Stream updateTooLargeDescriptionFail() { + return hapiTest( + overriding("nodes.nodeMaxDescriptionUtf8Bytes", "3"), + nodeCreate("testNode").description("toolarge").hasKnownStatus(INVALID_NODE_DESCRIPTION)); + } + + @HapiTest + @DisplayName("Check default setting, gossipEndpoint can not have domain names") + final Stream gossipEndpointHaveDomainNameFail() { + return hapiTest(nodeCreate("testNode") + .gossipEndpoint(GOSSIP_ENDPOINTS) + .hasKnownStatus(GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN)); + } + private static void assertEqualServiceEndpoints( List expected, List actual) { diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/hip869/NodeUpdateTest.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/hip869/NodeUpdateTest.java index b4fa3fcdffb4..d077711bf2be 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/hip869/NodeUpdateTest.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/hip869/NodeUpdateTest.java @@ -29,6 +29,7 @@ import static com.hedera.services.bdd.spec.utilops.EmbeddedVerbs.viewNode; import static com.hedera.services.bdd.spec.utilops.UtilVerbs.newKeyNamed; import static com.hedera.services.bdd.spec.utilops.UtilVerbs.overriding; +import static com.hedera.services.bdd.suites.HapiSuite.DEFAULT_PAYER; import static com.hedera.services.bdd.suites.HapiSuite.GENESIS; import static com.hedera.services.bdd.suites.HapiSuite.NONSENSE_KEY; import static com.hedera.services.bdd.suites.HapiSuite.ONE_HBAR; @@ -157,20 +158,22 @@ final Stream validateServiceEndpoint() { @EmbeddedHapiTest(NEEDS_STATE_ACCESS) final Stream updateMultipleFieldsWork() { + final var updateOp = nodeUpdate("testNode") + .adminKey("adminKey2") + .signedBy(DEFAULT_PAYER, "adminKey", "adminKey2") + .description("updated description") + .gossipEndpoint(List.of( + asServiceEndpoint("127.0.0.1:60"), + asServiceEndpoint("127.0.0.2:60"), + asServiceEndpoint("127.0.0.3:60"))) + .serviceEndpoint(List.of(asServiceEndpoint("127.0.1.1:60"), asServiceEndpoint("127.0.1.2:60"))) + .gossipCaCertificate("caCert") + .grpcCertificateHash("grpcCert"); return hapiTest( newKeyNamed("adminKey"), newKeyNamed("adminKey2"), nodeCreate("testNode").description("description to be changed").adminKey("adminKey"), - nodeUpdate("testNode") - .adminKey("adminKey") - .description("updated description") - .gossipEndpoint(List.of( - asServiceEndpoint("127.0.0.1:60"), - asServiceEndpoint("127.0.0.2:60"), - asServiceEndpoint("127.0.0.3:60"))) - .serviceEndpoint(List.of(asServiceEndpoint("127.0.1.1:60"), asServiceEndpoint("127.0.1.2:60"))) - .gossipCaCertificate("caCert") - .grpcCertificateHash("grpcCert"), + updateOp, viewNode("testNode", node -> { assertEquals("updated description", node.description(), "Node description should be updated"); assertIterableEquals( @@ -192,6 +195,7 @@ final Stream updateMultipleFieldsWork() { Bytes.wrap("grpcCert"), node.grpcCertificateHash(), "Node grpcCertificateHash should be updated"); + assertEquals(toPbj(updateOp.getAdminKey()), node.adminKey(), "Node adminKey should be updated"); })); } diff --git a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/regression/system/DabEnabledUpgradeTest.java b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/regression/system/DabEnabledUpgradeTest.java index 050938e4c054..1adfb64cce2d 100644 --- a/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/regression/system/DabEnabledUpgradeTest.java +++ b/hedera-node/test-clients/src/main/java/com/hedera/services/bdd/suites/regression/system/DabEnabledUpgradeTest.java @@ -30,7 +30,6 @@ import static com.hedera.services.bdd.spec.transactions.TxnVerbs.nodeCreate; import static com.hedera.services.bdd.spec.transactions.TxnVerbs.nodeDelete; import static com.hedera.services.bdd.spec.utilops.UtilVerbs.ensureStakingActivated; -import static com.hedera.services.bdd.spec.utilops.UtilVerbs.newKeyNamed; import static com.hedera.services.bdd.spec.utilops.UtilVerbs.sourcing; import static com.hedera.services.bdd.spec.utilops.UtilVerbs.validateUpgradeAddressBooks; import static com.hedera.services.bdd.spec.utilops.UtilVerbs.waitUntilStartOfNextStakingPeriod; @@ -173,13 +172,10 @@ class AfterAddingNode4 { @BeforeAll static void beforeAll(@NonNull final TestLifecycle testLifecycle) { - testLifecycle.doAdhoc( - newKeyNamed("adminKey"), - nodeCreate("node4") - .adminKey("adminKey") - .accountId(NEW_ACCOUNT_ID) - .description(CLASSIC_NODE_NAMES[4]) - .withAvailableSubProcessPorts()); + testLifecycle.doAdhoc(nodeCreate("node4") + .accountId(NEW_ACCOUNT_ID) + .description(CLASSIC_NODE_NAMES[4]) + .withAvailableSubProcessPorts()); } @HapiTest diff --git a/hedera-node/test-clients/src/main/java/module-info.java b/hedera-node/test-clients/src/main/java/module-info.java index b7c7d21be7a7..7438211cf0da 100644 --- a/hedera-node/test-clients/src/main/java/module-info.java +++ b/hedera-node/test-clients/src/main/java/module-info.java @@ -57,7 +57,6 @@ requires transitive org.junit.jupiter.api; requires transitive org.testcontainers; requires transitive tuweni.bytes; - requires com.hedera.node.app.service.addressbook.impl; requires com.hedera.node.app.service.addressbook; requires com.hedera.node.app.service.contract.impl; requires com.hedera.node.app.service.token.impl;