github.com/ethereum/go-ethereum@v1.16.1/triedb/pathdb/generate_test.go (about) 1 // Copyright 2024 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 pathdb 18 19 import ( 20 "fmt" 21 "testing" 22 "time" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/core/rawdb" 26 "github.com/ethereum/go-ethereum/core/types" 27 "github.com/ethereum/go-ethereum/crypto" 28 "github.com/ethereum/go-ethereum/ethdb" 29 "github.com/ethereum/go-ethereum/internal/testrand" 30 "github.com/ethereum/go-ethereum/rlp" 31 "github.com/ethereum/go-ethereum/trie" 32 "github.com/ethereum/go-ethereum/trie/trienode" 33 "github.com/holiman/uint256" 34 ) 35 36 func hashData(input []byte) common.Hash { 37 return crypto.Keccak256Hash(input) 38 } 39 40 type genTester struct { 41 diskdb ethdb.Database 42 db *Database 43 acctTrie *trie.Trie 44 nodes *trienode.MergedNodeSet 45 states *StateSetWithOrigin 46 } 47 48 func newGenTester() *genTester { 49 disk := rawdb.NewMemoryDatabase() 50 config := *Defaults 51 config.SnapshotNoBuild = true // no background generation 52 config.NoAsyncFlush = true // no async flush 53 db := New(disk, &config, false) 54 tr, _ := trie.New(trie.StateTrieID(types.EmptyRootHash), db) 55 return &genTester{ 56 diskdb: disk, 57 db: db, 58 acctTrie: tr, 59 nodes: trienode.NewMergedNodeSet(), 60 states: NewStateSetWithOrigin(nil, nil, nil, nil, false), 61 } 62 } 63 64 func (t *genTester) addTrieAccount(acckey string, acc *types.StateAccount) { 65 var ( 66 addr = common.BytesToAddress([]byte(acckey)) 67 key = hashData([]byte(acckey)) 68 val, _ = rlp.EncodeToBytes(acc) 69 ) 70 t.acctTrie.MustUpdate(key.Bytes(), val) 71 72 t.states.accountData[key] = val 73 t.states.accountOrigin[addr] = nil 74 } 75 76 func (t *genTester) addSnapAccount(acckey string, acc *types.StateAccount) { 77 key := hashData([]byte(acckey)) 78 rawdb.WriteAccountSnapshot(t.diskdb, key, types.SlimAccountRLP(*acc)) 79 } 80 81 func (t *genTester) addAccount(acckey string, acc *types.StateAccount) { 82 t.addTrieAccount(acckey, acc) 83 t.addSnapAccount(acckey, acc) 84 } 85 86 func (t *genTester) addSnapStorage(accKey string, keys []string, vals []string) { 87 accHash := hashData([]byte(accKey)) 88 for i, key := range keys { 89 rawdb.WriteStorageSnapshot(t.diskdb, accHash, hashData([]byte(key)), []byte(vals[i])) 90 } 91 } 92 93 func (t *genTester) makeStorageTrie(accKey string, keys []string, vals []string, commit bool) common.Hash { 94 var ( 95 owner = hashData([]byte(accKey)) 96 addr = common.BytesToAddress([]byte(accKey)) 97 id = trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash) 98 tr, _ = trie.New(id, t.db) 99 100 storages = make(map[common.Hash][]byte) 101 storageOrigins = make(map[common.Hash][]byte) 102 ) 103 for i, k := range keys { 104 key := hashData([]byte(k)) 105 tr.MustUpdate(key.Bytes(), []byte(vals[i])) 106 storages[key] = []byte(vals[i]) 107 storageOrigins[key] = nil 108 } 109 if !commit { 110 return tr.Hash() 111 } 112 root, nodes := tr.Commit(false) 113 if nodes != nil { 114 t.nodes.Merge(nodes) 115 } 116 t.states.storageData[owner] = storages 117 t.states.storageOrigin[addr] = storageOrigins 118 return root 119 } 120 121 func (t *genTester) Commit() common.Hash { 122 root, nodes := t.acctTrie.Commit(true) 123 if nodes != nil { 124 t.nodes.Merge(nodes) 125 } 126 t.db.Update(root, types.EmptyRootHash, 0, t.nodes, t.states) 127 t.db.Commit(root, false) 128 return root 129 } 130 131 func (t *genTester) CommitAndGenerate() (common.Hash, *diskLayer) { 132 root := t.Commit() 133 dl := generateSnapshot(t.db, root, false) 134 return root, dl 135 } 136 137 // Tests that snapshot generation from an empty database. 138 func TestGeneration(t *testing.T) { 139 helper := newGenTester() 140 stRoot := helper.makeStorageTrie("", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false) 141 142 helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 143 helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) 144 helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 145 146 helper.makeStorageTrie("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 147 helper.makeStorageTrie("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 148 149 root, dl := helper.CommitAndGenerate() 150 if have, want := root, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"); have != want { 151 t.Fatalf("have %#x want %#x", have, want) 152 } 153 select { 154 case <-dl.generator.done: 155 // Snapshot generation succeeded 156 case <-time.After(3 * time.Second): 157 t.Errorf("Snapshot generation failed") 158 } 159 // TODO(rjl493456442) enable the snapshot tests 160 // checkSnapRoot(t, snap, root) 161 162 // Signal abortion to the generator and wait for it to tear down 163 dl.generator.stop() 164 } 165 166 // Tests that snapshot generation with existent flat state, where the flat state 167 // contains some errors: 168 // - the contract with empty storage root but has storage entries in the disk 169 // - the contract with non empty storage root but empty storage slots 170 // - the contract(non-empty storage) misses some storage slots 171 // - miss in the beginning 172 // - miss in the middle 173 // - miss in the end 174 // 175 // - the contract(non-empty storage) has wrong storage slots 176 // - wrong slots in the beginning 177 // - wrong slots in the middle 178 // - wrong slots in the end 179 // 180 // - the contract(non-empty storage) has extra storage slots 181 // - extra slots in the beginning 182 // - extra slots in the middle 183 // - extra slots in the end 184 func TestGenerateExistentStateWithWrongStorage(t *testing.T) { 185 helper := newGenTester() 186 187 // Account one, empty storage trie root but non-empty flat states 188 helper.addAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) 189 helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 190 191 // Account two, non-empty storage trie root but empty flat states 192 stRoot := helper.makeStorageTrie("acc-2", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 193 helper.addAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 194 195 // Miss slots 196 { 197 // Account three, non-empty root but misses slots in the beginning 198 helper.makeStorageTrie("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 199 helper.addAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 200 helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"}) 201 202 // Account four, non-empty root but misses slots in the middle 203 helper.makeStorageTrie("acc-4", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 204 helper.addAccount("acc-4", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 205 helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"}) 206 207 // Account five, non-empty root but misses slots in the end 208 helper.makeStorageTrie("acc-5", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 209 helper.addAccount("acc-5", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 210 helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"}) 211 } 212 213 // Wrong storage slots 214 { 215 // Account six, non-empty root but wrong slots in the beginning 216 helper.makeStorageTrie("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 217 helper.addAccount("acc-6", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 218 helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"}) 219 220 // Account seven, non-empty root but wrong slots in the middle 221 helper.makeStorageTrie("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 222 helper.addAccount("acc-7", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 223 helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"}) 224 225 // Account eight, non-empty root but wrong slots in the end 226 helper.makeStorageTrie("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 227 helper.addAccount("acc-8", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 228 helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"}) 229 230 // Account 9, non-empty root but rotated slots 231 helper.makeStorageTrie("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 232 helper.addAccount("acc-9", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 233 helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"}) 234 } 235 236 // Extra storage slots 237 { 238 // Account 10, non-empty root but extra slots in the beginning 239 helper.makeStorageTrie("acc-10", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 240 helper.addAccount("acc-10", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 241 helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"}) 242 243 // Account 11, non-empty root but extra slots in the middle 244 helper.makeStorageTrie("acc-11", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 245 helper.addAccount("acc-11", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 246 helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"}) 247 248 // Account 12, non-empty root but extra slots in the end 249 helper.makeStorageTrie("acc-12", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 250 helper.addAccount("acc-12", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 251 helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"}) 252 } 253 254 root, dl := helper.CommitAndGenerate() 255 t.Logf("Root: %#x\n", root) // Root = 0x8746cce9fd9c658b2cfd639878ed6584b7a2b3e73bb40f607fcfa156002429a0 256 257 select { 258 case <-dl.generator.done: 259 // Snapshot generation succeeded 260 261 case <-time.After(3 * time.Second): 262 t.Errorf("Snapshot generation failed") 263 } 264 // TODO(rjl493456442) enable the snapshot tests 265 // checkSnapRoot(t, snap, root) 266 267 // Signal abortion to the generator and wait for it to tear down 268 dl.generator.stop() 269 } 270 271 // Tests that snapshot generation with existent flat state, where the flat state 272 // contains some errors: 273 // - miss accounts 274 // - wrong accounts 275 // - extra accounts 276 func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { 277 helper := newGenTester() 278 279 // Trie accounts [acc-1, acc-2, acc-3, acc-4, acc-6] 280 helper.makeStorageTrie("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 281 helper.makeStorageTrie("acc-2", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 282 helper.makeStorageTrie("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 283 helper.makeStorageTrie("acc-4", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 284 stRoot := helper.makeStorageTrie("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 285 286 // Missing accounts, only in the trie 287 { 288 helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Beginning 289 helper.addTrieAccount("acc-4", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Middle 290 helper.addTrieAccount("acc-6", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // End 291 } 292 293 // Wrong accounts 294 { 295 helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 296 helper.addSnapAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: common.Hex2Bytes("0x1234")}) 297 298 helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 299 helper.addSnapAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) 300 } 301 302 // Extra accounts, only in the snap 303 { 304 helper.addSnapAccount("acc-0", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // before the beginning 305 helper.addSnapAccount("acc-5", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: common.Hex2Bytes("0x1234")}) // Middle 306 helper.addSnapAccount("acc-7", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // after the end 307 } 308 309 root, dl := helper.CommitAndGenerate() 310 t.Logf("Root: %#x\n", root) // Root = 0x825891472281463511e7ebcc7f109e4f9200c20fa384754e11fd605cd98464e8 311 312 select { 313 case <-dl.generator.done: 314 // Snapshot generation succeeded 315 316 case <-time.After(3 * time.Second): 317 t.Errorf("Snapshot generation failed") 318 } 319 // TODO(rjl493456442) enable the snapshot tests 320 // checkSnapRoot(t, snap, root) 321 322 // Signal abortion to the generator and wait for it to tear down 323 dl.generator.stop() 324 } 325 326 func TestGenerateCorruptAccountTrie(t *testing.T) { 327 helper := newGenTester() 328 helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 329 helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 330 helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 331 332 root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 333 334 // Delete an account trie node and ensure the generator chokes 335 path := []byte{0xc} 336 if !rawdb.HasAccountTrieNode(helper.diskdb, path) { 337 t.Logf("Invalid node path to delete, %v", path) 338 } 339 rawdb.DeleteAccountTrieNode(helper.diskdb, path) 340 helper.db.tree.bottom().resetCache() 341 342 dl := generateSnapshot(helper.db, root, false) 343 select { 344 case <-dl.generator.done: 345 // Snapshot generation succeeded 346 t.Errorf("Snapshot generated against corrupt account trie") 347 348 case <-time.After(time.Second): 349 // Not generated fast enough, hopefully blocked inside on missing trie node fail 350 } 351 // Signal abortion to the generator and wait for it to tear down 352 dl.generator.stop() 353 } 354 355 func TestGenerateMissingStorageTrie(t *testing.T) { 356 var ( 357 acc1 = hashData([]byte("acc-1")) 358 acc3 = hashData([]byte("acc-3")) 359 helper = newGenTester() 360 ) 361 stRoot := helper.makeStorageTrie("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 362 helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e 363 helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 364 stRoot = helper.makeStorageTrie("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 365 helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 366 367 root := helper.Commit() 368 369 // Delete storage trie root of account one and three. 370 rawdb.DeleteStorageTrieNode(helper.diskdb, acc1, nil) 371 rawdb.DeleteStorageTrieNode(helper.diskdb, acc3, nil) 372 helper.db.tree.bottom().resetCache() 373 374 dl := generateSnapshot(helper.db, root, false) 375 select { 376 case <-dl.generator.done: 377 // Snapshot generation succeeded 378 t.Errorf("Snapshot generated against corrupt storage trie") 379 380 case <-time.After(time.Second): 381 // Not generated fast enough, hopefully blocked inside on missing trie node fail 382 } 383 // Signal abortion to the generator and wait for it to tear down 384 dl.generator.stop() 385 } 386 387 func TestGenerateCorruptStorageTrie(t *testing.T) { 388 helper := newGenTester() 389 390 stRoot := helper.makeStorageTrie("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 391 helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e 392 helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 393 stRoot = helper.makeStorageTrie("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 394 helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 395 396 root := helper.Commit() 397 398 // Delete a node in the storage trie. 399 path := []byte{0x4} 400 if !rawdb.HasStorageTrieNode(helper.diskdb, hashData([]byte("acc-1")), path) { 401 t.Logf("Invalid node path to delete, %v", path) 402 } 403 rawdb.DeleteStorageTrieNode(helper.diskdb, hashData([]byte("acc-1")), []byte{0x4}) 404 405 if !rawdb.HasStorageTrieNode(helper.diskdb, hashData([]byte("acc-3")), path) { 406 t.Logf("Invalid node path to delete, %v", path) 407 } 408 rawdb.DeleteStorageTrieNode(helper.diskdb, hashData([]byte("acc-3")), []byte{0x4}) 409 410 helper.db.tree.bottom().resetCache() 411 412 dl := generateSnapshot(helper.db, root, false) 413 select { 414 case <-dl.generator.done: 415 // Snapshot generation succeeded 416 t.Errorf("Snapshot generated against corrupt storage trie") 417 418 case <-time.After(time.Second): 419 // Not generated fast enough, hopefully blocked inside on missing trie node fail 420 } 421 // Signal abortion to the generator and wait for it to tear down 422 dl.generator.stop() 423 } 424 425 func TestGenerateWithExtraAccounts(t *testing.T) { 426 helper := newGenTester() 427 428 // Account one in the trie 429 stRoot := helper.makeStorageTrie("acc-1", 430 []string{"key-1", "key-2", "key-3", "key-4", "key-5"}, 431 []string{"val-1", "val-2", "val-3", "val-4", "val-5"}, 432 true, 433 ) 434 acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} 435 val, _ := rlp.EncodeToBytes(acc) 436 helper.acctTrie.MustUpdate(hashData([]byte("acc-1")).Bytes(), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e 437 438 // Identical in the snap 439 key := hashData([]byte("acc-1")) 440 rawdb.WriteAccountSnapshot(helper.diskdb, key, val) 441 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-1")), []byte("val-1")) 442 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-2")), []byte("val-2")) 443 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-3")), []byte("val-3")) 444 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-4")), []byte("val-4")) 445 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-5")), []byte("val-5")) 446 447 // Account two exists only in the snapshot 448 stRoot = helper.makeStorageTrie("acc-2", 449 []string{"key-1", "key-2", "key-3", "key-4", "key-5"}, 450 []string{"val-1", "val-2", "val-3", "val-4", "val-5"}, 451 true, 452 ) 453 acc = &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} 454 val, _ = rlp.EncodeToBytes(acc) 455 key = hashData([]byte("acc-2")) 456 rawdb.WriteAccountSnapshot(helper.diskdb, key, val) 457 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-1")), []byte("b-val-1")) 458 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-2")), []byte("b-val-2")) 459 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-3")), []byte("b-val-3")) 460 461 root := helper.Commit() 462 463 // To verify the test: If we now inspect the snap db, there should exist extraneous storage items 464 if data := rawdb.ReadStorageSnapshot(helper.diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data == nil { 465 t.Fatalf("expected snap storage to exist") 466 } 467 dl := generateSnapshot(helper.db, root, false) 468 select { 469 case <-dl.generator.done: 470 // Snapshot generation succeeded 471 472 case <-time.After(3 * time.Second): 473 t.Errorf("Snapshot generation failed") 474 } 475 // TODO(rjl493456442) enable the snapshot tests 476 // checkSnapRoot(t, snap, root) 477 478 // Signal abortion to the generator and wait for it to tear down 479 dl.generator.stop() 480 481 // If we now inspect the snap db, there should exist no extraneous storage items 482 if data := rawdb.ReadStorageSnapshot(helper.diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil { 483 t.Fatalf("expected slot to be removed, got %v", string(data)) 484 } 485 } 486 487 func TestGenerateWithManyExtraAccounts(t *testing.T) { 488 helper := newGenTester() 489 490 // Account one in the trie 491 stRoot := helper.makeStorageTrie("acc-1", 492 []string{"key-1", "key-2", "key-3"}, 493 []string{"val-1", "val-2", "val-3"}, 494 true, 495 ) 496 acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} 497 val, _ := rlp.EncodeToBytes(acc) 498 helper.acctTrie.MustUpdate(hashData([]byte("acc-1")).Bytes(), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e 499 500 // Identical in the snap 501 key := hashData([]byte("acc-1")) 502 rawdb.WriteAccountSnapshot(helper.diskdb, key, val) 503 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-1")), []byte("val-1")) 504 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-2")), []byte("val-2")) 505 rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-3")), []byte("val-3")) 506 507 // 100 accounts exist only in snapshot 508 for i := 0; i < 1000; i++ { 509 acc := &types.StateAccount{Balance: uint256.NewInt(uint64(i)), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()} 510 val, _ := rlp.EncodeToBytes(acc) 511 key := hashData([]byte(fmt.Sprintf("acc-%d", i))) 512 rawdb.WriteAccountSnapshot(helper.diskdb, key, val) 513 } 514 515 _, dl := helper.CommitAndGenerate() 516 select { 517 case <-dl.generator.done: 518 // Snapshot generation succeeded 519 520 case <-time.After(3 * time.Second): 521 t.Errorf("Snapshot generation failed") 522 } 523 // TODO(rjl493456442) enable the snapshot tests 524 // checkSnapRoot(t, snap, root) 525 526 // Signal abortion to the generator and wait for it to tear down 527 dl.generator.stop() 528 } 529 530 func TestGenerateWithExtraBeforeAndAfter(t *testing.T) { 531 helper := newGenTester() 532 533 acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()} 534 val, _ := rlp.EncodeToBytes(acc) 535 536 acctHashA := hashData([]byte("acc-1")) 537 acctHashB := hashData([]byte("acc-2")) 538 539 helper.acctTrie.MustUpdate(acctHashA.Bytes(), val) 540 helper.acctTrie.MustUpdate(acctHashB.Bytes(), val) 541 542 rawdb.WriteAccountSnapshot(helper.diskdb, acctHashA, val) 543 rawdb.WriteAccountSnapshot(helper.diskdb, acctHashB, val) 544 545 for i := 0; i < 16; i++ { 546 rawdb.WriteAccountSnapshot(helper.diskdb, common.Hash{byte(i)}, val) 547 } 548 _, dl := helper.CommitAndGenerate() 549 select { 550 case <-dl.generator.done: 551 // Snapshot generation succeeded 552 553 case <-time.After(3 * time.Second): 554 t.Errorf("Snapshot generation failed") 555 } 556 // TODO(rjl493456442) enable the snapshot tests 557 // checkSnapRoot(t, snap, root) 558 559 // Signal abortion to the generator and wait for it to tear down 560 dl.generator.stop() 561 } 562 563 func TestGenerateWithMalformedStateData(t *testing.T) { 564 helper := newGenTester() 565 566 acctHash := hashData([]byte("acc")) 567 acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()} 568 val, _ := rlp.EncodeToBytes(acc) 569 helper.acctTrie.MustUpdate(acctHash.Bytes(), val) 570 571 junk := make([]byte, 100) 572 copy(junk, []byte{0xde, 0xad}) 573 rawdb.WriteAccountSnapshot(helper.diskdb, acctHash, junk) 574 for i := 0; i < 16; i++ { 575 rawdb.WriteAccountSnapshot(helper.diskdb, common.Hash{byte(i)}, junk) 576 } 577 578 _, dl := helper.CommitAndGenerate() 579 select { 580 case <-dl.generator.done: 581 // Snapshot generation succeeded 582 583 case <-time.After(3 * time.Second): 584 t.Errorf("Snapshot generation failed") 585 } 586 // TODO(rjl493456442) enable the snapshot tests 587 // checkSnapRoot(t, snap, root) 588 589 // Signal abortion to the generator and wait for it to tear down 590 dl.generator.stop() 591 } 592 593 func TestGenerateFromEmptySnap(t *testing.T) { 594 helper := newGenTester() 595 596 for i := 0; i < 400; i++ { 597 stRoot := helper.makeStorageTrie(fmt.Sprintf("acc-%d", i), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 598 helper.addTrieAccount(fmt.Sprintf("acc-%d", i), &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 599 } 600 root, snap := helper.CommitAndGenerate() 601 t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4 602 603 select { 604 case <-snap.generator.done: 605 // Snapshot generation succeeded 606 607 case <-time.After(3 * time.Second): 608 t.Errorf("Snapshot generation failed") 609 } 610 // TODO(rjl493456442) enable the snapshot tests 611 // checkSnapRoot(t, snap, root) 612 613 // Signal abortion to the generator and wait for it to tear down 614 snap.generator.stop() 615 } 616 617 func TestGenerateWithIncompleteStorage(t *testing.T) { 618 helper := newGenTester() 619 stKeys := []string{"1", "2", "3", "4", "5", "6", "7", "8"} 620 stVals := []string{"v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"} 621 622 // We add 8 accounts, each one is missing exactly one of the storage slots. This means 623 // we don't have to order the keys and figure out exactly which hash-key winds up 624 // on the sensitive spots at the boundaries 625 for i := 0; i < 8; i++ { 626 accKey := fmt.Sprintf("acc-%d", i) 627 stRoot := helper.makeStorageTrie(accKey, stKeys, stVals, true) 628 helper.addAccount(accKey, &types.StateAccount{Balance: uint256.NewInt(uint64(i)), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 629 var moddedKeys []string 630 var moddedVals []string 631 for ii := 0; ii < 8; ii++ { 632 if ii != i { 633 moddedKeys = append(moddedKeys, stKeys[ii]) 634 moddedVals = append(moddedVals, stVals[ii]) 635 } 636 } 637 helper.addSnapStorage(accKey, moddedKeys, moddedVals) 638 } 639 root, dl := helper.CommitAndGenerate() 640 t.Logf("Root: %#x\n", root) // Root: 0xca73f6f05ba4ca3024ef340ef3dfca8fdabc1b677ff13f5a9571fd49c16e67ff 641 642 select { 643 case <-dl.generator.done: 644 // Snapshot generation succeeded 645 646 case <-time.After(3 * time.Second): 647 t.Errorf("Snapshot generation failed") 648 } 649 // TODO(rjl493456442) enable the snapshot tests 650 // checkSnapRoot(t, snap, root) 651 652 // Signal abortion to the generator and wait for it to tear down 653 dl.generator.stop() 654 } 655 656 func incKey(key []byte) []byte { 657 for i := len(key) - 1; i >= 0; i-- { 658 key[i]++ 659 if key[i] != 0x0 { 660 break 661 } 662 } 663 return key 664 } 665 666 func decKey(key []byte) []byte { 667 for i := len(key) - 1; i >= 0; i-- { 668 key[i]-- 669 if key[i] != 0xff { 670 break 671 } 672 } 673 return key 674 } 675 676 func populateDangling(disk ethdb.KeyValueStore) { 677 populate := func(accountHash common.Hash, keys []string, vals []string) { 678 for i, key := range keys { 679 rawdb.WriteStorageSnapshot(disk, accountHash, hashData([]byte(key)), []byte(vals[i])) 680 } 681 } 682 // Dangling storages of the "first" account 683 populate(common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 684 685 // Dangling storages of the "last" account 686 populate(common.HexToHash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 687 688 // Dangling storages around the account 1 689 hash := decKey(hashData([]byte("acc-1")).Bytes()) 690 populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 691 hash = incKey(hashData([]byte("acc-1")).Bytes()) 692 populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 693 694 // Dangling storages around the account 2 695 hash = decKey(hashData([]byte("acc-2")).Bytes()) 696 populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 697 hash = incKey(hashData([]byte("acc-2")).Bytes()) 698 populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 699 700 // Dangling storages around the account 3 701 hash = decKey(hashData([]byte("acc-3")).Bytes()) 702 populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 703 hash = incKey(hashData([]byte("acc-3")).Bytes()) 704 populate(common.BytesToHash(hash), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 705 706 // Dangling storages of the random account 707 populate(testrand.Hash(), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 708 populate(testrand.Hash(), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 709 populate(testrand.Hash(), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 710 } 711 712 func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { 713 var helper = newGenTester() 714 715 stRoot := helper.makeStorageTrie("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 716 helper.addAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 717 helper.addAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) 718 719 helper.makeStorageTrie("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 720 helper.addAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 721 722 helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 723 helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) 724 725 populateDangling(helper.diskdb) 726 727 _, dl := helper.CommitAndGenerate() 728 select { 729 case <-dl.generator.done: 730 // Snapshot generation succeeded 731 732 case <-time.After(3 * time.Second): 733 t.Errorf("Snapshot generation failed") 734 } 735 // TODO(rjl493456442) enable the snapshot tests 736 // checkSnapRoot(t, snap, root) 737 738 // Signal abortion to the generator and wait for it to tear down 739 dl.generator.stop() 740 } 741 742 func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) { 743 var helper = newGenTester() 744 745 stRoot := helper.makeStorageTrie("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 746 helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 747 helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) 748 749 helper.makeStorageTrie("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) 750 helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) 751 752 populateDangling(helper.diskdb) 753 754 _, dl := helper.CommitAndGenerate() 755 select { 756 case <-dl.generator.done: 757 // Snapshot generation succeeded 758 759 case <-time.After(3 * time.Second): 760 t.Errorf("Snapshot generation failed") 761 } 762 // TODO(rjl493456442) enable the snapshot tests 763 // checkSnapRoot(t, snap, root) 764 765 // Signal abortion to the generator and wait for it to tear down 766 dl.generator.stop() 767 }