aboutsummaryrefslogtreecommitdiff
path: root/qa
diff options
context:
space:
mode:
Diffstat (limited to 'qa')
-rwxr-xr-xqa/pull-tester/rpc-tests.py23
-rw-r--r--qa/replace-by-fee/.gitignore1
-rw-r--r--qa/replace-by-fee/README.md13
-rwxr-xr-xqa/replace-by-fee/rbf-tests.py360
-rwxr-xr-xqa/rpc-tests/mempool_packages.py3
-rwxr-xr-xqa/rpc-tests/mempool_reorg.py (renamed from qa/rpc-tests/mempool_coinbase_spends.py)26
-rwxr-xr-xqa/rpc-tests/multi_rpc.py122
-rwxr-xr-xqa/rpc-tests/prioritise_transaction.py147
-rwxr-xr-xqa/rpc-tests/replace-by-fee.py7
-rwxr-xr-xqa/rpc-tests/smartfees.py3
-rw-r--r--qa/rpc-tests/test_framework/util.py6
-rwxr-xr-xqa/rpc-tests/txn_clone.py2
-rwxr-xr-xqa/rpc-tests/txn_doublespend.py9
13 files changed, 323 insertions, 399 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/replace-by-fee/.gitignore b/qa/replace-by-fee/.gitignore
deleted file mode 100644
index b2c4f4657a..0000000000
--- a/qa/replace-by-fee/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-python-bitcoinlib
diff --git a/qa/replace-by-fee/README.md b/qa/replace-by-fee/README.md
deleted file mode 100644
index baad86de9a..0000000000
--- a/qa/replace-by-fee/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-Replace-by-fee regression tests
-===============================
-
-First get version v0.5.0 of the python-bitcoinlib library. In this directory
-run:
-
- git clone -n https://github.com/petertodd/python-bitcoinlib
- (cd python-bitcoinlib && git checkout 8270bfd9c6ac37907d75db3d8b9152d61c7255cd)
-
-Then run the tests themselves with a bitcoind available running in regtest
-mode:
-
- ./rbf-tests.py
diff --git a/qa/replace-by-fee/rbf-tests.py b/qa/replace-by-fee/rbf-tests.py
deleted file mode 100755
index 1ee6c83875..0000000000
--- a/qa/replace-by-fee/rbf-tests.py
+++ /dev/null
@@ -1,360 +0,0 @@
-#!/usr/bin/env python3
-# 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 replace-by-fee
-#
-
-import os
-import sys
-
-# Add python-bitcoinlib to module search path, prior to any system-wide
-# python-bitcoinlib.
-sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "python-bitcoinlib"))
-
-import unittest
-
-import bitcoin
-bitcoin.SelectParams('regtest')
-
-import bitcoin.rpc
-
-from bitcoin.core import *
-from bitcoin.core.script import *
-from bitcoin.wallet import *
-
-MAX_REPLACEMENT_LIMIT = 100
-
-class Test_ReplaceByFee(unittest.TestCase):
- proxy = None
-
- @classmethod
- def setUpClass(cls):
- if cls.proxy is None:
- cls.proxy = bitcoin.rpc.Proxy()
-
- @classmethod
- def mine_mempool(cls):
- """Mine until mempool is empty"""
- mempool_size = 1
- while mempool_size:
- cls.proxy.call('generate', 1)
- new_mempool_size = len(cls.proxy.getrawmempool())
-
- # It's possible to get stuck in a loop here if the mempool has
- # transactions that can't be mined.
- assert(new_mempool_size != mempool_size)
- mempool_size = new_mempool_size
-
- @classmethod
- def tearDownClass(cls):
- # Make sure mining works
- cls.mine_mempool()
-
- def make_txout(self, amount, confirmed=True, scriptPubKey=CScript([1])):
- """Create a txout with a given amount and scriptPubKey
-
- Mines coins as needed.
-
- confirmed - txouts created will be confirmed in the blockchain;
- unconfirmed otherwise.
- """
- fee = 1*COIN
- while self.proxy.getbalance() < amount + fee:
- self.proxy.call('generate', 100)
-
- addr = P2SHBitcoinAddress.from_redeemScript(CScript([]))
- txid = self.proxy.sendtoaddress(addr, amount + fee)
-
- tx1 = self.proxy.getrawtransaction(txid)
-
- i = None
- for i, txout in enumerate(tx1.vout):
- if txout.scriptPubKey == addr.to_scriptPubKey():
- break
- assert i is not None
-
- tx2 = CTransaction([CTxIn(COutPoint(txid, i), CScript([1, CScript([])]), nSequence=0)],
- [CTxOut(amount, scriptPubKey)])
-
- tx2_txid = self.proxy.sendrawtransaction(tx2, True)
-
- # If requested, ensure txouts are confirmed.
- if confirmed:
- self.mine_mempool()
-
- return COutPoint(tx2_txid, 0)
-
- def test_simple_doublespend(self):
- """Simple doublespend"""
- tx0_outpoint = self.make_txout(1.1*COIN)
-
- tx1a = CTransaction([CTxIn(tx0_outpoint, nSequence=0)],
- [CTxOut(1*COIN, CScript([b'a']))])
- tx1a_txid = self.proxy.sendrawtransaction(tx1a, True)
-
- # Should fail because we haven't changed the fee
- tx1b = CTransaction([CTxIn(tx0_outpoint, nSequence=0)],
- [CTxOut(1*COIN, CScript([b'b']))])
-
- try:
- tx1b_txid = self.proxy.sendrawtransaction(tx1b, True)
- except bitcoin.rpc.JSONRPCException as exp:
- self.assertEqual(exp.error['code'], -26) # insufficient fee
- else:
- self.fail()
-
- # Extra 0.1 BTC fee
- tx1b = CTransaction([CTxIn(tx0_outpoint, nSequence=0)],
- [CTxOut(0.9*COIN, CScript([b'b']))])
- tx1b_txid = self.proxy.sendrawtransaction(tx1b, True)
-
- # tx1a is in fact replaced
- with self.assertRaises(IndexError):
- self.proxy.getrawtransaction(tx1a_txid)
-
- self.assertEqual(tx1b, self.proxy.getrawtransaction(tx1b_txid))
-
- def test_doublespend_chain(self):
- """Doublespend of a long chain"""
-
- initial_nValue = 50*COIN
- tx0_outpoint = self.make_txout(initial_nValue)
-
- prevout = tx0_outpoint
- remaining_value = initial_nValue
- chain_txids = []
- while remaining_value > 10*COIN:
- remaining_value -= 1*COIN
- tx = CTransaction([CTxIn(prevout, nSequence=0)],
- [CTxOut(remaining_value, CScript([1]))])
- txid = self.proxy.sendrawtransaction(tx, True)
- chain_txids.append(txid)
- prevout = COutPoint(txid, 0)
-
- # Whether the double-spend is allowed is evaluated by including all
- # child fees - 40 BTC - so this attempt is rejected.
- dbl_tx = CTransaction([CTxIn(tx0_outpoint, nSequence=0)],
- [CTxOut(initial_nValue - 30*COIN, CScript([1]))])
-
- try:
- self.proxy.sendrawtransaction(dbl_tx, True)
- except bitcoin.rpc.JSONRPCException as exp:
- self.assertEqual(exp.error['code'], -26) # insufficient fee
- else:
- self.fail()
-
- # Accepted with sufficient fee
- dbl_tx = CTransaction([CTxIn(tx0_outpoint, nSequence=0)],
- [CTxOut(1*COIN, CScript([1]))])
- self.proxy.sendrawtransaction(dbl_tx, True)
-
- for doublespent_txid in chain_txids:
- with self.assertRaises(IndexError):
- self.proxy.getrawtransaction(doublespent_txid)
-
- def test_doublespend_tree(self):
- """Doublespend of a big tree of transactions"""
-
- initial_nValue = 50*COIN
- tx0_outpoint = self.make_txout(initial_nValue)
-
- def branch(prevout, initial_value, max_txs, *, tree_width=5, fee=0.0001*COIN, _total_txs=None):
- if _total_txs is None:
- _total_txs = [0]
- if _total_txs[0] >= max_txs:
- return
-
- txout_value = (initial_value - fee) // tree_width
- if txout_value < fee:
- return
-
- vout = [CTxOut(txout_value, CScript([i+1]))
- for i in range(tree_width)]
- tx = CTransaction([CTxIn(prevout, nSequence=0)],
- vout)
-
- self.assertTrue(len(tx.serialize()) < 100000)
- txid = self.proxy.sendrawtransaction(tx, True)
- yield tx
- _total_txs[0] += 1
-
- for i, txout in enumerate(tx.vout):
- yield from branch(COutPoint(txid, i), txout_value,
- max_txs,
- tree_width=tree_width, fee=fee,
- _total_txs=_total_txs)
-
- fee = 0.0001*COIN
- n = MAX_REPLACEMENT_LIMIT
- tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
- self.assertEqual(len(tree_txs), n)
-
- # Attempt double-spend, will fail because too little fee paid
- dbl_tx = CTransaction([CTxIn(tx0_outpoint, nSequence=0)],
- [CTxOut(initial_nValue - fee*n, CScript([1]))])
- try:
- self.proxy.sendrawtransaction(dbl_tx, True)
- except bitcoin.rpc.JSONRPCException as exp:
- self.assertEqual(exp.error['code'], -26) # insufficient fee
- else:
- self.fail()
-
- # 1 BTC fee is enough
- dbl_tx = CTransaction([CTxIn(tx0_outpoint, nSequence=0)],
- [CTxOut(initial_nValue - fee*n - 1*COIN, CScript([1]))])
- self.proxy.sendrawtransaction(dbl_tx, True)
-
- for tx in tree_txs:
- with self.assertRaises(IndexError):
- self.proxy.getrawtransaction(tx.GetHash())
-
- # Try again, but with more total transactions than the "max txs
- # double-spent at once" anti-DoS limit.
- for n in (MAX_REPLACEMENT_LIMIT, MAX_REPLACEMENT_LIMIT*2):
- fee = 0.0001*COIN
- tx0_outpoint = self.make_txout(initial_nValue)
- tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
- self.assertEqual(len(tree_txs), n)
-
- dbl_tx = CTransaction([CTxIn(tx0_outpoint, nSequence=0)],
- [CTxOut(initial_nValue - fee*n, CScript([1]))])
- try:
- self.proxy.sendrawtransaction(dbl_tx, True)
- except bitcoin.rpc.JSONRPCException as exp:
- self.assertEqual(exp.error['code'], -26)
- else:
- self.fail()
-
- for tx in tree_txs:
- self.proxy.getrawtransaction(tx.GetHash())
-
- def test_replacement_feeperkb(self):
- """Replacement requires fee-per-KB to be higher"""
- tx0_outpoint = self.make_txout(1.1*COIN)
-
- tx1a = CTransaction([CTxIn(tx0_outpoint, nSequence=0)],
- [CTxOut(1*COIN, CScript([b'a']))])
- tx1a_txid = self.proxy.sendrawtransaction(tx1a, True)
-
- # Higher fee, but the fee per KB is much lower, so the replacement is
- # rejected.
- tx1b = CTransaction([CTxIn(tx0_outpoint, nSequence=0)],
- [CTxOut(0.001*COIN,
- CScript([b'a'*999000]))])
-
- try:
- tx1b_txid = self.proxy.sendrawtransaction(tx1b, True)
- except bitcoin.rpc.JSONRPCException as exp:
- self.assertEqual(exp.error['code'], -26) # insufficient fee
- else:
- self.fail()
-
- def test_spends_of_conflicting_outputs(self):
- """Replacements that spend conflicting tx outputs are rejected"""
- utxo1 = self.make_txout(1.2*COIN)
- utxo2 = self.make_txout(3.0*COIN)
-
- tx1a = CTransaction([CTxIn(utxo1, nSequence=0)],
- [CTxOut(1.1*COIN, CScript([b'a']))])
- tx1a_txid = self.proxy.sendrawtransaction(tx1a, True)
-
- # Direct spend an output of the transaction we're replacing.
- tx2 = CTransaction([CTxIn(utxo1, nSequence=0), CTxIn(utxo2, nSequence=0),
- CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)],
- tx1a.vout)
-
- try:
- tx2_txid = self.proxy.sendrawtransaction(tx2, True)
- except bitcoin.rpc.JSONRPCException as exp:
- self.assertEqual(exp.error['code'], -26)
- else:
- self.fail()
-
- # Spend tx1a's output to test the indirect case.
- tx1b = CTransaction([CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)],
- [CTxOut(1.0*COIN, CScript([b'a']))])
- tx1b_txid = self.proxy.sendrawtransaction(tx1b, True)
-
- tx2 = CTransaction([CTxIn(utxo1, nSequence=0), CTxIn(utxo2, nSequence=0),
- CTxIn(COutPoint(tx1b_txid, 0))],
- tx1a.vout)
-
- try:
- tx2_txid = self.proxy.sendrawtransaction(tx2, True)
- except bitcoin.rpc.JSONRPCException as exp:
- self.assertEqual(exp.error['code'], -26)
- else:
- self.fail()
-
- def test_new_unconfirmed_inputs(self):
- """Replacements that add new unconfirmed inputs are rejected"""
- confirmed_utxo = self.make_txout(1.1*COIN)
- unconfirmed_utxo = self.make_txout(0.1*COIN, False)
-
- tx1 = CTransaction([CTxIn(confirmed_utxo)],
- [CTxOut(1.0*COIN, CScript([b'a']))])
- tx1_txid = self.proxy.sendrawtransaction(tx1, True)
-
- tx2 = CTransaction([CTxIn(confirmed_utxo), CTxIn(unconfirmed_utxo)],
- tx1.vout)
-
- try:
- tx2_txid = self.proxy.sendrawtransaction(tx2, True)
- except bitcoin.rpc.JSONRPCException as exp:
- self.assertEqual(exp.error['code'], -26)
- else:
- self.fail()
-
- def test_too_many_replacements(self):
- """Replacements that evict too many transactions are rejected"""
- # Try directly replacing more than MAX_REPLACEMENT_LIMIT
- # transactions
-
- # Start by creating a single transaction with many outputs
- initial_nValue = 10*COIN
- utxo = self.make_txout(initial_nValue)
- fee = 0.0001*COIN
- split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1))
- actual_fee = initial_nValue - split_value*(MAX_REPLACEMENT_LIMIT+1)
-
- outputs = []
- for i in range(MAX_REPLACEMENT_LIMIT+1):
- outputs.append(CTxOut(split_value, CScript([1])))
-
- splitting_tx = CTransaction([CTxIn(utxo, nSequence=0)], outputs)
- txid = self.proxy.sendrawtransaction(splitting_tx, True)
-
- # Now spend each of those outputs individually
- for i in range(MAX_REPLACEMENT_LIMIT+1):
- tx_i = CTransaction([CTxIn(COutPoint(txid, i), nSequence=0)],
- [CTxOut(split_value-fee, CScript([b'a']))])
- self.proxy.sendrawtransaction(tx_i, True)
-
- # Now create doublespend of the whole lot, should fail
- # Need a big enough fee to cover all spending transactions and have
- # a higher fee rate
- double_spend_value = (split_value-100*fee)*(MAX_REPLACEMENT_LIMIT+1)
- inputs = []
- for i in range(MAX_REPLACEMENT_LIMIT+1):
- inputs.append(CTxIn(COutPoint(txid, i), nSequence=0))
- double_tx = CTransaction(inputs, [CTxOut(double_spend_value, CScript([b'a']))])
-
- try:
- self.proxy.sendrawtransaction(double_tx, True)
- except bitcoin.rpc.JSONRPCException as exp:
- self.assertEqual(exp.error['code'], -26)
- self.assertEqual("too many potential replacements" in exp.error['message'], True)
- else:
- self.fail()
-
- # If we remove an input, it should pass
- double_tx = CTransaction(inputs[0:-1],
- [CTxOut(double_spend_value, CScript([b'a']))])
-
- self.proxy.sendrawtransaction(double_tx, True)
-
-if __name__ == '__main__':
- unittest.main()
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/replace-by-fee.py b/qa/rpc-tests/replace-by-fee.py
index 537a1ed8d9..6e9e0b304c 100755
--- a/qa/rpc-tests/replace-by-fee.py
+++ b/qa/rpc-tests/replace-by-fee.py
@@ -73,7 +73,12 @@ class ReplaceByFeeTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
- "-relaypriority=0", "-whitelist=127.0.0.1"]))
+ "-relaypriority=0", "-whitelist=127.0.0.1",
+ "-limitancestorcount=50",
+ "-limitancestorsize=101",
+ "-limitdescendantcount=200",
+ "-limitdescendantsize=101"
+ ]))
self.is_network_split = False
def run_test(self):
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