Skip to content

Commit

Permalink
eip4844 beacon block proposals (status-im#4540)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
henridf authored Jan 21, 2023
1 parent 90e1698 commit 349001b
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 22 deletions.
2 changes: 2 additions & 0 deletions beacon_chain/spec/forks.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
28 changes: 19 additions & 9 deletions beacon_chain/spec/state_transition.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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:
Expand All @@ -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(),
Expand Down Expand Up @@ -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
Expand All @@ -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](
Expand All @@ -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)
67 changes: 60 additions & 7 deletions beacon_chain/validators/validator_duties.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -514,6 +543,7 @@ proc makeBeaconBlockForHeadAndSlot*[EP](
exits,
syncAggregate,
payload,
(static(default(KZGCommitmentList))),
noRollback, # Temporary state - no need for rollback
cache,
verificationFlags = {},
Expand Down Expand Up @@ -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:
Expand All @@ -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(
Expand Down Expand Up @@ -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"
Expand Down
17 changes: 11 additions & 6 deletions research/block_sim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions research/wss_sim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ cli do(validatorsDir: string, secretsDir: string,
BeaconBlockValidatorChanges(),
syncAggregate,
default(bellatrix.ExecutionPayload),
default(eip4844.KZGCommitmentList),
noRollback,
cache).get()

Expand Down
1 change: 1 addition & 0 deletions tests/testblockutil.nim
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ proc addTestBlockAux[EP: bellatrix.ExecutionPayload | capella.ExecutionPayload](
BeaconBlockValidatorChanges(),
sync_aggregate,
execution_payload,
(static(default(eip4844.KZGCommitmentList))),
noRollback,
cache,
verificationFlags = {skipBlsValidation})
Expand Down

0 comments on commit 349001b

Please sign in to comment.