Skip to content

Commit 4d659d5

Browse files
authored
use EF consensus spec v1.5.0-beta.2 test vectors (#6909)
1 parent 146e4eb commit 4d659d5

11 files changed

+2345
-82
lines changed

ConsensusSpecPreset-mainnet.md

Lines changed: 801 additions & 10 deletions
Large diffs are not rendered by default.

ConsensusSpecPreset-minimal.md

Lines changed: 923 additions & 11 deletions
Large diffs are not rendered by default.

beacon_chain/spec/datatypes/base.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export
7474
tables, results, endians2, json_serialization, sszTypes, beacon_time, crypto,
7575
digest, presets
7676

77-
const SPEC_VERSION* = "1.5.0-beta.1"
77+
const SPEC_VERSION* = "1.5.0-beta.2"
7878
## Spec version we're aiming to be compatible with, right now
7979

8080
const

beacon_chain/spec/forks.nim

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -631,31 +631,6 @@ template Forky*(
631631
kind: static ConsensusFork): auto =
632632
kind.SignedBeaconBlock
633633

634-
# Workaround method used for tests that involve walking through
635-
# `nim-eth2-scenarios` fork dirs, to be removed once Fulu is
636-
# included in new release.
637-
template withAllButFulu*(
638-
x: typedesc[ConsensusFork], body: untyped): untyped =
639-
static: doAssert ConsensusFork.high == ConsensusFork.Fulu
640-
block:
641-
const consensusFork {.inject, used.} = ConsensusFork.Electra
642-
body
643-
block:
644-
const consensusFork {.inject, used.} = ConsensusFork.Deneb
645-
body
646-
block:
647-
const consensusFork {.inject, used.} = ConsensusFork.Capella
648-
body
649-
block:
650-
const consensusFork {.inject, used.} = ConsensusFork.Bellatrix
651-
body
652-
block:
653-
const consensusFork {.inject, used.} = ConsensusFork.Altair
654-
body
655-
block:
656-
const consensusFork {.inject, used.} = ConsensusFork.Phase0
657-
body
658-
659634
template withAll*(
660635
x: typedesc[ConsensusFork], body: untyped): untyped =
661636
static: doAssert ConsensusFork.high == ConsensusFork.Fulu
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# beacon_chain
2-
# Copyright (c) 2022-2024 Status Research & Development GmbH
2+
# Copyright (c) 2022-2025 Status Research & Development GmbH
33
# Licensed and distributed under either of
44
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
55
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@@ -9,4 +9,6 @@
99
{.used.}
1010

1111
import
12-
./test_fixture_ssz_consensus_objects
12+
./test_fixture_operations,
13+
./test_fixture_ssz_consensus_objects,
14+
./test_fixture_state_transition_epoch
Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
# beacon_chain
2+
# Copyright (c) 2025 Status Research & Development GmbH
3+
# Licensed and distributed under either of
4+
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
5+
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
6+
# at your option. This file may not be copied, modified, or distributed except according to those terms.
7+
8+
{.push raises: [].}
9+
{.used.}
10+
11+
import
12+
# Utilities
13+
chronicles,
14+
unittest2,
15+
# Beacon chain internals
16+
../../../beacon_chain/spec/state_transition_block,
17+
../../../beacon_chain/spec/datatypes/fulu,
18+
# Test utilities
19+
../../testutil,
20+
../fixtures_utils, ../os_ops,
21+
../../helpers/debug_state
22+
23+
from std/sequtils import anyIt, mapIt, toSeq
24+
from std/strutils import contains
25+
from ../../../beacon_chain/spec/beaconstate import
26+
get_base_reward_per_increment, get_state_exit_queue_info,
27+
get_total_active_balance, latest_block_root, process_attestation
28+
29+
const
30+
OpDir = SszTestsDir/const_preset/"fulu"/"operations"
31+
OpAttestationsDir = OpDir/"attestation"
32+
OpAttSlashingDir = OpDir/"attester_slashing"
33+
OpBlockHeaderDir = OpDir/"block_header"
34+
OpBlsToExecutionChangeDir = OpDir/"bls_to_execution_change"
35+
OpConsolidationRequestDir = OpDir/"consolidation_request"
36+
OpDepositRequestDir = OpDir/"deposit_request"
37+
OpDepositsDir = OpDir/"deposit"
38+
OpWithdrawalRequestDir = OpDir/"withdrawal_request"
39+
OpExecutionPayloadDir = OpDir/"execution_payload"
40+
OpProposerSlashingDir = OpDir/"proposer_slashing"
41+
OpSyncAggregateDir = OpDir/"sync_aggregate"
42+
OpVoluntaryExitDir = OpDir/"voluntary_exit"
43+
OpWithdrawalsDir = OpDir/"withdrawals"
44+
45+
baseDescription = "EF - Fulu - Operations - "
46+
47+
48+
const testDirs = toHashSet([
49+
OpAttestationsDir, OpAttSlashingDir, OpBlockHeaderDir,
50+
OpBlsToExecutionChangeDir, OpConsolidationRequestDir, OpDepositRequestDir,
51+
OpDepositsDir, OpWithdrawalRequestDir, OpExecutionPayloadDir,
52+
OpProposerSlashingDir, OpSyncAggregateDir, OpVoluntaryExitDir,
53+
OpWithdrawalsDir])
54+
55+
doAssert toHashSet(
56+
mapIt(toSeq(walkDir(OpDir, relative = false)), it.path)) == testDirs
57+
58+
proc runTest[T, U](
59+
testSuiteDir, suiteName, opName, applyFile: string,
60+
applyProc: U, identifier: string) =
61+
let testDir = testSuiteDir / "pyspec_tests" / identifier
62+
63+
let prefix =
64+
if fileExists(testDir/"post.ssz_snappy"):
65+
"[Valid] "
66+
else:
67+
"[Invalid] "
68+
69+
test prefix & baseDescription & opName & " - " & identifier:
70+
let preState = newClone(
71+
parseTest(testDir/"pre.ssz_snappy", SSZ, fulu.BeaconState))
72+
let done = applyProc(
73+
preState[], parseTest(testDir/(applyFile & ".ssz_snappy"), SSZ, T))
74+
75+
if fileExists(testDir/"post.ssz_snappy"):
76+
let postState =
77+
newClone(parseTest(
78+
testDir/"post.ssz_snappy", SSZ, fulu.BeaconState))
79+
80+
reportDiff(preState, postState)
81+
check:
82+
done.isOk()
83+
preState[].hash_tree_root() == postState[].hash_tree_root()
84+
else:
85+
check: done.isErr() # No post state = processing should fail
86+
87+
suite baseDescription & "Attestation " & preset():
88+
proc applyAttestation(
89+
preState: var fulu.BeaconState, attestation: electra.Attestation):
90+
Result[void, cstring] =
91+
var cache: StateCache
92+
let
93+
total_active_balance = get_total_active_balance(preState, cache)
94+
base_reward_per_increment =
95+
get_base_reward_per_increment(total_active_balance)
96+
97+
# This returns the proposer reward for including the attestation, which
98+
# isn't tested here.
99+
discard ? process_attestation(
100+
preState, attestation, {strictVerification}, base_reward_per_increment, cache)
101+
ok()
102+
103+
for path in walkTests(OpAttestationsDir):
104+
runTest[electra.Attestation, typeof applyAttestation](
105+
OpAttestationsDir, suiteName, "Attestation", "attestation",
106+
applyAttestation, path)
107+
108+
suite baseDescription & "Attester Slashing " & preset():
109+
proc applyAttesterSlashing(
110+
preState: var fulu.BeaconState,
111+
attesterSlashing: electra.AttesterSlashing): Result[void, cstring] =
112+
var cache: StateCache
113+
doAssert (? process_attester_slashing(
114+
defaultRuntimeConfig, preState, attesterSlashing, {},
115+
get_state_exit_queue_info(preState), cache))[0] > 0.Gwei
116+
ok()
117+
118+
for path in walkTests(OpAttSlashingDir):
119+
runTest[electra.AttesterSlashing, typeof applyAttesterSlashing](
120+
OpAttSlashingDir, suiteName, "Attester Slashing", "attester_slashing",
121+
applyAttesterSlashing, path)
122+
123+
suite baseDescription & "Block Header " & preset():
124+
proc applyBlockHeader(
125+
preState: var fulu.BeaconState, blck: fulu.BeaconBlock):
126+
Result[void, cstring] =
127+
if blck.is_execution_block:
128+
check blck.body.execution_payload.block_hash ==
129+
blck.compute_execution_block_hash()
130+
var cache: StateCache
131+
process_block_header(preState, blck, {}, cache)
132+
133+
for path in walkTests(OpBlockHeaderDir):
134+
runTest[fulu.BeaconBlock, typeof applyBlockHeader](
135+
OpBlockHeaderDir, suiteName, "Block Header", "block",
136+
applyBlockHeader, path)
137+
138+
from ../../../beacon_chain/spec/datatypes/capella import
139+
SignedBLSToExecutionChange
140+
141+
suite baseDescription & "BLS to execution change " & preset():
142+
proc applyBlsToExecutionChange(
143+
preState: var fulu.BeaconState,
144+
signed_address_change: SignedBLSToExecutionChange):
145+
Result[void, cstring] =
146+
process_bls_to_execution_change(
147+
defaultRuntimeConfig, preState, signed_address_change)
148+
149+
for path in walkTests(OpBlsToExecutionChangeDir):
150+
runTest[SignedBLSToExecutionChange, typeof applyBlsToExecutionChange](
151+
OpBlsToExecutionChangeDir, suiteName, "BLS to execution change", "address_change",
152+
applyBlsToExecutionChange, path)
153+
154+
from ".."/".."/".."/beacon_chain/validator_bucket_sort import
155+
sortValidatorBuckets
156+
157+
suite baseDescription & "Consolidation Request " & preset():
158+
proc applyConsolidationRequest(
159+
preState: var fulu.BeaconState,
160+
consolidation_request: ConsolidationRequest): Result[void, cstring] =
161+
var cache: StateCache
162+
process_consolidation_request(
163+
defaultRuntimeConfig, preState,
164+
sortValidatorBuckets(preState.validators.asSeq)[],
165+
consolidation_request, cache)
166+
ok()
167+
168+
for path in walkTests(OpConsolidationRequestDir):
169+
runTest[ConsolidationRequest, typeof applyConsolidationRequest](
170+
OpConsolidationRequestDir, suiteName, "Consolidation Request",
171+
"consolidation_request", applyConsolidationRequest, path)
172+
173+
suite baseDescription & "Deposit " & preset():
174+
func applyDeposit(
175+
preState: var fulu.BeaconState, deposit: Deposit):
176+
Result[void, cstring] =
177+
process_deposit(
178+
defaultRuntimeConfig, preState,
179+
sortValidatorBuckets(preState.validators.asSeq)[], deposit, {})
180+
181+
for path in walkTests(OpDepositsDir):
182+
runTest[Deposit, typeof applyDeposit](
183+
OpDepositsDir, suiteName, "Deposit", "deposit", applyDeposit, path)
184+
185+
suite baseDescription & "Deposit Request " & preset():
186+
func applyDepositRequest(
187+
preState: var fulu.BeaconState, depositRequest: DepositRequest):
188+
Result[void, cstring] =
189+
process_deposit_request(
190+
defaultRuntimeConfig, preState, depositRequest, {})
191+
192+
for path in walkTests(OpDepositRequestDir):
193+
runTest[DepositRequest, typeof applyDepositRequest](
194+
OpDepositRequestDir, suiteName, "Deposit Request", "deposit_request",
195+
applyDepositRequest, path)
196+
197+
suite baseDescription & "Execution Payload " & preset():
198+
func makeApplyExecutionPayloadCb(path: string): auto =
199+
return proc(
200+
preState: var fulu.BeaconState, body: fulu.BeaconBlockBody):
201+
Result[void, cstring] {.raises: [IOError].} =
202+
let payloadValid = os_ops.readFile(
203+
OpExecutionPayloadDir/"pyspec_tests"/path/"execution.yaml"
204+
).contains("execution_valid: true")
205+
if payloadValid and body.is_execution_block and
206+
not body.execution_payload.transactions.anyIt(it.len == 0):
207+
let expectedOk = (path != "incorrect_block_hash")
208+
check expectedOk == (body.execution_payload.block_hash ==
209+
body.compute_execution_block_hash(
210+
preState.latest_block_root(
211+
assignClone(preState)[].hash_tree_root())))
212+
func executePayload(_: fulu.ExecutionPayload): bool = payloadValid
213+
process_execution_payload(
214+
defaultRuntimeConfig, preState, body, executePayload)
215+
216+
for path in walkTests(OpExecutionPayloadDir):
217+
let applyExecutionPayload = makeApplyExecutionPayloadCb(path)
218+
runTest[fulu.BeaconBlockBody, typeof applyExecutionPayload](
219+
OpExecutionPayloadDir, suiteName, "Execution Payload", "body",
220+
applyExecutionPayload, path)
221+
222+
suite baseDescription & "Withdrawal Request " & preset():
223+
func applyWithdrawalRequest(
224+
preState: var fulu.BeaconState, withdrawalRequest: WithdrawalRequest):
225+
Result[void, cstring] =
226+
var cache: StateCache
227+
process_withdrawal_request(
228+
defaultRuntimeConfig, preState,
229+
sortValidatorBuckets(preState.validators.asSeq)[], withdrawalRequest,
230+
cache)
231+
ok()
232+
233+
for path in walkTests(OpWithdrawalRequestDir):
234+
runTest[WithdrawalRequest, typeof applyWithdrawalRequest](
235+
OpWithdrawalRequestDir, suiteName, "Withdrawal Request",
236+
"withdrawal_request", applyWithdrawalRequest, path)
237+
238+
suite baseDescription & "Proposer Slashing " & preset():
239+
proc applyProposerSlashing(
240+
preState: var fulu.BeaconState, proposerSlashing: ProposerSlashing):
241+
Result[void, cstring] =
242+
var cache: StateCache
243+
doAssert (? process_proposer_slashing(
244+
defaultRuntimeConfig, preState, proposerSlashing, {},
245+
get_state_exit_queue_info(preState), cache))[0] > 0.Gwei
246+
ok()
247+
248+
for path in walkTests(OpProposerSlashingDir):
249+
runTest[ProposerSlashing, typeof applyProposerSlashing](
250+
OpProposerSlashingDir, suiteName, "Proposer Slashing", "proposer_slashing",
251+
applyProposerSlashing, path)
252+
253+
suite baseDescription & "Sync Aggregate " & preset():
254+
proc applySyncAggregate(
255+
preState: var fulu.BeaconState, syncAggregate: SyncAggregate):
256+
Result[void, cstring] =
257+
var cache: StateCache
258+
discard ? process_sync_aggregate(
259+
preState, syncAggregate, get_total_active_balance(preState, cache),
260+
{}, cache)
261+
ok()
262+
263+
for path in walkTests(OpSyncAggregateDir):
264+
runTest[SyncAggregate, typeof applySyncAggregate](
265+
OpSyncAggregateDir, suiteName, "Sync Aggregate", "sync_aggregate",
266+
applySyncAggregate, path)
267+
268+
suite baseDescription & "Voluntary Exit " & preset():
269+
proc applyVoluntaryExit(
270+
preState: var fulu.BeaconState, voluntaryExit: SignedVoluntaryExit):
271+
Result[void, cstring] =
272+
var cache: StateCache
273+
if process_voluntary_exit(
274+
defaultRuntimeConfig, preState, voluntaryExit, {},
275+
get_state_exit_queue_info(preState), cache).isOk:
276+
ok()
277+
else:
278+
err("")
279+
280+
for path in walkTests(OpVoluntaryExitDir):
281+
runTest[SignedVoluntaryExit, typeof applyVoluntaryExit](
282+
OpVoluntaryExitDir, suiteName, "Voluntary Exit", "voluntary_exit",
283+
applyVoluntaryExit, path)
284+
285+
suite baseDescription & "Withdrawals " & preset():
286+
func applyWithdrawals(
287+
preState: var fulu.BeaconState,
288+
executionPayload: fulu.ExecutionPayload): Result[void, cstring] =
289+
process_withdrawals(preState, executionPayload)
290+
291+
for path in walkTests(OpWithdrawalsDir):
292+
runTest[fulu.ExecutionPayload, typeof applyWithdrawals](
293+
OpWithdrawalsDir, suiteName, "Withdrawals", "execution_payload",
294+
applyWithdrawals, path)

0 commit comments

Comments
 (0)