aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2017-12-09 08:34:31 +0100
committerWladimir J. van der Laan <laanwj@gmail.com>2017-12-09 08:38:36 +0100
commit59d3dc85b698430f71f6e242a01a25a70c9ef397 (patch)
tree08eb79fa9aee4696ba556deddc2fb3bf1fb43f1d
parent4ef4dfebbc07d93d72899f60e01ca77a280c9122 (diff)
parentde74c625833bba8d8171a2d0dd6ede2e9d5da88b (diff)
Merge #11740: Implement BIP159 NODE_NETWORK_LIMITED (pruned peers) *signaling only*
de74c62 [Doc] Update bip.md, add support for BIP 159 (Jonas Schnelli) e054d0e [QA] Add node_network_limited test (Jonas Schnelli) bd09416 Avoid leaking the prune height through getdata (fingerprinting countermeasure) (Jonas Schnelli) 27df193 Always set NODE_NETWORK_LIMITED bit (Jonas Schnelli) 7caba38 Add NODE_NETWORK_LIMITED flags and min block amount constants (Jonas Schnelli) Pull request description: Extracted from #10387. Does implement BIP159, but only the signalling part. No connections are made to NODE_NETWORK_LIMITED in this PR. The address relay and connection work (the more complicated part) can then be separated (probably in #10387). Tree-SHA512: e3218eb4789a9320b0f42dc10f62d30c13c49bdef00443fbe653bee22933477adcfc1cf8f6a95269324560b5721203ed41f3c5e2dd8a98ec2791f6a9d8346b1a
-rw-r--r--doc/bips.md1
-rw-r--r--src/init.cpp2
-rw-r--r--src/net_processing.cpp10
-rw-r--r--src/protocol.h9
-rw-r--r--src/validation.h2
-rwxr-xr-xtest/functional/node_network_limited.py81
-rwxr-xr-xtest/functional/test_runner.py1
7 files changed, 102 insertions, 4 deletions
diff --git a/doc/bips.md b/doc/bips.md
index bc8dcb6fb3..fbff94a329 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -33,3 +33,4 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.13.0**):
* [`BIP 145`](https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki): getblocktemplate updates for Segregated Witness as of **v0.13.0** ([PR 8149](https://github.com/bitcoin/bitcoin/pull/8149)).
* [`BIP 147`](https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki): NULLDUMMY softfork as of **v0.13.1** ([PR 8636](https://github.com/bitcoin/bitcoin/pull/8636) and [PR 8937](https://github.com/bitcoin/bitcoin/pull/8937)).
* [`BIP 152`](https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki): Compact block transfer and related optimizations are used as of **v0.13.0** ([PR 8068](https://github.com/bitcoin/bitcoin/pull/8068)).
+* [`BIP 159`](https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki): NODE_NETWORK_LIMITED service bit [signaling only] is supported as of **v0.16.0** ([PR 10740](https://github.com/bitcoin/bitcoin/pull/10740)).
diff --git a/src/init.cpp b/src/init.cpp
index 871a585267..67e01c9ba9 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -816,7 +816,7 @@ namespace { // Variables internal to initialization process only
int nMaxConnections;
int nUserMaxConnections;
int nFD;
-ServiceFlags nLocalServices = NODE_NETWORK;
+ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED);
} // namespace
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 442cd00c9b..85e6d9c73d 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1091,6 +1091,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
pfrom->fDisconnect = true;
send = false;
}
+ // Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
+ if (send && !pfrom->fWhitelisted && (
+ (((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (chainActive.Tip()->nHeight - mi->second->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
+ )) {
+ LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId());
+
+ //disconnect node and prevent it from stalling (would otherwise wait for the missing block)
+ pfrom->fDisconnect = true;
+ send = false;
+ }
// Pruned nodes may have deleted the block, so check whether
// it's available before trying to send.
if (send && (mi->second->nStatus & BLOCK_HAVE_DATA))
diff --git a/src/protocol.h b/src/protocol.h
index bc31434515..cf1d40db77 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -246,9 +246,8 @@ const std::vector<std::string> &getAllNetMessageTypes();
enum ServiceFlags : uint64_t {
// Nothing
NODE_NONE = 0,
- // NODE_NETWORK means that the node is capable of serving the block chain. It is currently
- // set by all Bitcoin Core nodes, and is unset by SPV clients or other peers that just want
- // network services but don't provide them.
+ // NODE_NETWORK means that the node is capable of serving the complete block chain. It is currently
+ // set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light clients.
NODE_NETWORK = (1 << 0),
// NODE_GETUTXO means the node is capable of responding to the getutxo protocol request.
// Bitcoin Core does not support this but a patch set called Bitcoin XT does.
@@ -264,6 +263,10 @@ enum ServiceFlags : uint64_t {
// NODE_XTHIN means the node supports Xtreme Thinblocks
// If this is turned off then the node will not service nor make xthin requests
NODE_XTHIN = (1 << 4),
+ // NODE_NETWORK_LIMITED means the same as NODE_NETWORK with the limitation of only
+ // serving the last 288 (2 day) blocks
+ // See BIP159 for details on how this is implemented.
+ NODE_NETWORK_LIMITED = (1 << 10),
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the
diff --git a/src/validation.h b/src/validation.h
index ec17d0d92d..49bff9f30c 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -203,6 +203,8 @@ extern bool fPruneMode;
extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
+/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
+static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
diff --git a/test/functional/node_network_limited.py b/test/functional/node_network_limited.py
new file mode 100755
index 0000000000..6d1bf7ced2
--- /dev/null
+++ b/test/functional/node_network_limited.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+from test_framework.mininode import *
+
+class BaseNode(P2PInterface):
+ nServices = 0
+ firstAddrnServices = 0
+ def on_version(self, message):
+ self.nServices = message.nServices
+
+class NodeNetworkLimitedTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+ self.extra_args = [['-prune=550']]
+
+ def getSignaledServiceFlags(self):
+ node = self.nodes[0].add_p2p_connection(BaseNode())
+ NetworkThread().start()
+ node.wait_for_verack()
+ services = node.nServices
+ self.nodes[0].disconnect_p2ps()
+ node.wait_for_disconnect()
+ return services
+
+ def tryGetBlockViaGetData(self, blockhash, must_disconnect):
+ node = self.nodes[0].add_p2p_connection(BaseNode())
+ NetworkThread().start()
+ node.wait_for_verack()
+ node.send_message(msg_verack())
+ getdata_request = msg_getdata()
+ getdata_request.inv.append(CInv(2, int(blockhash, 16)))
+ node.send_message(getdata_request)
+
+ if (must_disconnect):
+ #ensure we get disconnected
+ node.wait_for_disconnect(5)
+ else:
+ # check if the peer sends us the requested block
+ node.wait_for_block(int(blockhash, 16), 3)
+ self.nodes[0].disconnect_p2ps()
+ node.wait_for_disconnect()
+
+ def run_test(self):
+ #NODE_BLOOM & NODE_WITNESS & NODE_NETWORK_LIMITED must now be signaled
+ assert_equal(self.getSignaledServiceFlags(), 1036) #1036 == 0x40C == 0100 0000 1100
+# | ||
+# | |^--- NODE_BLOOM
+# | ^---- NODE_WITNESS
+# ^-- NODE_NETWORK_LIMITED
+
+ #now mine some blocks over the NODE_NETWORK_LIMITED + 2(racy buffer ext.) target
+ firstblock = self.nodes[0].generate(1)[0]
+ blocks = self.nodes[0].generate(292)
+ blockWithinLimitedRange = blocks[-1]
+
+ #make sure we can max retrive block at tip-288
+ #requesting block at height 2 (tip-289) must fail (ignored)
+ self.tryGetBlockViaGetData(firstblock, True) #first block must lead to disconnect
+ self.tryGetBlockViaGetData(blocks[1], False) #last block in valid range
+ self.tryGetBlockViaGetData(blocks[0], True) #first block outside of the 288+2 limit
+
+ #NODE_NETWORK_LIMITED must still be signaled after restart
+ self.restart_node(0)
+ assert_equal(self.getSignaledServiceFlags(), 1036)
+
+ #test the RPC service flags
+ assert_equal(self.nodes[0].getnetworkinfo()['localservices'], "000000000000040c")
+
+ # getdata a block above the NODE_NETWORK_LIMITED threshold must be possible
+ self.tryGetBlockViaGetData(blockWithinLimitedRange, False)
+
+ # getdata a block below the NODE_NETWORK_LIMITED threshold must be ignored
+ self.tryGetBlockViaGetData(firstblock, True)
+
+if __name__ == '__main__':
+ NodeNetworkLimitedTest().main()
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index e38146a79a..58faec521d 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -128,6 +128,7 @@ BASE_SCRIPTS= [
'uacomment.py',
'p2p-acceptblock.py',
'feature_logging.py',
+ 'node_network_limited.py',
]
EXTENDED_SCRIPTS = [