Skip to content

Commit 6abf6eb

Browse files
committed
Merge pull request #7063
2b31ab9 Add rpc test for prioritisetransaction (Suhas Daftuar) 6e8b07f Add rounding helper function to util.py (Suhas Daftuar)
2 parents 8f761e8 + 2b31ab9 commit 6abf6eb

File tree

5 files changed

+151
-6
lines changed

5 files changed

+151
-6
lines changed

qa/pull-tester/rpc-tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
'disablewallet.py',
100100
'sendheaders.py',
101101
'keypool.py',
102+
'prioritise_transaction.py',
102103
]
103104
testScriptsExt = [
104105
'bip65-cltv.py',

qa/rpc-tests/mempool_packages.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
from test_framework.test_framework import BitcoinTestFramework
99
from test_framework.util import *
1010

11-
def satoshi_round(amount):
12-
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
13-
1411
MAX_ANCESTORS = 25
1512
MAX_DESCENDANTS = 25
1613

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#!/usr/bin/env python2
2+
# Copyright (c) 2015 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 PrioritiseTransaction code
8+
#
9+
10+
from test_framework.test_framework import BitcoinTestFramework
11+
from test_framework.util import *
12+
13+
COIN = 100000000
14+
15+
class PrioritiseTransactionTest(BitcoinTestFramework):
16+
17+
def __init__(self):
18+
# Some pre-processing to create a bunch of OP_RETURN txouts to insert into transactions we create
19+
# So we have big transactions (and therefore can't fit very many into each block)
20+
# create one script_pubkey
21+
script_pubkey = "6a4d0200" #OP_RETURN OP_PUSH2 512 bytes
22+
for i in xrange (512):
23+
script_pubkey = script_pubkey + "01"
24+
# concatenate 128 txouts of above script_pubkey which we'll insert before the txout for change
25+
self.txouts = "81"
26+
for k in xrange(128):
27+
# add txout value
28+
self.txouts = self.txouts + "0000000000000000"
29+
# add length of script_pubkey
30+
self.txouts = self.txouts + "fd0402"
31+
# add script_pubkey
32+
self.txouts = self.txouts + script_pubkey
33+
34+
def setup_chain(self):
35+
print("Initializing test directory "+self.options.tmpdir)
36+
initialize_chain_clean(self.options.tmpdir, 1)
37+
38+
def setup_network(self):
39+
self.nodes = []
40+
self.is_network_split = False
41+
42+
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-printpriority=1"]))
43+
self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
44+
45+
def create_confirmed_utxos(self, count):
46+
self.nodes[0].generate(int(0.5*count)+101)
47+
utxos = self.nodes[0].listunspent()
48+
iterations = count - len(utxos)
49+
addr1 = self.nodes[0].getnewaddress()
50+
addr2 = self.nodes[0].getnewaddress()
51+
if iterations <= 0:
52+
return utxos
53+
for i in xrange(iterations):
54+
t = utxos.pop()
55+
fee = self.relayfee
56+
inputs = []
57+
inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
58+
outputs = {}
59+
send_value = t['amount'] - fee
60+
outputs[addr1] = satoshi_round(send_value/2)
61+
outputs[addr2] = satoshi_round(send_value/2)
62+
raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
63+
signed_tx = self.nodes[0].signrawtransaction(raw_tx)["hex"]
64+
txid = self.nodes[0].sendrawtransaction(signed_tx)
65+
66+
while (self.nodes[0].getmempoolinfo()['size'] > 0):
67+
self.nodes[0].generate(1)
68+
69+
utxos = self.nodes[0].listunspent()
70+
assert(len(utxos) >= count)
71+
return utxos
72+
73+
def create_lots_of_big_transactions(self, utxos, fee):
74+
addr = self.nodes[0].getnewaddress()
75+
txids = []
76+
for i in xrange(len(utxos)):
77+
t = utxos.pop()
78+
inputs = []
79+
inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
80+
outputs = {}
81+
send_value = t['amount'] - fee
82+
outputs[addr] = satoshi_round(send_value)
83+
rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
84+
newtx = rawtx[0:92]
85+
newtx = newtx + self.txouts
86+
newtx = newtx + rawtx[94:]
87+
signresult = self.nodes[0].signrawtransaction(newtx, None, None, "NONE")
88+
txid = self.nodes[0].sendrawtransaction(signresult["hex"], True)
89+
txids.append(txid)
90+
return txids
91+
92+
def run_test(self):
93+
utxos = self.create_confirmed_utxos(90)
94+
base_fee = self.relayfee*100 # our transactions are smaller than 100kb
95+
txids = []
96+
97+
# Create 3 batches of transactions at 3 different fee rate levels
98+
for i in xrange(3):
99+
txids.append([])
100+
txids[i] = self.create_lots_of_big_transactions(utxos[30*i:30*i+30], (i+1)*base_fee)
101+
102+
# add a fee delta to something in the cheapest bucket and make sure it gets mined
103+
# also check that a different entry in the cheapest bucket is NOT mined (lower
104+
# the priority to ensure its not mined due to priority)
105+
self.nodes[0].prioritisetransaction(txids[0][0], 0, int(3*base_fee*COIN))
106+
self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0)
107+
108+
self.nodes[0].generate(1)
109+
110+
mempool = self.nodes[0].getrawmempool()
111+
print "Assert that prioritised transasction was mined"
112+
assert(txids[0][0] not in mempool)
113+
assert(txids[0][1] in mempool)
114+
115+
high_fee_tx = None
116+
for x in txids[2]:
117+
if x not in mempool:
118+
high_fee_tx = x
119+
120+
# Something high-fee should have been mined!
121+
assert(high_fee_tx != None)
122+
123+
# Add a prioritisation before a tx is in the mempool (de-prioritising a
124+
# high-fee transaction).
125+
self.nodes[0].prioritisetransaction(high_fee_tx, -1e15, -int(2*base_fee*COIN))
126+
127+
# Add everything back to mempool
128+
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
129+
130+
# Check to make sure our high fee rate tx is back in the mempool
131+
mempool = self.nodes[0].getrawmempool()
132+
assert(high_fee_tx in mempool)
133+
134+
# Now verify the high feerate transaction isn't mined.
135+
self.nodes[0].generate(5)
136+
137+
# High fee transaction should not have been mined, but other high fee rate
138+
# transactions should have been.
139+
mempool = self.nodes[0].getrawmempool()
140+
print "Assert that de-prioritised transaction is still in mempool"
141+
assert(high_fee_tx in mempool)
142+
for x in txids[2]:
143+
if (x != high_fee_tx):
144+
assert(x not in mempool)
145+
146+
if __name__ == '__main__':
147+
PrioritiseTransactionTest().main()

qa/rpc-tests/smartfees.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
# 4 bytes of OP_TRUE and push 2-byte redeem script of "OP_1 OP_DROP" or "OP_2 OP_DROP"
2020
SCRIPT_SIG = ["0451025175", "0451025275"]
2121

22-
def satoshi_round(amount):
23-
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
24-
2522
def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee_increment):
2623
'''
2724
Create and send a transaction with a random fee.

qa/rpc-tests/test_framework/util.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,3 +404,6 @@ def assert_raises(exc, fun, *args, **kwds):
404404
raise AssertionError("Unexpected exception raised: "+type(e).__name__)
405405
else:
406406
raise AssertionError("No exception raised")
407+
408+
def satoshi_round(amount):
409+
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)

0 commit comments

Comments
 (0)