Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use mix of local key manager and external signer for sim tests #4583

Merged
merged 11 commits into from
Sep 23, 2022
10 changes: 1 addition & 9 deletions packages/cli/test/simulation/simulation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,34 +25,28 @@ const forksCases: {
params: {
altairEpoch: number;
bellatrixEpoch: number;
withExternalSigner?: boolean;
runTill: Epoch;
};
}[] = [
{
title: "mixed forks",
params: {altairEpoch: 2, bellatrixEpoch: 4, runTill: 6},
},
// {
// title: "mixed forks with remote signer",
// params: {altairEpoch: 1, bellatrixEpoch: 2, withExternalSigner: true, runTill: 3},
// },
];

let testCases = 0;

for (const {beaconNodes, validatorClients, validatorsPerClient} of nodeCases) {
for (const {
title,
params: {altairEpoch, bellatrixEpoch, withExternalSigner, runTill},
params: {altairEpoch, bellatrixEpoch, runTill},
} of forksCases) {
const testIdStr = [
`beaconNodes-${beaconNodes}`,
`validatorClients-${validatorClients}`,
`validatorsPerClient-${validatorsPerClient}`,
`altair-${altairEpoch}`,
`bellatrix-${bellatrixEpoch}`,
`externalSigner-${withExternalSigner ? "yes" : "no"}`,
].join("_");

console.log(
Expand All @@ -62,7 +56,6 @@ for (const {beaconNodes, validatorClients, validatorsPerClient} of nodeCases) {
validatorsPerClient,
altairEpoch,
bellatrixEpoch,
withExternalSigner,
})
);
const env = new SimulationEnvironment({
Expand All @@ -74,7 +67,6 @@ for (const {beaconNodes, validatorClients, validatorsPerClient} of nodeCases) {
genesisSlotsDelay: (SLOTS_PER_EPOCH * runTill + 50) * testCases + 30,
bellatrixEpoch,
logFilesDir: join(logFilesDir, testIdStr),
externalSigner: withExternalSigner,
});
testCases += 1;

Expand Down
10 changes: 5 additions & 5 deletions packages/cli/test/utils/simulation/ExternalSignerServer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import fastify from "fastify";
import {fromHexString, toHexString} from "@chainsafe/ssz";
import {fromHexString} from "@chainsafe/ssz";
import type {SecretKey} from "@chainsafe/bls/types";
import {EXTERNAL_SIGNER_BASE_PORT} from "./utils.js";

Expand All @@ -14,7 +14,7 @@ export class ExternalSignerServer {
constructor(secretKeys: SecretKey[]) {
const secretKeyMap = new Map<string, SecretKey>();
for (const secretKey of secretKeys) {
const pubkeyHex = toHexString(secretKey.toPublicKey().toBytes());
const pubkeyHex = secretKey.toPublicKey().toHex();
secretKeyMap.set(pubkeyHex, secretKey);
}
ExternalSignerServer.totalProcessCount++;
Expand All @@ -26,8 +26,8 @@ export class ExternalSignerServer {
return {status: "OK"};
});

this.server.get("/keys", async () => {
return {keys: Array.from(secretKeyMap.keys())};
this.server.get("/api/v1/eth2/publicKeys", async () => {
return [...secretKeyMap.keys()];
});

/* eslint-disable @typescript-eslint/naming-convention */
Expand All @@ -40,7 +40,7 @@ export class ExternalSignerServer {
/** Data to sign as a hex string */
signingRoot: string;
};
}>("/sign/:identifier", async (req) => {
}>("/api/v1/eth2/sign/:identifier", async (req) => {
const pubkeyHex: string = req.params.identifier;
const signingRootHex: string = req.body.signingRoot;

Expand Down
33 changes: 18 additions & 15 deletions packages/cli/test/utils/simulation/LodestarValidatorProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const LodestarValidatorProcess: ValidatorConstructor = class LodestarVali
readonly id: string;
readonly keyManagerApi: Api;
readonly secretKeys: SecretKey[] = [];
readonly externalSigner?: ExternalSignerServer;
readonly externalSigner: ExternalSignerServer;

private rootDir: string;
private clientIndex: number;
Expand Down Expand Up @@ -58,6 +58,11 @@ export const LodestarValidatorProcess: ValidatorConstructor = class LodestarVali
});
this.secretKeys = validatorSecretKeys;

// Split half of the keys to external signer
this.externalSigner = new ExternalSignerServer(
this.secretKeys.slice(0, this.secretKeys.length * this.params.externalKeysPercentage)
);

this.rcConfig = ({
network: "dev",
preset: "minimal",
Expand All @@ -78,11 +83,6 @@ export const LodestarValidatorProcess: ValidatorConstructor = class LodestarVali
logLevel: "info",
} as unknown) as IValidatorCliArgs & IGlobalArgs;

if (this.params.externalSigner) {
this.externalSigner = new ExternalSignerServer(this.secretKeys);
this.rcConfig["externalSigner.url"] = this.externalSigner.url;
}

this.keyManagerApi = getClient(
{baseUrl: `http://${this.address}:${this.keyManagerPort}`},
{config: this.forkConfig}
Expand All @@ -94,20 +94,18 @@ export const LodestarValidatorProcess: ValidatorConstructor = class LodestarVali
await mkdir(`${this.rootDir}/keystores`);

await writeFile(join(this.rootDir, "password.txt"), "password");

await writeFile(join(this.rootDir, "rc_config.json"), JSON.stringify(this.rcConfig, null, 2));

for (const key of this.secretKeys) {
// Split half of the keys to the keymanager
for (const key of this.secretKeys.slice(this.secretKeys.length * this.params.externalKeysPercentage)) {
const keystore = await Keystore.create("password", key.toBytes(), key.toPublicKey().toBytes(), "");
await writeFile(
join(this.rootDir, "keystores", `${key.toPublicKey().toHex()}.json`),
JSON.stringify(keystore.toObject(), null, 2)
);
}

if (this.externalSigner) {
await this.externalSigner.start();
}
await this.externalSigner.start();

console.log(`Starting lodestar validator "${this.id}".`, {dataDir: this.rootDir});

Expand All @@ -128,19 +126,24 @@ export const LodestarValidatorProcess: ValidatorConstructor = class LodestarVali
`Waiting for "${this.id}" to start.`
);

// Import half of the keys to the keymanager from external signer
await this.keyManagerApi.importRemoteKeys(
this.secretKeys
.slice(0, this.secretKeys.length / 2)
.map((sk) => ({pubkey: sk.toPublicKey().toHex(), url: this.externalSigner.url}))
);

console.log(`Validator "${this.id}" started.`);
}

async stop(): Promise<void> {
console.log(`Stopping validator "${this.id}".`);

if (this.externalSigner) {
await this.externalSigner.stop();
}

if (this.validatorProcess !== undefined) {
await closeChildProcess(this.validatorProcess);
}

await this.externalSigner.stop();
}

async ready(): Promise<boolean> {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/test/utils/simulation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export type SimulationRequiredParams = {

export type SimulationOptionalParams = {
validatorsPerClient: number;
withExternalSigner: boolean;
secondsPerSlot: number;
genesisSlotsDelay: number;
anchorState?: BeaconStateAllForks;
externalSigner: boolean;
// Use this percentage for external signer and rest will be used for local key manager
externalKeysPercentage: number;
};

export type RunTimeSimulationParams = {
Expand Down
5 changes: 1 addition & 4 deletions packages/cli/test/utils/simulation/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,17 @@ export const logFilesDir = "test-logs";

export const defaultSimulationParams: SimulationOptionalParams = {
validatorsPerClient: 32,
withExternalSigner: false,
secondsPerSlot: 2,
// delay a bit so regular sync sees it's up to date and sync is completed from the beginning
// allow time for bls worker threads to warm up
genesisSlotsDelay: 30,
externalSigner: false,
externalKeysPercentage: 0.5,
};

export const getSimulationId = ({
beaconNodes,
validatorClients,
validatorsPerClient,
withExternalSigner,
altairEpoch,
bellatrixEpoch,
}: SimulationParams): string =>
Expand All @@ -46,7 +44,6 @@ export const getSimulationId = ({
`validatorsPerClient-${validatorsPerClient}`,
`altair-${altairEpoch}`,
`bellatrix-${bellatrixEpoch}`,
`externalSigner-${withExternalSigner ? "yes" : "no"}`,
].join("_");

export const spawnProcessAndWait = async (
Expand Down