From 63d08cfbe0a7cfec9f111f8bc6fa40fc5ed68dc4 Mon Sep 17 00:00:00 2001 From: pablomendezroyo <41727368+pablomendezroyo@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:32:13 +0100 Subject: [PATCH] Contemplate edge case geth (#2053) * Contemplate edge case geth * migrate user settings for geth --- .../src/installer/getInstallerPackageData.ts | 32 +++++++++++++++ packages/stakers/src/execution.ts | 39 ++++++++++++++++--- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/packages/installer/src/installer/getInstallerPackageData.ts b/packages/installer/src/installer/getInstallerPackageData.ts index 5f08dddcc..3185f9767 100644 --- a/packages/installer/src/installer/getInstallerPackageData.ts +++ b/packages/installer/src/installer/getInstallerPackageData.ts @@ -11,6 +11,8 @@ import { ContainersStatus } from "@dappnode/types"; import { getBackupPath, getDockerComposePath, getImagePath, getManifestPath } from "@dappnode/utils"; +import { gt } from "semver"; +import { logs } from "@dappnode/logger"; interface GetInstallerPackageDataArg { releases: PackageRelease[]; @@ -74,6 +76,7 @@ function getInstallerPackageData( // If composePath does not exist, or is invalid: returns {} const prevUserSet = ComposeFileEditor.getUserSettingsIfExist(dnpName, isCore); + migrateGethUserSettingsIfNeeded(prevUserSet, dnpName, semVersion); const nextUserSet = deepmerge(prevUserSet, userSettings || {}); // Append to compose @@ -99,3 +102,32 @@ function getInstallerPackageData( containersStatus }; } + +/** + * Migrates the user settings from the old service name to the new service name + * + * Edge case for dnpName "geth.dnp.dappnode.eth" and serviceName "geth.dnp.dappnode.eth" + * The service name of the geth package has migrated to "geth" and the user settings should be applied to the new service name + * This edge case is implemented in core release 0.3.0 and should be safe to remove in the future + */ +function migrateGethUserSettingsIfNeeded(prevUserSet: UserSettings, dnpName: string, semVersion: string) { + const gethDnpName = "geth.dnp.dappnode.eth"; + const legacyGethServiceName = gethDnpName; + // migrate networks + if (dnpName === gethDnpName && gt(semVersion, "0.1.43")) { + logs.info(`Version ${semVersion} is greater than 0.1.43. Using service name "geth"`); + if (prevUserSet.networks) { + logs.info(`Migrating user settings networks from geth.dnp.dappnode.eth to geth`); + + prevUserSet.networks.serviceNetworks.geth = prevUserSet.networks.serviceNetworks[legacyGethServiceName]; + delete prevUserSet.networks.serviceNetworks[legacyGethServiceName]; + } + + // migrate envs + if (prevUserSet.environment) { + logs.info(`Migrating user settings environment from geth.dnp.dappnode.eth to geth`); + prevUserSet.environment.geth = prevUserSet.environment[legacyGethServiceName]; + delete prevUserSet.environment[legacyGethServiceName]; + } + } +} diff --git a/packages/stakers/src/execution.ts b/packages/stakers/src/execution.ts index c317833ee..e067f3c54 100644 --- a/packages/stakers/src/execution.ts +++ b/packages/stakers/src/execution.ts @@ -12,6 +12,9 @@ import { StakerComponent } from "./stakerComponent.js"; import { DappnodeInstaller, ethereumClient } from "@dappnode/installer"; import * as db from "@dappnode/db"; import { params } from "@dappnode/params"; +import { listPackage } from "@dappnode/dockerapi"; +import { logs } from "@dappnode/logger"; +import { gt } from "semver"; // TODO: move ethereumClient logic here @@ -80,7 +83,7 @@ export class Execution extends StakerComponent { return; } - const userSettings = this.getUserSettings(network, currentExecutionDnpName); + const userSettings = await this.getUserSettings(network, currentExecutionDnpName); await this.setStakerPkgConfig({ dnpName: currentExecutionDnpName, isInstalled, userSettings }); @@ -95,7 +98,7 @@ export class Execution extends StakerComponent { newStakerDnpName: newExecutionDnpName, dockerNetworkName: params.DOCKER_STAKER_NETWORKS[network], compatibleClients: Execution.CompatibleExecutions[network], - userSettings: this.getUserSettings(network, newExecutionDnpName), + userSettings: await this.getUserSettings(network, newExecutionDnpName), prevClient: prevExecClientDnpName }); @@ -111,14 +114,14 @@ export class Execution extends StakerComponent { } } - private getUserSettings(network: Network, dnpName: string | null): UserSettings { + private async getUserSettings(network: Network, dnpName: string | null): Promise { if (!dnpName) return {}; return { networks: { rootNetworks: this.getComposeRootNetworks(network), serviceNetworks: { - [this.getExecutionServiceName(dnpName)]: { + [await this.getExecutionServiceName(dnpName)]: { [params.DOCKER_STAKER_NETWORKS[network]]: { aliases: [`execution.${network}.staker.dappnode`] }, @@ -136,9 +139,19 @@ export class Execution extends StakerComponent { * * TODO: find a better way to get the service name of the execution client or force execution clients to have same service name "execution", similar as consensus clients with beacon-chain and validator services */ - private getExecutionServiceName(dnpName: string): string { + private async getExecutionServiceName(dnpName: string): Promise { // TODO: geth mainnet is the only execution with service name === dnpName. See https://github.com/dappnode/DAppNodePackage-geth/blob/7e8e5aa860a8861986f675170bfa92215760d32e/docker-compose.yml#L3 - if (dnpName === ExecutionClientMainnet.Geth) return ExecutionClientMainnet.Geth; + if (dnpName === ExecutionClientMainnet.Geth) { + logs.info(`Execution mainnet ${dnpName} has service name ${dnpName}`); + const version = await this.getExecutionVersion(dnpName); + if (gt(version, "0.1.43")) { + logs.info(`Version ${version} is greater than 0.1.43. Using service name "geth"`); + return "geth"; + } + logs.info(`Version ${version} is less than 0.1.44. Using service name ${dnpName}`); + return ExecutionClientMainnet.Geth; + } + if (dnpName.includes("geth")) return "geth"; if (dnpName.includes("nethermind")) return "nethermind"; if (dnpName.includes("erigon")) return "erigon"; @@ -147,4 +160,18 @@ export class Execution extends StakerComponent { return dnpName; } + + private async getExecutionVersion(dnpName: string): Promise { + const isInstalled = await this.isPackageInstalled(dnpName); + + if (isInstalled) { + const version = (await listPackage({ dnpName })).version; + logs.info(`Execution ${dnpName} is installed. Using version ${version}`); + return version; + } else { + const version = (await this.dappnodeInstaller.getVersionAndIpfsHash({ dnpNameOrHash: dnpName })).version; + logs.info(`Execution ${dnpName} is not installed. Using version ${version} from APM`); + return version; + } + } }