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