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