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