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