Repository: bitcoin/bitcoin (language: cpp)

Issue:
gettransaction does not contain the field "abandoned" for abandoned receiving tx
In specter https://github.com/cryptoadvance/specter-desktop/issues/1491#issuecomment-1126145011  a user can abandon an **receiving** tx that was evicted from the mempool (for example because it was double spent). The tx is marked via [abandontransaction](https://github.com/bitcoin-dot-org/developer.bitcoin.org/blob/master/reference/rpc/abandontransaction.rst) as abandoned in bitcoin core.

However [gettransaction](https://github.com/bitcoin-dot-org/developer.bitcoin.org/blob/master/reference/rpc/gettransaction.rst) and [listtransactions](https://github.com/bitcoin-dot-org/developer.bitcoin.org/blob/master/reference/rpc/listtransactions.rst) do not return the field `abandoned`, even though this is visible in the GUI:

![image](https://user-images.githubusercontent.com/60378539/168316171-45c1aa29-de52-4d9a-ae2b-3293aeadd663.png)

**Consequence**: Specter cannot get the `abandoned` information from bitcoin rpc, and will fetch the abandoned tx back again via [listtransactions](https://github.com/bitcoin-dot-org/developer.bitcoin.org/blob/master/reference/rpc/listtransactions.rst) after it was deleted in specter.   

**Describe the solution you'd like**
Always return the `abandoned` field in https://github.com/bitcoin/bitcoin/blob/225e5b57b2ee2bc1acd7f09c89ccccc15ef8c85f/src/wallet/rpc/transactions.cpp#L345  and not only in this special case https://github.com/bitcoin/bitcoin/blob/225e5b57b2ee2bc1acd7f09c89ccccc15ef8c85f/src/wallet/rpc/transactions.cpp#L375
That should then automatically solve  [gettransaction](https://github.com/bitcoin-dot-org/developer.bitcoin.org/blob/master/reference/rpc/gettransaction.rst)  via https://github.com/bitcoin/bitcoin/blob/225e5b57b2ee2bc1acd7f09c89ccccc15ef8c85f/src/wallet/rpc/transactions.cpp#L795

**Describe alternatives you've considered**
If specter can't get the information about abandoned tx from bitcoin, it would have to keep an internal list. That is possible, but redundant and can lead to many edge cases.

**Steps to reproduce**

- Wallet A:  Send 1 BTC to Wallet B  (rbf)
- Wallet A:  Replace tx with rbf to send all funds to wallet A
- Wallet B: Abandon tx (because no longer in mempool)
- Wallet B:  [gettransaction](https://github.com/bitcoin-dot-org/developer.bitcoin.org/blob/master/reference/rpc/gettransaction.rst) will not show the  `abandoned` field


Discussion / hints:
I can work on it if it gets some concept ACKs 
> I can work on it if it gets some concept ACKs

Wow, that would be great. Thanks!

Fix patch:
diff --git a/doc/release-notes-25158.md b/doc/release-notes-25158.md
new file mode 100644
index 0000000000000..ce8ab53ddd835
--- /dev/null
+++ b/doc/release-notes-25158.md
@@ -0,0 +1,6 @@
+RPC Wallet
+----------
+
+- The `gettransaction`, `listtransactions`, `listsinceblock` RPCs now return
+  the `abandoned` field for all transactions. Previously, the "abandoned" field
+  was only returned for sent transactions. (#25158)
\ No newline at end of file
diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp
index c257af13c4f26..d2b33a8b700f0 100644
--- a/src/wallet/rpc/transactions.cpp
+++ b/src/wallet/rpc/transactions.cpp
@@ -389,6 +389,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
                 entry.pushKV("label", label);
             }
             entry.pushKV("vout", r.vout);
+            entry.pushKV("abandoned", wtx.isAbandoned());
             if (fLong)
                 WalletTxToJSON(wallet, wtx, entry);
             ret.push_back(entry);
@@ -462,8 +463,7 @@ RPCHelpMan listtransactions()
                         },
                         TransactionDescriptionString()),
                         {
-                            {RPCResult::Type::BOOL, "abandoned", /*optional=*/true, "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
-                                 "'send' category of transactions."},
+                            {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
                         })},
                     }
                 },
@@ -576,8 +576,7 @@ RPCHelpMan listsinceblock()
                             },
                             TransactionDescriptionString()),
                             {
-                                {RPCResult::Type::BOOL, "abandoned", /*optional=*/true, "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
-                                     "'send' category of transactions."},
+                                {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
                                 {RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},
                             })},
                         }},
@@ -722,8 +721,7 @@ RPCHelpMan gettransaction()
                                 {RPCResult::Type::NUM, "vout", "the vout value"},
                                 {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
                                     "'send' category of transactions."},
-                                {RPCResult::Type::BOOL, "abandoned", /*optional=*/true, "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
-                                     "'send' category of transactions."},
+                                {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
                                 {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the scriptPubKey of this coin.", {
                                     {RPCResult::Type::STR, "desc", "The descriptor string."},
                                 }},


Test patch:
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index 1cb3f434e871d..f1e7869d914d1 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -539,6 +539,11 @@ def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address):
     # 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)
+
+    tx_bump_abandoned = rbf_node.gettransaction(bumpid)
+    for tx in tx_bump_abandoned['details']:
+        assert_equal(tx['abandoned'], True)
+
     assert bumpid not in rbf_node.getrawmempool()
     assert rbfid in rbf_node.getrawmempool()