From b272ecfdb39f976dd61e35bacb22047da02b3416 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Fri, 30 Oct 2015 00:04:00 -0400 Subject: Reject replacements that add new unconfirmed inputs --- qa/replace-by-fee/rbf-tests.py | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) (limited to 'qa/replace-by-fee/rbf-tests.py') diff --git a/qa/replace-by-fee/rbf-tests.py b/qa/replace-by-fee/rbf-tests.py index 5173da6412..b48748fb4b 100755 --- a/qa/replace-by-fee/rbf-tests.py +++ b/qa/replace-by-fee/rbf-tests.py @@ -35,11 +35,11 @@ class Test_ReplaceByFee(unittest.TestCase): cls.proxy = bitcoin.rpc.Proxy() @classmethod - def tearDownClass(cls): - # Make sure mining works + def mine_mempool(cls): + """Mine until mempool is empty""" mempool_size = 1 while mempool_size: - cls.proxy.call('generate',1) + cls.proxy.call('generate', 1) new_mempool_size = len(cls.proxy.getrawmempool()) # It's possible to get stuck in a loop here if the mempool has @@ -47,10 +47,18 @@ class Test_ReplaceByFee(unittest.TestCase): assert(new_mempool_size != mempool_size) mempool_size = new_mempool_size - def make_txout(self, amount, scriptPubKey=CScript([1])): + @classmethod + def tearDownClass(cls): + # Make sure mining works + cls.mine_mempool() + + def make_txout(self, amount, confirmed=True, scriptPubKey=CScript([1])): """Create a txout with a given amount and scriptPubKey Mines coins as needed. + + confirmed - txouts created will be confirmed in the blockchain; + unconfirmed otherwise. """ fee = 1*COIN while self.proxy.getbalance() < amount + fee: @@ -72,6 +80,10 @@ class Test_ReplaceByFee(unittest.TestCase): tx2_txid = self.proxy.sendrawtransaction(tx2, True) + # If requested, ensure txouts are confirmed. + if confirmed: + self.mine_mempool() + return COutPoint(tx2_txid, 0) def test_simple_doublespend(self): @@ -276,5 +288,24 @@ class Test_ReplaceByFee(unittest.TestCase): else: self.fail() + def test_new_unconfirmed_inputs(self): + """Replacements that add new unconfirmed inputs are rejected""" + confirmed_utxo = self.make_txout(1.1*COIN) + unconfirmed_utxo = self.make_txout(0.1*COIN, False) + + tx1 = CTransaction([CTxIn(confirmed_utxo)], + [CTxOut(1.0*COIN, CScript([b'a']))]) + tx1_txid = self.proxy.sendrawtransaction(tx1, True) + + tx2 = CTransaction([CTxIn(confirmed_utxo), CTxIn(unconfirmed_utxo)], + tx1.vout) + + try: + tx2_txid = self.proxy.sendrawtransaction(tx2, True) + except bitcoin.rpc.JSONRPCException as exp: + self.assertEqual(exp.error['code'], -26) + else: + self.fail() + if __name__ == '__main__': unittest.main() -- cgit v1.2.3