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