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