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  }