20 int confirms =
wallet.GetTxDepthInMainChain(wtx);
21 entry.
pushKV(
"confirmations", confirms);
23 entry.
pushKV(
"generated",
true);
26 entry.
pushKV(
"blockhash", conf->confirmed_block_hash.GetHex());
27 entry.
pushKV(
"blockheight", conf->confirmed_block_height);
28 entry.
pushKV(
"blockindex", conf->position_in_block);
31 entry.
pushKV(
"blocktime", block_time);
40 entry.
pushKV(
"walletconflicts", conflicts);
45 std::string rbfStatus =
"no";
49 rbfStatus =
"unknown";
53 entry.
pushKV(
"bip125-replaceable", rbfStatus);
55 for (
const std::pair<const std::string, std::string>& item : wtx.
mapValue)
56 entry.
pushKV(item.first, item.second);
62 int nConf{std::numeric_limits<int>::max()};
74 if (!params[0].isNull())
75 nMinDepth = params[0].get_int();
78 bool fIncludeEmpty =
false;
79 if (!params[1].isNull())
80 fIncludeEmpty = params[1].get_bool();
88 bool has_filtered_address =
false;
90 if (!by_label && !params[3].isNull() && !params[3].get_str().empty()) {
95 has_filtered_address =
true;
100 const bool include_coinbase{!
wallet.chain().rpcEnableDeprecated(
"exclude_coinbase")};
102 if (include_immature_coinbase && !include_coinbase) {
107 std::map<CTxDestination, tallyitem> mapTally;
108 for (
const std::pair<const uint256, CWalletTx>& pairWtx :
wallet.mapWallet) {
111 int nDepth =
wallet.GetTxDepthInMainChain(wtx);
112 if (nDepth < nMinDepth)
116 if ((wtx.
IsCoinBase() && (nDepth < 1 || !include_coinbase))
117 || (
wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase))
122 for (
const CTxOut& txout : wtx.
tx->vout)
128 if (has_filtered_address && !(filtered_address == address)) {
147 std::map<std::string, tallyitem> label_tally;
151 auto start =
wallet.m_address_book.begin();
152 auto end =
wallet.m_address_book.end();
154 if (has_filtered_address) {
155 start =
wallet.m_address_book.find(filtered_address);
157 end = std::next(start);
161 for (
auto item_it = start; item_it != end; ++item_it)
163 if (item_it->second.IsChange())
continue;
165 const std::string& label = item_it->second.GetLabel();
166 auto it = mapTally.find(address);
167 if (it == mapTally.end() && !fIncludeEmpty)
171 int nConf = std::numeric_limits<int>::max();
172 bool fIsWatchonly =
false;
173 if (it != mapTally.end())
175 nAmount = (*it).second.nAmount;
176 nConf = (*it).second.nConf;
177 fIsWatchonly = (*it).second.fIsWatchonly;
191 obj.
pushKV(
"involvesWatchonly",
true);
194 obj.
pushKV(
"confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
195 obj.
pushKV(
"label", label);
197 if (it != mapTally.end())
199 for (
const uint256& _item : (*it).second.txids)
204 obj.
pushKV(
"txids", transactions);
211 for (
const auto& entry : label_tally)
213 CAmount nAmount = entry.second.nAmount;
214 int nConf = entry.second.nConf;
216 if (entry.second.fIsWatchonly)
217 obj.
pushKV(
"involvesWatchonly",
true);
219 obj.
pushKV(
"confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
220 obj.
pushKV(
"label", entry.first);
231 "\nList balances by receiving address.\n",
244 {
RPCResult::Type::BOOL,
"involvesWatchonly",
true,
"Only returns true if imported addresses were involved in transaction"},
247 {
RPCResult::Type::NUM,
"confirmations",
"The number of confirmations of the most recent transaction included"},
248 {
RPCResult::Type::STR,
"label",
"The label of the receiving address. The default label is \"\""},
259 +
HelpExampleCli(
"listreceivedbyaddress",
"6 true true \"\" true")
270 pwallet->BlockUntilSyncedToCurrentChain();
272 const bool include_immature_coinbase{request.params[4].
isNull() ? false : request.params[4].get_bool()};
274 LOCK(pwallet->cs_wallet);
276 return ListReceived(*pwallet, request.params,
false, include_immature_coinbase);
284 "\nList received transactions by label.\n",
296 {
RPCResult::Type::BOOL,
"involvesWatchonly",
true,
"Only returns true if imported addresses were involved in transaction"},
298 {
RPCResult::Type::NUM,
"confirmations",
"The number of confirmations of the most recent transaction included"},
299 {
RPCResult::Type::STR,
"label",
"The label of the receiving address. The default label is \"\""},
315 pwallet->BlockUntilSyncedToCurrentChain();
317 const bool include_immature_coinbase{request.params[3].
isNull() ? false : request.params[3].get_bool()};
319 LOCK(pwallet->cs_wallet);
321 return ListReceived(*pwallet, request.params,
true, include_immature_coinbase);
347 std::list<COutputEntry> listReceived;
348 std::list<COutputEntry> listSent;
361 entry.
pushKV(
"involvesWatchonly",
true);
364 entry.
pushKV(
"category",
"send");
366 const auto* address_book_entry =
wallet.FindAddressBookEntry(s.destination);
367 if (address_book_entry) {
368 entry.
pushKV(
"label", address_book_entry->GetLabel());
370 entry.
pushKV(
"vout", s.vout);
374 entry.
pushKV(
"abandoned", wtx.isAbandoned());
375 ret.push_back(entry);
380 if (listReceived.size() > 0 &&
wallet.GetTxDepthInMainChain(wtx) >= nMinDepth) {
384 const auto* address_book_entry =
wallet.FindAddressBookEntry(r.destination);
385 if (address_book_entry) {
386 label = address_book_entry->GetLabel();
388 if (filter_label && label != *filter_label) {
393 entry.
pushKV(
"involvesWatchonly",
true);
396 if (wtx.IsCoinBase())
398 if (
wallet.GetTxDepthInMainChain(wtx) < 1)
399 entry.
pushKV(
"category",
"orphan");
400 else if (
wallet.IsTxImmatureCoinBase(wtx))
401 entry.
pushKV(
"category",
"immature");
403 entry.
pushKV(
"category",
"generate");
407 entry.
pushKV(
"category",
"receive");
410 if (address_book_entry) {
411 entry.
pushKV(
"label", label);
413 entry.
pushKV(
"vout", r.vout);
416 ret.push_back(entry);
424 return{{
RPCResult::Type::NUM,
"confirmations",
"The number of confirmations for the transaction. Negative confirmations means the\n"
425 "transaction conflicted that many blocks ago."},
426 {
RPCResult::Type::BOOL,
"generated",
true,
"Only present if the transaction's only input is a coinbase one."},
427 {
RPCResult::Type::BOOL,
"trusted",
true,
"Whether we consider the transaction to be trusted and safe to spend from.\n"
428 "Only present when the transaction has 0 confirmations (or negative confirmations, if conflicted)."},
431 {
RPCResult::Type::NUM,
"blockindex",
true,
"The index of the transaction in the block that includes it."},
444 {
RPCResult::Type::STR,
"comment",
true,
"If a comment is associated with the transaction, only present if not empty."},
445 {
RPCResult::Type::STR,
"bip125-replaceable",
"(\"yes|no|unknown\") Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
446 "may be unknown for unconfirmed transactions not in the mempool."}};
452 "\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
453 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
456 "with the specified label, or \"*\" to disable filtering and return all transactions."},
459 {
"include_watchonly",
RPCArg::Type::BOOL,
RPCArg::DefaultHint{
"true for watch-only wallets, otherwise false"},
"Include transactions to watch-only addresses (see 'importaddress')"},
466 {
RPCResult::Type::BOOL,
"involvesWatchonly",
true,
"Only returns true if imported addresses were involved in transaction."},
469 "\"send\" Transactions sent.\n"
470 "\"receive\" Non-coinbase transactions received.\n"
471 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
472 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
473 "\"orphan\" Orphaned coinbase transactions received."},
475 "for all other categories"},
479 "'send' category of transactions."},
483 {
RPCResult::Type::BOOL,
"abandoned",
true,
"'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
484 "'send' category of transactions."},
489 "\nList the most recent 10 transactions in the systems\n"
491 "\nList transactions 100 to 120\n"
493 "\nAs a JSON-RPC call\n"
503 pwallet->BlockUntilSyncedToCurrentChain();
505 const std::string* filter_label =
nullptr;
506 if (!request.params[0].isNull() && request.params[0].get_str() !=
"*") {
507 filter_label = &request.params[0].
get_str();
508 if (filter_label->empty()) {
513 if (!request.params[1].isNull())
514 nCount = request.params[1].get_int();
516 if (!request.params[2].isNull())
517 nFrom = request.params[2].get_int();
532 LOCK(pwallet->cs_wallet);
537 for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
541 if ((
int)ret.
size() >= (nCount+nFrom))
break;
547 if (nFrom > (
int)ret.
size())
549 if ((nFrom + nCount) > (
int)ret.
size())
550 nCount = ret.
size() - nFrom;
552 const std::vector<UniValue>& txs = ret.
getValues();
554 result.push_backV({ txs.rend() - nFrom - nCount, txs.rend() - nFrom });
563 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted.\n"
564 "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
565 "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",
568 {
"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"},
569 {
"include_watchonly",
RPCArg::Type::BOOL,
RPCArg::DefaultHint{
"true for watch-only wallets, otherwise false"},
"Include transactions to watch-only addresses (see 'importaddress')"},
571 "(not guaranteed to work on pruned nodes)"},
580 {
RPCResult::Type::BOOL,
"involvesWatchonly",
true,
"Only returns true if imported addresses were involved in transaction."},
583 "\"send\" Transactions sent.\n"
584 "\"receive\" Non-coinbase transactions received.\n"
585 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
586 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
587 "\"orphan\" Orphaned coinbase transactions received."},
589 "for all other categories"},
592 "'send' category of transactions."},
596 {
RPCResult::Type::BOOL,
"abandoned",
true,
"'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
597 "'send' category of transactions."},
601 {
RPCResult::Type::ARR,
"removed",
true,
"<structure is the same as \"transactions\" above, only present if include_removed=true>\n"
602 "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."
604 {
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"},
609 +
HelpExampleCli(
"listsinceblock",
"\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
610 +
HelpExampleRpc(
"listsinceblock",
"\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
620 wallet.BlockUntilSyncedToCurrentChain();
624 std::optional<int> height;
625 std::optional<int> altheight;
626 int target_confirms = 1;
630 if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
631 blockId =
ParseHashV(request.params[0],
"blockhash");
639 if (!request.params[1].isNull()) {
640 target_confirms = request.params[1].get_int();
642 if (target_confirms < 1) {
651 bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
653 int depth = height ?
wallet.GetLastBlockHeight() + 1 - *height : -1;
657 for (
const std::pair<const uint256, CWalletTx>& pairWtx :
wallet.mapWallet) {
660 if (depth == -1 || abs(
wallet.GetTxDepthInMainChain(tx)) < depth) {
668 while (include_removed && altheight && *altheight > *height) {
674 auto it =
wallet.mapWallet.find(tx->GetHash());
675 if (it !=
wallet.mapWallet.end()) {
686 target_confirms = std::min(target_confirms,
wallet.GetLastBlockHeight() + 1);
690 ret.
pushKV(
"transactions", transactions);
691 if (include_removed) ret.
pushKV(
"removed", removed);
702 "\nGet detailed information about in-wallet transaction <txid>\n",
706 "Whether to include watch-only addresses in balance calculation and details[]"},
708 "Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},
715 "'send' category of transactions."},
723 {
RPCResult::Type::BOOL,
"involvesWatchonly",
true,
"Only returns true if imported addresses were involved in transaction."},
726 "\"send\" Transactions sent.\n"
727 "\"receive\" Non-coinbase transactions received.\n"
728 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
729 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
730 "\"orphan\" Orphaned coinbase transactions received."},
735 "'send' category of transactions."},
736 {
RPCResult::Type::BOOL,
"abandoned",
true,
"'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
737 "'send' category of transactions."},
741 {
RPCResult::Type::OBJ,
"decoded",
true,
"The decoded transaction (only present when `verbose` is passed)",
743 {
RPCResult::Type::ELISION,
"",
"Equivalent to the RPC decoderawtransaction method, or the RPC getrawtransaction method when `verbose` is passed."},
748 HelpExampleCli(
"gettransaction",
"\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
749 +
HelpExampleCli(
"gettransaction",
"\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
750 +
HelpExampleCli(
"gettransaction",
"\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" false true")
751 +
HelpExampleRpc(
"gettransaction",
"\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
760 pwallet->BlockUntilSyncedToCurrentChain();
762 LOCK(pwallet->cs_wallet);
772 bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();
775 auto it = pwallet->mapWallet.find(hash);
776 if (it == pwallet->mapWallet.end()) {
783 CAmount nNet = nCredit - nDebit;
794 entry.
pushKV(
"details", details);
796 std::string strHex =
EncodeHexTx(*wtx.
tx, pwallet->chain().rpcSerializationFlags());
797 entry.
pushKV(
"hex", strHex);
802 entry.
pushKV(
"decoded", decoded);
813 "\nMark in-wallet transaction <txid> as abandoned\n"
814 "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
815 "for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n"
816 "It only works on transactions which are not included in a block and are not currently in the mempool.\n"
817 "It has no effect on transactions which are already abandoned.\n",
823 HelpExampleCli(
"abandontransaction",
"\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
824 +
HelpExampleRpc(
"abandontransaction",
"\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
833 pwallet->BlockUntilSyncedToCurrentChain();
835 LOCK(pwallet->cs_wallet);
839 if (!pwallet->mapWallet.count(hash)) {
842 if (!pwallet->AbandonTransaction(hash)) {
854 "\nRescan the local blockchain for wallet related transactions.\n"
855 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
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."},
879 wallet.BlockUntilSyncedToCurrentChain();
886 int start_height = 0;
887 std::optional<int> stop_height;
890 LOCK(pwallet->cs_wallet);
891 int tip_height = pwallet->GetLastBlockHeight();
893 if (!request.params[0].isNull()) {
894 start_height = request.params[0].get_int();
895 if (start_height < 0 || start_height > tip_height) {
900 if (!request.params[1].isNull()) {
901 stop_height = request.params[1].get_int();
902 if (*stop_height < 0 || *stop_height > tip_height) {
904 }
else if (*stop_height < start_height) {
910 if (!pwallet->chain().hasBlocks(pwallet->GetLastBlockHash(), start_height, stop_height)) {
911 throw JSONRPCError(
RPC_MISC_ERROR,
"Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
914 CHECK_NONFATAL(pwallet->chain().findAncestorByHeight(pwallet->GetLastBlockHash(), start_height,
FoundBlock().hash(start_block)));
918 pwallet->ScanForWalletTransactions(start_block, start_height, stop_height, reserver,
true );
929 response.
pushKV(
"start_height", start_height);
939 "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n"
940 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
944 "\nImport a private key\n"
946 "\nAbort the running wallet rescan\n"
948 "\nAs a JSON-RPC call\n"
956 if (!pwallet->IsScanning() || pwallet->IsAbortingRescan())
return false;
957 pwallet->AbortRescan();