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