@@ -218,6 +218,15 @@ fn dequeue_attestations(
218
218
std:: mem:: replace ( queued_attestations, remaining)
219
219
}
220
220
221
+ /// Denotes whether an attestation we are processing received from a block or from gossip.
222
+ /// Equivalent to the `is_from_block` bool in:
223
+ ///
224
+ /// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/fork-choice.md#validate_on_attestation
225
+ pub enum AttestationFromBlock {
226
+ True ,
227
+ False ,
228
+ }
229
+
221
230
/// Provides an implementation of "Ethereum 2.0 Phase 0 -- Beacon Chain Fork Choice":
222
231
///
223
232
/// https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/fork-choice.md#ethereum-20-phase-0----beacon-chain-fork-choice
@@ -537,25 +546,9 @@ where
537
546
if state. finalized_checkpoint ( ) . epoch > self . fc_store . finalized_checkpoint ( ) . epoch {
538
547
self . fc_store
539
548
. set_finalized_checkpoint ( state. finalized_checkpoint ( ) ) ;
540
- let finalized_slot =
541
- compute_start_slot_at_epoch :: < E > ( self . fc_store . finalized_checkpoint ( ) . epoch ) ;
542
-
543
- // Note: the `if` statement here is not part of the specification, but I claim that it
544
- // is an optimization and equivalent to the specification. See this PR for more
545
- // information:
546
- //
547
- // https://github.com/ethereum/eth2.0-specs/pull/1880
548
- if * self . fc_store . justified_checkpoint ( ) != state. current_justified_checkpoint ( )
549
- && ( state. current_justified_checkpoint ( ) . epoch
550
- > self . fc_store . justified_checkpoint ( ) . epoch
551
- || self
552
- . get_ancestor ( self . fc_store . justified_checkpoint ( ) . root , finalized_slot) ?
553
- != Some ( self . fc_store . finalized_checkpoint ( ) . root ) )
554
- {
555
- self . fc_store
556
- . set_justified_checkpoint ( state. current_justified_checkpoint ( ) )
557
- . map_err ( Error :: UnableToSetJustifiedCheckpoint ) ?;
558
- }
549
+ self . fc_store
550
+ . set_justified_checkpoint ( state. current_justified_checkpoint ( ) )
551
+ . map_err ( Error :: UnableToSetJustifiedCheckpoint ) ?;
559
552
}
560
553
561
554
let target_slot = block
@@ -629,6 +622,35 @@ where
629
622
Ok ( ( ) )
630
623
}
631
624
625
+ /// Validates the `epoch` against the current time according to the fork choice store.
626
+ ///
627
+ /// ## Specification
628
+ ///
629
+ /// Equivalent to:
630
+ ///
631
+ /// https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/fork-choice.md#validate_target_epoch_against_current_time
632
+ fn validate_target_epoch_against_current_time (
633
+ & self ,
634
+ target_epoch : Epoch ,
635
+ ) -> Result < ( ) , InvalidAttestation > {
636
+ let slot_now = self . fc_store . get_current_slot ( ) ;
637
+ let epoch_now = slot_now. epoch ( E :: slots_per_epoch ( ) ) ;
638
+
639
+ // Attestation must be from the current or previous epoch.
640
+ if target_epoch > epoch_now {
641
+ return Err ( InvalidAttestation :: FutureEpoch {
642
+ attestation_epoch : target_epoch,
643
+ current_epoch : epoch_now,
644
+ } ) ;
645
+ } else if target_epoch + 1 < epoch_now {
646
+ return Err ( InvalidAttestation :: PastEpoch {
647
+ attestation_epoch : target_epoch,
648
+ current_epoch : epoch_now,
649
+ } ) ;
650
+ }
651
+ Ok ( ( ) )
652
+ }
653
+
632
654
/// Validates the `indexed_attestation` for application to fork choice.
633
655
///
634
656
/// ## Specification
@@ -639,6 +661,7 @@ where
639
661
fn validate_on_attestation (
640
662
& self ,
641
663
indexed_attestation : & IndexedAttestation < E > ,
664
+ is_from_block : AttestationFromBlock ,
642
665
) -> Result < ( ) , InvalidAttestation > {
643
666
// There is no point in processing an attestation with an empty bitfield. Reject
644
667
// it immediately.
@@ -649,21 +672,10 @@ where
649
672
return Err ( InvalidAttestation :: EmptyAggregationBitfield ) ;
650
673
}
651
674
652
- let slot_now = self . fc_store . get_current_slot ( ) ;
653
- let epoch_now = slot_now. epoch ( E :: slots_per_epoch ( ) ) ;
654
675
let target = indexed_attestation. data . target ;
655
676
656
- // Attestation must be from the current or previous epoch.
657
- if target. epoch > epoch_now {
658
- return Err ( InvalidAttestation :: FutureEpoch {
659
- attestation_epoch : target. epoch ,
660
- current_epoch : epoch_now,
661
- } ) ;
662
- } else if target. epoch + 1 < epoch_now {
663
- return Err ( InvalidAttestation :: PastEpoch {
664
- attestation_epoch : target. epoch ,
665
- current_epoch : epoch_now,
666
- } ) ;
677
+ if matches ! ( is_from_block, AttestationFromBlock :: False ) {
678
+ self . validate_target_epoch_against_current_time ( target. epoch ) ?;
667
679
}
668
680
669
681
if target. epoch != indexed_attestation. data . slot . epoch ( E :: slots_per_epoch ( ) ) {
@@ -746,6 +758,7 @@ where
746
758
& mut self ,
747
759
current_slot : Slot ,
748
760
attestation : & IndexedAttestation < E > ,
761
+ is_from_block : AttestationFromBlock ,
749
762
) -> Result < ( ) , Error < T :: Error > > {
750
763
// Ensure the store is up-to-date.
751
764
self . update_time ( current_slot) ?;
@@ -767,7 +780,7 @@ where
767
780
return Ok ( ( ) ) ;
768
781
}
769
782
770
- self . validate_on_attestation ( attestation) ?;
783
+ self . validate_on_attestation ( attestation, is_from_block ) ?;
771
784
772
785
if attestation. data . slot < self . fc_store . get_current_slot ( ) {
773
786
for validator_index in attestation. attesting_indices . iter ( ) {
0 commit comments