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 }