@@ -307,5 +307,53 @@ def test_new_unconfirmed_inputs(self):
307
307
else :
308
308
self .fail ()
309
309
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
+
310
358
if __name__ == '__main__' :
311
359
unittest .main ()
0 commit comments