mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-10 03:47:29 -03:00
b24f6c6855
If no `from_node` parameter is passed explicitely to the `create_self_transfer` method, the test node passed in the course of creating the MiniWallet instance is used. This seems to be the main use-case in most of the current functional tests, i.e. in many instances the calls can be shortened.
119 lines
5.9 KiB
Python
Executable file
119 lines
5.9 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# Copyright (c) 2019-2021 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 p2p blocksonly mode & block-relay-only connections."""
|
|
|
|
import time
|
|
|
|
from test_framework.messages import msg_tx, msg_inv, CInv, MSG_WTX
|
|
from test_framework.p2p import P2PInterface, P2PTxInvStore
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
from test_framework.util import assert_equal
|
|
from test_framework.wallet import MiniWallet
|
|
|
|
|
|
class P2PBlocksOnly(BitcoinTestFramework):
|
|
def set_test_params(self):
|
|
self.num_nodes = 1
|
|
self.extra_args = [["-blocksonly"]]
|
|
|
|
def run_test(self):
|
|
self.miniwallet = MiniWallet(self.nodes[0])
|
|
# Add enough mature utxos to the wallet, so that all txs spend confirmed coins
|
|
self.miniwallet.rescan_utxos()
|
|
|
|
self.blocksonly_mode_tests()
|
|
self.blocks_relay_conn_tests()
|
|
|
|
def blocksonly_mode_tests(self):
|
|
self.log.info("Tests with node running in -blocksonly mode")
|
|
assert_equal(self.nodes[0].getnetworkinfo()['localrelay'], False)
|
|
|
|
self.nodes[0].add_p2p_connection(P2PInterface())
|
|
tx, txid, wtxid, tx_hex = self.check_p2p_tx_violation()
|
|
|
|
self.log.info('Check that tx invs also violate the protocol')
|
|
self.nodes[0].add_p2p_connection(P2PInterface())
|
|
with self.nodes[0].assert_debug_log(['transaction (0000000000000000000000000000000000000000000000000000000000001234) inv sent in violation of protocol, disconnecting peer']):
|
|
self.nodes[0].p2ps[0].send_message(msg_inv([CInv(t=MSG_WTX, h=0x1234)]))
|
|
self.nodes[0].p2ps[0].wait_for_disconnect()
|
|
del self.nodes[0].p2ps[0]
|
|
|
|
self.log.info('Check that txs from rpc are not rejected and relayed to other peers')
|
|
tx_relay_peer = self.nodes[0].add_p2p_connection(P2PInterface())
|
|
assert_equal(self.nodes[0].getpeerinfo()[0]['relaytxes'], True)
|
|
|
|
assert_equal(self.nodes[0].testmempoolaccept([tx_hex])[0]['allowed'], True)
|
|
with self.nodes[0].assert_debug_log(['received getdata for: wtx {} peer'.format(wtxid)]):
|
|
self.nodes[0].sendrawtransaction(tx_hex)
|
|
tx_relay_peer.wait_for_tx(txid)
|
|
assert_equal(self.nodes[0].getmempoolinfo()['size'], 1)
|
|
|
|
self.log.info("Restarting node 0 with relay permission and blocksonly")
|
|
self.restart_node(0, ["-persistmempool=0", "-whitelist=relay@127.0.0.1", "-blocksonly"])
|
|
assert_equal(self.nodes[0].getrawmempool(), [])
|
|
first_peer = self.nodes[0].add_p2p_connection(P2PInterface())
|
|
second_peer = self.nodes[0].add_p2p_connection(P2PInterface())
|
|
peer_1_info = self.nodes[0].getpeerinfo()[0]
|
|
assert_equal(peer_1_info['permissions'], ['relay'])
|
|
peer_2_info = self.nodes[0].getpeerinfo()[1]
|
|
assert_equal(peer_2_info['permissions'], ['relay'])
|
|
assert_equal(self.nodes[0].testmempoolaccept([tx_hex])[0]['allowed'], True)
|
|
|
|
self.log.info('Check that the tx from first_peer with relay-permission is relayed to others (ie.second_peer)')
|
|
with self.nodes[0].assert_debug_log(["received getdata"]):
|
|
# Note that normally, first_peer would never send us transactions since we're a blocksonly node.
|
|
# By activating blocksonly, we explicitly tell our peers that they should not send us transactions,
|
|
# and Bitcoin Core respects that choice and will not send transactions.
|
|
# But if, for some reason, first_peer decides to relay transactions to us anyway, we should relay them to
|
|
# second_peer since we gave relay permission to first_peer.
|
|
# See https://github.com/bitcoin/bitcoin/issues/19943 for details.
|
|
first_peer.send_message(msg_tx(tx))
|
|
self.log.info('Check that the peer with relay-permission is still connected after sending the transaction')
|
|
assert_equal(first_peer.is_connected, True)
|
|
second_peer.wait_for_tx(txid)
|
|
assert_equal(self.nodes[0].getmempoolinfo()['size'], 1)
|
|
self.log.info("Relay-permission peer's transaction is accepted and relayed")
|
|
|
|
self.nodes[0].disconnect_p2ps()
|
|
self.generate(self.nodes[0], 1)
|
|
|
|
def blocks_relay_conn_tests(self):
|
|
self.log.info('Tests with node in normal mode with block-relay-only connections')
|
|
self.restart_node(0, ["-noblocksonly"]) # disables blocks only mode
|
|
assert_equal(self.nodes[0].getnetworkinfo()['localrelay'], True)
|
|
|
|
# Ensure we disconnect if a block-relay-only connection sends us a transaction
|
|
self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=0, connection_type="block-relay-only")
|
|
assert_equal(self.nodes[0].getpeerinfo()[0]['relaytxes'], False)
|
|
_, txid, _, tx_hex = self.check_p2p_tx_violation()
|
|
|
|
self.log.info("Check that txs from RPC are not sent to blockrelay connection")
|
|
conn = self.nodes[0].add_outbound_p2p_connection(P2PTxInvStore(), p2p_idx=1, connection_type="block-relay-only")
|
|
|
|
self.nodes[0].sendrawtransaction(tx_hex)
|
|
|
|
# Bump time forward to ensure nNextInvSend timer pops
|
|
self.nodes[0].setmocktime(int(time.time()) + 60)
|
|
|
|
conn.sync_send_with_ping()
|
|
assert(int(txid, 16) not in conn.get_invs())
|
|
|
|
def check_p2p_tx_violation(self):
|
|
self.log.info('Check that txs from P2P are rejected and result in disconnect')
|
|
spendtx = self.miniwallet.create_self_transfer()
|
|
|
|
with self.nodes[0].assert_debug_log(['transaction sent in violation of protocol peer=0']):
|
|
self.nodes[0].p2ps[0].send_message(msg_tx(spendtx['tx']))
|
|
self.nodes[0].p2ps[0].wait_for_disconnect()
|
|
assert_equal(self.nodes[0].getmempoolinfo()['size'], 0)
|
|
|
|
# Remove the disconnected peer
|
|
del self.nodes[0].p2ps[0]
|
|
|
|
return spendtx['tx'], spendtx['txid'], spendtx['wtxid'], spendtx['hex']
|
|
|
|
|
|
if __name__ == '__main__':
|
|
P2PBlocksOnly().main()
|