From b044fcc81a73775263d4c743f10cf70b9d82b579 Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Wed, 29 Jan 2025 22:26:19 +0200 Subject: [PATCH] feat: Add adminKey flag to node setup command (#1193) Signed-off-by: Ivo Yankov Signed-off-by: Jeromy Cannon Co-authored-by: Jeromy Cannon --- src/commands/flags.ts | 13 +++++++ src/commands/node/configs.ts | 1 + src/commands/node/flags.ts | 2 +- src/commands/node/tasks.ts | 2 ++ .../genesis_network_data_constructor.ts | 35 ++++++++++++++++--- test/test_util.ts | 1 + 6 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/commands/flags.ts b/src/commands/flags.ts index d218a6075..32a972954 100644 --- a/src/commands/flags.ts +++ b/src/commands/flags.ts @@ -1338,6 +1338,17 @@ export class Flags { prompt: undefined, }; + static readonly adminPublicKeys: CommandFlag = { + constName: 'adminPublicKeys', + name: 'admin-public-keys', + definition: { + describe: 'Comma separated list of DER encoded ED25519 public keys and must match the order of the node aliases', + defaultValue: constants.GENESIS_KEY, + type: 'string', + }, + prompt: undefined, + }; + static readonly quiet: CommandFlag = { constName: 'quiet', name: 'quiet-mode', @@ -1718,6 +1729,8 @@ export class Flags { static readonly allFlags: CommandFlag[] = [ Flags.accountId, + Flags.adminKey, + Flags.adminPublicKeys, Flags.amount, Flags.apiPermissionProperties, Flags.app, diff --git a/src/commands/node/configs.ts b/src/commands/node/configs.ts index cb2d1216b..862bf0c91 100644 --- a/src/commands/node/configs.ts +++ b/src/commands/node/configs.ts @@ -424,6 +424,7 @@ export interface NodeDeleteConfigClass { export interface NodeSetupConfigClass { app: string; appConfig: string; + adminKey: string; cacheDir: string; devMode: boolean; localBuildPath: string; diff --git a/src/commands/node/flags.ts b/src/commands/node/flags.ts index 047a196e7..dbb7ce148 100644 --- a/src/commands/node/flags.ts +++ b/src/commands/node/flags.ts @@ -254,5 +254,5 @@ export const START_FLAGS = { export const SETUP_FLAGS = { requiredFlags: [flags.cacheDir, flags.namespace, flags.releaseTag], requiredFlagsWithDisabledPrompt: [flags.app, flags.appConfig, flags.nodeAliasesUnparsed], - optionalFlags: [flags.quiet, flags.devMode, flags.localBuildPath], + optionalFlags: [flags.quiet, flags.devMode, flags.localBuildPath, flags.adminPublicKeys], }; diff --git a/src/commands/node/tasks.ts b/src/commands/node/tasks.ts index 73bcb9d27..d5c68687e 100644 --- a/src/commands/node/tasks.ts +++ b/src/commands/node/tasks.ts @@ -958,11 +958,13 @@ export class NodeCommandTasks { ) { const networkNodeServiceMap = await this.accountManager.getNodeServiceMap(namespace); + const adminPublicKeys = splitFlagInput(this.configManager.getFlag(flags.adminPublicKeys)); const genesisNetworkData = await GenesisNetworkDataConstructor.initialize( nodeAliases, this.keyManager, keysDir, networkNodeServiceMap, + adminPublicKeys, ); const genesisNetworkJson = path.join(stagingDir, 'genesis-network.json'); diff --git a/src/core/genesis_network_models/genesis_network_data_constructor.ts b/src/core/genesis_network_models/genesis_network_data_constructor.ts index 3e3b4bd6e..eb0fb2920 100644 --- a/src/core/genesis_network_models/genesis_network_data_constructor.ts +++ b/src/core/genesis_network_models/genesis_network_data_constructor.ts @@ -14,7 +14,7 @@ * limitations under the License. * */ -import {AccountId, PrivateKey} from '@hashgraph/sdk'; +import {AccountId, PrivateKey, PublicKey} from '@hashgraph/sdk'; import {GenesisNetworkNodeDataWrapper} from './genesis_network_node_data_wrapper.js'; import * as constants from '../constants.js'; @@ -25,6 +25,8 @@ import {GenesisNetworkRosterEntryDataWrapper} from './genesis_network_roster_ent import {Templates} from '../templates.js'; import path from 'path'; import type {NetworkNodeServices} from '../network_node_services.js'; +import {SoloError} from '../errors.js'; +import {Flags as flags} from '../../commands/flags.js'; /** * Used to construct the nodes data and convert them to JSON @@ -38,10 +40,13 @@ export class GenesisNetworkDataConstructor implements ToJSON { private readonly keyManager: KeyManager, private readonly keysDir: string, private readonly networkNodeServiceMap: Map, + adminPublicKeyMap: Map, ) { nodeAliases.forEach(nodeAlias => { - const adminPrivateKey = PrivateKey.fromStringED25519(constants.GENESIS_KEY); - const adminPubKey = adminPrivateKey.publicKey; + const genesisPrivateKey = PrivateKey.fromStringED25519(constants.GENESIS_KEY); + const adminPubKey = PublicKey.fromStringED25519(adminPublicKeyMap[nodeAlias]) + ? adminPublicKeyMap[nodeAlias] + : genesisPrivateKey.publicKey; const nodeDataWrapper = new GenesisNetworkNodeDataWrapper( +networkNodeServiceMap.get(nodeAlias).nodeId, @@ -74,8 +79,30 @@ export class GenesisNetworkDataConstructor implements ToJSON { keyManager: KeyManager, keysDir: string, networkNodeServiceMap: Map, + adminPublicKeys: string[], ): Promise { - const instance = new GenesisNetworkDataConstructor(nodeAliases, keyManager, keysDir, networkNodeServiceMap); + const adminPublicKeyMap: Map = new Map(); + + const adminPublicKeyIsDefaultValue = + adminPublicKeys.length === 1 && adminPublicKeys[0] === flags.adminPublicKeys.definition.defaultValue; + // If admin keys are passed and if it is not the default value from flags then validate and build the adminPublicKeyMap + if (adminPublicKeys.length > 0 && !adminPublicKeyIsDefaultValue) { + if (adminPublicKeys.length !== nodeAliases.length) { + throw new SoloError('Provide a comma separated list of DER encoded ED25519 public keys for each node'); + } + + adminPublicKeys.forEach((key, i) => { + adminPublicKeyMap[nodeAliases[i]] = key; + }); + } + + const instance = new GenesisNetworkDataConstructor( + nodeAliases, + keyManager, + keysDir, + networkNodeServiceMap, + adminPublicKeyMap, + ); await instance.load(); diff --git a/test/test_util.ts b/test/test_util.ts index 11309101a..00f606672 100644 --- a/test/test_util.ts +++ b/test/test_util.ts @@ -304,6 +304,7 @@ export function e2eTestSuite( expect(nodeCmd.getUnusedConfigs(NodeCommandConfigs.SETUP_CONFIGS_NAME)).to.deep.equal([ flags.quiet.constName, flags.devMode.constName, + flags.adminPublicKeys.constName, ]); } catch (e) { nodeCmd.logger.showUserError(e);