Changeset View
Changeset View
Standalone View
Standalone View
test/functional/p2p_inv_download.py
Show First 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | NetConstants( | ||||
max_peer_announcements=5000, | max_peer_announcements=5000, | ||||
bypass_request_limits_permission_flags="relay", | bypass_request_limits_permission_flags="relay", | ||||
), | ), | ||||
) | ) | ||||
# Python test constants | # Python test constants | ||||
NUM_INBOUND = 10 | NUM_INBOUND = 10 | ||||
# Common network parameters | |||||
UNCONDITIONAL_RELAY_DELAY = 2 * 60 | |||||
def skip(context): | def skip(context): | ||||
def decorator(test): | def decorator(test): | ||||
@functools.wraps(test) | @functools.wraps(test) | ||||
def wrapper(*args, **kwargs): | def wrapper(*args, **kwargs): | ||||
# Assume the signature is test(self, context) unless context is | # Assume the signature is test(self, context) unless context is | ||||
# passed by name | # passed by name | ||||
call_context = kwargs.get("context", args[1]) | call_context = kwargs.get("context", args[1]) | ||||
Show All 39 Lines | def test_data_requests(self, context): | ||||
for i in outstanding_peer_index: | for i in outstanding_peer_index: | ||||
if getdata_found(i): | if getdata_found(i): | ||||
outstanding_peer_index.remove(i) | outstanding_peer_index.remove(i) | ||||
self.nodes[0].setmocktime(0) | self.nodes[0].setmocktime(0) | ||||
self.log.info("All outstanding peers received a getdata") | self.log.info("All outstanding peers received a getdata") | ||||
@skip(PROOF_TEST_CONTEXT) | @skip(PROOF_TEST_CONTEXT) | ||||
def test_inv_block(self, context): | def test_inv_tx(self, context): | ||||
self.log.info("Generate a transaction on node 0") | self.log.info("Generate a transaction on node 0") | ||||
tx = self.nodes[0].createrawtransaction( | tx = self.nodes[0].createrawtransaction( | ||||
inputs=[{ | inputs=[{ | ||||
# coinbase | # coinbase | ||||
"txid": self.nodes[0].getblock(self.nodes[0].getblockhash(1))['tx'][0], | "txid": self.nodes[0].getblock(self.nodes[0].getblockhash(1))['tx'][0], | ||||
"vout": 0 | "vout": 0 | ||||
}], | }], | ||||
outputs={ADDRESS_ECREG_UNSPENDABLE: 50000000 - 250.00}, | outputs={ADDRESS_ECREG_UNSPENDABLE: 50000000 - 250.00}, | ||||
Show All 9 Lines | def test_inv_tx(self, context): | ||||
"Announce the transaction to all nodes from all {} incoming peers, but never send it".format(NUM_INBOUND)) | "Announce the transaction to all nodes from all {} incoming peers, but never send it".format(NUM_INBOUND)) | ||||
msg = msg_inv([CInv(t=context.inv_type, h=txid)]) | msg = msg_inv([CInv(t=context.inv_type, h=txid)]) | ||||
for p in self.peers: | for p in self.peers: | ||||
p.send_and_ping(msg) | p.send_and_ping(msg) | ||||
self.log.info("Put the tx in node 0's mempool") | self.log.info("Put the tx in node 0's mempool") | ||||
self.nodes[0].sendrawtransaction(tx) | self.nodes[0].sendrawtransaction(tx) | ||||
# node1 is an inbound peer for node0, so the tx relay is delayed by a | |||||
# duration calculated using a poisson's law with a 5s average time. | |||||
# In order to make sure the inv is sent we move the time 2 minutes | |||||
# forward, which has the added side effect that the tx can be | |||||
# unconditionally requested. | |||||
with self.nodes[1].assert_debug_log([f"got inv: tx {txid:064x} new peer=0"]): | |||||
self.nodes[0].setmocktime( | |||||
int(time.time()) + UNCONDITIONAL_RELAY_DELAY) | |||||
# Since node 1 is connected outbound to an honest peer (node 0), it | # Since node 1 is connected outbound to an honest peer (node 0), it | ||||
# should get the tx within a timeout. (Assuming that node 0 | # should get the tx within a timeout. | ||||
# announced the tx within the timeout) | |||||
# The timeout is the sum of | # The timeout is the sum of | ||||
# * the worst case until the tx is first requested from an inbound | # * the worst case until the tx is first requested from an inbound | ||||
# peer, plus | # peer, plus | ||||
# * the first time it is re-requested from the outbound peer, plus | # * the first time it is re-requested from the outbound peer, plus | ||||
# * 2 seconds to avoid races | # * 2 seconds to avoid races | ||||
assert self.nodes[1].getpeerinfo()[0]['inbound'] is False | assert self.nodes[1].getpeerinfo()[0]['inbound'] is False | ||||
timeout = 2 + context.constants.inbound_peer_delay + \ | max_delay = context.constants.inbound_peer_delay + \ | ||||
context.constants.getdata_interval | context.constants.getdata_interval | ||||
margin = 2 | |||||
self.log.info( | self.log.info( | ||||
"Tx should be received at node 1 after {} seconds".format(timeout)) | "Tx should be received at node 1 after {} seconds".format(max_delay + margin)) | ||||
self.sync_mempools(timeout=timeout) | self.nodes[1].setmocktime(int(time.time()) + max_delay) | ||||
self.sync_mempools(timeout=margin) | |||||
def test_in_flight_max(self, context): | def test_in_flight_max(self, context): | ||||
max_getdata_in_flight = context.constants.max_getdata_in_flight | max_getdata_in_flight = context.constants.max_getdata_in_flight | ||||
max_inbound_delay = context.constants.inbound_peer_delay + \ | max_inbound_delay = context.constants.inbound_peer_delay + \ | ||||
context.constants.overloaded_peer_delay | context.constants.overloaded_peer_delay | ||||
self.log.info("Test that we don't load peers with more than {} getdata requests immediately".format( | self.log.info("Test that we don't load peers with more than {} getdata requests immediately".format( | ||||
max_getdata_in_flight)) | max_getdata_in_flight)) | ||||
▲ Show 20 Lines • Show All 241 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
self.test_disconnect_fallback(context) | self.test_disconnect_fallback(context) | ||||
self.test_notfound_fallback(context) | self.test_notfound_fallback(context) | ||||
self.test_preferred_inv(context) | self.test_preferred_inv(context) | ||||
self.test_large_inv_batch(context) | self.test_large_inv_batch(context) | ||||
self.test_spurious_notfound(context) | self.test_spurious_notfound(context) | ||||
# Run each test against new bitcoind instances, as setting mocktimes has long-term effects on when | # Run each test against new bitcoind instances, as setting mocktimes has long-term effects on when | ||||
# the next trickle relay event happens. | # the next trickle relay event happens. | ||||
for test in [self.test_in_flight_max, self.test_inv_block, | for test in [self.test_in_flight_max, self.test_inv_tx, | ||||
self.test_data_requests, self.test_orphan_download, self.test_request_invalid_once]: | self.test_data_requests, self.test_orphan_download, self.test_request_invalid_once]: | ||||
self.stop_nodes() | self.stop_nodes() | ||||
self.start_nodes() | self.start_nodes() | ||||
self.connect_nodes(1, 0) | self.connect_nodes(1, 0) | ||||
# Setup the p2p connections | # Setup the p2p connections | ||||
self.peers = [] | self.peers = [] | ||||
for node in self.nodes: | for node in self.nodes: | ||||
for _ in range(NUM_INBOUND): | for _ in range(NUM_INBOUND): | ||||
Show All 10 Lines |