Changeset View
Changeset View
Standalone View
Standalone View
test/functional/p2p_feefilter.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2016-2019 The Bitcoin Core developers | # Copyright (c) 2016-2019 The Bitcoin Core developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
"""Test processing of feefilter messages.""" | """Test processing of feefilter messages.""" | ||||
from decimal import Decimal | from decimal import Decimal | ||||
from test_framework.messages import MSG_TX, msg_feefilter | from test_framework.messages import MSG_TX, msg_feefilter | ||||
from test_framework.p2p import P2PInterface, p2p_lock | from test_framework.p2p import P2PInterface, p2p_lock | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import assert_equal | from test_framework.util import assert_equal | ||||
from test_framework.wallet import MiniWallet | |||||
def hashToHex(hash): | |||||
return format(hash, '064x') | |||||
class FeefilterConn(P2PInterface): | class FeefilterConn(P2PInterface): | ||||
feefilter_received = False | feefilter_received = False | ||||
def on_feefilter(self, message): | def on_feefilter(self, message): | ||||
self.feefilter_received = True | self.feefilter_received = True | ||||
def assert_feefilter_received(self, recv: bool): | def assert_feefilter_received(self, recv: bool): | ||||
with p2p_lock: | with p2p_lock: | ||||
assert_equal(self.feefilter_received, recv) | assert_equal(self.feefilter_received, recv) | ||||
class TestP2PConn(P2PInterface): | class TestP2PConn(P2PInterface): | ||||
def __init__(self): | def __init__(self): | ||||
super().__init__() | super().__init__() | ||||
self.txinvs = [] | self.txinvs = [] | ||||
def on_inv(self, message): | def on_inv(self, message): | ||||
for i in message.inv: | for i in message.inv: | ||||
if (i.type == MSG_TX): | if (i.type == MSG_TX): | ||||
self.txinvs.append(hashToHex(i.hash)) | self.txinvs.append('{:064x}'.format(i.hash)) | ||||
def wait_for_invs_to_match(self, invs_expected): | def wait_for_invs_to_match(self, invs_expected): | ||||
invs_expected.sort() | invs_expected.sort() | ||||
self.wait_until(lambda: invs_expected == sorted(self.txinvs)) | self.wait_until(lambda: invs_expected == sorted(self.txinvs)) | ||||
def clear_invs(self): | def clear_invs(self): | ||||
with p2p_lock: | with p2p_lock: | ||||
self.txinvs = [] | self.txinvs = [] | ||||
Show All 10 Lines | def set_test_params(self): | ||||
# grant noban permission to all peers to speed up tx relay / mempool | # grant noban permission to all peers to speed up tx relay / mempool | ||||
# sync | # sync | ||||
self.extra_args = [[ | self.extra_args = [[ | ||||
"-minrelaytxfee=1", | "-minrelaytxfee=1", | ||||
"-mintxfee=1", | "-mintxfee=1", | ||||
"-whitelist=noban@127.0.0.1", | "-whitelist=noban@127.0.0.1", | ||||
]] * self.num_nodes | ]] * self.num_nodes | ||||
def skip_test_if_missing_module(self): | |||||
self.skip_if_no_wallet() | |||||
def run_test(self): | def run_test(self): | ||||
self.test_feefilter_forcerelay() | self.test_feefilter_forcerelay() | ||||
self.test_feefilter() | self.test_feefilter() | ||||
def test_feefilter_forcerelay(self): | def test_feefilter_forcerelay(self): | ||||
self.log.info( | self.log.info( | ||||
'Check that peers without forcerelay permission (default) get a feefilter message') | 'Check that peers without forcerelay permission (default) get a feefilter message') | ||||
self.nodes[0].add_p2p_connection( | self.nodes[0].add_p2p_connection( | ||||
FeefilterConn()).assert_feefilter_received(True) | FeefilterConn()).assert_feefilter_received(True) | ||||
self.log.info( | self.log.info( | ||||
'Check that peers with forcerelay permission do not get a feefilter message') | 'Check that peers with forcerelay permission do not get a feefilter message') | ||||
self.restart_node(0, extra_args=['-whitelist=forcerelay@127.0.0.1']) | self.restart_node(0, extra_args=['-whitelist=forcerelay@127.0.0.1']) | ||||
self.nodes[0].add_p2p_connection( | self.nodes[0].add_p2p_connection( | ||||
FeefilterConn()).assert_feefilter_received(False) | FeefilterConn()).assert_feefilter_received(False) | ||||
# Restart to disconnect peers and load default extra_args | # Restart to disconnect peers and load default extra_args | ||||
self.restart_node(0) | self.restart_node(0) | ||||
self.connect_nodes(1, 0) | self.connect_nodes(1, 0) | ||||
def test_feefilter(self): | def test_feefilter(self): | ||||
node1 = self.nodes[1] | node1 = self.nodes[1] | ||||
node0 = self.nodes[0] | node0 = self.nodes[0] | ||||
miniwallet = MiniWallet(node1) | |||||
# Add enough mature utxos to the wallet, so that all txs spend | |||||
# confirmed coins | |||||
miniwallet.generate(5) | |||||
node1.generate(100) | |||||
conn = self.nodes[0].add_p2p_connection(TestP2PConn()) | conn = self.nodes[0].add_p2p_connection(TestP2PConn()) | ||||
self.log.info( | self.log.info( | ||||
"Test txs paying 0.2 sat/byte are received by test connection") | "Test txs paying 0.2 sat/byte are received by test connection") | ||||
node1.settxfee(Decimal("2")) | txids = [miniwallet.send_self_transfer(fee_rate=Decimal('2.00'), | ||||
txids = [node1.sendtoaddress(node1.getnewaddress(), 1000000) | from_node=node1)['txid'] | ||||
for _ in range(3)] | for _ in range(3)] | ||||
conn.wait_for_invs_to_match(txids) | conn.wait_for_invs_to_match(txids) | ||||
conn.clear_invs() | conn.clear_invs() | ||||
# Set a fee filter of 0.15 sat/byte on test connection | # Set a fee filter of 0.15 sat/byte on test connection | ||||
conn.send_and_ping(msg_feefilter(150)) | conn.send_and_ping(msg_feefilter(150)) | ||||
self.log.info( | self.log.info( | ||||
"Test txs paying 0.15 sat/byte are received by test connection") | "Test txs paying 0.15 sat/byte are received by test connection") | ||||
node1.settxfee(Decimal("1.5")) | txids = [miniwallet.send_self_transfer(fee_rate=Decimal('1.50'), | ||||
txids = [node1.sendtoaddress(node1.getnewaddress(), 1000000) | from_node=node1)['txid'] | ||||
for _ in range(3)] | for _ in range(3)] | ||||
conn.wait_for_invs_to_match(txids) | conn.wait_for_invs_to_match(txids) | ||||
conn.clear_invs() | conn.clear_invs() | ||||
self.log.info( | self.log.info( | ||||
"Test txs paying 0.1 sat/byte are no longer received by test connection") | "Test txs paying 0.1 sat/byte are no longer received by test connection") | ||||
node1.settxfee(Decimal("1")) | txids = [miniwallet.send_self_transfer(fee_rate=Decimal('1.00'), | ||||
[node1.sendtoaddress(node1.getnewaddress(), 1000000) for _ in range(3)] | from_node=node1)['txid'] | ||||
for _ in range(3)] | |||||
self.sync_mempools() # must be sure node 0 has received all txs | self.sync_mempools() # must be sure node 0 has received all txs | ||||
# Send one transaction from node0 that should be received, so that we | # Send one transaction from node0 that should be received, so that we | ||||
# we can sync the test on receipt (if node1's txs were relayed, they'd | # we can sync the test on receipt (if node1's txs were relayed, they'd | ||||
# be received by the time this node0 tx is received). This is | # be received by the time this node0 tx is received). This is | ||||
# unfortunately reliant on the current relay behavior where we batch up | # unfortunately reliant on the current relay behavior where we batch up | ||||
# to 35 entries in an inv, which means that when this next transaction | # to 35 entries in an inv, which means that when this next transaction | ||||
# is eligible for relay, the prior transactions from node1 are eligible | # is eligible for relay, the prior transactions from node1 are eligible | ||||
# as well. | # as well. | ||||
node0.settxfee(Decimal("200.00")) | txids = [miniwallet.send_self_transfer(fee_rate=Decimal('200.00'), | ||||
txids = [node0.sendtoaddress(node0.getnewaddress(), 1000000)] | from_node=node0)['txid'] | ||||
for _ in range(3)] | |||||
conn.wait_for_invs_to_match(txids) | conn.wait_for_invs_to_match(txids) | ||||
conn.clear_invs() | conn.clear_invs() | ||||
self.log.info("Remove fee filter and check txs are received again") | self.log.info("Remove fee filter and check txs are received again") | ||||
conn.send_and_ping(msg_feefilter(0)) | conn.send_and_ping(msg_feefilter(0)) | ||||
txids = [node1.sendtoaddress(node1.getnewaddress(), 1000000) | txids = [miniwallet.send_self_transfer(fee_rate=Decimal('200.00'), | ||||
from_node=node1)['txid'] | |||||
for _ in range(3)] | for _ in range(3)] | ||||
conn.wait_for_invs_to_match(txids) | conn.wait_for_invs_to_match(txids) | ||||
conn.clear_invs() | conn.clear_invs() | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
FeeFilterTest().main() | FeeFilterTest().main() |