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