Skip to content

Commit 67dfcd2

Browse files
committed
netsync: Rework external request from peer.
This reworks the logic that allows code external to the sync manager to request blocks, votes, and treasury spend transactions to both simplify and optimize it. The method now makes use of the same logic the sync manager itself uses when requesting data and no longer potentially returns an error. Of particular note is that it now uses the same much more efficient code path that the sync manager itself uses to determine if a transaction is needed as opposed to the rather expensive legacy utxo-based query approach. Finally, this also modifies the logic to potentially make more than one request if needed since it is technically more accurate and avoids any possibility of error even though the current request sizes are nowhere near the limits.
1 parent 1232311 commit 67dfcd2

2 files changed

Lines changed: 34 additions & 95 deletions

File tree

internal/netsync/manager.go

Lines changed: 31 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ package netsync
88
import (
99
"context"
1010
"errors"
11-
"fmt"
1211
"math"
1312
"sync"
1413
"sync/atomic"
1514
"time"
1615

17-
"github.com/decred/dcrd/blockchain/stake/v5"
1816
"github.com/decred/dcrd/chaincfg/chainhash"
1917
"github.com/decred/dcrd/chaincfg/v3"
2018
"github.com/decred/dcrd/container/apbf"
@@ -2062,116 +2060,63 @@ func (m *SyncManager) SyncPeerID() int32 {
20622060
// the peer is not banned for sending unrequested data when it responds.
20632061
//
20642062
// This function is safe for concurrent access.
2065-
func (m *SyncManager) RequestFromPeer(peer *Peer, blocks, voteHashes,
2066-
tSpendHashes []chainhash.Hash) error {
2067-
2063+
func (m *SyncManager) RequestFromPeer(peer *Peer, blocks, voteHashes, tSpendHashes []chainhash.Hash) {
20682064
if m.shutdownRequested() {
2069-
return nil
2065+
return
20702066
}
20712067

20722068
defer m.requestMtx.Unlock()
20732069
m.requestMtx.Lock()
20742070

2075-
// Add the blocks to the request.
2071+
// Request as many needed blocks as possible at once.
2072+
var numRequested uint32
20762073
gdMsg := wire.NewMsgGetData()
20772074
for i := range blocks {
2078-
// Skip the block when it has already been requested.
2079-
bh := &blocks[i]
2080-
if m.isRequestedBlock(bh) {
2081-
continue
2082-
}
2083-
2084-
// Skip the block when it is already known.
2085-
if m.cfg.Chain.HaveBlock(bh) {
2075+
// Skip the block when it has already been requested or is already
2076+
// known.
2077+
blockHash := &blocks[i]
2078+
if m.isRequestedBlock(blockHash) || m.cfg.Chain.HaveBlock(blockHash) {
20862079
continue
20872080
}
20882081

2089-
err := gdMsg.AddInvVect(wire.NewInvVect(wire.InvTypeBlock, bh))
2090-
if err != nil {
2091-
return fmt.Errorf("unexpected error encountered building request "+
2092-
"for block %v: %w", bh, err)
2082+
gdMsg.AddInvVect(wire.NewInvVect(wire.InvTypeBlock, blockHash))
2083+
m.requestedBlocks[*blockHash] = peer
2084+
numRequested++
2085+
if numRequested == wire.MaxInvPerMsg {
2086+
// Send full getdata message and reset.
2087+
peer.QueueMessage(gdMsg, nil)
2088+
gdMsg = wire.NewMsgGetData()
2089+
numRequested = 0
20932090
}
2094-
2095-
m.requestedBlocks[*bh] = peer
20962091
}
20972092

2098-
addTxsToRequest := func(hashes []chainhash.Hash, txType stake.TxType) error {
2099-
// Return immediately if txs is nil.
2100-
if hashes == nil {
2101-
return nil
2102-
}
2103-
2093+
// Request as many needed votes and treasury spend transactions as possible
2094+
// at once.
2095+
for _, hashes := range [][]chainhash.Hash{voteHashes, tSpendHashes} {
21042096
for i := range hashes {
2105-
// Skip the transaction when it has already been requested.
2097+
// Skip the transaction when it has already been requested or is
2098+
// otherwise not needed.
21062099
txHash := &hashes[i]
2107-
if _, ok := m.requestedTxns[*txHash]; ok {
2108-
continue
2109-
}
2110-
2111-
// Ask the transaction memory pool if the transaction is known
2112-
// to it in any form (main pool or orphan).
2113-
if m.cfg.TxMemPool.HaveTransaction(txHash) {
2114-
continue
2115-
}
2116-
2117-
// Check if the transaction exists from the point of view of the main
2118-
// chain tip. Note that this is only a best effort since it is expensive
2119-
// to check existence of every output and the only purpose of this check
2120-
// is to avoid requesting already known transactions.
2121-
//
2122-
// Check for a specific outpoint based on the tx type.
2123-
outpoint := wire.OutPoint{Hash: *txHash}
2124-
switch txType {
2125-
case stake.TxTypeSSGen:
2126-
// The first two outputs of vote transactions are OP_RETURN <data>, and
2127-
// therefore never exist as an unspent txo. Use the third output, as
2128-
// the third output (and subsequent outputs) are OP_SSGEN outputs.
2129-
outpoint.Index = 2
2130-
outpoint.Tree = wire.TxTreeStake
2131-
case stake.TxTypeTSpend:
2132-
// The first output of a tSpend transaction is OP_RETURN <data>, and
2133-
// therefore never exists as an unspent txo. Use the second output, as
2134-
// the second output (and subsequent outputs) are OP_TGEN outputs.
2135-
outpoint.Index = 1
2136-
outpoint.Tree = wire.TxTreeStake
2137-
}
2138-
entry, err := m.cfg.Chain.FetchUtxoEntry(outpoint)
2139-
if err != nil {
2140-
return err
2141-
}
2142-
if entry != nil {
2100+
_, alreadyRequested := m.requestedTxns[*txHash]
2101+
if alreadyRequested || !m.needTx(txHash) {
21432102
continue
21442103
}
21452104

2146-
err = gdMsg.AddInvVect(wire.NewInvVect(wire.InvTypeTx, txHash))
2147-
if err != nil {
2148-
return fmt.Errorf("unexpected error encountered building request "+
2149-
"for tx %v: %w", txHash, err)
2150-
}
2151-
2105+
gdMsg.AddInvVect(wire.NewInvVect(wire.InvTypeTx, txHash))
21522106
m.requestedTxns[*txHash] = peer
2107+
numRequested++
2108+
if numRequested == wire.MaxInvPerMsg {
2109+
// Send full getdata message and reset.
2110+
peer.QueueMessage(gdMsg, nil)
2111+
gdMsg = wire.NewMsgGetData()
2112+
numRequested = 0
2113+
}
21532114
}
2154-
2155-
return nil
2156-
}
2157-
2158-
// Add the vote transactions to the request.
2159-
err := addTxsToRequest(voteHashes, stake.TxTypeSSGen)
2160-
if err != nil {
2161-
return err
2162-
}
2163-
2164-
// Add the tspend transactions to the request.
2165-
err = addTxsToRequest(tSpendHashes, stake.TxTypeTSpend)
2166-
if err != nil {
2167-
return err
21682115
}
21692116

21702117
if len(gdMsg.InvList) > 0 {
21712118
peer.QueueMessage(gdMsg, nil)
21722119
}
2173-
2174-
return nil
21752120
}
21762121

21772122
// RequestMixMsgFromPeer requests the specified mix message from the given peer.

server.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,11 +1343,8 @@ func (sp *serverPeer) OnMiningState(_ *peer.Peer, msg *wire.MsgMiningState) {
13431343
}
13441344
}
13451345

1346-
err := sp.server.syncManager.RequestFromPeer(sp.syncMgrPeer, blockHashes,
1346+
sp.server.syncManager.RequestFromPeer(sp.syncMgrPeer, blockHashes,
13471347
voteHashes, nil)
1348-
if err != nil {
1349-
peerLog.Warnf("couldn't handle mining state message: %v", err)
1350-
}
13511348
}
13521349

13531350
// OnGetInitState is invoked when a peer receives a getinitstate wire message.
@@ -1429,11 +1426,8 @@ func (sp *serverPeer) OnGetInitState(_ *peer.Peer, msg *wire.MsgGetInitState) {
14291426
// OnInitState is invoked when a peer receives a initstate wire message. It
14301427
// requests the data advertised in the message from the peer.
14311428
func (sp *serverPeer) OnInitState(_ *peer.Peer, msg *wire.MsgInitState) {
1432-
err := sp.server.syncManager.RequestFromPeer(sp.syncMgrPeer,
1433-
msg.BlockHashes, msg.VoteHashes, msg.TSpendHashes)
1434-
if err != nil {
1435-
peerLog.Warnf("couldn't handle init state message: %v", err)
1436-
}
1429+
sp.server.syncManager.RequestFromPeer(sp.syncMgrPeer, msg.BlockHashes,
1430+
msg.VoteHashes, msg.TSpendHashes)
14371431
}
14381432

14391433
// OnTx is invoked when a peer receives a tx wire message. It blocks until the

0 commit comments

Comments
 (0)