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