Changeset View
Changeset View
Standalone View
Standalone View
test/functional/wallet_txn_doublespend.py
Show All 12 Lines | from test_framework.util import ( | ||||
find_output, | find_output, | ||||
sync_blocks, | sync_blocks, | ||||
) | ) | ||||
class TxnMallTest(BitcoinTestFramework): | class TxnMallTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.num_nodes = 4 | self.num_nodes = 4 | ||||
self.extra_args = [["-noparkdeepreorg", '-deprecatedrpc=accounts'], | self.extra_args = [["-noparkdeepreorg"], ["-noparkdeepreorg"], [], []] | ||||
["-noparkdeepreorg", '-deprecatedrpc=accounts'], | |||||
['-deprecatedrpc=accounts'], ['-deprecatedrpc=accounts']] | |||||
def add_options(self, parser): | def add_options(self, parser): | ||||
parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true", | parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true", | ||||
help="Test double-spend of 1-confirmed transaction") | help="Test double-spend of 1-confirmed transaction") | ||||
def setup_network(self): | def setup_network(self): | ||||
# Start with split network: | # Start with split network: | ||||
super().setup_network() | super().setup_network() | ||||
disconnect_nodes(self.nodes[1], self.nodes[2]) | disconnect_nodes(self.nodes[1], self.nodes[2]) | ||||
disconnect_nodes(self.nodes[2], self.nodes[1]) | disconnect_nodes(self.nodes[2], self.nodes[1]) | ||||
def run_test(self): | def run_test(self): | ||||
# All nodes should start with 1,250 BCH: | # All nodes should start with 1,250 BCH: | ||||
starting_balance = 1250 | starting_balance = 1250 | ||||
for i in range(4): | for i in range(4): | ||||
assert_equal(self.nodes[i].getbalance(), starting_balance) | assert_equal(self.nodes[i].getbalance(), starting_balance) | ||||
# bug workaround, coins generated assigned to first getnewaddress! | # bug workaround, coins generated assigned to first getnewaddress! | ||||
self.nodes[i].getnewaddress("") | self.nodes[i].getnewaddress("") | ||||
# Assign coins to foo and bar accounts: | # Assign coins to foo and bar addresses: | ||||
node0_address_foo = self.nodes[0].getnewaddress("foo") | node0_address_foo = self.nodes[0].getnewaddress() | ||||
fund_foo_txid = self.nodes[0].sendfrom("", node0_address_foo, 1219) | fund_foo_txid = self.nodes[0].sendtoaddress(node0_address_foo, 1219) | ||||
fund_foo_tx = self.nodes[0].gettransaction(fund_foo_txid) | fund_foo_tx = self.nodes[0].gettransaction(fund_foo_txid) | ||||
node0_address_bar = self.nodes[0].getnewaddress("bar") | node0_address_bar = self.nodes[0].getnewaddress() | ||||
fund_bar_txid = self.nodes[0].sendfrom("", node0_address_bar, 29) | fund_bar_txid = self.nodes[0].sendtoaddress(node0_address_bar, 29) | ||||
fund_bar_tx = self.nodes[0].gettransaction(fund_bar_txid) | fund_bar_tx = self.nodes[0].gettransaction(fund_bar_txid) | ||||
assert_equal(self.nodes[0].getbalance(""), | assert_equal(self.nodes[0].getbalance(), | ||||
starting_balance - 1219 - 29 + fund_foo_tx["fee"] + fund_bar_tx["fee"]) | starting_balance + fund_foo_tx["fee"] + fund_bar_tx["fee"]) | ||||
# Coins are sent to node1_address | # Coins are sent to node1_address | ||||
node1_address = self.nodes[1].getnewaddress("from0") | node1_address = self.nodes[1].getnewaddress() | ||||
# First: use raw transaction API to send 1240 BCH to node1_address, | # First: use raw transaction API to send 1240 BCH to node1_address, | ||||
# but don't broadcast: | # but don't broadcast: | ||||
doublespend_fee = Decimal('-.02') | doublespend_fee = Decimal('-.02') | ||||
rawtx_input_0 = {} | rawtx_input_0 = {} | ||||
rawtx_input_0["txid"] = fund_foo_txid | rawtx_input_0["txid"] = fund_foo_txid | ||||
rawtx_input_0["vout"] = find_output(self.nodes[0], fund_foo_txid, 1219) | rawtx_input_0["vout"] = find_output(self.nodes[0], fund_foo_txid, 1219) | ||||
rawtx_input_1 = {} | rawtx_input_1 = {} | ||||
rawtx_input_1["txid"] = fund_bar_txid | rawtx_input_1["txid"] = fund_bar_txid | ||||
rawtx_input_1["vout"] = find_output(self.nodes[0], fund_bar_txid, 29) | rawtx_input_1["vout"] = find_output(self.nodes[0], fund_bar_txid, 29) | ||||
inputs = [rawtx_input_0, rawtx_input_1] | inputs = [rawtx_input_0, rawtx_input_1] | ||||
change_address = self.nodes[0].getnewaddress() | change_address = self.nodes[0].getnewaddress() | ||||
outputs = {} | outputs = {} | ||||
outputs[node1_address] = 1240 | outputs[node1_address] = 1240 | ||||
outputs[change_address] = 1248 - 1240 + doublespend_fee | outputs[change_address] = 1248 - 1240 + doublespend_fee | ||||
rawtx = self.nodes[0].createrawtransaction(inputs, outputs) | rawtx = self.nodes[0].createrawtransaction(inputs, outputs) | ||||
doublespend = self.nodes[0].signrawtransactionwithwallet(rawtx) | doublespend = self.nodes[0].signrawtransactionwithwallet(rawtx) | ||||
assert_equal(doublespend["complete"], True) | assert_equal(doublespend["complete"], True) | ||||
# Create two spends using 1 50 BCH coin each | # Create two spends using 1 50 BCH coin each | ||||
txid1 = self.nodes[0].sendfrom("foo", node1_address, 40, 0) | txid1 = self.nodes[0].sendtoaddress(node1_address, 40) | ||||
txid2 = self.nodes[0].sendfrom("bar", node1_address, 20, 0) | txid2 = self.nodes[0].sendtoaddress(node1_address, 20) | ||||
# Have node0 mine a block: | # Have node0 mine a block: | ||||
if (self.options.mine_block): | if (self.options.mine_block): | ||||
self.nodes[0].generate(1) | self.nodes[0].generate(1) | ||||
sync_blocks(self.nodes[0:2]) | sync_blocks(self.nodes[0:2]) | ||||
tx1 = self.nodes[0].gettransaction(txid1) | tx1 = self.nodes[0].gettransaction(txid1) | ||||
tx2 = self.nodes[0].gettransaction(txid2) | tx2 = self.nodes[0].gettransaction(txid2) | ||||
# Node0's balance should be starting balance, plus 50BTC for another | # Node0's balance should be starting balance, plus 50BTC for another | ||||
# matured block, minus 40, minus 20, and minus transaction fees: | # matured block, minus 40, minus 20, and minus transaction fees: | ||||
expected = starting_balance + fund_foo_tx["fee"] + fund_bar_tx["fee"] | expected = starting_balance + fund_foo_tx["fee"] + fund_bar_tx["fee"] | ||||
if self.options.mine_block: | if self.options.mine_block: | ||||
expected += 50 | expected += 50 | ||||
expected += tx1["amount"] + tx1["fee"] | expected += tx1["amount"] + tx1["fee"] | ||||
expected += tx2["amount"] + tx2["fee"] | expected += tx2["amount"] + tx2["fee"] | ||||
assert_equal(self.nodes[0].getbalance(), expected) | assert_equal(self.nodes[0].getbalance(), expected) | ||||
# foo and bar accounts should be debited: | |||||
assert_equal(self.nodes[0].getbalance("foo", 0), | |||||
1219 + tx1["amount"] + tx1["fee"]) | |||||
assert_equal(self.nodes[0].getbalance("bar", 0), | |||||
29 + tx2["amount"] + tx2["fee"]) | |||||
if self.options.mine_block: | if self.options.mine_block: | ||||
assert_equal(tx1["confirmations"], 1) | assert_equal(tx1["confirmations"], 1) | ||||
assert_equal(tx2["confirmations"], 1) | assert_equal(tx2["confirmations"], 1) | ||||
# Node1's "from0" balance should be both transaction amounts: | # Node1's balance should be both transaction amounts: | ||||
assert_equal(self.nodes[1].getbalance( | assert_equal(self.nodes[1].getbalance( | ||||
"from0"), -(tx1["amount"] + tx2["amount"])) | ), starting_balance - tx1["amount"] - tx2["amount"]) | ||||
else: | else: | ||||
assert_equal(tx1["confirmations"], 0) | assert_equal(tx1["confirmations"], 0) | ||||
assert_equal(tx2["confirmations"], 0) | assert_equal(tx2["confirmations"], 0) | ||||
# Now give doublespend and its parents to miner: | # Now give doublespend and its parents to miner: | ||||
self.nodes[2].sendrawtransaction(fund_foo_tx["hex"]) | self.nodes[2].sendrawtransaction(fund_foo_tx["hex"]) | ||||
self.nodes[2].sendrawtransaction(fund_bar_tx["hex"]) | self.nodes[2].sendrawtransaction(fund_bar_tx["hex"]) | ||||
doublespend_txid = self.nodes[2].sendrawtransaction(doublespend["hex"]) | doublespend_txid = self.nodes[2].sendrawtransaction(doublespend["hex"]) | ||||
Show All 16 Lines | def run_test(self): | ||||
assert_equal(tx2["confirmations"], -2) | assert_equal(tx2["confirmations"], -2) | ||||
# Node0's total balance should be starting balance, plus 100BTC for | # Node0's total balance should be starting balance, plus 100BTC for | ||||
# two more matured blocks, minus 1240 for the double-spend, plus fees (which are | # two more matured blocks, minus 1240 for the double-spend, plus fees (which are | ||||
# negative): | # negative): | ||||
expected = starting_balance + 100 - 1240 + \ | expected = starting_balance + 100 - 1240 + \ | ||||
fund_foo_tx["fee"] + fund_bar_tx["fee"] + doublespend_fee | fund_foo_tx["fee"] + fund_bar_tx["fee"] + doublespend_fee | ||||
assert_equal(self.nodes[0].getbalance(), expected) | assert_equal(self.nodes[0].getbalance(), expected) | ||||
assert_equal(self.nodes[0].getbalance("*"), expected) | |||||
# Final "" balance is starting_balance - amount moved to accounts - doublespend + subsidies + | |||||
# fees (which are negative) | |||||
assert_equal(self.nodes[0].getbalance("foo"), 1219) | |||||
assert_equal(self.nodes[0].getbalance("bar"), 29) | |||||
assert_equal(self.nodes[0].getbalance(""), starting_balance | |||||
- 1219 | |||||
- 29 | |||||
- 1240 | |||||
+ 100 | |||||
+ fund_foo_tx["fee"] | |||||
+ fund_bar_tx["fee"] | |||||
+ doublespend_fee) | |||||
# Node1's "from0" account balance should be just the doublespend: | # Node1's balance should be its initial balance (1250 for 25 block rewards) plus the doublespend: | ||||
assert_equal(self.nodes[1].getbalance("from0"), 1240) | assert_equal(self.nodes[1].getbalance(), 1250 + 1240) | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
TxnMallTest().main() | TxnMallTest().main() |