@@ -328,144 +328,3 @@ proc addRawBlock*(
328328 if parent != nil :
329329 return addRawBlockKnownParent (dag, quarantine, signedBlock, parent, onBlockAdded)
330330 return addRawBlockUnresolved (dag, quarantine, signedBlock)
331-
332- # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/p2p-interface.md#beacon_block
333- proc isValidBeaconBlock * (
334- dag: ChainDAGRef , quarantine: var QuarantineRef ,
335- signed_beacon_block: SignedBeaconBlock , wallTime: BeaconTime ,
336- flags: UpdateFlags ):
337- Result [void , (ValidationResult , BlockError )] =
338- logScope:
339- topics = " clearance valid_blck"
340- received_block = shortLog (signed_beacon_block.message)
341- blockRoot = shortLog (signed_beacon_block.root)
342-
343- # In general, checks are ordered from cheap to expensive. Especially, crypto
344- # verification could be quite a bit more expensive than the rest. This is an
345- # externally easy-to-invoke function by tossing network packets at the node.
346-
347- # [IGNORE] The block is not from a future slot (with a
348- # MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e. validate that
349- # signed_beacon_block.message.slot <= current_slot (a client MAY queue future
350- # blocks for processing at the appropriate slot).
351- if not (signed_beacon_block.message.slot <=
352- (wallTime + MAXIMUM_GOSSIP_CLOCK_DISPARITY ).slotOrZero):
353- debug " block is from a future slot" ,
354- wallSlot = wallTime.toSlot ()
355- return err ((ValidationResult .Ignore , Invalid ))
356-
357- # [IGNORE] The block is from a slot greater than the latest finalized slot --
358- # i.e. validate that signed_beacon_block.message.slot >
359- # compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
360- if not (signed_beacon_block.message.slot > dag.finalizedHead.slot):
361- debug " block is not from a slot greater than the latest finalized slot"
362- return err ((ValidationResult .Ignore , Invalid ))
363-
364- # [IGNORE] The block is the first block with valid signature received for the
365- # proposer for the slot, signed_beacon_block.message.slot.
366- #
367- # While this condition is similar to the proposer slashing condition at
368- # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#proposer-slashing
369- # it's not identical, and this check does not address slashing:
370- #
371- # (1) The beacon blocks must be conflicting, i.e. different, for the same
372- # slot and proposer. This check also catches identical blocks.
373- #
374- # (2) By this point in the function, it's not been checked whether they're
375- # signed yet. As in general, expensive checks should be deferred, this
376- # would add complexity not directly relevant this function.
377- #
378- # (3) As evidenced by point (1), the similarity in the validation condition
379- # and slashing condition, while not coincidental, aren't similar enough
380- # to combine, as one or the other might drift.
381- #
382- # (4) Furthermore, this function, as much as possible, simply returns a yes
383- # or no answer, without modifying other state for p2p network interface
384- # validation. Complicating this interface, for the sake of sharing only
385- # couple lines of code, wouldn't be worthwhile.
386- #
387- # TODO might check unresolved/orphaned blocks too, and this might not see all
388- # blocks at a given slot (though, in theory, those get checked elsewhere), or
389- # adding metrics that count how often these conditions occur.
390- let
391- slotBlockRef = getBlockBySlot (dag, signed_beacon_block.message.slot)
392-
393- if not slotBlockRef.isNil:
394- let blck = dag.get (slotBlockRef).data
395- if blck.message.proposer_index ==
396- signed_beacon_block.message.proposer_index and
397- blck.message.slot == signed_beacon_block.message.slot and
398- blck.signature.toRaw () != signed_beacon_block.signature.toRaw ():
399- notice " block isn't first block with valid signature received for the proposer" ,
400- blckRef = slotBlockRef,
401- existing_block = shortLog (blck.message)
402- return err ((ValidationResult .Ignore , Invalid ))
403-
404- # [IGNORE] The block's parent (defined by block.parent_root) has been seen
405- # (via both gossip and non-gossip sources) (a client MAY queue blocks for
406- # processing once the parent block is retrieved).
407- #
408- # And implicitly:
409- # [REJECT] The block's parent (defined by block.parent_root) passes validation.
410- let parent_ref = dag.getRef (signed_beacon_block.message.parent_root)
411- if parent_ref.isNil:
412- # Pending dag gets checked via `ChainDAGRef.add(...)` later, and relevant
413- # checks are performed there. In usual paths beacon_node adds blocks via
414- # ChainDAGRef.add(...) directly, with no additional validity checks.
415- debug " parent unknown, putting block in quarantine" ,
416- current_slot = wallTime.toSlot ()
417- if not quarantine.add (dag, signed_beacon_block):
418- debug " Block quarantine full"
419- return err ((ValidationResult .Ignore , MissingParent ))
420-
421- # [REJECT] The current finalized_checkpoint is an ancestor of block -- i.e.
422- # get_ancestor(store, block.parent_root,
423- # compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)) ==
424- # store.finalized_checkpoint.root
425- let
426- finalized_checkpoint = dag.headState.data.data.finalized_checkpoint
427- ancestor = get_ancestor (
428- parent_ref, compute_start_slot_at_epoch (finalized_checkpoint.epoch))
429-
430- if ancestor.isNil:
431- debug " couldn't find ancestor block"
432- return err ((ValidationResult .Ignore , Invalid )) # might not've received block
433-
434- if not (finalized_checkpoint.root in [ancestor.root, Eth2Digest ()]):
435- debug " block not descendent of finalized block"
436- return err ((ValidationResult .Reject , Invalid ))
437-
438- # [REJECT] The block is proposed by the expected proposer_index for the
439- # block's slot in the context of the current shuffling (defined by
440- # parent_root/slot). If the proposer_index cannot immediately be verified
441- # against the expected shuffling, the block MAY be queued for later
442- # processing while proposers for the block's branch are calculated -- in such
443- # a case do not REJECT, instead IGNORE this message.
444- let
445- proposer = getProposer (dag, parent_ref, signed_beacon_block.message.slot)
446-
447- if proposer.isNone:
448- warn " cannot compute proposer for message"
449- return err ((ValidationResult .Ignore , Invalid )) # internal issue
450-
451- if proposer.get ()[0 ] !=
452- ValidatorIndex (signed_beacon_block.message.proposer_index):
453- notice " block had unexpected proposer" ,
454- expected_proposer = proposer.get ()[0 ]
455- return err ((ValidationResult .Reject , Invalid ))
456-
457- # [REJECT] The proposer signature, signed_beacon_block.signature, is valid
458- # with respect to the proposer_index pubkey.
459- if not verify_block_signature (
460- dag.headState.data.data.fork,
461- dag.headState.data.data.genesis_validators_root,
462- signed_beacon_block.message.slot,
463- signed_beacon_block.message,
464- proposer.get ()[1 ],
465- signed_beacon_block.signature):
466- debug " block failed signature verification" ,
467- signature = shortLog (signed_beacon_block.signature)
468-
469- return err ((ValidationResult .Reject , Invalid ))
470-
471- ok ()
0 commit comments