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