Skip to content

Commit a339289

Browse files
committed
Merge #19606: Backport wtxid relay to v0.20
d4a1ee8 Further improve comments around recentRejects (Suhas Daftuar) f082a13 Disconnect peers sending wtxidrelay message after VERACK (Suhas Daftuar) 22effa5 test: Use wtxid relay generally in functional tests (Fabian Jahr) e481681 test: Add tests for wtxid tx relay in segwit test (Fabian Jahr) 6be398b test: Update test framework p2p protocol version to 70016 (Fabian Jahr) e364b2a Rename AddInventoryKnown() to AddKnownTx() (Suhas Daftuar) 879a3cf Make TX_WITNESS_STRIPPED its own rejection reason (Suhas Daftuar) c1d6a10 Delay getdata requests from peers using txid-based relay (Suhas Daftuar) 181ffad Add p2p message "wtxidrelay" (Suhas Daftuar) 9382672 ignore non-wtxidrelay compliant invs (Anthony Towns) 2599277 Add support for tx-relay via wtxid (Suhas Daftuar) be1b7a8 Add wtxids to recentRejects (Suhas Daftuar) 7384521 Add wtxids of confirmed transactions to bloom filter (Suhas Daftuar) 606755b Add wtxid-index to orphan map (Suhas Daftuar) 3654937 Add a wtxid-index to mapRelay (Suhas Daftuar) f7833b5 Just pass a hash to AddInventoryKnown (Suhas Daftuar) 4df3d13 Add a wtxid-index to the mempool (Suhas Daftuar) Pull request description: We want wtxid relay to be widely deployed before taproot activation, so it should be backported to v0.20. The main difference from #18044 is removing the changes to the unbroadcast set (which was only added post-v0.20). The rest is mostly minor rebase conflicts (eg connman changed from a pointer to a reference in master, etc). We'll also want to backport #19569 after that's merged. ACKs for top commit: fjahr: re-ACK d4a1ee8 instagibbs: reACK d4a1ee8 laanwj: re-ACK d4a1ee8 hebasto: re-ACK d4a1ee8, only rebased since my [previous](#19606 (review)) review: Tree-SHA512: 1bb8725dd2313a9a03cacf8fb7317986eed3d8d1648fa627528441256c37c793bb0fae6c8c139d05ac45d0c7a86265792834e8e09cbf45286426ca6544c10cd5
2 parents b9ac31f + d4a1ee8 commit a339289

19 files changed

+444
-101
lines changed

src/consensus/validation.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@ enum class TxValidationResult {
3131
TX_MISSING_INPUTS, //!< transaction was missing some of its inputs
3232
TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
3333
/**
34-
* Transaction might be missing a witness, have a witness prior to SegWit
34+
* Transaction might have a witness prior to SegWit
3535
* activation, or witness may have been malleated (which includes
3636
* non-standard witnesses).
3737
*/
3838
TX_WITNESS_MUTATED,
39+
/**
40+
* Transaction is missing a witness.
41+
*/
42+
TX_WITNESS_STRIPPED,
3943
/**
4044
* Tx already in mempool or conflicts with a tx in the chain
4145
* (if it conflicts with another tx in mempool, we use MEMPOOL_POLICY as it failed to reach the RBF threshold)

src/net.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -969,11 +969,11 @@ class CNode
969969
}
970970

971971

972-
void AddInventoryKnown(const CInv& inv)
972+
void AddKnownTx(const uint256& hash)
973973
{
974974
if (m_tx_relay != nullptr) {
975975
LOCK(m_tx_relay->cs_tx_inventory);
976-
m_tx_relay->filterInventoryKnown.insert(inv.hash);
976+
m_tx_relay->filterInventoryKnown.insert(hash);
977977
}
978978
}
979979

src/net_processing.cpp

Lines changed: 225 additions & 57 deletions
Large diffs are not rendered by default.

src/net_processing.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,6 @@ struct CNodeStateStats {
9292
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
9393

9494
/** Relay transaction to every node */
95-
void RelayTransaction(const uint256&, const CConnman& connman);
95+
void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
9696

9797
#endif // BITCOIN_NET_PROCESSING_H

src/node/transaction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
7878
}
7979

8080
if (relay) {
81-
RelayTransaction(hashTx, *node.connman);
81+
LOCK(cs_main);
82+
RelayTransaction(hashTx, tx->GetWitnessHash(), *node.connman);
8283
}
8384

8485
return TransactionError::OK;

src/protocol.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const char *SENDCMPCT="sendcmpct";
4040
const char *CMPCTBLOCK="cmpctblock";
4141
const char *GETBLOCKTXN="getblocktxn";
4242
const char *BLOCKTXN="blocktxn";
43+
const char *WTXIDRELAY="wtxidrelay";
4344
} // namespace NetMsgType
4445

4546
/** All known message types. Keep this in the same order as the list of
@@ -71,6 +72,7 @@ const static std::string allNetMessageTypes[] = {
7172
NetMsgType::CMPCTBLOCK,
7273
NetMsgType::GETBLOCKTXN,
7374
NetMsgType::BLOCKTXN,
75+
NetMsgType::WTXIDRELAY,
7476
};
7577
const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));
7678

@@ -183,6 +185,8 @@ std::string CInv::GetCommand() const
183185
switch (masked)
184186
{
185187
case MSG_TX: return cmd.append(NetMsgType::TX);
188+
// WTX is not a message type, just an inv type
189+
case MSG_WTX: return cmd.append("wtx");
186190
case MSG_BLOCK: return cmd.append(NetMsgType::BLOCK);
187191
case MSG_FILTERED_BLOCK: return cmd.append(NetMsgType::MERKLEBLOCK);
188192
case MSG_CMPCT_BLOCK: return cmd.append(NetMsgType::CMPCTBLOCK);

src/protocol.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,12 @@ extern const char *GETBLOCKTXN;
234234
* @since protocol version 70014 as described by BIP 152
235235
*/
236236
extern const char *BLOCKTXN;
237+
/**
238+
* Indicates that a node prefers to relay transactions via wtxid, rather than
239+
* txid.
240+
* @since protocol version 70016 as described by BIP 339.
241+
*/
242+
extern const char *WTXIDRELAY;
237243
};
238244

239245
/* Get a vector of all valid message types (see above) */
@@ -362,12 +368,12 @@ const uint32_t MSG_TYPE_MASK = 0xffffffff >> 2;
362368
* These numbers are defined by the protocol. When adding a new value, be sure
363369
* to mention it in the respective BIP.
364370
*/
365-
enum GetDataMsg
366-
{
371+
enum GetDataMsg : uint32_t {
367372
UNDEFINED = 0,
368373
MSG_TX = 1,
369374
MSG_BLOCK = 2,
370-
// The following can only occur in getdata. Invs always use TX or BLOCK.
375+
MSG_WTX = 5, //!< Defined in BIP 339
376+
// The following can only occur in getdata. Invs always use TX/WTX or BLOCK.
371377
MSG_FILTERED_BLOCK = 3, //!< Defined in BIP37
372378
MSG_CMPCT_BLOCK = 4, //!< Defined in BIP152
373379
MSG_WITNESS_BLOCK = MSG_BLOCK | MSG_WITNESS_FLAG, //!< Defined in BIP144

src/txmempool.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -724,12 +724,12 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
724724
assert(innerUsage == cachedInnerUsage);
725725
}
726726

727-
bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb)
727+
bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb, bool wtxid)
728728
{
729729
LOCK(cs);
730-
indexed_transaction_set::const_iterator i = mapTx.find(hasha);
730+
indexed_transaction_set::const_iterator i = wtxid ? get_iter_from_wtxid(hasha) : mapTx.find(hasha);
731731
if (i == mapTx.end()) return false;
732-
indexed_transaction_set::const_iterator j = mapTx.find(hashb);
732+
indexed_transaction_set::const_iterator j = wtxid ? get_iter_from_wtxid(hashb) : mapTx.find(hashb);
733733
if (j == mapTx.end()) return true;
734734
uint64_t counta = i->GetCountWithAncestors();
735735
uint64_t countb = j->GetCountWithAncestors();
@@ -809,10 +809,10 @@ CTransactionRef CTxMemPool::get(const uint256& hash) const
809809
return i->GetSharedTx();
810810
}
811811

812-
TxMempoolInfo CTxMemPool::info(const uint256& hash) const
812+
TxMempoolInfo CTxMemPool::info(const uint256& hash, bool wtxid) const
813813
{
814814
LOCK(cs);
815-
indexed_transaction_set::const_iterator i = mapTx.find(hash);
815+
indexed_transaction_set::const_iterator i = (wtxid ? get_iter_from_wtxid(hash) : mapTx.find(hash));
816816
if (i == mapTx.end())
817817
return TxMempoolInfo();
818818
return GetInfo(i);
@@ -915,8 +915,8 @@ bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {
915915

916916
size_t CTxMemPool::DynamicMemoryUsage() const {
917917
LOCK(cs);
918-
// Estimate the overhead of mapTx to be 12 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented.
919-
return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 12 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage;
918+
// Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented.
919+
return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage;
920920
}
921921

922922
void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) {

src/txmempool.h

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,22 @@ struct mempoolentry_txid
198198
}
199199
};
200200

201+
// extracts a transaction witness-hash from CTxMemPoolEntry or CTransactionRef
202+
struct mempoolentry_wtxid
203+
{
204+
typedef uint256 result_type;
205+
result_type operator() (const CTxMemPoolEntry &entry) const
206+
{
207+
return entry.GetTx().GetWitnessHash();
208+
}
209+
210+
result_type operator() (const CTransactionRef& tx) const
211+
{
212+
return tx->GetWitnessHash();
213+
}
214+
};
215+
216+
201217
/** \class CompareTxMemPoolEntryByDescendantScore
202218
*
203219
* Sort an entry by max(score/size of entry's tx, score/size with all descendants).
@@ -318,6 +334,7 @@ class CompareTxMemPoolEntryByAncestorFee
318334
struct descendant_score {};
319335
struct entry_time {};
320336
struct ancestor_score {};
337+
struct index_by_wtxid {};
321338

322339
class CBlockPolicyEstimator;
323340

@@ -383,8 +400,9 @@ class SaltedTxidHasher
383400
*
384401
* CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping:
385402
*
386-
* mapTx is a boost::multi_index that sorts the mempool on 4 criteria:
387-
* - transaction hash
403+
* mapTx is a boost::multi_index that sorts the mempool on 5 criteria:
404+
* - transaction hash (txid)
405+
* - witness-transaction hash (wtxid)
388406
* - descendant feerate [we use max(feerate of tx, feerate of tx with all descendants)]
389407
* - time in mempool
390408
* - ancestor feerate [we use min(feerate of tx, feerate of tx with all unconfirmed ancestors)]
@@ -469,6 +487,12 @@ class CTxMemPool
469487
boost::multi_index::indexed_by<
470488
// sorted by txid
471489
boost::multi_index::hashed_unique<mempoolentry_txid, SaltedTxidHasher>,
490+
// sorted by wtxid
491+
boost::multi_index::hashed_unique<
492+
boost::multi_index::tag<index_by_wtxid>,
493+
mempoolentry_wtxid,
494+
SaltedTxidHasher
495+
>,
472496
// sorted by fee rate
473497
boost::multi_index::ordered_non_unique<
474498
boost::multi_index::tag<descendant_score>,
@@ -583,7 +607,7 @@ class CTxMemPool
583607

584608
void clear();
585609
void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); //lock free
586-
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
610+
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb, bool wtxid=false);
587611
void queryHashes(std::vector<uint256>& vtxid) const;
588612
bool isSpent(const COutPoint& outpoint) const;
589613
unsigned int GetTransactionsUpdated() const;
@@ -686,14 +710,22 @@ class CTxMemPool
686710
return totalTxSize;
687711
}
688712

689-
bool exists(const uint256& hash) const
713+
bool exists(const uint256& hash, bool wtxid=false) const
690714
{
691715
LOCK(cs);
716+
if (wtxid) {
717+
return (mapTx.get<index_by_wtxid>().count(hash) != 0);
718+
}
692719
return (mapTx.count(hash) != 0);
693720
}
694721

695722
CTransactionRef get(const uint256& hash) const;
696-
TxMempoolInfo info(const uint256& hash) const;
723+
txiter get_iter_from_wtxid(const uint256& wtxid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
724+
{
725+
AssertLockHeld(cs);
726+
return mapTx.project<0>(mapTx.get<index_by_wtxid>().find(wtxid));
727+
}
728+
TxMempoolInfo info(const uint256& hash, bool wtxid=false) const;
697729
std::vector<TxMempoolInfo> infoAll() const;
698730

699731
size_t DynamicMemoryUsage() const;

src/validation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,7 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
916916
if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
917917
!CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
918918
// Only the witness is missing, so the transaction itself may be fine.
919-
state.Invalid(TxValidationResult::TX_WITNESS_MUTATED,
919+
state.Invalid(TxValidationResult::TX_WITNESS_STRIPPED,
920920
state.GetRejectReason(), state.GetDebugMessage());
921921
}
922922
return false; // state filled in by CheckInputScripts

src/version.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* network protocol versioning
1010
*/
1111

12-
static const int PROTOCOL_VERSION = 70015;
12+
static const int PROTOCOL_VERSION = 70016;
1313

1414
//! initial proto version, to be increased after version/verack negotiation
1515
static const int INIT_PROTO_VERSION = 209;
@@ -42,4 +42,7 @@ static const int SHORT_IDS_BLOCKS_VERSION = 70014;
4242
//! not banning for invalid compact blocks starts with this version
4343
static const int INVALID_CB_NO_BAN_VERSION = 70015;
4444

45+
//! "wtxidrelay" command for wtxid-based relay starts with this version
46+
static const int WTXID_RELAY_VERSION = 70016;
47+
4548
#endif // BITCOIN_VERSION_H

test/functional/mempool_packages.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,15 @@ def run_test(self):
6767
fee = Decimal("0.0001")
6868
# MAX_ANCESTORS transactions off a confirmed tx should be fine
6969
chain = []
70+
witness_chain = []
7071
for i in range(MAX_ANCESTORS):
7172
(txid, sent_value) = self.chain_transaction(self.nodes[0], txid, 0, value, fee, 1)
7273
value = sent_value
7374
chain.append(txid)
75+
# We need the wtxids to check P2P announcements
76+
fulltx = self.nodes[0].getrawtransaction(txid)
77+
witnesstx = self.nodes[0].decoderawtransaction(fulltx, True)
78+
witness_chain.append(witnesstx['hash'])
7479

7580
# Check mempool has MAX_ANCESTORS transactions in it, and descendant and ancestor
7681
# count and fees should look correct

test/functional/p2p_blocksonly.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def run_test(self):
5252
self.log.info('Check that txs from rpc are not rejected and relayed to other peers')
5353
assert_equal(self.nodes[0].getpeerinfo()[0]['relaytxes'], True)
5454
txid = self.nodes[0].testmempoolaccept([sigtx])[0]['txid']
55-
with self.nodes[0].assert_debug_log(['received getdata for: tx {} peer=1'.format(txid)]):
55+
with self.nodes[0].assert_debug_log(['received getdata for: wtx {} peer=1'.format(txid)]):
5656
self.nodes[0].sendrawtransaction(sigtx)
5757
self.nodes[0].p2p.wait_for_tx(txid)
5858
assert_equal(self.nodes[0].getmempoolinfo()['size'], 1)

test/functional/p2p_feefilter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from decimal import Decimal
88
import time
99

10-
from test_framework.messages import msg_feefilter
10+
from test_framework.messages import MSG_TX, MSG_WTX, msg_feefilter
1111
from test_framework.mininode import mininode_lock, P2PInterface
1212
from test_framework.test_framework import BitcoinTestFramework
1313

@@ -31,7 +31,7 @@ def __init__(self):
3131

3232
def on_inv(self, message):
3333
for i in message.inv:
34-
if (i.type == 1):
34+
if (i.type == MSG_TX) or (i.type == MSG_WTX):
3535
self.txinvs.append(hashToHex(i.hash))
3636

3737
def clear_invs(self):

0 commit comments

Comments
 (0)