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,
143 const std::optional<AddressPurpose>& purpose) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) {
144 if (is_change) return; // no change addresses
145
146 // Entries in mapTally are only ever added for wallet.IsMine() addresses (see the tally
147 // loop above), so it's only addresses missing from mapTally that need the IsMine() check.
148 auto it = mapTally.find(address);
149 if (it == mapTally.end()) {
150 if (!fIncludeEmpty) return;
151 if (!wallet.IsMine(address)) return; // exclude addresses not owned by the wallet (e.g. "send" purpose)
152 }
153
154 CAmount nAmount = 0;
155 int nConf = std::numeric_limits<int>::max();
156 if (it != mapTally.end()) {
157 nAmount = (*it).second.nAmount;
158 nConf = (*it).second.nConf;
159 }
160
161 if (by_label) {
162 tallyitem& _item = label_tally[label];
163 _item.nAmount += nAmount;
164 _item.nConf = std::min(_item.nConf, nConf);
165 } else {
167 obj.pushKV("address", EncodeDestination(address));
168 obj.pushKV("amount", ValueFromAmount(nAmount));
169 obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
170 obj.pushKV("label", label);
171 UniValue transactions(UniValue::VARR);
172 if (it != mapTally.end()) {
173 for (const Txid& _item : (*it).second.txids) {
174 transactions.push_back(_item.GetHex());
175 }
176 }
177 obj.pushKV("txids", std::move(transactions));
178 ret.push_back(std::move(obj));
179 }
180 };
181
182 if (filtered_address) {
183 const auto& entry = wallet.FindAddressBookEntry(*filtered_address, /*allow_change=*/false);
184 if (entry) func(*filtered_address, entry->GetLabel(), entry->IsChange(), entry->purpose);
185 } else {
186 // No filtered addr, walk-through the addressbook entry
187 wallet.ForEachAddrBookEntry(func);
188 }
189
190 if (by_label) {
191 for (const auto& entry : label_tally) {
192 CAmount nAmount = entry.second.nAmount;
193 int nConf = entry.second.nConf;
195 obj.pushKV("amount", ValueFromAmount(nAmount));
196 obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
197 obj.pushKV("label", entry.first);
198 ret.push_back(std::move(obj));
199 }
200 }
201
202 return ret;
203}
204
206{
207 return RPCMethod{
208 "listreceivedbyaddress",
209 "List balances by receiving address.\n",
210 {
211 {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
212 {"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include addresses that haven't received any payments."},
213 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
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::STR, "address", "The receiving address"},
223 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received by the address"},
224 {RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
225 {RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
226 {RPCResult::Type::ARR, "txids", "",
227 {
228 {RPCResult::Type::STR_HEX, "txid", "The ids of transactions received with the address"},
229 }},
230 }},
231 }
232 },
234 HelpExampleCli("listreceivedbyaddress", "")
235 + HelpExampleCli("listreceivedbyaddress", "6 true")
236 + HelpExampleCli("listreceivedbyaddress", "6 true true \"\" true")
237 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
238 + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"" + EXAMPLE_ADDRESS[0] + "\", true")
239 },
240 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
241{
242 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
243 if (!pwallet) return UniValue::VNULL;
244
245 // Make sure the results are valid at least up to the most recent block
246 // the user could have gotten from another RPC command prior to now
247 pwallet->BlockUntilSyncedToCurrentChain();
248
249 const bool include_immature_coinbase{request.params[4].isNull() ? false : request.params[4].get_bool()};
250
251 LOCK(pwallet->cs_wallet);
252
253 return ListReceived(*pwallet, request.params, false, include_immature_coinbase);
254},
255 };
256}
257
259{
260 return RPCMethod{
261 "listreceivedbylabel",
262 "List 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::Default{false}, "(DEPRECATED) No longer used"},
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::STR_AMOUNT, "amount", "The total amount received by addresses with this label"},
275 {RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
276 {RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
277 }},
278 }
279 },
281 HelpExampleCli("listreceivedbylabel", "")
282 + HelpExampleCli("listreceivedbylabel", "6 true")
283 + HelpExampleRpc("listreceivedbylabel", "6, true, true, true")
284 },
285 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
286{
287 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
288 if (!pwallet) return UniValue::VNULL;
289
290 // Make sure the results are valid at least up to the most recent block
291 // the user could have gotten from another RPC command prior to now
292 pwallet->BlockUntilSyncedToCurrentChain();
293
294 const bool include_immature_coinbase{request.params[3].isNull() ? false : request.params[3].get_bool()};
295
296 LOCK(pwallet->cs_wallet);
297
298 return ListReceived(*pwallet, request.params, true, include_immature_coinbase);
299},
300 };
301}
302
303static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
304{
305 if (IsValidDestination(dest)) {
306 entry.pushKV("address", EncodeDestination(dest));
307 }
308}
309
320template <class Vec>
321static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong,
322 Vec& ret, const std::optional<std::string>& filter_label,
323 bool include_change = false)
325{
326 CAmount nFee;
327 std::list<COutputEntry> listReceived;
328 std::list<COutputEntry> listSent;
329
330 CachedTxGetAmounts(wallet, wtx, listReceived, listSent, nFee, include_change);
331
332 // Sent
333 if (!filter_label.has_value())
334 {
335 for (const COutputEntry& s : listSent)
336 {
338 MaybePushAddress(entry, s.destination);
339 entry.pushKV("category", "send");
340 entry.pushKV("amount", ValueFromAmount(-s.amount));
341 const auto* address_book_entry = wallet.FindAddressBookEntry(s.destination);
342 if (address_book_entry) {
343 entry.pushKV("label", address_book_entry->GetLabel());
344 }
345 entry.pushKV("vout", s.vout);
346 entry.pushKV("fee", ValueFromAmount(-nFee));
347 if (fLong)
348 WalletTxToJSON(wallet, wtx, entry);
349 entry.pushKV("abandoned", wtx.isAbandoned());
350 ret.push_back(std::move(entry));
351 }
352 }
353
354 // Received
355 if (listReceived.size() > 0 && wallet.GetTxDepthInMainChain(wtx) >= nMinDepth) {
356 for (const COutputEntry& r : listReceived)
357 {
358 std::string label;
359 const auto* address_book_entry = wallet.FindAddressBookEntry(r.destination);
360 if (address_book_entry) {
361 label = address_book_entry->GetLabel();
362 }
363 if (filter_label.has_value() && label != filter_label.value()) {
364 continue;
365 }
367 MaybePushAddress(entry, r.destination);
368 PushParentDescriptors(wallet, wtx.GetTx()->vout.at(r.vout).scriptPubKey, entry);
369 if (wtx.IsCoinBase())
370 {
371 if (wallet.GetTxDepthInMainChain(wtx) < 1)
372 entry.pushKV("category", "orphan");
373 else if (wallet.IsTxImmatureCoinBase(wtx))
374 entry.pushKV("category", "immature");
375 else
376 entry.pushKV("category", "generate");
377 }
378 else
379 {
380 entry.pushKV("category", "receive");
381 }
382 entry.pushKV("amount", ValueFromAmount(r.amount));
383 if (address_book_entry) {
384 entry.pushKV("label", label);
385 }
386 entry.pushKV("vout", r.vout);
387 entry.pushKV("abandoned", wtx.isAbandoned());
388 if (fLong)
389 WalletTxToJSON(wallet, wtx, entry);
390 ret.push_back(std::move(entry));
391 }
392 }
393}
394
395
396static std::vector<RPCResult> TransactionDescriptionString()
397{
398 return{{RPCResult::Type::NUM, "confirmations", "The number of confirmations for the transaction. Negative confirmations means the\n"
399 "transaction conflicted that many blocks ago."},
400 {RPCResult::Type::BOOL, "generated", /*optional=*/true, "Only present if the transaction's only input is a coinbase one."},
401 {RPCResult::Type::BOOL, "trusted", /*optional=*/true, "Whether we consider the transaction to be trusted and safe to spend from.\n"
402 "Only present when the transaction has 0 confirmations (or negative confirmations, if conflicted)."},
403 {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block hash containing the transaction."},
404 {RPCResult::Type::NUM, "blockheight", /*optional=*/true, "The block height containing the transaction."},
405 {RPCResult::Type::NUM, "blockindex", /*optional=*/true, "The index of the transaction in the block that includes it."},
406 {RPCResult::Type::NUM_TIME, "blocktime", /*optional=*/true, "The block time expressed in " + UNIX_EPOCH_TIME + "."},
407 {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
408 {RPCResult::Type::STR_HEX, "wtxid", "The hash of serialized transaction, including witness data."},
409 {RPCResult::Type::ARR, "alternate_wtxids", "The wtxids of transactions with different witness data but the same txid.",
410 {
411 {RPCResult::Type::STR_HEX, "wtxid", "The witness transaction id."},
412 }},
413 {RPCResult::Type::ARR, "walletconflicts", "Confirmed transactions that have been detected by the wallet to conflict with this transaction.",
414 {
415 {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
416 }},
417 {RPCResult::Type::STR_HEX, "replaced_by_txid", /*optional=*/true, "Only if 'category' is 'send'. The txid if this tx was replaced."},
418 {RPCResult::Type::STR_HEX, "replaces_txid", /*optional=*/true, "Only if 'category' is 'send'. The txid if this tx replaces another."},
419 {RPCResult::Type::ARR, "mempoolconflicts", "Transactions in the mempool that directly conflict with either this transaction or an ancestor transaction",
420 {
421 {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
422 }},
423 {RPCResult::Type::STR, "to", /*optional=*/true, "If a comment to is associated with the transaction."},
424 {RPCResult::Type::NUM_TIME, "time", "The transaction time expressed in " + UNIX_EPOCH_TIME + "."},
425 {RPCResult::Type::NUM_TIME, "timereceived", "The time received expressed in " + UNIX_EPOCH_TIME + "."},
426 {RPCResult::Type::STR, "comment", /*optional=*/true, "If a comment is associated with the transaction, only present if not empty."},
427 {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"
428 "May be unknown for unconfirmed transactions not in the mempool because their unconfirmed ancestors are unknown."},
429 {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the output script of this coin.", {
430 {RPCResult::Type::STR, "desc", "The descriptor string."},
431 }},
432 };
433}
434
436{
437 return RPCMethod{
438 "listtransactions",
439 "If a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
440 "Returns up to 'count' most recent transactions ordered from oldest to newest while skipping the first number of \n"
441 "transactions specified in the 'skip' argument. A transaction can have multiple entries in this RPC response. \n"
442 "For instance, a wallet transaction that pays three addresses — one wallet-owned and two external — will produce \n"
443 "four entries. The payment to the wallet-owned address appears both as a send entry and as a receive entry. \n"
444 "As a result, the RPC response will contain one entry in the receive category and three entries in the send category.\n",
445 {
446 {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If set, should be a valid label name to return only incoming transactions\n"
447 "with the specified label, or \"*\" to disable filtering and return all transactions."},
448 {"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"},
449 {"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"},
450 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
451 },
452 RPCResult{
453 RPCResult::Type::ARR, "", "",
454 {
455 {RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
456 {
457 {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)."},
458 {RPCResult::Type::STR, "category", "The transaction category.\n"
459 "\"send\" Transactions sent.\n"
460 "\"receive\" Non-coinbase transactions received.\n"
461 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
462 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
463 "\"orphan\" Orphaned coinbase transactions received."},
464 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
465 "for all other categories"},
466 {RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},
467 {RPCResult::Type::NUM, "vout", "the vout value"},
468 {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
469 "'send' category of transactions."},
470 },
472 {
473 {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
474 })},
475 }
476 },
478 "\nList the most recent 10 transactions in the systems\n"
479 + HelpExampleCli("listtransactions", "") +
480 "\nList transactions 100 to 120\n"
481 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
482 "\nAs a JSON-RPC call\n"
483 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
484 },
485 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
486{
487 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
488 if (!pwallet) return UniValue::VNULL;
489
490 // Make sure the results are valid at least up to the most recent block
491 // the user could have gotten from another RPC command prior to now
492 pwallet->BlockUntilSyncedToCurrentChain();
493
494 std::optional<std::string> filter_label;
495 if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
496 filter_label.emplace(LabelFromValue(request.params[0]));
497 if (filter_label.value().empty()) {
498 throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
499 }
500 }
501 int nCount = 10;
502 if (!request.params[1].isNull())
503 nCount = request.params[1].getInt<int>();
504 int nFrom = 0;
505 if (!request.params[2].isNull())
506 nFrom = request.params[2].getInt<int>();
507
508 if (nCount < 0)
509 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
510 if (nFrom < 0)
511 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
512
513 std::vector<UniValue> ret;
514 {
515 LOCK(pwallet->cs_wallet);
516
517 const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
518
519 // iterate backwards until we have nCount items to return:
520 for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
521 {
522 CWalletTx *const pwtx = (*it).second;
523 ListTransactions(*pwallet, *pwtx, 0, true, ret, filter_label);
524 if ((int)ret.size() >= (nCount+nFrom)) break;
525 }
526 }
527
528 // ret is newest to oldest
529
530 if (nFrom > (int)ret.size())
531 nFrom = ret.size();
532 if ((nFrom + nCount) > (int)ret.size())
533 nCount = ret.size() - nFrom;
534
535 auto txs_rev_it{std::make_move_iterator(ret.rend())};
536 UniValue result{UniValue::VARR};
537 result.push_backV(txs_rev_it - nFrom - nCount, txs_rev_it - nFrom); // Return oldest to newest
538 return result;
539},
540 };
541}
542
543static std::vector<RPCResult> ListSinceBlockTxFields()
544{
545 return Cat<std::vector<RPCResult>>(
546 {
547 {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)."},
548 {RPCResult::Type::STR, "category", "The transaction category.\n"
549 "\"send\" Transactions sent.\n"
550 "\"receive\" Non-coinbase transactions received.\n"
551 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
552 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
553 "\"orphan\" Orphaned coinbase transactions received."},
554 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
555 "for all other categories"},
556 {RPCResult::Type::NUM, "vout", "the vout value"},
557 {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
558 "'send' category of transactions."},
559 },
560 Cat(
562 std::vector<RPCResult>{
563 {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
564 {RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},
565 }
566 )
567 );
568}
569
571{
572 return RPCMethod{
573 "listsinceblock",
574 "Get all transactions in blocks since block [blockhash], or all transactions if omitted.\n"
575 "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
576 "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",
577 {
578 {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If set, the block hash to list transactions since, otherwise list all transactions."},
579 {"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"},
580 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
581 {"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n"
582 "(not guaranteed to work on pruned nodes)"},
583 {"include_change", RPCArg::Type::BOOL, RPCArg::Default{false}, "Also add entries for change outputs.\n"},
584 {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Return only incoming transactions paying to addresses with the specified label.\n"},
585 },
586 RPCResult{
587 RPCResult::Type::OBJ, "", "",
588 {
589 {RPCResult::Type::ARR, "transactions", "",
590 {
592 }},
593 {RPCResult::Type::ARR, "removed", /*optional=*/true, "<structure is the same as \"transactions\" above, only present if include_removed=true>\n"
594 "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.",
595 {
596 {RPCResult::Type::OBJ, "", "", ListSinceBlockTxFields(), {.print_elision = std::string{}}},
597 }},
598 {RPCResult::Type::STR_HEX, "lastblock", "The hash of the block (target_confirmations-1) from the best block on the main chain, or the genesis hash if the referenced block does not exist yet. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones"},
599 }
600 },
602 HelpExampleCli("listsinceblock", "")
603 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
604 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
605 },
606 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
607{
608 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
609 if (!pwallet) return UniValue::VNULL;
610
611 const CWallet& wallet = *pwallet;
612 // Make sure the results are valid at least up to the most recent block
613 // the user could have gotten from another RPC command prior to now
614 wallet.BlockUntilSyncedToCurrentChain();
615
616 LOCK(wallet.cs_wallet);
617
618 std::optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
619 std::optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
620 int target_confirms = 1;
621
622 uint256 blockId;
623 if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
624 blockId = ParseHashV(request.params[0], "blockhash");
625 height = int{};
626 altheight = int{};
627 if (!wallet.chain().findCommonAncestor(blockId, wallet.GetLastBlockHash(), /*ancestor_out=*/FoundBlock().height(*height), /*block1_out=*/FoundBlock().height(*altheight))) {
628 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
629 }
630 }
631
632 if (!request.params[1].isNull()) {
633 target_confirms = request.params[1].getInt<int>();
634
635 if (target_confirms < 1) {
636 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
637 }
638 }
639
640 bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
641 bool include_change = (!request.params[4].isNull() && request.params[4].get_bool());
642
643 // Only set it if 'label' was provided.
644 std::optional<std::string> filter_label;
645 if (!request.params[5].isNull()) filter_label.emplace(LabelFromValue(request.params[5]));
646
647 int depth = height ? wallet.GetLastBlockHeight() + 1 - *height : -1;
648
649 UniValue transactions(UniValue::VARR);
650
651 for (const auto& [_, tx] : wallet.mapWallet) {
652
653 if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) {
654 ListTransactions(wallet, tx, 0, true, transactions, filter_label, include_change);
655 }
656 }
657
658 // when a reorg'd block is requested, we also list any relevant transactions
659 // in the blocks of the chain that was detached
660 UniValue removed(UniValue::VARR);
661 while (include_removed && altheight && *altheight > *height) {
662 CBlock block;
663 if (!wallet.chain().findBlock(blockId, FoundBlock().data(block)) || block.IsNull()) {
664 throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
665 }
666 for (const CTransactionRef& tx : block.vtx) {
667 auto it = wallet.mapWallet.find(tx->GetHash());
668 if (it != wallet.mapWallet.end()) {
669 // We want all transactions regardless of confirmation count to appear here,
670 // even negative confirmation ones, hence the big negative.
671 ListTransactions(wallet, it->second, -100000000, true, removed, filter_label, include_change);
672 }
673 }
674 blockId = block.hashPrevBlock;
675 --*altheight;
676 }
677
678 uint256 lastblock;
679 target_confirms = std::min(target_confirms, wallet.GetLastBlockHeight() + 1);
680 CHECK_NONFATAL(wallet.chain().findAncestorByHeight(wallet.GetLastBlockHash(), wallet.GetLastBlockHeight() + 1 - target_confirms, FoundBlock().hash(lastblock)));
681
683 ret.pushKV("transactions", std::move(transactions));
684 if (include_removed) ret.pushKV("removed", std::move(removed));
685 ret.pushKV("lastblock", lastblock.GetHex());
686
687 return ret;
688},
689 };
690}
691
693{
694 return RPCMethod{
695 "gettransaction",
696 "Get detailed information about in-wallet transaction <txid>\n",
697 {
698 {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
699 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},
700 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
701 "Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},
702 },
703 RPCResult{
704 RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
705 {
706 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
707 {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
708 "'send' category of transactions."},
709 },
711 {
712 {RPCResult::Type::ARR, "details", "",
713 {
714 {RPCResult::Type::OBJ, "", "",
715 {
716 {RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address involved in the transaction."},
717 {RPCResult::Type::STR, "category", "The transaction category.\n"
718 "\"send\" Transactions sent.\n"
719 "\"receive\" Non-coinbase transactions received.\n"
720 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
721 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
722 "\"orphan\" Orphaned coinbase transactions received."},
723 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
724 {RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},
725 {RPCResult::Type::NUM, "vout", "the vout value"},
726 {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
727 "'send' category of transactions."},
728 {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
729 {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the output script of this coin.", {
730 {RPCResult::Type::STR, "desc", "The descriptor string."},
731 }},
732 }},
733 }},
734 {RPCResult::Type::STR_HEX, "hex", "Raw data for transaction"},
735 {RPCResult::Type::OBJ, "decoded", /*optional=*/true, "The decoded transaction (only present when `verbose` is passed)",
736 {
737 TxDoc({.wallet = true}),
738 }},
740 })
741 },
743 HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
744 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
745 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" false true")
746 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
747 },
748 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
749{
750 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
751 if (!pwallet) return UniValue::VNULL;
752
753 // Make sure the results are valid at least up to the most recent block
754 // the user could have gotten from another RPC command prior to now
755 pwallet->BlockUntilSyncedToCurrentChain();
756
757 LOCK(pwallet->cs_wallet);
758
759 Txid hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
760
761 bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();
762
764 auto it = pwallet->mapWallet.find(hash);
765 if (it == pwallet->mapWallet.end()) {
766 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
767 }
768 const CWalletTx& wtx = it->second;
769
770 CAmount nCredit = CachedTxGetCredit(*pwallet, wtx, /*avoid_reuse=*/false);
771 CAmount nDebit = CachedTxGetDebit(*pwallet, wtx, /*avoid_reuse=*/false);
772 CAmount nNet = nCredit - nDebit;
773 CAmount nFee = (CachedTxIsFromMe(*pwallet, wtx) ? wtx.GetTx()->GetValueOut() - nDebit : 0);
774
775 entry.pushKV("amount", ValueFromAmount(nNet - nFee));
776 if (CachedTxIsFromMe(*pwallet, wtx))
777 entry.pushKV("fee", ValueFromAmount(nFee));
778
779 WalletTxToJSON(*pwallet, wtx, entry);
780
781 UniValue details(UniValue::VARR);
782 ListTransactions(*pwallet, wtx, 0, false, details, /*filter_label=*/std::nullopt);
783 entry.pushKV("details", std::move(details));
784
785 entry.pushKV("hex", EncodeHexTx(*wtx.GetTx()));
786
787 if (verbose) {
788 UniValue decoded(UniValue::VOBJ);
789 TxToUniv(*wtx.GetTx(),
790 /*block_hash=*/uint256(),
791 /*entry=*/decoded,
792 /*include_hex=*/false,
793 /*txundo=*/nullptr,
794 /*verbosity=*/TxVerbosity::SHOW_DETAILS,
795 /*is_change_func=*/[&pwallet](const CTxOut& txout) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
796 AssertLockHeld(pwallet->cs_wallet);
797 return OutputIsChange(*pwallet, txout);
798 });
799 entry.pushKV("decoded", std::move(decoded));
800 }
801
802 AppendLastProcessedBlock(entry, *pwallet);
803 return entry;
804},
805 };
806}
807
809{
810 return RPCMethod{
811 "abandontransaction",
812 "Mark 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 RPCMethod& 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 Txid hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
837
838 if (!pwallet->mapWallet.contains(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 RPCMethod{
853 "rescanblockchain",
854 "Rescan the local blockchain for wallet related transactions.\n"
855 "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
856 "The rescan is significantly faster if block filters are available\n"
857 "(using startup option \"-blockfilterindex=1\").\n",
858 {
859 {"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "block height where the rescan should start"},
860 {"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."},
861 },
862 RPCResult{
863 RPCResult::Type::OBJ, "", "",
864 {
865 {RPCResult::Type::NUM, "start_height", "The block height where the rescan started (the requested height or 0)"},
866 {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."},
867 }
868 },
870 HelpExampleCli("rescanblockchain", "100000 120000")
871 + HelpExampleRpc("rescanblockchain", "100000, 120000")
872 },
873 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
874{
875 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
876 if (!pwallet) return UniValue::VNULL;
877 CWallet& wallet{*pwallet};
878
879 // Make sure the results are valid at least up to the most recent block
880 // the user could have gotten from another RPC command prior to now
881 wallet.BlockUntilSyncedToCurrentChain();
882
883 WalletRescanReserver reserver(*pwallet);
884 if (!reserver.reserve(/*with_passphrase=*/true)) {
885 throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
886 }
887
888 int start_height = 0;
889 std::optional<int> stop_height;
890 uint256 start_block;
891
892 LOCK(pwallet->m_relock_mutex);
893 {
894 LOCK(pwallet->cs_wallet);
895 EnsureWalletIsUnlocked(*pwallet);
896 int tip_height = pwallet->GetLastBlockHeight();
897
898 if (!request.params[0].isNull()) {
899 start_height = request.params[0].getInt<int>();
900 if (start_height < 0 || start_height > tip_height) {
901 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
902 }
903 }
904
905 if (!request.params[1].isNull()) {
906 stop_height = request.params[1].getInt<int>();
907 if (*stop_height < 0 || *stop_height > tip_height) {
908 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
909 } else if (*stop_height < start_height) {
910 throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height");
911 }
912 }
913
914 // We can't rescan unavailable blocks, stop and throw an error
915 if (!pwallet->chain().hasBlocks(pwallet->GetLastBlockHash(), start_height, stop_height)) {
916 if (pwallet->chain().havePruned() && pwallet->chain().getPruneHeight() >= start_height) {
917 throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
918 }
919 if (pwallet->chain().hasAssumedValidChain()) {
920 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.");
921 }
922 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).");
923 }
924
925 CHECK_NONFATAL(pwallet->chain().findAncestorByHeight(pwallet->GetLastBlockHash(), start_height, FoundBlock().hash(start_block)));
926 }
927
928 CWallet::ScanResult result =
929 pwallet->ScanForWalletTransactions(start_block, start_height, stop_height, reserver, /*save_progress=*/false);
930 switch (result.status) {
932 break;
934 throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
936 throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
937 } // no default case, so the compiler can warn about missing cases
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 RPCMethod{"abortrescan",
949 "Stops current wallet rescan triggered by an RPC call, e.g. by a rescanblockchain 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("rescanblockchain", "") +
956 "\nAbort the running wallet rescan\n"
957 + HelpExampleCli("abortrescan", "") +
958 "\nAs a JSON-RPC call\n"
959 + HelpExampleRpc("abortrescan", "")
960 },
961 [](const RPCMethod& 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: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:117
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:52
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:389
bool isAbandoned() const
Definition: transaction.h:381
CTransactionRef GetTx() const
Definition: transaction.h:349
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1111
bool reserve(bool with_passphrase=false)
Definition: wallet.h:1121
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
const RPCResult RESULT_LAST_PROCESSED_BLOCK
Definition: util.h:29
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:184
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:202
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:44
const std::string EXAMPLE_ADDRESS[2]
Example bech32 addresses for the RPCExamples help documentation.
Definition: util.cpp:45
uint256 ParseHashV(const UniValue &v, std::string_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:118
@ 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