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