Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
751if (!pwallet) return UniValue::VNULL;753// Make sure the results are valid at least up to the most recent block754// the user could have gotten from another RPC command prior to now755pwallet->BlockUntilSyncedToCurrentChain();757LOCK(pwallet->cs_wallet);759Txid hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};761bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();763UniValue entry(UniValue::VOBJ);764auto it = pwallet->mapWallet.find(hash);765if (it == pwallet->mapWallet.end()) {766throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");767}768const CWalletTx& wtx = it->second;770CAmount nCredit = CachedTxGetCredit(*pwallet, wtx, /*avoid_reuse=*/false);771CAmount nDebit = CachedTxGetDebit(*pwallet, wtx, /*avoid_reuse=*/false);772CAmount nNet = nCredit - nDebit;773CAmount nFee = (CachedTxIsFromMe(*pwallet, wtx) ? wtx.GetTx()->GetValueOut() - nDebit : 0);775entry.pushKV("amount", ValueFromAmount(nNet - nFee));776if (CachedTxIsFromMe(*pwallet, wtx))777entry.pushKV("fee", ValueFromAmount(nFee));779WalletTxToJSON(*pwallet, wtx, entry);781UniValue details(UniValue::VARR);782ListTransactions(*pwallet, wtx, 0, false, details, /*filter_label=*/std::nullopt);783entry.pushKV("details", std::move(details));785entry.pushKV("hex", EncodeHexTx(*wtx.GetTx()));787if (verbose) {788UniValue decoded(UniValue::VOBJ);789TxToUniv(*wtx.GetTx(),790/*block_hash=*/uint256(),791/*entry=*/decoded,792/*include_hex=*/false,793/*txundo=*/nullptr,794/*verbosity=*/TxVerbosity::SHOW_DETAILS,795/*is_change_func=*/[&pwallet](const CTxOut& txout) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {796AssertLockHeld(pwallet->cs_wallet);797return OutputIsChange(*pwallet, txout);798});799entry.pushKV("decoded", std::move(decoded));800}802AppendLastProcessedBlock(entry, *pwallet);803return entry;804},805};806}808RPCMethod abandontransaction()809{810return RPCMethod{811"abandontransaction",812"Mark in-wallet transaction <txid> as abandoned\n"813"This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"814"for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n"815"It only works on transactions which are not included in a block and are not currently in the mempool.\n"816"It has no effect on transactions which are already abandoned.\n",817{818{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},819},820RPCResult{RPCResult::Type::NONE, "", ""},821RPCExamples{822HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")823+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")824},825[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue826{827std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);828if (!pwallet) return UniValue::VNULL;830// Make sure the results are valid at least up to the most recent block831// the user could have gotten from another RPC command prior to now832pwallet->BlockUntilSyncedToCurrentChain();834LOCK(pwallet->cs_wallet);836Txid hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};838if (!pwallet->mapWallet.contains(hash)) {839throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");840}841if (!pwallet->AbandonTransaction(hash)) {842throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");843}845return UniValue::VNULL;846},847};848}850RPCMethod rescanblockchain()851{852return RPCMethod{853"rescanblockchain",854"Rescan the local blockchain for wallet related transactions.\n"855"Note: Use \"getwalletinfo\" to query the scanning progress.\n"856"The rescan is significantly faster if block filters are available\n"857"(using startup option \"-blockfilterindex=1\").\n",858{859{"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "block height where the rescan should start"},860{"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."},861},862RPCResult{863RPCResult::Type::OBJ, "", "",864{865{RPCResult::Type::NUM, "start_height", "The block height where the rescan started (the requested height or 0)"},866{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."},867}868},869RPCExamples{870HelpExampleCli("rescanblockchain", "100000 120000")871+ HelpExampleRpc("rescanblockchain", "100000, 120000")872},873[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue874{875std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);876if (!pwallet) return UniValue::VNULL;877CWallet& wallet{*pwallet};879// Make sure the results are valid at least up to the most recent block880// the user could have gotten from another RPC command prior to now881wallet.BlockUntilSyncedToCurrentChain();883WalletRescanReserver reserver(*pwallet);884if (!reserver.reserve(/*with_passphrase=*/true)) {885throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");886}888int start_height = 0;889std::optional<int> stop_height;890uint256 start_block;892LOCK(pwallet->m_relock_mutex);893{894LOCK(pwallet->cs_wallet);895EnsureWalletIsUnlocked(*pwallet);896int tip_height = pwallet->GetLastBlockHeight();898if (!request.params[0].isNull()) {899start_height = request.params[0].getInt<int>();900if (start_height < 0 || start_height > tip_height) {901throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");902}903}905if (!request.params[1].isNull()) {906stop_height = request.params[1].getInt<int>();907if (*stop_height < 0 || *stop_height > tip_height) {908throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");909} else if (*stop_height < start_height) {910throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height");911}912}914// We can't rescan unavailable blocks, stop and throw an error915if (!pwallet->chain().hasBlocks(pwallet->GetLastBlockHash(), start_height, stop_height)) {916if (pwallet->chain().havePruned() && pwallet->chain().getPruneHeight() >= start_height) {917throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");918}919if (pwallet->chain().hasAssumedValidChain()) {920throw 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.");921}922throw 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).");923}925CHECK_NONFATAL(pwallet->chain().findAncestorByHeight(pwallet->GetLastBlockHash(), start_height, FoundBlock().hash(start_block)));926}928CWallet::ScanResult result =929pwallet->ScanForWalletTransactions(start_block, start_height, stop_height, reserver, /*save_progress=*/false);930switch (result.status) {931case CWallet::ScanResult::SUCCESS:932break;933case CWallet::ScanResult::FAILURE:934throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");935case CWallet::ScanResult::USER_ABORT:936throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");937} // no default case, so the compiler can warn about missing cases938UniValue response(UniValue::VOBJ);939response.pushKV("start_height", start_height);940response.pushKV("stop_height", result.last_scanned_height ? *result.last_scanned_height : UniValue());941return response;942},943};944}946RPCMethod abortrescan()947{948return RPCMethod{"abortrescan",949"Stops current wallet rescan triggered by an RPC call, e.g. by a rescanblockchain call.\n"950"Note: Use \"getwalletinfo\" to query the scanning progress.\n",951{},952RPCResult{RPCResult::Type::BOOL, "", "Whether the abort was successful"},953RPCExamples{954"\nImport a private key\n"955+ HelpExampleCli("rescanblockchain", "") +956"\nAbort the running wallet rescan\n"957+ HelpExampleCli("abortrescan", "") +958"\nAs a JSON-RPC call\n"959+ HelpExampleRpc("abortrescan", "")960},961[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue962{963std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);964if (!pwallet) return UniValue::VNULL;966if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;967pwallet->AbortRescan();968return true;969},970};971}972} // namespace wallet