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