2
# Copyright (c) 2014-2015 The Bitcoin Core developers
2
# Copyright (c) 2014-2016 The Bitcoin Core developers
3
3
# Distributed under the MIT software license, see the accompanying
4
4
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
11
11
from test_framework.util import *
12
12
from test_framework.script import *
13
13
from test_framework.mininode import *
17
15
MAX_REPLACEMENT_LIMIT = 100
19
def satoshi_round(amount):
20
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
23
return binascii.hexlify(tx.serialize()).decode('utf-8')
18
return bytes_to_hex_str(tx.serialize())
25
20
def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
26
21
"""Create a txout with a given amount and scriptPubKey
54
49
tx2.vout = [CTxOut(amount, scriptPubKey)]
57
binascii.hexlify(tx2.serialize()).decode('utf-8')
59
signed_tx = node.signrawtransaction(binascii.hexlify(tx2.serialize()).decode('utf-8'))
52
signed_tx = node.signrawtransaction(txToHex(tx2))
61
54
txid = node.sendrawtransaction(signed_tx['hex'], True)
76
69
class ReplaceByFeeTest(BitcoinTestFramework):
74
self.setup_clean_chain = False
78
76
def setup_network(self):
80
78
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug",
89
87
def run_test(self):
90
88
make_utxo(self.nodes[0], 1*COIN)
92
print "Running test simple doublespend..."
90
print("Running test simple doublespend...")
93
91
self.test_simple_doublespend()
95
print "Running test doublespend chain..."
93
print("Running test doublespend chain...")
96
94
self.test_doublespend_chain()
98
print "Running test doublespend tree..."
96
print("Running test doublespend tree...")
99
97
self.test_doublespend_tree()
101
print "Running test replacement feeperkb..."
99
print("Running test replacement feeperkb...")
102
100
self.test_replacement_feeperkb()
104
print "Running test spends of conflicting outputs..."
102
print("Running test spends of conflicting outputs...")
105
103
self.test_spends_of_conflicting_outputs()
107
print "Running test new unconfirmed inputs..."
105
print("Running test new unconfirmed inputs...")
108
106
self.test_new_unconfirmed_inputs()
110
print "Running test too many replacements..."
108
print("Running test too many replacements...")
111
109
self.test_too_many_replacements()
113
print "Running test opt-in..."
111
print("Running test opt-in...")
114
112
self.test_opt_in()
116
print "Running test prioritised transactions..."
114
print("Running test prioritised transactions...")
117
115
self.test_prioritised_transactions()
121
119
def test_simple_doublespend(self):
122
120
"""Simple doublespend"""
123
tx0_outpoint = make_utxo(self.nodes[0], 1.1*COIN)
121
tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
125
123
tx1a = CTransaction()
126
124
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
144
142
# Extra 0.1 BTC fee
145
143
tx1b = CTransaction()
146
144
tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
147
tx1b.vout = [CTxOut(0.9*COIN, CScript([b'b']))]
145
tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))]
148
146
tx1b_hex = txToHex(tx1b)
149
147
tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
236
234
_total_txs=_total_txs):
237
fee = int(0.0001*COIN)
240
238
n = MAX_REPLACEMENT_LIMIT
241
239
tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
242
240
assert_equal(len(tree_txs), n)
269
267
# Try again, but with more total transactions than the "max txs
270
268
# double-spent at once" anti-DoS limit.
271
269
for n in (MAX_REPLACEMENT_LIMIT+1, MAX_REPLACEMENT_LIMIT*2):
270
fee = int(0.0001*COIN)
273
271
tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)
274
272
tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
275
273
assert_equal(len(tree_txs), n)
293
291
def test_replacement_feeperkb(self):
294
292
"""Replacement requires fee-per-KB to be higher"""
295
tx0_outpoint = make_utxo(self.nodes[0], 1.1*COIN)
293
tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
297
295
tx1a = CTransaction()
298
296
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
305
303
tx1b = CTransaction()
306
304
tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
307
tx1b.vout = [CTxOut(0.001*COIN, CScript([b'a'*999000]))]
305
tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*999000]))]
308
306
tx1b_hex = txToHex(tx1b)
317
315
def test_spends_of_conflicting_outputs(self):
318
316
"""Replacements that spend conflicting tx outputs are rejected"""
319
utxo1 = make_utxo(self.nodes[0], 1.2*COIN)
320
utxo2 = make_utxo(self.nodes[0], 3.0*COIN)
317
utxo1 = make_utxo(self.nodes[0], int(1.2*COIN))
318
utxo2 = make_utxo(self.nodes[0], 3*COIN)
322
320
tx1a = CTransaction()
323
321
tx1a.vin = [CTxIn(utxo1, nSequence=0)]
324
tx1a.vout = [CTxOut(1.1*COIN, CScript([b'a']))]
322
tx1a.vout = [CTxOut(int(1.1*COIN), CScript([b'a']))]
325
323
tx1a_hex = txToHex(tx1a)
326
324
tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
344
342
# Spend tx1a's output to test the indirect case.
345
343
tx1b = CTransaction()
346
344
tx1b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
347
tx1b.vout = [CTxOut(1.0*COIN, CScript([b'a']))]
345
tx1b.vout = [CTxOut(1*COIN, CScript([b'a']))]
348
346
tx1b_hex = txToHex(tx1b)
349
347
tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
350
348
tx1b_txid = int(tx1b_txid, 16)
365
363
def test_new_unconfirmed_inputs(self):
366
364
"""Replacements that add new unconfirmed inputs are rejected"""
367
confirmed_utxo = make_utxo(self.nodes[0], 1.1*COIN)
368
unconfirmed_utxo = make_utxo(self.nodes[0], 0.1*COIN, False)
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)
370
368
tx1 = CTransaction()
371
369
tx1.vin = [CTxIn(confirmed_utxo)]
372
tx1.vout = [CTxOut(1.0*COIN, CScript([b'a']))]
370
tx1.vout = [CTxOut(1*COIN, CScript([b'a']))]
373
371
tx1_hex = txToHex(tx1)
374
372
tx1_txid = self.nodes[0].sendrawtransaction(tx1_hex, True)
393
391
# Start by creating a single transaction with many outputs
394
392
initial_nValue = 10*COIN
395
393
utxo = make_utxo(self.nodes[0], initial_nValue)
394
fee = int(0.0001*COIN)
397
395
split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1))
398
396
actual_fee = initial_nValue - split_value*(MAX_REPLACEMENT_LIMIT+1)
447
445
def test_opt_in(self):
448
446
""" Replacing should only work if orig tx opted in """
449
tx0_outpoint = make_utxo(self.nodes[0], 1.1*COIN)
447
tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
451
449
# Create a non-opting in transaction
452
450
tx1a = CTransaction()
458
456
# Shouldn't be able to double-spend
459
457
tx1b = CTransaction()
460
458
tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
461
tx1b.vout = [CTxOut(0.9*COIN, CScript([b'b']))]
459
tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))]
462
460
tx1b_hex = txToHex(tx1b)
466
464
except JSONRPCException as exp:
467
465
assert_equal(exp.error['code'], -26)
472
tx1_outpoint = make_utxo(self.nodes[0], 1.1*COIN)
470
tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
474
472
# Create a different non-opting in transaction
475
473
tx2a = CTransaction()
481
479
# Still shouldn't be able to double-spend
482
480
tx2b = CTransaction()
483
481
tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]
484
tx2b.vout = [CTxOut(0.9*COIN, CScript([b'b']))]
482
tx2b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))]
485
483
tx2b_hex = txToHex(tx2b)
501
499
tx3a = CTransaction()
502
500
tx3a.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0xffffffff),
503
501
CTxIn(COutPoint(tx2a_txid, 0), nSequence=0xfffffffd)]
504
tx3a.vout = [CTxOut(0.9*COIN, CScript([b'c'])), CTxOut(0.9*COIN, CScript([b'd']))]
502
tx3a.vout = [CTxOut(int(0.9*COIN), CScript([b'c'])), CTxOut(int(0.9*COIN), CScript([b'd']))]
505
503
tx3a_hex = txToHex(tx3a)
507
505
self.nodes[0].sendrawtransaction(tx3a_hex, True)
509
507
tx3b = CTransaction()
510
508
tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
511
tx3b.vout = [CTxOut(0.5*COIN, CScript([b'e']))]
509
tx3b.vout = [CTxOut(int(0.5*COIN), CScript([b'e']))]
512
510
tx3b_hex = txToHex(tx3b)
514
512
tx3c = CTransaction()
515
513
tx3c.vin = [CTxIn(COutPoint(tx2a_txid, 0), nSequence=0)]
516
tx3c.vout = [CTxOut(0.5*COIN, CScript([b'f']))]
514
tx3c.vout = [CTxOut(int(0.5*COIN), CScript([b'f']))]
517
515
tx3c_hex = txToHex(tx3c)
519
517
self.nodes[0].sendrawtransaction(tx3b_hex, True)
526
524
# correctly used by replacement logic
528
526
# 1. Check that feeperkb uses modified fees
529
tx0_outpoint = make_utxo(self.nodes[0], 1.1*COIN)
527
tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
531
529
tx1a = CTransaction()
532
530
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
537
535
# Higher fee, but the actual fee per KB is much lower.
538
536
tx1b = CTransaction()
539
537
tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
540
tx1b.vout = [CTxOut(0.001*COIN, CScript([b'a'*740000]))]
538
tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*740000]))]
541
539
tx1b_hex = txToHex(tx1b)
543
541
# Verify tx1b cannot replace tx1a.
557
555
assert(tx1b_txid in self.nodes[0].getrawmempool())
559
557
# 2. Check that absolute fee checks use modified fee.
560
tx1_outpoint = make_utxo(self.nodes[0], 1.1*COIN)
558
tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
562
560
tx2a = CTransaction()
563
561
tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0)]
568
566
# Lower fee, but we'll prioritise it
569
567
tx2b = CTransaction()
570
568
tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]
571
tx2b.vout = [CTxOut(1.01*COIN, CScript([b'a']))]
569
tx2b.vout = [CTxOut(int(1.01*COIN), CScript([b'a']))]
573
571
tx2b_hex = txToHex(tx2b)