aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xqa/replace-by-fee/rbf-tests.py48
1 files changed, 48 insertions, 0 deletions
diff --git a/qa/replace-by-fee/rbf-tests.py b/qa/replace-by-fee/rbf-tests.py
index b48748fb4b..60be905262 100755
--- a/qa/replace-by-fee/rbf-tests.py
+++ b/qa/replace-by-fee/rbf-tests.py
@@ -307,5 +307,53 @@ class Test_ReplaceByFee(unittest.TestCase):
else:
self.fail()
+ def test_too_many_replacements(self):
+ """Replacements that evict too many transactions are rejected"""
+ # Try directly replacing more than MAX_REPLACEMENT_LIMIT
+ # transactions
+
+ # Start by creating a single transaction with many outputs
+ initial_nValue = 10*COIN
+ utxo = self.make_txout(initial_nValue)
+ fee = 0.0001*COIN
+ split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1))
+ actual_fee = initial_nValue - split_value*(MAX_REPLACEMENT_LIMIT+1)
+
+ outputs = []
+ for i in range(MAX_REPLACEMENT_LIMIT+1):
+ outputs.append(CTxOut(split_value, CScript([1])))
+
+ splitting_tx = CTransaction([CTxIn(utxo, nSequence=0)], outputs)
+ txid = self.proxy.sendrawtransaction(splitting_tx, True)
+
+ # Now spend each of those outputs individually
+ for i in range(MAX_REPLACEMENT_LIMIT+1):
+ tx_i = CTransaction([CTxIn(COutPoint(txid, i), nSequence=0)],
+ [CTxOut(split_value-fee, CScript([b'a']))])
+ self.proxy.sendrawtransaction(tx_i, True)
+
+ # Now create doublespend of the whole lot, should fail
+ # Need a big enough fee to cover all spending transactions and have
+ # a higher fee rate
+ double_spend_value = (split_value-100*fee)*(MAX_REPLACEMENT_LIMIT+1)
+ inputs = []
+ for i in range(MAX_REPLACEMENT_LIMIT+1):
+ inputs.append(CTxIn(COutPoint(txid, i), nSequence=0))
+ double_tx = CTransaction(inputs, [CTxOut(double_spend_value, CScript([b'a']))])
+
+ try:
+ self.proxy.sendrawtransaction(double_tx, True)
+ except bitcoin.rpc.JSONRPCException as exp:
+ self.assertEqual(exp.error['code'], -26)
+ self.assertEqual("too many potential replacements" in exp.error['message'], True)
+ else:
+ self.fail()
+
+ # If we remove an input, it should pass
+ double_tx = CTransaction(inputs[0:-1],
+ [CTxOut(double_spend_value, CScript([b'a']))])
+
+ self.proxy.sendrawtransaction(double_tx, True)
+
if __name__ == '__main__':
unittest.main()