update to latest LC test format (#3879)
The EF test format for the LC sync protocol is modified to verify checks after each step: https://github.com/ethereum/consensus-specs/pull/2938 - The test runner is updated accordingly.
This commit is contained in:
parent
c3f9844de1
commit
3bc42994e4
|
@ -422,16 +422,14 @@ ConsensusSpecPreset-mainnet
|
|||
+ bellatrix_fork_random_3 OK
|
||||
+ bellatrix_fork_random_low_balances OK
|
||||
+ bellatrix_fork_random_misc_balances OK
|
||||
+ finality_root_merkle_proof OK
|
||||
+ fork_base_state OK
|
||||
+ fork_many_next_epoch OK
|
||||
+ fork_next_epoch OK
|
||||
+ fork_next_epoch_with_block OK
|
||||
+ fork_random_low_balances OK
|
||||
+ fork_random_misc_balances OK
|
||||
+ next_sync_committee_merkle_proof OK
|
||||
```
|
||||
OK: 421/428 Fail: 0/428 Skip: 7/428
|
||||
OK: 419/426 Fail: 0/426 Skip: 7/426
|
||||
## Attestation
|
||||
```diff
|
||||
+ [Invalid] EF - Altair - Operations - Attestation - after_epoch_slots OK
|
||||
|
@ -852,17 +850,7 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
|
|||
+ Testing VoluntaryExit OK
|
||||
```
|
||||
OK: 35/35 Fail: 0/35 Skip: 0/35
|
||||
## EF - Altair - Sync protocol - Light client [Preset: mainnet]
|
||||
```diff
|
||||
All tests Skip
|
||||
```
|
||||
OK: 0/1 Fail: 0/1 Skip: 1/1
|
||||
## EF - Altair - Sync protocol - Update ranking [Preset: mainnet]
|
||||
```diff
|
||||
All tests Skip
|
||||
```
|
||||
OK: 0/1 Fail: 0/1 Skip: 1/1
|
||||
## EF - Altair - Unittests - Sync protocol [Preset: mainnet]
|
||||
## EF - Altair - Unittests - Light client - Sync protocol [Preset: mainnet]
|
||||
```diff
|
||||
+ process_light_client_update_finality_updated OK
|
||||
+ process_light_client_update_timeout OK
|
||||
|
@ -1261,4 +1249,4 @@ OK: 44/44 Fail: 0/44 Skip: 0/44
|
|||
OK: 27/27 Fail: 0/27 Skip: 0/27
|
||||
|
||||
---TOTAL---
|
||||
OK: 1074/1083 Fail: 0/1083 Skip: 9/1083
|
||||
OK: 1072/1079 Fail: 0/1079 Skip: 7/1079
|
||||
|
|
|
@ -471,7 +471,6 @@ ConsensusSpecPreset-minimal
|
|||
+ bellatrix_fork_random_large_validator_set OK
|
||||
+ bellatrix_fork_random_low_balances OK
|
||||
+ bellatrix_fork_random_misc_balances OK
|
||||
+ finality_root_merkle_proof OK
|
||||
+ fork_base_state OK
|
||||
+ fork_many_next_epoch OK
|
||||
+ fork_next_epoch OK
|
||||
|
@ -479,9 +478,8 @@ ConsensusSpecPreset-minimal
|
|||
+ fork_random_large_validator_set OK
|
||||
+ fork_random_low_balances OK
|
||||
+ fork_random_misc_balances OK
|
||||
+ next_sync_committee_merkle_proof OK
|
||||
```
|
||||
OK: 471/478 Fail: 0/478 Skip: 7/478
|
||||
OK: 469/476 Fail: 0/476 Skip: 7/476
|
||||
## Attestation
|
||||
```diff
|
||||
+ [Invalid] EF - Altair - Operations - Attestation - after_epoch_slots OK
|
||||
|
@ -917,17 +915,7 @@ OK: 5/5 Fail: 0/5 Skip: 0/5
|
|||
+ Testing VoluntaryExit OK
|
||||
```
|
||||
OK: 35/35 Fail: 0/35 Skip: 0/35
|
||||
## EF - Altair - Sync protocol - Light client [Preset: minimal]
|
||||
```diff
|
||||
All tests Skip
|
||||
```
|
||||
OK: 0/1 Fail: 0/1 Skip: 1/1
|
||||
## EF - Altair - Sync protocol - Update ranking [Preset: minimal]
|
||||
```diff
|
||||
All tests Skip
|
||||
```
|
||||
OK: 0/1 Fail: 0/1 Skip: 1/1
|
||||
## EF - Altair - Unittests - Sync protocol [Preset: minimal]
|
||||
## EF - Altair - Unittests - Light client - Sync protocol [Preset: minimal]
|
||||
```diff
|
||||
+ process_light_client_update_finality_updated OK
|
||||
+ process_light_client_update_timeout OK
|
||||
|
@ -1352,4 +1340,4 @@ OK: 48/48 Fail: 0/48 Skip: 0/48
|
|||
OK: 30/30 Fail: 0/30 Skip: 0/30
|
||||
|
||||
---TOTAL---
|
||||
OK: 1157/1166 Fail: 0/1166 Skip: 9/1166
|
||||
OK: 1155/1162 Fail: 0/1162 Skip: 7/1162
|
||||
|
|
|
@ -172,7 +172,7 @@ proc tryForceUpdate(
|
|||
|
||||
if store[].isSome:
|
||||
doAssert self.finalizationMode == LightClientFinalizationMode.Optimistic
|
||||
case store[].get.try_light_client_store_force_update(wallSlot)
|
||||
case store[].get.process_light_client_store_force_update(wallSlot)
|
||||
of NoUpdate:
|
||||
discard
|
||||
of DidUpdateWithoutSupermajority:
|
||||
|
|
|
@ -180,14 +180,14 @@ func apply_light_client_update(
|
|||
didProgress = true
|
||||
didProgress
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/vFuture/specs/altair/sync-protocol.md#try_light_client_store_force_update
|
||||
# https://github.com/ethereum/consensus-specs/blob/vFuture/specs/altair/sync-protocol.md#process_light_client_store_force_update
|
||||
type
|
||||
ForceUpdateResult* = enum
|
||||
NoUpdate,
|
||||
DidUpdateWithoutSupermajority,
|
||||
DidUpdateWithoutFinality
|
||||
|
||||
func try_light_client_store_force_update*(
|
||||
func process_light_client_store_force_update*(
|
||||
store: var LightClientStore,
|
||||
current_slot: Slot): ForceUpdateResult {.discardable.} =
|
||||
var res = NoUpdate
|
||||
|
|
|
@ -9,13 +9,10 @@
|
|||
|
||||
import
|
||||
./test_fixture_fork,
|
||||
./test_fixture_merkle_single_proof,
|
||||
./test_fixture_light_client_sync_protocol,
|
||||
./test_fixture_operations,
|
||||
./test_fixture_sanity_blocks,
|
||||
./test_fixture_sanity_slots,
|
||||
./test_fixture_ssz_consensus_objects,
|
||||
./test_fixture_state_transition_epoch,
|
||||
./test_fixture_sync_protocol_light_client_sync,
|
||||
./test_fixture_sync_protocol_update_ranking,
|
||||
./test_fixture_sync_protocol,
|
||||
./test_fixture_transition
|
||||
|
|
|
@ -153,7 +153,7 @@ func initialize_light_client_store(state: auto): LightClientStore =
|
|||
current_max_active_participants: 0,
|
||||
)
|
||||
|
||||
suite "EF - Altair - Unittests - Sync protocol" & preset():
|
||||
suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
let
|
||||
cfg = block:
|
||||
var res = defaultRuntimeConfig
|
||||
|
@ -161,7 +161,7 @@ suite "EF - Altair - Unittests - Sync protocol" & preset():
|
|||
res
|
||||
genesisState = newClone(initGenesisState(cfg = cfg))
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/vFuture/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L25-L67
|
||||
# https://github.com/ethereum/consensus-specs/blob/vFuture/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py#L25-L67
|
||||
test "test_process_light_client_update_not_timeout":
|
||||
let forked = assignClone(genesisState[])
|
||||
template state(): auto = forked[].altairData.data
|
||||
|
@ -207,7 +207,7 @@ suite "EF - Altair - Unittests - Sync protocol" & preset():
|
|||
store.optimistic_header == update.attested_header
|
||||
store.current_max_active_participants > 0
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/vFuture/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L70-L116
|
||||
# https://github.com/ethereum/consensus-specs/blob/vFuture/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py#L70-L116
|
||||
test "test_process_light_client_update_at_period_boundary":
|
||||
var forked = assignClone(genesisState[])
|
||||
template state(): auto = forked[].altairData.data
|
||||
|
@ -260,7 +260,7 @@ suite "EF - Altair - Unittests - Sync protocol" & preset():
|
|||
store.optimistic_header == update.attested_header
|
||||
store.current_max_active_participants > 0
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/vFuture/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L119-L166
|
||||
# https://github.com/ethereum/consensus-specs/blob/vFuture/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py#L119-L166
|
||||
test "process_light_client_update_timeout":
|
||||
let forked = assignClone(genesisState[])
|
||||
template state(): auto = forked[].altairData.data
|
||||
|
@ -316,7 +316,7 @@ suite "EF - Altair - Unittests - Sync protocol" & preset():
|
|||
store.optimistic_header == update.attested_header
|
||||
store.current_max_active_participants > 0
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/vFuture/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py#L169-L223
|
||||
# https://github.com/ethereum/consensus-specs/blob/vFuture/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py#L169-L223
|
||||
test "process_light_client_update_finality_updated":
|
||||
let forked = assignClone(genesisState[])
|
||||
template state(): auto = forked[].altairData.data
|
|
@ -1,63 +0,0 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2021-2022 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
import
|
||||
# Standard library
|
||||
std/[os, sequtils, streams],
|
||||
# Status libraries
|
||||
stew/bitops2,
|
||||
# Third-party
|
||||
yaml,
|
||||
# Beacon chain internals
|
||||
../../../beacon_chain/spec/datatypes/altair,
|
||||
../../../beacon_chain/spec/helpers,
|
||||
# Test utilities
|
||||
../../testutil,
|
||||
../fixtures_utils
|
||||
|
||||
const TestsDir =
|
||||
SszTestsDir/const_preset/"altair"/"merkle"/"single_proof"/"pyspec_tests"
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
let testDir = TestsDir / identifier
|
||||
|
||||
proc `testImpl _ merkle_single_proof _ identifier`() =
|
||||
test identifier:
|
||||
type
|
||||
TestProof = object
|
||||
leaf: string
|
||||
leaf_index: GeneralizedIndex
|
||||
branch: seq[string]
|
||||
|
||||
let
|
||||
proof = block:
|
||||
let s = openFileStream(testDir/"proof.yaml")
|
||||
defer: close(s)
|
||||
var res: TestProof
|
||||
yaml.load(s, res)
|
||||
res
|
||||
|
||||
state = newClone(parseTest(testDir/"state.ssz_snappy", SSZ,
|
||||
altair.BeaconState))
|
||||
|
||||
var computedProof = newSeq[Eth2Digest](log2trunc(proof.leaf_index))
|
||||
build_proof(state[], proof.leaf_index, computedProof).get
|
||||
|
||||
check:
|
||||
computedProof == proof.branch.mapIt(Eth2Digest.fromHex(it))
|
||||
is_valid_merkle_branch(Eth2Digest.fromHex(proof.leaf), computedProof,
|
||||
log2trunc(proof.leaf_index),
|
||||
get_subtree_index(proof.leaf_index),
|
||||
hash_tree_root(state[]))
|
||||
|
||||
`testImpl _ merkle_single_proof _ identifier`()
|
||||
|
||||
suite "EF - Altair - Merkle - Single proof" & preset():
|
||||
for kind, path in walkDir(TestsDir, relative = true, checkDir = true):
|
||||
runTest(path)
|
|
@ -1,144 +0,0 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
# This implements the pre-release proposal of the libp2p based light client sync
|
||||
# protocol. See https://github.com/ethereum/consensus-specs/pull/2802
|
||||
|
||||
import
|
||||
# Standard library
|
||||
std/[json, os, streams],
|
||||
# Status libraries
|
||||
stew/bitops2,
|
||||
# Third-party
|
||||
yaml,
|
||||
# Beacon chain internals
|
||||
../../../beacon_chain/spec/light_client_sync,
|
||||
../../../beacon_chain/spec/datatypes/altair,
|
||||
# Test utilities
|
||||
../../testutil,
|
||||
../fixtures_utils
|
||||
|
||||
const TestsDir =
|
||||
SszTestsDir/const_preset/"altair"/"sync_protocol"/"light_client_sync"/"pyspec_tests"
|
||||
|
||||
type
|
||||
TestMeta = object
|
||||
genesis_validators_root: string
|
||||
trusted_block_root: string
|
||||
|
||||
TestStepKind {.pure.} = enum
|
||||
ForceUpdate
|
||||
ProcessUpdate
|
||||
|
||||
TestStep = object
|
||||
case kind: TestStepKind
|
||||
of TestStepKind.ForceUpdate:
|
||||
discard
|
||||
of TestStepKind.ProcessUpdate:
|
||||
update: altair.LightClientUpdate
|
||||
current_slot: Slot
|
||||
|
||||
proc loadSteps(path: string): seq[TestStep] =
|
||||
let stepsYAML = readFile(path/"steps.yaml")
|
||||
let steps = yaml.loadToJson(stepsYAML)
|
||||
|
||||
result = @[]
|
||||
for step in steps[0]:
|
||||
if step.hasKey"force_update":
|
||||
let s = step["force_update"]
|
||||
result.add TestStep(kind: TestStepKind.ForceUpdate,
|
||||
current_slot: s["current_slot"].getInt().Slot)
|
||||
elif step.hasKey"process_update":
|
||||
let
|
||||
s = step["process_update"]
|
||||
filename = s["update"].getStr()
|
||||
update = parseTest(path/filename & ".ssz_snappy", SSZ,
|
||||
altair.LightClientUpdate)
|
||||
result.add TestStep(kind: TestStepKind.ProcessUpdate,
|
||||
update: update,
|
||||
current_slot: s["current_slot"].getInt().Slot)
|
||||
else:
|
||||
doAssert false, "Unreachable: " & $step
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
let testDir = TestsDir / identifier
|
||||
|
||||
proc `testImpl _ sync_protocol_light_client_sync _ identifier`() =
|
||||
test identifier:
|
||||
let
|
||||
meta = block:
|
||||
var s = openFileStream(testDir/"meta.yaml")
|
||||
defer: close(s)
|
||||
var res: TestMeta
|
||||
yaml.load(s, res)
|
||||
res
|
||||
genesis_validators_root =
|
||||
Eth2Digest.fromHex(meta.genesis_validators_root)
|
||||
trusted_block_root =
|
||||
Eth2Digest.fromHex(meta.trusted_block_root)
|
||||
|
||||
bootstrap = parseTest(testDir/"bootstrap.ssz_snappy", SSZ,
|
||||
altair.LightClientBootstrap)
|
||||
steps = loadSteps(testDir)
|
||||
|
||||
expected_finalized_header =
|
||||
parseTest(testDir/"expected_finalized_header.ssz_snappy", SSZ,
|
||||
BeaconBlockHeader)
|
||||
expected_optimistic_header =
|
||||
parseTest(testDir/"expected_optimistic_header.ssz_snappy", SSZ,
|
||||
BeaconBlockHeader)
|
||||
|
||||
var cfg = defaultRuntimeConfig
|
||||
cfg.ALTAIR_FORK_EPOCH = GENESIS_EPOCH
|
||||
|
||||
var store =
|
||||
initialize_light_client_store(trusted_block_root, bootstrap).get
|
||||
|
||||
for step in steps:
|
||||
case step.kind
|
||||
of TestStepKind.ForceUpdate:
|
||||
try_light_client_store_force_update(
|
||||
store, step.current_slot)
|
||||
of TestStepKind.ProcessUpdate:
|
||||
let res = process_light_client_update(
|
||||
store, step.update, step.current_slot,
|
||||
cfg, genesis_validators_root)
|
||||
check res.isOk
|
||||
|
||||
check:
|
||||
store.finalized_header == expected_finalized_header
|
||||
store.optimistic_header == expected_optimistic_header
|
||||
|
||||
`testImpl _ sync_protocol_light_client_sync _ identifier`()
|
||||
|
||||
suite "EF - Altair - Sync protocol - Light client" & preset():
|
||||
try:
|
||||
for kind, path in walkDir(TestsDir, relative = true, checkDir = true):
|
||||
runTest(path)
|
||||
except OSError:
|
||||
# These tests are for the pre-release proposal of the libp2p based light
|
||||
# client sync protocol. Corresponding test vectors need manual integration.
|
||||
# https://github.com/ethereum/consensus-specs/pull/2802
|
||||
#
|
||||
# To locally integrate the test vectors, clone the pre-release spec repo
|
||||
# at latest commit of https://github.com/ethereum/consensus-specs/pull/2802
|
||||
# and place it next to the `nimbus-eth2` repo, so that `nimbus-eth2` and
|
||||
# `consensus-specs` are in the same directory.
|
||||
#
|
||||
# To generate the additional test vectors, from `consensus-specs`:
|
||||
# $ rm -rf ../consensus-spec-tests && \
|
||||
# doctoc specs && make lint && make gen_sync_protocol
|
||||
#
|
||||
# To integrate the additional test vectors into `nimbus-eth2`, first run
|
||||
# `make test` from `nimbus-eth2` to ensure that the regular test vectors
|
||||
# have been downloaded and extracted, then proceed from `nimbus-eth2` with:
|
||||
# $ rsync -r ../consensus-spec-tests/tests/ \
|
||||
# ../nimbus-eth2/vendor/nim-eth2-scenarios/tests-v1.2.0-rc.1/
|
||||
test "All tests":
|
||||
skip()
|
|
@ -1,88 +0,0 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
# This implements the pre-release proposal of the libp2p based light client sync
|
||||
# protocol. See https://github.com/ethereum/consensus-specs/pull/2802
|
||||
|
||||
import
|
||||
# Standard library
|
||||
std/[algorithm, os, streams],
|
||||
# Status libraries
|
||||
stew/base10,
|
||||
# Third-party
|
||||
yaml,
|
||||
# Beacon chain internals
|
||||
../../../beacon_chain/spec/helpers,
|
||||
../../../beacon_chain/spec/datatypes/altair,
|
||||
# Test utilities
|
||||
../../testutil,
|
||||
../fixtures_utils
|
||||
|
||||
const TestsDir =
|
||||
SszTestsDir/const_preset/"altair"/"sync_protocol"/"update_ranking"/"pyspec_tests"
|
||||
|
||||
type
|
||||
TestMeta = object
|
||||
updates_count: uint64
|
||||
|
||||
proc runTest(identifier: string) =
|
||||
let testDir = TestsDir / identifier
|
||||
|
||||
proc `testImpl _ sync_protocol_update_ranking _ identifier`() =
|
||||
test identifier:
|
||||
let meta = block:
|
||||
var s = openFileStream(testDir/"meta.yaml")
|
||||
defer: close(s)
|
||||
var res: TestMeta
|
||||
yaml.load(s, res)
|
||||
res
|
||||
|
||||
var updates = newSeqOfCap[altair.LightClientUpdate](meta.updates_count)
|
||||
for i in 0 ..< meta.updates_count:
|
||||
updates.add parseTest(
|
||||
testDir/"updates_" & Base10.toString(i) & ".ssz_snappy",
|
||||
SSZ, altair.LightClientUpdate)
|
||||
|
||||
proc cmp(a, b: altair.LightClientUpdate): int =
|
||||
if a.is_better_update(b):
|
||||
check: not b.is_better_update(a)
|
||||
-1
|
||||
elif b.is_better_update(a):
|
||||
1
|
||||
else:
|
||||
0
|
||||
check: updates.isSorted(cmp)
|
||||
|
||||
`testImpl _ sync_protocol_update_ranking _ identifier`()
|
||||
|
||||
suite "EF - Altair - Sync protocol - Update ranking" & preset():
|
||||
try:
|
||||
for kind, path in walkDir(TestsDir, relative = true, checkDir = true):
|
||||
runTest(path)
|
||||
except OSError:
|
||||
# These tests are for the pre-release proposal of the libp2p based light
|
||||
# client sync protocol. Corresponding test vectors need manual integration.
|
||||
# https://github.com/ethereum/consensus-specs/pull/2802
|
||||
#
|
||||
# To locally integrate the test vectors, clone the pre-release spec repo
|
||||
# at latest commit of https://github.com/ethereum/consensus-specs/pull/2802
|
||||
# and place it next to the `nimbus-eth2` repo, so that `nimbus-eth2` and
|
||||
# `consensus-specs` are in the same directory.
|
||||
#
|
||||
# To generate the additional test vectors, from `consensus-specs`:
|
||||
# $ rm -rf ../consensus-spec-tests && \
|
||||
# doctoc specs && make lint && make gen_sync_protocol
|
||||
#
|
||||
# To integrate the additional test vectors into `nimbus-eth2`, first run
|
||||
# `make test` from `nimbus-eth2` to ensure that the regular test vectors
|
||||
# have been downloaded and extracted, then proceed from `nimbus-eth2` with:
|
||||
# $ rsync -r ../consensus-spec-tests/tests/ \
|
||||
# ../nimbus-eth2/vendor/nim-eth2-scenarios/tests-v1.2.0-rc.1/
|
||||
test "All tests":
|
||||
skip()
|
|
@ -14,6 +14,9 @@ import
|
|||
./phase0/all_phase0_fixtures,
|
||||
./altair/all_altair_fixtures,
|
||||
./bellatrix/all_bellatrix_fixtures,
|
||||
./test_fixture_fork_choice
|
||||
./test_fixture_fork_choice,
|
||||
./test_fixture_light_client_single_merkle_proof,
|
||||
./test_fixture_light_client_sync,
|
||||
./test_fixture_light_client_update_ranking
|
||||
|
||||
summarizeLongTests("ConsensusSpecPreset")
|
||||
|
|
|
@ -9,6 +9,7 @@ import
|
|||
# Standard library
|
||||
std/[os, strutils, typetraits],
|
||||
# Internals
|
||||
../../beacon_chain/spec/datatypes/[phase0, altair, bellatrix],
|
||||
../../beacon_chain/spec/[
|
||||
eth2_merkleization, eth2_ssz_serialization, forks],
|
||||
# Status libs,
|
||||
|
@ -112,3 +113,26 @@ proc parseTest*(path: string, Format: typedesc[SSZ], T: typedesc): T =
|
|||
stderr.write $Format & " load issue for file \"", path, "\"\n"
|
||||
stderr.write err.formatMsg(path), "\n"
|
||||
quit 1
|
||||
|
||||
proc loadForkedState*(
|
||||
path: string, fork: BeaconStateFork): ref ForkedHashedBeaconState =
|
||||
# TODO stack usage. newClone and assignClone do not seem to
|
||||
# prevent temporaries created by case objects
|
||||
let forkedState = new ForkedHashedBeaconState
|
||||
case fork
|
||||
of BeaconStateFork.Bellatrix:
|
||||
let state = newClone(parseTest(path, SSZ, bellatrix.BeaconState))
|
||||
forkedState.kind = BeaconStateFork.Bellatrix
|
||||
forkedState.bellatrixData.data = state[]
|
||||
forkedState.bellatrixData.root = hash_tree_root(state[])
|
||||
of BeaconStateFork.Altair:
|
||||
let state = newClone(parseTest(path, SSZ, altair.BeaconState))
|
||||
forkedState.kind = BeaconStateFork.Altair
|
||||
forkedState.altairData.data = state[]
|
||||
forkedState.altairData.root = hash_tree_root(state[])
|
||||
of BeaconStateFork.Phase0:
|
||||
let state = newClone(parseTest(path, SSZ, phase0.BeaconState))
|
||||
forkedState.kind = BeaconStateFork.Phase0
|
||||
forkedState.phase0Data.data = state[]
|
||||
forkedState.phase0Data.root = hash_tree_root(state[])
|
||||
forkedState
|
||||
|
|
|
@ -62,32 +62,14 @@ proc initialLoad(
|
|||
path: string, db: BeaconChainDB,
|
||||
StateType, BlockType: typedesc
|
||||
): tuple[dag: ChainDAGRef, fkChoice: ref ForkChoice] =
|
||||
let state = newClone(parseTest(
|
||||
path/"anchor_state.ssz_snappy",
|
||||
SSZ, StateType
|
||||
))
|
||||
let
|
||||
forkedState = loadForkedState(
|
||||
path/"anchor_state.ssz_snappy",
|
||||
StateType.toFork)
|
||||
|
||||
# TODO stack usage. newClone and assignClone do not seem to
|
||||
# prevent temporaries created by case objects
|
||||
let forkedState = new ForkedHashedBeaconState
|
||||
when StateType is bellatrix.BeaconState:
|
||||
forkedState.kind = BeaconStateFork.Bellatrix
|
||||
forkedState.bellatrixData.data = state[]
|
||||
forkedState.bellatrixData.root = hash_tree_root(state[])
|
||||
elif StateType is altair.BeaconState:
|
||||
forkedState.kind = BeaconStateFork.Altair
|
||||
forkedState.altairData.data = state[]
|
||||
forkedState.altairData.root = hash_tree_root(state[])
|
||||
elif StateType is phase0.BeaconState:
|
||||
forkedState.kind = BeaconStateFork.Phase0
|
||||
forkedState.phase0Data.data = state[]
|
||||
forkedState.phase0Data.root = hash_tree_root(state[])
|
||||
else: {.error: "Unknown state fork: " & name(StateType).}
|
||||
|
||||
let blck = parseTest(
|
||||
path/"anchor_block.ssz_snappy",
|
||||
SSZ, BlockType
|
||||
)
|
||||
blck = parseTest(
|
||||
path/"anchor_block.ssz_snappy",
|
||||
SSZ, BlockType)
|
||||
|
||||
when BlockType is bellatrix.BeaconBlock:
|
||||
let signedBlock = ForkedSignedBeaconBlock.init(bellatrix.SignedBeaconBlock(
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2021-2022 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
import
|
||||
# Standard library
|
||||
std/[os, sequtils, streams],
|
||||
# Status libraries
|
||||
stew/bitops2,
|
||||
# Third-party
|
||||
yaml,
|
||||
# Beacon chain internals
|
||||
../../../beacon_chain/spec/datatypes/altair,
|
||||
../../../beacon_chain/spec/helpers,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils
|
||||
|
||||
proc runTest(path: string, fork: BeaconStateFork) =
|
||||
test "Light client - Single merkle proof - " & path.relativePath(SszTestsDir):
|
||||
type
|
||||
TestProof = object
|
||||
leaf: string
|
||||
leaf_index: GeneralizedIndex
|
||||
branch: seq[string]
|
||||
|
||||
let
|
||||
proof = block:
|
||||
let s = openFileStream(path/"proof.yaml")
|
||||
defer: close(s)
|
||||
var res: TestProof
|
||||
yaml.load(s, res)
|
||||
res
|
||||
|
||||
state = loadForkedState(path/"state.ssz_snappy", fork)
|
||||
|
||||
withState(state[]):
|
||||
var computedProof = newSeq[Eth2Digest](log2trunc(proof.leaf_index))
|
||||
build_proof(state.data, proof.leaf_index, computedProof).get
|
||||
|
||||
check:
|
||||
computedProof == proof.branch.mapIt(Eth2Digest.fromHex(it))
|
||||
is_valid_merkle_branch(
|
||||
Eth2Digest.fromHex(proof.leaf),
|
||||
computedProof,
|
||||
log2trunc(proof.leaf_index),
|
||||
get_subtree_index(proof.leaf_index),
|
||||
state.root)
|
||||
|
||||
suite "EF - Light client - Single merkle proof" & preset():
|
||||
const presetPath = SszTestsDir/const_preset
|
||||
for kind, path in walkDir(presetPath, relative = true, checkDir = true):
|
||||
let testsPath = presetPath/path/"light_client"/"single_merkle_proof"
|
||||
if kind != pcDir or not dirExists(testsPath):
|
||||
continue
|
||||
let
|
||||
fork = forkForPathComponent(path).valueOr:
|
||||
raiseAssert "Unknown test fork: " & testsPath
|
||||
basePath = testsPath/"pyspec_tests"
|
||||
for kind, path in walkDir(basePath, relative = true, checkDir = true):
|
||||
runTest(basePath/path, fork)
|
|
@ -0,0 +1,151 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
# This implements the pre-release proposal of the libp2p based light client sync
|
||||
# protocol. See https://github.com/ethereum/consensus-specs/pull/2802
|
||||
|
||||
# These tests are for the pre-release proposal of the libp2p based light
|
||||
# client sync protocol. Corresponding test vectors need manual integration.
|
||||
# https://github.com/ethereum/consensus-specs/pull/2802
|
||||
#
|
||||
# To locally integrate the test vectors, clone the pre-release spec repo
|
||||
# at latest commit of https://github.com/ethereum/consensus-specs/pull/2802
|
||||
# and place it next to the `nimbus-eth2` repo, so that `nimbus-eth2` and
|
||||
# `consensus-specs` are in the same directory.
|
||||
#
|
||||
# To generate the additional test vectors, from `consensus-specs`:
|
||||
# $ rm -rf ../consensus-spec-tests && \
|
||||
# doctoc specs && make lint && make gen_light_client
|
||||
#
|
||||
# To integrate the additional test vectors into `nimbus-eth2`, first run
|
||||
# `make test` from `nimbus-eth2` to ensure that the regular test vectors
|
||||
# have been downloaded and extracted, then proceed from `nimbus-eth2` with:
|
||||
# $ rsync -r ../consensus-spec-tests/tests/ \
|
||||
# ../nimbus-eth2/vendor/nim-eth2-scenarios/tests-v1.2.0-rc.1/
|
||||
|
||||
import
|
||||
# Standard library
|
||||
std/[json, os, streams],
|
||||
# Status libraries
|
||||
stew/bitops2,
|
||||
# Third-party
|
||||
yaml,
|
||||
# Beacon chain internals
|
||||
../../../beacon_chain/spec/light_client_sync,
|
||||
../../../beacon_chain/spec/datatypes/altair,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils
|
||||
|
||||
type
|
||||
TestMeta = object
|
||||
genesis_validators_root: string
|
||||
trusted_block_root: string
|
||||
|
||||
TestChecks = object
|
||||
finalized_slot: Slot
|
||||
finalized_root: Eth2Digest
|
||||
optimistic_slot: Slot
|
||||
optimistic_root: Eth2Digest
|
||||
|
||||
TestStepKind {.pure.} = enum
|
||||
ForceUpdate
|
||||
ProcessUpdate
|
||||
|
||||
TestStep = object
|
||||
case kind: TestStepKind
|
||||
of TestStepKind.ForceUpdate:
|
||||
discard
|
||||
of TestStepKind.ProcessUpdate:
|
||||
update: altair.LightClientUpdate
|
||||
current_slot: Slot
|
||||
checks: TestChecks
|
||||
|
||||
proc loadSteps(path: string): seq[TestStep] =
|
||||
let stepsYAML = readFile(path/"steps.yaml")
|
||||
let steps = yaml.loadToJson(stepsYAML)
|
||||
|
||||
result = @[]
|
||||
for step in steps[0]:
|
||||
func getChecks(c: JsonNode): TestChecks =
|
||||
TestChecks(
|
||||
finalized_slot:
|
||||
c["finalized_header"]["slot"].getInt().Slot,
|
||||
finalized_root:
|
||||
Eth2Digest.fromHex(c["finalized_header"]["root"].getStr()),
|
||||
optimistic_slot:
|
||||
c["optimistic_header"]["slot"].getInt().Slot,
|
||||
optimistic_root:
|
||||
Eth2Digest.fromHex(c["optimistic_header"]["root"].getStr()))
|
||||
|
||||
if step.hasKey"force_update":
|
||||
let s = step["force_update"]
|
||||
result.add TestStep(kind: TestStepKind.ForceUpdate,
|
||||
current_slot: s["current_slot"].getInt().Slot,
|
||||
checks: s["checks"].getChecks())
|
||||
elif step.hasKey"process_update":
|
||||
let
|
||||
s = step["process_update"]
|
||||
filename = s["update"].getStr()
|
||||
update = parseTest(path/filename & ".ssz_snappy", SSZ,
|
||||
altair.LightClientUpdate)
|
||||
result.add TestStep(kind: TestStepKind.ProcessUpdate,
|
||||
update: update,
|
||||
current_slot: s["current_slot"].getInt().Slot,
|
||||
checks: s["checks"].getChecks())
|
||||
else:
|
||||
doAssert false, "Unknown test step: " & $step
|
||||
|
||||
proc runTest(path: string) =
|
||||
test "Light client - Sync - " & path.relativePath(SszTestsDir):
|
||||
let
|
||||
(cfg, unknowns) = readRuntimeConfig(path/"config.yaml")
|
||||
meta = block:
|
||||
var s = openFileStream(path/"meta.yaml")
|
||||
defer: close(s)
|
||||
var res: TestMeta
|
||||
yaml.load(s, res)
|
||||
res
|
||||
genesis_validators_root =
|
||||
Eth2Digest.fromHex(meta.genesis_validators_root)
|
||||
trusted_block_root =
|
||||
Eth2Digest.fromHex(meta.trusted_block_root)
|
||||
|
||||
bootstrap = parseTest(path/"bootstrap.ssz_snappy", SSZ,
|
||||
altair.LightClientBootstrap)
|
||||
steps = loadSteps(path)
|
||||
doAssert unknowns.len == 0, "Unknown config constants: " & $unknowns
|
||||
|
||||
var store =
|
||||
initialize_light_client_store(trusted_block_root, bootstrap).get
|
||||
for step in steps:
|
||||
case step.kind
|
||||
of TestStepKind.ForceUpdate:
|
||||
process_light_client_store_force_update(
|
||||
store, step.current_slot)
|
||||
of TestStepKind.ProcessUpdate:
|
||||
let res = process_light_client_update(
|
||||
store, step.update, step.current_slot,
|
||||
cfg, genesis_validators_root)
|
||||
check res.isOk
|
||||
check:
|
||||
store.finalized_header.slot == step.checks.finalized_slot
|
||||
hash_tree_root(store.finalized_header) == step.checks.finalized_root
|
||||
store.optimistic_header.slot == step.checks.optimistic_slot
|
||||
hash_tree_root(store.optimistic_header) == step.checks.optimistic_root
|
||||
|
||||
suite "EF - Light client - Sync" & preset():
|
||||
const presetPath = SszTestsDir/const_preset
|
||||
for kind, path in walkDir(presetPath, relative = true, checkDir = true):
|
||||
let basePath =
|
||||
presetPath/path/"light_client"/"sync"/"pyspec_tests"
|
||||
if kind != pcDir or not dirExists(basePath):
|
||||
continue
|
||||
for kind, path in walkDir(basePath, relative = true, checkDir = true):
|
||||
runTest(basePath/path)
|
|
@ -0,0 +1,83 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
# This implements the pre-release proposal of the libp2p based light client sync
|
||||
# protocol. See https://github.com/ethereum/consensus-specs/pull/2802
|
||||
|
||||
# These tests are for the pre-release proposal of the libp2p based light
|
||||
# client sync protocol. Corresponding test vectors need manual integration.
|
||||
# https://github.com/ethereum/consensus-specs/pull/2802
|
||||
#
|
||||
# To locally integrate the test vectors, clone the pre-release spec repo
|
||||
# at latest commit of https://github.com/ethereum/consensus-specs/pull/2802
|
||||
# and place it next to the `nimbus-eth2` repo, so that `nimbus-eth2` and
|
||||
# `consensus-specs` are in the same directory.
|
||||
#
|
||||
# To generate the additional test vectors, from `consensus-specs`:
|
||||
# $ rm -rf ../consensus-spec-tests && \
|
||||
# doctoc specs && make lint && make gen_light_client
|
||||
#
|
||||
# To integrate the additional test vectors into `nimbus-eth2`, first run
|
||||
# `make test` from `nimbus-eth2` to ensure that the regular test vectors
|
||||
# have been downloaded and extracted, then proceed from `nimbus-eth2` with:
|
||||
# $ rsync -r ../consensus-spec-tests/tests/ \
|
||||
# ../nimbus-eth2/vendor/nim-eth2-scenarios/tests-v1.2.0-rc.1/
|
||||
|
||||
import
|
||||
# Standard library
|
||||
std/[algorithm, os, streams],
|
||||
# Status libraries
|
||||
stew/base10,
|
||||
# Third-party
|
||||
yaml,
|
||||
# Beacon chain internals
|
||||
../../../beacon_chain/spec/helpers,
|
||||
../../../beacon_chain/spec/datatypes/altair,
|
||||
# Test utilities
|
||||
../testutil,
|
||||
./fixtures_utils
|
||||
|
||||
type
|
||||
TestMeta = object
|
||||
updates_count: uint64
|
||||
|
||||
proc runTest(path: string) =
|
||||
test "Light client - Update ranking - " & path.relativePath(SszTestsDir):
|
||||
let meta = block:
|
||||
var s = openFileStream(path/"meta.yaml")
|
||||
defer: close(s)
|
||||
var res: TestMeta
|
||||
yaml.load(s, res)
|
||||
res
|
||||
|
||||
var updates = newSeqOfCap[altair.LightClientUpdate](meta.updates_count)
|
||||
for i in 0 ..< meta.updates_count:
|
||||
updates.add parseTest(
|
||||
path/"updates_" & Base10.toString(i) & ".ssz_snappy",
|
||||
SSZ, altair.LightClientUpdate)
|
||||
|
||||
proc cmp(a, b: altair.LightClientUpdate): int =
|
||||
if a.is_better_update(b):
|
||||
check: not b.is_better_update(a)
|
||||
-1
|
||||
elif b.is_better_update(a):
|
||||
1
|
||||
else:
|
||||
0
|
||||
check: updates.isSorted(cmp)
|
||||
|
||||
suite "EF - Light client - Update ranking" & preset():
|
||||
const presetPath = SszTestsDir/const_preset
|
||||
for kind, path in walkDir(presetPath, relative = true, checkDir = true):
|
||||
let basePath =
|
||||
presetPath/path/"light_client"/"update_ranking"/"pyspec_tests"
|
||||
if kind != pcDir or not dirExists(basePath):
|
||||
continue
|
||||
for kind, path in walkDir(basePath, relative = true, checkDir = true):
|
||||
runTest(basePath/path)
|
Loading…
Reference in New Issue