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 }