Skip to content

Commit 505b39e

Browse files
committed
Merge #19610: p2p: refactor AlreadyHave(), CInv::type, INV/TX processing
fb56d37 p2p: ensure inv is GenMsgTx before ToGenTxid in inv processing (John Newbery) aa36213 test: use CInv::MSG_WITNESS_TX flag in p2p_segwit (Jon Atack) 24ee4f0 p2p: make gtxid(.hash) and fAlreadyHave localvars const (Jon Atack) b1c8554 p2p: use CInv block message helpers in net_processing.cpp (Jon Atack) acd6642 [net processing] Change AlreadyHaveTx() to take a GenTxid (John Newbery) 5fdfb80 [net processing] Change AlreadyHaveBlock() to take block_hash argument (John Newbery) 430e183 [net processing] Remove mempool argument from AlreadyHaveBlock() (John Newbery) 42ca561 [net processing] Split AlreadyHave() into separate block and tx functions (John Newbery) 39f1dc9 p2p: remove nFetchFlags from NetMsgType TX and INV processing (Jon Atack) 471714e p2p: add CInv block message helper methods (Jon Atack) Pull request description: Building on #19590 and the recent `wtxid` and `GenTxid` changes, this is a refactoring and cleanup PR to simplify and improve some of the net processing code. Some of the diffs are best reviewed with `-w` to ignore spacing. Co-authored by John Newbery. ACKs for top commit: laanwj: Code review ACK fb56d37 jnewbery: utACK fb56d37 vasild: ACK fb56d37 Tree-SHA512: ba39b58e6aaf850880a842fe5f6295e9f1870906ef690206acfc17140aae2ac854981e1066dbcd4238062478762fbd040ef772fdc2c50eea6869997c583e6a6d
2 parents 3a3e21d + fb56d37 commit 505b39e

File tree

4 files changed

+71
-71
lines changed

4 files changed

+71
-71
lines changed

src/net_processing.cpp

Lines changed: 53 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,47 +1465,40 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const BlockValidatio
14651465
//
14661466

14671467

1468-
bool static AlreadyHave(const CInv& inv, const CTxMemPool& mempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
1468+
bool static AlreadyHaveTx(const GenTxid& gtxid, const CTxMemPool& mempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
14691469
{
1470-
switch (inv.type)
1471-
{
1472-
case MSG_TX:
1473-
case MSG_WITNESS_TX:
1474-
case MSG_WTX:
1475-
{
1476-
assert(recentRejects);
1477-
if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip)
1478-
{
1479-
// If the chain tip has changed previously rejected transactions
1480-
// might be now valid, e.g. due to a nLockTime'd tx becoming valid,
1481-
// or a double-spend. Reset the rejects filter and give those
1482-
// txs a second chance.
1483-
hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash();
1484-
recentRejects->reset();
1485-
}
1486-
1487-
{
1488-
LOCK(g_cs_orphans);
1489-
if (!inv.IsMsgWtx() && mapOrphanTransactions.count(inv.hash)) {
1490-
return true;
1491-
} else if (inv.IsMsgWtx() && g_orphans_by_wtxid.count(inv.hash)) {
1492-
return true;
1493-
}
1494-
}
1470+
assert(recentRejects);
1471+
if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip) {
1472+
// If the chain tip has changed previously rejected transactions
1473+
// might be now valid, e.g. due to a nLockTime'd tx becoming valid,
1474+
// or a double-spend. Reset the rejects filter and give those
1475+
// txs a second chance.
1476+
hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash();
1477+
recentRejects->reset();
1478+
}
14951479

1496-
{
1497-
LOCK(g_cs_recent_confirmed_transactions);
1498-
if (g_recent_confirmed_transactions->contains(inv.hash)) return true;
1499-
}
1480+
const uint256& hash = gtxid.GetHash();
15001481

1501-
return recentRejects->contains(inv.hash) || mempool.exists(ToGenTxid(inv));
1482+
{
1483+
LOCK(g_cs_orphans);
1484+
if (!gtxid.IsWtxid() && mapOrphanTransactions.count(hash)) {
1485+
return true;
1486+
} else if (gtxid.IsWtxid() && g_orphans_by_wtxid.count(hash)) {
1487+
return true;
15021488
}
1503-
case MSG_BLOCK:
1504-
case MSG_WITNESS_BLOCK:
1505-
return LookupBlockIndex(inv.hash) != nullptr;
15061489
}
1507-
// Don't know what it is, just say we already got one
1508-
return true;
1490+
1491+
{
1492+
LOCK(g_cs_recent_confirmed_transactions);
1493+
if (g_recent_confirmed_transactions->contains(hash)) return true;
1494+
}
1495+
1496+
return recentRejects->contains(hash) || mempool.exists(gtxid);
1497+
}
1498+
1499+
bool static AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
1500+
{
1501+
return LookupBlockIndex(block_hash) != nullptr;
15091502
}
15101503

15111504
void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman)
@@ -1608,7 +1601,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
16081601
// disconnect node in case we have reached the outbound limit for serving historical blocks
16091602
if (send &&
16101603
connman.OutboundTargetReached(true) &&
1611-
(((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.type == MSG_FILTERED_BLOCK) &&
1604+
(((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
16121605
!pfrom.HasPermission(PF_DOWNLOAD) // nodes with the download permission may exceed target
16131606
) {
16141607
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId());
@@ -1634,7 +1627,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
16341627
std::shared_ptr<const CBlock> pblock;
16351628
if (a_recent_block && a_recent_block->GetHash() == pindex->GetBlockHash()) {
16361629
pblock = a_recent_block;
1637-
} else if (inv.type == MSG_WITNESS_BLOCK) {
1630+
} else if (inv.IsMsgWitnessBlk()) {
16381631
// Fast-path: in this case it is possible to serve the block directly from disk,
16391632
// as the network format matches the format on disk
16401633
std::vector<uint8_t> block_data;
@@ -1651,12 +1644,11 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
16511644
pblock = pblockRead;
16521645
}
16531646
if (pblock) {
1654-
if (inv.type == MSG_BLOCK)
1647+
if (inv.IsMsgBlk()) {
16551648
connman.PushMessage(&pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock));
1656-
else if (inv.type == MSG_WITNESS_BLOCK)
1649+
} else if (inv.IsMsgWitnessBlk()) {
16571650
connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
1658-
else if (inv.type == MSG_FILTERED_BLOCK)
1659-
{
1651+
} else if (inv.IsMsgFilteredBlk()) {
16601652
bool sendMerkleBlock = false;
16611653
CMerkleBlock merkleBlock;
16621654
if (pfrom.m_tx_relay != nullptr) {
@@ -1680,9 +1672,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
16801672
}
16811673
// else
16821674
// no response
1683-
}
1684-
else if (inv.type == MSG_CMPCT_BLOCK)
1685-
{
1675+
} else if (inv.IsMsgCmpctBlk()) {
16861676
// If a peer is asking for old blocks, we're almost guaranteed
16871677
// they won't have a useful mempool to match against a compact block,
16881678
// and we don't feel like constructing the object for them, so
@@ -1810,7 +1800,7 @@ void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnm
18101800
// expensive to process.
18111801
if (it != pfrom.vRecvGetData.end() && !pfrom.fPauseSend) {
18121802
const CInv &inv = *it++;
1813-
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK) {
1803+
if (inv.IsGenBlkMsg()) {
18141804
ProcessGetBlockData(pfrom, chainparams, inv, connman);
18151805
}
18161806
// else: If the first item on the queue is an unknown type, we erase it
@@ -2692,14 +2682,11 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
26922682

26932683
LOCK(cs_main);
26942684

2695-
uint32_t nFetchFlags = GetFetchFlags(pfrom);
26962685
const auto current_time = GetTime<std::chrono::microseconds>();
26972686
uint256* best_block{nullptr};
26982687

2699-
for (CInv &inv : vInv)
2700-
{
2701-
if (interruptMsgProc)
2702-
return;
2688+
for (CInv& inv : vInv) {
2689+
if (interruptMsgProc) return;
27032690

27042691
// Ignore INVs that don't match wtxidrelay setting.
27052692
// Note that orphan parent fetching always uses MSG_TX GETDATAs regardless of the wtxidrelay setting.
@@ -2710,14 +2697,10 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
27102697
if (inv.IsMsgWtx()) continue;
27112698
}
27122699

2713-
bool fAlreadyHave = AlreadyHave(inv, m_mempool);
2714-
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
2700+
if (inv.IsMsgBlk()) {
2701+
const bool fAlreadyHave = AlreadyHaveBlock(inv.hash);
2702+
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
27152703

2716-
if (inv.IsMsgTx()) {
2717-
inv.type |= nFetchFlags;
2718-
}
2719-
2720-
if (inv.type == MSG_BLOCK) {
27212704
UpdateBlockAvailability(pfrom.GetId(), inv.hash);
27222705
if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
27232706
// Headers-first is the primary method of announcement on
@@ -2727,15 +2710,21 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
27272710
// then fetch the blocks we need to catch up.
27282711
best_block = &inv.hash;
27292712
}
2730-
} else {
2713+
} else if (inv.IsGenTxMsg()) {
2714+
const GenTxid gtxid = ToGenTxid(inv);
2715+
const bool fAlreadyHave = AlreadyHaveTx(gtxid, mempool);
2716+
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
2717+
27312718
pfrom.AddKnownTx(inv.hash);
27322719
if (fBlocksOnly) {
27332720
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom.GetId());
27342721
pfrom.fDisconnect = true;
27352722
return;
27362723
} else if (!fAlreadyHave && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
2737-
RequestTx(State(pfrom.GetId()), ToGenTxid(inv), current_time);
2724+
RequestTx(State(pfrom.GetId()), gtxid, current_time);
27382725
}
2726+
} else {
2727+
LogPrint(BCLog::NET, "Unknown inv type \"%s\" received from peer=%d\n", inv.ToString(), pfrom.GetId());
27392728
}
27402729
}
27412730

@@ -3006,7 +2995,7 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
30062995
// already; and an adversary can already relay us old transactions
30072996
// (older than our recency filter) if trying to DoS us, without any need
30082997
// for witness malleation.
3009-
if (!AlreadyHave(CInv(MSG_WTX, wtxid), m_mempool) &&
2998+
if (!AlreadyHaveTx(GenTxid(/* is_wtxid=*/true, wtxid), m_mempool) &&
30102999
AcceptToMemoryPool(m_mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
30113000
m_mempool.check(&::ChainstateActive().CoinsTip());
30123001
RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman);
@@ -3050,7 +3039,6 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
30503039
}
30513040
}
30523041
if (!fRejectedParents) {
3053-
uint32_t nFetchFlags = GetFetchFlags(pfrom);
30543042
const auto current_time = GetTime<std::chrono::microseconds>();
30553043

30563044
for (const uint256& parent_txid : unique_parents) {
@@ -3059,9 +3047,9 @@ void PeerLogicValidation::ProcessMessage(CNode& pfrom, const std::string& msg_ty
30593047
// wtxidrelay peers.
30603048
// Eventually we should replace this with an improved
30613049
// protocol for getting all unconfirmed parents.
3062-
CInv _inv(MSG_TX | nFetchFlags, parent_txid);
3050+
const GenTxid gtxid{/* is_wtxid=*/false, parent_txid};
30633051
pfrom.AddKnownTx(parent_txid);
3064-
if (!AlreadyHave(_inv, m_mempool)) RequestTx(State(pfrom.GetId()), ToGenTxid(_inv), current_time);
3052+
if (!AlreadyHaveTx(gtxid, m_mempool)) RequestTx(State(pfrom.GetId()), gtxid, current_time);
30653053
}
30663054
AddOrphanTx(ptx, pfrom.GetId());
30673055

@@ -4611,7 +4599,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
46114599
// processing at a later time, see below)
46124600
tx_process_time.erase(tx_process_time.begin());
46134601
CInv inv(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*pto)), gtxid.GetHash());
4614-
if (!AlreadyHave(inv, m_mempool)) {
4602+
if (!AlreadyHaveTx(ToGenTxid(inv), m_mempool)) {
46154603
// If this transaction was last requested more than 1 minute ago,
46164604
// then request.
46174605
const auto last_request_time = GetTxRequestTime(gtxid);

src/protocol.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ extern const char* CFCHECKPT;
247247
* txid.
248248
* @since protocol version 70016 as described by BIP 339.
249249
*/
250-
extern const char *WTXIDRELAY;
250+
extern const char* WTXIDRELAY;
251251
}; // namespace NetMsgType
252252

253253
/* Get a vector of all valid message types (see above) */
@@ -418,12 +418,22 @@ class CInv
418418
std::string ToString() const;
419419

420420
// Single-message helper methods
421-
bool IsMsgTx() const { return type == MSG_TX; }
422-
bool IsMsgWtx() const { return type == MSG_WTX; }
423-
bool IsMsgWitnessTx() const { return type == MSG_WITNESS_TX; }
421+
bool IsMsgTx() const { return type == MSG_TX; }
422+
bool IsMsgBlk() const { return type == MSG_BLOCK; }
423+
bool IsMsgWtx() const { return type == MSG_WTX; }
424+
bool IsMsgFilteredBlk() const { return type == MSG_FILTERED_BLOCK; }
425+
bool IsMsgCmpctBlk() const { return type == MSG_CMPCT_BLOCK; }
426+
bool IsMsgWitnessBlk() const { return type == MSG_WITNESS_BLOCK; }
424427

425428
// Combined-message helper methods
426-
bool IsGenTxMsg() const { return type == MSG_TX || type == MSG_WTX || type == MSG_WITNESS_TX; }
429+
bool IsGenTxMsg() const
430+
{
431+
return type == MSG_TX || type == MSG_WTX || type == MSG_WITNESS_TX;
432+
}
433+
bool IsGenBlkMsg() const
434+
{
435+
return type == MSG_BLOCK || type == MSG_FILTERED_BLOCK || type == MSG_CMPCT_BLOCK || type == MSG_WITNESS_BLOCK;
436+
}
427437

428438
int type;
429439
uint256 hash;

test/functional/p2p_segwit.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
MSG_BLOCK,
2626
MSG_TX,
2727
MSG_WITNESS_FLAG,
28+
MSG_WITNESS_TX,
2829
MSG_WTX,
2930
NODE_NETWORK,
3031
NODE_WITNESS,
@@ -2157,7 +2158,7 @@ def received_wtxidrelay():
21572158
self.wtx_node.wait_for_getdata([tx.sha256], 60)
21582159
with p2p_lock:
21592160
lgd = self.wtx_node.lastgetdata[:]
2160-
assert_equal(lgd, [CInv(MSG_TX|MSG_WITNESS_FLAG, tx.sha256)])
2161+
assert_equal(lgd, [CInv(MSG_WITNESS_TX, tx.sha256)])
21612162

21622163
# Send tx through
21632164
test_transaction_acceptance(self.nodes[0], self.wtx_node, tx, with_witness=False, accepted=True)

test/functional/test_framework/messages.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
MSG_WTX = 5
6464
MSG_WITNESS_FLAG = 1 << 30
6565
MSG_TYPE_MASK = 0xffffffff >> 2
66+
MSG_WITNESS_TX = MSG_TX | MSG_WITNESS_FLAG
6667

6768
FILTER_TYPE_BASIC = 0
6869

0 commit comments

Comments
 (0)