2013-12-13 16:01:22 +01:00
// Copyright (c) 2010 Satoshi Nakamoto
2020-04-16 13:14:08 -04:00
// Copyright (c) 2009-2020 The Bitcoin Core developers
2014-11-20 10:19:29 +08:00
// Distributed under the MIT software license, see the accompanying
2013-12-13 16:01:22 +01:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-11-10 13:57:53 +13:00
# include <httpserver.h>
2020-07-31 14:01:31 +02:00
# include <index/blockfilterindex.h>
2020-08-22 18:31:34 +02:00
# include <index/coinstatsindex.h>
2020-07-31 14:01:31 +02:00
# include <index/txindex.h>
2017-12-05 15:57:12 -05:00
# include <interfaces/chain.h>
2020-11-24 13:59:33 -05:00
# include <interfaces/echo.h>
# include <interfaces/init.h>
# include <interfaces/ipc.h>
2019-09-23 14:45:51 -04:00
# include <key_io.h>
2020-02-12 11:12:20 -08:00
# include <node/context.h>
2018-04-25 18:43:31 +10:00
# include <outputtype.h>
2017-11-10 13:57:53 +13:00
# include <rpc/blockchain.h>
# include <rpc/server.h>
2017-09-29 00:21:28 -04:00
# include <rpc/util.h>
2020-02-12 11:12:20 -08:00
# include <scheduler.h>
2019-01-09 20:16:46 +01:00
# include <script/descriptor.h>
2019-09-23 14:45:51 -04:00
# include <util/check.h>
2019-11-22 17:17:29 +01:00
# include <util/message.h> // For MessageSign(), MessageVerify()
2018-10-22 15:51:11 -07:00
# include <util/strencodings.h>
2021-10-01 13:53:59 +00:00
# include <util/syscall_sandbox.h>
2019-09-23 14:45:51 -04:00
# include <util/system.h>
2013-12-13 16:01:22 +01:00
2021-08-04 13:38:36 +08:00
# include <optional>
2013-12-13 16:01:22 +01:00
# include <stdint.h>
2019-04-04 00:39:04 -07:00
# include <tuple>
2017-03-20 10:09:01 +01:00
# ifdef HAVE_MALLOC_INFO
# include <malloc.h>
# endif
2013-12-13 16:01:22 +01:00
2015-09-04 16:11:34 +02:00
# include <univalue.h>
2015-05-18 14:02:18 +02:00
2020-07-15 21:26:22 +02:00
static RPCHelpMan validateaddress ( )
2013-12-13 16:18:00 +01:00
{
2021-12-02 19:23:29 +01:00
return RPCHelpMan {
" validateaddress " ,
" \n Return information about the given bitcoin address. \n " ,
{
{ " address " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The bitcoin address to validate " } ,
} ,
RPCResult {
RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : BOOL , " isvalid " , " If the address is valid or not " } ,
{ RPCResult : : Type : : STR , " address " , /* optional */ true , " The bitcoin address validated " } ,
{ RPCResult : : Type : : STR_HEX , " scriptPubKey " , /* optional */ true , " The hex-encoded scriptPubKey generated by the address " } ,
{ RPCResult : : Type : : BOOL , " isscript " , /* optional */ true , " If the key is a script " } ,
{ RPCResult : : Type : : BOOL , " iswitness " , /* optional */ true , " If the address is a witness address " } ,
{ RPCResult : : Type : : NUM , " witness_version " , /* optional */ true , " The version number of the witness program " } ,
{ RPCResult : : Type : : STR_HEX , " witness_program " , /* optional */ true , " The hex value of the witness program " } ,
{ RPCResult : : Type : : STR , " error " , /* optional */ true , " Error message, if any " } ,
{ RPCResult : : Type : : ARR , " error_locations " , /*optional=*/ true , " Indices of likely error locations in address, if known (e.g. Bech32 errors) " ,
2020-01-10 00:00:57 +07:00
{
2021-12-02 19:23:29 +01:00
{ RPCResult : : Type : : NUM , " index " , " index of a potential error " } ,
} } ,
}
} ,
RPCExamples {
HelpExampleCli ( " validateaddress " , " \" " + EXAMPLE_ADDRESS [ 0 ] + " \" " ) +
HelpExampleRpc ( " validateaddress " , " \" " + EXAMPLE_ADDRESS [ 0 ] + " \" " )
} ,
2020-07-15 21:26:22 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2021-01-03 01:45:25 +01:00
std : : string error_msg ;
2021-10-01 12:51:18 +13:00
std : : vector < int > error_locations ;
CTxDestination dest = DecodeDestination ( request . params [ 0 ] . get_str ( ) , error_msg , & error_locations ) ;
2021-01-03 01:45:25 +01:00
const bool isValid = IsValidDestination ( dest ) ;
CHECK_NONFATAL ( isValid = = error_msg . empty ( ) ) ;
2013-12-13 16:18:00 +01:00
2015-05-10 14:48:35 +02:00
UniValue ret ( UniValue : : VOBJ ) ;
2017-09-22 20:04:07 +02:00
ret . pushKV ( " isvalid " , isValid ) ;
2021-01-03 01:45:25 +01:00
if ( isValid ) {
2018-02-20 09:02:34 -05:00
std : : string currentAddress = EncodeDestination ( dest ) ;
ret . pushKV ( " address " , currentAddress ) ;
2014-09-23 05:18:47 -04:00
2018-02-20 09:02:34 -05:00
CScript scriptPubKey = GetScriptForDestination ( dest ) ;
2020-06-24 15:48:26 +02:00
ret . pushKV ( " scriptPubKey " , HexStr ( scriptPubKey ) ) ;
2017-06-12 18:53:46 -07:00
2018-02-20 09:02:34 -05:00
UniValue detail = DescribeAddress ( dest ) ;
ret . pushKVs ( detail ) ;
2021-01-03 01:45:25 +01:00
} else {
2021-10-01 12:51:18 +13:00
UniValue error_indices ( UniValue : : VARR ) ;
for ( int i : error_locations ) error_indices . push_back ( i ) ;
ret . pushKV ( " error_locations " , error_indices ) ;
2021-01-03 01:45:25 +01:00
ret . pushKV ( " error " , error_msg ) ;
2013-12-13 16:18:00 +01:00
}
2021-01-03 01:45:25 +01:00
2013-12-13 16:18:00 +01:00
return ret ;
2020-07-15 21:26:22 +02:00
} ,
} ;
2013-12-13 16:18:00 +01:00
}
2020-07-15 21:26:22 +02:00
static RPCHelpMan createmultisig ( )
2013-12-13 16:21:38 +01:00
{
2020-07-15 21:26:22 +02:00
return RPCHelpMan { " createmultisig " ,
2018-11-23 11:21:38 -05:00
" \n Creates a multi-signature address with n signature of m keys required. \n "
" It returns a json object with the address and redeemScript. \n " ,
{
2018-12-10 16:56:51 -05:00
{ " nrequired " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " The number of required signatures out of the n keys. " } ,
2020-03-05 10:36:27 +00:00
{ " keys " , RPCArg : : Type : : ARR , RPCArg : : Optional : : NO , " The hex-encoded public keys. " ,
2018-11-23 11:21:38 -05:00
{
2018-12-10 16:56:51 -05:00
{ " key " , RPCArg : : Type : : STR_HEX , RPCArg : : Optional : : OMITTED , " The hex-encoded public key " } ,
2018-11-23 11:21:38 -05:00
} } ,
2021-04-14 15:01:00 +01:00
{ " address_type " , RPCArg : : Type : : STR , RPCArg : : Default { " legacy " } , " The address type to use. Options are \" legacy \" , \" p2sh-segwit \" , and \" bech32 \" . " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR , " address " , " The value of the new multisig address. " } ,
{ RPCResult : : Type : : STR_HEX , " redeemScript " , " The string value of the hex-encoded redemption script. " } ,
{ RPCResult : : Type : : STR , " descriptor " , " The descriptor for this multisig " } ,
}
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
2017-09-29 00:21:28 -04:00
" \n Create a multisig address from 2 public keys \n "
+ HelpExampleCli ( " createmultisig " , " 2 \" [ \\ \" 03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd \\ \" , \\ \" 03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626 \\ \" ] \" " ) +
2018-10-02 14:49:18 -05:00
" \n As a JSON-RPC call \n "
2020-03-26 19:27:32 +01:00
+ HelpExampleRpc ( " createmultisig " , " 2, [ \" 03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd \" , \" 03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626 \" ] " )
2018-12-21 12:29:36 -05:00
} ,
2020-07-15 21:26:22 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2017-09-29 00:21:28 -04:00
int required = request . params [ 0 ] . get_int ( ) ;
// Get the public keys
const UniValue & keys = request . params [ 1 ] . get_array ( ) ;
std : : vector < CPubKey > pubkeys ;
for ( unsigned int i = 0 ; i < keys . size ( ) ; + + i ) {
if ( IsHex ( keys [ i ] . get_str ( ) ) & & ( keys [ i ] . get_str ( ) . length ( ) = = 66 | | keys [ i ] . get_str ( ) . length ( ) = = 130 ) ) {
pubkeys . push_back ( HexToPubKey ( keys [ i ] . get_str ( ) ) ) ;
} else {
2018-08-06 11:49:05 -04:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , strprintf ( " Invalid public key: %s \n . " , keys [ i ] . get_str ( ) ) ) ;
2017-09-29 00:21:28 -04:00
}
}
2018-04-25 18:43:31 +10:00
// Get the output type
OutputType output_type = OutputType : : LEGACY ;
if ( ! request . params [ 2 ] . isNull ( ) ) {
2021-08-04 13:38:36 +08:00
std : : optional < OutputType > parsed = ParseOutputType ( request . params [ 2 ] . get_str ( ) ) ;
if ( ! parsed ) {
2018-04-25 18:43:31 +10:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , strprintf ( " Unknown address type '%s' " , request . params [ 2 ] . get_str ( ) ) ) ;
2021-08-04 13:38:36 +08:00
} else if ( parsed . value ( ) = = OutputType : : BECH32M ) {
2021-06-04 17:35:47 -04:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " createmultisig cannot create bech32m multisig addresses " ) ;
}
2021-08-04 13:38:36 +08:00
output_type = parsed . value ( ) ;
2018-04-25 18:43:31 +10:00
}
2013-12-13 16:21:38 +01:00
// Construct using pay-to-script-hash:
2019-06-06 16:33:23 +02:00
FillableSigningProvider keystore ;
2019-05-15 00:21:11 -04:00
CScript inner ;
const CTxDestination dest = AddAndGetMultisigDestination ( required , pubkeys , output_type , keystore , inner ) ;
2013-12-13 16:21:38 +01:00
2019-03-25 17:00:00 -04:00
// Make the descriptor
std : : unique_ptr < Descriptor > descriptor = InferDescriptor ( GetScriptForDestination ( dest ) , keystore ) ;
2015-06-02 12:28:54 +02:00
UniValue result ( UniValue : : VOBJ ) ;
2018-04-25 18:43:31 +10:00
result . pushKV ( " address " , EncodeDestination ( dest ) ) ;
2020-06-24 15:48:26 +02:00
result . pushKV ( " redeemScript " , HexStr ( inner ) ) ;
2019-03-25 17:00:00 -04:00
result . pushKV ( " descriptor " , descriptor - > ToString ( ) ) ;
2013-12-13 16:21:38 +01:00
return result ;
2020-07-15 21:26:22 +02:00
} ,
} ;
2013-12-13 16:21:38 +01:00
}
2020-07-15 21:26:22 +02:00
static RPCHelpMan getdescriptorinfo ( )
2019-02-07 15:09:08 -08:00
{
2020-03-26 19:27:32 +01:00
const std : : string EXAMPLE_DESCRIPTOR = " wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798) " ;
2020-07-15 21:26:22 +02:00
return RPCHelpMan { " getdescriptorinfo " ,
2019-02-07 15:09:08 -08:00
{ " \n Analyses a descriptor. \n " } ,
{
{ " descriptor " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The descriptor. " } ,
} ,
RPCResult {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : STR , " descriptor " , " The descriptor in canonical form, without private keys " } ,
{ RPCResult : : Type : : STR , " checksum " , " The checksum for the input descriptor " } ,
{ RPCResult : : Type : : BOOL , " isrange " , " Whether the descriptor is ranged " } ,
{ RPCResult : : Type : : BOOL , " issolvable " , " Whether the descriptor is solvable " } ,
{ RPCResult : : Type : : BOOL , " hasprivatekeys " , " Whether the input descriptor contained at least one private key " } ,
}
2019-02-07 15:09:08 -08:00
} ,
RPCExamples {
" Analyse a descriptor \n " +
2020-03-26 19:27:32 +01:00
HelpExampleCli ( " getdescriptorinfo " , " \" " + EXAMPLE_DESCRIPTOR + " \" " ) +
HelpExampleRpc ( " getdescriptorinfo " , " \" " + EXAMPLE_DESCRIPTOR + " \" " )
2020-07-15 21:26:22 +02:00
} ,
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2019-02-07 15:09:08 -08:00
RPCTypeCheck ( request . params , { UniValue : : VSTR } ) ;
FlatSigningProvider provider ;
2019-08-02 18:04:02 -04:00
std : : string error ;
auto desc = Parse ( request . params [ 0 ] . get_str ( ) , provider , error ) ;
2019-02-07 15:09:08 -08:00
if ( ! desc ) {
2019-08-02 19:19:53 -04:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , error ) ;
2019-02-07 15:09:08 -08:00
}
UniValue result ( UniValue : : VOBJ ) ;
result . pushKV ( " descriptor " , desc - > ToString ( ) ) ;
2019-05-08 14:03:29 -07:00
result . pushKV ( " checksum " , GetDescriptorChecksum ( request . params [ 0 ] . get_str ( ) ) ) ;
2019-02-07 15:09:08 -08:00
result . pushKV ( " isrange " , desc - > IsRange ( ) ) ;
result . pushKV ( " issolvable " , desc - > IsSolvable ( ) ) ;
result . pushKV ( " hasprivatekeys " , provider . keys . size ( ) > 0 ) ;
return result ;
2020-07-15 21:26:22 +02:00
} ,
} ;
2019-02-07 15:09:08 -08:00
}
2020-07-15 21:26:22 +02:00
static RPCHelpMan deriveaddresses ( )
2019-01-09 20:16:46 +01:00
{
2020-03-26 19:27:32 +01:00
const std : : string EXAMPLE_DESCRIPTOR = " wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu " ;
2020-07-15 21:26:22 +02:00
return RPCHelpMan { " deriveaddresses " ,
2019-01-09 20:16:46 +01:00
{ " \n Derives one or more addresses corresponding to an output descriptor. \n "
" Examples of output descriptors are: \n "
" pkh(<pubkey>) P2PKH outputs for the given pubkey \n "
" wpkh(<pubkey>) Native segwit P2PKH outputs for the given pubkey \n "
" sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys \n "
" raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts \n "
" \n In the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one \n "
" or more path elements separated by \" / \" , where \" h \" represents a hardened child key. \n "
" For more information on output descriptors, see the documentation in the doc/descriptors.md file. \n " } ,
{
2018-12-10 16:56:51 -05:00
{ " descriptor " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The descriptor. " } ,
2019-02-27 14:11:38 -08:00
{ " range " , RPCArg : : Type : : RANGE , RPCArg : : Optional : : OMITTED_NAMED_ARG , " If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive. " } ,
2019-01-09 20:16:46 +01:00
} ,
RPCResult {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : ARR , " " , " " ,
{
{ RPCResult : : Type : : STR , " address " , " the derived addresses " } ,
}
2019-01-09 20:16:46 +01:00
} ,
RPCExamples {
" First three native segwit receive addresses \n " +
2020-03-26 19:27:32 +01:00
HelpExampleCli ( " deriveaddresses " , " \" " + EXAMPLE_DESCRIPTOR + " \" \" [0,2] \" " ) +
HelpExampleRpc ( " deriveaddresses " , " \" " + EXAMPLE_DESCRIPTOR + " \" , \" [0,2] \" " )
2020-07-15 21:26:22 +02:00
} ,
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2019-02-27 14:11:38 -08:00
RPCTypeCheck ( request . params , { UniValue : : VSTR , UniValueType ( ) } ) ; // Range argument is checked later
2019-01-09 20:16:46 +01:00
const std : : string desc_str = request . params [ 0 ] . get_str ( ) ;
2019-02-27 14:11:38 -08:00
int64_t range_begin = 0 ;
int64_t range_end = 0 ;
2019-01-09 20:16:46 +01:00
2019-02-27 14:11:38 -08:00
if ( request . params . size ( ) > = 2 & & ! request . params [ 1 ] . isNull ( ) ) {
2019-04-04 00:39:04 -07:00
std : : tie ( range_begin , range_end ) = ParseDescriptorRange ( request . params [ 1 ] ) ;
2019-01-09 20:16:46 +01:00
}
2019-04-04 13:12:21 -07:00
FlatSigningProvider key_provider ;
2019-08-02 18:04:02 -04:00
std : : string error ;
auto desc = Parse ( desc_str , key_provider , error , /* require_checksum = */ true ) ;
2019-01-09 20:16:46 +01:00
if ( ! desc ) {
2019-08-02 19:19:53 -04:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , error ) ;
2019-01-09 20:16:46 +01:00
}
if ( ! desc - > IsRange ( ) & & request . params . size ( ) > 1 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Range should not be specified for an un-ranged descriptor " ) ;
}
if ( desc - > IsRange ( ) & & request . params . size ( ) = = 1 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Range must be specified for a ranged descriptor " ) ;
}
UniValue addresses ( UniValue : : VARR ) ;
for ( int i = range_begin ; i < = range_end ; + + i ) {
2019-04-04 13:12:21 -07:00
FlatSigningProvider provider ;
2019-01-09 20:16:46 +01:00
std : : vector < CScript > scripts ;
2019-04-04 13:12:21 -07:00
if ( ! desc - > Expand ( i , key_provider , scripts , provider ) ) {
2019-01-09 20:16:46 +01:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , strprintf ( " Cannot derive script without private keys " ) ) ;
}
for ( const CScript & script : scripts ) {
CTxDestination dest ;
if ( ! ExtractDestination ( script , dest ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , strprintf ( " Descriptor does not have a corresponding address " ) ) ;
}
addresses . push_back ( EncodeDestination ( dest ) ) ;
}
}
// This should not be possible, but an assert seems overkill:
if ( addresses . empty ( ) ) {
throw JSONRPCError ( RPC_MISC_ERROR , " Unexpected empty result " ) ;
}
return addresses ;
2020-07-15 21:26:22 +02:00
} ,
} ;
2019-01-09 20:16:46 +01:00
}
2020-07-15 21:26:22 +02:00
static RPCHelpMan verifymessage ( )
2013-12-13 16:23:39 +01:00
{
2020-07-15 21:26:22 +02:00
return RPCHelpMan { " verifymessage " ,
2018-10-20 08:19:44 -04:00
" \n Verify a signed message \n " ,
{
2018-12-10 16:56:51 -05:00
{ " address " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The bitcoin address to use for the signature. " } ,
{ " signature " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The signature provided by the signer in base 64 encoding (see signmessage). " } ,
{ " message " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The message that was signed. " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : BOOL , " " , " If the signature is verified or not. "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
2013-12-13 16:23:39 +01:00
" \n Unlock the wallet for 30 seconds \n "
+ HelpExampleCli ( " walletpassphrase " , " \" mypassphrase \" 30 " ) +
" \n Create the signature \n "
2017-02-26 14:01:05 +01:00
+ HelpExampleCli ( " signmessage " , " \" 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX \" \" my message \" " ) +
2013-12-13 16:23:39 +01:00
" \n Verify the signature \n "
2017-02-26 14:01:05 +01:00
+ HelpExampleCli ( " verifymessage " , " \" 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX \" \" signature \" \" my message \" " ) +
2018-10-02 14:49:18 -05:00
" \n As a JSON-RPC call \n "
2017-02-26 14:01:05 +01:00
+ HelpExampleRpc ( " verifymessage " , " \" 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX \" , \" signature \" , \" my message \" " )
2018-12-21 12:29:36 -05:00
} ,
2020-07-15 21:26:22 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2014-10-19 04:46:17 -04:00
LOCK ( cs_main ) ;
2017-01-04 13:22:19 +09:00
std : : string strAddress = request . params [ 0 ] . get_str ( ) ;
std : : string strSign = request . params [ 1 ] . get_str ( ) ;
std : : string strMessage = request . params [ 2 ] . get_str ( ) ;
2013-12-13 16:23:39 +01:00
2019-11-19 15:49:35 +01:00
switch ( MessageVerify ( strAddress , strSign , strMessage ) ) {
case MessageVerificationResult : : ERR_INVALID_ADDRESS :
2020-03-29 16:45:13 +02:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid address " ) ;
2019-11-19 15:49:35 +01:00
case MessageVerificationResult : : ERR_ADDRESS_NO_KEY :
2013-12-13 16:23:39 +01:00
throw JSONRPCError ( RPC_TYPE_ERROR , " Address does not refer to key " ) ;
2019-11-19 15:49:35 +01:00
case MessageVerificationResult : : ERR_MALFORMED_SIGNATURE :
2020-03-29 16:45:13 +02:00
throw JSONRPCError ( RPC_TYPE_ERROR , " Malformed base64 encoding " ) ;
2019-11-19 15:49:35 +01:00
case MessageVerificationResult : : ERR_PUBKEY_NOT_RECOVERED :
case MessageVerificationResult : : ERR_NOT_SIGNED :
2013-12-13 16:23:39 +01:00
return false ;
2019-11-19 15:49:35 +01:00
case MessageVerificationResult : : OK :
return true ;
}
2013-12-13 16:23:39 +01:00
2019-11-19 15:49:35 +01:00
return false ;
2020-07-15 21:26:22 +02:00
} ,
} ;
2013-12-13 16:23:39 +01:00
}
2014-11-12 18:59:41 -05:00
2020-07-15 21:26:22 +02:00
static RPCHelpMan signmessagewithprivkey ( )
2016-04-26 13:17:00 -04:00
{
2020-07-15 21:26:22 +02:00
return RPCHelpMan { " signmessagewithprivkey " ,
2018-10-20 08:19:44 -04:00
" \n Sign a message with the private key of an address \n " ,
{
2018-12-10 16:56:51 -05:00
{ " privkey " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The private key to sign the message with. " } ,
{ " message " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The message to create a signature of. " } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : STR , " signature " , " The signature of the message encoded in base 64 "
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
2016-04-26 13:17:00 -04:00
" \n Create the signature \n "
+ HelpExampleCli ( " signmessagewithprivkey " , " \" privkey \" \" my message \" " ) +
" \n Verify the signature \n "
2017-02-26 14:01:05 +01:00
+ HelpExampleCli ( " verifymessage " , " \" 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX \" \" signature \" \" my message \" " ) +
2018-10-02 14:49:18 -05:00
" \n As a JSON-RPC call \n "
2016-04-26 13:17:00 -04:00
+ HelpExampleRpc ( " signmessagewithprivkey " , " \" privkey \" , \" my message \" " )
2018-12-21 12:29:36 -05:00
} ,
2020-07-15 21:26:22 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2017-01-04 13:22:19 +09:00
std : : string strPrivkey = request . params [ 0 ] . get_str ( ) ;
std : : string strMessage = request . params [ 1 ] . get_str ( ) ;
2016-04-26 13:17:00 -04:00
2017-09-19 16:49:52 -07:00
CKey key = DecodeSecret ( strPrivkey ) ;
if ( ! key . IsValid ( ) ) {
2016-04-26 13:17:00 -04:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid private key " ) ;
2017-09-19 16:49:52 -07:00
}
2016-04-26 13:17:00 -04:00
2019-11-22 17:17:29 +01:00
std : : string signature ;
2016-04-26 13:17:00 -04:00
2019-11-22 17:17:29 +01:00
if ( ! MessageSign ( key , strMessage , signature ) ) {
2016-04-26 13:17:00 -04:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Sign failed " ) ;
2019-11-22 17:17:29 +01:00
}
2016-04-26 13:17:00 -04:00
2019-11-22 17:17:29 +01:00
return signature ;
2020-07-15 21:26:22 +02:00
} ,
} ;
2016-04-26 13:17:00 -04:00
}
2020-07-15 21:26:22 +02:00
static RPCHelpMan setmocktime ( )
2014-11-12 18:59:41 -05:00
{
2020-07-15 21:26:22 +02:00
return RPCHelpMan { " setmocktime " ,
2021-02-01 14:57:34 +00:00
" \n Set the local time to given timestamp (-regtest only) \n " ,
{
{ " timestamp " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , UNIX_EPOCH_TIME + " \n "
" Pass 0 to go back to using the system time. " } ,
} ,
RPCResult { RPCResult : : Type : : NONE , " " , " " } ,
RPCExamples { " " } ,
2020-07-15 21:26:22 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2020-03-04 14:01:31 -08:00
if ( ! Params ( ) . IsMockableChain ( ) ) {
throw std : : runtime_error ( " setmocktime is for regression testing (-regtest mode) only " ) ;
}
2014-11-12 18:59:41 -05:00
2017-01-19 13:01:18 -05:00
// For now, don't change mocktime if we're in the middle of validation, as
// this could have an effect on mempool time-based eviction, as well as
// IsCurrentForFeeEstimation() and IsInitialBlockDownload().
// TODO: figure out the right way to synchronize around mocktime, and
2017-02-06 15:16:18 +01:00
// ensure all call sites of GetTime() are accessing this safely.
2016-04-16 19:13:12 -04:00
LOCK ( cs_main ) ;
2014-10-19 04:46:17 -04:00
2017-06-06 21:15:28 +02:00
RPCTypeCheck ( request . params , { UniValue : : VNUM } ) ;
2021-02-01 14:57:34 +00:00
const int64_t time { request . params [ 0 ] . get_int64 ( ) } ;
if ( time < 0 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , strprintf ( " Mocktime can not be negative: %s. " , time ) ) ;
}
2017-12-05 15:57:12 -05:00
SetMockTime ( time ) ;
2020-12-01 00:36:36 +01:00
auto node_context = util : : AnyPtr < NodeContext > ( request . context ) ;
if ( node_context ) {
for ( const auto & chain_client : node_context - > chain_clients ) {
2017-12-05 15:57:12 -05:00
chain_client - > setMockTime ( time ) ;
}
}
2014-11-12 18:59:41 -05:00
2015-05-10 13:35:44 +02:00
return NullUniValue ;
2020-07-15 21:26:22 +02:00
} ,
} ;
2014-11-12 18:59:41 -05:00
}
2016-03-29 19:43:02 +02:00
2021-10-01 13:53:59 +00:00
# if defined(USE_SYSCALL_SANDBOX)
static RPCHelpMan invokedisallowedsyscall ( )
{
return RPCHelpMan {
" invokedisallowedsyscall " ,
" \n Invoke a disallowed syscall to trigger a syscall sandbox violation. Used for testing purposes. \n " ,
{ } ,
RPCResult { RPCResult : : Type : : NONE , " " , " " } ,
RPCExamples {
HelpExampleCli ( " invokedisallowedsyscall " , " " ) + HelpExampleRpc ( " invokedisallowedsyscall " , " " ) } ,
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue {
if ( ! Params ( ) . IsTestChain ( ) ) {
throw std : : runtime_error ( " invokedisallowedsyscall is used for testing only. " ) ;
}
TestDisallowedSandboxCall ( ) ;
return NullUniValue ;
} ,
} ;
}
# endif // USE_SYSCALL_SANDBOX
2020-07-15 21:26:22 +02:00
static RPCHelpMan mockscheduler ( )
2020-02-12 11:12:20 -08:00
{
2020-07-15 21:26:22 +02:00
return RPCHelpMan { " mockscheduler " ,
2020-02-12 11:12:20 -08:00
" \n Bump the scheduler into the future (-regtest only) \n " ,
{
{ " delta_time " , RPCArg : : Type : : NUM , RPCArg : : Optional : : NO , " Number of seconds to forward the scheduler into the future. " } ,
} ,
2020-03-13 14:40:53 -04:00
RPCResult { RPCResult : : Type : : NONE , " " , " " } ,
2020-02-12 11:12:20 -08:00
RPCExamples { " " } ,
2020-07-15 21:26:22 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2020-02-12 11:12:20 -08:00
if ( ! Params ( ) . IsMockableChain ( ) ) {
throw std : : runtime_error ( " mockscheduler is for regression testing (-regtest mode) only " ) ;
}
// check params are valid values
RPCTypeCheck ( request . params , { UniValue : : VNUM } ) ;
int64_t delta_seconds = request . params [ 0 ] . get_int64 ( ) ;
2021-05-14 12:52:15 +02:00
if ( delta_seconds < = 0 | | delta_seconds > 3600 ) {
2020-02-12 11:12:20 -08:00
throw std : : runtime_error ( " delta_time must be between 1 and 3600 seconds (1 hr) " ) ;
}
2020-12-01 00:36:36 +01:00
auto node_context = util : : AnyPtr < NodeContext > ( request . context ) ;
2020-02-12 11:12:20 -08:00
// protect against null pointer dereference
2020-12-01 00:36:36 +01:00
CHECK_NONFATAL ( node_context ) ;
CHECK_NONFATAL ( node_context - > scheduler ) ;
node_context - > scheduler - > MockForward ( std : : chrono : : seconds ( delta_seconds ) ) ;
2020-02-12 11:12:20 -08:00
return NullUniValue ;
2020-07-15 21:26:22 +02:00
} ,
} ;
2020-02-12 11:12:20 -08:00
}
2016-09-18 10:22:30 +02:00
static UniValue RPCLockedMemoryInfo ( )
{
LockedPool : : Stats stats = LockedPoolManager : : Instance ( ) . stats ( ) ;
UniValue obj ( UniValue : : VOBJ ) ;
2017-09-22 20:04:07 +02:00
obj . pushKV ( " used " , uint64_t ( stats . used ) ) ;
obj . pushKV ( " free " , uint64_t ( stats . free ) ) ;
obj . pushKV ( " total " , uint64_t ( stats . total ) ) ;
obj . pushKV ( " locked " , uint64_t ( stats . locked ) ) ;
obj . pushKV ( " chunks_used " , uint64_t ( stats . chunks_used ) ) ;
obj . pushKV ( " chunks_free " , uint64_t ( stats . chunks_free ) ) ;
2016-09-18 10:22:30 +02:00
return obj ;
}
2017-03-20 10:09:01 +01:00
# ifdef HAVE_MALLOC_INFO
static std : : string RPCMallocInfo ( )
{
char * ptr = nullptr ;
size_t size = 0 ;
FILE * f = open_memstream ( & ptr , & size ) ;
if ( f ) {
malloc_info ( 0 , f ) ;
fclose ( f ) ;
if ( ptr ) {
std : : string rv ( ptr , size ) ;
free ( ptr ) ;
return rv ;
}
}
return " " ;
}
# endif
2020-07-15 21:26:22 +02:00
static RPCHelpMan getmemoryinfo ( )
2016-09-18 10:22:30 +02:00
{
/* Please, avoid using the word "pool" here in the RPC interface or help,
* as users will undoubtedly confuse it with the other " memory pool "
*/
2020-07-15 21:26:22 +02:00
return RPCHelpMan { " getmemoryinfo " ,
2018-10-20 08:19:44 -04:00
" Returns an object containing information about memory usage. \n " ,
{
2021-04-14 15:01:00 +01:00
{ " mode " , RPCArg : : Type : : STR , RPCArg : : Default { " stats " } , " determines what kind of information is returned. \n "
2018-11-23 11:21:38 -05:00
" - \" stats \" returns general statistics about memory usage in the daemon. \n "
" - \" mallocinfo \" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+). " } ,
2018-12-21 12:29:36 -05:00
} ,
{
RPCResult { " mode \" stats \" " ,
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : OBJ , " " , " " ,
{
{ RPCResult : : Type : : OBJ , " locked " , " Information about locked memory manager " ,
{
{ RPCResult : : Type : : NUM , " used " , " Number of bytes used " } ,
{ RPCResult : : Type : : NUM , " free " , " Number of bytes available in current arenas " } ,
{ RPCResult : : Type : : NUM , " total " , " Total number of bytes managed " } ,
{ RPCResult : : Type : : NUM , " locked " , " Amount of bytes that succeeded locking. If this number is smaller than total, locking pages failed at some point and key data could be swapped to disk. " } ,
{ RPCResult : : Type : : NUM , " chunks_used " , " Number allocated chunks " } ,
{ RPCResult : : Type : : NUM , " chunks_free " , " Number unused chunks " } ,
} } ,
}
2018-12-21 12:29:36 -05:00
} ,
RPCResult { " mode \" mallocinfo \" " ,
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : STR , " " , " \" <malloc version= \" 1 \" >... \" "
2018-12-21 12:29:36 -05:00
} ,
} ,
RPCExamples {
HelpExampleCli ( " getmemoryinfo " , " " )
2016-09-18 10:22:30 +02:00
+ HelpExampleRpc ( " getmemoryinfo " , " " )
2018-12-21 12:29:36 -05:00
} ,
2020-07-15 21:26:22 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2017-08-14 19:38:18 -04:00
std : : string mode = request . params [ 0 ] . isNull ( ) ? " stats " : request . params [ 0 ] . get_str ( ) ;
2017-03-20 10:09:01 +01:00
if ( mode = = " stats " ) {
UniValue obj ( UniValue : : VOBJ ) ;
2017-09-22 20:04:07 +02:00
obj . pushKV ( " locked " , RPCLockedMemoryInfo ( ) ) ;
2017-03-20 10:09:01 +01:00
return obj ;
} else if ( mode = = " mallocinfo " ) {
# ifdef HAVE_MALLOC_INFO
return RPCMallocInfo ( ) ;
# else
2021-12-01 19:18:26 +08:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " mallocinfo mode not available " ) ;
2017-03-20 10:09:01 +01:00
# endif
} else {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " unknown mode " + mode ) ;
}
2020-07-15 21:26:22 +02:00
} ,
} ;
2016-09-18 10:22:30 +02:00
}
2018-05-02 17:14:48 +02:00
static void EnableOrDisableLogCategories ( UniValue cats , bool enable ) {
2017-04-03 13:39:11 -04:00
cats = cats . get_array ( ) ;
for ( unsigned int i = 0 ; i < cats . size ( ) ; + + i ) {
std : : string cat = cats [ i ] . get_str ( ) ;
2018-04-11 14:06:35 -07:00
bool success ;
2018-04-11 13:02:01 -07:00
if ( enable ) {
2019-01-25 15:54:49 -05:00
success = LogInstance ( ) . EnableCategory ( cat ) ;
2018-04-11 13:02:01 -07:00
} else {
2019-01-25 15:54:49 -05:00
success = LogInstance ( ) . DisableCategory ( cat ) ;
2018-04-11 14:06:35 -07:00
}
if ( ! success ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " unknown logging category " + cat ) ;
2017-08-29 20:32:16 +09:00
}
2017-04-03 13:39:11 -04:00
}
}
2020-07-15 21:26:22 +02:00
static RPCHelpMan logging ( )
2017-04-03 13:39:11 -04:00
{
2020-07-15 21:26:22 +02:00
return RPCHelpMan { " logging " ,
2017-04-03 13:39:11 -04:00
" Gets and sets the logging configuration. \n "
2017-08-29 20:32:16 +09:00
" When called without an argument, returns the list of categories with status that are currently being debug logged or not. \n "
" When called with arguments, adds or removes categories from debug logging and return the lists above. \n "
" The arguments are evaluated in order \" include \" , \" exclude \" . \n "
" If an item is both included and excluded, it will thus end up being excluded. \n "
2020-04-16 11:12:14 -04:00
" The valid logging categories are: " + LogInstance ( ) . LogCategoriesString ( ) + " \n "
2017-08-29 20:32:16 +09:00
" In addition, the following are available as category names with special meanings: \n "
" - \" all \" , \" 1 \" : represent all logging categories. \n "
" - \" none \" , \" 0 \" : even if other logging categories are specified, ignore all of them. \n "
2018-10-20 08:19:44 -04:00
,
{
2020-03-05 10:36:27 +00:00
{ " include " , RPCArg : : Type : : ARR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " The categories to add to debug logging " ,
2018-11-23 11:21:38 -05:00
{
2018-12-10 16:56:51 -05:00
{ " include_category " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED , " the valid logging category " } ,
2018-11-23 11:21:38 -05:00
} } ,
2020-03-05 10:36:27 +00:00
{ " exclude " , RPCArg : : Type : : ARR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " The categories to remove from debug logging " ,
2018-11-23 11:21:38 -05:00
{
2018-12-10 16:56:51 -05:00
{ " exclude_category " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED , " the valid logging category " } ,
2018-11-23 11:21:38 -05:00
} } ,
2018-12-21 12:29:36 -05:00
} ,
RPCResult {
2020-01-10 00:00:57 +07:00
RPCResult : : Type : : OBJ_DYN , " " , " keys are the logging categories, and values indicates its status " ,
{
{ RPCResult : : Type : : BOOL , " category " , " if being debug logged or not. false:inactive, true:active " } ,
}
2018-12-21 12:29:36 -05:00
} ,
RPCExamples {
HelpExampleCli ( " logging " , " \" [ \\ \" all \\ \" ] \" \" [ \\ \" http \\ \" ] \" " )
2019-01-27 22:47:55 +08:00
+ HelpExampleRpc ( " logging " , " [ \" all \" ], [ \" libevent \" ] " )
2018-12-21 12:29:36 -05:00
} ,
2020-07-15 21:26:22 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2019-01-25 15:54:49 -05:00
uint32_t original_log_categories = LogInstance ( ) . GetCategoryMask ( ) ;
2017-08-14 19:38:18 -04:00
if ( request . params [ 0 ] . isArray ( ) ) {
2018-04-11 13:02:01 -07:00
EnableOrDisableLogCategories ( request . params [ 0 ] , true ) ;
2017-04-03 13:39:11 -04:00
}
2017-08-14 19:38:18 -04:00
if ( request . params [ 1 ] . isArray ( ) ) {
2018-04-11 13:02:01 -07:00
EnableOrDisableLogCategories ( request . params [ 1 ] , false ) ;
2017-04-03 13:39:11 -04:00
}
2019-01-25 15:54:49 -05:00
uint32_t updated_log_categories = LogInstance ( ) . GetCategoryMask ( ) ;
2018-04-11 13:02:01 -07:00
uint32_t changed_log_categories = original_log_categories ^ updated_log_categories ;
2017-04-03 13:39:11 -04:00
2017-04-10 10:34:23 -04:00
// Update libevent logging if BCLog::LIBEVENT has changed.
// If the library version doesn't allow it, UpdateHTTPServerLogging() returns false,
// in which case we should clear the BCLog::LIBEVENT flag.
// Throw an error if the user has explicitly asked to change only the libevent
// flag and it failed.
2018-04-11 13:02:01 -07:00
if ( changed_log_categories & BCLog : : LIBEVENT ) {
2019-01-25 15:54:49 -05:00
if ( ! UpdateHTTPServerLogging ( LogInstance ( ) . WillLogCategory ( BCLog : : LIBEVENT ) ) ) {
LogInstance ( ) . DisableCategory ( BCLog : : LIBEVENT ) ;
2018-04-11 13:02:01 -07:00
if ( changed_log_categories = = BCLog : : LIBEVENT ) {
2017-04-10 10:34:23 -04:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " libevent logging cannot be updated when using libevent before v2.1.1. " ) ;
}
}
}
2017-04-03 13:39:11 -04:00
UniValue result ( UniValue : : VOBJ ) ;
2020-04-16 11:12:14 -04:00
for ( const auto & logCatActive : LogInstance ( ) . LogCategoriesList ( ) ) {
2017-04-03 13:39:11 -04:00
result . pushKV ( logCatActive . category , logCatActive . active ) ;
}
return result ;
2020-07-15 21:26:22 +02:00
} ,
} ;
2017-04-03 13:39:11 -04:00
}
2020-07-15 21:26:22 +02:00
static RPCHelpMan echo ( const std : : string & name )
2016-09-25 20:55:24 +02:00
{
2020-07-15 21:26:22 +02:00
return RPCHelpMan { name ,
2018-10-20 08:19:44 -04:00
" \n Simply echo back the input arguments. This command is for testing. \n "
2020-07-15 22:10:45 +02:00
" \n It will return an internal bug report when arg9='trigger_internal_bug' is passed. \n "
2018-11-15 12:19:41 -05:00
" \n The difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in "
2018-10-20 08:19:44 -04:00
" bitcoin-cli and the GUI. There is no server-side difference. " ,
2020-07-15 22:10:45 +02:00
{
{ " arg0 " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " " } ,
{ " arg1 " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " " } ,
{ " arg2 " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " " } ,
{ " arg3 " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " " } ,
{ " arg4 " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " " } ,
{ " arg5 " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " " } ,
{ " arg6 " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " " } ,
{ " arg7 " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " " } ,
{ " arg8 " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " " } ,
{ " arg9 " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " " } ,
} ,
2020-11-23 10:41:27 +01:00
RPCResult { RPCResult : : Type : : ANY , " " , " Returns whatever was passed in " } ,
2018-12-21 12:29:36 -05:00
RPCExamples { " " } ,
2020-07-15 21:26:22 +02:00
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
2020-07-15 22:10:45 +02:00
if ( request . params [ 9 ] . isStr ( ) ) {
CHECK_NONFATAL ( request . params [ 9 ] . get_str ( ) ! = " trigger_internal_bug " ) ;
}
2019-09-23 14:45:51 -04:00
2016-09-25 20:55:24 +02:00
return request . params ;
2020-07-15 21:26:22 +02:00
} ,
} ;
2016-09-25 20:55:24 +02:00
}
2020-07-15 21:26:22 +02:00
static RPCHelpMan echo ( ) { return echo ( " echo " ) ; }
static RPCHelpMan echojson ( ) { return echo ( " echojson " ) ; }
2020-11-24 13:59:33 -05:00
static RPCHelpMan echoipc ( )
{
return RPCHelpMan {
" echoipc " ,
" \n Echo back the input argument, passing it through a spawned process in a multiprocess build. \n "
" This command is for testing. \n " ,
{ { " arg " , RPCArg : : Type : : STR , RPCArg : : Optional : : NO , " The string to echo " , } } ,
RPCResult { RPCResult : : Type : : STR , " echo " , " The echoed string. " } ,
RPCExamples { HelpExampleCli ( " echo " , " \" Hello world \" " ) +
HelpExampleRpc ( " echo " , " \" Hello world \" " ) } ,
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue {
2017-12-05 15:57:12 -05:00
interfaces : : Init & local_init = * EnsureAnyNodeContext ( request . context ) . init ;
2020-11-24 13:59:33 -05:00
std : : unique_ptr < interfaces : : Echo > echo ;
2017-12-05 15:57:12 -05:00
if ( interfaces : : Ipc * ipc = local_init . ipc ( ) ) {
2020-11-24 13:59:33 -05:00
// Spawn a new bitcoin-node process and call makeEcho to get a
// client pointer to a interfaces::Echo instance running in
// that process. This is just for testing. A slightly more
// realistic test spawning a different executable instead of
// the same executable would add a new bitcoin-echo executable,
// and spawn bitcoin-echo below instead of bitcoin-node. But
// using bitcoin-node avoids the need to build and install a
// new executable just for this one test.
auto init = ipc - > spawnProcess ( " bitcoin-node " ) ;
echo = init - > makeEcho ( ) ;
ipc - > addCleanup ( * echo , [ init = init . release ( ) ] { delete init ; } ) ;
} else {
// IPC support is not available because this is a bitcoind
// process not a bitcoind-node process, so just create a local
// interfaces::Echo object and return it so the `echoipc` RPC
// method will work, and the python test calling `echoipc`
// can expect the same result.
2017-12-05 15:57:12 -05:00
echo = local_init . makeEcho ( ) ;
2020-11-24 13:59:33 -05:00
}
return echo - > echo ( request . params [ 0 ] . get_str ( ) ) ;
} ,
} ;
}
2020-07-31 14:01:31 +02:00
static UniValue SummaryToJSON ( const IndexSummary & & summary , std : : string index_name )
{
UniValue ret_summary ( UniValue : : VOBJ ) ;
if ( ! index_name . empty ( ) & & index_name ! = summary . name ) return ret_summary ;
UniValue entry ( UniValue : : VOBJ ) ;
entry . pushKV ( " synced " , summary . synced ) ;
entry . pushKV ( " best_block_height " , summary . best_block_height ) ;
ret_summary . pushKV ( summary . name , entry ) ;
return ret_summary ;
}
static RPCHelpMan getindexinfo ( )
{
return RPCHelpMan { " getindexinfo " ,
" \n Returns the status of one or all available indices currently running in the node. \n " ,
{
{ " index_name " , RPCArg : : Type : : STR , RPCArg : : Optional : : OMITTED_NAMED_ARG , " Filter results for an index with a specific name. " } ,
} ,
RPCResult {
2021-08-25 19:55:15 +02:00
RPCResult : : Type : : OBJ_DYN , " " , " " , {
2020-07-31 14:01:31 +02:00
{
RPCResult : : Type : : OBJ , " name " , " The name of the index " ,
{
{ RPCResult : : Type : : BOOL , " synced " , " Whether the index is synced or not " } ,
{ RPCResult : : Type : : NUM , " best_block_height " , " The block height to which the index is synced " } ,
}
} ,
} ,
} ,
RPCExamples {
HelpExampleCli ( " getindexinfo " , " " )
+ HelpExampleRpc ( " getindexinfo " , " " )
+ HelpExampleCli ( " getindexinfo " , " txindex " )
+ HelpExampleRpc ( " getindexinfo " , " txindex " )
} ,
[ & ] ( const RPCHelpMan & self , const JSONRPCRequest & request ) - > UniValue
{
UniValue result ( UniValue : : VOBJ ) ;
const std : : string index_name = request . params [ 0 ] . isNull ( ) ? " " : request . params [ 0 ] . get_str ( ) ;
if ( g_txindex ) {
result . pushKVs ( SummaryToJSON ( g_txindex - > GetSummary ( ) , index_name ) ) ;
}
2020-08-22 18:31:34 +02:00
if ( g_coin_stats_index ) {
result . pushKVs ( SummaryToJSON ( g_coin_stats_index - > GetSummary ( ) , index_name ) ) ;
}
2020-07-31 14:01:31 +02:00
ForEachBlockFilterIndex ( [ & result , & index_name ] ( const BlockFilterIndex & index ) {
result . pushKVs ( SummaryToJSON ( index . GetSummary ( ) , index_name ) ) ;
} ) ;
return result ;
} ,
} ;
}
2020-04-06 00:21:33 +08:00
void RegisterMiscRPCCommands ( CRPCTable & t )
{
2018-08-20 14:19:43 +02:00
// clang-format off
2016-03-29 19:43:02 +02:00
static const CRPCCommand commands [ ] =
2021-01-12 06:41:46 +01:00
{ // category actor (function)
// --------------------- ------------------------
{ " control " , & getmemoryinfo , } ,
{ " control " , & logging , } ,
{ " util " , & validateaddress , } ,
{ " util " , & createmultisig , } ,
{ " util " , & deriveaddresses , } ,
{ " util " , & getdescriptorinfo , } ,
{ " util " , & verifymessage , } ,
{ " util " , & signmessagewithprivkey , } ,
{ " util " , & getindexinfo , } ,
2016-03-29 19:43:02 +02:00
/* Not shown in help */
2021-01-12 06:41:46 +01:00
{ " hidden " , & setmocktime , } ,
{ " hidden " , & mockscheduler , } ,
{ " hidden " , & echo , } ,
{ " hidden " , & echojson , } ,
2020-11-24 13:59:33 -05:00
{ " hidden " , & echoipc , } ,
2021-10-01 13:53:59 +00:00
# if defined(USE_SYSCALL_SANDBOX)
{ " hidden " , & invokedisallowedsyscall , } ,
# endif // USE_SYSCALL_SANDBOX
2016-03-29 19:43:02 +02:00
} ;
2018-08-20 14:19:43 +02:00
// clang-format on
2020-07-15 21:29:41 +02:00
for ( const auto & c : commands ) {
t . appendCommand ( c . name , & c ) ;
}
2016-03-29 19:43:02 +02:00
}