github.com/ethereum/go-ethereum@v1.16.1/triedb/pathdb/history_reader_test.go (about) 1 // Copyright 2025 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 "fmt" 22 "testing" 23 "time" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/core/rawdb" 27 ) 28 29 func waitIndexing(db *Database) { 30 for { 31 metadata := loadIndexMetadata(db.diskdb) 32 if metadata != nil && metadata.Last >= db.tree.bottom().stateID() { 33 return 34 } 35 time.Sleep(100 * time.Millisecond) 36 } 37 } 38 39 func checkHistoricState(env *tester, root common.Hash, hr *historyReader) error { 40 // Short circuit if the historical state is no longer available 41 if rawdb.ReadStateID(env.db.diskdb, root) == nil { 42 return nil 43 } 44 var ( 45 dl = env.db.tree.bottom() 46 stateID = rawdb.ReadStateID(env.db.diskdb, root) 47 accounts = env.snapAccounts[root] 48 storages = env.snapStorages[root] 49 ) 50 for addrHash, accountData := range accounts { 51 latest, _ := dl.account(addrHash, 0) 52 blob, err := hr.read(newAccountIdentQuery(env.accountPreimage(addrHash), addrHash), *stateID, dl.stateID(), latest) 53 if err != nil { 54 return err 55 } 56 if !bytes.Equal(accountData, blob) { 57 return fmt.Errorf("wrong account data, expected %x, got %x", accountData, blob) 58 } 59 } 60 for i := 0; i < len(env.roots); i++ { 61 if env.roots[i] == root { 62 break 63 } 64 // Find all accounts deleted in the past, ensure the associated data is null 65 for addrHash := range env.snapAccounts[env.roots[i]] { 66 if _, ok := accounts[addrHash]; !ok { 67 latest, _ := dl.account(addrHash, 0) 68 blob, err := hr.read(newAccountIdentQuery(env.accountPreimage(addrHash), addrHash), *stateID, dl.stateID(), latest) 69 if err != nil { 70 return err 71 } 72 if len(blob) != 0 { 73 return fmt.Errorf("wrong account data, expected null, got %x", blob) 74 } 75 } 76 } 77 } 78 for addrHash, slots := range storages { 79 for slotHash, slotData := range slots { 80 latest, _ := dl.storage(addrHash, slotHash, 0) 81 blob, err := hr.read(newStorageIdentQuery(env.accountPreimage(addrHash), addrHash, env.hashPreimage(slotHash), slotHash), *stateID, dl.stateID(), latest) 82 if err != nil { 83 return err 84 } 85 if !bytes.Equal(slotData, blob) { 86 return fmt.Errorf("wrong storage data, expected %x, got %x", slotData, blob) 87 } 88 } 89 } 90 for i := 0; i < len(env.roots); i++ { 91 if env.roots[i] == root { 92 break 93 } 94 // Find all storage slots deleted in the past, ensure the associated data is null 95 for addrHash, slots := range env.snapStorages[env.roots[i]] { 96 for slotHash := range slots { 97 _, ok := storages[addrHash] 98 if ok { 99 _, ok = storages[addrHash][slotHash] 100 } 101 if !ok { 102 latest, _ := dl.storage(addrHash, slotHash, 0) 103 blob, err := hr.read(newStorageIdentQuery(env.accountPreimage(addrHash), addrHash, env.hashPreimage(slotHash), slotHash), *stateID, dl.stateID(), latest) 104 if err != nil { 105 return err 106 } 107 if len(blob) != 0 { 108 return fmt.Errorf("wrong storage data, expected null, got %x", blob) 109 } 110 } 111 } 112 } 113 } 114 return nil 115 } 116 117 func TestHistoryReader(t *testing.T) { 118 testHistoryReader(t, 0) // with all histories reserved 119 testHistoryReader(t, 10) // with latest 10 histories reserved 120 } 121 122 func testHistoryReader(t *testing.T, historyLimit uint64) { 123 maxDiffLayers = 4 124 defer func() { 125 maxDiffLayers = 128 126 }() 127 //log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelDebug, true))) 128 129 env := newTester(t, historyLimit, false, 64, true) 130 defer env.release() 131 waitIndexing(env.db) 132 133 var ( 134 roots = env.roots 135 dRoot = env.db.tree.bottom().rootHash() 136 hr = newHistoryReader(env.db.diskdb, env.db.freezer) 137 ) 138 for _, root := range roots { 139 if root == dRoot { 140 break 141 } 142 if err := checkHistoricState(env, root, hr); err != nil { 143 t.Fatal(err) 144 } 145 } 146 147 // Pile up more histories on top, ensuring the historic reader is not affected 148 env.extend(4) 149 waitIndexing(env.db) 150 151 for _, root := range roots { 152 if root == dRoot { 153 break 154 } 155 if err := checkHistoricState(env, root, hr); err != nil { 156 t.Fatal(err) 157 } 158 } 159 }