diff options
Diffstat (limited to 'qa')
-rwxr-xr-x | qa/pull-tester/rpc-tests.py | 23 | ||||
-rwxr-xr-x | qa/rpc-tests/mempool_packages.py | 3 | ||||
-rwxr-xr-x | qa/rpc-tests/mempool_reorg.py (renamed from qa/rpc-tests/mempool_coinbase_spends.py) | 26 | ||||
-rwxr-xr-x | qa/rpc-tests/multi_rpc.py | 122 | ||||
-rwxr-xr-x | qa/rpc-tests/prioritise_transaction.py | 147 | ||||
-rwxr-xr-x | qa/rpc-tests/smartfees.py | 3 | ||||
-rw-r--r-- | qa/rpc-tests/test_framework/util.py | 6 | ||||
-rwxr-xr-x | qa/rpc-tests/txn_clone.py | 2 | ||||
-rwxr-xr-x | qa/rpc-tests/txn_doublespend.py | 9 |
9 files changed, 317 insertions, 24 deletions
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 5004b09c18..df71e44b60 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -22,6 +22,7 @@ For a description of arguments recognized by test scripts, see """ import os +import time import shutil import sys import subprocess @@ -47,6 +48,10 @@ opts = set() passOn = "" p = re.compile("^--") +bold = ("","") +if (os.name == 'posix'): + bold = ('\033[0m', '\033[1m') + for arg in sys.argv[1:]: if arg == '--coverage': ENABLE_COVERAGE = 1 @@ -77,8 +82,9 @@ testScripts = [ 'rawtransactions.py', 'rest.py', 'mempool_spendcoinbase.py', - 'mempool_coinbase_spends.py', + 'mempool_reorg.py', 'httpbasics.py', + 'multi_rpc.py', 'zapwallettxes.py', 'proxy_test.py', 'merkle_blocks.py', @@ -92,6 +98,8 @@ testScripts = [ 'blockchain.py', 'disablewallet.py', 'sendheaders.py', + 'keypool.py', + 'prioritise_transaction.py', ] testScriptsExt = [ 'bip65-cltv.py', @@ -105,7 +113,6 @@ testScriptsExt = [ 'pruning.py', 'forknotify.py', 'invalidateblock.py', - 'keypool.py', # 'rpcbind_test.py', #temporary, bug in libevent, see #6655 'smartfees.py', 'maxblocksinflight.py', @@ -126,7 +133,7 @@ def runtests(): if ENABLE_COVERAGE: coverage = RPCCoverage() - print("Initializing coverage directory at %s" % coverage.dir) + print("Initializing coverage directory at %s\n" % coverage.dir) if(ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1): rpcTestDir = buildDir + '/qa/rpc-tests/' @@ -141,10 +148,12 @@ def runtests(): or run_extended or testScripts[i] in opts or re.sub(".py$", "", testScripts[i]) in opts ): - print("Running testscript " + testScripts[i] + "...") + print("Running testscript %s%s%s ..." % (bold[1], testScripts[i], bold[0])) + time0 = time.time() subprocess.check_call( rpcTestDir + testScripts[i] + flags, shell=True) + print("Duration: %s s\n" % (int(time.time() - time0))) # exit if help is called so we print just one set of # instructions @@ -156,12 +165,14 @@ def runtests(): for i in range(len(testScriptsExt)): if (run_extended or testScriptsExt[i] in opts or re.sub(".py$", "", testScriptsExt[i]) in opts): + print( "Running 2nd level testscript " - + testScriptsExt[i] + "...") - + + "%s%s%s ..." % (bold[1], testScriptsExt[i], bold[0])) + time0 = time.time() subprocess.check_call( rpcTestDir + testScriptsExt[i] + flags, shell=True) + print("Duration: %s s\n" % (int(time.time() - time0))) if coverage: coverage.report_rpc_coverage() diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py index 746c26ff5e..34b316a6a3 100755 --- a/qa/rpc-tests/mempool_packages.py +++ b/qa/rpc-tests/mempool_packages.py @@ -8,9 +8,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -def satoshi_round(amount): - return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) - MAX_ANCESTORS = 25 MAX_DESCENDANTS = 25 diff --git a/qa/rpc-tests/mempool_coinbase_spends.py b/qa/rpc-tests/mempool_reorg.py index c64a15b9f5..fdbaf689ad 100755 --- a/qa/rpc-tests/mempool_coinbase_spends.py +++ b/qa/rpc-tests/mempool_reorg.py @@ -52,16 +52,25 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1 # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase), # and make sure the mempool code behaves correctly. - b = [ self.nodes[0].getblockhash(n) for n in range(102, 105) ] + b = [ self.nodes[0].getblockhash(n) for n in range(101, 105) ] coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] - spend_101_raw = self.create_tx(coinbase_txids[0], node1_address, 50) - spend_102_raw = self.create_tx(coinbase_txids[1], node0_address, 50) - spend_103_raw = self.create_tx(coinbase_txids[2], node0_address, 50) + spend_101_raw = self.create_tx(coinbase_txids[1], node1_address, 50) + spend_102_raw = self.create_tx(coinbase_txids[2], node0_address, 50) + spend_103_raw = self.create_tx(coinbase_txids[3], node0_address, 50) + + # Create a block-height-locked transaction which will be invalid after reorg + timelock_tx = self.nodes[0].createrawtransaction([{"txid": coinbase_txids[0], "vout": 0}], {node0_address: 50}) + # Set the time lock + timelock_tx = timelock_tx.replace("ffffffff", "11111111", 1) + timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + "000000" + timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)["hex"] + assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx) # Broadcast and mine spend_102 and 103: spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw) spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw) self.nodes[0].generate(1) + assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx) # Create 102_1 and 103_1: spend_102_1_raw = self.create_tx(spend_102_id, node1_address, 50) @@ -69,7 +78,8 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # Broadcast and mine 103_1: spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw) - self.nodes[0].generate(1) + last_block = self.nodes[0].generate(1) + timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx) # ... now put spend_101 and spend_102_1 in memory pools: spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw) @@ -77,7 +87,11 @@ class MempoolCoinbaseTest(BitcoinTestFramework): self.sync_all() - assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_101_id, spend_102_1_id ])) + assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_101_id, spend_102_1_id, timelock_tx_id ])) + + for node in self.nodes: + node.invalidateblock(last_block[0]) + assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_101_id, spend_102_1_id, spend_103_1_id ])) # Use invalidateblock to re-org back and make all those coinbase spends # immature/invalid: diff --git a/qa/rpc-tests/multi_rpc.py b/qa/rpc-tests/multi_rpc.py new file mode 100755 index 0000000000..62071d426e --- /dev/null +++ b/qa/rpc-tests/multi_rpc.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 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 mulitple rpc user config option rpcauth +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import base64 + +try: + import http.client as httplib +except ImportError: + import httplib +try: + import urllib.parse as urlparse +except ImportError: + import urlparse + +class HTTPBasicsTest (BitcoinTestFramework): + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir) + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain(self.options.tmpdir) + #Append rpcauth to bitcoin.conf before initialization + rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144" + rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e" + with open(os.path.join(self.options.tmpdir+"/node0", "bitcoin.conf"), 'a') as f: + f.write(rpcauth+"\n") + f.write(rpcauth2+"\n") + + def run_test(self): + + ################################################## + # Check correctness of the rpcauth config option # + ################################################## + url = urlparse.urlparse(self.nodes[0].url) + + #Old authpair + authpair = url.username + ':' + url.password + + #New authpair generated via contrib/rpcuser tool + rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144" + password = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM=" + + #Second authpair with different username + rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e" + password2 = "8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI=" + authpairnew = "rt:"+password + + headers = {"Authorization": "Basic " + base64.b64encode(authpair)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, False) + conn.close() + + #Use new authpair to confirm both work + headers = {"Authorization": "Basic " + base64.b64encode(authpairnew)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, False) + conn.close() + + #Wrong login name with rt's password + authpairnew = "rtwrong:"+password + headers = {"Authorization": "Basic " + base64.b64encode(authpairnew)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, True) + conn.close() + + #Wrong password for rt + authpairnew = "rt:"+password+"wrong" + headers = {"Authorization": "Basic " + base64.b64encode(authpairnew)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, True) + conn.close() + + #Correct for rt2 + authpairnew = "rt2:"+password2 + headers = {"Authorization": "Basic " + base64.b64encode(authpairnew)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, False) + conn.close() + + #Wrong password for rt2 + authpairnew = "rt2:"+password2+"wrong" + headers = {"Authorization": "Basic " + base64.b64encode(authpairnew)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + assert_equal(resp.status==401, True) + conn.close() + + + +if __name__ == '__main__': + HTTPBasicsTest ().main () diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py new file mode 100755 index 0000000000..f376ceee5e --- /dev/null +++ b/qa/rpc-tests/prioritise_transaction.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 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 PrioritiseTransaction code +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +COIN = 100000000 + +class PrioritiseTransactionTest(BitcoinTestFramework): + + def __init__(self): + # Some pre-processing to create a bunch of OP_RETURN txouts to insert into transactions we create + # So we have big transactions (and therefore can't fit very many into each block) + # create one script_pubkey + script_pubkey = "6a4d0200" #OP_RETURN OP_PUSH2 512 bytes + for i in xrange (512): + script_pubkey = script_pubkey + "01" + # concatenate 128 txouts of above script_pubkey which we'll insert before the txout for change + self.txouts = "81" + for k in xrange(128): + # add txout value + self.txouts = self.txouts + "0000000000000000" + # add length of script_pubkey + self.txouts = self.txouts + "fd0402" + # add script_pubkey + self.txouts = self.txouts + script_pubkey + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self): + self.nodes = [] + self.is_network_split = False + + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-printpriority=1"])) + self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] + + def create_confirmed_utxos(self, count): + self.nodes[0].generate(int(0.5*count)+101) + utxos = self.nodes[0].listunspent() + iterations = count - len(utxos) + addr1 = self.nodes[0].getnewaddress() + addr2 = self.nodes[0].getnewaddress() + if iterations <= 0: + return utxos + for i in xrange(iterations): + t = utxos.pop() + fee = self.relayfee + inputs = [] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) + outputs = {} + send_value = t['amount'] - fee + outputs[addr1] = satoshi_round(send_value/2) + outputs[addr2] = satoshi_round(send_value/2) + raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) + signed_tx = self.nodes[0].signrawtransaction(raw_tx)["hex"] + txid = self.nodes[0].sendrawtransaction(signed_tx) + + while (self.nodes[0].getmempoolinfo()['size'] > 0): + self.nodes[0].generate(1) + + utxos = self.nodes[0].listunspent() + assert(len(utxos) >= count) + return utxos + + def create_lots_of_big_transactions(self, utxos, fee): + addr = self.nodes[0].getnewaddress() + txids = [] + for i in xrange(len(utxos)): + t = utxos.pop() + inputs = [] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) + outputs = {} + send_value = t['amount'] - fee + outputs[addr] = satoshi_round(send_value) + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + newtx = rawtx[0:92] + newtx = newtx + self.txouts + newtx = newtx + rawtx[94:] + signresult = self.nodes[0].signrawtransaction(newtx, None, None, "NONE") + txid = self.nodes[0].sendrawtransaction(signresult["hex"], True) + txids.append(txid) + return txids + + def run_test(self): + utxos = self.create_confirmed_utxos(90) + base_fee = self.relayfee*100 # our transactions are smaller than 100kb + txids = [] + + # Create 3 batches of transactions at 3 different fee rate levels + for i in xrange(3): + txids.append([]) + txids[i] = self.create_lots_of_big_transactions(utxos[30*i:30*i+30], (i+1)*base_fee) + + # add a fee delta to something in the cheapest bucket and make sure it gets mined + # also check that a different entry in the cheapest bucket is NOT mined (lower + # the priority to ensure its not mined due to priority) + self.nodes[0].prioritisetransaction(txids[0][0], 0, int(3*base_fee*COIN)) + self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0) + + self.nodes[0].generate(1) + + mempool = self.nodes[0].getrawmempool() + print "Assert that prioritised transasction was mined" + assert(txids[0][0] not in mempool) + assert(txids[0][1] in mempool) + + high_fee_tx = None + for x in txids[2]: + if x not in mempool: + high_fee_tx = x + + # Something high-fee should have been mined! + assert(high_fee_tx != None) + + # Add a prioritisation before a tx is in the mempool (de-prioritising a + # high-fee transaction). + self.nodes[0].prioritisetransaction(high_fee_tx, -1e15, -int(2*base_fee*COIN)) + + # Add everything back to mempool + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + # Check to make sure our high fee rate tx is back in the mempool + mempool = self.nodes[0].getrawmempool() + assert(high_fee_tx in mempool) + + # Now verify the high feerate transaction isn't mined. + self.nodes[0].generate(5) + + # High fee transaction should not have been mined, but other high fee rate + # transactions should have been. + mempool = self.nodes[0].getrawmempool() + print "Assert that de-prioritised transaction is still in mempool" + assert(high_fee_tx in mempool) + for x in txids[2]: + if (x != high_fee_tx): + assert(x not in mempool) + +if __name__ == '__main__': + PrioritiseTransactionTest().main() diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py index ecfffc1b45..b209ae0c16 100755 --- a/qa/rpc-tests/smartfees.py +++ b/qa/rpc-tests/smartfees.py @@ -19,9 +19,6 @@ P2SH_2 = "2NBdpwq8Aoo1EEKEXPNrKvr5xQr3M9UfcZA" # P2SH of "OP_2 OP_DROP" # 4 bytes of OP_TRUE and push 2-byte redeem script of "OP_1 OP_DROP" or "OP_2 OP_DROP" SCRIPT_SIG = ["0451025175", "0451025275"] -def satoshi_round(amount): - return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) - def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee_increment): ''' Create and send a transaction with a random fee. diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index d9d5129f21..b7e90a8a8b 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -217,7 +217,8 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary= datadir = os.path.join(dirname, "node"+str(i)) if binary is None: binary = os.getenv("BITCOIND", "bitcoind") - args = [ binary, "-datadir="+datadir, "-keypool=1", "-discover=0", "-rest" ] + # RPC tests still depend on free transactions + args = [ binary, "-datadir="+datadir, "-keypool=1", "-discover=0", "-rest", "-blockprioritysize=50000" ] if extra_args is not None: args.extend(extra_args) bitcoind_processes[i] = subprocess.Popen(args) devnull = open(os.devnull, "w") @@ -404,3 +405,6 @@ def assert_raises(exc, fun, *args, **kwds): raise AssertionError("Unexpected exception raised: "+type(e).__name__) else: raise AssertionError("No exception raised") + +def satoshi_round(amount): + return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) diff --git a/qa/rpc-tests/txn_clone.py b/qa/rpc-tests/txn_clone.py index e8ced0e5bb..b1f603a192 100755 --- a/qa/rpc-tests/txn_clone.py +++ b/qa/rpc-tests/txn_clone.py @@ -136,7 +136,7 @@ class TxnMallTest(BitcoinTestFramework): tx2 = self.nodes[0].gettransaction(txid2) # Verify expected confirmations - assert_equal(tx1["confirmations"], -1) + assert_equal(tx1["confirmations"], -2) assert_equal(tx1_clone["confirmations"], 2) assert_equal(tx2["confirmations"], 1) diff --git a/qa/rpc-tests/txn_doublespend.py b/qa/rpc-tests/txn_doublespend.py index 36081127b4..d4665b3d42 100755 --- a/qa/rpc-tests/txn_doublespend.py +++ b/qa/rpc-tests/txn_doublespend.py @@ -99,7 +99,7 @@ class TxnMallTest(BitcoinTestFramework): # Now give doublespend and its parents to miner: self.nodes[2].sendrawtransaction(fund_foo_tx["hex"]) self.nodes[2].sendrawtransaction(fund_bar_tx["hex"]) - self.nodes[2].sendrawtransaction(doublespend["hex"]) + doublespend_txid = self.nodes[2].sendrawtransaction(doublespend["hex"]) # ... mine a block... self.nodes[2].generate(1) @@ -107,14 +107,15 @@ class TxnMallTest(BitcoinTestFramework): connect_nodes(self.nodes[1], 2) self.nodes[2].generate(1) # Mine another block to make sure we sync sync_blocks(self.nodes) + assert_equal(self.nodes[0].gettransaction(doublespend_txid)["confirmations"], 2) # Re-fetch transaction info: tx1 = self.nodes[0].gettransaction(txid1) tx2 = self.nodes[0].gettransaction(txid2) - + # Both transactions should be conflicted - assert_equal(tx1["confirmations"], -1) - assert_equal(tx2["confirmations"], -1) + assert_equal(tx1["confirmations"], -2) + assert_equal(tx2["confirmations"], -2) # Node0's total balance should be starting balance, plus 100BTC for # two more matured blocks, minus 1240 for the double-spend, plus fees (which are |