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