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