Skip to content

Commit

Permalink
check-in: add node spec diff tool and modal with changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jgresham committed Jun 26, 2024
1 parent 84f7a97 commit bd6c6e1
Show file tree
Hide file tree
Showing 12 changed files with 382 additions and 57 deletions.
118 changes: 118 additions & 0 deletions src/common/node-spec-tool/specDiff.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import type { SelectControl, SelectTranslation } from '../nodeConfig.js';
import type { DockerExecution, NodeSpecification } from '../nodeSpec.js';
import { assert, compareObjects } from './util.js';

export type UserSpecDiff = {
message: string;
};

// Only time a user default would be overridden is if the user default is not in the new spec as
// an option on a select config. In that case, the default should be used. So we should highlight any
// removal of select options.
// returns a list of changes
export const calcUserSpecDiff = (
oldSpec: NodeSpecification,
newSpec: NodeSpecification,
): UserSpecDiff[] => {
assert(oldSpec.specId === newSpec.specId, 'specId mismatch');
assert(
oldSpec.version < newSpec.version,
'newSpec version is not greater than oldSpec version',
);

const diffs: UserSpecDiff[] = [];
diffs.push({
message: `Controller version: ${oldSpec.version} -> ${newSpec.version}`,
});
if (oldSpec.displayName !== newSpec.displayName) {
diffs.push({
message: `Name: ${oldSpec.displayName} -> ${newSpec.displayName}`,
});
}

/////// [start] Execution
const oldSpecExecution = oldSpec.execution as DockerExecution;
const newSpecExecution = newSpec.execution as DockerExecution;
if (oldSpecExecution.imageName !== newSpecExecution.imageName) {
diffs.push({
message: `Download URL: ${oldSpecExecution.imageName} -> ${newSpecExecution.imageName}`,
});
}
if (oldSpecExecution.defaultImageTag !== newSpecExecution.defaultImageTag) {
diffs.push({
message: `Version: ${oldSpecExecution.defaultImageTag} -> ${newSpecExecution.defaultImageTag}`,
});
}
/////// [end] Execution

/////// [start] System Requirements
const oldSysReq = oldSpec.systemRequirements;
const newSysReq = newSpec.systemRequirements;
if (!compareObjects(oldSysReq, newSysReq)) {
let oldSysReqString = '';
let newSysReqString = '';
if (!compareObjects(oldSysReq?.cpu, newSysReq?.cpu)) {
oldSysReqString += ` CPU: ${JSON.stringify(oldSysReq?.cpu)}`;
newSysReqString += ` CPU: ${JSON.stringify(newSysReq?.cpu)}`;
}
if (!compareObjects(oldSysReq?.memory, newSysReq?.memory)) {
oldSysReqString += ` Memory: ${JSON.stringify(oldSysReq?.memory)}`;
newSysReqString += ` Memory: ${JSON.stringify(newSysReq?.memory)}`;
}
if (!compareObjects(oldSysReq?.storage, newSysReq?.storage)) {
oldSysReqString += ` Storage: ${JSON.stringify(oldSysReq?.storage)}`;
newSysReqString += ` Storage: ${JSON.stringify(newSysReq?.storage)}`;
}
if (!compareObjects(oldSysReq?.internet, newSysReq?.internet)) {
oldSysReqString += ` Internet: ${JSON.stringify(oldSysReq?.internet)}`;
newSysReqString += ` Internet: ${JSON.stringify(newSysReq?.internet)}`;
}

diffs.push({
message: `System requirements: ${oldSysReqString} -> ${newSysReqString}`,
});
}
/////// [end] System Requirements

/////// [start] Config Tralsations
const oldTranslations = oldSpec.configTranslation ?? {};
const newTranslations = newSpec.configTranslation ?? {};
const oldTranslationKeys = Object.keys(oldTranslations);
const newTranslationKeys = Object.keys(newTranslations);
for (const key of oldTranslationKeys) {
if (!newTranslationKeys.includes(key)) {
diffs.push({
message: `Removed setting: ${oldTranslations[key]?.displayName}`,
});
} else {
if (oldTranslations[key]?.uiControl?.type.includes('select')) {
const oldSelectOptions = (
oldTranslations[key].uiControl as SelectControl
)?.controlTranslations as SelectTranslation[];
const newSelectOptions = (
newTranslations[key].uiControl as SelectControl
)?.controlTranslations as SelectTranslation[];
if (!compareObjects(oldSelectOptions, newSelectOptions)) {
diffs.push({
message: `Changed setting options: ${JSON.stringify(
oldSelectOptions,
)} -> ${JSON.stringify(newSelectOptions)}`,
});
}
}

// else, they're the same
}
}
for (const key of newTranslationKeys) {
if (!oldTranslationKeys.includes(key)) {
diffs.push({
message: `New setting: ${newTranslations[key]?.displayName}`,
});
}
// else, they were compared when iterating over oldTranslationKeys
}
/////// [end] Config Tralsations

return diffs;
};
177 changes: 177 additions & 0 deletions src/common/node-spec-tool/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
export function assert(condition: boolean, message: string): asserts condition {
if (!condition) {
throw new Error(message);
}
}

/**
* Simple json.stringify comparison of two objects
*/
export function compareObjects(obj1: any, obj2: any) {
return JSON.stringify(obj1) === JSON.stringify(obj2);
}

export const gethv1 = {
specId: 'geth',
version: '1.0.0',
displayName: 'Geth',
execution: {
executionTypes: ['docker'],
defaultExecutionType: 'docker',
input: {
defaultConfig: {
http: 'Enabled',
httpCorsDomains: 'http://localhost',
webSockets: 'Disabled',
httpVirtualHosts: 'localhost,host.containers.internal',
authVirtualHosts: 'localhost,host.containers.internal',
httpAddress: '0.0.0.0',
webSocketAddress: '0.0.0.0',
syncMode: 'snap',
},
docker: {
containerVolumePath: '/root/.ethereum',
raw: '',
forcedRawNodeInput:
'--authrpc.addr 0.0.0.0 --authrpc.jwtsecret /root/.ethereum/jwtsecret --ipcdisable',
},
},
imageName: 'docker.io/ethereum/client-go',
defaultImageTag: 'stable',
},
category: 'L1/ExecutionClient',
rpcTranslation: 'eth-l1',
systemRequirements: {
documentationUrl: 'https://geth.ethereum.org/docs/interface/hardware',
cpu: {
cores: 4,
},
memory: {
minSizeGBs: 16,
},
storage: {
minSizeGBs: 1600,
ssdRequired: true,
},
internet: {
minDownloadSpeedMbps: 25,
minUploadSpeedMbps: 10,
},
docker: {
required: true,
},
},
configTranslation: {
dataDir: {
displayName: 'Data location',
cliConfigPrefix: '--datadir ',
defaultValue: '~/.ethereum',
uiControl: {
type: 'filePath',
},
infoDescription:
'Data directory for the databases and keystore (default: "~/.ethereum")',
},
network: {
displayName: 'Network',
defaultValue: 'Mainnet',
hideFromUserAfterStart: true,
uiControl: {
type: 'select/single',
controlTranslations: [
{
value: 'Mainnet',
config: '--mainnet',
},
{
value: 'Holesky',
config: '--holesky',
},
{
value: 'Sepolia',
config: '--sepolia',
},
],
},
},
webSocketsPort: {
displayName: 'WebSockets JSON-RPC port',
cliConfigPrefix: '--ws.port ',
defaultValue: '8546',
uiControl: {
type: 'text',
},
infoDescription:
'The port (TCP) on which WebSocket JSON-RPC listens. The default is 8546. You must expose ports appropriately.',
documentation:
'https://geth.ethereum.org/docs/rpc/server#websocket-server',
},
webSocketApis: {
displayName: 'Enabled WebSocket APIs',
cliConfigPrefix: '--ws.api ',
defaultValue: ['eth', 'net', 'web3'],
valuesJoinStr: ',',
uiControl: {
type: 'select/multiple',
controlTranslations: [
{
value: 'eth',
config: 'eth',
},
{
value: 'net',
config: 'net',
},
{
value: 'web3',
config: 'web3',
},
{
value: 'debug',
config: 'debug',
},

{
value: 'personal',
config: 'personal',
},
{
value: 'admin',
config: 'admin',
},
],
},
},
syncMode: {
displayName: 'Execution Client Sync Mode',
category: 'Syncronization',
uiControl: {
type: 'select/single',
controlTranslations: [
{
value: 'snap',
config: '--syncmode snap',
info: '',
},
{
value: 'full',
config: '--syncmode full',
info: '~800GB / ~2d',
},
{
value: 'archive',
config: '--syncmode full --gcmode archive',
info: '~16TB',
},
],
},
addNodeFlow: 'required',
defaultValue: 'snap',
hideFromUserAfterStart: true,
documentation:
'https://geth.ethereum.org/docs/faq#how-does-ethereum-syncing-work',
},
},
iconUrl:
'https://clientdiversity.org/assets/img/execution-clients/geth-logo.png',
};
14 changes: 12 additions & 2 deletions src/common/nodeSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,12 @@ export type NodeSpecification = {
// (ex. peers, syncing, latest block num, etc.)
iconUrl?: string;
category?: string;
documentation?: { default?: string; docker?: string; binary?: string, releaseNotesUrl?: string };
documentation?: {
default?: string;
docker?: string;
binary?: string;
releaseNotesUrl?: string;
};
resources?: LabelValuesSectionItemsProps[];
};

Expand Down Expand Up @@ -141,7 +146,12 @@ export type NodePackageSpecification = {
// (ex. peers, syncing, latest block num, etc.)
iconUrl?: string;
category?: string;
documentation?: { default?: string; docker?: string; binary?: string; releaseNotesUrl?: string };
documentation?: {
default?: string;
docker?: string;
binary?: string;
releaseNotesUrl?: string;
};
addNodeDescription?: string;
description?: string;
resources?: LabelValuesSectionItemsProps[];
Expand Down
8 changes: 5 additions & 3 deletions src/main/nodeLibraryManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const initialize = async () => {

// todo: use user defined url if available
const getCartridgePackages = async (): Promise<NodeSpecification[]> => {
const cartridgePackagesApiURL = 'http://localhost:3000/api/cartridgePackage'
const cartridgePackagesApiURL = 'http://localhost:3000/api/cartridgePackage';
const isHttp = true;
// const cartridgePackagesApiURL =
// 'https://api.nicenode.xyz/api/cartridgePackage';
Expand All @@ -76,7 +76,7 @@ const getCartridgePackages = async (): Promise<NodeSpecification[]> => {
};

const getCartridges = async (): Promise<NodeSpecification[]> => {
const cartridgesApiURL = 'http://localhost:3000/api/cartridge'
const cartridgesApiURL = 'http://localhost:3000/api/cartridge';
const isHttp = true;
// const cartridgesApiURL = 'https://api.nicenode.xyz/api/cartridge';
// const isHttp = false;
Expand Down Expand Up @@ -235,7 +235,9 @@ export const getCheckForCartridgeUpdate = async (
// if newer, update node.updateAvailable = true
const node: Node = getNode(nodeId);
if (node) {
const latestCartridge: NodeSpecification = await getCartridge(node.spec.specId);
const latestCartridge: NodeSpecification = await getCartridge(
node.spec.specId,
);
logger.info(
`getCheckForCartridgeUpdate: latestCartridge: ${JSON.stringify(
latestCartridge,
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/Generics/redesign/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import type { NodeSpecification } from '../../../../common/nodeSpec.js';
import { modalRoutes } from '../../../Presentational/ModalManager/modalUtils.js';
import electron from '../../../electronGlobal.js';
import { useAppDispatch } from '../../../state/hooks';
import { setModalState } from '../../../state/modal';
Expand All @@ -22,8 +24,6 @@ import {
titleStyle,
versionContainer,
} from './header.css';
import { modalRoutes } from '../../../Presentational/ModalManager/modalUtils.js';
import { NodeSpecification } from '../../../../common/nodeSpec.js';

type HeaderProps = {
nodeOverview: NodeOverviewProps;
Expand Down
7 changes: 7 additions & 0 deletions src/renderer/Generics/redesign/Modal/modal.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ export const titleFont = style({
lineHeight: '24px',
letterSpacing: '-0.4px',
},
'&.controllerUpdate': {
paddingLeft: 32,
},
},
});

Expand Down Expand Up @@ -127,5 +130,9 @@ export const modalChildrenContainer = style({
padding: 0,
overflowX: 'hidden',
},
'&.controllerUpdate': {
overflowY: 'auto',
overflowX: 'hidden',
},
},
});
Loading

0 comments on commit bd6c6e1

Please sign in to comment.