From 841e9008730c73198fbeee6257b54dae5b7b2249 Mon Sep 17 00:00:00 2001 From: Tuyen Nguyen Date: Mon, 27 Sep 2021 18:02:02 +0700 Subject: [PATCH 1/9] Fix statusProcessEpoch: check attSlot < stateSlot --- .../phase0/epoch/processPendingAttestations.ts | 5 +++-- .../test/spec/allForks/epochProcessing.ts | 18 +----------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/packages/beacon-state-transition/src/phase0/epoch/processPendingAttestations.ts b/packages/beacon-state-transition/src/phase0/epoch/processPendingAttestations.ts index 955bed69e586..97a1730d10ea 100644 --- a/packages/beacon-state-transition/src/phase0/epoch/processPendingAttestations.ts +++ b/packages/beacon-state-transition/src/phase0/epoch/processPendingAttestations.ts @@ -23,7 +23,7 @@ export function statusProcessEpoch( 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) { @@ -40,7 +40,8 @@ export function statusProcessEpoch( 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); diff --git a/packages/spec-test-runner/test/spec/allForks/epochProcessing.ts b/packages/spec-test-runner/test/spec/allForks/epochProcessing.ts index 390d2b39dff8..11fae2a003cd 100644 --- a/packages/spec-test-runner/test/spec/allForks/epochProcessing.ts +++ b/packages/spec-test-runner/test/spec/allForks/epochProcessing.ts @@ -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"; @@ -53,22 +53,6 @@ export function epochProcessing(fork: ForkName, epochProcessFns: Record { 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"), } ); } From ba20a23bfa11b8d4274d335c23a81214e6a6fa9f Mon Sep 17 00:00:00 2001 From: Tuyen Nguyen Date: Tue, 28 Sep 2021 08:54:20 +0700 Subject: [PATCH 2/9] Modify CHURN_LIMIT_QUOTIENT for minimal preset --- packages/config/src/chainConfig/presets/minimal.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/config/src/chainConfig/presets/minimal.ts b/packages/config/src/chainConfig/presets/minimal.ts index 0b8644cdd646..e648a1cd8c32 100644 --- a/packages/config/src/chainConfig/presets/minimal.ts +++ b/packages/config/src/chainConfig/presets/minimal.ts @@ -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 // --------------------------------------------------------------- From c2b28445cd60b466f5b813ed9fd84349502f2b52 Mon Sep 17 00:00:00 2001 From: Tuyen Nguyen Date: Tue, 28 Sep 2021 09:53:05 +0700 Subject: [PATCH 3/9] New forkchoice test format --- .../test/spec/allForks/forkChoice.ts | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/packages/spec-test-runner/test/spec/allForks/forkChoice.ts b/packages/spec-test-runner/test/spec/allForks/forkChoice.ts index 15146f3e78e0..574bc7a8187c 100644 --- a/packages/spec-test-runner/test/spec/allForks/forkChoice.ts +++ b/packages/spec-test-runner/test/spec/allForks/forkChoice.ts @@ -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"; @@ -82,8 +82,8 @@ export function forkChoiceTest(fork: ForkName): void { const { head: expectedHead, time: expectedTime, - justifiedCheckpointRoot, - finalizedCheckpointRoot, + justifiedCheckpoint, + finalizedCheckpoint, bestJustifiedCheckpoint, } = step.checks; @@ -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}` ); + } } } }, @@ -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", } ); } @@ -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 @@ -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; }; }; From 59e3035ad39b730bebd3408e769d9c78786801fd Mon Sep 17 00:00:00 2001 From: Tuyen Nguyen Date: Tue, 28 Sep 2021 10:16:30 +0700 Subject: [PATCH 4/9] Spec test v1.1.0 --- packages/spec-test-runner/test/specTestVersioning.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/spec-test-runner/test/specTestVersioning.ts b/packages/spec-test-runner/test/specTestVersioning.ts index 9cee15a61a65..156bcb3eadac 100644 --- a/packages/spec-test-runner/test/specTestVersioning.ts +++ b/packages/spec-test-runner/test/specTestVersioning.ts @@ -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"); From 26191ac8cbf79b84dfe5ea28b3a14b121b307c04 Mon Sep 17 00:00:00 2001 From: Tuyen Nguyen Date: Tue, 28 Sep 2021 14:14:42 +0700 Subject: [PATCH 5/9] Fix payload extraData type --- packages/types/src/merge/sszTypes.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/types/src/merge/sszTypes.ts b/packages/types/src/merge/sszTypes.ts index e500e9f8221c..1a7d3a3a243a 100644 --- a/packages/types/src/merge/sszTypes.ts +++ b/packages/types/src/merge/sszTypes.ts @@ -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<{ @@ -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, From 162c0aeda59eeba4af47b5b86a3c7be4f6a4bcab Mon Sep 17 00:00:00 2001 From: Tuyen Nguyen Date: Tue, 28 Sep 2021 14:18:15 +0700 Subject: [PATCH 6/9] Enable merge spec tests in github workflow --- .github/workflows/test-spec.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-spec.yml b/.github/workflows/test-spec.yml index f06e8e2a65f2..dc3b08f04014 100644 --- a/.github/workflows/test-spec.yml +++ b/.github/workflows/test-spec.yml @@ -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 From dabb97ad6ee4aa90af4aafd8ded6bbf56e81dca3 Mon Sep 17 00:00:00 2001 From: Tuyen Nguyen Date: Tue, 28 Sep 2021 17:05:21 +0700 Subject: [PATCH 7/9] Fix test-spec.yml format --- .github/workflows/test-spec.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-spec.yml b/.github/workflows/test-spec.yml index dc3b08f04014..fdc7571b39cb 100644 --- a/.github/workflows/test-spec.yml +++ b/.github/workflows/test-spec.yml @@ -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 From e503eba199efd45c4b51fe24522fbb1834486d78 Mon Sep 17 00:00:00 2001 From: Tuyen Nguyen Date: Wed, 29 Sep 2021 09:14:12 +0700 Subject: [PATCH 8/9] Add altair merkle test --- packages/spec-test-runner/package.json | 1 + .../test/spec/altair/merkle.test.ts | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 packages/spec-test-runner/test/spec/altair/merkle.test.ts diff --git a/packages/spec-test-runner/package.json b/packages/spec-test-runner/package.json index 90caf81a2513..4df9d79b1ab2 100644 --- a/packages/spec-test-runner/package.json +++ b/packages/spec-test-runner/package.json @@ -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": [ diff --git a/packages/spec-test-runner/test/spec/altair/merkle.test.ts b/packages/spec-test-runner/test/spec/altair/merkle.test.ts new file mode 100644 index 000000000000..b28ed8a96c8b --- /dev/null +++ b/packages/spec-test-runner/test/spec/altair/merkle.test.ts @@ -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( + `${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; + 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[]; +} From e09b6ecdd200bd0520e7be5f2a46e5e0c6f40a8c Mon Sep 17 00:00:00 2001 From: Tuyen Nguyen Date: Wed, 29 Sep 2021 09:49:08 +0700 Subject: [PATCH 9/9] Add merge genesis spec test --- packages/beacon-state-transition/src/util/genesis.ts | 2 ++ packages/spec-test-runner/test/spec/merge/genesis.test.ts | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 packages/spec-test-runner/test/spec/merge/genesis.test.ts diff --git a/packages/beacon-state-transition/src/util/genesis.ts b/packages/beacon-state-transition/src/util/genesis.ts index 7ca1a7f3d6a7..f1d135cd7669 100644 --- a/packages/beacon-state-transition/src/util/genesis.ts +++ b/packages/beacon-state-transition/src/util/genesis.ts @@ -222,6 +222,8 @@ export function initializeBeaconStateFromEth1( if (GENESIS_SLOT >= config.MERGE_FORK_EPOCH) { const stateMerge = state as TreeBacked; + // 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; diff --git a/packages/spec-test-runner/test/spec/merge/genesis.test.ts b/packages/spec-test-runner/test/spec/merge/genesis.test.ts new file mode 100644 index 000000000000..be93ce1b0065 --- /dev/null +++ b/packages/spec-test-runner/test/spec/merge/genesis.test.ts @@ -0,0 +1,4 @@ +import {ForkName} from "@chainsafe/lodestar-params"; +import {genesis} from "../allForks/genesis"; + +genesis(ForkName.merge);