Skip to content

Commit df7addc

Browse files
committed
Merge #15990: Add tests and documentation for blocksonly
fa8ced3 doc: Mention blocksonly in reduce-traffic.md, unhide option (MarcoFalke) fa320de test: Add test for p2p_blocksonly (MarcoFalke) fa3872e test: Format predicate source as multiline on error (MarcoFalke) fa1dce7 net: Rename ::fRelayTxes to ::g_relay_txes (MarcoFalke) Pull request description: This is de-facto no longer hidden ACKs for commit fa8ced: jamesob: utACK bitcoin/bitcoin@fa8ced3 Tree-SHA512: 474fbdee6cbd035ed9068a066b6056c1f909ec7520be0417820fcd1672ab3069b53f55c5147968978d9258fd3a3933fe1a9ef8e4f6e14fb6ebbd79701a0a1245
2 parents 1c719f7 + fa8ced3 commit df7addc

File tree

10 files changed

+89
-9
lines changed

10 files changed

+89
-9
lines changed

doc/reduce-traffic.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,16 @@ blocks and transactions to fewer nodes.
3535
Reducing the maximum connected nodes to a minimum could be desirable if traffic
3636
limits are tiny. Keep in mind that bitcoin's trustless model works best if you are
3737
connected to a handful of nodes.
38+
39+
## 4. Turn off transaction relay (`-blocksonly`)
40+
41+
Forwarding transactions to peers increases the P2P traffic. To only sync blocks
42+
with other peers, you can disable transaction relay.
43+
44+
Be reminded of the effects of this setting.
45+
46+
- Fee estimation will no longer work.
47+
- Not relaying other's transactions could hurt your privacy if used while a
48+
wallet is loaded or if you use the node to broadcast transactions.
49+
- It makes block propagation slower because compact block relay can only be
50+
used when transaction relay is enabled.

src/init.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ void SetupServerArgs()
383383
gArgs.AddArg("-blocksdir=<dir>", "Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)", false, OptionsCategory::OPTIONS);
384384
gArgs.AddArg("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)", false, OptionsCategory::OPTIONS);
385385
gArgs.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), false, OptionsCategory::OPTIONS);
386-
gArgs.AddArg("-blocksonly", strprintf("Whether to operate in a blocks only mode (default: %u)", DEFAULT_BLOCKSONLY), true, OptionsCategory::OPTIONS);
386+
gArgs.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Transactions from the wallet or RPC are not affected. (default: %u)", DEFAULT_BLOCKSONLY), false, OptionsCategory::OPTIONS);
387387
gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS);
388388
gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS);
389389
gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS);
@@ -1426,7 +1426,7 @@ bool AppInitMain(InitInterfaces& interfaces)
14261426
// see Step 2: parameter interactions for more information about these
14271427
fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN);
14281428
fDiscover = gArgs.GetBoolArg("-discover", true);
1429-
fRelayTxes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
1429+
g_relay_txes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
14301430

14311431
for (const std::string& strAddr : gArgs.GetArgs("-externalip")) {
14321432
CService addrLocal;

src/net.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // S
7979
//
8080
bool fDiscover = true;
8181
bool fListen = true;
82-
bool fRelayTxes = true;
82+
bool g_relay_txes = !DEFAULT_BLOCKSONLY;
8383
CCriticalSection cs_mapLocalHost;
8484
std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost);
8585
static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {};

src/net.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
519519

520520
extern bool fDiscover;
521521
extern bool fListen;
522-
extern bool fRelayTxes;
522+
extern bool g_relay_txes;
523523

524524
/** Subversion as sent to the P2P network in `version` messages */
525525
extern std::string strSubVersion;

src/net_processing.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime)
422422
CAddress addrMe = CAddress(CService(), nLocalNodeServices);
423423

424424
connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
425-
nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes));
425+
nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes));
426426

427427
if (fLogIPs) {
428428
LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid);
@@ -2189,7 +2189,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
21892189
return false;
21902190
}
21912191

2192-
bool fBlocksOnly = !fRelayTxes;
2192+
bool fBlocksOnly = !g_relay_txes;
21932193

21942194
// Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true
21952195
if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))
@@ -2445,7 +2445,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
24452445
if (strCommand == NetMsgType::TX) {
24462446
// Stop processing the transaction early if
24472447
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
2448-
if (!fRelayTxes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
2448+
if (!g_relay_txes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
24492449
{
24502450
LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId());
24512451
return true;

src/rpc/net.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
496496
obj.pushKV("protocolversion",PROTOCOL_VERSION);
497497
if(g_connman)
498498
obj.pushKV("localservices", strprintf("%016x", g_connman->GetLocalServices()));
499-
obj.pushKV("localrelay", fRelayTxes);
499+
obj.pushKV("localrelay", g_relay_txes);
500500
obj.pushKV("timeoffset", GetTimeOffset());
501501
if (g_connman) {
502502
obj.pushKV("networkactive", g_connman->GetNetworkActive());

test/functional/p2p_blocksonly.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2019 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Test p2p blocksonly"""
6+
7+
from test_framework.messages import msg_tx, CTransaction, FromHex
8+
from test_framework.mininode import P2PInterface
9+
from test_framework.test_framework import BitcoinTestFramework
10+
from test_framework.util import assert_equal
11+
12+
13+
class P2PBlocksOnly(BitcoinTestFramework):
14+
def set_test_params(self):
15+
self.setup_clean_chain = False
16+
self.num_nodes = 1
17+
self.extra_args = [["-blocksonly"]]
18+
19+
def run_test(self):
20+
self.nodes[0].add_p2p_connection(P2PInterface())
21+
22+
self.log.info('Check that txs from p2p are rejected')
23+
prevtx = self.nodes[0].getblock(self.nodes[0].getblockhash(1), 2)['tx'][0]
24+
rawtx = self.nodes[0].createrawtransaction(
25+
inputs=[{
26+
'txid': prevtx['txid'],
27+
'vout': 0
28+
}],
29+
outputs=[{
30+
self.nodes[0].get_deterministic_priv_key().address: 50 - 0.00125
31+
}],
32+
)
33+
sigtx = self.nodes[0].signrawtransactionwithkey(
34+
hexstring=rawtx,
35+
privkeys=[self.nodes[0].get_deterministic_priv_key().key],
36+
prevtxs=[{
37+
'txid': prevtx['txid'],
38+
'vout': 0,
39+
'scriptPubKey': prevtx['vout'][0]['scriptPubKey']['hex'],
40+
}],
41+
)['hex']
42+
assert_equal(self.nodes[0].getnetworkinfo()['localrelay'], False)
43+
with self.nodes[0].assert_debug_log(['transaction sent in violation of protocol peer=0']):
44+
self.nodes[0].p2p.send_message(msg_tx(FromHex(CTransaction(), sigtx)))
45+
self.nodes[0].p2p.sync_with_ping()
46+
assert_equal(self.nodes[0].getmempoolinfo()['size'], 0)
47+
48+
self.log.info('Check that txs from rpc are not rejected and relayed to other peers')
49+
assert_equal(self.nodes[0].getpeerinfo()[0]['relaytxes'], True)
50+
txid = self.nodes[0].testmempoolaccept([sigtx])[0]['txid']
51+
with self.nodes[0].assert_debug_log(['received getdata for: tx {} peer=0'.format(txid)]):
52+
self.nodes[0].sendrawtransaction(sigtx)
53+
self.nodes[0].p2p.wait_for_tx(txid)
54+
assert_equal(self.nodes[0].getmempoolinfo()['size'], 1)
55+
56+
57+
if __name__ == '__main__':
58+
P2PBlocksOnly().main()

test/functional/test_framework/mininode.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,14 @@ def wait_for_disconnect(self, timeout=60):
361361

362362
# Message receiving helper methods
363363

364+
def wait_for_tx(self, txid, timeout=60):
365+
def test_function():
366+
if not self.last_message.get('tx'):
367+
return False
368+
return self.last_message['tx'].tx.rehash() == txid
369+
370+
wait_until(test_function, timeout=timeout, lock=mininode_lock)
371+
364372
def wait_for_block(self, blockhash, timeout=60):
365373
test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash
366374
wait_until(test_function, timeout=timeout, lock=mininode_lock)

test/functional/test_framework/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=N
216216
time.sleep(0.05)
217217

218218
# Print the cause of the timeout
219-
predicate_source = inspect.getsourcelines(predicate)
219+
predicate_source = "''''\n" + inspect.getsource(predicate) + "'''"
220220
logger.error("wait_until() failed. Predicate: {}".format(predicate_source))
221221
if attempt >= attempts:
222222
raise AssertionError("Predicate {} not true after {} attempts".format(predicate_source, attempts))

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
'rpc_net.py',
142142
'wallet_keypool.py',
143143
'p2p_mempool.py',
144+
'p2p_blocksonly.py',
144145
'mining_prioritisetransaction.py',
145146
'p2p_invalid_locator.py',
146147
'p2p_invalid_block.py',

0 commit comments

Comments
 (0)