github.com/prysmaticlabs/prysm@v1.4.4/validator/db/kv/prune_attester_protection.go (about) 1 package kv 2 3 import ( 4 "context" 5 6 types "github.com/prysmaticlabs/eth2-types" 7 "github.com/prysmaticlabs/prysm/shared/bytesutil" 8 "github.com/prysmaticlabs/prysm/shared/params" 9 bolt "go.etcd.io/bbolt" 10 "go.opencensus.io/trace" 11 ) 12 13 // PruneAttestations loops through every public key in the public keys bucket 14 // and prunes all attestation data that has target epochs older the highest 15 // target epoch minus some constant of how many epochs we keep track of for slashing 16 // protection. This routine is meant to run on startup. 17 func (s *Store) PruneAttestations(ctx context.Context) error { 18 ctx, span := trace.StartSpan(ctx, "Validator.PruneAttestations") 19 defer span.End() 20 var pubkeys [][]byte 21 err := s.view(func(tx *bolt.Tx) error { 22 bucket := tx.Bucket(pubKeysBucket) 23 return bucket.ForEach(func(pubKey []byte, _ []byte) error { 24 key := make([]byte, len(pubKey)) 25 copy(key, pubKey) 26 pubkeys = append(pubkeys, pubKey) 27 return nil 28 }) 29 }) 30 if err != nil { 31 return err 32 } 33 for _, k := range pubkeys { 34 err = s.update(func(tx *bolt.Tx) error { 35 bucket := tx.Bucket(pubKeysBucket) 36 pkBucket := bucket.Bucket(k) 37 if pkBucket == nil { 38 return nil 39 } 40 if err := pruneSourceEpochsBucket(pkBucket); err != nil { 41 return err 42 } 43 if err := pruneTargetEpochsBucket(pkBucket); err != nil { 44 return err 45 } 46 return pruneSigningRootsBucket(pkBucket) 47 }) 48 if err != nil { 49 return err 50 } 51 } 52 return nil 53 } 54 55 func pruneSourceEpochsBucket(bucket *bolt.Bucket) error { 56 sourceEpochsBucket := bucket.Bucket(attestationSourceEpochsBucket) 57 if sourceEpochsBucket == nil { 58 return nil 59 } 60 61 return pruneBucket(sourceEpochsBucket) 62 } 63 64 func pruneTargetEpochsBucket(bucket *bolt.Bucket) error { 65 targetEpochsBucket := bucket.Bucket(attestationTargetEpochsBucket) 66 if targetEpochsBucket == nil { 67 return nil 68 } 69 70 return pruneBucket(targetEpochsBucket) 71 } 72 73 func pruneSigningRootsBucket(bucket *bolt.Bucket) error { 74 signingRootsBucket := bucket.Bucket(attestationSigningRootsBucket) 75 if signingRootsBucket == nil { 76 return nil 77 } 78 79 return pruneBucket(signingRootsBucket) 80 } 81 82 // pruneBucket iterates through epoch keys and deletes any key/value lower than 83 // the pruning cut off epoch as determined by the highest key in the bucket. 84 func pruneBucket(bkt *bolt.Bucket) error { 85 if bkt == nil { 86 return nil 87 } 88 89 // We obtain the highest target epoch from the signing roots bucket. 90 highestEpochBytes, _ := bkt.Cursor().Last() 91 highestEpoch := bytesutil.BytesToEpochBigEndian(highestEpochBytes) 92 upperBounds := pruningEpochCutoff(highestEpoch) 93 94 c := bkt.Cursor() 95 for k, _ := c.First(); k != nil; k, _ = c.Next() { 96 targetEpoch := bytesutil.BytesToEpochBigEndian(k) 97 if targetEpoch >= upperBounds { 98 return nil 99 } 100 if err := bkt.Delete(k); err != nil { 101 return err 102 } 103 } 104 105 return nil 106 } 107 108 // This helper function determines the cutoff epoch where, for all epochs before it, we should prune 109 // the slashing protection database. This is computed by taking in an epoch and subtracting 110 // SLASHING_PROTECTION_PRUNING_EPOCHS from the value. For example, if we are keeping track of 512 epochs 111 // in the database, if we pass in epoch 612, then we want to prune all epochs before epoch 100. 112 func pruningEpochCutoff(epoch types.Epoch) types.Epoch { 113 minEpoch := types.Epoch(0) 114 if epoch > params.BeaconConfig().SlashingProtectionPruningEpochs { 115 minEpoch = epoch - params.BeaconConfig().SlashingProtectionPruningEpochs 116 } 117 return minEpoch 118 }