aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional')
-rwxr-xr-xtest/functional/interface_rest.py4
-rwxr-xr-xtest/functional/mempool_limit.py2
-rwxr-xr-xtest/functional/mempool_packages.py46
-rwxr-xr-xtest/functional/p2p_node_network_limited.py78
-rwxr-xr-xtest/functional/rpc_blockchain.py18
-rwxr-xr-x[-rw-r--r--]test/functional/test_framework/messages.py17
-rw-r--r--test/functional/test_framework/script.py4
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/wallet_dump.py2
-rwxr-xr-xtest/functional/wallet_fallbackfee.py28
10 files changed, 175 insertions, 25 deletions
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index 3e87f6d33f..8440f13a0d 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -296,8 +296,10 @@ class RESTTest (BitcoinTestFramework):
# check that there are our submitted transactions in the TX memory pool
json_string = http_get_call(url.hostname, url.port, '/rest/mempool/contents'+self.FORMAT_SEPARATOR+'json')
json_obj = json.loads(json_string)
- for tx in txs:
+ for i, tx in enumerate(txs):
assert_equal(tx in json_obj, True)
+ assert_equal(json_obj[tx]['spentby'], txs[i+1:i+2])
+ assert_equal(json_obj[tx]['depends'], txs[i-1:i])
# now mine the transactions
newblockhash = self.nodes[1].generate(1)
diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py
index 47f7efd3e7..5382fe439e 100755
--- a/test/functional/mempool_limit.py
+++ b/test/functional/mempool_limit.py
@@ -58,7 +58,7 @@ class MempoolLimitTest(BitcoinTestFramework):
# specifically fund this tx with a fee < mempoolminfee, >= than minrelaytxfee
txF = self.nodes[0].fundrawtransaction(tx, {'feeRate': relayfee})
txFS = self.nodes[0].signrawtransactionwithwallet(txF['hex'])
- assert_raises_rpc_error(-26, "mempool min fee not met, 166 < 411 (code 66)", self.nodes[0].sendrawtransaction, txFS['hex'])
+ assert_raises_rpc_error(-26, "mempool min fee not met", self.nodes[0].sendrawtransaction, txFS['hex'])
if __name__ == '__main__':
MempoolLimitTest().main()
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 23797d83db..8880db8002 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -47,7 +47,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
value = sent_value
chain.append(txid)
- # Check mempool has MAX_ANCESTORS transactions in it, and descendant
+ # Check mempool has MAX_ANCESTORS transactions in it, and descendant and ancestor
# count and fees should look correct
mempool = self.nodes[0].getrawmempool(True)
assert_equal(len(mempool), MAX_ANCESTORS)
@@ -55,6 +55,10 @@ class MempoolPackagesTest(BitcoinTestFramework):
descendant_fees = 0
descendant_size = 0
+ ancestor_size = sum([mempool[tx]['size'] for tx in mempool])
+ ancestor_count = MAX_ANCESTORS
+ ancestor_fees = sum([mempool[tx]['fee'] for tx in mempool])
+
descendants = []
ancestors = list(chain)
for x in reversed(chain):
@@ -71,14 +75,43 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(mempool[x]['descendantsize'], descendant_size)
descendant_count += 1
+ # Check that ancestor calculations are correct
+ assert_equal(mempool[x]['ancestorcount'], ancestor_count)
+ assert_equal(mempool[x]['ancestorfees'], ancestor_fees * COIN)
+ assert_equal(mempool[x]['ancestorsize'], ancestor_size)
+ ancestor_size -= mempool[x]['size']
+ ancestor_fees -= mempool[x]['fee']
+ ancestor_count -= 1
+
+ # Check that parent/child list is correct
+ assert_equal(mempool[x]['spentby'], descendants[-1:])
+ assert_equal(mempool[x]['depends'], ancestors[-2:-1])
+
# Check that getmempooldescendants is correct
assert_equal(sorted(descendants), sorted(self.nodes[0].getmempooldescendants(x)))
+
+ # Check getmempooldescendants verbose output is correct
+ for descendant, dinfo in self.nodes[0].getmempooldescendants(x, True).items():
+ assert_equal(dinfo['depends'], [chain[chain.index(descendant)-1]])
+ if dinfo['descendantcount'] > 1:
+ assert_equal(dinfo['spentby'], [chain[chain.index(descendant)+1]])
+ else:
+ assert_equal(dinfo['spentby'], [])
descendants.append(x)
# Check that getmempoolancestors is correct
ancestors.remove(x)
assert_equal(sorted(ancestors), sorted(self.nodes[0].getmempoolancestors(x)))
+ # Check that getmempoolancestors verbose output is correct
+ for ancestor, ainfo in self.nodes[0].getmempoolancestors(x, True).items():
+ assert_equal(ainfo['spentby'], [chain[chain.index(ancestor)+1]])
+ if ainfo['ancestorcount'] > 1:
+ assert_equal(ainfo['depends'], [chain[chain.index(ancestor)-1]])
+ else:
+ assert_equal(ainfo['depends'], [])
+
+
# Check that getmempoolancestors/getmempooldescendants correctly handle verbose=true
v_ancestors = self.nodes[0].getmempoolancestors(chain[-1], True)
assert_equal(len(v_ancestors), len(chain)-1)
@@ -100,7 +133,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
for x in chain:
ancestor_fees += mempool[x]['fee']
assert_equal(mempool[x]['ancestorfees'], ancestor_fees * COIN + 1000)
-
+
# Undo the prioritisetransaction for later tests
self.nodes[0].prioritisetransaction(txid=chain[0], fee_delta=-1000)
@@ -149,6 +182,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
vout = utxo[1]['vout']
transaction_package = []
+ tx_children = []
# First create one parent tx with 10 children
(txid, sent_value) = self.chain_transaction(self.nodes[0], txid, vout, value, fee, 10)
parent_transaction = txid
@@ -159,11 +193,17 @@ class MempoolPackagesTest(BitcoinTestFramework):
for i in range(MAX_DESCENDANTS - 1):
utxo = transaction_package.pop(0)
(txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
+ if utxo['txid'] is parent_transaction:
+ tx_children.append(txid)
for j in range(10):
transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value})
mempool = self.nodes[0].getrawmempool(True)
assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS)
+ assert_equal(sorted(mempool[parent_transaction]['spentby']), sorted(tx_children))
+
+ for child in tx_children:
+ assert_equal(mempool[child]['depends'], [parent_transaction])
# Sending one more chained transaction will fail
utxo = transaction_package.pop(0)
@@ -232,7 +272,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx)
txid = self.nodes[0].sendrawtransaction(signedtx['hex'])
sync_mempools(self.nodes)
-
+
# Now try to disconnect the tip on each node...
self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py
index 70415e0168..81a41d6a97 100755
--- a/test/functional/p2p_node_network_limited.py
+++ b/test/functional/p2p_node_network_limited.py
@@ -8,16 +8,21 @@ Tests that a node configured with -prune=550 signals NODE_NETWORK_LIMITED correc
and that it responds to getdata requests for blocks correctly:
- send a block within 288 + 2 of the tip
- disconnect peers who request blocks older than that."""
-from test_framework.messages import CInv, msg_getdata
-from test_framework.mininode import NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_WITNESS, NetworkThread, P2PInterface
+from test_framework.messages import CInv, msg_getdata, msg_verack
+from test_framework.mininode import NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_WITNESS, P2PInterface, wait_until, mininode_lock, network_thread_start, network_thread_join
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
+from test_framework.util import assert_equal, disconnect_nodes, connect_nodes_bi, sync_blocks
class P2PIgnoreInv(P2PInterface):
+ firstAddrnServices = 0
def on_inv(self, message):
# The node will send us invs for other blocks. Ignore them.
pass
-
+ def on_addr(self, message):
+ self.firstAddrnServices = message.addrs[0].nServices
+ def wait_for_addr(self, timeout=5):
+ test_function = lambda: self.last_message.get("addr")
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
def send_getdata_for_block(self, blockhash):
getdata_request = msg_getdata()
getdata_request.inv.append(CInv(2, int(blockhash, 16)))
@@ -26,12 +31,24 @@ class P2PIgnoreInv(P2PInterface):
class NodeNetworkLimitedTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
- self.num_nodes = 1
- self.extra_args = [['-prune=550']]
+ self.num_nodes = 3
+ self.extra_args = [['-prune=550', '-addrmantest'], [], []]
+
+ def disconnect_all(self):
+ disconnect_nodes(self.nodes[0], 1)
+ disconnect_nodes(self.nodes[1], 0)
+ disconnect_nodes(self.nodes[2], 1)
+ disconnect_nodes(self.nodes[2], 0)
+ disconnect_nodes(self.nodes[0], 2)
+ disconnect_nodes(self.nodes[1], 2)
+
+ def setup_network(self):
+ super(NodeNetworkLimitedTest, self).setup_network()
+ self.disconnect_all()
def run_test(self):
node = self.nodes[0].add_p2p_connection(P2PIgnoreInv())
- NetworkThread().start()
+ network_thread_start()
node.wait_for_verack()
expected_services = NODE_BLOOM | NODE_WITNESS | NODE_NETWORK_LIMITED
@@ -43,7 +60,9 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
assert_equal(int(self.nodes[0].getnetworkinfo()['localservices'], 16), expected_services)
self.log.info("Mine enough blocks to reach the NODE_NETWORK_LIMITED range.")
- blocks = self.nodes[0].generate(292)
+ connect_nodes_bi(self.nodes, 0, 1)
+ blocks = self.nodes[1].generate(292)
+ sync_blocks([self.nodes[0], self.nodes[1]])
self.log.info("Make sure we can max retrive block at tip-288.")
node.send_getdata_for_block(blocks[1]) # last block in valid range
@@ -53,5 +72,48 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
node.send_getdata_for_block(blocks[0]) # first block outside of the 288+2 limit
node.wait_for_disconnect(5)
+ self.log.info("Check local address relay, do a fresh connection.")
+ self.nodes[0].disconnect_p2ps()
+ network_thread_join()
+ node1 = self.nodes[0].add_p2p_connection(P2PIgnoreInv())
+ network_thread_start()
+ node1.wait_for_verack()
+ node1.send_message(msg_verack())
+
+ node1.wait_for_addr()
+ #must relay address with NODE_NETWORK_LIMITED
+ assert_equal(node1.firstAddrnServices, 1036)
+
+ self.nodes[0].disconnect_p2ps()
+ node1.wait_for_disconnect()
+
+ # connect unsynced node 2 with pruned NODE_NETWORK_LIMITED peer
+ # because node 2 is in IBD and node 0 is a NODE_NETWORK_LIMITED peer, sync must not be possible
+ connect_nodes_bi(self.nodes, 0, 2)
+ try:
+ sync_blocks([self.nodes[0], self.nodes[2]], timeout=5)
+ except:
+ pass
+ # node2 must remain at heigh 0
+ assert_equal(self.nodes[2].getblockheader(self.nodes[2].getbestblockhash())['height'], 0)
+
+ # now connect also to node 1 (non pruned)
+ connect_nodes_bi(self.nodes, 1, 2)
+
+ # sync must be possible
+ sync_blocks(self.nodes)
+
+ # disconnect all peers
+ self.disconnect_all()
+
+ # mine 10 blocks on node 0 (pruned node)
+ self.nodes[0].generate(10)
+
+ # connect node1 (non pruned) with node0 (pruned) and check if the can sync
+ connect_nodes_bi(self.nodes, 0, 1)
+
+ # sync must be possible, node 1 is no longer in IBD and should therefore connect to node 0 (NODE_NETWORK_LIMITED)
+ sync_blocks([self.nodes[0], self.nodes[1]])
+
if __name__ == '__main__':
NodeNetworkLimitedTest().main()
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 7cf2abe6f0..a9e14d3e3c 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -102,6 +102,22 @@ class BlockchainTest(BitcoinTestFramework):
def _test_getchaintxstats(self):
self.log.info("Test getchaintxstats")
+ # Test `getchaintxstats` invalid extra parameters
+ assert_raises_rpc_error(-1, 'getchaintxstats', self.nodes[0].getchaintxstats, 0, '', 0)
+
+ # Test `getchaintxstats` invalid `nblocks`
+ assert_raises_rpc_error(-1, "JSON value is not an integer as expected", self.nodes[0].getchaintxstats, '')
+ assert_raises_rpc_error(-8, "Invalid block count: should be between 0 and the block's height - 1", self.nodes[0].getchaintxstats, -1)
+ assert_raises_rpc_error(-8, "Invalid block count: should be between 0 and the block's height - 1", self.nodes[0].getchaintxstats, self.nodes[0].getblockcount())
+
+ # Test `getchaintxstats` invalid `blockhash`
+ assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].getchaintxstats, blockhash=0)
+ assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getchaintxstats, blockhash='0')
+ blockhash = self.nodes[0].getblockhash(200)
+ self.nodes[0].invalidateblock(blockhash)
+ assert_raises_rpc_error(-8, "Block is not in main chain", self.nodes[0].getchaintxstats, blockhash=blockhash)
+ self.nodes[0].reconsiderblock(blockhash)
+
chaintxstats = self.nodes[0].getchaintxstats(1)
# 200 txs plus genesis tx
assert_equal(chaintxstats['txcount'], 201)
@@ -133,8 +149,6 @@ class BlockchainTest(BitcoinTestFramework):
assert('window_interval' not in chaintxstats)
assert('txrate' not in chaintxstats)
- assert_raises_rpc_error(-8, "Invalid block count: should be between 0 and the block's height - 1", self.nodes[0].getchaintxstats, 201)
-
def _test_gettxoutsetinfo(self):
node = self.nodes[0]
res = node.gettxoutsetinfo()
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 46ef7521e0..e032be1337 100644..100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -186,19 +186,24 @@ def ToHex(obj):
class CAddress():
def __init__(self):
+ self.time = 0
self.nServices = 1
self.pchReserved = b"\x00" * 10 + b"\xff" * 2
self.ip = "0.0.0.0"
self.port = 0
- def deserialize(self, f):
+ def deserialize(self, f, with_time=True):
+ if with_time:
+ self.time = struct.unpack("<i", f.read(4))[0]
self.nServices = struct.unpack("<Q", f.read(8))[0]
self.pchReserved = f.read(12)
self.ip = socket.inet_ntoa(f.read(4))
self.port = struct.unpack(">H", f.read(2))[0]
- def serialize(self):
+ def serialize(self, with_time=True):
r = b""
+ if with_time:
+ r += struct.pack("<i", self.time)
r += struct.pack("<Q", self.nServices)
r += self.pchReserved
r += socket.inet_aton(self.ip)
@@ -856,11 +861,11 @@ class msg_version():
self.nServices = struct.unpack("<Q", f.read(8))[0]
self.nTime = struct.unpack("<q", f.read(8))[0]
self.addrTo = CAddress()
- self.addrTo.deserialize(f)
+ self.addrTo.deserialize(f, False)
if self.nVersion >= 106:
self.addrFrom = CAddress()
- self.addrFrom.deserialize(f)
+ self.addrFrom.deserialize(f, False)
self.nNonce = struct.unpack("<Q", f.read(8))[0]
self.strSubVer = deser_string(f)
else:
@@ -888,8 +893,8 @@ class msg_version():
r += struct.pack("<i", self.nVersion)
r += struct.pack("<Q", self.nServices)
r += struct.pack("<q", self.nTime)
- r += self.addrTo.serialize()
- r += self.addrFrom.serialize()
+ r += self.addrTo.serialize(False)
+ r += self.addrFrom.serialize(False)
r += struct.pack("<Q", self.nNonce)
r += ser_string(self.strSubVer)
r += struct.pack("<i", self.nStartingHeight)
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index dae8a4e569..6fe0b445da 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -526,11 +526,9 @@ class CScript(bytes):
yield CScriptOp(opcode)
def __repr__(self):
- # For Python3 compatibility add b before strings so testcases don't
- # need to change
def _repr(o):
if isinstance(o, bytes):
- return b"x('%s')" % hexlify(o).decode('ascii')
+ return "x('%s')" % hexlify(o).decode('ascii')
else:
return repr(o)
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 945f645eac..082191098e 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -126,6 +126,7 @@ BASE_SCRIPTS= [
'feature_cltv.py',
'rpc_uptime.py',
'wallet_resendwallettransactions.py',
+ 'wallet_fallbackfee.py',
'feature_minchainwork.py',
'p2p_fingerprint.py',
'feature_uacomment.py',
diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py
index 68a203150b..ce861ef012 100755
--- a/test/functional/wallet_dump.py
+++ b/test/functional/wallet_dump.py
@@ -49,7 +49,7 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old):
# count key types
for addrObj in addrs:
if addrObj['address'] == addr.split(",")[0] and addrObj['hdkeypath'] == keypath and keytype == "label=":
- # a labled entry in the wallet should contain both a native address
+ # a labeled entry in the wallet should contain both a native address
# and the p2sh-p2wpkh address that was added at wallet setup
if len(addr.split(",")) == 2:
addr_list = addr.split(",")
diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py
new file mode 100755
index 0000000000..e9cd052344
--- /dev/null
+++ b/test/functional/wallet_fallbackfee.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017 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 wallet replace-by-fee capabilities in conjunction with the fallbackfee."""
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+class WalletRBFTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def run_test(self):
+ self.nodes[0].generate(101)
+
+ # sending a transaction without fee estimations must be possible by default on regtest
+ self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+
+ # test sending a tx with disabled fallback fee (must fail)
+ self.restart_node(0, extra_args=["-fallbackfee=0"])
+ assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1))
+ assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].fundrawtransaction(self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress(): 1})))
+ assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].sendfrom("", self.nodes[0].getnewaddress(), 1))
+ assert_raises_rpc_error(-6, "Fee estimation failed", lambda: self.nodes[0].sendmany("", {self.nodes[0].getnewaddress(): 1}))
+
+if __name__ == '__main__':
+ WalletRBFTest().main()