mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
Squash the main verkle PR ahead of rebase don't call Bytes() in GetTreeKey (#137) trie: avoid endianness conversion in GetTreeKey (#140) * trie/utils: add concrete expected value in trie key generation test Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * mod: update to latest go-verkle Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * trie/utils: avoid endianness conversions Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * apply review changes & update to official go-verkle version Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> upgrade go-verkle to CoW version and get TestProcessVerkle to build (#138) updating ci to use self-hosted machine (#143) fix: storage offset in non-header group + reuse of value buffer (#145) dedup call to ChunkifyCode, same as replay branch (#156) * dedup call to ChunkifyCode, same as replay branch * fix some linter issues fix code offset in tree update (#157) fix REVERT in state processor test execution (#158) * fix code offset in tree update * fix REVERT in test execution save on key hashing: lump code size update with first code chunk group (#159) fix code chunk key calculation and storage key calculation (#161) * fix codeKey calculation * Remove * fix storageOffset * fix the fix to the fix to the offset fix * Remove copy/pasted, unused code in test * fix linter --------- Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> fix: infinite loop when calling extcodecopy on empty code (#151) upgrade to latest go-verkle fix: only update code in the tree if it's dirty (#174) fix: read-touch the code size and Keccak of the origin (#175) List of changes for converting a sepolia database (#182) * naive conversion rebased on top of beverly hills * changes for the sepolia shadow fork conversion * fixes to please the linter * fixes to please the linter Unified point cache (#180) * Unified point cache * Use cache for Try*Account * alter Trie interface to use caching for slots (#181) * alter Trie interface to use caching for slots * fix: use a lock to protect the point cache (#185) * use fastest non-master go-verkle version & pull trie/Verkle.go changes to use new api (#184) * mod: update to fastest go-verkle version today Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * trie/verkle: use new batch serialization api Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> * fix: TryDelete signature in unit tests --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> trie/utils: fix potential overflow (#191) * trie/utils: fix potential overflow Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * trie/utils: receive storage key as a byte slice Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * revert formatter changes Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * trie/utils: fix mod 256 Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> trie/utils: fix incorrect bigint assignment (#193) Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> upgrade precomp link to fix CI fix: add missing code size&keccak leaves in empty accounts (#192) fixes to use the latest go-verkle@master (#197) * fixes to use the latest go-verkle@master * linter fixes * linter fixes for tests * fix: use jsign's go-verkle fix refactor: remove unused (*StateDB).GetXLittleEndian methods (#204) fix gas accounting issue in state_processor_test.go (#207) update go-verkle not to use StatelessNode anymore (#206) * update go-verkle not to use StatelessNode anymore * update go-verkle to latest refactor: move verkle gas accounting to its own block in TransitionDB (#208) fix a panic in deserializeVerkleProof if GetProofItems returns a nil ProofElements use the cachingDB instead of a custom VerkleDB (#209) * use the cachingDB instead of a custom VerkleDB * fix stack trace in LES remove holiman from CODEOWNERS as he gets too many emails read from tree in state object if the snapshot is nil (#205) add missing error checks for the root node type (#214) implement OpenStorageTrie for verkle trees (#210) * implement OpenStorageTrie for verkle trees * add a few comments for future maintenance * fix linter issue fix: copy balance leaf to new buffer in TryGetAccount (#217) implement some heretofore unimplemented iterator methods (#219) params: move verkle params to their own file (#228) fix: proper number of chunk evals (#215) overlay transition (#244) * overlay transition Fix some bugs identified in the code review Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> Include base -> overlay key-values migration logic (#199) * mod: add go-verkle version with key-value migration new apis Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * core/stateprocessor: use constant for max number of migrated key-values Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * core: add base->overlay key-values migration logic Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * core: fix some compiler errors Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * trie: consider removing transition trie api in the future Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * mod: use latest go-verkle Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> fix some unit tests errors get convresion block from file fix compilation issues fix initialization issue in migrator fix: changes needed to run the first 28 blocks important sutff: fix the banner fix: use nonce instead of balance in nonce leaf (#202) fixes for performing the overlay transition (#203) * fixes for performing the overlay transition * fixes for the full replay * fix: deletion-and-recreation of EoA * fixes to replay 2M+ blocks * upgrade to go-verkle@master * fix: proper number of chunk evals * rewrite conversion loop to fix known issues changes to make replay work with the overlay method (#216) * fixes for performing the overlay transition fixes for the full replay fix: deletion-and-recreation of EoA fixes to replay 2M+ blocks upgrade to go-verkle@master fix: proper number of chunk evals rewrite conversion loop to fix known issues changes to make replay work with the overlay method fixes to replay 2M+ blocks update to latest go-verkle@master * use a PBSS-like scheme for internal nodes (#221) * use a PBSS-like scheme for internal nodes * a couple of fixes coming from debugging replay * fix: use an error to notify the transition tree that a deleted account was found in the overlay tree (#222) * fixes for pbss replay (#227) * fixes for pbss replay * trie/verkle: use capped batch size (#229) * trie/verkle: use capped batch size Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * trie/verkle: avoid path variable allocation per db.Put Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * don't keep more than 32 state root conversions in RAM (#230) --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> * cleanup some code * mod: update go-verkle Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * re-enable snapshot (#231) * re-enable cancun block / snapshot (#226) * clear storage conversion key upon translating account (#234) * clear storage conversion key upon translating account * mod: use latest go-verkle Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> * fix: self-deadlock with translated root map mutex (#236) * return compressed commitment as root commitment (#237) --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> fix first panic in *TransitionTrie.Copy() upgrade go-verkle to latest master mod: update go-verkle (#239) Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> core: print state root every 100 blocks (#240) Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> fix: only Commit the account trie (#242) fixes to get TestProcessVerkle to work with the overlay branch (#238) * fixes to get TestProcessVerkle to work with the overlay branch * fix all panics in verkle state processor test * fix proof verification move transition management to cachingDB * fix: mark the verkle transition as started if it's ended without being started * fix the verkle state processing test * fix linter errors * Add a function to clear verkle params for replay * fix: handle TransitionTrie in OpenStorageTrie * fix linter issue * fix the deleted account error (#247) * code cleanup (#248) * fix: don't error on a missing conversion.txt (#249) * Overlay Tree preimages exporting and usage (#246) * export overlay preimages tool Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * use preimages flat file in overlay tree migration logic Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * cmd/geth: add --roothash to overlay tree preimage exporting command Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * cleanup Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * review feedback Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * fix: reduce the PR footprint (#250) * fix: don't fail when preimages.bin is missing (#251) * fix: don't fail when preimages.bin is missing * fix: don't open the preimages file when outside of transition --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> review changes remove replay-specific code
360 lines
12 KiB
Go
360 lines
12 KiB
Go
// Copyright 2020 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package state
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/metrics"
|
|
)
|
|
|
|
var (
|
|
// triePrefetchMetricsPrefix is the prefix under which to publish the metrics.
|
|
triePrefetchMetricsPrefix = "trie/prefetch/"
|
|
)
|
|
|
|
// triePrefetcher is an active prefetcher, which receives accounts or storage
|
|
// items and does trie-loading of them. The goal is to get as much useful content
|
|
// into the caches as possible.
|
|
//
|
|
// Note, the prefetcher's API is not thread safe.
|
|
type triePrefetcher struct {
|
|
db Database // Database to fetch trie nodes through
|
|
root common.Hash // Root hash of the account trie for metrics
|
|
fetches map[string]Trie // Partially or fully fetcher tries
|
|
fetchers map[string]*subfetcher // Subfetchers for each trie
|
|
|
|
deliveryMissMeter metrics.Meter
|
|
accountLoadMeter metrics.Meter
|
|
accountDupMeter metrics.Meter
|
|
accountSkipMeter metrics.Meter
|
|
accountWasteMeter metrics.Meter
|
|
storageLoadMeter metrics.Meter
|
|
storageDupMeter metrics.Meter
|
|
storageSkipMeter metrics.Meter
|
|
storageWasteMeter metrics.Meter
|
|
}
|
|
|
|
func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePrefetcher {
|
|
prefix := triePrefetchMetricsPrefix + namespace
|
|
p := &triePrefetcher{
|
|
db: db,
|
|
root: root,
|
|
fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map
|
|
|
|
deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil),
|
|
accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil),
|
|
accountDupMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup", nil),
|
|
accountSkipMeter: metrics.GetOrRegisterMeter(prefix+"/account/skip", nil),
|
|
accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil),
|
|
storageLoadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load", nil),
|
|
storageDupMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup", nil),
|
|
storageSkipMeter: metrics.GetOrRegisterMeter(prefix+"/storage/skip", nil),
|
|
storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil),
|
|
}
|
|
return p
|
|
}
|
|
|
|
// close iterates over all the subfetchers, aborts any that were left spinning
|
|
// and reports the stats to the metrics subsystem.
|
|
func (p *triePrefetcher) close() {
|
|
for _, fetcher := range p.fetchers {
|
|
fetcher.abort() // safe to do multiple times
|
|
|
|
if metrics.Enabled {
|
|
if fetcher.root == p.root {
|
|
p.accountLoadMeter.Mark(int64(len(fetcher.seen)))
|
|
p.accountDupMeter.Mark(int64(fetcher.dups))
|
|
p.accountSkipMeter.Mark(int64(len(fetcher.tasks)))
|
|
|
|
for _, key := range fetcher.used {
|
|
delete(fetcher.seen, string(key))
|
|
}
|
|
p.accountWasteMeter.Mark(int64(len(fetcher.seen)))
|
|
} else {
|
|
p.storageLoadMeter.Mark(int64(len(fetcher.seen)))
|
|
p.storageDupMeter.Mark(int64(fetcher.dups))
|
|
p.storageSkipMeter.Mark(int64(len(fetcher.tasks)))
|
|
|
|
for _, key := range fetcher.used {
|
|
delete(fetcher.seen, string(key))
|
|
}
|
|
p.storageWasteMeter.Mark(int64(len(fetcher.seen)))
|
|
}
|
|
}
|
|
}
|
|
// Clear out all fetchers (will crash on a second call, deliberate)
|
|
p.fetchers = nil
|
|
}
|
|
|
|
// copy creates a deep-but-inactive copy of the trie prefetcher. Any trie data
|
|
// already loaded will be copied over, but no goroutines will be started. This
|
|
// is mostly used in the miner which creates a copy of it's actively mutated
|
|
// state to be sealed while it may further mutate the state.
|
|
func (p *triePrefetcher) copy() *triePrefetcher {
|
|
copy := &triePrefetcher{
|
|
db: p.db,
|
|
root: p.root,
|
|
fetches: make(map[string]Trie), // Active prefetchers use the fetches map
|
|
|
|
deliveryMissMeter: p.deliveryMissMeter,
|
|
accountLoadMeter: p.accountLoadMeter,
|
|
accountDupMeter: p.accountDupMeter,
|
|
accountSkipMeter: p.accountSkipMeter,
|
|
accountWasteMeter: p.accountWasteMeter,
|
|
storageLoadMeter: p.storageLoadMeter,
|
|
storageDupMeter: p.storageDupMeter,
|
|
storageSkipMeter: p.storageSkipMeter,
|
|
storageWasteMeter: p.storageWasteMeter,
|
|
}
|
|
// If the prefetcher is already a copy, duplicate the data
|
|
if p.fetches != nil {
|
|
for root, fetch := range p.fetches {
|
|
if fetch == nil {
|
|
continue
|
|
}
|
|
copy.fetches[root] = p.db.CopyTrie(fetch)
|
|
}
|
|
return copy
|
|
}
|
|
// Otherwise we're copying an active fetcher, retrieve the current states
|
|
for id, fetcher := range p.fetchers {
|
|
copy.fetches[id] = fetcher.peek()
|
|
}
|
|
return copy
|
|
}
|
|
|
|
// prefetch schedules a batch of trie items to prefetch.
|
|
func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) {
|
|
// If the prefetcher is an inactive one, bail out
|
|
if p.fetches != nil {
|
|
return
|
|
}
|
|
// Active fetcher, schedule the retrievals
|
|
id := p.trieID(owner, root)
|
|
fetcher := p.fetchers[id]
|
|
if fetcher == nil {
|
|
fetcher = newSubfetcher(p.db, p.root, owner, root, addr)
|
|
p.fetchers[id] = fetcher
|
|
}
|
|
fetcher.schedule(keys)
|
|
}
|
|
|
|
// trie returns the trie matching the root hash, or nil if the prefetcher doesn't
|
|
// have it.
|
|
func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie {
|
|
// If the prefetcher is inactive, return from existing deep copies
|
|
id := p.trieID(owner, root)
|
|
if p.fetches != nil {
|
|
trie := p.fetches[id]
|
|
if trie == nil {
|
|
p.deliveryMissMeter.Mark(1)
|
|
return nil
|
|
}
|
|
return p.db.CopyTrie(trie)
|
|
}
|
|
// Otherwise the prefetcher is active, bail if no trie was prefetched for this root
|
|
fetcher := p.fetchers[id]
|
|
if fetcher == nil {
|
|
p.deliveryMissMeter.Mark(1)
|
|
return nil
|
|
}
|
|
// Interrupt the prefetcher if it's by any chance still running and return
|
|
// a copy of any pre-loaded trie.
|
|
fetcher.abort() // safe to do multiple times
|
|
|
|
trie := fetcher.peek()
|
|
if trie == nil {
|
|
p.deliveryMissMeter.Mark(1)
|
|
return nil
|
|
}
|
|
return trie
|
|
}
|
|
|
|
// used marks a batch of state items used to allow creating statistics as to
|
|
// how useful or wasteful the prefetcher is.
|
|
func (p *triePrefetcher) used(owner common.Hash, root common.Hash, used [][]byte) {
|
|
if fetcher := p.fetchers[p.trieID(owner, root)]; fetcher != nil {
|
|
fetcher.used = used
|
|
}
|
|
}
|
|
|
|
// trieID returns an unique trie identifier consists the trie owner and root hash.
|
|
func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string {
|
|
return string(append(owner.Bytes(), root.Bytes()...))
|
|
}
|
|
|
|
// subfetcher is a trie fetcher goroutine responsible for pulling entries for a
|
|
// single trie. It is spawned when a new root is encountered and lives until the
|
|
// main prefetcher is paused and either all requested items are processed or if
|
|
// the trie being worked on is retrieved from the prefetcher.
|
|
type subfetcher struct {
|
|
db Database // Database to load trie nodes through
|
|
state common.Hash // Root hash of the state to prefetch
|
|
owner common.Hash // Owner of the trie, usually account hash
|
|
root common.Hash // Root hash of the trie to prefetch
|
|
addr common.Address // Address of the account that the trie belongs to
|
|
trie Trie // Trie being populated with nodes
|
|
|
|
tasks [][]byte // Items queued up for retrieval
|
|
lock sync.Mutex // Lock protecting the task queue
|
|
|
|
wake chan struct{} // Wake channel if a new task is scheduled
|
|
stop chan struct{} // Channel to interrupt processing
|
|
term chan struct{} // Channel to signal interruption
|
|
copy chan chan Trie // Channel to request a copy of the current trie
|
|
|
|
seen map[string]struct{} // Tracks the entries already loaded
|
|
dups int // Number of duplicate preload tasks
|
|
used [][]byte // Tracks the entries used in the end
|
|
}
|
|
|
|
// newSubfetcher creates a goroutine to prefetch state items belonging to a
|
|
// particular root hash.
|
|
func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher {
|
|
sf := &subfetcher{
|
|
db: db,
|
|
state: state,
|
|
owner: owner,
|
|
root: root,
|
|
addr: addr,
|
|
wake: make(chan struct{}, 1),
|
|
stop: make(chan struct{}),
|
|
term: make(chan struct{}),
|
|
copy: make(chan chan Trie),
|
|
seen: make(map[string]struct{}),
|
|
}
|
|
go sf.loop()
|
|
return sf
|
|
}
|
|
|
|
// schedule adds a batch of trie keys to the queue to prefetch.
|
|
func (sf *subfetcher) schedule(keys [][]byte) {
|
|
// Append the tasks to the current queue
|
|
sf.lock.Lock()
|
|
sf.tasks = append(sf.tasks, keys...)
|
|
sf.lock.Unlock()
|
|
|
|
// Notify the prefetcher, it's fine if it's already terminated
|
|
select {
|
|
case sf.wake <- struct{}{}:
|
|
default:
|
|
}
|
|
}
|
|
|
|
// peek tries to retrieve a deep copy of the fetcher's trie in whatever form it
|
|
// is currently.
|
|
func (sf *subfetcher) peek() Trie {
|
|
ch := make(chan Trie)
|
|
select {
|
|
case sf.copy <- ch:
|
|
// Subfetcher still alive, return copy from it
|
|
return <-ch
|
|
|
|
case <-sf.term:
|
|
// Subfetcher already terminated, return a copy directly
|
|
if sf.trie == nil {
|
|
return nil
|
|
}
|
|
return sf.db.CopyTrie(sf.trie)
|
|
}
|
|
}
|
|
|
|
// abort interrupts the subfetcher immediately. It is safe to call abort multiple
|
|
// times but it is not thread safe.
|
|
func (sf *subfetcher) abort() {
|
|
select {
|
|
case <-sf.stop:
|
|
default:
|
|
close(sf.stop)
|
|
}
|
|
<-sf.term
|
|
}
|
|
|
|
// loop waits for new tasks to be scheduled and keeps loading them until it runs
|
|
// out of tasks or its underlying trie is retrieved for committing.
|
|
func (sf *subfetcher) loop() {
|
|
// No matter how the loop stops, signal anyone waiting that it's terminated
|
|
defer close(sf.term)
|
|
|
|
// Start by opening the trie and stop processing if it fails
|
|
if sf.owner == (common.Hash{}) {
|
|
trie, err := sf.db.OpenTrie(sf.root)
|
|
if err != nil {
|
|
log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err)
|
|
return
|
|
}
|
|
sf.trie = trie
|
|
} else {
|
|
trie, err := sf.db.OpenStorageTrie(sf.state, sf.addr, sf.root, nil /* safe to set to nil for now, as there is no prefetcher for verkle */)
|
|
if err != nil {
|
|
log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err)
|
|
return
|
|
}
|
|
sf.trie = trie
|
|
}
|
|
// Trie opened successfully, keep prefetching items
|
|
for {
|
|
select {
|
|
case <-sf.wake:
|
|
// Subfetcher was woken up, retrieve any tasks to avoid spinning the lock
|
|
sf.lock.Lock()
|
|
tasks := sf.tasks
|
|
sf.tasks = nil
|
|
sf.lock.Unlock()
|
|
|
|
// Prefetch any tasks until the loop is interrupted
|
|
for i, task := range tasks {
|
|
select {
|
|
case <-sf.stop:
|
|
// If termination is requested, add any leftover back and return
|
|
sf.lock.Lock()
|
|
sf.tasks = append(sf.tasks, tasks[i:]...)
|
|
sf.lock.Unlock()
|
|
return
|
|
|
|
case ch := <-sf.copy:
|
|
// Somebody wants a copy of the current trie, grant them
|
|
ch <- sf.db.CopyTrie(sf.trie)
|
|
|
|
default:
|
|
// No termination request yet, prefetch the next entry
|
|
if _, ok := sf.seen[string(task)]; ok {
|
|
sf.dups++
|
|
} else {
|
|
if len(task) == common.AddressLength {
|
|
sf.trie.GetAccount(common.BytesToAddress(task))
|
|
} else {
|
|
sf.trie.GetStorage(sf.addr, task)
|
|
}
|
|
sf.seen[string(task)] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
|
|
case ch := <-sf.copy:
|
|
// Somebody wants a copy of the current trie, grant them
|
|
ch <- sf.db.CopyTrie(sf.trie)
|
|
|
|
case <-sf.stop:
|
|
// Termination is requested, abort and leave remaining tasks
|
|
return
|
|
}
|
|
}
|
|
}
|