Inside Bitcoin
Opening the selected file…
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.
1251} else {1252error += "Incorrect rpcuser or rpcpassword were specified.";1253}1254error += strprintf(" Configuration file: (%s)", fs::PathToString(gArgs.GetConfigFilePath()));1255throw std::runtime_error(error);1256} else if (response.status == HTTP_SERVICE_UNAVAILABLE) {1257throw std::runtime_error(strprintf("Server response: %s", response.body));1258} else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)1259throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));1260else if (response.body.empty())1261throw std::runtime_error("no response from server");1263// Parse reply1264UniValue valReply(UniValue::VSTR);1265if (!valReply.read(response.body))1266throw std::runtime_error("couldn't parse reply from server");1267UniValue reply = rh->ProcessReply(valReply);1268if (reply.empty())1269throw std::runtime_error("expected reply to have result, error and id properties");1271return reply;1272}1274/**1275* ConnectAndCallRPC wraps CallRPC with -rpcwait and an exception handler.1276*1277* @param[in] rh Pointer to RequestHandler.1278* @param[in] strMethod Reference to const string method to forward to CallRPC.1279* @param[in] rpcwallet Reference to const optional string wallet name to forward to CallRPC.1280* @returns the RPC response as a UniValue object.1281* @throws a CConnectionFailed std::runtime_error if connection failed or RPC server still in warmup.1282*/1283static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const std::optional<std::string>& rpcwallet = {})1284{1285UniValue response(UniValue::VOBJ);1286// Execute and handle connection failures with -rpcwait.1287const bool fWait = gArgs.GetBoolArg("-rpcwait", false);1288const int timeout = gArgs.GetIntArg("-rpcwaittimeout", DEFAULT_WAIT_CLIENT_TIMEOUT);1289const auto deadline{std::chrono::steady_clock::now() + 1s * timeout};1291// check if we should use a special wallet endpoint1292std::string endpoint = "/";1293if (rpcwallet) {1294endpoint = "/wallet/" + UrlEncode(*rpcwallet);1295}1297std::string username{gArgs.GetArg("-rpcuser", "")};1298do {1299try {1300if (auto ipc_response{CallIPC(rh, strMethod, args, endpoint, username)}) {1301response = std::move(*ipc_response);1302} else {1303response = CallRPC(rh, strMethod, args, endpoint, username);1304}1305if (fWait) {1306const UniValue& error = response.find_value("error");1307if (!error.isNull() && error["code"].getInt<int>() == RPC_IN_WARMUP) {1308throw CConnectionFailed("server in warmup");1309}1310}1311break; // Connection succeeded, no need to retry.1312} catch (const CConnectionFailed& e) {1313if (fWait && (timeout <= 0 || std::chrono::steady_clock::now() < deadline)) {1314UninterruptibleSleep(1s);1315} else if (fWait) {1316throw CConnectionFailed(strprintf("timeout on transient error: %s", e.what()));1317} else {1318throw;1319}1320}1321} while (fWait);1322return response;1323}1325/** Parse UniValue result to update the message to print to std::cout. */1326static void ParseResult(const UniValue& result, std::string& strPrint)1327{1328if (result.isNull()) return;1329strPrint = result.isStr() ? result.get_str() : result.write(2);1330}1332/** Parse UniValue error to update the message to print to std::cerr and the code to return. */1333static void ParseError(const UniValue& error, std::string& strPrint, int& nRet)1334{1335if (error.isObject()) {1336const UniValue& err_code = error.find_value("code");1337const UniValue& err_msg = error.find_value("message");1338if (!err_code.isNull()) {1339strPrint = "error code: " + err_code.getValStr() + "\n";1340}1341if (err_msg.isStr()) {1342strPrint += ("error message:\n" + err_msg.get_str());1343}1344if (err_code.isNum() && err_code.getInt<int>() == RPC_WALLET_NOT_SPECIFIED) {1345strPrint += " Or for the CLI, specify the \"-rpcwallet=<walletname>\" option before the command";1346strPrint += " (run \"bitcoin-cli -h\" for help or \"bitcoin-cli listwallets\" to see which wallets are currently loaded).";1347}1348} else {1349strPrint = "error: " + error.write();1350}1351nRet = abs(error["code"].getInt<int>());1352}1354/**1355* GetWalletBalances calls listwallets; if more than one wallet is loaded, it then1356* fetches mine.trusted balances for each loaded wallet and pushes them to `result`.1357*1358* @param result Reference to UniValue object the wallet names and balances are pushed to.1359*/1360static void GetWalletBalances(UniValue& result)1361{1362DefaultRequestHandler rh;1363const UniValue listwallets = ConnectAndCallRPC(&rh, "listwallets", /* args=*/{});1364if (!listwallets.find_value("error").isNull()) return;1365const UniValue& wallets = listwallets.find_value("result");1366if (wallets.size() <= 1) return;1368UniValue balances(UniValue::VOBJ);1369for (const UniValue& wallet : wallets.getValues()) {1370const std::string& wallet_name = wallet.get_str();1371const UniValue getbalances = ConnectAndCallRPC(&rh, "getbalances", /* args=*/{}, wallet_name);1372const UniValue& balance = getbalances.find_value("result")["mine"]["trusted"];1373balances.pushKV(wallet_name, balance);1374}1375result.pushKV("balances", std::move(balances));1376}1378/**1379* GetProgressBar constructs a progress bar with 5% intervals.1380*1381* @param[in] progress The proportion of the progress bar to be filled between 0 and 1.1382* @param[out] progress_bar String representation of the progress bar.1383*/1384static void GetProgressBar(double progress, std::string& progress_bar)1385{1386if (progress < 0 || progress > 1) return;1388static constexpr double INCREMENT{0.05};1389static const std::string COMPLETE_BAR{"\u2592"};1390static const std::string INCOMPLETE_BAR{"\u2591"};1392for (int i = 0; i < progress / INCREMENT; ++i) {1393progress_bar += COMPLETE_BAR;1394}1396for (int i = 0; i < (1 - progress) / INCREMENT; ++i) {1397progress_bar += INCOMPLETE_BAR;1398}1399}1401/**1402* ParseGetInfoResult takes in -getinfo result in UniValue object and parses it1403* into a user friendly UniValue string to be printed on the console.1404* @param[out] result Reference to UniValue result containing the -getinfo output.1405*/1406static void ParseGetInfoResult(UniValue& result)1407{1408if (!result.find_value("error").isNull()) return;1410std::string RESET, GREEN, BLUE, YELLOW, MAGENTA, CYAN;1411bool should_colorize = false;1413#ifndef WIN321414if (isatty(fileno(stdout))) {1415// By default, only print colored text if OS is not WIN32 and stdout is connected to a terminal.1416should_colorize = true;1417}1418#endif1420{1421const std::string color{gArgs.GetArg("-color", DEFAULT_COLOR_SETTING)};1422if (color == "always") {1423should_colorize = true;1424} else if (color == "never") {1425should_colorize = false;1426} else if (color != "auto") {1427throw std::runtime_error("Invalid value for -color option. Valid values: always, auto, never.");1428}1429}1431if (should_colorize) {1432RESET = "\x1B[0m";1433GREEN = "\x1B[32m";1434BLUE = "\x1B[34m";1435YELLOW = "\x1B[33m";1436MAGENTA = "\x1B[35m";1437CYAN = "\x1B[36m";1438}1440std::string result_string = strprintf("%sChain: %s%s\n", BLUE, result["chain"].getValStr(), RESET);1441result_string += strprintf("Blocks: %s\n", result["blocks"].getValStr());1442result_string += strprintf("Headers: %s\n", result["headers"].getValStr());1444const double ibd_progress{result["verificationprogress"].get_real()};1445std::string ibd_progress_bar;1446// Display the progress bar only if IBD progress is less than 99%1447if (ibd_progress < 0.99) {1448GetProgressBar(ibd_progress, ibd_progress_bar);1449// Add padding between progress bar and IBD progress1450ibd_progress_bar += " ";1451}1453result_string += strprintf("Verification progress: %s%.4f%%\n", ibd_progress_bar, ibd_progress * 100);1454result_string += strprintf("Difficulty: %s\n\n", result["difficulty"].getValStr());1456result_string += strprintf(1457"%sNetwork: in %s, out %s, total %s%s\n",1458GREEN,1459result["connections"]["in"].getValStr(),1460result["connections"]["out"].getValStr(),1461result["connections"]["total"].getValStr(),1462RESET);1463result_string += strprintf("Version: %s\n", result["version"].getValStr());1464result_string += strprintf("Time offset (s): %s\n", result["timeoffset"].getValStr());1466// proxies1467std::map<std::string, std::vector<std::string>> proxy_networks;1468std::vector<std::string> ordered_proxies;1470for (const UniValue& network : result["networks"].getValues()) {1471const std::string proxy = network["proxy"].getValStr();1472if (proxy.empty()) continue;1473// Add proxy to ordered_proxy if has not been processed1474if (!proxy_networks.contains(proxy)) ordered_proxies.push_back(proxy);1476proxy_networks[proxy].push_back(network["name"].getValStr());1477}1479std::vector<std::string> formatted_proxies;1480formatted_proxies.reserve(ordered_proxies.size());1481for (const std::string& proxy : ordered_proxies) {1482formatted_proxies.emplace_back(strprintf("%s (%s)", proxy, Join(proxy_networks.find(proxy)->second, ", ")));1483}1484result_string += strprintf("Proxies: %s\n", formatted_proxies.empty() ? "n/a" : Join(formatted_proxies, ", "));1486result_string += strprintf("Min tx relay fee rate (%s/kvB): %s\n\n", CURRENCY_UNIT, result["relayfee"].getValStr());1488if (!result["has_wallet"].isNull()) {1489const std::string walletname = result["walletname"].getValStr();1490result_string += strprintf("%sWallet: %s%s\n", MAGENTA, walletname.empty() ? "\"\"" : walletname, RESET);1492result_string += strprintf("Keypool size: %s\n", result["keypoolsize"].getValStr());1493if (!result["unlocked_until"].isNull()) {1494result_string += strprintf("Unlocked until: %s\n", result["unlocked_until"].getValStr());1495}1496}1497if (!result["balance"].isNull()) {1498result_string += strprintf("%sBalance:%s %s\n\n", CYAN, RESET, result["balance"].getValStr());1499}