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) T(kind: BeaconBlockFork.Bellatrix, bellatrixData: blck)
template init*(T: type ForkedBeaconBlock, blck: capella.BeaconBlock): T = template init*(T: type ForkedBeaconBlock, blck: capella.BeaconBlock): T =
T(kind: BeaconBlockFork.Capella, capellaData: blck) 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 = template init*(T: type ForkedTrustedBeaconBlock, blck: phase0.TrustedBeaconBlock): T =
T(kind: BeaconBlockFork.Phase0, phase0Data: blck) T(kind: BeaconBlockFork.Phase0, phase0Data: blck)

View File

@ -343,6 +343,7 @@ template partialBeaconBlock*(
deposits: seq[Deposit], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges, validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, sync_aggregate: SyncAggregate,
blob_kzg_commitments: KZGCommitmentList,
execution_payload: bellatrix.ExecutionPayload): execution_payload: bellatrix.ExecutionPayload):
phase0.BeaconBlock = phase0.BeaconBlock =
phase0.BeaconBlock( phase0.BeaconBlock(
@ -371,6 +372,7 @@ template partialBeaconBlock*(
deposits: seq[Deposit], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges, validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, sync_aggregate: SyncAggregate,
blob_kzg_commitments: KZGCommitmentList,
execution_payload: bellatrix.ExecutionPayload): execution_payload: bellatrix.ExecutionPayload):
altair.BeaconBlock = altair.BeaconBlock =
altair.BeaconBlock( altair.BeaconBlock(
@ -400,6 +402,7 @@ template partialBeaconBlock*(
deposits: seq[Deposit], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges, validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, sync_aggregate: SyncAggregate,
blob_kzg_commitments: KZGCommitmentList,
execution_payload: bellatrix.ExecutionPayload): execution_payload: bellatrix.ExecutionPayload):
bellatrix.BeaconBlock = bellatrix.BeaconBlock =
bellatrix.BeaconBlock( bellatrix.BeaconBlock(
@ -430,6 +433,7 @@ template partialBeaconBlock*(
deposits: seq[Deposit], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges, validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, sync_aggregate: SyncAggregate,
blob_kzg_commitments: KZGCommitmentList,
execution_payload: capella.ExecutionPayload, execution_payload: capella.ExecutionPayload,
): ):
capella.BeaconBlock = capella.BeaconBlock =
@ -463,10 +467,10 @@ template partialBeaconBlock*(
deposits: seq[Deposit], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges, validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, sync_aggregate: SyncAggregate,
kzg_commitments: eip4844.KZGCommitmentList,
execution_payload: eip4844.ExecutionPayload, execution_payload: eip4844.ExecutionPayload,
): ):
eip4844.BeaconBlock = eip4844.BeaconBlock =
discard $eip4844ImplementationMissing & ": state_transition.nim: partialBeaconBlock, leaves additional fields default, okay for block_sim"
eip4844.BeaconBlock( eip4844.BeaconBlock(
slot: state.data.slot, slot: state.data.slot,
proposer_index: proposer_index.uint64, proposer_index: proposer_index.uint64,
@ -482,10 +486,12 @@ template partialBeaconBlock*(
voluntary_exits: validator_changes.voluntary_exits, voluntary_exits: validator_changes.voluntary_exits,
sync_aggregate: sync_aggregate, sync_aggregate: sync_aggregate,
execution_payload: execution_payload, 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, cfg: RuntimeConfig,
state: var ForkedHashedBeaconState, state: var ForkedHashedBeaconState,
proposer_index: ValidatorIndex, proposer_index: ValidatorIndex,
@ -497,6 +503,7 @@ proc makeBeaconBlock*[T: bellatrix.ExecutionPayload | capella.ExecutionPayload](
validator_changes: BeaconBlockValidatorChanges, validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, sync_aggregate: SyncAggregate,
executionPayload: T, executionPayload: T,
blob_kzg_commitments: KZGCommitmentList,
rollback: RollbackForkedHashedProc, rollback: RollbackForkedHashedProc,
cache: var StateCache, cache: var StateCache,
# TODO: # TODO:
@ -520,7 +527,7 @@ proc makeBeaconBlock*[T: bellatrix.ExecutionPayload | capella.ExecutionPayload](
partialBeaconBlock( partialBeaconBlock(
cfg, state.`kind Data`, proposer_index, randao_reveal, eth1_data, cfg, state.`kind Data`, proposer_index, randao_reveal, eth1_data,
graffiti, attestations, deposits, validator_changes, sync_aggregate, graffiti, attestations, deposits, validator_changes, sync_aggregate,
executionPayload)) blob_kzg_commitments, executionPayload))
let res = process_block( let res = process_block(
cfg, state.`kind Data`.data, blck.`kind Data`.asSigVerified(), 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, of BeaconStateFork.Phase0, BeaconStateFork.Altair,
BeaconStateFork.Bellatrix, BeaconStateFork.Capella: BeaconStateFork.Bellatrix, BeaconStateFork.Capella:
raiseAssert "Attempt to use EIP4844 payload with non-EIP4844 state" raiseAssert "Attempt to use EIP4844 payload with non-EIP4844 state"
of BeaconStateFork.EIP4844: of BeaconStateFork.EIP4844: makeBeaconBlock(eip4844)
debugRaiseAssert $eip4844ImplementationMissing & ": state_transition"
# workaround for https://github.com/nim-lang/Nim/issues/20900 rather than have # workaround for https://github.com/nim-lang/Nim/issues/20900 rather than have
# these be default arguments # these be default arguments
@ -588,13 +595,14 @@ proc makeBeaconBlock*[T](
attestations: seq[Attestation], deposits: seq[Deposit], attestations: seq[Attestation], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges, validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, executionPayload: T, sync_aggregate: SyncAggregate, executionPayload: T,
blob_kzg_commitments: KZGCommitmentList,
rollback: RollbackForkedHashedProc, cache: var StateCache): rollback: RollbackForkedHashedProc, cache: var StateCache):
Result[ForkedBeaconBlock, cstring] = Result[ForkedBeaconBlock, cstring] =
makeBeaconBlock( makeBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, validator_changes, sync_aggregate, attestations, deposits, validator_changes, sync_aggregate,
executionPayload, rollback, cache, verificationFlags = {}, executionPayload, blob_kzg_commitments, rollback, cache,
transactions_root = Opt.none Eth2Digest, verificationFlags = {}, transactions_root = Opt.none Eth2Digest,
execution_payload_root = Opt.none Eth2Digest) execution_payload_root = Opt.none Eth2Digest)
proc makeBeaconBlock*[T]( proc makeBeaconBlock*[T](
@ -604,12 +612,14 @@ proc makeBeaconBlock*[T](
attestations: seq[Attestation], deposits: seq[Deposit], attestations: seq[Attestation], deposits: seq[Deposit],
validator_changes: BeaconBlockValidatorChanges, validator_changes: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate, executionPayload: T, sync_aggregate: SyncAggregate, executionPayload: T,
blob_kzg_commitments: KZGCommitmentList,
rollback: RollbackForkedHashedProc, rollback: RollbackForkedHashedProc,
cache: var StateCache, verificationFlags: UpdateFlags): cache: var StateCache, verificationFlags: UpdateFlags):
Result[ForkedBeaconBlock, cstring] = Result[ForkedBeaconBlock, cstring] =
makeBeaconBlock( makeBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, validator_changes, sync_aggregate, attestations, deposits, validator_changes, sync_aggregate,
executionPayload, rollback, cache, verificationFlags = verificationFlags, executionPayload, blob_kzg_commitments, rollback, cache,
verificationFlags = verificationFlags,
transactions_root = Opt.none Eth2Digest, transactions_root = Opt.none Eth2Digest,
execution_payload_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, declareCounter beacon_block_payload_errors,
"Number of times execution client failed to produce block payload" "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 # Metrics for tracking external block builder usage
declareCounter beacon_block_builder_missed_with_fallback, declareCounter beacon_block_builder_missed_with_fallback,
"Number of beacon chain blocks where an attempt to use an external block builder failed 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( asConsensusExecutionPayload(
await execution_engine.getPayloadV2(payload_id.get)) await execution_engine.getPayloadV2(payload_id.get))
elif EP is eip4844.ExecutionPayload: elif EP is eip4844.ExecutionPayload:
debugRaiseAssert $eip4844ImplementationMissing & ": get_execution_payload" asConsensusExecutionPayload(
default(EP) await execution_engine.getPayloadV3(payload_id.get))
else: else:
static: doAssert "unknown execution payload type" static: doAssert "unknown execution payload type"
@ -436,6 +439,32 @@ proc getExecutionPayload[T](
msg = err.msg msg = err.msg
return Opt.some empty_execution_payload 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]( proc makeBeaconBlockForHeadAndSlot*[EP](
node: BeaconNode, randao_reveal: ValidatorSig, node: BeaconNode, randao_reveal: ValidatorSig,
validator_index: ValidatorIndex, graffiti: GraffitiBytes, head: BlockRef, validator_index: ValidatorIndex, graffiti: GraffitiBytes, head: BlockRef,
@ -514,6 +543,7 @@ proc makeBeaconBlockForHeadAndSlot*[EP](
exits, exits,
syncAggregate, syncAggregate,
payload, payload,
(static(default(KZGCommitmentList))),
noRollback, # Temporary state - no need for rollback noRollback, # Temporary state - no need for rollback
cache, cache,
verificationFlags = {}, verificationFlags = {},
@ -835,7 +865,10 @@ proc proposeBlock(node: BeaconNode,
return newBlockMEV.get return newBlockMEV.get
let newBlock = 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]( await makeBeaconBlockForHeadAndSlot[capella.ExecutionPayload](
node, randao, validator_index, node.graffitiBytes, head, slot) node, randao, validator_index, node.graffitiBytes, head, slot)
else: else:
@ -845,9 +878,31 @@ proc proposeBlock(node: BeaconNode,
if newBlock.isErr(): if newBlock.isErr():
return head # already logged elsewhere! return head # already logged elsewhere!
let forkedBlck = newBlock.get() var forkedBlck = newBlock.get()
var blobs_sidecar = eip4844.BlobsSidecar()
withBlck(forkedBlck): 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 let
blockRoot = hash_tree_root(blck) blockRoot = hash_tree_root(blck)
signingRoot = compute_block_signing_root( signingRoot = compute_block_signing_root(
@ -889,12 +944,10 @@ proc proposeBlock(node: BeaconNode,
elif blck is capella.BeaconBlock: elif blck is capella.BeaconBlock:
capella.SignedBeaconBlock( capella.SignedBeaconBlock(
message: blck, signature: signature, root: blockRoot) 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: elif blck is eip4844.BeaconBlock:
eip4844.SignedBeaconBlockAndBlobsSidecar( eip4844.SignedBeaconBlockAndBlobsSidecar(
beacon_block:eip4844.SignedBeaconBlock(message: blck, signature: signature, root: blockRoot), beacon_block:eip4844.SignedBeaconBlock(message: blck, signature: signature, root: blockRoot),
blobs_sidecar: eip4844.BlobsSidecar() blobs_sidecar: blobs_sidecar
) )
else: else:
static: doAssert "Unknown SignedBeaconBlock type" static: doAssert "Unknown SignedBeaconBlock type"

View File

@ -19,7 +19,7 @@ import
chronos/timer, eth/keys, taskpools, chronos/timer, eth/keys, taskpools,
../tests/testblockutil, ../tests/testblockutil,
../beacon_chain/spec/[forks, state_transition], ../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/[beacon_chain_db, beacon_clock],
../beacon_chain/eth1/eth1_monitor, ../beacon_chain/eth1/eth1_monitor,
../beacon_chain/validators/validator_pool, ../beacon_chain/validators/validator_pool,
@ -101,7 +101,8 @@ proc makeBeaconBlock(
var blck = partialBeaconBlock( var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, 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( let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache) cfg, state.data, blck.asSigVerified(), verificationFlags, cache)
@ -144,7 +145,8 @@ proc makeBeaconBlock(
var blck = partialBeaconBlock( var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, 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 # Signatures are verified elsewhere, so don't duplicate inefficiently here
let res = process_block( let res = process_block(
@ -188,7 +190,8 @@ proc makeBeaconBlock(
var blck = partialBeaconBlock( var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, 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( let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache) cfg, state.data, blck.asSigVerified(), verificationFlags, cache)
@ -231,7 +234,8 @@ proc makeBeaconBlock(
var blck = partialBeaconBlock( var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, 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( let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache) cfg, state.data, blck.asSigVerified(), verificationFlags, cache)
@ -274,7 +278,8 @@ proc makeBeaconBlock(
var blck = partialBeaconBlock( var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, 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( let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache) cfg, state.data, blck.asSigVerified(), verificationFlags, cache)

View File

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

View File

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