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