eip4844 beacon block proposals (#4540)

* eip4844 beacon block proposals

* Don't fetch blobs under minimal preset

@tersec's summary of the issue:

BlobsBundleV1 in the execution API spec assumes a mainnet preset blob
size, where the EIP4844 consensus spec defines
FIELD_ELEMENTS_PER_BLOB: 4 under the minimal preset, which leads to a
Blob having a length of 4 * 32, not 4096 * 32 which BlobsBundleV1
requires.

* Revert unintentional script change
This commit is contained in:
henridf 2023-01-22 00:13:21 +01:00 committed by GitHub
parent 90e169869c
commit 349001b7fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 94 additions and 22 deletions

View File

@ -361,6 +361,8 @@ template init*(T: type ForkedBeaconBlock, blck: bellatrix.BeaconBlock): T =
T(kind: BeaconBlockFork.Bellatrix, bellatrixData: blck)
template init*(T: type ForkedBeaconBlock, blck: capella.BeaconBlock): T =
T(kind: BeaconBlockFork.Capella, capellaData: blck)
template init*(T: type ForkedBeaconBlock, blck: eip4844.BeaconBlock): T =
T(kind: BeaconBlockFork.EIP4844, eip4844Data: blck)
template init*(T: type ForkedTrustedBeaconBlock, blck: phase0.TrustedBeaconBlock): T =
T(kind: BeaconBlockFork.Phase0, phase0Data: blck)

View File

@ -343,6 +343,7 @@ template partialBeaconBlock*(
deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate,
blob_kzg_commitments: KZGCommitmentList,
execution_payload: bellatrix.ExecutionPayload):
phase0.BeaconBlock =
phase0.BeaconBlock(
@ -371,6 +372,7 @@ template partialBeaconBlock*(
deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate,
blob_kzg_commitments: KZGCommitmentList,
execution_payload: bellatrix.ExecutionPayload):
altair.BeaconBlock =
altair.BeaconBlock(
@ -400,6 +402,7 @@ template partialBeaconBlock*(
deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate,
blob_kzg_commitments: KZGCommitmentList,
execution_payload: bellatrix.ExecutionPayload):
bellatrix.BeaconBlock =
bellatrix.BeaconBlock(
@ -430,6 +433,7 @@ template partialBeaconBlock*(
deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate,
blob_kzg_commitments: KZGCommitmentList,
execution_payload: capella.ExecutionPayload,
):
capella.BeaconBlock =
@ -463,10 +467,10 @@ template partialBeaconBlock*(
deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate,
kzg_commitments: eip4844.KZGCommitmentList,
execution_payload: eip4844.ExecutionPayload,
):
eip4844.BeaconBlock =
discard $eip4844ImplementationMissing & ": state_transition.nim: partialBeaconBlock, leaves additional fields default, okay for block_sim"
eip4844.BeaconBlock(
slot: state.data.slot,
proposer_index: proposer_index.uint64,
@ -482,10 +486,12 @@ template partialBeaconBlock*(
voluntary_exits: validator_changes.voluntary_exits,
sync_aggregate: sync_aggregate,
execution_payload: execution_payload,
bls_to_execution_changes: validator_changes.bls_to_execution_changes
bls_to_execution_changes: validator_changes.bls_to_execution_changes,
blob_kzg_commitments: kzg_commitments
))
proc makeBeaconBlock*[T: bellatrix.ExecutionPayload | capella.ExecutionPayload](
proc makeBeaconBlock*[T: bellatrix.ExecutionPayload | capella.ExecutionPayload |
eip4844.ExecutionPayload](
cfg: RuntimeConfig,
state: var ForkedHashedBeaconState,
proposer_index: ValidatorIndex,
@ -497,6 +503,7 @@ proc makeBeaconBlock*[T: bellatrix.ExecutionPayload | capella.ExecutionPayload](
validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate,
executionPayload: T,
blob_kzg_commitments: KZGCommitmentList,
rollback: RollbackForkedHashedProc,
cache: var StateCache,
# TODO:
@ -520,7 +527,7 @@ proc makeBeaconBlock*[T: bellatrix.ExecutionPayload | capella.ExecutionPayload](
partialBeaconBlock(
cfg, state.`kind Data`, proposer_index, randao_reveal, eth1_data,
graffiti, attestations, deposits, validator_changes, sync_aggregate,
executionPayload))
blob_kzg_commitments, executionPayload))
let res = process_block(
cfg, state.`kind Data`.data, blck.`kind Data`.asSigVerified(),
@ -576,8 +583,8 @@ proc makeBeaconBlock*[T: bellatrix.ExecutionPayload | capella.ExecutionPayload](
of BeaconStateFork.Phase0, BeaconStateFork.Altair,
BeaconStateFork.Bellatrix, BeaconStateFork.Capella:
raiseAssert "Attempt to use EIP4844 payload with non-EIP4844 state"
of BeaconStateFork.EIP4844:
debugRaiseAssert $eip4844ImplementationMissing & ": state_transition"
of BeaconStateFork.EIP4844: makeBeaconBlock(eip4844)
# workaround for https://github.com/nim-lang/Nim/issues/20900 rather than have
# these be default arguments
@ -588,13 +595,14 @@ proc makeBeaconBlock*[T](
attestations: seq[Attestation], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, executionPayload: T,
blob_kzg_commitments: KZGCommitmentList,
rollback: RollbackForkedHashedProc, cache: var StateCache):
Result[ForkedBeaconBlock, cstring] =
makeBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, validator_changes, sync_aggregate,
executionPayload, rollback, cache, verificationFlags = {},
transactions_root = Opt.none Eth2Digest,
executionPayload, blob_kzg_commitments, rollback, cache,
verificationFlags = {}, transactions_root = Opt.none Eth2Digest,
execution_payload_root = Opt.none Eth2Digest)
proc makeBeaconBlock*[T](
@ -604,12 +612,14 @@ proc makeBeaconBlock*[T](
attestations: seq[Attestation], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, executionPayload: T,
blob_kzg_commitments: KZGCommitmentList,
rollback: RollbackForkedHashedProc,
cache: var StateCache, verificationFlags: UpdateFlags):
Result[ForkedBeaconBlock, cstring] =
makeBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, validator_changes, sync_aggregate,
executionPayload, rollback, cache, verificationFlags = verificationFlags,
executionPayload, blob_kzg_commitments, rollback, cache,
verificationFlags = verificationFlags,
transactions_root = Opt.none Eth2Digest,
execution_payload_root = Opt.none Eth2Digest)

View File

@ -65,6 +65,9 @@ declareCounter beacon_block_production_errors,
declareCounter beacon_block_payload_errors,
"Number of times execution client failed to produce block payload"
declareCounter beacon_blobs_sidecar_payload_errors,
"Number of times execution client failed to produce blobs sidecar"
# Metrics for tracking external block builder usage
declareCounter beacon_block_builder_missed_with_fallback,
"Number of beacon chain blocks where an attempt to use an external block builder failed with fallback"
@ -320,8 +323,8 @@ proc get_execution_payload[EP](
asConsensusExecutionPayload(
await execution_engine.getPayloadV2(payload_id.get))
elif EP is eip4844.ExecutionPayload:
debugRaiseAssert $eip4844ImplementationMissing & ": get_execution_payload"
default(EP)
asConsensusExecutionPayload(
await execution_engine.getPayloadV3(payload_id.get))
else:
static: doAssert "unknown execution payload type"
@ -436,6 +439,32 @@ proc getExecutionPayload[T](
msg = err.msg
return Opt.some empty_execution_payload
proc getBlobsBundle(
node: BeaconNode, epoch: Epoch, validator_index: ValidatorIndex,
payload_id: PayloadID): Future[BlobsBundleV1] {.async.} =
# https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/validator.md#get_blobs_and_kzg_commitments
# Minimize window for Eth1 monitor to shut down connection
await node.consensusManager.eth1Monitor.ensureDataProvider()
# https://github.com/ethereum/execution-apis/blob/8058687053598e8fa3cc25a4ca4965fb96cf1e65/src/engine/experimental/blob-extension.md#engine_getblobsbundlev1
const GETBLOBS_TIMEOUT = 1.seconds
let payload = try:
awaitWithTimeout(
node.consensusManager.eth1Monitor.getBlobsBundleV1(payload_id),
GETBLOBS_TIMEOUT):
beacon_block_payload_errors.inc()
warn "Getting blobs sidecar from Engine API timed out", payload_id
default(BlobsBundleV1)
except CatchableError as err:
beacon_block_payload_errors.inc()
warn "Getting blobs sidecar from Engine API failed",
payload_id, err = err.msg
default(BlobsBundleV1)
return payload
proc makeBeaconBlockForHeadAndSlot*[EP](
node: BeaconNode, randao_reveal: ValidatorSig,
validator_index: ValidatorIndex, graffiti: GraffitiBytes, head: BlockRef,
@ -514,6 +543,7 @@ proc makeBeaconBlockForHeadAndSlot*[EP](
exits,
syncAggregate,
payload,
(static(default(KZGCommitmentList))),
noRollback, # Temporary state - no need for rollback
cache,
verificationFlags = {},
@ -835,7 +865,10 @@ proc proposeBlock(node: BeaconNode,
return newBlockMEV.get
let newBlock =
if slot.epoch >= node.dag.cfg.CAPELLA_FORK_EPOCH:
if slot.epoch >= node.dag.cfg.EIP4844_FORK_EPOCH:
await makeBeaconBlockForHeadAndSlot[eip4844.ExecutionPayload](
node, randao, validator_index, node.graffitiBytes, head, slot)
elif slot.epoch >= node.dag.cfg.CAPELLA_FORK_EPOCH:
await makeBeaconBlockForHeadAndSlot[capella.ExecutionPayload](
node, randao, validator_index, node.graffitiBytes, head, slot)
else:
@ -845,9 +878,31 @@ proc proposeBlock(node: BeaconNode,
if newBlock.isErr():
return head # already logged elsewhere!
let forkedBlck = newBlock.get()
var forkedBlck = newBlock.get()
var blobs_sidecar = eip4844.BlobsSidecar()
withBlck(forkedBlck):
when blck is eip4844.BeaconBlock and const_preset != "minimal":
let
lastFcU = node.consensusManager.forkchoiceUpdatedInfo
payload_id = bellatrix.PayloadID(lastFcU.get.payloadId)
bundle = await getBlobsBundle(node, slot.epoch, validator_index, default(PayloadID))
# todo: actually compute proof over blobs using nim-kzg-4844
kzg_aggregated_proof = default(KZGProof)
blck.body.blob_kzg_commitments =
List[eip4844.KZGCommitment, Limit MAX_BLOBS_PER_BLOCK].init(
mapIt(bundle.kzgs, eip4844.KzgCommitment(it)))
blobs_sidecar = BlobsSidecar(
beacon_block_root: hash_tree_root(blck),
beacon_block_slot: slot,
blobs: List[eip4844.Blob, Limit MAX_BLOBS_PER_BLOCK].init(
mapIt(bundle.blobs, eip4844.Blob(it))),
kzg_aggregated_proof: kzg_aggregated_proof
)
let
blockRoot = hash_tree_root(blck)
signingRoot = compute_block_signing_root(
@ -889,12 +944,10 @@ proc proposeBlock(node: BeaconNode,
elif blck is capella.BeaconBlock:
capella.SignedBeaconBlock(
message: blck, signature: signature, root: blockRoot)
# TODO: Fetch blobs from EE
# https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/validator.md#blob-kzg-commitments
elif blck is eip4844.BeaconBlock:
eip4844.SignedBeaconBlockAndBlobsSidecar(
beacon_block:eip4844.SignedBeaconBlock(message: blck, signature: signature, root: blockRoot),
blobs_sidecar: eip4844.BlobsSidecar()
blobs_sidecar: blobs_sidecar
)
else:
static: doAssert "Unknown SignedBeaconBlock type"

View File

@ -19,7 +19,7 @@ import
chronos/timer, eth/keys, taskpools,
../tests/testblockutil,
../beacon_chain/spec/[forks, state_transition],
../beacon_chain/spec/datatypes/[phase0, altair, bellatrix],
../beacon_chain/spec/datatypes/[phase0, altair, bellatrix, eip4844],
../beacon_chain/[beacon_chain_db, beacon_clock],
../beacon_chain/eth1/eth1_monitor,
../beacon_chain/validators/validator_pool,
@ -101,7 +101,8 @@ proc makeBeaconBlock(
var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, exits, sync_aggregate, execution_payload)
attestations, deposits, exits, sync_aggregate,
static(default(eip4844.KZGCommitmentList)), execution_payload)
let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache)
@ -144,7 +145,8 @@ proc makeBeaconBlock(
var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, exits, sync_aggregate, execution_payload)
attestations, deposits, exits, sync_aggregate,
static(default(eip4844.KZGCommitmentList)), execution_payload)
# Signatures are verified elsewhere, so don't duplicate inefficiently here
let res = process_block(
@ -188,7 +190,8 @@ proc makeBeaconBlock(
var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, exits, sync_aggregate, execution_payload)
attestations, deposits, exits, sync_aggregate,
static(default(eip4844.KZGCommitmentList)), execution_payload)
let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache)
@ -231,7 +234,8 @@ proc makeBeaconBlock(
var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, exits, sync_aggregate, execution_payload)
attestations, deposits, exits, sync_aggregate,
static(default(eip4844.KZGCommitmentList)), execution_payload)
let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache)
@ -274,7 +278,8 @@ proc makeBeaconBlock(
var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, exits, sync_aggregate, execution_payload)
attestations, deposits, exits, sync_aggregate,
default(eip4844.KZGCommitmentList), execution_payload)
let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache)

View File

@ -163,6 +163,7 @@ cli do(validatorsDir: string, secretsDir: string,
BeaconBlockValidatorChanges(),
syncAggregate,
default(bellatrix.ExecutionPayload),
default(eip4844.KZGCommitmentList),
noRollback,
cache).get()

View File

@ -202,6 +202,7 @@ proc addTestBlockAux[EP: bellatrix.ExecutionPayload | capella.ExecutionPayload](
BeaconBlockValidatorChanges(),
sync_aggregate,
execution_payload,
(static(default(eip4844.KZGCommitmentList))),
noRollback,
cache,
verificationFlags = {skipBlsValidation})