aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2018-01-27 17:45:32 -0500
committerMarcoFalke <falke.marco@gmail.com>2018-02-06 09:54:31 -0500
commitfa795cf9c52b82cc3cccd21483360d6e03f767f0 (patch)
treed06ffc7091c67a6bbd0f9ddfa11d893f1b3afde6
parent598a9c4e4dcd03c6d80fba005de729a6a3aeba7e (diff)
downloadbitcoin-fa795cf9c52b82cc3cccd21483360d6e03f767f0.tar.xz
wallet: Disallow abandon of conflicted txes
-rw-r--r--src/wallet/rpcwallet.cpp5
-rw-r--r--src/wallet/wallet.cpp4
-rwxr-xr-xtest/functional/wallet_abandonconflict.py8
-rwxr-xr-xtest/functional/wallet_bumpfee.py11
4 files changed, 19 insertions, 9 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index fcee22a14a..139c2bf2d5 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2190,14 +2190,14 @@ UniValue abandontransaction(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1)
+ if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
"abandontransaction \"txid\"\n"
"\nMark in-wallet transaction <txid> as abandoned\n"
"This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
"for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n"
"It only works on transactions which are not included in a block and are not currently in the mempool.\n"
- "It has no effect on transactions which are already conflicted or abandoned.\n"
+ "It has no effect on transactions which are already abandoned.\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
"\nResult:\n"
@@ -2205,6 +2205,7 @@ UniValue abandontransaction(const JSONRPCRequest& request)
+ HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ }
ObserveSafeMode();
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 07a23ce249..258161cffc 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1083,7 +1083,7 @@ bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const
{
LOCK2(cs_main, cs_wallet);
const CWalletTx* wtx = GetWalletTx(hashTx);
- return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() <= 0 && !wtx->InMempool();
+ return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() == 0 && !wtx->InMempool();
}
bool CWallet::AbandonTransaction(const uint256& hashTx)
@@ -1099,7 +1099,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
auto it = mapWallet.find(hashTx);
assert(it != mapWallet.end());
CWalletTx& origtx = it->second;
- if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) {
+ if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool()) {
return false;
}
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index 14964438af..8fb860cd7e 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -8,11 +8,12 @@
descendants as abandoned which allows their inputs to be respent. It can be
used to replace "stuck" or evicted transactions. It only works on transactions
which are not included in a block and are not currently in the mempool. It has
- no effect on transactions which are already conflicted or abandoned.
+ no effect on transactions which are already abandoned.
"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
+
class AbandonConflictTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
@@ -28,6 +29,11 @@ class AbandonConflictTest(BitcoinTestFramework):
sync_mempools(self.nodes)
self.nodes[1].generate(1)
+ # Can not abandon non-wallet transaction
+ assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', lambda: self.nodes[0].abandontransaction(txid='ff' * 32))
+ # Can not abandon confirmed transaction
+ assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: self.nodes[0].abandontransaction(txid=txA))
+
sync_blocks(self.nodes)
newbalance = self.nodes[0].getbalance()
assert(balance - newbalance < Decimal("0.001")) #no more than fees lost
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index 2cd4127854..f621d41b4e 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -231,13 +231,16 @@ def test_unconfirmed_not_spendable(rbf_node, rbf_node_address):
assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == bumpid], [])
# submit a block with the rbf tx to clear the bump tx out of the mempool,
- # then call abandon to make sure the wallet doesn't attempt to resubmit the
- # bump tx, then invalidate the block so the rbf tx will be put back in the
- # mempool. this makes it possible to check whether the rbf tx outputs are
+ # then invalidate the block so the rbf tx will be put back in the mempool.
+ # This makes it possible to check whether the rbf tx outputs are
# spendable before the rbf tx is confirmed.
block = submit_block_with_tx(rbf_node, rbftx)
- rbf_node.abandontransaction(bumpid)
+ # Can not abandon conflicted tx
+ assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: rbf_node.abandontransaction(txid=bumpid))
rbf_node.invalidateblock(block.hash)
+ # Call abandon to make sure the wallet doesn't attempt to resubmit
+ # the bump tx and hope the wallet does not rebroadcast before we call.
+ rbf_node.abandontransaction(bumpid)
assert bumpid not in rbf_node.getrawmempool()
assert rbfid in rbf_node.getrawmempool()