github.com/prysmaticlabs/prysm@v1.4.4/validator/db/kv/migration_source_target_epochs_bucket.go (about)

     1  package kv
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  
     7  	"github.com/prysmaticlabs/prysm/shared/progressutil"
     8  	bolt "go.etcd.io/bbolt"
     9  )
    10  
    11  var (
    12  	migrationSourceTargetEpochsBucketKey = []byte("source_target_epochs_bucket_0")
    13  )
    14  
    15  const (
    16  	publicKeyMigrationBatchSize = 100 // Batch update 100 public keys at a time.
    17  )
    18  
    19  func (s *Store) migrateSourceTargetEpochsBucketUp(ctx context.Context) error {
    20  	// First, we extract the public keys we need to migrate data for.
    21  	publicKeyBytes := make([][]byte, 0)
    22  	err := s.db.View(func(tx *bolt.Tx) error {
    23  		mb := tx.Bucket(migrationsBucket)
    24  		if b := mb.Get(migrationSourceTargetEpochsBucketKey); bytes.Equal(b, migrationCompleted) {
    25  			return nil // Migration already completed.
    26  		}
    27  		bkt := tx.Bucket(pubKeysBucket)
    28  		return bkt.ForEach(func(k, _ []byte) error {
    29  			if k == nil {
    30  				return nil
    31  			}
    32  			nk := make([]byte, len(k))
    33  			copy(nk, k)
    34  			publicKeyBytes = append(publicKeyBytes, nk)
    35  			return nil
    36  		})
    37  	})
    38  	if err != nil {
    39  		return err
    40  	}
    41  
    42  	// Next up, we initiate a bolt transaction for batches of public keys for efficiency.
    43  	// If we did a single transaction for all public keys, resource use might be too high,
    44  	// and if we do a single one per key, the migration will take too long.
    45  	batchedKeys := batchPublicKeys(publicKeyBytes, publicKeyMigrationBatchSize)
    46  	bar := progressutil.InitializeProgressBar(
    47  		len(batchedKeys), "Adding optimizations for validator slashing protection",
    48  	)
    49  	for _, batch := range batchedKeys {
    50  		err = s.db.Update(func(tx *bolt.Tx) error {
    51  			bkt := tx.Bucket(pubKeysBucket)
    52  			for _, pubKey := range batch {
    53  				pkb := bkt.Bucket(pubKey)
    54  				if pkb == nil {
    55  					continue
    56  				}
    57  				sourceBucket := pkb.Bucket(attestationSourceEpochsBucket)
    58  				if sourceBucket == nil {
    59  					continue
    60  				}
    61  				targetBucket, err := pkb.CreateBucketIfNotExists(attestationTargetEpochsBucket)
    62  				if err != nil {
    63  					return err
    64  				}
    65  				err = sourceBucket.ForEach(func(sourceEpochBytes, targetEpochsBytes []byte) error {
    66  					for i := 0; i < len(targetEpochsBytes); i += 8 {
    67  						if err := insertTargetSource(
    68  							targetBucket,
    69  							targetEpochsBytes[i:i+8],
    70  							sourceEpochBytes,
    71  						); err != nil {
    72  							return err
    73  						}
    74  					}
    75  					return nil
    76  				})
    77  				if err != nil {
    78  					return err
    79  				}
    80  			}
    81  			return nil
    82  		})
    83  		if err != nil {
    84  			return err
    85  		}
    86  		if err := bar.Add(1); err != nil {
    87  			return err
    88  		}
    89  	}
    90  
    91  	// Finally we mark the migration as completed.
    92  	return s.db.Update(func(tx *bolt.Tx) error {
    93  		mb := tx.Bucket(migrationsBucket)
    94  		return mb.Put(migrationSourceTargetEpochsBucketKey, migrationCompleted)
    95  	})
    96  }
    97  
    98  func (s *Store) migrateSourceTargetEpochsBucketDown(ctx context.Context) error {
    99  	return s.db.Update(func(tx *bolt.Tx) error {
   100  		bkt := tx.Bucket(pubKeysBucket)
   101  		err := bkt.ForEach(func(k, _ []byte) error {
   102  			if k == nil {
   103  				return nil
   104  			}
   105  			pkBucket := bkt.Bucket(k)
   106  			if pkBucket == nil {
   107  				return nil
   108  			}
   109  			return pkBucket.DeleteBucket(attestationTargetEpochsBucket)
   110  		})
   111  		if err != nil {
   112  			return err
   113  		}
   114  		migrationsBkt := tx.Bucket(migrationsBucket)
   115  		return migrationsBkt.Delete(migrationSourceTargetEpochsBucketKey)
   116  	})
   117  }
   118  
   119  func insertTargetSource(bkt *bolt.Bucket, targetEpochBytes, sourceEpochBytes []byte) error {
   120  	var existingAttestedSourceBytes []byte
   121  	if existing := bkt.Get(targetEpochBytes); existing != nil {
   122  		existingAttestedSourceBytes = append(existing, sourceEpochBytes...)
   123  	} else {
   124  		existingAttestedSourceBytes = sourceEpochBytes
   125  	}
   126  	return bkt.Put(targetEpochBytes, existingAttestedSourceBytes)
   127  }
   128  
   129  func batchPublicKeys(publicKeys [][]byte, batchSize int) [][][]byte {
   130  	if len(publicKeys) < batchSize {
   131  		return [][][]byte{publicKeys}
   132  	}
   133  	batch := make([][][]byte, 0)
   134  	for i := 0; i < len(publicKeys); i += batchSize {
   135  		if i+batchSize >= len(publicKeys)+1 {
   136  			batch = append(batch, publicKeys[i:])
   137  		} else {
   138  			batch = append(batch, publicKeys[i:i+batchSize])
   139  		}
   140  	}
   141  	return batch
   142  }