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