Skip to content

Commit 9e56532

Browse files
committed
Coinbases-in-mempool regression test
Immature coinbase spends are allowed in the memory pool if they can be mined in the next block. They are not allowed in the memory pool if they cannot be mined in the next block. This regression test tests those edge cases.
1 parent 90f7aa7 commit 9e56532

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

qa/pull-tester/rpc-tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then
2222
${BUILDDIR}/qa/rpc-tests/txn_doublespend.py --mineblock --srcdir "${BUILDDIR}/src"
2323
${BUILDDIR}/qa/rpc-tests/getchaintips.py --srcdir "${BUILDDIR}/src"
2424
${BUILDDIR}/qa/rpc-tests/rest.py --srcdir "${BUILDDIR}/src"
25+
${BUILDDIR}/qa/rpc-tests/mempool_spendcoinbase.py --srcdir "${BUILDDIR}/src"
2526
#${BUILDDIR}/qa/rpc-tests/forknotify.py --srcdir "${BUILDDIR}/src"
2627
else
2728
echo "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled"

qa/rpc-tests/mempool_spendcoinbase.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python
2+
# Copyright (c) 2014 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#
7+
# Test spending coinbase transactions.
8+
# The coinbase transaction in block N can appear in block
9+
# N+100... so is valid in the mempool when the best block
10+
# height is N+99.
11+
# This test makes sure coinbase spends that will be mature
12+
# in the next block are accepted into the memory pool,
13+
# but less mature coinbase spends are NOT.
14+
#
15+
16+
from test_framework import BitcoinTestFramework
17+
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
18+
from util import *
19+
import os
20+
import shutil
21+
22+
# Create one-input, one-output, no-fee transaction:
23+
class MempoolSpendCoinbaseTest(BitcoinTestFramework):
24+
25+
def setup_network(self):
26+
# Just need one node for this test
27+
args = ["-checkmempool", "-debug=mempool"]
28+
self.nodes = []
29+
self.nodes.append(start_node(0, self.options.tmpdir, args))
30+
self.is_network_split = False
31+
32+
def create_tx(self, from_txid, to_address, amount):
33+
inputs = [{ "txid" : from_txid, "vout" : 0}]
34+
outputs = { to_address : amount }
35+
rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
36+
signresult = self.nodes[0].signrawtransaction(rawtx)
37+
assert_equal(signresult["complete"], True)
38+
return signresult["hex"]
39+
40+
def run_test(self):
41+
chain_height = self.nodes[0].getblockcount()
42+
assert_equal(chain_height, 200)
43+
node0_address = self.nodes[0].getnewaddress()
44+
45+
# Coinbase at height chain_height-100+1 ok in mempool, should
46+
# get mined. Coinbase at height chain_height-100+2 is
47+
# is too immature to spend.
48+
b = [ self.nodes[0].getblockhash(n) for n in range(101, 103) ]
49+
coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]
50+
spends_raw = [ self.create_tx(txid, node0_address, 50) for txid in coinbase_txids ]
51+
52+
spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])
53+
54+
# coinbase at height 102 should be too immature to spend
55+
assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, spends_raw[1])
56+
57+
# mempool should have just spend_101:
58+
assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ])
59+
60+
# mine a block, spend_101 should get confirmed
61+
self.nodes[0].setgenerate(True, 1)
62+
assert_equal(set(self.nodes[0].getrawmempool()), set())
63+
64+
# ... and now height 102 can be spent:
65+
spend_102_id = self.nodes[0].sendrawtransaction(spends_raw[1])
66+
assert_equal(self.nodes[0].getrawmempool(), [ spend_102_id ])
67+
68+
if __name__ == '__main__':
69+
MempoolSpendCoinbaseTest().main()

qa/rpc-tests/util.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,4 +330,14 @@ def assert_equal(thing1, thing2):
330330

331331
def assert_greater_than(thing1, thing2):
332332
if thing1 <= thing2:
333-
raise AssertionError("%s <= %s"%(str(thing1),str(thing2)))
333+
raise AssertionError("%s <= %s"%(str(thing1),str(thing2)))
334+
335+
def assert_raises(exc, fun, *args, **kwds):
336+
try:
337+
fun(*args, **kwds)
338+
except exc:
339+
pass
340+
except Exception as e:
341+
raise AssertionError("Unexpected exception raised: "+type(e).__name__)
342+
else:
343+
raise AssertionError("No exception raised")

0 commit comments

Comments
 (0)