github.com/number571/tendermint@v0.34.11-gost/scripts/keymigrate/migrate_test.go (about) 1 package keymigrate 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "fmt" 8 "math" 9 "testing" 10 11 "github.com/google/orderedcode" 12 "github.com/stretchr/testify/require" 13 dbm "github.com/tendermint/tm-db" 14 ) 15 16 func makeKey(t *testing.T, elems ...interface{}) []byte { 17 t.Helper() 18 out, err := orderedcode.Append([]byte{}, elems...) 19 require.NoError(t, err) 20 return out 21 } 22 23 func getLegacyPrefixKeys(val int) map[string][]byte { 24 return map[string][]byte{ 25 "Height": []byte(fmt.Sprintf("H:%d", val)), 26 "BlockPart": []byte(fmt.Sprintf("P:%d:%d", val, val)), 27 "BlockPartTwo": []byte(fmt.Sprintf("P:%d:%d", val+2, val+val)), 28 "BlockCommit": []byte(fmt.Sprintf("C:%d", val)), 29 "SeenCommit": []byte(fmt.Sprintf("SC:%d", val)), 30 "BlockHeight": []byte(fmt.Sprintf("BH:%d", val)), 31 "Validators": []byte(fmt.Sprintf("validatorsKey:%d", val)), 32 "ConsensusParams": []byte(fmt.Sprintf("consensusParamsKey:%d", val)), 33 "ABCIResponse": []byte(fmt.Sprintf("abciResponsesKey:%d", val)), 34 "State": []byte("stateKey"), 35 "CommittedEvidence": append([]byte{0x00}, []byte(fmt.Sprintf("%0.16X/%X", int64(val), []byte("committed")))...), 36 "PendingEvidence": append([]byte{0x01}, []byte(fmt.Sprintf("%0.16X/%X", int64(val), []byte("pending")))...), 37 "LightBLock": []byte(fmt.Sprintf("lb/foo/%020d", val)), 38 "Size": []byte("size"), 39 "UserKey0": []byte(fmt.Sprintf("foo/bar/%d/%d", val, val)), 40 "UserKey1": []byte(fmt.Sprintf("foo/bar/baz/%d/%d", val, val)), 41 "TxHeight": []byte(fmt.Sprintf("tx.height/%s/%d/%d", fmt.Sprint(val), val, val)), 42 "TxHash": append( 43 bytes.Repeat([]byte{fmt.Sprint(val)[0]}, 16), 44 bytes.Repeat([]byte{fmt.Sprint(val)[len([]byte(fmt.Sprint(val)))-1]}, 16)..., 45 ), 46 } 47 } 48 49 func getNewPrefixKeys(t *testing.T, val int) map[string][]byte { 50 t.Helper() 51 return map[string][]byte{ 52 "Height": makeKey(t, int64(0), int64(val)), 53 "BlockPart": makeKey(t, int64(1), int64(val), int64(val)), 54 "BlockPartTwo": makeKey(t, int64(1), int64(val+2), int64(val+val)), 55 "BlockCommit": makeKey(t, int64(2), int64(val)), 56 "SeenCommit": makeKey(t, int64(3), int64(val)), 57 "BlockHeight": makeKey(t, int64(4), int64(val)), 58 "Validators": makeKey(t, int64(5), int64(val)), 59 "ConsensusParams": makeKey(t, int64(6), int64(val)), 60 "ABCIResponse": makeKey(t, int64(7), int64(val)), 61 "State": makeKey(t, int64(8)), 62 "CommittedEvidence": makeKey(t, int64(9), int64(val)), 63 "PendingEvidence": makeKey(t, int64(10), int64(val)), 64 "LightBLock": makeKey(t, int64(11), int64(val)), 65 "Size": makeKey(t, int64(12)), 66 "UserKey0": makeKey(t, "foo", "bar", int64(val), int64(val)), 67 "UserKey1": makeKey(t, "foo", "bar/baz", int64(val), int64(val)), 68 "TxHeight": makeKey(t, "tx.height", fmt.Sprint(val), int64(val), int64(val+2), int64(val+val)), 69 "TxHash": makeKey(t, "tx.hash", string(bytes.Repeat([]byte{[]byte(fmt.Sprint(val))[0]}, 32))), 70 } 71 } 72 73 func getLegacyDatabase(t *testing.T) (int, dbm.DB) { 74 db := dbm.NewMemDB() 75 batch := db.NewBatch() 76 ct := 0 77 78 generated := []map[string][]byte{ 79 getLegacyPrefixKeys(8), 80 getLegacyPrefixKeys(9001), 81 getLegacyPrefixKeys(math.MaxInt32 << 1), 82 getLegacyPrefixKeys(math.MaxInt64 - 8), 83 } 84 85 // populate database 86 for _, km := range generated { 87 for _, key := range km { 88 ct++ 89 require.NoError(t, batch.Set(key, []byte(fmt.Sprintf(`{"value": %d}`, ct)))) 90 } 91 } 92 require.NoError(t, batch.WriteSync()) 93 require.NoError(t, batch.Close()) 94 return ct - (2 * len(generated)) + 2, db 95 } 96 97 func TestMigration(t *testing.T) { 98 t.Run("Idempotency", func(t *testing.T) { 99 // we want to make sure that the key space for new and 100 // legacy keys are entirely non-overlapping. 101 102 legacyPrefixes := getLegacyPrefixKeys(42) 103 104 newPrefixes := getNewPrefixKeys(t, 42) 105 106 require.Equal(t, len(legacyPrefixes), len(newPrefixes)) 107 108 t.Run("Legacy", func(t *testing.T) { 109 for kind, le := range legacyPrefixes { 110 require.True(t, keyIsLegacy(le), kind) 111 } 112 }) 113 t.Run("New", func(t *testing.T) { 114 for kind, ne := range newPrefixes { 115 require.False(t, keyIsLegacy(ne), kind) 116 } 117 }) 118 t.Run("Conversion", func(t *testing.T) { 119 for kind, le := range legacyPrefixes { 120 nk, err := migarateKey(le) 121 require.NoError(t, err, kind) 122 require.False(t, keyIsLegacy(nk), kind) 123 } 124 }) 125 t.Run("Hashes", func(t *testing.T) { 126 t.Run("NewKeysAreNotHashes", func(t *testing.T) { 127 for _, key := range getNewPrefixKeys(t, 9001) { 128 require.True(t, len(key) != 32) 129 } 130 }) 131 t.Run("ContrivedLegacyKeyDetection", func(t *testing.T) { 132 require.True(t, keyIsLegacy([]byte("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))) 133 require.False(t, keyIsLegacy([]byte("xxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxx"))) 134 }) 135 }) 136 }) 137 t.Run("Migrations", func(t *testing.T) { 138 t.Run("Errors", func(t *testing.T) { 139 table := map[string][]byte{ 140 "Height": []byte(fmt.Sprintf("H:%f", 4.22222)), 141 "BlockPart": []byte(fmt.Sprintf("P:%f", 4.22222)), 142 "BlockPartTwo": []byte(fmt.Sprintf("P:%d", 42)), 143 "BlockPartThree": []byte(fmt.Sprintf("P:%f:%f", 4.222, 8.444)), 144 "BlockPartFour": []byte(fmt.Sprintf("P:%d:%f", 4222, 8.444)), 145 "BlockCommit": []byte(fmt.Sprintf("C:%f", 4.22222)), 146 "SeenCommit": []byte(fmt.Sprintf("SC:%f", 4.22222)), 147 "BlockHeight": []byte(fmt.Sprintf("BH:%f", 4.22222)), 148 "Validators": []byte(fmt.Sprintf("validatorsKey:%f", 4.22222)), 149 "ConsensusParams": []byte(fmt.Sprintf("consensusParamsKey:%f", 4.22222)), 150 "ABCIResponse": []byte(fmt.Sprintf("abciResponsesKey:%f", 4.22222)), 151 "LightBlockShort": []byte(fmt.Sprintf("lb/foo/%010d", 42)), 152 "LightBlockLong": []byte("lb/foo/12345678910.1234567890"), 153 "Invalid": {0x03}, 154 "BadTXHeight0": []byte(fmt.Sprintf("tx.height/%s/%f/%f", "boop", 4.4, 4.5)), 155 "BadTXHeight1": []byte(fmt.Sprintf("tx.height/%s/%f", "boop", 4.4)), 156 "UserKey0": []byte("foo/bar/1.3/3.4"), 157 "UserKey1": []byte("foo/bar/1/3.4"), 158 "UserKey2": []byte("foo/bar/baz/1/3.4"), 159 "UserKey3": []byte("foo/bar/baz/1.2/4"), 160 } 161 for kind, key := range table { 162 out, err := migarateKey(key) 163 require.Error(t, err, kind) 164 require.Nil(t, out, kind) 165 } 166 }) 167 t.Run("Replacement", func(t *testing.T) { 168 t.Run("MissingKey", func(t *testing.T) { 169 db := dbm.NewMemDB() 170 require.NoError(t, replaceKey(db, keyID("hi"), nil)) 171 }) 172 t.Run("ReplacementFails", func(t *testing.T) { 173 db := dbm.NewMemDB() 174 key := keyID("hi") 175 require.NoError(t, db.Set(key, []byte("world"))) 176 require.Error(t, replaceKey(db, key, func(k keyID) (keyID, error) { 177 return nil, errors.New("hi") 178 })) 179 }) 180 t.Run("KeyDisapears", func(t *testing.T) { 181 db := dbm.NewMemDB() 182 key := keyID("hi") 183 require.NoError(t, db.Set(key, []byte("world"))) 184 require.Error(t, replaceKey(db, key, func(k keyID) (keyID, error) { 185 require.NoError(t, db.Delete(key)) 186 return keyID("wat"), nil 187 })) 188 189 exists, err := db.Has(key) 190 require.NoError(t, err) 191 require.False(t, exists) 192 193 exists, err = db.Has(keyID("wat")) 194 require.NoError(t, err) 195 require.False(t, exists) 196 }) 197 }) 198 }) 199 t.Run("Integration", func(t *testing.T) { 200 t.Run("KeyDiscovery", func(t *testing.T) { 201 size, db := getLegacyDatabase(t) 202 keys, err := getAllLegacyKeys(db) 203 require.NoError(t, err) 204 require.Equal(t, size, len(keys)) 205 legacyKeys := 0 206 for _, k := range keys { 207 if keyIsLegacy(k) { 208 legacyKeys++ 209 } 210 } 211 require.Equal(t, size, legacyKeys) 212 }) 213 t.Run("KeyIdempotency", func(t *testing.T) { 214 for _, key := range getNewPrefixKeys(t, 84) { 215 require.False(t, keyIsLegacy(key)) 216 } 217 }) 218 t.Run("ChannelConversion", func(t *testing.T) { 219 ch := makeKeyChan([]keyID{ 220 makeKey(t, "abc", int64(2), int64(42)), 221 makeKey(t, int64(42)), 222 }) 223 count := 0 224 for range ch { 225 count++ 226 } 227 require.Equal(t, 2, count) 228 }) 229 t.Run("Migrate", func(t *testing.T) { 230 _, db := getLegacyDatabase(t) 231 232 ctx := context.Background() 233 err := Migrate(ctx, db) 234 require.NoError(t, err) 235 keys, err := getAllLegacyKeys(db) 236 require.NoError(t, err) 237 require.Equal(t, 0, len(keys)) 238 239 }) 240 }) 241 }