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