mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
4c8e77a48d
d841301010914203fb5ef02627c76fad99cb11f1 test: Add docstring to wait_until() in util.py to warn about its usage (Seleme Topuz) 1343c86c7cc1fc896696b3ed87c12039e4ef3a0c test: Update wait_until usage in tests not to use the one from utils (Seleme Topuz) Pull request description: Replace global (from [test_framework/util.py](https://github.com/bitcoin/bitcoin/blob/master/test/functional/test_framework/util.py#L228)) `wait_until()` usages with the ones provided by `BitcoinTestFramework` and `P2PInterface` classes. The motivation behind this change is that the `util.wait_until()` expects a timeout, timeout_factor and lock and it is not aware of the context of the test framework. `BitcoinTestFramework` offers a `wait_until()` which has an understandable amount of default `timeout` and a shared `timeout_factor`. Moreover, on top of these, `mininode.wait_until()` also has a shared lock. closes #19080 ACKs for top commit: MarcoFalke: ACK d841301010914203fb5ef02627c76fad99cb11f1 🦆 kallewoof: utACK d841301010914203fb5ef02627c76fad99cb11f1 Tree-SHA512: 81604f4cfa87fed98071a80e4afe940b3897fe65cf680a69619a93e97d45f25b313c12227de7040e19517fa9c003291b232f1b40b2567aba0148f22c23c47a88
150 lines
5.8 KiB
Python
Executable File
150 lines
5.8 KiB
Python
Executable File
#!/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.
|
|
"""Test various fingerprinting protections.
|
|
|
|
If a stale block more than a month old or its header are requested by a peer,
|
|
the node should pretend that it does not have it to avoid fingerprinting.
|
|
"""
|
|
import time
|
|
|
|
from test_framework.blocktools import (create_block, create_coinbase)
|
|
from test_framework.messages import CInv, MSG_BLOCK
|
|
from test_framework.p2p import (
|
|
P2PInterface,
|
|
msg_headers,
|
|
msg_block,
|
|
msg_getdata,
|
|
msg_getheaders,
|
|
)
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
from test_framework.util import (
|
|
assert_equal,
|
|
)
|
|
|
|
|
|
class P2PFingerprintTest(BitcoinTestFramework):
|
|
|
|
def set_test_params(self):
|
|
self.setup_clean_chain = True
|
|
self.num_nodes = 1
|
|
|
|
# Build a chain of blocks on top of given one
|
|
def build_chain(self, nblocks, prev_hash, prev_height, prev_median_time):
|
|
blocks = []
|
|
for _ in range(nblocks):
|
|
coinbase = create_coinbase(prev_height + 1)
|
|
block_time = prev_median_time + 1
|
|
block = create_block(int(prev_hash, 16), coinbase, block_time)
|
|
block.solve()
|
|
|
|
blocks.append(block)
|
|
prev_hash = block.hash
|
|
prev_height += 1
|
|
prev_median_time = block_time
|
|
return blocks
|
|
|
|
# Send a getdata request for a given block hash
|
|
def send_block_request(self, block_hash, node):
|
|
msg = msg_getdata()
|
|
msg.inv.append(CInv(MSG_BLOCK, block_hash))
|
|
node.send_message(msg)
|
|
|
|
# Send a getheaders request for a given single block hash
|
|
def send_header_request(self, block_hash, node):
|
|
msg = msg_getheaders()
|
|
msg.hashstop = block_hash
|
|
node.send_message(msg)
|
|
|
|
# Check whether last block received from node has a given hash
|
|
def last_block_equals(self, expected_hash, node):
|
|
block_msg = node.last_message.get("block")
|
|
return block_msg and block_msg.block.rehash() == expected_hash
|
|
|
|
# Check whether last block header received from node has a given hash
|
|
def last_header_equals(self, expected_hash, node):
|
|
headers_msg = node.last_message.get("headers")
|
|
return (headers_msg and
|
|
headers_msg.headers and
|
|
headers_msg.headers[0].rehash() == expected_hash)
|
|
|
|
# Checks that stale blocks timestamped more than a month ago are not served
|
|
# by the node while recent stale blocks and old active chain blocks are.
|
|
# This does not currently test that stale blocks timestamped within the
|
|
# last month but that have over a month's worth of work are also withheld.
|
|
def run_test(self):
|
|
node0 = self.nodes[0].add_p2p_connection(P2PInterface())
|
|
|
|
# Set node time to 60 days ago
|
|
self.nodes[0].setmocktime(int(time.time()) - 60 * 24 * 60 * 60)
|
|
|
|
# Generating a chain of 10 blocks
|
|
block_hashes = self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
|
|
|
|
# Create longer chain starting 2 blocks before current tip
|
|
height = len(block_hashes) - 2
|
|
block_hash = block_hashes[height - 1]
|
|
block_time = self.nodes[0].getblockheader(block_hash)["mediantime"] + 1
|
|
new_blocks = self.build_chain(5, block_hash, height, block_time)
|
|
|
|
# Force reorg to a longer chain
|
|
node0.send_message(msg_headers(new_blocks))
|
|
node0.wait_for_getdata([x.sha256 for x in new_blocks])
|
|
for block in new_blocks:
|
|
node0.send_and_ping(msg_block(block))
|
|
|
|
# Check that reorg succeeded
|
|
assert_equal(self.nodes[0].getblockcount(), 13)
|
|
|
|
stale_hash = int(block_hashes[-1], 16)
|
|
|
|
# Check that getdata request for stale block succeeds
|
|
self.send_block_request(stale_hash, node0)
|
|
test_function = lambda: self.last_block_equals(stale_hash, node0)
|
|
self.wait_until(test_function, timeout=3)
|
|
|
|
# Check that getheader request for stale block header succeeds
|
|
self.send_header_request(stale_hash, node0)
|
|
test_function = lambda: self.last_header_equals(stale_hash, node0)
|
|
self.wait_until(test_function, timeout=3)
|
|
|
|
# Longest chain is extended so stale is much older than chain tip
|
|
self.nodes[0].setmocktime(0)
|
|
tip = self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[0]
|
|
assert_equal(self.nodes[0].getblockcount(), 14)
|
|
|
|
# Send getdata & getheaders to refresh last received getheader message
|
|
block_hash = int(tip, 16)
|
|
self.send_block_request(block_hash, node0)
|
|
self.send_header_request(block_hash, node0)
|
|
node0.wait_for_block(block_hash, timeout=3)
|
|
|
|
# Request for very old stale block should now fail
|
|
self.send_block_request(stale_hash, node0)
|
|
time.sleep(3)
|
|
assert not self.last_block_equals(stale_hash, node0)
|
|
|
|
# Request for very old stale block header should now fail
|
|
self.send_header_request(stale_hash, node0)
|
|
time.sleep(3)
|
|
assert not self.last_header_equals(stale_hash, node0)
|
|
|
|
# Verify we can fetch very old blocks and headers on the active chain
|
|
block_hash = int(block_hashes[2], 16)
|
|
self.send_block_request(block_hash, node0)
|
|
self.send_header_request(block_hash, node0)
|
|
node0.sync_with_ping()
|
|
|
|
self.send_block_request(block_hash, node0)
|
|
test_function = lambda: self.last_block_equals(block_hash, node0)
|
|
self.wait_until(test_function, timeout=3)
|
|
|
|
self.send_header_request(block_hash, node0)
|
|
test_function = lambda: self.last_header_equals(block_hash, node0)
|
|
self.wait_until(test_function, timeout=3)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
P2PFingerprintTest().main()
|