2013-10-11 18:09:59 -03:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2020-04-16 13:14:08 -04:00
// Copyright (c) 2009-2020 The Bitcoin Core developers
2014-12-13 01:09:33 -03:00
// Distributed under the MIT software license, see the accompanying
2013-10-11 18:09:59 -03:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2015-12-09 07:53:12 -03:00
# if defined(HAVE_CONFIG_H)
2017-11-09 21:57:53 -03:00
# include <config/bitcoin-config.h>
2015-12-09 07:53:12 -03:00
# endif
2017-11-09 21:57:53 -03:00
# include <chainparamsbase.h>
# include <clientversion.h>
2021-05-02 04:31:52 -04:00
# include <policy/feerate.h>
2017-11-09 21:57:53 -03:00
# include <rpc/client.h>
2020-05-31 09:41:08 -04:00
# include <rpc/mining.h>
2017-11-09 21:57:53 -03:00
# include <rpc/protocol.h>
2019-06-19 13:39:38 -04:00
# include <rpc/request.h>
2020-10-16 06:59:27 -03:00
# include <tinyformat.h>
2018-10-22 19:51:11 -03:00
# include <util/strencodings.h>
2019-06-17 03:56:52 -04:00
# include <util/system.h>
# include <util/translation.h>
2020-04-02 09:35:10 -03:00
# include <util/url.h>
2013-10-11 18:09:59 -03:00
2020-10-25 11:07:01 -03:00
# include <algorithm>
2021-01-27 04:04:34 -03:00
# include <cmath>
2019-06-17 03:56:52 -04:00
# include <functional>
2018-04-02 15:31:40 -03:00
# include <memory>
2021-03-15 00:59:05 -03:00
# include <optional>
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
# include <stdio.h>
2020-05-18 04:14:10 -04:00
# include <string>
2018-08-05 12:38:25 -04:00
# include <tuple>
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
2021-05-02 04:31:52 -04:00
# ifndef WIN32
# include <unistd.h>
# endif
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
# include <event2/buffer.h>
# include <event2/keyvalq_struct.h>
2017-11-09 21:57:53 -03:00
# include <support/events.h>
2013-04-13 02:13:08 -03:00
2015-09-04 11:11:34 -03:00
# include <univalue.h>
2018-07-19 10:48:55 -04:00
# include <compat/stdin.h>
2015-05-18 09:02:18 -03:00
2018-08-13 17:13:29 -03:00
const std : : function < std : : string ( const char * ) > G_TRANSLATION_FUN = nullptr ;
2020-04-02 09:35:10 -03:00
UrlDecodeFn * const URL_DECODE = urlDecode ;
2018-08-13 17:13:29 -03:00
2015-06-27 16:21:41 -03:00
static const char DEFAULT_RPCCONNECT [ ] = " 127.0.0.1 " ;
2015-09-18 10:45:38 -03:00
static const int DEFAULT_HTTP_CLIENT_TIMEOUT = 900 ;
2021-02-01 13:55:38 -03:00
static constexpr int DEFAULT_WAIT_CLIENT_TIMEOUT = 0 ;
2016-11-22 10:56:29 -03:00
static const bool DEFAULT_NAMED = false ;
2016-11-02 15:59:09 -03:00
static const int CONTINUE_EXECUTION = - 1 ;
2021-04-01 05:46:20 -03:00
static constexpr int8_t UNKNOWN_NETWORK { - 1 } ;
2015-09-18 10:45:38 -03:00
2020-05-31 09:41:08 -04:00
/** Default number of blocks to generate for RPC generatetoaddress. */
static const std : : string DEFAULT_NBLOCKS = " 1 " ;
2021-05-02 04:31:52 -04:00
/** Default -color setting. */
static const std : : string DEFAULT_COLOR_SETTING { " auto " } ;
2020-07-19 03:31:51 -04:00
static void SetupCliArgs ( ArgsManager & argsman )
2014-05-26 05:38:44 -04:00
{
2020-07-19 03:31:51 -04:00
SetupHelpOptions ( argsman ) ;
2019-02-06 15:57:52 -03:00
2015-05-21 22:50:01 -03:00
const auto defaultBaseParams = CreateBaseChainParams ( CBaseChainParams : : MAIN ) ;
const auto testnetBaseParams = CreateBaseChainParams ( CBaseChainParams : : TESTNET ) ;
2020-09-25 08:55:40 -03:00
const auto signetBaseParams = CreateBaseChainParams ( CBaseChainParams : : SIGNET ) ;
2018-08-20 20:46:34 -03:00
const auto regtestBaseParams = CreateBaseChainParams ( CBaseChainParams : : REGTEST ) ;
2014-05-26 05:38:44 -04:00
2020-07-19 03:47:05 -04:00
argsman . AddArg ( " -version " , " Print version and exit " , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
argsman . AddArg ( " -conf=<file> " , strprintf ( " Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s) " , BITCOIN_CONF_FILENAME ) , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
argsman . AddArg ( " -datadir=<dir> " , " Specify data directory " , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
2021-01-28 21:38:57 -03:00
argsman . AddArg ( " -generate " , strprintf ( " Generate blocks immediately, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000 " , DEFAULT_NBLOCKS , DEFAULT_MAX_TRIES ) , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
2021-04-04 10:20:47 -04:00
argsman . AddArg ( " -addrinfo " , " Get the number of addresses known to the node, per network and total. " , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
2020-07-19 03:47:05 -04:00
argsman . AddArg ( " -getinfo " , " Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result 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 : : OPTIONS ) ;
2020-12-26 16:18:26 -03:00
argsman . AddArg ( " -netinfo " , " Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \" help \" for detailed help documentation. " , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
2020-07-27 02:20:26 -04:00
2020-07-19 03:31:51 -04:00
SetupChainParamsBaseOptions ( argsman ) ;
2021-05-02 04:31:52 -04:00
argsman . AddArg ( " -color=<when> " , strprintf ( " Color setting for CLI output (default: %s). Valid values: always, auto (add color codes when standard output is connected to a terminal and OS is not WIN32), never. " , DEFAULT_COLOR_SETTING ) , ArgsManager : : ALLOW_STRING , OptionsCategory : : OPTIONS ) ;
2020-07-19 03:47:05 -04:00
argsman . AddArg ( " -named " , strprintf ( " Pass named instead of positional arguments (default: %s) " , DEFAULT_NAMED ) , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
argsman . AddArg ( " -rpcclienttimeout=<n> " , strprintf ( " Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d) " , DEFAULT_HTTP_CLIENT_TIMEOUT ) , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
argsman . AddArg ( " -rpcconnect=<ip> " , strprintf ( " Send commands to node running on <ip> (default: %s) " , DEFAULT_RPCCONNECT ) , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
argsman . AddArg ( " -rpccookiefile=<loc> " , " Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir) " , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
argsman . AddArg ( " -rpcpassword=<pw> " , " Password for JSON-RPC connections " , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
2020-09-25 08:55:40 -03:00
argsman . AddArg ( " -rpcport=<port> " , strprintf ( " Connect to JSON-RPC on <port> (default: %u, testnet: %u, signet: %u, regtest: %u) " , defaultBaseParams - > RPCPort ( ) , testnetBaseParams - > RPCPort ( ) , signetBaseParams - > RPCPort ( ) , regtestBaseParams - > RPCPort ( ) ) , ArgsManager : : ALLOW_ANY | ArgsManager : : NETWORK_ONLY , OptionsCategory : : OPTIONS ) ;
2020-07-19 03:47:05 -04:00
argsman . AddArg ( " -rpcuser=<user> " , " Username for JSON-RPC connections " , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
argsman . AddArg ( " -rpcwait " , " Wait for RPC server to start " , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
2021-02-01 13:55:38 -03:00
argsman . AddArg ( " -rpcwaittimeout=<n> " , strprintf ( " Timeout in seconds to wait for the RPC server to start, or 0 for no timeout. (default: %d) " , DEFAULT_WAIT_CLIENT_TIMEOUT ) , ArgsManager : : ALLOW_INT , OptionsCategory : : OPTIONS ) ;
2020-07-19 03:47:05 -04:00
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 ) ;
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 ) ;
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 ) ;
argsman . AddArg ( " -stdinwalletpassphrase " , " Read wallet passphrase from standard input as a single line. When combined with -stdin, the first line from standard input is used for the wallet passphrase. " , ArgsManager : : ALLOW_ANY , OptionsCategory : : OPTIONS ) ;
2014-05-26 05:38:44 -04:00
}
2018-06-04 14:55:00 -04:00
/** libevent event log callback */
static void libevent_log_cb ( int severity , const char * msg )
{
# ifndef EVENT_LOG_ERR // EVENT_LOG_ERR was added in 2.0.19; but before then _EVENT_LOG_ERR existed.
# define EVENT_LOG_ERR _EVENT_LOG_ERR
# endif
// Ignore everything other than errors
if ( severity > = EVENT_LOG_ERR ) {
throw std : : runtime_error ( strprintf ( " libevent error: %s " , msg ) ) ;
}
}
2014-10-29 14:08:31 -03:00
//
// Exception thrown on connection error. This error is used to determine
// when to wait if -rpcwait is given.
//
class CConnectionFailed : public std : : runtime_error
{
public :
explicit inline CConnectionFailed ( const std : : string & msg ) :
std : : runtime_error ( msg )
{ }
} ;
2016-11-02 15:59:09 -03:00
//
// This function returns either one of EXIT_ codes when it's expected to stop the process or
// CONTINUE_EXECUTION when it's expected to continue further.
//
static int AppInitRPC ( int argc , char * argv [ ] )
2013-10-11 18:09:59 -03:00
{
2020-07-19 03:31:51 -04:00
SetupCliArgs ( gArgs ) ;
2018-04-28 20:40:51 -03:00
std : : string error ;
if ( ! gArgs . ParseParameters ( argc , argv , error ) ) {
2019-10-28 09:30:20 -03:00
tfm : : format ( std : : cerr , " Error parsing command line arguments: %s \n " , error ) ;
2018-04-28 20:40:51 -03:00
return EXIT_FAILURE ;
}
2018-03-30 17:47:36 -03:00
if ( argc < 2 | | HelpRequested ( gArgs ) | | gArgs . IsArgSet ( " -version " ) ) {
2018-05-08 12:31:21 -03:00
std : : string strUsage = PACKAGE_NAME " RPC client version " + FormatFullVersion ( ) + " \n " ;
2017-08-01 15:17:40 -04:00
if ( ! gArgs . IsArgSet ( " -version " ) ) {
2018-05-08 12:31:21 -03:00
strUsage + = " \n "
" Usage: bitcoin-cli [options] <command> [params] Send command to " PACKAGE_NAME " \n "
" or: bitcoin-cli [options] -named <command> [name=value]... Send command to " PACKAGE_NAME " (with named arguments) \n "
" or: bitcoin-cli [options] help List commands \n "
" or: bitcoin-cli [options] help <command> Get help for a command \n " ;
2018-04-28 17:54:58 -03:00
strUsage + = " \n " + gArgs . GetHelpMessage ( ) ;
2014-11-22 15:56:25 -03:00
}
2019-10-28 09:30:20 -03:00
tfm : : format ( std : : cout , " %s " , strUsage ) ;
2016-11-02 15:59:09 -03:00
if ( argc < 2 ) {
2019-06-13 09:16:10 -04:00
tfm : : format ( std : : cerr , " Error: too few parameters \n " ) ;
2016-11-02 15:59:09 -03:00
return EXIT_FAILURE ;
}
return EXIT_SUCCESS ;
2014-11-22 15:56:25 -03:00
}
2019-07-24 11:54:46 -04:00
if ( ! CheckDataDirOption ( ) ) {
2019-10-28 09:30:20 -03:00
tfm : : format ( std : : cerr , " Error: Specified data directory \" %s \" does not exist. \n " , gArgs . GetArg ( " -datadir " , " " ) ) ;
2016-11-02 15:59:09 -03:00
return EXIT_FAILURE ;
2013-10-11 18:09:59 -03:00
}
2018-04-28 20:40:51 -03:00
if ( ! gArgs . ReadConfigFiles ( error , true ) ) {
2019-10-28 09:30:20 -03:00
tfm : : format ( std : : cerr , " Error reading configuration file: %s \n " , error ) ;
2016-11-02 15:59:09 -03:00
return EXIT_FAILURE ;
2014-04-07 05:10:01 -03:00
}
2020-09-22 10:57:30 -03:00
// Check for chain settings (BaseParams() calls are only valid after this clause)
2015-05-25 04:00:17 -03:00
try {
2018-03-29 02:00:00 -03:00
SelectBaseParams ( gArgs . GetChainName ( ) ) ;
2015-10-27 13:39:42 -03:00
} catch ( const std : : exception & e ) {
2019-06-13 09:16:10 -04:00
tfm : : format ( std : : cerr , " Error: %s \n " , e . what ( ) ) ;
2016-11-02 15:59:09 -03:00
return EXIT_FAILURE ;
2013-11-28 13:28:27 -03:00
}
2016-11-02 15:59:09 -03:00
return CONTINUE_EXECUTION ;
2013-10-11 18:09:59 -03:00
}
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
/** Reply structure for request_done to fill in */
struct HTTPReply
2014-05-26 05:38:44 -04:00
{
2016-09-14 10:08:34 -03:00
HTTPReply ( ) : status ( 0 ) , error ( - 1 ) { }
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
int status ;
2016-09-14 10:08:34 -03:00
int error ;
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
std : : string body ;
} ;
2020-05-18 04:14:10 -04:00
static std : : string http_errorstring ( int code )
2016-09-14 10:08:34 -03:00
{
switch ( code ) {
# if LIBEVENT_VERSION_NUMBER >= 0x02010300
case EVREQ_HTTP_TIMEOUT :
return " timeout reached " ;
case EVREQ_HTTP_EOF :
return " EOF reached " ;
case EVREQ_HTTP_INVALID_HEADER :
return " error while reading header, or invalid header " ;
case EVREQ_HTTP_BUFFER_ERROR :
return " error encountered while reading or writing " ;
case EVREQ_HTTP_REQUEST_CANCEL :
return " request was canceled " ;
case EVREQ_HTTP_DATA_TOO_LONG :
return " response body is larger than allowed " ;
# endif
default :
return " unknown " ;
}
}
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
static void http_request_done ( struct evhttp_request * req , void * ctx )
{
HTTPReply * reply = static_cast < HTTPReply * > ( ctx ) ;
2017-08-07 01:36:37 -04:00
if ( req = = nullptr ) {
/* If req is nullptr, it means an error occurred while connecting: the
2016-09-14 10:08:34 -03:00
* error code will have been passed to http_error_cb .
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
*/
reply - > status = 0 ;
return ;
}
2014-05-26 05:38:44 -04:00
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
reply - > status = evhttp_request_get_response_code ( req ) ;
struct evbuffer * buf = evhttp_request_get_input_buffer ( req ) ;
if ( buf )
{
size_t size = evbuffer_get_length ( buf ) ;
const char * data = ( const char * ) evbuffer_pullup ( buf , size ) ;
if ( data )
reply - > body = std : : string ( data , size ) ;
evbuffer_drain ( buf , size ) ;
}
}
2016-09-14 10:08:34 -03:00
# if LIBEVENT_VERSION_NUMBER >= 0x02010300
static void http_error_cb ( enum evhttp_request_error err , void * ctx )
{
HTTPReply * reply = static_cast < HTTPReply * > ( ctx ) ;
reply - > error = err ;
}
# endif
2016-09-29 11:45:19 -03:00
/** Class that handles the conversion from a command-line to a JSON-RPC request,
* as well as converting back to a JSON object that can be shown as result .
*/
class BaseRequestHandler
{
public :
2017-12-29 12:20:28 -03:00
virtual ~ BaseRequestHandler ( ) { }
2016-09-29 11:45:19 -03:00
virtual UniValue PrepareRequest ( const std : : string & method , const std : : vector < std : : string > & args ) = 0 ;
virtual UniValue ProcessReply ( const UniValue & batch_in ) = 0 ;
} ;
2021-04-01 05:46:20 -03:00
/** Process addrinfo requests */
class AddrinfoRequestHandler : public BaseRequestHandler
{
private :
2021-04-20 04:19:31 -04:00
static constexpr std : : array m_networks { " ipv4 " , " ipv6 " , " torv2 " , " torv3 " , " i2p " } ;
2021-04-01 05:46:20 -03:00
int8_t NetworkStringToId ( const std : : string & str ) const
{
2021-04-20 04:19:31 -04:00
for ( size_t i = 0 ; i < m_networks . size ( ) ; + + i ) {
2021-04-01 05:46:20 -03:00
if ( str = = m_networks . at ( i ) ) return i ;
}
return UNKNOWN_NETWORK ;
}
public :
UniValue PrepareRequest ( const std : : string & method , const std : : vector < std : : string > & args ) override
{
if ( ! args . empty ( ) ) {
throw std : : runtime_error ( " -addrinfo takes no arguments " ) ;
}
UniValue params { RPCConvertValues ( " getnodeaddresses " , std : : vector < std : : string > { { " 0 " } } ) } ;
return JSONRPCRequestObj ( " getnodeaddresses " , params , 1 ) ;
}
UniValue ProcessReply ( const UniValue & reply ) override
{
2021-04-09 03:40:57 -04:00
if ( ! reply [ " error " ] . isNull ( ) ) return reply ;
const std : : vector < UniValue > & nodes { reply [ " result " ] . getValues ( ) } ;
if ( ! nodes . empty ( ) & & nodes . at ( 0 ) [ " network " ] . isNull ( ) ) {
throw std : : runtime_error ( " -addrinfo requires bitcoind server to be running v22.0 and up " ) ;
}
2021-04-01 05:46:20 -03:00
// Count the number of peers we know by network, including torv2 versus torv3.
2021-04-20 04:19:31 -04:00
std : : array < uint64_t , m_networks . size ( ) > counts { { } } ;
2021-04-09 03:40:57 -04:00
for ( const UniValue & node : nodes ) {
2021-04-01 05:46:20 -03:00
std : : string network_name { node [ " network " ] . get_str ( ) } ;
if ( network_name = = " onion " ) {
network_name = node [ " address " ] . get_str ( ) . size ( ) > 22 ? " torv3 " : " torv2 " ;
}
const int8_t network_id { NetworkStringToId ( network_name ) } ;
if ( network_id = = UNKNOWN_NETWORK ) continue ;
+ + counts . at ( network_id ) ;
}
// Prepare result to return to user.
UniValue result { UniValue : : VOBJ } , addresses { UniValue : : VOBJ } ;
uint64_t total { 0 } ; // Total address count
2021-04-20 04:19:31 -04:00
for ( size_t i = 0 ; i < m_networks . size ( ) ; + + i ) {
2021-04-01 05:46:20 -03:00
addresses . pushKV ( m_networks . at ( i ) , counts . at ( i ) ) ;
total + = counts . at ( i ) ;
}
addresses . pushKV ( " total " , total ) ;
result . pushKV ( " addresses_known " , addresses ) ;
return JSONRPCReplyObj ( result , NullUniValue , 1 ) ;
}
} ;
2016-09-29 11:45:19 -03:00
/** Process getinfo requests */
class GetinfoRequestHandler : public BaseRequestHandler
{
public :
const int ID_NETWORKINFO = 0 ;
const int ID_BLOCKCHAININFO = 1 ;
const int ID_WALLETINFO = 2 ;
2020-03-27 19:12:38 -03:00
const int ID_BALANCES = 3 ;
2016-09-29 11:45:19 -03:00
/** Create a simulated `getinfo` request. */
UniValue PrepareRequest ( const std : : string & method , const std : : vector < std : : string > & args ) override
{
2017-11-17 10:11:02 -03:00
if ( ! args . empty ( ) ) {
throw std : : runtime_error ( " -getinfo takes no arguments " ) ;
}
2016-09-29 11:45:19 -03:00
UniValue result ( UniValue : : VARR ) ;
result . push_back ( JSONRPCRequestObj ( " getnetworkinfo " , NullUniValue , ID_NETWORKINFO ) ) ;
result . push_back ( JSONRPCRequestObj ( " getblockchaininfo " , NullUniValue , ID_BLOCKCHAININFO ) ) ;
result . push_back ( JSONRPCRequestObj ( " getwalletinfo " , NullUniValue , ID_WALLETINFO ) ) ;
2020-03-27 19:12:38 -03:00
result . push_back ( JSONRPCRequestObj ( " getbalances " , NullUniValue , ID_BALANCES ) ) ;
2016-09-29 11:45:19 -03:00
return result ;
}
/** Collect values from the batch and form a simulated `getinfo` reply. */
UniValue ProcessReply ( const UniValue & batch_in ) override
{
UniValue result ( UniValue : : VOBJ ) ;
2020-04-12 15:46:16 -04:00
const std : : vector < UniValue > batch = JSONRPCProcessBatchReply ( batch_in ) ;
2020-03-27 19:12:38 -03:00
// Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass them on;
// getwalletinfo() and getbalances() are allowed to fail if there is no wallet.
2016-09-29 11:45:19 -03:00
if ( ! batch [ ID_NETWORKINFO ] [ " error " ] . isNull ( ) ) {
return batch [ ID_NETWORKINFO ] ;
}
if ( ! batch [ ID_BLOCKCHAININFO ] [ " error " ] . isNull ( ) ) {
return batch [ ID_BLOCKCHAININFO ] ;
}
result . pushKV ( " version " , batch [ ID_NETWORKINFO ] [ " result " ] [ " version " ] ) ;
result . pushKV ( " blocks " , batch [ ID_BLOCKCHAININFO ] [ " result " ] [ " blocks " ] ) ;
2019-10-29 15:29:13 -03:00
result . pushKV ( " headers " , batch [ ID_BLOCKCHAININFO ] [ " result " ] [ " headers " ] ) ;
result . pushKV ( " verificationprogress " , batch [ ID_BLOCKCHAININFO ] [ " result " ] [ " verificationprogress " ] ) ;
2016-09-29 11:45:19 -03:00
result . pushKV ( " timeoffset " , batch [ ID_NETWORKINFO ] [ " result " ] [ " timeoffset " ] ) ;
2020-06-29 04:05:15 -04:00
UniValue connections ( UniValue : : VOBJ ) ;
connections . pushKV ( " in " , batch [ ID_NETWORKINFO ] [ " result " ] [ " connections_in " ] ) ;
connections . pushKV ( " out " , batch [ ID_NETWORKINFO ] [ " result " ] [ " connections_out " ] ) ;
connections . pushKV ( " total " , batch [ ID_NETWORKINFO ] [ " result " ] [ " connections " ] ) ;
result . pushKV ( " connections " , connections ) ;
2016-09-29 11:45:19 -03:00
result . pushKV ( " proxy " , batch [ ID_NETWORKINFO ] [ " result " ] [ " networks " ] [ 0 ] [ " proxy " ] ) ;
result . pushKV ( " difficulty " , batch [ ID_BLOCKCHAININFO ] [ " result " ] [ " difficulty " ] ) ;
2019-03-09 05:15:17 -03:00
result . pushKV ( " chain " , UniValue ( batch [ ID_BLOCKCHAININFO ] [ " result " ] [ " chain " ] ) ) ;
2019-11-04 16:39:34 -03:00
if ( ! batch [ ID_WALLETINFO ] [ " result " ] . isNull ( ) ) {
2021-05-02 04:31:52 -04:00
result . pushKV ( " has_wallet " , true ) ;
2016-09-29 11:45:19 -03:00
result . pushKV ( " keypoolsize " , batch [ ID_WALLETINFO ] [ " result " ] [ " keypoolsize " ] ) ;
2021-05-02 04:31:52 -04:00
result . pushKV ( " walletname " , batch [ ID_WALLETINFO ] [ " result " ] [ " walletname " ] ) ;
2016-09-29 11:45:19 -03:00
if ( ! batch [ ID_WALLETINFO ] [ " result " ] [ " unlocked_until " ] . isNull ( ) ) {
result . pushKV ( " unlocked_until " , batch [ ID_WALLETINFO ] [ " result " ] [ " unlocked_until " ] ) ;
}
result . pushKV ( " paytxfee " , batch [ ID_WALLETINFO ] [ " result " ] [ " paytxfee " ] ) ;
}
2020-03-27 19:12:38 -03:00
if ( ! batch [ ID_BALANCES ] [ " result " ] . isNull ( ) ) {
result . pushKV ( " balance " , batch [ ID_BALANCES ] [ " result " ] [ " mine " ] [ " trusted " ] ) ;
}
2016-09-29 11:45:19 -03:00
result . pushKV ( " relayfee " , batch [ ID_NETWORKINFO ] [ " result " ] [ " relayfee " ] ) ;
result . pushKV ( " warnings " , batch [ ID_NETWORKINFO ] [ " result " ] [ " warnings " ] ) ;
return JSONRPCReplyObj ( result , NullUniValue , 1 ) ;
}
} ;
2020-07-27 02:20:26 -04:00
/** Process netinfo requests */
class NetinfoRequestHandler : public BaseRequestHandler
{
private :
2021-02-15 16:01:52 -03:00
static constexpr uint8_t MAX_DETAIL_LEVEL { 4 } ;
2021-04-20 04:19:31 -04:00
static constexpr std : : array m_networks { " ipv4 " , " ipv6 " , " onion " , " i2p " } ;
std : : array < std : : array < uint16_t , m_networks . size ( ) + 1 > , 3 > m_counts { { { } } } ; //!< Peer counts by (in/out/total, networks/total)
2021-02-02 11:03:05 -03:00
uint8_t m_block_relay_peers_count { 0 } ;
2020-12-24 14:42:06 -03:00
uint8_t m_manual_peers_count { 0 } ;
2020-10-02 17:19:52 -03:00
int8_t NetworkStringToId ( const std : : string & str ) const
{
2021-04-20 04:19:31 -04:00
for ( size_t i = 0 ; i < m_networks . size ( ) ; + + i ) {
2020-10-02 17:19:52 -03:00
if ( str = = m_networks . at ( i ) ) return i ;
}
return UNKNOWN_NETWORK ;
}
2021-01-07 12:27:46 -03:00
uint8_t m_details_level { 0 } ; //!< Optional user-supplied arg to set dashboard details level
2020-08-29 06:20:37 -04:00
bool DetailsRequested ( ) const { return m_details_level > 0 & & m_details_level < 5 ; }
bool IsAddressSelected ( ) const { return m_details_level = = 2 | | m_details_level = = 4 ; }
bool IsVersionSelected ( ) const { return m_details_level = = 3 | | m_details_level = = 4 ; }
2020-10-02 17:57:40 -03:00
bool m_is_asmap_on { false } ;
size_t m_max_addr_length { 0 } ;
2020-12-24 16:03:50 -03:00
size_t m_max_age_length { 3 } ;
2020-10-02 17:57:40 -03:00
size_t m_max_id_length { 2 } ;
2020-08-13 10:59:57 -04:00
struct Peer {
2020-09-19 15:59:25 -03:00
std : : string addr ;
std : : string sub_version ;
2020-12-24 14:08:08 -03:00
std : : string conn_type ;
2020-09-19 15:59:25 -03:00
std : : string network ;
2020-10-16 06:59:27 -03:00
std : : string age ;
2020-09-19 15:59:25 -03:00
double min_ping ;
double ping ;
2020-08-28 08:03:06 -04:00
int64_t last_blck ;
2020-08-13 10:59:57 -04:00
int64_t last_recv ;
int64_t last_send ;
2020-08-28 08:03:06 -04:00
int64_t last_trxn ;
2020-09-19 15:59:25 -03:00
int id ;
int mapped_as ;
int version ;
2020-12-24 16:03:50 -03:00
bool is_bip152_hb_from ;
bool is_bip152_hb_to ;
2020-08-13 10:59:57 -04:00
bool is_block_relay ;
bool is_outbound ;
bool operator < ( const Peer & rhs ) const { return std : : tie ( is_outbound , min_ping ) < std : : tie ( rhs . is_outbound , rhs . min_ping ) ; }
} ;
2020-10-02 17:57:40 -03:00
std : : vector < Peer > m_peers ;
2020-08-13 10:29:10 -04:00
std : : string ChainToString ( ) const
{
if ( gArgs . GetChainName ( ) = = CBaseChainParams : : TESTNET ) return " testnet " ;
2020-09-19 15:59:25 -03:00
if ( gArgs . GetChainName ( ) = = CBaseChainParams : : SIGNET ) return " signet " ;
2020-08-13 10:29:10 -04:00
if ( gArgs . GetChainName ( ) = = CBaseChainParams : : REGTEST ) return " regtest " ;
return " " ;
}
2020-10-25 11:11:41 -03:00
std : : string PingTimeToString ( double seconds ) const
{
if ( seconds < 0 ) return " " ;
const double milliseconds { round ( 1000 * seconds ) } ;
return milliseconds > 999999 ? " - " : ToString ( milliseconds ) ;
}
2020-12-24 14:09:02 -03:00
std : : string ConnectionTypeForNetinfo ( const std : : string & conn_type ) const
{
if ( conn_type = = " outbound-full-relay " ) return " full " ;
if ( conn_type = = " block-relay-only " ) return " block " ;
if ( conn_type = = " manual " | | conn_type = = " feeler " ) return conn_type ;
if ( conn_type = = " addr-fetch " ) return " addr " ;
return " " ;
}
2021-03-30 04:19:01 -03:00
const int64_t m_time_now { GetTimeSeconds ( ) } ;
2020-10-02 17:57:40 -03:00
2020-07-27 02:20:26 -04:00
public :
2020-09-23 05:53:33 -03:00
static constexpr int ID_PEERINFO = 0 ;
static constexpr int ID_NETWORKINFO = 1 ;
2020-07-27 02:20:26 -04:00
UniValue PrepareRequest ( const std : : string & method , const std : : vector < std : : string > & args ) override
{
if ( ! args . empty ( ) ) {
2020-08-29 05:28:48 -04:00
uint8_t n { 0 } ;
if ( ParseUInt8 ( args . at ( 0 ) , & n ) ) {
2021-02-15 16:01:52 -03:00
m_details_level = std : : min ( n , MAX_DETAIL_LEVEL ) ;
2020-12-26 16:18:26 -03:00
} else {
2021-01-07 09:51:28 -03:00
throw std : : runtime_error ( strprintf ( " invalid -netinfo argument: %s \n For more information, run: bitcoin-cli -netinfo help " , args . at ( 0 ) ) ) ;
2020-08-29 05:28:48 -04:00
}
2020-07-27 02:20:26 -04:00
}
UniValue result ( UniValue : : VARR ) ;
result . push_back ( JSONRPCRequestObj ( " getpeerinfo " , NullUniValue , ID_PEERINFO ) ) ;
result . push_back ( JSONRPCRequestObj ( " getnetworkinfo " , NullUniValue , ID_NETWORKINFO ) ) ;
return result ;
}
UniValue ProcessReply ( const UniValue & batch_in ) override
{
const std : : vector < UniValue > batch { JSONRPCProcessBatchReply ( batch_in ) } ;
if ( ! batch [ ID_PEERINFO ] [ " error " ] . isNull ( ) ) return batch [ ID_PEERINFO ] ;
if ( ! batch [ ID_NETWORKINFO ] [ " error " ] . isNull ( ) ) return batch [ ID_NETWORKINFO ] ;
2020-08-13 10:19:27 -04:00
2020-08-30 06:38:40 -04:00
const UniValue & networkinfo { batch [ ID_NETWORKINFO ] [ " result " ] } ;
if ( networkinfo [ " version " ] . get_int ( ) < 209900 ) {
throw std : : runtime_error ( " -netinfo requires bitcoind server to be running v0.21.0 and up " ) ;
}
2020-08-29 05:28:48 -04:00
// Count peer connection totals, and if DetailsRequested(), store peer data in a vector of structs.
2020-10-02 17:19:52 -03:00
for ( const UniValue & peer : batch [ ID_PEERINFO ] [ " result " ] . getValues ( ) ) {
2020-09-23 05:53:33 -03:00
const std : : string network { peer [ " network " ] . get_str ( ) } ;
2020-10-02 17:19:52 -03:00
const int8_t network_id { NetworkStringToId ( network ) } ;
if ( network_id = = UNKNOWN_NETWORK ) continue ;
const bool is_outbound { ! peer [ " inbound " ] . get_bool ( ) } ;
const bool is_block_relay { ! peer [ " relaytxes " ] . get_bool ( ) } ;
2020-12-24 14:08:08 -03:00
const std : : string conn_type { peer [ " connection_type " ] . get_str ( ) } ;
2021-04-20 04:19:31 -04:00
+ + m_counts . at ( is_outbound ) . at ( network_id ) ; // in/out by network
+ + m_counts . at ( is_outbound ) . at ( m_networks . size ( ) ) ; // in/out overall
+ + m_counts . at ( 2 ) . at ( network_id ) ; // total by network
+ + m_counts . at ( 2 ) . at ( m_networks . size ( ) ) ; // total overall
2021-02-02 11:03:05 -03:00
if ( conn_type = = " block-relay-only " ) + + m_block_relay_peers_count ;
2020-12-24 14:42:06 -03:00
if ( conn_type = = " manual " ) + + m_manual_peers_count ;
2020-08-29 05:28:48 -04:00
if ( DetailsRequested ( ) ) {
2020-08-13 10:59:57 -04:00
// Push data for this peer to the peers vector.
const int peer_id { peer [ " id " ] . get_int ( ) } ;
2020-09-23 05:53:33 -03:00
const int mapped_as { peer [ " mapped_as " ] . isNull ( ) ? 0 : peer [ " mapped_as " ] . get_int ( ) } ;
2020-08-13 10:59:57 -04:00
const int version { peer [ " version " ] . get_int ( ) } ;
const int64_t conn_time { peer [ " conntime " ] . get_int64 ( ) } ;
2020-08-28 08:03:06 -04:00
const int64_t last_blck { peer [ " last_block " ] . get_int64 ( ) } ;
2020-08-13 10:59:57 -04:00
const int64_t last_recv { peer [ " lastrecv " ] . get_int64 ( ) } ;
const int64_t last_send { peer [ " lastsend " ] . get_int64 ( ) } ;
2020-08-28 08:03:06 -04:00
const int64_t last_trxn { peer [ " last_transaction " ] . get_int64 ( ) } ;
2020-08-13 10:59:57 -04:00
const double min_ping { peer [ " minping " ] . isNull ( ) ? - 1 : peer [ " minping " ] . get_real ( ) } ;
const double ping { peer [ " pingtime " ] . isNull ( ) ? - 1 : peer [ " pingtime " ] . get_real ( ) } ;
2020-09-23 05:53:33 -03:00
const std : : string addr { peer [ " addr " ] . get_str ( ) } ;
2020-10-16 06:59:27 -03:00
const std : : string age { conn_time = = 0 ? " " : ToString ( ( m_time_now - conn_time ) / 60 ) } ;
2020-09-23 05:53:33 -03:00
const std : : string sub_version { peer [ " subver " ] . get_str ( ) } ;
2020-12-24 16:03:50 -03:00
const bool is_bip152_hb_from { peer [ " bip152_hb_from " ] . get_bool ( ) } ;
const bool is_bip152_hb_to { peer [ " bip152_hb_to " ] . get_bool ( ) } ;
m_peers . push_back ( { addr , sub_version , conn_type , network , age , min_ping , ping , last_blck , last_recv , last_send , last_trxn , peer_id , mapped_as , version , is_bip152_hb_from , is_bip152_hb_to , is_block_relay , is_outbound } ) ;
2020-10-02 17:57:40 -03:00
m_max_addr_length = std : : max ( addr . length ( ) + 1 , m_max_addr_length ) ;
2020-10-16 06:59:27 -03:00
m_max_age_length = std : : max ( age . length ( ) , m_max_age_length ) ;
m_max_id_length = std : : max ( ToString ( peer_id ) . length ( ) , m_max_id_length ) ;
2020-10-02 17:57:40 -03:00
m_is_asmap_on | = ( mapped_as ! = 0 ) ;
2020-08-13 10:59:57 -04:00
}
2020-08-13 10:19:27 -04:00
}
2020-08-13 10:29:10 -04:00
// Generate report header.
std : : string result { strprintf ( " %s %s%s - %i%s \n \n " , PACKAGE_NAME , FormatFullVersion ( ) , ChainToString ( ) , networkinfo [ " protocolversion " ] . get_int ( ) , networkinfo [ " subversion " ] . get_str ( ) ) } ;
2020-08-13 11:13:14 -04:00
// Report detailed peer connections list sorted by direction and minimum ping time.
2020-10-02 17:57:40 -03:00
if ( DetailsRequested ( ) & & ! m_peers . empty ( ) ) {
std : : sort ( m_peers . begin ( ) , m_peers . end ( ) ) ;
2020-12-24 16:03:50 -03:00
result + = strprintf ( " <-> type net mping ping send recv txn blk hb %*s " , m_max_age_length , " age " ) ;
2020-10-02 17:57:40 -03:00
if ( m_is_asmap_on ) result + = " asmap " ;
result + = strprintf ( " %*s %-*s%s \n " , m_max_id_length , " id " , IsAddressSelected ( ) ? m_max_addr_length : 0 , IsAddressSelected ( ) ? " address " : " " , IsVersionSelected ( ) ? " version " : " " ) ;
for ( const Peer & peer : m_peers ) {
2020-08-13 11:13:14 -04:00
std : : string version { ToString ( peer . version ) + peer . sub_version } ;
result + = strprintf (
2020-12-24 16:03:50 -03:00
" %3s %6s %5s%7s%7s%5s%5s%5s%5s %2s %*s%*i %*s %-*s%s \n " ,
2020-08-13 11:13:14 -04:00
peer . is_outbound ? " out " : " in " ,
2020-12-24 14:08:08 -03:00
ConnectionTypeForNetinfo ( peer . conn_type ) ,
2020-09-23 05:53:33 -03:00
peer . network ,
2020-10-25 11:11:41 -03:00
PingTimeToString ( peer . min_ping ) ,
PingTimeToString ( peer . ping ) ,
2020-10-02 17:57:40 -03:00
peer . last_send = = 0 ? " " : ToString ( m_time_now - peer . last_send ) ,
peer . last_recv = = 0 ? " " : ToString ( m_time_now - peer . last_recv ) ,
peer . last_trxn = = 0 ? " " : ToString ( ( m_time_now - peer . last_trxn ) / 60 ) ,
peer . last_blck = = 0 ? " " : ToString ( ( m_time_now - peer . last_blck ) / 60 ) ,
2020-12-24 16:03:50 -03:00
strprintf ( " %s%s " , peer . is_bip152_hb_to ? " . " : " " , peer . is_bip152_hb_from ? " * " : " " ) ,
2020-10-16 06:59:27 -03:00
m_max_age_length , // variable spacing
peer . age ,
2020-10-02 17:57:40 -03:00
m_is_asmap_on ? 7 : 0 , // variable spacing
m_is_asmap_on & & peer . mapped_as ! = 0 ? ToString ( peer . mapped_as ) : " " ,
m_max_id_length , // variable spacing
2020-08-13 11:13:14 -04:00
peer . id ,
2020-10-02 17:57:40 -03:00
IsAddressSelected ( ) ? m_max_addr_length : 0 , // variable spacing
2020-08-29 06:20:37 -04:00
IsAddressSelected ( ) ? peer . addr : " " ,
IsVersionSelected ( ) & & version ! = " 0 " ? version : " " ) ;
2020-08-13 11:13:14 -04:00
}
2020-12-24 16:03:50 -03:00
result + = strprintf ( " ms ms sec sec min min %*s \n \n " , m_max_age_length , " min " ) ;
2020-08-13 11:13:14 -04:00
}
2020-08-13 10:25:04 -04:00
// Report peer connection totals by type.
2020-11-03 18:47:30 -03:00
result + = " ipv4 ipv6 onion " ;
2021-02-05 12:01:43 -03:00
const bool any_i2p_peers = m_counts . at ( 2 ) . at ( 3 ) ; // false if total i2p peers count is 0, otherwise true
if ( any_i2p_peers ) result + = " i2p " ;
2020-11-03 18:47:30 -03:00
result + = " total block " ;
2020-12-24 14:42:06 -03:00
if ( m_manual_peers_count ) result + = " manual " ;
2021-04-20 04:19:31 -04:00
const std : : array rows { " in " , " out " , " total " } ;
2020-11-03 18:47:30 -03:00
for ( uint8_t i = 0 ; i < 3 ; + + i ) {
result + = strprintf ( " \n %-5s %5i %5i %5i " , rows . at ( i ) , m_counts . at ( i ) . at ( 0 ) , m_counts . at ( i ) . at ( 1 ) , m_counts . at ( i ) . at ( 2 ) ) ; // ipv4/ipv6/onion peers counts
2021-02-05 12:01:43 -03:00
if ( any_i2p_peers ) result + = strprintf ( " %5i " , m_counts . at ( i ) . at ( 3 ) ) ; // i2p peers count
2021-04-20 04:19:31 -04:00
result + = strprintf ( " %5i " , m_counts . at ( i ) . at ( m_networks . size ( ) ) ) ; // total peers count
2021-02-02 11:03:05 -03:00
if ( i = = 1 ) { // the outbound row has two extra columns for block relay and manual peer counts
result + = strprintf ( " %5i " , m_block_relay_peers_count ) ;
if ( m_manual_peers_count ) result + = strprintf ( " %5i " , m_manual_peers_count ) ;
}
2020-10-02 17:19:52 -03:00
}
2020-08-13 10:25:04 -04:00
2020-08-13 10:51:22 -04:00
// Report local addresses, ports, and scores.
2020-12-24 14:42:06 -03:00
result + = " \n \n Local addresses " ;
2020-10-25 11:07:01 -03:00
const std : : vector < UniValue > & local_addrs { networkinfo [ " localaddresses " ] . getValues ( ) } ;
2020-08-13 10:51:22 -04:00
if ( local_addrs . empty ( ) ) {
result + = " : n/a \n " ;
} else {
2020-10-25 11:07:01 -03:00
size_t max_addr_size { 0 } ;
for ( const UniValue & addr : local_addrs ) {
max_addr_size = std : : max ( addr [ " address " ] . get_str ( ) . length ( ) + 1 , max_addr_size ) ;
}
for ( const UniValue & addr : local_addrs ) {
result + = strprintf ( " \n %-*s port %6i score %6i " , max_addr_size , addr [ " address " ] . get_str ( ) , addr [ " port " ] . get_int ( ) , addr [ " score " ] . get_int ( ) ) ;
2020-08-13 10:51:22 -04:00
}
}
2020-07-27 02:20:26 -04:00
return JSONRPCReplyObj ( UniValue { result } , NullUniValue , 1 ) ;
}
2021-01-07 12:27:46 -03:00
const std : : string m_help_doc {
" -netinfo level| \" help \" \n \n "
" Returns a network peer connections dashboard with information from the remote server. \n "
2021-01-07 12:44:02 -03:00
" This human-readable interface will change regularly and is not intended to be a stable API. \n "
2021-01-07 12:27:46 -03:00
" Under the hood, -netinfo fetches the data by calling getpeerinfo and getnetworkinfo. \n "
2021-02-17 11:02:55 -03:00
+ strprintf ( " An optional integer argument from 0 to %d can be passed for different peers listings; %d to 255 are parsed as %d. \n " , MAX_DETAIL_LEVEL , MAX_DETAIL_LEVEL , MAX_DETAIL_LEVEL ) +
2021-01-07 12:27:46 -03:00
" Pass \" help \" to see this detailed help documentation. \n "
" If more than one argument is passed, only the first one is read and parsed. \n "
" Suggestion: use with the Linux watch(1) command for a live dashboard; see example below. \n \n "
" Arguments: \n "
2021-02-17 11:02:55 -03:00
+ strprintf ( " 1. level (integer 0-%d, optional) Specify the info level of the peers dashboard (default 0): \n " , MAX_DETAIL_LEVEL ) +
2021-01-07 12:27:46 -03:00
" 0 - Connection counts and local addresses \n "
" 1 - Like 0 but with a peers listing (without address or version columns) \n "
" 2 - Like 1 but with an address column \n "
" 3 - Like 1 but with a version column \n "
" 4 - Like 1 but with both address and version columns \n "
" 2. help (string \" help \" , optional) Print this help documentation instead of the dashboard. \n \n "
" Result: \n \n "
2021-02-17 11:02:55 -03:00
+ strprintf ( " * The peers listing in levels 1-%d displays all of the peers sorted by direction and minimum ping time: \n \n " , MAX_DETAIL_LEVEL ) +
2021-01-07 12:27:46 -03:00
" Column Description \n "
" ------ ----------- \n "
" <-> Direction \n "
" \" in \" - inbound connections are those initiated by the peer \n "
" \" out \" - outbound connections are those initiated by us \n "
" type Type of peer connection \n "
" \" full \" - full relay, the default \n "
" \" block \" - block relay; like full relay but does not relay transactions or addresses \n "
" \" manual \" - peer we manually added using RPC addnode or the -addnode/-connect config options \n "
" \" feeler \" - short-lived connection for testing addresses \n "
" \" addr \" - address fetch; short-lived connection for requesting addresses \n "
" net Network the peer connected through ( \" ipv4 \" , \" ipv6 \" , \" onion \" , \" i2p \" , or \" cjdns \" ) \n "
" mping Minimum observed ping time, in milliseconds (ms) \n "
" ping Last observed ping time, in milliseconds (ms) \n "
" send Time since last message sent to the peer, in seconds \n "
" recv Time since last message received from the peer, in seconds \n "
" txn Time since last novel transaction received from the peer and accepted into our mempool, in minutes \n "
" blk Time since last novel block passing initial validity checks received from the peer, in minutes \n "
" hb High-bandwidth BIP152 compact block relay \n "
" \" . \" (to) - we selected the peer as a high-bandwidth peer \n "
" \" * \" (from) - the peer selected us as a high-bandwidth peer \n "
" age Duration of connection to the peer, in minutes \n "
" asmap Mapped AS (Autonomous System) number in the BGP route to the peer, used for diversifying \n "
" peer selection (only displayed if the -asmap config option is set) \n "
" id Peer index, in increasing order of peer connections since node startup \n "
" address IP address and port of the peer \n "
" version Peer version and subversion concatenated, e.g. \" 70016/Satoshi:21.0.0/ \" \n \n "
" * The connection counts table displays the number of peers by direction, network, and the totals \n "
" for each, as well as two special outbound columns for block relay peers and manual peers. \n \n "
" * The local addresses table lists each local address broadcast by the node, the port, and the score. \n \n "
" Examples: \n \n "
" Connection counts and local addresses only \n "
" > bitcoin-cli -netinfo \n \n "
" Compact peers listing \n "
" > bitcoin-cli -netinfo 1 \n \n "
" Full dashboard \n "
2021-02-17 11:02:55 -03:00
+ strprintf ( " > bitcoin-cli -netinfo %d \n \n " , MAX_DETAIL_LEVEL ) +
2021-01-07 12:27:46 -03:00
" Full live dashboard, adjust --interval or --no-title as needed (Linux) \n "
2021-02-17 11:02:55 -03:00
+ strprintf ( " > watch --interval 1 --no-title bitcoin-cli -netinfo %d \n \n " , MAX_DETAIL_LEVEL ) +
2021-01-07 12:27:46 -03:00
" See this help \n "
" > bitcoin-cli -netinfo help \n " } ;
2020-07-27 02:20:26 -04:00
} ;
2019-12-09 15:52:12 -03:00
/** Process RPC generatetoaddress request. */
class GenerateToAddressRequestHandler : public BaseRequestHandler
{
public :
UniValue PrepareRequest ( const std : : string & method , const std : : vector < std : : string > & args ) override
{
address_str = args . at ( 1 ) ;
UniValue params { RPCConvertValues ( " generatetoaddress " , args ) } ;
return JSONRPCRequestObj ( " generatetoaddress " , params , 1 ) ;
}
UniValue ProcessReply ( const UniValue & reply ) override
{
UniValue result ( UniValue : : VOBJ ) ;
result . pushKV ( " address " , address_str ) ;
result . pushKV ( " blocks " , reply . get_obj ( ) [ " result " ] ) ;
return JSONRPCReplyObj ( result , NullUniValue , 1 ) ;
}
protected :
std : : string address_str ;
} ;
2016-09-29 11:45:19 -03:00
/** Process default single requests */
class DefaultRequestHandler : public BaseRequestHandler {
public :
UniValue PrepareRequest ( const std : : string & method , const std : : vector < std : : string > & args ) override
{
UniValue params ;
if ( gArgs . GetBoolArg ( " -named " , DEFAULT_NAMED ) ) {
params = RPCConvertNamedValues ( method , args ) ;
} else {
params = RPCConvertValues ( method , args ) ;
}
return JSONRPCRequestObj ( method , params , 1 ) ;
}
UniValue ProcessReply ( const UniValue & reply ) override
{
return reply . get_obj ( ) ;
}
} ;
2021-03-14 23:41:30 -03:00
static UniValue CallRPC ( BaseRequestHandler * rh , const std : : string & strMethod , const std : : vector < std : : string > & args , const std : : optional < std : : string > & rpcwallet = { } )
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
{
2017-07-12 16:59:09 -04:00
std : : string host ;
// In preference order, we choose the following for the port:
// 1. -rpcport
// 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
// 3. default port for chain
2021-03-01 17:35:28 -03:00
uint16_t port { BaseParams ( ) . RPCPort ( ) } ;
2017-08-01 15:17:40 -04:00
SplitHostPort ( gArgs . GetArg ( " -rpcconnect " , DEFAULT_RPCCONNECT ) , port , host ) ;
2021-03-01 17:35:28 -03:00
port = static_cast < uint16_t > ( gArgs . GetArg ( " -rpcport " , port ) ) ;
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
2016-12-20 08:46:11 -03:00
// Obtain event base
raii_event_base base = obtain_event_base ( ) ;
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
// Synchronously look up hostname
2016-12-20 08:46:11 -03:00
raii_evhttp_connection evcon = obtain_evhttp_connection_base ( base . get ( ) , host , port ) ;
2019-10-13 19:19:47 -03:00
// Set connection timeout
{
const int timeout = gArgs . GetArg ( " -rpcclienttimeout " , DEFAULT_HTTP_CLIENT_TIMEOUT ) ;
if ( timeout > 0 ) {
evhttp_connection_set_timeout ( evcon . get ( ) , timeout ) ;
} else {
// Indefinite request timeouts are not possible in libevent-http, so we
// set the timeout to a very long time period instead.
constexpr int YEAR_IN_SECONDS = 31556952 ; // Average length of year in Gregorian calendar
evhttp_connection_set_timeout ( evcon . get ( ) , 5 * YEAR_IN_SECONDS ) ;
}
}
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
HTTPReply response ;
2016-12-20 08:46:11 -03:00
raii_evhttp_request req = obtain_evhttp_request ( http_request_done , ( void * ) & response ) ;
2017-08-07 01:36:37 -04:00
if ( req = = nullptr )
2016-11-25 05:17:57 -03:00
throw std : : runtime_error ( " create http request failed " ) ;
2016-09-14 10:08:34 -03:00
# if LIBEVENT_VERSION_NUMBER >= 0x02010300
2016-12-20 08:46:11 -03:00
evhttp_request_set_error_cb ( req . get ( ) , http_error_cb ) ;
2016-09-14 10:08:34 -03:00
# endif
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
// Get credentials
2015-07-07 09:53:48 -03:00
std : : string strRPCUserColonPass ;
2018-03-09 02:09:57 -03:00
bool failedToGetAuthCookie = false ;
2017-08-01 15:17:40 -04:00
if ( gArgs . GetArg ( " -rpcpassword " , " " ) = = " " ) {
2015-07-07 09:53:48 -03:00
// Try fall back to cookie-based authentication if no password is provided
if ( ! GetAuthCookie ( & strRPCUserColonPass ) ) {
2018-03-09 02:09:57 -03:00
failedToGetAuthCookie = true ;
2015-07-07 09:53:48 -03:00
}
} else {
2017-08-01 15:17:40 -04:00
strRPCUserColonPass = gArgs . GetArg ( " -rpcuser " , " " ) + " : " + gArgs . GetArg ( " -rpcpassword " , " " ) ;
2015-07-07 09:53:48 -03:00
}
2016-12-20 08:46:11 -03:00
struct evkeyvalq * output_headers = evhttp_request_get_output_headers ( req . get ( ) ) ;
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
assert ( output_headers ) ;
evhttp_add_header ( output_headers , " Host " , host . c_str ( ) ) ;
evhttp_add_header ( output_headers , " Connection " , " close " ) ;
2020-10-01 12:31:10 -03:00
evhttp_add_header ( output_headers , " Content-Type " , " application/json " ) ;
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
evhttp_add_header ( output_headers , " Authorization " , ( std : : string ( " Basic " ) + EncodeBase64 ( strRPCUserColonPass ) ) . c_str ( ) ) ;
// Attach request data
2016-09-29 11:45:19 -03:00
std : : string strRequest = rh - > PrepareRequest ( strMethod , args ) . write ( ) + " \n " ;
2016-12-20 08:46:11 -03:00
struct evbuffer * output_buffer = evhttp_request_get_output_buffer ( req . get ( ) ) ;
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
assert ( output_buffer ) ;
evbuffer_add ( output_buffer , strRequest . data ( ) , strRequest . size ( ) ) ;
2017-07-13 11:06:27 -04:00
// check if we should use a special wallet endpoint
std : : string endpoint = " / " ;
2020-04-10 16:34:43 -04:00
if ( rpcwallet ) {
char * encodedURI = evhttp_uriencode ( rpcwallet - > data ( ) , rpcwallet - > size ( ) , false ) ;
2017-07-13 11:06:27 -04:00
if ( encodedURI ) {
2020-04-10 16:34:43 -04:00
endpoint = " /wallet/ " + std : : string ( encodedURI ) ;
2017-07-13 11:06:27 -04:00
free ( encodedURI ) ;
2020-04-10 16:34:43 -04:00
} else {
2017-07-13 11:06:27 -04:00
throw CConnectionFailed ( " uri-encode failed " ) ;
}
}
int r = evhttp_make_request ( evcon . get ( ) , req . get ( ) , EVHTTP_REQ_POST , endpoint . c_str ( ) ) ;
2016-12-20 08:46:11 -03:00
req . release ( ) ; // ownership moved to evcon in above call
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
if ( r ! = 0 ) {
throw CConnectionFailed ( " send http request failed " ) ;
}
2014-05-26 05:38:44 -04:00
2016-12-20 08:46:11 -03:00
event_base_dispatch ( base . get ( ) ) ;
2014-05-26 05:38:44 -04:00
2018-03-09 02:09:57 -03:00
if ( response . status = = 0 ) {
std : : string responseErrorMessage ;
if ( response . error ! = - 1 ) {
responseErrorMessage = strprintf ( " (error code %d - \" %s \" ) " , response . error , http_errorstring ( response . error ) ) ;
}
throw CConnectionFailed ( strprintf ( " Could not connect to the server %s:%d%s \n \n Make sure the bitcoind server is running and that you are connecting to the correct RPC port. " , host , port , responseErrorMessage ) ) ;
} else if ( response . status = = HTTP_UNAUTHORIZED ) {
if ( failedToGetAuthCookie ) {
throw std : : runtime_error ( strprintf (
2018-05-29 12:49:44 -04:00
" Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s) " ,
2019-10-28 09:30:20 -03:00
GetConfigFile ( gArgs . GetArg ( " -conf " , BITCOIN_CONF_FILENAME ) ) . string ( ) ) ) ;
2018-03-09 02:09:57 -03:00
} else {
throw std : : runtime_error ( " Authorization failed: Incorrect rpcuser or rpcpassword " ) ;
}
2020-04-04 12:02:27 -03:00
} else if ( response . status = = HTTP_SERVICE_UNAVAILABLE ) {
throw std : : runtime_error ( strprintf ( " Server response: %s " , response . body ) ) ;
2018-03-09 02:09:57 -03:00
} else if ( response . status > = 400 & & response . status ! = HTTP_BAD_REQUEST & & response . status ! = HTTP_NOT_FOUND & & response . status ! = HTTP_INTERNAL_SERVER_ERROR )
2016-11-25 05:17:57 -03:00
throw std : : runtime_error ( strprintf ( " server returned HTTP error %d " , response . status ) ) ;
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
else if ( response . body . empty ( ) )
2016-11-25 05:17:57 -03:00
throw std : : runtime_error ( " no response from server " ) ;
2014-05-26 05:38:44 -04:00
// Parse reply
2015-05-13 16:29:19 -03:00
UniValue valReply ( UniValue : : VSTR ) ;
evhttpd implementation
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with #4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.
- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.
- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral
- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.
- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.
By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as #5674, #5655, #344 should be avoided.
What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.
Configuration options:
- `-rpcthreads`: repurposed as "number of work handler threads". Still
defaults to 4.
- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.
- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.
- `-debug=http`: low-level http activity logging
2015-01-23 03:53:17 -03:00
if ( ! valReply . read ( response . body ) )
2016-11-25 05:17:57 -03:00
throw std : : runtime_error ( " couldn't parse reply from server " ) ;
2016-09-29 11:45:19 -03:00
const UniValue reply = rh - > ProcessReply ( valReply ) ;
2014-05-26 05:38:44 -04:00
if ( reply . empty ( ) )
2016-11-25 05:17:57 -03:00
throw std : : runtime_error ( " expected reply to have result, error and id properties " ) ;
2014-05-26 05:38:44 -04:00
return reply ;
}
2020-04-12 15:01:29 -04:00
/**
* ConnectAndCallRPC wraps CallRPC with - rpcwait and an exception handler .
*
* @ param [ in ] rh Pointer to RequestHandler .
* @ param [ in ] strMethod Reference to const string method to forward to CallRPC .
2020-04-10 16:34:43 -04:00
* @ param [ in ] rpcwallet Reference to const optional string wallet name to forward to CallRPC .
2020-04-12 15:01:29 -04:00
* @ returns the RPC response as a UniValue object .
* @ throws a CConnectionFailed std : : runtime_error if connection failed or RPC server still in warmup .
*/
2021-03-14 23:41:30 -03:00
static UniValue ConnectAndCallRPC ( BaseRequestHandler * rh , const std : : string & strMethod , const std : : vector < std : : string > & args , const std : : optional < std : : string > & rpcwallet = { } )
2020-04-12 15:01:29 -04:00
{
UniValue response ( UniValue : : VOBJ ) ;
// Execute and handle connection failures with -rpcwait.
const bool fWait = gArgs . GetBoolArg ( " -rpcwait " , false ) ;
2021-02-01 13:55:38 -03:00
const int timeout = gArgs . GetArg ( " -rpcwaittimeout " , DEFAULT_WAIT_CLIENT_TIMEOUT ) ;
2021-06-23 08:45:02 -04:00
const auto deadline { GetTime < std : : chrono : : microseconds > ( ) + 1 s * timeout } ;
2021-02-01 13:55:38 -03:00
2020-04-12 15:01:29 -04:00
do {
try {
2020-04-10 16:34:43 -04:00
response = CallRPC ( rh , strMethod , args , rpcwallet ) ;
2020-04-12 15:01:29 -04:00
if ( fWait ) {
const UniValue & error = find_value ( response , " error " ) ;
if ( ! error . isNull ( ) & & error [ " code " ] . get_int ( ) = = RPC_IN_WARMUP ) {
throw CConnectionFailed ( " server in warmup " ) ;
}
}
break ; // Connection succeeded, no need to retry.
2021-03-23 10:39:25 -03:00
} catch ( const CConnectionFailed & e ) {
2021-06-23 08:45:02 -04:00
const auto now { GetTime < std : : chrono : : microseconds > ( ) } ;
2021-02-01 13:55:38 -03:00
if ( fWait & & ( timeout < = 0 | | now < deadline ) ) {
2021-06-23 08:45:02 -04:00
UninterruptibleSleep ( 1 s ) ;
2020-04-12 15:01:29 -04:00
} else {
2021-03-23 10:39:25 -03:00
throw CConnectionFailed ( strprintf ( " timeout on transient error: %s " , e . what ( ) ) ) ;
2020-04-12 15:01:29 -04:00
}
}
} while ( fWait ) ;
return response ;
}
2020-05-31 05:44:51 -04:00
/** Parse UniValue result to update the message to print to std::cout. */
static void ParseResult ( const UniValue & result , std : : string & strPrint )
{
if ( result . isNull ( ) ) return ;
strPrint = result . isStr ( ) ? result . get_str ( ) : result . write ( 2 ) ;
}
/** Parse UniValue error to update the message to print to std::cerr and the code to return. */
static void ParseError ( const UniValue & error , std : : string & strPrint , int & nRet )
{
if ( error . isObject ( ) ) {
const UniValue & err_code = find_value ( error , " code " ) ;
const UniValue & err_msg = find_value ( error , " message " ) ;
if ( ! err_code . isNull ( ) ) {
strPrint = " error code: " + err_code . getValStr ( ) + " \n " ;
}
if ( err_msg . isStr ( ) ) {
strPrint + = ( " error message: \n " + err_msg . get_str ( ) ) ;
}
if ( err_code . isNum ( ) & & err_code . get_int ( ) = = RPC_WALLET_NOT_SPECIFIED ) {
strPrint + = " \n Try adding \" -rpcwallet=<filename> \" option to bitcoin-cli command line. " ;
}
} else {
strPrint = " error: " + error . write ( ) ;
}
nRet = abs ( error [ " code " ] . get_int ( ) ) ;
}
2020-04-12 15:28:19 -04:00
/**
* GetWalletBalances calls listwallets ; if more than one wallet is loaded , it then
* fetches mine . trusted balances for each loaded wallet and pushes them to ` result ` .
*
* @ param result Reference to UniValue object the wallet names and balances are pushed to .
*/
static void GetWalletBalances ( UniValue & result )
{
2020-07-05 09:25:11 -04:00
DefaultRequestHandler rh ;
const UniValue listwallets = ConnectAndCallRPC ( & rh , " listwallets " , /* args=*/ { } ) ;
2020-04-12 15:28:19 -04:00
if ( ! find_value ( listwallets , " error " ) . isNull ( ) ) return ;
const UniValue & wallets = find_value ( listwallets , " result " ) ;
if ( wallets . size ( ) < = 1 ) return ;
UniValue balances ( UniValue : : VOBJ ) ;
for ( const UniValue & wallet : wallets . getValues ( ) ) {
const std : : string wallet_name = wallet . get_str ( ) ;
2020-07-05 09:25:11 -04:00
const UniValue getbalances = ConnectAndCallRPC ( & rh , " getbalances " , /* args=*/ { } , wallet_name ) ;
2020-04-12 15:28:19 -04:00
const UniValue & balance = find_value ( getbalances , " result " ) [ " mine " ] [ " trusted " ] ;
balances . pushKV ( wallet_name , balance ) ;
}
result . pushKV ( " balances " , balances ) ;
}
2021-07-25 12:08:19 -04:00
/**
2021-08-22 10:50:36 -04:00
* GetProgressBar constructs a progress bar with 5 % intervals .
2021-07-25 12:08:19 -04:00
*
* @ param [ in ] progress The proportion of the progress bar to be filled between 0 and 1.
* @ param [ out ] progress_bar String representation of the progress bar .
*/
static void GetProgressBar ( double progress , std : : string & progress_bar )
{
if ( progress < 0 | | progress > 1 ) return ;
static constexpr double INCREMENT { 0.05 } ;
static const std : : string COMPLETE_BAR { " \u2592 " } ;
static const std : : string INCOMPLETE_BAR { " \u2591 " } ;
for ( int i = 0 ; i < progress / INCREMENT ; + + i ) {
progress_bar + = COMPLETE_BAR ;
}
for ( int i = 0 ; i < ( 1 - progress ) / INCREMENT ; + + i ) {
progress_bar + = INCOMPLETE_BAR ;
}
}
2021-05-02 04:31:52 -04:00
/**
* ParseGetInfoResult takes in - getinfo result in UniValue object and parses it
* into a user friendly UniValue string to be printed on the console .
* @ param [ out ] result Reference to UniValue result containing the - getinfo output .
*/
static void ParseGetInfoResult ( UniValue & result )
{
if ( ! find_value ( result , " error " ) . isNull ( ) ) return ;
std : : string RESET , GREEN , BLUE , YELLOW , MAGENTA , CYAN ;
bool should_colorize = false ;
# ifndef WIN32
if ( isatty ( fileno ( stdout ) ) ) {
// By default, only print colored text if OS is not WIN32 and stdout is connected to a terminal.
should_colorize = true ;
}
# endif
if ( gArgs . IsArgSet ( " -color " ) ) {
const std : : string color { gArgs . GetArg ( " -color " , DEFAULT_COLOR_SETTING ) } ;
if ( color = = " always " ) {
should_colorize = true ;
} else if ( color = = " never " ) {
should_colorize = false ;
} else if ( color ! = " auto " ) {
throw std : : runtime_error ( " Invalid value for -color option. Valid values: always, auto, never. " ) ;
}
}
if ( should_colorize ) {
RESET = " \x1B [0m " ;
GREEN = " \x1B [32m " ;
BLUE = " \x1B [34m " ;
YELLOW = " \x1B [33m " ;
MAGENTA = " \x1B [35m " ;
CYAN = " \x1B [36m " ;
}
std : : string result_string = strprintf ( " %sChain: %s%s \n " , BLUE , result [ " chain " ] . getValStr ( ) , RESET ) ;
result_string + = strprintf ( " Blocks: %s \n " , result [ " blocks " ] . getValStr ( ) ) ;
result_string + = strprintf ( " Headers: %s \n " , result [ " headers " ] . getValStr ( ) ) ;
2021-07-25 12:08:19 -04:00
const double ibd_progress { result [ " verificationprogress " ] . get_real ( ) } ;
std : : string ibd_progress_bar ;
// Display the progress bar only if IBD progress is less than 99%
if ( ibd_progress < 0.99 ) {
GetProgressBar ( ibd_progress , ibd_progress_bar ) ;
// Add padding between progress bar and IBD progress
ibd_progress_bar + = " " ;
}
result_string + = strprintf ( " Verification progress: %s%.4f%% \n " , ibd_progress_bar , ibd_progress * 100 ) ;
2021-05-02 04:31:52 -04:00
result_string + = strprintf ( " Difficulty: %s \n \n " , result [ " difficulty " ] . getValStr ( ) ) ;
result_string + = strprintf (
" %sNetwork: in %s, out %s, total %s%s \n " ,
GREEN ,
result [ " connections " ] [ " in " ] . getValStr ( ) ,
result [ " connections " ] [ " out " ] . getValStr ( ) ,
result [ " connections " ] [ " total " ] . getValStr ( ) ,
RESET ) ;
result_string + = strprintf ( " Version: %s \n " , result [ " version " ] . getValStr ( ) ) ;
result_string + = strprintf ( " Time offset (s): %s \n " , result [ " timeoffset " ] . getValStr ( ) ) ;
const std : : string proxy = result [ " proxy " ] . getValStr ( ) ;
result_string + = strprintf ( " Proxy: %s \n " , proxy . empty ( ) ? " N/A " : proxy ) ;
result_string + = strprintf ( " Min tx relay fee rate (%s/kvB): %s \n \n " , CURRENCY_UNIT , result [ " relayfee " ] . getValStr ( ) ) ;
if ( ! result [ " has_wallet " ] . isNull ( ) ) {
const std : : string walletname = result [ " walletname " ] . getValStr ( ) ;
result_string + = strprintf ( " %sWallet: %s%s \n " , MAGENTA , walletname . empty ( ) ? " \" \" " : walletname , RESET ) ;
result_string + = strprintf ( " Keypool size: %s \n " , result [ " keypoolsize " ] . getValStr ( ) ) ;
if ( ! result [ " unlocked_until " ] . isNull ( ) ) {
result_string + = strprintf ( " Unlocked until: %s \n " , result [ " unlocked_until " ] . getValStr ( ) ) ;
}
result_string + = strprintf ( " Transaction fee rate (-paytxfee) (%s/kvB): %s \n \n " , CURRENCY_UNIT , result [ " paytxfee " ] . getValStr ( ) ) ;
}
if ( ! result [ " balance " ] . isNull ( ) ) {
result_string + = strprintf ( " %sBalance:%s %s \n \n " , CYAN , RESET , result [ " balance " ] . getValStr ( ) ) ;
}
if ( ! result [ " balances " ] . isNull ( ) ) {
result_string + = strprintf ( " %sBalances%s \n " , CYAN , RESET ) ;
size_t max_balance_length { 10 } ;
for ( const std : : string & wallet : result [ " balances " ] . getKeys ( ) ) {
max_balance_length = std : : max ( result [ " balances " ] [ wallet ] . getValStr ( ) . length ( ) , max_balance_length ) ;
}
for ( const std : : string & wallet : result [ " balances " ] . getKeys ( ) ) {
result_string + = strprintf ( " %*s %s \n " ,
max_balance_length ,
result [ " balances " ] [ wallet ] . getValStr ( ) ,
wallet . empty ( ) ? " \" \" " : wallet ) ;
}
result_string + = " \n " ;
}
result_string + = strprintf ( " %sWarnings:%s %s " , YELLOW , RESET , result [ " warnings " ] . getValStr ( ) ) ;
result . setStr ( result_string ) ;
}
2020-06-01 05:57:12 -04:00
/**
* Call RPC getnewaddress .
* @ returns getnewaddress response as a UniValue object .
*/
static UniValue GetNewAddress ( )
{
2021-03-14 23:41:30 -03:00
std : : optional < std : : string > wallet_name { } ;
2020-05-31 12:03:47 -04:00
if ( gArgs . IsArgSet ( " -rpcwallet " ) ) wallet_name = gArgs . GetArg ( " -rpcwallet " , " " ) ;
2020-07-05 09:25:11 -04:00
DefaultRequestHandler rh ;
return ConnectAndCallRPC ( & rh , " getnewaddress " , /* args=*/ { } , wallet_name ) ;
2020-06-01 05:57:12 -04:00
}
2020-05-31 09:41:08 -04:00
/**
* Check bounds and set up args for RPC generatetoaddress params : nblocks , address , maxtries .
* @ param [ in ] address Reference to const string address to insert into the args .
* @ param args Reference to vector of string args to modify .
*/
static void SetGenerateToAddressArgs ( const std : : string & address , std : : vector < std : : string > & args )
{
if ( args . size ( ) > 2 ) throw std : : runtime_error ( " too many arguments (maximum 2 for nblocks and maxtries) " ) ;
if ( args . size ( ) = = 0 ) {
args . emplace_back ( DEFAULT_NBLOCKS ) ;
} else if ( args . at ( 0 ) = = " 0 " ) {
throw std : : runtime_error ( " the first argument (number of blocks to generate, default: " + DEFAULT_NBLOCKS + " ) must be an integer value greater than zero " ) ;
}
args . emplace ( args . begin ( ) + 1 , address ) ;
}
2018-05-02 12:14:48 -03:00
static int CommandLineRPC ( int argc , char * argv [ ] )
2014-05-26 05:38:44 -04:00
{
2016-11-25 05:17:57 -03:00
std : : string strPrint ;
2014-05-26 05:38:44 -04:00
int nRet = 0 ;
2014-06-25 21:09:36 -04:00
try {
2014-05-26 05:38:44 -04:00
// Skip switches
2014-06-25 21:09:36 -04:00
while ( argc > 1 & & IsSwitchChar ( argv [ 1 ] [ 0 ] ) ) {
2014-05-26 05:38:44 -04:00
argc - - ;
argv + + ;
}
2017-08-23 15:48:00 -03:00
std : : string rpcPass ;
if ( gArgs . GetBoolArg ( " -stdinrpcpass " , false ) ) {
2018-07-19 10:48:55 -04:00
NO_STDIN_ECHO ( ) ;
if ( ! StdinReady ( ) ) {
fputs ( " RPC password> " , stderr ) ;
fflush ( stderr ) ;
}
2017-08-24 14:35:06 -03:00
if ( ! std : : getline ( std : : cin , rpcPass ) ) {
2017-08-23 15:48:00 -03:00
throw std : : runtime_error ( " -stdinrpcpass specified but failed to read from standard input " ) ;
2017-08-24 14:35:06 -03:00
}
2019-02-14 02:51:28 -03:00
if ( StdinTerminal ( ) ) {
fputc ( ' \n ' , stdout ) ;
}
2017-08-23 15:48:00 -03:00
gArgs . ForceSetArg ( " -rpcpassword " , rpcPass ) ;
}
2016-02-17 11:03:38 -03:00
std : : vector < std : : string > args = std : : vector < std : : string > ( & argv [ 1 ] , & argv [ argc ] ) ;
2018-07-19 10:48:55 -04:00
if ( gArgs . GetBoolArg ( " -stdinwalletpassphrase " , false ) ) {
NO_STDIN_ECHO ( ) ;
std : : string walletPass ;
if ( args . size ( ) < 1 | | args [ 0 ] . substr ( 0 , 16 ) ! = " walletpassphrase " ) {
throw std : : runtime_error ( " -stdinwalletpassphrase is only applicable for walletpassphrase(change) " ) ;
}
if ( ! StdinReady ( ) ) {
fputs ( " Wallet passphrase> " , stderr ) ;
fflush ( stderr ) ;
}
if ( ! std : : getline ( std : : cin , walletPass ) ) {
throw std : : runtime_error ( " -stdinwalletpassphrase specified but failed to read from standard input " ) ;
}
2019-02-14 02:51:28 -03:00
if ( StdinTerminal ( ) ) {
fputc ( ' \n ' , stdout ) ;
}
2018-07-19 10:48:55 -04:00
args . insert ( args . begin ( ) + 1 , walletPass ) ;
}
2017-08-01 15:17:40 -04:00
if ( gArgs . GetBoolArg ( " -stdin " , false ) ) {
2016-02-17 11:03:38 -03:00
// Read one arg per line from stdin and append
std : : string line ;
2017-08-24 14:35:06 -03:00
while ( std : : getline ( std : : cin , line ) ) {
2016-02-17 11:03:38 -03:00
args . push_back ( line ) ;
2017-08-24 14:35:06 -03:00
}
2019-02-14 02:51:28 -03:00
if ( StdinTerminal ( ) ) {
fputc ( ' \n ' , stdout ) ;
}
2016-02-17 11:03:38 -03:00
}
2016-09-29 11:45:19 -03:00
std : : unique_ptr < BaseRequestHandler > rh ;
std : : string method ;
2020-05-03 05:10:24 -04:00
if ( gArgs . IsArgSet ( " -getinfo " ) ) {
2016-09-29 11:45:19 -03:00
rh . reset ( new GetinfoRequestHandler ( ) ) ;
2020-07-27 02:20:26 -04:00
} else if ( gArgs . GetBoolArg ( " -netinfo " , false ) ) {
2021-01-07 12:27:46 -03:00
if ( ! args . empty ( ) & & args . at ( 0 ) = = " help " ) {
tfm : : format ( std : : cout , " %s \n " , NetinfoRequestHandler ( ) . m_help_doc ) ;
return 0 ;
}
2020-07-27 02:20:26 -04:00
rh . reset ( new NetinfoRequestHandler ( ) ) ;
2020-05-31 09:41:08 -04:00
} else if ( gArgs . GetBoolArg ( " -generate " , false ) ) {
const UniValue getnewaddress { GetNewAddress ( ) } ;
const UniValue & error { find_value ( getnewaddress , " error " ) } ;
if ( error . isNull ( ) ) {
SetGenerateToAddressArgs ( find_value ( getnewaddress , " result " ) . get_str ( ) , args ) ;
rh . reset ( new GenerateToAddressRequestHandler ( ) ) ;
} else {
ParseError ( error , strPrint , nRet ) ;
}
2021-04-04 10:20:47 -04:00
} else if ( gArgs . GetBoolArg ( " -addrinfo " , false ) ) {
rh . reset ( new AddrinfoRequestHandler ( ) ) ;
2016-11-22 10:56:29 -03:00
} else {
2016-09-29 11:45:19 -03:00
rh . reset ( new DefaultRequestHandler ( ) ) ;
if ( args . size ( ) < 1 ) {
throw std : : runtime_error ( " too few parameters (need at least command) " ) ;
}
method = args [ 0 ] ;
args . erase ( args . begin ( ) ) ; // Remove trailing method name from arguments vector
2016-11-22 10:56:29 -03:00
}
2020-05-31 05:44:51 -04:00
if ( nRet = = 0 ) {
// Perform RPC call
2021-03-14 23:41:30 -03:00
std : : optional < std : : string > wallet_name { } ;
2020-05-31 05:44:51 -04:00
if ( gArgs . IsArgSet ( " -rpcwallet " ) ) wallet_name = gArgs . GetArg ( " -rpcwallet " , " " ) ;
const UniValue reply = ConnectAndCallRPC ( rh . get ( ) , method , args , wallet_name ) ;
// Parse reply
UniValue result = find_value ( reply , " result " ) ;
const UniValue & error = find_value ( reply , " error " ) ;
if ( error . isNull ( ) ) {
2021-05-02 04:31:52 -04:00
if ( gArgs . GetBoolArg ( " -getinfo " , false ) ) {
if ( ! gArgs . IsArgSet ( " -rpcwallet " ) ) {
GetWalletBalances ( result ) ; // fetch multiwallet balances and append to result
}
ParseGetInfoResult ( result ) ;
2014-10-29 14:08:31 -03:00
}
2021-05-02 04:31:52 -04:00
2020-05-31 05:44:51 -04:00
ParseResult ( result , strPrint ) ;
2020-04-12 15:01:29 -04:00
} else {
2020-05-31 05:44:51 -04:00
ParseError ( error , strPrint , nRet ) ;
2014-10-29 14:08:31 -03:00
}
2020-04-12 15:01:29 -04:00
}
} catch ( const std : : exception & e ) {
2016-11-25 05:17:57 -03:00
strPrint = std : : string ( " error: " ) + e . what ( ) ;
2014-05-26 05:38:44 -04:00
nRet = EXIT_FAILURE ;
2020-04-12 15:01:29 -04:00
} catch ( . . . ) {
2017-08-07 01:36:37 -04:00
PrintExceptionContinue ( nullptr , " CommandLineRPC() " ) ;
2014-05-26 05:38:44 -04:00
throw ;
}
2014-06-25 21:09:36 -04:00
if ( strPrint ! = " " ) {
2019-10-28 09:30:20 -03:00
tfm : : format ( nRet = = 0 ? std : : cout : std : : cerr , " %s \n " , strPrint ) ;
2014-05-26 05:38:44 -04:00
}
return nRet ;
}
2018-08-05 12:38:25 -04:00
# ifdef WIN32
build: fix ASLR for bitcoin-cli on Windows
ASLR is not currently working for the bitcoin-cli.exe binary. This is
due to it not having a .reloc section, which is stripped by default by
the mingw-w64 ld we use for gitian builds. A good summary of issues with
ld and mingw-w64 is available in this thread:
https://sourceware.org/bugzilla/show_bug.cgi?id=19011.
All other Windows binaries that we distribute (bitcoind, bitcoin-qt,
bitcoin-wallet, bitcoin-tx and test_bitcoin) do not suffer this issue,
and currently having working ASLR. This is due to them exporting
(inadvertent or not) libsecp256k1 symbols, and, as a result, the .reloc
section is not stripped by ld.
This change is a temporary workaround, also the same one described here:
https://www.kb.cert.org/vuls/id/307144/, that causes main() to be
exported. Exporting a symbol will mean that the .reloc section is not
stripped, and ASLR will function correctly.
2020-04-18 22:05:29 -04:00
// Export main() and ensure working ASLR on Windows.
// Exporting a symbol will prevent the linker from stripping
// the .reloc section from the binary, which is a requirement
// for ASLR. This is a temporary workaround until a fixed
// version of binutils is used for releases.
__declspec ( dllexport ) int main ( int argc , char * argv [ ] )
{
2018-08-05 12:38:25 -04:00
util : : WinCmdLineArgs winArgs ;
std : : tie ( argc , argv ) = winArgs . get ( ) ;
build: fix ASLR for bitcoin-cli on Windows
ASLR is not currently working for the bitcoin-cli.exe binary. This is
due to it not having a .reloc section, which is stripped by default by
the mingw-w64 ld we use for gitian builds. A good summary of issues with
ld and mingw-w64 is available in this thread:
https://sourceware.org/bugzilla/show_bug.cgi?id=19011.
All other Windows binaries that we distribute (bitcoind, bitcoin-qt,
bitcoin-wallet, bitcoin-tx and test_bitcoin) do not suffer this issue,
and currently having working ASLR. This is due to them exporting
(inadvertent or not) libsecp256k1 symbols, and, as a result, the .reloc
section is not stripped by ld.
This change is a temporary workaround, also the same one described here:
https://www.kb.cert.org/vuls/id/307144/, that causes main() to be
exported. Exporting a symbol will mean that the .reloc section is not
stripped, and ASLR will function correctly.
2020-04-18 22:05:29 -04:00
# else
int main ( int argc , char * argv [ ] )
{
2018-08-05 12:38:25 -04:00
# endif
2014-05-13 06:15:00 -04:00
SetupEnvironment ( ) ;
2015-09-02 11:18:16 -03:00
if ( ! SetupNetworking ( ) ) {
2019-06-13 09:16:10 -04:00
tfm : : format ( std : : cerr , " Error: Initializing networking failed \n " ) ;
2016-05-02 13:48:04 -03:00
return EXIT_FAILURE ;
2015-09-02 11:18:16 -03:00
}
2018-06-04 14:55:00 -04:00
event_set_log_callback ( & libevent_log_cb ) ;
2014-05-13 06:15:00 -04:00
2014-06-25 21:09:36 -04:00
try {
2016-11-02 15:59:09 -03:00
int ret = AppInitRPC ( argc , argv ) ;
if ( ret ! = CONTINUE_EXECUTION )
return ret ;
2013-10-11 18:09:59 -03:00
}
2014-12-07 09:29:06 -03:00
catch ( const std : : exception & e ) {
2013-10-11 18:09:59 -03:00
PrintExceptionContinue ( & e , " AppInitRPC() " ) ;
2014-06-12 22:26:46 -04:00
return EXIT_FAILURE ;
2013-10-11 18:09:59 -03:00
} catch ( . . . ) {
2017-08-07 01:36:37 -04:00
PrintExceptionContinue ( nullptr , " AppInitRPC() " ) ;
2014-06-12 22:26:46 -04:00
return EXIT_FAILURE ;
2013-10-11 18:09:59 -03:00
}
2014-06-12 22:26:46 -04:00
int ret = EXIT_FAILURE ;
2014-06-25 21:09:36 -04:00
try {
2014-02-24 10:08:56 -03:00
ret = CommandLineRPC ( argc , argv ) ;
2013-10-11 18:09:59 -03:00
}
2014-12-07 09:29:06 -03:00
catch ( const std : : exception & e ) {
2013-10-11 18:09:59 -03:00
PrintExceptionContinue ( & e , " CommandLineRPC() " ) ;
} catch ( . . . ) {
2017-08-07 01:36:37 -04:00
PrintExceptionContinue ( nullptr , " CommandLineRPC() " ) ;
2013-10-11 18:09:59 -03:00
}
2014-02-24 10:08:56 -03:00
return ret ;
2013-10-11 18:09:59 -03:00
}