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