github.com/klaytn/klaytn@v1.12.1/snapshot/generate_test.go (about) 1 // Modifications Copyright 2021 The klaytn Authors 2 // Copyright 2020 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from core/state/snapshot/generate_test.go (2021/10/21). 19 // Modified and improved for the klaytn development. 20 21 package snapshot 22 23 import ( 24 "fmt" 25 "math/big" 26 "testing" 27 "time" 28 29 "github.com/klaytn/klaytn/blockchain/types/account" 30 "github.com/klaytn/klaytn/blockchain/types/accountkey" 31 "github.com/klaytn/klaytn/params" 32 33 "github.com/klaytn/klaytn/log" 34 35 "github.com/klaytn/klaytn/common" 36 "github.com/klaytn/klaytn/rlp" 37 "github.com/klaytn/klaytn/storage/database" 38 "github.com/klaytn/klaytn/storage/statedb" 39 "golang.org/x/crypto/sha3" 40 ) 41 42 func genExternallyOwnedAccount(nonce uint64, balance *big.Int) (account.Account, error) { 43 return account.NewAccountWithMap(account.ExternallyOwnedAccountType, map[account.AccountValueKeyType]interface{}{ 44 account.AccountValueKeyNonce: nonce, 45 account.AccountValueKeyBalance: balance, 46 account.AccountValueKeyHumanReadable: false, 47 account.AccountValueKeyAccountKey: accountkey.NewAccountKeyLegacy(), 48 }) 49 } 50 51 func genSmartContractAccount(nonce uint64, balance *big.Int, storageRoot common.Hash, codeHash []byte) (account.Account, error) { 52 return account.NewAccountWithMap(account.SmartContractAccountType, map[account.AccountValueKeyType]interface{}{ 53 account.AccountValueKeyNonce: nonce, 54 account.AccountValueKeyBalance: balance, 55 account.AccountValueKeyHumanReadable: false, 56 account.AccountValueKeyAccountKey: accountkey.NewAccountKeyLegacy(), 57 account.AccountValueKeyStorageRoot: storageRoot, 58 account.AccountValueKeyCodeHash: codeHash, 59 account.AccountValueKeyCodeInfo: params.CodeInfo(0), 60 }) 61 } 62 63 // Tests that snapshot generation from an empty database. 64 func TestGeneration(t *testing.T) { 65 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 66 67 var ( 68 dbm = database.NewMemoryDBManager() 69 triedb = statedb.NewDatabase(dbm) 70 ) 71 stTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 72 stTrie.Update([]byte("key-1"), []byte("val-1")) // 0x1314700b81afc49f94db3623ef1df38f3ed18b73a1b7ea2f6c095118cf6118a0 73 stTrie.Update([]byte("key-2"), []byte("val-2")) // 0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371 74 stTrie.Update([]byte("key-3"), []byte("val-3")) // 0x51c71a47af0695957647fb68766d0becee77e953df17c29b3c2f25436f055c78 75 stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 76 77 accTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 78 79 acc1, _ := genSmartContractAccount(0, big.NewInt(1), stTrie.Hash(), emptyCode.Bytes()) 80 serializer := account.NewAccountSerializerWithAccount(acc1) 81 val, _ := rlp.EncodeToBytes(serializer) 82 accTrie.Update([]byte("acc-1"), val) // 0x30301e37c9af8ee5f609f1d60a3307d3e113bea03bef203e39aadc46bd5ad5ee 83 84 acc2, _ := genExternallyOwnedAccount(0, big.NewInt(2)) 85 serializer2 := account.NewAccountSerializerWithAccount(acc2) 86 val, _ = rlp.EncodeToBytes(serializer2) 87 accTrie.Update([]byte("acc-2"), val) // 0x11944b79b322f047379973e18ba21657b8ad4b50ecd94217177bc56f89905228 88 89 acc3, _ := genSmartContractAccount(0, big.NewInt(3), stTrie.Hash(), emptyCode.Bytes()) 90 serializer3 := account.NewAccountSerializerWithAccount(acc3) 91 val, _ = rlp.EncodeToBytes(serializer3) // 0x8c2477df4801bbf88c6636445a2a9feff54c098cc218df403dc3f1007add780c 92 accTrie.Update([]byte("acc-3"), val) 93 94 root, _ := accTrie.Commit(nil) // Root: 0x4a651234bc4b8c7462b5ad4eb95bbb724eb636fed72bb5278d886f9ea4c345f8 95 96 // TODO-Klaytn-Snapshot update proper block number 97 triedb.Commit(root, false, 0) 98 99 if have, want := root, common.HexToHash("0x4a651234bc4b8c7462b5ad4eb95bbb724eb636fed72bb5278d886f9ea4c345f8"); have != want { 100 t.Fatalf("have %#x want %#x", have, want) 101 } 102 snap := generateSnapshot(dbm, triedb, 16, root) 103 104 select { 105 case <-snap.genPending: 106 // Snapshot generation succeeded 107 108 case <-time.After(3 * time.Second): 109 t.Errorf("Snapshot generation failed") 110 } 111 112 checkSnapRoot(t, snap, root) 113 // Signal abortion to the generator and wait for it to tear down 114 stop := make(chan *generatorStats) 115 snap.genAbort <- stop 116 <-stop 117 } 118 119 func hashData(input []byte) common.Hash { 120 hasher := sha3.NewLegacyKeccak256() 121 var hash common.Hash 122 hasher.Reset() 123 hasher.Write(input) 124 hasher.Sum(hash[:0]) 125 return hash 126 } 127 128 // Tests that snapshot generation with existent flat state. 129 func TestGenerateExistentState(t *testing.T) { 130 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 131 132 // We can't use statedb to make a test trie (circular dependency), so make 133 // a fake one manually. We're going with a small account trie of 3 accounts, 134 // two of which also has the same 3-slot storage trie attached. 135 var ( 136 diskdb = database.NewMemoryDBManager() 137 triedb = statedb.NewDatabase(diskdb) 138 ) 139 stTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 140 stTrie.Update([]byte("key-1"), []byte("val-1")) // 0x1314700b81afc49f94db3623ef1df38f3ed18b73a1b7ea2f6c095118cf6118a0 141 stTrie.Update([]byte("key-2"), []byte("val-2")) // 0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371 142 stTrie.Update([]byte("key-3"), []byte("val-3")) // 0x51c71a47af0695957647fb68766d0becee77e953df17c29b3c2f25436f055c78 143 stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 144 145 accTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 146 acc, _ := genSmartContractAccount(uint64(0), big.NewInt(1), stTrie.Hash(), emptyCode.Bytes()) 147 serializer := account.NewAccountSerializerWithAccount(acc) 148 val, _ := rlp.EncodeToBytes(serializer) 149 accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e 150 diskdb.WriteAccountSnapshot(hashData([]byte("acc-1")), val) 151 diskdb.WriteStorageSnapshot(hashData([]byte("acc-1")), hashData([]byte("key-1")), []byte("val-1")) 152 diskdb.WriteStorageSnapshot(hashData([]byte("acc-1")), hashData([]byte("key-2")), []byte("val-2")) 153 diskdb.WriteStorageSnapshot(hashData([]byte("acc-1")), hashData([]byte("key-3")), []byte("val-3")) 154 155 acc, _ = genSmartContractAccount(uint64(0), big.NewInt(2), stTrie.Hash(), emptyCode.Bytes()) 156 serializer = account.NewAccountSerializerWithAccount(acc) 157 val, _ = rlp.EncodeToBytes(serializer) 158 accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 159 // diskdb.Put(hashData([]byte("acc-2")).Bytes(), val) 160 diskdb.WriteAccountSnapshot(hashData([]byte("acc-2")), val) 161 162 acc, _ = genSmartContractAccount(uint64(0), big.NewInt(3), stTrie.Hash(), emptyCode.Bytes()) 163 serializer = account.NewAccountSerializerWithAccount(acc) 164 val, _ = rlp.EncodeToBytes(serializer) 165 accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 166 diskdb.WriteAccountSnapshot(hashData([]byte("acc-3")), val) 167 diskdb.WriteStorageSnapshot(hashData([]byte("acc-3")), hashData([]byte("key-1")), []byte("val-1")) 168 diskdb.WriteStorageSnapshot(hashData([]byte("acc-3")), hashData([]byte("key-2")), []byte("val-2")) 169 diskdb.WriteStorageSnapshot(hashData([]byte("acc-3")), hashData([]byte("key-3")), []byte("val-3")) 170 171 root, _ := accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd 172 // TODO-Klaytn-Snapshot put proper block number 173 triedb.Commit(root, false, 0) 174 175 snap := generateSnapshot(diskdb, triedb, 16, root) 176 select { 177 case <-snap.genPending: 178 // Snapshot generation succeeded 179 180 case <-time.After(3 * time.Second): 181 t.Errorf("Snapshot generation failed") 182 } 183 checkSnapRoot(t, snap, root) 184 // Signal abortion to the generator and wait for it to tear down 185 stop := make(chan *generatorStats) 186 snap.genAbort <- stop 187 <-stop 188 } 189 190 func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) { 191 t.Helper() 192 accIt := snap.AccountIterator(common.Hash{}) 193 defer accIt.Release() 194 snapRoot, err := generateTrieRoot(accIt, common.Hash{}, trieGenerate, 195 func(accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { 196 storageIt, _ := snap.StorageIterator(accountHash, common.Hash{}) 197 defer storageIt.Release() 198 199 hash, err := generateTrieRoot(storageIt, accountHash, trieGenerate, nil, stat, false) 200 if err != nil { 201 return common.Hash{}, err 202 } 203 return hash, nil 204 }, newGenerateStats(), true) 205 if err != nil { 206 t.Fatal(err) 207 } 208 if snapRoot != trieRoot { 209 t.Fatalf("snaproot: %#x != trieroot %#x", snapRoot, trieRoot) 210 } 211 } 212 213 type testHelper struct { 214 diskdb database.DBManager 215 triedb *statedb.Database 216 accTrie *statedb.SecureTrie 217 } 218 219 func newHelper() *testHelper { 220 diskdb := database.NewMemoryDBManager() 221 triedb := statedb.NewDatabase(diskdb) 222 accTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 223 return &testHelper{ 224 diskdb: diskdb, 225 triedb: triedb, 226 accTrie: accTrie, 227 } 228 } 229 230 func (t *testHelper) addTrieAccount(acckey string, acc account.Account) { 231 val, _ := rlp.EncodeToBytes(account.NewAccountSerializerWithAccount(acc)) 232 t.accTrie.Update([]byte(acckey), val) 233 } 234 235 func (t *testHelper) addSnapAccount(acckey string, acc account.Account) { 236 val, _ := rlp.EncodeToBytes(account.NewAccountSerializerWithAccount(acc)) 237 key := hashData([]byte(acckey)) 238 t.diskdb.WriteAccountSnapshot(key, val) 239 } 240 241 func (t *testHelper) addAccount(acckey string, acc account.Account) { 242 t.addTrieAccount(acckey, acc) 243 t.addSnapAccount(acckey, acc) 244 } 245 246 func (t *testHelper) addSnapStorage(accKey string, keys []string, vals []string) { 247 accHash := hashData([]byte(accKey)) 248 for i, key := range keys { 249 t.diskdb.WriteStorageSnapshot(accHash, hashData([]byte(key)), []byte(vals[i])) 250 } 251 } 252 253 func (t *testHelper) makeStorageTrie(keys []string, vals []string) common.Hash { 254 stTrie, _ := statedb.NewSecureTrie(common.Hash{}, t.triedb, nil) 255 for i, k := range keys { 256 stTrie.Update([]byte(k), []byte(vals[i])) 257 } 258 root, _ := stTrie.Commit(nil) 259 return root 260 } 261 262 func (t *testHelper) Generate() (common.Hash, *diskLayer) { 263 root, _ := t.accTrie.Commit(nil) 264 // TODO-Klaytn-Snapshot input proper block number 265 t.triedb.Commit(root, false, 0) 266 snap := generateSnapshot(t.diskdb, t.triedb, 16, root) 267 return root, snap 268 } 269 270 // Tests that snapshot generation with existent flat state, where the flat state 271 // contains some errors: 272 // - the contract with empty storage root but has storage entries in the disk 273 // - the contract with non empty storage root but empty storage slots 274 // - the contract(non-empty storage) misses some storage slots 275 // - miss in the beginning 276 // - miss in the middle 277 // - miss in the end 278 // - the contract(non-empty storage) has wrong storage slots 279 // - wrong slots in the beginning 280 // - wrong slots in the middle 281 // - wrong slots in the end 282 // - the contract(non-empty storage) has extra storage slots 283 // - extra slots in the beginning 284 // - extra slots in the middle 285 // - extra slots in the end 286 func TestGenerateExistentStateWithWrongStorage(t *testing.T) { 287 helper := newHelper() 288 stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 289 290 // Account one, empty root but non-empty database 291 acc1, _ := genExternallyOwnedAccount(0, big.NewInt(1)) 292 helper.addAccount("acc-1", acc1) 293 helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 294 295 // Account two, non empty root but empty database 296 acc2, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 297 helper.addAccount("acc-2", acc2) 298 299 // Miss slots 300 { 301 // Account three, non empty root but misses slots in the beginning 302 acc3, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 303 helper.addAccount("acc-3", acc3) 304 helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"}) 305 306 // Account four, non empty root but misses slots in the middle 307 acc4, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 308 helper.addAccount("acc-4", acc4) 309 helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"}) 310 311 // Account five, non empty root but misses slots in the end 312 acc5, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 313 helper.addAccount("acc-5", acc5) 314 helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"}) 315 } 316 317 // Wrong storage slots 318 { 319 // Account six, non empty root but wrong slots in the beginning 320 321 acc6, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 322 helper.addAccount("acc-6", acc6) 323 helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"}) 324 325 // Account seven, non empty root but wrong slots in the middle 326 acc7, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 327 helper.addAccount("acc-7", acc7) 328 helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"}) 329 330 // Account eight, non empty root but wrong slots in the end 331 acc8, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 332 helper.addAccount("acc-8", acc8) 333 helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"}) 334 335 // Account 9, non empty root but rotated slots 336 acc9, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 337 helper.addAccount("acc-9", acc9) 338 helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"}) 339 } 340 341 // Extra storage slots 342 { 343 // Account 10, non empty root but extra slots in the beginning 344 acc10, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 345 helper.addAccount("acc-10", acc10) 346 helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"}) 347 348 // Account 11, non empty root but extra slots in the middle 349 acc11, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 350 helper.addAccount("acc-11", acc11) 351 helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"}) 352 353 // Account 12, non empty root but extra slots in the end 354 acc12, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 355 helper.addAccount("acc-12", acc12) 356 helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"}) 357 } 358 359 root, snap := helper.Generate() 360 t.Logf("Root: %#x\n", root) // Root = 0x8746cce9fd9c658b2cfd639878ed6584b7a2b3e73bb40f607fcfa156002429a0 361 362 select { 363 case <-snap.genPending: 364 // Snapshot generation succeeded 365 366 case <-time.After(3 * time.Second): 367 t.Errorf("Snapshot generation failed") 368 } 369 checkSnapRoot(t, snap, root) 370 // Signal abortion to the generator and wait for it to tear down 371 stop := make(chan *generatorStats) 372 snap.genAbort <- stop 373 <-stop 374 } 375 376 // Tests that snapshot generation with existent flat state, where the flat state 377 // contains some errors: 378 // - miss accounts 379 // - wrong accounts 380 // - extra accounts 381 func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { 382 helper := newHelper() 383 stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 384 385 // Trie accounts [acc-1, acc-2, acc-3, acc-4, acc-6] 386 // Extra accounts [acc-0, acc-5, acc-7] 387 388 // Missing accounts, only in the trie 389 { 390 391 acc1, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 392 helper.addTrieAccount("acc-1", acc1) // Beginning 393 acc4, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 394 helper.addTrieAccount("acc-4", acc4) // Middle 395 acc6, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 396 helper.addTrieAccount("acc-6", acc6) // End 397 } 398 399 // Wrong accounts 400 { 401 acc2, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 402 helper.addTrieAccount("acc-2", acc2) 403 acc2, _ = genSmartContractAccount(0, big.NewInt(1), stRoot, common.Hex2Bytes("0x1234")) 404 helper.addSnapAccount("acc-2", acc2) 405 406 acc3, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 407 helper.addTrieAccount("acc-3", acc3) 408 acc3, _ = genExternallyOwnedAccount(0, big.NewInt(1)) 409 helper.addSnapAccount("acc-3", acc3) 410 } 411 412 // Extra accounts, only in the snap 413 { 414 acc0, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyRoot.Bytes()) 415 helper.addSnapAccount("acc-0", acc0) // before the beginning 416 acc5, _ := genSmartContractAccount(0, big.NewInt(1), emptyRoot, common.Hex2Bytes("0x1234")) 417 helper.addSnapAccount("acc-5", acc5) // Middle 418 acc7, _ := genSmartContractAccount(0, big.NewInt(1), emptyRoot, emptyRoot.Bytes()) 419 helper.addSnapAccount("acc-7", acc7) // after the end 420 } 421 422 root, snap := helper.Generate() 423 t.Logf("Root: %#x\n", root) // Root = 0x825891472281463511e7ebcc7f109e4f9200c20fa384754e11fd605cd98464e8 424 425 select { 426 case <-snap.genPending: 427 // Snapshot generation succeeded 428 429 case <-time.After(3 * time.Second): 430 t.Errorf("Snapshot generation failed") 431 } 432 checkSnapRoot(t, snap, root) 433 434 // Signal abortion to the generator and wait for it to tear down 435 stop := make(chan *generatorStats) 436 snap.genAbort <- stop 437 <-stop 438 } 439 440 // Tests that snapshot generation errors out correctly in case of a missing trie 441 // node in the account trie. 442 func TestGenerateCorruptAccountTrie(t *testing.T) { 443 // We can't use statedb to make a test trie (circular dependency), so make 444 // a fake one manually. We're going with a small account trie of 3 accounts, 445 // without any storage slots to keep the test smaller. 446 var ( 447 diskdb = database.NewMemoryDBManager() 448 triedb = statedb.NewDatabase(diskdb) 449 ) 450 tr, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 451 acc1, _ := genExternallyOwnedAccount(0, big.NewInt(1)) 452 serializer1 := account.NewAccountSerializerWithAccount(acc1) 453 val, _ := rlp.EncodeToBytes(serializer1) 454 tr.Update([]byte("acc-1"), val) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 455 456 acc2, _ := genExternallyOwnedAccount(0, big.NewInt(2)) 457 serializer2 := account.NewAccountSerializerWithAccount(acc2) 458 val, _ = rlp.EncodeToBytes(serializer2) 459 tr.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 460 461 acc3, _ := genExternallyOwnedAccount(0, big.NewInt(3)) 462 serializer3 := account.NewAccountSerializerWithAccount(acc3) 463 val, _ = rlp.EncodeToBytes(serializer3) 464 tr.Update([]byte("acc-3"), val) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 465 tr.Commit(nil) // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 466 467 // Delete an account trie leaf and ensure the generator chokes 468 // TODO-Klaytn-Snapshot put propoer block number 469 triedb.Commit(common.HexToHash("0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978"), false, 0) 470 diskdb.DeleteTrieNode(common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7").ExtendZero()) 471 472 snap := generateSnapshot(diskdb, triedb, 16, common.HexToHash("0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978")) 473 select { 474 case <-snap.genPending: 475 // Snapshot generation succeeded 476 t.Errorf("Snapshot generated against corrupt account trie") 477 478 case <-time.After(time.Second): 479 // Not generated fast enough, hopefully blocked inside on missing trie node fail 480 } 481 // Signal abortion to the generator and wait for it to tear down 482 stop := make(chan *generatorStats) 483 snap.genAbort <- stop 484 <-stop 485 } 486 487 // Tests that snapshot generation errors out correctly in case of a missing root 488 // trie node for a storage trie. It's similar to internal corruption but it is 489 // handled differently inside the generator. 490 func TestGenerateMissingStorageTrie(t *testing.T) { 491 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 492 493 // We can't use statedb to make a test trie (circular dependency), so make 494 // a fake one manually. We're going with a small account trie of 3 accounts, 495 // two of which also has the same 3-slot storage trie attached. 496 var ( 497 diskdb = database.NewMemoryDBManager() 498 triedb = statedb.NewDatabase(diskdb) 499 ) 500 stTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 501 stTrie.Update([]byte("key-1"), []byte("val-1")) // 0x1314700b81afc49f94db3623ef1df38f3ed18b73a1b7ea2f6c095118cf6118a0 502 stTrie.Update([]byte("key-2"), []byte("val-2")) // 0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371 503 stTrie.Update([]byte("key-3"), []byte("val-3")) // 0x51c71a47af0695957647fb68766d0becee77e953df17c29b3c2f25436f055c78 504 stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 505 506 accTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 507 acc, _ := genSmartContractAccount(0, big.NewInt(1), stTrie.Hash(), emptyCode.Bytes()) 508 val, _ := rlp.EncodeToBytes(account.NewAccountSerializerWithAccount(acc)) 509 accTrie.Update([]byte("acc-1"), val) // 0x30301e37c9af8ee5f609f1d60a3307d3e113bea03bef203e39aadc46bd5ad5ee 510 511 acc, _ = genSmartContractAccount(0, big.NewInt(2), stTrie.Hash(), emptyCode.Bytes()) 512 val, _ = rlp.EncodeToBytes(account.NewAccountSerializerWithAccount(acc)) 513 accTrie.Update([]byte("acc-2"), val) // 0xff964e27aca3ef5766a7709de6beff44863d539c9af88ab1719865b80a55b6b2 514 t.Log(accTrie.Hash().String()) 515 516 acc, _ = genSmartContractAccount(0, big.NewInt(3), stTrie.Hash(), emptyCode.Bytes()) 517 val, _ = rlp.EncodeToBytes(account.NewAccountSerializerWithAccount(acc)) 518 accTrie.Update([]byte("acc-3"), val) // 0x8c2477df4801bbf88c6636445a2a9feff54c098cc218df403dc3f1007add780c 519 accTrie.Commit(nil) // Root: 0xa2282b99de1fc11e32d26bee37707ef49a6978b2d375796a1b026a497193a2ef 520 521 // We can only corrupt the disk database, so flush the tries out 522 triedb.Reference( 523 common.HexToExtHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), 524 common.HexToExtHash("0x30301e37c9af8ee5f609f1d60a3307d3e113bea03bef203e39aadc46bd5ad5ee"), 525 ) 526 triedb.Reference( 527 common.HexToExtHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), 528 common.HexToExtHash("0x8c2477df4801bbf88c6636445a2a9feff54c098cc218df403dc3f1007add780c"), 529 ) 530 // TODO-Klaytn-Snapshot put proper block number 531 triedb.Commit(common.HexToHash("0xa2282b99de1fc11e32d26bee37707ef49a6978b2d375796a1b026a497193a2ef"), false, 0) 532 533 // Delete a storage trie root and ensure the generator chokes 534 diskdb.DeleteTrieNode(common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67").ExtendZero()) 535 536 snap := generateSnapshot(diskdb, triedb, 16, common.HexToHash("0xa2282b99de1fc11e32d26bee37707ef49a6978b2d375796a1b026a497193a2ef")) 537 select { 538 case <-snap.genPending: 539 // Snapshot generation succeeded 540 t.Errorf("Snapshot generated against corrupt storage trie") 541 542 case <-time.After(time.Second): 543 // Not generated fast enough, hopefully blocked inside on missing trie node fail 544 } 545 // Signal abortion to the generator and wait for it to tear down 546 stop := make(chan *generatorStats) 547 snap.genAbort <- stop 548 <-stop 549 } 550 551 // Tests that snapshot generation errors out correctly in case of a missing trie 552 // node in a storage trie. 553 func TestGenerateCorruptStorageTrie(t *testing.T) { 554 // We can't use statedb to make a test trie (circular dependency), so make 555 // a fake one manually. We're going with a small account trie of 3 accounts, 556 // two of which also has the same 3-slot storage trie attached. 557 var ( 558 diskdb = database.NewMemoryDBManager() 559 triedb = statedb.NewDatabase(diskdb) 560 ) 561 stTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 562 stTrie.Update([]byte("key-1"), []byte("val-1")) // 0x1314700b81afc49f94db3623ef1df38f3ed18b73a1b7ea2f6c095118cf6118a0 563 stTrie.Update([]byte("key-2"), []byte("val-2")) // 0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371 564 stTrie.Update([]byte("key-3"), []byte("val-3")) // 0x51c71a47af0695957647fb68766d0becee77e953df17c29b3c2f25436f055c78 565 stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 566 567 accTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 568 acc, _ := genSmartContractAccount(0, big.NewInt(1), stTrie.Hash(), emptyCode.Bytes()) 569 serializer := account.NewAccountSerializerWithAccount(acc) 570 val, _ := rlp.EncodeToBytes(serializer) 571 accTrie.Update([]byte("acc-1"), val) // 0x30301e37c9af8ee5f609f1d60a3307d3e113bea03bef203e39aadc46bd5ad5ee 572 573 acc, _ = genExternallyOwnedAccount(0, big.NewInt(2)) 574 serializer = account.NewAccountSerializerWithAccount(acc) 575 val, _ = rlp.EncodeToBytes(serializer) 576 accTrie.Update([]byte("acc-2"), val) // 0x11944b79b322f047379973e18ba21657b8ad4b50ecd94217177bc56f89905228 577 578 acc, _ = genSmartContractAccount(0, big.NewInt(3), stTrie.Hash(), emptyCode.Bytes()) 579 serializer = account.NewAccountSerializerWithAccount(acc) 580 val, _ = rlp.EncodeToBytes(serializer) 581 accTrie.Update([]byte("acc-3"), val) // 0x8c2477df4801bbf88c6636445a2a9feff54c098cc218df403dc3f1007add780c 582 accTrie.Commit(nil) // Root: 0x4a651234bc4b8c7462b5ad4eb95bbb724eb636fed72bb5278d886f9ea4c345f8 583 584 // We can only corrupt the disk database, so flush the tries out 585 triedb.Reference( 586 common.HexToExtHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), 587 common.HexToExtHash("0x30301e37c9af8ee5f609f1d60a3307d3e113bea03bef203e39aadc46bd5ad5ee"), 588 ) 589 triedb.Reference( 590 common.HexToExtHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), 591 common.HexToExtHash("0x8c2477df4801bbf88c6636445a2a9feff54c098cc218df403dc3f1007add780c"), 592 ) 593 // TODO-Klaytn-Snapshot put proper block number 594 triedb.Commit(common.HexToHash("0x4a651234bc4b8c7462b5ad4eb95bbb724eb636fed72bb5278d886f9ea4c345f8"), false, 0) 595 596 // Delete a storage trie leaf and ensure the generator chokes 597 diskdb.DeleteTrieNode(common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371").ExtendZero()) 598 599 snap := generateSnapshot(diskdb, triedb, 16, common.HexToHash("0x4a651234bc4b8c7462b5ad4eb95bbb724eb636fed72bb5278d886f9ea4c345f8")) 600 select { 601 case <-snap.genPending: 602 // Snapshot generation succeeded 603 t.Errorf("Snapshot generated against corrupt storage trie") 604 605 case <-time.After(time.Second): 606 // Not generated fast enough, hopefully blocked inside on missing trie node fail 607 } 608 // Signal abortion to the generator and wait for it to tear down 609 stop := make(chan *generatorStats) 610 snap.genAbort <- stop 611 <-stop 612 } 613 614 func getStorageTrie(n int, triedb *statedb.Database) *statedb.SecureTrie { 615 stTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 616 for i := 0; i < n; i++ { 617 k := fmt.Sprintf("key-%d", i) 618 v := fmt.Sprintf("val-%d", i) 619 stTrie.Update([]byte(k), []byte(v)) 620 } 621 stTrie.Commit(nil) 622 return stTrie 623 } 624 625 // Tests that snapshot generation when an extra account with storage exists in the snap state. 626 func TestGenerateWithExtraAccounts(t *testing.T) { 627 var ( 628 diskdb = database.NewMemoryDBManager() 629 triedb = statedb.NewDatabase(diskdb) 630 stTrie = getStorageTrie(5, triedb) 631 ) 632 accTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 633 { // Account one in the trie 634 acc, _ := genSmartContractAccount(0, big.NewInt(1), stTrie.Hash(), emptyCode.Bytes()) 635 val, _ := rlp.EncodeToBytes(account.NewAccountSerializerWithAccount(acc)) 636 accTrie.Update([]byte("acc-1"), val) // 0xfa43eb0210d32b0013ae744d26ded52489ee3cab4a5bd9128a599135aba7c088 637 // Identical in the snap 638 key := hashData([]byte("acc-1")) 639 diskdb.WriteAccountSnapshot(key, val) 640 diskdb.WriteStorageSnapshot(key, hashData([]byte("key-1")), []byte("val-1")) 641 diskdb.WriteStorageSnapshot(key, hashData([]byte("key-2")), []byte("val-2")) 642 diskdb.WriteStorageSnapshot(key, hashData([]byte("key-3")), []byte("val-3")) 643 diskdb.WriteStorageSnapshot(key, hashData([]byte("key-4")), []byte("val-4")) 644 diskdb.WriteStorageSnapshot(key, hashData([]byte("key-5")), []byte("val-5")) 645 } 646 { // Account two exists only in the snapshot 647 acc, _ := genSmartContractAccount(0, big.NewInt(1), stTrie.Hash(), emptyCode.Bytes()) 648 val, _ := rlp.EncodeToBytes(account.NewAccountSerializerWithAccount(acc)) 649 key := hashData([]byte("acc-2")) 650 diskdb.WriteAccountSnapshot(key, val) 651 diskdb.WriteStorageSnapshot(key, hashData([]byte("b-key-1")), []byte("b-val-1")) 652 diskdb.WriteStorageSnapshot(key, hashData([]byte("b-key-2")), []byte("b-val-2")) 653 diskdb.WriteStorageSnapshot(key, hashData([]byte("b-key-3")), []byte("b-val-3")) 654 } 655 root, _ := accTrie.Commit(nil) 656 t.Logf("root: %x", root) 657 // TODO-Klaytn-Snapshot put proper block number 658 triedb.Commit(root, false, 0) 659 // To verify the test: If we now inspect the snap db, there should exist extraneous storage items 660 if data := diskdb.ReadStorageSnapshot(hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data == nil { 661 t.Fatalf("expected snap storage to exist") 662 } 663 664 snap := generateSnapshot(diskdb, triedb, 16, root) 665 select { 666 case <-snap.genPending: 667 // Snapshot generation succeeded 668 669 case <-time.After(3 * time.Second): 670 t.Errorf("Snapshot generation failed") 671 } 672 checkSnapRoot(t, snap, root) 673 // Signal abortion to the generator and wait for it to tear down 674 stop := make(chan *generatorStats) 675 snap.genAbort <- stop 676 <-stop 677 // If we now inspect the snap db, there should exist no extraneous storage items 678 if data := diskdb.ReadStorageSnapshot(hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil { 679 t.Fatalf("expected slot to be removed, got %v", string(data)) 680 } 681 } 682 683 // Tests that snapshot generation when an extra account with storage exists in the snap state. 684 func TestGenerateWithManyExtraAccounts(t *testing.T) { 685 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 686 687 var ( 688 diskdb = database.NewMemoryDBManager() 689 triedb = statedb.NewDatabase(diskdb) 690 stTrie = getStorageTrie(3, triedb) 691 ) 692 accTrie, _ := statedb.NewSecureTrie(common.Hash{}, triedb, nil) 693 { // Account one in the trie 694 acc, _ := genSmartContractAccount(0, big.NewInt(1), stTrie.Hash(), emptyCode.Bytes()) 695 val, _ := rlp.EncodeToBytes(account.NewAccountSerializerWithAccount(acc)) 696 accTrie.Update([]byte("acc-1"), val) // 0xe9ddf05eaf05dbd7c6fb1137e90b4f3b1ed43383aaaa88312de297e304599966 697 // Identical in the snap 698 key := hashData([]byte("acc-1")) 699 diskdb.WriteAccountSnapshot(key, val) 700 diskdb.WriteStorageSnapshot(key, hashData([]byte("key-1")), []byte("val-1")) 701 diskdb.WriteStorageSnapshot(key, hashData([]byte("key-2")), []byte("val-2")) 702 diskdb.WriteStorageSnapshot(key, hashData([]byte("key-3")), []byte("val-3")) 703 } 704 { // 100 accounts exist only in snapshot 705 for i := 0; i < 1000; i++ { 706 acc, _ := genExternallyOwnedAccount(uint64(i), big.NewInt(int64(i))) 707 val, _ := rlp.EncodeToBytes(acc) 708 key := hashData([]byte(fmt.Sprintf("acc-%d", i))) 709 diskdb.WriteAccountSnapshot(key, val) 710 } 711 } 712 root, _ := accTrie.Commit(nil) 713 t.Logf("root: %x", root) 714 // TODO-Klaytn-Snapshot put proper block number 715 triedb.Commit(root, false, 0) 716 717 snap := generateSnapshot(diskdb, triedb, 16, root) 718 select { 719 case <-snap.genPending: 720 // Snapshot generation succeeded 721 722 case <-time.After(3 * time.Second): 723 t.Errorf("Snapshot generation failed") 724 } 725 checkSnapRoot(t, snap, root) 726 // Signal abortion to the generator and wait for it to tear down 727 stop := make(chan *generatorStats) 728 snap.genAbort <- stop 729 <-stop 730 } 731 732 // Tests this case 733 // maxAccountRange 3 734 // snapshot-accounts: 01, 02, 03, 04, 05, 06, 07 735 // trie-accounts: 03, 07 736 // 737 // We iterate three snapshot storage slots (max = 3) from the database. They are 0x01, 0x02, 0x03. 738 // The trie has a lot of deletions. 739 // So in trie, we iterate 2 entries 0x03, 0x07. We create the 0x07 in the database and abort the procedure, because the trie is exhausted. 740 // But in the database, we still have the stale storage slots 0x04, 0x05. They are not iterated yet, but the procedure is finished. 741 func TestGenerateWithExtraBeforeAndAfter(t *testing.T) { 742 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 743 accountCheckRange = 3 744 var ( 745 diskdb = database.NewMemoryDBManager() 746 triedb = statedb.NewDatabase(diskdb) 747 ) 748 accTrie, _ := statedb.NewTrie(common.Hash{}, triedb, nil) 749 { 750 acc, _ := genExternallyOwnedAccount(0, big.NewInt(1)) 751 val, _ := rlp.EncodeToBytes(account.NewAccountSerializerWithAccount(acc)) 752 accTrie.Update(common.HexToHash("0x03").Bytes(), val) 753 accTrie.Update(common.HexToHash("0x07").Bytes(), val) 754 755 diskdb.WriteAccountSnapshot(common.HexToHash("0x01"), val) 756 diskdb.WriteAccountSnapshot(common.HexToHash("0x02"), val) 757 diskdb.WriteAccountSnapshot(common.HexToHash("0x03"), val) 758 diskdb.WriteAccountSnapshot(common.HexToHash("0x04"), val) 759 diskdb.WriteAccountSnapshot(common.HexToHash("0x05"), val) 760 diskdb.WriteAccountSnapshot(common.HexToHash("0x06"), val) 761 diskdb.WriteAccountSnapshot(common.HexToHash("0x07"), val) 762 } 763 764 root, _ := accTrie.Commit(nil) 765 t.Logf("root: %x", root) 766 // TODO-Klaytn-Snapshot put proper block number 767 triedb.Commit(root, false, 0) 768 769 snap := generateSnapshot(diskdb, triedb, 16, root) 770 select { 771 case <-snap.genPending: 772 // Snapshot generation succeeded 773 774 case <-time.After(3 * time.Second): 775 t.Errorf("Snapshot generation failed") 776 } 777 checkSnapRoot(t, snap, root) 778 // Signal abortion to the generator and wait for it to tear down 779 stop := make(chan *generatorStats) 780 snap.genAbort <- stop 781 <-stop 782 } 783 784 // TestGenerateWithMalformedSnapdata tests what happes if we have some junk 785 // in the snapshot database, which cannot be parsed back to an account 786 func TestGenerateWithMalformedSnapdata(t *testing.T) { 787 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 788 accountCheckRange = 3 789 var ( 790 diskdb = database.NewMemoryDBManager() 791 triedb = statedb.NewDatabase(diskdb) 792 ) 793 accTrie, _ := statedb.NewTrie(common.Hash{}, triedb, nil) 794 { 795 acc, _ := genExternallyOwnedAccount(0, big.NewInt(1)) 796 val, _ := rlp.EncodeToBytes(account.NewAccountSerializerWithAccount(acc)) 797 accTrie.Update(common.HexToHash("0x03").Bytes(), val) 798 799 junk := make([]byte, 100) 800 copy(junk, []byte{0xde, 0xad}) 801 diskdb.WriteAccountSnapshot(common.HexToHash("0x02"), junk) 802 diskdb.WriteAccountSnapshot(common.HexToHash("0x03"), junk) 803 diskdb.WriteAccountSnapshot(common.HexToHash("0x04"), junk) 804 diskdb.WriteAccountSnapshot(common.HexToHash("0x05"), junk) 805 } 806 807 root, _ := accTrie.Commit(nil) 808 t.Logf("root: %x", root) 809 // TODO-Klaytn-Snapshot put proper block number 810 triedb.Commit(root, false, 0) 811 812 snap := generateSnapshot(diskdb, triedb, 16, root) 813 select { 814 case <-snap.genPending: 815 // Snapshot generation succeeded 816 817 case <-time.After(3 * time.Second): 818 t.Errorf("Snapshot generation failed") 819 } 820 checkSnapRoot(t, snap, root) 821 // Signal abortion to the generator and wait for it to tear down 822 stop := make(chan *generatorStats) 823 snap.genAbort <- stop 824 <-stop 825 // If we now inspect the snap db, there should exist no extraneous storage items 826 if data := diskdb.ReadStorageSnapshot(hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil { 827 t.Fatalf("expected slot to be removed, got %v", string(data)) 828 } 829 } 830 831 func TestGenerateFromEmptySnap(t *testing.T) { 832 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 833 accountCheckRange = 10 834 storageCheckRange = 20 835 helper := newHelper() 836 stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 837 // Add 1K accounts to the trie 838 for i := 0; i < 400; i++ { 839 acc, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 840 helper.addTrieAccount(fmt.Sprintf("acc-%d", i), acc) 841 } 842 root, snap := helper.Generate() 843 t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4 844 845 select { 846 case <-snap.genPending: 847 // Snapshot generation succeeded 848 849 case <-time.After(3 * time.Second): 850 t.Errorf("Snapshot generation failed") 851 } 852 checkSnapRoot(t, snap, root) 853 // Signal abortion to the generator and wait for it to tear down 854 stop := make(chan *generatorStats) 855 snap.genAbort <- stop 856 <-stop 857 } 858 859 // Tests that snapshot generation with existent flat state, where the flat state 860 // storage is correct, but incomplete. 861 // The incomplete part is on the second range 862 // snap: [ 0x01, 0x02, 0x03, 0x04] , [ 0x05, 0x06, 0x07, {missing}] (with storageCheck = 4) 863 // trie: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 864 // This hits a case where the snap verification passes, but there are more elements in the trie 865 // which we must also add. 866 func TestGenerateWithIncompleteStorage(t *testing.T) { 867 storageCheckRange = 4 868 helper := newHelper() 869 stKeys := []string{"1", "2", "3", "4", "5", "6", "7", "8"} 870 stVals := []string{"v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"} 871 stRoot := helper.makeStorageTrie(stKeys, stVals) 872 // We add 8 accounts, each one is missing exactly one of the storage slots. This means 873 // we don't have to order the keys and figure out exactly which hash-key winds up 874 // on the sensitive spots at the boundaries 875 for i := 0; i < 8; i++ { 876 accKey := fmt.Sprintf("acc-%d", i) 877 acc, _ := genSmartContractAccount(0, big.NewInt(1), stRoot, emptyCode.Bytes()) 878 helper.addAccount(accKey, acc) 879 var moddedKeys []string 880 var moddedVals []string 881 for ii := 0; ii < 8; ii++ { 882 if ii != i { 883 moddedKeys = append(moddedKeys, stKeys[ii]) 884 moddedVals = append(moddedVals, stVals[ii]) 885 } 886 } 887 helper.addSnapStorage(accKey, moddedKeys, moddedVals) 888 } 889 890 root, snap := helper.Generate() 891 t.Logf("Root: %#x\n", root) // Root: 0xca73f6f05ba4ca3024ef340ef3dfca8fdabc1b677ff13f5a9571fd49c16e67ff 892 893 select { 894 case <-snap.genPending: 895 // Snapshot generation succeeded 896 897 case <-time.After(3 * time.Second): 898 t.Errorf("Snapshot generation failed") 899 } 900 checkSnapRoot(t, snap, root) 901 // Signal abortion to the generator and wait for it to tear down 902 stop := make(chan *generatorStats) 903 snap.genAbort <- stop 904 <-stop 905 }