2021-12-12 14:38:12 +01:00
// Copyright (c) 2017-2019 The Bitcoin Core developers
2020-05-15 11:34:41 +02:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# ifndef BITCOIN_RPC_UTIL_H
# define BITCOIN_RPC_UTIL_H
2019-01-30 06:32:38 +01:00
# include <node/transaction.h>
2019-03-01 17:06:27 +01:00
# include <protocol.h>
2022-02-27 09:05:32 +01:00
# include <pubkey.h>
2019-02-22 20:42:58 +01:00
# include <rpc/protocol.h>
2022-02-27 08:46:53 +01:00
# include <rpc/request.h>
2020-12-17 13:46:20 +01:00
# include <script/standard.h>
# include <univalue.h>
2022-02-27 09:05:32 +01:00
# include <util/check.h>
2021-06-27 08:33:13 +02:00
# include <util/strencodings.h>
2020-12-17 13:46:20 +01:00
2020-05-15 11:34:41 +02:00
# include <string>
# include <vector>
2019-02-13 00:42:50 +01:00
# include <boost/variant.hpp>
2020-05-15 11:34:41 +02:00
class CKeyStore ;
class CPubKey ;
class CScript ;
2019-12-25 21:26:59 +01:00
struct Sections ;
2018-11-09 15:36:34 +01:00
struct InitInterfaces ;
//! Pointers to interfaces that need to be accessible from RPC methods. Due to
//! limitations of the RPC framework, there's currently no direct way to pass in
//! state to RPC method implementations.
extern InitInterfaces * g_rpc_interfaces ;
2020-05-15 11:34:41 +02:00
2021-11-16 16:19:47 +01:00
/** Wrapper for UniValue::VType, which includes typeAny:
* Used to denote don ' t care type . */
struct UniValueType {
UniValueType ( UniValue : : VType _type ) : typeAny ( false ) , type ( _type ) { }
UniValueType ( ) : typeAny ( true ) { }
bool typeAny ;
UniValue : : VType type ;
} ;
/**
* Type - check arguments ; throws JSONRPCError if wrong type given . Does not check that
* the right number of arguments are passed , just that any passed are the correct type .
*/
void RPCTypeCheck ( const UniValue & params ,
const std : : list < UniValueType > & typesExpected , bool fAllowNull = false ) ;
/**
* Type - check one argument ; throws JSONRPCError if wrong type given .
*/
void RPCTypeCheckArgument ( const UniValue & value , const UniValueType & typeExpected ) ;
/*
Check for expected keys / value types in an Object .
*/
void RPCTypeCheckObj ( const UniValue & o ,
const std : : map < std : : string , UniValueType > & typesExpected ,
bool fAllowNull = false ,
bool fStrict = false ) ;
/**
* Utilities : convert hex - encoded Values
* ( throws error if not hex ) .
*/
extern uint256 ParseHashV ( const UniValue & v , std : : string strName ) ;
extern uint256 ParseHashO ( const UniValue & o , std : : string strKey ) ;
extern std : : vector < unsigned char > ParseHexV ( const UniValue & v , std : : string strName ) ;
extern std : : vector < unsigned char > ParseHexO ( const UniValue & o , std : : string strKey ) ;
extern int32_t ParseInt32V ( const UniValue & v , const std : : string & strName ) ;
extern int64_t ParseInt64V ( const UniValue & v , const std : : string & strName ) ;
extern double ParseDoubleV ( const UniValue & v , const std : : string & strName ) ;
extern bool ParseBoolV ( const UniValue & v , const std : : string & strName ) ;
extern CAmount AmountFromValue ( const UniValue & value ) ;
extern std : : string HelpExampleCli ( const std : : string & methodname , const std : : string & args ) ;
extern std : : string HelpExampleRpc ( const std : : string & methodname , const std : : string & args ) ;
2020-05-15 11:34:41 +02:00
CPubKey HexToPubKey ( const std : : string & hex_in ) ;
CPubKey AddrToPubKey ( CKeyStore * const keystore , const std : : string & addr_in ) ;
CScript CreateMultisigRedeemscript ( const int required , const std : : vector < CPubKey > & pubkeys ) ;
2020-12-17 13:46:20 +01:00
UniValue DescribeAddress ( const CTxDestination & dest ) ;
2019-02-11 14:34:10 +01:00
//! Parse a confirm target option and raise an RPC error if it is invalid.
2021-11-14 11:02:37 +01:00
unsigned int ParseConfirmTarget ( const UniValue & value , unsigned int max_target ) ;
2019-02-11 14:34:10 +01:00
2019-03-01 17:06:27 +01:00
/** Returns, given services flags, a list of humanly readable (known) network services */
UniValue GetServicesNames ( ServiceFlags services ) ;
Merge #15497: rpc: Consistent range arguments in scantxoutset/importmulti/deriveaddresses
ca253f6ebf Make deriveaddresses use stop/[start,stop] notation for ranges (Pieter Wuille)
1675b7ce55 Use stop/[start,stop] notation in importmulti desc range (Pieter Wuille)
4566011631 Add support for stop/[start,stop] ranges to scantxoutset (Pieter Wuille)
6b9f45e81b Support ranges arguments in RPC help (Pieter Wuille)
7aa6a8aefb Add ParseRange function to parse args of the form int/[int,int] (Pieter Wuille)
Pull request description:
This introduces a consistent notation for RPC arguments in `scantxoutset`, `importmulti`, and `deriveaddresses`, either:
* `"range" : int` to just specify the end of the range
* `"range" : [int,int]` to specify both the begin and the end of the range.
For `scantxoutset`, this is a backward compatible new feature. For the two other RPCs, it's an incompatible change, but neither of them has been in a release so far. Because of that non-released reason, this only makes sense in 0.18, in my opinion.
I suggest this as an alternative to #15496, which only makes `deriveaddresses` compatible with `importmulti`, but not with the existing `scantxoutset` RPC. I also think `[int,int]` is more convenient than `{"start":int,"stop":int}`.
I realize this is technically a feature added to `scantxoutset` after the feature freeze. If desired, I'll drop the `scantxoutset` changes.
Tree-SHA512: 1cbebb90cf34f106786dbcec7afbf3f43fb8b7e46cc7e6763faf1bc1babf12375a1b3c3cf86ee83c21ed2171d99b5a2f60331850bc613db25538c38b6a056676
2019-03-01 15:13:05 +01:00
//! Parse a JSON range specified as int64, or [int64, int64]
2019-05-10 14:09:34 +02:00
std : : pair < int64_t , int64_t > ParseDescriptorRange ( const UniValue & value ) ;
Merge #15497: rpc: Consistent range arguments in scantxoutset/importmulti/deriveaddresses
ca253f6ebf Make deriveaddresses use stop/[start,stop] notation for ranges (Pieter Wuille)
1675b7ce55 Use stop/[start,stop] notation in importmulti desc range (Pieter Wuille)
4566011631 Add support for stop/[start,stop] ranges to scantxoutset (Pieter Wuille)
6b9f45e81b Support ranges arguments in RPC help (Pieter Wuille)
7aa6a8aefb Add ParseRange function to parse args of the form int/[int,int] (Pieter Wuille)
Pull request description:
This introduces a consistent notation for RPC arguments in `scantxoutset`, `importmulti`, and `deriveaddresses`, either:
* `"range" : int` to just specify the end of the range
* `"range" : [int,int]` to specify both the begin and the end of the range.
For `scantxoutset`, this is a backward compatible new feature. For the two other RPCs, it's an incompatible change, but neither of them has been in a release so far. Because of that non-released reason, this only makes sense in 0.18, in my opinion.
I suggest this as an alternative to #15496, which only makes `deriveaddresses` compatible with `importmulti`, but not with the existing `scantxoutset` RPC. I also think `[int,int]` is more convenient than `{"start":int,"stop":int}`.
I realize this is technically a feature added to `scantxoutset` after the feature freeze. If desired, I'll drop the `scantxoutset` changes.
Tree-SHA512: 1cbebb90cf34f106786dbcec7afbf3f43fb8b7e46cc7e6763faf1bc1babf12375a1b3c3cf86ee83c21ed2171d99b5a2f60331850bc613db25538c38b6a056676
2019-03-01 15:13:05 +01:00
2019-12-25 21:26:59 +01:00
/**
* Serializing JSON objects depends on the outer type . Only arrays and
* dictionaries can be nested in json . The top - level outer type is " NONE " .
*/
enum class OuterType {
ARR ,
OBJ ,
NONE , // Only set on first recursion
} ;
2018-11-13 18:34:43 +01:00
struct RPCArg {
enum class Type {
OBJ ,
ARR ,
STR ,
NUM ,
BOOL ,
OBJ_USER_KEYS , //!< Special type where the user must set the keys e.g. to define multiple addresses; as opposed to e.g. an options object where the keys are predefined
AMOUNT , //!< Special type representing a floating point amount (can be either NUM or STR)
STR_HEX , //!< Special type that is a STR with only hex chars
Merge #15497: rpc: Consistent range arguments in scantxoutset/importmulti/deriveaddresses
ca253f6ebf Make deriveaddresses use stop/[start,stop] notation for ranges (Pieter Wuille)
1675b7ce55 Use stop/[start,stop] notation in importmulti desc range (Pieter Wuille)
4566011631 Add support for stop/[start,stop] ranges to scantxoutset (Pieter Wuille)
6b9f45e81b Support ranges arguments in RPC help (Pieter Wuille)
7aa6a8aefb Add ParseRange function to parse args of the form int/[int,int] (Pieter Wuille)
Pull request description:
This introduces a consistent notation for RPC arguments in `scantxoutset`, `importmulti`, and `deriveaddresses`, either:
* `"range" : int` to just specify the end of the range
* `"range" : [int,int]` to specify both the begin and the end of the range.
For `scantxoutset`, this is a backward compatible new feature. For the two other RPCs, it's an incompatible change, but neither of them has been in a release so far. Because of that non-released reason, this only makes sense in 0.18, in my opinion.
I suggest this as an alternative to #15496, which only makes `deriveaddresses` compatible with `importmulti`, but not with the existing `scantxoutset` RPC. I also think `[int,int]` is more convenient than `{"start":int,"stop":int}`.
I realize this is technically a feature added to `scantxoutset` after the feature freeze. If desired, I'll drop the `scantxoutset` changes.
Tree-SHA512: 1cbebb90cf34f106786dbcec7afbf3f43fb8b7e46cc7e6763faf1bc1babf12375a1b3c3cf86ee83c21ed2171d99b5a2f60331850bc613db25538c38b6a056676
2019-03-01 15:13:05 +01:00
RANGE , //!< Special type that is a NUM or [NUM,NUM]
2018-11-13 18:34:43 +01:00
} ;
2019-02-13 00:42:50 +01:00
enum class Optional {
/** Required arg */
NO ,
/**
2021-12-12 14:38:12 +01:00
* Optional arg that is a named argument and has a default value of
2019-02-13 00:42:50 +01:00
* ` null ` . When possible , the default value should be specified .
*/
OMITTED_NAMED_ARG ,
/**
* Optional argument with default value omitted because they are
* implicitly clear . That is , elements in an array or object may not
* exist by default .
* When possible , the default value should be specified .
*/
OMITTED ,
} ;
using Fallback = boost : : variant < Optional , /* default value for optional args */ std : : string > ;
2022-03-01 07:30:23 +01:00
const std : : string m_names ; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments)
2018-11-13 18:34:43 +01:00
const Type m_type ;
2020-04-17 19:28:29 +02:00
const bool m_hidden ;
2018-11-13 18:34:43 +01:00
const std : : vector < RPCArg > m_inner ; //!< Only used for arrays or dicts
2019-02-13 00:42:50 +01:00
const Fallback m_fallback ;
2018-12-05 17:02:57 +01:00
const std : : string m_description ;
2021-10-11 23:55:23 +02:00
const std : : string m_oneline_description ; //!< Should be empty unless it is supposed to override the auto-generated summary line
2018-12-05 17:02:57 +01:00
const std : : vector < std : : string > m_type_str ; //!< Should be empty unless it is supposed to override the auto-generated type strings. Vector length is either 0 or 2, m_type_str.at(0) will override the type of the value in a key-value pair, m_type_str.at(1) will override the type in the argument description.
RPCArg (
2019-12-25 21:26:59 +01:00
const std : : string name ,
const Type type ,
const Fallback fallback ,
const std : : string description ,
const std : : string oneline_description = " " ,
2020-04-17 19:28:29 +02:00
const std : : vector < std : : string > type_str = { } ,
const bool hidden = false )
2022-03-01 07:30:23 +01:00
: m_names { std : : move ( name ) } ,
2019-12-25 21:26:59 +01:00
m_type { std : : move ( type ) } ,
2020-04-17 19:28:29 +02:00
m_hidden { hidden } ,
2019-12-25 21:26:59 +01:00
m_fallback { std : : move ( fallback ) } ,
m_description { std : : move ( description ) } ,
m_oneline_description { std : : move ( oneline_description ) } ,
m_type_str { std : : move ( type_str ) }
2018-11-13 18:34:43 +01:00
{
2022-02-27 09:05:32 +01:00
CHECK_NONFATAL ( type ! = Type : : ARR & & type ! = Type : : OBJ ) ;
2018-11-13 18:34:43 +01:00
}
2018-12-05 17:02:57 +01:00
RPCArg (
2019-12-25 21:26:59 +01:00
const std : : string name ,
const Type type ,
const Fallback fallback ,
const std : : string description ,
const std : : vector < RPCArg > inner ,
const std : : string oneline_description = " " ,
const std : : vector < std : : string > type_str = { } )
2022-03-01 07:30:23 +01:00
: m_names { std : : move ( name ) } ,
2019-12-25 21:26:59 +01:00
m_type { std : : move ( type ) } ,
2020-04-17 19:28:29 +02:00
m_hidden { false } ,
2019-12-25 21:26:59 +01:00
m_inner { std : : move ( inner ) } ,
m_fallback { std : : move ( fallback ) } ,
m_description { std : : move ( description ) } ,
m_oneline_description { std : : move ( oneline_description ) } ,
m_type_str { std : : move ( type_str ) }
2018-11-13 18:34:43 +01:00
{
2022-02-27 09:05:32 +01:00
CHECK_NONFATAL ( type = = Type : : ARR | | type = = Type : : OBJ ) ;
2018-11-13 18:34:43 +01:00
}
2021-12-12 14:38:12 +01:00
bool IsOptional ( ) const ;
2022-03-01 07:30:23 +01:00
/** Return the first of all aliases */
std : : string GetFirstName ( ) const ;
/** Return the name, throws when there are aliases */
std : : string GetName ( ) const ;
2018-12-05 17:02:57 +01:00
/**
* Return the type string of the argument .
2018-12-10 20:02:15 +01:00
* Set oneline to allow it to be overridden by a custom oneline type string ( m_oneline_description ) .
2018-12-05 17:02:57 +01:00
*/
std : : string ToString ( bool oneline ) const ;
/**
* Return the type string of the argument when it is in an object ( dict ) .
* Set oneline to get the oneline representation ( less whitespace )
*/
std : : string ToStringObj ( bool oneline ) const ;
/**
* Return the description string , including the argument type and whether
* the argument is required .
*/
2019-02-13 00:42:50 +01:00
std : : string ToDescriptionString ( ) const ;
2018-11-13 18:34:43 +01:00
} ;
2019-01-29 15:55:37 +01:00
struct RPCResult {
2019-12-25 21:26:59 +01:00
enum class Type {
OBJ ,
ARR ,
STR ,
NUM ,
BOOL ,
NONE ,
STR_AMOUNT , //!< Special string to represent a floating point amount
STR_HEX , //!< Special string with only hex chars
OBJ_DYN , //!< Special dictionary with keys that are not literals
ARR_FIXED , //!< Special array that has a fixed number of entries
NUM_TIME , //!< Special numeric to denote unix epoch time
ELISION , //!< Special type to denote elision (...)
} ;
const Type m_type ;
const std : : string m_key_name ; //!< Only used for dicts
const std : : vector < RPCResult > m_inner ; //!< Only used for arrays or dicts
const bool m_optional ;
const std : : string m_description ;
2019-01-29 15:55:37 +01:00
const std : : string m_cond ;
2022-03-04 15:49:24 +01:00
const bool m_legacy ; //!< Used for legacy support
const std : : string m_result ; //!< Used for legacy support
2019-01-29 15:55:37 +01:00
2019-12-25 21:26:59 +01:00
RPCResult (
const std : : string cond ,
const Type type ,
const std : : string m_key_name ,
const bool optional ,
const std : : string description ,
const std : : vector < RPCResult > inner = { } )
: m_type { std : : move ( type ) } ,
m_key_name { std : : move ( m_key_name ) } ,
m_inner { std : : move ( inner ) } ,
m_optional { optional } ,
m_description { std : : move ( description ) } ,
2022-03-04 15:49:24 +01:00
m_cond { std : : move ( cond ) } ,
m_result { } ,
m_legacy { false }
2019-01-29 15:55:37 +01:00
{
2019-12-25 21:26:59 +01:00
CHECK_NONFATAL ( ! m_cond . empty ( ) ) ;
const bool inner_needed { type = = Type : : ARR | | type = = Type : : ARR_FIXED | | type = = Type : : OBJ | | type = = Type : : OBJ_DYN } ;
CHECK_NONFATAL ( inner_needed ! = inner . empty ( ) ) ;
2019-01-29 15:55:37 +01:00
}
2022-03-04 15:49:24 +01:00
// start legacy support logic
RPCResult ( std : : string cond , std : : string result )
: m_type { Type : : NONE } ,
m_key_name { } ,
m_inner { } ,
m_optional { false } ,
m_description { } ,
m_cond { std : : move ( cond ) } ,
m_result { std : : move ( result ) } ,
m_legacy { true }
{
CHECK_NONFATAL ( ! m_cond . empty ( ) ) ;
CHECK_NONFATAL ( ! m_result . empty ( ) ) ;
}
RPCResult ( std : : string result )
: m_type { Type : : NONE } ,
m_key_name { } ,
m_inner { } ,
m_optional { false } ,
m_description { } ,
m_cond { } ,
m_result { std : : move ( result ) } ,
m_legacy { true }
{
CHECK_NONFATAL ( ! m_result . empty ( ) ) ;
}
// end legacy support logic
2019-12-25 21:26:59 +01:00
RPCResult (
const std : : string cond ,
const Type type ,
const std : : string m_key_name ,
const std : : string description ,
const std : : vector < RPCResult > inner = { } )
: RPCResult { cond , type , m_key_name , false , description , inner } { }
RPCResult (
const Type type ,
const std : : string m_key_name ,
const bool optional ,
const std : : string description ,
const std : : vector < RPCResult > inner = { } )
: m_type { std : : move ( type ) } ,
m_key_name { std : : move ( m_key_name ) } ,
m_inner { std : : move ( inner ) } ,
m_optional { optional } ,
m_description { std : : move ( description ) } ,
2022-03-04 15:49:24 +01:00
m_cond { } ,
m_result { } ,
m_legacy { false }
2019-01-29 15:55:37 +01:00
{
2019-12-25 21:26:59 +01:00
const bool inner_needed { type = = Type : : ARR | | type = = Type : : ARR_FIXED | | type = = Type : : OBJ | | type = = Type : : OBJ_DYN } ;
CHECK_NONFATAL ( inner_needed ! = inner . empty ( ) ) ;
2019-01-29 15:55:37 +01:00
}
2019-12-25 21:26:59 +01:00
RPCResult (
const Type type ,
const std : : string m_key_name ,
const std : : string description ,
const std : : vector < RPCResult > inner = { } )
: RPCResult { type , m_key_name , false , description , inner } { }
/** Append the sections of the result. */
void ToSections ( Sections & sections , OuterType outer_type = OuterType : : NONE , const int current_indent = 0 ) const ;
/** Return the type string of the result when it is in an object (dict). */
std : : string ToStringObj ( ) const ;
/** Return the description string, including the result type. */
std : : string ToDescriptionString ( ) const ;
2019-01-29 15:55:37 +01:00
} ;
struct RPCResults {
const std : : vector < RPCResult > m_results ;
RPCResults ( RPCResult result )
: m_results { { result } }
{
}
RPCResults ( std : : initializer_list < RPCResult > results )
: m_results { results }
{
}
/**
* Return the description string .
*/
std : : string ToDescriptionString ( ) const ;
} ;
struct RPCExamples {
const std : : string m_examples ;
2019-07-08 20:22:55 +02:00
explicit RPCExamples (
2019-01-29 15:55:37 +01:00
std : : string examples )
: m_examples ( std : : move ( examples ) )
{
}
std : : string ToDescriptionString ( ) const ;
} ;
2018-11-13 18:34:43 +01:00
class RPCHelpMan
{
public :
2019-01-29 15:55:37 +01:00
RPCHelpMan ( std : : string name , std : : string description , std : : vector < RPCArg > args , RPCResults results , RPCExamples examples ) ;
2020-04-17 19:28:29 +02:00
using RPCMethodImpl = std : : function < UniValue ( const RPCHelpMan & , const JSONRPCRequest & ) > ;
RPCHelpMan ( std : : string name , std : : string description , std : : vector < RPCArg > args , RPCResults results , RPCExamples examples , RPCMethodImpl fun ) ;
2018-11-13 18:34:43 +01:00
std : : string ToString ( ) const ;
2020-04-17 19:28:29 +02:00
UniValue HandleRequest ( const JSONRPCRequest & request )
{
Check ( request ) ;
return m_fun ( * this , request ) ;
}
2021-12-12 14:38:12 +01:00
/** If the supplied number of args is neither too small nor too high */
bool IsValidNumArgs ( size_t num_args ) const ;
2022-02-27 08:46:53 +01:00
/**
* Check if the given request is valid according to this command or if
* the user is asking for help information , and throw help when appropriate .
*/
inline void Check ( const JSONRPCRequest & request ) const {
if ( request . fHelp | | ! IsValidNumArgs ( request . params . size ( ) ) ) {
throw std : : runtime_error ( ToString ( ) ) ;
}
}
2018-11-13 18:34:43 +01:00
2022-02-27 08:44:07 +01:00
[ [ noreturn ] ] inline void Throw ( ) const {
throw std : : runtime_error ( ToString ( ) ) ;
}
2020-04-17 19:28:29 +02:00
std : : vector < std : : string > GetArgNames ( ) const ;
2018-11-13 18:34:43 +01:00
const std : : string m_name ;
2020-04-17 19:28:29 +02:00
private :
const RPCMethodImpl m_fun ;
2021-10-11 23:55:23 +02:00
const std : : string m_description ;
2018-11-13 18:34:43 +01:00
const std : : vector < RPCArg > m_args ;
2019-01-29 15:55:37 +01:00
const RPCResults m_results ;
const RPCExamples m_examples ;
2018-11-13 18:34:43 +01:00
} ;
2019-01-30 06:32:38 +01:00
RPCErrorCode RPCErrorFromTransactionError ( TransactionError terr ) ;
UniValue JSONRPCTransactionError ( TransactionError terr , const std : : string & err_string = " " ) ;
2020-05-15 11:34:41 +02:00
# endif // BITCOIN_RPC_UTIL_H