Remove -respendnotify option
This commit is contained in:
@@ -96,7 +96,6 @@ testScripts = [
|
||||
'receivedby.py',
|
||||
'mempool_resurrect_test.py',
|
||||
'txn_doublespend.py --mineblock',
|
||||
'txn_doublespendrelay.py',
|
||||
'txn_clone.py',
|
||||
'getchaintips.py',
|
||||
'rawtransactions.py',
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Test double-spend-relay and notification code
|
||||
#
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
from decimal import Decimal
|
||||
|
||||
class DoubleSpendRelay(BitcoinTestFramework):
|
||||
|
||||
#
|
||||
# Create a 4-node network; roles for the nodes are:
|
||||
# [0] : transaction creator
|
||||
# [1] : respend sender
|
||||
# [2] : relay node
|
||||
# [3] : receiver, should detect/notify of double-spends
|
||||
#
|
||||
# Node connectivity is:
|
||||
# [0,1] <--> [2] <--> [3]
|
||||
#
|
||||
def setup_network(self):
|
||||
self.is_network_split = False
|
||||
self.nodes = []
|
||||
for i in range(0,4):
|
||||
self.nodes.append(start_node(i, self.options.tmpdir))
|
||||
connect_nodes(self.nodes[0], 2)
|
||||
connect_nodes(self.nodes[1], 2)
|
||||
connect_nodes(self.nodes[3], 2)
|
||||
return self.nodes
|
||||
|
||||
def run_test(self):
|
||||
fee = Decimal("0.01")
|
||||
|
||||
nodes = self.nodes
|
||||
# Test 1: First spend
|
||||
# shutdown nodes[1] so it is not aware of the first spend
|
||||
# and will be willing to broadcast a respend
|
||||
stop_node(nodes[1], 1)
|
||||
# First spend: nodes[0] -> nodes[3]
|
||||
amount = Decimal("144") # We rely on this requiring 3 50-BTC inputs
|
||||
(total_in, tx1_inputs) = gather_inputs(nodes[0], amount+fee)
|
||||
change_outputs = make_change(nodes[0], total_in, amount, fee)
|
||||
outputs = dict(change_outputs)
|
||||
outputs[nodes[3].getnewaddress()] = amount
|
||||
signed = nodes[0].signrawtransaction(nodes[0].createrawtransaction(tx1_inputs, outputs))
|
||||
txid1 = nodes[0].sendrawtransaction(signed["hex"], True)
|
||||
sync_mempools([nodes[0], nodes[3]])
|
||||
|
||||
txid1_info = nodes[3].gettransaction(txid1)
|
||||
assert_equal(txid1_info["respendsobserved"], [])
|
||||
|
||||
# Test 2: Is double-spend of tx1_inputs[0] relayed?
|
||||
# Restart nodes[1]
|
||||
nodes[1] = start_node(1, self.options.tmpdir)
|
||||
connect_nodes(nodes[1], 2)
|
||||
# Second spend: nodes[0] -> nodes[0]
|
||||
amount = Decimal("40")
|
||||
total_in = Decimal("50")
|
||||
inputs2 = [tx1_inputs[0]]
|
||||
change_outputs = make_change(nodes[0], total_in, amount, fee)
|
||||
outputs = dict(change_outputs)
|
||||
outputs[nodes[0].getnewaddress()] = amount
|
||||
signed = nodes[0].signrawtransaction(nodes[0].createrawtransaction(inputs2, outputs))
|
||||
txid2 = nodes[1].sendrawtransaction(signed["hex"], True)
|
||||
# Wait until txid2 is relayed to nodes[3] (but don't wait forever):
|
||||
# Note we can't use sync_mempools, because the respend isn't added to
|
||||
# the mempool.
|
||||
for i in range(1,7):
|
||||
txid1_info = nodes[3].gettransaction(txid1)
|
||||
if txid1_info["respendsobserved"] != []:
|
||||
break
|
||||
time.sleep(0.1 * i**2) # geometric back-off
|
||||
assert_equal(txid1_info["respendsobserved"], [txid2])
|
||||
|
||||
# Test 3: Is triple-spend of tx1_inputs[0] not relayed?
|
||||
# Clear node1 mempool
|
||||
stop_node(nodes[1], 1)
|
||||
nodes[1] = start_node(1, self.options.tmpdir)
|
||||
connect_nodes(nodes[1], 2)
|
||||
# Third spend: nodes[0] -> nodes[0]
|
||||
outputs = dict(change_outputs)
|
||||
outputs[nodes[0].getnewaddress()] = amount
|
||||
signed = nodes[0].signrawtransaction(nodes[0].createrawtransaction(inputs2, outputs))
|
||||
txid3 = nodes[1].sendrawtransaction(signed["hex"], True)
|
||||
# Ensure txid3 not relayed to nodes[3]:
|
||||
time.sleep(9.1)
|
||||
txid1_info = nodes[3].gettransaction(txid1)
|
||||
assert_equal(txid1_info["respendsobserved"], [txid2])
|
||||
|
||||
# Test 4: Is double-spend of tx1_inputs[1] relayed when triple-spend of tx1_inputs[0] precedes it?
|
||||
# Clear node1 mempool
|
||||
stop_node(nodes[1], 1)
|
||||
nodes[1] = start_node(1, self.options.tmpdir)
|
||||
connect_nodes(nodes[1], 2)
|
||||
# Inputs are third spend, second spend
|
||||
amount = Decimal("89")
|
||||
total_in = Decimal("100")
|
||||
inputs4 = [tx1_inputs[0],tx1_inputs[1]]
|
||||
change_outputs = make_change(nodes[0], total_in, amount, fee)
|
||||
outputs = dict(change_outputs)
|
||||
outputs[nodes[0].getnewaddress()] = amount
|
||||
signed = nodes[0].signrawtransaction(nodes[0].createrawtransaction(inputs4, outputs))
|
||||
txid4 = nodes[1].sendrawtransaction(signed["hex"], True)
|
||||
# Wait until txid4 is relayed to nodes[3] (but don't wait forever):
|
||||
for i in range(1,7):
|
||||
txid1_info = nodes[3].gettransaction(txid1)
|
||||
if txid1_info["respendsobserved"] != [txid2]:
|
||||
break
|
||||
time.sleep(0.1 * i**2) # geometric back-off
|
||||
assert_equal(sorted(txid1_info["respendsobserved"]), sorted([txid2,txid4]))
|
||||
|
||||
# Test 5: Is double-spend of tx1_inputs[2] relayed when triple-spend of tx1_inputs[0] follows it?
|
||||
# Clear node1 mempool
|
||||
stop_node(nodes[1], 1)
|
||||
nodes[1] = start_node(1, self.options.tmpdir)
|
||||
connect_nodes(nodes[1], 2)
|
||||
# Inputs are second spend, third spend
|
||||
amount = Decimal("88")
|
||||
total_in = Decimal("100")
|
||||
inputs5 = [tx1_inputs[2],tx1_inputs[0]]
|
||||
change_outputs = make_change(nodes[0], total_in, amount, fee)
|
||||
outputs = dict(change_outputs)
|
||||
outputs[nodes[0].getnewaddress()] = amount
|
||||
signed = nodes[0].signrawtransaction(nodes[0].createrawtransaction(inputs5, outputs))
|
||||
txid5 = nodes[1].sendrawtransaction(signed["hex"], True)
|
||||
# Wait until txid5 is relayed to nodes[3] (but don't wait forever):
|
||||
for i in range(1,7):
|
||||
txid1_info = nodes[3].gettransaction(txid1)
|
||||
if sorted(txid1_info["respendsobserved"]) != sorted([txid2,txid4]):
|
||||
break
|
||||
time.sleep(0.1 * i**2) # geometric back-off
|
||||
assert_equal(sorted(txid1_info["respendsobserved"]), sorted([txid2,txid4,txid5]))
|
||||
|
||||
if __name__ == '__main__':
|
||||
DoubleSpendRelay().main()
|
||||
|
||||
@@ -92,10 +92,6 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
|
||||
BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
|
||||
conflicts.push_back(conflict.GetHex());
|
||||
entry.push_back(Pair("walletconflicts", conflicts));
|
||||
UniValue respends;
|
||||
BOOST_FOREACH(const uint256& respend, wtx.GetConflicts(false))
|
||||
respends.push_back(respend.GetHex());
|
||||
entry.push_back(Pair("respendsobserved", respends));
|
||||
entry.push_back(Pair("time", wtx.GetTxTime()));
|
||||
entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
|
||||
BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
|
||||
@@ -1406,12 +1402,6 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
|
||||
" category of transactions.\n"
|
||||
" \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
|
||||
" \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
|
||||
" \"walletconflicts\" : [\n"
|
||||
" \"conflictid\", (string) Ids of transactions, including equivalent clones, that re-spend a txid input.\n"
|
||||
" ],\n"
|
||||
" \"respendsobserved\" : [\n"
|
||||
" \"respendid\", (string) Ids of transactions, NOT equivalent clones, that re-spend a txid input. \"Double-spends.\"\n"
|
||||
" ],\n"
|
||||
" \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
|
||||
" \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
|
||||
" for 'send' and 'receive' category of transactions.\n"
|
||||
@@ -1604,12 +1594,6 @@ UniValue listsinceblock(const UniValue& params, bool fHelp)
|
||||
" \"blockindex\": n, (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive' category of transactions.\n"
|
||||
" \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
|
||||
" \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
|
||||
" \"walletconflicts\" : [\n"
|
||||
" \"conflictid\", (string) Ids of transactions, including equivalent clones, that re-spend a txid input.\n"
|
||||
" ],\n"
|
||||
" \"respendsobserved\" : [\n"
|
||||
" \"respendid\", (string) Ids of transactions, NOT equivalent clones, that re-spend a txid input. \"Double-spends.\"\n"
|
||||
" ],\n"
|
||||
" \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
|
||||
" \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
|
||||
" \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
|
||||
@@ -1694,12 +1678,6 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
|
||||
" \"blockindex\" : xx, (numeric) The index of the transaction in the block that includes it\n"
|
||||
" \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
|
||||
" \"txid\" : \"transactionid\", (string) The transaction id.\n"
|
||||
" \"walletconflicts\" : [\n"
|
||||
" \"conflictid\", (string) Ids of transactions, including equivalent clones, that re-spend a txid input.\n"
|
||||
" ],\n"
|
||||
" \"respendsobserved\" : [\n"
|
||||
" \"respendid\", (string) Ids of transactions, NOT equivalent clones, that re-spend a txid input. \"Double-spends.\"\n"
|
||||
" ],\n"
|
||||
" \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
|
||||
" \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
|
||||
" \"details\" : [\n"
|
||||
|
||||
@@ -1181,28 +1181,6 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
|
||||
// Notify UI of new or updated transaction
|
||||
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
|
||||
|
||||
// Notifications for existing transactions that now have conflicts with this one
|
||||
if (fInsertedNew)
|
||||
{
|
||||
BOOST_FOREACH(const uint256& conflictHash, wtxIn.GetConflicts(false))
|
||||
{
|
||||
CWalletTx& txConflict = mapWallet[conflictHash];
|
||||
NotifyTransactionChanged(this, conflictHash, CT_UPDATED); //Updates UI table
|
||||
if (IsFromMe(txConflict) || IsMine(txConflict))
|
||||
{
|
||||
// external respend notify
|
||||
std::string strCmd = GetArg("-respendnotify", "");
|
||||
if (!strCmd.empty())
|
||||
{
|
||||
NotifyTransactionChanged(this, conflictHash, CT_GOT_CONFLICT); //Throws dialog
|
||||
boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
|
||||
boost::replace_all(strCmd, "%t", conflictHash.GetHex());
|
||||
boost::thread t(runCommand, strCmd); // thread runs free
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// notify an external script when a wallet transaction comes in or is updated
|
||||
std::string strCmd = GetArg("-walletnotify", "");
|
||||
|
||||
@@ -3751,7 +3729,6 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
|
||||
strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
|
||||
strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
|
||||
strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
|
||||
strUsage += HelpMessageOpt("-respendnotify=<cmd>", _("Execute command when a network tx respends wallet tx input (%s=respend TxID, %t=wallet TxID)"));
|
||||
strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
|
||||
" " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user