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 """Test the RBF code."""
7 from test_framework
.test_framework
import BitcoinTestFramework
8 from test_framework
.util
import *
9 from test_framework
.script
import *
10 from test_framework
.mininode
import *
12 MAX_REPLACEMENT_LIMIT
= 100
15 return bytes_to_hex_str(tx
.serialize())
17 def make_utxo(node
, amount
, confirmed
=True, scriptPubKey
=CScript([1])):
18 """Create a txout with a given amount and scriptPubKey
20 Mines coins as needed.
22 confirmed - txouts created will be confirmed in the blockchain;
23 unconfirmed otherwise.
26 while node
.getbalance() < satoshi_round((amount
+ fee
)/COIN
):
29 new_addr
= node
.getnewaddress()
30 txid
= node
.sendtoaddress(new_addr
, satoshi_round((amount
+fee
)/COIN
))
31 tx1
= node
.getrawtransaction(txid
, 1)
35 for i
, txout
in enumerate(tx1
['vout']):
36 if txout
['scriptPubKey']['addresses'] == [new_addr
]:
41 tx2
.vin
= [CTxIn(COutPoint(txid
, i
))]
42 tx2
.vout
= [CTxOut(amount
, scriptPubKey
)]
45 signed_tx
= node
.signrawtransaction(txToHex(tx2
))
47 txid
= node
.sendrawtransaction(signed_tx
['hex'], True)
49 # If requested, ensure txouts are confirmed.
51 mempool_size
= len(node
.getrawmempool())
52 while mempool_size
> 0:
54 new_size
= len(node
.getrawmempool())
55 # Error out if we have something stuck in the mempool, as this
56 # would likely be a bug.
57 assert(new_size
< mempool_size
)
58 mempool_size
= new_size
60 return COutPoint(int(txid
, 16), 0)
62 class ReplaceByFeeTest(BitcoinTestFramework
):
64 def set_test_params(self
):
66 self
.extra_args
= [["-maxorphantx=1000",
67 "-whitelist=127.0.0.1",
68 "-limitancestorcount=50",
69 "-limitancestorsize=101",
70 "-limitdescendantcount=200",
71 "-limitdescendantsize=101"],
72 ["-mempoolreplacement=0"]]
75 make_utxo(self
.nodes
[0], 1*COIN
)
77 self
.log
.info("Running test simple doublespend...")
78 self
.test_simple_doublespend()
80 self
.log
.info("Running test doublespend chain...")
81 self
.test_doublespend_chain()
83 self
.log
.info("Running test doublespend tree...")
84 self
.test_doublespend_tree()
86 self
.log
.info("Running test replacement feeperkb...")
87 self
.test_replacement_feeperkb()
89 self
.log
.info("Running test spends of conflicting outputs...")
90 self
.test_spends_of_conflicting_outputs()
92 self
.log
.info("Running test new unconfirmed inputs...")
93 self
.test_new_unconfirmed_inputs()
95 self
.log
.info("Running test too many replacements...")
96 self
.test_too_many_replacements()
98 self
.log
.info("Running test opt-in...")
101 self
.log
.info("Running test RPC...")
104 self
.log
.info("Running test prioritised transactions...")
105 self
.test_prioritised_transactions()
107 self
.log
.info("Passed")
109 def test_simple_doublespend(self
):
110 """Simple doublespend"""
111 tx0_outpoint
= make_utxo(self
.nodes
[0], int(1.1*COIN
))
113 tx1a
= CTransaction()
114 tx1a
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
115 tx1a
.vout
= [CTxOut(1*COIN
, CScript([b
'a']))]
116 tx1a_hex
= txToHex(tx1a
)
117 tx1a_txid
= self
.nodes
[0].sendrawtransaction(tx1a_hex
, True)
119 self
.sync_all([self
.nodes
])
121 # Should fail because we haven't changed the fee
122 tx1b
= CTransaction()
123 tx1b
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
124 tx1b
.vout
= [CTxOut(1*COIN
, CScript([b
'b']))]
125 tx1b_hex
= txToHex(tx1b
)
127 # This will raise an exception due to insufficient fee
128 assert_raises_jsonrpc(-26, "insufficient fee", self
.nodes
[0].sendrawtransaction
, tx1b_hex
, True)
129 # This will raise an exception due to transaction replacement being disabled
130 assert_raises_jsonrpc(-26, "txn-mempool-conflict", self
.nodes
[1].sendrawtransaction
, tx1b_hex
, True)
133 tx1b
= CTransaction()
134 tx1b
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
135 tx1b
.vout
= [CTxOut(int(0.9*COIN
), CScript([b
'b']))]
136 tx1b_hex
= txToHex(tx1b
)
137 # Replacement still disabled even with "enough fee"
138 assert_raises_jsonrpc(-26, "txn-mempool-conflict", self
.nodes
[1].sendrawtransaction
, tx1b_hex
, True)
140 tx1b_txid
= self
.nodes
[0].sendrawtransaction(tx1b_hex
, True)
142 mempool
= self
.nodes
[0].getrawmempool()
144 assert (tx1a_txid
not in mempool
)
145 assert (tx1b_txid
in mempool
)
147 assert_equal(tx1b_hex
, self
.nodes
[0].getrawtransaction(tx1b_txid
))
149 # Second node is running mempoolreplacement=0, will not replace originally-seen txn
150 mempool
= self
.nodes
[1].getrawmempool()
151 assert tx1a_txid
in mempool
152 assert tx1b_txid
not in mempool
154 def test_doublespend_chain(self
):
155 """Doublespend of a long chain"""
157 initial_nValue
= 50*COIN
158 tx0_outpoint
= make_utxo(self
.nodes
[0], initial_nValue
)
160 prevout
= tx0_outpoint
161 remaining_value
= initial_nValue
163 while remaining_value
> 10*COIN
:
164 remaining_value
-= 1*COIN
166 tx
.vin
= [CTxIn(prevout
, nSequence
=0)]
167 tx
.vout
= [CTxOut(remaining_value
, CScript([1]))]
169 txid
= self
.nodes
[0].sendrawtransaction(tx_hex
, True)
170 chain_txids
.append(txid
)
171 prevout
= COutPoint(int(txid
, 16), 0)
173 # Whether the double-spend is allowed is evaluated by including all
174 # child fees - 40 BTC - so this attempt is rejected.
175 dbl_tx
= CTransaction()
176 dbl_tx
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
177 dbl_tx
.vout
= [CTxOut(initial_nValue
- 30*COIN
, CScript([1]))]
178 dbl_tx_hex
= txToHex(dbl_tx
)
180 # This will raise an exception due to insufficient fee
181 assert_raises_jsonrpc(-26, "insufficient fee", self
.nodes
[0].sendrawtransaction
, dbl_tx_hex
, True)
183 # Accepted with sufficient fee
184 dbl_tx
= CTransaction()
185 dbl_tx
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
186 dbl_tx
.vout
= [CTxOut(1*COIN
, CScript([1]))]
187 dbl_tx_hex
= txToHex(dbl_tx
)
188 self
.nodes
[0].sendrawtransaction(dbl_tx_hex
, True)
190 mempool
= self
.nodes
[0].getrawmempool()
191 for doublespent_txid
in chain_txids
:
192 assert(doublespent_txid
not in mempool
)
194 def test_doublespend_tree(self
):
195 """Doublespend of a big tree of transactions"""
197 initial_nValue
= 50*COIN
198 tx0_outpoint
= make_utxo(self
.nodes
[0], initial_nValue
)
200 def branch(prevout
, initial_value
, max_txs
, tree_width
=5, fee
=0.0001*COIN
, _total_txs
=None):
201 if _total_txs
is None:
203 if _total_txs
[0] >= max_txs
:
206 txout_value
= (initial_value
- fee
) // tree_width
207 if txout_value
< fee
:
210 vout
= [CTxOut(txout_value
, CScript([i
+1]))
211 for i
in range(tree_width
)]
213 tx
.vin
= [CTxIn(prevout
, nSequence
=0)]
217 assert(len(tx
.serialize()) < 100000)
218 txid
= self
.nodes
[0].sendrawtransaction(tx_hex
, True)
224 for i
, txout
in enumerate(tx
.vout
):
225 for x
in branch(COutPoint(txid
, i
), txout_value
,
227 tree_width
=tree_width
, fee
=fee
,
228 _total_txs
=_total_txs
):
231 fee
= int(0.0001*COIN
)
232 n
= MAX_REPLACEMENT_LIMIT
233 tree_txs
= list(branch(tx0_outpoint
, initial_nValue
, n
, fee
=fee
))
234 assert_equal(len(tree_txs
), n
)
236 # Attempt double-spend, will fail because too little fee paid
237 dbl_tx
= CTransaction()
238 dbl_tx
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
239 dbl_tx
.vout
= [CTxOut(initial_nValue
- fee
*n
, CScript([1]))]
240 dbl_tx_hex
= txToHex(dbl_tx
)
241 # This will raise an exception due to insufficient fee
242 assert_raises_jsonrpc(-26, "insufficient fee", self
.nodes
[0].sendrawtransaction
, dbl_tx_hex
, True)
244 # 1 BTC fee is enough
245 dbl_tx
= CTransaction()
246 dbl_tx
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
247 dbl_tx
.vout
= [CTxOut(initial_nValue
- fee
*n
- 1*COIN
, CScript([1]))]
248 dbl_tx_hex
= txToHex(dbl_tx
)
249 self
.nodes
[0].sendrawtransaction(dbl_tx_hex
, True)
251 mempool
= self
.nodes
[0].getrawmempool()
255 assert (tx
.hash not in mempool
)
257 # Try again, but with more total transactions than the "max txs
258 # double-spent at once" anti-DoS limit.
259 for n
in (MAX_REPLACEMENT_LIMIT
+1, MAX_REPLACEMENT_LIMIT
*2):
260 fee
= int(0.0001*COIN
)
261 tx0_outpoint
= make_utxo(self
.nodes
[0], initial_nValue
)
262 tree_txs
= list(branch(tx0_outpoint
, initial_nValue
, n
, fee
=fee
))
263 assert_equal(len(tree_txs
), n
)
265 dbl_tx
= CTransaction()
266 dbl_tx
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
267 dbl_tx
.vout
= [CTxOut(initial_nValue
- 2*fee
*n
, CScript([1]))]
268 dbl_tx_hex
= txToHex(dbl_tx
)
269 # This will raise an exception
270 assert_raises_jsonrpc(-26, "too many potential replacements", self
.nodes
[0].sendrawtransaction
, dbl_tx_hex
, True)
274 self
.nodes
[0].getrawtransaction(tx
.hash)
276 def test_replacement_feeperkb(self
):
277 """Replacement requires fee-per-KB to be higher"""
278 tx0_outpoint
= make_utxo(self
.nodes
[0], int(1.1*COIN
))
280 tx1a
= CTransaction()
281 tx1a
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
282 tx1a
.vout
= [CTxOut(1*COIN
, CScript([b
'a']))]
283 tx1a_hex
= txToHex(tx1a
)
284 self
.nodes
[0].sendrawtransaction(tx1a_hex
, True)
286 # Higher fee, but the fee per KB is much lower, so the replacement is
288 tx1b
= CTransaction()
289 tx1b
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
290 tx1b
.vout
= [CTxOut(int(0.001*COIN
), CScript([b
'a'*999000]))]
291 tx1b_hex
= txToHex(tx1b
)
293 # This will raise an exception due to insufficient fee
294 assert_raises_jsonrpc(-26, "insufficient fee", self
.nodes
[0].sendrawtransaction
, tx1b_hex
, True)
296 def test_spends_of_conflicting_outputs(self
):
297 """Replacements that spend conflicting tx outputs are rejected"""
298 utxo1
= make_utxo(self
.nodes
[0], int(1.2*COIN
))
299 utxo2
= make_utxo(self
.nodes
[0], 3*COIN
)
301 tx1a
= CTransaction()
302 tx1a
.vin
= [CTxIn(utxo1
, nSequence
=0)]
303 tx1a
.vout
= [CTxOut(int(1.1*COIN
), CScript([b
'a']))]
304 tx1a_hex
= txToHex(tx1a
)
305 tx1a_txid
= self
.nodes
[0].sendrawtransaction(tx1a_hex
, True)
307 tx1a_txid
= int(tx1a_txid
, 16)
309 # Direct spend an output of the transaction we're replacing.
311 tx2
.vin
= [CTxIn(utxo1
, nSequence
=0), CTxIn(utxo2
, nSequence
=0)]
312 tx2
.vin
.append(CTxIn(COutPoint(tx1a_txid
, 0), nSequence
=0))
314 tx2_hex
= txToHex(tx2
)
316 # This will raise an exception
317 assert_raises_jsonrpc(-26, "bad-txns-spends-conflicting-tx", self
.nodes
[0].sendrawtransaction
, tx2_hex
, True)
319 # Spend tx1a's output to test the indirect case.
320 tx1b
= CTransaction()
321 tx1b
.vin
= [CTxIn(COutPoint(tx1a_txid
, 0), nSequence
=0)]
322 tx1b
.vout
= [CTxOut(1*COIN
, CScript([b
'a']))]
323 tx1b_hex
= txToHex(tx1b
)
324 tx1b_txid
= self
.nodes
[0].sendrawtransaction(tx1b_hex
, True)
325 tx1b_txid
= int(tx1b_txid
, 16)
328 tx2
.vin
= [CTxIn(utxo1
, nSequence
=0), CTxIn(utxo2
, nSequence
=0),
329 CTxIn(COutPoint(tx1b_txid
, 0))]
331 tx2_hex
= txToHex(tx2
)
333 # This will raise an exception
334 assert_raises_jsonrpc(-26, "bad-txns-spends-conflicting-tx", self
.nodes
[0].sendrawtransaction
, tx2_hex
, True)
336 def test_new_unconfirmed_inputs(self
):
337 """Replacements that add new unconfirmed inputs are rejected"""
338 confirmed_utxo
= make_utxo(self
.nodes
[0], int(1.1*COIN
))
339 unconfirmed_utxo
= make_utxo(self
.nodes
[0], int(0.1*COIN
), False)
342 tx1
.vin
= [CTxIn(confirmed_utxo
)]
343 tx1
.vout
= [CTxOut(1*COIN
, CScript([b
'a']))]
344 tx1_hex
= txToHex(tx1
)
345 self
.nodes
[0].sendrawtransaction(tx1_hex
, True)
348 tx2
.vin
= [CTxIn(confirmed_utxo
), CTxIn(unconfirmed_utxo
)]
350 tx2_hex
= txToHex(tx2
)
352 # This will raise an exception
353 assert_raises_jsonrpc(-26, "replacement-adds-unconfirmed", self
.nodes
[0].sendrawtransaction
, tx2_hex
, True)
355 def test_too_many_replacements(self
):
356 """Replacements that evict too many transactions are rejected"""
357 # Try directly replacing more than MAX_REPLACEMENT_LIMIT
360 # Start by creating a single transaction with many outputs
361 initial_nValue
= 10*COIN
362 utxo
= make_utxo(self
.nodes
[0], initial_nValue
)
363 fee
= int(0.0001*COIN
)
364 split_value
= int((initial_nValue
-fee
)/(MAX_REPLACEMENT_LIMIT
+1))
367 for i
in range(MAX_REPLACEMENT_LIMIT
+1):
368 outputs
.append(CTxOut(split_value
, CScript([1])))
370 splitting_tx
= CTransaction()
371 splitting_tx
.vin
= [CTxIn(utxo
, nSequence
=0)]
372 splitting_tx
.vout
= outputs
373 splitting_tx_hex
= txToHex(splitting_tx
)
375 txid
= self
.nodes
[0].sendrawtransaction(splitting_tx_hex
, True)
378 # Now spend each of those outputs individually
379 for i
in range(MAX_REPLACEMENT_LIMIT
+1):
380 tx_i
= CTransaction()
381 tx_i
.vin
= [CTxIn(COutPoint(txid
, i
), nSequence
=0)]
382 tx_i
.vout
= [CTxOut(split_value
-fee
, CScript([b
'a']))]
383 tx_i_hex
= txToHex(tx_i
)
384 self
.nodes
[0].sendrawtransaction(tx_i_hex
, True)
386 # Now create doublespend of the whole lot; should fail.
387 # Need a big enough fee to cover all spending transactions and have
389 double_spend_value
= (split_value
-100*fee
)*(MAX_REPLACEMENT_LIMIT
+1)
391 for i
in range(MAX_REPLACEMENT_LIMIT
+1):
392 inputs
.append(CTxIn(COutPoint(txid
, i
), nSequence
=0))
393 double_tx
= CTransaction()
394 double_tx
.vin
= inputs
395 double_tx
.vout
= [CTxOut(double_spend_value
, CScript([b
'a']))]
396 double_tx_hex
= txToHex(double_tx
)
398 # This will raise an exception
399 assert_raises_jsonrpc(-26, "too many potential replacements", self
.nodes
[0].sendrawtransaction
, double_tx_hex
, True)
401 # If we remove an input, it should pass
402 double_tx
= CTransaction()
403 double_tx
.vin
= inputs
[0:-1]
404 double_tx
.vout
= [CTxOut(double_spend_value
, CScript([b
'a']))]
405 double_tx_hex
= txToHex(double_tx
)
406 self
.nodes
[0].sendrawtransaction(double_tx_hex
, True)
408 def test_opt_in(self
):
409 """Replacing should only work if orig tx opted in"""
410 tx0_outpoint
= make_utxo(self
.nodes
[0], int(1.1*COIN
))
412 # Create a non-opting in transaction
413 tx1a
= CTransaction()
414 tx1a
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0xffffffff)]
415 tx1a
.vout
= [CTxOut(1*COIN
, CScript([b
'a']))]
416 tx1a_hex
= txToHex(tx1a
)
417 tx1a_txid
= self
.nodes
[0].sendrawtransaction(tx1a_hex
, True)
419 # Shouldn't be able to double-spend
420 tx1b
= CTransaction()
421 tx1b
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
422 tx1b
.vout
= [CTxOut(int(0.9*COIN
), CScript([b
'b']))]
423 tx1b_hex
= txToHex(tx1b
)
425 # This will raise an exception
426 assert_raises_jsonrpc(-26, "txn-mempool-conflict", self
.nodes
[0].sendrawtransaction
, tx1b_hex
, True)
428 tx1_outpoint
= make_utxo(self
.nodes
[0], int(1.1*COIN
))
430 # Create a different non-opting in transaction
431 tx2a
= CTransaction()
432 tx2a
.vin
= [CTxIn(tx1_outpoint
, nSequence
=0xfffffffe)]
433 tx2a
.vout
= [CTxOut(1*COIN
, CScript([b
'a']))]
434 tx2a_hex
= txToHex(tx2a
)
435 tx2a_txid
= self
.nodes
[0].sendrawtransaction(tx2a_hex
, True)
437 # Still shouldn't be able to double-spend
438 tx2b
= CTransaction()
439 tx2b
.vin
= [CTxIn(tx1_outpoint
, nSequence
=0)]
440 tx2b
.vout
= [CTxOut(int(0.9*COIN
), CScript([b
'b']))]
441 tx2b_hex
= txToHex(tx2b
)
443 # This will raise an exception
444 assert_raises_jsonrpc(-26, "txn-mempool-conflict", self
.nodes
[0].sendrawtransaction
, tx2b_hex
, True)
446 # Now create a new transaction that spends from tx1a and tx2a
447 # opt-in on one of the inputs
448 # Transaction should be replaceable on either input
450 tx1a_txid
= int(tx1a_txid
, 16)
451 tx2a_txid
= int(tx2a_txid
, 16)
453 tx3a
= CTransaction()
454 tx3a
.vin
= [CTxIn(COutPoint(tx1a_txid
, 0), nSequence
=0xffffffff),
455 CTxIn(COutPoint(tx2a_txid
, 0), nSequence
=0xfffffffd)]
456 tx3a
.vout
= [CTxOut(int(0.9*COIN
), CScript([b
'c'])), CTxOut(int(0.9*COIN
), CScript([b
'd']))]
457 tx3a_hex
= txToHex(tx3a
)
459 self
.nodes
[0].sendrawtransaction(tx3a_hex
, True)
461 tx3b
= CTransaction()
462 tx3b
.vin
= [CTxIn(COutPoint(tx1a_txid
, 0), nSequence
=0)]
463 tx3b
.vout
= [CTxOut(int(0.5*COIN
), CScript([b
'e']))]
464 tx3b_hex
= txToHex(tx3b
)
466 tx3c
= CTransaction()
467 tx3c
.vin
= [CTxIn(COutPoint(tx2a_txid
, 0), nSequence
=0)]
468 tx3c
.vout
= [CTxOut(int(0.5*COIN
), CScript([b
'f']))]
469 tx3c_hex
= txToHex(tx3c
)
471 self
.nodes
[0].sendrawtransaction(tx3b_hex
, True)
472 # If tx3b was accepted, tx3c won't look like a replacement,
473 # but make sure it is accepted anyway
474 self
.nodes
[0].sendrawtransaction(tx3c_hex
, True)
476 def test_prioritised_transactions(self
):
477 # Ensure that fee deltas used via prioritisetransaction are
478 # correctly used by replacement logic
480 # 1. Check that feeperkb uses modified fees
481 tx0_outpoint
= make_utxo(self
.nodes
[0], int(1.1*COIN
))
483 tx1a
= CTransaction()
484 tx1a
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
485 tx1a
.vout
= [CTxOut(1*COIN
, CScript([b
'a']))]
486 tx1a_hex
= txToHex(tx1a
)
487 tx1a_txid
= self
.nodes
[0].sendrawtransaction(tx1a_hex
, True)
489 # Higher fee, but the actual fee per KB is much lower.
490 tx1b
= CTransaction()
491 tx1b
.vin
= [CTxIn(tx0_outpoint
, nSequence
=0)]
492 tx1b
.vout
= [CTxOut(int(0.001*COIN
), CScript([b
'a'*740000]))]
493 tx1b_hex
= txToHex(tx1b
)
495 # Verify tx1b cannot replace tx1a.
496 assert_raises_jsonrpc(-26, "insufficient fee", self
.nodes
[0].sendrawtransaction
, tx1b_hex
, True)
498 # Use prioritisetransaction to set tx1a's fee to 0.
499 self
.nodes
[0].prioritisetransaction(txid
=tx1a_txid
, fee_delta
=int(-0.1*COIN
))
501 # Now tx1b should be able to replace tx1a
502 tx1b_txid
= self
.nodes
[0].sendrawtransaction(tx1b_hex
, True)
504 assert(tx1b_txid
in self
.nodes
[0].getrawmempool())
506 # 2. Check that absolute fee checks use modified fee.
507 tx1_outpoint
= make_utxo(self
.nodes
[0], int(1.1*COIN
))
509 tx2a
= CTransaction()
510 tx2a
.vin
= [CTxIn(tx1_outpoint
, nSequence
=0)]
511 tx2a
.vout
= [CTxOut(1*COIN
, CScript([b
'a']))]
512 tx2a_hex
= txToHex(tx2a
)
513 self
.nodes
[0].sendrawtransaction(tx2a_hex
, True)
515 # Lower fee, but we'll prioritise it
516 tx2b
= CTransaction()
517 tx2b
.vin
= [CTxIn(tx1_outpoint
, nSequence
=0)]
518 tx2b
.vout
= [CTxOut(int(1.01*COIN
), CScript([b
'a']))]
520 tx2b_hex
= txToHex(tx2b
)
522 # Verify tx2b cannot replace tx2a.
523 assert_raises_jsonrpc(-26, "insufficient fee", self
.nodes
[0].sendrawtransaction
, tx2b_hex
, True)
525 # Now prioritise tx2b to have a higher modified fee
526 self
.nodes
[0].prioritisetransaction(txid
=tx2b
.hash, fee_delta
=int(0.1*COIN
))
528 # tx2b should now be accepted
529 tx2b_txid
= self
.nodes
[0].sendrawtransaction(tx2b_hex
, True)
531 assert(tx2b_txid
in self
.nodes
[0].getrawmempool())
534 us0
= self
.nodes
[0].listunspent()[0]
536 outs
= {self
.nodes
[0].getnewaddress() : Decimal(1.0000000)}
537 rawtx0
= self
.nodes
[0].createrawtransaction(ins
, outs
, 0, True)
538 rawtx1
= self
.nodes
[0].createrawtransaction(ins
, outs
, 0, False)
539 json0
= self
.nodes
[0].decoderawtransaction(rawtx0
)
540 json1
= self
.nodes
[0].decoderawtransaction(rawtx1
)
541 assert_equal(json0
["vin"][0]["sequence"], 4294967293)
542 assert_equal(json1
["vin"][0]["sequence"], 4294967295)
544 rawtx2
= self
.nodes
[0].createrawtransaction([], outs
)
545 frawtx2a
= self
.nodes
[0].fundrawtransaction(rawtx2
, {"replaceable": True})
546 frawtx2b
= self
.nodes
[0].fundrawtransaction(rawtx2
, {"replaceable": False})
548 json0
= self
.nodes
[0].decoderawtransaction(frawtx2a
['hex'])
549 json1
= self
.nodes
[0].decoderawtransaction(frawtx2b
['hex'])
550 assert_equal(json0
["vin"][0]["sequence"], 4294967293)
551 assert_equal(json1
["vin"][0]["sequence"], 4294967294)
553 if __name__
== '__main__':
554 ReplaceByFeeTest().main()