2018-07-27 00:36:45 +02:00
// Copyright (c) 2017-2018 The Bitcoin Core developers
2017-09-29 06:21:28 +02:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-09-20 03:12:25 +02:00
# include <key_io.h>
2017-09-29 06:21:28 +02:00
# include <keystore.h>
# include <rpc/protocol.h>
# include <rpc/util.h>
# include <tinyformat.h>
2018-10-23 00:51:11 +02:00
# include <util/strencodings.h>
2017-09-29 06:21:28 +02:00
2017-05-30 21:55:17 +02:00
InitInterfaces * g_rpc_interfaces = nullptr ;
2017-09-29 06:21:28 +02:00
// Converts a hex string to a public key if possible
CPubKey HexToPubKey ( const std : : string & hex_in )
{
if ( ! IsHex ( hex_in ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid public key: " + hex_in ) ;
}
CPubKey vchPubKey ( ParseHex ( hex_in ) ) ;
if ( ! vchPubKey . IsFullyValid ( ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid public key: " + hex_in ) ;
}
return vchPubKey ;
}
// Retrieves a public key for an address from the given CKeyStore
CPubKey AddrToPubKey ( CKeyStore * const keystore , const std : : string & addr_in )
{
CTxDestination dest = DecodeDestination ( addr_in ) ;
if ( ! IsValidDestination ( dest ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid address: " + addr_in ) ;
}
CKeyID key = GetKeyForDestination ( * keystore , dest ) ;
if ( key . IsNull ( ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , strprintf ( " %s does not refer to a key " , addr_in ) ) ;
}
CPubKey vchPubKey ;
if ( ! keystore - > GetPubKey ( key , vchPubKey ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , strprintf ( " no full public key for address %s " , addr_in ) ) ;
}
if ( ! vchPubKey . IsFullyValid ( ) ) {
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Wallet contains an invalid public key " ) ;
}
return vchPubKey ;
}
// Creates a multisig redeemscript from a given list of public keys and number required.
CScript CreateMultisigRedeemscript ( const int required , const std : : vector < CPubKey > & pubkeys )
{
// Gather public keys
if ( required < 1 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " a multisignature address must require at least one key to redeem " ) ;
}
if ( ( int ) pubkeys . size ( ) < required ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , strprintf ( " not enough keys supplied (got %u keys, but need at least %d to redeem) " , pubkeys.size(), required)) ;
}
if ( pubkeys . size ( ) > 16 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Number of keys involved in the multisignature address creation > 16 \n Reduce the number " ) ;
}
CScript result = GetScriptForMultisig ( required , pubkeys ) ;
if ( result . size ( ) > MAX_SCRIPT_ELEMENT_SIZE ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , ( strprintf ( " redeemScript exceeds size limit: %d > %d " , result . size ( ) , MAX_SCRIPT_ELEMENT_SIZE ) ) ) ;
}
return result ;
}
2017-12-04 18:49:20 +01:00
class DescribeAddressVisitor : public boost : : static_visitor < UniValue >
{
public :
explicit DescribeAddressVisitor ( ) { }
UniValue operator ( ) ( const CNoDestination & dest ) const
{
return UniValue ( UniValue : : VOBJ ) ;
}
UniValue operator ( ) ( const CKeyID & keyID ) const
{
UniValue obj ( UniValue : : VOBJ ) ;
obj . pushKV ( " isscript " , false ) ;
obj . pushKV ( " iswitness " , false ) ;
return obj ;
}
UniValue operator ( ) ( const CScriptID & scriptID ) const
{
UniValue obj ( UniValue : : VOBJ ) ;
obj . pushKV ( " isscript " , true ) ;
obj . pushKV ( " iswitness " , false ) ;
return obj ;
}
UniValue operator ( ) ( const WitnessV0KeyHash & id ) const
{
UniValue obj ( UniValue : : VOBJ ) ;
obj . pushKV ( " isscript " , false ) ;
obj . pushKV ( " iswitness " , true ) ;
obj . pushKV ( " witness_version " , 0 ) ;
obj . pushKV ( " witness_program " , HexStr ( id . begin ( ) , id . end ( ) ) ) ;
return obj ;
}
UniValue operator ( ) ( const WitnessV0ScriptHash & id ) const
{
UniValue obj ( UniValue : : VOBJ ) ;
obj . pushKV ( " isscript " , true ) ;
obj . pushKV ( " iswitness " , true ) ;
obj . pushKV ( " witness_version " , 0 ) ;
obj . pushKV ( " witness_program " , HexStr ( id . begin ( ) , id . end ( ) ) ) ;
return obj ;
}
UniValue operator ( ) ( const WitnessUnknown & id ) const
{
UniValue obj ( UniValue : : VOBJ ) ;
obj . pushKV ( " iswitness " , true ) ;
obj . pushKV ( " witness_version " , ( int ) id . version ) ;
obj . pushKV ( " witness_program " , HexStr ( id . program , id . program + id . length ) ) ;
return obj ;
}
} ;
UniValue DescribeAddress ( const CTxDestination & dest )
{
return boost : : apply_visitor ( DescribeAddressVisitor ( ) , dest ) ;
}
2018-10-23 21:22:28 +02:00
std : : string RPCHelpMan : : ToString ( ) const
{
std : : string ret ;
ret + = m_name ;
bool is_optional { false } ;
for ( const auto & arg : m_args ) {
ret + = " " ;
if ( arg . m_optional ) {
if ( ! is_optional ) ret + = " ( " ;
is_optional = true ;
} else {
// Currently we still support unnamed arguments, so any argument following an optional argument must also be optional
// If support for positional arguments is deprecated in the future, remove this line
assert ( ! is_optional ) ;
}
ret + = arg . ToString ( ) ;
}
if ( is_optional ) ret + = " ) " ;
ret + = " \n " ;
2018-10-20 14:19:44 +02:00
ret + = m_description ;
2018-10-23 21:22:28 +02:00
return ret ;
}
std : : string RPCArg : : ToStringObj ( ) const
{
std : : string res = " \" " + m_name + " \" : " ;
switch ( m_type ) {
case Type : : STR :
return res + " \" str \" " ;
case Type : : STR_HEX :
return res + " \" hex \" " ;
case Type : : NUM :
return res + " n " ;
case Type : : AMOUNT :
return res + " amount " ;
case Type : : BOOL :
return res + " bool " ;
case Type : : ARR :
res + = " [ " ;
for ( const auto & i : m_inner ) {
res + = i . ToString ( ) + " , " ;
}
return res + " ...] " ;
case Type : : OBJ :
case Type : : OBJ_USER_KEYS :
// Currently unused, so avoid writing dead code
assert ( false ) ;
// no default case, so the compiler can warn about missing cases
}
assert ( false ) ;
}
std : : string RPCArg : : ToString ( ) const
{
2018-10-20 14:19:44 +02:00
if ( ! m_oneline_description . empty ( ) ) return m_oneline_description ;
2018-10-23 21:22:28 +02:00
switch ( m_type ) {
case Type : : STR_HEX :
case Type : : STR : {
return " \" " + m_name + " \" " ;
}
case Type : : NUM :
case Type : : AMOUNT :
case Type : : BOOL : {
return m_name ;
}
case Type : : OBJ :
case Type : : OBJ_USER_KEYS : {
std : : string res ;
for ( size_t i = 0 ; i < m_inner . size ( ) ; ) {
res + = m_inner [ i ] . ToStringObj ( ) ;
if ( + + i < m_inner . size ( ) ) res + = " , " ;
}
if ( m_type = = Type : : OBJ ) {
return " { " + res + " } " ;
} else {
return " { " + res + " ,...} " ;
}
}
case Type : : ARR : {
std : : string res ;
for ( const auto & i : m_inner ) {
res + = i . ToString ( ) + " , " ;
}
return " [ " + res + " ...] " ;
}
// no default case, so the compiler can warn about missing cases
}
assert ( false ) ;
}