Bypass headers anti-DoS checks for NoBan peers

This commit is contained in:
Suhas Daftuar 2022-08-30 12:45:21 -04:00
parent 132ed7eaaa
commit e5982ecdc4
2 changed files with 33 additions and 6 deletions

View File

@ -2820,6 +2820,13 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
} }
} }
// If our peer has NetPermissionFlags::NoBan privileges, then bypass our
// anti-DoS logic (this saves bandwidth when we connect to a trusted peer
// on startup).
if (pfrom.HasPermission(NetPermissionFlags::NoBan)) {
already_validated_work = true;
}
// At this point, the headers connect to something in our block index. // At this point, the headers connect to something in our block index.
// Do anti-DoS checks to determine if we should process or store for later // Do anti-DoS checks to determine if we should process or store for later
// processing. // processing.

View File

@ -28,9 +28,9 @@ NODE2_BLOCKS_REQUIRED = 2047
class RejectLowDifficultyHeadersTest(BitcoinTestFramework): class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
def set_test_params(self): def set_test_params(self):
self.setup_clean_chain = True self.setup_clean_chain = True
self.num_nodes = 3 self.num_nodes = 4
# Node0 has no required chainwork; node1 requires 15 blocks on top of the genesis block; node2 requires 2047 # Node0 has no required chainwork; node1 requires 15 blocks on top of the genesis block; node2 requires 2047
self.extra_args = [["-minimumchainwork=0x0", "-checkblockindex=0"], ["-minimumchainwork=0x1f", "-checkblockindex=0"], ["-minimumchainwork=0x1000", "-checkblockindex=0"]] self.extra_args = [["-minimumchainwork=0x0", "-checkblockindex=0"], ["-minimumchainwork=0x1f", "-checkblockindex=0"], ["-minimumchainwork=0x1000", "-checkblockindex=0"], ["-minimumchainwork=0x1000", "-checkblockindex=0", "-whitelist=noban@127.0.0.1"]]
def setup_network(self): def setup_network(self):
self.setup_nodes() self.setup_nodes()
@ -40,17 +40,34 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
def disconnect_all(self): def disconnect_all(self):
self.disconnect_nodes(0, 1) self.disconnect_nodes(0, 1)
self.disconnect_nodes(0, 2) self.disconnect_nodes(0, 2)
self.disconnect_nodes(0, 3)
def reconnect_all(self): def reconnect_all(self):
self.connect_nodes(0, 1) self.connect_nodes(0, 1)
self.connect_nodes(0, 2) self.connect_nodes(0, 2)
self.connect_nodes(0, 3)
def test_chains_sync_when_long_enough(self): def test_chains_sync_when_long_enough(self):
self.log.info("Generate blocks on the node with no required chainwork, and verify nodes 1 and 2 have no new headers in their headers tree") self.log.info("Generate blocks on the node with no required chainwork, and verify nodes 1 and 2 have no new headers in their headers tree")
with self.nodes[1].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=14)"]), self.nodes[2].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=14)"]): with self.nodes[1].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=14)"]), self.nodes[2].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=14)"]):
self.generate(self.nodes[0], NODE1_BLOCKS_REQUIRED-1, sync_fun=self.no_op) self.generate(self.nodes[0], NODE1_BLOCKS_REQUIRED-1, sync_fun=self.no_op)
for node in self.nodes[1:]: # Node3 should always allow headers due to noban permissions
self.log.info("Check that node3 will sync headers (due to noban permissions)")
def check_node3_chaintips(num_tips, tip_hash, height):
node3_chaintips = self.nodes[3].getchaintips()
assert(len(node3_chaintips) == num_tips)
assert {
'height': height,
'hash': tip_hash,
'branchlen': height,
'status': 'headers-only',
} in node3_chaintips
check_node3_chaintips(2, self.nodes[0].getbestblockhash(), NODE1_BLOCKS_REQUIRED-1)
for node in self.nodes[1:3]:
chaintips = node.getchaintips() chaintips = node.getchaintips()
assert(len(chaintips) == 1) assert(len(chaintips) == 1)
assert { assert {
@ -63,7 +80,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
self.log.info("Generate more blocks to satisfy node1's minchainwork requirement, and verify node2 still has no new headers in headers tree") self.log.info("Generate more blocks to satisfy node1's minchainwork requirement, and verify node2 still has no new headers in headers tree")
with self.nodes[2].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=15)"]): with self.nodes[2].assert_debug_log(expected_msgs=["[net] Ignoring low-work chain (height=15)"]):
self.generate(self.nodes[0], NODE1_BLOCKS_REQUIRED - self.nodes[0].getblockcount(), sync_fun=self.no_op) self.generate(self.nodes[0], NODE1_BLOCKS_REQUIRED - self.nodes[0].getblockcount(), sync_fun=self.no_op)
self.sync_blocks(self.nodes[0:2]) self.sync_blocks(self.nodes[0:2]) # node3 will sync headers (noban permissions) but not blocks (due to minchainwork)
assert { assert {
'height': 0, 'height': 0,
@ -74,10 +91,13 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework):
assert(len(self.nodes[2].getchaintips()) == 1) assert(len(self.nodes[2].getchaintips()) == 1)
self.log.info("Generate long chain for node0/node1") self.log.info("Check that node3 accepted these headers as well")
check_node3_chaintips(2, self.nodes[0].getbestblockhash(), NODE1_BLOCKS_REQUIRED)
self.log.info("Generate long chain for node0/node1/node3")
self.generate(self.nodes[0], NODE2_BLOCKS_REQUIRED-self.nodes[0].getblockcount(), sync_fun=self.no_op) self.generate(self.nodes[0], NODE2_BLOCKS_REQUIRED-self.nodes[0].getblockcount(), sync_fun=self.no_op)
self.log.info("Verify that node2 will sync the chain when it gets long enough") self.log.info("Verify that node2 and node3 will sync the chain when it gets long enough")
self.sync_blocks() self.sync_blocks()
def test_peerinfo_includes_headers_presync_height(self): def test_peerinfo_includes_headers_presync_height(self):