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