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