1#!/usr/bin/env python3
2# Copyright (c) 2014-2016 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 replace by fee code
8#
9
10from test_framework.test_framework import BitcoinTestFramework
11from test_framework.util import *
12from test_framework.script import *
13from test_framework.mininode import *
14
15MAX_REPLACEMENT_LIMIT = 100
16
17def txToHex(tx):
18    return bytes_to_hex_str(tx.serialize())
19
20def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
21    """Create a txout with a given amount and scriptPubKey
22
23    Mines coins as needed.
24
25    confirmed - txouts created will be confirmed in the blockchain;
26                unconfirmed otherwise.
27    """
28    fee = 1*COIN
29    while node.getbalance() < satoshi_round((amount + fee)/COIN):
30        node.generate(100)
31        #print (node.getbalance(), amount, fee)
32
33    new_addr = node.getnewaddress()
34    #print new_addr
35    txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN))
36    tx1 = node.getrawtransaction(txid, 1)
37    txid = int(txid, 16)
38    i = None
39
40    for i, txout in enumerate(tx1['vout']):
41        #print i, txout['scriptPubKey']['addresses']
42        if txout['scriptPubKey']['addresses'] == [new_addr]:
43            #print i
44            break
45    assert i is not None
46
47    tx2 = CTransaction()
48    tx2.vin = [CTxIn(COutPoint(txid, i))]
49    tx2.vout = [CTxOut(amount, scriptPubKey)]
50    tx2.rehash()
51
52    signed_tx = node.signrawtransaction(txToHex(tx2))
53
54    txid = node.sendrawtransaction(signed_tx['hex'], True)
55
56    # If requested, ensure txouts are confirmed.
57    if confirmed:
58        mempool_size = len(node.getrawmempool())
59        while mempool_size > 0:
60            node.generate(1)
61            new_size = len(node.getrawmempool())
62            # Error out if we have something stuck in the mempool, as this
63            # would likely be a bug.
64            assert(new_size < mempool_size)
65            mempool_size = new_size
66
67    return COutPoint(int(txid, 16), 0)
68
69class ReplaceByFeeTest(BitcoinTestFramework):
70
71    def __init__(self):
72        super().__init__()
73        self.num_nodes = 1
74        self.setup_clean_chain = False
75
76    def setup_network(self):
77        self.nodes = []
78        self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug",
79                                                              "-relaypriority=0", "-whitelist=127.0.0.1",
80                                                              "-limitancestorcount=50",
81                                                              "-limitancestorsize=101",
82                                                              "-limitdescendantcount=200",
83                                                              "-limitdescendantsize=101"
84                                                              ]))
85        self.is_network_split = False
86
87    def run_test(self):
88        make_utxo(self.nodes[0], 1*COIN)
89
90        print("Running test simple doublespend...")
91        self.test_simple_doublespend()
92
93        print("Running test doublespend chain...")
94        self.test_doublespend_chain()
95
96        print("Running test doublespend tree...")
97        self.test_doublespend_tree()
98
99        print("Running test replacement feeperkb...")
100        self.test_replacement_feeperkb()
101
102        print("Running test spends of conflicting outputs...")
103        self.test_spends_of_conflicting_outputs()
104
105        print("Running test new unconfirmed inputs...")
106        self.test_new_unconfirmed_inputs()
107
108        print("Running test too many replacements...")
109        self.test_too_many_replacements()
110
111        print("Running test opt-in...")
112        self.test_opt_in()
113
114        print("Running test prioritised transactions...")
115        self.test_prioritised_transactions()
116
117        print("Passed\n")
118
119    def test_simple_doublespend(self):
120        """Simple doublespend"""
121        tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
122
123        tx1a = CTransaction()
124        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
125        tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))]
126        tx1a_hex = txToHex(tx1a)
127        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
128
129        # Should fail because we haven't changed the fee
130        tx1b = CTransaction()
131        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
132        tx1b.vout = [CTxOut(1*COIN, CScript([b'b']))]
133        tx1b_hex = txToHex(tx1b)
134
135        try:
136            tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
137        except JSONRPCException as exp:
138            assert_equal(exp.error['code'], -26) # insufficient fee
139        else:
140            assert(False)
141
142        # Extra 0.1 BTC fee
143        tx1b = CTransaction()
144        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
145        tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))]
146        tx1b_hex = txToHex(tx1b)
147        tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
148
149        mempool = self.nodes[0].getrawmempool()
150
151        assert (tx1a_txid not in mempool)
152        assert (tx1b_txid in mempool)
153
154        assert_equal(tx1b_hex, self.nodes[0].getrawtransaction(tx1b_txid))
155
156    def test_doublespend_chain(self):
157        """Doublespend of a long chain"""
158
159        initial_nValue = 50*COIN
160        tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)
161
162        prevout = tx0_outpoint
163        remaining_value = initial_nValue
164        chain_txids = []
165        while remaining_value > 10*COIN:
166            remaining_value -= 1*COIN
167            tx = CTransaction()
168            tx.vin = [CTxIn(prevout, nSequence=0)]
169            tx.vout = [CTxOut(remaining_value, CScript([1]))]
170            tx_hex = txToHex(tx)
171            txid = self.nodes[0].sendrawtransaction(tx_hex, True)
172            chain_txids.append(txid)
173            prevout = COutPoint(int(txid, 16), 0)
174
175        # Whether the double-spend is allowed is evaluated by including all
176        # child fees - 40 BTC - so this attempt is rejected.
177        dbl_tx = CTransaction()
178        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
179        dbl_tx.vout = [CTxOut(initial_nValue - 30*COIN, CScript([1]))]
180        dbl_tx_hex = txToHex(dbl_tx)
181
182        try:
183            self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
184        except JSONRPCException as exp:
185            assert_equal(exp.error['code'], -26) # insufficient fee
186        else:
187            assert(False) # transaction mistakenly accepted!
188
189        # Accepted with sufficient fee
190        dbl_tx = CTransaction()
191        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
192        dbl_tx.vout = [CTxOut(1*COIN, CScript([1]))]
193        dbl_tx_hex = txToHex(dbl_tx)
194        self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
195
196        mempool = self.nodes[0].getrawmempool()
197        for doublespent_txid in chain_txids:
198            assert(doublespent_txid not in mempool)
199
200    def test_doublespend_tree(self):
201        """Doublespend of a big tree of transactions"""
202
203        initial_nValue = 50*COIN
204        tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)
205
206        def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _total_txs=None):
207            if _total_txs is None:
208                _total_txs = [0]
209            if _total_txs[0] >= max_txs:
210                return
211
212            txout_value = (initial_value - fee) // tree_width
213            if txout_value < fee:
214                return
215
216            vout = [CTxOut(txout_value, CScript([i+1]))
217                    for i in range(tree_width)]
218            tx = CTransaction()
219            tx.vin = [CTxIn(prevout, nSequence=0)]
220            tx.vout = vout
221            tx_hex = txToHex(tx)
222
223            assert(len(tx.serialize()) < 100000)
224            txid = self.nodes[0].sendrawtransaction(tx_hex, True)
225            yield tx
226            _total_txs[0] += 1
227
228            txid = int(txid, 16)
229
230            for i, txout in enumerate(tx.vout):
231                for x in branch(COutPoint(txid, i), txout_value,
232                                  max_txs,
233                                  tree_width=tree_width, fee=fee,
234                                  _total_txs=_total_txs):
235                    yield x
236
237        fee = int(0.0001*COIN)
238        n = MAX_REPLACEMENT_LIMIT
239        tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
240        assert_equal(len(tree_txs), n)
241
242        # Attempt double-spend, will fail because too little fee paid
243        dbl_tx = CTransaction()
244        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
245        dbl_tx.vout = [CTxOut(initial_nValue - fee*n, CScript([1]))]
246        dbl_tx_hex = txToHex(dbl_tx)
247        try:
248            self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
249        except JSONRPCException as exp:
250            assert_equal(exp.error['code'], -26) # insufficient fee
251        else:
252            assert(False)
253
254        # 1 BTC fee is enough
255        dbl_tx = CTransaction()
256        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
257        dbl_tx.vout = [CTxOut(initial_nValue - fee*n - 1*COIN, CScript([1]))]
258        dbl_tx_hex = txToHex(dbl_tx)
259        self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
260
261        mempool = self.nodes[0].getrawmempool()
262
263        for tx in tree_txs:
264            tx.rehash()
265            assert (tx.hash not in mempool)
266
267        # Try again, but with more total transactions than the "max txs
268        # double-spent at once" anti-DoS limit.
269        for n in (MAX_REPLACEMENT_LIMIT+1, MAX_REPLACEMENT_LIMIT*2):
270            fee = int(0.0001*COIN)
271            tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)
272            tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
273            assert_equal(len(tree_txs), n)
274
275            dbl_tx = CTransaction()
276            dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
277            dbl_tx.vout = [CTxOut(initial_nValue - 2*fee*n, CScript([1]))]
278            dbl_tx_hex = txToHex(dbl_tx)
279            try:
280                self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
281            except JSONRPCException as exp:
282                assert_equal(exp.error['code'], -26)
283                assert_equal("too many potential replacements" in exp.error['message'], True)
284            else:
285                assert(False)
286
287            for tx in tree_txs:
288                tx.rehash()
289                self.nodes[0].getrawtransaction(tx.hash)
290
291    def test_replacement_feeperkb(self):
292        """Replacement requires fee-per-KB to be higher"""
293        tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
294
295        tx1a = CTransaction()
296        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
297        tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))]
298        tx1a_hex = txToHex(tx1a)
299        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
300
301        # Higher fee, but the fee per KB is much lower, so the replacement is
302        # rejected.
303        tx1b = CTransaction()
304        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
305        tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*999000]))]
306        tx1b_hex = txToHex(tx1b)
307
308        try:
309            tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
310        except JSONRPCException as exp:
311            assert_equal(exp.error['code'], -26) # insufficient fee
312        else:
313            assert(False)
314
315    def test_spends_of_conflicting_outputs(self):
316        """Replacements that spend conflicting tx outputs are rejected"""
317        utxo1 = make_utxo(self.nodes[0], int(1.2*COIN))
318        utxo2 = make_utxo(self.nodes[0], 3*COIN)
319
320        tx1a = CTransaction()
321        tx1a.vin = [CTxIn(utxo1, nSequence=0)]
322        tx1a.vout = [CTxOut(int(1.1*COIN), CScript([b'a']))]
323        tx1a_hex = txToHex(tx1a)
324        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
325
326        tx1a_txid = int(tx1a_txid, 16)
327
328        # Direct spend an output of the transaction we're replacing.
329        tx2 = CTransaction()
330        tx2.vin = [CTxIn(utxo1, nSequence=0), CTxIn(utxo2, nSequence=0)]
331        tx2.vin.append(CTxIn(COutPoint(tx1a_txid, 0), nSequence=0))
332        tx2.vout = tx1a.vout
333        tx2_hex = txToHex(tx2)
334
335        try:
336            tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True)
337        except JSONRPCException as exp:
338            assert_equal(exp.error['code'], -26)
339        else:
340            assert(False)
341
342        # Spend tx1a's output to test the indirect case.
343        tx1b = CTransaction()
344        tx1b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
345        tx1b.vout = [CTxOut(1*COIN, CScript([b'a']))]
346        tx1b_hex = txToHex(tx1b)
347        tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
348        tx1b_txid = int(tx1b_txid, 16)
349
350        tx2 = CTransaction()
351        tx2.vin = [CTxIn(utxo1, nSequence=0), CTxIn(utxo2, nSequence=0),
352                   CTxIn(COutPoint(tx1b_txid, 0))]
353        tx2.vout = tx1a.vout
354        tx2_hex = txToHex(tx2)
355
356        try:
357            tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True)
358        except JSONRPCException as exp:
359            assert_equal(exp.error['code'], -26)
360        else:
361            assert(False)
362
363    def test_new_unconfirmed_inputs(self):
364        """Replacements that add new unconfirmed inputs are rejected"""
365        confirmed_utxo = make_utxo(self.nodes[0], int(1.1*COIN))
366        unconfirmed_utxo = make_utxo(self.nodes[0], int(0.1*COIN), False)
367
368        tx1 = CTransaction()
369        tx1.vin = [CTxIn(confirmed_utxo)]
370        tx1.vout = [CTxOut(1*COIN, CScript([b'a']))]
371        tx1_hex = txToHex(tx1)
372        tx1_txid = self.nodes[0].sendrawtransaction(tx1_hex, True)
373
374        tx2 = CTransaction()
375        tx2.vin = [CTxIn(confirmed_utxo), CTxIn(unconfirmed_utxo)]
376        tx2.vout = tx1.vout
377        tx2_hex = txToHex(tx2)
378
379        try:
380            tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True)
381        except JSONRPCException as exp:
382            assert_equal(exp.error['code'], -26)
383        else:
384            assert(False)
385
386    def test_too_many_replacements(self):
387        """Replacements that evict too many transactions are rejected"""
388        # Try directly replacing more than MAX_REPLACEMENT_LIMIT
389        # transactions
390
391        # Start by creating a single transaction with many outputs
392        initial_nValue = 10*COIN
393        utxo = make_utxo(self.nodes[0], initial_nValue)
394        fee = int(0.0001*COIN)
395        split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1))
396        actual_fee = initial_nValue - split_value*(MAX_REPLACEMENT_LIMIT+1)
397
398        outputs = []
399        for i in range(MAX_REPLACEMENT_LIMIT+1):
400            outputs.append(CTxOut(split_value, CScript([1])))
401
402        splitting_tx = CTransaction()
403        splitting_tx.vin = [CTxIn(utxo, nSequence=0)]
404        splitting_tx.vout = outputs
405        splitting_tx_hex = txToHex(splitting_tx)
406
407        txid = self.nodes[0].sendrawtransaction(splitting_tx_hex, True)
408        txid = int(txid, 16)
409
410        # Now spend each of those outputs individually
411        for i in range(MAX_REPLACEMENT_LIMIT+1):
412            tx_i = CTransaction()
413            tx_i.vin = [CTxIn(COutPoint(txid, i), nSequence=0)]
414            tx_i.vout = [CTxOut(split_value-fee, CScript([b'a']))]
415            tx_i_hex = txToHex(tx_i)
416            self.nodes[0].sendrawtransaction(tx_i_hex, True)
417
418        # Now create doublespend of the whole lot; should fail.
419        # Need a big enough fee to cover all spending transactions and have
420        # a higher fee rate
421        double_spend_value = (split_value-100*fee)*(MAX_REPLACEMENT_LIMIT+1)
422        inputs = []
423        for i in range(MAX_REPLACEMENT_LIMIT+1):
424            inputs.append(CTxIn(COutPoint(txid, i), nSequence=0))
425        double_tx = CTransaction()
426        double_tx.vin = inputs
427        double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))]
428        double_tx_hex = txToHex(double_tx)
429
430        try:
431            self.nodes[0].sendrawtransaction(double_tx_hex, True)
432        except JSONRPCException as exp:
433            assert_equal(exp.error['code'], -26)
434            assert_equal("too many potential replacements" in exp.error['message'], True)
435        else:
436            assert(False)
437
438        # If we remove an input, it should pass
439        double_tx = CTransaction()
440        double_tx.vin = inputs[0:-1]
441        double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))]
442        double_tx_hex = txToHex(double_tx)
443        self.nodes[0].sendrawtransaction(double_tx_hex, True)
444
445    def test_opt_in(self):
446        """ Replacing should only work if orig tx opted in """
447        tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
448
449        # Create a non-opting in transaction
450        tx1a = CTransaction()
451        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0xffffffff)]
452        tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))]
453        tx1a_hex = txToHex(tx1a)
454        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
455
456        # Shouldn't be able to double-spend
457        tx1b = CTransaction()
458        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
459        tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))]
460        tx1b_hex = txToHex(tx1b)
461
462        try:
463            tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
464        except JSONRPCException as exp:
465            assert_equal(exp.error['code'], -26)
466        else:
467            print(tx1b_txid)
468            assert(False)
469
470        tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
471
472        # Create a different non-opting in transaction
473        tx2a = CTransaction()
474        tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0xfffffffe)]
475        tx2a.vout = [CTxOut(1*COIN, CScript([b'a']))]
476        tx2a_hex = txToHex(tx2a)
477        tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, True)
478
479        # Still shouldn't be able to double-spend
480        tx2b = CTransaction()
481        tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]
482        tx2b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))]
483        tx2b_hex = txToHex(tx2b)
484
485        try:
486            tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
487        except JSONRPCException as exp:
488            assert_equal(exp.error['code'], -26)
489        else:
490            assert(False)
491
492        # Now create a new transaction that spends from tx1a and tx2a
493        # opt-in on one of the inputs
494        # Transaction should be replaceable on either input
495
496        tx1a_txid = int(tx1a_txid, 16)
497        tx2a_txid = int(tx2a_txid, 16)
498
499        tx3a = CTransaction()
500        tx3a.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0xffffffff),
501                    CTxIn(COutPoint(tx2a_txid, 0), nSequence=0xfffffffd)]
502        tx3a.vout = [CTxOut(int(0.9*COIN), CScript([b'c'])), CTxOut(int(0.9*COIN), CScript([b'd']))]
503        tx3a_hex = txToHex(tx3a)
504
505        self.nodes[0].sendrawtransaction(tx3a_hex, True)
506
507        tx3b = CTransaction()
508        tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
509        tx3b.vout = [CTxOut(int(0.5*COIN), CScript([b'e']))]
510        tx3b_hex = txToHex(tx3b)
511
512        tx3c = CTransaction()
513        tx3c.vin = [CTxIn(COutPoint(tx2a_txid, 0), nSequence=0)]
514        tx3c.vout = [CTxOut(int(0.5*COIN), CScript([b'f']))]
515        tx3c_hex = txToHex(tx3c)
516
517        self.nodes[0].sendrawtransaction(tx3b_hex, True)
518        # If tx3b was accepted, tx3c won't look like a replacement,
519        # but make sure it is accepted anyway
520        self.nodes[0].sendrawtransaction(tx3c_hex, True)
521
522    def test_prioritised_transactions(self):
523        # Ensure that fee deltas used via prioritisetransaction are
524        # correctly used by replacement logic
525
526        # 1. Check that feeperkb uses modified fees
527        tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
528
529        tx1a = CTransaction()
530        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
531        tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))]
532        tx1a_hex = txToHex(tx1a)
533        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
534
535        # Higher fee, but the actual fee per KB is much lower.
536        tx1b = CTransaction()
537        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
538        tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*740000]))]
539        tx1b_hex = txToHex(tx1b)
540
541        # Verify tx1b cannot replace tx1a.
542        try:
543            tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
544        except JSONRPCException as exp:
545            assert_equal(exp.error['code'], -26)
546        else:
547            assert(False)
548
549        # Use prioritisetransaction to set tx1a's fee to 0.
550        self.nodes[0].prioritisetransaction(tx1a_txid, 0, int(-0.1*COIN))
551
552        # Now tx1b should be able to replace tx1a
553        tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
554
555        assert(tx1b_txid in self.nodes[0].getrawmempool())
556
557        # 2. Check that absolute fee checks use modified fee.
558        tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
559
560        tx2a = CTransaction()
561        tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0)]
562        tx2a.vout = [CTxOut(1*COIN, CScript([b'a']))]
563        tx2a_hex = txToHex(tx2a)
564        tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, True)
565
566        # Lower fee, but we'll prioritise it
567        tx2b = CTransaction()
568        tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]
569        tx2b.vout = [CTxOut(int(1.01*COIN), CScript([b'a']))]
570        tx2b.rehash()
571        tx2b_hex = txToHex(tx2b)
572
573        # Verify tx2b cannot replace tx2a.
574        try:
575            tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
576        except JSONRPCException as exp:
577            assert_equal(exp.error['code'], -26)
578        else:
579            assert(False)
580
581        # Now prioritise tx2b to have a higher modified fee
582        self.nodes[0].prioritisetransaction(tx2b.hash, 0, int(0.1*COIN))
583
584        # tx2b should now be accepted
585        tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
586
587        assert(tx2b_txid in self.nodes[0].getrawmempool())
588
589if __name__ == '__main__':
590    ReplaceByFeeTest().main()
591