add blob validation to `test_fixture_fork_choice` (#5441)

Preparation for processing new tests from:

- https://github.com/ethereum/consensus-specs/pull/3463
This commit is contained in:
Etan Kissling 2023-09-20 03:14:49 +02:00 committed by GitHub
parent eadd0d69ce
commit aacb853a0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 16 deletions

View File

@ -321,7 +321,7 @@ consensus_spec_tests_minimal: | build deps
MAKE="$(MAKE)" V="$(V)" $(ENV_SCRIPT) scripts/compile_nim_program.sh \ MAKE="$(MAKE)" V="$(V)" $(ENV_SCRIPT) scripts/compile_nim_program.sh \
$@ \ $@ \
"tests/consensus_spec/consensus_spec_tests_preset.nim" \ "tests/consensus_spec/consensus_spec_tests_preset.nim" \
$(NIM_PARAMS) -d:const_preset=minimal $(TEST_MODULES_FLAGS) && \ $(NIM_PARAMS) -d:const_preset=minimal -d:FIELD_ELEMENTS_PER_BLOB=4 $(TEST_MODULES_FLAGS) && \
echo -e $(BUILD_END_MSG) "build/$@" echo -e $(BUILD_END_MSG) "build/$@"
# Tests we only run for the default preset # Tests we only run for the default preset

View File

@ -9,7 +9,7 @@
import import
# Status libraries # Status libraries
stew/results, chronicles, stew/[byteutils, results], chronicles,
taskpools, taskpools,
# Internals # Internals
../../beacon_chain/spec/[helpers, forks, state_transition_block], ../../beacon_chain/spec/[helpers, forks, state_transition_block],
@ -28,7 +28,7 @@ import
from std/json import from std/json import
JsonNode, getBool, getInt, getStr, hasKey, items, len, pairs, `$`, `[]` JsonNode, getBool, getInt, getStr, hasKey, items, len, pairs, `$`, `[]`
from std/sequtils import toSeq from std/sequtils import mapIt, toSeq
from std/strutils import contains from std/strutils import contains
# Test format described at https://github.com/ethereum/consensus-specs/tree/v1.3.0/tests/formats/fork_choice # Test format described at https://github.com/ethereum/consensus-specs/tree/v1.3.0/tests/formats/fork_choice
@ -45,6 +45,10 @@ type
opInvalidateRoot opInvalidateRoot
opChecks opChecks
BlobData = object
blobs: seq[KzgBlob]
proofs: seq[KzgProof]
Operation = object Operation = object
valid: bool valid: bool
# variant specific fields # variant specific fields
@ -55,6 +59,7 @@ type
att: Attestation att: Attestation
of opOnBlock: of opOnBlock:
blck: ForkedSignedBeaconBlock blck: ForkedSignedBeaconBlock
blobData: Opt[BlobData]
of opOnMergeBlock: of opOnMergeBlock:
powBlock: PowBlock powBlock: PowBlock
of opOnAttesterSlashing: of opOnAttesterSlashing:
@ -69,7 +74,7 @@ from ../../beacon_chain/spec/datatypes/capella import
BeaconBlock, BeaconState, SignedBeaconBlock BeaconBlock, BeaconState, SignedBeaconBlock
from ../../beacon_chain/spec/datatypes/deneb import from ../../beacon_chain/spec/datatypes/deneb import
BeaconBlock, BeaconState, SignedBeaconBlock KzgBlob, KzgProof, BeaconBlock, BeaconState, SignedBeaconBlock
proc initialLoad( proc initialLoad(
path: string, db: BeaconChainDB, path: string, db: BeaconChainDB,
@ -134,6 +139,8 @@ proc loadOps(path: string, fork: ConsensusFork): seq[Operation] =
result = @[] result = @[]
for step in steps[0]: for step in steps[0]:
var numExtraFields = 0
if step.hasKey"tick": if step.hasKey"tick":
result.add Operation(kind: opOnTick, result.add Operation(kind: opOnTick,
tick: step["tick"].getInt()) tick: step["tick"].getInt())
@ -147,12 +154,14 @@ proc loadOps(path: string, fork: ConsensusFork): seq[Operation] =
att: att) att: att)
elif step.hasKey"block": elif step.hasKey"block":
let filename = step["block"].getStr() let filename = step["block"].getStr()
doAssert step.hasKey"blobs" == step.hasKey"proofs"
case fork case fork
of ConsensusFork.Phase0: of ConsensusFork.Phase0:
let blck = parseTest( let blck = parseTest(
path/filename & ".ssz_snappy", path/filename & ".ssz_snappy",
SSZ, phase0.SignedBeaconBlock SSZ, phase0.SignedBeaconBlock
) )
doAssert not step.hasKey"blobs"
result.add Operation(kind: opOnBlock, result.add Operation(kind: opOnBlock,
blck: ForkedSignedBeaconBlock.init(blck)) blck: ForkedSignedBeaconBlock.init(blck))
of ConsensusFork.Altair: of ConsensusFork.Altair:
@ -160,6 +169,7 @@ proc loadOps(path: string, fork: ConsensusFork): seq[Operation] =
path/filename & ".ssz_snappy", path/filename & ".ssz_snappy",
SSZ, altair.SignedBeaconBlock SSZ, altair.SignedBeaconBlock
) )
doAssert not step.hasKey"blobs"
result.add Operation(kind: opOnBlock, result.add Operation(kind: opOnBlock,
blck: ForkedSignedBeaconBlock.init(blck)) blck: ForkedSignedBeaconBlock.init(blck))
of ConsensusFork.Bellatrix: of ConsensusFork.Bellatrix:
@ -167,6 +177,7 @@ proc loadOps(path: string, fork: ConsensusFork): seq[Operation] =
path/filename & ".ssz_snappy", path/filename & ".ssz_snappy",
SSZ, bellatrix.SignedBeaconBlock SSZ, bellatrix.SignedBeaconBlock
) )
doAssert not step.hasKey"blobs"
result.add Operation(kind: opOnBlock, result.add Operation(kind: opOnBlock,
blck: ForkedSignedBeaconBlock.init(blck)) blck: ForkedSignedBeaconBlock.init(blck))
of ConsensusFork.Capella: of ConsensusFork.Capella:
@ -174,15 +185,27 @@ proc loadOps(path: string, fork: ConsensusFork): seq[Operation] =
path/filename & ".ssz_snappy", path/filename & ".ssz_snappy",
SSZ, capella.SignedBeaconBlock SSZ, capella.SignedBeaconBlock
) )
doAssert not step.hasKey"blobs"
result.add Operation(kind: opOnBlock, result.add Operation(kind: opOnBlock,
blck: ForkedSignedBeaconBlock.init(blck)) blck: ForkedSignedBeaconBlock.init(blck))
of ConsensusFork.Deneb: of ConsensusFork.Deneb:
let blck = parseTest( let
path/filename & ".ssz_snappy", blck = parseTest(
SSZ, deneb.SignedBeaconBlock path/filename & ".ssz_snappy",
) SSZ, deneb.SignedBeaconBlock)
blobData =
if step.hasKey"blobs":
numExtraFields += 2
Opt.some BlobData(
blobs: distinctBase(parseTest(
path/(step["blobs"].getStr()) & ".ssz_snappy",
SSZ, List[KzgBlob, Limit MAX_BLOBS_PER_BLOCK])),
proofs: step["proofs"].mapIt(KzgProof.fromHex(it.getStr())))
else:
Opt.none(BlobData)
result.add Operation(kind: opOnBlock, result.add Operation(kind: opOnBlock,
blck: ForkedSignedBeaconBlock.init(blck)) blck: ForkedSignedBeaconBlock.init(blck),
blobData: blobData)
elif step.hasKey"attester_slashing": elif step.hasKey"attester_slashing":
let filename = step["attester_slashing"].getStr() let filename = step["attester_slashing"].getStr()
let attesterSlashing = parseTest( let attesterSlashing = parseTest(
@ -205,10 +228,10 @@ proc loadOps(path: string, fork: ConsensusFork): seq[Operation] =
doAssert false, "Unknown test step: " & $step doAssert false, "Unknown test step: " & $step
if step.hasKey"valid": if step.hasKey"valid":
doAssert step.len == 2 doAssert step.len == 2 + numExtraFields
result[^1].valid = step["valid"].getBool() result[^1].valid = step["valid"].getBool()
elif not step.hasKey"checks" and not step.hasKey"payload_status": elif not step.hasKey"checks" and not step.hasKey"payload_status":
doAssert step.len == 1 doAssert step.len == 1 + numExtraFields
result[^1].valid = true result[^1].valid = true
proc stepOnBlock( proc stepOnBlock(
@ -218,10 +241,21 @@ proc stepOnBlock(
state: var ForkedHashedBeaconState, state: var ForkedHashedBeaconState,
stateCache: var StateCache, stateCache: var StateCache,
signedBlock: ForkySignedBeaconBlock, signedBlock: ForkySignedBeaconBlock,
blobData: Opt[BlobData],
time: BeaconTime, time: BeaconTime,
invalidatedRoots: Table[Eth2Digest, Eth2Digest]): invalidatedRoots: Table[Eth2Digest, Eth2Digest]):
Result[BlockRef, VerifierError] = Result[BlockRef, VerifierError] =
# 1. Move state to proper slot. # 1. Validate blobs
when typeof(signedBlock).toFork() >= ConsensusFork.Deneb:
let kzgCommits = signedBlock.message.body.blob_kzg_commitments.asSeq
if kzgCommits.len > 0 or blobData.isSome:
if blobData.isNone or kzgCommits.validate_blobs(
blobData.get.blobs, blobData.get.proofs).isErr:
return err(VerifierError.Invalid)
else:
doAssert blobData.isNone, "Pre-Deneb test with specified blob data"
# 2. Move state to proper slot
doAssert dag.updateState( doAssert dag.updateState(
state, state,
dag.getBlockIdAtSlot(time.slotOrZero).expect("block exists"), dag.getBlockIdAtSlot(time.slotOrZero).expect("block exists"),
@ -229,7 +263,7 @@ proc stepOnBlock(
stateCache stateCache
) )
# 2. Add block to DAG # 3. Add block to DAG
when signedBlock is phase0.SignedBeaconBlock: when signedBlock is phase0.SignedBeaconBlock:
type TrustedBlock = phase0.TrustedSignedBeaconBlock type TrustedBlock = phase0.TrustedSignedBeaconBlock
elif signedBlock is altair.SignedBeaconBlock: elif signedBlock is altair.SignedBeaconBlock:
@ -272,12 +306,12 @@ proc stepOnBlock(
blckRef: BlockRef, signedBlock: TrustedBlock, blckRef: BlockRef, signedBlock: TrustedBlock,
epochRef: EpochRef, unrealized: FinalityCheckpoints): epochRef: EpochRef, unrealized: FinalityCheckpoints):
# 3. Update fork choice if valid # 4. Update fork choice if valid
let status = fkChoice[].process_block( let status = fkChoice[].process_block(
dag, epochRef, blckRef, unrealized, signedBlock.message, time) dag, epochRef, blckRef, unrealized, signedBlock.message, time)
doAssert status.isOk() doAssert status.isOk()
# 4. Update DAG with new head # 5. Update DAG with new head
var quarantine = Quarantine.init() var quarantine = Quarantine.init()
let newHead = fkChoice[].get_head(dag, time).get() let newHead = fkChoice[].get_head(dag, time).get()
dag.updateHead(dag.getBlockRef(newHead).get(), quarantine, []) dag.updateHead(dag.getBlockRef(newHead).get(), quarantine, [])
@ -377,7 +411,7 @@ proc doRunTest(path: string, fork: ConsensusFork) =
let status = stepOnBlock( let status = stepOnBlock(
stores.dag, stores.fkChoice, stores.dag, stores.fkChoice,
verifier, state[], stateCache, verifier, state[], stateCache,
blck, time, invalidatedRoots) blck, step.blobData, time, invalidatedRoots)
doAssert status.isOk == step.valid doAssert status.isOk == step.valid
of opOnAttesterSlashing: of opOnAttesterSlashing:
let indices = let indices =
@ -436,5 +470,8 @@ template fcSuite(suiteName: static[string], testPathElem: static[string]) =
for kind, path in walkDir(basePath, relative = true, checkDir = true): for kind, path in walkDir(basePath, relative = true, checkDir = true):
runTest(suiteName, basePath/path, fork) runTest(suiteName, basePath/path, fork)
from ../../beacon_chain/conf import loadKzgTrustedSetup
discard loadKzgTrustedSetup() # Required for Deneb tests
fcSuite("ForkChoice", "fork_choice") fcSuite("ForkChoice", "fork_choice")
fcSuite("Sync", "sync") fcSuite("Sync", "sync")