Skip to content

Commit

Permalink
Allow preset overrides (#4601)
Browse files Browse the repository at this point in the history
* Allow preset overrides

* Apply review comments

* Update packages/params/README.md

* Update overridePresetError.ts

* Update packages/params/test/e2e/overridePresetError.ts

Co-authored-by: Cayman <caymannava@gmail.com>
Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com>
  • Loading branch information
3 people committed Oct 7, 2022
1 parent 081afbb commit 1cba836
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 3 deletions.
1 change: 1 addition & 0 deletions packages/params/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ Important Notes:
- Interacting with and understanding the active preset is only necessary in very limited testing environments, eg: for ephemeral testnets
- The `minimal` preset is NOT compatible with the `mainnet` preset.
- using `setActivePreset` may be dangerous, and only should be run once before loading any other libraries. All downstream Lodestar libraries expect the active preset to never change.
- Preset values can be overriden by executing `setActivePreset(presetName: PresetName, overrides?: Partial<BeaconPreset>)` and supplying values to override.

## License

Expand Down
4 changes: 2 additions & 2 deletions packages/params/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {preset as mainnet} from "./presets/mainnet/index.js";
import {preset as minimal} from "./presets/minimal/index.js";
import {preset as gnosis} from "./presets/gnosis/index.js";
import {presetStatus} from "./presetStatus.js";
import {userSelectedPreset} from "./setPreset.js";
import {userSelectedPreset, userOverrides} from "./setPreset.js";

export * from "./interface/index.js";
export {ForkName, ForkSeq} from "./forkName.js";
Expand Down Expand Up @@ -88,7 +88,7 @@ export const {
WITHDRAWAL_QUEUE_LIMIT,
MAX_BLS_TO_EXECUTION_CHANGES,
MAX_WITHDRAWALS_PER_PAYLOAD,
} = presets[ACTIVE_PRESET];
} = {...presets[ACTIVE_PRESET], ...userOverrides};

////////////
// Constants
Expand Down
9 changes: 8 additions & 1 deletion packages/params/src/setPreset.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {PresetName} from "./presetName.js";
import {presetStatus} from "./presetStatus.js";
import {BeaconPreset} from "./interface/index.js";

export {PresetName};

Expand All @@ -13,14 +14,19 @@ export {PresetName};
*/
export let userSelectedPreset: PresetName | null = null;

export let userOverrides: Partial<BeaconPreset> | undefined = undefined;

/**
* Override the active preset
*
* WARNING: Lodestar libraries rely on preset values being _constant_, so the active preset must be set _before_ loading any other lodestar libraries.
*
* Only call this function if you _really_ know what you are doing.
*
* @param presetName - the preset to use as a base
* @param overrides - customized fields
*/
export function setActivePreset(presetName: PresetName): void {
export function setActivePreset(presetName: PresetName, overrides?: Partial<BeaconPreset>): void {
if (presetStatus.frozen) {
throw Error(`Lodestar preset is already frozen. You must call setActivePreset() at the top of your
application entry point, before importing @lodestar/params, or any library that may import it.
Expand All @@ -37,4 +43,5 @@ console.log({SLOTS_PER_EPOCH})
}

userSelectedPreset = presetName;
userOverrides = overrides;
}
36 changes: 36 additions & 0 deletions packages/params/test/e2e/overridePreset.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import path from "node:path";
import util from "node:util";
import child from "node:child_process";
import {fileURLToPath} from "node:url";
import {expect, use} from "chai";
import chaiAsPromised from "chai-as-promised";

const scriptNames = {
ok: "overridePresetOk.ts",
error: "overridePresetError.ts",
};

use(chaiAsPromised);

const exec = util.promisify(child.exec);

// Global variable __dirname no longer available in ES6 modules.
// Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const tsNodeBinary = path.join(__dirname, "../../../../node_modules/.bin/ts-node-esm");

describe("Override preset", function () {
// Allow time for ts-node to compile Typescript source
this.timeout(30_000);

it("Should correctly override preset", async () => {
await exec(`${tsNodeBinary} ${path.join(__dirname, scriptNames.ok)}`);
});

it("Should throw trying to override preset in the wrong order", async () => {
await expect(exec(`${tsNodeBinary} ${path.join(__dirname, scriptNames.error)}`)).to.be.rejectedWith(
"Lodestar preset is already frozen"
);
});
});
11 changes: 11 additions & 0 deletions packages/params/test/e2e/overridePresetError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// This script is should be run in an e2e !!
// It demostrates how NOT to change the Lodestar preset

// 1. Import from not only @lodestar/params/setPreset will trigger an error
import {SLOTS_PER_EPOCH} from "../../lib/index.js";
import {setActivePreset, PresetName} from "../../lib/setPreset.js";
// This line should throw
// eslint-disable-next-line @typescript-eslint/naming-convention
setActivePreset(PresetName.minimal, {SLOTS_PER_EPOCH: 2});

SLOTS_PER_EPOCH;
18 changes: 18 additions & 0 deletions packages/params/test/e2e/overridePresetOk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import assert from "node:assert";

/* eslint import/order: "off" */
// This script is should be run in an e2e !!
// It demostrates how to properly change the Lodestar preset safely

// 1. Import from @lodestar/params/setPreset only
import {setActivePreset, PresetName} from "../../src/setPreset.js";
// eslint-disable-next-line @typescript-eslint/naming-convention
setActivePreset(PresetName.minimal, {SLOTS_PER_EPOCH: 2});

// 2. Import from any other @lodestar/params paths

const {SLOTS_PER_EPOCH, BASE_REWARD_FACTOR} = await import("../../src/index.js");

assert.equal(SLOTS_PER_EPOCH, 2, "SLOTS_PER_EPOCH should have overriden preset value");
assert.equal(BASE_REWARD_FACTOR, 64, "BASE_REWARD_FACTOR should have preset value");
assert.equal(process.env.LODESTAR_PRESET, undefined, "LODESTAR_PRESET ENV must not be set");

0 comments on commit 1cba836

Please sign in to comment.