Skip to content

Commit 20367d8

Browse files
sdaftuarpetertodd
authored andcommitted
Add test for max replacement limit
1 parent 73d9040 commit 20367d8

File tree

1 file changed

+48
-0
lines changed

1 file changed

+48
-0
lines changed

qa/replace-by-fee/rbf-tests.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,5 +307,53 @@ def test_new_unconfirmed_inputs(self):
307307
else:
308308
self.fail()
309309

310+
def test_too_many_replacements(self):
311+
"""Replacements that evict too many transactions are rejected"""
312+
# Try directly replacing more than MAX_REPLACEMENT_LIMIT
313+
# transactions
314+
315+
# Start by creating a single transaction with many outputs
316+
initial_nValue = 10*COIN
317+
utxo = self.make_txout(initial_nValue)
318+
fee = 0.0001*COIN
319+
split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1))
320+
actual_fee = initial_nValue - split_value*(MAX_REPLACEMENT_LIMIT+1)
321+
322+
outputs = []
323+
for i in range(MAX_REPLACEMENT_LIMIT+1):
324+
outputs.append(CTxOut(split_value, CScript([1])))
325+
326+
splitting_tx = CTransaction([CTxIn(utxo, nSequence=0)], outputs)
327+
txid = self.proxy.sendrawtransaction(splitting_tx, True)
328+
329+
# Now spend each of those outputs individually
330+
for i in range(MAX_REPLACEMENT_LIMIT+1):
331+
tx_i = CTransaction([CTxIn(COutPoint(txid, i), nSequence=0)],
332+
[CTxOut(split_value-fee, CScript([b'a']))])
333+
self.proxy.sendrawtransaction(tx_i, True)
334+
335+
# Now create doublespend of the whole lot, should fail
336+
# Need a big enough fee to cover all spending transactions and have
337+
# a higher fee rate
338+
double_spend_value = (split_value-100*fee)*(MAX_REPLACEMENT_LIMIT+1)
339+
inputs = []
340+
for i in range(MAX_REPLACEMENT_LIMIT+1):
341+
inputs.append(CTxIn(COutPoint(txid, i), nSequence=0))
342+
double_tx = CTransaction(inputs, [CTxOut(double_spend_value, CScript([b'a']))])
343+
344+
try:
345+
self.proxy.sendrawtransaction(double_tx, True)
346+
except bitcoin.rpc.JSONRPCException as exp:
347+
self.assertEqual(exp.error['code'], -26)
348+
self.assertEqual("too many potential replacements" in exp.error['message'], True)
349+
else:
350+
self.fail()
351+
352+
# If we remove an input, it should pass
353+
double_tx = CTransaction(inputs[0:-1],
354+
[CTxOut(double_spend_value, CScript([b'a']))])
355+
356+
self.proxy.sendrawtransaction(double_tx, True)
357+
310358
if __name__ == '__main__':
311359
unittest.main()

0 commit comments

Comments
 (0)