2020-01-28 02:04:43 +00:00
|
|
|
package blockchain
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2020-11-03 21:18:15 +00:00
|
|
|
"strconv"
|
2020-01-28 02:04:43 +00:00
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
2021-02-09 10:05:22 +00:00
|
|
|
"github.com/prysmaticlabs/eth2-types"
|
2020-01-28 02:04:43 +00:00
|
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
2020-01-31 20:57:01 +00:00
|
|
|
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
2020-01-28 02:04:43 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
2021-02-08 21:11:21 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
2020-11-03 21:18:15 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/mputil"
|
2020-01-28 02:04:43 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
|
|
)
|
|
|
|
|
2020-01-30 19:06:20 +00:00
|
|
|
// getAttPreState retrieves the att pre state by either from the cache or the DB.
|
2020-01-31 20:57:01 +00:00
|
|
|
func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (*stateTrie.BeaconState, error) {
|
2020-11-03 21:18:15 +00:00
|
|
|
// Use a multilock to allow scoped holding of a mutex by a checkpoint root + epoch
|
|
|
|
// allowing us to behave smarter in terms of how this function is used concurrently.
|
2021-02-09 10:05:22 +00:00
|
|
|
epochKey := strconv.FormatUint(uint64(c.Epoch), 10 /* base 10 */)
|
2020-11-03 21:18:15 +00:00
|
|
|
lock := mputil.NewMultilock(string(c.Root) + epochKey)
|
|
|
|
lock.Lock()
|
|
|
|
defer lock.Unlock()
|
|
|
|
cachedState, err := s.checkpointStateCache.StateByCheckpoint(c)
|
2020-01-30 19:06:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "could not get cached checkpoint state")
|
|
|
|
}
|
|
|
|
if cachedState != nil {
|
|
|
|
return cachedState, nil
|
|
|
|
}
|
2020-03-16 19:07:07 +00:00
|
|
|
|
2020-06-23 00:19:33 +00:00
|
|
|
baseState, err := s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(c.Root))
|
2020-04-23 19:03:51 +00:00
|
|
|
if err != nil {
|
2020-09-02 02:52:36 +00:00
|
|
|
return nil, errors.Wrapf(err, "could not get pre state for epoch %d", c.Epoch)
|
2020-04-23 19:03:51 +00:00
|
|
|
}
|
2020-11-03 21:18:15 +00:00
|
|
|
|
2020-09-02 02:52:36 +00:00
|
|
|
epochStartSlot, err := helpers.StartSlot(c.Epoch)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if epochStartSlot > baseState.Slot() {
|
2021-02-08 21:11:21 +00:00
|
|
|
if featureconfig.Get().EnableNextSlotStateCache {
|
|
|
|
baseState, err = state.ProcessSlotsUsingNextSlotCache(ctx, baseState, c.Root, epochStartSlot)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
baseState, err = state.ProcessSlots(ctx, baseState, epochStartSlot)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch)
|
|
|
|
}
|
2020-01-30 19:06:20 +00:00
|
|
|
}
|
2020-10-28 05:42:54 +00:00
|
|
|
if err := s.checkpointStateCache.AddCheckpointState(c, baseState); err != nil {
|
2020-08-17 21:20:34 +00:00
|
|
|
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
|
|
|
}
|
|
|
|
return baseState, nil
|
2020-01-30 19:06:20 +00:00
|
|
|
}
|
2020-10-31 18:38:01 +00:00
|
|
|
|
|
|
|
// To avoid sharing the same state across checkpoint state cache and hot state cache,
|
|
|
|
// we don't add the state to check point cache.
|
|
|
|
has, err := s.stateGen.HasStateInCache(ctx, bytesutil.ToBytes32(c.Root))
|
2020-08-17 21:20:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if !has {
|
2020-10-28 05:42:54 +00:00
|
|
|
if err := s.checkpointStateCache.AddCheckpointState(c, baseState); err != nil {
|
2020-08-17 21:20:34 +00:00
|
|
|
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
|
|
|
}
|
2020-01-30 19:06:20 +00:00
|
|
|
}
|
2020-02-02 05:23:05 +00:00
|
|
|
return baseState, nil
|
2020-11-03 21:18:15 +00:00
|
|
|
|
2020-01-28 02:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// verifyAttTargetEpoch validates attestation is from the current or previous epoch.
|
2020-10-12 08:11:05 +00:00
|
|
|
func (s *Service) verifyAttTargetEpoch(_ context.Context, genesisTime, nowTime uint64, c *ethpb.Checkpoint) error {
|
2020-01-28 02:04:43 +00:00
|
|
|
currentSlot := (nowTime - genesisTime) / params.BeaconConfig().SecondsPerSlot
|
|
|
|
currentEpoch := helpers.SlotToEpoch(currentSlot)
|
2021-02-09 10:05:22 +00:00
|
|
|
var prevEpoch types.Epoch
|
2020-01-28 02:04:43 +00:00
|
|
|
// Prevents previous epoch under flow
|
|
|
|
if currentEpoch > 1 {
|
|
|
|
prevEpoch = currentEpoch - 1
|
|
|
|
}
|
|
|
|
if c.Epoch != prevEpoch && c.Epoch != currentEpoch {
|
|
|
|
return fmt.Errorf("target epoch %d does not match current epoch %d or prev epoch %d", c.Epoch, currentEpoch, prevEpoch)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// verifyBeaconBlock verifies beacon head block is known and not from the future.
|
|
|
|
func (s *Service) verifyBeaconBlock(ctx context.Context, data *ethpb.AttestationData) error {
|
2020-07-14 15:46:00 +00:00
|
|
|
r := bytesutil.ToBytes32(data.BeaconBlockRoot)
|
|
|
|
b, err := s.beaconDB.Block(ctx, r)
|
2020-01-28 02:04:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-07-14 15:46:00 +00:00
|
|
|
// If the block does not exist in db, check again if block exists in initial sync block cache.
|
|
|
|
// This could happen as the node first syncs to head.
|
|
|
|
if b == nil && s.hasInitSyncBlock(r) {
|
|
|
|
b = s.getInitSyncBlock(r)
|
|
|
|
}
|
2020-01-28 02:04:43 +00:00
|
|
|
if b == nil || b.Block == nil {
|
|
|
|
return fmt.Errorf("beacon block %#x does not exist", bytesutil.Trunc(data.BeaconBlockRoot))
|
|
|
|
}
|
|
|
|
if b.Block.Slot > data.Slot {
|
2020-03-24 04:30:28 +00:00
|
|
|
return fmt.Errorf("could not process attestation for future block, block.Slot=%d > attestation.Data.Slot=%d", b.Block.Slot, data.Slot)
|
2020-01-28 02:04:43 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|