mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-02-01 17:27:30 +00:00
validate EL block hash in EL simulation (#4420)
When simulating EL with `--optimistic` flag, perform block hash check.
This commit is contained in:
parent
07d4160e00
commit
c91d9d61e2
@ -374,14 +374,28 @@ proc storeBlock*(
|
||||
self.consensusManager.quarantine[].addUnviable(signedBlock.root)
|
||||
return err((VerifierError.UnviableFork, ProcessingStatus.completed))
|
||||
|
||||
if NewPayloadStatus.noResponse == payloadStatus and not self[].optimistic:
|
||||
# Disallow the `MissingParent` from leaking to the sync/request managers
|
||||
# as it will be descored. However sync and request managers interact via
|
||||
# `processBlock` (indirectly). `validator_duties` does call `storeBlock`
|
||||
# directly, so is exposed to this, but only cares about whether there is
|
||||
# an error or not.
|
||||
return err((
|
||||
VerifierError.MissingParent, ProcessingStatus.notCompleted))
|
||||
if NewPayloadStatus.noResponse == payloadStatus:
|
||||
if not self[].optimistic:
|
||||
# Disallow the `MissingParent` from leaking to the sync/request managers
|
||||
# as it will be descored. However sync and request managers interact via
|
||||
# `processBlock` (indirectly). `validator_duties` does call `storeBlock`
|
||||
# directly, so is exposed to this, but only cares about whether there is
|
||||
# an error or not.
|
||||
return err((
|
||||
VerifierError.MissingParent, ProcessingStatus.notCompleted))
|
||||
|
||||
# Client software MUST validate blockHash value as being equivalent to
|
||||
# Keccak256(RLP(ExecutionBlockHeader))
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.1/src/engine/specification.md#specification
|
||||
when typeof(signedBlock).toFork() >= BeaconBlockFork.Bellatrix:
|
||||
template payload(): auto = signedBlock.message.body.execution_payload
|
||||
if payload.block_hash != payload.compute_execution_block_hash():
|
||||
debug "EL block hash validation failed", execution_payload = payload
|
||||
doAssert strictVerification notin dag.updateFlags
|
||||
self.consensusManager.quarantine[].addUnviable(signedBlock.root)
|
||||
return err((VerifierError.UnviableFork, ProcessingStatus.completed))
|
||||
else:
|
||||
discard
|
||||
|
||||
# We'll also remove the block as an orphan: it's unlikely the parent is
|
||||
# missing if we get this far - should that be the case, the block will
|
||||
|
@ -372,6 +372,19 @@ func compute_timestamp_at_slot*(state: ForkyBeaconState, slot: Slot): uint64 =
|
||||
let slots_since_genesis = slot - GENESIS_SLOT
|
||||
state.genesis_time + slots_since_genesis * SECONDS_PER_SLOT
|
||||
|
||||
proc computeTransactionsTrieRoot*(
|
||||
payload: bellatrix.ExecutionPayload | capella.ExecutionPayload): Hash256 =
|
||||
if payload.transactions.len == 0:
|
||||
return EMPTY_ROOT_HASH
|
||||
|
||||
var tr = initHexaryTrie(newMemoryDB())
|
||||
for i, transaction in payload.transactions:
|
||||
try:
|
||||
tr.put(rlp.encode(i), distinctBase(transaction)) # Already RLP encoded
|
||||
except RlpError as exc:
|
||||
doAssert false, "HexaryTrie.put failed: " & $exc.msg
|
||||
tr.rootHash()
|
||||
|
||||
func gweiToWei*(gwei: Gwei): UInt256 =
|
||||
gwei.u256 * 1_000_000_000.u256
|
||||
|
||||
@ -397,18 +410,15 @@ proc computeWithdrawalsTrieRoot*(
|
||||
doAssert false, "HexaryTrie.put failed: " & $exc.msg
|
||||
tr.rootHash()
|
||||
|
||||
proc emptyPayloadToBlockHeader*(
|
||||
proc payloadToBlockHeader*(
|
||||
payload: bellatrix.ExecutionPayload | capella.ExecutionPayload
|
||||
): ExecutionBlockHeader =
|
||||
static: # `GasInt` is signed. We only use it for hashing.
|
||||
doAssert sizeof(GasInt) == sizeof(payload.gas_limit)
|
||||
doAssert sizeof(GasInt) == sizeof(payload.gas_used)
|
||||
|
||||
## This function assumes that the payload is empty!
|
||||
doAssert payload.transactions.len == 0
|
||||
|
||||
let
|
||||
txRoot = EMPTY_ROOT_HASH
|
||||
txRoot = payload.computeTransactionsTrieRoot()
|
||||
withdrawalsRoot =
|
||||
when payload is bellatrix.ExecutionPayload:
|
||||
none(Hash256)
|
||||
@ -434,7 +444,12 @@ proc emptyPayloadToBlockHeader*(
|
||||
fee : some payload.base_fee_per_gas,
|
||||
withdrawalsRoot: withdrawalsRoot)
|
||||
|
||||
func build_empty_execution_payload*(
|
||||
proc compute_execution_block_hash*(
|
||||
payload: bellatrix.ExecutionPayload | capella.ExecutionPayload
|
||||
): Eth2Digest =
|
||||
rlpHash payloadToBlockHeader(payload)
|
||||
|
||||
proc build_empty_execution_payload*(
|
||||
state: bellatrix.BeaconState,
|
||||
feeRecipient: Eth1Address): bellatrix.ExecutionPayload =
|
||||
## Assuming a pre-state of the same slot, build a valid ExecutionPayload
|
||||
@ -459,7 +474,7 @@ func build_empty_execution_payload*(
|
||||
timestamp: timestamp,
|
||||
base_fee_per_gas: base_fee)
|
||||
|
||||
payload.block_hash = rlpHash emptyPayloadToBlockHeader(payload)
|
||||
payload.block_hash = payload.compute_execution_block_hash()
|
||||
|
||||
payload
|
||||
|
||||
@ -491,6 +506,6 @@ proc build_empty_execution_payload*(
|
||||
for withdrawal in expectedWithdrawals:
|
||||
doAssert payload.withdrawals.add withdrawal
|
||||
|
||||
payload.block_hash = rlpHash emptyPayloadToBlockHeader(payload)
|
||||
payload.block_hash = payload.compute_execution_block_hash()
|
||||
|
||||
payload
|
||||
|
@ -96,7 +96,7 @@ suite "Spec helpers":
|
||||
for i, withdrawal in withdrawals:
|
||||
check payload.withdrawals[i] == withdrawal
|
||||
|
||||
let elHeader = emptyPayloadToBlockHeader(payload)
|
||||
let elHeader = payloadToBlockHeader(payload)
|
||||
check elHeader.withdrawalsRoot.isSome
|
||||
if withdrawals.len == 0:
|
||||
check elHeader.withdrawalsRoot.get == EMPTY_ROOT_HASH
|
||||
|
@ -81,7 +81,7 @@ func signBlock(
|
||||
from ../beacon_chain/spec/datatypes/capella import
|
||||
BeaconState, ExecutionPayload, SignedBLSToExecutionChangeList
|
||||
|
||||
func build_empty_merge_execution_payload(state: bellatrix.BeaconState):
|
||||
proc build_empty_merge_execution_payload(state: bellatrix.BeaconState):
|
||||
bellatrix.ExecutionPayload =
|
||||
## Assuming a pre-state of the same slot, build a valid ExecutionPayload
|
||||
## without any transactions from a non-merged block.
|
||||
@ -104,7 +104,7 @@ func build_empty_merge_execution_payload(state: bellatrix.BeaconState):
|
||||
timestamp: timestamp,
|
||||
base_fee_per_gas: EIP1559_INITIAL_BASE_FEE)
|
||||
|
||||
payload.block_hash = rlpHash emptyPayloadToBlockHeader(payload)
|
||||
payload.block_hash = rlpHash payloadToBlockHeader(payload)
|
||||
|
||||
payload
|
||||
|
||||
@ -131,7 +131,7 @@ proc build_empty_merge_execution_payload(state: capella.BeaconState):
|
||||
timestamp: timestamp,
|
||||
base_fee_per_gas: EIP1559_INITIAL_BASE_FEE)
|
||||
|
||||
payload.block_hash = rlpHash emptyPayloadToBlockHeader(payload)
|
||||
payload.block_hash = rlpHash payloadToBlockHeader(payload)
|
||||
|
||||
payload
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user