github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/blockchain/receive_attestation.go (about)

     1  package blockchain
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"time"
     8  
     9  	"github.com/pkg/errors"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
    11  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    12  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    13  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    14  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    15  	"github.com/prysmaticlabs/prysm/shared/params"
    16  	"github.com/prysmaticlabs/prysm/shared/slotutil"
    17  	"github.com/sirupsen/logrus"
    18  	"go.opencensus.io/trace"
    19  )
    20  
    21  // AttestationReceiver interface defines the methods of chain service receive and processing new attestations.
    22  type AttestationReceiver interface {
    23  	ReceiveAttestationNoPubsub(ctx context.Context, att *ethpb.Attestation) error
    24  	AttestationPreState(ctx context.Context, att *ethpb.Attestation) (iface.BeaconState, error)
    25  	VerifyLmdFfgConsistency(ctx context.Context, att *ethpb.Attestation) error
    26  	VerifyFinalizedConsistency(ctx context.Context, root []byte) error
    27  }
    28  
    29  // ReceiveAttestationNoPubsub is a function that defines the operations that are performed on
    30  // attestation that is received from regular sync. The operations consist of:
    31  //  1. Validate attestation, update validator's latest vote
    32  //  2. Apply fork choice to the processed attestation
    33  //  3. Save latest head info
    34  func (s *Service) ReceiveAttestationNoPubsub(ctx context.Context, att *ethpb.Attestation) error {
    35  	ctx, span := trace.StartSpan(ctx, "beacon-chain.blockchain.ReceiveAttestationNoPubsub")
    36  	defer span.End()
    37  
    38  	if err := s.onAttestation(ctx, att); err != nil {
    39  		return errors.Wrap(err, "could not process attestation")
    40  	}
    41  
    42  	return nil
    43  }
    44  
    45  // AttestationPreState returns the pre state of attestation.
    46  func (s *Service) AttestationPreState(ctx context.Context, att *ethpb.Attestation) (iface.BeaconState, error) {
    47  	ss, err := helpers.StartSlot(att.Data.Target.Epoch)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  	if err := helpers.ValidateSlotClock(ss, uint64(s.genesisTime.Unix())); err != nil {
    52  		return nil, err
    53  	}
    54  	return s.getAttPreState(ctx, att.Data.Target)
    55  }
    56  
    57  // VerifyLmdFfgConsistency verifies that attestation's LMD and FFG votes are consistency to each other.
    58  func (s *Service) VerifyLmdFfgConsistency(ctx context.Context, a *ethpb.Attestation) error {
    59  	targetSlot, err := helpers.StartSlot(a.Data.Target.Epoch)
    60  	if err != nil {
    61  		return err
    62  	}
    63  	r, err := s.ancestor(ctx, a.Data.BeaconBlockRoot, targetSlot)
    64  	if err != nil {
    65  		return err
    66  	}
    67  	if !bytes.Equal(a.Data.Target.Root, r) {
    68  		return errors.New("FFG and LMD votes are not consistent")
    69  	}
    70  	return nil
    71  }
    72  
    73  // VerifyFinalizedConsistency verifies input root is consistent with finalized store.
    74  // When the input root is not be consistent with finalized store then we know it is not
    75  // on the finalized check point that leads to current canonical chain and should be rejected accordingly.
    76  func (s *Service) VerifyFinalizedConsistency(ctx context.Context, root []byte) error {
    77  	// A canonical root implies the root to has an ancestor that aligns with finalized check point.
    78  	// In this case, we could exit early to save on additional computation.
    79  	if s.cfg.ForkChoiceStore.IsCanonical(bytesutil.ToBytes32(root)) {
    80  		return nil
    81  	}
    82  
    83  	f := s.FinalizedCheckpt()
    84  	ss, err := helpers.StartSlot(f.Epoch)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	r, err := s.ancestor(ctx, root, ss)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	if !bytes.Equal(f.Root, r) {
    93  		return errors.New("Root and finalized store are not consistent")
    94  	}
    95  
    96  	return nil
    97  }
    98  
    99  // This routine processes fork choice attestations from the pool to account for validator votes and fork choice.
   100  func (s *Service) processAttestationsRoutine(subscribedToStateEvents chan<- struct{}) {
   101  	// Wait for state to be initialized.
   102  	stateChannel := make(chan *feed.Event, 1)
   103  	stateSub := s.cfg.StateNotifier.StateFeed().Subscribe(stateChannel)
   104  	subscribedToStateEvents <- struct{}{}
   105  	<-stateChannel
   106  	stateSub.Unsubscribe()
   107  
   108  	if s.genesisTime.IsZero() {
   109  		log.Warn("ProcessAttestations routine waiting for genesis time")
   110  		for s.genesisTime.IsZero() {
   111  			time.Sleep(1 * time.Second)
   112  		}
   113  		log.Warn("Genesis time received, now available to process attestations")
   114  	}
   115  
   116  	st := slotutil.NewSlotTicker(s.genesisTime, params.BeaconConfig().SecondsPerSlot)
   117  	for {
   118  		select {
   119  		case <-s.ctx.Done():
   120  			return
   121  		case <-st.C():
   122  			// Continue when there's no fork choice attestation, there's nothing to process and update head.
   123  			// This covers the condition when the node is still initial syncing to the head of the chain.
   124  			if s.cfg.AttPool.ForkchoiceAttestationCount() == 0 {
   125  				continue
   126  			}
   127  			s.processAttestations(s.ctx)
   128  			if err := s.updateHead(s.ctx, s.getJustifiedBalances()); err != nil {
   129  				log.Warnf("Resolving fork due to new attestation: %v", err)
   130  			}
   131  		}
   132  	}
   133  }
   134  
   135  // This processes fork choice attestations from the pool to account for validator votes and fork choice.
   136  func (s *Service) processAttestations(ctx context.Context) {
   137  	atts := s.cfg.AttPool.ForkchoiceAttestations()
   138  	for _, a := range atts {
   139  		// Based on the spec, don't process the attestation until the subsequent slot.
   140  		// This delays consideration in the fork choice until their slot is in the past.
   141  		// https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/fork-choice.md#validate_on_attestation
   142  		nextSlot := a.Data.Slot + 1
   143  		if err := helpers.VerifySlotTime(uint64(s.genesisTime.Unix()), nextSlot, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
   144  			continue
   145  		}
   146  
   147  		hasState := s.cfg.BeaconDB.HasStateSummary(ctx, bytesutil.ToBytes32(a.Data.BeaconBlockRoot))
   148  		hasBlock := s.hasBlock(ctx, bytesutil.ToBytes32(a.Data.BeaconBlockRoot))
   149  		if !(hasState && hasBlock) {
   150  			continue
   151  		}
   152  
   153  		if err := s.cfg.AttPool.DeleteForkchoiceAttestation(a); err != nil {
   154  			log.WithError(err).Error("Could not delete fork choice attestation in pool")
   155  		}
   156  
   157  		if !helpers.VerifyCheckpointEpoch(a.Data.Target, s.genesisTime) {
   158  			continue
   159  		}
   160  
   161  		if err := s.ReceiveAttestationNoPubsub(ctx, a); err != nil {
   162  			log.WithFields(logrus.Fields{
   163  				"slot":             a.Data.Slot,
   164  				"committeeIndex":   a.Data.CommitteeIndex,
   165  				"beaconBlockRoot":  fmt.Sprintf("%#x", bytesutil.Trunc(a.Data.BeaconBlockRoot)),
   166  				"targetRoot":       fmt.Sprintf("%#x", bytesutil.Trunc(a.Data.Target.Root)),
   167  				"aggregationCount": a.AggregationBits.Count(),
   168  			}).WithError(err).Warn("Could not process attestation for fork choice")
   169  		}
   170  	}
   171  }