github.com/prysmaticlabs/prysm@v1.4.4/validator/db/kv/migration_source_target_epochs_bucket_test.go (about) 1 package kv 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "reflect" 8 "testing" 9 10 "github.com/prysmaticlabs/prysm/shared/bytesutil" 11 "github.com/prysmaticlabs/prysm/shared/testutil/require" 12 bolt "go.etcd.io/bbolt" 13 ) 14 15 func TestStore_migrateSourceTargetEpochsBucketUp(t *testing.T) { 16 numEpochs := uint64(100) 17 // numKeys should be more than batch size for testing. 18 // See: https://github.com/prysmaticlabs/prysm/issues/8509 19 numKeys := 2*publicKeyMigrationBatchSize + 1 20 pubKeys := make([][48]byte, numKeys) 21 for i := 0; i < numKeys; i++ { 22 var pk [48]byte 23 copy(pk[:], fmt.Sprintf("%d", i)) 24 pubKeys[i] = pk 25 } 26 tests := []struct { 27 name string 28 setup func(t *testing.T, validatorDB *Store) 29 eval func(t *testing.T, validatorDB *Store) 30 }{ 31 { 32 name: "only runs once", 33 setup: func(t *testing.T, validatorDB *Store) { 34 err := validatorDB.update(func(tx *bolt.Tx) error { 35 return tx.Bucket(migrationsBucket).Put(migrationSourceTargetEpochsBucketKey, migrationCompleted) 36 }) 37 require.NoError(t, err) 38 }, 39 eval: func(t *testing.T, validatorDB *Store) { 40 err := validatorDB.view(func(tx *bolt.Tx) error { 41 data := tx.Bucket(migrationsBucket).Get(migrationSourceTargetEpochsBucketKey) 42 require.DeepEqual(t, data, migrationCompleted) 43 return nil 44 }) 45 require.NoError(t, err) 46 }, 47 }, 48 { 49 name: "populates new target epochs bucket", 50 setup: func(t *testing.T, validatorDB *Store) { 51 err := validatorDB.update(func(tx *bolt.Tx) error { 52 bucket := tx.Bucket(pubKeysBucket) 53 for _, pubKey := range pubKeys { 54 pkBucket, err := bucket.CreateBucketIfNotExists(pubKey[:]) 55 if err != nil { 56 return err 57 } 58 sourceEpochsBucket, err := pkBucket.CreateBucketIfNotExists(attestationSourceEpochsBucket) 59 if err != nil { 60 return err 61 } 62 for epoch := uint64(1); epoch < numEpochs; epoch++ { 63 source := epoch - 1 64 target := epoch 65 sourceEpoch := bytesutil.Uint64ToBytesBigEndian(source) 66 targetEpoch := bytesutil.Uint64ToBytesBigEndian(target) 67 if err := sourceEpochsBucket.Put(sourceEpoch, targetEpoch); err != nil { 68 return err 69 } 70 } 71 } 72 return nil 73 }) 74 require.NoError(t, err) 75 }, 76 eval: func(t *testing.T, validatorDB *Store) { 77 // Verify we indeed have the data for all epochs 78 // since genesis to epoch 50 under the new schema. 79 err := validatorDB.view(func(tx *bolt.Tx) error { 80 bucket := tx.Bucket(pubKeysBucket) 81 for _, pubKey := range pubKeys { 82 pkBucket := bucket.Bucket(pubKey[:]) 83 sourceEpochsBucket := pkBucket.Bucket(attestationSourceEpochsBucket) 84 targetEpochsBucket := pkBucket.Bucket(attestationTargetEpochsBucket) 85 86 // Verify we have (source epoch, target epoch) pairs. 87 for sourceEpoch := uint64(0); sourceEpoch < numEpochs-1; sourceEpoch++ { 88 sourceEpochBytes := bytesutil.Uint64ToBytesBigEndian(sourceEpoch) 89 targetEpochBytes := sourceEpochsBucket.Get(sourceEpochBytes) 90 targetEpoch := bytesutil.BytesToUint64BigEndian(targetEpochBytes) 91 require.Equal(t, sourceEpoch+1, targetEpoch) 92 } 93 // Verify we have (target epoch, source epoch) pairs. 94 for targetEpoch := uint64(1); targetEpoch < numEpochs; targetEpoch++ { 95 targetEpochBytes := bytesutil.Uint64ToBytesBigEndian(targetEpoch) 96 sourceEpochBytes := targetEpochsBucket.Get(targetEpochBytes) 97 sourceEpoch := bytesutil.BytesToUint64BigEndian(sourceEpochBytes) 98 require.Equal(t, targetEpoch-1, sourceEpoch) 99 } 100 } 101 return nil 102 }) 103 require.NoError(t, err) 104 }, 105 }, 106 } 107 for _, tt := range tests { 108 t.Run(tt.name, func(t *testing.T) { 109 validatorDB := setupDB(t, pubKeys) 110 tt.setup(t, validatorDB) 111 require.NoError(t, validatorDB.migrateSourceTargetEpochsBucketUp(context.Background())) 112 tt.eval(t, validatorDB) 113 }) 114 } 115 } 116 117 func TestStore_migrateSourceTargetEpochsBucketDown(t *testing.T) { 118 // numKeys should be more than batch size for testing. 119 // See: https://github.com/prysmaticlabs/prysm/issues/8509 120 numKeys := 2*publicKeyMigrationBatchSize + 1 121 pubKeys := make([][48]byte, numKeys) 122 for i := 0; i < numKeys; i++ { 123 var pk [48]byte 124 copy(pk[:], fmt.Sprintf("%d", i)) 125 pubKeys[i] = pk 126 } 127 tests := []struct { 128 name string 129 setup func(t *testing.T, validatorDB *Store) 130 eval func(t *testing.T, validatorDB *Store) 131 }{ 132 { 133 name: "unsets the migration completed key upon completion", 134 setup: func(t *testing.T, validatorDB *Store) { 135 err := validatorDB.update(func(tx *bolt.Tx) error { 136 return tx.Bucket(migrationsBucket).Put(migrationSourceTargetEpochsBucketKey, migrationCompleted) 137 }) 138 require.NoError(t, err) 139 }, 140 eval: func(t *testing.T, validatorDB *Store) { 141 err := validatorDB.view(func(tx *bolt.Tx) error { 142 data := tx.Bucket(migrationsBucket).Get(migrationSourceTargetEpochsBucketKey) 143 require.DeepEqual(t, true, data == nil) 144 return nil 145 }) 146 require.NoError(t, err) 147 }, 148 }, 149 { 150 name: "unsets the migration, even if unset already (no panic)", 151 setup: func(t *testing.T, validatorDB *Store) {}, 152 eval: func(t *testing.T, validatorDB *Store) { 153 // Ensure the migration is not marked as complete. 154 err := validatorDB.view(func(tx *bolt.Tx) error { 155 data := tx.Bucket(migrationsBucket).Get(migrationSourceTargetEpochsBucketKey) 156 require.DeepNotEqual(t, data, migrationCompleted) 157 return nil 158 }) 159 require.NoError(t, err) 160 }, 161 }, 162 { 163 name: "deletes the new bucket that was created in the up migration", 164 setup: func(t *testing.T, validatorDB *Store) { 165 err := validatorDB.update(func(tx *bolt.Tx) error { 166 bucket := tx.Bucket(pubKeysBucket) 167 for _, pubKey := range pubKeys { 168 pkBucket, err := bucket.CreateBucketIfNotExists(pubKey[:]) 169 if err != nil { 170 return err 171 } 172 if _, err := pkBucket.CreateBucketIfNotExists(attestationSourceEpochsBucket); err != nil { 173 return err 174 } 175 if _, err := pkBucket.CreateBucketIfNotExists(attestationTargetEpochsBucket); err != nil { 176 return err 177 } 178 } 179 return nil 180 }) 181 require.NoError(t, err) 182 }, 183 eval: func(t *testing.T, validatorDB *Store) { 184 err := validatorDB.view(func(tx *bolt.Tx) error { 185 bucket := tx.Bucket(pubKeysBucket) 186 for _, pubKey := range pubKeys { 187 pkBucket := bucket.Bucket(pubKey[:]) 188 if pkBucket == nil { 189 return errors.New("expected pubkey bucket to exist") 190 } 191 targetEpochsBucket := pkBucket.Bucket(attestationTargetEpochsBucket) 192 if targetEpochsBucket != nil { 193 return errors.New("expected target epochs bucket to have been deleted") 194 } 195 } 196 return nil 197 }) 198 require.NoError(t, err) 199 }, 200 }, 201 } 202 for _, tt := range tests { 203 t.Run(tt.name, func(t *testing.T) { 204 validatorDB := setupDB(t, nil) 205 tt.setup(t, validatorDB) 206 require.NoError(t, validatorDB.migrateSourceTargetEpochsBucketDown(context.Background())) 207 tt.eval(t, validatorDB) 208 }) 209 } 210 } 211 212 func Test_batchPublicKeys(t *testing.T) { 213 tests := []struct { 214 name string 215 batchSize int 216 publicKeys [][]byte 217 want [][][]byte 218 }{ 219 { 220 name: "less than batch size returns all keys", 221 batchSize: 100, 222 publicKeys: [][]byte{{1}, {2}, {3}}, 223 want: [][][]byte{{{1}, {2}, {3}}}, 224 }, 225 { 226 name: "equals batch size returns all keys", 227 batchSize: 3, 228 publicKeys: [][]byte{{1}, {2}, {3}}, 229 want: [][][]byte{{{1}, {2}, {3}}}, 230 }, 231 { 232 name: "> batch size returns proper batches", 233 batchSize: 5, 234 publicKeys: [][]byte{{1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}}, 235 want: [][][]byte{{{1}, {2}, {3}, {4}, {5}}, {{6}, {7}, {8}}}, 236 }, 237 { 238 name: "equal size batches returns proper batches", 239 batchSize: 2, 240 publicKeys: [][]byte{{1}, {2}, {3}, {4}}, 241 want: [][][]byte{{{1}, {2}}, {{3}, {4}}}, 242 }, 243 } 244 for _, tt := range tests { 245 t.Run(tt.name, func(t *testing.T) { 246 if got := batchPublicKeys(tt.publicKeys, tt.batchSize); !reflect.DeepEqual(got, tt.want) { 247 t.Errorf("batchPublicKeys() = %v, want %v", got, tt.want) 248 } 249 }) 250 } 251 }