Merge BeaconBlock gossip validation (#3165)
* Merge BeaconBlock gossip validation * figure/ground inversion * revert cosmetic cleanups to reduce merge conflicts
This commit is contained in:
parent
6f077ce82c
commit
2ca28fb861
|
@ -177,6 +177,10 @@ type
|
|||
eth1_deposit_index*: uint64
|
||||
beacon_proposers*: array[SLOTS_PER_EPOCH, Option[ValidatorIndex]]
|
||||
shuffled_active_validator_indices*: seq[ValidatorIndex]
|
||||
|
||||
# enables more efficient merge block validation
|
||||
merge_transition_complete*: bool
|
||||
|
||||
# balances, as used in fork choice
|
||||
effective_balances_bytes*: seq[byte]
|
||||
|
||||
|
|
|
@ -153,7 +153,15 @@ func init*(
|
|||
getStateField(state.data, current_justified_checkpoint),
|
||||
finalized_checkpoint: getStateField(state.data, finalized_checkpoint),
|
||||
shuffled_active_validator_indices:
|
||||
cache.get_shuffled_active_validator_indices(state.data, epoch)
|
||||
cache.get_shuffled_active_validator_indices(state.data, epoch),
|
||||
merge_transition_complete:
|
||||
case state.data.kind:
|
||||
of BeaconStateFork.Phase0: false
|
||||
of BeaconStateFork.Altair: false
|
||||
of BeaconStateFork.Merge:
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/merge/beacon-chain.md#is_merge_transition_complete
|
||||
state.data.mergeData.data.latest_execution_payload_header !=
|
||||
ExecutionPayloadHeader()
|
||||
)
|
||||
|
||||
for i in 0'u64..<SLOTS_PER_EPOCH:
|
||||
|
|
|
@ -355,7 +355,7 @@ proc addBlock*(chain: var Eth1Chain, newBlock: Eth1Block) =
|
|||
chain.blocksByHash[newBlock.voteData.block_hash.asBlockHash] = newBlock
|
||||
eth1_chain_len.set chain.blocks.len.int64
|
||||
|
||||
func hash(x: Eth1Data): Hash =
|
||||
func hash*(x: Eth1Data): Hash =
|
||||
hash(x.block_hash)
|
||||
|
||||
template awaitWithRetries*[T](lazyFutExpr: Future[T],
|
||||
|
|
|
@ -12,7 +12,7 @@ import
|
|||
stew/results, bearssl,
|
||||
chronicles, chronos, metrics, taskpools,
|
||||
../spec/[helpers, forks],
|
||||
../spec/datatypes/[altair, phase0],
|
||||
../spec/datatypes/[altair, merge, phase0],
|
||||
../consensus_object_pools/[
|
||||
block_clearance, block_quarantine, blockchain_dag, exit_pool, attestation_pool,
|
||||
sync_committee_msg_pool],
|
||||
|
@ -172,7 +172,8 @@ proc new*(T: type Eth2Processor,
|
|||
|
||||
proc blockValidator*(
|
||||
self: var Eth2Processor,
|
||||
signedBlock: phase0.SignedBeaconBlock | altair.SignedBeaconBlock): ValidationRes =
|
||||
signedBlock: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
|
||||
merge.SignedBeaconBlock): ValidationRes =
|
||||
let
|
||||
wallTime = self.getCurrentBeaconTime()
|
||||
(afterGenesis, wallSlot) = wallTime.toSlot()
|
||||
|
|
|
@ -12,7 +12,7 @@ import
|
|||
chronicles, chronos, metrics,
|
||||
stew/results,
|
||||
# Internals
|
||||
../spec/datatypes/[phase0, altair],
|
||||
../spec/datatypes/[phase0, altair, merge],
|
||||
../spec/[
|
||||
beaconstate, state_transition_block, forks, helpers, network, signatures],
|
||||
../consensus_object_pools/[
|
||||
|
@ -141,10 +141,9 @@ func check_attestation_subnet(
|
|||
epochRef: EpochRef, attestation: Attestation,
|
||||
subnet_id: SubnetId): Result[void, ValidationError] =
|
||||
let
|
||||
expectedSubnet =
|
||||
compute_subnet_for_attestation(
|
||||
get_committee_count_per_slot(epochRef),
|
||||
attestation.data.slot, attestation.data.index.CommitteeIndex)
|
||||
expectedSubnet = compute_subnet_for_attestation(
|
||||
get_committee_count_per_slot(epochRef),
|
||||
attestation.data.slot, attestation.data.index.CommitteeIndex)
|
||||
|
||||
if expectedSubnet != subnet_id:
|
||||
return errReject("Attestation not on the correct subnet")
|
||||
|
@ -171,10 +170,59 @@ template checkedReject(error: ValidationError): untyped =
|
|||
raiseAssert $error[1]
|
||||
err(error)
|
||||
|
||||
template validateBeaconBlockMerge(
|
||||
signed_beacon_block: phase0.SignedBeaconBlock |
|
||||
altair.SignedBeaconBlock): untyped =
|
||||
discard
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/merge/p2p-interface.md#beacon_block
|
||||
template validateBeaconBlockMerge(
|
||||
signed_beacon_block: merge.SignedBeaconBlock): untyped =
|
||||
# If the execution is enabled for the block -- i.e.
|
||||
# is_execution_enabled(state, block.body) then validate the following:
|
||||
let executionEnabled =
|
||||
if signed_beacon_block.message.body.execution_payload !=
|
||||
default(ExecutionPayload):
|
||||
true
|
||||
elif dag.getEpochRef(parent_ref, parent_ref.slot.epoch).merge_transition_complete:
|
||||
# Should usually be inexpensive, but could require cache refilling
|
||||
true
|
||||
else:
|
||||
# Somewhat more expensive fallback, with database I/O, but should be
|
||||
# mostly relevant around merge transition epochs. It's possible that
|
||||
# the previous block is phase 0 or Altair, if this is the transition
|
||||
# block itself.
|
||||
let blockData = dag.get(parent_ref)
|
||||
case blockData.data.kind:
|
||||
of BeaconBlockFork.Phase0:
|
||||
false
|
||||
of BeaconBlockFork.Altair:
|
||||
false
|
||||
of BeaconBlockFork.Merge:
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/merge/beacon-chain.md#process_execution_payload
|
||||
# shows how this gets folded into the state each block; checking this
|
||||
# is equivalent, without ever requiring state replay or any similarly
|
||||
# expensive computation.
|
||||
blockData.data.mergeData.message.body.execution_payload !=
|
||||
default(ExecutionPayload)
|
||||
|
||||
if executionEnabled:
|
||||
# [REJECT] The block's execution payload timestamp is correct with respect
|
||||
# to the slot -- i.e. execution_payload.timestamp ==
|
||||
# compute_timestamp_at_slot(state, block.slot).
|
||||
let timestampAtSlot =
|
||||
withState(dag.headState.data):
|
||||
compute_timestamp_at_slot(state.data, signed_beacon_block.message.slot)
|
||||
if not (signed_beacon_block.message.body.execution_payload.timestamp ==
|
||||
timestampAtSlot):
|
||||
return errReject("BeaconBlock: Mismatched execution payload timestamp")
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/p2p-interface.md#beacon_block
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/merge/p2p-interface.md#beacon_block
|
||||
proc validateBeaconBlock*(
|
||||
dag: ChainDAGRef, quarantine: ref Quarantine,
|
||||
signed_beacon_block: phase0.SignedBeaconBlock | altair.SignedBeaconBlock,
|
||||
signed_beacon_block: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
|
||||
merge.SignedBeaconBlock,
|
||||
wallTime: BeaconTime, flags: UpdateFlags): Result[void, ValidationError] =
|
||||
# In general, checks are ordered from cheap to expensive. Especially, crypto
|
||||
# verification could be quite a bit more expensive than the rest. This is an
|
||||
|
@ -296,6 +344,8 @@ proc validateBeaconBlock*(
|
|||
signed_beacon_block.signature):
|
||||
return errReject("Invalid proposer signature")
|
||||
|
||||
validateBeaconBlockMerge(signed_beacon_block)
|
||||
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/p2p-interface.md#beacon_attestation_subnet_id
|
||||
|
|
|
@ -1047,6 +1047,11 @@ proc installMessageValidators(node: BeaconNode) =
|
|||
proc (signedBlock: altair.SignedBeaconBlock): ValidationResult =
|
||||
toValidationResult(node.processor[].blockValidator(signedBlock)))
|
||||
|
||||
node.network.addValidator(
|
||||
getBeaconBlocksTopic(node.dag.forkDigests.merge),
|
||||
proc (signedBlock: merge.SignedBeaconBlock): ValidationResult =
|
||||
toValidationResult(node.processor[].blockValidator(signedBlock)))
|
||||
|
||||
template installSyncCommitteeeValidators(digest: auto) =
|
||||
for committeeIdx in allSyncSubcommittees():
|
||||
closureScope:
|
||||
|
|
Loading…
Reference in New Issue