6#include <bitcoin-build-config.h>
72static constexpr std::array
NETWORKS{
"not_publicly_routable",
"ipv4",
"ipv6",
"onion",
"i2p",
"cjdns",
"internal"};
73static constexpr std::array
NETWORK_SHORT_NAMES{
"npr",
"ipv4",
"ipv6",
"onion",
"i2p",
"cjdns",
"int"};
94 std::vector<std::pair<std::string, std::string>>
m_headers;
98 std::optional<std::string>
FindFirst(std::string_view key)
const;
107 const std::string_view line = *maybe_line;
110 if (line.empty())
return;
115 const size_t pos{line.find(
':')};
116 if (pos == std::string::npos)
throw HTTPError{
"Header missing colon (:)"};
120 std::string value =
util::TrimString(std::string_view(line).substr(pos + 1));
125 if (key.empty())
throw HTTPError{
"Empty header name"};
127 m_headers.emplace_back(std::move(key), std::move(value));
154 argsman.
AddArg(
"-generate",
155 strprintf(
"Generate blocks, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer "
156 "arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to "
157 "RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000",
161 argsman.
AddArg(
"-getinfo",
"Get general information from the remote server. Note that unlike server-side RPC calls, the output of -getinfo is the result of multiple non-atomic requests. Some entries in the output may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)",
ArgsManager::ALLOW_ANY,
OptionsCategory::CLI_COMMANDS);
162 argsman.
AddArg(
"-netinfo",
strprintf(
"Get network peer connection information from the remote server. An optional argument from 0 to %d can be passed for different peers listings (default: 0). If a non-zero value is passed, an additional \"outonly\" (or \"o\") argument can be passed to see outbound peers only. Pass \"help\" (or \"h\") for detailed help documentation.",
NETINFO_MAX_LEVEL),
ArgsManager::ALLOW_ANY,
OptionsCategory::CLI_COMMANDS);
172 argsman.
AddArg(
"-rpcport=<port>",
strprintf(
"Connect to JSON-RPC on <port> (default: %u, testnet: %u, testnet4: %u, signet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), testnet4BaseParams->RPCPort(), signetBaseParams->RPCPort(), regtestBaseParams->RPCPort()),
ArgsManager::ALLOW_ANY |
ArgsManager::NETWORK_ONLY,
OptionsCategory::OPTIONS);
176 argsman.
AddArg(
"-rpcwallet=<walletname>",
"Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to bitcoind). This changes the RPC endpoint used, e.g. http://127.0.0.1:8332/wallet/<walletname>",
ArgsManager::ALLOW_ANY,
OptionsCategory::OPTIONS);
177 argsman.
AddArg(
"-stdin",
"Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password.",
ArgsManager::ALLOW_ANY,
OptionsCategory::OPTIONS);
178 argsman.
AddArg(
"-stdinrpcpass",
"Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password. When combined with -stdinwalletpassphrase, -stdinrpcpass consumes the first line, and -stdinwalletpassphrase consumes the second.",
ArgsManager::ALLOW_ANY,
OptionsCategory::OPTIONS);
180 argsman.
AddArg(
"-ipcconnect=<address>",
"Connect to bitcoin-node through IPC socket instead of TCP socket to execute requests. Valid <address> values are 'auto' to try to connect to default socket path at <datadir>/node.sock but fall back to TCP if it is not available, 'unix' to connect to the default socket and fail if it isn't available, or 'unix:<socket path>' to connect to a socket at a nonstandard path. -noipcconnect can be specified to avoid attempting to use IPC at all. Default value: auto",
ArgsManager::ALLOW_ANY,
OptionsCategory::IPC);
209 tfm::format(std::cerr,
"Error parsing command line arguments: %s\n", error);
213 std::string strUsage = CLIENT_NAME
" RPC client version " +
FormatFullVersion() +
"\n";
219 "The bitcoin-cli utility provides a command line interface to interact with a " CLIENT_NAME
" RPC server.\n"
220 "\nIt can be used to query network information, manage wallets, create or broadcast transactions, and control the " CLIENT_NAME
" server.\n"
221 "\nUse the \"help\" command to list all commands. Use \"help <command>\" to show help for that command.\n"
222 "The -named option allows you to specify parameters using the key=value format, eliminating the need to pass unused positional parameters.\n"
224 "Usage: bitcoin-cli [options] <command> [params]\n"
225 "or: bitcoin-cli [options] -named <command> [name=value]...\n"
226 "or: bitcoin-cli [options] help\n"
227 "or: bitcoin-cli [options] help <command>\n"
234 tfm::format(std::cerr,
"Error: too few parameters\n");
240 tfm::format(std::cerr,
"Error: Specified data directory \"%s\" does not exist.\n",
gArgs.
GetArg(
"-datadir",
""));
244 tfm::format(std::cerr,
"Error reading configuration file: %s\n", error);
250 }
catch (
const std::exception& e) {
265 for (
size_t i = 0; i <
NETWORKS.size(); ++i) {
285 throw std::runtime_error(
"-addrinfo takes no arguments");
292 if (!reply[
"error"].isNull()) {
294 throw std::runtime_error(
"-addrinfo requires bitcoind v26.0 or later which supports getaddrmaninfo RPC. Please upgrade your node or use bitcoin-cli from the same version.");
299 const std::vector<std::string>& network_types{reply[
"result"].
getKeys()};
300 const std::vector<UniValue>& addrman_counts{reply[
"result"].
getValues()};
305 for (
size_t i = 0; i < network_types.size(); ++i) {
306 int addr_count = addrman_counts[i][
"total"].getInt<
int>();
307 if (network_types[i] ==
"all_networks") {
308 addresses.pushKV(
"total", addr_count);
310 addresses.pushKV(network_types[i], addr_count);
313 result.pushKV(
"addresses_known", std::move(addresses));
329 throw std::runtime_error(
"-getinfo takes no arguments");
362 result.
pushKV(
"connections", std::move(connections));
368 result.
pushKV(
"has_wallet",
true);
371 if (!batch[
ID_WALLETINFO][
"result"][
"unlocked_until"].isNull()) {
448 if (seconds < 0)
return "";
449 const double milliseconds{round(1000 * seconds)};
450 return milliseconds > 999999 ?
"-" :
ToString(milliseconds);
454 if (conn_type ==
"outbound-full-relay")
return "full";
455 if (conn_type ==
"block-relay-only")
return "block";
456 if (conn_type ==
"manual" || conn_type ==
"feeler")
return conn_type;
457 if (conn_type ==
"addr-fetch")
return "addr";
458 if (conn_type ==
"private-broadcast")
return "priv";
464 for (
size_t i = 0; i < services.
size(); ++i) {
465 const std::string
s{services[i].
get_str()};
466 str +=
s ==
"NETWORK_LIMITED" ?
'l' :
s ==
"P2P_V2" ?
'2' :
ToLower(
s[0]);
472 std::string str{services.
size() ? services[0].
get_str() :
""};
473 for (
size_t i{1}; i < services.
size(); ++i) {
474 str +=
", " + services[i].
get_str();
477 c = (c ==
'_' ?
' ' :
ToLower(c));
490 if (
const auto res{ToIntegral<uint8_t>(
args.at(0))}) {
494 throw std::runtime_error(
strprintf(
"invalid -netinfo level argument: %s\nFor more information, run: bitcoin-cli -netinfo help",
args.at(0)));
496 if (
args.size() > 1) {
497 if (std::string_view
s{
args.at(1)}; n && (
s ==
"o" ||
s ==
"outonly")) {
500 throw std::runtime_error(
strprintf(
"invalid -netinfo outonly argument: %s\nFor more information, run: bitcoin-cli -netinfo help",
s));
502 throw std::runtime_error(
strprintf(
"invalid -netinfo outonly argument: %s\nThe outonly argument is only valid for a level greater than 0 (the first argument). For more information, run: bitcoin-cli -netinfo help",
s));
519 if (networkinfo[
"version"].getInt<int>() < 209900) {
520 throw std::runtime_error(
"-netinfo requires bitcoind server to be running v0.21.0 and up");
522 const int64_t time_now{TicksSinceEpoch<std::chrono::seconds>(CliClock::now())};
526 const std::string network{peer[
"network"].get_str()};
529 const bool is_outbound{!peer[
"inbound"].get_bool()};
530 const bool is_tx_relay{peer[
"relaytxes"].isNull() ? true : peer[
"relaytxes"].get_bool()};
531 const std::string conn_type{peer[
"connection_type"].get_str()};
532 ++
m_counts.at(is_outbound).at(network_id);
541 const int peer_id{peer[
"id"].getInt<
int>()};
542 const int mapped_as{peer[
"mapped_as"].isNull() ? 0 : peer[
"mapped_as"].getInt<
int>()};
543 const int version{peer[
"version"].getInt<
int>()};
544 const int64_t addr_processed{peer[
"addr_processed"].isNull() ? 0 : peer[
"addr_processed"].getInt<int64_t>()};
545 const int64_t addr_rate_limited{peer[
"addr_rate_limited"].isNull() ? 0 : peer[
"addr_rate_limited"].getInt<int64_t>()};
546 const int64_t conn_time{peer[
"conntime"].getInt<int64_t>()};
547 const int64_t last_blck{peer[
"last_block"].getInt<int64_t>()};
548 const int64_t last_recv{peer[
"lastrecv"].getInt<int64_t>()};
549 const int64_t last_send{peer[
"lastsend"].getInt<int64_t>()};
550 const int64_t last_trxn{peer[
"last_transaction"].getInt<int64_t>()};
551 const double min_ping{peer[
"minping"].isNull() ? -1 : peer[
"minping"].get_real()};
552 const double ping{peer[
"pingtime"].isNull() ? -1 : peer[
"pingtime"].get_real()};
553 const std::string addr{peer[
"addr"].get_str()};
554 const std::string age{conn_time == 0 ?
"" :
ToString((time_now - conn_time) / 60)};
555 const std::string services{
FormatServices(peer[
"servicesnames"])};
556 const std::string sub_version{peer[
"subver"].get_str()};
557 const std::string transport{peer[
"transport_protocol_type"].isNull() ?
"v1" : peer[
"transport_protocol_type"].get_str()};
558 const bool is_addr_relay_enabled{peer[
"addr_relay_enabled"].isNull() ? false : peer[
"addr_relay_enabled"].get_bool()};
559 const bool is_bip152_hb_from{peer[
"bip152_hb_from"].get_bool()};
560 const bool is_bip152_hb_to{peer[
"bip152_hb_to"].get_bool()};
561 m_peers.push_back({addr, sub_version, conn_type,
NETWORK_SHORT_NAMES[network_id], age, services, transport, min_ping,
ping, addr_processed, addr_rate_limited, last_blck, last_recv, last_send, last_trxn, peer_id, mapped_as, version, is_addr_relay_enabled, is_bip152_hb_from, is_bip152_hb_to, is_outbound, is_tx_relay});
574 std::string result{
strprintf(
"%s client %s%s - server %i%s%s\n\n", CLIENT_NAME,
FormatFullVersion(),
ChainToString(), networkinfo[
"protocolversion"].getInt<int>(), networkinfo[
"subversion"].get_str(), services)};
579 result +=
strprintf(
"<-> type net %*s v mping ping send recv txn blk hb %*s%*s%*s ",
587 std::string version{
ToString(peer.version) + peer.sub_version};
589 "%3s %6s %5s %*s %2s%7s%7s%5s%5s%5s%5s %2s %*s%*s%*s%*i %*s %-*s%s\n",
590 peer.is_outbound ?
"out" :
"in",
595 (peer.transport_protocol_type.size() == 2 && peer.transport_protocol_type[0] ==
'v') ? peer.transport_protocol_type[1] :
' ',
598 peer.last_send ?
ToString(time_now - peer.last_send) :
"",
599 peer.last_recv ?
ToString(time_now - peer.last_recv) :
"",
600 peer.last_trxn ?
ToString((time_now - peer.last_trxn) / 60) : peer.is_tx_relay ?
"" :
"*",
601 peer.last_blck ?
ToString((time_now - peer.last_blck) / 60) :
"",
602 strprintf(
"%s%s", peer.is_bip152_hb_to ?
"." :
" ", peer.is_bip152_hb_from ?
"*" :
" "),
604 peer.addr_processed ?
ToString(peer.addr_processed) : peer.is_addr_relay_enabled ?
"" :
".",
606 peer.addr_rate_limited ?
ToString(peer.addr_rate_limited) :
"",
622 std::vector<int8_t> reachable_networks;
623 for (
const UniValue& network : networkinfo[
"networks"].getValues()) {
624 if (network[
"reachable"].get_bool()) {
625 const std::string& network_name{network[
"name"].get_str()};
628 result +=
strprintf(
"%8s", network_name);
629 reachable_networks.push_back(network_id);
634 if (
m_counts.at(2).at(network_id) == 0)
continue;
636 reachable_networks.push_back(network_id);
639 result +=
" total block";
642 const std::array rows{
"in",
"out",
"total"};
643 for (
size_t i = 0; i < rows.size(); ++i) {
645 for (int8_t n : reachable_networks) {
659 result +=
"\n\nLocal addresses";
660 const std::vector<UniValue>& local_addrs{networkinfo[
"localaddresses"].getValues()};
661 if (local_addrs.empty()) {
664 size_t max_addr_size{0};
665 for (
const UniValue& addr : local_addrs) {
666 max_addr_size = std::max(addr[
"address"].get_str().length() + 1, max_addr_size);
668 for (
const UniValue& addr : local_addrs) {
669 result +=
strprintf(
"\n%-*s port %6i score %6i", max_addr_size, addr[
"address"].get_str(), addr[
"port"].getInt<int>(), addr[
"score"].getInt<int>());
677 "-netinfo (level [outonly]) | help\n\n"
678 "Returns a network peer connections dashboard with information from the remote server.\n"
679 "This human-readable interface will change regularly and is not intended to be a stable API.\n"
680 "Under the hood, -netinfo fetches the data by calling getpeerinfo and getnetworkinfo.\n"
682 "If that argument is passed, an optional additional \"outonly\" argument may be passed to obtain the listing with outbound peers only.\n"
683 "Pass \"help\" or \"h\" to see this detailed help documentation.\n"
684 "If more than two arguments are passed, only the first two are read and parsed.\n"
685 "Suggestion: use -netinfo with the Linux watch(1) command for a live dashboard; see example below.\n\n"
687 +
strprintf(
"1. level (integer 0-%d, optional) Specify the info level of the peers dashboard (default 0):\n",
NETINFO_MAX_LEVEL) +
688 " 0 - Peer counts for each reachable network as well as for block relay peers\n"
689 " and manual peers, and the list of local addresses and ports\n"
690 " 1 - Like 0 but preceded by a peers listing (without address and version columns)\n"
691 " 2 - Like 1 but with an address column\n"
692 " 3 - Like 1 but with a version column\n"
693 " 4 - Like 1 but with both address and version columns\n"
694 "2. outonly (\"outonly\" or \"o\", optional) Return the peers listing with outbound peers only, i.e. to save screen space\n"
695 " when a node has many inbound peers. Only valid if a level is passed.\n\n"
696 "help (\"help\" or \"h\", optional) Print this help documentation instead of the dashboard.\n\n"
698 +
strprintf(
"* The peers listing in levels 1-%d displays all of the peers sorted by direction and minimum ping time:\n\n",
NETINFO_MAX_LEVEL) +
699 " Column Description\n"
700 " ------ -----------\n"
702 " \"in\" - inbound connections are those initiated by the peer\n"
703 " \"out\" - outbound connections are those initiated by us\n"
704 " type Type of peer connection\n"
705 " \"full\" - full relay, the default\n"
706 " \"block\" - block relay; like full relay but does not relay transactions or addresses\n"
707 " \"manual\" - peer we manually added using RPC addnode or the -addnode/-connect config options\n"
708 " \"feeler\" - short-lived connection for testing addresses\n"
709 " \"addr\" - address fetch; short-lived connection for requesting addresses\n"
710 " \"priv\" - private broadcast; short-lived connection for broadcasting our transactions\n"
711 " net Network the peer connected through (\"ipv4\", \"ipv6\", \"onion\", \"i2p\", \"cjdns\", or \"npr\" (not publicly routable))\n"
712 " serv Services offered by the peer\n"
713 " \"n\" - NETWORK: peer can serve the full block chain\n"
714 " \"b\" - BLOOM: peer can handle bloom-filtered connections (see BIP 111)\n"
715 " \"w\" - WITNESS: peer can be asked for blocks and transactions with witness data (SegWit)\n"
716 " \"c\" - COMPACT_FILTERS: peer can handle basic block filter requests (see BIPs 157 and 158)\n"
717 " \"l\" - NETWORK_LIMITED: peer limited to serving only the last 288 blocks (~2 days)\n"
718 " \"2\" - P2P_V2: peer supports version 2 P2P transport protocol, as defined in BIP 324\n"
719 " \"u\" - UNKNOWN: unrecognized bit flag\n"
720 " v Version of transport protocol used for the connection\n"
721 " mping Minimum observed ping time, in milliseconds (ms)\n"
722 " ping Last observed ping time, in milliseconds (ms)\n"
723 " send Time since last message sent to the peer, in seconds\n"
724 " recv Time since last message received from the peer, in seconds\n"
725 " txn Time since last novel transaction received from the peer and accepted into our mempool, in minutes\n"
726 " \"*\" - we do not relay transactions to this peer (getpeerinfo \"relaytxes\" is false)\n"
727 " blk Time since last novel block passing initial validity checks received from the peer, in minutes\n"
728 " hb High-bandwidth BIP152 compact block relay\n"
729 " \".\" (to) - we selected the peer as a high-bandwidth peer\n"
730 " \"*\" (from) - the peer selected us as a high-bandwidth peer\n"
731 " addrp Total number of addresses processed, excluding those dropped due to rate limiting\n"
732 " \".\" - we do not relay addresses to this peer (getpeerinfo \"addr_relay_enabled\" is false)\n"
733 " addrl Total number of addresses dropped due to rate limiting\n"
734 " age Duration of connection to the peer, in minutes\n"
735 " asmap Mapped AS (Autonomous System) number at the end of the BGP route to the peer, used for diversifying\n"
736 " peer selection (only displayed if the -asmap config option is set)\n"
737 " id Peer index, in increasing order of peer connections since node startup\n"
738 " address IP address and port of the peer\n"
739 " version Peer version and subversion concatenated, e.g. \"70016/Satoshi:21.0.0/\"\n\n"
740 "* The peer counts table displays the number of peers for each reachable network as well as\n"
741 " the number of block relay peers and manual peers.\n\n"
742 "* The local addresses table lists each local address broadcast by the node, the port, and the score.\n\n"
744 "Peer counts table of reachable networks and list of local addresses\n"
745 "> bitcoin-cli -netinfo\n\n"
746 "The same, preceded by a peers listing without address and version columns\n"
747 "> bitcoin-cli -netinfo 1\n\n"
750 "Full dashboard, but with outbound peers only\n"
752 "Full live dashboard, adjust --interval or --no-title as needed (Linux)\n"
755 "> bitcoin-cli -netinfo help\n"};
800static std::optional<UniValue>
CallIPC(
BaseRequestHandler* rh,
const std::string& strMethod,
const std::vector<std::string>&
args,
const std::string& endpoint,
const std::string& username)
802 auto ipcconnect{
gArgs.
GetArg(
"-ipcconnect",
"auto")};
803 if (ipcconnect ==
"0")
return {};
805 if (ipcconnect ==
"auto")
return {};
806 throw std::runtime_error(
"-rpcconnect and -ipcconnect options cannot both be enabled");
810 if (!local_init || !local_init->ipc()) {
811 if (ipcconnect ==
"auto")
return {};
812 throw std::runtime_error(
"bitcoin-cli was not built with IPC support");
815 std::unique_ptr<interfaces::Init> node_init;
817 node_init = local_init->ipc()->connectAddress(ipcconnect);
818 if (!node_init)
return {};
819 }
catch (
const std::exception& e) {
822 "Probably bitcoin-node is not running or not listening on a unix socket. Can be started with:\n\n"
826 std::unique_ptr<interfaces::Rpc> rpc{node_init->makeRpc()};
829 UniValue reply{rpc->executeRpc(std::move(request), endpoint, username)};
839 static HTTPClient Connect(
const std::string& host, uint16_t port, std::chrono::seconds timeout);
842 std::span<
const std::pair<std::string, std::string>>
headers,
843 const std::string& body);
853 HTTPClient(std::unique_ptr<Sock>&& socket,
const std::string& host, std::chrono::seconds timeout)
857 std::optional<std::string>
Recv(std::chrono::time_point<std::chrono::steady_clock> deadline);
862 std::vector<CService> services =
Lookup(host, port,
true, 256);
863 if (services.empty()) {
867 const auto deadline{std::chrono::steady_clock::now() + timeout};
868 for (
const CService& service : services) {
869 const auto time_left{std::chrono::duration_cast<std::chrono::milliseconds>(deadline - std::chrono::steady_clock::now())};
870 if (time_left.count() <= 0)
break;
873 if (sock)
return HTTPClient{std::move(sock), host, timeout};
880 std::span<
const std::pair<std::string, std::string>>
headers,
881 const std::string& body)
885 std::string request =
strprintf(
"POST %s HTTP/1.1\r\n"
887 "Connection: close\r\n"
888 "Content-Length: %d\r\n",
889 endpoint,
m_host, body.size());
909 const auto deadline{std::chrono::steady_clock::now() +
m_timeout};
911 while (!request.empty()) {
913 auto time_left = std::chrono::duration_cast<std::chrono::milliseconds>(
914 deadline - std::chrono::steady_clock::now());
927 std::this_thread::yield();
932 request.remove_prefix(sent);
941 const auto deadline{std::chrono::steady_clock::now() +
m_timeout};
944 size_t headers_end = 0;
946 while (headers_end == 0) {
947 if (
auto result{
Recv(deadline)}) {
948 buffer.append(*result);
950 std::this_thread::yield();
955 size_t pos = buffer.find(
"\r\n\r\n");
956 if (pos != std::string::npos) {
957 headers_end = pos + 4;
965 throw HTTPError{
"Failed to read status line"};
968 const std::string_view status_str = *status_line;
970 if (status_str.size() < 12 || !status_str.starts_with(
"HTTP/")) {
974 size_t space1 = status_str.find(
' ');
975 if (space1 == std::string::npos || space1 + 4 > status_str.size()) {
976 throw HTTPError{
"Invalid status line format"};
979 const std::string_view status_code_str = status_str.substr(space1 + 1, 3);
980 auto status_code = ToIntegral<int>(status_code_str);
984 response.
status = *status_code;
990 size_t content_length = 0;
991 bool chunked =
false;
997 if (transfer_encoding &&
ToLower(*transfer_encoding).find(
"chunked") != std::string::npos) {
1001 if (content_length_header) {
1002 auto maybe_len = ToIntegral<size_t>(*content_length_header);
1004 throw HTTPError{
"Invalid Content-Length"};
1006 content_length = *maybe_len;
1011 buffer.erase(0, headers_end);
1020 std::string_view chunk_data{buffer};
1021 size_t line_end = chunk_data.find(
"\r\n");
1023 if (line_end != std::string::npos) {
1025 std::string_view size_str = chunk_data.substr(0, line_end);
1027 size_t semi = size_str.find(
';');
1028 if (semi != std::string::npos) {
1029 size_str = size_str.substr(0, semi);
1037 if (*chunk_size == 0) {
1042 buffer.erase(0, line_end + 2);
1044 size_t crlf_pos = buffer.find(
"\r\n");
1045 if (crlf_pos == std::string::npos) {
1047 if (
auto result{
Recv(deadline)}) {
1048 buffer.append(*result);
1050 std::this_thread::yield();
1054 buffer.erase(0, crlf_pos + 2);
1055 if (crlf_pos == 0)
break;
1061 size_t chunk_start = line_end + 2;
1062 if (*chunk_size > std::numeric_limits<size_t>::max() - chunk_start - 2) {
1063 throw HTTPError{
"Chunk size too large"};
1065 size_t chunk_end = chunk_start + *chunk_size + 2;
1067 if (buffer.size() >= chunk_end) {
1069 body.append(buffer, chunk_start, *chunk_size);
1072 buffer.erase(0, chunk_end);
1079 if (
auto result{
Recv(deadline)}) {
1080 buffer.append(*result);
1083 std::this_thread::yield();
1088 response.
body = std::move(body);
1089 }
else if (content_length > 0) {
1091 while (buffer.size() < content_length) {
1092 if (
auto result{
Recv(deadline)}) {
1093 buffer.append(*result);
1095 std::this_thread::yield();
1101 buffer.resize(content_length);
1102 response.
body = std::move(buffer);
1108 if (
auto result{
Recv(deadline)}) {
1109 buffer.append(*result);
1111 std::this_thread::yield();
1115 response.
body = std::move(buffer);
1121std::optional<std::string>
HTTPClient::Recv(
const std::chrono::time_point<std::chrono::steady_clock> deadline)
1123 auto wait_for_readable{[
this](std::chrono::milliseconds timeout) ->
bool {
1131 auto time_left = std::chrono::duration_cast<std::chrono::milliseconds>(
1132 deadline - std::chrono::steady_clock::now());
1133 if (time_left.count() <= 0 || !wait_for_readable(time_left)) {
1137 char recv_buf[4096];
1138 ssize_t nrecv =
m_socket->Recv(recv_buf,
sizeof(recv_buf), 0);
1143 return std::nullopt;
1152 return std::string{recv_buf,
static_cast<size_t>(nrecv)};
1164 uint16_t rpcconnect_port{0};
1166 if (!
SplitHostPort(rpcconnect_str, rpcconnect_port, host)) {
1170 throw std::runtime_error(
strprintf(
"Invalid port provided in -rpcconnect: %s", rpcconnect_str));
1172 if (rpcconnect_port != 0) {
1174 port = rpcconnect_port;
1178 if (std::optional<std::string> rpcport_arg =
gArgs.
GetArg(
"-rpcport")) {
1180 const uint16_t rpcport_int{ToIntegral<uint16_t>(rpcport_arg.value()).value_or(0)};
1181 if (rpcport_int == 0) {
1185 throw std::runtime_error(
strprintf(
"Invalid port provided in -rpcport: %s", rpcport_arg.value()));
1193 if (rpcconnect_port != 0) {
1194 tfm::format(std::cerr,
"Warning: Port specified in both -rpcconnect and -rpcport. Using -rpcport %u\n", port);
1201 std::chrono::seconds timeout_duration;
1203 timeout_duration = std::chrono::seconds(timeout);
1206 timeout_duration = std::chrono::years(5);
1210 std::string rpc_credentials;
1211 std::optional<AuthCookieResult> auth_cookie_result;
1216 rpc_credentials = username +
":" +
gArgs.
GetArg(
"-rpcpassword",
"");
1219 const std::pair<std::string, std::string>
headers[]{
1220 {
"Content-Type",
"application/json"},
1221 {
"Authorization",
"Basic " +
EncodeBase64(rpc_credentials)},
1230 const std::string formatted_error{*e.what() ?
strprintf(
" (%s)", e.what()) :
""};
1232 "Make sure the bitcoind server is running and that you are connecting to the correct RPC port.\n"
1233 "Use \"bitcoin-cli -help\" for more info.",
1234 host, port, formatted_error));
1238 std::string error{
"Authorization failed: "};
1239 bool read_err =
false;
1240 if (auth_cookie_result.has_value()) {
1241 switch (*auth_cookie_result) {
1243 error +=
"Failed to read cookie file and no rpcpassword was specified.";
1247 error +=
"Cookie file was disabled via -norpccookiefile and no rpcpassword was specified.";
1250 error +=
"Cookie file credentials were invalid and no rpcpassword was specified.";
1254 error +=
"Incorrect rpcuser or rpcpassword were specified.";
1258 error +=
"\nIs your -signetchallenge correct for custom signets?";
1260 throw std::runtime_error(error);
1262 throw std::runtime_error(
strprintf(
"Server response: %s", response.
body));
1264 throw std::runtime_error(
strprintf(
"server returned HTTP error %d", response.
status));
1265 else if (response.
body.empty())
1266 throw std::runtime_error(
"no response from server");
1271 throw std::runtime_error(
"couldn't parse reply from server");
1274 throw std::runtime_error(
"expected reply to have result, error and id properties");
1294 const auto deadline{std::chrono::steady_clock::now() + 1
s * timeout};
1297 std::string endpoint =
"/";
1299 endpoint =
"/wallet/" +
UrlEncode(*rpcwallet);
1302 std::string username{
gArgs.
GetArg(
"-rpcuser",
"")};
1305 if (
auto ipc_response{
CallIPC(rh, strMethod,
args, endpoint, username)}) {
1306 response = std::move(*ipc_response);
1308 response =
CallRPC(rh, strMethod,
args, endpoint, username);
1318 if (fWait && (timeout <= 0 || std::chrono::steady_clock::now() < deadline)) {
1333 if (result.
isNull())
return;
1343 if (!err_code.
isNull()) {
1346 if (err_msg.
isStr()) {
1350 strPrint +=
" Or for the CLI, specify the \"-rpcwallet=<walletname>\" option before the command";
1351 strPrint +=
" (run \"bitcoin-cli -h\" for help or \"bitcoin-cli listwallets\" to see which wallets are currently loaded).";
1356 nRet = abs(error[
"code"].getInt<int>());
1369 if (!
listwallets.find_value(
"error").isNull())
return;
1371 if (wallets.
size() <= 1)
return;
1375 const std::string& wallet_name =
wallet.get_str();
1378 balances.
pushKV(wallet_name, balance);
1380 result.
pushKV(
"balances", std::move(balances));
1391 if (progress < 0 || progress > 1)
return;
1393 static constexpr double INCREMENT{0.05};
1394 static const std::string COMPLETE_BAR{
"\u2592"};
1395 static const std::string INCOMPLETE_BAR{
"\u2591"};
1397 for (
int i = 0; i < progress / INCREMENT; ++i) {
1398 progress_bar += COMPLETE_BAR;
1401 for (
int i = 0; i < (1 - progress) / INCREMENT; ++i) {
1402 progress_bar += INCOMPLETE_BAR;
1415 std::string RESET, GREEN, BLUE, YELLOW, MAGENTA, CYAN;
1416 bool should_colorize =
false;
1419 if (isatty(fileno(stdout))) {
1421 should_colorize =
true;
1427 if (color ==
"always") {
1428 should_colorize =
true;
1429 }
else if (color ==
"never") {
1430 should_colorize =
false;
1431 }
else if (color !=
"auto") {
1432 throw std::runtime_error(
"Invalid value for -color option. Valid values: always, auto, never.");
1436 if (should_colorize) {
1440 YELLOW =
"\x1B[33m";
1441 MAGENTA =
"\x1B[35m";
1445 std::string result_string =
strprintf(
"%sChain: %s%s\n", BLUE, result[
"chain"].getValStr(), RESET);
1446 result_string +=
strprintf(
"Blocks: %s\n", result[
"blocks"].getValStr());
1447 result_string +=
strprintf(
"Headers: %s\n", result[
"headers"].getValStr());
1449 const double ibd_progress{result[
"verificationprogress"].
get_real()};
1450 std::string ibd_progress_bar;
1452 if (ibd_progress < 0.99) {
1455 ibd_progress_bar +=
" ";
1458 result_string +=
strprintf(
"Verification progress: %s%.4f%%\n", ibd_progress_bar, ibd_progress * 100);
1459 result_string +=
strprintf(
"Difficulty: %s\n\n", result[
"difficulty"].getValStr());
1462 "%sNetwork: in %s, out %s, total %s%s\n",
1464 result[
"connections"][
"in"].getValStr(),
1465 result[
"connections"][
"out"].getValStr(),
1466 result[
"connections"][
"total"].getValStr(),
1468 result_string +=
strprintf(
"Version: %s\n", result[
"version"].getValStr());
1469 result_string +=
strprintf(
"Time offset (s): %s\n", result[
"timeoffset"].getValStr());
1472 std::map<std::string, std::vector<std::string>> proxy_networks;
1473 std::vector<std::string> ordered_proxies;
1475 for (
const UniValue& network : result[
"networks"].getValues()) {
1476 const std::string proxy = network[
"proxy"].getValStr();
1477 if (proxy.empty())
continue;
1479 if (!proxy_networks.contains(proxy)) ordered_proxies.push_back(proxy);
1481 proxy_networks[proxy].push_back(network[
"name"].getValStr());
1484 std::vector<std::string> formatted_proxies;
1485 formatted_proxies.reserve(ordered_proxies.size());
1486 for (
const std::string& proxy : ordered_proxies) {
1487 formatted_proxies.emplace_back(
strprintf(
"%s (%s)", proxy,
Join(proxy_networks.find(proxy)->second,
", ")));
1489 result_string +=
strprintf(
"Proxies: %s\n", formatted_proxies.empty() ?
"n/a" :
Join(formatted_proxies,
", "));
1491 result_string +=
strprintf(
"Min tx relay fee rate (%s/kvB): %s\n\n",
CURRENCY_UNIT, result[
"relayfee"].getValStr());
1493 if (!result[
"has_wallet"].isNull()) {
1494 const std::string walletname = result[
"walletname"].
getValStr();
1495 result_string +=
strprintf(
"%sWallet: %s%s\n", MAGENTA, walletname.empty() ?
"\"\"" : walletname, RESET);
1497 result_string +=
strprintf(
"Keypool size: %s\n", result[
"keypoolsize"].getValStr());
1498 if (!result[
"unlocked_until"].isNull()) {
1499 result_string +=
strprintf(
"Unlocked until: %s\n", result[
"unlocked_until"].getValStr());
1502 if (!result[
"balance"].isNull()) {
1503 result_string +=
strprintf(
"%sBalance:%s %s\n\n", CYAN, RESET, result[
"balance"].getValStr());
1506 if (!result[
"balances"].isNull()) {
1507 result_string +=
strprintf(
"%sBalances%s\n", CYAN, RESET);
1509 size_t max_balance_length{10};
1511 for (
const std::string&
wallet : result[
"balances"].getKeys()) {
1512 max_balance_length = std::max(result[
"balances"][
wallet].getValStr().length(), max_balance_length);
1515 for (
const std::string&
wallet : result[
"balances"].getKeys()) {
1518 result[
"balances"][
wallet].getValStr(),
1521 result_string +=
"\n";
1524 const std::string warnings{result[
"warnings"].
getValStr()};
1525 result_string +=
strprintf(
"%sWarnings:%s %s", YELLOW, RESET, warnings.empty() ?
"(none)" : warnings);
1527 result.
setStr(result_string);
1547 if (
args.size() > 2)
throw std::runtime_error(
"too many arguments (maximum 2 for nblocks and maxtries)");
1548 if (
args.size() == 0) {
1550 }
else if (
args.at(0) ==
"0") {
1551 throw std::runtime_error(
"the first argument (number of blocks to generate, default: " +
DEFAULT_NBLOCKS +
") must be an integer value greater than zero");
1553 args.emplace(
args.begin() + 1, address);
1566 std::string rpcPass;
1570 fputs(
"RPC password> ", stderr);
1573 if (!std::getline(std::cin, rpcPass)) {
1574 throw std::runtime_error(
"-stdinrpcpass specified but failed to read from standard input");
1577 fputc(
'\n', stdout);
1581 std::vector<std::string>
args = std::vector<std::string>(&argv[1], &argv[argc]);
1584 std::string walletPass;
1585 if (
args.size() < 1 || !
args[0].starts_with(
"walletpassphrase")) {
1586 throw std::runtime_error(
"-stdinwalletpassphrase is only applicable for walletpassphrase(change)");
1589 fputs(
"Wallet passphrase> ", stderr);
1592 if (!std::getline(std::cin, walletPass)) {
1593 throw std::runtime_error(
"-stdinwalletpassphrase specified but failed to read from standard input");
1596 fputc(
'\n', stdout);
1598 args.insert(
args.begin() + 1, walletPass);
1603 while (std::getline(std::cin, line)) {
1604 args.push_back(line);
1607 fputc(
'\n', stdout);
1611 std::unique_ptr<BaseRequestHandler> rh;
1616 if (!
args.empty() && (
args.at(0) ==
"h" ||
args.at(0) ==
"help")) {
1634 if (
args.size() < 1) {
1635 throw std::runtime_error(
"too few parameters (need at least command)");
1661 }
catch (
const std::exception& e) {
1662 strPrint = std::string(
"error: ") + e.what();
1663 nRet = EXIT_FAILURE;
1679 tfm::format(std::cerr,
"Error: Initializing networking failed\n");
1680 return EXIT_FAILURE;
1688 catch (
const std::exception& e) {
1690 return EXIT_FAILURE;
1693 return EXIT_FAILURE;
1700 catch (
const std::exception& e) {
bool HelpRequested(const ArgsManager &args)
void SetupHelpOptions(ArgsManager &args)
Add help options to the args manager.
bool CheckDataDirOption(const ArgsManager &args)
const char *const BITCOIN_CONF_FILENAME
bool IsSwitchChar(char c)
static const char DEFAULT_RPCCONNECT[]
static constexpr int8_t UNKNOWN_NETWORK
static constexpr int DEFAULT_WAIT_CLIENT_TIMEOUT
static const int CONTINUE_EXECUTION
static int AppInitRPC(int argc, char *argv[])
static void ParseError(const UniValue &error, std::string &strPrint, int &nRet)
Parse UniValue error to update the message to print to std::cerr and the code to return.
static constexpr std::array UNREACHABLE_NETWORK_IDS
static int CommandLineRPC(int argc, char *argv[])
static constexpr uint8_t NETINFO_MAX_LEVEL
static const int DEFAULT_HTTP_CLIENT_TIMEOUT
static void ParseGetInfoResult(UniValue &result)
ParseGetInfoResult takes in -getinfo result in UniValue object and parses it into a user friendly Uni...
static std::optional< UniValue > CallIPC(BaseRequestHandler *rh, const std::string &strMethod, const std::vector< std::string > &args, const std::string &endpoint, const std::string &username)
static void ParseResult(const UniValue &result, std::string &strPrint)
Parse UniValue result to update the message to print to std::cout.
static const std::string DEFAULT_NBLOCKS
Default number of blocks to generate for RPC generatetoaddress.
static UniValue ConnectAndCallRPC(BaseRequestHandler *rh, const std::string &strMethod, const std::vector< std::string > &args, const std::optional< std::string > &rpcwallet={})
ConnectAndCallRPC wraps CallRPC with -rpcwait and an exception handler.
static void SetGenerateToAddressArgs(const std::string &address, std::vector< std::string > &args)
Check bounds and set up args for RPC generatetoaddress params: nblocks, address, maxtries.
static void GetWalletBalances(UniValue &result)
GetWalletBalances calls listwallets; if more than one wallet is loaded, it then fetches mine....
static constexpr std::array NETWORKS
static void SetupCliArgs(ArgsManager &argsman)
static const std::string DEFAULT_COLOR_SETTING
Default -color setting.
std::optional< std::string > RpcWalletName(const ArgsManager &args)
const TranslateFn G_TRANSLATION_FUN
Translate string to current locale using Qt.
std::chrono::system_clock CliClock
static constexpr const char * DEFAULT_RPC_REQ_ID
static constexpr std::array NETWORK_SHORT_NAMES
static int8_t NetworkStringToId(const std::string &str)
static const bool DEFAULT_NAMED
static void GetProgressBar(double progress, std::string &progress_bar)
GetProgressBar constructs a progress bar with 5% intervals.
static UniValue CallRPC(BaseRequestHandler *rh, const std::string &strMethod, const std::vector< std::string > &args, const std::string &endpoint, const std::string &username)
static UniValue GetNewAddress()
Call RPC getnewaddress.
const CBaseChainParams & BaseParams()
Return the currently selected parameters.
void SetupChainParamsBaseOptions(ArgsManager &argsman)
Set the arguments for chainparams.
void SelectBaseParams(const ChainType chain)
Sets the params returned by Params() to those for the given chain.
std::unique_ptr< CBaseChainParams > CreateBaseChainParams(const ArgsManager &args, const ChainType chain)
Port numbers for incoming Tor connections (8334, 18334, 38334, 48334, 18445) have been chosen arbitra...
bool ParseParameters(int argc, const char *const argv[], std::string &error) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
ChainType GetChainType() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Returns the appropriate chain type from the program arguments.
void CheckMultipleCLIArgs() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Check CLI command args.
@ ALLOW_ANY
disable validation
@ DISALLOW_NEGATION
disallow -nofoo syntax
@ DISALLOW_ELISION
disallow -foo syntax that doesn't assign any value
fs::path GetConfigFilePath() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return config file path (read-only)
void AddArg(const std::string &name, const std::string &help, unsigned int flags, const OptionsCategory &cat) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Add argument.
bool ReadConfigFiles(std::string &error, bool ignore_invalid_keys=false) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
void ForceSetArg(const std::string &strArg, const std::string &strValue) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
std::string GetArg(const std::string &strArg, const std::string &strDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return string argument or default value.
std::string GetChainTypeString() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Returns the appropriate chain type string from the program arguments.
bool IsArgSet(const std::string &strArg) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return true if the given argument has been manually set.
bool IsArgNegated(const std::string &strArg) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return true if the argument was originally passed as a negated option, i.e.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
bool GetBoolArg(const std::string &strArg, bool fDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return boolean argument or default value.
std::string GetHelpMessage() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Get the help string.
A combination of a network address (CNetAddr) and a (TCP) port.
Process RPC generatetoaddress request.
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
UniValue ProcessReply(const UniValue &reply) override
Simple synchronous HTTP client using Sock class.
std::chrono::seconds m_timeout
bool SendRequest(std::string_view request)
static HTTPClient Connect(const std::string &host, uint16_t port, std::chrono::seconds timeout)
HTTPClient(std::unique_ptr< Sock > &&socket, const std::string &host, std::chrono::seconds timeout)
HTTPResponse Post(const std::string &endpoint, std::span< const std::pair< std::string, std::string > > headers, const std::string &body)
std::optional< std::string > Recv(std::chrono::time_point< std::chrono::steady_clock > deadline)
std::unique_ptr< Sock > m_socket
HTTPResponse ReadResponse()
Process netinfo requests.
bool m_outbound_only_selected
uint8_t m_block_relay_peers_count
bool DetailsRequested() const
std::vector< Peer > m_peers
UniValue ProcessReply(const UniValue &batch_in) override
static std::string ServicesList(const UniValue &services)
uint8_t m_details_level
Optional user-supplied arg to set dashboard details level.
size_t m_max_addr_rate_limited_length
size_t m_max_addr_processed_length
bool IsAddressSelected() const
std::string FormatServices(const UniValue &services)
std::string ConnectionTypeForNetinfo(const std::string &conn_type) const
bool IsVersionSelected() const
uint8_t m_manual_peers_count
const std::string m_help_doc
static constexpr int ID_PEERINFO
std::string ChainToString() const
size_t m_max_services_length
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
std::array< std::array< uint16_t, NETWORKS.size()+1 >, 3 > m_counts
Peer counts by (in/out/total, networks/total)
static constexpr int ID_NETWORKINFO
std::string PingTimeToString(double seconds) const
static constexpr Event RecvEvent
If passed to Wait(), then it will wait for readiness to read from the socket.
static constexpr Event SendEvent
If passed to Wait(), then it will wait for readiness to send to the socket.
void push_back(UniValue val)
const std::string & get_str() const
const UniValue & find_value(std::string_view key) const
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
const std::string & getValStr() const
const UniValue & get_obj() const
const std::vector< UniValue > & getValues() const
const std::vector< std::string > & getKeys() const
bool read(std::string_view json)
Parse JSON; set value to null on failure.
void setStr(std::string str)
void pushKV(std::string key, UniValue val)
std::optional< std::string_view > ReadLine() LIFETIMEBOUND
Returns a string from current iterator position up to (but not including) next and advances iterator...
UniValue RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert command lines arguments to params object when -named is disabled.
UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert command line arguments to params object when -named is enabled.
std::string FormatFullVersion()
#define WSAGetLastError()
void PrintExceptionContinue(const std::exception *pex, std::string_view thread_name)
const std::string CURRENCY_UNIT
static std::string PathToString(const path &path)
Convert path object to a byte string.
std::string LicenseInfo()
Returns licensing information (for -version)
std::unique_ptr< ProxyClient< messages::FooInterface > > client
std::unique_ptr< Init > MakeBasicInit(const char *exe_name, const char *process_argv0)
Return implementation of Init interface for a basic IPC client that doesn't provide any IPC services ...
std::string_view TrimStringView(std::string_view str LIFETIMEBOUND, std::string_view pattern=" \f\n\r\t\v")
std::string ToString(const T &t)
Locale-independent version of std::to_string.
std::string TrimString(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
static RPCMethod listwallets()
RPCMethod getnewaddress()
std::unique_ptr< Sock > ConnectDirectly(const CService &dest, bool manual_connection)
Create a socket and try to connect to the specified service.
std::vector< CService > Lookup(const std::string &name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
Resolve a service string to its corresponding service.
std::vector< UniValue > JSONRPCProcessBatchReply(const UniValue &in)
Parse JSON-RPC batch reply into a vector.
UniValue JSONRPCRequestObj(const std::string &strMethod, const UniValue ¶ms, const UniValue &id)
JSON-RPC protocol.
AuthCookieResult GetAuthCookie(std::string &cookie_out)
Read the RPC authentication cookie from disk.
UniValue JSONRPCReplyObj(UniValue result, UniValue error, std::optional< UniValue > id, JSONRPCVersion jsonrpc_version)
constexpr uint64_t DEFAULT_MAX_TRIES
Default max iterations to try in RPC generatetodescriptor, generatetoaddress, and generateblock.
@ HTTP_SERVICE_UNAVAILABLE
@ HTTP_INTERNAL_SERVER_ERROR
@ RPC_WALLET_NOT_SPECIFIED
No wallet specified (error when there are multiple wallets loaded)
@ RPC_IN_WARMUP
Client still warming up.
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
bool IOErrorIsPermanent(int err)
Process addrinfo requests.
UniValue ProcessReply(const UniValue &reply) override
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
Handle the conversion from a command-line to a JSON-RPC request, as well as converting back to a JSON...
virtual UniValue ProcessReply(const UniValue &batch_in)=0
virtual ~BaseRequestHandler()=default
virtual UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args)=0
CConnectionFailed(const std::string &msg)
Process default single requests.
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
UniValue ProcessReply(const UniValue &reply) override
Process getinfo requests.
const int ID_BLOCKCHAININFO
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
Create a simulated getinfo request.
UniValue ProcessReply(const UniValue &batch_in) override
Collect values from the batch and form a simulated getinfo reply.
HTTPError(const std::string &msg)
bool is_addr_relay_enabled
std::string transport_protocol_type
int64_t addr_rate_limited
bool operator<(const Peer &rhs) const
std::function< std::string(const char *)> TranslateFn
Translate a message to the native language of the user.
const UniValue NullUniValue
std::string UrlEncode(std::string_view str)
bool CaseInsensitiveEqual(std::string_view s1, std::string_view s2)
Locale-independent, ASCII-only comparator.
std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
Format a paragraph of text to a fixed width, adding spaces for indentation to any added line.
bool SplitHostPort(std::string_view in, uint16_t &portOut, std::string &hostOut)
Splits socket address string into host string and port value.
std::string EncodeBase64(std::span< const unsigned char > input)
std::string ToLower(std::string_view str)
Returns the lowercase equivalent of the given string.
void UninterruptibleSleep(const std::chrono::microseconds &n)