Skip to content

Commit

Permalink
Merge a78c493 into 1602f67
Browse files Browse the repository at this point in the history
  • Loading branch information
nazarhussain authored May 17, 2023
2 parents 1602f67 + a78c493 commit c11a3ef
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 66 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test-sim.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ on:
workflow_dispatch:

env:
GETH_DOCKER_IMAGE: ethereum/client-go:v1.10.25
GETH_DOCKER_IMAGE: ethereum/client-go:v1.11.6
LIGHTHOUSE_DOCKER_IMAGE: sigp/lighthouse:latest-amd64-unstable-dev
NETHERMIND_DOCKER_IMAGE: nethermind/nethermind:1.14.5
NETHERMIND_DOCKER_IMAGE: nethermind/nethermind:1.18.0

jobs:
tests-sim:
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/test/sim/backup_eth_provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from "../utils/simulation/utils/index.js";
import {connectAllNodes, waitForSlot} from "../utils/simulation/utils/network.js";

const genesisSlotsDelay = 20;
const genesisDelaySeconds = 20 * SIM_TESTS_SECONDS_PER_SLOT;
const altairForkEpoch = 2;
const bellatrixForkEpoch = 4;
// Make sure bellatrix started before TTD reach
Expand All @@ -23,15 +23,15 @@ const syncWaitEpoch = 2;

const runTimeoutMs =
getEstimatedTimeInSecForRun({
genesisSlotDelay: genesisSlotsDelay,
genesisDelaySeconds,
secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT,
runTill: runTillEpoch + syncWaitEpoch,
// After adding Nethermind its took longer to complete
graceExtraTimeFraction: 0.3,
}) * 1000;

const ttd = getEstimatedTTD({
genesisDelay: genesisSlotsDelay,
genesisDelaySeconds,
bellatrixForkEpoch: bellatrixForkEpoch,
secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT,
cliqueSealingPeriod: CLIQUE_SEALING_PERIOD,
Expand All @@ -45,7 +45,7 @@ const env = await SimulationEnvironment.initWithDefaults(
chainConfig: {
ALTAIR_FORK_EPOCH: altairForkEpoch,
BELLATRIX_FORK_EPOCH: bellatrixForkEpoch,
GENESIS_DELAY: genesisSlotsDelay,
GENESIS_DELAY: genesisDelaySeconds,
TERMINAL_TOTAL_DIFFICULTY: ttd,
},
},
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/test/sim/deneb.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.j
import {getEstimatedTimeInSecForRun, getEstimatedTTD, logFilesDir} from "../utils/simulation/utils/index.js";
import {connectAllNodes, connectNewNode, waitForNodeSync, waitForSlot} from "../utils/simulation/utils/network.js";

const genesisSlotsDelay = 20;
const genesisDelaySeconds = 20 * SIM_TESTS_SECONDS_PER_SLOT;
const altairForkEpoch = 2;
const bellatrixForkEpoch = 4;
// Make sure bellatrix started before TTD reach
Expand All @@ -20,15 +20,15 @@ const syncWaitEpoch = 2;

const runTimeoutMs =
getEstimatedTimeInSecForRun({
genesisSlotDelay: genesisSlotsDelay,
genesisDelaySeconds,
secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT,
runTill: runTillEpoch + syncWaitEpoch,
// After adding Nethermind its took longer to complete
graceExtraTimeFraction: 0.3,
}) * 1000;

const ttd = getEstimatedTTD({
genesisDelay: genesisSlotsDelay,
genesisDelaySeconds,
bellatrixForkEpoch: bellatrixForkEpoch,
secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT,
cliqueSealingPeriod: CLIQUE_SEALING_PERIOD,
Expand All @@ -42,7 +42,7 @@ const env = await SimulationEnvironment.initWithDefaults(
chainConfig: {
ALTAIR_FORK_EPOCH: altairForkEpoch,
BELLATRIX_FORK_EPOCH: bellatrixForkEpoch,
GENESIS_DELAY: genesisSlotsDelay,
GENESIS_DELAY: genesisDelaySeconds,
TERMINAL_TOTAL_DIFFICULTY: ttd,
},
},
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/test/sim/endpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import {getEstimatedTimeInSecForRun, logFilesDir} from "../utils/simulation/util
import {waitForSlot} from "../utils/simulation/utils/network.js";
import {SIM_TESTS_SECONDS_PER_SLOT} from "../utils/simulation/constants.js";

const genesisSlotsDelay = 10;
const genesisDelaySeconds = 10 * SIM_TESTS_SECONDS_PER_SLOT;
const altairForkEpoch = 2;
const bellatrixForkEpoch = 4;
const validatorCount = 2;
const runTimeoutMs =
getEstimatedTimeInSecForRun({
genesisSlotDelay: genesisSlotsDelay,
genesisDelaySeconds,
secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT,
runTill: 2,
// After adding Nethermind its took longer to complete
Expand All @@ -30,7 +30,7 @@ const env = await SimulationEnvironment.initWithDefaults(
chainConfig: {
ALTAIR_FORK_EPOCH: altairForkEpoch,
BELLATRIX_FORK_EPOCH: bellatrixForkEpoch,
GENESIS_DELAY: genesisSlotsDelay,
GENESIS_DELAY: genesisDelaySeconds,
},
},
[
Expand Down
32 changes: 20 additions & 12 deletions packages/cli/test/sim/multi_fork.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/naming-convention */
import path from "node:path";
import {activePreset} from "@lodestar/params";
import {sleep, toHexString} from "@lodestar/utils";
import {ApiError} from "@lodestar/api";
import {CLIQUE_SEALING_PERIOD, SIM_TESTS_SECONDS_PER_SLOT} from "../utils/simulation/constants.js";
Expand All @@ -16,27 +15,29 @@ import {
} from "../utils/simulation/utils/network.js";
import {nodeAssertion} from "../utils/simulation/assertions/nodeAssertion.js";
import {mergeAssertion} from "../utils/simulation/assertions/mergeAssertion.js";
import {createForkAssertion} from "../utils/simulation/assertions/forkAssertion.js";

const genesisSlotsDelay = 20;
const genesisDelaySeconds = 20 * SIM_TESTS_SECONDS_PER_SLOT;
const altairForkEpoch = 2;
const bellatrixForkEpoch = 4;
const capellaForkEpoch = 6;
// Make sure bellatrix started before TTD reach
const additionalSlotsForTTD = activePreset.SLOTS_PER_EPOCH - 2;
const runTillEpoch = 6;
const additionalSlotsForTTD = 2;
const runTillEpoch = 8;
const syncWaitEpoch = 2;

const runTimeoutMs =
getEstimatedTimeInSecForRun({
genesisSlotDelay: genesisSlotsDelay,
genesisDelaySeconds,
secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT,
runTill: runTillEpoch + syncWaitEpoch,
// After adding Nethermind its took longer to complete
graceExtraTimeFraction: 0.3,
}) * 1000;

const ttd = getEstimatedTTD({
genesisDelay: genesisSlotsDelay,
bellatrixForkEpoch: bellatrixForkEpoch,
genesisDelaySeconds,
bellatrixForkEpoch,
secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT,
cliqueSealingPeriod: CLIQUE_SEALING_PERIOD,
additionalSlots: additionalSlotsForTTD,
Expand All @@ -49,7 +50,8 @@ const env = await SimulationEnvironment.initWithDefaults(
chainConfig: {
ALTAIR_FORK_EPOCH: altairForkEpoch,
BELLATRIX_FORK_EPOCH: bellatrixForkEpoch,
GENESIS_DELAY: genesisSlotsDelay,
CAPELLA_FORK_EPOCH: capellaForkEpoch,
GENESIS_DELAY: genesisDelaySeconds,
TERMINAL_TOTAL_DIFFICULTY: ttd,
},
},
Expand Down Expand Up @@ -79,10 +81,16 @@ env.tracker.register({
await env.start({runTimeoutMs});
await connectAllNodes(env.nodes);

// The `TTD` will be reach around `start of bellatrixForkEpoch + additionalSlotsForMerge` slot
// We wait for the end of that epoch with half more epoch to make sure merge transition is complete
await waitForSlot(env.clock.getLastSlotOfEpoch(bellatrixForkEpoch) + activePreset.SLOTS_PER_EPOCH / 2, env.nodes, {
silent: true,
let lastForkEpoch = 0;
// Go through every fork and check which one is active and register assertion for it
// This will make sure this test would identify if we add new fork or activate one of the existing ones
for (const fork of env.forkConfig.forksAscendingEpochOrder) {
if (!Number.isInteger(fork.epoch)) continue;
lastForkEpoch = fork.epoch;
env.tracker.register(createForkAssertion(fork.name, fork.epoch));
}

await waitForSlot(env.clock.getLastSlotOfEpoch(lastForkEpoch + 1), env.nodes, {
env,
});

Expand Down
61 changes: 37 additions & 24 deletions packages/cli/test/utils/simulation/SimulationEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
CLNode,
ELClient,
ELGeneratorClientOptions,
ELGeneratorGenesisOptions,
ELNode,
ELStartMode,
IRunner,
Expand All @@ -42,7 +43,13 @@ import {
SimulationOptions,
} from "./interfaces.js";
import {SimulationTracker} from "./SimulationTracker.js";
import {getEstimatedTTD, makeUniqueArray, regsiterProcessHandler, replaceIpFromUrl} from "./utils/index.js";
import {
getEstimatedShanghaiTime,
getEstimatedTTD,
makeUniqueArray,
registerProcessHandler,
replaceIpFromUrl,
} from "./utils/index.js";
import {generateLighthouseBeaconNode} from "./cl_clients/lighthouse.js";
import {Runner} from "./runner/index.js";
import {createKeystores} from "./utils/keys.js";
Expand Down Expand Up @@ -75,7 +82,7 @@ export class SimulationEnvironment {
this.options = options;

this.clock = new EpochClock({
genesisTime: this.options.genesisTime,
genesisTime: this.options.eth1GenesisTime + this.forkConfig.GENESIS_DELAY,
secondsPerSlot: this.forkConfig.SECONDS_PER_SLOT,
slotsPerEpoch: activePreset.SLOTS_PER_EPOCH,
signal: this.options.controller.signal,
Expand All @@ -97,11 +104,11 @@ export class SimulationEnvironment {
clients: NodePairOptions[]
): Promise<SimulationEnvironment> {
const secondsPerSlot = chainConfig.SECONDS_PER_SLOT ?? SIM_TESTS_SECONDS_PER_SLOT;
const genesisTime = Math.floor(Date.now() / 1000) + chainConfig.GENESIS_DELAY * secondsPerSlot;
const genesisTime = Math.floor(Date.now() / 1000);
const ttd =
chainConfig.TERMINAL_TOTAL_DIFFICULTY ??
getEstimatedTTD({
genesisDelay: chainConfig.GENESIS_DELAY,
genesisDelaySeconds: chainConfig.GENESIS_DELAY,
bellatrixForkEpoch: chainConfig.BELLATRIX_FORK_EPOCH,
secondsPerSlot: secondsPerSlot,
cliqueSealingPeriod: CLIQUE_SEALING_PERIOD,
Expand All @@ -115,12 +122,14 @@ export class SimulationEnvironment {
TERMINAL_TOTAL_DIFFICULTY: ttd,
DEPOSIT_CHAIN_ID: SIM_ENV_CHAIN_ID,
DEPOSIT_NETWORK_ID: SIM_ENV_NETWORK_ID,
SECONDS_PER_ETH1_BLOCK: CLIQUE_SEALING_PERIOD,
ETH1_FOLLOW_DISTANCE: 1,
});

const env = new SimulationEnvironment(forkConfig, {
logsDir,
id,
genesisTime,
eth1GenesisTime: genesisTime,
controller: new AbortController(),
rootDir: path.join(tmp.dirSync({unsafeCleanup: true, tmpdir: "/tmp", template: "sim-XXXXXX"}).name, id),
});
Expand Down Expand Up @@ -157,7 +166,7 @@ export class SimulationEnvironment {
}, msToGenesis);

try {
regsiterProcessHandler(this);
registerProcessHandler(this);
if (!fs.existsSync(this.options.rootDir)) {
await mkdir(this.options.rootDir);
}
Expand Down Expand Up @@ -203,12 +212,12 @@ export class SimulationEnvironment {
process.removeAllListeners("SIGTERM");
process.removeAllListeners("SIGINT");
console.log(`Simulation environment "${this.options.id}" is stopping: ${message}`);
this.options.controller.abort();
await this.tracker.stop();
await Promise.all(this.nodes.map((node) => node.el.job.stop()));
await Promise.all(this.nodes.map((node) => node.cl.job.stop()));
await this.externalSigner.stop();
await this.runner.stop();
this.options.controller.abort();

if (this.tracker.getErrorCount() > 0) {
this.tracker.reporter.summary();
Expand Down Expand Up @@ -299,7 +308,7 @@ export class SimulationEnvironment {
paths: clPaths,
nodeIndex: options.nodeIndex,
keys: options?.keys ?? {type: "no-keys"},
genesisTime: this.options.genesisTime,
genesisTime: this.options.eth1GenesisTime + this.forkConfig.GENESIS_DELAY,
engineMock: options?.engineMock ?? false,
clientOptions: options?.clientOptions ?? {},
address: "127.0.0.1",
Expand Down Expand Up @@ -357,30 +366,34 @@ export class SimulationEnvironment {

const mode =
options?.mode ?? (this.forkConfig.BELLATRIX_FORK_EPOCH > 0 ? ELStartMode.PreMerge : ELStartMode.PostMerge);

await writeFile(
elPaths.genesisFilePath,
JSON.stringify(
getGethGenesisBlock(mode, {
ttd: options?.ttd ?? this.forkConfig.TERMINAL_TOTAL_DIFFICULTY,
cliqueSealingPeriod: options?.cliqueSealingPeriod ?? CLIQUE_SEALING_PERIOD,
clientOptions: [],
})
)
);
const genesisOptions: ELGeneratorGenesisOptions<E> = {
ttd: options?.ttd ?? this.forkConfig.TERMINAL_TOTAL_DIFFICULTY,
cliqueSealingPeriod: options?.cliqueSealingPeriod ?? CLIQUE_SEALING_PERIOD,
genesisTime: options?.genesisTime ?? this.options.eth1GenesisTime,
shanghaiTime:
options?.shanghaiTime ??
getEstimatedShanghaiTime({
genesisDelaySeconds: this.forkConfig.GENESIS_DELAY,
capellaForkEpoch: this.forkConfig.CAPELLA_FORK_EPOCH,
eth1GenesisTime: this.options.eth1GenesisTime,
secondsPerSlot: this.forkConfig.SECONDS_PER_SLOT,
additionalSlots: 0,
}),
clientOptions: options.clientOptions ?? [],
};

const opts: ELGeneratorClientOptions<E> = {
...genesisOptions,
id: elId,
paths: elPaths,
mode,
nodeIndex: options.nodeIndex,
mode: options?.mode ?? (this.forkConfig.BELLATRIX_FORK_EPOCH > 0 ? ELStartMode.PreMerge : ELStartMode.PostMerge),
ttd: options?.ttd ?? this.forkConfig.TERMINAL_TOTAL_DIFFICULTY,
cliqueSealingPeriod: options?.cliqueSealingPeriod ?? CLIQUE_SEALING_PERIOD,
address: this.runner.getNextIp(),
mining: options?.mining ?? false,
clientOptions: options.clientOptions ?? [],
};

await writeFile(elPaths.genesisFilePath, JSON.stringify(getGethGenesisBlock(mode, genesisOptions)));

switch (client) {
case ELClient.Mock: {
return generateMockNode(opts as ELGeneratorClientOptions<ELClient.Mock>, this.runner);
Expand Down Expand Up @@ -409,7 +422,7 @@ export class SimulationEnvironment {
}

const genesisState = nodeUtils.initDevState(this.forkConfig, this.keysCount, {
genesisTime: this.options.genesisTime,
genesisTime: this.options.eth1GenesisTime + this.forkConfig.GENESIS_DELAY,
eth1BlockHash: fromHexString(eth1Genesis.hash),
}).state;

Expand Down
37 changes: 37 additions & 0 deletions packages/cli/test/utils/simulation/assertions/forkAssertion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {ApiError} from "@lodestar/api";
import {ForkName} from "@lodestar/params";
import {Epoch} from "@lodestar/types";
import {toHexString} from "@lodestar/utils";
import {SimulationAssertion} from "../interfaces.js";

export function createForkAssertion(fork: ForkName, epoch: Epoch): SimulationAssertion<string, string> {
return {
id: `fork-${fork}`,
match: ({slot, clock}) => {
return slot === clock.getFirstSlotOfEpoch(epoch) ? {match: true, remove: true} : false;
},
assert: async ({nodes, slot, forkConfig}) => {
const errors: string[] = [];
for (const node of nodes) {
const res = await node.cl.api.debug.getStateV2("head");
ApiError.assert(res);
const expectedForkVersion = toHexString(forkConfig.getForkInfo(slot).version);
const currentForkVersion = toHexString(res.response.data.fork.currentVersion);

if (expectedForkVersion !== currentForkVersion) {
errors.push(
`Node is not on correct fork. ${JSON.stringify({
id: node.cl.id,
slot,
fork,
expectedForkVersion,
currentForkVersion,
})}`
);
}
}

return errors;
},
};
}
2 changes: 1 addition & 1 deletion packages/cli/test/utils/simulation/el_clients/geth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export const generateGethNode: ELClientGenerator<ELClient.Geth> = (opts, runner)
// Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail
"--verbosity",
"5",
...(mining ? ["--mine"] : []),
...(mining ? ["--mine", "--miner.etherbase", GENESIS_ACCOUNT] : []),
...(mode == ELStartMode.PreMerge ? ["--nodiscover"] : []),
...clientOptions,
],
Expand Down
Loading

0 comments on commit c11a3ef

Please sign in to comment.