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