Skip to content

Commit

Permalink
check blob versioned hashes when no EL is connected (#6501)
Browse files Browse the repository at this point in the history
* check blob versioned hashes when no EL is connected

When no EL is conencted, we have to at the very least ensure that the
data in the beacon block is consistent with the execution payload.
We already do this for the block hash, but also have to do it for the
`blob_kzg_commitments`. To validate that they are linked with the
execution payload, we have to RLP decode all EIP-4844 blob transactions
and compare their blob versioned hashes with the hashed commitments.

* simplify loop in case where `blob_versioned_hashes` doesn't exist

* skip blob transaction parsing pre Deneb
  • Loading branch information
etan-status authored Aug 22, 2024
1 parent 21aeeaf commit a597fe9
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 7 deletions.
23 changes: 16 additions & 7 deletions beacon_chain/gossip_processing/block_processor.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import
chronicles, chronos, metrics,
../spec/[forks, signatures, signatures_batch],
../spec/[forks, helpers_el, signatures, signatures_batch],
../sszdump

from std/deques import Deque, addLast, contains, initDeque, items, len, shrink
Expand Down Expand Up @@ -548,8 +548,11 @@ proc storeBlock(
if signedBlock.message.is_execution_block:
template payload(): auto = signedBlock.message.body.execution_payload

template returnWithError(msg: string): untyped =
debug msg, executionPayload = shortLog(payload)
template returnWithError(msg: string, extraMsg = ""): untyped =
if extraMsg != "":
debug msg, reason = extraMsg, executionPayload = shortLog(payload)
else:
debug msg, executionPayload = shortLog(payload)
self[].dumpInvalidBlock(signedBlock)
doAssert strictVerification notin dag.updateFlags
self.consensusManager.quarantine[].addUnviable(signedBlock.root)
Expand All @@ -563,10 +566,16 @@ proc storeBlock(
returnWithError "Execution block hash validation failed"

# [New in Deneb:EIP4844]
# TODO run https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/deneb/beacon-chain.md#blob-kzg-commitments
# https://github.com/ethereum/execution-apis/blob/main/src/engine/experimental/blob-extension.md#specification
# "This validation MUST be instantly run in all cases even during active
# sync process."
when typeof(signedBlock).kind >= ConsensusFork.Deneb:
let blobsRes = signedBlock.message.is_valid_versioned_hashes
if blobsRes.isErr:
returnWithError "Blob versioned hashes invalid", blobsRes.error
else:
# If there are EIP-4844 (type 3) transactions in the payload with
# versioned hashes, the transactions would be rejected by the EL
# based on payload timestamp (only allowed post Deneb);
# There are no `blob_kzg_commitments` before Deneb to compare against
discard

let newPayloadTick = Moment.now()

Expand Down
46 changes: 46 additions & 0 deletions beacon_chain/spec/helpers_el.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# beacon_chain
# Copyright (c) 2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.

{.push raises: [].}

import
std/typetraits,
eth/common/eth_types_rlp,
"."/[helpers, state_transition_block]

func readExecutionTransaction(
txBytes: bellatrix.Transaction): Result[ExecutionTransaction, string] =
# Nim 2.0.8: `rlp.decode(distinctBase(txBytes), ExecutionTransaction)`
# uses the generic `read` from `rlp.nim` instead of the specific `read`
# from `eth_types_rlp.nim`, leading to compilation error.
# Doing this in two steps works around this resolution order issue.
var rlp = rlpFromBytes(distinctBase(txBytes))
try:
ok rlp.read(ExecutionTransaction)
except RlpError as exc:
err("Invalid transaction: " & exc.msg)

# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.4/specs/deneb/beacon-chain.md#is_valid_versioned_hashes
func is_valid_versioned_hashes*(blck: ForkyBeaconBlock): Result[void, string] =
static: doAssert typeof(blck).kind >= ConsensusFork.Deneb
template transactions: untyped = blck.body.execution_payload.transactions
template commitments: untyped = blck.body.blob_kzg_commitments

var i = 0
for txBytes in transactions:
if txBytes.len == 0 or txBytes[0] != TxEip4844.byte:
continue # Only blob transactions may have blobs
let tx = ? txBytes.readExecutionTransaction()
for vHash in tx.versionedHashes:
if commitments.len <= i:
return err("Extra blobs without matching `blob_kzg_commitments`")
if vHash.data != kzg_commitment_to_versioned_hash(commitments[i]):
return err("Invalid `blob_versioned_hash` at index " & $i)
inc i
if i != commitments.len:
return err("Extra `blob_kzg_commitments` without matching blobs")
ok()

0 comments on commit a597fe9

Please sign in to comment.