Skip to content

Commit 663911e

Browse files
committed
Merge #12282: wallet: Disallow abandon of conflicted txes
fa795cf wallet: Disallow abandon of conflicted txes (MarcoFalke) Pull request description: Abandon transactions that are already conflicted is a noop, so don't try and return false/throw instead. Tree-SHA512: fd2af4149bd2323f7f31fe18685c763790b8589319b4e467b464ab456d5e8971501ab16d124e57a22693666b06ae433ac3e59f0fd6dfbd2be2c6cae8be5bcbd8
2 parents 935eb8d + fa795cf commit 663911e

File tree

4 files changed

+19
-9
lines changed

4 files changed

+19
-9
lines changed

src/wallet/rpcwallet.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2184,21 +2184,22 @@ UniValue abandontransaction(const JSONRPCRequest& request)
21842184
return NullUniValue;
21852185
}
21862186

2187-
if (request.fHelp || request.params.size() != 1)
2187+
if (request.fHelp || request.params.size() != 1) {
21882188
throw std::runtime_error(
21892189
"abandontransaction \"txid\"\n"
21902190
"\nMark in-wallet transaction <txid> as abandoned\n"
21912191
"This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
21922192
"for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n"
21932193
"It only works on transactions which are not included in a block and are not currently in the mempool.\n"
2194-
"It has no effect on transactions which are already conflicted or abandoned.\n"
2194+
"It has no effect on transactions which are already abandoned.\n"
21952195
"\nArguments:\n"
21962196
"1. \"txid\" (string, required) The transaction id\n"
21972197
"\nResult:\n"
21982198
"\nExamples:\n"
21992199
+ HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
22002200
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
22012201
);
2202+
}
22022203

22032204
ObserveSafeMode();
22042205

src/wallet/wallet.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,7 +1078,7 @@ bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const
10781078
{
10791079
LOCK2(cs_main, cs_wallet);
10801080
const CWalletTx* wtx = GetWalletTx(hashTx);
1081-
return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() <= 0 && !wtx->InMempool();
1081+
return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() == 0 && !wtx->InMempool();
10821082
}
10831083

10841084
bool CWallet::AbandonTransaction(const uint256& hashTx)
@@ -1094,7 +1094,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
10941094
auto it = mapWallet.find(hashTx);
10951095
assert(it != mapWallet.end());
10961096
CWalletTx& origtx = it->second;
1097-
if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) {
1097+
if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool()) {
10981098
return false;
10991099
}
11001100

test/functional/wallet_abandonconflict.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
descendants as abandoned which allows their inputs to be respent. It can be
99
used to replace "stuck" or evicted transactions. It only works on transactions
1010
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.
11+
no effect on transactions which are already abandoned.
1212
"""
1313
from test_framework.test_framework import BitcoinTestFramework
1414
from test_framework.util import *
1515

16+
1617
class AbandonConflictTest(BitcoinTestFramework):
1718
def set_test_params(self):
1819
self.num_nodes = 2
@@ -28,6 +29,11 @@ def run_test(self):
2829
sync_mempools(self.nodes)
2930
self.nodes[1].generate(1)
3031

32+
# Can not abandon non-wallet transaction
33+
assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', lambda: self.nodes[0].abandontransaction(txid='ff' * 32))
34+
# Can not abandon confirmed transaction
35+
assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: self.nodes[0].abandontransaction(txid=txA))
36+
3137
sync_blocks(self.nodes)
3238
newbalance = self.nodes[0].getbalance()
3339
assert(balance - newbalance < Decimal("0.001")) #no more than fees lost

test/functional/wallet_bumpfee.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,16 @@ def test_unconfirmed_not_spendable(rbf_node, rbf_node_address):
231231
assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == bumpid], [])
232232

233233
# submit a block with the rbf tx to clear the bump tx out of the mempool,
234-
# then call abandon to make sure the wallet doesn't attempt to resubmit the
235-
# bump tx, then invalidate the block so the rbf tx will be put back in the
236-
# mempool. this makes it possible to check whether the rbf tx outputs are
234+
# then invalidate the block so the rbf tx will be put back in the mempool.
235+
# This makes it possible to check whether the rbf tx outputs are
237236
# spendable before the rbf tx is confirmed.
238237
block = submit_block_with_tx(rbf_node, rbftx)
239-
rbf_node.abandontransaction(bumpid)
238+
# Can not abandon conflicted tx
239+
assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: rbf_node.abandontransaction(txid=bumpid))
240240
rbf_node.invalidateblock(block.hash)
241+
# Call abandon to make sure the wallet doesn't attempt to resubmit
242+
# the bump tx and hope the wallet does not rebroadcast before we call.
243+
rbf_node.abandontransaction(bumpid)
241244
assert bumpid not in rbf_node.getrawmempool()
242245
assert rbfid in rbf_node.getrawmempool()
243246

0 commit comments

Comments
 (0)