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.
2001if (max_height && block_height >= *max_height) {2002break;2003}2004// If rescanning was triggered with cs_wallet permanently locked (AttachChain), additional blocks that were connected during the rescan2005// aren't processed here but will be processed with the pending blockConnected notifications after the lock is released.2006// If rescanning without a permanent cs_wallet lock, additional blocks that were added during the rescan will be re-processed if2007// the notification was processed and the last block height was updated.2008if (block_height >= WITH_LOCK(cs_wallet, return GetLastBlockHeight())) {2009break;2010}2012{2013if (!next_block) {2014// break successfully when rescan has reached the tip, or2015// previous block is no longer on the chain due to a reorg2016break;2017}2019// increment block and verification progress2020block_hash = next_block_hash;2021++block_height;2022progress_current = chain().guessVerificationProgress(block_hash);2024// handle updated tip hash2025const uint256 prev_tip_hash = tip_hash;2026tip_hash = WITH_LOCK(cs_wallet, return GetLastBlockHash());2027if (!max_height && prev_tip_hash != tip_hash) {2028// in case the tip has changed, update progress max2029progress_end = chain().guessVerificationProgress(tip_hash);2030}2031}2032}2033if (!max_height) {2034WalletLogPrintf("Scanning current mempool transactions.\n");2035WITH_LOCK(cs_wallet, chain().requestMempoolTransactions(*this));2036}2037ShowProgress(strprintf("[%s] %s", DisplayName(), _("Rescanning…")), 100); // hide progress dialog in GUI2038if (fAbortRescan) {2039WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);2040result.status = ScanResult::USER_ABORT;2041} else if (chain().shutdownRequested()) {2042WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);2043result.status = ScanResult::USER_ABORT;2044} else {2045WalletLogPrintf("Rescan completed in %15dms\n", Ticks<std::chrono::milliseconds>(reserver.now() - start_time));2046}2047return result;2048}2050bool CWallet::SubmitTxMemoryPoolAndRelay(CWalletTx& wtx,2051std::string& err_string,2052node::TxBroadcast broadcast_method) const2053{2054AssertLockHeld(cs_wallet);2056// Can't relay if wallet is not broadcasting2057if (!GetBroadcastTransactions()) return false;2058// Don't relay abandoned transactions2059if (wtx.isAbandoned()) return false;2060// Don't try to submit coinbase transactions. These would fail anyway but would2061// cause log spam.2062if (wtx.IsCoinBase()) return false;2063// Don't try to submit conflicted or confirmed transactions.2064if (GetTxDepthInMainChain(wtx) != 0) return false;2066const char* what{""};2067switch (broadcast_method) {2068case node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL:2069what = "to mempool and for broadcast to peers";2070break;2071case node::TxBroadcast::MEMPOOL_NO_BROADCAST:2072what = "to mempool without broadcast";2073break;2074case node::TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST:2075what = "for private broadcast without adding to the mempool";2076break;2077}2078WalletLogPrintf("Submitting wtx %s %s\n", wtx.GetHash().ToString(), what);2079// We must set TxStateInMempool here. Even though it will also be set later by the2080// entered-mempool callback, if we did not there would be a race where a2081// user could call sendmoney in a loop and hit spurious out of funds errors2082// because we think that this newly generated transaction's change is2083// unavailable as we're not yet aware that it is in the mempool.2084//2085// If broadcast fails for any reason, trying to set wtx.m_state here would be incorrect.2086// If transaction was previously in the mempool, it should be updated when2087// TransactionRemovedFromMempool fires.2088bool ret = chain().broadcastTransaction(wtx.GetTx(), m_default_max_tx_fee, broadcast_method, err_string);2089if (ret) wtx.m_state = TxStateInMempool{};2090return ret;2091}2093std::set<Txid> CWallet::GetTxConflicts(const CWalletTx& wtx) const2094{2095AssertLockHeld(cs_wallet);2097const Txid myHash{wtx.GetHash()};2098std::set<Txid> result{GetConflicts(myHash)};2099result.erase(myHash);2100return result;2101}2103bool CWallet::ShouldResend() const2104{2105// Don't attempt to resubmit if the wallet is configured to not broadcast2106if (!fBroadcastTransactions) return false;2108// During reindex, importing and IBD, old wallet transactions become2109// unconfirmed. Don't resend them as that would spam other nodes.2110// We only allow forcing mempool submission when not relaying to avoid this spam.2111if (!chain().isReadyToBroadcast()) return false;2113// Do this infrequently and randomly to avoid giving away2114// that these are our transactions.2115if (NodeClock::now() < m_next_resend) return false;2117return true;2118}2120NodeClock::time_point CWallet::GetDefaultNextResend() { return FastRandomContext{}.rand_uniform_delay(NodeClock::now() + 12h, 24h); }2122// Resubmit transactions from the wallet to the mempool, optionally asking the2123// mempool to relay them. On startup, we will do this for all unconfirmed2124// transactions but will not ask the mempool to relay them. We do this on startup2125// to ensure that our own mempool is aware of our transactions. There2126// is a privacy side effect here as not broadcasting on startup also means that we won't2127// inform the world of our wallet's state, particularly if the wallet (or node) is not2128// yet synced.2129//2130// Otherwise this function is called periodically in order to relay our unconfirmed txs.2131// We do this on a random timer to slightly obfuscate which transactions2132// come from our wallet.2133//2134// TODO: Ideally, we'd only resend transactions that we think should have been2135// mined in the most recent block. Any transaction that wasn't in the top2136// blockweight of transactions in the mempool shouldn't have been mined,2137// and so is probably just sitting in the mempool waiting to be confirmed.2138// Rebroadcasting does nothing to speed up confirmation and only damages2139// privacy.2140//2141// The `force` option results in all unconfirmed transactions being submitted to2142// the mempool. This does not necessarily result in those transactions being relayed,2143// that depends on the `broadcast_method` option. Periodic rebroadcast uses the pattern2144// broadcast_method=TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL force=false, while loading into2145// the mempool (on start, or after import) uses2146// broadcast_method=TxBroadcast::MEMPOOL_NO_BROADCAST force=true.2147void CWallet::ResubmitWalletTransactions(node::TxBroadcast broadcast_method, bool force)2148{2149// Don't attempt to resubmit if the wallet is configured to not broadcast,2150// even if forcing.2151if (!fBroadcastTransactions) return;2153int submitted_tx_count = 0;2155{ // cs_wallet scope2156LOCK(cs_wallet);2158// First filter for the transactions we want to rebroadcast.2159// We use a set with WalletTxOrderComparator so that rebroadcasting occurs in insertion order2160std::set<CWalletTx*, WalletTxOrderComparator> to_submit;2161for (auto& [txid, wtx] : mapWallet) {2162// Only rebroadcast unconfirmed txs2163if (!wtx.isUnconfirmed()) continue;2165// Attempt to rebroadcast all txes more than 5 minutes older than2166// the last block, or all txs if forcing.2167if (!force && wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;2168to_submit.insert(&wtx);2169}2170// Now try submitting the transactions to the memory pool and (optionally) relay them.2171for (auto wtx : to_submit) {2172std::string unused_err_string;2173if (SubmitTxMemoryPoolAndRelay(*wtx, unused_err_string, broadcast_method)) ++submitted_tx_count;2174}2175} // cs_wallet2177if (submitted_tx_count > 0) {2178WalletLogPrintf("%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);2179}2180}2182/** @} */ // end of mapWallet2184void MaybeResendWalletTxs(WalletContext& context)2185{2186for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {2187if (!pwallet->ShouldResend()) continue;2188pwallet->ResubmitWalletTransactions(node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL, /*force=*/false);2189pwallet->SetNextResend();2190}2191}2194bool CWallet::SignTransaction(CMutableTransaction& tx) const2195{2196AssertLockHeld(cs_wallet);2198// Build coins map2199std::map<COutPoint, Coin> coins;2200for (auto& input : tx.vin) {2201const auto mi = mapWallet.find(input.prevout.hash);2202if(mi == mapWallet.end() || input.prevout.n >= mi->second.GetTx()->vout.size()) {2203return false;2204}2205const CWalletTx& wtx = mi->second;2206int prev_height = wtx.state<TxStateConfirmed>() ? wtx.state<TxStateConfirmed>()->confirmed_block_height : 0;2207coins[input.prevout] = Coin(wtx.GetTx()->vout[input.prevout.n], prev_height, wtx.IsCoinBase());2208}2209std::map<int, bilingual_str> input_errors;2210return SignTransaction(tx, coins, SIGHASH_DEFAULT, input_errors);2211}2213bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const2214{2215// Try to sign with all ScriptPubKeyMans2216for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {2217// spk_man->SignTransaction will return true if the transaction is complete,2218// so we can exit early and return true if that happens2219if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {2220return true;2221}2222}2224// At this point, one input was not fully signed otherwise we would have exited already2225return false;2226}2228std::optional<PSBTError> CWallet::FillPSBT(PartiallySignedTransaction& psbtx, const common::PSBTFillOptions& options, bool& complete, size_t* n_signed) const2229{2230if (n_signed) {2231*n_signed = 0;2232}2233LOCK(cs_wallet);2234// Get all of the previous transactions2235for (PSBTInput& input : psbtx.inputs) {2236if (PSBTInputSigned(input)) {2237continue;2238}2240// If we have no utxo, grab it from the wallet.2241if (!input.non_witness_utxo) {2242const Txid& txhash = input.prev_txid;2243const auto it = mapWallet.find(txhash);2244if (it != mapWallet.end()) {2245const CWalletTx& wtx = it->second;2246// We only need the non_witness_utxo, which is a superset of the witness_utxo.2247// The signing code will switch to the smaller witness_utxo if this is ok.2248input.non_witness_utxo = wtx.GetTx();2249}2250}