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.
1251auto result{kernel::SanityChecks(kernel)};1252if (!result) {1253InitError(util::ErrorString(result));1254return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), CLIENT_NAME));1255}1257if (!ECC_InitSanityCheck()) {1258return InitError(strprintf(_("Elliptic curve cryptography sanity check failure. %s is shutting down."), CLIENT_NAME));1259}1261// Probe the directory locks to give an early error message, if possible1262// We cannot hold the directory locks here, as the forking for daemon() hasn't yet happened,1263// and a fork will cause weird behavior to them.1264return LockDirectories(true);1265}1267bool AppInitLockDirectories()1268{1269// After daemonization get the directory locks again and hold on to them until exit1270// This creates a slight window for a race condition to happen, however this condition is harmless: it1271// will at most make us exit without printing a message to console.1272if (!LockDirectories(false)) {1273// Detailed error printed inside LockDirectory1274return false;1275}1276return true;1277}1279bool AppInitInterfaces(NodeContext& node)1280{1281node.chain = interfaces::MakeChain(node);1282// Specify wait_loaded=false so internal mining interface can be initialized1283// on early startup and does not need to be tied to chainstate loading.1284node.mining = interfaces::MakeMining(node, /*wait_loaded=*/false);1285return true;1286}1288bool CheckHostPortOptions(const ArgsManager& args) {1289for (const std::string port_option : {1290"-port",1291"-rpcport",1292}) {1293if (const auto port{args.GetArg(port_option)}) {1294const auto n{ToIntegral<uint16_t>(*port)};1295if (!n || *n == 0) {1296return InitError(InvalidPortErrMsg(port_option, *port));1297}1298}1299}1301for ([[maybe_unused]] const auto& [param_name, unix, suffix_allowed] : std::vector<std::tuple<std::string, bool, bool>>{1302// arg name UNIX socket support =suffix allowed1303{"-i2psam", false, false},1304{"-onion", true, false},1305{"-proxy", true, true},1306{"-bind", false, true},1307{"-rpcbind", false, false},1308{"-torcontrol", false, false},1309{"-whitebind", false, false},1310{"-zmqpubhashblock", true, false},1311{"-zmqpubhashtx", true, false},1312{"-zmqpubrawblock", true, false},1313{"-zmqpubrawtx", true, false},1314{"-zmqpubsequence", true, false},1315}) {1316for (const std::string& param_value : args.GetArgs(param_name)) {1317const std::string param_value_hostport{1318suffix_allowed ? param_value.substr(0, param_value.rfind('=')) : param_value};1319std::string host_out;1320uint16_t port_out{0};1321if (!SplitHostPort(param_value_hostport, port_out, host_out)) {1322#ifdef HAVE_SOCKADDR_UN1323// Allow unix domain sockets for some options e.g. unix:/some/file/path1324if (!unix || !param_value.starts_with(ADDR_PREFIX_UNIX)) {1325return InitError(InvalidPortErrMsg(param_name, param_value));1326}1327#else1328return InitError(InvalidPortErrMsg(param_name, param_value));1329#endif1330}1331}1332}1334return true;1335}1337/**1338* @brief Checks for duplicate bindings across all binding configurations.1339*1340* @param[in] conn_options Connection options containing the binding vectors to check1341* @return std::optional<CService> containing the first duplicate found, or std::nullopt if no duplicates1342*/1343static std::optional<CService> CheckBindingConflicts(const CConnman::Options& conn_options)1344{1345std::set<CService> seen;1347// Check all whitelisted bindings1348for (const auto& wb : conn_options.vWhiteBinds) {1349if (!seen.insert(wb.m_service).second) {1350return wb.m_service;1351}1352}1354// Check regular bindings1355for (const auto& bind : conn_options.vBinds) {1356if (!seen.insert(bind).second) {1357return bind;1358}1359}1361// Check onion bindings1362for (const auto& onion_bind : conn_options.onion_binds) {1363if (!seen.insert(onion_bind).second) {1364return onion_bind;1365}1366}1368return std::nullopt;1369}1371// A GUI user may opt to retry once with do_reindex set if there is a failure during chainstate initialization.1372// The function therefore has to support re-entry.1373static ChainstateLoadResult InitAndLoadChainstate(1374NodeContext& node,1375bool do_reindex,1376const bool do_reindex_chainstate,1377const kernel::CacheSizes& cache_sizes,1378const ArgsManager& args)1379{1380// This function may be called twice, so any dirty state must be reset.1381node.notifications->setChainstateLoaded(false); // Drop state, such as a cached tip block1382node.mempool.reset();1383node.chainman.reset(); // Drop state, such as an initialized m_block_tree_db1385const CChainParams& chainparams = Params();1387CTxMemPool::Options mempool_opts{1388.check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0,1389.signals = node.validation_signals.get(),1390};1391Assert(ApplyArgsManOptions(args, chainparams, mempool_opts)); // no error can happen, already checked in AppInitParameterInteraction1392bilingual_str mempool_error;1393Assert(!node.mempool); // Was reset above1394node.mempool = std::make_unique<CTxMemPool>(mempool_opts, mempool_error);1395if (!mempool_error.empty()) {1396return {ChainstateLoadStatus::FAILURE_FATAL, mempool_error};1397}1398auto mining_args{node::ReadMiningArgs(args)};1399Assert(mining_args); // no error can happen, already checked in AppInitParameterInteraction1400node.mining_args = std::move(*mining_args);1401LogInfo("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)",1402cache_sizes.coins / double(1_MiB),1403mempool_opts.max_size_bytes / double(1_MiB));1404ChainstateManager::Options chainman_opts{1405.chainparams = chainparams,1406.datadir = args.GetDataDirNet(),1407.notifications = *node.notifications,1408.signals = node.validation_signals.get(),1409};1410Assert(ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction1412BlockManager::Options blockman_opts{1413.chainparams = chainman_opts.chainparams,1414.blocks_dir = args.GetBlocksDirPath(),1415.notifications = chainman_opts.notifications,1416.block_tree_db_params = DBParams{1417.path = args.GetDataDirNet() / "blocks" / "index",1418.cache_bytes = cache_sizes.block_tree_db,1419.wipe_data = do_reindex,1420},1421};1422Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction1424// Creating the chainstate manager internally creates a BlockManager, opens1425// the blocks tree db, and wipes existing block files in case of a reindex.1426// The coinsdb is opened at a later point on LoadChainstate.1427Assert(!node.chainman); // Was reset above1428try {1429node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown_signal), chainman_opts, blockman_opts);1430} catch (dbwrapper_error& e) {1431LogError("%s", e.what());1432return {ChainstateLoadStatus::FAILURE, _("Error opening block database")};1433} catch (std::exception& e) {1434return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated(strprintf("Failed to initialize ChainstateManager: %s", e.what()))};1435}1436ChainstateManager& chainman = *node.chainman;1437if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};1439// This is defined and set here instead of inline in validation.h to avoid a hard1440// dependency between validation and index/base, since the latter is not in1441// libbitcoinkernel.1442chainman.snapshot_download_completed = [&node]() {1443if (!node.chainman->m_blockman.IsPruneMode()) {1444LogInfo("[snapshot] re-enabling NODE_NETWORK services");1445node.connman->AddLocalServices(NODE_NETWORK);1446}1447LogInfo("[snapshot] restarting indexes");1448// Drain the validation interface queue to ensure that the old indexes1449// don't have any pending work.1450Assert(node.validation_signals)->SyncWithValidationInterfaceQueue();1451for (auto* index : node.indexes) {1452index->Interrupt();1453index->Stop();1454if (!(index->Init() && index->StartBackgroundSync())) {1455LogWarning("[snapshot] Failed to restart index %s on snapshot chain", index->GetName());1456}1457}1458};1459node::ChainstateLoadOptions options;1460options.mempool = Assert(node.mempool.get());1461options.wipe_chainstate_db = do_reindex || do_reindex_chainstate;1462options.prune = chainman.m_blockman.IsPruneMode();1463options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);1464options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);1465options.require_full_verification = args.IsArgSet("-checkblocks") || args.IsArgSet("-checklevel");1466options.coins_error_cb = [] {1467uiInterface.ThreadSafeMessageBox(1468_("Error reading from database, shutting down."),1469CClientUIInterface::MSG_ERROR);1470};1471uiInterface.InitMessage(_("Loading block index…"));1472auto catch_exceptions = [](auto&& f) -> ChainstateLoadResult {1473try {1474return f();1475} catch (const std::exception& e) {1476LogError("%s\n", e.what());1477return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error loading databases"));1478}1479};1480auto [status, error] = catch_exceptions([&] { return LoadChainstate(chainman, cache_sizes, options); });1481if (status == node::ChainstateLoadStatus::SUCCESS) {1482uiInterface.InitMessage(_("Verifying blocks…"));1483if (chainman.m_blockman.m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) {1484LogWarning("pruned datadir may not have more than %d blocks; only checking available blocks\n",1485MIN_BLOCKS_TO_KEEP);1486}1487std::tie(status, error) = catch_exceptions([&] { return VerifyLoadedChainstate(chainman, options); });1488if (status == node::ChainstateLoadStatus::SUCCESS) {1489LogInfo("Block index and chainstate loaded");1490node.notifications->setChainstateLoaded(true);1491}1492}1493return {status, error};1494};1496bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)1497{1498const ArgsManager& args = *Assert(node.args);1499const CChainParams& chainparams = Params();