Bitcoin Core 30.99.0
P2P Digital Currency
transactions.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <core_io.h>
6#include <key_io.h>
7#include <policy/rbf.h>
9#include <rpc/util.h>
11#include <rpc/blockchain.h>
12#include <util/vector.h>
13#include <wallet/receive.h>
14#include <wallet/rpc/util.h>
15#include <wallet/wallet.h>
16
18
19namespace wallet {
20static void WalletTxToJSON(const CWallet& wallet, const CWalletTx& wtx, UniValue& entry)
22{
23 interfaces::Chain& chain = wallet.chain();
24 int confirms = wallet.GetTxDepthInMainChain(wtx);
25 entry.pushKV("confirmations", confirms);
26 if (wtx.IsCoinBase())
27 entry.pushKV("generated", true);
28 if (auto* conf = wtx.state<TxStateConfirmed>())
29 {
30 entry.pushKV("blockhash", conf->confirmed_block_hash.GetHex());
31 entry.pushKV("blockheight", conf->confirmed_block_height);
32 entry.pushKV("blockindex", conf->position_in_block);
33 int64_t block_time;
34 CHECK_NONFATAL(chain.findBlock(conf->confirmed_block_hash, FoundBlock().time(block_time)));
35 entry.pushKV("blocktime", block_time);
36 } else {
37 entry.pushKV("trusted", CachedTxIsTrusted(wallet, wtx));
38 }
39 entry.pushKV("txid", wtx.GetHash().GetHex());
40 entry.pushKV("wtxid", wtx.GetWitnessHash().GetHex());
41 UniValue conflicts(UniValue::VARR);
42 for (const Txid& conflict : wallet.GetTxConflicts(wtx))
43 conflicts.push_back(conflict.GetHex());
44 entry.pushKV("walletconflicts", std::move(conflicts));
45 UniValue mempool_conflicts(UniValue::VARR);
46 for (const Txid& mempool_conflict : wtx.mempool_conflicts)
47 mempool_conflicts.push_back(mempool_conflict.GetHex());
48 entry.pushKV("mempoolconflicts", std::move(mempool_conflicts));
49 entry.pushKV("time", wtx.GetTxTime());
50 entry.pushKV("timereceived", int64_t{wtx.nTimeReceived});
51
52 // Add opt-in RBF status
53 std::string rbfStatus = "no";
54 if (confirms <= 0) {
55 RBFTransactionState rbfState = chain.isRBFOptIn(*wtx.tx);
56 if (rbfState == RBFTransactionState::UNKNOWN)
57 rbfStatus = "unknown";
58 else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125)
59 rbfStatus = "yes";
60 }
61 entry.pushKV("bip125-replaceable", rbfStatus);
62
63 for (const std::pair<const std::string, std::string>& item : wtx.mapValue)
64 entry.pushKV(item.first, item.second);
65}
66
68{
70 int nConf{std::numeric_limits<int>::max()};
71 std::vector<Txid> txids;
72 tallyitem() = default;
73};
74
75static UniValue ListReceived(const CWallet& wallet, const UniValue& params, const bool by_label, const bool include_immature_coinbase) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
76{
77 // Minimum confirmations
78 int nMinDepth = 1;
79 if (!params[0].isNull())
80 nMinDepth = params[0].getInt<int>();
81
82 // Whether to include empty labels
83 bool fIncludeEmpty = false;
84 if (!params[1].isNull())
85 fIncludeEmpty = params[1].get_bool();
86
87 std::optional<CTxDestination> filtered_address{std::nullopt};
88 if (!by_label && !params[3].isNull() && !params[3].get_str().empty()) {
89 if (!IsValidDestinationString(params[3].get_str())) {
90 throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid");
91 }
92 filtered_address = DecodeDestination(params[3].get_str());
93 }
94
95 // Tally
96 std::map<CTxDestination, tallyitem> mapTally;
97 for (const auto& [_, wtx] : wallet.mapWallet) {
98
99 int nDepth = wallet.GetTxDepthInMainChain(wtx);
100 if (nDepth < nMinDepth)
101 continue;
102
103 // Coinbase with less than 1 confirmation is no longer in the main chain
104 if ((wtx.IsCoinBase() && (nDepth < 1))
105 || (wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase)) {
106 continue;
107 }
108
109 for (const CTxOut& txout : wtx.tx->vout) {
110 CTxDestination address;
111 if (!ExtractDestination(txout.scriptPubKey, address))
112 continue;
113
114 if (filtered_address && !(filtered_address == address)) {
115 continue;
116 }
117
118 if (!wallet.IsMine(address))
119 continue;
120
121 tallyitem& item = mapTally[address];
122 item.nAmount += txout.nValue;
123 item.nConf = std::min(item.nConf, nDepth);
124 item.txids.push_back(wtx.GetHash());
125 }
126 }
127
128 // Reply
130 std::map<std::string, tallyitem> label_tally;
131
132 const auto& func = [&](const CTxDestination& address, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) {
133 if (is_change) return; // no change addresses
134
135 auto it = mapTally.find(address);
136 if (it == mapTally.end() && !fIncludeEmpty)
137 return;
138
139 CAmount nAmount = 0;
140 int nConf = std::numeric_limits<int>::max();
141 if (it != mapTally.end()) {
142 nAmount = (*it).second.nAmount;
143 nConf = (*it).second.nConf;
144 }
145
146 if (by_label) {
147 tallyitem& _item = label_tally[label];
148 _item.nAmount += nAmount;
149 _item.nConf = std::min(_item.nConf, nConf);
150 } else {
152 obj.pushKV("address", EncodeDestination(address));
153 obj.pushKV("amount", ValueFromAmount(nAmount));
154 obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
155 obj.pushKV("label", label);
156 UniValue transactions(UniValue::VARR);
157 if (it != mapTally.end()) {
158 for (const Txid& _item : (*it).second.txids) {
159 transactions.push_back(_item.GetHex());
160 }
161 }
162 obj.pushKV("txids", std::move(transactions));
163 ret.push_back(std::move(obj));
164 }
165 };
166
167 if (filtered_address) {
168 const auto& entry = wallet.FindAddressBookEntry(*filtered_address, /*allow_change=*/false);
169 if (entry) func(*filtered_address, entry->GetLabel(), entry->IsChange(), entry->purpose);
170 } else {
171 // No filtered addr, walk-through the addressbook entry
172 wallet.ForEachAddrBookEntry(func);
173 }
174
175 if (by_label) {
176 for (const auto& entry : label_tally) {
177 CAmount nAmount = entry.second.nAmount;
178 int nConf = entry.second.nConf;
180 obj.pushKV("amount", ValueFromAmount(nAmount));
181 obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
182 obj.pushKV("label", entry.first);
183 ret.push_back(std::move(obj));
184 }
185 }
186
187 return ret;
188}
189
191{
192 return RPCHelpMan{
193 "listreceivedbyaddress",
194 "List balances by receiving address.\n",
195 {
196 {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
197 {"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include addresses that haven't received any payments."},
198 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
199 {"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If present and non-empty, only return information on this address."},
200 {"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
201 },
202 RPCResult{
203 RPCResult::Type::ARR, "", "",
204 {
205 {RPCResult::Type::OBJ, "", "",
206 {
207 {RPCResult::Type::STR, "address", "The receiving address"},
208 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received by the address"},
209 {RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
210 {RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
211 {RPCResult::Type::ARR, "txids", "",
212 {
213 {RPCResult::Type::STR_HEX, "txid", "The ids of transactions received with the address"},
214 }},
215 }},
216 }
217 },
219 HelpExampleCli("listreceivedbyaddress", "")
220 + HelpExampleCli("listreceivedbyaddress", "6 true")
221 + HelpExampleCli("listreceivedbyaddress", "6 true true \"\" true")
222 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
223 + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"" + EXAMPLE_ADDRESS[0] + "\", true")
224 },
225 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
226{
227 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
228 if (!pwallet) return UniValue::VNULL;
229
230 // Make sure the results are valid at least up to the most recent block
231 // the user could have gotten from another RPC command prior to now
232 pwallet->BlockUntilSyncedToCurrentChain();
233
234 const bool include_immature_coinbase{request.params[4].isNull() ? false : request.params[4].get_bool()};
235
236 LOCK(pwallet->cs_wallet);
237
238 return ListReceived(*pwallet, request.params, false, include_immature_coinbase);
239},
240 };
241}
242
244{
245 return RPCHelpMan{
246 "listreceivedbylabel",
247 "List received transactions by label.\n",
248 {
249 {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
250 {"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include labels that haven't received any payments."},
251 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
252 {"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
253 },
254 RPCResult{
255 RPCResult::Type::ARR, "", "",
256 {
257 {RPCResult::Type::OBJ, "", "",
258 {
259 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount received by addresses with this label"},
260 {RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
261 {RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
262 }},
263 }
264 },
266 HelpExampleCli("listreceivedbylabel", "")
267 + HelpExampleCli("listreceivedbylabel", "6 true")
268 + HelpExampleRpc("listreceivedbylabel", "6, true, true, true")
269 },
270 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
271{
272 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
273 if (!pwallet) return UniValue::VNULL;
274
275 // Make sure the results are valid at least up to the most recent block
276 // the user could have gotten from another RPC command prior to now
277 pwallet->BlockUntilSyncedToCurrentChain();
278
279 const bool include_immature_coinbase{request.params[3].isNull() ? false : request.params[3].get_bool()};
280
281 LOCK(pwallet->cs_wallet);
282
283 return ListReceived(*pwallet, request.params, true, include_immature_coinbase);
284},
285 };
286}
287
288static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
289{
290 if (IsValidDestination(dest)) {
291 entry.pushKV("address", EncodeDestination(dest));
292 }
293}
294
305template <class Vec>
306static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong,
307 Vec& ret, const std::optional<std::string>& filter_label,
308 bool include_change = false)
310{
311 CAmount nFee;
312 std::list<COutputEntry> listReceived;
313 std::list<COutputEntry> listSent;
314
315 CachedTxGetAmounts(wallet, wtx, listReceived, listSent, nFee, include_change);
316
317 // Sent
318 if (!filter_label.has_value())
319 {
320 for (const COutputEntry& s : listSent)
321 {
323 MaybePushAddress(entry, s.destination);
324 entry.pushKV("category", "send");
325 entry.pushKV("amount", ValueFromAmount(-s.amount));
326 const auto* address_book_entry = wallet.FindAddressBookEntry(s.destination);
327 if (address_book_entry) {
328 entry.pushKV("label", address_book_entry->GetLabel());
329 }
330 entry.pushKV("vout", s.vout);
331 entry.pushKV("fee", ValueFromAmount(-nFee));
332 if (fLong)
333 WalletTxToJSON(wallet, wtx, entry);
334 entry.pushKV("abandoned", wtx.isAbandoned());
335 ret.push_back(std::move(entry));
336 }
337 }
338
339 // Received
340 if (listReceived.size() > 0 && wallet.GetTxDepthInMainChain(wtx) >= nMinDepth) {
341 for (const COutputEntry& r : listReceived)
342 {
343 std::string label;
344 const auto* address_book_entry = wallet.FindAddressBookEntry(r.destination);
345 if (address_book_entry) {
346 label = address_book_entry->GetLabel();
347 }
348 if (filter_label.has_value() && label != filter_label.value()) {
349 continue;
350 }
352 MaybePushAddress(entry, r.destination);
353 PushParentDescriptors(wallet, wtx.tx->vout.at(r.vout).scriptPubKey, entry);
354 if (wtx.IsCoinBase())
355 {
356 if (wallet.GetTxDepthInMainChain(wtx) < 1)
357 entry.pushKV("category", "orphan");
358 else if (wallet.IsTxImmatureCoinBase(wtx))
359 entry.pushKV("category", "immature");
360 else
361 entry.pushKV("category", "generate");
362 }
363 else
364 {
365 entry.pushKV("category", "receive");
366 }
367 entry.pushKV("amount", ValueFromAmount(r.amount));
368 if (address_book_entry) {
369 entry.pushKV("label", label);
370 }
371 entry.pushKV("vout", r.vout);
372 entry.pushKV("abandoned", wtx.isAbandoned());
373 if (fLong)
374 WalletTxToJSON(wallet, wtx, entry);
375 ret.push_back(std::move(entry));
376 }
377 }
378}
379
380
381static std::vector<RPCResult> TransactionDescriptionString()
382{
383 return{{RPCResult::Type::NUM, "confirmations", "The number of confirmations for the transaction. Negative confirmations means the\n"
384 "transaction conflicted that many blocks ago."},
385 {RPCResult::Type::BOOL, "generated", /*optional=*/true, "Only present if the transaction's only input is a coinbase one."},
386 {RPCResult::Type::BOOL, "trusted", /*optional=*/true, "Whether we consider the transaction to be trusted and safe to spend from.\n"
387 "Only present when the transaction has 0 confirmations (or negative confirmations, if conflicted)."},
388 {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block hash containing the transaction."},
389 {RPCResult::Type::NUM, "blockheight", /*optional=*/true, "The block height containing the transaction."},
390 {RPCResult::Type::NUM, "blockindex", /*optional=*/true, "The index of the transaction in the block that includes it."},
391 {RPCResult::Type::NUM_TIME, "blocktime", /*optional=*/true, "The block time expressed in " + UNIX_EPOCH_TIME + "."},
392 {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
393 {RPCResult::Type::STR_HEX, "wtxid", "The hash of serialized transaction, including witness data."},
394 {RPCResult::Type::ARR, "walletconflicts", "Confirmed transactions that have been detected by the wallet to conflict with this transaction.",
395 {
396 {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
397 }},
398 {RPCResult::Type::STR_HEX, "replaced_by_txid", /*optional=*/true, "Only if 'category' is 'send'. The txid if this tx was replaced."},
399 {RPCResult::Type::STR_HEX, "replaces_txid", /*optional=*/true, "Only if 'category' is 'send'. The txid if this tx replaces another."},
400 {RPCResult::Type::ARR, "mempoolconflicts", "Transactions in the mempool that directly conflict with either this transaction or an ancestor transaction",
401 {
402 {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
403 }},
404 {RPCResult::Type::STR, "to", /*optional=*/true, "If a comment to is associated with the transaction."},
405 {RPCResult::Type::NUM_TIME, "time", "The transaction time expressed in " + UNIX_EPOCH_TIME + "."},
406 {RPCResult::Type::NUM_TIME, "timereceived", "The time received expressed in " + UNIX_EPOCH_TIME + "."},
407 {RPCResult::Type::STR, "comment", /*optional=*/true, "If a comment is associated with the transaction, only present if not empty."},
408 {RPCResult::Type::STR, "bip125-replaceable", "(\"yes|no|unknown\") Whether this transaction signals BIP125 replaceability or has an unconfirmed ancestor signaling BIP125 replaceability.\n"
409 "May be unknown for unconfirmed transactions not in the mempool because their unconfirmed ancestors are unknown."},
410 {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the output script of this coin.", {
411 {RPCResult::Type::STR, "desc", "The descriptor string."},
412 }},
413 };
414}
415
417{
418 return RPCHelpMan{
419 "listtransactions",
420 "If a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
421 "Returns up to 'count' most recent transactions ordered from oldest to newest while skipping the first number of \n"
422 "transactions specified in the 'skip' argument. A transaction can have multiple entries in this RPC response. \n"
423 "For instance, a wallet transaction that pays three addresses — one wallet-owned and two external — will produce \n"
424 "four entries. The payment to the wallet-owned address appears both as a send entry and as a receive entry. \n"
425 "As a result, the RPC response will contain one entry in the receive category and three entries in the send category.\n",
426 {
427 {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If set, should be a valid label name to return only incoming transactions\n"
428 "with the specified label, or \"*\" to disable filtering and return all transactions."},
429 {"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"},
430 {"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"},
431 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
432 },
433 RPCResult{
434 RPCResult::Type::ARR, "", "",
435 {
436 {RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
437 {
438 {RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data)."},
439 {RPCResult::Type::STR, "category", "The transaction category.\n"
440 "\"send\" Transactions sent.\n"
441 "\"receive\" Non-coinbase transactions received.\n"
442 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
443 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
444 "\"orphan\" Orphaned coinbase transactions received."},
445 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
446 "for all other categories"},
447 {RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},
448 {RPCResult::Type::NUM, "vout", "the vout value"},
449 {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
450 "'send' category of transactions."},
451 },
453 {
454 {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
455 })},
456 }
457 },
459 "\nList the most recent 10 transactions in the systems\n"
460 + HelpExampleCli("listtransactions", "") +
461 "\nList transactions 100 to 120\n"
462 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
463 "\nAs a JSON-RPC call\n"
464 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
465 },
466 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
467{
468 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
469 if (!pwallet) return UniValue::VNULL;
470
471 // Make sure the results are valid at least up to the most recent block
472 // the user could have gotten from another RPC command prior to now
473 pwallet->BlockUntilSyncedToCurrentChain();
474
475 std::optional<std::string> filter_label;
476 if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
477 filter_label.emplace(LabelFromValue(request.params[0]));
478 if (filter_label.value().empty()) {
479 throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
480 }
481 }
482 int nCount = 10;
483 if (!request.params[1].isNull())
484 nCount = request.params[1].getInt<int>();
485 int nFrom = 0;
486 if (!request.params[2].isNull())
487 nFrom = request.params[2].getInt<int>();
488
489 if (nCount < 0)
490 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
491 if (nFrom < 0)
492 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
493
494 std::vector<UniValue> ret;
495 {
496 LOCK(pwallet->cs_wallet);
497
498 const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
499
500 // iterate backwards until we have nCount items to return:
501 for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
502 {
503 CWalletTx *const pwtx = (*it).second;
504 ListTransactions(*pwallet, *pwtx, 0, true, ret, filter_label);
505 if ((int)ret.size() >= (nCount+nFrom)) break;
506 }
507 }
508
509 // ret is newest to oldest
510
511 if (nFrom > (int)ret.size())
512 nFrom = ret.size();
513 if ((nFrom + nCount) > (int)ret.size())
514 nCount = ret.size() - nFrom;
515
516 auto txs_rev_it{std::make_move_iterator(ret.rend())};
517 UniValue result{UniValue::VARR};
518 result.push_backV(txs_rev_it - nFrom - nCount, txs_rev_it - nFrom); // Return oldest to newest
519 return result;
520},
521 };
522}
523
525{
526 return RPCHelpMan{
527 "listsinceblock",
528 "Get all transactions in blocks since block [blockhash], or all transactions if omitted.\n"
529 "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
530 "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",
531 {
532 {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If set, the block hash to list transactions since, otherwise list all transactions."},
533 {"target_confirmations", RPCArg::Type::NUM, RPCArg::Default{1}, "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
534 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
535 {"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n"
536 "(not guaranteed to work on pruned nodes)"},
537 {"include_change", RPCArg::Type::BOOL, RPCArg::Default{false}, "Also add entries for change outputs.\n"},
538 {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Return only incoming transactions paying to addresses with the specified label.\n"},
539 },
540 RPCResult{
541 RPCResult::Type::OBJ, "", "",
542 {
543 {RPCResult::Type::ARR, "transactions", "",
544 {
545 {RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
546 {
547 {RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data)."},
548 {RPCResult::Type::STR, "category", "The transaction category.\n"
549 "\"send\" Transactions sent.\n"
550 "\"receive\" Non-coinbase transactions received.\n"
551 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
552 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
553 "\"orphan\" Orphaned coinbase transactions received."},
554 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
555 "for all other categories"},
556 {RPCResult::Type::NUM, "vout", "the vout value"},
557 {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
558 "'send' category of transactions."},
559 },
561 {
562 {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
563 {RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},
564 })},
565 }},
566 {RPCResult::Type::ARR, "removed", /*optional=*/true, "<structure is the same as \"transactions\" above, only present if include_removed=true>\n"
567 "Note: transactions that were re-added in the active chain will appear as-is in this array, and may thus have a positive confirmation count."
568 , {{RPCResult::Type::ELISION, "", ""},}},
569 {RPCResult::Type::STR_HEX, "lastblock", "The hash of the block (target_confirmations-1) from the best block on the main chain, or the genesis hash if the referenced block does not exist yet. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones"},
570 }
571 },
573 HelpExampleCli("listsinceblock", "")
574 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
575 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
576 },
577 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
578{
579 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
580 if (!pwallet) return UniValue::VNULL;
581
582 const CWallet& wallet = *pwallet;
583 // Make sure the results are valid at least up to the most recent block
584 // the user could have gotten from another RPC command prior to now
585 wallet.BlockUntilSyncedToCurrentChain();
586
587 LOCK(wallet.cs_wallet);
588
589 std::optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
590 std::optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
591 int target_confirms = 1;
592
593 uint256 blockId;
594 if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
595 blockId = ParseHashV(request.params[0], "blockhash");
596 height = int{};
597 altheight = int{};
598 if (!wallet.chain().findCommonAncestor(blockId, wallet.GetLastBlockHash(), /*ancestor_out=*/FoundBlock().height(*height), /*block1_out=*/FoundBlock().height(*altheight))) {
599 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
600 }
601 }
602
603 if (!request.params[1].isNull()) {
604 target_confirms = request.params[1].getInt<int>();
605
606 if (target_confirms < 1) {
607 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
608 }
609 }
610
611 bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
612 bool include_change = (!request.params[4].isNull() && request.params[4].get_bool());
613
614 // Only set it if 'label' was provided.
615 std::optional<std::string> filter_label;
616 if (!request.params[5].isNull()) filter_label.emplace(LabelFromValue(request.params[5]));
617
618 int depth = height ? wallet.GetLastBlockHeight() + 1 - *height : -1;
619
620 UniValue transactions(UniValue::VARR);
621
622 for (const auto& [_, tx] : wallet.mapWallet) {
623
624 if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) {
625 ListTransactions(wallet, tx, 0, true, transactions, filter_label, include_change);
626 }
627 }
628
629 // when a reorg'd block is requested, we also list any relevant transactions
630 // in the blocks of the chain that was detached
631 UniValue removed(UniValue::VARR);
632 while (include_removed && altheight && *altheight > *height) {
633 CBlock block;
634 if (!wallet.chain().findBlock(blockId, FoundBlock().data(block)) || block.IsNull()) {
635 throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
636 }
637 for (const CTransactionRef& tx : block.vtx) {
638 auto it = wallet.mapWallet.find(tx->GetHash());
639 if (it != wallet.mapWallet.end()) {
640 // We want all transactions regardless of confirmation count to appear here,
641 // even negative confirmation ones, hence the big negative.
642 ListTransactions(wallet, it->second, -100000000, true, removed, filter_label, include_change);
643 }
644 }
645 blockId = block.hashPrevBlock;
646 --*altheight;
647 }
648
649 uint256 lastblock;
650 target_confirms = std::min(target_confirms, wallet.GetLastBlockHeight() + 1);
651 CHECK_NONFATAL(wallet.chain().findAncestorByHeight(wallet.GetLastBlockHash(), wallet.GetLastBlockHeight() + 1 - target_confirms, FoundBlock().hash(lastblock)));
652
654 ret.pushKV("transactions", std::move(transactions));
655 if (include_removed) ret.pushKV("removed", std::move(removed));
656 ret.pushKV("lastblock", lastblock.GetHex());
657
658 return ret;
659},
660 };
661}
662
664{
665 return RPCHelpMan{
666 "gettransaction",
667 "Get detailed information about in-wallet transaction <txid>\n",
668 {
669 {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
670 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
671 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
672 "Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},
673 },
674 RPCResult{
675 RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
676 {
677 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
678 {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
679 "'send' category of transactions."},
680 },
682 {
683 {RPCResult::Type::ARR, "details", "",
684 {
685 {RPCResult::Type::OBJ, "", "",
686 {
687 {RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address involved in the transaction."},
688 {RPCResult::Type::STR, "category", "The transaction category.\n"
689 "\"send\" Transactions sent.\n"
690 "\"receive\" Non-coinbase transactions received.\n"
691 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
692 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
693 "\"orphan\" Orphaned coinbase transactions received."},
694 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
695 {RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},
696 {RPCResult::Type::NUM, "vout", "the vout value"},
697 {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
698 "'send' category of transactions."},
699 {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
700 {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the output script of this coin.", {
701 {RPCResult::Type::STR, "desc", "The descriptor string."},
702 }},
703 }},
704 }},
705 {RPCResult::Type::STR_HEX, "hex", "Raw data for transaction"},
706 {RPCResult::Type::OBJ, "decoded", /*optional=*/true, "The decoded transaction (only present when `verbose` is passed)",
707 {
708 DecodeTxDoc(/*txid_field_doc=*/"The transaction id", /*wallet=*/true),
709 }},
711 })
712 },
714 HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
715 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
716 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" false true")
717 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
718 },
719 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
720{
721 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
722 if (!pwallet) return UniValue::VNULL;
723
724 // Make sure the results are valid at least up to the most recent block
725 // the user could have gotten from another RPC command prior to now
726 pwallet->BlockUntilSyncedToCurrentChain();
727
728 LOCK(pwallet->cs_wallet);
729
730 Txid hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
731
732 bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();
733
735 auto it = pwallet->mapWallet.find(hash);
736 if (it == pwallet->mapWallet.end()) {
737 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
738 }
739 const CWalletTx& wtx = it->second;
740
741 CAmount nCredit = CachedTxGetCredit(*pwallet, wtx, /*avoid_reuse=*/false);
742 CAmount nDebit = CachedTxGetDebit(*pwallet, wtx, /*avoid_reuse=*/false);
743 CAmount nNet = nCredit - nDebit;
744 CAmount nFee = (CachedTxIsFromMe(*pwallet, wtx) ? wtx.tx->GetValueOut() - nDebit : 0);
745
746 entry.pushKV("amount", ValueFromAmount(nNet - nFee));
747 if (CachedTxIsFromMe(*pwallet, wtx))
748 entry.pushKV("fee", ValueFromAmount(nFee));
749
750 WalletTxToJSON(*pwallet, wtx, entry);
751
752 UniValue details(UniValue::VARR);
753 ListTransactions(*pwallet, wtx, 0, false, details, /*filter_label=*/std::nullopt);
754 entry.pushKV("details", std::move(details));
755
756 entry.pushKV("hex", EncodeHexTx(*wtx.tx));
757
758 if (verbose) {
759 UniValue decoded(UniValue::VOBJ);
760 TxToUniv(*wtx.tx,
761 /*block_hash=*/uint256(),
762 /*entry=*/decoded,
763 /*include_hex=*/false,
764 /*txundo=*/nullptr,
765 /*verbosity=*/TxVerbosity::SHOW_DETAILS,
766 /*is_change_func=*/[&pwallet](const CTxOut& txout) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
767 AssertLockHeld(pwallet->cs_wallet);
768 return OutputIsChange(*pwallet, txout);
769 });
770 entry.pushKV("decoded", std::move(decoded));
771 }
772
773 AppendLastProcessedBlock(entry, *pwallet);
774 return entry;
775},
776 };
777}
778
780{
781 return RPCHelpMan{
782 "abandontransaction",
783 "Mark in-wallet transaction <txid> as abandoned\n"
784 "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
785 "for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n"
786 "It only works on transactions which are not included in a block and are not currently in the mempool.\n"
787 "It has no effect on transactions which are already abandoned.\n",
788 {
789 {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
790 },
793 HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
794 + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
795 },
796 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
797{
798 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
799 if (!pwallet) return UniValue::VNULL;
800
801 // Make sure the results are valid at least up to the most recent block
802 // the user could have gotten from another RPC command prior to now
803 pwallet->BlockUntilSyncedToCurrentChain();
804
805 LOCK(pwallet->cs_wallet);
806
807 Txid hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
808
809 if (!pwallet->mapWallet.contains(hash)) {
810 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
811 }
812 if (!pwallet->AbandonTransaction(hash)) {
813 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
814 }
815
816 return UniValue::VNULL;
817},
818 };
819}
820
822{
823 return RPCHelpMan{
824 "rescanblockchain",
825 "Rescan the local blockchain for wallet related transactions.\n"
826 "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
827 "The rescan is significantly faster if block filters are available\n"
828 "(using startup option \"-blockfilterindex=1\").\n",
829 {
830 {"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "block height where the rescan should start"},
831 {"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."},
832 },
833 RPCResult{
834 RPCResult::Type::OBJ, "", "",
835 {
836 {RPCResult::Type::NUM, "start_height", "The block height where the rescan started (the requested height or 0)"},
837 {RPCResult::Type::NUM, "stop_height", "The height of the last rescanned block. May be null in rare cases if there was a reorg and the call didn't scan any blocks because they were already scanned in the background."},
838 }
839 },
841 HelpExampleCli("rescanblockchain", "100000 120000")
842 + HelpExampleRpc("rescanblockchain", "100000, 120000")
843 },
844 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
845{
846 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
847 if (!pwallet) return UniValue::VNULL;
848 CWallet& wallet{*pwallet};
849
850 // Make sure the results are valid at least up to the most recent block
851 // the user could have gotten from another RPC command prior to now
852 wallet.BlockUntilSyncedToCurrentChain();
853
854 WalletRescanReserver reserver(*pwallet);
855 if (!reserver.reserve(/*with_passphrase=*/true)) {
856 throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
857 }
858
859 int start_height = 0;
860 std::optional<int> stop_height;
861 uint256 start_block;
862
863 LOCK(pwallet->m_relock_mutex);
864 {
865 LOCK(pwallet->cs_wallet);
866 EnsureWalletIsUnlocked(*pwallet);
867 int tip_height = pwallet->GetLastBlockHeight();
868
869 if (!request.params[0].isNull()) {
870 start_height = request.params[0].getInt<int>();
871 if (start_height < 0 || start_height > tip_height) {
872 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
873 }
874 }
875
876 if (!request.params[1].isNull()) {
877 stop_height = request.params[1].getInt<int>();
878 if (*stop_height < 0 || *stop_height > tip_height) {
879 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
880 } else if (*stop_height < start_height) {
881 throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height");
882 }
883 }
884
885 // We can't rescan unavailable blocks, stop and throw an error
886 if (!pwallet->chain().hasBlocks(pwallet->GetLastBlockHash(), start_height, stop_height)) {
887 if (pwallet->chain().havePruned() && pwallet->chain().getPruneHeight() >= start_height) {
888 throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
889 }
890 if (pwallet->chain().hasAssumedValidChain()) {
891 throw JSONRPCError(RPC_MISC_ERROR, "Failed to rescan unavailable blocks likely due to an in-progress assumeutxo background sync. Check logs or getchainstates RPC for assumeutxo background sync progress and try again later.");
892 }
893 throw JSONRPCError(RPC_MISC_ERROR, "Failed to rescan unavailable blocks, potentially caused by data corruption. If the issue persists you may want to reindex (see -reindex option).");
894 }
895
896 CHECK_NONFATAL(pwallet->chain().findAncestorByHeight(pwallet->GetLastBlockHash(), start_height, FoundBlock().hash(start_block)));
897 }
898
899 CWallet::ScanResult result =
900 pwallet->ScanForWalletTransactions(start_block, start_height, stop_height, reserver, /*fUpdate=*/true, /*save_progress=*/false);
901 switch (result.status) {
903 break;
905 throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
907 throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
908 // no default case, so the compiler can warn about missing cases
909 }
910 UniValue response(UniValue::VOBJ);
911 response.pushKV("start_height", start_height);
912 response.pushKV("stop_height", result.last_scanned_height ? *result.last_scanned_height : UniValue());
913 return response;
914},
915 };
916}
917
919{
920 return RPCHelpMan{"abortrescan",
921 "Stops current wallet rescan triggered by an RPC call, e.g. by a rescanblockchain call.\n"
922 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
923 {},
924 RPCResult{RPCResult::Type::BOOL, "", "Whether the abort was successful"},
926 "\nImport a private key\n"
927 + HelpExampleCli("rescanblockchain", "") +
928 "\nAbort the running wallet rescan\n"
929 + HelpExampleCli("abortrescan", "") +
930 "\nAs a JSON-RPC call\n"
931 + HelpExampleRpc("abortrescan", "")
932 },
933 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
934{
935 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
936 if (!pwallet) return UniValue::VNULL;
937
938 if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
939 pwallet->AbortRescan();
940 return true;
941},
942 };
943}
944} // namespace wallet
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a scriptPubKey for the destination.
Definition: addresstype.cpp:49
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination corresponds to one with an address.
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:143
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
int ret
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:109
uint256 hashPrevBlock
Definition: block.h:26
bool IsNull() const
Definition: block.h:49
Definition: block.h:69
std::vector< CTransactionRef > vtx
Definition: block.h:72
An output of a transaction.
Definition: transaction.h:140
CScript scriptPubKey
Definition: transaction.h:143
CAmount nValue
Definition: transaction.h:142
void push_back(UniValue val)
Definition: univalue.cpp:104
@ VNULL
Definition: univalue.h:24
@ VOBJ
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
std::string GetHex() const
Definition: uint256.cpp:11
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:118
virtual RBFTransactionState isRBFOptIn(const CTransaction &tx)=0
Check if transaction is RBF opt in.
virtual bool findBlock(const uint256 &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
Helper for findBlock to selectively return pieces of block data.
Definition: chain.h:53
std::string GetHex() const
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition: uint256.h:195
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:312
std::multimap< int64_t, CWalletTx * > TxItems
Definition: wallet.h:502
A transaction with a bunch of additional info that only the owner cares about.
Definition: transaction.h:195
CTransactionRef tx
Definition: transaction.h:269
bool IsCoinBase() const
Definition: transaction.h:369
bool isAbandoned() const
Definition: transaction.h:361
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1075
bool reserve(bool with_passphrase=false)
Definition: wallet.h:1085
std::string EncodeHexTx(const CTransaction &tx)
Definition: core_write.cpp:143
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS, std::function< bool(const CTxOut &)> is_change_func={})
Definition: core_write.cpp:171
@ SHOW_DETAILS
Include TXID, inputs, outputs, and other common block's transaction information.
UniValue ValueFromAmount(const CAmount amount)
Definition: core_write.cpp:26
const std::string CURRENCY_UNIT
Definition: feerate.h:18
bool IsValidDestinationString(const std::string &str, const CChainParams &params)
Definition: key_io.cpp:310
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg, std::vector< int > *error_locations)
Definition: key_io.cpp:299
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:294
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:64
RPCHelpMan listreceivedbyaddress()
static std::vector< RPCResult > TransactionDescriptionString()
bool CachedTxIsFromMe(const CWallet &wallet, const CWalletTx &wtx)
Definition: receive.cpp:196
bool CachedTxIsTrusted(const CWallet &wallet, const CWalletTx &wtx, std::set< Txid > &trusted_parents)
Definition: receive.cpp:205
static const RPCResult RESULT_LAST_PROCESSED_BLOCK
Definition: util.h:30
void EnsureWalletIsUnlocked(const CWallet &wallet)
Definition: util.cpp:88
void PushParentDescriptors(const CWallet &wallet, const CScript &script_pubkey, UniValue &entry)
Fetch parent descriptors of this scriptPubKey.
Definition: util.cpp:115
RPCHelpMan abandontransaction()
RPCHelpMan listtransactions()
RPCHelpMan listsinceblock()
std::string LabelFromValue(const UniValue &value)
Definition: util.cpp:104
RPCHelpMan abortrescan()
CAmount CachedTxGetDebit(const CWallet &wallet, const CWalletTx &wtx, bool avoid_reuse)
Definition: receive.cpp:122
void AppendLastProcessedBlock(UniValue &entry, const CWallet &wallet)
Definition: util.cpp:155
CAmount CachedTxGetCredit(const CWallet &wallet, const CWalletTx &wtx, bool avoid_reuse)
Definition: receive.cpp:110
static UniValue ListReceived(const CWallet &wallet, const UniValue &params, const bool by_label, const bool include_immature_coinbase) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
void CachedTxGetAmounts(const CWallet &wallet, const CWalletTx &wtx, std::list< COutputEntry > &listReceived, std::list< COutputEntry > &listSent, CAmount &nFee, bool include_change)
Definition: receive.cpp:139
RPCHelpMan gettransaction()
static void ListTransactions(const CWallet &wallet, const CWalletTx &wtx, int nMinDepth, bool fLong, Vec &ret, const std::optional< std::string > &filter_label, bool include_change=false) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
List transactions based on the given criteria.
RPCHelpMan rescanblockchain()
static void WalletTxToJSON(const CWallet &wallet, const CWalletTx &wtx, UniValue &entry) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
RPCHelpMan listreceivedbylabel()
static void MaybePushAddress(UniValue &entry, const CTxDestination &dest)
RBFTransactionState
The rbf state of unconfirmed transactions.
Definition: rbf.h:29
@ UNKNOWN
Unconfirmed tx that does not signal rbf and is not in the mempool.
@ REPLACEABLE_BIP125
Either this tx or a mempool ancestor signals rbf.
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
std::vector< RPCResult > DecodeTxDoc(const std::string &txid_field_doc, bool wallet)
Explain the UniValue "decoded" transaction object, may include extra fields if processed by wallet.
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
@ RPC_MISC_ERROR
General application defined errors.
Definition: protocol.h:40
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
@ RPC_WALLET_ERROR
Wallet errors.
Definition: protocol.h:71
@ RPC_INTERNAL_ERROR
Definition: protocol.h:36
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:183
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:201
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency.
Definition: util.cpp:43
const std::string EXAMPLE_ADDRESS[2]
Example bech32 addresses for the RPCExamples help documentation.
Definition: util.cpp:44
uint256 ParseHashV(const UniValue &v, std::string_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:117
@ STR_HEX
Special type that is a STR with only hex chars.
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
@ ELISION
Special type to denote elision (...)
@ NUM_TIME
Special numeric to denote unix epoch time.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
Definition: receive.h:32
std::optional< int > last_scanned_height
Definition: wallet.h:643
enum wallet::CWallet::ScanResult::@18 status
State of transaction confirmed in a block.
Definition: transaction.h:32
std::vector< Txid > txids
tallyitem()=default
#define LOCK(cs)
Definition: sync.h:259
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:51
consteval auto _(util::TranslatedLiteral str)
Definition: translation.h:79
V Cat(V v1, V &&v2)
Concatenate two vectors, moving elements.
Definition: vector.h:34