From fa1dce7329d3e74d46ab98b93772b1832a3f1819 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 9 May 2019 09:16:29 -0400 Subject: [PATCH 1/4] net: Rename ::fRelayTxes to ::g_relay_txes This helps to distinguish it from CNode::fRelayTxes and avoid bugs like 425278d17bd0edf8a3a7cc81e55016f7fd8e7726 --- src/init.cpp | 2 +- src/net.cpp | 2 +- src/net.h | 2 +- src/net_processing.cpp | 6 +++--- src/rpc/net.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 8095105cce..806b0e48b9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1426,7 +1426,7 @@ bool AppInitMain(InitInterfaces& interfaces) // see Step 2: parameter interactions for more information about these fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN); fDiscover = gArgs.GetBoolArg("-discover", true); - fRelayTxes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); + g_relay_txes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); for (const std::string& strAddr : gArgs.GetArgs("-externalip")) { CService addrLocal; diff --git a/src/net.cpp b/src/net.cpp index 1335804b06..3c6f5a05f3 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -79,7 +79,7 @@ static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // S // bool fDiscover = true; bool fListen = true; -bool fRelayTxes = true; +bool g_relay_txes = !DEFAULT_BLOCKSONLY; CCriticalSection cs_mapLocalHost; std::map mapLocalHost GUARDED_BY(cs_mapLocalHost); static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {}; diff --git a/src/net.h b/src/net.h index 7af33ef13b..37aaf1a63b 100644 --- a/src/net.h +++ b/src/net.h @@ -519,7 +519,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices) extern bool fDiscover; extern bool fListen; -extern bool fRelayTxes; +extern bool g_relay_txes; /** Subversion as sent to the P2P network in `version` messages */ extern std::string strSubVersion; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index b3facdcd3a..cb2b9f8c03 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -422,7 +422,7 @@ static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime) CAddress addrMe = CAddress(CService(), nLocalNodeServices); connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, - nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes)); + nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes)); if (fLogIPs) { 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 return false; } - bool fBlocksOnly = !fRelayTxes; + bool fBlocksOnly = !g_relay_txes; // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) @@ -2445,7 +2445,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (strCommand == NetMsgType::TX) { // Stop processing the transaction early if // We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off - if (!fRelayTxes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))) + if (!g_relay_txes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))) { LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId()); return true; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index e8cdce623c..e49c3e031f 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -496,7 +496,7 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) obj.pushKV("protocolversion",PROTOCOL_VERSION); if(g_connman) obj.pushKV("localservices", strprintf("%016x", g_connman->GetLocalServices())); - obj.pushKV("localrelay", fRelayTxes); + obj.pushKV("localrelay", g_relay_txes); obj.pushKV("timeoffset", GetTimeOffset()); if (g_connman) { obj.pushKV("networkactive", g_connman->GetNetworkActive()); From fa3872e7b4540857261aed948b94b6b2bfdbc3d1 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 9 May 2019 10:36:53 -0400 Subject: [PATCH 2/4] test: Format predicate source as multiline on error --- test/functional/test_framework/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 190301b215..0583b42388 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -216,7 +216,7 @@ def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=N time.sleep(0.05) # Print the cause of the timeout - predicate_source = inspect.getsourcelines(predicate) + predicate_source = "''''\n" + inspect.getsource(predicate) + "'''" logger.error("wait_until() failed. Predicate: {}".format(predicate_source)) if attempt >= attempts: raise AssertionError("Predicate {} not true after {} attempts".format(predicate_source, attempts)) From fa320de79faaca2b088fcbe7f76701faa9bff236 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 9 May 2019 10:42:56 -0400 Subject: [PATCH 3/4] test: Add test for p2p_blocksonly --- test/functional/p2p_blocksonly.py | 58 ++++++++++++++++++++++ test/functional/test_framework/mininode.py | 8 +++ test/functional/test_runner.py | 1 + 3 files changed, 67 insertions(+) create mode 100755 test/functional/p2p_blocksonly.py diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py new file mode 100755 index 0000000000..12cb06a407 --- /dev/null +++ b/test/functional/p2p_blocksonly.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test p2p blocksonly""" + +from test_framework.messages import msg_tx, CTransaction, FromHex +from test_framework.mininode import P2PInterface +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + + +class P2PBlocksOnly(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = False + self.num_nodes = 1 + self.extra_args = [["-blocksonly"]] + + def run_test(self): + self.nodes[0].add_p2p_connection(P2PInterface()) + + self.log.info('Check that txs from p2p are rejected') + prevtx = self.nodes[0].getblock(self.nodes[0].getblockhash(1), 2)['tx'][0] + rawtx = self.nodes[0].createrawtransaction( + inputs=[{ + 'txid': prevtx['txid'], + 'vout': 0 + }], + outputs=[{ + self.nodes[0].get_deterministic_priv_key().address: 50 - 0.00125 + }], + ) + sigtx = self.nodes[0].signrawtransactionwithkey( + hexstring=rawtx, + privkeys=[self.nodes[0].get_deterministic_priv_key().key], + prevtxs=[{ + 'txid': prevtx['txid'], + 'vout': 0, + 'scriptPubKey': prevtx['vout'][0]['scriptPubKey']['hex'], + }], + )['hex'] + assert_equal(self.nodes[0].getnetworkinfo()['localrelay'], False) + with self.nodes[0].assert_debug_log(['transaction sent in violation of protocol peer=0']): + self.nodes[0].p2p.send_message(msg_tx(FromHex(CTransaction(), sigtx))) + self.nodes[0].p2p.sync_with_ping() + assert_equal(self.nodes[0].getmempoolinfo()['size'], 0) + + 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=0'.format(txid)]): + self.nodes[0].sendrawtransaction(sigtx) + self.nodes[0].p2p.wait_for_tx(txid) + assert_equal(self.nodes[0].getmempoolinfo()['size'], 1) + + +if __name__ == '__main__': + P2PBlocksOnly().main() diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index 11ea968257..cc3a4cc72a 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -361,6 +361,14 @@ class P2PInterface(P2PConnection): # Message receiving helper methods + def wait_for_tx(self, txid, timeout=60): + def test_function(): + if not self.last_message.get('tx'): + return False + return self.last_message['tx'].tx.rehash() == txid + + wait_until(test_function, timeout=timeout, lock=mininode_lock) + def wait_for_block(self, blockhash, timeout=60): test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash wait_until(test_function, timeout=timeout, lock=mininode_lock) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index ec5d6f1715..eff6128588 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -141,6 +141,7 @@ BASE_SCRIPTS = [ 'rpc_net.py', 'wallet_keypool.py', 'p2p_mempool.py', + 'p2p_blocksonly.py', 'mining_prioritisetransaction.py', 'p2p_invalid_locator.py', 'p2p_invalid_block.py', From fa8ced32a60dea37ac169241cf9a1f708ef46c4b Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 9 May 2019 09:29:08 -0400 Subject: [PATCH 4/4] doc: Mention blocksonly in reduce-traffic.md, unhide option --- doc/reduce-traffic.md | 13 +++++++++++++ src/init.cpp | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/doc/reduce-traffic.md b/doc/reduce-traffic.md index dd1469f563..5a71f62e0f 100644 --- a/doc/reduce-traffic.md +++ b/doc/reduce-traffic.md @@ -35,3 +35,16 @@ blocks and transactions to fewer nodes. Reducing the maximum connected nodes to a minimum could be desirable if traffic limits are tiny. Keep in mind that bitcoin's trustless model works best if you are connected to a handful of nodes. + +## 4. Turn off transaction relay (`-blocksonly`) + +Forwarding transactions to peers increases the P2P traffic. To only sync blocks +with other peers, you can disable transaction relay. + +Be reminded of the effects of this setting. + +- Fee estimation will no longer work. +- Not relaying other's transactions could hurt your privacy if used while a + wallet is loaded or if you use the node to broadcast transactions. +- It makes block propagation slower because compact block relay can only be + used when transaction relay is enabled. diff --git a/src/init.cpp b/src/init.cpp index 806b0e48b9..3d825a29b6 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -383,7 +383,7 @@ void SetupServerArgs() gArgs.AddArg("-blocksdir=", "Specify blocks directory (default: /blocks)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-blocknotify=", "Execute command when the best block changes (%s in cmd is replaced by block hash)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-blockreconstructionextratxn=", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), false, OptionsCategory::OPTIONS); - gArgs.AddArg("-blocksonly", strprintf("Whether to operate in a blocks only mode (default: %u)", DEFAULT_BLOCKSONLY), true, OptionsCategory::OPTIONS); + 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); gArgs.AddArg("-conf=", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS); gArgs.AddArg("-datadir=", "Specify data directory", false, OptionsCategory::OPTIONS); gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS);