github.com/ethereum/go-ethereum@v1.16.1/triedb/pathdb/layertree.go (about) 1 // Copyright 2023 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 "errors" 21 "fmt" 22 "sync" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/trie/trienode" 26 ) 27 28 // layerTree is a group of state layers identified by the state root. 29 // This structure defines a few basic operations for manipulating 30 // state layers linked with each other in a tree structure. It's 31 // thread-safe to use. However, callers need to ensure the thread-safety 32 // of the referenced layer by themselves. 33 type layerTree struct { 34 base *diskLayer 35 layers map[common.Hash]layer 36 37 // descendants is a two-dimensional map where the keys represent 38 // an ancestor state root, and the values are the state roots of 39 // all its descendants. 40 // 41 // For example: r -> [c1, c2, ..., cn], where c1 through cn are 42 // the descendants of state r. 43 // 44 // This map includes all the existing diff layers and the disk layer. 45 descendants map[common.Hash]map[common.Hash]struct{} 46 lookup *lookup 47 lock sync.RWMutex 48 } 49 50 // newLayerTree constructs the layerTree with the given head layer. 51 func newLayerTree(head layer) *layerTree { 52 tree := new(layerTree) 53 tree.init(head) 54 return tree 55 } 56 57 // init initializes the layerTree by the given head layer. 58 func (tree *layerTree) init(head layer) { 59 tree.lock.Lock() 60 defer tree.lock.Unlock() 61 62 current := head 63 tree.layers = make(map[common.Hash]layer) 64 tree.descendants = make(map[common.Hash]map[common.Hash]struct{}) 65 66 for { 67 tree.layers[current.rootHash()] = current 68 tree.fillAncestors(current) 69 70 parent := current.parentLayer() 71 if parent == nil { 72 break 73 } 74 current = parent 75 } 76 tree.base = current.(*diskLayer) // panic if it's not a disk layer 77 tree.lookup = newLookup(head, tree.isDescendant) 78 } 79 80 // get retrieves a layer belonging to the given state root. 81 func (tree *layerTree) get(root common.Hash) layer { 82 tree.lock.RLock() 83 defer tree.lock.RUnlock() 84 85 return tree.layers[root] 86 } 87 88 // isDescendant returns whether the specified layer with given root is a 89 // descendant of a specific ancestor. 90 // 91 // This function assumes the read lock has been held. 92 func (tree *layerTree) isDescendant(root common.Hash, ancestor common.Hash) bool { 93 subset := tree.descendants[ancestor] 94 if subset == nil { 95 return false 96 } 97 _, ok := subset[root] 98 return ok 99 } 100 101 // fillAncestors identifies the ancestors of the given layer and populates the 102 // descendants set. The ancestors include the diff layers below the supplied 103 // layer and also the disk layer. 104 // 105 // This function assumes the write lock has been held. 106 func (tree *layerTree) fillAncestors(layer layer) { 107 hash := layer.rootHash() 108 for { 109 parent := layer.parentLayer() 110 if parent == nil { 111 break 112 } 113 layer = parent 114 115 phash := parent.rootHash() 116 subset := tree.descendants[phash] 117 if subset == nil { 118 subset = make(map[common.Hash]struct{}) 119 tree.descendants[phash] = subset 120 } 121 subset[hash] = struct{}{} 122 } 123 } 124 125 // forEach iterates the stored layers inside and applies the 126 // given callback on them. 127 func (tree *layerTree) forEach(onLayer func(layer)) { 128 tree.lock.RLock() 129 defer tree.lock.RUnlock() 130 131 for _, layer := range tree.layers { 132 onLayer(layer) 133 } 134 } 135 136 // len returns the number of layers cached. 137 func (tree *layerTree) len() int { 138 tree.lock.RLock() 139 defer tree.lock.RUnlock() 140 141 return len(tree.layers) 142 } 143 144 // add inserts a new layer into the tree if it can be linked to an existing old parent. 145 func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *StateSetWithOrigin) error { 146 // Reject noop updates to avoid self-loops. This is a special case that can 147 // happen for clique networks and proof-of-stake networks where empty blocks 148 // don't modify the state (0 block subsidy). 149 // 150 // Although we could silently ignore this internally, it should be the caller's 151 // responsibility to avoid even attempting to insert such a layer. 152 if root == parentRoot { 153 return errors.New("layer cycle") 154 } 155 parent := tree.get(parentRoot) 156 if parent == nil { 157 return fmt.Errorf("triedb parent [%#x] layer missing", parentRoot) 158 } 159 l := parent.update(root, parent.stateID()+1, block, newNodeSet(nodes.Flatten()), states) 160 161 tree.lock.Lock() 162 defer tree.lock.Unlock() 163 164 // Link the given layer into the layer set 165 tree.layers[l.rootHash()] = l 166 167 // Link the given layer into its ancestors (up to the current disk layer) 168 tree.fillAncestors(l) 169 170 // Link the given layer into the state mutation history 171 tree.lookup.addLayer(l) 172 return nil 173 } 174 175 // cap traverses downwards the diff tree until the number of allowed diff layers 176 // are crossed. All diffs beyond the permitted number are flattened downwards. 177 func (tree *layerTree) cap(root common.Hash, layers int) error { 178 // Retrieve the head layer to cap from 179 l := tree.get(root) 180 if l == nil { 181 return fmt.Errorf("triedb layer [%#x] missing", root) 182 } 183 diff, ok := l.(*diffLayer) 184 if !ok { 185 return fmt.Errorf("triedb layer [%#x] is disk layer", root) 186 } 187 tree.lock.Lock() 188 defer tree.lock.Unlock() 189 190 // If full commit was requested, flatten the diffs and merge onto disk 191 if layers == 0 { 192 base, err := diff.persist(true) 193 if err != nil { 194 return err 195 } 196 tree.base = base 197 198 // Reset the layer tree with the single new disk layer 199 tree.layers = map[common.Hash]layer{ 200 base.rootHash(): base, 201 } 202 // Resets the descendants map, since there's only a single disk layer 203 // with no descendants. 204 tree.descendants = make(map[common.Hash]map[common.Hash]struct{}) 205 tree.lookup = newLookup(base, tree.isDescendant) 206 return nil 207 } 208 // Dive until we run out of layers or reach the persistent database 209 for i := 0; i < layers-1; i++ { 210 // If we still have diff layers below, continue down 211 if parent, ok := diff.parentLayer().(*diffLayer); ok { 212 diff = parent 213 } else { 214 // Diff stack too shallow, return without modifications 215 return nil 216 } 217 } 218 // We're out of layers, flatten anything below, stopping if it's the disk or if 219 // the memory limit is not yet exceeded. 220 var ( 221 err error 222 replaced layer 223 newBase *diskLayer 224 ) 225 switch parent := diff.parentLayer().(type) { 226 case *diskLayer: 227 return nil 228 229 case *diffLayer: 230 // Hold the lock to prevent any read operations until the new 231 // parent is linked correctly. 232 diff.lock.Lock() 233 234 // Hold the reference of the original layer being replaced 235 replaced = parent 236 237 // Replace the original parent layer with new disk layer. The procedure 238 // can be illustrated as below: 239 // 240 // Before change: 241 // Chain: 242 // C1->C2->C3->C4 (HEAD) 243 // ->C2'->C3'->C4' 244 // 245 // After change: 246 // Chain: 247 // (a) C3->C4 (HEAD) 248 // (b) C1->C2 249 // ->C2'->C3'->C4' 250 // The original C3 is replaced by the new base (with root C3) 251 // Dangling layers in (b) will be removed later 252 newBase, err = parent.persist(false) 253 if err != nil { 254 diff.lock.Unlock() 255 return err 256 } 257 tree.layers[newBase.rootHash()] = newBase 258 259 // Link the new parent and release the lock 260 diff.parent = newBase 261 diff.lock.Unlock() 262 263 default: 264 panic(fmt.Sprintf("unknown data layer in triedb: %T", parent)) 265 } 266 // Remove any layer that is stale or links into a stale layer 267 children := make(map[common.Hash][]common.Hash) 268 for root, layer := range tree.layers { 269 if dl, ok := layer.(*diffLayer); ok { 270 parent := dl.parentLayer().rootHash() 271 children[parent] = append(children[parent], root) 272 } 273 } 274 clearDiff := func(layer layer) { 275 diff, ok := layer.(*diffLayer) 276 if !ok { 277 return 278 } 279 tree.lookup.removeLayer(diff) 280 } 281 var remove func(root common.Hash) 282 remove = func(root common.Hash) { 283 clearDiff(tree.layers[root]) 284 285 // Unlink the layer from the layer tree and cascade to its children 286 delete(tree.descendants, root) 287 delete(tree.layers, root) 288 for _, child := range children[root] { 289 remove(child) 290 } 291 delete(children, root) 292 } 293 remove(tree.base.rootHash()) // remove the old/stale disk layer 294 clearDiff(replaced) // remove the lookup data of the stale parent being replaced 295 tree.base = newBase // update the base layer with newly constructed one 296 return nil 297 } 298 299 // bottom returns the bottom-most disk layer in this tree. 300 func (tree *layerTree) bottom() *diskLayer { 301 tree.lock.RLock() 302 defer tree.lock.RUnlock() 303 304 return tree.base 305 } 306 307 // lookupAccount returns the layer that is guaranteed to contain the account data 308 // corresponding to the specified state root being queried. 309 func (tree *layerTree) lookupAccount(accountHash common.Hash, state common.Hash) (layer, error) { 310 // Hold the read lock to prevent the unexpected layer changes 311 tree.lock.RLock() 312 defer tree.lock.RUnlock() 313 314 tip := tree.lookup.accountTip(accountHash, state, tree.base.root) 315 if tip == (common.Hash{}) { 316 return nil, fmt.Errorf("[%#x] %w", state, errSnapshotStale) 317 } 318 l := tree.layers[tip] 319 if l == nil { 320 return nil, fmt.Errorf("triedb layer [%#x] missing", tip) 321 } 322 return l, nil 323 } 324 325 // lookupStorage returns the layer that is guaranteed to contain the storage slot 326 // data corresponding to the specified state root being queried. 327 func (tree *layerTree) lookupStorage(accountHash common.Hash, slotHash common.Hash, state common.Hash) (layer, error) { 328 // Hold the read lock to prevent the unexpected layer changes 329 tree.lock.RLock() 330 defer tree.lock.RUnlock() 331 332 tip := tree.lookup.storageTip(accountHash, slotHash, state, tree.base.root) 333 if tip == (common.Hash{}) { 334 return nil, fmt.Errorf("[%#x] %w", state, errSnapshotStale) 335 } 336 l := tree.layers[tip] 337 if l == nil { 338 return nil, fmt.Errorf("triedb layer [%#x] missing", tip) 339 } 340 return l, nil 341 }