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

chore: update the naming conventions used in sim tests #6805

Merged
merged 6 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions packages/cli/test/scripts/e2e_test_env.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* eslint-disable @typescript-eslint/naming-convention */
import path from "node:path";
import {BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js";
import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js";
import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js";
import {connectAllNodes} from "../utils/simulation/utils/network.js";
import {BeaconClient, ExecutionClient} from "../utils/crucible/interfaces.js";
import {Simulation} from "../utils/crucible/simulation.js";
import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js";
import {connectAllNodes} from "../utils/crucible/utils/network.js";

const altairForkEpoch = 1;
const bellatrixForkEpoch = 2;
Expand All @@ -17,7 +17,7 @@ const {forkConfig} = defineSimTestConfig({
initialNodes: 2,
});

const env = await SimulationEnvironment.initWithDefaults(
const env = await Simulation.initWithDefaults(
{
id: "e2e-test-env",
logsDir: path.join(logFilesDir, "e2e-test-env"),
Expand Down
14 changes: 7 additions & 7 deletions packages/cli/test/sim/backupEthProvider.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/* eslint-disable @typescript-eslint/naming-convention */
import path from "node:path";
import {activePreset} from "@lodestar/params";
import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js";
import {nodeAssertion} from "../utils/simulation/assertions/nodeAssertion.js";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I lean towards keeping assertion vs scenario

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assertion is one step of the whole process that involves in it, capturing data, asserting logic, dumping raw data for debugging.

So why I tend to use a broader term here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scenario to me is like "range syncing" or similar.... doesn't speak to "collecting information and asserting against it"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you can implement same "range syncing" with this, but to implement this scenario you need some flow, some structure to capture key points and then decide if the range sync was successful or not, if not then dump the raw data for debugging.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as in "a scenario" is the "range syncing scenario".... and within a scenario there are a number of data points that are collected and asserted against. the collection and asserting is "an assertion" to me, not "a scenario". like there are assertions that happen at the slot, there are assertions that happen at the epoch. not there are scenarios that happen at the slot and scenarios that happen at the epoch... i think "scenario" is the wrong work for this construct and prefer it the way it was before the change. I think the wording "Assertion" was more descriptive before.

Copy link
Member

@matthewkeil matthewkeil May 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, def should let others weigh in on the semantics. I think the whole flow of collect data, check assertion and store result is an "assertion"..... for merge it would be a MergeAssertion for blobs it would be a BlobAssertion. Like a blob assertion in my mind is the hook to send the blob transaction, to wait scheduling for the blob to be propagated, the calling of the API to get the blobs from the CL and then the assert statement to check the blob that was received is the same as the blob that was sent... That whole workflow is an "assertion". I suppose "Test" would also be appropriate because the test can contain several "assertions". But a "scenario" is more something the talks about the flow or conditions of the simulation as a whole.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That whole flow usually referred as AAA Pattern and assertion is one part of it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @matthewkeil. Open to other ideas, but between those two, assertion is more helpful here.

Copy link
Member

@nflaig nflaig May 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mergeScenario vs mergeAssertion

Looking at this in the code, this is definitely an assertion as it asserts that the merge transition was successful. A "merge scenario" sounds like a configuration you would pass to the simulation framework to test the merge as a whole.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So be it assertion then.

import {AssertionMatch, BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js";
import {defineSimTestConfig, logFilesDir, replaceIpFromUrl} from "../utils/simulation/utils/index.js";
import {connectAllNodes, waitForSlot} from "../utils/simulation/utils/network.js";
import {Simulation} from "../utils/crucible/simulation.js";
import {nodeAssertion} from "../utils/crucible/assertions/nodeAssertion.js";
import {Match, BeaconClient, ExecutionClient} from "../utils/crucible/interfaces.js";
import {defineSimTestConfig, logFilesDir, replaceIpFromUrl} from "../utils/crucible/utils/index.js";
import {connectAllNodes, waitForSlot} from "../utils/crucible/utils/network.js";

const altairForkEpoch = 2;
const bellatrixForkEpoch = 4;
Expand All @@ -19,7 +19,7 @@ const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({
initialNodes: 3,
});

const env = await SimulationEnvironment.initWithDefaults(
const env = await Simulation.initWithDefaults(
{
id: "backup-eth-provider",
logsDir: path.join(logFilesDir, "backup-eth-provider"),
Expand All @@ -31,7 +31,7 @@ const env = await SimulationEnvironment.initWithDefaults(
env.tracker.register({
...nodeAssertion,
match: ({slot}) => {
return slot === 1 ? AssertionMatch.Assert | AssertionMatch.Capture | AssertionMatch.Remove : AssertionMatch.None;
return slot === 1 ? Match.Assert | Match.Capture | Match.Remove : Match.None;
},
});

Expand Down
14 changes: 7 additions & 7 deletions packages/cli/test/sim/deneb.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/* eslint-disable @typescript-eslint/naming-convention */
import path from "node:path";
import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js";
import {BeaconClient, ExecutionClient, ValidatorClient} from "../utils/simulation/interfaces.js";
import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js";
import {connectAllNodes, waitForSlot} from "../utils/simulation/utils/network.js";
import {createBlobsAssertion} from "../utils/simulation/assertions/blobsAssertion.js";
import {assertCheckpointSync, assertRangeSync} from "../utils/simulation/utils/syncing.js";
import {Simulation} from "../utils/crucible/simulation.js";
import {BeaconClient, ExecutionClient, ValidatorClient} from "../utils/crucible/interfaces.js";
import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js";
import {connectAllNodes, waitForSlot} from "../utils/crucible/utils/network.js";
import {createBlobsAssertion} from "../utils/crucible/assertions/blobsAssertion.js";
import {assertCheckpointSync, assertRangeSync} from "../utils/crucible/utils/syncing.js";

const runTillEpoch = 6;
const syncWaitEpoch = 2;
Expand All @@ -20,7 +20,7 @@ const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({
additionalSlotsForTTD: 0,
});

const env = await SimulationEnvironment.initWithDefaults(
const env = await Simulation.initWithDefaults(
{
id: "deneb",
logsDir: path.join(logFilesDir, "deneb"),
Expand Down
10 changes: 5 additions & 5 deletions packages/cli/test/sim/endpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import path from "node:path";
import assert from "node:assert";
import {toHexString} from "@chainsafe/ssz";
import {ApiError, routes} from "@lodestar/api";
import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js";
import {BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js";
import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js";
import {waitForSlot} from "../utils/simulation/utils/network.js";
import {Simulation} from "../utils/crucible/simulation.js";
import {BeaconClient, ExecutionClient} from "../utils/crucible/interfaces.js";
import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js";
import {waitForSlot} from "../utils/crucible/utils/network.js";

const altairForkEpoch = 2;
const bellatrixForkEpoch = 4;
Expand All @@ -19,7 +19,7 @@ const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({
initialNodes: 1,
});

const env = await SimulationEnvironment.initWithDefaults(
const env = await Simulation.initWithDefaults(
{
id: "beacon-endpoints",
logsDir: path.join(logFilesDir, "beacon-endpoints"),
Expand Down
14 changes: 7 additions & 7 deletions packages/cli/test/sim/mixedClient.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/* eslint-disable @typescript-eslint/naming-convention */
import path from "node:path";
import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js";
import {nodeAssertion} from "../utils/simulation/assertions/nodeAssertion.js";
import {AssertionMatch, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/simulation/interfaces.js";
import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js";
import {connectAllNodes, waitForSlot} from "../utils/simulation/utils/network.js";
import {Simulation} from "../utils/crucible/simulation.js";
import {nodeAssertion} from "../utils/crucible/assertions/nodeAssertion.js";
import {Match, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/crucible/interfaces.js";
import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js";
import {connectAllNodes, waitForSlot} from "../utils/crucible/utils/network.js";

const altairForkEpoch = 2;
const bellatrixForkEpoch = 4;
Expand All @@ -22,7 +22,7 @@ const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({
initialNodes: 2,
});

const env = await SimulationEnvironment.initWithDefaults(
const env = await Simulation.initWithDefaults(
{
id: "mixed-clients",
logsDir: path.join(logFilesDir, "mixed-clients"),
Expand Down Expand Up @@ -58,7 +58,7 @@ const env = await SimulationEnvironment.initWithDefaults(
env.tracker.register({
...nodeAssertion,
match: ({slot}) => {
return slot === 1 ? AssertionMatch.Assert | AssertionMatch.Capture | AssertionMatch.Remove : AssertionMatch.None;
return slot === 1 ? Match.Assert | Match.Capture | Match.Remove : Match.None;
},
});

Expand Down
30 changes: 15 additions & 15 deletions packages/cli/test/sim/multiFork.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/* eslint-disable @typescript-eslint/naming-convention */
import path from "node:path";
import {AssertionMatch, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/simulation/interfaces.js";
import {SimulationEnvironment} from "../utils/simulation/simulationEnvironment.js";
import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js";
import {connectAllNodes, waitForSlot} 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";
import {createAccountBalanceAssertion} from "../utils/simulation/assertions/accountBalanceAssertion.js";
import {createExecutionHeadAssertion} from "../utils/simulation/assertions/executionHeadAssertion.js";
import {createWithdrawalAssertions} from "../utils/simulation/assertions/withdrawalsAssertion.js";
import {assertCheckpointSync, assertRangeSync, assertUnknownBlockSync} from "../utils/simulation/utils/syncing.js";
import {Match, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/crucible/interfaces.js";
import {Simulation} from "../utils/crucible/simulation.js";
import {defineSimTestConfig, logFilesDir} from "../utils/crucible/utils/index.js";
import {connectAllNodes, waitForSlot} from "../utils/crucible/utils/network.js";
import {nodeAssertion} from "../utils/crucible/assertions/nodeAssertion.js";
import {mergeAssertion} from "../utils/crucible/assertions/mergeAssertion.js";
import {createForkAssertion} from "../utils/crucible/assertions/forkAssertion.js";
import {createAccountBalanceAssertion} from "../utils/crucible/assertions/accountBalanceAssertion.js";
import {createExecutionHeadAssertion} from "../utils/crucible/assertions/executionHeadAssertion.js";
import {createWithdrawalAssertions} from "../utils/crucible/assertions/withdrawalsAssertion.js";
import {assertCheckpointSync, assertRangeSync, assertUnknownBlockSync} from "../utils/crucible/utils/syncing.js";

const altairForkEpoch = 2;
const bellatrixForkEpoch = 4;
Expand All @@ -28,7 +28,7 @@ const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({
initialNodes: 5,
});

const env = await SimulationEnvironment.initWithDefaults(
const env = await Simulation.initWithDefaults(
{
id: "multi-fork",
logsDir: path.join(logFilesDir, "multi-fork"),
Expand Down Expand Up @@ -114,7 +114,7 @@ const env = await SimulationEnvironment.initWithDefaults(
env.tracker.register({
...nodeAssertion,
match: ({slot}) => {
return slot === 1 ? AssertionMatch.Assert | AssertionMatch.Capture | AssertionMatch.Remove : AssertionMatch.None;
return slot === 1 ? Match.Assert | Match.Capture | Match.Remove : Match.None;
},
});

Expand All @@ -123,8 +123,8 @@ env.tracker.register({
match: ({slot}) => {
// Check at the end of bellatrix fork, merge should happen by then
return slot === env.clock.getLastSlotOfEpoch(bellatrixForkEpoch)
? AssertionMatch.Assert | AssertionMatch.Remove
: AssertionMatch.None;
? Match.Assert | Match.Remove
: Match.None;
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Lodestar Simulation Test
# Crucible by Lodestar

matthewkeil marked this conversation as resolved.
Show resolved Hide resolved
> a test of faith, patience, or strength

Lodestar simulation tests allows to setup a small, local devnet for the variety of Consensus and Execution Layer clients. We use the `minimal` preset for all CL clients. Following clients are currently supported.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {EL_GENESIS_ACCOUNT} from "../constants.js";
import {AssertionMatch, AssertionResult, NodePair, SimulationAssertion} from "../interfaces.js";
import {Match, AssertionResult, NodePair, Assertion} from "../interfaces.js";

const transactionAmount = BigInt(2441406250);

Expand All @@ -13,13 +13,13 @@ export function createAccountBalanceAssertion({
sendTransactionsAtSlot: number[];
validateTotalBalanceAt: number[];
targetNode: NodePair;
}): SimulationAssertion<`accountBalance_${typeof address}`, bigint> {
}): Assertion<`accountBalance_${typeof address}`, bigint> {
return {
id: `accountBalance_${address}`,
match({slot, node}) {
if (sendTransactionsAtSlot.includes(slot) && node.id === targetNode.id) return AssertionMatch.Capture;
if (validateTotalBalanceAt.includes(slot) && node.id === targetNode.id) return AssertionMatch.Assert;
return AssertionMatch.None;
if (sendTransactionsAtSlot.includes(slot) && node.id === targetNode.id) return Match.Capture;
if (validateTotalBalanceAt.includes(slot) && node.id === targetNode.id) return Match.Assert;
return Match.None;
},
async capture({node}) {
await node.execution.provider?.eth.sendTransaction({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {randomBytes} from "node:crypto";
import {ApiError} from "@lodestar/api";
import {fromHex, toHex} from "@lodestar/utils";
import {SimulationAssertion, AssertionMatch, AssertionResult, NodePair} from "../interfaces.js";
import {Assertion, Match, AssertionResult, NodePair} from "../interfaces.js";
import {EL_GENESIS_ACCOUNT, EL_GENESIS_SECRET_KEY, SIM_ENV_CHAIN_ID} from "../constants.js";
import {generateBlobsForTransaction} from "../utils/blobs.js";
import {BlobsEIP4844Transaction} from "../web3js/blobsEIP4844Transaction.js";
Expand All @@ -12,16 +12,16 @@ const sentBlobs: Uint8Array[] = [];
export function createBlobsAssertion(
nodes: NodePair[],
{sendBlobsAtSlot, validateBlobsAt}: {sendBlobsAtSlot: number; validateBlobsAt: number}
): SimulationAssertion<string, Uint8Array[]> {
): Assertion<string, Uint8Array[]> {
return {
id: `blobs-${nodes.map((n) => n.id).join("-")}`,
match: ({slot}) => {
// Run capture every sendBlobsAtSlot -> validateBlobsAt and validate only at validateBlobsAt
return slot === validateBlobsAt
? AssertionMatch.Capture | AssertionMatch.Assert
? Match.Capture | Match.Assert
: slot >= sendBlobsAtSlot && slot <= validateBlobsAt
? AssertionMatch.Capture
: AssertionMatch.None;
? Match.Capture
: Match.None;
},

async capture({slot, node}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import {MAX_COMMITTEES_PER_SLOT} from "@lodestar/params";
import {AssertionMatch, AssertionResult, SimulationAssertion} from "../../interfaces.js";
import {Match, AssertionResult, Assertion} from "../../interfaces.js";
import {inclusionDelayAssertion, expectedMaxInclusionDelay} from "./inclusionDelayAssertion.js";

export const expectedMinAttestationCount = MAX_COMMITTEES_PER_SLOT - 1;

export const attestationsCountAssertion: SimulationAssertion<
"attestationsCount",
number,
[typeof inclusionDelayAssertion]
> = {
export const attestationsCountAssertion: Assertion<"attestationsCount", number, [typeof inclusionDelayAssertion]> = {
id: "attestationsCount",
match: () => {
// TODO : Disable the assertion for now as the attestations count could be different per slot.
return AssertionMatch.Capture;
return Match.Capture;
},
dependencies: [inclusionDelayAssertion],

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import {ApiError} from "@lodestar/api";
import {TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX} from "@lodestar/params";
import {isActiveValidator} from "@lodestar/state-transition";
import {altair} from "@lodestar/types";
import {AssertionMatch, AssertionResult, SimulationAssertion} from "../../interfaces.js";
import {Match, AssertionResult, Assertion} from "../../interfaces.js";

const TIMELY_HEAD = 1 << TIMELY_HEAD_FLAG_INDEX;
const TIMELY_SOURCE = 1 << TIMELY_SOURCE_FLAG_INDEX;
const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX;

const expectedMinParticipationRate = 0.8;

export const attestationParticipationAssertion: SimulationAssertion<
export const attestationParticipationAssertion: Assertion<
"attestationParticipation",
{head: number; source: number; target: number}
> = {
Expand All @@ -19,10 +19,10 @@ export const attestationParticipationAssertion: SimulationAssertion<
// Capture data only when epoch and one extra slot passed
// Only assert at first slot of an epoch
if (epoch >= forkConfig.ALTAIR_FORK_EPOCH && clock.isFirstSlotOfEpoch(slot)) {
return AssertionMatch.Capture | AssertionMatch.Assert;
return Match.Capture | Match.Assert;
}

return AssertionMatch.None;
return Match.None;
},

async capture({node, epoch}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {ApiError} from "@lodestar/api";
import {AssertionResult, SimulationAssertion} from "../../interfaces.js";
import {AssertionResult, Assertion} from "../../interfaces.js";
import {everySlotMatcher} from "../matchers.js";

export const connectedPeerCountAssertion: SimulationAssertion<"connectedPeerCount", number> = {
export const connectedPeerCountAssertion: Assertion<"connectedPeerCount", number> = {
id: "connectedPeerCount",
match: everySlotMatcher,
async capture({node}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {ApiError} from "@lodestar/api";
import {Slot} from "@lodestar/types";
import {AssertionResult, SimulationAssertion} from "../../interfaces.js";
import {AssertionResult, Assertion} from "../../interfaces.js";
import {everySlotMatcher} from "../matchers.js";

export const finalizedAssertion: SimulationAssertion<"finalized", Slot> = {
export const finalizedAssertion: Assertion<"finalized", Slot> = {
id: "finalized",
match: everySlotMatcher,
async capture({node}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import {ApiError} from "@lodestar/api";
import {RootHex, Slot} from "@lodestar/types";
import {toHexString} from "@lodestar/utils";
import {AssertionResult, SimulationAssertion} from "../../interfaces.js";
import {AssertionResult, Assertion} from "../../interfaces.js";
import {everySlotMatcher} from "../matchers.js";

export interface HeadSummary {
blockRoot: RootHex;
slot: Slot;
}

export const headAssertion: SimulationAssertion<"head", HeadSummary> = {
export const headAssertion: Assertion<"head", HeadSummary> = {
id: "head",
match: everySlotMatcher,
async capture({node}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {AssertionResult, SimulationAssertion} from "../../interfaces.js";
import {AssertionResult, Assertion} from "../../interfaces.js";
import {avg} from "../../utils/index.js";
import {everySlotMatcher} from "../matchers.js";

export const expectedMaxInclusionDelay = 2;

export const inclusionDelayAssertion: SimulationAssertion<"inclusionDelay", number> = {
export const inclusionDelayAssertion: Assertion<"inclusionDelay", number> = {
id: "inclusionDelay",
match: everySlotMatcher,
async capture(input) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {isNullish} from "../../../../utils.js";
import {AssertionMatch, AssertionResult, SimulationAssertion} from "../../interfaces.js";
import {Match, AssertionResult, Assertion} from "../../interfaces.js";
import {arrayEquals} from "../../utils/index.js";
import {headAssertion} from "./headAssertion.js";

export const missedBlocksAssertion: SimulationAssertion<"missedBlocks", number[], [typeof headAssertion]> = {
export const missedBlocksAssertion: Assertion<"missedBlocks", number[], [typeof headAssertion]> = {
id: "missedBlocks",
match: ({clock, slot}) => {
return clock.isLastSlotOfEpoch(slot) ? AssertionMatch.Capture | AssertionMatch.Assert : AssertionMatch.None;
return clock.isLastSlotOfEpoch(slot) ? Match.Capture | Match.Assert : Match.None;
},
dependencies: [headAssertion],
async capture({node, epoch, slot, dependantStores, clock}) {
Expand Down
Loading
Loading