scripted-diff: Use the C++11 keyword nullptr to denote the pointer literal instead...
[bitcoinplatinum.git] / test / functional / abandonconflict.py
blobc87c02492d7cc488196706311d65bff7f284ff81
1 #!/usr/bin/env python3
2 # Copyright (c) 2014-2016 The Bitcoin Core developers
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 """Test the abandontransaction RPC.
7 The abandontransaction RPC marks a transaction and all its in-wallet
8 descendants as abandoned which allows their inputs to be respent. It can be
9 used to replace "stuck" or evicted transactions. It only works on transactions
10 which are not included in a block and are not currently in the mempool. It has
11 no effect on transactions which are already conflicted or abandoned.
12 """
13 from test_framework.test_framework import BitcoinTestFramework
14 from test_framework.util import *
16 class AbandonConflictTest(BitcoinTestFramework):
17 def __init__(self):
18 super().__init__()
19 self.num_nodes = 2
20 self.setup_clean_chain = False
21 self.extra_args = [["-minrelaytxfee=0.00001"], []]
23 def run_test(self):
24 self.nodes[1].generate(100)
25 sync_blocks(self.nodes)
26 balance = self.nodes[0].getbalance()
27 txA = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
28 txB = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
29 txC = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
30 sync_mempools(self.nodes)
31 self.nodes[1].generate(1)
33 sync_blocks(self.nodes)
34 newbalance = self.nodes[0].getbalance()
35 assert(balance - newbalance < Decimal("0.001")) #no more than fees lost
36 balance = newbalance
38 # Disconnect nodes so node0's transactions don't get into node1's mempool
39 disconnect_nodes(self.nodes[0], 1)
41 # Identify the 10btc outputs
42 nA = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txA, 1)["vout"]) if vout["value"] == Decimal("10"))
43 nB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txB, 1)["vout"]) if vout["value"] == Decimal("10"))
44 nC = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txC, 1)["vout"]) if vout["value"] == Decimal("10"))
46 inputs =[]
47 # spend 10btc outputs from txA and txB
48 inputs.append({"txid":txA, "vout":nA})
49 inputs.append({"txid":txB, "vout":nB})
50 outputs = {}
52 outputs[self.nodes[0].getnewaddress()] = Decimal("14.99998")
53 outputs[self.nodes[1].getnewaddress()] = Decimal("5")
54 signed = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))
55 txAB1 = self.nodes[0].sendrawtransaction(signed["hex"])
57 # Identify the 14.99998btc output
58 nAB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txAB1, 1)["vout"]) if vout["value"] == Decimal("14.99998"))
60 #Create a child tx spending AB1 and C
61 inputs = []
62 inputs.append({"txid":txAB1, "vout":nAB})
63 inputs.append({"txid":txC, "vout":nC})
64 outputs = {}
65 outputs[self.nodes[0].getnewaddress()] = Decimal("24.9996")
66 signed2 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))
67 txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"])
69 # In mempool txs from self should increase balance from change
70 newbalance = self.nodes[0].getbalance()
71 assert_equal(newbalance, balance - Decimal("30") + Decimal("24.9996"))
72 balance = newbalance
74 # Restart the node with a higher min relay fee so the parent tx is no longer in mempool
75 # TODO: redo with eviction
76 self.stop_node(0)
77 self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
79 # Verify txs no longer in either node's mempool
80 assert_equal(len(self.nodes[0].getrawmempool()), 0)
81 assert_equal(len(self.nodes[1].getrawmempool()), 0)
83 # Not in mempool txs from self should only reduce balance
84 # inputs are still spent, but change not received
85 newbalance = self.nodes[0].getbalance()
86 assert_equal(newbalance, balance - Decimal("24.9996"))
87 # Unconfirmed received funds that are not in mempool, also shouldn't show
88 # up in unconfirmed balance
89 unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()
90 assert_equal(unconfbalance, newbalance)
91 # Also shouldn't show up in listunspent
92 assert(not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)])
93 balance = newbalance
95 # Abandon original transaction and verify inputs are available again
96 # including that the child tx was also abandoned
97 self.nodes[0].abandontransaction(txAB1)
98 newbalance = self.nodes[0].getbalance()
99 assert_equal(newbalance, balance + Decimal("30"))
100 balance = newbalance
102 # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned
103 self.stop_node(0)
104 self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"])
105 assert_equal(len(self.nodes[0].getrawmempool()), 0)
106 assert_equal(self.nodes[0].getbalance(), balance)
108 # But if its received again then it is unabandoned
109 # And since now in mempool, the change is available
110 # But its child tx remains abandoned
111 self.nodes[0].sendrawtransaction(signed["hex"])
112 newbalance = self.nodes[0].getbalance()
113 assert_equal(newbalance, balance - Decimal("20") + Decimal("14.99998"))
114 balance = newbalance
116 # Send child tx again so its unabandoned
117 self.nodes[0].sendrawtransaction(signed2["hex"])
118 newbalance = self.nodes[0].getbalance()
119 assert_equal(newbalance, balance - Decimal("10") - Decimal("14.99998") + Decimal("24.9996"))
120 balance = newbalance
122 # Remove using high relay fee again
123 self.stop_node(0)
124 self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
125 assert_equal(len(self.nodes[0].getrawmempool()), 0)
126 newbalance = self.nodes[0].getbalance()
127 assert_equal(newbalance, balance - Decimal("24.9996"))
128 balance = newbalance
130 # Create a double spend of AB1 by spending again from only A's 10 output
131 # Mine double spend from node 1
132 inputs =[]
133 inputs.append({"txid":txA, "vout":nA})
134 outputs = {}
135 outputs[self.nodes[1].getnewaddress()] = Decimal("9.9999")
136 tx = self.nodes[0].createrawtransaction(inputs, outputs)
137 signed = self.nodes[0].signrawtransaction(tx)
138 self.nodes[1].sendrawtransaction(signed["hex"])
139 self.nodes[1].generate(1)
141 connect_nodes(self.nodes[0], 1)
142 sync_blocks(self.nodes)
144 # Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted
145 newbalance = self.nodes[0].getbalance()
146 assert_equal(newbalance, balance + Decimal("20"))
147 balance = newbalance
149 # There is currently a minor bug around this and so this test doesn't work. See Issue #7315
150 # Invalidate the block with the double spend and B's 10 BTC output should no longer be available
151 # Don't think C's should either
152 self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
153 newbalance = self.nodes[0].getbalance()
154 #assert_equal(newbalance, balance - Decimal("10"))
155 self.log.info("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
156 self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
157 self.log.info(str(balance) + " -> " + str(newbalance) + " ?")
159 if __name__ == '__main__':
160 AbandonConflictTest().main()