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