github.com/theQRL/go-zond@v0.1.1/trie/triedb/pathdb/database_test.go (about) 1 // Copyright 2022 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 "bytes" 21 "errors" 22 "fmt" 23 "math/big" 24 "math/rand" 25 "testing" 26 27 "github.com/theQRL/go-zond/common" 28 "github.com/theQRL/go-zond/core/rawdb" 29 "github.com/theQRL/go-zond/core/types" 30 "github.com/theQRL/go-zond/crypto" 31 "github.com/theQRL/go-zond/rlp" 32 "github.com/theQRL/go-zond/trie/testutil" 33 "github.com/theQRL/go-zond/trie/trienode" 34 "github.com/theQRL/go-zond/trie/triestate" 35 ) 36 37 func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[common.Hash][]byte) (common.Hash, *trienode.NodeSet) { 38 h, err := newTestHasher(addrHash, root, cleans) 39 if err != nil { 40 panic(fmt.Errorf("failed to create hasher, err: %w", err)) 41 } 42 for key, val := range dirties { 43 if len(val) == 0 { 44 h.Delete(key.Bytes()) 45 } else { 46 h.Update(key.Bytes(), val) 47 } 48 } 49 root, nodes, _ := h.Commit(false) 50 return root, nodes 51 } 52 53 func generateAccount(storageRoot common.Hash) types.StateAccount { 54 return types.StateAccount{ 55 Nonce: uint64(rand.Intn(100)), 56 Balance: big.NewInt(rand.Int63()), 57 CodeHash: testutil.RandBytes(32), 58 Root: storageRoot, 59 } 60 } 61 62 const ( 63 createAccountOp int = iota 64 modifyAccountOp 65 deleteAccountOp 66 opLen 67 ) 68 69 type genctx struct { 70 accounts map[common.Hash][]byte 71 storages map[common.Hash]map[common.Hash][]byte 72 accountOrigin map[common.Address][]byte 73 storageOrigin map[common.Address]map[common.Hash][]byte 74 nodes *trienode.MergedNodeSet 75 } 76 77 func newCtx() *genctx { 78 return &genctx{ 79 accounts: make(map[common.Hash][]byte), 80 storages: make(map[common.Hash]map[common.Hash][]byte), 81 accountOrigin: make(map[common.Address][]byte), 82 storageOrigin: make(map[common.Address]map[common.Hash][]byte), 83 nodes: trienode.NewMergedNodeSet(), 84 } 85 } 86 87 type tester struct { 88 db *Database 89 roots []common.Hash 90 preimages map[common.Hash]common.Address 91 accounts map[common.Hash][]byte 92 storages map[common.Hash]map[common.Hash][]byte 93 94 // state snapshots 95 snapAccounts map[common.Hash]map[common.Hash][]byte 96 snapStorages map[common.Hash]map[common.Hash]map[common.Hash][]byte 97 } 98 99 func newTester(t *testing.T) *tester { 100 var ( 101 disk, _ = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) 102 db = New(disk, &Config{CleanCacheSize: 256 * 1024, DirtyCacheSize: 256 * 1024}) 103 obj = &tester{ 104 db: db, 105 preimages: make(map[common.Hash]common.Address), 106 accounts: make(map[common.Hash][]byte), 107 storages: make(map[common.Hash]map[common.Hash][]byte), 108 snapAccounts: make(map[common.Hash]map[common.Hash][]byte), 109 snapStorages: make(map[common.Hash]map[common.Hash]map[common.Hash][]byte), 110 } 111 ) 112 for i := 0; i < 2*128; i++ { 113 var parent = types.EmptyRootHash 114 if len(obj.roots) != 0 { 115 parent = obj.roots[len(obj.roots)-1] 116 } 117 root, nodes, states := obj.generate(parent) 118 if err := db.Update(root, parent, uint64(i), nodes, states); err != nil { 119 panic(fmt.Errorf("failed to update state changes, err: %w", err)) 120 } 121 obj.roots = append(obj.roots, root) 122 } 123 return obj 124 } 125 126 func (t *tester) release() { 127 t.db.Close() 128 t.db.diskdb.Close() 129 } 130 131 func (t *tester) randAccount() (common.Address, []byte) { 132 for addrHash, account := range t.accounts { 133 return t.preimages[addrHash], account 134 } 135 return common.Address{}, nil 136 } 137 138 func (t *tester) generateStorage(ctx *genctx, addr common.Address) common.Hash { 139 var ( 140 addrHash = crypto.Keccak256Hash(addr.Bytes()) 141 storage = make(map[common.Hash][]byte) 142 origin = make(map[common.Hash][]byte) 143 ) 144 for i := 0; i < 10; i++ { 145 v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testutil.RandBytes(32))) 146 hash := testutil.RandomHash() 147 148 storage[hash] = v 149 origin[hash] = nil 150 } 151 root, set := updateTrie(addrHash, types.EmptyRootHash, storage, nil) 152 153 ctx.storages[addrHash] = storage 154 ctx.storageOrigin[addr] = origin 155 ctx.nodes.Merge(set) 156 return root 157 } 158 159 func (t *tester) mutateStorage(ctx *genctx, addr common.Address, root common.Hash) common.Hash { 160 var ( 161 addrHash = crypto.Keccak256Hash(addr.Bytes()) 162 storage = make(map[common.Hash][]byte) 163 origin = make(map[common.Hash][]byte) 164 ) 165 for hash, val := range t.storages[addrHash] { 166 origin[hash] = val 167 storage[hash] = nil 168 169 if len(origin) == 3 { 170 break 171 } 172 } 173 for i := 0; i < 3; i++ { 174 v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testutil.RandBytes(32))) 175 hash := testutil.RandomHash() 176 177 storage[hash] = v 178 origin[hash] = nil 179 } 180 root, set := updateTrie(crypto.Keccak256Hash(addr.Bytes()), root, storage, t.storages[addrHash]) 181 182 ctx.storages[addrHash] = storage 183 ctx.storageOrigin[addr] = origin 184 ctx.nodes.Merge(set) 185 return root 186 } 187 188 func (t *tester) clearStorage(ctx *genctx, addr common.Address, root common.Hash) common.Hash { 189 var ( 190 addrHash = crypto.Keccak256Hash(addr.Bytes()) 191 storage = make(map[common.Hash][]byte) 192 origin = make(map[common.Hash][]byte) 193 ) 194 for hash, val := range t.storages[addrHash] { 195 origin[hash] = val 196 storage[hash] = nil 197 } 198 root, set := updateTrie(addrHash, root, storage, t.storages[addrHash]) 199 if root != types.EmptyRootHash { 200 panic("failed to clear storage trie") 201 } 202 ctx.storages[addrHash] = storage 203 ctx.storageOrigin[addr] = origin 204 ctx.nodes.Merge(set) 205 return root 206 } 207 208 func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNodeSet, *triestate.Set) { 209 var ( 210 ctx = newCtx() 211 dirties = make(map[common.Hash]struct{}) 212 ) 213 for i := 0; i < 20; i++ { 214 switch rand.Intn(opLen) { 215 case createAccountOp: 216 // account creation 217 addr := testutil.RandomAddress() 218 addrHash := crypto.Keccak256Hash(addr.Bytes()) 219 if _, ok := t.accounts[addrHash]; ok { 220 continue 221 } 222 if _, ok := dirties[addrHash]; ok { 223 continue 224 } 225 dirties[addrHash] = struct{}{} 226 227 root := t.generateStorage(ctx, addr) 228 ctx.accounts[addrHash] = types.SlimAccountRLP(generateAccount(root)) 229 ctx.accountOrigin[addr] = nil 230 t.preimages[addrHash] = addr 231 232 case modifyAccountOp: 233 // account mutation 234 addr, account := t.randAccount() 235 if addr == (common.Address{}) { 236 continue 237 } 238 addrHash := crypto.Keccak256Hash(addr.Bytes()) 239 if _, ok := dirties[addrHash]; ok { 240 continue 241 } 242 dirties[addrHash] = struct{}{} 243 244 acct, _ := types.FullAccount(account) 245 stRoot := t.mutateStorage(ctx, addr, acct.Root) 246 newAccount := types.SlimAccountRLP(generateAccount(stRoot)) 247 248 ctx.accounts[addrHash] = newAccount 249 ctx.accountOrigin[addr] = account 250 251 case deleteAccountOp: 252 // account deletion 253 addr, account := t.randAccount() 254 if addr == (common.Address{}) { 255 continue 256 } 257 addrHash := crypto.Keccak256Hash(addr.Bytes()) 258 if _, ok := dirties[addrHash]; ok { 259 continue 260 } 261 dirties[addrHash] = struct{}{} 262 263 acct, _ := types.FullAccount(account) 264 if acct.Root != types.EmptyRootHash { 265 t.clearStorage(ctx, addr, acct.Root) 266 } 267 ctx.accounts[addrHash] = nil 268 ctx.accountOrigin[addr] = account 269 } 270 } 271 root, set := updateTrie(common.Hash{}, parent, ctx.accounts, t.accounts) 272 ctx.nodes.Merge(set) 273 274 // Save state snapshot before commit 275 t.snapAccounts[parent] = copyAccounts(t.accounts) 276 t.snapStorages[parent] = copyStorages(t.storages) 277 278 // Commit all changes to live state set 279 for addrHash, account := range ctx.accounts { 280 if len(account) == 0 { 281 delete(t.accounts, addrHash) 282 } else { 283 t.accounts[addrHash] = account 284 } 285 } 286 for addrHash, slots := range ctx.storages { 287 if _, ok := t.storages[addrHash]; !ok { 288 t.storages[addrHash] = make(map[common.Hash][]byte) 289 } 290 for sHash, slot := range slots { 291 if len(slot) == 0 { 292 delete(t.storages[addrHash], sHash) 293 } else { 294 t.storages[addrHash][sHash] = slot 295 } 296 } 297 } 298 return root, ctx.nodes, triestate.New(ctx.accountOrigin, ctx.storageOrigin, nil) 299 } 300 301 // lastRoot returns the latest root hash, or empty if nothing is cached. 302 func (t *tester) lastHash() common.Hash { 303 if len(t.roots) == 0 { 304 return common.Hash{} 305 } 306 return t.roots[len(t.roots)-1] 307 } 308 309 func (t *tester) verifyState(root common.Hash) error { 310 reader, err := t.db.Reader(root) 311 if err != nil { 312 return err 313 } 314 _, err = reader.Node(common.Hash{}, nil, root) 315 if err != nil { 316 return errors.New("root node is not available") 317 } 318 for addrHash, account := range t.snapAccounts[root] { 319 blob, err := reader.Node(common.Hash{}, addrHash.Bytes(), crypto.Keccak256Hash(account)) 320 if err != nil || !bytes.Equal(blob, account) { 321 return fmt.Errorf("account is mismatched: %w", err) 322 } 323 } 324 for addrHash, slots := range t.snapStorages[root] { 325 for hash, slot := range slots { 326 blob, err := reader.Node(addrHash, hash.Bytes(), crypto.Keccak256Hash(slot)) 327 if err != nil || !bytes.Equal(blob, slot) { 328 return fmt.Errorf("slot is mismatched: %w", err) 329 } 330 } 331 } 332 return nil 333 } 334 335 func (t *tester) verifyHistory() error { 336 bottom := t.bottomIndex() 337 for i, root := range t.roots { 338 // The state history related to the state above disk layer should not exist. 339 if i > bottom { 340 _, err := readHistory(t.db.freezer, uint64(i+1)) 341 if err == nil { 342 return errors.New("unexpected state history") 343 } 344 continue 345 } 346 // The state history related to the state below or equal to the disk layer 347 // should exist. 348 obj, err := readHistory(t.db.freezer, uint64(i+1)) 349 if err != nil { 350 return err 351 } 352 parent := types.EmptyRootHash 353 if i != 0 { 354 parent = t.roots[i-1] 355 } 356 if obj.meta.parent != parent { 357 return fmt.Errorf("unexpected parent, want: %x, got: %x", parent, obj.meta.parent) 358 } 359 if obj.meta.root != root { 360 return fmt.Errorf("unexpected root, want: %x, got: %x", root, obj.meta.root) 361 } 362 } 363 return nil 364 } 365 366 // bottomIndex returns the index of current disk layer. 367 func (t *tester) bottomIndex() int { 368 bottom := t.db.tree.bottom() 369 for i := 0; i < len(t.roots); i++ { 370 if t.roots[i] == bottom.rootHash() { 371 return i 372 } 373 } 374 return -1 375 } 376 377 func TestDatabaseRollback(t *testing.T) { 378 // Verify state histories 379 tester := newTester(t) 380 defer tester.release() 381 382 if err := tester.verifyHistory(); err != nil { 383 t.Fatalf("Invalid state history, err: %v", err) 384 } 385 // Revert database from top to bottom 386 for i := tester.bottomIndex(); i >= 0; i-- { 387 root := tester.roots[i] 388 parent := types.EmptyRootHash 389 if i > 0 { 390 parent = tester.roots[i-1] 391 } 392 loader := newHashLoader(tester.snapAccounts[root], tester.snapStorages[root]) 393 if err := tester.db.Recover(parent, loader); err != nil { 394 t.Fatalf("Failed to revert db, err: %v", err) 395 } 396 tester.verifyState(parent) 397 } 398 if tester.db.tree.len() != 1 { 399 t.Fatal("Only disk layer is expected") 400 } 401 } 402 403 func TestDatabaseRecoverable(t *testing.T) { 404 var ( 405 tester = newTester(t) 406 index = tester.bottomIndex() 407 ) 408 defer tester.release() 409 410 var cases = []struct { 411 root common.Hash 412 expect bool 413 }{ 414 // Unknown state should be unrecoverable 415 {common.Hash{0x1}, false}, 416 417 // Initial state should be recoverable 418 {types.EmptyRootHash, true}, 419 420 // Initial state should be recoverable 421 {common.Hash{}, true}, 422 423 // Layers below current disk layer are recoverable 424 {tester.roots[index-1], true}, 425 426 // Disklayer itself is not recoverable, since it's 427 // available for accessing. 428 {tester.roots[index], false}, 429 430 // Layers above current disk layer are not recoverable 431 // since they are available for accessing. 432 {tester.roots[index+1], false}, 433 } 434 for i, c := range cases { 435 result := tester.db.Recoverable(c.root) 436 if result != c.expect { 437 t.Fatalf("case: %d, unexpected result, want %t, got %t", i, c.expect, result) 438 } 439 } 440 } 441 442 func TestReset(t *testing.T) { 443 var ( 444 tester = newTester(t) 445 index = tester.bottomIndex() 446 ) 447 defer tester.release() 448 449 // Reset database to unknown target, should reject it 450 if err := tester.db.Reset(testutil.RandomHash()); err == nil { 451 t.Fatal("Failed to reject invalid reset") 452 } 453 // Reset database to state persisted in the disk 454 if err := tester.db.Reset(types.EmptyRootHash); err != nil { 455 t.Fatalf("Failed to reset database %v", err) 456 } 457 // Ensure journal is deleted from disk 458 if blob := rawdb.ReadTrieJournal(tester.db.diskdb); len(blob) != 0 { 459 t.Fatal("Failed to clean journal") 460 } 461 // Ensure all trie histories are removed 462 for i := 0; i <= index; i++ { 463 _, err := readHistory(tester.db.freezer, uint64(i+1)) 464 if err == nil { 465 t.Fatalf("Failed to clean state history, index %d", i+1) 466 } 467 } 468 // Verify layer tree structure, single disk layer is expected 469 if tester.db.tree.len() != 1 { 470 t.Fatalf("Extra layer kept %d", tester.db.tree.len()) 471 } 472 if tester.db.tree.bottom().rootHash() != types.EmptyRootHash { 473 t.Fatalf("Root hash is not matched exp %x got %x", types.EmptyRootHash, tester.db.tree.bottom().rootHash()) 474 } 475 } 476 477 func TestCommit(t *testing.T) { 478 tester := newTester(t) 479 defer tester.release() 480 481 if err := tester.db.Commit(tester.lastHash(), false); err != nil { 482 t.Fatalf("Failed to cap database, err: %v", err) 483 } 484 // Verify layer tree structure, single disk layer is expected 485 if tester.db.tree.len() != 1 { 486 t.Fatal("Layer tree structure is invalid") 487 } 488 if tester.db.tree.bottom().rootHash() != tester.lastHash() { 489 t.Fatal("Layer tree structure is invalid") 490 } 491 // Verify states 492 if err := tester.verifyState(tester.lastHash()); err != nil { 493 t.Fatalf("State is invalid, err: %v", err) 494 } 495 // Verify state histories 496 if err := tester.verifyHistory(); err != nil { 497 t.Fatalf("State history is invalid, err: %v", err) 498 } 499 } 500 501 func TestJournal(t *testing.T) { 502 tester := newTester(t) 503 defer tester.release() 504 505 if err := tester.db.Journal(tester.lastHash()); err != nil { 506 t.Errorf("Failed to journal, err: %v", err) 507 } 508 tester.db.Close() 509 tester.db = New(tester.db.diskdb, nil) 510 511 // Verify states including disk layer and all diff on top. 512 for i := 0; i < len(tester.roots); i++ { 513 if i >= tester.bottomIndex() { 514 if err := tester.verifyState(tester.roots[i]); err != nil { 515 t.Fatalf("Invalid state, err: %v", err) 516 } 517 continue 518 } 519 if err := tester.verifyState(tester.roots[i]); err == nil { 520 t.Fatal("Unexpected state") 521 } 522 } 523 } 524 525 func TestCorruptedJournal(t *testing.T) { 526 tester := newTester(t) 527 defer tester.release() 528 529 if err := tester.db.Journal(tester.lastHash()); err != nil { 530 t.Errorf("Failed to journal, err: %v", err) 531 } 532 tester.db.Close() 533 _, root := rawdb.ReadAccountTrieNode(tester.db.diskdb, nil) 534 535 // Mutate the journal in disk, it should be regarded as invalid 536 blob := rawdb.ReadTrieJournal(tester.db.diskdb) 537 blob[0] = 1 538 rawdb.WriteTrieJournal(tester.db.diskdb, blob) 539 540 // Verify states, all not-yet-written states should be discarded 541 tester.db = New(tester.db.diskdb, nil) 542 for i := 0; i < len(tester.roots); i++ { 543 if tester.roots[i] == root { 544 if err := tester.verifyState(root); err != nil { 545 t.Fatalf("Disk state is corrupted, err: %v", err) 546 } 547 continue 548 } 549 if err := tester.verifyState(tester.roots[i]); err == nil { 550 t.Fatal("Unexpected state") 551 } 552 } 553 } 554 555 // copyAccounts returns a deep-copied account set of the provided one. 556 func copyAccounts(set map[common.Hash][]byte) map[common.Hash][]byte { 557 copied := make(map[common.Hash][]byte, len(set)) 558 for key, val := range set { 559 copied[key] = common.CopyBytes(val) 560 } 561 return copied 562 } 563 564 // copyStorages returns a deep-copied storage set of the provided one. 565 func copyStorages(set map[common.Hash]map[common.Hash][]byte) map[common.Hash]map[common.Hash][]byte { 566 copied := make(map[common.Hash]map[common.Hash][]byte, len(set)) 567 for addrHash, subset := range set { 568 copied[addrHash] = make(map[common.Hash][]byte, len(subset)) 569 for key, val := range subset { 570 copied[addrHash][key] = common.CopyBytes(val) 571 } 572 } 573 return copied 574 }