aboutsummaryrefslogtreecommitdiff
path: root/qa
diff options
context:
space:
mode:
Diffstat (limited to 'qa')
-rwxr-xr-xqa/rpc-tests/fundrawtransaction.py59
-rwxr-xr-xqa/rpc-tests/keypool.py15
-rwxr-xr-xqa/rpc-tests/listtransactions.py10
-rwxr-xr-xqa/rpc-tests/rest.py13
-rwxr-xr-xqa/rpc-tests/test_framework/comptool.py94
5 files changed, 141 insertions, 50 deletions
diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py
index ce52247b2e..fc29789218 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/qa/rpc-tests/fundrawtransaction.py
@@ -13,14 +13,15 @@ class RawTransactionsTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 3)
+ initialize_chain_clean(self.options.tmpdir, 4)
def setup_network(self, split=False):
- self.nodes = start_nodes(3, self.options.tmpdir)
+ self.nodes = start_nodes(4, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
+ connect_nodes_bi(self.nodes,0,3)
self.is_network_split=False
self.sync_all()
@@ -31,11 +32,20 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[2].generate(1)
self.sync_all()
- self.nodes[0].generate(101)
+ self.nodes[0].generate(121)
self.sync_all()
+
+ watchonly_address = self.nodes[0].getnewaddress()
+ watchonly_pubkey = self.nodes[0].validateaddress(watchonly_address)["pubkey"]
+ watchonly_amount = 200
+ self.nodes[3].importpubkey(watchonly_pubkey, "", True)
+ watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, watchonly_amount)
+ self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), watchonly_amount / 10);
+
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5);
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0);
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0);
+
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
@@ -428,11 +438,12 @@ class RawTransactionsTest(BitcoinTestFramework):
stop_nodes(self.nodes)
wait_bitcoinds()
- self.nodes = start_nodes(3, self.options.tmpdir)
+ self.nodes = start_nodes(4, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
+ connect_nodes_bi(self.nodes,0,3)
self.is_network_split=False
self.sync_all()
@@ -541,5 +552,45 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(len(dec_tx['vout']), 2) # one change output added
+ ##################################################
+ # test a fundrawtransaction using only watchonly #
+ ##################################################
+
+ inputs = []
+ outputs = {self.nodes[2].getnewaddress() : watchonly_amount / 2}
+ rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
+
+ result = self.nodes[3].fundrawtransaction(rawtx, True)
+ res_dec = self.nodes[0].decoderawtransaction(result["hex"])
+ assert_equal(len(res_dec["vin"]), 1)
+ assert_equal(res_dec["vin"][0]["txid"], watchonly_txid)
+
+ assert_equal("fee" in result.keys(), True)
+ assert_greater_than(result["changepos"], -1)
+
+ ###############################################################
+ # test fundrawtransaction using the entirety of watched funds #
+ ###############################################################
+
+ inputs = []
+ outputs = {self.nodes[2].getnewaddress() : watchonly_amount}
+ rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
+
+ result = self.nodes[3].fundrawtransaction(rawtx, True)
+ res_dec = self.nodes[0].decoderawtransaction(result["hex"])
+ assert_equal(len(res_dec["vin"]), 2)
+ assert(res_dec["vin"][0]["txid"] == watchonly_txid or res_dec["vin"][1]["txid"] == watchonly_txid)
+
+ assert_greater_than(result["fee"], 0)
+ assert_greater_than(result["changepos"], -1)
+ assert_equal(result["fee"] + res_dec["vout"][result["changepos"]]["value"], watchonly_amount / 10)
+
+ signedtx = self.nodes[3].signrawtransaction(result["hex"])
+ assert(not signedtx["complete"])
+ signedtx = self.nodes[0].signrawtransaction(signedtx["hex"])
+ assert(signedtx["complete"])
+ self.nodes[0].sendrawtransaction(signedtx["hex"])
+
+
if __name__ == '__main__':
RawTransactionsTest().main()
diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py
index aee29a596a..5a67220021 100755
--- a/qa/rpc-tests/keypool.py
+++ b/qa/rpc-tests/keypool.py
@@ -73,6 +73,21 @@ def run_test(nodes, tmpdir):
except JSONRPCException,e:
assert(e.error['code']==-12)
+ # refill keypool with three new addresses
+ nodes[0].walletpassphrase('test', 12000)
+ nodes[0].keypoolrefill(3)
+ nodes[0].walletlock()
+
+ # drain them by mining
+ nodes[0].generate(1)
+ nodes[0].generate(1)
+ nodes[0].generate(1)
+ nodes[0].generate(1)
+ try:
+ nodes[0].generate(1)
+ raise AssertionError('Keypool should be exhausted after three addesses')
+ except JSONRPCException,e:
+ assert(e.error['code']==-12)
def main():
import optparse
diff --git a/qa/rpc-tests/listtransactions.py b/qa/rpc-tests/listtransactions.py
index eeae2d2fa2..b30a6bc9d1 100755
--- a/qa/rpc-tests/listtransactions.py
+++ b/qa/rpc-tests/listtransactions.py
@@ -93,6 +93,16 @@ class ListTransactionsTest(BitcoinTestFramework):
{"category":"receive","amount":Decimal("0.44")},
{"txid":txid, "account" : "toself"} )
+ multisig = self.nodes[1].createmultisig(1, [self.nodes[1].getnewaddress()])
+ self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True)
+ txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1)
+ self.nodes[1].generate(1)
+ self.sync_all()
+ assert(len(self.nodes[0].listtransactions("watchonly", 100, 0, False)) == 0)
+ check_array_result(self.nodes[0].listtransactions("watchonly", 100, 0, True),
+ {"category":"receive","amount":Decimal("0.1")},
+ {"txid":txid, "account" : "watchonly"} )
+
if __name__ == '__main__':
ListTransactionsTest().main()
diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py
index eca655a595..3a035f996c 100755
--- a/qa/rpc-tests/rest.py
+++ b/qa/rpc-tests/rest.py
@@ -292,6 +292,19 @@ class RESTTest (BitcoinTestFramework):
txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11))
self.sync_all()
+ # check that there are exactly 3 transactions in the TX memory pool before generating the block
+ json_string = http_get_call(url.hostname, url.port, '/rest/mempool/info'+self.FORMAT_SEPARATOR+'json')
+ json_obj = json.loads(json_string)
+ assert_equal(json_obj['size'], 3)
+ # the size of the memory pool should be greater than 3x ~100 bytes
+ assert_greater_than(json_obj['bytes'], 300)
+
+ # 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:
+ assert_equal(tx in json_obj, True)
+
# now mine the transactions
newblockhash = self.nodes[1].generate(1)
self.sync_all()
diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py
index f4808df08f..b945f1bf29 100755
--- a/qa/rpc-tests/test_framework/comptool.py
+++ b/qa/rpc-tests/test_framework/comptool.py
@@ -27,6 +27,20 @@ generator that returns TestInstance objects. See below for definition.
global mininode_lock
+def wait_until(predicate, attempts=float('inf'), timeout=float('inf')):
+ attempt = 0
+ elapsed = 0
+
+ while attempt < attempts and elapsed < timeout:
+ with mininode_lock:
+ if predicate():
+ return True
+ attempt += 1
+ elapsed += 0.05
+ time.sleep(0.05)
+
+ return False
+
class TestNode(NodeConnCB):
def __init__(self, block_store, tx_store):
@@ -43,6 +57,10 @@ class TestNode(NodeConnCB):
# a response
self.pingMap = {}
self.lastInv = []
+ self.closed = False
+
+ def on_close(self, conn):
+ self.closed = True
def add_connection(self, conn):
self.conn = conn
@@ -132,6 +150,7 @@ class TestManager(object):
def __init__(self, testgen, datadir):
self.test_generator = testgen
self.connections = []
+ self.test_nodes = []
self.block_store = BlockStore(datadir)
self.tx_store = TxStore(datadir)
self.ping_counter = 1
@@ -139,54 +158,40 @@ class TestManager(object):
def add_all_connections(self, nodes):
for i in range(len(nodes)):
# Create a p2p connection to each node
- self.connections.append(NodeConn('127.0.0.1', p2p_port(i),
- nodes[i], TestNode(self.block_store, self.tx_store)))
+ test_node = TestNode(self.block_store, self.tx_store)
+ self.test_nodes.append(test_node)
+ self.connections.append(NodeConn('127.0.0.1', p2p_port(i), nodes[i], test_node))
# Make sure the TestNode (callback class) has a reference to its
# associated NodeConn
- self.connections[-1].cb.add_connection(self.connections[-1])
+ test_node.add_connection(self.connections[-1])
+
+ def wait_for_disconnections(self):
+ def disconnected():
+ return all(node.closed for node in self.test_nodes)
+ return wait_until(disconnected, timeout=10)
def wait_for_verack(self):
- sleep_time = 0.05
- max_tries = 10 / sleep_time # Wait at most 10 seconds
- while max_tries > 0:
- done = True
- with mininode_lock:
- for c in self.connections:
- if c.cb.verack_received is False:
- done = False
- break
- if done:
- break
- time.sleep(sleep_time)
+ def veracked():
+ return all(node.verack_received for node in self.test_nodes)
+ return wait_until(veracked, timeout=10)
def wait_for_pings(self, counter):
- received_pongs = False
- while received_pongs is not True:
- time.sleep(0.05)
- received_pongs = True
- with mininode_lock:
- for c in self.connections:
- if c.cb.received_ping_response(counter) is not True:
- received_pongs = False
- break
+ def received_pongs():
+ return all(node.received_ping_response(counter) for node in self.test_nodes)
+ return wait_until(received_pongs)
# sync_blocks: Wait for all connections to request the blockhash given
# then send get_headers to find out the tip of each node, and synchronize
# the response by using a ping (and waiting for pong with same nonce).
def sync_blocks(self, blockhash, num_blocks):
- # Wait for nodes to request block (50ms sleep * 20 tries * num_blocks)
- max_tries = 20*num_blocks
- while max_tries > 0:
- with mininode_lock:
- results = [ blockhash in c.cb.block_request_map and
- c.cb.block_request_map[blockhash] for c in self.connections ]
- if False not in results:
- break
- time.sleep(0.05)
- max_tries -= 1
+ def blocks_requested():
+ return all(
+ blockhash in node.block_request_map and node.block_request_map[blockhash]
+ for node in self.test_nodes
+ )
# --> error if not requested
- if max_tries == 0:
+ if not wait_until(blocks_requested, attempts=20*num_blocks):
# print [ c.cb.block_request_map for c in self.connections ]
raise AssertionError("Not all nodes requested block")
# --> Answer request (we did this inline!)
@@ -202,18 +207,14 @@ class TestManager(object):
# Analogous to sync_block (see above)
def sync_transaction(self, txhash, num_events):
# Wait for nodes to request transaction (50ms sleep * 20 tries * num_events)
- max_tries = 20*num_events
- while max_tries > 0:
- with mininode_lock:
- results = [ txhash in c.cb.tx_request_map and
- c.cb.tx_request_map[txhash] for c in self.connections ]
- if False not in results:
- break
- time.sleep(0.05)
- max_tries -= 1
+ def transaction_requested():
+ return all(
+ txhash in node.tx_request_map and node.tx_request_map[txhash]
+ for node in self.test_nodes
+ )
# --> error if not requested
- if max_tries == 0:
+ if not wait_until(transaction_requested, attempts=20*num_events):
# print [ c.cb.tx_request_map for c in self.connections ]
raise AssertionError("Not all nodes requested transaction")
# --> Answer request (we did this inline!)
@@ -336,6 +337,7 @@ class TestManager(object):
print "Test %d: PASS" % test_number, [ c.rpc.getblockcount() for c in self.connections ]
test_number += 1
+ [ c.disconnect_node() for c in self.connections ]
+ self.wait_for_disconnections()
self.block_store.close()
self.tx_store.close()
- [ c.disconnect_node() for c in self.connections ]