github.com/LampardNguyen234/go-ethereum@v1.10.16-0.20220117140830-b6a3b0260724/eth/downloader/downloader.go (about) 1 // Copyright 2015 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 downloader contains the manual full chain synchronisation. 18 package downloader 19 20 import ( 21 "errors" 22 "fmt" 23 "math/big" 24 "sync" 25 "sync/atomic" 26 "time" 27 28 "github.com/LampardNguyen234/go-ethereum" 29 "github.com/LampardNguyen234/go-ethereum/common" 30 "github.com/LampardNguyen234/go-ethereum/core/rawdb" 31 "github.com/LampardNguyen234/go-ethereum/core/state/snapshot" 32 "github.com/LampardNguyen234/go-ethereum/core/types" 33 "github.com/LampardNguyen234/go-ethereum/eth/protocols/eth" 34 "github.com/LampardNguyen234/go-ethereum/eth/protocols/snap" 35 "github.com/LampardNguyen234/go-ethereum/ethdb" 36 "github.com/LampardNguyen234/go-ethereum/event" 37 "github.com/LampardNguyen234/go-ethereum/log" 38 "github.com/LampardNguyen234/go-ethereum/params" 39 ) 40 41 var ( 42 MaxBlockFetch = 128 // Amount of blocks to be fetched per retrieval request 43 MaxHeaderFetch = 192 // Amount of block headers to be fetched per retrieval request 44 MaxSkeletonSize = 128 // Number of header fetches to need for a skeleton assembly 45 MaxReceiptFetch = 256 // Amount of transaction receipts to allow fetching per request 46 47 maxQueuedHeaders = 32 * 1024 // [eth/62] Maximum number of headers to queue for import (DOS protection) 48 maxHeadersProcess = 2048 // Number of header download results to import at once into the chain 49 maxResultsProcess = 2048 // Number of content download results to import at once into the chain 50 fullMaxForkAncestry uint64 = params.FullImmutabilityThreshold // Maximum chain reorganisation (locally redeclared so tests can reduce it) 51 lightMaxForkAncestry uint64 = params.LightImmutabilityThreshold // Maximum chain reorganisation (locally redeclared so tests can reduce it) 52 53 reorgProtThreshold = 48 // Threshold number of recent blocks to disable mini reorg protection 54 reorgProtHeaderDelay = 2 // Number of headers to delay delivering to cover mini reorgs 55 56 fsHeaderCheckFrequency = 100 // Verification frequency of the downloaded headers during snap sync 57 fsHeaderSafetyNet = 2048 // Number of headers to discard in case a chain violation is detected 58 fsHeaderForceVerify = 24 // Number of headers to verify before and after the pivot to accept it 59 fsHeaderContCheck = 3 * time.Second // Time interval to check for header continuations during state download 60 fsMinFullBlocks = 64 // Number of blocks to retrieve fully even in snap sync 61 ) 62 63 var ( 64 errBusy = errors.New("busy") 65 errUnknownPeer = errors.New("peer is unknown or unhealthy") 66 errBadPeer = errors.New("action from bad peer ignored") 67 errStallingPeer = errors.New("peer is stalling") 68 errUnsyncedPeer = errors.New("unsynced peer") 69 errNoPeers = errors.New("no peers to keep download active") 70 errTimeout = errors.New("timeout") 71 errEmptyHeaderSet = errors.New("empty header set by peer") 72 errPeersUnavailable = errors.New("no peers available or all tried for download") 73 errInvalidAncestor = errors.New("retrieved ancestor is invalid") 74 errInvalidChain = errors.New("retrieved hash chain is invalid") 75 errInvalidBody = errors.New("retrieved block body is invalid") 76 errInvalidReceipt = errors.New("retrieved receipt is invalid") 77 errCancelStateFetch = errors.New("state data download canceled (requested)") 78 errCancelContentProcessing = errors.New("content processing canceled (requested)") 79 errCanceled = errors.New("syncing canceled (requested)") 80 errTooOld = errors.New("peer's protocol version too old") 81 errNoAncestorFound = errors.New("no common ancestor found") 82 ) 83 84 // peerDropFn is a callback type for dropping a peer detected as malicious. 85 type peerDropFn func(id string) 86 87 // headerTask is a set of downloaded headers to queue along with their precomputed 88 // hashes to avoid constant rehashing. 89 type headerTask struct { 90 headers []*types.Header 91 hashes []common.Hash 92 } 93 94 type Downloader struct { 95 mode uint32 // Synchronisation mode defining the strategy used (per sync cycle), use d.getMode() to get the SyncMode 96 mux *event.TypeMux // Event multiplexer to announce sync operation events 97 98 checkpoint uint64 // Checkpoint block number to enforce head against (e.g. snap sync) 99 genesis uint64 // Genesis block number to limit sync to (e.g. light client CHT) 100 queue *queue // Scheduler for selecting the hashes to download 101 peers *peerSet // Set of active peers from which download can proceed 102 103 stateDB ethdb.Database // Database to state sync into (and deduplicate via) 104 105 // Statistics 106 syncStatsChainOrigin uint64 // Origin block number where syncing started at 107 syncStatsChainHeight uint64 // Highest block number known when syncing started 108 syncStatsLock sync.RWMutex // Lock protecting the sync stats fields 109 110 lightchain LightChain 111 blockchain BlockChain 112 113 // Callbacks 114 dropPeer peerDropFn // Drops a peer for misbehaving 115 116 // Status 117 synchroniseMock func(id string, hash common.Hash) error // Replacement for synchronise during testing 118 synchronising int32 119 notified int32 120 committed int32 121 ancientLimit uint64 // The maximum block number which can be regarded as ancient data. 122 123 // Channels 124 headerProcCh chan *headerTask // Channel to feed the header processor new tasks 125 126 // State sync 127 pivotHeader *types.Header // Pivot block header to dynamically push the syncing state root 128 pivotLock sync.RWMutex // Lock protecting pivot header reads from updates 129 130 snapSync bool // Whether to run state sync over the snap protocol 131 SnapSyncer *snap.Syncer // TODO(karalabe): make private! hack for now 132 stateSyncStart chan *stateSync 133 134 // Cancellation and termination 135 cancelPeer string // Identifier of the peer currently being used as the master (cancel on drop) 136 cancelCh chan struct{} // Channel to cancel mid-flight syncs 137 cancelLock sync.RWMutex // Lock to protect the cancel channel and peer in delivers 138 cancelWg sync.WaitGroup // Make sure all fetcher goroutines have exited. 139 140 quitCh chan struct{} // Quit channel to signal termination 141 quitLock sync.Mutex // Lock to prevent double closes 142 143 // Testing hooks 144 syncInitHook func(uint64, uint64) // Method to call upon initiating a new sync run 145 bodyFetchHook func([]*types.Header) // Method to call upon starting a block body fetch 146 receiptFetchHook func([]*types.Header) // Method to call upon starting a receipt fetch 147 chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations) 148 } 149 150 // LightChain encapsulates functions required to synchronise a light chain. 151 type LightChain interface { 152 // HasHeader verifies a header's presence in the local chain. 153 HasHeader(common.Hash, uint64) bool 154 155 // GetHeaderByHash retrieves a header from the local chain. 156 GetHeaderByHash(common.Hash) *types.Header 157 158 // CurrentHeader retrieves the head header from the local chain. 159 CurrentHeader() *types.Header 160 161 // GetTd returns the total difficulty of a local block. 162 GetTd(common.Hash, uint64) *big.Int 163 164 // InsertHeaderChain inserts a batch of headers into the local chain. 165 InsertHeaderChain([]*types.Header, int) (int, error) 166 167 // SetHead rewinds the local chain to a new head. 168 SetHead(uint64) error 169 } 170 171 // BlockChain encapsulates functions required to sync a (full or snap) blockchain. 172 type BlockChain interface { 173 LightChain 174 175 // HasBlock verifies a block's presence in the local chain. 176 HasBlock(common.Hash, uint64) bool 177 178 // HasFastBlock verifies a snap block's presence in the local chain. 179 HasFastBlock(common.Hash, uint64) bool 180 181 // GetBlockByHash retrieves a block from the local chain. 182 GetBlockByHash(common.Hash) *types.Block 183 184 // CurrentBlock retrieves the head block from the local chain. 185 CurrentBlock() *types.Block 186 187 // CurrentFastBlock retrieves the head snap block from the local chain. 188 CurrentFastBlock() *types.Block 189 190 // SnapSyncCommitHead directly commits the head block to a certain entity. 191 SnapSyncCommitHead(common.Hash) error 192 193 // InsertChain inserts a batch of blocks into the local chain. 194 InsertChain(types.Blocks) (int, error) 195 196 // InsertReceiptChain inserts a batch of receipts into the local chain. 197 InsertReceiptChain(types.Blocks, []types.Receipts, uint64) (int, error) 198 199 // Snapshots returns the blockchain snapshot tree to paused it during sync. 200 Snapshots() *snapshot.Tree 201 } 202 203 // New creates a new downloader to fetch hashes and blocks from remote peers. 204 func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn) *Downloader { 205 if lightchain == nil { 206 lightchain = chain 207 } 208 dl := &Downloader{ 209 stateDB: stateDb, 210 mux: mux, 211 checkpoint: checkpoint, 212 queue: newQueue(blockCacheMaxItems, blockCacheInitialItems), 213 peers: newPeerSet(), 214 blockchain: chain, 215 lightchain: lightchain, 216 dropPeer: dropPeer, 217 headerProcCh: make(chan *headerTask, 1), 218 quitCh: make(chan struct{}), 219 SnapSyncer: snap.NewSyncer(stateDb), 220 stateSyncStart: make(chan *stateSync), 221 } 222 go dl.stateFetcher() 223 return dl 224 } 225 226 // Progress retrieves the synchronisation boundaries, specifically the origin 227 // block where synchronisation started at (may have failed/suspended); the block 228 // or header sync is currently at; and the latest known block which the sync targets. 229 // 230 // In addition, during the state download phase of snap synchronisation the number 231 // of processed and the total number of known states are also returned. Otherwise 232 // these are zero. 233 func (d *Downloader) Progress() ethereum.SyncProgress { 234 // Lock the current stats and return the progress 235 d.syncStatsLock.RLock() 236 defer d.syncStatsLock.RUnlock() 237 238 current := uint64(0) 239 mode := d.getMode() 240 switch { 241 case d.blockchain != nil && mode == FullSync: 242 current = d.blockchain.CurrentBlock().NumberU64() 243 case d.blockchain != nil && mode == SnapSync: 244 current = d.blockchain.CurrentFastBlock().NumberU64() 245 case d.lightchain != nil: 246 current = d.lightchain.CurrentHeader().Number.Uint64() 247 default: 248 log.Error("Unknown downloader chain/mode combo", "light", d.lightchain != nil, "full", d.blockchain != nil, "mode", mode) 249 } 250 progress, pending := d.SnapSyncer.Progress() 251 252 return ethereum.SyncProgress{ 253 StartingBlock: d.syncStatsChainOrigin, 254 CurrentBlock: current, 255 HighestBlock: d.syncStatsChainHeight, 256 SyncedAccounts: progress.AccountSynced, 257 SyncedAccountBytes: uint64(progress.AccountBytes), 258 SyncedBytecodes: progress.BytecodeSynced, 259 SyncedBytecodeBytes: uint64(progress.BytecodeBytes), 260 SyncedStorage: progress.StorageSynced, 261 SyncedStorageBytes: uint64(progress.StorageBytes), 262 HealedTrienodes: progress.TrienodeHealSynced, 263 HealedTrienodeBytes: uint64(progress.TrienodeHealBytes), 264 HealedBytecodes: progress.BytecodeHealSynced, 265 HealedBytecodeBytes: uint64(progress.BytecodeHealBytes), 266 HealingTrienodes: pending.TrienodeHeal, 267 HealingBytecode: pending.BytecodeHeal, 268 } 269 } 270 271 // Synchronising returns whether the downloader is currently retrieving blocks. 272 func (d *Downloader) Synchronising() bool { 273 return atomic.LoadInt32(&d.synchronising) > 0 274 } 275 276 // RegisterPeer injects a new download peer into the set of block source to be 277 // used for fetching hashes and blocks from. 278 func (d *Downloader) RegisterPeer(id string, version uint, peer Peer) error { 279 var logger log.Logger 280 if len(id) < 16 { 281 // Tests use short IDs, don't choke on them 282 logger = log.New("peer", id) 283 } else { 284 logger = log.New("peer", id[:8]) 285 } 286 logger.Trace("Registering sync peer") 287 if err := d.peers.Register(newPeerConnection(id, version, peer, logger)); err != nil { 288 logger.Error("Failed to register sync peer", "err", err) 289 return err 290 } 291 return nil 292 } 293 294 // RegisterLightPeer injects a light client peer, wrapping it so it appears as a regular peer. 295 func (d *Downloader) RegisterLightPeer(id string, version uint, peer LightPeer) error { 296 return d.RegisterPeer(id, version, &lightPeerWrapper{peer}) 297 } 298 299 // UnregisterPeer remove a peer from the known list, preventing any action from 300 // the specified peer. An effort is also made to return any pending fetches into 301 // the queue. 302 func (d *Downloader) UnregisterPeer(id string) error { 303 // Unregister the peer from the active peer set and revoke any fetch tasks 304 var logger log.Logger 305 if len(id) < 16 { 306 // Tests use short IDs, don't choke on them 307 logger = log.New("peer", id) 308 } else { 309 logger = log.New("peer", id[:8]) 310 } 311 logger.Trace("Unregistering sync peer") 312 if err := d.peers.Unregister(id); err != nil { 313 logger.Error("Failed to unregister sync peer", "err", err) 314 return err 315 } 316 d.queue.Revoke(id) 317 318 return nil 319 } 320 321 // Synchronise tries to sync up our local block chain with a remote peer, both 322 // adding various sanity checks as well as wrapping it with various log entries. 323 func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int, mode SyncMode) error { 324 err := d.synchronise(id, head, td, mode) 325 326 switch err { 327 case nil, errBusy, errCanceled: 328 return err 329 } 330 if errors.Is(err, errInvalidChain) || errors.Is(err, errBadPeer) || errors.Is(err, errTimeout) || 331 errors.Is(err, errStallingPeer) || errors.Is(err, errUnsyncedPeer) || errors.Is(err, errEmptyHeaderSet) || 332 errors.Is(err, errPeersUnavailable) || errors.Is(err, errTooOld) || errors.Is(err, errInvalidAncestor) { 333 log.Warn("Synchronisation failed, dropping peer", "peer", id, "err", err) 334 if d.dropPeer == nil { 335 // The dropPeer method is nil when `--copydb` is used for a local copy. 336 // Timeouts can occur if e.g. compaction hits at the wrong time, and can be ignored 337 log.Warn("Downloader wants to drop peer, but peerdrop-function is not set", "peer", id) 338 } else { 339 d.dropPeer(id) 340 } 341 return err 342 } 343 log.Warn("Synchronisation failed, retrying", "err", err) 344 return err 345 } 346 347 // synchronise will select the peer and use it for synchronising. If an empty string is given 348 // it will use the best peer possible and synchronize if its TD is higher than our own. If any of the 349 // checks fail an error will be returned. This method is synchronous 350 func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode SyncMode) error { 351 // Mock out the synchronisation if testing 352 if d.synchroniseMock != nil { 353 return d.synchroniseMock(id, hash) 354 } 355 // Make sure only one goroutine is ever allowed past this point at once 356 if !atomic.CompareAndSwapInt32(&d.synchronising, 0, 1) { 357 return errBusy 358 } 359 defer atomic.StoreInt32(&d.synchronising, 0) 360 361 // Post a user notification of the sync (only once per session) 362 if atomic.CompareAndSwapInt32(&d.notified, 0, 1) { 363 log.Info("Block synchronisation started") 364 } 365 // If snap sync was requested, create the snap scheduler and switch to snap 366 // sync mode. Long term we could drop snap sync or merge the two together, 367 // but until snap becomes prevalent, we should support both. TODO(karalabe). 368 if mode == SnapSync { 369 // Snap sync uses the snapshot namespace to store potentially flakey data until 370 // sync completely heals and finishes. Pause snapshot maintenance in the mean- 371 // time to prevent access. 372 if snapshots := d.blockchain.Snapshots(); snapshots != nil { // Only nil in tests 373 snapshots.Disable() 374 } 375 } 376 // Reset the queue, peer set and wake channels to clean any internal leftover state 377 d.queue.Reset(blockCacheMaxItems, blockCacheInitialItems) 378 d.peers.Reset() 379 380 for _, ch := range []chan bool{d.queue.blockWakeCh, d.queue.receiptWakeCh} { 381 select { 382 case <-ch: 383 default: 384 } 385 } 386 for empty := false; !empty; { 387 select { 388 case <-d.headerProcCh: 389 default: 390 empty = true 391 } 392 } 393 // Create cancel channel for aborting mid-flight and mark the master peer 394 d.cancelLock.Lock() 395 d.cancelCh = make(chan struct{}) 396 d.cancelPeer = id 397 d.cancelLock.Unlock() 398 399 defer d.Cancel() // No matter what, we can't leave the cancel channel open 400 401 // Atomically set the requested sync mode 402 atomic.StoreUint32(&d.mode, uint32(mode)) 403 404 // Retrieve the origin peer and initiate the downloading process 405 p := d.peers.Peer(id) 406 if p == nil { 407 return errUnknownPeer 408 } 409 return d.syncWithPeer(p, hash, td) 410 } 411 412 func (d *Downloader) getMode() SyncMode { 413 return SyncMode(atomic.LoadUint32(&d.mode)) 414 } 415 416 // syncWithPeer starts a block synchronization based on the hash chain from the 417 // specified peer and head hash. 418 func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.Int) (err error) { 419 d.mux.Post(StartEvent{}) 420 defer func() { 421 // reset on error 422 if err != nil { 423 d.mux.Post(FailedEvent{err}) 424 } else { 425 latest := d.lightchain.CurrentHeader() 426 d.mux.Post(DoneEvent{latest}) 427 } 428 }() 429 if p.version < eth.ETH66 { 430 return fmt.Errorf("%w: advertized %d < required %d", errTooOld, p.version, eth.ETH66) 431 } 432 mode := d.getMode() 433 434 log.Debug("Synchronising with the network", "peer", p.id, "eth", p.version, "head", hash, "td", td, "mode", mode) 435 defer func(start time.Time) { 436 log.Debug("Synchronisation terminated", "elapsed", common.PrettyDuration(time.Since(start))) 437 }(time.Now()) 438 439 // Look up the sync boundaries: the common ancestor and the target block 440 latest, pivot, err := d.fetchHead(p) 441 if err != nil { 442 return err 443 } 444 if mode == SnapSync && pivot == nil { 445 // If no pivot block was returned, the head is below the min full block 446 // threshold (i.e. new chain). In that case we won't really snap sync 447 // anyway, but still need a valid pivot block to avoid some code hitting 448 // nil panics on an access. 449 pivot = d.blockchain.CurrentBlock().Header() 450 } 451 height := latest.Number.Uint64() 452 453 origin, err := d.findAncestor(p, latest) 454 if err != nil { 455 return err 456 } 457 d.syncStatsLock.Lock() 458 if d.syncStatsChainHeight <= origin || d.syncStatsChainOrigin > origin { 459 d.syncStatsChainOrigin = origin 460 } 461 d.syncStatsChainHeight = height 462 d.syncStatsLock.Unlock() 463 464 // Ensure our origin point is below any snap sync pivot point 465 if mode == SnapSync { 466 if height <= uint64(fsMinFullBlocks) { 467 origin = 0 468 } else { 469 pivotNumber := pivot.Number.Uint64() 470 if pivotNumber <= origin { 471 origin = pivotNumber - 1 472 } 473 // Write out the pivot into the database so a rollback beyond it will 474 // reenable snap sync 475 rawdb.WriteLastPivotNumber(d.stateDB, pivotNumber) 476 } 477 } 478 d.committed = 1 479 if mode == SnapSync && pivot.Number.Uint64() != 0 { 480 d.committed = 0 481 } 482 if mode == SnapSync { 483 // Set the ancient data limitation. 484 // If we are running snap sync, all block data older than ancientLimit will be 485 // written to the ancient store. More recent data will be written to the active 486 // database and will wait for the freezer to migrate. 487 // 488 // If there is a checkpoint available, then calculate the ancientLimit through 489 // that. Otherwise calculate the ancient limit through the advertised height 490 // of the remote peer. 491 // 492 // The reason for picking checkpoint first is that a malicious peer can give us 493 // a fake (very high) height, forcing the ancient limit to also be very high. 494 // The peer would start to feed us valid blocks until head, resulting in all of 495 // the blocks might be written into the ancient store. A following mini-reorg 496 // could cause issues. 497 if d.checkpoint != 0 && d.checkpoint > fullMaxForkAncestry+1 { 498 d.ancientLimit = d.checkpoint 499 } else if height > fullMaxForkAncestry+1 { 500 d.ancientLimit = height - fullMaxForkAncestry - 1 501 } else { 502 d.ancientLimit = 0 503 } 504 frozen, _ := d.stateDB.Ancients() // Ignore the error here since light client can also hit here. 505 506 // If a part of blockchain data has already been written into active store, 507 // disable the ancient style insertion explicitly. 508 if origin >= frozen && frozen != 0 { 509 d.ancientLimit = 0 510 log.Info("Disabling direct-ancient mode", "origin", origin, "ancient", frozen-1) 511 } else if d.ancientLimit > 0 { 512 log.Debug("Enabling direct-ancient mode", "ancient", d.ancientLimit) 513 } 514 // Rewind the ancient store and blockchain if reorg happens. 515 if origin+1 < frozen { 516 if err := d.lightchain.SetHead(origin); err != nil { 517 return err 518 } 519 } 520 } 521 // Initiate the sync using a concurrent header and content retrieval algorithm 522 d.queue.Prepare(origin+1, mode) 523 if d.syncInitHook != nil { 524 d.syncInitHook(origin, height) 525 } 526 fetchers := []func() error{ 527 func() error { return d.fetchHeaders(p, origin+1, latest.Number.Uint64()) }, // Headers are always retrieved 528 func() error { return d.fetchBodies(origin + 1) }, // Bodies are retrieved during normal and snap sync 529 func() error { return d.fetchReceipts(origin + 1) }, // Receipts are retrieved during snap sync 530 func() error { return d.processHeaders(origin+1, td) }, 531 } 532 if mode == SnapSync { 533 d.pivotLock.Lock() 534 d.pivotHeader = pivot 535 d.pivotLock.Unlock() 536 537 fetchers = append(fetchers, func() error { return d.processSnapSyncContent() }) 538 } else if mode == FullSync { 539 fetchers = append(fetchers, d.processFullSyncContent) 540 } 541 return d.spawnSync(fetchers) 542 } 543 544 // spawnSync runs d.process and all given fetcher functions to completion in 545 // separate goroutines, returning the first error that appears. 546 func (d *Downloader) spawnSync(fetchers []func() error) error { 547 errc := make(chan error, len(fetchers)) 548 d.cancelWg.Add(len(fetchers)) 549 for _, fn := range fetchers { 550 fn := fn 551 go func() { defer d.cancelWg.Done(); errc <- fn() }() 552 } 553 // Wait for the first error, then terminate the others. 554 var err error 555 for i := 0; i < len(fetchers); i++ { 556 if i == len(fetchers)-1 { 557 // Close the queue when all fetchers have exited. 558 // This will cause the block processor to end when 559 // it has processed the queue. 560 d.queue.Close() 561 } 562 if err = <-errc; err != nil && err != errCanceled { 563 break 564 } 565 } 566 d.queue.Close() 567 d.Cancel() 568 return err 569 } 570 571 // cancel aborts all of the operations and resets the queue. However, cancel does 572 // not wait for the running download goroutines to finish. This method should be 573 // used when cancelling the downloads from inside the downloader. 574 func (d *Downloader) cancel() { 575 // Close the current cancel channel 576 d.cancelLock.Lock() 577 defer d.cancelLock.Unlock() 578 579 if d.cancelCh != nil { 580 select { 581 case <-d.cancelCh: 582 // Channel was already closed 583 default: 584 close(d.cancelCh) 585 } 586 } 587 } 588 589 // Cancel aborts all of the operations and waits for all download goroutines to 590 // finish before returning. 591 func (d *Downloader) Cancel() { 592 d.cancel() 593 d.cancelWg.Wait() 594 } 595 596 // Terminate interrupts the downloader, canceling all pending operations. 597 // The downloader cannot be reused after calling Terminate. 598 func (d *Downloader) Terminate() { 599 // Close the termination channel (make sure double close is allowed) 600 d.quitLock.Lock() 601 select { 602 case <-d.quitCh: 603 default: 604 close(d.quitCh) 605 } 606 d.quitLock.Unlock() 607 608 // Cancel any pending download requests 609 d.Cancel() 610 } 611 612 // fetchHead retrieves the head header and prior pivot block (if available) from 613 // a remote peer. 614 func (d *Downloader) fetchHead(p *peerConnection) (head *types.Header, pivot *types.Header, err error) { 615 p.log.Debug("Retrieving remote chain head") 616 mode := d.getMode() 617 618 // Request the advertised remote head block and wait for the response 619 latest, _ := p.peer.Head() 620 fetch := 1 621 if mode == SnapSync { 622 fetch = 2 // head + pivot headers 623 } 624 headers, hashes, err := d.fetchHeadersByHash(p, latest, fetch, fsMinFullBlocks-1, true) 625 if err != nil { 626 return nil, nil, err 627 } 628 // Make sure the peer gave us at least one and at most the requested headers 629 if len(headers) == 0 || len(headers) > fetch { 630 return nil, nil, fmt.Errorf("%w: returned headers %d != requested %d", errBadPeer, len(headers), fetch) 631 } 632 // The first header needs to be the head, validate against the checkpoint 633 // and request. If only 1 header was returned, make sure there's no pivot 634 // or there was not one requested. 635 head = headers[0] 636 if (mode == SnapSync || mode == LightSync) && head.Number.Uint64() < d.checkpoint { 637 return nil, nil, fmt.Errorf("%w: remote head %d below checkpoint %d", errUnsyncedPeer, head.Number, d.checkpoint) 638 } 639 if len(headers) == 1 { 640 if mode == SnapSync && head.Number.Uint64() > uint64(fsMinFullBlocks) { 641 return nil, nil, fmt.Errorf("%w: no pivot included along head header", errBadPeer) 642 } 643 p.log.Debug("Remote head identified, no pivot", "number", head.Number, "hash", hashes[0]) 644 return head, nil, nil 645 } 646 // At this point we have 2 headers in total and the first is the 647 // validated head of the chain. Check the pivot number and return, 648 pivot = headers[1] 649 if pivot.Number.Uint64() != head.Number.Uint64()-uint64(fsMinFullBlocks) { 650 return nil, nil, fmt.Errorf("%w: remote pivot %d != requested %d", errInvalidChain, pivot.Number, head.Number.Uint64()-uint64(fsMinFullBlocks)) 651 } 652 return head, pivot, nil 653 } 654 655 // calculateRequestSpan calculates what headers to request from a peer when trying to determine the 656 // common ancestor. 657 // It returns parameters to be used for peer.RequestHeadersByNumber: 658 // from - starting block number 659 // count - number of headers to request 660 // skip - number of headers to skip 661 // and also returns 'max', the last block which is expected to be returned by the remote peers, 662 // given the (from,count,skip) 663 func calculateRequestSpan(remoteHeight, localHeight uint64) (int64, int, int, uint64) { 664 var ( 665 from int 666 count int 667 MaxCount = MaxHeaderFetch / 16 668 ) 669 // requestHead is the highest block that we will ask for. If requestHead is not offset, 670 // the highest block that we will get is 16 blocks back from head, which means we 671 // will fetch 14 or 15 blocks unnecessarily in the case the height difference 672 // between us and the peer is 1-2 blocks, which is most common 673 requestHead := int(remoteHeight) - 1 674 if requestHead < 0 { 675 requestHead = 0 676 } 677 // requestBottom is the lowest block we want included in the query 678 // Ideally, we want to include the one just below our own head 679 requestBottom := int(localHeight - 1) 680 if requestBottom < 0 { 681 requestBottom = 0 682 } 683 totalSpan := requestHead - requestBottom 684 span := 1 + totalSpan/MaxCount 685 if span < 2 { 686 span = 2 687 } 688 if span > 16 { 689 span = 16 690 } 691 692 count = 1 + totalSpan/span 693 if count > MaxCount { 694 count = MaxCount 695 } 696 if count < 2 { 697 count = 2 698 } 699 from = requestHead - (count-1)*span 700 if from < 0 { 701 from = 0 702 } 703 max := from + (count-1)*span 704 return int64(from), count, span - 1, uint64(max) 705 } 706 707 // findAncestor tries to locate the common ancestor link of the local chain and 708 // a remote peers blockchain. In the general case when our node was in sync and 709 // on the correct chain, checking the top N links should already get us a match. 710 // In the rare scenario when we ended up on a long reorganisation (i.e. none of 711 // the head links match), we do a binary search to find the common ancestor. 712 func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) (uint64, error) { 713 // Figure out the valid ancestor range to prevent rewrite attacks 714 var ( 715 floor = int64(-1) 716 localHeight uint64 717 remoteHeight = remoteHeader.Number.Uint64() 718 ) 719 mode := d.getMode() 720 switch mode { 721 case FullSync: 722 localHeight = d.blockchain.CurrentBlock().NumberU64() 723 case SnapSync: 724 localHeight = d.blockchain.CurrentFastBlock().NumberU64() 725 default: 726 localHeight = d.lightchain.CurrentHeader().Number.Uint64() 727 } 728 p.log.Debug("Looking for common ancestor", "local", localHeight, "remote", remoteHeight) 729 730 // Recap floor value for binary search 731 maxForkAncestry := fullMaxForkAncestry 732 if d.getMode() == LightSync { 733 maxForkAncestry = lightMaxForkAncestry 734 } 735 if localHeight >= maxForkAncestry { 736 // We're above the max reorg threshold, find the earliest fork point 737 floor = int64(localHeight - maxForkAncestry) 738 } 739 // If we're doing a light sync, ensure the floor doesn't go below the CHT, as 740 // all headers before that point will be missing. 741 if mode == LightSync { 742 // If we don't know the current CHT position, find it 743 if d.genesis == 0 { 744 header := d.lightchain.CurrentHeader() 745 for header != nil { 746 d.genesis = header.Number.Uint64() 747 if floor >= int64(d.genesis)-1 { 748 break 749 } 750 header = d.lightchain.GetHeaderByHash(header.ParentHash) 751 } 752 } 753 // We already know the "genesis" block number, cap floor to that 754 if floor < int64(d.genesis)-1 { 755 floor = int64(d.genesis) - 1 756 } 757 } 758 759 ancestor, err := d.findAncestorSpanSearch(p, mode, remoteHeight, localHeight, floor) 760 if err == nil { 761 return ancestor, nil 762 } 763 // The returned error was not nil. 764 // If the error returned does not reflect that a common ancestor was not found, return it. 765 // If the error reflects that a common ancestor was not found, continue to binary search, 766 // where the error value will be reassigned. 767 if !errors.Is(err, errNoAncestorFound) { 768 return 0, err 769 } 770 771 ancestor, err = d.findAncestorBinarySearch(p, mode, remoteHeight, floor) 772 if err != nil { 773 return 0, err 774 } 775 return ancestor, nil 776 } 777 778 func (d *Downloader) findAncestorSpanSearch(p *peerConnection, mode SyncMode, remoteHeight, localHeight uint64, floor int64) (uint64, error) { 779 from, count, skip, max := calculateRequestSpan(remoteHeight, localHeight) 780 781 p.log.Trace("Span searching for common ancestor", "count", count, "from", from, "skip", skip) 782 headers, hashes, err := d.fetchHeadersByNumber(p, uint64(from), count, skip, false) 783 if err != nil { 784 return 0, err 785 } 786 // Wait for the remote response to the head fetch 787 number, hash := uint64(0), common.Hash{} 788 789 // Make sure the peer actually gave something valid 790 if len(headers) == 0 { 791 p.log.Warn("Empty head header set") 792 return 0, errEmptyHeaderSet 793 } 794 // Make sure the peer's reply conforms to the request 795 for i, header := range headers { 796 expectNumber := from + int64(i)*int64(skip+1) 797 if number := header.Number.Int64(); number != expectNumber { 798 p.log.Warn("Head headers broke chain ordering", "index", i, "requested", expectNumber, "received", number) 799 return 0, fmt.Errorf("%w: %v", errInvalidChain, errors.New("head headers broke chain ordering")) 800 } 801 } 802 // Check if a common ancestor was found 803 for i := len(headers) - 1; i >= 0; i-- { 804 // Skip any headers that underflow/overflow our requested set 805 if headers[i].Number.Int64() < from || headers[i].Number.Uint64() > max { 806 continue 807 } 808 // Otherwise check if we already know the header or not 809 h := hashes[i] 810 n := headers[i].Number.Uint64() 811 812 var known bool 813 switch mode { 814 case FullSync: 815 known = d.blockchain.HasBlock(h, n) 816 case SnapSync: 817 known = d.blockchain.HasFastBlock(h, n) 818 default: 819 known = d.lightchain.HasHeader(h, n) 820 } 821 if known { 822 number, hash = n, h 823 break 824 } 825 } 826 // If the head fetch already found an ancestor, return 827 if hash != (common.Hash{}) { 828 if int64(number) <= floor { 829 p.log.Warn("Ancestor below allowance", "number", number, "hash", hash, "allowance", floor) 830 return 0, errInvalidAncestor 831 } 832 p.log.Debug("Found common ancestor", "number", number, "hash", hash) 833 return number, nil 834 } 835 return 0, errNoAncestorFound 836 } 837 838 func (d *Downloader) findAncestorBinarySearch(p *peerConnection, mode SyncMode, remoteHeight uint64, floor int64) (uint64, error) { 839 hash := common.Hash{} 840 841 // Ancestor not found, we need to binary search over our chain 842 start, end := uint64(0), remoteHeight 843 if floor > 0 { 844 start = uint64(floor) 845 } 846 p.log.Trace("Binary searching for common ancestor", "start", start, "end", end) 847 848 for start+1 < end { 849 // Split our chain interval in two, and request the hash to cross check 850 check := (start + end) / 2 851 852 headers, hashes, err := d.fetchHeadersByNumber(p, check, 1, 0, false) 853 if err != nil { 854 return 0, err 855 } 856 // Make sure the peer actually gave something valid 857 if len(headers) != 1 { 858 p.log.Warn("Multiple headers for single request", "headers", len(headers)) 859 return 0, fmt.Errorf("%w: multiple headers (%d) for single request", errBadPeer, len(headers)) 860 } 861 // Modify the search interval based on the response 862 h := hashes[0] 863 n := headers[0].Number.Uint64() 864 865 var known bool 866 switch mode { 867 case FullSync: 868 known = d.blockchain.HasBlock(h, n) 869 case SnapSync: 870 known = d.blockchain.HasFastBlock(h, n) 871 default: 872 known = d.lightchain.HasHeader(h, n) 873 } 874 if !known { 875 end = check 876 continue 877 } 878 header := d.lightchain.GetHeaderByHash(h) // Independent of sync mode, header surely exists 879 if header.Number.Uint64() != check { 880 p.log.Warn("Received non requested header", "number", header.Number, "hash", header.Hash(), "request", check) 881 return 0, fmt.Errorf("%w: non-requested header (%d)", errBadPeer, header.Number) 882 } 883 start = check 884 hash = h 885 } 886 // Ensure valid ancestry and return 887 if int64(start) <= floor { 888 p.log.Warn("Ancestor below allowance", "number", start, "hash", hash, "allowance", floor) 889 return 0, errInvalidAncestor 890 } 891 p.log.Debug("Found common ancestor", "number", start, "hash", hash) 892 return start, nil 893 } 894 895 // fetchHeaders keeps retrieving headers concurrently from the number 896 // requested, until no more are returned, potentially throttling on the way. To 897 // facilitate concurrency but still protect against malicious nodes sending bad 898 // headers, we construct a header chain skeleton using the "origin" peer we are 899 // syncing with, and fill in the missing headers using anyone else. Headers from 900 // other peers are only accepted if they map cleanly to the skeleton. If no one 901 // can fill in the skeleton - not even the origin peer - it's assumed invalid and 902 // the origin is dropped. 903 func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, head uint64) error { 904 p.log.Debug("Directing header downloads", "origin", from) 905 defer p.log.Debug("Header download terminated") 906 907 // Start pulling the header chain skeleton until all is done 908 var ( 909 skeleton = true // Skeleton assembly phase or finishing up 910 pivoting = false // Whether the next request is pivot verification 911 ancestor = from 912 mode = d.getMode() 913 ) 914 for { 915 // Pull the next batch of headers, it either: 916 // - Pivot check to see if the chain moved too far 917 // - Skeleton retrieval to permit concurrent header fetches 918 // - Full header retrieval if we're near the chain head 919 var ( 920 headers []*types.Header 921 hashes []common.Hash 922 err error 923 ) 924 switch { 925 case pivoting: 926 d.pivotLock.RLock() 927 pivot := d.pivotHeader.Number.Uint64() 928 d.pivotLock.RUnlock() 929 930 p.log.Trace("Fetching next pivot header", "number", pivot+uint64(fsMinFullBlocks)) 931 headers, hashes, err = d.fetchHeadersByNumber(p, pivot+uint64(fsMinFullBlocks), 2, fsMinFullBlocks-9, false) // move +64 when it's 2x64-8 deep 932 933 case skeleton: 934 p.log.Trace("Fetching skeleton headers", "count", MaxHeaderFetch, "from", from) 935 headers, hashes, err = d.fetchHeadersByNumber(p, from+uint64(MaxHeaderFetch)-1, MaxSkeletonSize, MaxHeaderFetch-1, false) 936 937 default: 938 p.log.Trace("Fetching full headers", "count", MaxHeaderFetch, "from", from) 939 headers, hashes, err = d.fetchHeadersByNumber(p, from, MaxHeaderFetch, 0, false) 940 } 941 switch err { 942 case nil: 943 // Headers retrieved, continue with processing 944 945 case errCanceled: 946 // Sync cancelled, no issue, propagate up 947 return err 948 949 default: 950 // Header retrieval either timed out, or the peer failed in some strange way 951 // (e.g. disconnect). Consider the master peer bad and drop 952 d.dropPeer(p.id) 953 954 // Finish the sync gracefully instead of dumping the gathered data though 955 for _, ch := range []chan bool{d.queue.blockWakeCh, d.queue.receiptWakeCh} { 956 select { 957 case ch <- false: 958 case <-d.cancelCh: 959 } 960 } 961 select { 962 case d.headerProcCh <- nil: 963 case <-d.cancelCh: 964 } 965 return fmt.Errorf("%w: header request failed: %v", errBadPeer, err) 966 } 967 // If the pivot is being checked, move if it became stale and run the real retrieval 968 var pivot uint64 969 970 d.pivotLock.RLock() 971 if d.pivotHeader != nil { 972 pivot = d.pivotHeader.Number.Uint64() 973 } 974 d.pivotLock.RUnlock() 975 976 if pivoting { 977 if len(headers) == 2 { 978 if have, want := headers[0].Number.Uint64(), pivot+uint64(fsMinFullBlocks); have != want { 979 log.Warn("Peer sent invalid next pivot", "have", have, "want", want) 980 return fmt.Errorf("%w: next pivot number %d != requested %d", errInvalidChain, have, want) 981 } 982 if have, want := headers[1].Number.Uint64(), pivot+2*uint64(fsMinFullBlocks)-8; have != want { 983 log.Warn("Peer sent invalid pivot confirmer", "have", have, "want", want) 984 return fmt.Errorf("%w: next pivot confirmer number %d != requested %d", errInvalidChain, have, want) 985 } 986 log.Warn("Pivot seemingly stale, moving", "old", pivot, "new", headers[0].Number) 987 pivot = headers[0].Number.Uint64() 988 989 d.pivotLock.Lock() 990 d.pivotHeader = headers[0] 991 d.pivotLock.Unlock() 992 993 // Write out the pivot into the database so a rollback beyond 994 // it will reenable snap sync and update the state root that 995 // the state syncer will be downloading. 996 rawdb.WriteLastPivotNumber(d.stateDB, pivot) 997 } 998 // Disable the pivot check and fetch the next batch of headers 999 pivoting = false 1000 continue 1001 } 1002 // If the skeleton's finished, pull any remaining head headers directly from the origin 1003 if skeleton && len(headers) == 0 { 1004 // A malicious node might withhold advertised headers indefinitely 1005 if from+uint64(MaxHeaderFetch)-1 <= head { 1006 p.log.Warn("Peer withheld skeleton headers", "advertised", head, "withheld", from+uint64(MaxHeaderFetch)-1) 1007 return fmt.Errorf("%w: withheld skeleton headers: advertised %d, withheld #%d", errStallingPeer, head, from+uint64(MaxHeaderFetch)-1) 1008 } 1009 p.log.Debug("No skeleton, fetching headers directly") 1010 skeleton = false 1011 continue 1012 } 1013 // If no more headers are inbound, notify the content fetchers and return 1014 if len(headers) == 0 { 1015 // Don't abort header fetches while the pivot is downloading 1016 if atomic.LoadInt32(&d.committed) == 0 && pivot <= from { 1017 p.log.Debug("No headers, waiting for pivot commit") 1018 select { 1019 case <-time.After(fsHeaderContCheck): 1020 continue 1021 case <-d.cancelCh: 1022 return errCanceled 1023 } 1024 } 1025 // Pivot done (or not in snap sync) and no more headers, terminate the process 1026 p.log.Debug("No more headers available") 1027 select { 1028 case d.headerProcCh <- nil: 1029 return nil 1030 case <-d.cancelCh: 1031 return errCanceled 1032 } 1033 } 1034 // If we received a skeleton batch, resolve internals concurrently 1035 var progressed bool 1036 if skeleton { 1037 filled, hashset, proced, err := d.fillHeaderSkeleton(from, headers) 1038 if err != nil { 1039 p.log.Debug("Skeleton chain invalid", "err", err) 1040 return fmt.Errorf("%w: %v", errInvalidChain, err) 1041 } 1042 headers = filled[proced:] 1043 hashes = hashset[proced:] 1044 1045 progressed = proced > 0 1046 from += uint64(proced) 1047 } else { 1048 // A malicious node might withhold advertised headers indefinitely 1049 if n := len(headers); n < MaxHeaderFetch && headers[n-1].Number.Uint64() < head { 1050 p.log.Warn("Peer withheld headers", "advertised", head, "delivered", headers[n-1].Number.Uint64()) 1051 return fmt.Errorf("%w: withheld headers: advertised %d, delivered %d", errStallingPeer, head, headers[n-1].Number.Uint64()) 1052 } 1053 // If we're closing in on the chain head, but haven't yet reached it, delay 1054 // the last few headers so mini reorgs on the head don't cause invalid hash 1055 // chain errors. 1056 if n := len(headers); n > 0 { 1057 // Retrieve the current head we're at 1058 var head uint64 1059 if mode == LightSync { 1060 head = d.lightchain.CurrentHeader().Number.Uint64() 1061 } else { 1062 head = d.blockchain.CurrentFastBlock().NumberU64() 1063 if full := d.blockchain.CurrentBlock().NumberU64(); head < full { 1064 head = full 1065 } 1066 } 1067 // If the head is below the common ancestor, we're actually deduplicating 1068 // already existing chain segments, so use the ancestor as the fake head. 1069 // Otherwise, we might end up delaying header deliveries pointlessly. 1070 if head < ancestor { 1071 head = ancestor 1072 } 1073 // If the head is way older than this batch, delay the last few headers 1074 if head+uint64(reorgProtThreshold) < headers[n-1].Number.Uint64() { 1075 delay := reorgProtHeaderDelay 1076 if delay > n { 1077 delay = n 1078 } 1079 headers = headers[:n-delay] 1080 hashes = hashes[:n-delay] 1081 } 1082 } 1083 } 1084 // If no headers have bene delivered, or all of them have been delayed, 1085 // sleep a bit and retry. Take care with headers already consumed during 1086 // skeleton filling 1087 if len(headers) == 0 && !progressed { 1088 p.log.Trace("All headers delayed, waiting") 1089 select { 1090 case <-time.After(fsHeaderContCheck): 1091 continue 1092 case <-d.cancelCh: 1093 return errCanceled 1094 } 1095 } 1096 // Insert any remaining new headers and fetch the next batch 1097 if len(headers) > 0 { 1098 p.log.Trace("Scheduling new headers", "count", len(headers), "from", from) 1099 select { 1100 case d.headerProcCh <- &headerTask{ 1101 headers: headers, 1102 hashes: hashes, 1103 }: 1104 case <-d.cancelCh: 1105 return errCanceled 1106 } 1107 from += uint64(len(headers)) 1108 } 1109 // If we're still skeleton filling snap sync, check pivot staleness 1110 // before continuing to the next skeleton filling 1111 if skeleton && pivot > 0 { 1112 pivoting = true 1113 } 1114 } 1115 } 1116 1117 // fillHeaderSkeleton concurrently retrieves headers from all our available peers 1118 // and maps them to the provided skeleton header chain. 1119 // 1120 // Any partial results from the beginning of the skeleton is (if possible) forwarded 1121 // immediately to the header processor to keep the rest of the pipeline full even 1122 // in the case of header stalls. 1123 // 1124 // The method returns the entire filled skeleton and also the number of headers 1125 // already forwarded for processing. 1126 func (d *Downloader) fillHeaderSkeleton(from uint64, skeleton []*types.Header) ([]*types.Header, []common.Hash, int, error) { 1127 log.Debug("Filling up skeleton", "from", from) 1128 d.queue.ScheduleSkeleton(from, skeleton) 1129 1130 err := d.concurrentFetch((*headerQueue)(d)) 1131 if err != nil { 1132 log.Debug("Skeleton fill failed", "err", err) 1133 } 1134 filled, hashes, proced := d.queue.RetrieveHeaders() 1135 if err == nil { 1136 log.Debug("Skeleton fill succeeded", "filled", len(filled), "processed", proced) 1137 } 1138 return filled, hashes, proced, err 1139 } 1140 1141 // fetchBodies iteratively downloads the scheduled block bodies, taking any 1142 // available peers, reserving a chunk of blocks for each, waiting for delivery 1143 // and also periodically checking for timeouts. 1144 func (d *Downloader) fetchBodies(from uint64) error { 1145 log.Debug("Downloading block bodies", "origin", from) 1146 err := d.concurrentFetch((*bodyQueue)(d)) 1147 1148 log.Debug("Block body download terminated", "err", err) 1149 return err 1150 } 1151 1152 // fetchReceipts iteratively downloads the scheduled block receipts, taking any 1153 // available peers, reserving a chunk of receipts for each, waiting for delivery 1154 // and also periodically checking for timeouts. 1155 func (d *Downloader) fetchReceipts(from uint64) error { 1156 log.Debug("Downloading receipts", "origin", from) 1157 err := d.concurrentFetch((*receiptQueue)(d)) 1158 1159 log.Debug("Receipt download terminated", "err", err) 1160 return err 1161 } 1162 1163 // processHeaders takes batches of retrieved headers from an input channel and 1164 // keeps processing and scheduling them into the header chain and downloader's 1165 // queue until the stream ends or a failure occurs. 1166 func (d *Downloader) processHeaders(origin uint64, td *big.Int) error { 1167 // Keep a count of uncertain headers to roll back 1168 var ( 1169 rollback uint64 // Zero means no rollback (fine as you can't unroll the genesis) 1170 rollbackErr error 1171 mode = d.getMode() 1172 ) 1173 defer func() { 1174 if rollback > 0 { 1175 lastHeader, lastFastBlock, lastBlock := d.lightchain.CurrentHeader().Number, common.Big0, common.Big0 1176 if mode != LightSync { 1177 lastFastBlock = d.blockchain.CurrentFastBlock().Number() 1178 lastBlock = d.blockchain.CurrentBlock().Number() 1179 } 1180 if err := d.lightchain.SetHead(rollback - 1); err != nil { // -1 to target the parent of the first uncertain block 1181 // We're already unwinding the stack, only print the error to make it more visible 1182 log.Error("Failed to roll back chain segment", "head", rollback-1, "err", err) 1183 } 1184 curFastBlock, curBlock := common.Big0, common.Big0 1185 if mode != LightSync { 1186 curFastBlock = d.blockchain.CurrentFastBlock().Number() 1187 curBlock = d.blockchain.CurrentBlock().Number() 1188 } 1189 log.Warn("Rolled back chain segment", 1190 "header", fmt.Sprintf("%d->%d", lastHeader, d.lightchain.CurrentHeader().Number), 1191 "snap", fmt.Sprintf("%d->%d", lastFastBlock, curFastBlock), 1192 "block", fmt.Sprintf("%d->%d", lastBlock, curBlock), "reason", rollbackErr) 1193 } 1194 }() 1195 // Wait for batches of headers to process 1196 gotHeaders := false 1197 1198 for { 1199 select { 1200 case <-d.cancelCh: 1201 rollbackErr = errCanceled 1202 return errCanceled 1203 1204 case task := <-d.headerProcCh: 1205 // Terminate header processing if we synced up 1206 if task == nil || len(task.headers) == 0 { 1207 // Notify everyone that headers are fully processed 1208 for _, ch := range []chan bool{d.queue.blockWakeCh, d.queue.receiptWakeCh} { 1209 select { 1210 case ch <- false: 1211 case <-d.cancelCh: 1212 } 1213 } 1214 // If no headers were retrieved at all, the peer violated its TD promise that it had a 1215 // better chain compared to ours. The only exception is if its promised blocks were 1216 // already imported by other means (e.g. fetcher): 1217 // 1218 // R <remote peer>, L <local node>: Both at block 10 1219 // R: Mine block 11, and propagate it to L 1220 // L: Queue block 11 for import 1221 // L: Notice that R's head and TD increased compared to ours, start sync 1222 // L: Import of block 11 finishes 1223 // L: Sync begins, and finds common ancestor at 11 1224 // L: Request new headers up from 11 (R's TD was higher, it must have something) 1225 // R: Nothing to give 1226 if mode != LightSync { 1227 head := d.blockchain.CurrentBlock() 1228 if !gotHeaders && td.Cmp(d.blockchain.GetTd(head.Hash(), head.NumberU64())) > 0 { 1229 return errStallingPeer 1230 } 1231 } 1232 // If snap or light syncing, ensure promised headers are indeed delivered. This is 1233 // needed to detect scenarios where an attacker feeds a bad pivot and then bails out 1234 // of delivering the post-pivot blocks that would flag the invalid content. 1235 // 1236 // This check cannot be executed "as is" for full imports, since blocks may still be 1237 // queued for processing when the header download completes. However, as long as the 1238 // peer gave us something useful, we're already happy/progressed (above check). 1239 if mode == SnapSync || mode == LightSync { 1240 head := d.lightchain.CurrentHeader() 1241 if td.Cmp(d.lightchain.GetTd(head.Hash(), head.Number.Uint64())) > 0 { 1242 return errStallingPeer 1243 } 1244 } 1245 // Disable any rollback and return 1246 rollback = 0 1247 return nil 1248 } 1249 // Otherwise split the chunk of headers into batches and process them 1250 headers, hashes := task.headers, task.hashes 1251 1252 gotHeaders = true 1253 for len(headers) > 0 { 1254 // Terminate if something failed in between processing chunks 1255 select { 1256 case <-d.cancelCh: 1257 rollbackErr = errCanceled 1258 return errCanceled 1259 default: 1260 } 1261 // Select the next chunk of headers to import 1262 limit := maxHeadersProcess 1263 if limit > len(headers) { 1264 limit = len(headers) 1265 } 1266 chunkHeaders := headers[:limit] 1267 chunkHashes := hashes[:limit] 1268 1269 // In case of header only syncing, validate the chunk immediately 1270 if mode == SnapSync || mode == LightSync { 1271 // If we're importing pure headers, verify based on their recentness 1272 var pivot uint64 1273 1274 d.pivotLock.RLock() 1275 if d.pivotHeader != nil { 1276 pivot = d.pivotHeader.Number.Uint64() 1277 } 1278 d.pivotLock.RUnlock() 1279 1280 frequency := fsHeaderCheckFrequency 1281 if chunkHeaders[len(chunkHeaders)-1].Number.Uint64()+uint64(fsHeaderForceVerify) > pivot { 1282 frequency = 1 1283 } 1284 if n, err := d.lightchain.InsertHeaderChain(chunkHeaders, frequency); err != nil { 1285 rollbackErr = err 1286 1287 // If some headers were inserted, track them as uncertain 1288 if (mode == SnapSync || frequency > 1) && n > 0 && rollback == 0 { 1289 rollback = chunkHeaders[0].Number.Uint64() 1290 } 1291 log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err) 1292 return fmt.Errorf("%w: %v", errInvalidChain, err) 1293 } 1294 // All verifications passed, track all headers within the alloted limits 1295 if mode == SnapSync { 1296 head := chunkHeaders[len(chunkHeaders)-1].Number.Uint64() 1297 if head-rollback > uint64(fsHeaderSafetyNet) { 1298 rollback = head - uint64(fsHeaderSafetyNet) 1299 } else { 1300 rollback = 1 1301 } 1302 } 1303 } 1304 // Unless we're doing light chains, schedule the headers for associated content retrieval 1305 if mode == FullSync || mode == SnapSync { 1306 // If we've reached the allowed number of pending headers, stall a bit 1307 for d.queue.PendingBodies() >= maxQueuedHeaders || d.queue.PendingReceipts() >= maxQueuedHeaders { 1308 select { 1309 case <-d.cancelCh: 1310 rollbackErr = errCanceled 1311 return errCanceled 1312 case <-time.After(time.Second): 1313 } 1314 } 1315 // Otherwise insert the headers for content retrieval 1316 inserts := d.queue.Schedule(chunkHeaders, chunkHashes, origin) 1317 if len(inserts) != len(chunkHeaders) { 1318 rollbackErr = fmt.Errorf("stale headers: len inserts %v len(chunk) %v", len(inserts), len(chunkHeaders)) 1319 return fmt.Errorf("%w: stale headers", errBadPeer) 1320 } 1321 } 1322 headers = headers[limit:] 1323 hashes = hashes[limit:] 1324 origin += uint64(limit) 1325 } 1326 // Update the highest block number we know if a higher one is found. 1327 d.syncStatsLock.Lock() 1328 if d.syncStatsChainHeight < origin { 1329 d.syncStatsChainHeight = origin - 1 1330 } 1331 d.syncStatsLock.Unlock() 1332 1333 // Signal the content downloaders of the availablility of new tasks 1334 for _, ch := range []chan bool{d.queue.blockWakeCh, d.queue.receiptWakeCh} { 1335 select { 1336 case ch <- true: 1337 default: 1338 } 1339 } 1340 } 1341 } 1342 } 1343 1344 // processFullSyncContent takes fetch results from the queue and imports them into the chain. 1345 func (d *Downloader) processFullSyncContent() error { 1346 for { 1347 results := d.queue.Results(true) 1348 if len(results) == 0 { 1349 return nil 1350 } 1351 if d.chainInsertHook != nil { 1352 d.chainInsertHook(results) 1353 } 1354 if err := d.importBlockResults(results); err != nil { 1355 return err 1356 } 1357 } 1358 } 1359 1360 func (d *Downloader) importBlockResults(results []*fetchResult) error { 1361 // Check for any early termination requests 1362 if len(results) == 0 { 1363 return nil 1364 } 1365 select { 1366 case <-d.quitCh: 1367 return errCancelContentProcessing 1368 default: 1369 } 1370 // Retrieve the a batch of results to import 1371 first, last := results[0].Header, results[len(results)-1].Header 1372 log.Debug("Inserting downloaded chain", "items", len(results), 1373 "firstnum", first.Number, "firsthash", first.Hash(), 1374 "lastnum", last.Number, "lasthash", last.Hash(), 1375 ) 1376 blocks := make([]*types.Block, len(results)) 1377 for i, result := range results { 1378 blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) 1379 } 1380 // Downloaded blocks are always regarded as trusted after the 1381 // transition. Because the downloaded chain is guided by the 1382 // consensus-layer. 1383 if index, err := d.blockchain.InsertChain(blocks); err != nil { 1384 if index < len(results) { 1385 log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err) 1386 } else { 1387 // The InsertChain method in blockchain.go will sometimes return an out-of-bounds index, 1388 // when it needs to preprocess blocks to import a sidechain. 1389 // The importer will put together a new list of blocks to import, which is a superset 1390 // of the blocks delivered from the downloader, and the indexing will be off. 1391 log.Debug("Downloaded item processing failed on sidechain import", "index", index, "err", err) 1392 } 1393 return fmt.Errorf("%w: %v", errInvalidChain, err) 1394 } 1395 return nil 1396 } 1397 1398 // processSnapSyncContent takes fetch results from the queue and writes them to the 1399 // database. It also controls the synchronisation of state nodes of the pivot block. 1400 func (d *Downloader) processSnapSyncContent() error { 1401 // Start syncing state of the reported head block. This should get us most of 1402 // the state of the pivot block. 1403 d.pivotLock.RLock() 1404 sync := d.syncState(d.pivotHeader.Root) 1405 d.pivotLock.RUnlock() 1406 1407 defer func() { 1408 // The `sync` object is replaced every time the pivot moves. We need to 1409 // defer close the very last active one, hence the lazy evaluation vs. 1410 // calling defer sync.Cancel() !!! 1411 sync.Cancel() 1412 }() 1413 1414 closeOnErr := func(s *stateSync) { 1415 if err := s.Wait(); err != nil && err != errCancelStateFetch && err != errCanceled && err != snap.ErrCancelled { 1416 d.queue.Close() // wake up Results 1417 } 1418 } 1419 go closeOnErr(sync) 1420 1421 // To cater for moving pivot points, track the pivot block and subsequently 1422 // accumulated download results separately. 1423 var ( 1424 oldPivot *fetchResult // Locked in pivot block, might change eventually 1425 oldTail []*fetchResult // Downloaded content after the pivot 1426 ) 1427 for { 1428 // Wait for the next batch of downloaded data to be available, and if the pivot 1429 // block became stale, move the goalpost 1430 results := d.queue.Results(oldPivot == nil) // Block if we're not monitoring pivot staleness 1431 if len(results) == 0 { 1432 // If pivot sync is done, stop 1433 if oldPivot == nil { 1434 return sync.Cancel() 1435 } 1436 // If sync failed, stop 1437 select { 1438 case <-d.cancelCh: 1439 sync.Cancel() 1440 return errCanceled 1441 default: 1442 } 1443 } 1444 if d.chainInsertHook != nil { 1445 d.chainInsertHook(results) 1446 } 1447 // If we haven't downloaded the pivot block yet, check pivot staleness 1448 // notifications from the header downloader 1449 d.pivotLock.RLock() 1450 pivot := d.pivotHeader 1451 d.pivotLock.RUnlock() 1452 1453 if oldPivot == nil { 1454 if pivot.Root != sync.root { 1455 sync.Cancel() 1456 sync = d.syncState(pivot.Root) 1457 1458 go closeOnErr(sync) 1459 } 1460 } else { 1461 results = append(append([]*fetchResult{oldPivot}, oldTail...), results...) 1462 } 1463 // Split around the pivot block and process the two sides via snap/full sync 1464 if atomic.LoadInt32(&d.committed) == 0 { 1465 latest := results[len(results)-1].Header 1466 // If the height is above the pivot block by 2 sets, it means the pivot 1467 // become stale in the network and it was garbage collected, move to a 1468 // new pivot. 1469 // 1470 // Note, we have `reorgProtHeaderDelay` number of blocks withheld, Those 1471 // need to be taken into account, otherwise we're detecting the pivot move 1472 // late and will drop peers due to unavailable state!!! 1473 if height := latest.Number.Uint64(); height >= pivot.Number.Uint64()+2*uint64(fsMinFullBlocks)-uint64(reorgProtHeaderDelay) { 1474 log.Warn("Pivot became stale, moving", "old", pivot.Number.Uint64(), "new", height-uint64(fsMinFullBlocks)+uint64(reorgProtHeaderDelay)) 1475 pivot = results[len(results)-1-fsMinFullBlocks+reorgProtHeaderDelay].Header // must exist as lower old pivot is uncommitted 1476 1477 d.pivotLock.Lock() 1478 d.pivotHeader = pivot 1479 d.pivotLock.Unlock() 1480 1481 // Write out the pivot into the database so a rollback beyond it will 1482 // reenable snap sync 1483 rawdb.WriteLastPivotNumber(d.stateDB, pivot.Number.Uint64()) 1484 } 1485 } 1486 P, beforeP, afterP := splitAroundPivot(pivot.Number.Uint64(), results) 1487 if err := d.commitSnapSyncData(beforeP, sync); err != nil { 1488 return err 1489 } 1490 if P != nil { 1491 // If new pivot block found, cancel old state retrieval and restart 1492 if oldPivot != P { 1493 sync.Cancel() 1494 sync = d.syncState(P.Header.Root) 1495 1496 go closeOnErr(sync) 1497 oldPivot = P 1498 } 1499 // Wait for completion, occasionally checking for pivot staleness 1500 select { 1501 case <-sync.done: 1502 if sync.err != nil { 1503 return sync.err 1504 } 1505 if err := d.commitPivotBlock(P); err != nil { 1506 return err 1507 } 1508 oldPivot = nil 1509 1510 case <-time.After(time.Second): 1511 oldTail = afterP 1512 continue 1513 } 1514 } 1515 // Fast sync done, pivot commit done, full import 1516 if err := d.importBlockResults(afterP); err != nil { 1517 return err 1518 } 1519 } 1520 } 1521 1522 func splitAroundPivot(pivot uint64, results []*fetchResult) (p *fetchResult, before, after []*fetchResult) { 1523 if len(results) == 0 { 1524 return nil, nil, nil 1525 } 1526 if lastNum := results[len(results)-1].Header.Number.Uint64(); lastNum < pivot { 1527 // the pivot is somewhere in the future 1528 return nil, results, nil 1529 } 1530 // This can also be optimized, but only happens very seldom 1531 for _, result := range results { 1532 num := result.Header.Number.Uint64() 1533 switch { 1534 case num < pivot: 1535 before = append(before, result) 1536 case num == pivot: 1537 p = result 1538 default: 1539 after = append(after, result) 1540 } 1541 } 1542 return p, before, after 1543 } 1544 1545 func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *stateSync) error { 1546 // Check for any early termination requests 1547 if len(results) == 0 { 1548 return nil 1549 } 1550 select { 1551 case <-d.quitCh: 1552 return errCancelContentProcessing 1553 case <-stateSync.done: 1554 if err := stateSync.Wait(); err != nil { 1555 return err 1556 } 1557 default: 1558 } 1559 // Retrieve the a batch of results to import 1560 first, last := results[0].Header, results[len(results)-1].Header 1561 log.Debug("Inserting snap-sync blocks", "items", len(results), 1562 "firstnum", first.Number, "firsthash", first.Hash(), 1563 "lastnumn", last.Number, "lasthash", last.Hash(), 1564 ) 1565 blocks := make([]*types.Block, len(results)) 1566 receipts := make([]types.Receipts, len(results)) 1567 for i, result := range results { 1568 blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) 1569 receipts[i] = result.Receipts 1570 } 1571 if index, err := d.blockchain.InsertReceiptChain(blocks, receipts, d.ancientLimit); err != nil { 1572 log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err) 1573 return fmt.Errorf("%w: %v", errInvalidChain, err) 1574 } 1575 return nil 1576 } 1577 1578 func (d *Downloader) commitPivotBlock(result *fetchResult) error { 1579 block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) 1580 log.Debug("Committing snap sync pivot as new head", "number", block.Number(), "hash", block.Hash()) 1581 1582 // Commit the pivot block as the new head, will require full sync from here on 1583 if _, err := d.blockchain.InsertReceiptChain([]*types.Block{block}, []types.Receipts{result.Receipts}, d.ancientLimit); err != nil { 1584 return err 1585 } 1586 if err := d.blockchain.SnapSyncCommitHead(block.Hash()); err != nil { 1587 return err 1588 } 1589 atomic.StoreInt32(&d.committed, 1) 1590 return nil 1591 } 1592 1593 // DeliverSnapPacket is invoked from a peer's message handler when it transmits a 1594 // data packet for the local node to consume. 1595 func (d *Downloader) DeliverSnapPacket(peer *snap.Peer, packet snap.Packet) error { 1596 switch packet := packet.(type) { 1597 case *snap.AccountRangePacket: 1598 hashes, accounts, err := packet.Unpack() 1599 if err != nil { 1600 return err 1601 } 1602 return d.SnapSyncer.OnAccounts(peer, packet.ID, hashes, accounts, packet.Proof) 1603 1604 case *snap.StorageRangesPacket: 1605 hashset, slotset := packet.Unpack() 1606 return d.SnapSyncer.OnStorage(peer, packet.ID, hashset, slotset, packet.Proof) 1607 1608 case *snap.ByteCodesPacket: 1609 return d.SnapSyncer.OnByteCodes(peer, packet.ID, packet.Codes) 1610 1611 case *snap.TrieNodesPacket: 1612 return d.SnapSyncer.OnTrieNodes(peer, packet.ID, packet.Nodes) 1613 1614 default: 1615 return fmt.Errorf("unexpected snap packet type: %T", packet) 1616 } 1617 }