diff options
author | Alex Morcos <morcos@chaincode.com> | 2016-03-04 16:11:49 -0500 |
---|---|---|
committer | Alex Morcos <morcos@chaincode.com> | 2016-03-21 10:46:25 -0400 |
commit | b536a6fc83ee20cfb80da8bcb5f21c664ec7b5fe (patch) | |
tree | 167b1d80c87cddcefa1f452d99142360fcfeabf7 | |
parent | 5fa66e4682a59047d2ed2934760ccc052fd85f50 (diff) |
Add p2p test for feefilter
-rwxr-xr-x | qa/pull-tester/rpc-tests.py | 3 | ||||
-rwxr-xr-x | qa/rpc-tests/p2p-feefilter.py | 99 | ||||
-rwxr-xr-x | qa/rpc-tests/test_framework/mininode.py | 21 |
3 files changed, 121 insertions, 2 deletions
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index f15eaacbda..74be96da74 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -127,7 +127,6 @@ testScriptsExt = [ 'getblocktemplate_proposals.py', 'txn_doublespend.py', 'txn_clone.py --mineblock', - 'pruning.py', 'forknotify.py', 'invalidateblock.py', # 'rpcbind_test.py', #temporary, bug in libevent, see #6655 @@ -137,6 +136,8 @@ testScriptsExt = [ 'mempool_packages.py', 'maxuploadtarget.py', 'replace-by-fee.py', + 'p2p-feefilter.py', + 'pruning.py', # leave pruning last as it takes a REALLY long time ] #Enable ZMQ tests diff --git a/qa/rpc-tests/p2p-feefilter.py b/qa/rpc-tests/p2p-feefilter.py new file mode 100755 index 0000000000..f85c18dcd5 --- /dev/null +++ b/qa/rpc-tests/p2p-feefilter.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python2 +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# + +from test_framework.mininode import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import time + +''' +FeeFilterTest -- test processing of feefilter messages +''' + +def hashToHex(hash): + return format(hash, '064x').decode('utf-8') + +# Wait up to 60 secs to see if the testnode has received all the expected invs +def allInvsMatch(invsExpected, testnode): + for x in xrange(60): + with mininode_lock: + if (sorted(invsExpected) == sorted(testnode.txinvs)): + return True; + time.sleep(1) + return False; + +# TestNode: bare-bones "peer". Used to track which invs are received from a node +# and to send the node feefilter messages. +class TestNode(SingleNodeConnCB): + def __init__(self): + SingleNodeConnCB.__init__(self) + self.txinvs = [] + + def on_inv(self, conn, message): + for i in message.inv: + if (i.type == 1): + self.txinvs.append(hashToHex(i.hash)) + + def clear_invs(self): + with mininode_lock: + self.txinvs = [] + + def send_filter(self, feerate): + self.send_message(msg_feefilter(feerate)) + self.sync_with_ping() + +class FeeFilterTest(BitcoinTestFramework): + def setup_network(self): + # Node1 will be used to generate txs which should be relayed from Node0 + # to our test node + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros"])) + connect_nodes(self.nodes[0], 1) + + def run_test(self): + node1 = self.nodes[1] + # Get out of IBD + node1.generate(1) + sync_blocks(self.nodes) + + # Setup the p2p connections and start up the network thread. + test_node = TestNode() + connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node) + test_node.add_connection(connection) + NetworkThread().start() + test_node.wait_for_verack() + + # Test that invs are received for all txs at feerate of 20 sat/byte + node1.settxfee(Decimal("0.00020000")) + txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + assert(allInvsMatch(txids, test_node)) + test_node.clear_invs() + + # Set a filter of 15 sat/byte + test_node.send_filter(15000) + + # Test that txs are still being received (paying 20 sat/byte) + txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + assert(allInvsMatch(txids, test_node)) + test_node.clear_invs() + + # Change tx fee rate to 10 sat/byte and test they are no longer received + node1.settxfee(Decimal("0.00010000")) + [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + sync_mempools(self.nodes) # must be sure node 0 has received all txs + time.sleep(10) # wait 10 secs to be sure its doesn't relay any + assert(allInvsMatch([], test_node)) + test_node.clear_invs() + + # Remove fee filter and check that txs are received again + test_node.send_filter(0) + txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)] + assert(allInvsMatch(txids, test_node)) + test_node.clear_invs() + +if __name__ == '__main__': + FeeFilterTest().main() diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index 5b6bb190e4..20386c642c 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -1023,6 +1023,23 @@ def wait_until(predicate, attempts=float('inf'), timeout=float('inf')): return False +class msg_feefilter(object): + command = "feefilter" + + def __init__(self, feerate=0L): + self.feerate = feerate + + def deserialize(self, f): + self.feerate = struct.unpack("<Q", f.read(8))[0] + + def serialize(self): + r = "" + r += struct.pack("<Q", self.feerate) + return r + + def __repr__(self): + return "msg_feefilter(feerate=%08x)" % self.feerate + # This is what a callback should look like for NodeConn # Reimplement the on_* functions to provide handling for events class NodeConnCB(object): @@ -1098,6 +1115,7 @@ class NodeConnCB(object): def on_close(self, conn): pass def on_mempool(self, conn): pass def on_pong(self, conn, message): pass + def on_feefilter(self, conn, message): pass # More useful callbacks and functions for NodeConnCB's which have a single NodeConn class SingleNodeConnCB(NodeConnCB): @@ -1145,7 +1163,8 @@ class NodeConn(asyncore.dispatcher): "headers": msg_headers, "getheaders": msg_getheaders, "reject": msg_reject, - "mempool": msg_mempool + "mempool": msg_mempool, + "feefilter": msg_feefilter } MAGIC_BYTES = { "mainnet": "\xf9\xbe\xb4\xd9", # mainnet |