github.com/MetalBlockchain/subnet-evm@v0.4.9/core/state/snapshot/snapshot.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2019 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 // Package snapshot implements a journalled, dynamic state dump. 28 package snapshot 29 30 import ( 31 "bytes" 32 "errors" 33 "fmt" 34 "sync" 35 "sync/atomic" 36 "time" 37 38 "github.com/MetalBlockchain/subnet-evm/core/rawdb" 39 "github.com/MetalBlockchain/subnet-evm/ethdb" 40 "github.com/MetalBlockchain/subnet-evm/metrics" 41 "github.com/MetalBlockchain/subnet-evm/trie" 42 "github.com/MetalBlockchain/subnet-evm/utils" 43 "github.com/ethereum/go-ethereum/common" 44 "github.com/ethereum/go-ethereum/log" 45 ) 46 47 const ( 48 // skipGenThreshold is the minimum time that must have elapsed since the 49 // creation of the previous disk layer to start snapshot generation on a new 50 // disk layer. 51 // 52 // If disk layers are being discarded at a frequency greater than this threshold, 53 // starting snapshot generation is not worth it (will be aborted before meaningful 54 // work can be done). 55 skipGenThreshold = 500 * time.Millisecond 56 ) 57 58 var ( 59 snapshotCleanAccountHitMeter = metrics.NewRegisteredMeter("state/snapshot/clean/account/hit", nil) 60 snapshotCleanAccountMissMeter = metrics.NewRegisteredMeter("state/snapshot/clean/account/miss", nil) 61 snapshotCleanAccountInexMeter = metrics.NewRegisteredMeter("state/snapshot/clean/account/inex", nil) 62 snapshotCleanAccountReadMeter = metrics.NewRegisteredMeter("state/snapshot/clean/account/read", nil) 63 snapshotCleanAccountWriteMeter = metrics.NewRegisteredMeter("state/snapshot/clean/account/write", nil) 64 65 snapshotCleanStorageHitMeter = metrics.NewRegisteredMeter("state/snapshot/clean/storage/hit", nil) 66 snapshotCleanStorageMissMeter = metrics.NewRegisteredMeter("state/snapshot/clean/storage/miss", nil) 67 snapshotCleanStorageInexMeter = metrics.NewRegisteredMeter("state/snapshot/clean/storage/inex", nil) 68 snapshotCleanStorageReadMeter = metrics.NewRegisteredMeter("state/snapshot/clean/storage/read", nil) 69 snapshotCleanStorageWriteMeter = metrics.NewRegisteredMeter("state/snapshot/clean/storage/write", nil) 70 71 snapshotDirtyAccountHitMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/account/hit", nil) 72 snapshotDirtyAccountMissMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/account/miss", nil) 73 snapshotDirtyAccountInexMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/account/inex", nil) 74 snapshotDirtyAccountReadMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/account/read", nil) 75 snapshotDirtyAccountWriteMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/account/write", nil) 76 77 snapshotDirtyStorageHitMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/hit", nil) 78 snapshotDirtyStorageMissMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/miss", nil) 79 snapshotDirtyStorageInexMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/inex", nil) 80 snapshotDirtyStorageReadMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/read", nil) 81 snapshotDirtyStorageWriteMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/write", nil) 82 83 snapshotDirtyAccountHitDepthHist = metrics.NewRegisteredHistogram("state/snapshot/dirty/account/hit/depth", nil, metrics.NewExpDecaySample(1028, 0.015)) 84 snapshotDirtyStorageHitDepthHist = metrics.NewRegisteredHistogram("state/snapshot/dirty/storage/hit/depth", nil, metrics.NewExpDecaySample(1028, 0.015)) 85 86 snapshotFlushAccountItemMeter = metrics.NewRegisteredMeter("state/snapshot/flush/account/item", nil) 87 snapshotFlushAccountSizeMeter = metrics.NewRegisteredMeter("state/snapshot/flush/account/size", nil) 88 snapshotFlushStorageItemMeter = metrics.NewRegisteredMeter("state/snapshot/flush/storage/item", nil) 89 snapshotFlushStorageSizeMeter = metrics.NewRegisteredMeter("state/snapshot/flush/storage/size", nil) 90 91 snapshotBloomIndexTimer = metrics.NewRegisteredResettingTimer("state/snapshot/bloom/index", nil) 92 snapshotBloomErrorGauge = metrics.NewRegisteredGaugeFloat64("state/snapshot/bloom/error", nil) 93 94 snapshotBloomAccountTrueHitMeter = metrics.NewRegisteredMeter("state/snapshot/bloom/account/truehit", nil) 95 snapshotBloomAccountFalseHitMeter = metrics.NewRegisteredMeter("state/snapshot/bloom/account/falsehit", nil) 96 snapshotBloomAccountMissMeter = metrics.NewRegisteredMeter("state/snapshot/bloom/account/miss", nil) 97 98 snapshotBloomStorageTrueHitMeter = metrics.NewRegisteredMeter("state/snapshot/bloom/storage/truehit", nil) 99 snapshotBloomStorageFalseHitMeter = metrics.NewRegisteredMeter("state/snapshot/bloom/storage/falsehit", nil) 100 snapshotBloomStorageMissMeter = metrics.NewRegisteredMeter("state/snapshot/bloom/storage/miss", nil) 101 102 // ErrSnapshotStale is returned from data accessors if the underlying snapshot 103 // layer had been invalidated due to the chain progressing forward far enough 104 // to not maintain the layer's original state. 105 ErrSnapshotStale = errors.New("snapshot stale") 106 107 // ErrStaleParentLayer is returned when Flatten attempts to flatten a diff layer into 108 // a stale parent. 109 ErrStaleParentLayer = errors.New("parent disk layer is stale") 110 111 // ErrNotCoveredYet is returned from data accessors if the underlying snapshot 112 // is being generated currently and the requested data item is not yet in the 113 // range of accounts covered. 114 ErrNotCoveredYet = errors.New("not covered yet") 115 116 // ErrNotConstructed is returned if the callers want to iterate the snapshot 117 // while the generation is not finished yet. 118 ErrNotConstructed = errors.New("snapshot is not constructed") 119 ) 120 121 // Snapshot represents the functionality supported by a snapshot storage layer. 122 type Snapshot interface { 123 // Root returns the root hash for which this snapshot was made. 124 Root() common.Hash 125 126 // Account directly retrieves the account associated with a particular hash in 127 // the snapshot slim data format. 128 Account(hash common.Hash) (*Account, error) 129 130 // AccountRLP directly retrieves the account RLP associated with a particular 131 // hash in the snapshot slim data format. 132 AccountRLP(hash common.Hash) ([]byte, error) 133 134 // Storage directly retrieves the storage data associated with a particular hash, 135 // within a particular account. 136 Storage(accountHash, storageHash common.Hash) ([]byte, error) 137 138 // AccountIterator creates an account iterator over the account trie given by the provided root hash. 139 AccountIterator(seek common.Hash) AccountIterator 140 141 // StorageIterator creates a storage iterator over the storage trie given by the provided root hash. 142 StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) 143 } 144 145 // snapshot is the internal version of the snapshot data layer that supports some 146 // additional methods compared to the public API. 147 type snapshot interface { 148 Snapshot 149 150 BlockHash() common.Hash 151 152 // Parent returns the subsequent layer of a snapshot, or nil if the base was 153 // reached. 154 // 155 // Note, the method is an internal helper to avoid type switching between the 156 // disk and diff layers. There is no locking involved. 157 Parent() snapshot 158 159 // Update creates a new layer on top of the existing snapshot diff tree with 160 // the specified data items. 161 // 162 // Note, the maps are retained by the method to avoid copying everything. 163 Update(blockHash, blockRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer 164 165 // Stale return whether this layer has become stale (was flattened across) or 166 // if it's still live. 167 Stale() bool 168 } 169 170 // Tree is an Ethereum state snapshot tree. It consists of one persistent base 171 // layer backed by a key-value store, on top of which arbitrarily many in-memory 172 // diff layers are topped. The memory diffs can form a tree with branching, but 173 // the disk layer is singleton and common to all. If a reorg goes deeper than the 174 // disk layer, everything needs to be deleted. 175 // 176 // The goal of a state snapshot is twofold: to allow direct access to account and 177 // storage data to avoid expensive multi-level trie lookups; and to allow sorted, 178 // cheap iteration of the account/storage tries for sync aid. 179 type Tree struct { 180 diskdb ethdb.KeyValueStore // Persistent database to store the snapshot 181 triedb *trie.Database // In-memory cache to access the trie through 182 cache int // Megabytes permitted to use for read caches 183 // Collection of all known layers 184 // blockHash -> snapshot 185 blockLayers map[common.Hash]snapshot 186 // stateRoot -> blockHash -> snapshot 187 // Update creates a new block layer with a parent taken from the blockHash -> snapshot map 188 // we can support grabbing a read only Snapshot by getting any one from the state root based map 189 stateLayers map[common.Hash]map[common.Hash]snapshot 190 verified bool // Indicates if snapshot integrity has been verified 191 lock sync.RWMutex 192 193 // Test hooks 194 onFlatten func() // Hook invoked when the bottom most diff layers are flattened 195 } 196 197 // New attempts to load an already existing snapshot from a persistent key-value 198 // store (with a number of memory layers from a journal), ensuring that the head 199 // of the snapshot matches the expected one. 200 // 201 // If the snapshot is missing or the disk layer is broken, the snapshot will be 202 // reconstructed using both the existing data and the state trie. 203 // The repair happens on a background thread. 204 func New(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, blockHash, root common.Hash, async bool, rebuild bool, verify bool) (*Tree, error) { 205 // Create a new, empty snapshot tree 206 snap := &Tree{ 207 diskdb: diskdb, 208 triedb: triedb, 209 cache: cache, 210 blockLayers: make(map[common.Hash]snapshot), 211 stateLayers: make(map[common.Hash]map[common.Hash]snapshot), 212 verified: !verify, // if verify is false, all verification will be bypassed 213 } 214 215 // Attempt to load a previously persisted snapshot and rebuild one if failed 216 head, generated, err := loadSnapshot(diskdb, triedb, cache, blockHash, root) 217 if err != nil { 218 if rebuild { 219 log.Warn("Failed to load snapshot, regenerating", "err", err) 220 snap.Rebuild(blockHash, root) 221 if !async { 222 if err := snap.verifyIntegrity(snap.disklayer(), true); err != nil { 223 return nil, err 224 } 225 } 226 return snap, nil 227 } 228 return nil, err // Bail out the error, don't rebuild automatically. 229 } 230 231 // Existing snapshot loaded, seed all the layers 232 // It is unnecessary to grab the lock here, since it was created within this function 233 // call, but we grab it nevertheless to follow the spec for insertSnap. 234 snap.lock.Lock() 235 defer snap.lock.Unlock() 236 for head != nil { 237 snap.insertSnap(head) 238 head = head.Parent() 239 } 240 241 // Verify any synchronously generated or loaded snapshot from disk 242 if !async || generated { 243 if err := snap.verifyIntegrity(snap.disklayer(), !async && !generated); err != nil { 244 return nil, err 245 } 246 } 247 248 return snap, nil 249 } 250 251 // insertSnap inserts [snap] into the tree. 252 // Assumes the lock is held. 253 func (t *Tree) insertSnap(snap snapshot) { 254 t.blockLayers[snap.BlockHash()] = snap 255 blockSnaps, ok := t.stateLayers[snap.Root()] 256 if !ok { 257 blockSnaps = make(map[common.Hash]snapshot) 258 t.stateLayers[snap.Root()] = blockSnaps 259 } 260 blockSnaps[snap.BlockHash()] = snap 261 } 262 263 // Snapshot retrieves a snapshot belonging to the given state root, or nil if no 264 // snapshot is maintained for that state root. 265 func (t *Tree) Snapshot(stateRoot common.Hash) Snapshot { 266 return t.getSnapshot(stateRoot, false) 267 } 268 269 // getSnapshot retrieves a Snapshot by its state root. If the caller already holds the 270 // snapTree lock when callthing this function, [holdsTreeLock] should be set to true. 271 func (t *Tree) getSnapshot(stateRoot common.Hash, holdsTreeLock bool) snapshot { 272 if !holdsTreeLock { 273 t.lock.RLock() 274 defer t.lock.RUnlock() 275 } 276 277 layers := t.stateLayers[stateRoot] 278 for _, layer := range layers { 279 return layer 280 } 281 return nil 282 } 283 284 // Snapshots returns all visited layers from the topmost layer with specific 285 // root and traverses downward. The layer amount is limited by the given number. 286 // If nodisk is set, then disk layer is excluded. 287 func (t *Tree) Snapshots(blockHash common.Hash, limits int, nodisk bool) []Snapshot { 288 t.lock.RLock() 289 defer t.lock.RUnlock() 290 291 if limits == 0 { 292 return nil 293 } 294 layer, ok := t.blockLayers[blockHash] 295 if !ok { 296 return nil 297 } 298 var ret []Snapshot 299 for { 300 if _, isdisk := layer.(*diskLayer); isdisk && nodisk { 301 break 302 } 303 ret = append(ret, layer) 304 limits -= 1 305 if limits == 0 { 306 break 307 } 308 parent := layer.Parent() 309 if parent == nil { 310 break 311 } 312 layer = parent 313 } 314 return ret 315 } 316 317 // Update adds a new snapshot into the tree, if that can be linked to an existing 318 // old parent. It is disallowed to insert a disk layer (the origin of all). 319 func (t *Tree) Update(blockHash, blockRoot, parentBlockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { 320 t.lock.Lock() 321 defer t.lock.Unlock() 322 323 // Grab the parent snapshot based on the parent block hash, not the parent state root 324 parent := t.blockLayers[parentBlockHash] 325 if parent == nil { 326 return fmt.Errorf("parent [%#x] snapshot missing", parentBlockHash) 327 } 328 329 snap := t.blockLayers[blockHash] 330 if snap != nil { 331 log.Warn("Attempted to insert a snapshot layer for an existing block", 332 "blockHash", blockHash, "blockRoot", blockRoot, "parentHash", parentBlockHash, 333 "existingBlockRoot", snap.Root(), 334 ) 335 } 336 337 snap = parent.Update(blockHash, blockRoot, destructs, accounts, storage) 338 t.insertSnap(snap) 339 return nil 340 } 341 342 // verifyIntegrity performs an integrity check on the current snapshot using 343 // verify. Most importantly, verifyIntegrity ensures verify is called at 344 // most once during the entire lifetime of [Tree], returning immediately if 345 // already invoked. If [waitBuild] is true, verifyIntegrity will wait for 346 // generation of the snapshot to finish before verifying. 347 // 348 // It is assumed that the caller holds the [snapTree] lock 349 // when calling this function. 350 func (t *Tree) verifyIntegrity(base *diskLayer, waitBuild bool) error { 351 // Find the rebuild termination channel and wait until 352 // the snapshot is generated 353 if done := base.genPending; waitBuild && done != nil { 354 log.Info("Waiting for snapshot generation", "root", base.root) 355 <-done 356 } 357 358 if t.verified { 359 return nil 360 } 361 362 if base.genMarker != nil { 363 return errors.New("cannot verify integrity of an unfinished snapshot") 364 } 365 366 start := time.Now() 367 log.Info("Verifying snapshot integrity", "root", base.root) 368 if err := t.verify(base.root, true); err != nil { 369 return fmt.Errorf("unable to verify snapshot integrity: %w", err) 370 } 371 372 log.Info("Verified snapshot integrity", "root", base.root, "elapsed", time.Since(start)) 373 t.verified = true 374 return nil 375 } 376 377 // Flatten flattens the snapshot for [blockHash] into its parent. if its 378 // parent is not a disk layer, Flatten will return an error. 379 // Note: a blockHash is used instead of a state root so that the exact state 380 // transition between the two states is well defined. This is intended to 381 // prevent the following edge case 382 // A 383 // / \ 384 // B C 385 // | 386 // D 387 // In this scenario, it's possible For (A, B) and (A, C, D) to be two 388 // different paths to the resulting state. We use block hashes and parent 389 // block hashes to ensure that the exact path through which we flatten 390 // diffLayers is well defined. 391 func (t *Tree) Flatten(blockHash common.Hash) error { 392 t.lock.Lock() 393 defer t.lock.Unlock() 394 395 start := time.Now() 396 snap, ok := t.blockLayers[blockHash] 397 if !ok { 398 return fmt.Errorf("cannot flatten missing snapshot: %s", blockHash) 399 } 400 diff, ok := snap.(*diffLayer) 401 if !ok { 402 return fmt.Errorf("cannot flatten disk layer: (%s, %s)", blockHash, snap.Root()) 403 } 404 if diff.parent == nil { 405 return fmt.Errorf("cannot flatten snapshot with missing parent (%s, %s)", blockHash, diff.root) 406 } 407 if parentDiff, ok := diff.parent.(*diffLayer); ok { 408 return fmt.Errorf("cannot flatten snapshot (%s, %s) into diff layer parent (%s, %s)", blockHash, diff.root, parentDiff.blockHash, parentDiff.root) 409 } 410 parentLayer := t.blockLayers[diff.parent.BlockHash()] 411 if parentLayer == nil { 412 return fmt.Errorf("snapshot missing parent layer: %s", diff.parent.BlockHash()) 413 } 414 415 diff.lock.Lock() 416 // Invoke the hook if it's registered. Ugly hack. 417 if t.onFlatten != nil { 418 t.onFlatten() 419 } 420 base, snapshotGenerated, err := diffToDisk(diff) 421 diff.lock.Unlock() 422 if err != nil { 423 return err 424 } 425 426 // Remove parent layer 427 if err := t.discard(diff.parent.BlockHash(), true); err != nil { 428 return fmt.Errorf("failed to discard parent layer while flattening (%s, %s): %w", blockHash, diff.root, err) 429 } 430 // We created a new diskLayer [base] to replace [diff], so we need to replace 431 // it in both maps and replace all pointers to it. 432 t.blockLayers[base.blockHash] = base 433 stateSnaps := t.stateLayers[base.root] 434 // stateSnaps must already be initialized here, since we are replacing 435 // an existing snapshot instead of adding a new one. 436 stateSnaps[base.blockHash] = base 437 438 // Replace the parent pointers for any snapshot that referenced 439 // the replaced diffLayer. 440 for _, snap := range t.blockLayers { 441 if diff, ok := snap.(*diffLayer); ok { 442 if base.blockHash == diff.parent.BlockHash() { 443 diff.lock.Lock() 444 diff.parent = base 445 diff.lock.Unlock() 446 } 447 } 448 } 449 450 // TODO add tracking of children to the snapshots to reduce overhead here. 451 children := make(map[common.Hash][]common.Hash) 452 for blockHash, snap := range t.blockLayers { 453 if diff, ok := snap.(*diffLayer); ok { 454 parent := diff.parent.BlockHash() 455 children[parent] = append(children[parent], blockHash) 456 } 457 } 458 var remove func(blockHash common.Hash) 459 remove = func(blockHash common.Hash) { 460 t.discard(blockHash, false) 461 for _, child := range children[blockHash] { 462 remove(child) 463 } 464 delete(children, blockHash) 465 } 466 for blockHash, snap := range t.blockLayers { 467 if snap.Stale() { 468 remove(blockHash) 469 } 470 } 471 // If the disk layer was modified, regenerate all the cumulative blooms 472 var rebloom func(blockHash common.Hash) 473 rebloom = func(blockHash common.Hash) { 474 if diff, ok := t.blockLayers[blockHash].(*diffLayer); ok { 475 diff.rebloom(base) 476 } 477 for _, child := range children[blockHash] { 478 rebloom(child) 479 } 480 } 481 rebloom(base.blockHash) 482 log.Debug("Flattened snapshot tree", "blockHash", blockHash, "root", base.root, "size", len(t.blockLayers), "elapsed", common.PrettyDuration(time.Since(start))) 483 484 if !snapshotGenerated { 485 return nil 486 } 487 return t.verifyIntegrity(base, false) 488 } 489 490 // Length returns the number of snapshot layers that is currently being maintained. 491 func (t *Tree) NumStateLayers() int { 492 t.lock.RLock() 493 defer t.lock.RUnlock() 494 495 return len(t.stateLayers) 496 } 497 498 func (t *Tree) NumBlockLayers() int { 499 t.lock.RLock() 500 defer t.lock.RUnlock() 501 502 return len(t.blockLayers) 503 } 504 505 // Discard removes layers that we no longer need 506 func (t *Tree) Discard(blockHash common.Hash) error { 507 t.lock.Lock() 508 defer t.lock.Unlock() 509 510 return t.discard(blockHash, false) 511 } 512 513 // discard removes the snapshot associated with [blockHash] from the 514 // snapshot tree. 515 // If [force] is true, discard may delete the disk layer. This should 516 // only be called within Flatten, when a new disk layer is being created. 517 // Assumes the lock is held. 518 func (t *Tree) discard(blockHash common.Hash, force bool) error { 519 snap := t.blockLayers[blockHash] 520 if snap == nil { 521 return fmt.Errorf("cannot discard missing snapshot: %s", blockHash) 522 } 523 _, ok := snap.(*diffLayer) 524 // Never discard the disk layer 525 if !ok && !force { 526 return fmt.Errorf("cannot discard the disk layer: %s", blockHash) 527 } 528 snaps, ok := t.stateLayers[snap.Root()] 529 if !ok { 530 return fmt.Errorf("cannot discard snapshot %s missing from state: %s", blockHash, snap.Root()) 531 } 532 // Discard the block from the map. If there are no more blocks 533 // mapping to the same state remove it from [stateLayers] as well. 534 delete(snaps, blockHash) 535 if len(snaps) == 0 { 536 delete(t.stateLayers, snap.Root()) 537 } 538 delete(t.blockLayers, blockHash) 539 return nil 540 } 541 542 // AbortGeneration aborts an ongoing snapshot generation process (if it hasn't 543 // stopped already). 544 // 545 // It is not required to manually abort snapshot generation. If generation has not 546 // been manually aborted prior to invoking [diffToDisk], it will be aborted anyways. 547 // 548 // It is safe to call this method multiple times and when there is no snapshot 549 // generation currently underway. 550 func (t *Tree) AbortGeneration() { 551 t.lock.Lock() 552 defer t.lock.Unlock() 553 554 dl := t.disklayer() 555 dl.abortGeneration() 556 } 557 558 // abortGeneration sends an abort message to the generate goroutine and waits 559 // for it to shutdown before returning (if it is running). This call should not 560 // be made concurrently. 561 func (dl *diskLayer) abortGeneration() bool { 562 // Store ideal time for abort to get better estimate of load 563 // 564 // Note that we set this time regardless if abortion was skipped otherwise we 565 // will never restart generation (age will always be negative). 566 if dl.abortStarted.IsZero() { 567 dl.abortStarted = time.Now() 568 } 569 570 // If the disk layer is running a snapshot generator, abort it 571 if dl.genAbort != nil && dl.genStats == nil { 572 abort := make(chan struct{}) 573 dl.genAbort <- abort 574 <-abort 575 return true 576 } 577 578 return false 579 } 580 581 // diffToDisk merges a bottom-most diff into the persistent disk layer underneath 582 // it. The method will panic if called onto a non-bottom-most diff layer. 583 // 584 // The disk layer persistence should be operated in an atomic way. All updates should 585 // be discarded if the whole transition if not finished. 586 func diffToDisk(bottom *diffLayer) (*diskLayer, bool, error) { 587 var ( 588 base = bottom.parent.(*diskLayer) 589 batch = base.diskdb.NewBatch() 590 ) 591 592 // Attempt to abort generation (if not already aborted) 593 base.abortGeneration() 594 595 // Put the deletion in the batch writer, flush all updates in the final step. 596 rawdb.DeleteSnapshotBlockHash(batch) 597 rawdb.DeleteSnapshotRoot(batch) 598 599 // Mark the original base as stale as we're going to create a new wrapper 600 base.lock.Lock() 601 if base.stale { 602 base.lock.Unlock() 603 return nil, false, ErrStaleParentLayer // we've committed into the same base from two children, boo 604 } 605 base.stale = true 606 base.lock.Unlock() 607 608 // Destroy all the destructed accounts from the database 609 for hash := range bottom.destructSet { 610 // Skip any account not covered yet by the snapshot 611 if base.genMarker != nil && bytes.Compare(hash[:], base.genMarker) > 0 { 612 continue 613 } 614 // Remove all storage slots 615 rawdb.DeleteAccountSnapshot(batch, hash) 616 base.cache.Set(hash[:], nil) 617 618 it := rawdb.IterateStorageSnapshots(base.diskdb, hash) 619 for it.Next() { 620 key := it.Key() 621 batch.Delete(key) 622 base.cache.Del(key[1:]) 623 snapshotFlushStorageItemMeter.Mark(1) 624 625 // Ensure we don't delete too much data blindly (contract can be 626 // huge). It's ok to flush, the root will go missing in case of a 627 // crash and we'll detect and regenerate the snapshot. 628 if batch.ValueSize() > ethdb.IdealBatchSize { 629 if err := batch.Write(); err != nil { 630 log.Crit("Failed to write storage deletions", "err", err) 631 } 632 batch.Reset() 633 } 634 } 635 it.Release() 636 } 637 // Push all updated accounts into the database 638 for hash, data := range bottom.accountData { 639 // Skip any account not covered yet by the snapshot 640 if base.genMarker != nil && bytes.Compare(hash[:], base.genMarker) > 0 { 641 continue 642 } 643 // Push the account to disk 644 rawdb.WriteAccountSnapshot(batch, hash, data) 645 base.cache.Set(hash[:], data) 646 snapshotCleanAccountWriteMeter.Mark(int64(len(data))) 647 648 snapshotFlushAccountItemMeter.Mark(1) 649 snapshotFlushAccountSizeMeter.Mark(int64(len(data))) 650 651 // Ensure we don't write too much data blindly. It's ok to flush, the 652 // root will go missing in case of a crash and we'll detect and regen 653 // the snapshot. 654 if batch.ValueSize() > ethdb.IdealBatchSize { 655 if err := batch.Write(); err != nil { 656 log.Crit("Failed to write storage deletions", "err", err) 657 } 658 batch.Reset() 659 } 660 } 661 // Push all the storage slots into the database 662 for accountHash, storage := range bottom.storageData { 663 // Skip any account not covered yet by the snapshot 664 if base.genMarker != nil && bytes.Compare(accountHash[:], base.genMarker) > 0 { 665 continue 666 } 667 // Generation might be mid-account, track that case too 668 midAccount := base.genMarker != nil && bytes.Equal(accountHash[:], base.genMarker[:common.HashLength]) 669 670 for storageHash, data := range storage { 671 // Skip any slot not covered yet by the snapshot 672 if midAccount && bytes.Compare(storageHash[:], base.genMarker[common.HashLength:]) > 0 { 673 continue 674 } 675 if len(data) > 0 { 676 rawdb.WriteStorageSnapshot(batch, accountHash, storageHash, data) 677 base.cache.Set(append(accountHash[:], storageHash[:]...), data) 678 snapshotCleanStorageWriteMeter.Mark(int64(len(data))) 679 } else { 680 rawdb.DeleteStorageSnapshot(batch, accountHash, storageHash) 681 base.cache.Set(append(accountHash[:], storageHash[:]...), nil) 682 } 683 snapshotFlushStorageItemMeter.Mark(1) 684 snapshotFlushStorageSizeMeter.Mark(int64(len(data))) 685 } 686 } 687 // Update the snapshot block marker and write any remainder data 688 rawdb.WriteSnapshotBlockHash(batch, bottom.blockHash) 689 rawdb.WriteSnapshotRoot(batch, bottom.root) 690 691 // Write out the generator progress marker and report 692 journalProgress(batch, base.genMarker, base.genStats) 693 694 // Flush all the updates in the single db operation. Ensure the 695 // disk layer transition is atomic. 696 if err := batch.Write(); err != nil { 697 log.Crit("Failed to write leftover snapshot", "err", err) 698 } 699 log.Debug("Journalled disk layer", "root", bottom.root, "complete", base.genMarker == nil) 700 res := &diskLayer{ 701 root: bottom.root, 702 blockHash: bottom.blockHash, 703 cache: base.cache, 704 diskdb: base.diskdb, 705 triedb: base.triedb, 706 genMarker: base.genMarker, 707 genPending: base.genPending, 708 created: time.Now(), 709 } 710 // If snapshot generation hasn't finished yet, port over all the starts and 711 // continue where the previous round left off. 712 // 713 // Note, the `base.genAbort` comparison is not used normally, it's checked 714 // to allow the tests to play with the marker without triggering this path. 715 if base.genMarker != nil && base.genAbort != nil { 716 res.genMarker = base.genMarker 717 res.genAbort = make(chan chan struct{}) 718 719 // If the diskLayer we are about to discard is not very old, we skip 720 // generation on the next layer (assuming generation will just get canceled 721 // before doing meaningful work anyways). 722 diskLayerAge := base.abortStarted.Sub(base.created) 723 if diskLayerAge < skipGenThreshold { 724 log.Debug("Skipping snapshot generation", "previous disk layer age", diskLayerAge) 725 res.genStats = base.genStats 726 } else { 727 go res.generate(base.genStats) 728 } 729 } 730 return res, base.genMarker == nil, nil 731 } 732 733 // Rebuild wipes all available snapshot data from the persistent database and 734 // discard all caches and diff layers. Afterwards, it starts a new snapshot 735 // generator with the given root hash. 736 func (t *Tree) Rebuild(blockHash, root common.Hash) { 737 t.lock.Lock() 738 defer t.lock.Unlock() 739 740 // Track whether there's a wipe currently running and keep it alive if so 741 var wiper chan struct{} 742 743 // Iterate over and mark all layers stale 744 for _, layer := range t.blockLayers { 745 switch layer := layer.(type) { 746 case *diskLayer: 747 // If the base layer is generating, abort it and save 748 if layer.genAbort != nil { 749 abort := make(chan struct{}) 750 layer.genAbort <- abort 751 <-abort 752 753 if stats := layer.genStats; stats != nil { 754 wiper = stats.wiping 755 } 756 } 757 // Layer should be inactive now, mark it as stale 758 layer.lock.Lock() 759 layer.stale = true 760 layer.lock.Unlock() 761 762 case *diffLayer: 763 // If the layer is a simple diff, simply mark as stale 764 layer.lock.Lock() 765 atomic.StoreUint32(&layer.stale, 1) 766 layer.lock.Unlock() 767 768 default: 769 panic(fmt.Sprintf("unknown layer type: %T", layer)) 770 } 771 } 772 // Start generating a new snapshot from scratch on a background thread. The 773 // generator will run a wiper first if there's not one running right now. 774 log.Info("Rebuilding state snapshot") 775 base := generateSnapshot(t.diskdb, t.triedb, t.cache, blockHash, root, wiper) 776 t.blockLayers = map[common.Hash]snapshot{ 777 blockHash: base, 778 } 779 t.stateLayers = map[common.Hash]map[common.Hash]snapshot{ 780 root: { 781 blockHash: base, 782 }, 783 } 784 } 785 786 // AccountIterator creates a new account iterator for the specified root hash and 787 // seeks to a starting account hash. When [force] is true, a new account 788 // iterator is created without acquiring the [snapTree] lock and without 789 // confirming that the snapshot on the disk layer is fully generated. 790 func (t *Tree) AccountIterator(root common.Hash, seek common.Hash, force bool) (AccountIterator, error) { 791 if !force { 792 ok, err := t.generating() 793 if err != nil { 794 return nil, err 795 } 796 if ok { 797 return nil, ErrNotConstructed 798 } 799 } 800 return newFastAccountIterator(t, root, seek, force) 801 } 802 803 // StorageIterator creates a new storage iterator for the specified root hash and 804 // account. The iterator will be move to the specific start position. When [force] 805 // is true, a new account iterator is created without acquiring the [snapTree] 806 // lock and without confirming that the snapshot on the disk layer is fully generated. 807 func (t *Tree) StorageIterator(root common.Hash, account common.Hash, seek common.Hash, force bool) (StorageIterator, error) { 808 if !force { 809 ok, err := t.generating() 810 if err != nil { 811 return nil, err 812 } 813 if ok { 814 return nil, ErrNotConstructed 815 } 816 } 817 return newFastStorageIterator(t, root, account, seek, force) 818 } 819 820 // Verify iterates the whole state(all the accounts as well as the corresponding storages) 821 // with the specific root and compares the re-computed hash with the original one. 822 func (t *Tree) Verify(root common.Hash) error { 823 return t.verify(root, false) 824 } 825 826 // verify iterates the whole state(all the accounts as well as the corresponding storages) 827 // with the specific root and compares the re-computed hash with the original one. 828 // When [force] is true, it is assumed that the caller has confirmed that the 829 // snapshot is generated and that they hold the snapTree lock. 830 func (t *Tree) verify(root common.Hash, force bool) error { 831 acctIt, err := t.AccountIterator(root, common.Hash{}, force) 832 if err != nil { 833 return err 834 } 835 defer acctIt.Release() 836 837 got, err := generateTrieRoot(nil, acctIt, common.Hash{}, stackTrieGenerate, func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { 838 storageIt, err := t.StorageIterator(root, accountHash, common.Hash{}, force) 839 if err != nil { 840 return common.Hash{}, err 841 } 842 defer storageIt.Release() 843 844 hash, err := generateTrieRoot(nil, storageIt, accountHash, stackTrieGenerate, nil, stat, false) 845 if err != nil { 846 return common.Hash{}, err 847 } 848 return hash, nil 849 }, newGenerateStats(), true) 850 851 if err != nil { 852 return err 853 } 854 if got != root { 855 return fmt.Errorf("state root hash mismatch: got %x, want %x", got, root) 856 } 857 return nil 858 } 859 860 // disklayer is an internal helper function to return the disk layer. 861 // The lock of snapTree is assumed to be held already. 862 func (t *Tree) disklayer() *diskLayer { 863 var snap snapshot 864 for _, s := range t.blockLayers { 865 snap = s 866 break 867 } 868 if snap == nil { 869 return nil 870 } 871 switch layer := snap.(type) { 872 case *diskLayer: 873 return layer 874 case *diffLayer: 875 return layer.origin 876 default: 877 panic(fmt.Sprintf("%T: undefined layer", snap)) 878 } 879 } 880 881 // diskRoot is a internal helper function to return the disk layer root. 882 // The lock of snapTree is assumed to be held already. 883 func (t *Tree) diskRoot() common.Hash { 884 disklayer := t.disklayer() 885 if disklayer == nil { 886 return common.Hash{} 887 } 888 return disklayer.Root() 889 } 890 891 // generating is an internal helper function which reports whether the snapshot 892 // is still under the construction. 893 func (t *Tree) generating() (bool, error) { 894 t.lock.Lock() 895 defer t.lock.Unlock() 896 897 layer := t.disklayer() 898 if layer == nil { 899 return false, errors.New("disk layer is missing") 900 } 901 layer.lock.RLock() 902 defer layer.lock.RUnlock() 903 return layer.genMarker != nil, nil 904 } 905 906 // diskRoot is a external helper function to return the disk layer root. 907 func (t *Tree) DiskRoot() common.Hash { 908 t.lock.Lock() 909 defer t.lock.Unlock() 910 911 return t.diskRoot() 912 } 913 914 func (t *Tree) DiskAccountIterator(seek common.Hash) AccountIterator { 915 t.lock.Lock() 916 defer t.lock.Unlock() 917 918 return t.disklayer().AccountIterator(seek) 919 } 920 921 func (t *Tree) DiskStorageIterator(account common.Hash, seek common.Hash) StorageIterator { 922 t.lock.Lock() 923 defer t.lock.Unlock() 924 925 it, _ := t.disklayer().StorageIterator(account, seek) 926 return it 927 } 928 929 // NewDiskLayer creates a diskLayer for direct access to the contents of the on-disk 930 // snapshot. Does not perform any validation. 931 func NewDiskLayer(diskdb ethdb.KeyValueStore) Snapshot { 932 return &diskLayer{ 933 diskdb: diskdb, 934 created: time.Now(), 935 936 // state sync uses iterators to access data, so this cache is not used. 937 // initializing it out of caution. 938 cache: utils.NewMeteredCache(32*1024, "", "", 0), 939 } 940 } 941 942 // NewTestTree creates a *Tree with a pre-populated diskLayer 943 func NewTestTree(diskdb ethdb.KeyValueStore, blockHash, root common.Hash) *Tree { 944 base := &diskLayer{ 945 diskdb: diskdb, 946 root: root, 947 blockHash: blockHash, 948 cache: utils.NewMeteredCache(128*256, "", "", 0), 949 created: time.Now(), 950 } 951 return &Tree{ 952 blockLayers: map[common.Hash]snapshot{ 953 blockHash: base, 954 }, 955 stateLayers: map[common.Hash]map[common.Hash]snapshot{ 956 root: { 957 blockHash: base, 958 }, 959 }, 960 } 961 }