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.
501int nCount = 10;502if (!request.params[1].isNull())503nCount = request.params[1].getInt<int>();504int nFrom = 0;505if (!request.params[2].isNull())506nFrom = request.params[2].getInt<int>();508if (nCount < 0)509throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");510if (nFrom < 0)511throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");513std::vector<UniValue> ret;514{515LOCK(pwallet->cs_wallet);517const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;519// iterate backwards until we have nCount items to return:520for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)521{522CWalletTx *const pwtx = (*it).second;523ListTransactions(*pwallet, *pwtx, 0, true, ret, filter_label);524if ((int)ret.size() >= (nCount+nFrom)) break;525}526}528// ret is newest to oldest530if (nFrom > (int)ret.size())531nFrom = ret.size();532if ((nFrom + nCount) > (int)ret.size())533nCount = ret.size() - nFrom;535auto txs_rev_it{std::make_move_iterator(ret.rend())};536UniValue result{UniValue::VARR};537result.push_backV(txs_rev_it - nFrom - nCount, txs_rev_it - nFrom); // Return oldest to newest538return result;539},540};541}543static std::vector<RPCResult> ListSinceBlockTxFields()544{545return 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},560Cat(561TransactionDescriptionString(),562std::vector<RPCResult>{563{RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},564{RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},565}566)567);568}570RPCMethod listsinceblock()571{572return RPCMethod{573"listsinceblock",574"Get all transactions in blocks since block [blockhash], or all transactions if omitted.\n"575"If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"576"Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",577{578{"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "If set, the block hash to list transactions since, otherwise list all transactions."},579{"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"},580{"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},581{"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n"582"(not guaranteed to work on pruned nodes)"},583{"include_change", RPCArg::Type::BOOL, RPCArg::Default{false}, "Also add entries for change outputs.\n"},584{"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Return only incoming transactions paying to addresses with the specified label.\n"},585},586RPCResult{587RPCResult::Type::OBJ, "", "",588{589{RPCResult::Type::ARR, "transactions", "",590{591{RPCResult::Type::OBJ, "", "", ListSinceBlockTxFields()},592}},593{RPCResult::Type::ARR, "removed", /*optional=*/true, "<structure is the same as \"transactions\" above, only present if include_removed=true>\n"594"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.",595{596{RPCResult::Type::OBJ, "", "", ListSinceBlockTxFields(), {.print_elision = std::string{}}},597}},598{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"},599}600},601RPCExamples{602HelpExampleCli("listsinceblock", "")603+ HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")604+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")605},606[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue607{608const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);609if (!pwallet) return UniValue::VNULL;611const CWallet& wallet = *pwallet;612// Make sure the results are valid at least up to the most recent block613// the user could have gotten from another RPC command prior to now614wallet.BlockUntilSyncedToCurrentChain();616LOCK(wallet.cs_wallet);618std::optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.619std::optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.620int target_confirms = 1;622uint256 blockId;623if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {624blockId = ParseHashV(request.params[0], "blockhash");625height = int{};626altheight = int{};627if (!wallet.chain().findCommonAncestor(blockId, wallet.GetLastBlockHash(), /*ancestor_out=*/FoundBlock().height(*height), /*block1_out=*/FoundBlock().height(*altheight))) {628throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");629}630}632if (!request.params[1].isNull()) {633target_confirms = request.params[1].getInt<int>();635if (target_confirms < 1) {636throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");637}638}640bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());641bool include_change = (!request.params[4].isNull() && request.params[4].get_bool());643// Only set it if 'label' was provided.644std::optional<std::string> filter_label;645if (!request.params[5].isNull()) filter_label.emplace(LabelFromValue(request.params[5]));647int depth = height ? wallet.GetLastBlockHeight() + 1 - *height : -1;649UniValue transactions(UniValue::VARR);651for (const auto& [_, tx] : wallet.mapWallet) {653if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) {654ListTransactions(wallet, tx, 0, true, transactions, filter_label, include_change);655}656}658// when a reorg'd block is requested, we also list any relevant transactions659// in the blocks of the chain that was detached660UniValue removed(UniValue::VARR);661while (include_removed && altheight && *altheight > *height) {662CBlock block;663if (!wallet.chain().findBlock(blockId, FoundBlock().data(block)) || block.IsNull()) {664throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");665}666for (const CTransactionRef& tx : block.vtx) {667auto it = wallet.mapWallet.find(tx->GetHash());668if (it != wallet.mapWallet.end()) {669// We want all transactions regardless of confirmation count to appear here,670// even negative confirmation ones, hence the big negative.671ListTransactions(wallet, it->second, -100000000, true, removed, filter_label, include_change);672}673}674blockId = block.hashPrevBlock;675--*altheight;676}678uint256 lastblock;679target_confirms = std::min(target_confirms, wallet.GetLastBlockHeight() + 1);680CHECK_NONFATAL(wallet.chain().findAncestorByHeight(wallet.GetLastBlockHash(), wallet.GetLastBlockHeight() + 1 - target_confirms, FoundBlock().hash(lastblock)));682UniValue ret(UniValue::VOBJ);683ret.pushKV("transactions", std::move(transactions));684if (include_removed) ret.pushKV("removed", std::move(removed));685ret.pushKV("lastblock", lastblock.GetHex());687return ret;688},689};690}692RPCMethod gettransaction()693{694return RPCMethod{695"gettransaction",696"Get detailed information about in-wallet transaction <txid>\n",697{698{"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},699{"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},700{"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},701"Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},702},703RPCResult{704RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(705{706{RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},707{RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"708"'send' category of transactions."},709},710TransactionDescriptionString()),711{712{RPCResult::Type::ARR, "details", "",713{714{RPCResult::Type::OBJ, "", "",715{716{RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address involved in the transaction."},717{RPCResult::Type::STR, "category", "The transaction category.\n"718"\"send\" Transactions sent.\n"719"\"receive\" Non-coinbase transactions received.\n"720"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"721"\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"722"\"orphan\" Orphaned coinbase transactions received."},723{RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},724{RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},725{RPCResult::Type::NUM, "vout", "the vout value"},726{RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"727"'send' category of transactions."},728{RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},729{RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'receive'. List of parent descriptors for the output script of this coin.", {730{RPCResult::Type::STR, "desc", "The descriptor string."},731}},732}},733}},734{RPCResult::Type::STR_HEX, "hex", "Raw data for transaction"},735{RPCResult::Type::OBJ, "decoded", /*optional=*/true, "The decoded transaction (only present when `verbose` is passed)",736{737TxDoc({.wallet = true}),738}},739RESULT_LAST_PROCESSED_BLOCK,740})741},742RPCExamples{743HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")744+ HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")745+ HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" false true")746+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")747},748[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue749{750const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);