|
1 | 1 | // Copyright (c) 2013-2016 The btcsuite developers |
2 | | -// Copyright (c) 2015-2024 The Decred developers |
| 2 | +// Copyright (c) 2015-2025 The Decred developers |
3 | 3 | // Use of this source code is governed by an ISC |
4 | 4 | // license that can be found in the LICENSE file. |
5 | 5 |
|
@@ -213,9 +213,9 @@ type Peer struct { |
213 | 213 | requestedBlocks map[chainhash.Hash]struct{} |
214 | 214 | requestedMixMsgs map[chainhash.Hash]struct{} |
215 | 215 |
|
216 | | - // initialStateRequested tracks whether or not the initial state data has |
217 | | - // been requested from the peer. |
218 | | - initialStateRequested bool |
| 216 | + // requestInitialStateOnce is used to ensure the initial state data is only |
| 217 | + // requested from the peer once. |
| 218 | + requestInitialStateOnce sync.Once |
219 | 219 |
|
220 | 220 | // numConsecutiveOrphanHeaders tracks the number of consecutive header |
221 | 221 | // messages sent by the peer that contain headers which do not connect. It |
@@ -258,6 +258,49 @@ func NewPeer(peer *peerpkg.Peer) *Peer { |
258 | 258 | } |
259 | 259 | } |
260 | 260 |
|
| 261 | +// maybeRequestInitialState potentially requests initial state information from |
| 262 | +// the peer by sending it an appropriate initial state sync message dependending |
| 263 | +// on the protocol version. |
| 264 | +// |
| 265 | +// The request will not be sent more than once or when the peer is in the |
| 266 | +// process of being removed. |
| 267 | +// |
| 268 | +// This function is safe for concurrent access. |
| 269 | +func (peer *Peer) maybeRequestInitialState(includeMiningState bool) { |
| 270 | + // Don't request the initial state more than once or when the peer is in the |
| 271 | + // process of being removed. |
| 272 | + if !peer.Connected() { |
| 273 | + return |
| 274 | + } |
| 275 | + peer.requestInitialStateOnce.Do(func() { |
| 276 | + // Choose which initial state sync p2p messages to use based on the |
| 277 | + // protocol version. |
| 278 | + // |
| 279 | + // Protocol versions prior to the init state version use getminingstate |
| 280 | + // and miningstate while those after use getinitstate and initstate. |
| 281 | + if peer.ProtocolVersion() < wire.InitStateVersion { |
| 282 | + if includeMiningState { |
| 283 | + peer.QueueMessage(wire.NewMsgGetMiningState(), nil) |
| 284 | + } |
| 285 | + return |
| 286 | + } |
| 287 | + |
| 288 | + // Always request treasury spends for newer protocol versions. |
| 289 | + types := make([]string, 0, 3) |
| 290 | + types = append(types, wire.InitStateTSpends) |
| 291 | + if includeMiningState { |
| 292 | + types = append(types, wire.InitStateHeadBlocks) |
| 293 | + types = append(types, wire.InitStateHeadBlockVotes) |
| 294 | + } |
| 295 | + msg := wire.NewMsgGetInitState() |
| 296 | + if err := msg.AddTypes(types...); err != nil { |
| 297 | + log.Errorf("Failed to build getinitstate msg: %v", err) |
| 298 | + return |
| 299 | + } |
| 300 | + peer.QueueMessage(msg, nil) |
| 301 | + }) |
| 302 | +} |
| 303 | + |
261 | 304 | // headerSyncState houses the state used to track the header sync progress and |
262 | 305 | // related stall handling. |
263 | 306 | type headerSyncState struct { |
@@ -613,55 +656,17 @@ func (m *SyncManager) startSync() { |
613 | 656 | } |
614 | 657 | } |
615 | 658 |
|
616 | | -// maybeRequestInitialState potentially requests initial state information from |
617 | | -// the provided peer by sending it an appropriate initial state sync message |
618 | | -// dependending on the protocol version. |
619 | | -// |
620 | | -// The request will not be sent more than once or when the peer is in the |
621 | | -// process of being removed. |
622 | | -func maybeRequestInitialState(peer *Peer) { |
623 | | - // Don't request the initial state more than once or when the peer is in the |
624 | | - // process of being removed. |
625 | | - if peer.initialStateRequested || !peer.Connected() { |
626 | | - return |
627 | | - } |
628 | | - |
629 | | - // Choose which initial state sync p2p messages to use based on the protocol |
630 | | - // version. Protocol versions prior to the init state version use |
631 | | - // getminingstate and miningstate while those after use getinitstate and |
632 | | - // initstate. |
633 | | - var msg wire.Message |
634 | | - if peer.ProtocolVersion() < wire.InitStateVersion { |
635 | | - msg = wire.NewMsgGetMiningState() |
636 | | - } else { |
637 | | - m := wire.NewMsgGetInitState() |
638 | | - err := m.AddTypes(wire.InitStateHeadBlocks, |
639 | | - wire.InitStateHeadBlockVotes, |
640 | | - wire.InitStateTSpends) |
641 | | - if err != nil { |
642 | | - log.Errorf("Unexpected error building getinitstate msg: %v", err) |
643 | | - return |
644 | | - } |
645 | | - msg = m |
646 | | - } |
647 | | - peer.QueueMessage(msg, nil) |
648 | | - |
649 | | - peer.initialStateRequested = true |
650 | | -} |
651 | | - |
652 | 659 | // onInitialChainSyncDone is invoked when the initial chain sync process |
653 | 660 | // completes. |
654 | 661 | func (m *SyncManager) onInitialChainSyncDone() { |
655 | 662 | best := m.cfg.Chain.BestSnapshot() |
656 | 663 | log.Infof("Initial chain sync complete (hash %s, height %d)", |
657 | 664 | best.Hash, best.Height) |
658 | 665 |
|
659 | | - // Request initial state from all peers that are marked as needing it now |
660 | | - // that the initial chain sync is done when enabled. |
661 | | - if !m.cfg.NoMiningStateSync { |
662 | | - for peer := range m.peers { |
663 | | - maybeRequestInitialState(peer) |
664 | | - } |
| 666 | + // Request initial state from all peers that still need it now that the |
| 667 | + // initial chain sync is done. |
| 668 | + for peer := range m.peers { |
| 669 | + peer.maybeRequestInitialState(!m.cfg.NoMiningStateSync) |
665 | 670 | } |
666 | 671 | } |
667 | 672 |
|
@@ -698,11 +703,11 @@ func (m *SyncManager) handlePeerConnectedMsg(ctx context.Context, peer *Peer) { |
698 | 703 | m.startSync() |
699 | 704 | } |
700 | 705 |
|
701 | | - // Request the initial state from this peer now when enabled and the manager |
| 706 | + // Potentially request the initial state from this peer now when the manager |
702 | 707 | // believes the chain is fully synced. Otherwise, it will be requested when |
703 | 708 | // the initial chain sync process is complete. |
704 | | - if !m.cfg.NoMiningStateSync && m.IsCurrent() { |
705 | | - maybeRequestInitialState(peer) |
| 709 | + if m.IsCurrent() { |
| 710 | + peer.maybeRequestInitialState(!m.cfg.NoMiningStateSync) |
706 | 711 | } |
707 | 712 | } |
708 | 713 |
|
|
0 commit comments