Skip to content

Commit

Permalink
feat: add cli flag to ignore the wss check failure on checkpoint sync (
Browse files Browse the repository at this point in the history
…#6453)

* feat: add cli flag to ignore the wss check failure on checkpoint sync

* minor fixes
  • Loading branch information
g11tech committed Feb 19, 2024
1 parent c7c9941 commit efb684a
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 13 deletions.
43 changes: 30 additions & 13 deletions packages/cli/src/cmds/beacon/initBeaconState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from "@lodestar/beacon-node";
import {Checkpoint} from "@lodestar/types/phase0";

import {downloadOrLoadFile} from "../../util/index.js";
import {downloadOrLoadFile, wrapFnError} from "../../util/index.js";
import {defaultNetwork, GlobalArgs} from "../../options/globalOptions.js";
import {
fetchWeakSubjectivityState,
Expand All @@ -31,7 +31,8 @@ async function initAndVerifyWeakSubjectivityState(
logger: Logger,
store: BeaconStateAllForks,
wsState: BeaconStateAllForks,
wsCheckpoint: Checkpoint
wsCheckpoint: Checkpoint,
opts: {ignoreWeakSubjectivityCheck?: boolean} = {}
): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint: Checkpoint}> {
// Check if the store's state and wsState are compatible
if (
Expand All @@ -56,12 +57,16 @@ async function initAndVerifyWeakSubjectivityState(
);
}

// Instead of warning user of wss check failure, we throw because user explicity wants to use
// the checkpoint sync
ensureWithinWeakSubjectivityPeriod(config, anchorState, anchorCheckpoint);
// Throw error unless user explicitly asked not to, in testnets can happen that wss period is too small
// that even some epochs of non finalization can cause finalized checkpoint to be out of valid range
const wssCheck = wrapFnError(() => ensureWithinWeakSubjectivityPeriod(config, anchorState, anchorCheckpoint));
const isWithinWeakSubjectivityPeriod = wssCheck.err === null;
if (!isWithinWeakSubjectivityPeriod && !opts.ignoreWeakSubjectivityCheck) {
throw wssCheck.err;
}

anchorState = await initStateFromAnchorState(config, db, logger, anchorState, {
isWithinWeakSubjectivityPeriod: true,
isWithinWeakSubjectivityPeriod,
isCheckpointState,
});

Expand Down Expand Up @@ -123,15 +128,23 @@ export async function initBeaconState(
if (args.checkpointState) {
return readWSState(
lastDbState,
{checkpointState: args.checkpointState, wssCheckpoint: args.wssCheckpoint},
{
checkpointState: args.checkpointState,
wssCheckpoint: args.wssCheckpoint,
ignoreWeakSubjectivityCheck: args.ignoreWeakSubjectivityCheck,
},
chainForkConfig,
db,
logger
);
} else if (args.checkpointSyncUrl) {
return fetchWSStateFromBeaconApi(
lastDbState,
{checkpointSyncUrl: args.checkpointSyncUrl, wssCheckpoint: args.wssCheckpoint},
{
checkpointSyncUrl: args.checkpointSyncUrl,
wssCheckpoint: args.wssCheckpoint,
ignoreWeakSubjectivityCheck: args.ignoreWeakSubjectivityCheck,
},
chainForkConfig,
db,
logger
Expand All @@ -158,27 +171,29 @@ export async function initBeaconState(

async function readWSState(
lastDbState: BeaconStateAllForks | null,
wssOpts: {checkpointState: string; wssCheckpoint?: string},
wssOpts: {checkpointState: string; wssCheckpoint?: string; ignoreWeakSubjectivityCheck?: boolean},
chainForkConfig: ChainForkConfig,
db: IBeaconDb,
logger: Logger
): Promise<{anchorState: BeaconStateAllForks; wsCheckpoint?: Checkpoint}> {
// weak subjectivity sync from a provided state file:
// if a weak subjectivity checkpoint has been provided, it is used for additional verification
// otherwise, the state itself is used for verification (not bad, because the trusted state has been explicitly provided)
const {checkpointState, wssCheckpoint} = wssOpts;
const {checkpointState, wssCheckpoint, ignoreWeakSubjectivityCheck} = wssOpts;

const stateBytes = await downloadOrLoadFile(checkpointState);
const wsState = getStateTypeFromBytes(chainForkConfig, stateBytes).deserializeToViewDU(stateBytes);
const config = createBeaconConfig(chainForkConfig, wsState.genesisValidatorsRoot);
const store = lastDbState ?? wsState;
const checkpoint = wssCheckpoint ? getCheckpointFromArg(wssCheckpoint) : getCheckpointFromState(wsState);
return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsState, checkpoint);
return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsState, checkpoint, {
ignoreWeakSubjectivityCheck,
});
}

async function fetchWSStateFromBeaconApi(
lastDbState: BeaconStateAllForks | null,
wssOpts: {checkpointSyncUrl: string; wssCheckpoint?: string},
wssOpts: {checkpointSyncUrl: string; wssCheckpoint?: string; ignoreWeakSubjectivityCheck?: boolean},
chainForkConfig: ChainForkConfig,
db: IBeaconDb,
logger: Logger
Expand All @@ -201,5 +216,7 @@ async function fetchWSStateFromBeaconApi(
const {wsState, wsCheckpoint} = await fetchWeakSubjectivityState(chainForkConfig, logger, wssOpts);
const config = createBeaconConfig(chainForkConfig, wsState.genesisValidatorsRoot);
const store = lastDbState ?? wsState;
return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsState, wsCheckpoint);
return initAndVerifyWeakSubjectivityState(config, db, logger, store, wsState, wsCheckpoint, {
ignoreWeakSubjectivityCheck: wssOpts.ignoreWeakSubjectivityCheck,
});
}
9 changes: 9 additions & 0 deletions packages/cli/src/cmds/beacon/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type BeaconExtraArgs = {
checkpointState?: string;
wssCheckpoint?: string;
forceCheckpointSync?: boolean;
ignoreWeakSubjectivityCheck?: boolean;
beaconDir?: string;
dbDir?: string;
persistInvalidSszObjectsDir?: string;
Expand Down Expand Up @@ -75,6 +76,14 @@ export const beaconExtraOptions: CliCommandOptions<BeaconExtraArgs> = {
group: "weak subjectivity",
},

ignoreWeakSubjectivityCheck: {
description:
"Ignore the checkpoint sync state failing the weak subjectivity check. This is relevant in testnets where the weak subjectivity period is too small for even few epochs of non finalization causing last finalized to be out of range. This flag is not recommended for mainnet use.",
hidden: true,
type: "boolean",
group: "weak subjectivity",
},

beaconDir: {
description: "Beacon root directory",
defaultDescription: defaultBeaconPaths.beaconDir,
Expand Down
7 changes: 7 additions & 0 deletions packages/cli/src/util/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ export async function wrapError<T>(promise: Promise<T>): Promise<Result<T>> {
return {err: err as Error};
}
}
export function wrapFnError<T>(fn: () => T): Result<T> {
try {
return {err: null, result: fn()};
} catch (err) {
return {err: err as Error};
}
}

0 comments on commit efb684a

Please sign in to comment.