Skip to content

Commit 59d3dc8

Browse files
committed
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
2 parents 4ef4dfe + de74c62 commit 59d3dc8

File tree

7 files changed

+102
-4
lines changed

7 files changed

+102
-4
lines changed

doc/bips.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.13.0**):
3333
* [`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)).
3434
* [`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)).
3535
* [`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)).
36+
* [`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)).

src/init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ namespace { // Variables internal to initialization process only
816816
int nMaxConnections;
817817
int nUserMaxConnections;
818818
int nFD;
819-
ServiceFlags nLocalServices = NODE_NETWORK;
819+
ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED);
820820

821821
} // namespace
822822

src/net_processing.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
10911091
pfrom->fDisconnect = true;
10921092
send = false;
10931093
}
1094+
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
1095+
if (send && !pfrom->fWhitelisted && (
1096+
(((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 */) )
1097+
)) {
1098+
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId());
1099+
1100+
//disconnect node and prevent it from stalling (would otherwise wait for the missing block)
1101+
pfrom->fDisconnect = true;
1102+
send = false;
1103+
}
10941104
// Pruned nodes may have deleted the block, so check whether
10951105
// it's available before trying to send.
10961106
if (send && (mi->second->nStatus & BLOCK_HAVE_DATA))

src/protocol.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,8 @@ const std::vector<std::string> &getAllNetMessageTypes();
246246
enum ServiceFlags : uint64_t {
247247
// Nothing
248248
NODE_NONE = 0,
249-
// NODE_NETWORK means that the node is capable of serving the block chain. It is currently
250-
// set by all Bitcoin Core nodes, and is unset by SPV clients or other peers that just want
251-
// network services but don't provide them.
249+
// NODE_NETWORK means that the node is capable of serving the complete block chain. It is currently
250+
// set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light clients.
252251
NODE_NETWORK = (1 << 0),
253252
// NODE_GETUTXO means the node is capable of responding to the getutxo protocol request.
254253
// Bitcoin Core does not support this but a patch set called Bitcoin XT does.
@@ -264,6 +263,10 @@ enum ServiceFlags : uint64_t {
264263
// NODE_XTHIN means the node supports Xtreme Thinblocks
265264
// If this is turned off then the node will not service nor make xthin requests
266265
NODE_XTHIN = (1 << 4),
266+
// NODE_NETWORK_LIMITED means the same as NODE_NETWORK with the limitation of only
267+
// serving the last 288 (2 day) blocks
268+
// See BIP159 for details on how this is implemented.
269+
NODE_NETWORK_LIMITED = (1 << 10),
267270

268271
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
269272
// isn't getting used, or one not being used much, and notify the

src/validation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ extern bool fPruneMode;
203203
extern uint64_t nPruneTarget;
204204
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
205205
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
206+
/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
207+
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
206208

207209
static const signed int DEFAULT_CHECKBLOCKS = 6;
208210
static const unsigned int DEFAULT_CHECKLEVEL = 3;
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2017 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+
from test_framework.test_framework import BitcoinTestFramework
6+
from test_framework.util import *
7+
from test_framework.mininode import *
8+
9+
class BaseNode(P2PInterface):
10+
nServices = 0
11+
firstAddrnServices = 0
12+
def on_version(self, message):
13+
self.nServices = message.nServices
14+
15+
class NodeNetworkLimitedTest(BitcoinTestFramework):
16+
def set_test_params(self):
17+
self.setup_clean_chain = True
18+
self.num_nodes = 1
19+
self.extra_args = [['-prune=550']]
20+
21+
def getSignaledServiceFlags(self):
22+
node = self.nodes[0].add_p2p_connection(BaseNode())
23+
NetworkThread().start()
24+
node.wait_for_verack()
25+
services = node.nServices
26+
self.nodes[0].disconnect_p2ps()
27+
node.wait_for_disconnect()
28+
return services
29+
30+
def tryGetBlockViaGetData(self, blockhash, must_disconnect):
31+
node = self.nodes[0].add_p2p_connection(BaseNode())
32+
NetworkThread().start()
33+
node.wait_for_verack()
34+
node.send_message(msg_verack())
35+
getdata_request = msg_getdata()
36+
getdata_request.inv.append(CInv(2, int(blockhash, 16)))
37+
node.send_message(getdata_request)
38+
39+
if (must_disconnect):
40+
#ensure we get disconnected
41+
node.wait_for_disconnect(5)
42+
else:
43+
# check if the peer sends us the requested block
44+
node.wait_for_block(int(blockhash, 16), 3)
45+
self.nodes[0].disconnect_p2ps()
46+
node.wait_for_disconnect()
47+
48+
def run_test(self):
49+
#NODE_BLOOM & NODE_WITNESS & NODE_NETWORK_LIMITED must now be signaled
50+
assert_equal(self.getSignaledServiceFlags(), 1036) #1036 == 0x40C == 0100 0000 1100
51+
# | ||
52+
# | |^--- NODE_BLOOM
53+
# | ^---- NODE_WITNESS
54+
# ^-- NODE_NETWORK_LIMITED
55+
56+
#now mine some blocks over the NODE_NETWORK_LIMITED + 2(racy buffer ext.) target
57+
firstblock = self.nodes[0].generate(1)[0]
58+
blocks = self.nodes[0].generate(292)
59+
blockWithinLimitedRange = blocks[-1]
60+
61+
#make sure we can max retrive block at tip-288
62+
#requesting block at height 2 (tip-289) must fail (ignored)
63+
self.tryGetBlockViaGetData(firstblock, True) #first block must lead to disconnect
64+
self.tryGetBlockViaGetData(blocks[1], False) #last block in valid range
65+
self.tryGetBlockViaGetData(blocks[0], True) #first block outside of the 288+2 limit
66+
67+
#NODE_NETWORK_LIMITED must still be signaled after restart
68+
self.restart_node(0)
69+
assert_equal(self.getSignaledServiceFlags(), 1036)
70+
71+
#test the RPC service flags
72+
assert_equal(self.nodes[0].getnetworkinfo()['localservices'], "000000000000040c")
73+
74+
# getdata a block above the NODE_NETWORK_LIMITED threshold must be possible
75+
self.tryGetBlockViaGetData(blockWithinLimitedRange, False)
76+
77+
# getdata a block below the NODE_NETWORK_LIMITED threshold must be ignored
78+
self.tryGetBlockViaGetData(firstblock, True)
79+
80+
if __name__ == '__main__':
81+
NodeNetworkLimitedTest().main()

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
'uacomment.py',
129129
'p2p-acceptblock.py',
130130
'feature_logging.py',
131+
'node_network_limited.py',
131132
]
132133

133134
EXTENDED_SCRIPTS = [

0 commit comments

Comments
 (0)