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

Spec test v1.1.0 #3264

Merged
merged 9 commits into from
Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 6 additions & 6 deletions .github/workflows/test-spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ jobs:
- name: Spec tests altair-mainnet
run: yarn test:spec-altair-mainnet
working-directory: packages/spec-test-runner
# - name: Spec tests merge-minimal
# run: yarn test:spec-merge-minimal
# working-directory: packages/spec-test-runner
# - name: Spec tests merge-mainnet
# run: yarn test:spec-merge-mainnet
# working-directory: packages/spec-test-runner
- name: Spec tests merge-minimal
run: yarn test:spec-merge-minimal
working-directory: packages/spec-test-runner
- name: Spec tests merge-mainnet
run: yarn test:spec-merge-mainnet
working-directory: packages/spec-test-runner
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function statusProcessEpoch<T extends allForks.BeaconState>(
targetFlag: number,
headFlag: number
): void {
const {epochCtx} = state;
const {epochCtx, slot: stateSlot} = state;
const rootType = ssz.Root;
const prevEpoch = epochCtx.previousShuffling.epoch;
if (attestations.length === 0) {
Expand All @@ -40,7 +40,8 @@ export function statusProcessEpoch<T extends allForks.BeaconState>(
const attBeaconBlockRoot = attData.beaconBlockRoot;
const attTarget = attData.target;
const attVotedTargetRoot = rootType.equals(attTarget.root, actualTargetBlockRoot);
const attVotedHeadRoot = rootType.equals(attBeaconBlockRoot, getBlockRootAtSlot(state, attSlot));
const attVotedHeadRoot =
attSlot < stateSlot && rootType.equals(attBeaconBlockRoot, getBlockRootAtSlot(state, attSlot));
const committee = epochCtx.getBeaconCommittee(attSlot, committeeIndex);
const participants = zipIndexesCommitteeBits(committee, aggregationBits);

Expand Down
2 changes: 2 additions & 0 deletions packages/beacon-state-transition/src/util/genesis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ export function initializeBeaconStateFromEth1(

if (GENESIS_SLOT >= config.MERGE_FORK_EPOCH) {
const stateMerge = state as TreeBacked<merge.BeaconState>;
// as of Sep 2021, this is for spec test only
stateMerge.fork.previousVersion = config.GENESIS_FORK_VERSION;
stateMerge.latestExecutionPayloadHeader.blockHash = eth1BlockHash;
stateMerge.latestExecutionPayloadHeader.timestamp = eth1Timestamp;
stateMerge.latestExecutionPayloadHeader.random = eth1BlockHash;
Expand Down
4 changes: 2 additions & 2 deletions packages/config/src/chainConfig/presets/minimal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ export const chainConfig: IChainConfig = {
EJECTION_BALANCE: 16000000000,
// 2**2 (= 4)
MIN_PER_EPOCH_CHURN_LIMIT: 4,
// 2**16 (= 65,536)
CHURN_LIMIT_QUOTIENT: 65536,
// [customized] scale queue churn at much lower validator counts for testing
CHURN_LIMIT_QUOTIENT: 32,

// Deposit contract
// ---------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions packages/spec-test-runner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"@chainsafe/lodestar-utils": "^0.30.0",
"@chainsafe/lodestar-validator": "^0.30.0",
"@chainsafe/ssz": "^0.8.17",
"@chainsafe/persistent-merkle-tree": "^0.3.7",
"@types/yargs": "^17.0.2"
},
"keywords": [
Expand Down
18 changes: 1 addition & 17 deletions packages/spec-test-runner/test/spec/allForks/epochProcessing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {CachedBeaconState, allForks} from "@chainsafe/lodestar-beacon-state-tran
import {describeDirectorySpecTest} from "@chainsafe/lodestar-spec-test-util";
import {ssz} from "@chainsafe/lodestar-types";
import {TreeBacked} from "@chainsafe/ssz";
import {ACTIVE_PRESET, ForkName, PresetName} from "@chainsafe/lodestar-params";
import {ACTIVE_PRESET, ForkName} from "@chainsafe/lodestar-params";
import {SPEC_TEST_LOCATION} from "../../specTestVersioning";
import {expectEqualBeaconState, inputTypeSszTreeBacked} from "../util";
import {getConfig} from "./util";
Expand Down Expand Up @@ -53,22 +53,6 @@ export function epochProcessing(fork: ForkName, epochProcessFns: Record<string,
expectFunc: (testCase, expected, actual) => {
expectEqualBeaconState(fork, expected, actual);
},
shouldSkip: (testCase, n) =>
// TODO: All the tests below fail with the same error
//
// Error: Cannot get block root for slot in the future: 47 < 47
// at Object.lt (/home/lion/Code/eth2.0/lodestar/packages/utils/src/assert.ts:43:13)
// at Object.getBlockRootAtSlot (/home/lion/Code/eth2.0/lodestar/packages/beacon-state-transition/src/util/blockRoot.ts:17:10)
// at Object.statusProcessEpoch (/home/lion/Code/eth2.0/lodestar/packages/beacon-state-transition/src/phase0/epoch/processPendingAttestations.ts:40:66)
// at Object.beforeProcessEpoch (/home/lion/Code/eth2.0/lodestar/packages/beacon-state-transition/src/allForks/util/epochProcess.ts:189:5)
fork === ForkName.phase0 &&
ACTIVE_PRESET === PresetName.minimal &&
testDir === "justification_and_finalization" &&
(n === "123_ok_support" ||
n === "123_poor_support" ||
n === "12_ok_support" ||
n === "12_ok_support_messed_target" ||
n === "12_poor_support"),
}
);
}
Expand Down
52 changes: 29 additions & 23 deletions packages/spec-test-runner/test/spec/allForks/forkChoice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
// eslint-disable-next-line no-restricted-imports
import {ChainEventEmitter} from "@chainsafe/lodestar/lib/chain/emitter";
import {toHexString} from "@chainsafe/ssz";
import {IForkChoice} from "@chainsafe/lodestar-fork-choice";
import {CheckpointWithHex, IForkChoice} from "@chainsafe/lodestar-fork-choice";
import {ssz} from "@chainsafe/lodestar-types";
import {ACTIVE_PRESET, SLOTS_PER_EPOCH, ForkName} from "@chainsafe/lodestar-params";
import {SPEC_TEST_LOCATION} from "../../specTestVersioning";
Expand Down Expand Up @@ -82,8 +82,8 @@ export function forkChoiceTest(fork: ForkName): void {
const {
head: expectedHead,
time: expectedTime,
justifiedCheckpointRoot,
finalizedCheckpointRoot,
justifiedCheckpoint,
finalizedCheckpoint,
bestJustifiedCheckpoint,
} = step.checks;

Expand All @@ -99,21 +99,24 @@ export function forkChoiceTest(fork: ForkName): void {
Number(expectedTime),
`Invalid forkchoice time at step ${i}`
);
if (justifiedCheckpointRoot)
expect(toHexString(forkchoice.getJustifiedCheckpoint().root)).to.be.equal(
justifiedCheckpointRoot,
`Invalid justified checkpoint time at step ${i}`
if (justifiedCheckpoint) {
expect(toSpecTestCheckpoint(forkchoice.getJustifiedCheckpoint())).to.be.deep.equal(
justifiedCheckpoint,
`Invalid justified checkpoint at step ${i}`
);
if (finalizedCheckpointRoot)
expect(toHexString(forkchoice.getFinalizedCheckpoint().root)).to.be.equal(
finalizedCheckpointRoot,
`Invalid finalized checkpoint time at step ${i}`
}
if (finalizedCheckpoint) {
expect(toSpecTestCheckpoint(forkchoice.getFinalizedCheckpoint())).to.be.deep.equal(
finalizedCheckpoint,
`Invalid finalized checkpoint at step ${i}`
);
if (bestJustifiedCheckpoint)
expect(toHexString(forkchoice.getBestJustifiedCheckpoint().root)).to.be.equal(
}
if (bestJustifiedCheckpoint) {
expect(toSpecTestCheckpoint(forkchoice.getBestJustifiedCheckpoint())).to.be.deep.equal(
bestJustifiedCheckpoint,
`Invalid best justified checkpoint time at step ${i}`
`Invalid best justified checkpoint at step ${i}`
);
}
}
}
},
Expand Down Expand Up @@ -154,12 +157,6 @@ export function forkChoiceTest(fork: ForkName): void {
timeout: 10000,
// eslint-disable-next-line @typescript-eslint/no-empty-function
expectFunc: () => {},

shouldSkip: (_, n) =>
// we should enable this for next spec test release
// refer to https://github.com/hwwhww/consensus-spec-tests/tree/fork-choice-pr2577
n === "new_justified_is_later_than_store_justified" ||
n === "on_block_finalized_skip_slots_not_in_skip_chain",
}
);
}
Expand Down Expand Up @@ -250,8 +247,17 @@ function cacheState(
stateCache.set(toHexString(blockRoot), wrappedState);
}

function toSpecTestCheckpoint(checkpoint: CheckpointWithHex): SpecTestCheckpoint {
return {
epoch: BigInt(checkpoint.epoch),
root: checkpoint.rootHex,
};
}

type Step = OnTick | OnAttestation | OnBlock | Checks;

type SpecTestCheckpoint = {epoch: BigInt; root: string};

// This test executes steps in sequence. There may be multiple items of the following types:
// on_tick execution step

Expand Down Expand Up @@ -279,9 +285,9 @@ type Checks = {
checks: {
head: {slot: number; root: string};
time?: number;
justifiedCheckpointRoot?: string;
finalizedCheckpointRoot?: string;
bestJustifiedCheckpoint?: string;
justifiedCheckpoint?: SpecTestCheckpoint;
finalizedCheckpoint?: SpecTestCheckpoint;
bestJustifiedCheckpoint?: SpecTestCheckpoint;
};
};

Expand Down
61 changes: 61 additions & 0 deletions packages/spec-test-runner/test/spec/altair/merkle.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {join} from "path";
import {altair, ssz} from "@chainsafe/lodestar-types";
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
import {ProofType, SingleProof} from "@chainsafe/persistent-merkle-tree";
import {ACTIVE_PRESET} from "@chainsafe/lodestar-params";
import {fromHexString, toHexString, TreeBacked} from "@chainsafe/ssz";
import {SPEC_TEST_LOCATION} from "../../specTestVersioning";
import {IBaseSpecTest} from "../type";
import {verifyMerkleBranch} from "@chainsafe/lodestar-utils";
import {expect} from "chai";

describeDirectorySpecTest<IMerkleTestCase, IProof>(
`${ACTIVE_PRESET}/altair/transition`,
join(SPEC_TEST_LOCATION, `/tests/${ACTIVE_PRESET}/altair/merkle/single_proof/pyspec_tests`),
(testcase) => {
const {proof: specTestProof, state} = testcase;
const stateTB = state as TreeBacked<altair.BeaconState>;
const stateRoot = stateTB.hashTreeRoot();
const leaf = fromHexString(specTestProof.leaf);
const branch = specTestProof.branch.map((item) => fromHexString(item));
const depth = Math.floor(Math.log2(Number(specTestProof.leafIndex)));
const verified = verifyMerkleBranch(leaf, branch, depth, Number(specTestProof.leafIndex) % 2 ** depth, stateRoot);
expect(verified, "cannot verify merkle branch").to.be.true;
const lodestarProof = stateTB.tree.getProof({
gindex: specTestProof.leafIndex,
type: ProofType.single,
}) as SingleProof;
return {
leaf: toHexString(lodestarProof.leaf),
leafIndex: lodestarProof.gindex,
branch: lodestarProof.witnesses.map(toHexString),
};
},
{
inputTypes: {
state: {type: InputType.SSZ_SNAPPY as const, treeBacked: true as const},
proof: InputType.YAML as const,
},
getSszTypes: () => {
return {
state: ssz.altair.BeaconState,
};
},
timeout: 10000,
getExpected: (testCase) => testCase.proof,
expectFunc: (testCase, expected, actual) => {
expect(actual).to.be.deep.equal(expected, "incorrect proof");
},
}
);

interface IMerkleTestCase extends IBaseSpecTest {
state: altair.BeaconState;
proof: IProof;
}

interface IProof {
leaf: string;
leafIndex: bigint;
branch: string[];
}
4 changes: 4 additions & 0 deletions packages/spec-test-runner/test/spec/merge/genesis.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import {ForkName} from "@chainsafe/lodestar-params";
import {genesis} from "../allForks/genesis";

genesis(ForkName.merge);
2 changes: 1 addition & 1 deletion packages/spec-test-runner/test/specTestVersioning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ import path from "path";
// The contents of this file MUST include the URL, version and target path, and nothing else.

export const SPEC_TEST_REPO_URL = "https://github.com/ethereum/consensus-spec-tests";
export const SPEC_TEST_VERSION = "v1.1.0-beta.3";
export const SPEC_TEST_VERSION = "v1.1.0";
export const SPEC_TEST_LOCATION = path.join(__dirname, "../spec-tests");
5 changes: 3 additions & 2 deletions packages/types/src/merge/sszTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {ssz as altairSsz} from "../altair";
import * as merge from "./types";
import {LazyVariable} from "../utils/lazyVar";

const {Bytes20, Bytes32, Number64, Slot, ValidatorIndex, Root, BLSSignature} = primitiveSsz;
const {Bytes20, Bytes32, Number64, Slot, ValidatorIndex, Root, BLSSignature, Uint8} = primitiveSsz;

// So the expandedRoots can be referenced, and break the circular dependency
const typesRef = new LazyVariable<{
Expand Down Expand Up @@ -61,7 +61,8 @@ const executionPayloadFields = {
gasLimit: Number64,
gasUsed: Number64,
timestamp: Number64,
extraData: new ByteVectorType({length: MAX_EXTRA_DATA_BYTES}),
// TODO: if there is perf issue, consider making ByteListType
extraData: new ListType({limit: MAX_EXTRA_DATA_BYTES, elementType: Uint8}),
baseFeePerGas: Bytes32,
// Extra payload fields
blockHash: Root,
Expand Down