Skip to content

Commit

Permalink
changes from other branch
Browse files Browse the repository at this point in the history
Signed-off-by: instamenta <[email protected]>
  • Loading branch information
instamenta committed Dec 11, 2024
1 parent 88c2506 commit 5a62289
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 15 deletions.
18 changes: 16 additions & 2 deletions src/commands/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export interface NetworkDeployConfigClass {
grpcWebTlsCertificatePath: string;
grpcTlsKeyPath: string;
grpcWebTlsKeyPath: string;
genesisNetworkJson: string;
getUnusedConfigs: () => string[];
haproxyIps: string;
envoyIps: string;
Expand Down Expand Up @@ -140,6 +141,7 @@ export class NetworkCommand extends BaseCommand {
releaseTag?: string;
persistentVolumeClaims?: string;
valuesFile?: string;
genesisNetworkJson?: string;
haproxyIpsParsed?: Record<NodeAlias, IP>;
envoyIpsParsed?: Record<NodeAlias, IP>;
} = {},
Expand Down Expand Up @@ -197,6 +199,8 @@ export class NetworkCommand extends BaseCommand {
valuesArg += this.prepareValuesFiles(config.valuesFile);
}

valuesArg += `--set "hedera.configMaps.genesisNetworkJson=${config.genesisNetworkJson}"`

this.logger.debug('Prepared helm chart values', {valuesArg});
return valuesArg;
}
Expand Down Expand Up @@ -257,6 +261,8 @@ export class NetworkCommand extends BaseCommand {
constants.SOLO_DEPLOYMENT_CHART,
);

config.genesisNetworkJson = this.prepareGenesisNetworkJson(config)

config.valuesArg = await this.prepareValuesArg(config);

// compute other config parameters
Expand Down Expand Up @@ -390,7 +396,7 @@ export class NetworkCommand extends BaseCommand {
task: (ctx, parentTask) => {
const config = ctx.config;

// set up the sub-tasks
// set up the subtasks
return parentTask.newListr(self.platformInstaller.copyNodeKeys(config.stagingDir, config.nodeAliases), {
concurrent: true,
rendererOptions: constants.LISTR_DEFAULT_RENDERER_OPTION,
Expand Down Expand Up @@ -506,7 +512,7 @@ export class NetworkCommand extends BaseCommand {
),
});

// set up the sub-tasks
// set up the subtasks
return task.newListr(subTasks, {
concurrent: false, // no need to run concurrently since if one node is up, the rest should be up by then
rendererOptions: {
Expand Down Expand Up @@ -675,6 +681,14 @@ export class NetworkCommand extends BaseCommand {
return true;
}

prepareGenesisNetworkJson(config: NetworkDeployConfigClass): string {
const data = {network: {nodes: []}}

// TODO

return JSON.stringify(data);
}

getCommandDefinition(): {command: string; desc: string; builder: CommandBuilder} {
const self = this;
return {
Expand Down
1 change: 1 addition & 0 deletions src/core/account_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ export class AccountManager {
* @param networkNodeServicesMap - a map of the service objects that proxy the nodes
* @param operatorId - the account id of the operator of the transactions
* @param operatorKey - the private key of the operator of the transactions
* @param skipNodeAlias -
* @returns a node client that can be used to call transactions
*/
async _getNodeClient(
Expand Down
3 changes: 2 additions & 1 deletion src/core/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,14 @@ export function addDebugOptions(valuesArg: string, debugNodeAlias: NodeAlias, in
export function addSaveContextParser(ctx: any) {
const exportedCtx = {} as Record<string, string>;

const config = /** @type {NodeAddConfigClass} **/ ctx.config;
const config = ctx.config as NodeAddConfigClass;
const exportedFields = ['tlsCertHash', 'upgradeZipHash', 'newNode'];

exportedCtx.signingCertDer = ctx.signingCertDer.toString();
exportedCtx.gossipEndpoints = ctx.gossipEndpoints.map((ep: any) => `${ep.getDomainName}:${ep.getPort}`);
exportedCtx.grpcServiceEndpoints = ctx.grpcServiceEndpoints.map((ep: any) => `${ep.getDomainName}:${ep.getPort}`);
exportedCtx.adminKey = ctx.adminKey.toString();
// @ts-ignore
exportedCtx.existingNodeAliases = config.existingNodeAliases;

for (const prop of exportedFields) {
Expand Down
57 changes: 57 additions & 0 deletions src/core/models/genesisNetworkDataConstructor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* 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.
*
*/
import type {NodeAlias, NodeAliases} from '../../types/aliases.js';
import {GenesisNetworkNodeDataWrapper} from './genesisNetworkNodeDataWrapper.js';
import {Templates} from '../templates.js';
import {KeyManager} from '../key_manager.js';

import crypto from 'node:crypto';
import {PrivateKey} from '@hashgraph/sdk';
import {constants} from '../index.js';

export class GenesisNetworkDataConstructor {
public readonly nodes: Record<NodeAlias, GenesisNetworkNodeDataWrapper>;

constructor (public readonly nodeAliases: NodeAliases) {
this.nodeAliases.forEach(nodeAlias => {
this.nodes[nodeAlias] = new GenesisNetworkNodeDataWrapper(Templates.nodeIdFromNodeAlias(nodeAlias))

const adminKey = PrivateKey.fromStringED25519(constants.GENESIS_KEY)
this.nodes[nodeAlias].adminKey = adminKey.publicKey
})
}

/**
* @param keyManager
* @param keysDir - !!! config.keysDir !!!
*/
async load (keyManager: KeyManager, keysDir: string) {
await Promise.all(this.nodeAliases.map(async nodeAlias => {
const nodeKeys = await keyManager.loadSigningKey(nodeAlias, keysDir);

this.nodes[nodeAlias].gossipCaCertificate = nodeKeys.certificate.toString()

const certificate = nodeKeys.certificate.toString();

// TODO: change parameters
const hash = crypto.createHash('sha256').update(certificate).digest('hex');

this.nodes[nodeAlias].gossipCaCertificate = certificate;
this.nodes[nodeAlias].grpcCertificateHash = hash;
}))
}
}
58 changes: 58 additions & 0 deletions src/core/models/genesisNetworkNodeDataWrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* 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.
*
*/
import type {Nullable} from '../../types/aliases.js';
import type {AccountId, Key} from '@hashgraph/sdk';
import type {ServiceEndpoint} from '../../types/index.js';

interface Node {
nodeId: number;
accountId: AccountId | string;
description: string;
gossipEndpoint: Nullable<ServiceEndpoint>;
serviceEndpoint: Nullable<ServiceEndpoint>;
gossipCaCertificate: string; // Bytes
grpcCertificateHash: string; // Bytes
weight: number;
deleted: boolean;
adminKey: Nullable<Key>;
}

export class GenesisNetworkNodeDataWrapper implements Node{
public readonly nodeId: number;
public readonly accountId: AccountId | string;
public readonly description: string;
public gossipEndpoint: ServiceEndpoint;
public serviceEndpoint: ServiceEndpoint;
public gossipCaCertificate: string;
public grpcCertificateHash: string;
public readonly weight: number;
public readonly deleted: boolean;
public adminKey: Nullable<Key>;

constructor (nodeId: number) {
this.nodeId = nodeId;
this.deleted = false;
}

addGossipEndpoint (ipAddressV4: string, port: number, domainName: string): void {
this.gossipEndpoint = {ipAddressV4, port, domainName};
}

addServiceEndpoint (ipAddressV4: string, port: number, domainName: string): void {
this.serviceEndpoint = {ipAddressV4, port, domainName};
}
}
28 changes: 17 additions & 11 deletions src/core/profile_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import * as helpers from './helpers.js';
import {getNodeAccountMap} from './helpers.js';
import type {SoloLogger} from './logging.js';
import type {NodeAlias, NodeAliases} from '../types/aliases.js';
import {GenesisNetworkDataConstructor} from './models/genesisNetworkDataConstructor.js';

const consensusSidecars = [
'recordStreamUploader',
Expand Down Expand Up @@ -100,10 +101,10 @@ export class ProfileManager {
}

/**
* Set value in the yaml object
* Set value in the YAML object
* @param itemPath - item path in the yaml
* @param value - value to be set
* @param yamlRoot - root of the yaml object
* @param yamlRoot - root of the YAML object
* @returns
*/
_setValue(itemPath: string, value: any, yamlRoot: object): object {
Expand Down Expand Up @@ -309,14 +310,14 @@ export class ProfileManager {
const nodeAliases = helpers.parseNodeAliases(this.configManager.getFlag(flags.nodeAliasesUnparsed));
if (!nodeAliases) throw new SoloError('Node IDs are not set in the config');

// generate the yaml
// generate the YAML
const yamlRoot = {};
this.resourcesForConsensusPod(profile, nodeAliases, yamlRoot);
this.resourcesForHaProxyPod(profile, yamlRoot);
this.resourcesForEnvoyProxyPod(profile, yamlRoot);
this.resourcesForMinioTenantPod(profile, yamlRoot);

// write the yaml
// write the YAML
const cachedValuesFile = path.join(this.cacheDir, `solo-${profileName}.yaml`);
return new Promise<string>((resolve, reject) => {
fs.writeFile(cachedValuesFile, yaml.stringify(yamlRoot), err => {
Expand Down Expand Up @@ -372,11 +373,11 @@ export class ProfileManager {
const profile = this.getProfile(profileName) as any;
if (!profile.rpcRelay) return Promise.resolve(); // use chart defaults

// generate the yaml
// generate the YAML
const yamlRoot = {};
this._setChartItems('', profile.rpcRelay, yamlRoot);

// write the yaml
// write the YAML
const cachedValuesFile = path.join(this.cacheDir, `rpcRelay-${profileName}.yaml`);
return new Promise<string>((resolve, reject) => {
fs.writeFile(cachedValuesFile, yaml.stringify(yamlRoot), err => {
Expand All @@ -392,11 +393,11 @@ export class ProfileManager {
prepareValuesHederaExplorerChart(profileName: string) {
if (!profileName) throw new MissingArgumentError('profileName is required');
const profile = this.getProfile(profileName) as any;
// generate the yaml
// generate the YAML
const yamlRoot = {};
this.resourcesForHederaExplorerPod(profile, yamlRoot);

// write the yaml
// write the YAML
const cachedValuesFile = path.join(this.cacheDir, `explorer-${profileName}.yaml`);
return new Promise<string>((resolve, reject) => {
fs.writeFile(cachedValuesFile, yaml.stringify(yamlRoot), err => {
Expand All @@ -412,14 +413,14 @@ export class ProfileManager {
/**
* Prepare a values file for mirror-node Helm chart
* @param profileName - resource profile name
* @returns return the full path to the values file
* @returns the full path to the values file
*/
prepareValuesForMirrorNodeChart(profileName: string) {
if (!profileName) throw new MissingArgumentError('profileName is required');
const profile = this.getProfile(profileName) as any;
if (!profile.mirror) return Promise.resolve(); // use chart defaults

// generate the yaml
// generate the YAML
const yamlRoot = {};
if (profile.mirror.postgresql) {
if (profile.mirror.postgresql.persistence) {
Expand All @@ -435,7 +436,7 @@ export class ProfileManager {
this._setChartItems('grpc', profile.mirror.grpc, yamlRoot);
this._setChartItems('monitor', profile.mirror.monitor, yamlRoot);

// write the yaml
// write the YAML
const cachedValuesFile = path.join(this.cacheDir, `mirror-${profileName}.yaml`);
return new Promise<string>((resolve, reject) => {
fs.writeFile(cachedValuesFile, yaml.stringify(yamlRoot), err => {
Expand Down Expand Up @@ -467,6 +468,7 @@ export class ProfileManager {
* @param releaseTag - release tag e.g. v0.42.0
* @param [appName] - the app name (default: HederaNode.jar)
* @param [chainId] - chain ID (298 for local network)
* @param genesisNetworkData
* @returns the config.txt file path
*/
prepareConfigTxt(
Expand All @@ -476,6 +478,7 @@ export class ProfileManager {
releaseTag: string,
appName = constants.HEDERA_APP_NAME,
chainId = constants.HEDERA_CHAIN_ID,
genesisNetworkData: GenesisNetworkDataConstructor
) {
if (!nodeAccountMap || nodeAccountMap.size === 0)
throw new MissingArgumentError('nodeAccountMap the map of node IDs to account IDs is required');
Expand All @@ -502,6 +505,9 @@ export class ProfileManager {
const internalIP = Templates.renderFullyQualifiedNetworkPodName(namespace, nodeAlias);
const externalIP = Templates.renderFullyQualifiedNetworkSvcName(namespace, nodeAlias);

genesisNetworkData.nodes[nodeAlias].addGossipEndpoint(externalIP, +externalPort, '');
genesisNetworkData.nodes[nodeAlias].addServiceEndpoint(internalIP, +internalPort, '');

const account = nodeAccountMap.get(nodeAlias);
if (releaseVersion.minor >= 40) {
configLines.push(
Expand Down
55 changes: 54 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import type * as x509 from '@peculiar/x509';
import type net from 'net';
import type * as WebSocket from 'ws';
import type crypto from 'crypto';
import type {ListrTask} from 'listr2';
import type {ListrTask, ListrTaskWrapper} from 'listr2';

// NOTE: DO NOT add any Solo imports in this file to avoid circular dependencies

Expand Down Expand Up @@ -80,3 +80,56 @@ export interface ToObject<T> {
export type SoloListrTask<T> = ListrTask<T, any, any>;

export type EmptyContextConfig = object;

export type SoloListrTaskWrapper<T> = ListrTaskWrapper<T, any, any>

// export interface NodeMetadata {
// rosterEntry: RosterEntry
// node: Node
// tssEncryptionKey: string
// }

// export interface RosterEntry {
// nodeId: number
// weight: number
// gossipCaCertificate: string
// gossipEndpoint: Array<ServiceEndpoint>
// }

export interface ServiceEndpoint {
ipAddressV4: string
port: number
domainName: string
}

// basically what node update does
//
// export interface Node {
// nodeId number ✅
// AccountID accountId ✅
// description string ✅
// gossipEndpoint Array<ServiceEndpoint>
// all of this are in single network, single cluster,
// is going to be fully qualified domain name for
// what we are currently putting as external ( ha proxy endpoint )
// serviceEndpoint: Array<ServiceEndpoint>
// gossipCaCertificate: Bytes - node keys ✅
// grpcCertificateHash: Bytes - kode in node command how to generate it
// weight: number,
// deleted: boolean, ✅
// adminKey: Key ✅
// right now dynamically
// generate it but add it as a secret as
// all other ledger uhh account keys
//
// generate it the same way without genesis, a unique one and store it as a secret, we want to name it a bit differently
// }

// gleda configureNodeAccess

// internal is the network pod name
// external ip is the network service name
// the gossip endpoint is externalIP

// the service endpoint - for the grpc calls, configureNodeAccess

0 comments on commit 5a62289

Please sign in to comment.