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.
2001for (auto index : node.indexes) if (!index->Init()) return false;2003// ********************************************************* Step 9: load wallet2004for (const auto& client : node.chain_clients) {2005if (!client->load()) {2006return false;2007}2008}2010// ********************************************************* Step 10: data directory maintenance2012// if pruning, perform the initial blockstore prune2013// after any wallet rescanning has taken place.2014if (chainman.m_blockman.IsPruneMode()) {2015if (chainman.m_blockman.m_blockfiles_indexed) {2016LOCK(cs_main);2017for (const auto& chainstate : chainman.m_chainstates) {2018uiInterface.InitMessage(_("Pruning blockstore…"));2019chainstate->PruneAndFlush();2020}2021}2022} else {2023// Prior to setting NODE_NETWORK, check if we can provide historical blocks.2024if (!WITH_LOCK(chainman.GetMutex(), return chainman.HistoricalChainstate())) {2025LogInfo("Setting NODE_NETWORK in non-prune mode");2026g_local_services = ServiceFlags(g_local_services | NODE_NETWORK);2027} else {2028LogInfo("Running node in NODE_NETWORK_LIMITED mode until snapshot background sync completes");2029}2030}2032// ********************************************************* Step 11: import blocks2034if (!CheckDiskSpace(args.GetDataDirNet())) {2035InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(args.GetDataDirNet()))));2036return false;2037}2038if (!CheckDiskSpace(args.GetBlocksDirPath())) {2039InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(args.GetBlocksDirPath()))));2040return false;2041}2043int chain_active_height = WITH_LOCK(cs_main, return chainman.ActiveChain().Height());2045// On first startup, warn on low block storage space2046if (!do_reindex && !do_reindex_chainstate && chain_active_height <= 1) {2047uint64_t assumed_chain_bytes{chainparams.AssumedBlockchainSize() * 1_GiB};2048uint64_t additional_bytes_needed{2049chainman.m_blockman.IsPruneMode() ?2050std::min(chainman.m_blockman.GetPruneTarget(), assumed_chain_bytes) :2051assumed_chain_bytes};2053if (!CheckDiskSpace(args.GetBlocksDirPath(), additional_bytes_needed)) {2054InitWarning(strprintf(_(2055"Disk space for %s may not accommodate the block files. " \2056"Approximately %u GB of data will be stored in this directory."2057),2058fs::quoted(fs::PathToString(args.GetBlocksDirPath())),2059chainparams.AssumedBlockchainSize()2060));2061}2062}2064#ifdef __APPLE__2065auto check_and_warn_fs{[&](const fs::path& path, std::string_view desc) {2066const auto path_desc{strprintf("%s (\"%s\")", desc, fs::PathToString(path))};2067switch (GetFilesystemType(path)) {2068case FSType::EXFAT:2069InitWarning(strprintf(_("The %s path uses exFAT, which is known to have intermittent corruption problems on macOS. "2070"Move this directory to a different filesystem to avoid data loss."), path_desc));2071break;2072case FSType::ERROR:2073LogInfo("Failed to detect filesystem type for %s", path_desc);2074break;2075case FSType::OTHER:2076break;2077}2078}};2080check_and_warn_fs(args.GetDataDirNet(), "data directory");2081check_and_warn_fs(args.GetBlocksDirPath(), "blocks directory");2082#endif2084#if HAVE_SYSTEM2085const std::string block_notify = args.GetArg("-blocknotify", "");2086if (!block_notify.empty()) {2087uiInterface.NotifyBlockTip.connect([block_notify](SynchronizationState sync_state, const CBlockIndex& block, double /* verification_progress */) {2088if (sync_state != SynchronizationState::POST_INIT) return;2089std::string command = block_notify;2090ReplaceAll(command, "%s", block.GetBlockHash().GetHex());2091std::thread t(runCommand, command);2092t.detach(); // thread runs free2093});2094}2095#endif2097std::vector<fs::path> vImportFiles;2098for (const std::string& strFile : args.GetArgs("-loadblock")) {2099vImportFiles.push_back(fs::PathFromString(strFile));2100}2102/// \anchor initload2103node.background_init_thread = std::thread(&util::TraceThread, "initload", [=, &chainman, &args, &kernel_notifications, &node] {2104ScheduleBatchPriority();2105// Import blocks and ActivateBestChain()2106ImportBlocks(chainman, vImportFiles);2107// An interrupted import may return without activating genesis. Wake2108// the init thread's genesis wait, which is otherwise only notified2109// on blockTip, and that never fires when the import was interrupted2110// before activating genesis. This wakeup lets the wait observe the2111// shutdown request.2112WITH_LOCK(kernel_notifications.m_tip_block_mutex, kernel_notifications.m_tip_block_cv.notify_all());2113WITH_LOCK(::cs_main, chainman.UpdateIBDStatus());2114if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {2115LogInfo("Stopping after block import");2116if (!(Assert(node.shutdown_request))()) {2117LogError("Failed to send shutdown signal after finishing block import\n");2118}2119return;2120}2122// Start indexes initial sync2123if (!StartIndexBackgroundSync(node)) {2124bilingual_str err_str = _("Failed to start indexes, shutting down…");2125chainman.GetNotifications().fatalError(err_str);2126return;2127}2128// Load mempool from disk2129if (auto* pool{chainman.ActiveChainstate().GetMempool()}) {2130const bool loaded{LoadMempool(*pool, ShouldPersistMempool(args) ? MempoolPath(args) : fs::path{}, chainman.ActiveChainstate(), {})};2131// A shutdown request sets m_interrupt and aborts the mempool load, which is not a2132// load failure, so only notify the fee estimator when the load actually failed.2133if (node.fee_estimator_man && !chainman.m_interrupt && !loaded) {2134node.fee_estimator_man->MempoolLoadFailed();2135}2136pool->SetLoadTried(!chainman.m_interrupt);2137}2138});2140/*2141* Wait for genesis block to be processed. Typically kernel_notifications.m_tip_block2142* has already been set by a call to LoadChainTip() in CompleteChainstateInitialization().2143* But this is skipped if the chainstate doesn't exist yet or is being wiped:2144*2145* 1. first startup with an empty datadir2146* 2. reindex2147* 3. reindex-chainstate2148*2149* In these case it's connected by a call to ActivateBestChain() in the initload thread.2150*/2151{2152WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock);2153kernel_notifications.m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {2154return kernel_notifications.TipBlock() || ShutdownRequested(node);2155});2156}2158if (ShutdownRequested(node)) {2159return true;2160}2162// ********************************************************* Step 12: start node2164int64_t best_block_time{};2165{2166LOCK(chainman.GetMutex());2167const auto& tip{*Assert(chainman.ActiveTip())};2168LogInfo("block tree size = %u", chainman.BlockIndex().size());2169chain_active_height = tip.nHeight;2170best_block_time = tip.GetBlockTime();2171if (tip_info) {2172tip_info->block_height = chain_active_height;2173tip_info->block_time = best_block_time;2174tip_info->verification_progress = chainman.GuessVerificationProgress(&tip);2175}2176if (tip_info && chainman.m_best_header) {2177tip_info->header_height = chainman.m_best_header->nHeight;2178tip_info->header_time = chainman.m_best_header->GetBlockTime();2179}2180}2181LogInfo("nBestHeight = %d", chain_active_height);2182if (node.peerman) node.peerman->SetBestBlock(chain_active_height, std::chrono::seconds{best_block_time});2184// Map ports with NAT-PMP2185StartMapPort(args.GetBoolArg("-natpmp", DEFAULT_NATPMP));2187CConnman::Options connOptions;2188connOptions.m_local_services = g_local_services;2189connOptions.m_max_automatic_connections = num_p2p_max_connections;2190connOptions.m_full_relay_inbound_percent = std::clamp<int>(args.GetIntArg("-inboundrelaypercent", DEFAULT_FULL_RELAY_INBOUND_PCT), 0, 100);2191connOptions.uiInterface = &uiInterface;2192connOptions.m_banman = node.banman.get();2193connOptions.m_msgproc = node.peerman.get();2194connOptions.nSendBufferMaxSize = 1000 * args.GetIntArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);2195connOptions.nReceiveFloodSize = 1000 * args.GetIntArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);2196for (const std::string& added_node : args.GetArgs("-addnode")) {2197// Such a value is not a valid connection target, but would otherwise be2198// treated as one and retried indefinitely.2199if (TrimStringView(added_node).empty()) {2200LogWarning("Ignoring empty -addnode value");2201continue;2202}2203connOptions.m_added_nodes.push_back(added_node);2204}2205connOptions.nMaxOutboundLimit = *opt_max_upload;2206connOptions.m_peer_connect_timeout = peer_connect_timeout;2207connOptions.whitelist_forcerelay = args.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY);2208connOptions.whitelist_relay = args.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY);2209connOptions.m_capture_messages = args.GetBoolArg("-capturemessages", false);2211// Port to bind to if `-bind=addr` is provided without a `:port` suffix.2212const uint16_t default_bind_port =2213static_cast<uint16_t>(args.GetIntArg("-port", Params().GetDefaultPort()));2215const uint16_t default_bind_port_onion = default_bind_port + 1;2217const auto BadPortWarning = [](const char* prefix, uint16_t port) {2218return strprintf(_("%s request to listen on port %u. This port is considered \"bad\" and "2219"thus it is unlikely that any peer will connect to it. See "2220"doc/p2p-bad-ports.md for details and a full list."),2221prefix,2222port);2223};2225for (const std::string& bind_arg : args.GetArgs("-bind")) {2226std::optional<CService> bind_addr;2227const size_t index = bind_arg.rfind('=');2228if (index == std::string::npos) {2229bind_addr = Lookup(bind_arg, default_bind_port, /*fAllowLookup=*/false);2230if (bind_addr.has_value()) {2231connOptions.vBinds.push_back(bind_addr.value());2232if (IsBadPort(bind_addr.value().GetPort())) {2233InitWarning(BadPortWarning("-bind", bind_addr.value().GetPort()));2234}2235continue;2236}2237} else {2238const std::string network_type = bind_arg.substr(index + 1);2239if (network_type == "onion") {2240const std::string truncated_bind_arg = bind_arg.substr(0, index);2241bind_addr = Lookup(truncated_bind_arg, default_bind_port_onion, false);2242if (bind_addr.has_value()) {2243connOptions.onion_binds.push_back(bind_addr.value());2244continue;2245}2246}2247}2248return InitError(ResolveErrMsg("bind", bind_arg));2249}