github.com/prysmaticlabs/prysm@v1.4.4/slasher/db/kv/block_header.go (about)

     1  package kv
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  
     7  	"github.com/pkg/errors"
     8  	types "github.com/prysmaticlabs/eth2-types"
     9  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    10  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    11  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    12  	"github.com/prysmaticlabs/prysm/shared/params"
    13  	bolt "go.etcd.io/bbolt"
    14  	"go.opencensus.io/trace"
    15  	"google.golang.org/protobuf/proto"
    16  )
    17  
    18  func unmarshalBlockHeader(ctx context.Context, enc []byte) (*ethpb.SignedBeaconBlockHeader, error) {
    19  	ctx, span := trace.StartSpan(ctx, "slasherDB.unmarshalBlockHeader")
    20  	defer span.End()
    21  	protoBlockHeader := &ethpb.SignedBeaconBlockHeader{}
    22  	err := proto.Unmarshal(enc, protoBlockHeader)
    23  	if err != nil {
    24  		return nil, errors.Wrap(err, "failed to unmarshal encoding")
    25  	}
    26  	return protoBlockHeader, nil
    27  }
    28  
    29  // BlockHeaders accepts an slot and validator id and returns the corresponding block header array.
    30  // Returns nil if the block header for those values does not exist.
    31  func (s *Store) BlockHeaders(ctx context.Context, slot types.Slot, validatorIndex types.ValidatorIndex) ([]*ethpb.SignedBeaconBlockHeader, error) {
    32  	ctx, span := trace.StartSpan(ctx, "slasherDB.BlockHeaders")
    33  	defer span.End()
    34  	var blockHeaders []*ethpb.SignedBeaconBlockHeader
    35  	err := s.view(func(tx *bolt.Tx) error {
    36  		c := tx.Bucket(historicBlockHeadersBucket).Cursor()
    37  		prefix := encodeSlotValidatorIndex(slot, validatorIndex)
    38  		for k, v := c.Seek(prefix); k != nil && bytes.HasPrefix(k, prefix); k, v = c.Next() {
    39  			bh, err := unmarshalBlockHeader(ctx, v)
    40  			if err != nil {
    41  				return err
    42  			}
    43  			blockHeaders = append(blockHeaders, bh)
    44  		}
    45  		return nil
    46  	})
    47  	return blockHeaders, err
    48  }
    49  
    50  // HasBlockHeader accepts a slot and validator id and returns true if the block header exists.
    51  func (s *Store) HasBlockHeader(ctx context.Context, slot types.Slot, validatorIndex types.ValidatorIndex) bool {
    52  	ctx, span := trace.StartSpan(ctx, "slasherDB.HasBlockHeader")
    53  	defer span.End()
    54  	prefix := encodeSlotValidatorIndex(slot, validatorIndex)
    55  	var hasBlockHeader bool
    56  	if err := s.view(func(tx *bolt.Tx) error {
    57  		c := tx.Bucket(historicBlockHeadersBucket).Cursor()
    58  		for k, _ := c.Seek(prefix); k != nil && bytes.HasPrefix(k, prefix); k, _ = c.Next() {
    59  			hasBlockHeader = true
    60  			return nil
    61  		}
    62  		hasBlockHeader = false
    63  		return nil
    64  	}); err != nil {
    65  		log.WithError(err).Error("Failed to lookup block header from DB")
    66  	}
    67  
    68  	return hasBlockHeader
    69  }
    70  
    71  // SaveBlockHeader accepts a block header and writes it to disk.
    72  func (s *Store) SaveBlockHeader(ctx context.Context, blockHeader *ethpb.SignedBeaconBlockHeader) error {
    73  	ctx, span := trace.StartSpan(ctx, "slasherDB.SaveBlockHeader")
    74  	defer span.End()
    75  	epoch := helpers.SlotToEpoch(blockHeader.Header.Slot)
    76  	key := encodeSlotValidatorIndexSig(blockHeader.Header.Slot, blockHeader.Header.ProposerIndex, blockHeader.Signature)
    77  	enc, err := proto.Marshal(blockHeader)
    78  	if err != nil {
    79  		return errors.Wrap(err, "failed to encode block")
    80  	}
    81  
    82  	err = s.update(func(tx *bolt.Tx) error {
    83  		bucket := tx.Bucket(historicBlockHeadersBucket)
    84  		if err := bucket.Put(key, enc); err != nil {
    85  			return errors.Wrap(err, "failed to include block header in the historical bucket")
    86  		}
    87  
    88  		return err
    89  	})
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	// Prune block header history every 10th epoch.
    95  	if epoch%params.BeaconConfig().PruneSlasherStoragePeriod == 0 {
    96  		return s.PruneBlockHistory(ctx, epoch, params.BeaconConfig().WeakSubjectivityPeriod)
    97  	}
    98  	return nil
    99  }
   100  
   101  // DeleteBlockHeader deletes a block header using the slot and validator id.
   102  func (s *Store) DeleteBlockHeader(ctx context.Context, blockHeader *ethpb.SignedBeaconBlockHeader) error {
   103  	ctx, span := trace.StartSpan(ctx, "slasherDB.DeleteBlockHeader")
   104  	defer span.End()
   105  	key := encodeSlotValidatorIndexSig(blockHeader.Header.Slot, blockHeader.Header.ProposerIndex, blockHeader.Signature)
   106  	return s.update(func(tx *bolt.Tx) error {
   107  		bucket := tx.Bucket(historicBlockHeadersBucket)
   108  		if err := bucket.Delete(key); err != nil {
   109  			return errors.Wrap(err, "failed to delete the block header from historical bucket")
   110  		}
   111  		return bucket.Delete(key)
   112  	})
   113  }
   114  
   115  // PruneBlockHistory leaves only records younger then history size.
   116  func (s *Store) PruneBlockHistory(ctx context.Context, currentEpoch, pruningEpochAge types.Epoch) error {
   117  	ctx, span := trace.StartSpan(ctx, "slasherDB.pruneBlockHistory")
   118  	defer span.End()
   119  	pruneTill := int64(currentEpoch) - int64(pruningEpochAge)
   120  	if pruneTill <= 0 {
   121  		return nil
   122  	}
   123  	pruneTillSlot := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(pruneTill)))
   124  	return s.update(func(tx *bolt.Tx) error {
   125  		bucket := tx.Bucket(historicBlockHeadersBucket)
   126  		c := tx.Bucket(historicBlockHeadersBucket).Cursor()
   127  		for k, _ := c.First(); k != nil && bytesutil.FromBytes8(k[:8]) <= pruneTillSlot; k, _ = c.Next() {
   128  			if err := bucket.Delete(k); err != nil {
   129  				return errors.Wrap(err, "failed to delete the block header from historical bucket")
   130  			}
   131  		}
   132  		return nil
   133  	})
   134  }