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