From 110ff1142c5284edba8aab77fcac0bea0e551969 Mon Sep 17 00:00:00 2001
From: Jonas Schnelli <dev@jonasschnelli.ch>
Date: Mon, 30 Nov 2015 15:42:27 +0100
Subject: [PATCH] [Tests] Add mempool_limit.py test

---
 qa/pull-tester/rpc-tests.py   |   1 +
 qa/rpc-tests/mempool_limit.py | 119 ++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+)
 create mode 100755 qa/rpc-tests/mempool_limit.py

diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index df71e44b6..993646c50 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -83,6 +83,7 @@ testScripts = [
     'rest.py',
     'mempool_spendcoinbase.py',
     'mempool_reorg.py',
+    'mempool_limit.py',
     'httpbasics.py',
     'multi_rpc.py',
     'zapwallettxes.py',
diff --git a/qa/rpc-tests/mempool_limit.py b/qa/rpc-tests/mempool_limit.py
new file mode 100755
index 000000000..aeaaa29f3
--- /dev/null
+++ b/qa/rpc-tests/mempool_limit.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python2
+# Copyright (c) 2014-2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+# Test mempool limiting together/eviction with the wallet
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+class MempoolLimitTest(BitcoinTestFramework):
+
+    def satoshi_round(self, amount):
+        return  Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
+
+    def __init__(self):
+        # Some pre-processing to create a bunch of OP_RETURN txouts to insert into transactions we create
+        # So we have big transactions (and therefore can't fit very many into each block)
+        # create one script_pubkey
+        script_pubkey = "6a4d0200" #OP_RETURN OP_PUSH2 512 bytes
+        for i in xrange (512):
+            script_pubkey = script_pubkey + "01"
+        # concatenate 128 txouts of above script_pubkey which we'll insert before the txout for change
+        self.txouts = "81"
+        for k in xrange(128):
+            # add txout value
+            self.txouts = self.txouts + "0000000000000000"
+            # add length of script_pubkey
+            self.txouts = self.txouts + "fd0402"
+            # add script_pubkey
+            self.txouts = self.txouts + script_pubkey
+
+    def create_confirmed_utxos(self, count):
+        self.nodes[0].generate(int(0.5*90)+102)
+        utxos = self.nodes[0].listunspent()
+        iterations = count - len(utxos)
+        addr1 = self.nodes[0].getnewaddress()
+        addr2 = self.nodes[0].getnewaddress()
+        if iterations <= 0:
+            return utxos
+        for i in xrange(iterations):
+            t = utxos.pop()
+            fee = self.relayfee
+            inputs = []
+            inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
+            outputs = {}
+            send_value = t['amount'] - fee
+            outputs[addr1] = self.satoshi_round(send_value/2)
+            outputs[addr2] = self.satoshi_round(send_value/2)
+            raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
+            signed_tx = self.nodes[0].signrawtransaction(raw_tx)["hex"]
+            txid = self.nodes[0].sendrawtransaction(signed_tx)
+
+        while (self.nodes[0].getmempoolinfo()['size'] > 0):
+            self.nodes[0].generate(1)
+
+        utxos = self.nodes[0].listunspent()
+        assert(len(utxos) >= count)
+        return utxos
+
+    def create_lots_of_big_transactions(self, utxos, fee):
+        addr = self.nodes[0].getnewaddress()
+        txids = []
+        for i in xrange(len(utxos)):
+            t = utxos.pop()
+            inputs = []
+            inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
+            outputs = {}
+            send_value = t['amount'] - fee
+            outputs[addr] = self.satoshi_round(send_value)
+            rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+            newtx = rawtx[0:92]
+            newtx = newtx + self.txouts
+            newtx = newtx + rawtx[94:]
+            signresult = self.nodes[0].signrawtransaction(newtx, None, None, "NONE")
+            txid = self.nodes[0].sendrawtransaction(signresult["hex"], True)
+            txids.append(txid)
+        return txids
+                    
+    def setup_network(self):
+        self.nodes = []
+        self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0", "-debug"]))
+        self.nodes.append(start_node(1, self.options.tmpdir, []))
+        connect_nodes(self.nodes[0], 1)
+        self.is_network_split = False
+        self.sync_all()
+        self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
+
+    def setup_chain(self):
+        print("Initializing test directory "+self.options.tmpdir)
+        initialize_chain_clean(self.options.tmpdir, 2)
+
+    def run_test(self):
+        txids = []
+        utxos = self.create_confirmed_utxos(90)
+
+        #create a mempool tx that will be evicted
+        us0 = utxos.pop()
+        inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}]
+        outputs = {self.nodes[1].getnewaddress() : 0.0001}
+        tx = self.nodes[0].createrawtransaction(inputs, outputs)
+        txF = self.nodes[0].fundrawtransaction(tx)
+        txFS = self.nodes[0].signrawtransaction(txF['hex'])
+        txid = self.nodes[0].sendrawtransaction(txFS['hex'])
+        self.nodes[0].lockunspent(True, [us0])
+
+        relayfee = self.nodes[0].getnetworkinfo()['relayfee']
+        base_fee = relayfee*100
+        for i in xrange (4):
+            txids.append([])
+            txids[i] = self.create_lots_of_big_transactions(utxos[30*i:30*i+30], (i+1)*base_fee)
+
+        # by now, the tx should be evicted, check confirmation state
+        assert(txid not in self.nodes[0].getrawmempool())
+        txdata = self.nodes[0].gettransaction(txid);
+        assert(txdata['confirmations'] ==  0) #confirmation should still be 0
+
+if __name__ == '__main__':
+    MempoolLimitTest().main()