@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
97 lines • 7.04 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
import { it, describe } from 'mocha';
import { expect } from 'chai';
import { Flags as flags } from '../../../src/commands/flags.js';
import * as constants from '../../../src/core/constants.js';
import { accountCreationShouldSucceed, balanceQueryShouldSucceed, getNodeAliasesPrivateKeysHash, getTemporaryDirectory, } from '../../test-utility.js';
import { Duration } from '../../../src/core/time/duration.js';
import { NodeUpdateTest } from './tests/node-update-test.js';
import { main } from '../../../src/index.js';
import { PrivateKey, AccountCreateTransaction, Hbar, HbarUnit, AccountId } from '@hiero-ledger/sdk';
export function testSeparateNodeUpdate(argv, bootstrapResp, namespace, timeout) {
const updateNodeId = 'node2';
let newAccountId = '';
argv.setArg(flags.nodeAliasesUnparsed, 'node1,node2,node3');
argv.setArg(flags.nodeAlias, updateNodeId);
argv.setArg(flags.newAccountNumber, newAccountId);
argv.setArg(flags.newAdminKey, '302e020100300506032b6570042204200cde8d512569610f184b8b399e91e46899805c6171f7c2b8666d2a417bcc66c2');
const { opts: { k8Factory, logger, remoteConfig, accountManager, keyManager }, } = bootstrapResp;
describe('Node update via separated commands', async () => {
let existingServiceMap;
let existingNodeIdsPrivateKeysHash;
it('should create a new account for the updated node', async () => {
await accountManager.loadNodeClient(namespace, remoteConfig.getClusterRefs(), argv.getArg(flags.deployment), argv.getArg(flags.forcePortForward));
const privateKey = PrivateKey.generateED25519();
const amount = 100;
const newAccount = await new AccountCreateTransaction()
.setKeyWithoutAlias(privateKey)
.setInitialBalance(Hbar.from(amount, HbarUnit.Hbar))
.execute(accountManager._nodeClient);
const getReceipt = await newAccount.getReceipt(accountManager._nodeClient);
const accountId = getReceipt.accountId.toString();
logger.info(`New account created for updated node: ${accountId}`);
argv.setArg(flags.newAccountNumber, accountId);
newAccountId = accountId;
// save to k8 secret for later use
await accountManager.createOrReplaceAccountKeySecret(privateKey, AccountId.fromString(accountId), false, namespace);
}).timeout(Duration.ofMinutes(2).toMillis());
it('cache current version of private keys', async () => {
existingServiceMap = await accountManager.getNodeServiceMap(namespace, remoteConfig.getClusterRefs(), argv.getArg(flags.deployment));
existingNodeIdsPrivateKeysHash = await getNodeAliasesPrivateKeysHash(existingServiceMap, k8Factory, getTemporaryDirectory());
}).timeout(Duration.ofMinutes(8).toMillis());
it('should update a new node property successfully', async () => {
// generate gossip and tls keys for the updated node
const temporaryDirectory = getTemporaryDirectory();
const signingKey = await keyManager.generateSigningKey(updateNodeId);
const signingKeyFiles = await keyManager.storeSigningKey(updateNodeId, signingKey, temporaryDirectory);
logger.debug(`generated test gossip signing keys for node ${updateNodeId} : ${signingKeyFiles.certificateFile}`);
argv.setArg(flags.gossipPublicKey, signingKeyFiles.certificateFile);
argv.setArg(flags.gossipPrivateKey, signingKeyFiles.privateKeyFile);
const tlsKey = await keyManager.generateGrpcTlsKey(updateNodeId);
const tlsKeyFiles = await keyManager.storeTLSKey(updateNodeId, tlsKey, temporaryDirectory);
logger.debug(`generated test TLS keys for node ${updateNodeId} : ${tlsKeyFiles.certificateFile}`);
argv.setArg(flags.tlsPublicKey, tlsKeyFiles.certificateFile);
argv.setArg(flags.tlsPrivateKey, tlsKeyFiles.privateKeyFile);
const temporaryDirectory2 = 'contextDir';
await main(NodeUpdateTest.soloNodeUpdatePrepareArgv(argv.getArg(flags.deployment), temporaryDirectory2, argv.getArg(flags.cacheDir), {
nodeAlias: updateNodeId,
newAdminKey: argv.getArg(flags.newAdminKey),
newAccountNumber: argv.getArg(flags.newAccountNumber),
tlsPublicKey: argv.getArg(flags.tlsPublicKey),
tlsPrivateKey: argv.getArg(flags.tlsPrivateKey),
gossipPublicKey: argv.getArg(flags.gossipPublicKey),
gossipPrivateKey: argv.getArg(flags.gossipPrivateKey),
}));
await main(NodeUpdateTest.soloNodeUpdateSubmitArgv(argv.getArg(flags.deployment), temporaryDirectory2, argv.getArg(flags.cacheDir)));
await main(NodeUpdateTest.soloNodeUpdateExecuteArgv(argv.getArg(flags.deployment), temporaryDirectory2, argv.getArg(flags.cacheDir)));
await accountManager.close();
}).timeout(Duration.ofMinutes(30).toMillis());
balanceQueryShouldSucceed(accountManager, namespace, remoteConfig, logger, updateNodeId);
accountCreationShouldSucceed(accountManager, namespace, remoteConfig, logger, updateNodeId);
it('signing key and tls key should not match previous one', async () => {
const currentNodeIdsPrivateKeysHash = await getNodeAliasesPrivateKeysHash(existingServiceMap, k8Factory, getTemporaryDirectory());
for (const [nodeAlias, existingKeyHashMap] of existingNodeIdsPrivateKeysHash.entries()) {
const currentNodeKeyHashMap = currentNodeIdsPrivateKeysHash.get(nodeAlias);
for (const [keyFileName, existingKeyHash] of existingKeyHashMap.entries()) {
if (nodeAlias === updateNodeId &&
(keyFileName.startsWith(constants.SIGNING_KEY_PREFIX) || keyFileName.startsWith('hedera'))) {
expect(`${nodeAlias}:${keyFileName}:${currentNodeKeyHashMap.get(keyFileName)}`).not.to.equal(`${nodeAlias}:${keyFileName}:${existingKeyHash}`);
}
else {
expect(`${nodeAlias}:${keyFileName}:${currentNodeKeyHashMap.get(keyFileName)}`).to.equal(`${nodeAlias}:${keyFileName}:${existingKeyHash}`);
}
}
}
}).timeout(timeout);
it('the consensus nodes accountId should be the newAccountId', async () => {
// read config.txt file from first node, read config.txt line by line, it should not contain value of newAccountId
const pods = await k8Factory
.default()
.pods()
.list(namespace, [`solo.hedera.com/node-name=${updateNodeId}`]);
const accountId = pods[0].labels['solo.hedera.com/account-id'];
expect(accountId).to.equal(newAccountId);
}).timeout(Duration.ofMinutes(10).toMillis());
});
}
//# sourceMappingURL=separate-node-update.test.js.map