github.com/Unheilbar/quorum@v1.0.0/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/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/core/rawdb" 28 "github.com/ethereum/go-ethereum/ethdb" 29 "github.com/ethereum/go-ethereum/ethdb/memorydb" 30 "github.com/ethereum/go-ethereum/log" 31 "github.com/ethereum/go-ethereum/rlp" 32 "github.com/ethereum/go-ethereum/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(250 * time.Millisecond): 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(250 * time.Millisecond): 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 // 238 // - the contract(non-empty storage) has wrong storage slots 239 // - wrong slots in the beginning 240 // - wrong slots in the middle 241 // - wrong slots in the end 242 // 243 // - the contract(non-empty storage) has extra storage slots 244 // - extra slots in the beginning 245 // - extra slots in the middle 246 // - extra slots in the end 247 func TestGenerateExistentStateWithWrongStorage(t *testing.T) { 248 helper := newHelper() 249 stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 250 251 // Account one, empty root but non-empty database 252 helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) 253 helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 254 255 // Account two, non empty root but empty database 256 helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 257 258 // Miss slots 259 { 260 // Account three, non empty root but misses slots in the beginning 261 helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 262 helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"}) 263 264 // Account four, non empty root but misses slots in the middle 265 helper.addAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 266 helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"}) 267 268 // Account five, non empty root but misses slots in the end 269 helper.addAccount("acc-5", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 270 helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"}) 271 } 272 273 // Wrong storage slots 274 { 275 // Account six, non empty root but wrong slots in the beginning 276 helper.addAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 277 helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"}) 278 279 // Account seven, non empty root but wrong slots in the middle 280 helper.addAccount("acc-7", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 281 helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"}) 282 283 // Account eight, non empty root but wrong slots in the end 284 helper.addAccount("acc-8", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 285 helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"}) 286 287 // Account 9, non empty root but rotated slots 288 helper.addAccount("acc-9", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 289 helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"}) 290 } 291 292 // Extra storage slots 293 { 294 // Account 10, non empty root but extra slots in the beginning 295 helper.addAccount("acc-10", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 296 helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"}) 297 298 // Account 11, non empty root but extra slots in the middle 299 helper.addAccount("acc-11", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 300 helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"}) 301 302 // Account 12, non empty root but extra slots in the end 303 helper.addAccount("acc-12", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 304 helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"}) 305 } 306 307 root, snap := helper.Generate() 308 t.Logf("Root: %#x\n", root) // Root = 0x8746cce9fd9c658b2cfd639878ed6584b7a2b3e73bb40f607fcfa156002429a0 309 310 select { 311 case <-snap.genPending: 312 // Snapshot generation succeeded 313 314 case <-time.After(250 * time.Millisecond): 315 t.Errorf("Snapshot generation failed") 316 } 317 checkSnapRoot(t, snap, root) 318 // Signal abortion to the generator and wait for it to tear down 319 stop := make(chan *generatorStats) 320 snap.genAbort <- stop 321 <-stop 322 } 323 324 // Tests that snapshot generation with existent flat state, where the flat state 325 // contains some errors: 326 // - miss accounts 327 // - wrong accounts 328 // - extra accounts 329 func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { 330 helper := newHelper() 331 stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 332 333 // Trie accounts [acc-1, acc-2, acc-3, acc-4, acc-6] 334 // Extra accounts [acc-0, acc-5, acc-7] 335 336 // Missing accounts, only in the trie 337 { 338 helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // Beginning 339 helper.addTrieAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // Middle 340 helper.addTrieAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // End 341 } 342 343 // Wrong accounts 344 { 345 helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 346 helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: common.Hex2Bytes("0x1234")}) 347 348 helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 349 helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) 350 } 351 352 // Extra accounts, only in the snap 353 { 354 helper.addSnapAccount("acc-0", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyRoot.Bytes()}) // before the beginning 355 helper.addSnapAccount("acc-5", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: common.Hex2Bytes("0x1234")}) // Middle 356 helper.addSnapAccount("acc-7", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyRoot.Bytes()}) // after the end 357 } 358 359 root, snap := helper.Generate() 360 t.Logf("Root: %#x\n", root) // Root = 0x825891472281463511e7ebcc7f109e4f9200c20fa384754e11fd605cd98464e8 361 362 select { 363 case <-snap.genPending: 364 // Snapshot generation succeeded 365 366 case <-time.After(250 * time.Millisecond): 367 t.Errorf("Snapshot generation failed") 368 } 369 checkSnapRoot(t, snap, root) 370 371 // Signal abortion to the generator and wait for it to tear down 372 stop := make(chan *generatorStats) 373 snap.genAbort <- stop 374 <-stop 375 } 376 377 // Tests that snapshot generation errors out correctly in case of a missing trie 378 // node in the account trie. 379 func TestGenerateCorruptAccountTrie(t *testing.T) { 380 // We can't use statedb to make a test trie (circular dependency), so make 381 // a fake one manually. We're going with a small account trie of 3 accounts, 382 // without any storage slots to keep the test smaller. 383 var ( 384 diskdb = memorydb.New() 385 triedb = trie.NewDatabase(diskdb) 386 ) 387 tr, _ := trie.NewSecure(common.Hash{}, triedb) 388 acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} 389 val, _ := rlp.EncodeToBytes(acc) 390 tr.Update([]byte("acc-1"), val) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 391 392 acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} 393 val, _ = rlp.EncodeToBytes(acc) 394 tr.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 395 396 acc = &Account{Balance: big.NewInt(3), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} 397 val, _ = rlp.EncodeToBytes(acc) 398 tr.Update([]byte("acc-3"), val) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 399 tr.Commit(nil) // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 400 401 // Delete an account trie leaf and ensure the generator chokes 402 triedb.Commit(common.HexToHash("0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978"), false, nil) 403 diskdb.Delete(common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7").Bytes()) 404 405 snap := generateSnapshot(diskdb, triedb, 16, common.HexToHash("0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978")) 406 select { 407 case <-snap.genPending: 408 // Snapshot generation succeeded 409 t.Errorf("Snapshot generated against corrupt account trie") 410 411 case <-time.After(250 * time.Millisecond): 412 // Not generated fast enough, hopefully blocked inside on missing trie node fail 413 } 414 // Signal abortion to the generator and wait for it to tear down 415 stop := make(chan *generatorStats) 416 snap.genAbort <- stop 417 <-stop 418 } 419 420 // Tests that snapshot generation errors out correctly in case of a missing root 421 // trie node for a storage trie. It's similar to internal corruption but it is 422 // handled differently inside the generator. 423 func TestGenerateMissingStorageTrie(t *testing.T) { 424 // We can't use statedb to make a test trie (circular dependency), so make 425 // a fake one manually. We're going with a small account trie of 3 accounts, 426 // two of which also has the same 3-slot storage trie attached. 427 var ( 428 diskdb = memorydb.New() 429 triedb = trie.NewDatabase(diskdb) 430 ) 431 stTrie, _ := trie.NewSecure(common.Hash{}, triedb) 432 stTrie.Update([]byte("key-1"), []byte("val-1")) // 0x1314700b81afc49f94db3623ef1df38f3ed18b73a1b7ea2f6c095118cf6118a0 433 stTrie.Update([]byte("key-2"), []byte("val-2")) // 0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371 434 stTrie.Update([]byte("key-3"), []byte("val-3")) // 0x51c71a47af0695957647fb68766d0becee77e953df17c29b3c2f25436f055c78 435 stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 436 437 accTrie, _ := trie.NewSecure(common.Hash{}, triedb) 438 acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} 439 val, _ := rlp.EncodeToBytes(acc) 440 accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e 441 442 acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} 443 val, _ = rlp.EncodeToBytes(acc) 444 accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 445 446 acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} 447 val, _ = rlp.EncodeToBytes(acc) 448 accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 449 accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd 450 451 // We can only corrupt the disk database, so flush the tries out 452 triedb.Reference( 453 common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), 454 common.HexToHash("0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e"), 455 ) 456 triedb.Reference( 457 common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), 458 common.HexToHash("0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2"), 459 ) 460 triedb.Commit(common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"), false, nil) 461 462 // Delete a storage trie root and ensure the generator chokes 463 diskdb.Delete(common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67").Bytes()) 464 465 snap := generateSnapshot(diskdb, triedb, 16, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd")) 466 select { 467 case <-snap.genPending: 468 // Snapshot generation succeeded 469 t.Errorf("Snapshot generated against corrupt storage trie") 470 471 case <-time.After(250 * time.Millisecond): 472 // Not generated fast enough, hopefully blocked inside on missing trie node fail 473 } 474 // Signal abortion to the generator and wait for it to tear down 475 stop := make(chan *generatorStats) 476 snap.genAbort <- stop 477 <-stop 478 } 479 480 // Tests that snapshot generation errors out correctly in case of a missing trie 481 // node in a storage trie. 482 func TestGenerateCorruptStorageTrie(t *testing.T) { 483 // We can't use statedb to make a test trie (circular dependency), so make 484 // a fake one manually. We're going with a small account trie of 3 accounts, 485 // two of which also has the same 3-slot storage trie attached. 486 var ( 487 diskdb = memorydb.New() 488 triedb = trie.NewDatabase(diskdb) 489 ) 490 stTrie, _ := trie.NewSecure(common.Hash{}, triedb) 491 stTrie.Update([]byte("key-1"), []byte("val-1")) // 0x1314700b81afc49f94db3623ef1df38f3ed18b73a1b7ea2f6c095118cf6118a0 492 stTrie.Update([]byte("key-2"), []byte("val-2")) // 0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371 493 stTrie.Update([]byte("key-3"), []byte("val-3")) // 0x51c71a47af0695957647fb68766d0becee77e953df17c29b3c2f25436f055c78 494 stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 495 496 accTrie, _ := trie.NewSecure(common.Hash{}, triedb) 497 acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} 498 val, _ := rlp.EncodeToBytes(acc) 499 accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e 500 501 acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} 502 val, _ = rlp.EncodeToBytes(acc) 503 accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 504 505 acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} 506 val, _ = rlp.EncodeToBytes(acc) 507 accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 508 accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd 509 510 // We can only corrupt the disk database, so flush the tries out 511 triedb.Reference( 512 common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), 513 common.HexToHash("0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e"), 514 ) 515 triedb.Reference( 516 common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), 517 common.HexToHash("0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2"), 518 ) 519 triedb.Commit(common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"), false, nil) 520 521 // Delete a storage trie leaf and ensure the generator chokes 522 diskdb.Delete(common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371").Bytes()) 523 524 snap := generateSnapshot(diskdb, triedb, 16, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd")) 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 *generatorStats) 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, root) 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 *generatorStats) 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, root) 647 select { 648 case <-snap.genPending: 649 // Snapshot generation succeeded 650 651 case <-time.After(250 * time.Millisecond): 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 accountCheckRange = 3 672 if false { 673 enableLogging() 674 } 675 var ( 676 diskdb = memorydb.New() 677 triedb = trie.NewDatabase(diskdb) 678 ) 679 accTrie, _ := trie.New(common.Hash{}, triedb) 680 { 681 acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} 682 val, _ := rlp.EncodeToBytes(acc) 683 accTrie.Update(common.HexToHash("0x03").Bytes(), val) 684 accTrie.Update(common.HexToHash("0x07").Bytes(), val) 685 686 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x01"), val) 687 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x02"), val) 688 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x03"), val) 689 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x04"), val) 690 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x05"), val) 691 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x06"), val) 692 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x07"), val) 693 } 694 695 root, _ := accTrie.Commit(nil) 696 t.Logf("root: %x", root) 697 triedb.Commit(root, false, nil) 698 699 snap := generateSnapshot(diskdb, triedb, 16, root) 700 select { 701 case <-snap.genPending: 702 // Snapshot generation succeeded 703 704 case <-time.After(250 * time.Millisecond): 705 t.Errorf("Snapshot generation failed") 706 } 707 checkSnapRoot(t, snap, root) 708 // Signal abortion to the generator and wait for it to tear down 709 stop := make(chan *generatorStats) 710 snap.genAbort <- stop 711 <-stop 712 } 713 714 // TestGenerateWithMalformedSnapdata tests what happes if we have some junk 715 // in the snapshot database, which cannot be parsed back to an account 716 func TestGenerateWithMalformedSnapdata(t *testing.T) { 717 accountCheckRange = 3 718 if false { 719 enableLogging() 720 } 721 var ( 722 diskdb = memorydb.New() 723 triedb = trie.NewDatabase(diskdb) 724 ) 725 accTrie, _ := trie.New(common.Hash{}, triedb) 726 { 727 acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} 728 val, _ := rlp.EncodeToBytes(acc) 729 accTrie.Update(common.HexToHash("0x03").Bytes(), val) 730 731 junk := make([]byte, 100) 732 copy(junk, []byte{0xde, 0xad}) 733 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x02"), junk) 734 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x03"), junk) 735 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x04"), junk) 736 rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x05"), junk) 737 } 738 739 root, _ := accTrie.Commit(nil) 740 t.Logf("root: %x", root) 741 triedb.Commit(root, false, nil) 742 743 snap := generateSnapshot(diskdb, triedb, 16, root) 744 select { 745 case <-snap.genPending: 746 // Snapshot generation succeeded 747 748 case <-time.After(250 * time.Millisecond): 749 t.Errorf("Snapshot generation failed") 750 } 751 checkSnapRoot(t, snap, root) 752 // Signal abortion to the generator and wait for it to tear down 753 stop := make(chan *generatorStats) 754 snap.genAbort <- stop 755 <-stop 756 // If we now inspect the snap db, there should exist no extraneous storage items 757 if data := rawdb.ReadStorageSnapshot(diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil { 758 t.Fatalf("expected slot to be removed, got %v", string(data)) 759 } 760 } 761 762 func TestGenerateFromEmptySnap(t *testing.T) { 763 //enableLogging() 764 accountCheckRange = 10 765 storageCheckRange = 20 766 helper := newHelper() 767 stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 768 // Add 1K accounts to the trie 769 for i := 0; i < 400; i++ { 770 helper.addTrieAccount(fmt.Sprintf("acc-%d", i), 771 &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) 772 } 773 root, snap := helper.Generate() 774 t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4 775 776 select { 777 case <-snap.genPending: 778 // Snapshot generation succeeded 779 780 case <-time.After(1 * time.Second): 781 t.Errorf("Snapshot generation failed") 782 } 783 checkSnapRoot(t, snap, root) 784 // Signal abortion to the generator and wait for it to tear down 785 stop := make(chan *generatorStats) 786 snap.genAbort <- stop 787 <-stop 788 } 789 790 // Tests that snapshot generation with existent flat state, where the flat state 791 // storage is correct, but incomplete. 792 // The incomplete part is on the second range 793 // snap: [ 0x01, 0x02, 0x03, 0x04] , [ 0x05, 0x06, 0x07, {missing}] (with storageCheck = 4) 794 // trie: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 795 // This hits a case where the snap verification passes, but there are more elements in the trie 796 // which we must also add. 797 func TestGenerateWithIncompleteStorage(t *testing.T) { 798 storageCheckRange = 4 799 helper := newHelper() 800 stKeys := []string{"1", "2", "3", "4", "5", "6", "7", "8"} 801 stVals := []string{"v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"} 802 stRoot := helper.makeStorageTrie(stKeys, stVals) 803 // We add 8 accounts, each one is missing exactly one of the storage slots. This means 804 // we don't have to order the keys and figure out exactly which hash-key winds up 805 // on the sensitive spots at the boundaries 806 for i := 0; i < 8; i++ { 807 accKey := fmt.Sprintf("acc-%d", i) 808 helper.addAccount(accKey, &Account{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: emptyCode.Bytes()}) 809 var moddedKeys []string 810 var moddedVals []string 811 for ii := 0; ii < 8; ii++ { 812 if ii != i { 813 moddedKeys = append(moddedKeys, stKeys[ii]) 814 moddedVals = append(moddedVals, stVals[ii]) 815 } 816 } 817 helper.addSnapStorage(accKey, moddedKeys, moddedVals) 818 } 819 820 root, snap := helper.Generate() 821 t.Logf("Root: %#x\n", root) // Root: 0xca73f6f05ba4ca3024ef340ef3dfca8fdabc1b677ff13f5a9571fd49c16e67ff 822 823 select { 824 case <-snap.genPending: 825 // Snapshot generation succeeded 826 827 case <-time.After(250 * time.Millisecond): 828 t.Errorf("Snapshot generation failed") 829 } 830 checkSnapRoot(t, snap, root) 831 // Signal abortion to the generator and wait for it to tear down 832 stop := make(chan *generatorStats) 833 snap.genAbort <- stop 834 <-stop 835 }