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

     1  package blockchain
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strconv"
     7  
     8  	"github.com/pkg/errors"
     9  	types "github.com/prysmaticlabs/eth2-types"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    11  	"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
    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/featureconfig"
    16  	"github.com/prysmaticlabs/prysm/shared/mputil"
    17  	"github.com/prysmaticlabs/prysm/shared/params"
    18  )
    19  
    20  // getAttPreState retrieves the att pre state by either from the cache or the DB.
    21  func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (iface.BeaconState, error) {
    22  	// Use a multilock to allow scoped holding of a mutex by a checkpoint root + epoch
    23  	// allowing us to behave smarter in terms of how this function is used concurrently.
    24  	epochKey := strconv.FormatUint(uint64(c.Epoch), 10 /* base 10 */)
    25  	lock := mputil.NewMultilock(string(c.Root) + epochKey)
    26  	lock.Lock()
    27  	defer lock.Unlock()
    28  	cachedState, err := s.checkpointStateCache.StateByCheckpoint(c)
    29  	if err != nil {
    30  		return nil, errors.Wrap(err, "could not get cached checkpoint state")
    31  	}
    32  	if cachedState != nil && !cachedState.IsNil() {
    33  		return cachedState, nil
    34  	}
    35  
    36  	baseState, err := s.cfg.StateGen.StateByRoot(ctx, bytesutil.ToBytes32(c.Root))
    37  	if err != nil {
    38  		return nil, errors.Wrapf(err, "could not get pre state for epoch %d", c.Epoch)
    39  	}
    40  
    41  	epochStartSlot, err := helpers.StartSlot(c.Epoch)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	if epochStartSlot > baseState.Slot() {
    46  		if featureconfig.Get().EnableNextSlotStateCache {
    47  			baseState, err = state.ProcessSlotsUsingNextSlotCache(ctx, baseState, c.Root, epochStartSlot)
    48  			if err != nil {
    49  				return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch)
    50  			}
    51  		} else {
    52  			baseState, err = state.ProcessSlots(ctx, baseState, epochStartSlot)
    53  			if err != nil {
    54  				return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch)
    55  			}
    56  		}
    57  	}
    58  	// Sharing the same state across caches is perfectly fine here, the fetching
    59  	// of attestation prestate is by far the most accessed state fetching pattern in
    60  	// the beacon node. An extra state instance cached isn't an issue in the bigger
    61  	// picture.
    62  	if err := s.checkpointStateCache.AddCheckpointState(c, baseState); err != nil {
    63  		return nil, errors.Wrap(err, "could not save checkpoint state to cache")
    64  	}
    65  	return baseState, nil
    66  
    67  }
    68  
    69  // verifyAttTargetEpoch validates attestation is from the current or previous epoch.
    70  func (s *Service) verifyAttTargetEpoch(_ context.Context, genesisTime, nowTime uint64, c *ethpb.Checkpoint) error {
    71  	currentSlot := types.Slot((nowTime - genesisTime) / params.BeaconConfig().SecondsPerSlot)
    72  	currentEpoch := helpers.SlotToEpoch(currentSlot)
    73  	var prevEpoch types.Epoch
    74  	// Prevents previous epoch under flow
    75  	if currentEpoch > 1 {
    76  		prevEpoch = currentEpoch - 1
    77  	}
    78  	if c.Epoch != prevEpoch && c.Epoch != currentEpoch {
    79  		return fmt.Errorf("target epoch %d does not match current epoch %d or prev epoch %d", c.Epoch, currentEpoch, prevEpoch)
    80  	}
    81  	return nil
    82  }
    83  
    84  // verifyBeaconBlock verifies beacon head block is known and not from the future.
    85  func (s *Service) verifyBeaconBlock(ctx context.Context, data *ethpb.AttestationData) error {
    86  	r := bytesutil.ToBytes32(data.BeaconBlockRoot)
    87  	b, err := s.cfg.BeaconDB.Block(ctx, r)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	// If the block does not exist in db, check again if block exists in initial sync block cache.
    92  	// This could happen as the node first syncs to head.
    93  	if (b == nil || b.IsNil()) && s.hasInitSyncBlock(r) {
    94  		b = s.getInitSyncBlock(r)
    95  	}
    96  	if err := helpers.VerifyNilBeaconBlock(b); err != nil {
    97  		return err
    98  	}
    99  	if b.Block().Slot() > data.Slot {
   100  		return fmt.Errorf("could not process attestation for future block, block.Slot=%d > attestation.Data.Slot=%d", b.Block().Slot(), data.Slot)
   101  	}
   102  	return nil
   103  }