Skip to content

Commit 70d3541

Browse files
committed
Merge #13134: net: Add option -enablebip61 to configure sending of BIP61 notifications
87fe292 doc: Mention disabling BIP61 in bips.md (Wladimir J. van der Laan) fe16dd8 net: Add option `-enablebip61` to configure sending of BIP61 notifications (Wladimir J. van der Laan) Pull request description: This commit adds a boolean option `-peersendreject`, defaulting to `1`, that can be used to disable the sending of [BIP61](https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki) `reject` messages. This functionality has been requested for various reasons: - security (DoS): reject messages can reveal internal state that can be used to target certain resources such as the mempool more easily. - bandwidth: a typical node sends lots of reject messages; this counts against upstream bandwidth. Also the reject messages tend to be larger than the message that was rejected. On the other hand, reject messages can be useful while developing client software (I found them indispensable while creating bitcoin-submittx), as well as for our own test cases, so whatever the default becomes on the long run, IMO the functionality should be retained as option. But that's a discussion for later, for now it's simply a node operator decision. Also adds a RPC test that checks the functionality. Tree-SHA512: 9488cc53e13cd8e5c6f8eb472a44309572673405c1d1438c3488f627fae622c95e2198bde5ed7d29e56b948e2918bf1920239e9f865889f4c37c097c37a4d7a9
2 parents 3fd0c23 + 87fe292 commit 70d3541

File tree

5 files changed

+40
-11
lines changed

5 files changed

+40
-11
lines changed

doc/bips.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.16.0**):
1515
* [`BIP 35`](https://github.com/bitcoin/bips/blob/master/bip-0035.mediawiki): The 'mempool' protocol message (and the protocol version bump to 60002) has been implemented since **v0.7.0** ([PR #1641](https://github.com/bitcoin/bitcoin/pull/1641)).
1616
* [`BIP 37`](https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki): The bloom filtering for transaction relaying, partial merkle trees for blocks, and the protocol version bump to 70001 (enabling low-bandwidth SPV clients) has been implemented since **v0.8.0** ([PR #1795](https://github.com/bitcoin/bitcoin/pull/1795)).
1717
* [`BIP 42`](https://github.com/bitcoin/bips/blob/master/bip-0042.mediawiki): The bug that would have caused the subsidy schedule to resume after block 13440000 was fixed in **v0.9.2** ([PR #3842](https://github.com/bitcoin/bitcoin/pull/3842)).
18-
* [`BIP 61`](https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki): The 'reject' protocol message (and the protocol version bump to 70002) was added in **v0.9.0** ([PR #3185](https://github.com/bitcoin/bitcoin/pull/3185)).
18+
* [`BIP 61`](https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki): The 'reject' protocol message (and the protocol version bump to 70002) was added in **v0.9.0** ([PR #3185](https://github.com/bitcoin/bitcoin/pull/3185)). Starting *v0.17.0*, whether to send reject messages can be configured with the `-enablebip61` option.
1919
* [`BIP 65`](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki): The CHECKLOCKTIMEVERIFY softfork was merged in **v0.12.0** ([PR #6351](https://github.com/bitcoin/bitcoin/pull/6351)), and backported to **v0.11.2** and **v0.10.4**. Mempool-only CLTV was added in [PR #6124](https://github.com/bitcoin/bitcoin/pull/6124).
2020
* [`BIP 66`](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki): The strict DER rules and associated version 3 blocks have been implemented since **v0.10.0** ([PR #5713](https://github.com/bitcoin/bitcoin/pull/5713)).
2121
* [`BIP 68`](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki): Sequence locks have been implemented as of **v0.12.1** ([PR #7184](https://github.com/bitcoin/bitcoin/pull/7184)), and have been activated since *block 419328*.

src/init.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ void SetupServerArgs()
395395
gArgs.AddArg("-discover", _("Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)"), false, OptionsCategory::CONNECTION);
396396
gArgs.AddArg("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + strprintf(_("(default: %u)"), DEFAULT_NAME_LOOKUP), false, OptionsCategory::CONNECTION);
397397
gArgs.AddArg("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)"), false, OptionsCategory::CONNECTION);
398+
gArgs.AddArg("-enablebip61", strprintf(_("Send reject messages per BIP61 (default: %u)"), DEFAULT_ENABLE_BIP61), false, OptionsCategory::CONNECTION);
398399
gArgs.AddArg("-externalip=<ip>", _("Specify your own public address"), false, OptionsCategory::CONNECTION);
399400
gArgs.AddArg("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), DEFAULT_FORCEDNSSEED), false, OptionsCategory::CONNECTION);
400401
gArgs.AddArg("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)"), false, OptionsCategory::CONNECTION);
@@ -1099,6 +1100,8 @@ bool AppInitParameterInteraction()
10991100
if (gArgs.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
11001101
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
11011102

1103+
g_enable_bip61 = gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61);
1104+
11021105
if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0)
11031106
return InitError("rpcserialversion must be non-negative.");
11041107

src/net_processing.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#endif
3838

3939
std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block
40+
bool g_enable_bip61 = DEFAULT_ENABLE_BIP61;
4041

4142
struct IteratorComparator
4243
{
@@ -1591,7 +1592,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
15911592
// Each connection can only send one version message
15921593
if (pfrom->nVersion != 0)
15931594
{
1594-
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message")));
1595+
if (g_enable_bip61) {
1596+
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message")));
1597+
}
15951598
LOCK(cs_main);
15961599
Misbehaving(pfrom->GetId(), 1);
15971600
return false;
@@ -1620,8 +1623,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
16201623
if (!pfrom->fInbound && !pfrom->fFeeler && !pfrom->m_manual_connection && !HasAllDesirableServiceFlags(nServices))
16211624
{
16221625
LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->GetId(), nServices, GetDesirableServiceFlags(nServices));
1623-
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
1624-
strprintf("Expected to offer services %08x", GetDesirableServiceFlags(nServices))));
1626+
if (g_enable_bip61) {
1627+
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
1628+
strprintf("Expected to offer services %08x", GetDesirableServiceFlags(nServices))));
1629+
}
16251630
pfrom->fDisconnect = true;
16261631
return false;
16271632
}
@@ -1641,8 +1646,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
16411646
{
16421647
// disconnect from peers older than this proto version
16431648
LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion);
1644-
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
1645-
strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)));
1649+
if (g_enable_bip61) {
1650+
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
1651+
strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)));
1652+
}
16461653
pfrom->fDisconnect = true;
16471654
return false;
16481655
}
@@ -2340,9 +2347,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
23402347
LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
23412348
pfrom->GetId(),
23422349
FormatStateMessage(state));
2343-
if (state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
2350+
if (g_enable_bip61 && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) { // Never send AcceptToMemoryPool's internal codes over P2P
23442351
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
23452352
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash));
2353+
}
23462354
if (nDoS > 0) {
23472355
Misbehaving(pfrom->GetId(), nDoS);
23482356
}
@@ -2915,8 +2923,10 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman)
29152923
AssertLockHeld(cs_main);
29162924
CNodeState &state = *State(pnode->GetId());
29172925

2918-
for (const CBlockReject& reject : state.rejects) {
2919-
connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, std::string(NetMsgType::BLOCK), reject.chRejectCode, reject.strRejectReason, reject.hashBlock));
2926+
if (g_enable_bip61) {
2927+
for (const CBlockReject& reject : state.rejects) {
2928+
connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, std::string(NetMsgType::BLOCK), reject.chRejectCode, reject.strRejectReason, reject.hashBlock));
2929+
}
29202930
}
29212931
state.rejects.clear();
29222932

@@ -3023,7 +3033,9 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
30233033
}
30243034
catch (const std::ios_base::failure& e)
30253035
{
3026-
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message")));
3036+
if (g_enable_bip61) {
3037+
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message")));
3038+
}
30273039
if (strstr(e.what(), "end of data"))
30283040
{
30293041
// Allow exceptions from under-length message on vRecv

src/net_processing.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ static constexpr int64_t EXTRA_PEER_CHECK_INTERVAL = 45;
3535
/** Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict, in seconds */
3636
static constexpr int64_t MINIMUM_CONNECT_TIME = 30;
3737

38+
/** Default for BIP61 (sending reject messages) */
39+
static constexpr bool DEFAULT_ENABLE_BIP61 = true;
40+
/** Enable BIP61 (sending reject messages) */
41+
extern bool g_enable_bip61;
42+
3843
class PeerLogicValidation final : public CValidationInterface, public NetEventsInterface {
3944
private:
4045
CConnman* const connman;

test/functional/p2p_invalid_tx.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
)
2222

2323

24+
REJECT_INVALID = 16
25+
2426
class InvalidTxRequestTest(BitcoinTestFramework):
2527
def set_test_params(self):
2628
self.num_nodes = 1
@@ -71,7 +73,7 @@ def run_test(self):
7173
# and we get disconnected immediately
7274
self.log.info('Test a transaction that is rejected')
7375
tx1 = create_transaction(block1.vtx[0], 0, b'\x64' * 35, 50 * COIN - 12000)
74-
node.p2p.send_txs_and_test([tx1], node, success=False, expect_disconnect=True)
76+
node.p2p.send_txs_and_test([tx1], node, success=False, expect_disconnect=True, reject_code=REJECT_INVALID, reject_reason=b'mandatory-script-verify-flag-failed (Invalid OP_IF construction)')
7577

7678
# Make two p2p connections to provide the node with orphans
7779
# * p2ps[0] will send valid orphan txs (one with low fee)
@@ -137,6 +139,13 @@ def run_test(self):
137139
wait_until(lambda: 1 == len(node.getpeerinfo()), timeout=12) # p2ps[1] is no longer connected
138140
assert_equal(expected_mempool, set(node.getrawmempool()))
139141

142+
# restart node with sending BIP61 messages disabled, check that it disconnects without sending the reject message
143+
self.log.info('Test a transaction that is rejected, with BIP61 disabled')
144+
self.restart_node(0, ['-enablebip61=0','-persistmempool=0'])
145+
self.reconnect_p2p(num_connections=1)
146+
node.p2p.send_txs_and_test([tx1], node, success=False, expect_disconnect=True)
147+
# send_txs_and_test will have waited for disconnect, so we can safely check that no reject has been received
148+
assert_equal(node.p2p.reject_code_received, None)
140149

141150
if __name__ == '__main__':
142151
InvalidTxRequestTest().main()

0 commit comments

Comments
 (0)