Skip to content

Commit

Permalink
Merge #19606: Backport wtxid relay to v0.20
Browse files Browse the repository at this point in the history
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
  • Loading branch information
laanwj committed Nov 5, 2020
2 parents b9ac31f + d4a1ee8 commit a339289
Show file tree
Hide file tree
Showing 19 changed files with 444 additions and 101 deletions.
6 changes: 5 additions & 1 deletion src/consensus/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,15 @@ enum class TxValidationResult {
TX_MISSING_INPUTS, //!< transaction was missing some of its inputs
TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
/**
* Transaction might be missing a witness, have a witness prior to SegWit
* Transaction might have a witness prior to SegWit
* activation, or witness may have been malleated (which includes
* non-standard witnesses).
*/
TX_WITNESS_MUTATED,
/**
* Transaction is missing a witness.
*/
TX_WITNESS_STRIPPED,
/**
* Tx already in mempool or conflicts with a tx in the chain
* (if it conflicts with another tx in mempool, we use MEMPOOL_POLICY as it failed to reach the RBF threshold)
Expand Down
4 changes: 2 additions & 2 deletions src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -969,11 +969,11 @@ class CNode
}


void AddInventoryKnown(const CInv& inv)
void AddKnownTx(const uint256& hash)
{
if (m_tx_relay != nullptr) {
LOCK(m_tx_relay->cs_tx_inventory);
m_tx_relay->filterInventoryKnown.insert(inv.hash);
m_tx_relay->filterInventoryKnown.insert(hash);
}
}

Expand Down
282 changes: 225 additions & 57 deletions src/net_processing.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/net_processing.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,6 @@ struct CNodeStateStats {
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);

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

#endif // BITCOIN_NET_PROCESSING_H
3 changes: 2 additions & 1 deletion src/node/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
}

if (relay) {
RelayTransaction(hashTx, *node.connman);
LOCK(cs_main);
RelayTransaction(hashTx, tx->GetWitnessHash(), *node.connman);
}

return TransactionError::OK;
Expand Down
4 changes: 4 additions & 0 deletions src/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const char *SENDCMPCT="sendcmpct";
const char *CMPCTBLOCK="cmpctblock";
const char *GETBLOCKTXN="getblocktxn";
const char *BLOCKTXN="blocktxn";
const char *WTXIDRELAY="wtxidrelay";
} // namespace NetMsgType

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

Expand Down Expand Up @@ -183,6 +185,8 @@ std::string CInv::GetCommand() const
switch (masked)
{
case MSG_TX: return cmd.append(NetMsgType::TX);
// WTX is not a message type, just an inv type
case MSG_WTX: return cmd.append("wtx");
case MSG_BLOCK: return cmd.append(NetMsgType::BLOCK);
case MSG_FILTERED_BLOCK: return cmd.append(NetMsgType::MERKLEBLOCK);
case MSG_CMPCT_BLOCK: return cmd.append(NetMsgType::CMPCTBLOCK);
Expand Down
12 changes: 9 additions & 3 deletions src/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ extern const char *GETBLOCKTXN;
* @since protocol version 70014 as described by BIP 152
*/
extern const char *BLOCKTXN;
/**
* Indicates that a node prefers to relay transactions via wtxid, rather than
* txid.
* @since protocol version 70016 as described by BIP 339.
*/
extern const char *WTXIDRELAY;
};

/* Get a vector of all valid message types (see above) */
Expand Down Expand Up @@ -362,12 +368,12 @@ const uint32_t MSG_TYPE_MASK = 0xffffffff >> 2;
* These numbers are defined by the protocol. When adding a new value, be sure
* to mention it in the respective BIP.
*/
enum GetDataMsg
{
enum GetDataMsg : uint32_t {
UNDEFINED = 0,
MSG_TX = 1,
MSG_BLOCK = 2,
// The following can only occur in getdata. Invs always use TX or BLOCK.
MSG_WTX = 5, //!< Defined in BIP 339
// The following can only occur in getdata. Invs always use TX/WTX or BLOCK.
MSG_FILTERED_BLOCK = 3, //!< Defined in BIP37
MSG_CMPCT_BLOCK = 4, //!< Defined in BIP152
MSG_WITNESS_BLOCK = MSG_BLOCK | MSG_WITNESS_FLAG, //!< Defined in BIP144
Expand Down
14 changes: 7 additions & 7 deletions src/txmempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -724,12 +724,12 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(innerUsage == cachedInnerUsage);
}

bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb)
bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb, bool wtxid)
{
LOCK(cs);
indexed_transaction_set::const_iterator i = mapTx.find(hasha);
indexed_transaction_set::const_iterator i = wtxid ? get_iter_from_wtxid(hasha) : mapTx.find(hasha);
if (i == mapTx.end()) return false;
indexed_transaction_set::const_iterator j = mapTx.find(hashb);
indexed_transaction_set::const_iterator j = wtxid ? get_iter_from_wtxid(hashb) : mapTx.find(hashb);
if (j == mapTx.end()) return true;
uint64_t counta = i->GetCountWithAncestors();
uint64_t countb = j->GetCountWithAncestors();
Expand Down Expand Up @@ -809,10 +809,10 @@ CTransactionRef CTxMemPool::get(const uint256& hash) const
return i->GetSharedTx();
}

TxMempoolInfo CTxMemPool::info(const uint256& hash) const
TxMempoolInfo CTxMemPool::info(const uint256& hash, bool wtxid) const
{
LOCK(cs);
indexed_transaction_set::const_iterator i = mapTx.find(hash);
indexed_transaction_set::const_iterator i = (wtxid ? get_iter_from_wtxid(hash) : mapTx.find(hash));
if (i == mapTx.end())
return TxMempoolInfo();
return GetInfo(i);
Expand Down Expand Up @@ -915,8 +915,8 @@ bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {

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

void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) {
Expand Down
42 changes: 37 additions & 5 deletions src/txmempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,22 @@ struct mempoolentry_txid
}
};

// extracts a transaction witness-hash from CTxMemPoolEntry or CTransactionRef
struct mempoolentry_wtxid
{
typedef uint256 result_type;
result_type operator() (const CTxMemPoolEntry &entry) const
{
return entry.GetTx().GetWitnessHash();
}

result_type operator() (const CTransactionRef& tx) const
{
return tx->GetWitnessHash();
}
};


/** \class CompareTxMemPoolEntryByDescendantScore
*
* Sort an entry by max(score/size of entry's tx, score/size with all descendants).
Expand Down Expand Up @@ -318,6 +334,7 @@ class CompareTxMemPoolEntryByAncestorFee
struct descendant_score {};
struct entry_time {};
struct ancestor_score {};
struct index_by_wtxid {};

class CBlockPolicyEstimator;

Expand Down Expand Up @@ -383,8 +400,9 @@ class SaltedTxidHasher
*
* CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping:
*
* mapTx is a boost::multi_index that sorts the mempool on 4 criteria:
* - transaction hash
* mapTx is a boost::multi_index that sorts the mempool on 5 criteria:
* - transaction hash (txid)
* - witness-transaction hash (wtxid)
* - descendant feerate [we use max(feerate of tx, feerate of tx with all descendants)]
* - time in mempool
* - ancestor feerate [we use min(feerate of tx, feerate of tx with all unconfirmed ancestors)]
Expand Down Expand Up @@ -469,6 +487,12 @@ class CTxMemPool
boost::multi_index::indexed_by<
// sorted by txid
boost::multi_index::hashed_unique<mempoolentry_txid, SaltedTxidHasher>,
// sorted by wtxid
boost::multi_index::hashed_unique<
boost::multi_index::tag<index_by_wtxid>,
mempoolentry_wtxid,
SaltedTxidHasher
>,
// sorted by fee rate
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<descendant_score>,
Expand Down Expand Up @@ -583,7 +607,7 @@ class CTxMemPool

void clear();
void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); //lock free
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb, bool wtxid=false);
void queryHashes(std::vector<uint256>& vtxid) const;
bool isSpent(const COutPoint& outpoint) const;
unsigned int GetTransactionsUpdated() const;
Expand Down Expand Up @@ -686,14 +710,22 @@ class CTxMemPool
return totalTxSize;
}

bool exists(const uint256& hash) const
bool exists(const uint256& hash, bool wtxid=false) const
{
LOCK(cs);
if (wtxid) {
return (mapTx.get<index_by_wtxid>().count(hash) != 0);
}
return (mapTx.count(hash) != 0);
}

CTransactionRef get(const uint256& hash) const;
TxMempoolInfo info(const uint256& hash) const;
txiter get_iter_from_wtxid(const uint256& wtxid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
{
AssertLockHeld(cs);
return mapTx.project<0>(mapTx.get<index_by_wtxid>().find(wtxid));
}
TxMempoolInfo info(const uint256& hash, bool wtxid=false) const;
std::vector<TxMempoolInfo> infoAll() const;

size_t DynamicMemoryUsage() const;
Expand Down
2 changes: 1 addition & 1 deletion src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
!CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
// Only the witness is missing, so the transaction itself may be fine.
state.Invalid(TxValidationResult::TX_WITNESS_MUTATED,
state.Invalid(TxValidationResult::TX_WITNESS_STRIPPED,
state.GetRejectReason(), state.GetDebugMessage());
}
return false; // state filled in by CheckInputScripts
Expand Down
5 changes: 4 additions & 1 deletion src/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* network protocol versioning
*/

static const int PROTOCOL_VERSION = 70015;
static const int PROTOCOL_VERSION = 70016;

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

//! "wtxidrelay" command for wtxid-based relay starts with this version
static const int WTXID_RELAY_VERSION = 70016;

#endif // BITCOIN_VERSION_H
5 changes: 5 additions & 0 deletions test/functional/mempool_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,15 @@ def run_test(self):
fee = Decimal("0.0001")
# MAX_ANCESTORS transactions off a confirmed tx should be fine
chain = []
witness_chain = []
for i in range(MAX_ANCESTORS):
(txid, sent_value) = self.chain_transaction(self.nodes[0], txid, 0, value, fee, 1)
value = sent_value
chain.append(txid)
# We need the wtxids to check P2P announcements
fulltx = self.nodes[0].getrawtransaction(txid)
witnesstx = self.nodes[0].decoderawtransaction(fulltx, True)
witness_chain.append(witnesstx['hash'])

# Check mempool has MAX_ANCESTORS transactions in it, and descendant and ancestor
# count and fees should look correct
Expand Down
2 changes: 1 addition & 1 deletion test/functional/p2p_blocksonly.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def run_test(self):
self.log.info('Check that txs from rpc are not rejected and relayed to other peers')
assert_equal(self.nodes[0].getpeerinfo()[0]['relaytxes'], True)
txid = self.nodes[0].testmempoolaccept([sigtx])[0]['txid']
with self.nodes[0].assert_debug_log(['received getdata for: tx {} peer=1'.format(txid)]):
with self.nodes[0].assert_debug_log(['received getdata for: wtx {} peer=1'.format(txid)]):
self.nodes[0].sendrawtransaction(sigtx)
self.nodes[0].p2p.wait_for_tx(txid)
assert_equal(self.nodes[0].getmempoolinfo()['size'], 1)
Expand Down
4 changes: 2 additions & 2 deletions test/functional/p2p_feefilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from decimal import Decimal
import time

from test_framework.messages import msg_feefilter
from test_framework.messages import MSG_TX, MSG_WTX, msg_feefilter
from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.test_framework import BitcoinTestFramework

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

def on_inv(self, message):
for i in message.inv:
if (i.type == 1):
if (i.type == MSG_TX) or (i.type == MSG_WTX):
self.txinvs.append(hashToHex(i.hash))

def clear_invs(self):
Expand Down
Loading

0 comments on commit a339289

Please sign in to comment.