Skip to content

Commit

Permalink
polishing new classes added new interfaces and aliases to make clarif…
Browse files Browse the repository at this point in the history
…y what they do

Signed-off-by: instamenta <[email protected]>
  • Loading branch information
instamenta committed Dec 12, 2024
1 parent 3e3cdd9 commit 1a29c82
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 93 deletions.
39 changes: 20 additions & 19 deletions src/commands/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,21 +132,19 @@ export class NetworkCommand extends BaseCommand {
];
}

async prepareValuesArg(
config: {
chartDirectory?: string;
app?: string;
nodeAliases: string[];
debugNodeAlias?: NodeAlias;
enablePrometheusSvcMonitor?: boolean;
releaseTag?: string;
persistentVolumeClaims?: string;
valuesFile?: string;
haproxyIpsParsed?: Record<NodeAlias, IP>;
envoyIpsParsed?: Record<NodeAlias, IP>;
genesisNetworkData: GenesisNetworkDataConstructor;
}
) {
async prepareValuesArg(config: {
chartDirectory?: string;
app?: string;
nodeAliases: string[];
debugNodeAlias?: NodeAlias;
enablePrometheusSvcMonitor?: boolean;
releaseTag?: string;
persistentVolumeClaims?: string;
valuesFile?: string;
haproxyIpsParsed?: Record<NodeAlias, IP>;
envoyIpsParsed?: Record<NodeAlias, IP>;
genesisNetworkData: GenesisNetworkDataConstructor;
}) {
let valuesArg = config.chartDirectory
? `-f ${path.join(config.chartDirectory, 'solo-deployment', 'values.yaml')}`
: '';
Expand All @@ -163,7 +161,10 @@ export class NetworkCommand extends BaseCommand {
}

const profileName = this.configManager.getFlag<string>(flags.profileName) as string;
this.profileValuesFile = await this.profileManager.prepareValuesForSoloChart(profileName, config.genesisNetworkData);
this.profileValuesFile = await this.profileManager.prepareValuesForSoloChart(
profileName,
config.genesisNetworkData,
);
if (this.profileValuesFile) {
valuesArg += this.prepareValuesFiles(this.profileValuesFile);
}
Expand Down Expand Up @@ -200,7 +201,7 @@ export class NetworkCommand extends BaseCommand {
valuesArg += this.prepareValuesFiles(config.valuesFile);
}

valuesArg += `--set "hedera.configMaps.genesisNetworkJson=${config.genesisNetworkData.toJSON()}"`
valuesArg += `--set "hedera.configMaps.genesisNetworkJson=${config.genesisNetworkData.toJSON()}"`;

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

config.genesisNetworkData = new GenesisNetworkDataConstructor(config.nodeAliases);
config.genesisNetworkData = new GenesisNetworkDataConstructor(config.nodeAliases, this.keyManager, config.keysDir);

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

Expand Down Expand Up @@ -683,7 +684,7 @@ export class NetworkCommand extends BaseCommand {
}

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

// TODO

Expand Down
2 changes: 1 addition & 1 deletion src/core/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {type NodeAlias, type NodeAliases} from '../types/aliases.js';
import {type CommandFlag} from '../types/flag_types.js';
import {type SoloLogger} from './logging.js';
import {type Duration} from './time/duration.js';
import {NodeAddConfigClass} from '../commands/node/configs.js';
import {type NodeAddConfigClass} from '../commands/node/configs.js';

export function sleep(duration: Duration) {
return new Promise<void>(resolve => {
Expand Down
65 changes: 38 additions & 27 deletions src/core/models/genesisNetworkDataConstructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,61 @@
* 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 * as constants from '../constants.js';
import {Templates} from '../templates.js';
import {GenesisNetworkNodeDataWrapper} from './genesisNetworkNodeDataWrapper.js';
import * as x509 from '@peculiar/x509';
import * as constants from '../constants.js';

import type {KeyManager} from '../key_manager.js';
import type {ToJSON} from '../../types/index.js';
import type {NodeAlias, NodeAliases} from '../../types/aliases.js';

export class GenesisNetworkDataConstructor {
/**
* Used to construct the nodes data and convert them to JSON
*/
export class GenesisNetworkDataConstructor implements ToJSON {
public readonly nodes: Record<NodeAlias, GenesisNetworkNodeDataWrapper>;

public constructor (public readonly nodeAliases: NodeAliases) {
public constructor(
private readonly nodeAliases: NodeAliases,
private readonly keyManager: KeyManager,
private readonly keysDir: string,
) {
this.nodeAliases.forEach(nodeAlias => {
this.nodes[nodeAlias] = new GenesisNetworkNodeDataWrapper(Templates.nodeIdFromNodeAlias(nodeAlias))
const nodeId = Templates.nodeIdFromNodeAlias(nodeAlias);

const adminKey = PrivateKey.fromStringED25519(constants.GENESIS_KEY);

const adminKey = PrivateKey.fromStringED25519(constants.GENESIS_KEY)
this.nodes[nodeAlias].adminKey = adminKey.publicKey
})
this.nodes[nodeAlias] = new GenesisNetworkNodeDataWrapper(nodeId, adminKey.publicKey.toStringRaw(), nodeAlias);
});
}

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

public async load() {
await Promise.all(
this.nodeAliases.map(async nodeAlias => {
const nodeKeys = await this.keyManager.loadSigningKey(nodeAlias, this.keysDir);

const certPem = nodeKeys.certificate.toString()
const certPem = nodeKeys.certificate.toString();

this.nodes[nodeAlias].gossipCaCertificate = certPem
this.nodes[nodeAlias].gossipCaCertificate = certPem;

const tlsCertDer = new Uint8Array(x509.PemConverter.decode(certPem)[0]);
const tlsCertDer = new Uint8Array(x509.PemConverter.decode(certPem)[0]);

const grpcCertificateHash = crypto.createHash('sha384').update(tlsCertDer).digest();
const grpcCertificateHash = crypto.createHash('sha384').update(tlsCertDer).digest();

this.nodes[nodeAlias].grpcCertificateHash = grpcCertificateHash.toString();
}))
this.nodes[nodeAlias].grpcCertificateHash = grpcCertificateHash.toString();
}),
);
}

public toJSON (): string {
return JSON.stringify(this.nodes);
public toJSON() {
return JSON.stringify({
nodeMetadata: Object.values(this.nodes).map(node => node.toObject()),
});
}
}
}
84 changes: 52 additions & 32 deletions src/core/models/genesisNetworkNodeDataWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,45 +14,65 @@
* 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';
import {parseIpAddressToUint8Array} from '../helpers.js';
import type {AccountId} from '@hashgraph/sdk';
import {type GenesisNetworkNodeStructure, type ServiceEndpoint, type ToObject} 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;
export class GenesisNetworkNodeDataWrapper
implements GenesisNetworkNodeStructure, ToObject<{node: GenesisNetworkNodeStructure}>
{
public accountId: AccountId | string;
public readonly description: string;
public gossipEndpoint: ServiceEndpoint;
public serviceEndpoint: ServiceEndpoint;
public gossipEndpoint: ServiceEndpoint[] = [];
public serviceEndpoint: ServiceEndpoint[] = [];
public gossipCaCertificate: string;
public grpcCertificateHash: string;
public readonly weight: number;
public readonly deleted: boolean;
public adminKey: Nullable<Key>;
public weight: number;
public readonly deleted = false;

constructor (nodeId: number) {
this.nodeId = nodeId;
this.deleted = false;
constructor(
public readonly nodeId: number,
public readonly adminKey: string,
public readonly description: string,
) {}

/**
* @param domainName - a fully qualified domain name
* @param port
*/
public addServiceEndpoint(domainName: string, port: number): void {
this.serviceEndpoint.push({
ipAddressV4: parseIpAddressToUint8Array(domainName),
domainName,
port,
});
}

addGossipEndpoint (ipAddressV4: string, port: number, domainName: string): void {
this.gossipEndpoint = {ipAddressV4, port, domainName};
/**
* @param domainName - a fully qualified domain name
* @param port
*/
public addGossipEndpoint(domainName: string, port: number): void {
this.gossipEndpoint.push({
ipAddressV4: parseIpAddressToUint8Array(domainName),
domainName,
port,
});
}

addServiceEndpoint (ipAddressV4: string, port: number, domainName: string): void {
this.serviceEndpoint = {ipAddressV4, port, domainName};
public toObject() {
return {
node: {
nodeId: this.nodeId,
accountId: this.accountId,
description: this.description,
gossipEndpoint: this.gossipEndpoint,
serviceEndpoint: this.serviceEndpoint,
gossipCaCertificate: this.gossipCaCertificate,
grpcCertificateHash: this.grpcCertificateHash,
weight: this.weight,
deleted: this.deleted,
adminKey: this.adminKey,
},
};
}
}
}
32 changes: 22 additions & 10 deletions src/core/profile_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ import {Templates} from './templates.js';
import * as constants from './constants.js';
import {type ConfigManager} from './config_manager.js';
import * as helpers from './helpers.js';
import {getNodeAccountMap} from './helpers.js';
import {getNodeAccountMap, parseIpAddressToUint8Array} from './helpers.js';
import type {SoloLogger} from './logging.js';
import type {NodeAlias, NodeAliases} from '../types/aliases.js';
import {GenesisNetworkDataConstructor} from './models/genesisNetworkDataConstructor.js';
import {type GenesisNetworkDataConstructor} from './models/genesisNetworkDataConstructor.js';

const consensusSidecars = [
'recordStreamUploader',
Expand Down Expand Up @@ -171,7 +171,12 @@ export class ProfileManager {
}
}

resourcesForConsensusPod(profile: any, nodeAliases: NodeAliases, yamlRoot: object, genesisNetworkData: GenesisNetworkDataConstructor): object {
resourcesForConsensusPod(
profile: any,
nodeAliases: NodeAliases,
yamlRoot: object,
genesisNetworkData: GenesisNetworkDataConstructor,
): object {
if (!profile) throw new MissingArgumentError('profile is required');

const accountMap = getNodeAccountMap(nodeAliases);
Expand All @@ -198,7 +203,7 @@ export class ProfileManager {
this.configManager.getFlag(flags.releaseTag),
this.configManager.getFlag(flags.app),
this.configManager.getFlag(flags.chainId),
genesisNetworkData
genesisNetworkData,
);

for (const flag of flags.nodeConfigFileFlags.values()) {
Expand Down Expand Up @@ -480,7 +485,7 @@ export class ProfileManager {
releaseTag: string,
appName = constants.HEDERA_APP_NAME,
chainId = constants.HEDERA_CHAIN_ID,
genesisNetworkData: GenesisNetworkDataConstructor
genesisNetworkData: GenesisNetworkDataConstructor,
) {
if (!nodeAccountMap || nodeAccountMap.size === 0)
throw new MissingArgumentError('nodeAccountMap the map of node IDs to account IDs is required');
Expand All @@ -490,8 +495,8 @@ export class ProfileManager {
throw new IllegalArgumentError(`config destPath does not exist: ${destPath}`, destPath);

// init variables
const internalPort = constants.HEDERA_NODE_INTERNAL_GOSSIP_PORT;
const externalPort = constants.HEDERA_NODE_EXTERNAL_GOSSIP_PORT;
const internalPort = +constants.HEDERA_NODE_INTERNAL_GOSSIP_PORT;
const externalPort = +constants.HEDERA_NODE_EXTERNAL_GOSSIP_PORT;
const nodeStakeAmount = constants.HEDERA_NODE_DEFAULT_STAKE_AMOUNT;

// @ts-ignore
Expand All @@ -508,12 +513,19 @@ export class ProfileManager {
const externalIP = Templates.renderFullyQualifiedNetworkSvcName(namespace, nodeAlias);

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

nodeDataWrapper.weight = nodeStakeAmount;

// Add gossip endpoints
nodeDataWrapper.addGossipEndpoint(externalIP, externalPort);
nodeDataWrapper.addGossipEndpoint(internalIP, internalPort);

// Add service endpoints
nodeDataWrapper.addServiceEndpoint(internalIP, internalPort);

const account = nodeAccountMap.get(nodeAlias);

nodeDataWrapper.accountId = account
nodeDataWrapper.accountId = account;

if (releaseVersion.minor >= 40) {
configLines.push(
Expand Down
2 changes: 2 additions & 0 deletions src/types/aliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ export type ConfigBuilder = (argv, ctx, task) => Promise<any>;
export type Nullable<T> = T | null;

export type IP = string;

export type JsonString = string;
Loading

0 comments on commit 1a29c82

Please sign in to comment.