github.com/ethereum/go-ethereum@v1.16.1/triedb/pathdb/generate.go (about) 1 // Copyright 2019 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 "sync" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/common/hexutil" 28 "github.com/ethereum/go-ethereum/core/rawdb" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/crypto" 31 "github.com/ethereum/go-ethereum/ethdb" 32 "github.com/ethereum/go-ethereum/log" 33 "github.com/ethereum/go-ethereum/rlp" 34 "github.com/ethereum/go-ethereum/trie" 35 "github.com/ethereum/go-ethereum/triedb/database" 36 ) 37 38 var ( 39 // accountCheckRange is the upper limit of the number of accounts involved in 40 // each range check. This is a value estimated based on experience. If this 41 // range is too large, the failure rate of range proof will increase. Otherwise, 42 // if the range is too small, the efficiency of the state recovery will decrease. 43 accountCheckRange = 128 44 45 // storageCheckRange is the upper limit of the number of storage slots involved 46 // in each range check. This is a value estimated based on experience. If this 47 // range is too large, the failure rate of range proof will increase. Otherwise, 48 // if the range is too small, the efficiency of the state recovery will decrease. 49 storageCheckRange = 1024 50 51 // errMissingTrie is returned if the target trie is missing while the generation 52 // is running. In this case the generation is aborted and wait the new signal. 53 errMissingTrie = errors.New("missing trie") 54 ) 55 56 // diskReader is a wrapper of key-value store and implements database.NodeReader, 57 // providing a function for accessing persistent trie nodes in the disk 58 type diskReader struct{ db ethdb.KeyValueStore } 59 60 // Node retrieves the trie node blob with the provided trie identifier, 61 // node path and the corresponding node hash. No error will be returned 62 // if the node is not found. 63 func (r *diskReader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) { 64 if owner == (common.Hash{}) { 65 return rawdb.ReadAccountTrieNode(r.db, path), nil 66 } 67 return rawdb.ReadStorageTrieNode(r.db, owner, path), nil 68 } 69 70 // diskStore is a wrapper of key-value store and implements database.NodeDatabase. 71 // It's meant to be used for generating state snapshot from the trie data. 72 type diskStore struct { 73 db ethdb.KeyValueStore 74 } 75 76 // NodeReader returns a node reader associated with the specific state. 77 // An error will be returned if the specified state is not available. 78 func (s *diskStore) NodeReader(stateRoot common.Hash) (database.NodeReader, error) { 79 root := types.EmptyRootHash 80 if blob := rawdb.ReadAccountTrieNode(s.db, nil); len(blob) > 0 { 81 root = crypto.Keccak256Hash(blob) 82 } 83 if root != stateRoot { 84 return nil, fmt.Errorf("state %x is not available", stateRoot) 85 } 86 return &diskReader{s.db}, nil 87 } 88 89 // Generator is the struct for initial state snapshot generation. It is not thread-safe; 90 // the caller must manage concurrency issues themselves. 91 type generator struct { 92 noBuild bool // Flag indicating whether snapshot generation is permitted 93 running bool // Flag indicating whether the background generation is running 94 95 db ethdb.KeyValueStore // Key-value store containing the snapshot data 96 stats *generatorStats // Generation statistics used throughout the entire life cycle 97 abort chan chan struct{} // Notification channel to abort generating the snapshot in this layer 98 done chan struct{} // Notification channel when generation is done 99 100 progress []byte // Progress marker of the state generation, nil means it's completed 101 lock sync.RWMutex // Lock which protects the progress, only generator can mutate the progress 102 } 103 104 // newGenerator constructs the state snapshot generator. 105 // 106 // noBuild will be true if the background snapshot generation is not allowed, 107 // usually used in read-only mode. 108 // 109 // progress indicates the starting position for resuming snapshot generation. 110 // It must be provided even if generation is not allowed; otherwise, uncovered 111 // states may be exposed for serving. 112 func newGenerator(db ethdb.KeyValueStore, noBuild bool, progress []byte, stats *generatorStats) *generator { 113 if stats == nil { 114 stats = &generatorStats{start: time.Now()} 115 } 116 return &generator{ 117 noBuild: noBuild, 118 progress: progress, 119 db: db, 120 stats: stats, 121 abort: make(chan chan struct{}), 122 done: make(chan struct{}), 123 } 124 } 125 126 // run starts the state snapshot generation in the background. 127 func (g *generator) run(root common.Hash) { 128 if g.noBuild { 129 log.Warn("Snapshot generation is not permitted") 130 return 131 } 132 if g.running { 133 g.stop() 134 log.Warn("Paused the leftover generation cycle") 135 } 136 g.running = true 137 go g.generate(newGeneratorContext(root, g.progress, g.db)) 138 } 139 140 // stop terminates the background generation if it's actively running. 141 // The Recent generation progress being made will be saved before returning. 142 func (g *generator) stop() { 143 if !g.running { 144 log.Debug("Snapshot generation is not running") 145 return 146 } 147 ch := make(chan struct{}) 148 g.abort <- ch 149 <-ch 150 g.running = false 151 } 152 153 // completed returns the flag indicating if the whole generation is done. 154 func (g *generator) completed() bool { 155 progress := g.progressMarker() 156 return progress == nil 157 } 158 159 // progressMarker returns the current generation progress marker. It may slightly 160 // lag behind the actual generation position, as the progress field is only updated 161 // when checkAndFlush is called. The only effect is that some generated states 162 // may be refused for serving. 163 func (g *generator) progressMarker() []byte { 164 g.lock.RLock() 165 defer g.lock.RUnlock() 166 167 return g.progress 168 } 169 170 // splitMarker is an internal helper which splits the generation progress marker 171 // into two parts. 172 func splitMarker(marker []byte) ([]byte, []byte) { 173 var accMarker []byte 174 if len(marker) > 0 { 175 accMarker = marker[:common.HashLength] 176 } 177 return accMarker, marker 178 } 179 180 // generateSnapshot regenerates a brand-new snapshot based on an existing state 181 // database and head block asynchronously. The snapshot is returned immediately 182 // and generation is continued in the background until done. 183 func generateSnapshot(triedb *Database, root common.Hash, noBuild bool) *diskLayer { 184 // Create a new disk layer with an initialized state marker at zero 185 var ( 186 stats = &generatorStats{start: time.Now()} 187 genMarker = []byte{} // Initialized but empty! 188 ) 189 dl := newDiskLayer(root, 0, triedb, nil, nil, newBuffer(triedb.config.WriteBufferSize, nil, nil, 0), nil) 190 dl.setGenerator(newGenerator(triedb.diskdb, noBuild, genMarker, stats)) 191 192 if !noBuild { 193 dl.generator.run(root) 194 log.Info("Started snapshot generation", "root", root) 195 } 196 return dl 197 } 198 199 // journalProgress persists the generator stats into the database to resume later. 200 func journalProgress(db ethdb.KeyValueWriter, marker []byte, stats *generatorStats) { 201 // Write out the generator marker. Note it's a standalone disk layer generator 202 // which is not mixed with journal. It's ok if the generator is persisted while 203 // journal is not. 204 entry := journalGenerator{ 205 Done: marker == nil, 206 Marker: marker, 207 } 208 if stats != nil { 209 entry.Accounts = stats.accounts 210 entry.Slots = stats.slots 211 entry.Storage = uint64(stats.storage) 212 } 213 blob, err := rlp.EncodeToBytes(entry) 214 if err != nil { 215 panic(err) // Cannot happen, here to catch dev errors 216 } 217 var logstr string 218 switch { 219 case marker == nil: 220 logstr = "done" 221 case bytes.Equal(marker, []byte{}): 222 logstr = "empty" 223 case len(marker) == common.HashLength: 224 logstr = fmt.Sprintf("%#x", marker) 225 default: 226 logstr = fmt.Sprintf("%#x:%#x", marker[:common.HashLength], marker[common.HashLength:]) 227 } 228 log.Debug("Journalled generator progress", "progress", logstr) 229 rawdb.WriteSnapshotGenerator(db, blob) 230 } 231 232 // proofResult contains the output of range proving which can be used 233 // for further processing regardless if it is successful or not. 234 type proofResult struct { 235 keys [][]byte // The key set of all elements being iterated, even proving is failed 236 vals [][]byte // The val set of all elements being iterated, even proving is failed 237 diskMore bool // Set when the database has extra snapshot states since last iteration 238 trieMore bool // Set when the trie has extra snapshot states(only meaningful for successful proving) 239 proofErr error // Indicator whether the given state range is valid or not 240 tr *trie.Trie // The trie, in case the trie was resolved by the prover (may be nil) 241 } 242 243 // valid returns the indicator that range proof is successful or not. 244 func (result *proofResult) valid() bool { 245 return result.proofErr == nil 246 } 247 248 // last returns the last verified element key regardless of whether the range proof is 249 // successful or not. Nil is returned if nothing involved in the proving. 250 func (result *proofResult) last() []byte { 251 var last []byte 252 if len(result.keys) > 0 { 253 last = result.keys[len(result.keys)-1] 254 } 255 return last 256 } 257 258 // forEach iterates all the visited elements and applies the given callback on them. 259 // The iteration is aborted if the callback returns non-nil error. 260 func (result *proofResult) forEach(callback func(key []byte, val []byte) error) error { 261 for i := 0; i < len(result.keys); i++ { 262 key, val := result.keys[i], result.vals[i] 263 if err := callback(key, val); err != nil { 264 return err 265 } 266 } 267 return nil 268 } 269 270 // proveRange proves the snapshot segment with particular prefix is "valid". 271 // The iteration start point will be assigned if the iterator is restored from 272 // the last interruption. Max will be assigned in order to limit the maximum 273 // amount of data involved in each iteration. 274 // 275 // The proof result will be returned if the range proving is finished, otherwise 276 // the error will be returned to abort the entire procedure. 277 func (g *generator) proveRange(ctx *generatorContext, trieId *trie.ID, prefix []byte, kind string, origin []byte, max int, valueConvertFn func([]byte) ([]byte, error)) (*proofResult, error) { 278 var ( 279 keys [][]byte 280 vals [][]byte 281 proof = rawdb.NewMemoryDatabase() 282 diskMore = false 283 iter = ctx.iterator(kind) 284 start = time.Now() 285 min = append(prefix, origin...) 286 ) 287 for iter.Next() { 288 // Ensure the iterated item is always equal or larger than the given origin. 289 key := iter.Key() 290 if bytes.Compare(key, min) < 0 { 291 return nil, errors.New("invalid iteration position") 292 } 293 // Ensure the iterated item still fall in the specified prefix. If 294 // not which means the items in the specified area are all visited. 295 // Move the iterator a step back since we iterate one extra element 296 // out. 297 if !bytes.Equal(key[:len(prefix)], prefix) { 298 iter.Hold() 299 break 300 } 301 // Break if we've reached the max size, and signal that we're not 302 // done yet. Move the iterator a step back since we iterate one 303 // extra element out. 304 if len(keys) == max { 305 iter.Hold() 306 diskMore = true 307 break 308 } 309 keys = append(keys, common.CopyBytes(key[len(prefix):])) 310 311 if valueConvertFn == nil { 312 vals = append(vals, common.CopyBytes(iter.Value())) 313 } else { 314 val, err := valueConvertFn(iter.Value()) 315 if err != nil { 316 // Special case, the state data is corrupted (invalid slim-format account), 317 // don't abort the entire procedure directly. Instead, let the fallback 318 // generation to heal the invalid data. 319 // 320 // Here append the original value to ensure that the number of key and 321 // value are aligned. 322 vals = append(vals, common.CopyBytes(iter.Value())) 323 log.Error("Failed to convert account state data", "err", err) 324 } else { 325 vals = append(vals, val) 326 } 327 } 328 } 329 // Update metrics for database iteration and merkle proving 330 if kind == snapStorage { 331 storageSnapReadCounter.Inc(time.Since(start).Nanoseconds()) 332 } else { 333 accountSnapReadCounter.Inc(time.Since(start).Nanoseconds()) 334 } 335 defer func(start time.Time) { 336 if kind == snapStorage { 337 storageProveCounter.Inc(time.Since(start).Nanoseconds()) 338 } else { 339 accountProveCounter.Inc(time.Since(start).Nanoseconds()) 340 } 341 }(time.Now()) 342 343 // The snap state is exhausted, pass the entire key/val set for verification 344 root := trieId.Root 345 if origin == nil && !diskMore { 346 stackTr := trie.NewStackTrie(nil) 347 for i, key := range keys { 348 if err := stackTr.Update(key, vals[i]); err != nil { 349 return nil, err 350 } 351 } 352 if gotRoot := stackTr.Hash(); gotRoot != root { 353 return &proofResult{ 354 keys: keys, 355 vals: vals, 356 proofErr: fmt.Errorf("wrong root: have %#x want %#x", gotRoot, root), 357 }, nil 358 } 359 return &proofResult{keys: keys, vals: vals}, nil 360 } 361 // Snap state is chunked, generate edge proofs for verification. 362 tr, err := trie.New(trieId, &diskStore{db: g.db}) 363 if err != nil { 364 log.Info("Trie missing, snapshotting paused", "state", ctx.root, "kind", kind, "root", trieId.Root) 365 return nil, errMissingTrie 366 } 367 // Generate the Merkle proofs for the first and last element 368 if origin == nil { 369 origin = common.Hash{}.Bytes() 370 } 371 if err := tr.Prove(origin, proof); err != nil { 372 log.Debug("Failed to prove range", "kind", kind, "origin", origin, "err", err) 373 return &proofResult{ 374 keys: keys, 375 vals: vals, 376 diskMore: diskMore, 377 proofErr: err, 378 tr: tr, 379 }, nil 380 } 381 if len(keys) > 0 { 382 if err := tr.Prove(keys[len(keys)-1], proof); err != nil { 383 log.Debug("Failed to prove range", "kind", kind, "last", keys[len(keys)-1], "err", err) 384 return &proofResult{ 385 keys: keys, 386 vals: vals, 387 diskMore: diskMore, 388 proofErr: err, 389 tr: tr, 390 }, nil 391 } 392 } 393 // Verify the snapshot segment with range prover, ensure that all flat states 394 // in this range correspond to merkle trie. 395 cont, err := trie.VerifyRangeProof(root, origin, keys, vals, proof) 396 return &proofResult{ 397 keys: keys, 398 vals: vals, 399 diskMore: diskMore, 400 trieMore: cont, 401 proofErr: err, 402 tr: tr}, 403 nil 404 } 405 406 // onStateCallback is a function that is called by generateRange, when processing a range of 407 // accounts or storage slots. For each element, the callback is invoked. 408 // 409 // - If 'delete' is true, then this element (and potential slots) needs to be deleted from the snapshot. 410 // - If 'write' is true, then this element needs to be updated with the 'val'. 411 // - If 'write' is false, then this element is already correct, and needs no update. 412 // The 'val' is the canonical encoding of the value (not the slim format for accounts) 413 // 414 // However, for accounts, the storage trie of the account needs to be checked. Also, 415 // dangling storages(storage exists but the corresponding account is missing) need to 416 // be cleaned up. 417 type onStateCallback func(key []byte, val []byte, write bool, delete bool) error 418 419 // generateRange generates the state segment with particular prefix. Generation can 420 // either verify the correctness of existing state through range-proof and skip 421 // generation, or iterate trie to regenerate state on demand. 422 func (g *generator) generateRange(ctx *generatorContext, trieId *trie.ID, prefix []byte, kind string, origin []byte, max int, onState onStateCallback, valueConvertFn func([]byte) ([]byte, error)) (bool, []byte, error) { 423 // Use range prover to check the validity of the flat state in the range 424 result, err := g.proveRange(ctx, trieId, prefix, kind, origin, max, valueConvertFn) 425 if err != nil { 426 return false, nil, err 427 } 428 last := result.last() 429 430 // Construct contextual logger 431 logCtx := []interface{}{"kind", kind, "prefix", hexutil.Encode(prefix)} 432 if len(origin) > 0 { 433 logCtx = append(logCtx, "origin", hexutil.Encode(origin)) 434 } 435 logger := log.New(logCtx...) 436 437 // The range prover says the range is correct, skip trie iteration 438 if result.valid() { 439 successfulRangeProofMeter.Mark(1) 440 logger.Trace("Proved state range", "last", hexutil.Encode(last)) 441 442 // The verification is passed, process each state with the given 443 // callback function. If this state represents a contract, the 444 // corresponding storage check will be performed in the callback 445 if err := result.forEach(func(key []byte, val []byte) error { return onState(key, val, false, false) }); err != nil { 446 return false, nil, err 447 } 448 // Only abort the iteration when both database and trie are exhausted 449 return !result.diskMore && !result.trieMore, last, nil 450 } 451 logger.Trace("Detected outdated state range", "last", hexutil.Encode(last), "err", result.proofErr) 452 failedRangeProofMeter.Mark(1) 453 454 // Special case, the entire trie is missing. In the original trie scheme, 455 // all the duplicated subtries will be filtered out (only one copy of data 456 // will be stored). While in the snapshot model, all the storage tries 457 // belong to different contracts will be kept even they are duplicated. 458 // Track it to a certain extent remove the noise data used for statistics. 459 if origin == nil && last == nil { 460 meter := missallAccountMeter 461 if kind == snapStorage { 462 meter = missallStorageMeter 463 } 464 meter.Mark(1) 465 } 466 // We use the snap data to build up a cache which can be used by the 467 // main account trie as a primary lookup when resolving hashes 468 var resolver trie.NodeResolver 469 if len(result.keys) > 0 { 470 tr := trie.NewEmpty(nil) 471 for i, key := range result.keys { 472 tr.Update(key, result.vals[i]) 473 } 474 _, nodes := tr.Commit(false) 475 hashSet := nodes.HashSet() 476 resolver = func(owner common.Hash, path []byte, hash common.Hash) []byte { 477 return hashSet[hash] 478 } 479 } 480 // Construct the trie for state iteration, reuse the trie 481 // if it's already opened with some nodes resolved. 482 tr := result.tr 483 if tr == nil { 484 tr, err = trie.New(trieId, &diskStore{db: g.db}) 485 if err != nil { 486 log.Info("Trie missing, snapshotting paused", "state", ctx.root, "kind", kind, "root", trieId.Root) 487 return false, nil, errMissingTrie 488 } 489 } 490 var ( 491 trieMore bool 492 kvkeys, kvvals = result.keys, result.vals 493 494 // counters 495 count = 0 // number of states delivered by iterator 496 created = 0 // states created from the trie 497 updated = 0 // states updated from the trie 498 deleted = 0 // states not in trie, but were in snapshot 499 untouched = 0 // states already correct 500 501 // timers 502 start = time.Now() 503 internal time.Duration 504 ) 505 nodeIt, err := tr.NodeIterator(origin) 506 if err != nil { 507 return false, nil, err 508 } 509 nodeIt.AddResolver(resolver) 510 iter := trie.NewIterator(nodeIt) 511 512 for iter.Next() { 513 if last != nil && bytes.Compare(iter.Key, last) > 0 { 514 trieMore = true 515 break 516 } 517 count++ 518 write := true 519 created++ 520 for len(kvkeys) > 0 { 521 if cmp := bytes.Compare(kvkeys[0], iter.Key); cmp < 0 { 522 // delete the key 523 istart := time.Now() 524 if err := onState(kvkeys[0], nil, false, true); err != nil { 525 return false, nil, err 526 } 527 kvkeys = kvkeys[1:] 528 kvvals = kvvals[1:] 529 deleted++ 530 internal += time.Since(istart) 531 continue 532 } else if cmp == 0 { 533 // the snapshot key can be overwritten 534 created-- 535 if write = !bytes.Equal(kvvals[0], iter.Value); write { 536 updated++ 537 } else { 538 untouched++ 539 } 540 kvkeys = kvkeys[1:] 541 kvvals = kvvals[1:] 542 } 543 break 544 } 545 istart := time.Now() 546 if err := onState(iter.Key, iter.Value, write, false); err != nil { 547 return false, nil, err 548 } 549 internal += time.Since(istart) 550 } 551 if iter.Err != nil { 552 // Trie errors should never happen. Still, in case of a bug, expose the 553 // error here, as the outer code will presume errors are interrupts, not 554 // some deeper issues. 555 log.Error("State snapshotter failed to iterate trie", "err", iter.Err) 556 return false, nil, iter.Err 557 } 558 // Delete all stale snapshot states remaining 559 istart := time.Now() 560 for _, key := range kvkeys { 561 if err := onState(key, nil, false, true); err != nil { 562 return false, nil, err 563 } 564 deleted += 1 565 } 566 internal += time.Since(istart) 567 568 // Update metrics for counting trie iteration 569 if kind == snapStorage { 570 storageTrieReadCounter.Inc((time.Since(start) - internal).Nanoseconds()) 571 } else { 572 accountTrieReadCounter.Inc((time.Since(start) - internal).Nanoseconds()) 573 } 574 logger.Trace("Regenerated state range", "root", trieId.Root, "last", hexutil.Encode(last), 575 "count", count, "created", created, "updated", updated, "untouched", untouched, "deleted", deleted) 576 577 // If there are either more trie items, or there are more snap items 578 // (in the next segment), then we need to keep working 579 return !trieMore && !result.diskMore, last, nil 580 } 581 582 // checkAndFlush checks if an interruption signal is received or the 583 // batch size has exceeded the allowance. 584 func (g *generator) checkAndFlush(ctx *generatorContext, current []byte) error { 585 var abort chan struct{} 586 select { 587 case abort = <-g.abort: 588 default: 589 } 590 if ctx.batch.ValueSize() > ethdb.IdealBatchSize || abort != nil { 591 if bytes.Compare(current, g.progress) < 0 { 592 log.Error("Snapshot generator went backwards", "current", fmt.Sprintf("%x", current), "genMarker", fmt.Sprintf("%x", g.progress)) 593 } 594 // Persist the progress marker regardless of whether the batch is empty or not. 595 // It may happen that all the flat states in the database are correct, so the 596 // generator indeed makes progress even if there is nothing to commit. 597 journalProgress(ctx.batch, current, g.stats) 598 599 // Flush out the database writes atomically 600 if err := ctx.batch.Write(); err != nil { 601 return err 602 } 603 ctx.batch.Reset() 604 605 // Update the generation progress marker 606 g.lock.Lock() 607 g.progress = current 608 g.lock.Unlock() 609 610 // Abort the generation if it's required 611 if abort != nil { 612 g.stats.log("Aborting snapshot generation", ctx.root, g.progress) 613 return newAbortErr(abort) // bubble up an error for interruption 614 } 615 // Don't hold the iterators too long, release them to let compactor works 616 ctx.reopenIterator(snapAccount) 617 ctx.reopenIterator(snapStorage) 618 } 619 if time.Since(ctx.logged) > 8*time.Second { 620 g.stats.log("Generating snapshot", ctx.root, g.progress) 621 ctx.logged = time.Now() 622 } 623 return nil 624 } 625 626 // generateStorages generates the missing storage slots of the specific contract. 627 // It's supposed to restart the generation from the given origin position. 628 func (g *generator) generateStorages(ctx *generatorContext, account common.Hash, storageRoot common.Hash, storeMarker []byte) error { 629 onStorage := func(key []byte, val []byte, write bool, delete bool) error { 630 defer func(start time.Time) { 631 storageWriteCounter.Inc(time.Since(start).Nanoseconds()) 632 }(time.Now()) 633 634 if delete { 635 rawdb.DeleteStorageSnapshot(ctx.batch, account, common.BytesToHash(key)) 636 wipedStorageMeter.Mark(1) 637 return nil 638 } 639 if write { 640 rawdb.WriteStorageSnapshot(ctx.batch, account, common.BytesToHash(key), val) 641 generatedStorageMeter.Mark(1) 642 } else { 643 recoveredStorageMeter.Mark(1) 644 } 645 g.stats.storage += common.StorageSize(1 + 2*common.HashLength + len(val)) 646 g.stats.slots++ 647 648 // If we've exceeded our batch allowance or termination was requested, flush to disk 649 if err := g.checkAndFlush(ctx, append(account[:], key...)); err != nil { 650 return err 651 } 652 return nil 653 } 654 // Loop for re-generating the missing storage slots. 655 var origin = common.CopyBytes(storeMarker) 656 for { 657 id := trie.StorageTrieID(ctx.root, account, storageRoot) 658 exhausted, last, err := g.generateRange(ctx, id, append(rawdb.SnapshotStoragePrefix, account.Bytes()...), snapStorage, origin, storageCheckRange, onStorage, nil) 659 if err != nil { 660 return err // The procedure it aborted, either by external signal or internal error. 661 } 662 // Abort the procedure if the entire contract storage is generated 663 if exhausted { 664 break 665 } 666 if origin = increaseKey(last); origin == nil { 667 break // special case, the last is 0xffffffff...fff 668 } 669 } 670 return nil 671 } 672 673 // generateAccounts generates the missing snapshot accounts as well as their 674 // storage slots in the main trie. It's supposed to restart the generation 675 // from the given origin position. 676 func (g *generator) generateAccounts(ctx *generatorContext, accMarker []byte) error { 677 onAccount := func(key []byte, val []byte, write bool, delete bool) error { 678 // Make sure to clear all dangling storages before this account 679 account := common.BytesToHash(key) 680 g.stats.dangling += ctx.removeStorageBefore(account) 681 682 start := time.Now() 683 if delete { 684 rawdb.DeleteAccountSnapshot(ctx.batch, account) 685 wipedAccountMeter.Mark(1) 686 accountWriteCounter.Inc(time.Since(start).Nanoseconds()) 687 688 ctx.removeStorageAt(account) 689 return nil 690 } 691 // Retrieve the current account and flatten it into the internal format 692 var acc types.StateAccount 693 if err := rlp.DecodeBytes(val, &acc); err != nil { 694 log.Crit("Invalid account encountered during snapshot creation", "err", err) 695 } 696 // If the account is not yet in-progress, write it out 697 if accMarker == nil || !bytes.Equal(account[:], accMarker) { 698 dataLen := len(val) // Approximate size, saves us a round of RLP-encoding 699 if !write { 700 if bytes.Equal(acc.CodeHash, types.EmptyCodeHash[:]) { 701 dataLen -= 32 702 } 703 if acc.Root == types.EmptyRootHash { 704 dataLen -= 32 705 } 706 recoveredAccountMeter.Mark(1) 707 } else { 708 data := types.SlimAccountRLP(acc) 709 dataLen = len(data) 710 rawdb.WriteAccountSnapshot(ctx.batch, account, data) 711 generatedAccountMeter.Mark(1) 712 } 713 g.stats.storage += common.StorageSize(1 + common.HashLength + dataLen) 714 g.stats.accounts++ 715 } 716 // If the snap generation goes here after interrupted, genMarker may go backward 717 // when last genMarker is consisted of accountHash and storageHash 718 marker := account[:] 719 if accMarker != nil && bytes.Equal(marker, accMarker) && len(g.progress) > common.HashLength { 720 marker = g.progress 721 } 722 // If we've exceeded our batch allowance or termination was requested, flush to disk 723 if err := g.checkAndFlush(ctx, marker); err != nil { 724 return err 725 } 726 accountWriteCounter.Inc(time.Since(start).Nanoseconds()) // let's count flush time as well 727 728 // If the iterated account is the contract, create a further loop to 729 // verify or regenerate the contract storage. 730 if acc.Root == types.EmptyRootHash { 731 ctx.removeStorageAt(account) 732 } else { 733 var storeMarker []byte 734 if accMarker != nil && bytes.Equal(account[:], accMarker) && len(g.progress) > common.HashLength { 735 storeMarker = g.progress[common.HashLength:] 736 } 737 if err := g.generateStorages(ctx, account, acc.Root, storeMarker); err != nil { 738 return err 739 } 740 } 741 // Some account processed, unmark the marker 742 accMarker = nil 743 return nil 744 } 745 origin := common.CopyBytes(accMarker) 746 for { 747 id := trie.StateTrieID(ctx.root) 748 exhausted, last, err := g.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountCheckRange, onAccount, types.FullAccountRLP) 749 if err != nil { 750 return err // The procedure it aborted, either by external signal or internal error. 751 } 752 origin = increaseKey(last) 753 754 // Last step, cleanup the storages after the last account. 755 // All the left storages should be treated as dangling. 756 if origin == nil || exhausted { 757 g.stats.dangling += ctx.removeRemainingStorage() 758 break 759 } 760 } 761 return nil 762 } 763 764 // generate is a background thread that iterates over the state and storage tries, 765 // constructing the state snapshot. All the arguments are purely for statistics 766 // gathering and logging, since the method surfs the blocks as they arrive, often 767 // being restarted. 768 func (g *generator) generate(ctx *generatorContext) { 769 g.stats.log("Resuming snapshot generation", ctx.root, g.progress) 770 defer ctx.close() 771 772 // Persist the initial marker and state snapshot root if progress is none 773 if len(g.progress) == 0 { 774 batch := g.db.NewBatch() 775 rawdb.WriteSnapshotRoot(batch, ctx.root) 776 journalProgress(batch, g.progress, g.stats) 777 if err := batch.Write(); err != nil { 778 log.Crit("Failed to write initialized state marker", "err", err) 779 } 780 } 781 // Initialize the global generator context. The snapshot iterators are 782 // opened at the interrupted position because the assumption is held 783 // that all the snapshot data are generated correctly before the marker. 784 // Even if the snapshot data is updated during the interruption (before 785 // or at the marker), the assumption is still held. 786 // For the account or storage slot at the interruption, they will be 787 // processed twice by the generator(they are already processed in the 788 // last run) but it's fine. 789 var ( 790 accMarker, _ = splitMarker(g.progress) 791 abort chan struct{} 792 ) 793 if err := g.generateAccounts(ctx, accMarker); err != nil { 794 // Extract the received interruption signal if exists 795 var aerr *abortErr 796 if errors.As(err, &aerr) { 797 abort = aerr.abort 798 } 799 // Aborted by internal error, wait the signal 800 if abort == nil { 801 abort = <-g.abort 802 } 803 close(abort) 804 return 805 } 806 // Snapshot fully generated, set the marker to nil. 807 // Note even there is nothing to commit, persist the 808 // generator anyway to mark the snapshot is complete. 809 journalProgress(ctx.batch, nil, g.stats) 810 if err := ctx.batch.Write(); err != nil { 811 log.Error("Failed to flush batch", "err", err) 812 abort = <-g.abort 813 close(abort) 814 return 815 } 816 ctx.batch.Reset() 817 818 log.Info("Generated snapshot", "accounts", g.stats.accounts, "slots", g.stats.slots, 819 "storage", g.stats.storage, "dangling", g.stats.dangling, "elapsed", common.PrettyDuration(time.Since(g.stats.start))) 820 821 // Update the generation progress marker 822 g.lock.Lock() 823 g.progress = nil 824 g.lock.Unlock() 825 close(g.done) 826 827 // Someone will be looking for us, wait it out 828 abort = <-g.abort 829 close(abort) 830 } 831 832 // increaseKey increase the input key by one bit. Return nil if the entire 833 // addition operation overflows. 834 func increaseKey(key []byte) []byte { 835 for i := len(key) - 1; i >= 0; i-- { 836 key[i]++ 837 if key[i] != 0x0 { 838 return key 839 } 840 } 841 return nil 842 } 843 844 // abortErr wraps an interruption signal received to represent the 845 // generation is aborted by external processes. 846 type abortErr struct { 847 abort chan struct{} 848 } 849 850 func newAbortErr(abort chan struct{}) error { 851 return &abortErr{abort: abort} 852 } 853 854 func (err *abortErr) Error() string { 855 return "aborted" 856 }