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 := ðpb.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 }