Skip to content

Commit b536a6f

Browse files
committed
Add p2p test for feefilter
1 parent 5fa66e4 commit b536a6f

File tree

3 files changed

+121
-2
lines changed

3 files changed

+121
-2
lines changed

qa/pull-tester/rpc-tests.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@
127127
'getblocktemplate_proposals.py',
128128
'txn_doublespend.py',
129129
'txn_clone.py --mineblock',
130-
'pruning.py',
131130
'forknotify.py',
132131
'invalidateblock.py',
133132
# 'rpcbind_test.py', #temporary, bug in libevent, see #6655
@@ -137,6 +136,8 @@
137136
'mempool_packages.py',
138137
'maxuploadtarget.py',
139138
'replace-by-fee.py',
139+
'p2p-feefilter.py',
140+
'pruning.py', # leave pruning last as it takes a REALLY long time
140141
]
141142

142143
#Enable ZMQ tests

qa/rpc-tests/p2p-feefilter.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/usr/bin/env python2
2+
# Copyright (c) 2016 The Bitcoin Core developers
3+
# Distributed under the MIT/X11 software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
#
6+
7+
from test_framework.mininode import *
8+
from test_framework.test_framework import BitcoinTestFramework
9+
from test_framework.util import *
10+
import time
11+
12+
'''
13+
FeeFilterTest -- test processing of feefilter messages
14+
'''
15+
16+
def hashToHex(hash):
17+
return format(hash, '064x').decode('utf-8')
18+
19+
# Wait up to 60 secs to see if the testnode has received all the expected invs
20+
def allInvsMatch(invsExpected, testnode):
21+
for x in xrange(60):
22+
with mininode_lock:
23+
if (sorted(invsExpected) == sorted(testnode.txinvs)):
24+
return True;
25+
time.sleep(1)
26+
return False;
27+
28+
# TestNode: bare-bones "peer". Used to track which invs are received from a node
29+
# and to send the node feefilter messages.
30+
class TestNode(SingleNodeConnCB):
31+
def __init__(self):
32+
SingleNodeConnCB.__init__(self)
33+
self.txinvs = []
34+
35+
def on_inv(self, conn, message):
36+
for i in message.inv:
37+
if (i.type == 1):
38+
self.txinvs.append(hashToHex(i.hash))
39+
40+
def clear_invs(self):
41+
with mininode_lock:
42+
self.txinvs = []
43+
44+
def send_filter(self, feerate):
45+
self.send_message(msg_feefilter(feerate))
46+
self.sync_with_ping()
47+
48+
class FeeFilterTest(BitcoinTestFramework):
49+
def setup_network(self):
50+
# Node1 will be used to generate txs which should be relayed from Node0
51+
# to our test node
52+
self.nodes = []
53+
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros"]))
54+
self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros"]))
55+
connect_nodes(self.nodes[0], 1)
56+
57+
def run_test(self):
58+
node1 = self.nodes[1]
59+
# Get out of IBD
60+
node1.generate(1)
61+
sync_blocks(self.nodes)
62+
63+
# Setup the p2p connections and start up the network thread.
64+
test_node = TestNode()
65+
connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)
66+
test_node.add_connection(connection)
67+
NetworkThread().start()
68+
test_node.wait_for_verack()
69+
70+
# Test that invs are received for all txs at feerate of 20 sat/byte
71+
node1.settxfee(Decimal("0.00020000"))
72+
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
73+
assert(allInvsMatch(txids, test_node))
74+
test_node.clear_invs()
75+
76+
# Set a filter of 15 sat/byte
77+
test_node.send_filter(15000)
78+
79+
# Test that txs are still being received (paying 20 sat/byte)
80+
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
81+
assert(allInvsMatch(txids, test_node))
82+
test_node.clear_invs()
83+
84+
# Change tx fee rate to 10 sat/byte and test they are no longer received
85+
node1.settxfee(Decimal("0.00010000"))
86+
[node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
87+
sync_mempools(self.nodes) # must be sure node 0 has received all txs
88+
time.sleep(10) # wait 10 secs to be sure its doesn't relay any
89+
assert(allInvsMatch([], test_node))
90+
test_node.clear_invs()
91+
92+
# Remove fee filter and check that txs are received again
93+
test_node.send_filter(0)
94+
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
95+
assert(allInvsMatch(txids, test_node))
96+
test_node.clear_invs()
97+
98+
if __name__ == '__main__':
99+
FeeFilterTest().main()

qa/rpc-tests/test_framework/mininode.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,23 @@ def wait_until(predicate, attempts=float('inf'), timeout=float('inf')):
10231023

10241024
return False
10251025

1026+
class msg_feefilter(object):
1027+
command = "feefilter"
1028+
1029+
def __init__(self, feerate=0L):
1030+
self.feerate = feerate
1031+
1032+
def deserialize(self, f):
1033+
self.feerate = struct.unpack("<Q", f.read(8))[0]
1034+
1035+
def serialize(self):
1036+
r = ""
1037+
r += struct.pack("<Q", self.feerate)
1038+
return r
1039+
1040+
def __repr__(self):
1041+
return "msg_feefilter(feerate=%08x)" % self.feerate
1042+
10261043
# This is what a callback should look like for NodeConn
10271044
# Reimplement the on_* functions to provide handling for events
10281045
class NodeConnCB(object):
@@ -1098,6 +1115,7 @@ def on_reject(self, conn, message): pass
10981115
def on_close(self, conn): pass
10991116
def on_mempool(self, conn): pass
11001117
def on_pong(self, conn, message): pass
1118+
def on_feefilter(self, conn, message): pass
11011119

11021120
# More useful callbacks and functions for NodeConnCB's which have a single NodeConn
11031121
class SingleNodeConnCB(NodeConnCB):
@@ -1145,7 +1163,8 @@ class NodeConn(asyncore.dispatcher):
11451163
"headers": msg_headers,
11461164
"getheaders": msg_getheaders,
11471165
"reject": msg_reject,
1148-
"mempool": msg_mempool
1166+
"mempool": msg_mempool,
1167+
"feefilter": msg_feefilter
11491168
}
11501169
MAGIC_BYTES = {
11511170
"mainnet": "\xf9\xbe\xb4\xd9", # mainnet

0 commit comments

Comments
 (0)