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