github.com/calmw/ethereum@v0.1.1/eth/protocols/snap/sync.go (about)

     1  // Copyright 2020 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 snap
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	gomath "math"
    25  	"math/big"
    26  	"math/rand"
    27  	"sort"
    28  	"sync"
    29  	"sync/atomic"
    30  	"time"
    31  
    32  	"github.com/calmw/ethereum/common"
    33  	"github.com/calmw/ethereum/common/math"
    34  	"github.com/calmw/ethereum/core/rawdb"
    35  	"github.com/calmw/ethereum/core/state"
    36  	"github.com/calmw/ethereum/core/state/snapshot"
    37  	"github.com/calmw/ethereum/core/types"
    38  	"github.com/calmw/ethereum/crypto"
    39  	"github.com/calmw/ethereum/ethdb"
    40  	"github.com/calmw/ethereum/event"
    41  	"github.com/calmw/ethereum/light"
    42  	"github.com/calmw/ethereum/log"
    43  	"github.com/calmw/ethereum/p2p/msgrate"
    44  	"github.com/calmw/ethereum/rlp"
    45  	"github.com/calmw/ethereum/trie"
    46  	"golang.org/x/crypto/sha3"
    47  )
    48  
    49  const (
    50  	// minRequestSize is the minimum number of bytes to request from a remote peer.
    51  	// This number is used as the low cap for account and storage range requests.
    52  	// Bytecode and trienode are limited inherently by item count (1).
    53  	minRequestSize = 64 * 1024
    54  
    55  	// maxRequestSize is the maximum number of bytes to request from a remote peer.
    56  	// This number is used as the high cap for account and storage range requests.
    57  	// Bytecode and trienode are limited more explicitly by the caps below.
    58  	maxRequestSize = 512 * 1024
    59  
    60  	// maxCodeRequestCount is the maximum number of bytecode blobs to request in a
    61  	// single query. If this number is too low, we're not filling responses fully
    62  	// and waste round trip times. If it's too high, we're capping responses and
    63  	// waste bandwidth.
    64  	//
    65  	// Deployed bytecodes are currently capped at 24KB, so the minimum request
    66  	// size should be maxRequestSize / 24K. Assuming that most contracts do not
    67  	// come close to that, requesting 4x should be a good approximation.
    68  	maxCodeRequestCount = maxRequestSize / (24 * 1024) * 4
    69  
    70  	// maxTrieRequestCount is the maximum number of trie node blobs to request in
    71  	// a single query. If this number is too low, we're not filling responses fully
    72  	// and waste round trip times. If it's too high, we're capping responses and
    73  	// waste bandwidth.
    74  	maxTrieRequestCount = maxRequestSize / 512
    75  
    76  	// trienodeHealRateMeasurementImpact is the impact a single measurement has on
    77  	// the local node's trienode processing capacity. A value closer to 0 reacts
    78  	// slower to sudden changes, but it is also more stable against temporary hiccups.
    79  	trienodeHealRateMeasurementImpact = 0.005
    80  
    81  	// minTrienodeHealThrottle is the minimum divisor for throttling trie node
    82  	// heal requests to avoid overloading the local node and excessively expanding
    83  	// the state trie breadth wise.
    84  	minTrienodeHealThrottle = 1
    85  
    86  	// maxTrienodeHealThrottle is the maximum divisor for throttling trie node
    87  	// heal requests to avoid overloading the local node and exessively expanding
    88  	// the state trie bedth wise.
    89  	maxTrienodeHealThrottle = maxTrieRequestCount
    90  
    91  	// trienodeHealThrottleIncrease is the multiplier for the throttle when the
    92  	// rate of arriving data is higher than the rate of processing it.
    93  	trienodeHealThrottleIncrease = 1.33
    94  
    95  	// trienodeHealThrottleDecrease is the divisor for the throttle when the
    96  	// rate of arriving data is lower than the rate of processing it.
    97  	trienodeHealThrottleDecrease = 1.25
    98  )
    99  
   100  var (
   101  	// accountConcurrency is the number of chunks to split the account trie into
   102  	// to allow concurrent retrievals.
   103  	accountConcurrency = 16
   104  
   105  	// storageConcurrency is the number of chunks to split the a large contract
   106  	// storage trie into to allow concurrent retrievals.
   107  	storageConcurrency = 16
   108  )
   109  
   110  // ErrCancelled is returned from snap syncing if the operation was prematurely
   111  // terminated.
   112  var ErrCancelled = errors.New("sync cancelled")
   113  
   114  // accountRequest tracks a pending account range request to ensure responses are
   115  // to actual requests and to validate any security constraints.
   116  //
   117  // Concurrency note: account requests and responses are handled concurrently from
   118  // the main runloop to allow Merkle proof verifications on the peer's thread and
   119  // to drop on invalid response. The request struct must contain all the data to
   120  // construct the response without accessing runloop internals (i.e. task). That
   121  // is only included to allow the runloop to match a response to the task being
   122  // synced without having yet another set of maps.
   123  type accountRequest struct {
   124  	peer string    // Peer to which this request is assigned
   125  	id   uint64    // Request ID of this request
   126  	time time.Time // Timestamp when the request was sent
   127  
   128  	deliver chan *accountResponse // Channel to deliver successful response on
   129  	revert  chan *accountRequest  // Channel to deliver request failure on
   130  	cancel  chan struct{}         // Channel to track sync cancellation
   131  	timeout *time.Timer           // Timer to track delivery timeout
   132  	stale   chan struct{}         // Channel to signal the request was dropped
   133  
   134  	origin common.Hash // First account requested to allow continuation checks
   135  	limit  common.Hash // Last account requested to allow non-overlapping chunking
   136  
   137  	task *accountTask // Task which this request is filling (only access fields through the runloop!!)
   138  }
   139  
   140  // accountResponse is an already Merkle-verified remote response to an account
   141  // range request. It contains the subtrie for the requested account range and
   142  // the database that's going to be filled with the internal nodes on commit.
   143  type accountResponse struct {
   144  	task *accountTask // Task which this request is filling
   145  
   146  	hashes   []common.Hash         // Account hashes in the returned range
   147  	accounts []*types.StateAccount // Expanded accounts in the returned range
   148  
   149  	cont bool // Whether the account range has a continuation
   150  }
   151  
   152  // bytecodeRequest tracks a pending bytecode request to ensure responses are to
   153  // actual requests and to validate any security constraints.
   154  //
   155  // Concurrency note: bytecode requests and responses are handled concurrently from
   156  // the main runloop to allow Keccak256 hash verifications on the peer's thread and
   157  // to drop on invalid response. The request struct must contain all the data to
   158  // construct the response without accessing runloop internals (i.e. task). That
   159  // is only included to allow the runloop to match a response to the task being
   160  // synced without having yet another set of maps.
   161  type bytecodeRequest struct {
   162  	peer string    // Peer to which this request is assigned
   163  	id   uint64    // Request ID of this request
   164  	time time.Time // Timestamp when the request was sent
   165  
   166  	deliver chan *bytecodeResponse // Channel to deliver successful response on
   167  	revert  chan *bytecodeRequest  // Channel to deliver request failure on
   168  	cancel  chan struct{}          // Channel to track sync cancellation
   169  	timeout *time.Timer            // Timer to track delivery timeout
   170  	stale   chan struct{}          // Channel to signal the request was dropped
   171  
   172  	hashes []common.Hash // Bytecode hashes to validate responses
   173  	task   *accountTask  // Task which this request is filling (only access fields through the runloop!!)
   174  }
   175  
   176  // bytecodeResponse is an already verified remote response to a bytecode request.
   177  type bytecodeResponse struct {
   178  	task *accountTask // Task which this request is filling
   179  
   180  	hashes []common.Hash // Hashes of the bytecode to avoid double hashing
   181  	codes  [][]byte      // Actual bytecodes to store into the database (nil = missing)
   182  }
   183  
   184  // storageRequest tracks a pending storage ranges request to ensure responses are
   185  // to actual requests and to validate any security constraints.
   186  //
   187  // Concurrency note: storage requests and responses are handled concurrently from
   188  // the main runloop to allow Merkle proof verifications on the peer's thread and
   189  // to drop on invalid response. The request struct must contain all the data to
   190  // construct the response without accessing runloop internals (i.e. tasks). That
   191  // is only included to allow the runloop to match a response to the task being
   192  // synced without having yet another set of maps.
   193  type storageRequest struct {
   194  	peer string    // Peer to which this request is assigned
   195  	id   uint64    // Request ID of this request
   196  	time time.Time // Timestamp when the request was sent
   197  
   198  	deliver chan *storageResponse // Channel to deliver successful response on
   199  	revert  chan *storageRequest  // Channel to deliver request failure on
   200  	cancel  chan struct{}         // Channel to track sync cancellation
   201  	timeout *time.Timer           // Timer to track delivery timeout
   202  	stale   chan struct{}         // Channel to signal the request was dropped
   203  
   204  	accounts []common.Hash // Account hashes to validate responses
   205  	roots    []common.Hash // Storage roots to validate responses
   206  
   207  	origin common.Hash // First storage slot requested to allow continuation checks
   208  	limit  common.Hash // Last storage slot requested to allow non-overlapping chunking
   209  
   210  	mainTask *accountTask // Task which this response belongs to (only access fields through the runloop!!)
   211  	subTask  *storageTask // Task which this response is filling (only access fields through the runloop!!)
   212  }
   213  
   214  // storageResponse is an already Merkle-verified remote response to a storage
   215  // range request. It contains the subtries for the requested storage ranges and
   216  // the databases that's going to be filled with the internal nodes on commit.
   217  type storageResponse struct {
   218  	mainTask *accountTask // Task which this response belongs to
   219  	subTask  *storageTask // Task which this response is filling
   220  
   221  	accounts []common.Hash // Account hashes requested, may be only partially filled
   222  	roots    []common.Hash // Storage roots requested, may be only partially filled
   223  
   224  	hashes [][]common.Hash // Storage slot hashes in the returned range
   225  	slots  [][][]byte      // Storage slot values in the returned range
   226  
   227  	cont bool // Whether the last storage range has a continuation
   228  }
   229  
   230  // trienodeHealRequest tracks a pending state trie request to ensure responses
   231  // are to actual requests and to validate any security constraints.
   232  //
   233  // Concurrency note: trie node requests and responses are handled concurrently from
   234  // the main runloop to allow Keccak256 hash verifications on the peer's thread and
   235  // to drop on invalid response. The request struct must contain all the data to
   236  // construct the response without accessing runloop internals (i.e. task). That
   237  // is only included to allow the runloop to match a response to the task being
   238  // synced without having yet another set of maps.
   239  type trienodeHealRequest struct {
   240  	peer string    // Peer to which this request is assigned
   241  	id   uint64    // Request ID of this request
   242  	time time.Time // Timestamp when the request was sent
   243  
   244  	deliver chan *trienodeHealResponse // Channel to deliver successful response on
   245  	revert  chan *trienodeHealRequest  // Channel to deliver request failure on
   246  	cancel  chan struct{}              // Channel to track sync cancellation
   247  	timeout *time.Timer                // Timer to track delivery timeout
   248  	stale   chan struct{}              // Channel to signal the request was dropped
   249  
   250  	paths  []string      // Trie node paths for identifying trie node
   251  	hashes []common.Hash // Trie node hashes to validate responses
   252  
   253  	task *healTask // Task which this request is filling (only access fields through the runloop!!)
   254  }
   255  
   256  // trienodeHealResponse is an already verified remote response to a trie node request.
   257  type trienodeHealResponse struct {
   258  	task *healTask // Task which this request is filling
   259  
   260  	paths  []string      // Paths of the trie nodes
   261  	hashes []common.Hash // Hashes of the trie nodes to avoid double hashing
   262  	nodes  [][]byte      // Actual trie nodes to store into the database (nil = missing)
   263  }
   264  
   265  // bytecodeHealRequest tracks a pending bytecode request to ensure responses are to
   266  // actual requests and to validate any security constraints.
   267  //
   268  // Concurrency note: bytecode requests and responses are handled concurrently from
   269  // the main runloop to allow Keccak256 hash verifications on the peer's thread and
   270  // to drop on invalid response. The request struct must contain all the data to
   271  // construct the response without accessing runloop internals (i.e. task). That
   272  // is only included to allow the runloop to match a response to the task being
   273  // synced without having yet another set of maps.
   274  type bytecodeHealRequest struct {
   275  	peer string    // Peer to which this request is assigned
   276  	id   uint64    // Request ID of this request
   277  	time time.Time // Timestamp when the request was sent
   278  
   279  	deliver chan *bytecodeHealResponse // Channel to deliver successful response on
   280  	revert  chan *bytecodeHealRequest  // Channel to deliver request failure on
   281  	cancel  chan struct{}              // Channel to track sync cancellation
   282  	timeout *time.Timer                // Timer to track delivery timeout
   283  	stale   chan struct{}              // Channel to signal the request was dropped
   284  
   285  	hashes []common.Hash // Bytecode hashes to validate responses
   286  	task   *healTask     // Task which this request is filling (only access fields through the runloop!!)
   287  }
   288  
   289  // bytecodeHealResponse is an already verified remote response to a bytecode request.
   290  type bytecodeHealResponse struct {
   291  	task *healTask // Task which this request is filling
   292  
   293  	hashes []common.Hash // Hashes of the bytecode to avoid double hashing
   294  	codes  [][]byte      // Actual bytecodes to store into the database (nil = missing)
   295  }
   296  
   297  // accountTask represents the sync task for a chunk of the account snapshot.
   298  type accountTask struct {
   299  	// These fields get serialized to leveldb on shutdown
   300  	Next     common.Hash                    // Next account to sync in this interval
   301  	Last     common.Hash                    // Last account to sync in this interval
   302  	SubTasks map[common.Hash][]*storageTask // Storage intervals needing fetching for large contracts
   303  
   304  	// These fields are internals used during runtime
   305  	req  *accountRequest  // Pending request to fill this task
   306  	res  *accountResponse // Validate response filling this task
   307  	pend int              // Number of pending subtasks for this round
   308  
   309  	needCode  []bool // Flags whether the filling accounts need code retrieval
   310  	needState []bool // Flags whether the filling accounts need storage retrieval
   311  	needHeal  []bool // Flags whether the filling accounts's state was chunked and need healing
   312  
   313  	codeTasks  map[common.Hash]struct{}    // Code hashes that need retrieval
   314  	stateTasks map[common.Hash]common.Hash // Account hashes->roots that need full state retrieval
   315  
   316  	genBatch ethdb.Batch     // Batch used by the node generator
   317  	genTrie  *trie.StackTrie // Node generator from storage slots
   318  
   319  	done bool // Flag whether the task can be removed
   320  }
   321  
   322  // storageTask represents the sync task for a chunk of the storage snapshot.
   323  type storageTask struct {
   324  	Next common.Hash // Next account to sync in this interval
   325  	Last common.Hash // Last account to sync in this interval
   326  
   327  	// These fields are internals used during runtime
   328  	root common.Hash     // Storage root hash for this instance
   329  	req  *storageRequest // Pending request to fill this task
   330  
   331  	genBatch ethdb.Batch     // Batch used by the node generator
   332  	genTrie  *trie.StackTrie // Node generator from storage slots
   333  
   334  	done bool // Flag whether the task can be removed
   335  }
   336  
   337  // healTask represents the sync task for healing the snap-synced chunk boundaries.
   338  type healTask struct {
   339  	scheduler *trie.Sync // State trie sync scheduler defining the tasks
   340  
   341  	trieTasks map[string]common.Hash   // Set of trie node tasks currently queued for retrieval, indexed by node path
   342  	codeTasks map[common.Hash]struct{} // Set of byte code tasks currently queued for retrieval, indexed by code hash
   343  }
   344  
   345  // SyncProgress is a database entry to allow suspending and resuming a snapshot state
   346  // sync. Opposed to full and fast sync, there is no way to restart a suspended
   347  // snap sync without prior knowledge of the suspension point.
   348  type SyncProgress struct {
   349  	Tasks []*accountTask // The suspended account tasks (contract tasks within)
   350  
   351  	// Status report during syncing phase
   352  	AccountSynced  uint64             // Number of accounts downloaded
   353  	AccountBytes   common.StorageSize // Number of account trie bytes persisted to disk
   354  	BytecodeSynced uint64             // Number of bytecodes downloaded
   355  	BytecodeBytes  common.StorageSize // Number of bytecode bytes downloaded
   356  	StorageSynced  uint64             // Number of storage slots downloaded
   357  	StorageBytes   common.StorageSize // Number of storage trie bytes persisted to disk
   358  
   359  	// Status report during healing phase
   360  	TrienodeHealSynced uint64             // Number of state trie nodes downloaded
   361  	TrienodeHealBytes  common.StorageSize // Number of state trie bytes persisted to disk
   362  	BytecodeHealSynced uint64             // Number of bytecodes downloaded
   363  	BytecodeHealBytes  common.StorageSize // Number of bytecodes persisted to disk
   364  }
   365  
   366  // SyncPending is analogous to SyncProgress, but it's used to report on pending
   367  // ephemeral sync progress that doesn't get persisted into the database.
   368  type SyncPending struct {
   369  	TrienodeHeal uint64 // Number of state trie nodes pending
   370  	BytecodeHeal uint64 // Number of bytecodes pending
   371  }
   372  
   373  // SyncPeer abstracts out the methods required for a peer to be synced against
   374  // with the goal of allowing the construction of mock peers without the full
   375  // blown networking.
   376  type SyncPeer interface {
   377  	// ID retrieves the peer's unique identifier.
   378  	ID() string
   379  
   380  	// RequestAccountRange fetches a batch of accounts rooted in a specific account
   381  	// trie, starting with the origin.
   382  	RequestAccountRange(id uint64, root, origin, limit common.Hash, bytes uint64) error
   383  
   384  	// RequestStorageRanges fetches a batch of storage slots belonging to one or
   385  	// more accounts. If slots from only one account is requested, an origin marker
   386  	// may also be used to retrieve from there.
   387  	RequestStorageRanges(id uint64, root common.Hash, accounts []common.Hash, origin, limit []byte, bytes uint64) error
   388  
   389  	// RequestByteCodes fetches a batch of bytecodes by hash.
   390  	RequestByteCodes(id uint64, hashes []common.Hash, bytes uint64) error
   391  
   392  	// RequestTrieNodes fetches a batch of account or storage trie nodes rooted in
   393  	// a specific state trie.
   394  	RequestTrieNodes(id uint64, root common.Hash, paths []TrieNodePathSet, bytes uint64) error
   395  
   396  	// Log retrieves the peer's own contextual logger.
   397  	Log() log.Logger
   398  }
   399  
   400  // Syncer is an Ethereum account and storage trie syncer based on snapshots and
   401  // the  snap protocol. It's purpose is to download all the accounts and storage
   402  // slots from remote peers and reassemble chunks of the state trie, on top of
   403  // which a state sync can be run to fix any gaps / overlaps.
   404  //
   405  // Every network request has a variety of failure events:
   406  //   - The peer disconnects after task assignment, failing to send the request
   407  //   - The peer disconnects after sending the request, before delivering on it
   408  //   - The peer remains connected, but does not deliver a response in time
   409  //   - The peer delivers a stale response after a previous timeout
   410  //   - The peer delivers a refusal to serve the requested state
   411  type Syncer struct {
   412  	db     ethdb.KeyValueStore // Database to store the trie nodes into (and dedup)
   413  	scheme string              // Node scheme used in node database
   414  
   415  	root    common.Hash    // Current state trie root being synced
   416  	tasks   []*accountTask // Current account task set being synced
   417  	snapped bool           // Flag to signal that snap phase is done
   418  	healer  *healTask      // Current state healing task being executed
   419  	update  chan struct{}  // Notification channel for possible sync progression
   420  
   421  	peers    map[string]SyncPeer // Currently active peers to download from
   422  	peerJoin *event.Feed         // Event feed to react to peers joining
   423  	peerDrop *event.Feed         // Event feed to react to peers dropping
   424  	rates    *msgrate.Trackers   // Message throughput rates for peers
   425  
   426  	// Request tracking during syncing phase
   427  	statelessPeers map[string]struct{} // Peers that failed to deliver state data
   428  	accountIdlers  map[string]struct{} // Peers that aren't serving account requests
   429  	bytecodeIdlers map[string]struct{} // Peers that aren't serving bytecode requests
   430  	storageIdlers  map[string]struct{} // Peers that aren't serving storage requests
   431  
   432  	accountReqs  map[uint64]*accountRequest  // Account requests currently running
   433  	bytecodeReqs map[uint64]*bytecodeRequest // Bytecode requests currently running
   434  	storageReqs  map[uint64]*storageRequest  // Storage requests currently running
   435  
   436  	accountSynced  uint64             // Number of accounts downloaded
   437  	accountBytes   common.StorageSize // Number of account trie bytes persisted to disk
   438  	bytecodeSynced uint64             // Number of bytecodes downloaded
   439  	bytecodeBytes  common.StorageSize // Number of bytecode bytes downloaded
   440  	storageSynced  uint64             // Number of storage slots downloaded
   441  	storageBytes   common.StorageSize // Number of storage trie bytes persisted to disk
   442  
   443  	extProgress *SyncProgress // progress that can be exposed to external caller.
   444  
   445  	// Request tracking during healing phase
   446  	trienodeHealIdlers map[string]struct{} // Peers that aren't serving trie node requests
   447  	bytecodeHealIdlers map[string]struct{} // Peers that aren't serving bytecode requests
   448  
   449  	trienodeHealReqs map[uint64]*trienodeHealRequest // Trie node requests currently running
   450  	bytecodeHealReqs map[uint64]*bytecodeHealRequest // Bytecode requests currently running
   451  
   452  	trienodeHealRate      float64       // Average heal rate for processing trie node data
   453  	trienodeHealPend      atomic.Uint64 // Number of trie nodes currently pending for processing
   454  	trienodeHealThrottle  float64       // Divisor for throttling the amount of trienode heal data requested
   455  	trienodeHealThrottled time.Time     // Timestamp the last time the throttle was updated
   456  
   457  	trienodeHealSynced uint64             // Number of state trie nodes downloaded
   458  	trienodeHealBytes  common.StorageSize // Number of state trie bytes persisted to disk
   459  	trienodeHealDups   uint64             // Number of state trie nodes already processed
   460  	trienodeHealNops   uint64             // Number of state trie nodes not requested
   461  	bytecodeHealSynced uint64             // Number of bytecodes downloaded
   462  	bytecodeHealBytes  common.StorageSize // Number of bytecodes persisted to disk
   463  	bytecodeHealDups   uint64             // Number of bytecodes already processed
   464  	bytecodeHealNops   uint64             // Number of bytecodes not requested
   465  
   466  	stateWriter        ethdb.Batch        // Shared batch writer used for persisting raw states
   467  	accountHealed      uint64             // Number of accounts downloaded during the healing stage
   468  	accountHealedBytes common.StorageSize // Number of raw account bytes persisted to disk during the healing stage
   469  	storageHealed      uint64             // Number of storage slots downloaded during the healing stage
   470  	storageHealedBytes common.StorageSize // Number of raw storage bytes persisted to disk during the healing stage
   471  
   472  	startTime time.Time // Time instance when snapshot sync started
   473  	logTime   time.Time // Time instance when status was last reported
   474  
   475  	pend sync.WaitGroup // Tracks network request goroutines for graceful shutdown
   476  	lock sync.RWMutex   // Protects fields that can change outside of sync (peers, reqs, root)
   477  }
   478  
   479  // NewSyncer creates a new snapshot syncer to download the Ethereum state over the
   480  // snap protocol.
   481  func NewSyncer(db ethdb.KeyValueStore, scheme string) *Syncer {
   482  	return &Syncer{
   483  		db:     db,
   484  		scheme: scheme,
   485  
   486  		peers:    make(map[string]SyncPeer),
   487  		peerJoin: new(event.Feed),
   488  		peerDrop: new(event.Feed),
   489  		rates:    msgrate.NewTrackers(log.New("proto", "snap")),
   490  		update:   make(chan struct{}, 1),
   491  
   492  		accountIdlers:  make(map[string]struct{}),
   493  		storageIdlers:  make(map[string]struct{}),
   494  		bytecodeIdlers: make(map[string]struct{}),
   495  
   496  		accountReqs:  make(map[uint64]*accountRequest),
   497  		storageReqs:  make(map[uint64]*storageRequest),
   498  		bytecodeReqs: make(map[uint64]*bytecodeRequest),
   499  
   500  		trienodeHealIdlers: make(map[string]struct{}),
   501  		bytecodeHealIdlers: make(map[string]struct{}),
   502  
   503  		trienodeHealReqs:     make(map[uint64]*trienodeHealRequest),
   504  		bytecodeHealReqs:     make(map[uint64]*bytecodeHealRequest),
   505  		trienodeHealThrottle: maxTrienodeHealThrottle, // Tune downward instead of insta-filling with junk
   506  		stateWriter:          db.NewBatch(),
   507  
   508  		extProgress: new(SyncProgress),
   509  	}
   510  }
   511  
   512  // Register injects a new data source into the syncer's peerset.
   513  func (s *Syncer) Register(peer SyncPeer) error {
   514  	// Make sure the peer is not registered yet
   515  	id := peer.ID()
   516  
   517  	s.lock.Lock()
   518  	if _, ok := s.peers[id]; ok {
   519  		log.Error("Snap peer already registered", "id", id)
   520  
   521  		s.lock.Unlock()
   522  		return errors.New("already registered")
   523  	}
   524  	s.peers[id] = peer
   525  	s.rates.Track(id, msgrate.NewTracker(s.rates.MeanCapacities(), s.rates.MedianRoundTrip()))
   526  
   527  	// Mark the peer as idle, even if no sync is running
   528  	s.accountIdlers[id] = struct{}{}
   529  	s.storageIdlers[id] = struct{}{}
   530  	s.bytecodeIdlers[id] = struct{}{}
   531  	s.trienodeHealIdlers[id] = struct{}{}
   532  	s.bytecodeHealIdlers[id] = struct{}{}
   533  	s.lock.Unlock()
   534  
   535  	// Notify any active syncs that a new peer can be assigned data
   536  	s.peerJoin.Send(id)
   537  	return nil
   538  }
   539  
   540  // Unregister injects a new data source into the syncer's peerset.
   541  func (s *Syncer) Unregister(id string) error {
   542  	// Remove all traces of the peer from the registry
   543  	s.lock.Lock()
   544  	if _, ok := s.peers[id]; !ok {
   545  		log.Error("Snap peer not registered", "id", id)
   546  
   547  		s.lock.Unlock()
   548  		return errors.New("not registered")
   549  	}
   550  	delete(s.peers, id)
   551  	s.rates.Untrack(id)
   552  
   553  	// Remove status markers, even if no sync is running
   554  	delete(s.statelessPeers, id)
   555  
   556  	delete(s.accountIdlers, id)
   557  	delete(s.storageIdlers, id)
   558  	delete(s.bytecodeIdlers, id)
   559  	delete(s.trienodeHealIdlers, id)
   560  	delete(s.bytecodeHealIdlers, id)
   561  	s.lock.Unlock()
   562  
   563  	// Notify any active syncs that pending requests need to be reverted
   564  	s.peerDrop.Send(id)
   565  	return nil
   566  }
   567  
   568  // Sync starts (or resumes a previous) sync cycle to iterate over a state trie
   569  // with the given root and reconstruct the nodes based on the snapshot leaves.
   570  // Previously downloaded segments will not be redownloaded of fixed, rather any
   571  // errors will be healed after the leaves are fully accumulated.
   572  func (s *Syncer) Sync(root common.Hash, cancel chan struct{}) error {
   573  	// Move the trie root from any previous value, revert stateless markers for
   574  	// any peers and initialize the syncer if it was not yet run
   575  	s.lock.Lock()
   576  	s.root = root
   577  	s.healer = &healTask{
   578  		scheduler: state.NewStateSync(root, s.db, s.onHealState, s.scheme),
   579  		trieTasks: make(map[string]common.Hash),
   580  		codeTasks: make(map[common.Hash]struct{}),
   581  	}
   582  	s.statelessPeers = make(map[string]struct{})
   583  	s.lock.Unlock()
   584  
   585  	if s.startTime == (time.Time{}) {
   586  		s.startTime = time.Now()
   587  	}
   588  	// Retrieve the previous sync status from LevelDB and abort if already synced
   589  	s.loadSyncStatus()
   590  	if len(s.tasks) == 0 && s.healer.scheduler.Pending() == 0 {
   591  		log.Debug("Snapshot sync already completed")
   592  		return nil
   593  	}
   594  	defer func() { // Persist any progress, independent of failure
   595  		for _, task := range s.tasks {
   596  			s.forwardAccountTask(task)
   597  		}
   598  		s.cleanAccountTasks()
   599  		s.saveSyncStatus()
   600  	}()
   601  
   602  	log.Debug("Starting snapshot sync cycle", "root", root)
   603  
   604  	// Flush out the last committed raw states
   605  	defer func() {
   606  		if s.stateWriter.ValueSize() > 0 {
   607  			s.stateWriter.Write()
   608  			s.stateWriter.Reset()
   609  		}
   610  	}()
   611  	defer s.report(true)
   612  	// commit any trie- and bytecode-healing data.
   613  	defer s.commitHealer(true)
   614  
   615  	// Whether sync completed or not, disregard any future packets
   616  	defer func() {
   617  		log.Debug("Terminating snapshot sync cycle", "root", root)
   618  		s.lock.Lock()
   619  		s.accountReqs = make(map[uint64]*accountRequest)
   620  		s.storageReqs = make(map[uint64]*storageRequest)
   621  		s.bytecodeReqs = make(map[uint64]*bytecodeRequest)
   622  		s.trienodeHealReqs = make(map[uint64]*trienodeHealRequest)
   623  		s.bytecodeHealReqs = make(map[uint64]*bytecodeHealRequest)
   624  		s.lock.Unlock()
   625  	}()
   626  	// Keep scheduling sync tasks
   627  	peerJoin := make(chan string, 16)
   628  	peerJoinSub := s.peerJoin.Subscribe(peerJoin)
   629  	defer peerJoinSub.Unsubscribe()
   630  
   631  	peerDrop := make(chan string, 16)
   632  	peerDropSub := s.peerDrop.Subscribe(peerDrop)
   633  	defer peerDropSub.Unsubscribe()
   634  
   635  	// Create a set of unique channels for this sync cycle. We need these to be
   636  	// ephemeral so a data race doesn't accidentally deliver something stale on
   637  	// a persistent channel across syncs (yup, this happened)
   638  	var (
   639  		accountReqFails      = make(chan *accountRequest)
   640  		storageReqFails      = make(chan *storageRequest)
   641  		bytecodeReqFails     = make(chan *bytecodeRequest)
   642  		accountResps         = make(chan *accountResponse)
   643  		storageResps         = make(chan *storageResponse)
   644  		bytecodeResps        = make(chan *bytecodeResponse)
   645  		trienodeHealReqFails = make(chan *trienodeHealRequest)
   646  		bytecodeHealReqFails = make(chan *bytecodeHealRequest)
   647  		trienodeHealResps    = make(chan *trienodeHealResponse)
   648  		bytecodeHealResps    = make(chan *bytecodeHealResponse)
   649  	)
   650  	for {
   651  		// Remove all completed tasks and terminate sync if everything's done
   652  		s.cleanStorageTasks()
   653  		s.cleanAccountTasks()
   654  		if len(s.tasks) == 0 && s.healer.scheduler.Pending() == 0 {
   655  			return nil
   656  		}
   657  		// Assign all the data retrieval tasks to any free peers
   658  		s.assignAccountTasks(accountResps, accountReqFails, cancel)
   659  		s.assignBytecodeTasks(bytecodeResps, bytecodeReqFails, cancel)
   660  		s.assignStorageTasks(storageResps, storageReqFails, cancel)
   661  
   662  		if len(s.tasks) == 0 {
   663  			// Sync phase done, run heal phase
   664  			s.assignTrienodeHealTasks(trienodeHealResps, trienodeHealReqFails, cancel)
   665  			s.assignBytecodeHealTasks(bytecodeHealResps, bytecodeHealReqFails, cancel)
   666  		}
   667  		// Update sync progress
   668  		s.lock.Lock()
   669  		s.extProgress = &SyncProgress{
   670  			AccountSynced:      s.accountSynced,
   671  			AccountBytes:       s.accountBytes,
   672  			BytecodeSynced:     s.bytecodeSynced,
   673  			BytecodeBytes:      s.bytecodeBytes,
   674  			StorageSynced:      s.storageSynced,
   675  			StorageBytes:       s.storageBytes,
   676  			TrienodeHealSynced: s.trienodeHealSynced,
   677  			TrienodeHealBytes:  s.trienodeHealBytes,
   678  			BytecodeHealSynced: s.bytecodeHealSynced,
   679  			BytecodeHealBytes:  s.bytecodeHealBytes,
   680  		}
   681  		s.lock.Unlock()
   682  		// Wait for something to happen
   683  		select {
   684  		case <-s.update:
   685  			// Something happened (new peer, delivery, timeout), recheck tasks
   686  		case <-peerJoin:
   687  			// A new peer joined, try to schedule it new tasks
   688  		case id := <-peerDrop:
   689  			s.revertRequests(id)
   690  		case <-cancel:
   691  			return ErrCancelled
   692  
   693  		case req := <-accountReqFails:
   694  			s.revertAccountRequest(req)
   695  		case req := <-bytecodeReqFails:
   696  			s.revertBytecodeRequest(req)
   697  		case req := <-storageReqFails:
   698  			s.revertStorageRequest(req)
   699  		case req := <-trienodeHealReqFails:
   700  			s.revertTrienodeHealRequest(req)
   701  		case req := <-bytecodeHealReqFails:
   702  			s.revertBytecodeHealRequest(req)
   703  
   704  		case res := <-accountResps:
   705  			s.processAccountResponse(res)
   706  		case res := <-bytecodeResps:
   707  			s.processBytecodeResponse(res)
   708  		case res := <-storageResps:
   709  			s.processStorageResponse(res)
   710  		case res := <-trienodeHealResps:
   711  			s.processTrienodeHealResponse(res)
   712  		case res := <-bytecodeHealResps:
   713  			s.processBytecodeHealResponse(res)
   714  		}
   715  		// Report stats if something meaningful happened
   716  		s.report(false)
   717  	}
   718  }
   719  
   720  // loadSyncStatus retrieves a previously aborted sync status from the database,
   721  // or generates a fresh one if none is available.
   722  func (s *Syncer) loadSyncStatus() {
   723  	var progress SyncProgress
   724  
   725  	if status := rawdb.ReadSnapshotSyncStatus(s.db); status != nil {
   726  		if err := json.Unmarshal(status, &progress); err != nil {
   727  			log.Error("Failed to decode snap sync status", "err", err)
   728  		} else {
   729  			for _, task := range progress.Tasks {
   730  				log.Debug("Scheduled account sync task", "from", task.Next, "last", task.Last)
   731  			}
   732  			s.tasks = progress.Tasks
   733  			for _, task := range s.tasks {
   734  				task.genBatch = ethdb.HookedBatch{
   735  					Batch: s.db.NewBatch(),
   736  					OnPut: func(key []byte, value []byte) {
   737  						s.accountBytes += common.StorageSize(len(key) + len(value))
   738  					},
   739  				}
   740  				task.genTrie = trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, val []byte) {
   741  					rawdb.WriteTrieNode(task.genBatch, owner, path, hash, val, s.scheme)
   742  				})
   743  				for accountHash, subtasks := range task.SubTasks {
   744  					for _, subtask := range subtasks {
   745  						subtask.genBatch = ethdb.HookedBatch{
   746  							Batch: s.db.NewBatch(),
   747  							OnPut: func(key []byte, value []byte) {
   748  								s.storageBytes += common.StorageSize(len(key) + len(value))
   749  							},
   750  						}
   751  						subtask.genTrie = trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) {
   752  							rawdb.WriteTrieNode(subtask.genBatch, owner, path, hash, val, s.scheme)
   753  						}, accountHash)
   754  					}
   755  				}
   756  			}
   757  			s.lock.Lock()
   758  			defer s.lock.Unlock()
   759  
   760  			s.snapped = len(s.tasks) == 0
   761  
   762  			s.accountSynced = progress.AccountSynced
   763  			s.accountBytes = progress.AccountBytes
   764  			s.bytecodeSynced = progress.BytecodeSynced
   765  			s.bytecodeBytes = progress.BytecodeBytes
   766  			s.storageSynced = progress.StorageSynced
   767  			s.storageBytes = progress.StorageBytes
   768  
   769  			s.trienodeHealSynced = progress.TrienodeHealSynced
   770  			s.trienodeHealBytes = progress.TrienodeHealBytes
   771  			s.bytecodeHealSynced = progress.BytecodeHealSynced
   772  			s.bytecodeHealBytes = progress.BytecodeHealBytes
   773  			return
   774  		}
   775  	}
   776  	// Either we've failed to decode the previous state, or there was none.
   777  	// Start a fresh sync by chunking up the account range and scheduling
   778  	// them for retrieval.
   779  	s.tasks = nil
   780  	s.accountSynced, s.accountBytes = 0, 0
   781  	s.bytecodeSynced, s.bytecodeBytes = 0, 0
   782  	s.storageSynced, s.storageBytes = 0, 0
   783  	s.trienodeHealSynced, s.trienodeHealBytes = 0, 0
   784  	s.bytecodeHealSynced, s.bytecodeHealBytes = 0, 0
   785  
   786  	var next common.Hash
   787  	step := new(big.Int).Sub(
   788  		new(big.Int).Div(
   789  			new(big.Int).Exp(common.Big2, common.Big256, nil),
   790  			big.NewInt(int64(accountConcurrency)),
   791  		), common.Big1,
   792  	)
   793  	for i := 0; i < accountConcurrency; i++ {
   794  		last := common.BigToHash(new(big.Int).Add(next.Big(), step))
   795  		if i == accountConcurrency-1 {
   796  			// Make sure we don't overflow if the step is not a proper divisor
   797  			last = common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
   798  		}
   799  		batch := ethdb.HookedBatch{
   800  			Batch: s.db.NewBatch(),
   801  			OnPut: func(key []byte, value []byte) {
   802  				s.accountBytes += common.StorageSize(len(key) + len(value))
   803  			},
   804  		}
   805  		s.tasks = append(s.tasks, &accountTask{
   806  			Next:     next,
   807  			Last:     last,
   808  			SubTasks: make(map[common.Hash][]*storageTask),
   809  			genBatch: batch,
   810  			genTrie: trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, val []byte) {
   811  				rawdb.WriteTrieNode(batch, owner, path, hash, val, s.scheme)
   812  			}),
   813  		})
   814  		log.Debug("Created account sync task", "from", next, "last", last)
   815  		next = common.BigToHash(new(big.Int).Add(last.Big(), common.Big1))
   816  	}
   817  }
   818  
   819  // saveSyncStatus marshals the remaining sync tasks into leveldb.
   820  func (s *Syncer) saveSyncStatus() {
   821  	// Serialize any partial progress to disk before spinning down
   822  	for _, task := range s.tasks {
   823  		if err := task.genBatch.Write(); err != nil {
   824  			log.Error("Failed to persist account slots", "err", err)
   825  		}
   826  		for _, subtasks := range task.SubTasks {
   827  			for _, subtask := range subtasks {
   828  				if err := subtask.genBatch.Write(); err != nil {
   829  					log.Error("Failed to persist storage slots", "err", err)
   830  				}
   831  			}
   832  		}
   833  	}
   834  	// Store the actual progress markers
   835  	progress := &SyncProgress{
   836  		Tasks:              s.tasks,
   837  		AccountSynced:      s.accountSynced,
   838  		AccountBytes:       s.accountBytes,
   839  		BytecodeSynced:     s.bytecodeSynced,
   840  		BytecodeBytes:      s.bytecodeBytes,
   841  		StorageSynced:      s.storageSynced,
   842  		StorageBytes:       s.storageBytes,
   843  		TrienodeHealSynced: s.trienodeHealSynced,
   844  		TrienodeHealBytes:  s.trienodeHealBytes,
   845  		BytecodeHealSynced: s.bytecodeHealSynced,
   846  		BytecodeHealBytes:  s.bytecodeHealBytes,
   847  	}
   848  	status, err := json.Marshal(progress)
   849  	if err != nil {
   850  		panic(err) // This can only fail during implementation
   851  	}
   852  	rawdb.WriteSnapshotSyncStatus(s.db, status)
   853  }
   854  
   855  // Progress returns the snap sync status statistics.
   856  func (s *Syncer) Progress() (*SyncProgress, *SyncPending) {
   857  	s.lock.Lock()
   858  	defer s.lock.Unlock()
   859  	pending := new(SyncPending)
   860  	if s.healer != nil {
   861  		pending.TrienodeHeal = uint64(len(s.healer.trieTasks))
   862  		pending.BytecodeHeal = uint64(len(s.healer.codeTasks))
   863  	}
   864  	return s.extProgress, pending
   865  }
   866  
   867  // cleanAccountTasks removes account range retrieval tasks that have already been
   868  // completed.
   869  func (s *Syncer) cleanAccountTasks() {
   870  	// If the sync was already done before, don't even bother
   871  	if len(s.tasks) == 0 {
   872  		return
   873  	}
   874  	// Sync wasn't finished previously, check for any task that can be finalized
   875  	for i := 0; i < len(s.tasks); i++ {
   876  		if s.tasks[i].done {
   877  			s.tasks = append(s.tasks[:i], s.tasks[i+1:]...)
   878  			i--
   879  		}
   880  	}
   881  	// If everything was just finalized just, generate the account trie and start heal
   882  	if len(s.tasks) == 0 {
   883  		s.lock.Lock()
   884  		s.snapped = true
   885  		s.lock.Unlock()
   886  
   887  		// Push the final sync report
   888  		s.reportSyncProgress(true)
   889  	}
   890  }
   891  
   892  // cleanStorageTasks iterates over all the account tasks and storage sub-tasks
   893  // within, cleaning any that have been completed.
   894  func (s *Syncer) cleanStorageTasks() {
   895  	for _, task := range s.tasks {
   896  		for account, subtasks := range task.SubTasks {
   897  			// Remove storage range retrieval tasks that completed
   898  			for j := 0; j < len(subtasks); j++ {
   899  				if subtasks[j].done {
   900  					subtasks = append(subtasks[:j], subtasks[j+1:]...)
   901  					j--
   902  				}
   903  			}
   904  			if len(subtasks) > 0 {
   905  				task.SubTasks[account] = subtasks
   906  				continue
   907  			}
   908  			// If all storage chunks are done, mark the account as done too
   909  			for j, hash := range task.res.hashes {
   910  				if hash == account {
   911  					task.needState[j] = false
   912  				}
   913  			}
   914  			delete(task.SubTasks, account)
   915  			task.pend--
   916  
   917  			// If this was the last pending task, forward the account task
   918  			if task.pend == 0 {
   919  				s.forwardAccountTask(task)
   920  			}
   921  		}
   922  	}
   923  }
   924  
   925  // assignAccountTasks attempts to match idle peers to pending account range
   926  // retrievals.
   927  func (s *Syncer) assignAccountTasks(success chan *accountResponse, fail chan *accountRequest, cancel chan struct{}) {
   928  	s.lock.Lock()
   929  	defer s.lock.Unlock()
   930  
   931  	// Sort the peers by download capacity to use faster ones if many available
   932  	idlers := &capacitySort{
   933  		ids:  make([]string, 0, len(s.accountIdlers)),
   934  		caps: make([]int, 0, len(s.accountIdlers)),
   935  	}
   936  	targetTTL := s.rates.TargetTimeout()
   937  	for id := range s.accountIdlers {
   938  		if _, ok := s.statelessPeers[id]; ok {
   939  			continue
   940  		}
   941  		idlers.ids = append(idlers.ids, id)
   942  		idlers.caps = append(idlers.caps, s.rates.Capacity(id, AccountRangeMsg, targetTTL))
   943  	}
   944  	if len(idlers.ids) == 0 {
   945  		return
   946  	}
   947  	sort.Sort(sort.Reverse(idlers))
   948  
   949  	// Iterate over all the tasks and try to find a pending one
   950  	for _, task := range s.tasks {
   951  		// Skip any tasks already filling
   952  		if task.req != nil || task.res != nil {
   953  			continue
   954  		}
   955  		// Task pending retrieval, try to find an idle peer. If no such peer
   956  		// exists, we probably assigned tasks for all (or they are stateless).
   957  		// Abort the entire assignment mechanism.
   958  		if len(idlers.ids) == 0 {
   959  			return
   960  		}
   961  		var (
   962  			idle = idlers.ids[0]
   963  			peer = s.peers[idle]
   964  			cap  = idlers.caps[0]
   965  		)
   966  		idlers.ids, idlers.caps = idlers.ids[1:], idlers.caps[1:]
   967  
   968  		// Matched a pending task to an idle peer, allocate a unique request id
   969  		var reqid uint64
   970  		for {
   971  			reqid = uint64(rand.Int63())
   972  			if reqid == 0 {
   973  				continue
   974  			}
   975  			if _, ok := s.accountReqs[reqid]; ok {
   976  				continue
   977  			}
   978  			break
   979  		}
   980  		// Generate the network query and send it to the peer
   981  		req := &accountRequest{
   982  			peer:    idle,
   983  			id:      reqid,
   984  			time:    time.Now(),
   985  			deliver: success,
   986  			revert:  fail,
   987  			cancel:  cancel,
   988  			stale:   make(chan struct{}),
   989  			origin:  task.Next,
   990  			limit:   task.Last,
   991  			task:    task,
   992  		}
   993  		req.timeout = time.AfterFunc(s.rates.TargetTimeout(), func() {
   994  			peer.Log().Debug("Account range request timed out", "reqid", reqid)
   995  			s.rates.Update(idle, AccountRangeMsg, 0, 0)
   996  			s.scheduleRevertAccountRequest(req)
   997  		})
   998  		s.accountReqs[reqid] = req
   999  		delete(s.accountIdlers, idle)
  1000  
  1001  		s.pend.Add(1)
  1002  		go func(root common.Hash) {
  1003  			defer s.pend.Done()
  1004  
  1005  			// Attempt to send the remote request and revert if it fails
  1006  			if cap > maxRequestSize {
  1007  				cap = maxRequestSize
  1008  			}
  1009  			if cap < minRequestSize { // Don't bother with peers below a bare minimum performance
  1010  				cap = minRequestSize
  1011  			}
  1012  			if err := peer.RequestAccountRange(reqid, root, req.origin, req.limit, uint64(cap)); err != nil {
  1013  				peer.Log().Debug("Failed to request account range", "err", err)
  1014  				s.scheduleRevertAccountRequest(req)
  1015  			}
  1016  		}(s.root)
  1017  
  1018  		// Inject the request into the task to block further assignments
  1019  		task.req = req
  1020  	}
  1021  }
  1022  
  1023  // assignBytecodeTasks attempts to match idle peers to pending code retrievals.
  1024  func (s *Syncer) assignBytecodeTasks(success chan *bytecodeResponse, fail chan *bytecodeRequest, cancel chan struct{}) {
  1025  	s.lock.Lock()
  1026  	defer s.lock.Unlock()
  1027  
  1028  	// Sort the peers by download capacity to use faster ones if many available
  1029  	idlers := &capacitySort{
  1030  		ids:  make([]string, 0, len(s.bytecodeIdlers)),
  1031  		caps: make([]int, 0, len(s.bytecodeIdlers)),
  1032  	}
  1033  	targetTTL := s.rates.TargetTimeout()
  1034  	for id := range s.bytecodeIdlers {
  1035  		if _, ok := s.statelessPeers[id]; ok {
  1036  			continue
  1037  		}
  1038  		idlers.ids = append(idlers.ids, id)
  1039  		idlers.caps = append(idlers.caps, s.rates.Capacity(id, ByteCodesMsg, targetTTL))
  1040  	}
  1041  	if len(idlers.ids) == 0 {
  1042  		return
  1043  	}
  1044  	sort.Sort(sort.Reverse(idlers))
  1045  
  1046  	// Iterate over all the tasks and try to find a pending one
  1047  	for _, task := range s.tasks {
  1048  		// Skip any tasks not in the bytecode retrieval phase
  1049  		if task.res == nil {
  1050  			continue
  1051  		}
  1052  		// Skip tasks that are already retrieving (or done with) all codes
  1053  		if len(task.codeTasks) == 0 {
  1054  			continue
  1055  		}
  1056  		// Task pending retrieval, try to find an idle peer. If no such peer
  1057  		// exists, we probably assigned tasks for all (or they are stateless).
  1058  		// Abort the entire assignment mechanism.
  1059  		if len(idlers.ids) == 0 {
  1060  			return
  1061  		}
  1062  		var (
  1063  			idle = idlers.ids[0]
  1064  			peer = s.peers[idle]
  1065  			cap  = idlers.caps[0]
  1066  		)
  1067  		idlers.ids, idlers.caps = idlers.ids[1:], idlers.caps[1:]
  1068  
  1069  		// Matched a pending task to an idle peer, allocate a unique request id
  1070  		var reqid uint64
  1071  		for {
  1072  			reqid = uint64(rand.Int63())
  1073  			if reqid == 0 {
  1074  				continue
  1075  			}
  1076  			if _, ok := s.bytecodeReqs[reqid]; ok {
  1077  				continue
  1078  			}
  1079  			break
  1080  		}
  1081  		// Generate the network query and send it to the peer
  1082  		if cap > maxCodeRequestCount {
  1083  			cap = maxCodeRequestCount
  1084  		}
  1085  		hashes := make([]common.Hash, 0, cap)
  1086  		for hash := range task.codeTasks {
  1087  			delete(task.codeTasks, hash)
  1088  			hashes = append(hashes, hash)
  1089  			if len(hashes) >= cap {
  1090  				break
  1091  			}
  1092  		}
  1093  		req := &bytecodeRequest{
  1094  			peer:    idle,
  1095  			id:      reqid,
  1096  			time:    time.Now(),
  1097  			deliver: success,
  1098  			revert:  fail,
  1099  			cancel:  cancel,
  1100  			stale:   make(chan struct{}),
  1101  			hashes:  hashes,
  1102  			task:    task,
  1103  		}
  1104  		req.timeout = time.AfterFunc(s.rates.TargetTimeout(), func() {
  1105  			peer.Log().Debug("Bytecode request timed out", "reqid", reqid)
  1106  			s.rates.Update(idle, ByteCodesMsg, 0, 0)
  1107  			s.scheduleRevertBytecodeRequest(req)
  1108  		})
  1109  		s.bytecodeReqs[reqid] = req
  1110  		delete(s.bytecodeIdlers, idle)
  1111  
  1112  		s.pend.Add(1)
  1113  		go func() {
  1114  			defer s.pend.Done()
  1115  
  1116  			// Attempt to send the remote request and revert if it fails
  1117  			if err := peer.RequestByteCodes(reqid, hashes, maxRequestSize); err != nil {
  1118  				log.Debug("Failed to request bytecodes", "err", err)
  1119  				s.scheduleRevertBytecodeRequest(req)
  1120  			}
  1121  		}()
  1122  	}
  1123  }
  1124  
  1125  // assignStorageTasks attempts to match idle peers to pending storage range
  1126  // retrievals.
  1127  func (s *Syncer) assignStorageTasks(success chan *storageResponse, fail chan *storageRequest, cancel chan struct{}) {
  1128  	s.lock.Lock()
  1129  	defer s.lock.Unlock()
  1130  
  1131  	// Sort the peers by download capacity to use faster ones if many available
  1132  	idlers := &capacitySort{
  1133  		ids:  make([]string, 0, len(s.storageIdlers)),
  1134  		caps: make([]int, 0, len(s.storageIdlers)),
  1135  	}
  1136  	targetTTL := s.rates.TargetTimeout()
  1137  	for id := range s.storageIdlers {
  1138  		if _, ok := s.statelessPeers[id]; ok {
  1139  			continue
  1140  		}
  1141  		idlers.ids = append(idlers.ids, id)
  1142  		idlers.caps = append(idlers.caps, s.rates.Capacity(id, StorageRangesMsg, targetTTL))
  1143  	}
  1144  	if len(idlers.ids) == 0 {
  1145  		return
  1146  	}
  1147  	sort.Sort(sort.Reverse(idlers))
  1148  
  1149  	// Iterate over all the tasks and try to find a pending one
  1150  	for _, task := range s.tasks {
  1151  		// Skip any tasks not in the storage retrieval phase
  1152  		if task.res == nil {
  1153  			continue
  1154  		}
  1155  		// Skip tasks that are already retrieving (or done with) all small states
  1156  		if len(task.SubTasks) == 0 && len(task.stateTasks) == 0 {
  1157  			continue
  1158  		}
  1159  		// Task pending retrieval, try to find an idle peer. If no such peer
  1160  		// exists, we probably assigned tasks for all (or they are stateless).
  1161  		// Abort the entire assignment mechanism.
  1162  		if len(idlers.ids) == 0 {
  1163  			return
  1164  		}
  1165  		var (
  1166  			idle = idlers.ids[0]
  1167  			peer = s.peers[idle]
  1168  			cap  = idlers.caps[0]
  1169  		)
  1170  		idlers.ids, idlers.caps = idlers.ids[1:], idlers.caps[1:]
  1171  
  1172  		// Matched a pending task to an idle peer, allocate a unique request id
  1173  		var reqid uint64
  1174  		for {
  1175  			reqid = uint64(rand.Int63())
  1176  			if reqid == 0 {
  1177  				continue
  1178  			}
  1179  			if _, ok := s.storageReqs[reqid]; ok {
  1180  				continue
  1181  			}
  1182  			break
  1183  		}
  1184  		// Generate the network query and send it to the peer. If there are
  1185  		// large contract tasks pending, complete those before diving into
  1186  		// even more new contracts.
  1187  		if cap > maxRequestSize {
  1188  			cap = maxRequestSize
  1189  		}
  1190  		if cap < minRequestSize { // Don't bother with peers below a bare minimum performance
  1191  			cap = minRequestSize
  1192  		}
  1193  		storageSets := cap / 1024
  1194  
  1195  		var (
  1196  			accounts = make([]common.Hash, 0, storageSets)
  1197  			roots    = make([]common.Hash, 0, storageSets)
  1198  			subtask  *storageTask
  1199  		)
  1200  		for account, subtasks := range task.SubTasks {
  1201  			for _, st := range subtasks {
  1202  				// Skip any subtasks already filling
  1203  				if st.req != nil {
  1204  					continue
  1205  				}
  1206  				// Found an incomplete storage chunk, schedule it
  1207  				accounts = append(accounts, account)
  1208  				roots = append(roots, st.root)
  1209  				subtask = st
  1210  				break // Large contract chunks are downloaded individually
  1211  			}
  1212  			if subtask != nil {
  1213  				break // Large contract chunks are downloaded individually
  1214  			}
  1215  		}
  1216  		if subtask == nil {
  1217  			// No large contract required retrieval, but small ones available
  1218  			for account, root := range task.stateTasks {
  1219  				delete(task.stateTasks, account)
  1220  
  1221  				accounts = append(accounts, account)
  1222  				roots = append(roots, root)
  1223  
  1224  				if len(accounts) >= storageSets {
  1225  					break
  1226  				}
  1227  			}
  1228  		}
  1229  		// If nothing was found, it means this task is actually already fully
  1230  		// retrieving, but large contracts are hard to detect. Skip to the next.
  1231  		if len(accounts) == 0 {
  1232  			continue
  1233  		}
  1234  		req := &storageRequest{
  1235  			peer:     idle,
  1236  			id:       reqid,
  1237  			time:     time.Now(),
  1238  			deliver:  success,
  1239  			revert:   fail,
  1240  			cancel:   cancel,
  1241  			stale:    make(chan struct{}),
  1242  			accounts: accounts,
  1243  			roots:    roots,
  1244  			mainTask: task,
  1245  			subTask:  subtask,
  1246  		}
  1247  		if subtask != nil {
  1248  			req.origin = subtask.Next
  1249  			req.limit = subtask.Last
  1250  		}
  1251  		req.timeout = time.AfterFunc(s.rates.TargetTimeout(), func() {
  1252  			peer.Log().Debug("Storage request timed out", "reqid", reqid)
  1253  			s.rates.Update(idle, StorageRangesMsg, 0, 0)
  1254  			s.scheduleRevertStorageRequest(req)
  1255  		})
  1256  		s.storageReqs[reqid] = req
  1257  		delete(s.storageIdlers, idle)
  1258  
  1259  		s.pend.Add(1)
  1260  		go func(root common.Hash) {
  1261  			defer s.pend.Done()
  1262  
  1263  			// Attempt to send the remote request and revert if it fails
  1264  			var origin, limit []byte
  1265  			if subtask != nil {
  1266  				origin, limit = req.origin[:], req.limit[:]
  1267  			}
  1268  			if err := peer.RequestStorageRanges(reqid, root, accounts, origin, limit, uint64(cap)); err != nil {
  1269  				log.Debug("Failed to request storage", "err", err)
  1270  				s.scheduleRevertStorageRequest(req)
  1271  			}
  1272  		}(s.root)
  1273  
  1274  		// Inject the request into the subtask to block further assignments
  1275  		if subtask != nil {
  1276  			subtask.req = req
  1277  		}
  1278  	}
  1279  }
  1280  
  1281  // assignTrienodeHealTasks attempts to match idle peers to trie node requests to
  1282  // heal any trie errors caused by the snap sync's chunked retrieval model.
  1283  func (s *Syncer) assignTrienodeHealTasks(success chan *trienodeHealResponse, fail chan *trienodeHealRequest, cancel chan struct{}) {
  1284  	s.lock.Lock()
  1285  	defer s.lock.Unlock()
  1286  
  1287  	// Sort the peers by download capacity to use faster ones if many available
  1288  	idlers := &capacitySort{
  1289  		ids:  make([]string, 0, len(s.trienodeHealIdlers)),
  1290  		caps: make([]int, 0, len(s.trienodeHealIdlers)),
  1291  	}
  1292  	targetTTL := s.rates.TargetTimeout()
  1293  	for id := range s.trienodeHealIdlers {
  1294  		if _, ok := s.statelessPeers[id]; ok {
  1295  			continue
  1296  		}
  1297  		idlers.ids = append(idlers.ids, id)
  1298  		idlers.caps = append(idlers.caps, s.rates.Capacity(id, TrieNodesMsg, targetTTL))
  1299  	}
  1300  	if len(idlers.ids) == 0 {
  1301  		return
  1302  	}
  1303  	sort.Sort(sort.Reverse(idlers))
  1304  
  1305  	// Iterate over pending tasks and try to find a peer to retrieve with
  1306  	for len(s.healer.trieTasks) > 0 || s.healer.scheduler.Pending() > 0 {
  1307  		// If there are not enough trie tasks queued to fully assign, fill the
  1308  		// queue from the state sync scheduler. The trie synced schedules these
  1309  		// together with bytecodes, so we need to queue them combined.
  1310  		var (
  1311  			have = len(s.healer.trieTasks) + len(s.healer.codeTasks)
  1312  			want = maxTrieRequestCount + maxCodeRequestCount
  1313  		)
  1314  		if have < want {
  1315  			paths, hashes, codes := s.healer.scheduler.Missing(want - have)
  1316  			for i, path := range paths {
  1317  				s.healer.trieTasks[path] = hashes[i]
  1318  			}
  1319  			for _, hash := range codes {
  1320  				s.healer.codeTasks[hash] = struct{}{}
  1321  			}
  1322  		}
  1323  		// If all the heal tasks are bytecodes or already downloading, bail
  1324  		if len(s.healer.trieTasks) == 0 {
  1325  			return
  1326  		}
  1327  		// Task pending retrieval, try to find an idle peer. If no such peer
  1328  		// exists, we probably assigned tasks for all (or they are stateless).
  1329  		// Abort the entire assignment mechanism.
  1330  		if len(idlers.ids) == 0 {
  1331  			return
  1332  		}
  1333  		var (
  1334  			idle = idlers.ids[0]
  1335  			peer = s.peers[idle]
  1336  			cap  = idlers.caps[0]
  1337  		)
  1338  		idlers.ids, idlers.caps = idlers.ids[1:], idlers.caps[1:]
  1339  
  1340  		// Matched a pending task to an idle peer, allocate a unique request id
  1341  		var reqid uint64
  1342  		for {
  1343  			reqid = uint64(rand.Int63())
  1344  			if reqid == 0 {
  1345  				continue
  1346  			}
  1347  			if _, ok := s.trienodeHealReqs[reqid]; ok {
  1348  				continue
  1349  			}
  1350  			break
  1351  		}
  1352  		// Generate the network query and send it to the peer
  1353  		if cap > maxTrieRequestCount {
  1354  			cap = maxTrieRequestCount
  1355  		}
  1356  		cap = int(float64(cap) / s.trienodeHealThrottle)
  1357  		if cap <= 0 {
  1358  			cap = 1
  1359  		}
  1360  		var (
  1361  			hashes   = make([]common.Hash, 0, cap)
  1362  			paths    = make([]string, 0, cap)
  1363  			pathsets = make([]TrieNodePathSet, 0, cap)
  1364  		)
  1365  		for path, hash := range s.healer.trieTasks {
  1366  			delete(s.healer.trieTasks, path)
  1367  
  1368  			paths = append(paths, path)
  1369  			hashes = append(hashes, hash)
  1370  			if len(paths) >= cap {
  1371  				break
  1372  			}
  1373  		}
  1374  		// Group requests by account hash
  1375  		paths, hashes, _, pathsets = sortByAccountPath(paths, hashes)
  1376  		req := &trienodeHealRequest{
  1377  			peer:    idle,
  1378  			id:      reqid,
  1379  			time:    time.Now(),
  1380  			deliver: success,
  1381  			revert:  fail,
  1382  			cancel:  cancel,
  1383  			stale:   make(chan struct{}),
  1384  			paths:   paths,
  1385  			hashes:  hashes,
  1386  			task:    s.healer,
  1387  		}
  1388  		req.timeout = time.AfterFunc(s.rates.TargetTimeout(), func() {
  1389  			peer.Log().Debug("Trienode heal request timed out", "reqid", reqid)
  1390  			s.rates.Update(idle, TrieNodesMsg, 0, 0)
  1391  			s.scheduleRevertTrienodeHealRequest(req)
  1392  		})
  1393  		s.trienodeHealReqs[reqid] = req
  1394  		delete(s.trienodeHealIdlers, idle)
  1395  
  1396  		s.pend.Add(1)
  1397  		go func(root common.Hash) {
  1398  			defer s.pend.Done()
  1399  
  1400  			// Attempt to send the remote request and revert if it fails
  1401  			if err := peer.RequestTrieNodes(reqid, root, pathsets, maxRequestSize); err != nil {
  1402  				log.Debug("Failed to request trienode healers", "err", err)
  1403  				s.scheduleRevertTrienodeHealRequest(req)
  1404  			}
  1405  		}(s.root)
  1406  	}
  1407  }
  1408  
  1409  // assignBytecodeHealTasks attempts to match idle peers to bytecode requests to
  1410  // heal any trie errors caused by the snap sync's chunked retrieval model.
  1411  func (s *Syncer) assignBytecodeHealTasks(success chan *bytecodeHealResponse, fail chan *bytecodeHealRequest, cancel chan struct{}) {
  1412  	s.lock.Lock()
  1413  	defer s.lock.Unlock()
  1414  
  1415  	// Sort the peers by download capacity to use faster ones if many available
  1416  	idlers := &capacitySort{
  1417  		ids:  make([]string, 0, len(s.bytecodeHealIdlers)),
  1418  		caps: make([]int, 0, len(s.bytecodeHealIdlers)),
  1419  	}
  1420  	targetTTL := s.rates.TargetTimeout()
  1421  	for id := range s.bytecodeHealIdlers {
  1422  		if _, ok := s.statelessPeers[id]; ok {
  1423  			continue
  1424  		}
  1425  		idlers.ids = append(idlers.ids, id)
  1426  		idlers.caps = append(idlers.caps, s.rates.Capacity(id, ByteCodesMsg, targetTTL))
  1427  	}
  1428  	if len(idlers.ids) == 0 {
  1429  		return
  1430  	}
  1431  	sort.Sort(sort.Reverse(idlers))
  1432  
  1433  	// Iterate over pending tasks and try to find a peer to retrieve with
  1434  	for len(s.healer.codeTasks) > 0 || s.healer.scheduler.Pending() > 0 {
  1435  		// If there are not enough trie tasks queued to fully assign, fill the
  1436  		// queue from the state sync scheduler. The trie synced schedules these
  1437  		// together with trie nodes, so we need to queue them combined.
  1438  		var (
  1439  			have = len(s.healer.trieTasks) + len(s.healer.codeTasks)
  1440  			want = maxTrieRequestCount + maxCodeRequestCount
  1441  		)
  1442  		if have < want {
  1443  			paths, hashes, codes := s.healer.scheduler.Missing(want - have)
  1444  			for i, path := range paths {
  1445  				s.healer.trieTasks[path] = hashes[i]
  1446  			}
  1447  			for _, hash := range codes {
  1448  				s.healer.codeTasks[hash] = struct{}{}
  1449  			}
  1450  		}
  1451  		// If all the heal tasks are trienodes or already downloading, bail
  1452  		if len(s.healer.codeTasks) == 0 {
  1453  			return
  1454  		}
  1455  		// Task pending retrieval, try to find an idle peer. If no such peer
  1456  		// exists, we probably assigned tasks for all (or they are stateless).
  1457  		// Abort the entire assignment mechanism.
  1458  		if len(idlers.ids) == 0 {
  1459  			return
  1460  		}
  1461  		var (
  1462  			idle = idlers.ids[0]
  1463  			peer = s.peers[idle]
  1464  			cap  = idlers.caps[0]
  1465  		)
  1466  		idlers.ids, idlers.caps = idlers.ids[1:], idlers.caps[1:]
  1467  
  1468  		// Matched a pending task to an idle peer, allocate a unique request id
  1469  		var reqid uint64
  1470  		for {
  1471  			reqid = uint64(rand.Int63())
  1472  			if reqid == 0 {
  1473  				continue
  1474  			}
  1475  			if _, ok := s.bytecodeHealReqs[reqid]; ok {
  1476  				continue
  1477  			}
  1478  			break
  1479  		}
  1480  		// Generate the network query and send it to the peer
  1481  		if cap > maxCodeRequestCount {
  1482  			cap = maxCodeRequestCount
  1483  		}
  1484  		hashes := make([]common.Hash, 0, cap)
  1485  		for hash := range s.healer.codeTasks {
  1486  			delete(s.healer.codeTasks, hash)
  1487  
  1488  			hashes = append(hashes, hash)
  1489  			if len(hashes) >= cap {
  1490  				break
  1491  			}
  1492  		}
  1493  		req := &bytecodeHealRequest{
  1494  			peer:    idle,
  1495  			id:      reqid,
  1496  			time:    time.Now(),
  1497  			deliver: success,
  1498  			revert:  fail,
  1499  			cancel:  cancel,
  1500  			stale:   make(chan struct{}),
  1501  			hashes:  hashes,
  1502  			task:    s.healer,
  1503  		}
  1504  		req.timeout = time.AfterFunc(s.rates.TargetTimeout(), func() {
  1505  			peer.Log().Debug("Bytecode heal request timed out", "reqid", reqid)
  1506  			s.rates.Update(idle, ByteCodesMsg, 0, 0)
  1507  			s.scheduleRevertBytecodeHealRequest(req)
  1508  		})
  1509  		s.bytecodeHealReqs[reqid] = req
  1510  		delete(s.bytecodeHealIdlers, idle)
  1511  
  1512  		s.pend.Add(1)
  1513  		go func() {
  1514  			defer s.pend.Done()
  1515  
  1516  			// Attempt to send the remote request and revert if it fails
  1517  			if err := peer.RequestByteCodes(reqid, hashes, maxRequestSize); err != nil {
  1518  				log.Debug("Failed to request bytecode healers", "err", err)
  1519  				s.scheduleRevertBytecodeHealRequest(req)
  1520  			}
  1521  		}()
  1522  	}
  1523  }
  1524  
  1525  // revertRequests locates all the currently pending requests from a particular
  1526  // peer and reverts them, rescheduling for others to fulfill.
  1527  func (s *Syncer) revertRequests(peer string) {
  1528  	// Gather the requests first, revertals need the lock too
  1529  	s.lock.Lock()
  1530  	var accountReqs []*accountRequest
  1531  	for _, req := range s.accountReqs {
  1532  		if req.peer == peer {
  1533  			accountReqs = append(accountReqs, req)
  1534  		}
  1535  	}
  1536  	var bytecodeReqs []*bytecodeRequest
  1537  	for _, req := range s.bytecodeReqs {
  1538  		if req.peer == peer {
  1539  			bytecodeReqs = append(bytecodeReqs, req)
  1540  		}
  1541  	}
  1542  	var storageReqs []*storageRequest
  1543  	for _, req := range s.storageReqs {
  1544  		if req.peer == peer {
  1545  			storageReqs = append(storageReqs, req)
  1546  		}
  1547  	}
  1548  	var trienodeHealReqs []*trienodeHealRequest
  1549  	for _, req := range s.trienodeHealReqs {
  1550  		if req.peer == peer {
  1551  			trienodeHealReqs = append(trienodeHealReqs, req)
  1552  		}
  1553  	}
  1554  	var bytecodeHealReqs []*bytecodeHealRequest
  1555  	for _, req := range s.bytecodeHealReqs {
  1556  		if req.peer == peer {
  1557  			bytecodeHealReqs = append(bytecodeHealReqs, req)
  1558  		}
  1559  	}
  1560  	s.lock.Unlock()
  1561  
  1562  	// Revert all the requests matching the peer
  1563  	for _, req := range accountReqs {
  1564  		s.revertAccountRequest(req)
  1565  	}
  1566  	for _, req := range bytecodeReqs {
  1567  		s.revertBytecodeRequest(req)
  1568  	}
  1569  	for _, req := range storageReqs {
  1570  		s.revertStorageRequest(req)
  1571  	}
  1572  	for _, req := range trienodeHealReqs {
  1573  		s.revertTrienodeHealRequest(req)
  1574  	}
  1575  	for _, req := range bytecodeHealReqs {
  1576  		s.revertBytecodeHealRequest(req)
  1577  	}
  1578  }
  1579  
  1580  // scheduleRevertAccountRequest asks the event loop to clean up an account range
  1581  // request and return all failed retrieval tasks to the scheduler for reassignment.
  1582  func (s *Syncer) scheduleRevertAccountRequest(req *accountRequest) {
  1583  	select {
  1584  	case req.revert <- req:
  1585  		// Sync event loop notified
  1586  	case <-req.cancel:
  1587  		// Sync cycle got cancelled
  1588  	case <-req.stale:
  1589  		// Request already reverted
  1590  	}
  1591  }
  1592  
  1593  // revertAccountRequest cleans up an account range request and returns all failed
  1594  // retrieval tasks to the scheduler for reassignment.
  1595  //
  1596  // Note, this needs to run on the event runloop thread to reschedule to idle peers.
  1597  // On peer threads, use scheduleRevertAccountRequest.
  1598  func (s *Syncer) revertAccountRequest(req *accountRequest) {
  1599  	log.Debug("Reverting account request", "peer", req.peer, "reqid", req.id)
  1600  	select {
  1601  	case <-req.stale:
  1602  		log.Trace("Account request already reverted", "peer", req.peer, "reqid", req.id)
  1603  		return
  1604  	default:
  1605  	}
  1606  	close(req.stale)
  1607  
  1608  	// Remove the request from the tracked set
  1609  	s.lock.Lock()
  1610  	delete(s.accountReqs, req.id)
  1611  	s.lock.Unlock()
  1612  
  1613  	// If there's a timeout timer still running, abort it and mark the account
  1614  	// task as not-pending, ready for rescheduling
  1615  	req.timeout.Stop()
  1616  	if req.task.req == req {
  1617  		req.task.req = nil
  1618  	}
  1619  }
  1620  
  1621  // scheduleRevertBytecodeRequest asks the event loop to clean up a bytecode request
  1622  // and return all failed retrieval tasks to the scheduler for reassignment.
  1623  func (s *Syncer) scheduleRevertBytecodeRequest(req *bytecodeRequest) {
  1624  	select {
  1625  	case req.revert <- req:
  1626  		// Sync event loop notified
  1627  	case <-req.cancel:
  1628  		// Sync cycle got cancelled
  1629  	case <-req.stale:
  1630  		// Request already reverted
  1631  	}
  1632  }
  1633  
  1634  // revertBytecodeRequest cleans up a bytecode request and returns all failed
  1635  // retrieval tasks to the scheduler for reassignment.
  1636  //
  1637  // Note, this needs to run on the event runloop thread to reschedule to idle peers.
  1638  // On peer threads, use scheduleRevertBytecodeRequest.
  1639  func (s *Syncer) revertBytecodeRequest(req *bytecodeRequest) {
  1640  	log.Debug("Reverting bytecode request", "peer", req.peer)
  1641  	select {
  1642  	case <-req.stale:
  1643  		log.Trace("Bytecode request already reverted", "peer", req.peer, "reqid", req.id)
  1644  		return
  1645  	default:
  1646  	}
  1647  	close(req.stale)
  1648  
  1649  	// Remove the request from the tracked set
  1650  	s.lock.Lock()
  1651  	delete(s.bytecodeReqs, req.id)
  1652  	s.lock.Unlock()
  1653  
  1654  	// If there's a timeout timer still running, abort it and mark the code
  1655  	// retrievals as not-pending, ready for rescheduling
  1656  	req.timeout.Stop()
  1657  	for _, hash := range req.hashes {
  1658  		req.task.codeTasks[hash] = struct{}{}
  1659  	}
  1660  }
  1661  
  1662  // scheduleRevertStorageRequest asks the event loop to clean up a storage range
  1663  // request and return all failed retrieval tasks to the scheduler for reassignment.
  1664  func (s *Syncer) scheduleRevertStorageRequest(req *storageRequest) {
  1665  	select {
  1666  	case req.revert <- req:
  1667  		// Sync event loop notified
  1668  	case <-req.cancel:
  1669  		// Sync cycle got cancelled
  1670  	case <-req.stale:
  1671  		// Request already reverted
  1672  	}
  1673  }
  1674  
  1675  // revertStorageRequest cleans up a storage range request and returns all failed
  1676  // retrieval tasks to the scheduler for reassignment.
  1677  //
  1678  // Note, this needs to run on the event runloop thread to reschedule to idle peers.
  1679  // On peer threads, use scheduleRevertStorageRequest.
  1680  func (s *Syncer) revertStorageRequest(req *storageRequest) {
  1681  	log.Debug("Reverting storage request", "peer", req.peer)
  1682  	select {
  1683  	case <-req.stale:
  1684  		log.Trace("Storage request already reverted", "peer", req.peer, "reqid", req.id)
  1685  		return
  1686  	default:
  1687  	}
  1688  	close(req.stale)
  1689  
  1690  	// Remove the request from the tracked set
  1691  	s.lock.Lock()
  1692  	delete(s.storageReqs, req.id)
  1693  	s.lock.Unlock()
  1694  
  1695  	// If there's a timeout timer still running, abort it and mark the storage
  1696  	// task as not-pending, ready for rescheduling
  1697  	req.timeout.Stop()
  1698  	if req.subTask != nil {
  1699  		req.subTask.req = nil
  1700  	} else {
  1701  		for i, account := range req.accounts {
  1702  			req.mainTask.stateTasks[account] = req.roots[i]
  1703  		}
  1704  	}
  1705  }
  1706  
  1707  // scheduleRevertTrienodeHealRequest asks the event loop to clean up a trienode heal
  1708  // request and return all failed retrieval tasks to the scheduler for reassignment.
  1709  func (s *Syncer) scheduleRevertTrienodeHealRequest(req *trienodeHealRequest) {
  1710  	select {
  1711  	case req.revert <- req:
  1712  		// Sync event loop notified
  1713  	case <-req.cancel:
  1714  		// Sync cycle got cancelled
  1715  	case <-req.stale:
  1716  		// Request already reverted
  1717  	}
  1718  }
  1719  
  1720  // revertTrienodeHealRequest cleans up a trienode heal request and returns all
  1721  // failed retrieval tasks to the scheduler for reassignment.
  1722  //
  1723  // Note, this needs to run on the event runloop thread to reschedule to idle peers.
  1724  // On peer threads, use scheduleRevertTrienodeHealRequest.
  1725  func (s *Syncer) revertTrienodeHealRequest(req *trienodeHealRequest) {
  1726  	log.Debug("Reverting trienode heal request", "peer", req.peer)
  1727  	select {
  1728  	case <-req.stale:
  1729  		log.Trace("Trienode heal request already reverted", "peer", req.peer, "reqid", req.id)
  1730  		return
  1731  	default:
  1732  	}
  1733  	close(req.stale)
  1734  
  1735  	// Remove the request from the tracked set
  1736  	s.lock.Lock()
  1737  	delete(s.trienodeHealReqs, req.id)
  1738  	s.lock.Unlock()
  1739  
  1740  	// If there's a timeout timer still running, abort it and mark the trie node
  1741  	// retrievals as not-pending, ready for rescheduling
  1742  	req.timeout.Stop()
  1743  	for i, path := range req.paths {
  1744  		req.task.trieTasks[path] = req.hashes[i]
  1745  	}
  1746  }
  1747  
  1748  // scheduleRevertBytecodeHealRequest asks the event loop to clean up a bytecode heal
  1749  // request and return all failed retrieval tasks to the scheduler for reassignment.
  1750  func (s *Syncer) scheduleRevertBytecodeHealRequest(req *bytecodeHealRequest) {
  1751  	select {
  1752  	case req.revert <- req:
  1753  		// Sync event loop notified
  1754  	case <-req.cancel:
  1755  		// Sync cycle got cancelled
  1756  	case <-req.stale:
  1757  		// Request already reverted
  1758  	}
  1759  }
  1760  
  1761  // revertBytecodeHealRequest cleans up a bytecode heal request and returns all
  1762  // failed retrieval tasks to the scheduler for reassignment.
  1763  //
  1764  // Note, this needs to run on the event runloop thread to reschedule to idle peers.
  1765  // On peer threads, use scheduleRevertBytecodeHealRequest.
  1766  func (s *Syncer) revertBytecodeHealRequest(req *bytecodeHealRequest) {
  1767  	log.Debug("Reverting bytecode heal request", "peer", req.peer)
  1768  	select {
  1769  	case <-req.stale:
  1770  		log.Trace("Bytecode heal request already reverted", "peer", req.peer, "reqid", req.id)
  1771  		return
  1772  	default:
  1773  	}
  1774  	close(req.stale)
  1775  
  1776  	// Remove the request from the tracked set
  1777  	s.lock.Lock()
  1778  	delete(s.bytecodeHealReqs, req.id)
  1779  	s.lock.Unlock()
  1780  
  1781  	// If there's a timeout timer still running, abort it and mark the code
  1782  	// retrievals as not-pending, ready for rescheduling
  1783  	req.timeout.Stop()
  1784  	for _, hash := range req.hashes {
  1785  		req.task.codeTasks[hash] = struct{}{}
  1786  	}
  1787  }
  1788  
  1789  // processAccountResponse integrates an already validated account range response
  1790  // into the account tasks.
  1791  func (s *Syncer) processAccountResponse(res *accountResponse) {
  1792  	// Switch the task from pending to filling
  1793  	res.task.req = nil
  1794  	res.task.res = res
  1795  
  1796  	// Ensure that the response doesn't overflow into the subsequent task
  1797  	last := res.task.Last.Big()
  1798  	for i, hash := range res.hashes {
  1799  		// Mark the range complete if the last is already included.
  1800  		// Keep iteration to delete the extra states if exists.
  1801  		cmp := hash.Big().Cmp(last)
  1802  		if cmp == 0 {
  1803  			res.cont = false
  1804  			continue
  1805  		}
  1806  		if cmp > 0 {
  1807  			// Chunk overflown, cut off excess
  1808  			res.hashes = res.hashes[:i]
  1809  			res.accounts = res.accounts[:i]
  1810  			res.cont = false // Mark range completed
  1811  			break
  1812  		}
  1813  	}
  1814  	// Iterate over all the accounts and assemble which ones need further sub-
  1815  	// filling before the entire account range can be persisted.
  1816  	res.task.needCode = make([]bool, len(res.accounts))
  1817  	res.task.needState = make([]bool, len(res.accounts))
  1818  	res.task.needHeal = make([]bool, len(res.accounts))
  1819  
  1820  	res.task.codeTasks = make(map[common.Hash]struct{})
  1821  	res.task.stateTasks = make(map[common.Hash]common.Hash)
  1822  
  1823  	resumed := make(map[common.Hash]struct{})
  1824  
  1825  	res.task.pend = 0
  1826  	for i, account := range res.accounts {
  1827  		// Check if the account is a contract with an unknown code
  1828  		if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
  1829  			if !rawdb.HasCodeWithPrefix(s.db, common.BytesToHash(account.CodeHash)) {
  1830  				res.task.codeTasks[common.BytesToHash(account.CodeHash)] = struct{}{}
  1831  				res.task.needCode[i] = true
  1832  				res.task.pend++
  1833  			}
  1834  		}
  1835  		// Check if the account is a contract with an unknown storage trie
  1836  		if account.Root != types.EmptyRootHash {
  1837  			if !rawdb.HasTrieNode(s.db, res.hashes[i], nil, account.Root, s.scheme) {
  1838  				// If there was a previous large state retrieval in progress,
  1839  				// don't restart it from scratch. This happens if a sync cycle
  1840  				// is interrupted and resumed later. However, *do* update the
  1841  				// previous root hash.
  1842  				if subtasks, ok := res.task.SubTasks[res.hashes[i]]; ok {
  1843  					log.Debug("Resuming large storage retrieval", "account", res.hashes[i], "root", account.Root)
  1844  					for _, subtask := range subtasks {
  1845  						subtask.root = account.Root
  1846  					}
  1847  					res.task.needHeal[i] = true
  1848  					resumed[res.hashes[i]] = struct{}{}
  1849  				} else {
  1850  					res.task.stateTasks[res.hashes[i]] = account.Root
  1851  				}
  1852  				res.task.needState[i] = true
  1853  				res.task.pend++
  1854  			}
  1855  		}
  1856  	}
  1857  	// Delete any subtasks that have been aborted but not resumed. This may undo
  1858  	// some progress if a new peer gives us less accounts than an old one, but for
  1859  	// now we have to live with that.
  1860  	for hash := range res.task.SubTasks {
  1861  		if _, ok := resumed[hash]; !ok {
  1862  			log.Debug("Aborting suspended storage retrieval", "account", hash)
  1863  			delete(res.task.SubTasks, hash)
  1864  		}
  1865  	}
  1866  	// If the account range contained no contracts, or all have been fully filled
  1867  	// beforehand, short circuit storage filling and forward to the next task
  1868  	if res.task.pend == 0 {
  1869  		s.forwardAccountTask(res.task)
  1870  		return
  1871  	}
  1872  	// Some accounts are incomplete, leave as is for the storage and contract
  1873  	// task assigners to pick up and fill.
  1874  }
  1875  
  1876  // processBytecodeResponse integrates an already validated bytecode response
  1877  // into the account tasks.
  1878  func (s *Syncer) processBytecodeResponse(res *bytecodeResponse) {
  1879  	batch := s.db.NewBatch()
  1880  
  1881  	var (
  1882  		codes uint64
  1883  	)
  1884  	for i, hash := range res.hashes {
  1885  		code := res.codes[i]
  1886  
  1887  		// If the bytecode was not delivered, reschedule it
  1888  		if code == nil {
  1889  			res.task.codeTasks[hash] = struct{}{}
  1890  			continue
  1891  		}
  1892  		// Code was delivered, mark it not needed any more
  1893  		for j, account := range res.task.res.accounts {
  1894  			if res.task.needCode[j] && hash == common.BytesToHash(account.CodeHash) {
  1895  				res.task.needCode[j] = false
  1896  				res.task.pend--
  1897  			}
  1898  		}
  1899  		// Push the bytecode into a database batch
  1900  		codes++
  1901  		rawdb.WriteCode(batch, hash, code)
  1902  	}
  1903  	bytes := common.StorageSize(batch.ValueSize())
  1904  	if err := batch.Write(); err != nil {
  1905  		log.Crit("Failed to persist bytecodes", "err", err)
  1906  	}
  1907  	s.bytecodeSynced += codes
  1908  	s.bytecodeBytes += bytes
  1909  
  1910  	log.Debug("Persisted set of bytecodes", "count", codes, "bytes", bytes)
  1911  
  1912  	// If this delivery completed the last pending task, forward the account task
  1913  	// to the next chunk
  1914  	if res.task.pend == 0 {
  1915  		s.forwardAccountTask(res.task)
  1916  		return
  1917  	}
  1918  	// Some accounts are still incomplete, leave as is for the storage and contract
  1919  	// task assigners to pick up and fill.
  1920  }
  1921  
  1922  // processStorageResponse integrates an already validated storage response
  1923  // into the account tasks.
  1924  func (s *Syncer) processStorageResponse(res *storageResponse) {
  1925  	// Switch the subtask from pending to idle
  1926  	if res.subTask != nil {
  1927  		res.subTask.req = nil
  1928  	}
  1929  	batch := ethdb.HookedBatch{
  1930  		Batch: s.db.NewBatch(),
  1931  		OnPut: func(key []byte, value []byte) {
  1932  			s.storageBytes += common.StorageSize(len(key) + len(value))
  1933  		},
  1934  	}
  1935  	var (
  1936  		slots           int
  1937  		oldStorageBytes = s.storageBytes
  1938  	)
  1939  	// Iterate over all the accounts and reconstruct their storage tries from the
  1940  	// delivered slots
  1941  	for i, account := range res.accounts {
  1942  		// If the account was not delivered, reschedule it
  1943  		if i >= len(res.hashes) {
  1944  			res.mainTask.stateTasks[account] = res.roots[i]
  1945  			continue
  1946  		}
  1947  		// State was delivered, if complete mark as not needed any more, otherwise
  1948  		// mark the account as needing healing
  1949  		for j, hash := range res.mainTask.res.hashes {
  1950  			if account != hash {
  1951  				continue
  1952  			}
  1953  			acc := res.mainTask.res.accounts[j]
  1954  
  1955  			// If the packet contains multiple contract storage slots, all
  1956  			// but the last are surely complete. The last contract may be
  1957  			// chunked, so check it's continuation flag.
  1958  			if res.subTask == nil && res.mainTask.needState[j] && (i < len(res.hashes)-1 || !res.cont) {
  1959  				res.mainTask.needState[j] = false
  1960  				res.mainTask.pend--
  1961  			}
  1962  			// If the last contract was chunked, mark it as needing healing
  1963  			// to avoid writing it out to disk prematurely.
  1964  			if res.subTask == nil && !res.mainTask.needHeal[j] && i == len(res.hashes)-1 && res.cont {
  1965  				res.mainTask.needHeal[j] = true
  1966  			}
  1967  			// If the last contract was chunked, we need to switch to large
  1968  			// contract handling mode
  1969  			if res.subTask == nil && i == len(res.hashes)-1 && res.cont {
  1970  				// If we haven't yet started a large-contract retrieval, create
  1971  				// the subtasks for it within the main account task
  1972  				if tasks, ok := res.mainTask.SubTasks[account]; !ok {
  1973  					var (
  1974  						keys    = res.hashes[i]
  1975  						chunks  = uint64(storageConcurrency)
  1976  						lastKey common.Hash
  1977  					)
  1978  					if len(keys) > 0 {
  1979  						lastKey = keys[len(keys)-1]
  1980  					}
  1981  					// If the number of slots remaining is low, decrease the
  1982  					// number of chunks. Somewhere on the order of 10-15K slots
  1983  					// fit into a packet of 500KB. A key/slot pair is maximum 64
  1984  					// bytes, so pessimistically maxRequestSize/64 = 8K.
  1985  					//
  1986  					// Chunk so that at least 2 packets are needed to fill a task.
  1987  					if estimate, err := estimateRemainingSlots(len(keys), lastKey); err == nil {
  1988  						if n := estimate / (2 * (maxRequestSize / 64)); n+1 < chunks {
  1989  							chunks = n + 1
  1990  						}
  1991  						log.Debug("Chunked large contract", "initiators", len(keys), "tail", lastKey, "remaining", estimate, "chunks", chunks)
  1992  					} else {
  1993  						log.Debug("Chunked large contract", "initiators", len(keys), "tail", lastKey, "chunks", chunks)
  1994  					}
  1995  					r := newHashRange(lastKey, chunks)
  1996  
  1997  					// Our first task is the one that was just filled by this response.
  1998  					batch := ethdb.HookedBatch{
  1999  						Batch: s.db.NewBatch(),
  2000  						OnPut: func(key []byte, value []byte) {
  2001  							s.storageBytes += common.StorageSize(len(key) + len(value))
  2002  						},
  2003  					}
  2004  					tasks = append(tasks, &storageTask{
  2005  						Next:     common.Hash{},
  2006  						Last:     r.End(),
  2007  						root:     acc.Root,
  2008  						genBatch: batch,
  2009  						genTrie: trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) {
  2010  							rawdb.WriteTrieNode(batch, owner, path, hash, val, s.scheme)
  2011  						}, account),
  2012  					})
  2013  					for r.Next() {
  2014  						batch := ethdb.HookedBatch{
  2015  							Batch: s.db.NewBatch(),
  2016  							OnPut: func(key []byte, value []byte) {
  2017  								s.storageBytes += common.StorageSize(len(key) + len(value))
  2018  							},
  2019  						}
  2020  						tasks = append(tasks, &storageTask{
  2021  							Next:     r.Start(),
  2022  							Last:     r.End(),
  2023  							root:     acc.Root,
  2024  							genBatch: batch,
  2025  							genTrie: trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) {
  2026  								rawdb.WriteTrieNode(batch, owner, path, hash, val, s.scheme)
  2027  							}, account),
  2028  						})
  2029  					}
  2030  					for _, task := range tasks {
  2031  						log.Debug("Created storage sync task", "account", account, "root", acc.Root, "from", task.Next, "last", task.Last)
  2032  					}
  2033  					res.mainTask.SubTasks[account] = tasks
  2034  
  2035  					// Since we've just created the sub-tasks, this response
  2036  					// is surely for the first one (zero origin)
  2037  					res.subTask = tasks[0]
  2038  				}
  2039  			}
  2040  			// If we're in large contract delivery mode, forward the subtask
  2041  			if res.subTask != nil {
  2042  				// Ensure the response doesn't overflow into the subsequent task
  2043  				last := res.subTask.Last.Big()
  2044  				// Find the first overflowing key. While at it, mark res as complete
  2045  				// if we find the range to include or pass the 'last'
  2046  				index := sort.Search(len(res.hashes[i]), func(k int) bool {
  2047  					cmp := res.hashes[i][k].Big().Cmp(last)
  2048  					if cmp >= 0 {
  2049  						res.cont = false
  2050  					}
  2051  					return cmp > 0
  2052  				})
  2053  				if index >= 0 {
  2054  					// cut off excess
  2055  					res.hashes[i] = res.hashes[i][:index]
  2056  					res.slots[i] = res.slots[i][:index]
  2057  				}
  2058  				// Forward the relevant storage chunk (even if created just now)
  2059  				if res.cont {
  2060  					res.subTask.Next = incHash(res.hashes[i][len(res.hashes[i])-1])
  2061  				} else {
  2062  					res.subTask.done = true
  2063  				}
  2064  			}
  2065  		}
  2066  		// Iterate over all the complete contracts, reconstruct the trie nodes and
  2067  		// push them to disk. If the contract is chunked, the trie nodes will be
  2068  		// reconstructed later.
  2069  		slots += len(res.hashes[i])
  2070  
  2071  		if i < len(res.hashes)-1 || res.subTask == nil {
  2072  			tr := trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) {
  2073  				rawdb.WriteTrieNode(batch, owner, path, hash, val, s.scheme)
  2074  			}, account)
  2075  			for j := 0; j < len(res.hashes[i]); j++ {
  2076  				tr.Update(res.hashes[i][j][:], res.slots[i][j])
  2077  			}
  2078  			tr.Commit()
  2079  		}
  2080  		// Persist the received storage segments. These flat state maybe
  2081  		// outdated during the sync, but it can be fixed later during the
  2082  		// snapshot generation.
  2083  		for j := 0; j < len(res.hashes[i]); j++ {
  2084  			rawdb.WriteStorageSnapshot(batch, account, res.hashes[i][j], res.slots[i][j])
  2085  
  2086  			// If we're storing large contracts, generate the trie nodes
  2087  			// on the fly to not trash the gluing points
  2088  			if i == len(res.hashes)-1 && res.subTask != nil {
  2089  				res.subTask.genTrie.Update(res.hashes[i][j][:], res.slots[i][j])
  2090  			}
  2091  		}
  2092  	}
  2093  	// Large contracts could have generated new trie nodes, flush them to disk
  2094  	if res.subTask != nil {
  2095  		if res.subTask.done {
  2096  			if root, err := res.subTask.genTrie.Commit(); err != nil {
  2097  				log.Error("Failed to commit stack slots", "err", err)
  2098  			} else if root == res.subTask.root {
  2099  				// If the chunk's root is an overflown but full delivery, clear the heal request
  2100  				for i, account := range res.mainTask.res.hashes {
  2101  					if account == res.accounts[len(res.accounts)-1] {
  2102  						res.mainTask.needHeal[i] = false
  2103  					}
  2104  				}
  2105  			}
  2106  		}
  2107  		if res.subTask.genBatch.ValueSize() > ethdb.IdealBatchSize || res.subTask.done {
  2108  			if err := res.subTask.genBatch.Write(); err != nil {
  2109  				log.Error("Failed to persist stack slots", "err", err)
  2110  			}
  2111  			res.subTask.genBatch.Reset()
  2112  		}
  2113  	}
  2114  	// Flush anything written just now and update the stats
  2115  	if err := batch.Write(); err != nil {
  2116  		log.Crit("Failed to persist storage slots", "err", err)
  2117  	}
  2118  	s.storageSynced += uint64(slots)
  2119  
  2120  	log.Debug("Persisted set of storage slots", "accounts", len(res.hashes), "slots", slots, "bytes", s.storageBytes-oldStorageBytes)
  2121  
  2122  	// If this delivery completed the last pending task, forward the account task
  2123  	// to the next chunk
  2124  	if res.mainTask.pend == 0 {
  2125  		s.forwardAccountTask(res.mainTask)
  2126  		return
  2127  	}
  2128  	// Some accounts are still incomplete, leave as is for the storage and contract
  2129  	// task assigners to pick up and fill.
  2130  }
  2131  
  2132  // processTrienodeHealResponse integrates an already validated trienode response
  2133  // into the healer tasks.
  2134  func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) {
  2135  	var (
  2136  		start = time.Now()
  2137  		fills int
  2138  	)
  2139  	for i, hash := range res.hashes {
  2140  		node := res.nodes[i]
  2141  
  2142  		// If the trie node was not delivered, reschedule it
  2143  		if node == nil {
  2144  			res.task.trieTasks[res.paths[i]] = res.hashes[i]
  2145  			continue
  2146  		}
  2147  		fills++
  2148  
  2149  		// Push the trie node into the state syncer
  2150  		s.trienodeHealSynced++
  2151  		s.trienodeHealBytes += common.StorageSize(len(node))
  2152  
  2153  		err := s.healer.scheduler.ProcessNode(trie.NodeSyncResult{Path: res.paths[i], Data: node})
  2154  		switch err {
  2155  		case nil:
  2156  		case trie.ErrAlreadyProcessed:
  2157  			s.trienodeHealDups++
  2158  		case trie.ErrNotRequested:
  2159  			s.trienodeHealNops++
  2160  		default:
  2161  			log.Error("Invalid trienode processed", "hash", hash, "err", err)
  2162  		}
  2163  	}
  2164  	s.commitHealer(false)
  2165  
  2166  	// Calculate the processing rate of one filled trie node
  2167  	rate := float64(fills) / (float64(time.Since(start)) / float64(time.Second))
  2168  
  2169  	// Update the currently measured trienode queueing and processing throughput.
  2170  	//
  2171  	// The processing rate needs to be updated uniformly independent if we've
  2172  	// processed 1x100 trie nodes or 100x1 to keep the rate consistent even in
  2173  	// the face of varying network packets. As such, we cannot just measure the
  2174  	// time it took to process N trie nodes and update once, we need one update
  2175  	// per trie node.
  2176  	//
  2177  	// Naively, that would be:
  2178  	//
  2179  	//   for i:=0; i<fills; i++ {
  2180  	//     healRate = (1-measurementImpact)*oldRate + measurementImpact*newRate
  2181  	//   }
  2182  	//
  2183  	// Essentially, a recursive expansion of HR = (1-MI)*HR + MI*NR.
  2184  	//
  2185  	// We can expand that formula for the Nth item as:
  2186  	//   HR(N) = (1-MI)^N*OR + (1-MI)^(N-1)*MI*NR + (1-MI)^(N-2)*MI*NR + ... + (1-MI)^0*MI*NR
  2187  	//
  2188  	// The above is a geometric sequence that can be summed to:
  2189  	//   HR(N) = (1-MI)^N*(OR-NR) + NR
  2190  	s.trienodeHealRate = gomath.Pow(1-trienodeHealRateMeasurementImpact, float64(fills))*(s.trienodeHealRate-rate) + rate
  2191  
  2192  	pending := s.trienodeHealPend.Load()
  2193  	if time.Since(s.trienodeHealThrottled) > time.Second {
  2194  		// Periodically adjust the trie node throttler
  2195  		if float64(pending) > 2*s.trienodeHealRate {
  2196  			s.trienodeHealThrottle *= trienodeHealThrottleIncrease
  2197  		} else {
  2198  			s.trienodeHealThrottle /= trienodeHealThrottleDecrease
  2199  		}
  2200  		if s.trienodeHealThrottle > maxTrienodeHealThrottle {
  2201  			s.trienodeHealThrottle = maxTrienodeHealThrottle
  2202  		} else if s.trienodeHealThrottle < minTrienodeHealThrottle {
  2203  			s.trienodeHealThrottle = minTrienodeHealThrottle
  2204  		}
  2205  		s.trienodeHealThrottled = time.Now()
  2206  
  2207  		log.Debug("Updated trie node heal throttler", "rate", s.trienodeHealRate, "pending", pending, "throttle", s.trienodeHealThrottle)
  2208  	}
  2209  }
  2210  
  2211  func (s *Syncer) commitHealer(force bool) {
  2212  	if !force && s.healer.scheduler.MemSize() < ethdb.IdealBatchSize {
  2213  		return
  2214  	}
  2215  	batch := s.db.NewBatch()
  2216  	if err := s.healer.scheduler.Commit(batch); err != nil {
  2217  		log.Error("Failed to commit healing data", "err", err)
  2218  	}
  2219  	if err := batch.Write(); err != nil {
  2220  		log.Crit("Failed to persist healing data", "err", err)
  2221  	}
  2222  	log.Debug("Persisted set of healing data", "type", "trienodes", "bytes", common.StorageSize(batch.ValueSize()))
  2223  }
  2224  
  2225  // processBytecodeHealResponse integrates an already validated bytecode response
  2226  // into the healer tasks.
  2227  func (s *Syncer) processBytecodeHealResponse(res *bytecodeHealResponse) {
  2228  	for i, hash := range res.hashes {
  2229  		node := res.codes[i]
  2230  
  2231  		// If the trie node was not delivered, reschedule it
  2232  		if node == nil {
  2233  			res.task.codeTasks[hash] = struct{}{}
  2234  			continue
  2235  		}
  2236  		// Push the trie node into the state syncer
  2237  		s.bytecodeHealSynced++
  2238  		s.bytecodeHealBytes += common.StorageSize(len(node))
  2239  
  2240  		err := s.healer.scheduler.ProcessCode(trie.CodeSyncResult{Hash: hash, Data: node})
  2241  		switch err {
  2242  		case nil:
  2243  		case trie.ErrAlreadyProcessed:
  2244  			s.bytecodeHealDups++
  2245  		case trie.ErrNotRequested:
  2246  			s.bytecodeHealNops++
  2247  		default:
  2248  			log.Error("Invalid bytecode processed", "hash", hash, "err", err)
  2249  		}
  2250  	}
  2251  	s.commitHealer(false)
  2252  }
  2253  
  2254  // forwardAccountTask takes a filled account task and persists anything available
  2255  // into the database, after which it forwards the next account marker so that the
  2256  // task's next chunk may be filled.
  2257  func (s *Syncer) forwardAccountTask(task *accountTask) {
  2258  	// Remove any pending delivery
  2259  	res := task.res
  2260  	if res == nil {
  2261  		return // nothing to forward
  2262  	}
  2263  	task.res = nil
  2264  
  2265  	// Persist the received account segments. These flat state maybe
  2266  	// outdated during the sync, but it can be fixed later during the
  2267  	// snapshot generation.
  2268  	oldAccountBytes := s.accountBytes
  2269  
  2270  	batch := ethdb.HookedBatch{
  2271  		Batch: s.db.NewBatch(),
  2272  		OnPut: func(key []byte, value []byte) {
  2273  			s.accountBytes += common.StorageSize(len(key) + len(value))
  2274  		},
  2275  	}
  2276  	for i, hash := range res.hashes {
  2277  		if task.needCode[i] || task.needState[i] {
  2278  			break
  2279  		}
  2280  		slim := snapshot.SlimAccountRLP(res.accounts[i].Nonce, res.accounts[i].Balance, res.accounts[i].Root, res.accounts[i].CodeHash)
  2281  		rawdb.WriteAccountSnapshot(batch, hash, slim)
  2282  
  2283  		// If the task is complete, drop it into the stack trie to generate
  2284  		// account trie nodes for it
  2285  		if !task.needHeal[i] {
  2286  			full, err := snapshot.FullAccountRLP(slim) // TODO(karalabe): Slim parsing can be omitted
  2287  			if err != nil {
  2288  				panic(err) // Really shouldn't ever happen
  2289  			}
  2290  			task.genTrie.Update(hash[:], full)
  2291  		}
  2292  	}
  2293  	// Flush anything written just now and update the stats
  2294  	if err := batch.Write(); err != nil {
  2295  		log.Crit("Failed to persist accounts", "err", err)
  2296  	}
  2297  	s.accountSynced += uint64(len(res.accounts))
  2298  
  2299  	// Task filling persisted, push it the chunk marker forward to the first
  2300  	// account still missing data.
  2301  	for i, hash := range res.hashes {
  2302  		if task.needCode[i] || task.needState[i] {
  2303  			return
  2304  		}
  2305  		task.Next = incHash(hash)
  2306  	}
  2307  	// All accounts marked as complete, track if the entire task is done
  2308  	task.done = !res.cont
  2309  
  2310  	// Stack trie could have generated trie nodes, push them to disk (we need to
  2311  	// flush after finalizing task.done. It's fine even if we crash and lose this
  2312  	// write as it will only cause more data to be downloaded during heal.
  2313  	if task.done {
  2314  		if _, err := task.genTrie.Commit(); err != nil {
  2315  			log.Error("Failed to commit stack account", "err", err)
  2316  		}
  2317  	}
  2318  	if task.genBatch.ValueSize() > ethdb.IdealBatchSize || task.done {
  2319  		if err := task.genBatch.Write(); err != nil {
  2320  			log.Error("Failed to persist stack account", "err", err)
  2321  		}
  2322  		task.genBatch.Reset()
  2323  	}
  2324  	log.Debug("Persisted range of accounts", "accounts", len(res.accounts), "bytes", s.accountBytes-oldAccountBytes)
  2325  }
  2326  
  2327  // OnAccounts is a callback method to invoke when a range of accounts are
  2328  // received from a remote peer.
  2329  func (s *Syncer) OnAccounts(peer SyncPeer, id uint64, hashes []common.Hash, accounts [][]byte, proof [][]byte) error {
  2330  	size := common.StorageSize(len(hashes) * common.HashLength)
  2331  	for _, account := range accounts {
  2332  		size += common.StorageSize(len(account))
  2333  	}
  2334  	for _, node := range proof {
  2335  		size += common.StorageSize(len(node))
  2336  	}
  2337  	logger := peer.Log().New("reqid", id)
  2338  	logger.Trace("Delivering range of accounts", "hashes", len(hashes), "accounts", len(accounts), "proofs", len(proof), "bytes", size)
  2339  
  2340  	// Whether or not the response is valid, we can mark the peer as idle and
  2341  	// notify the scheduler to assign a new task. If the response is invalid,
  2342  	// we'll drop the peer in a bit.
  2343  	defer func() {
  2344  		s.lock.Lock()
  2345  		defer s.lock.Unlock()
  2346  		if _, ok := s.peers[peer.ID()]; ok {
  2347  			s.accountIdlers[peer.ID()] = struct{}{}
  2348  		}
  2349  		select {
  2350  		case s.update <- struct{}{}:
  2351  		default:
  2352  		}
  2353  	}()
  2354  	s.lock.Lock()
  2355  	// Ensure the response is for a valid request
  2356  	req, ok := s.accountReqs[id]
  2357  	if !ok {
  2358  		// Request stale, perhaps the peer timed out but came through in the end
  2359  		logger.Warn("Unexpected account range packet")
  2360  		s.lock.Unlock()
  2361  		return nil
  2362  	}
  2363  	delete(s.accountReqs, id)
  2364  	s.rates.Update(peer.ID(), AccountRangeMsg, time.Since(req.time), int(size))
  2365  
  2366  	// Clean up the request timeout timer, we'll see how to proceed further based
  2367  	// on the actual delivered content
  2368  	if !req.timeout.Stop() {
  2369  		// The timeout is already triggered, and this request will be reverted+rescheduled
  2370  		s.lock.Unlock()
  2371  		return nil
  2372  	}
  2373  	// Response is valid, but check if peer is signalling that it does not have
  2374  	// the requested data. For account range queries that means the state being
  2375  	// retrieved was either already pruned remotely, or the peer is not yet
  2376  	// synced to our head.
  2377  	if len(hashes) == 0 && len(accounts) == 0 && len(proof) == 0 {
  2378  		logger.Debug("Peer rejected account range request", "root", s.root)
  2379  		s.statelessPeers[peer.ID()] = struct{}{}
  2380  		s.lock.Unlock()
  2381  
  2382  		// Signal this request as failed, and ready for rescheduling
  2383  		s.scheduleRevertAccountRequest(req)
  2384  		return nil
  2385  	}
  2386  	root := s.root
  2387  	s.lock.Unlock()
  2388  
  2389  	// Reconstruct a partial trie from the response and verify it
  2390  	keys := make([][]byte, len(hashes))
  2391  	for i, key := range hashes {
  2392  		keys[i] = common.CopyBytes(key[:])
  2393  	}
  2394  	nodes := make(light.NodeList, len(proof))
  2395  	for i, node := range proof {
  2396  		nodes[i] = node
  2397  	}
  2398  	proofdb := nodes.NodeSet()
  2399  
  2400  	var end []byte
  2401  	if len(keys) > 0 {
  2402  		end = keys[len(keys)-1]
  2403  	}
  2404  	cont, err := trie.VerifyRangeProof(root, req.origin[:], end, keys, accounts, proofdb)
  2405  	if err != nil {
  2406  		logger.Warn("Account range failed proof", "err", err)
  2407  		// Signal this request as failed, and ready for rescheduling
  2408  		s.scheduleRevertAccountRequest(req)
  2409  		return err
  2410  	}
  2411  	accs := make([]*types.StateAccount, len(accounts))
  2412  	for i, account := range accounts {
  2413  		acc := new(types.StateAccount)
  2414  		if err := rlp.DecodeBytes(account, acc); err != nil {
  2415  			panic(err) // We created these blobs, we must be able to decode them
  2416  		}
  2417  		accs[i] = acc
  2418  	}
  2419  	response := &accountResponse{
  2420  		task:     req.task,
  2421  		hashes:   hashes,
  2422  		accounts: accs,
  2423  		cont:     cont,
  2424  	}
  2425  	select {
  2426  	case req.deliver <- response:
  2427  	case <-req.cancel:
  2428  	case <-req.stale:
  2429  	}
  2430  	return nil
  2431  }
  2432  
  2433  // OnByteCodes is a callback method to invoke when a batch of contract
  2434  // bytes codes are received from a remote peer.
  2435  func (s *Syncer) OnByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) error {
  2436  	s.lock.RLock()
  2437  	syncing := !s.snapped
  2438  	s.lock.RUnlock()
  2439  
  2440  	if syncing {
  2441  		return s.onByteCodes(peer, id, bytecodes)
  2442  	}
  2443  	return s.onHealByteCodes(peer, id, bytecodes)
  2444  }
  2445  
  2446  // onByteCodes is a callback method to invoke when a batch of contract
  2447  // bytes codes are received from a remote peer in the syncing phase.
  2448  func (s *Syncer) onByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) error {
  2449  	var size common.StorageSize
  2450  	for _, code := range bytecodes {
  2451  		size += common.StorageSize(len(code))
  2452  	}
  2453  	logger := peer.Log().New("reqid", id)
  2454  	logger.Trace("Delivering set of bytecodes", "bytecodes", len(bytecodes), "bytes", size)
  2455  
  2456  	// Whether or not the response is valid, we can mark the peer as idle and
  2457  	// notify the scheduler to assign a new task. If the response is invalid,
  2458  	// we'll drop the peer in a bit.
  2459  	defer func() {
  2460  		s.lock.Lock()
  2461  		defer s.lock.Unlock()
  2462  		if _, ok := s.peers[peer.ID()]; ok {
  2463  			s.bytecodeIdlers[peer.ID()] = struct{}{}
  2464  		}
  2465  		select {
  2466  		case s.update <- struct{}{}:
  2467  		default:
  2468  		}
  2469  	}()
  2470  	s.lock.Lock()
  2471  	// Ensure the response is for a valid request
  2472  	req, ok := s.bytecodeReqs[id]
  2473  	if !ok {
  2474  		// Request stale, perhaps the peer timed out but came through in the end
  2475  		logger.Warn("Unexpected bytecode packet")
  2476  		s.lock.Unlock()
  2477  		return nil
  2478  	}
  2479  	delete(s.bytecodeReqs, id)
  2480  	s.rates.Update(peer.ID(), ByteCodesMsg, time.Since(req.time), len(bytecodes))
  2481  
  2482  	// Clean up the request timeout timer, we'll see how to proceed further based
  2483  	// on the actual delivered content
  2484  	if !req.timeout.Stop() {
  2485  		// The timeout is already triggered, and this request will be reverted+rescheduled
  2486  		s.lock.Unlock()
  2487  		return nil
  2488  	}
  2489  
  2490  	// Response is valid, but check if peer is signalling that it does not have
  2491  	// the requested data. For bytecode range queries that means the peer is not
  2492  	// yet synced.
  2493  	if len(bytecodes) == 0 {
  2494  		logger.Debug("Peer rejected bytecode request")
  2495  		s.statelessPeers[peer.ID()] = struct{}{}
  2496  		s.lock.Unlock()
  2497  
  2498  		// Signal this request as failed, and ready for rescheduling
  2499  		s.scheduleRevertBytecodeRequest(req)
  2500  		return nil
  2501  	}
  2502  	s.lock.Unlock()
  2503  
  2504  	// Cross reference the requested bytecodes with the response to find gaps
  2505  	// that the serving node is missing
  2506  	hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState)
  2507  	hash := make([]byte, 32)
  2508  
  2509  	codes := make([][]byte, len(req.hashes))
  2510  	for i, j := 0, 0; i < len(bytecodes); i++ {
  2511  		// Find the next hash that we've been served, leaving misses with nils
  2512  		hasher.Reset()
  2513  		hasher.Write(bytecodes[i])
  2514  		hasher.Read(hash)
  2515  
  2516  		for j < len(req.hashes) && !bytes.Equal(hash, req.hashes[j][:]) {
  2517  			j++
  2518  		}
  2519  		if j < len(req.hashes) {
  2520  			codes[j] = bytecodes[i]
  2521  			j++
  2522  			continue
  2523  		}
  2524  		// We've either ran out of hashes, or got unrequested data
  2525  		logger.Warn("Unexpected bytecodes", "count", len(bytecodes)-i)
  2526  		// Signal this request as failed, and ready for rescheduling
  2527  		s.scheduleRevertBytecodeRequest(req)
  2528  		return errors.New("unexpected bytecode")
  2529  	}
  2530  	// Response validated, send it to the scheduler for filling
  2531  	response := &bytecodeResponse{
  2532  		task:   req.task,
  2533  		hashes: req.hashes,
  2534  		codes:  codes,
  2535  	}
  2536  	select {
  2537  	case req.deliver <- response:
  2538  	case <-req.cancel:
  2539  	case <-req.stale:
  2540  	}
  2541  	return nil
  2542  }
  2543  
  2544  // OnStorage is a callback method to invoke when ranges of storage slots
  2545  // are received from a remote peer.
  2546  func (s *Syncer) OnStorage(peer SyncPeer, id uint64, hashes [][]common.Hash, slots [][][]byte, proof [][]byte) error {
  2547  	// Gather some trace stats to aid in debugging issues
  2548  	var (
  2549  		hashCount int
  2550  		slotCount int
  2551  		size      common.StorageSize
  2552  	)
  2553  	for _, hashset := range hashes {
  2554  		size += common.StorageSize(common.HashLength * len(hashset))
  2555  		hashCount += len(hashset)
  2556  	}
  2557  	for _, slotset := range slots {
  2558  		for _, slot := range slotset {
  2559  			size += common.StorageSize(len(slot))
  2560  		}
  2561  		slotCount += len(slotset)
  2562  	}
  2563  	for _, node := range proof {
  2564  		size += common.StorageSize(len(node))
  2565  	}
  2566  	logger := peer.Log().New("reqid", id)
  2567  	logger.Trace("Delivering ranges of storage slots", "accounts", len(hashes), "hashes", hashCount, "slots", slotCount, "proofs", len(proof), "size", size)
  2568  
  2569  	// Whether or not the response is valid, we can mark the peer as idle and
  2570  	// notify the scheduler to assign a new task. If the response is invalid,
  2571  	// we'll drop the peer in a bit.
  2572  	defer func() {
  2573  		s.lock.Lock()
  2574  		defer s.lock.Unlock()
  2575  		if _, ok := s.peers[peer.ID()]; ok {
  2576  			s.storageIdlers[peer.ID()] = struct{}{}
  2577  		}
  2578  		select {
  2579  		case s.update <- struct{}{}:
  2580  		default:
  2581  		}
  2582  	}()
  2583  	s.lock.Lock()
  2584  	// Ensure the response is for a valid request
  2585  	req, ok := s.storageReqs[id]
  2586  	if !ok {
  2587  		// Request stale, perhaps the peer timed out but came through in the end
  2588  		logger.Warn("Unexpected storage ranges packet")
  2589  		s.lock.Unlock()
  2590  		return nil
  2591  	}
  2592  	delete(s.storageReqs, id)
  2593  	s.rates.Update(peer.ID(), StorageRangesMsg, time.Since(req.time), int(size))
  2594  
  2595  	// Clean up the request timeout timer, we'll see how to proceed further based
  2596  	// on the actual delivered content
  2597  	if !req.timeout.Stop() {
  2598  		// The timeout is already triggered, and this request will be reverted+rescheduled
  2599  		s.lock.Unlock()
  2600  		return nil
  2601  	}
  2602  
  2603  	// Reject the response if the hash sets and slot sets don't match, or if the
  2604  	// peer sent more data than requested.
  2605  	if len(hashes) != len(slots) {
  2606  		s.lock.Unlock()
  2607  		s.scheduleRevertStorageRequest(req) // reschedule request
  2608  		logger.Warn("Hash and slot set size mismatch", "hashset", len(hashes), "slotset", len(slots))
  2609  		return errors.New("hash and slot set size mismatch")
  2610  	}
  2611  	if len(hashes) > len(req.accounts) {
  2612  		s.lock.Unlock()
  2613  		s.scheduleRevertStorageRequest(req) // reschedule request
  2614  		logger.Warn("Hash set larger than requested", "hashset", len(hashes), "requested", len(req.accounts))
  2615  		return errors.New("hash set larger than requested")
  2616  	}
  2617  	// Response is valid, but check if peer is signalling that it does not have
  2618  	// the requested data. For storage range queries that means the state being
  2619  	// retrieved was either already pruned remotely, or the peer is not yet
  2620  	// synced to our head.
  2621  	if len(hashes) == 0 {
  2622  		logger.Debug("Peer rejected storage request")
  2623  		s.statelessPeers[peer.ID()] = struct{}{}
  2624  		s.lock.Unlock()
  2625  		s.scheduleRevertStorageRequest(req) // reschedule request
  2626  		return nil
  2627  	}
  2628  	s.lock.Unlock()
  2629  
  2630  	// Reconstruct the partial tries from the response and verify them
  2631  	var cont bool
  2632  
  2633  	for i := 0; i < len(hashes); i++ {
  2634  		// Convert the keys and proofs into an internal format
  2635  		keys := make([][]byte, len(hashes[i]))
  2636  		for j, key := range hashes[i] {
  2637  			keys[j] = common.CopyBytes(key[:])
  2638  		}
  2639  		nodes := make(light.NodeList, 0, len(proof))
  2640  		if i == len(hashes)-1 {
  2641  			for _, node := range proof {
  2642  				nodes = append(nodes, node)
  2643  			}
  2644  		}
  2645  		var err error
  2646  		if len(nodes) == 0 {
  2647  			// No proof has been attached, the response must cover the entire key
  2648  			// space and hash to the origin root.
  2649  			_, err = trie.VerifyRangeProof(req.roots[i], nil, nil, keys, slots[i], nil)
  2650  			if err != nil {
  2651  				s.scheduleRevertStorageRequest(req) // reschedule request
  2652  				logger.Warn("Storage slots failed proof", "err", err)
  2653  				return err
  2654  			}
  2655  		} else {
  2656  			// A proof was attached, the response is only partial, check that the
  2657  			// returned data is indeed part of the storage trie
  2658  			proofdb := nodes.NodeSet()
  2659  
  2660  			var end []byte
  2661  			if len(keys) > 0 {
  2662  				end = keys[len(keys)-1]
  2663  			}
  2664  			cont, err = trie.VerifyRangeProof(req.roots[i], req.origin[:], end, keys, slots[i], proofdb)
  2665  			if err != nil {
  2666  				s.scheduleRevertStorageRequest(req) // reschedule request
  2667  				logger.Warn("Storage range failed proof", "err", err)
  2668  				return err
  2669  			}
  2670  		}
  2671  	}
  2672  	// Partial tries reconstructed, send them to the scheduler for storage filling
  2673  	response := &storageResponse{
  2674  		mainTask: req.mainTask,
  2675  		subTask:  req.subTask,
  2676  		accounts: req.accounts,
  2677  		roots:    req.roots,
  2678  		hashes:   hashes,
  2679  		slots:    slots,
  2680  		cont:     cont,
  2681  	}
  2682  	select {
  2683  	case req.deliver <- response:
  2684  	case <-req.cancel:
  2685  	case <-req.stale:
  2686  	}
  2687  	return nil
  2688  }
  2689  
  2690  // OnTrieNodes is a callback method to invoke when a batch of trie nodes
  2691  // are received from a remote peer.
  2692  func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error {
  2693  	var size common.StorageSize
  2694  	for _, node := range trienodes {
  2695  		size += common.StorageSize(len(node))
  2696  	}
  2697  	logger := peer.Log().New("reqid", id)
  2698  	logger.Trace("Delivering set of healing trienodes", "trienodes", len(trienodes), "bytes", size)
  2699  
  2700  	// Whether or not the response is valid, we can mark the peer as idle and
  2701  	// notify the scheduler to assign a new task. If the response is invalid,
  2702  	// we'll drop the peer in a bit.
  2703  	defer func() {
  2704  		s.lock.Lock()
  2705  		defer s.lock.Unlock()
  2706  		if _, ok := s.peers[peer.ID()]; ok {
  2707  			s.trienodeHealIdlers[peer.ID()] = struct{}{}
  2708  		}
  2709  		select {
  2710  		case s.update <- struct{}{}:
  2711  		default:
  2712  		}
  2713  	}()
  2714  	s.lock.Lock()
  2715  	// Ensure the response is for a valid request
  2716  	req, ok := s.trienodeHealReqs[id]
  2717  	if !ok {
  2718  		// Request stale, perhaps the peer timed out but came through in the end
  2719  		logger.Warn("Unexpected trienode heal packet")
  2720  		s.lock.Unlock()
  2721  		return nil
  2722  	}
  2723  	delete(s.trienodeHealReqs, id)
  2724  	s.rates.Update(peer.ID(), TrieNodesMsg, time.Since(req.time), len(trienodes))
  2725  
  2726  	// Clean up the request timeout timer, we'll see how to proceed further based
  2727  	// on the actual delivered content
  2728  	if !req.timeout.Stop() {
  2729  		// The timeout is already triggered, and this request will be reverted+rescheduled
  2730  		s.lock.Unlock()
  2731  		return nil
  2732  	}
  2733  
  2734  	// Response is valid, but check if peer is signalling that it does not have
  2735  	// the requested data. For bytecode range queries that means the peer is not
  2736  	// yet synced.
  2737  	if len(trienodes) == 0 {
  2738  		logger.Debug("Peer rejected trienode heal request")
  2739  		s.statelessPeers[peer.ID()] = struct{}{}
  2740  		s.lock.Unlock()
  2741  
  2742  		// Signal this request as failed, and ready for rescheduling
  2743  		s.scheduleRevertTrienodeHealRequest(req)
  2744  		return nil
  2745  	}
  2746  	s.lock.Unlock()
  2747  
  2748  	// Cross reference the requested trienodes with the response to find gaps
  2749  	// that the serving node is missing
  2750  	var (
  2751  		hasher = sha3.NewLegacyKeccak256().(crypto.KeccakState)
  2752  		hash   = make([]byte, 32)
  2753  		nodes  = make([][]byte, len(req.hashes))
  2754  		fills  uint64
  2755  	)
  2756  	for i, j := 0, 0; i < len(trienodes); i++ {
  2757  		// Find the next hash that we've been served, leaving misses with nils
  2758  		hasher.Reset()
  2759  		hasher.Write(trienodes[i])
  2760  		hasher.Read(hash)
  2761  
  2762  		for j < len(req.hashes) && !bytes.Equal(hash, req.hashes[j][:]) {
  2763  			j++
  2764  		}
  2765  		if j < len(req.hashes) {
  2766  			nodes[j] = trienodes[i]
  2767  			fills++
  2768  			j++
  2769  			continue
  2770  		}
  2771  		// We've either ran out of hashes, or got unrequested data
  2772  		logger.Warn("Unexpected healing trienodes", "count", len(trienodes)-i)
  2773  
  2774  		// Signal this request as failed, and ready for rescheduling
  2775  		s.scheduleRevertTrienodeHealRequest(req)
  2776  		return errors.New("unexpected healing trienode")
  2777  	}
  2778  	// Response validated, send it to the scheduler for filling
  2779  	s.trienodeHealPend.Add(fills)
  2780  	defer func() {
  2781  		s.trienodeHealPend.Add(^(fills - 1))
  2782  	}()
  2783  	response := &trienodeHealResponse{
  2784  		paths:  req.paths,
  2785  		task:   req.task,
  2786  		hashes: req.hashes,
  2787  		nodes:  nodes,
  2788  	}
  2789  	select {
  2790  	case req.deliver <- response:
  2791  	case <-req.cancel:
  2792  	case <-req.stale:
  2793  	}
  2794  	return nil
  2795  }
  2796  
  2797  // onHealByteCodes is a callback method to invoke when a batch of contract
  2798  // bytes codes are received from a remote peer in the healing phase.
  2799  func (s *Syncer) onHealByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) error {
  2800  	var size common.StorageSize
  2801  	for _, code := range bytecodes {
  2802  		size += common.StorageSize(len(code))
  2803  	}
  2804  	logger := peer.Log().New("reqid", id)
  2805  	logger.Trace("Delivering set of healing bytecodes", "bytecodes", len(bytecodes), "bytes", size)
  2806  
  2807  	// Whether or not the response is valid, we can mark the peer as idle and
  2808  	// notify the scheduler to assign a new task. If the response is invalid,
  2809  	// we'll drop the peer in a bit.
  2810  	defer func() {
  2811  		s.lock.Lock()
  2812  		defer s.lock.Unlock()
  2813  		if _, ok := s.peers[peer.ID()]; ok {
  2814  			s.bytecodeHealIdlers[peer.ID()] = struct{}{}
  2815  		}
  2816  		select {
  2817  		case s.update <- struct{}{}:
  2818  		default:
  2819  		}
  2820  	}()
  2821  	s.lock.Lock()
  2822  	// Ensure the response is for a valid request
  2823  	req, ok := s.bytecodeHealReqs[id]
  2824  	if !ok {
  2825  		// Request stale, perhaps the peer timed out but came through in the end
  2826  		logger.Warn("Unexpected bytecode heal packet")
  2827  		s.lock.Unlock()
  2828  		return nil
  2829  	}
  2830  	delete(s.bytecodeHealReqs, id)
  2831  	s.rates.Update(peer.ID(), ByteCodesMsg, time.Since(req.time), len(bytecodes))
  2832  
  2833  	// Clean up the request timeout timer, we'll see how to proceed further based
  2834  	// on the actual delivered content
  2835  	if !req.timeout.Stop() {
  2836  		// The timeout is already triggered, and this request will be reverted+rescheduled
  2837  		s.lock.Unlock()
  2838  		return nil
  2839  	}
  2840  
  2841  	// Response is valid, but check if peer is signalling that it does not have
  2842  	// the requested data. For bytecode range queries that means the peer is not
  2843  	// yet synced.
  2844  	if len(bytecodes) == 0 {
  2845  		logger.Debug("Peer rejected bytecode heal request")
  2846  		s.statelessPeers[peer.ID()] = struct{}{}
  2847  		s.lock.Unlock()
  2848  
  2849  		// Signal this request as failed, and ready for rescheduling
  2850  		s.scheduleRevertBytecodeHealRequest(req)
  2851  		return nil
  2852  	}
  2853  	s.lock.Unlock()
  2854  
  2855  	// Cross reference the requested bytecodes with the response to find gaps
  2856  	// that the serving node is missing
  2857  	hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState)
  2858  	hash := make([]byte, 32)
  2859  
  2860  	codes := make([][]byte, len(req.hashes))
  2861  	for i, j := 0, 0; i < len(bytecodes); i++ {
  2862  		// Find the next hash that we've been served, leaving misses with nils
  2863  		hasher.Reset()
  2864  		hasher.Write(bytecodes[i])
  2865  		hasher.Read(hash)
  2866  
  2867  		for j < len(req.hashes) && !bytes.Equal(hash, req.hashes[j][:]) {
  2868  			j++
  2869  		}
  2870  		if j < len(req.hashes) {
  2871  			codes[j] = bytecodes[i]
  2872  			j++
  2873  			continue
  2874  		}
  2875  		// We've either ran out of hashes, or got unrequested data
  2876  		logger.Warn("Unexpected healing bytecodes", "count", len(bytecodes)-i)
  2877  		// Signal this request as failed, and ready for rescheduling
  2878  		s.scheduleRevertBytecodeHealRequest(req)
  2879  		return errors.New("unexpected healing bytecode")
  2880  	}
  2881  	// Response validated, send it to the scheduler for filling
  2882  	response := &bytecodeHealResponse{
  2883  		task:   req.task,
  2884  		hashes: req.hashes,
  2885  		codes:  codes,
  2886  	}
  2887  	select {
  2888  	case req.deliver <- response:
  2889  	case <-req.cancel:
  2890  	case <-req.stale:
  2891  	}
  2892  	return nil
  2893  }
  2894  
  2895  // onHealState is a callback method to invoke when a flat state(account
  2896  // or storage slot) is downloaded during the healing stage. The flat states
  2897  // can be persisted blindly and can be fixed later in the generation stage.
  2898  // Note it's not concurrent safe, please handle the concurrent issue outside.
  2899  func (s *Syncer) onHealState(paths [][]byte, value []byte) error {
  2900  	if len(paths) == 1 {
  2901  		var account types.StateAccount
  2902  		if err := rlp.DecodeBytes(value, &account); err != nil {
  2903  			return nil // Returning the error here would drop the remote peer
  2904  		}
  2905  		blob := snapshot.SlimAccountRLP(account.Nonce, account.Balance, account.Root, account.CodeHash)
  2906  		rawdb.WriteAccountSnapshot(s.stateWriter, common.BytesToHash(paths[0]), blob)
  2907  		s.accountHealed += 1
  2908  		s.accountHealedBytes += common.StorageSize(1 + common.HashLength + len(blob))
  2909  	}
  2910  	if len(paths) == 2 {
  2911  		rawdb.WriteStorageSnapshot(s.stateWriter, common.BytesToHash(paths[0]), common.BytesToHash(paths[1]), value)
  2912  		s.storageHealed += 1
  2913  		s.storageHealedBytes += common.StorageSize(1 + 2*common.HashLength + len(value))
  2914  	}
  2915  	if s.stateWriter.ValueSize() > ethdb.IdealBatchSize {
  2916  		s.stateWriter.Write() // It's fine to ignore the error here
  2917  		s.stateWriter.Reset()
  2918  	}
  2919  	return nil
  2920  }
  2921  
  2922  // hashSpace is the total size of the 256 bit hash space for accounts.
  2923  var hashSpace = new(big.Int).Exp(common.Big2, common.Big256, nil)
  2924  
  2925  // report calculates various status reports and provides it to the user.
  2926  func (s *Syncer) report(force bool) {
  2927  	if len(s.tasks) > 0 {
  2928  		s.reportSyncProgress(force)
  2929  		return
  2930  	}
  2931  	s.reportHealProgress(force)
  2932  }
  2933  
  2934  // reportSyncProgress calculates various status reports and provides it to the user.
  2935  func (s *Syncer) reportSyncProgress(force bool) {
  2936  	// Don't report all the events, just occasionally
  2937  	if !force && time.Since(s.logTime) < 8*time.Second {
  2938  		return
  2939  	}
  2940  	// Don't report anything until we have a meaningful progress
  2941  	synced := s.accountBytes + s.bytecodeBytes + s.storageBytes
  2942  	if synced == 0 {
  2943  		return
  2944  	}
  2945  	accountGaps := new(big.Int)
  2946  	for _, task := range s.tasks {
  2947  		accountGaps.Add(accountGaps, new(big.Int).Sub(task.Last.Big(), task.Next.Big()))
  2948  	}
  2949  	accountFills := new(big.Int).Sub(hashSpace, accountGaps)
  2950  	if accountFills.BitLen() == 0 {
  2951  		return
  2952  	}
  2953  	s.logTime = time.Now()
  2954  	estBytes := float64(new(big.Int).Div(
  2955  		new(big.Int).Mul(new(big.Int).SetUint64(uint64(synced)), hashSpace),
  2956  		accountFills,
  2957  	).Uint64())
  2958  	// Don't report anything until we have a meaningful progress
  2959  	if estBytes < 1.0 {
  2960  		return
  2961  	}
  2962  	elapsed := time.Since(s.startTime)
  2963  	estTime := elapsed / time.Duration(synced) * time.Duration(estBytes)
  2964  
  2965  	// Create a mega progress report
  2966  	var (
  2967  		progress = fmt.Sprintf("%.2f%%", float64(synced)*100/estBytes)
  2968  		accounts = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.accountSynced), s.accountBytes.TerminalString())
  2969  		storage  = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.storageSynced), s.storageBytes.TerminalString())
  2970  		bytecode = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.bytecodeSynced), s.bytecodeBytes.TerminalString())
  2971  	)
  2972  	log.Info("Syncing: state download in progress", "synced", progress, "state", synced,
  2973  		"accounts", accounts, "slots", storage, "codes", bytecode, "eta", common.PrettyDuration(estTime-elapsed))
  2974  }
  2975  
  2976  // reportHealProgress calculates various status reports and provides it to the user.
  2977  func (s *Syncer) reportHealProgress(force bool) {
  2978  	// Don't report all the events, just occasionally
  2979  	if !force && time.Since(s.logTime) < 8*time.Second {
  2980  		return
  2981  	}
  2982  	s.logTime = time.Now()
  2983  
  2984  	// Create a mega progress report
  2985  	var (
  2986  		trienode = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.trienodeHealSynced), s.trienodeHealBytes.TerminalString())
  2987  		bytecode = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.bytecodeHealSynced), s.bytecodeHealBytes.TerminalString())
  2988  		accounts = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.accountHealed), s.accountHealedBytes.TerminalString())
  2989  		storage  = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.storageHealed), s.storageHealedBytes.TerminalString())
  2990  	)
  2991  	log.Info("Syncing: state healing in progress", "accounts", accounts, "slots", storage,
  2992  		"codes", bytecode, "nodes", trienode, "pending", s.healer.scheduler.Pending())
  2993  }
  2994  
  2995  // estimateRemainingSlots tries to determine roughly how many slots are left in
  2996  // a contract storage, based on the number of keys and the last hash. This method
  2997  // assumes that the hashes are lexicographically ordered and evenly distributed.
  2998  func estimateRemainingSlots(hashes int, last common.Hash) (uint64, error) {
  2999  	if last == (common.Hash{}) {
  3000  		return 0, errors.New("last hash empty")
  3001  	}
  3002  	space := new(big.Int).Mul(math.MaxBig256, big.NewInt(int64(hashes)))
  3003  	space.Div(space, last.Big())
  3004  	if !space.IsUint64() {
  3005  		// Gigantic address space probably due to too few or malicious slots
  3006  		return 0, errors.New("too few slots for estimation")
  3007  	}
  3008  	return space.Uint64() - uint64(hashes), nil
  3009  }
  3010  
  3011  // capacitySort implements the Sort interface, allowing sorting by peer message
  3012  // throughput. Note, callers should use sort.Reverse to get the desired effect
  3013  // of highest capacity being at the front.
  3014  type capacitySort struct {
  3015  	ids  []string
  3016  	caps []int
  3017  }
  3018  
  3019  func (s *capacitySort) Len() int {
  3020  	return len(s.ids)
  3021  }
  3022  
  3023  func (s *capacitySort) Less(i, j int) bool {
  3024  	return s.caps[i] < s.caps[j]
  3025  }
  3026  
  3027  func (s *capacitySort) Swap(i, j int) {
  3028  	s.ids[i], s.ids[j] = s.ids[j], s.ids[i]
  3029  	s.caps[i], s.caps[j] = s.caps[j], s.caps[i]
  3030  }
  3031  
  3032  // healRequestSort implements the Sort interface, allowing sorting trienode
  3033  // heal requests, which is a prerequisite for merging storage-requests.
  3034  type healRequestSort struct {
  3035  	paths     []string
  3036  	hashes    []common.Hash
  3037  	syncPaths []trie.SyncPath
  3038  }
  3039  
  3040  func (t *healRequestSort) Len() int {
  3041  	return len(t.hashes)
  3042  }
  3043  
  3044  func (t *healRequestSort) Less(i, j int) bool {
  3045  	a := t.syncPaths[i]
  3046  	b := t.syncPaths[j]
  3047  	switch bytes.Compare(a[0], b[0]) {
  3048  	case -1:
  3049  		return true
  3050  	case 1:
  3051  		return false
  3052  	}
  3053  	// identical first part
  3054  	if len(a) < len(b) {
  3055  		return true
  3056  	}
  3057  	if len(b) < len(a) {
  3058  		return false
  3059  	}
  3060  	if len(a) == 2 {
  3061  		return bytes.Compare(a[1], b[1]) < 0
  3062  	}
  3063  	return false
  3064  }
  3065  
  3066  func (t *healRequestSort) Swap(i, j int) {
  3067  	t.paths[i], t.paths[j] = t.paths[j], t.paths[i]
  3068  	t.hashes[i], t.hashes[j] = t.hashes[j], t.hashes[i]
  3069  	t.syncPaths[i], t.syncPaths[j] = t.syncPaths[j], t.syncPaths[i]
  3070  }
  3071  
  3072  // Merge merges the pathsets, so that several storage requests concerning the
  3073  // same account are merged into one, to reduce bandwidth.
  3074  // OBS: This operation is moot if t has not first been sorted.
  3075  func (t *healRequestSort) Merge() []TrieNodePathSet {
  3076  	var result []TrieNodePathSet
  3077  	for _, path := range t.syncPaths {
  3078  		pathset := TrieNodePathSet(path)
  3079  		if len(path) == 1 {
  3080  			// It's an account reference.
  3081  			result = append(result, pathset)
  3082  		} else {
  3083  			// It's a storage reference.
  3084  			end := len(result) - 1
  3085  			if len(result) == 0 || !bytes.Equal(pathset[0], result[end][0]) {
  3086  				// The account doesn't match last, create a new entry.
  3087  				result = append(result, pathset)
  3088  			} else {
  3089  				// It's the same account as the previous one, add to the storage
  3090  				// paths of that request.
  3091  				result[end] = append(result[end], pathset[1])
  3092  			}
  3093  		}
  3094  	}
  3095  	return result
  3096  }
  3097  
  3098  // sortByAccountPath takes hashes and paths, and sorts them. After that, it generates
  3099  // the TrieNodePaths and merges paths which belongs to the same account path.
  3100  func sortByAccountPath(paths []string, hashes []common.Hash) ([]string, []common.Hash, []trie.SyncPath, []TrieNodePathSet) {
  3101  	var syncPaths []trie.SyncPath
  3102  	for _, path := range paths {
  3103  		syncPaths = append(syncPaths, trie.NewSyncPath([]byte(path)))
  3104  	}
  3105  	n := &healRequestSort{paths, hashes, syncPaths}
  3106  	sort.Sort(n)
  3107  	pathsets := n.Merge()
  3108  	return n.paths, n.hashes, n.syncPaths, pathsets
  3109  }