2013-12-13 16:01:22 +01:00
// Copyright (c) 2010 Satoshi Nakamoto
2016-12-31 19:01:21 +01:00
// Copyright (c) 2009-2016 The Bitcoin Core developers
2014-11-20 03:19:29 +01: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 01:57:53 +01:00
# include <base58.h>
# include <chain.h>
# include <clientversion.h>
# include <core_io.h>
# include <crypto/ripemd160.h>
# include <init.h>
# include <validation.h>
# include <httpserver.h>
# include <net.h>
# include <netbase.h>
# include <rpc/blockchain.h>
# include <rpc/server.h>
# include <timedata.h>
# include <util.h>
# include <utilstrencodings.h>
2013-12-13 16:01:22 +01:00
# ifdef ENABLE_WALLET
2017-11-10 01:57:53 +01:00
# include <wallet/rpcwallet.h>
# include <wallet/wallet.h>
# include <wallet/walletdb.h>
2013-12-13 16:01:22 +01:00
# endif
2017-11-10 01:57:53 +01:00
# include <warnings.h>
2013-12-13 16:01:22 +01:00
# include <stdint.h>
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
2013-12-13 16:18:00 +01:00
# ifdef ENABLE_WALLET
2015-05-18 14:02:18 +02:00
class DescribeAddressVisitor : public boost : : static_visitor < UniValue >
2013-12-13 16:18:00 +01:00
{
public :
2016-09-09 07:32:12 +02:00
CWallet * const pwallet ;
2017-08-01 12:22:41 +02:00
explicit DescribeAddressVisitor ( CWallet * _pwallet ) : pwallet ( _pwallet ) { }
2016-09-09 07:32:12 +02:00
2015-05-18 14:02:18 +02:00
UniValue operator ( ) ( const CNoDestination & dest ) const { return UniValue ( UniValue : : VOBJ ) ; }
2013-12-13 16:18:00 +01:00
2015-05-13 21:29:19 +02:00
UniValue operator ( ) ( const CKeyID & keyID ) const {
2015-05-10 14:48:35 +02:00
UniValue obj ( UniValue : : VOBJ ) ;
2013-12-13 16:18:00 +01:00
CPubKey vchPubKey ;
obj . push_back ( Pair ( " isscript " , false ) ) ;
2017-08-26 04:55:52 +02:00
obj . push_back ( Pair ( " iswitness " , false ) ) ;
2016-09-09 07:32:12 +02:00
if ( pwallet & & pwallet - > GetPubKey ( keyID , vchPubKey ) ) {
2013-07-26 01:06:01 +02:00
obj . push_back ( Pair ( " pubkey " , HexStr ( vchPubKey ) ) ) ;
obj . push_back ( Pair ( " iscompressed " , vchPubKey . IsCompressed ( ) ) ) ;
}
2013-12-13 16:18:00 +01:00
return obj ;
}
2015-05-13 21:29:19 +02:00
UniValue operator ( ) ( const CScriptID & scriptID ) const {
2015-05-10 14:48:35 +02:00
UniValue obj ( UniValue : : VOBJ ) ;
Return all available information via validateaddress
`"validateaddress"` omits some information, even in cases where is it available.
The primary motivation is to be able to retrieve redeemScripts, after using `"addmultisigaddress"`, when not all keys are available in the keystore, but the redeemScript actually is.
The output of `"validateaddress"` with this commit:
Keys not available:
```js
validateaddress "n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3"
{
"isvalid": true,
"address": "n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3",
"scriptPubKey": "76a914fa20d564550b105787f7ce3a9ad7fd9a45cd407088ac",
"ismine": false,
"iswatchonly": false,
"isscript": false
}
```
```js
validateaddress "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK"
{
"isvalid": true,
"address": "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK",
"scriptPubKey": "a9146769c19a16c9400b908756e19a4d2afb9e9760e187",
"ismine": false,
"iswatchonly": false,
"isscript": true
}
```
After adding the redeemScript:
```js
addmultisigaddress 2 '["02537357B156A33306A7A014A3748631C59DF405B56F11BA4AA4A3CE81501AF095","02F1FB200390E7864EF4450C07B15988179A57C3CF3A878F668E1070CB615749FE"]'
2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK
validateaddress "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK"
{
"isvalid": true,
"address": "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK",
"scriptPubKey": "a9146769c19a16c9400b908756e19a4d2afb9e9760e187",
"ismine": false,
"iswatchonly": false,
"isscript": true,
"script": "multisig",
"hex": "522102537357b156a33306a7a014a3748631c59df405b56f11ba4aa4a3ce81501af0952102f1fb200390e7864ef4450c07b15988179a57c3cf3a878f668e1070cb615749fe52ae",
"addresses": [
"n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3",
"mmSKNtbYYHRrhTLKiok5TuYrGEs4Y2A4k6"
],
"sigsrequired": 2,
"account": ""
}
```
All keys available:
```js
validateaddress "n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3"
{
"isvalid": true,
"address": "n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3",
"scriptPubKey": "76a914fa20d564550b105787f7ce3a9ad7fd9a45cd407088ac",
"ismine": true,
"iswatchonly": false,
"isscript": false,
"pubkey": "02537357b156a33306a7a014a3748631c59df405b56f11ba4aa4a3ce81501af095",
"iscompressed": true,
"account": ""
}
```
```js
validateaddress "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK"
{
"isvalid": true,
"address": "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK",
"scriptPubKey": "a9146769c19a16c9400b908756e19a4d2afb9e9760e187",
"ismine": true,
"iswatchonly": false,
"isscript": true,
"script": "multisig",
"hex": "522102537357b156a33306a7a014a3748631c59df405b56f11ba4aa4a3ce81501af0952102f1fb200390e7864ef4450c07b15988179a57c3cf3a878f668e1070cb615749fe52ae",
"addresses": [
"n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3",
"mmSKNtbYYHRrhTLKiok5TuYrGEs4Y2A4k6"
],
"sigsrequired": 2,
"account": ""
}
```
2015-06-09 17:11:13 +02:00
CScript subscript ;
2013-12-13 16:18:00 +01:00
obj . push_back ( Pair ( " isscript " , true ) ) ;
2017-08-26 04:55:52 +02:00
obj . push_back ( Pair ( " iswitness " , false ) ) ;
2016-09-09 07:32:12 +02:00
if ( pwallet & & pwallet - > GetCScript ( scriptID , subscript ) ) {
2013-07-26 01:06:01 +02:00
std : : vector < CTxDestination > addresses ;
txnouttype whichType ;
int nRequired ;
ExtractDestinations ( subscript , whichType , addresses , nRequired ) ;
obj . push_back ( Pair ( " script " , GetTxnOutputType ( whichType ) ) ) ;
obj . push_back ( Pair ( " hex " , HexStr ( subscript . begin ( ) , subscript . end ( ) ) ) ) ;
2015-05-10 14:48:35 +02:00
UniValue a ( UniValue : : VARR ) ;
2017-08-23 03:02:33 +02:00
for ( const CTxDestination & addr : addresses ) {
a . push_back ( EncodeDestination ( addr ) ) ;
}
2013-07-26 01:06:01 +02:00
obj . push_back ( Pair ( " addresses " , a ) ) ;
if ( whichType = = TX_MULTISIG )
obj . push_back ( Pair ( " sigsrequired " , nRequired ) ) ;
}
2013-12-13 16:18:00 +01:00
return obj ;
}
2017-08-26 04:55:52 +02:00
UniValue operator ( ) ( const WitnessV0KeyHash & id ) const
{
UniValue obj ( UniValue : : VOBJ ) ;
CPubKey pubkey ;
obj . push_back ( Pair ( " isscript " , false ) ) ;
obj . push_back ( Pair ( " iswitness " , true ) ) ;
obj . push_back ( Pair ( " witness_version " , 0 ) ) ;
obj . push_back ( Pair ( " witness_program " , HexStr ( id . begin ( ) , id . end ( ) ) ) ) ;
if ( pwallet & & pwallet - > GetPubKey ( CKeyID ( id ) , pubkey ) ) {
obj . push_back ( Pair ( " pubkey " , HexStr ( pubkey ) ) ) ;
}
return obj ;
}
UniValue operator ( ) ( const WitnessV0ScriptHash & id ) const
{
UniValue obj ( UniValue : : VOBJ ) ;
CScript subscript ;
obj . push_back ( Pair ( " isscript " , true ) ) ;
obj . push_back ( Pair ( " iswitness " , true ) ) ;
obj . push_back ( Pair ( " witness_version " , 0 ) ) ;
obj . push_back ( Pair ( " witness_program " , HexStr ( id . begin ( ) , id . end ( ) ) ) ) ;
CRIPEMD160 hasher ;
uint160 hash ;
hasher . Write ( id . begin ( ) , 32 ) . Finalize ( hash . begin ( ) ) ;
if ( pwallet & & pwallet - > GetCScript ( CScriptID ( hash ) , subscript ) ) {
obj . push_back ( Pair ( " hex " , HexStr ( subscript . begin ( ) , subscript . end ( ) ) ) ) ;
}
return obj ;
}
UniValue operator ( ) ( const WitnessUnknown & id ) const
{
UniValue obj ( UniValue : : VOBJ ) ;
CScript subscript ;
obj . push_back ( Pair ( " iswitness " , true ) ) ;
obj . push_back ( Pair ( " witness_version " , ( int ) id . version ) ) ;
obj . push_back ( Pair ( " witness_program " , HexStr ( id . program , id . program + id . length ) ) ) ;
return obj ;
}
2013-12-13 16:18:00 +01:00
} ;
# endif
2016-09-22 09:46:41 +02:00
UniValue validateaddress ( const JSONRPCRequest & request )
2013-12-13 16:18:00 +01:00
{
2016-09-22 09:46:41 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 1 )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error (
2016-11-21 14:39:58 +01:00
" validateaddress \" address \" \n "
2013-12-13 16:18:00 +01:00
" \n Return information about the given bitcoin address. \n "
" \n Arguments: \n "
2016-11-21 14:39:58 +01:00
" 1. \" address \" (string, required) The bitcoin address to validate \n "
2013-12-13 16:18:00 +01:00
" \n Result: \n "
" { \n "
2015-08-10 20:10:56 +02:00
" \" isvalid \" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned. \n "
2016-11-21 14:39:58 +01:00
" \" address \" : \" address \" , (string) The bitcoin address validated \n "
2014-09-23 11:18:47 +02:00
" \" scriptPubKey \" : \" hex \" , (string) The hex encoded scriptPubKey generated by the address \n "
2015-08-10 20:10:56 +02:00
" \" ismine \" : true|false, (boolean) If the address is yours or not \n "
" \" iswatchonly \" : true|false, (boolean) If the address is watchonly \n "
" \" isscript \" : true|false, (boolean) If the key is a script \n "
2017-06-27 05:23:48 +02:00
" \" script \" : \" type \" (string, optional) The output script type. Possible types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash, witness_v0_scripthash \n "
" \" hex \" : \" hex \" , (string, optional) The redeemscript for the p2sh address \n "
" \" addresses \" (string, optional) Array of addresses associated with the known redeemscript \n "
" [ \n "
" \" address \" \n "
" ,... \n "
" ] \n "
" \" sigsrequired \" : xxxxx (numeric, optional) Number of signatures required to spend multisig output \n "
2013-12-13 16:18:00 +01:00
" \" pubkey \" : \" publickeyhex \" , (string) The hex value of the raw public key \n "
2015-08-10 20:10:56 +02:00
" \" iscompressed \" : true|false, (boolean) If the address is compressed \n "
2014-12-30 15:32:07 +01:00
" \" account \" : \" account \" (string) DEPRECATED. The account associated with the address, \" \" is the default account \n "
2017-02-06 17:13:05 +01:00
" \" timestamp \" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT) \n "
2016-07-09 11:41:32 +02:00
" \" hdkeypath \" : \" keypath \" (string, optional) The HD keypath if the key is HD and available \n "
" \" hdmasterkeyid \" : \" <hash160> \" (string, optional) The Hash160 of the HD master pubkey \n "
2013-12-13 16:18:00 +01:00
" } \n "
" \n Examples: \n "
+ HelpExampleCli ( " validateaddress " , " \" 1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc \" " )
+ HelpExampleRpc ( " validateaddress " , " \" 1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc \" " )
) ;
2014-10-19 10:46:17 +02:00
# ifdef ENABLE_WALLET
2016-10-25 09:45:57 +02:00
CWallet * const pwallet = GetWalletForJSONRPCRequest ( request ) ;
2017-08-07 07:36:37 +02:00
LOCK2 ( cs_main , pwallet ? & pwallet - > cs_wallet : nullptr ) ;
2014-10-19 10:46:17 +02:00
# else
LOCK ( cs_main ) ;
# endif
2017-08-23 03:02:33 +02:00
CTxDestination dest = DecodeDestination ( request . params [ 0 ] . get_str ( ) ) ;
bool isValid = IsValidDestination ( dest ) ;
2013-12-13 16:18:00 +01:00
2015-05-10 14:48:35 +02:00
UniValue ret ( UniValue : : VOBJ ) ;
2013-12-13 16:18:00 +01:00
ret . push_back ( Pair ( " isvalid " , isValid ) ) ;
if ( isValid )
{
2017-08-23 03:02:33 +02:00
std : : string currentAddress = EncodeDestination ( dest ) ;
2013-12-13 16:18:00 +01:00
ret . push_back ( Pair ( " address " , currentAddress ) ) ;
2014-09-23 11:18:47 +02:00
CScript scriptPubKey = GetScriptForDestination ( dest ) ;
ret . push_back ( Pair ( " scriptPubKey " , HexStr ( scriptPubKey . begin ( ) , scriptPubKey . end ( ) ) ) ) ;
2013-12-13 16:18:00 +01:00
# ifdef ENABLE_WALLET
2016-10-25 09:45:57 +02:00
isminetype mine = pwallet ? IsMine ( * pwallet , dest ) : ISMINE_NO ;
2017-06-08 12:06:09 +02:00
ret . push_back ( Pair ( " ismine " , bool ( mine & ISMINE_SPENDABLE ) ) ) ;
ret . push_back ( Pair ( " iswatchonly " , bool ( mine & ISMINE_WATCH_ONLY ) ) ) ;
2016-10-25 09:45:57 +02:00
UniValue detail = boost : : apply_visitor ( DescribeAddressVisitor ( pwallet ) , dest ) ;
Return all available information via validateaddress
`"validateaddress"` omits some information, even in cases where is it available.
The primary motivation is to be able to retrieve redeemScripts, after using `"addmultisigaddress"`, when not all keys are available in the keystore, but the redeemScript actually is.
The output of `"validateaddress"` with this commit:
Keys not available:
```js
validateaddress "n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3"
{
"isvalid": true,
"address": "n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3",
"scriptPubKey": "76a914fa20d564550b105787f7ce3a9ad7fd9a45cd407088ac",
"ismine": false,
"iswatchonly": false,
"isscript": false
}
```
```js
validateaddress "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK"
{
"isvalid": true,
"address": "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK",
"scriptPubKey": "a9146769c19a16c9400b908756e19a4d2afb9e9760e187",
"ismine": false,
"iswatchonly": false,
"isscript": true
}
```
After adding the redeemScript:
```js
addmultisigaddress 2 '["02537357B156A33306A7A014A3748631C59DF405B56F11BA4AA4A3CE81501AF095","02F1FB200390E7864EF4450C07B15988179A57C3CF3A878F668E1070CB615749FE"]'
2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK
validateaddress "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK"
{
"isvalid": true,
"address": "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK",
"scriptPubKey": "a9146769c19a16c9400b908756e19a4d2afb9e9760e187",
"ismine": false,
"iswatchonly": false,
"isscript": true,
"script": "multisig",
"hex": "522102537357b156a33306a7a014a3748631c59df405b56f11ba4aa4a3ce81501af0952102f1fb200390e7864ef4450c07b15988179a57c3cf3a878f668e1070cb615749fe52ae",
"addresses": [
"n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3",
"mmSKNtbYYHRrhTLKiok5TuYrGEs4Y2A4k6"
],
"sigsrequired": 2,
"account": ""
}
```
All keys available:
```js
validateaddress "n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3"
{
"isvalid": true,
"address": "n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3",
"scriptPubKey": "76a914fa20d564550b105787f7ce3a9ad7fd9a45cd407088ac",
"ismine": true,
"iswatchonly": false,
"isscript": false,
"pubkey": "02537357b156a33306a7a014a3748631c59df405b56f11ba4aa4a3ce81501af095",
"iscompressed": true,
"account": ""
}
```
```js
validateaddress "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK"
{
"isvalid": true,
"address": "2N2g2H7gjA8a11g1yKBgh5VTqndyvbnWpBK",
"scriptPubKey": "a9146769c19a16c9400b908756e19a4d2afb9e9760e187",
"ismine": true,
"iswatchonly": false,
"isscript": true,
"script": "multisig",
"hex": "522102537357b156a33306a7a014a3748631c59df405b56f11ba4aa4a3ce81501af0952102f1fb200390e7864ef4450c07b15988179a57c3cf3a878f668e1070cb615749fe52ae",
"addresses": [
"n4KWZKx349gdMQGgTnZ8W6WfgSwybkGSK3",
"mmSKNtbYYHRrhTLKiok5TuYrGEs4Y2A4k6"
],
"sigsrequired": 2,
"account": ""
}
```
2015-06-09 17:11:13 +02:00
ret . pushKVs ( detail ) ;
2016-10-25 10:04:23 +02:00
if ( pwallet & & pwallet - > mapAddressBook . count ( dest ) ) {
2016-10-25 09:45:57 +02:00
ret . push_back ( Pair ( " account " , pwallet - > mapAddressBook [ dest ] . name ) ) ;
2016-10-25 10:04:23 +02:00
}
2016-10-25 09:45:57 +02:00
if ( pwallet ) {
2017-12-08 18:50:46 +01:00
const CKeyMetadata * meta = nullptr ;
if ( const CKeyID * key_id = boost : : get < CKeyID > ( & dest ) ) {
auto it = pwallet - > mapKeyMetadata . find ( * key_id ) ;
if ( it ! = pwallet - > mapKeyMetadata . end ( ) ) {
meta = & it - > second ;
}
}
if ( ! meta ) {
auto it = pwallet - > m_script_metadata . find ( CScriptID ( scriptPubKey ) ) ;
if ( it ! = pwallet - > m_script_metadata . end ( ) ) {
meta = & it - > second ;
}
2016-11-08 22:55:02 +01:00
}
2017-12-08 18:50:46 +01:00
if ( meta ) {
ret . push_back ( Pair ( " timestamp " , meta - > nCreateTime ) ) ;
if ( ! meta - > hdKeypath . empty ( ) ) {
ret . push_back ( Pair ( " hdkeypath " , meta - > hdKeypath ) ) ;
ret . push_back ( Pair ( " hdmasterkeyid " , meta - > hdMasterKeyID . GetHex ( ) ) ) ;
2017-02-06 17:13:05 +01:00
}
}
2016-07-09 11:41:32 +02:00
}
2013-12-13 16:18:00 +01:00
# endif
}
return ret ;
}
2017-01-06 18:53:06 +01:00
// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around
class CWallet ;
2014-11-20 03:19:29 +01:00
/**
* Used by addmultisigaddress / createmultisig :
*/
2016-09-09 07:32:12 +02:00
CScript _createmultisig_redeemScript ( CWallet * const pwallet , const UniValue & params )
2013-12-13 16:21:38 +01:00
{
int nRequired = params [ 0 ] . get_int ( ) ;
2015-05-18 14:02:18 +02:00
const UniValue & keys = params [ 1 ] . get_array ( ) ;
2013-12-13 16:21:38 +01:00
// Gather public keys
if ( nRequired < 1 )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error ( " a multisignature address must require at least one key to redeem " ) ;
2013-12-13 16:21:38 +01:00
if ( ( int ) keys . size ( ) < nRequired )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error (
2013-12-13 16:21:38 +01:00
strprintf ( " not enough keys supplied "
2014-05-06 15:25:01 +02:00
" (got %u keys, but need at least %d to redeem) " , keys . size ( ) , nRequired ) ) ;
2015-01-25 13:11:57 +01:00
if ( keys . size ( ) > 16 )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error ( " Number of addresses involved in the multisignature address creation > 16 \n Reduce the number " ) ;
2013-12-13 16:21:38 +01:00
std : : vector < CPubKey > pubkeys ;
pubkeys . resize ( keys . size ( ) ) ;
for ( unsigned int i = 0 ; i < keys . size ( ) ; i + + )
{
const std : : string & ks = keys [ i ] . get_str ( ) ;
# ifdef ENABLE_WALLET
// Case 1: Bitcoin address and we have full public key:
2017-08-23 03:02:33 +02:00
CTxDestination dest = DecodeDestination ( ks ) ;
if ( pwallet & & IsValidDestination ( dest ) ) {
const CKeyID * keyID = boost : : get < CKeyID > ( & dest ) ;
if ( ! keyID ) {
throw std : : runtime_error ( strprintf ( " %s does not refer to a key " , ks ) ) ;
}
2013-12-13 16:21:38 +01:00
CPubKey vchPubKey ;
2017-08-23 03:02:33 +02:00
if ( ! pwallet - > GetPubKey ( * keyID , vchPubKey ) ) {
throw std : : runtime_error ( strprintf ( " no full public key for address %s " , ks ) ) ;
2016-10-25 10:04:23 +02:00
}
2013-12-13 16:21:38 +01:00
if ( ! vchPubKey . IsFullyValid ( ) )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error ( " Invalid public key: " + ks ) ;
2013-12-13 16:21:38 +01:00
pubkeys [ i ] = vchPubKey ;
}
// Case 2: hex public key
else
# endif
if ( IsHex ( ks ) )
{
CPubKey vchPubKey ( ParseHex ( ks ) ) ;
if ( ! vchPubKey . IsFullyValid ( ) )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error ( " Invalid public key: " + ks ) ;
2013-12-13 16:21:38 +01:00
pubkeys [ i ] = vchPubKey ;
}
else
{
2017-01-04 05:22:19 +01:00
throw std : : runtime_error ( " Invalid public key: " + ks ) ;
2013-12-13 16:21:38 +01:00
}
}
2014-09-11 19:15:29 +02:00
CScript result = GetScriptForMultisig ( nRequired , pubkeys ) ;
2014-03-11 03:43:15 +01:00
if ( result . size ( ) > MAX_SCRIPT_ELEMENT_SIZE )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error (
2014-03-11 03:43:15 +01:00
strprintf ( " redeemScript exceeds size limit: %d > %d " , result . size ( ) , MAX_SCRIPT_ELEMENT_SIZE ) ) ;
2013-12-13 16:21:38 +01:00
return result ;
}
2016-09-22 09:46:41 +02:00
UniValue createmultisig ( const JSONRPCRequest & request )
2013-12-13 16:21:38 +01:00
{
2016-10-25 09:45:57 +02:00
# ifdef ENABLE_WALLET
CWallet * const pwallet = GetWalletForJSONRPCRequest ( request ) ;
# else
2017-08-07 07:36:37 +02:00
CWallet * const pwallet = nullptr ;
2016-10-25 09:45:57 +02:00
# endif
2016-09-22 09:46:41 +02:00
if ( request . fHelp | | request . params . size ( ) < 2 | | request . params . size ( ) > 2 )
2013-12-13 16:21:38 +01:00
{
2017-01-04 05:22:19 +01:00
std : : string msg = " createmultisig nrequired [ \" key \" ,...] \n "
2013-12-13 16:21:38 +01: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 "
" \n Arguments: \n "
" 1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses. \n "
" 2. \" keys \" (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys \n "
" [ \n "
" \" key \" (string) bitcoin address or hex-encoded public key \n "
" ,... \n "
" ] \n "
" \n Result: \n "
" { \n "
" \" address \" : \" multisigaddress \" , (string) The value of the new multisig address. \n "
" \" redeemScript \" : \" script \" (string) The string value of the hex-encoded redemption script. \n "
" } \n "
" \n Examples: \n "
" \n Create a multisig address from 2 addresses \n "
+ HelpExampleCli ( " createmultisig " , " 2 \" [ \\ \" 16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5 \\ \" , \\ \" 171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV \\ \" ] \" " ) +
" \n As a json rpc call \n "
2014-03-31 09:03:13 +02:00
+ HelpExampleRpc ( " createmultisig " , " 2, \" [ \\ \" 16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5 \\ \" , \\ \" 171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV \\ \" ] \" " )
2013-12-13 16:21:38 +01:00
;
2017-01-04 05:22:19 +01:00
throw std : : runtime_error ( msg ) ;
2013-12-13 16:21:38 +01:00
}
// Construct using pay-to-script-hash:
2016-10-25 09:45:57 +02:00
CScript inner = _createmultisig_redeemScript ( pwallet , request . params ) ;
2014-09-25 04:24:46 +02:00
CScriptID innerID ( inner ) ;
2013-12-13 16:21:38 +01:00
2015-06-02 12:28:54 +02:00
UniValue result ( UniValue : : VOBJ ) ;
2017-08-23 03:02:33 +02:00
result . push_back ( Pair ( " address " , EncodeDestination ( innerID ) ) ) ;
2013-12-13 16:21:38 +01:00
result . push_back ( Pair ( " redeemScript " , HexStr ( inner . begin ( ) , inner . end ( ) ) ) ) ;
return result ;
}
2016-09-22 09:46:41 +02:00
UniValue verifymessage ( const JSONRPCRequest & request )
2013-12-13 16:23:39 +01:00
{
2016-09-22 09:46:41 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 3 )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error (
2016-11-21 14:39:58 +01:00
" verifymessage \" address \" \" signature \" \" message \" \n "
2013-12-13 16:23:39 +01:00
" \n Verify a signed message \n "
" \n Arguments: \n "
2016-12-09 18:06:42 +01:00
" 1. \" address \" (string, required) The bitcoin address to use for the signature. \n "
2013-12-13 16:23:39 +01:00
" 2. \" signature \" (string, required) The signature provided by the signer in base 64 encoding (see signmessage). \n "
" 3. \" message \" (string, required) The message that was signed. \n "
" \n Result: \n "
" true|false (boolean) If the signature is verified or not. \n "
" \n Examples: \n "
" \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 \" " ) +
2013-12-13 16:23:39 +01:00
" \n As json rpc \n "
2017-02-26 14:01:05 +01:00
+ HelpExampleRpc ( " verifymessage " , " \" 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX \" , \" signature \" , \" my message \" " )
2013-12-13 16:23:39 +01:00
) ;
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2017-01-04 05:22:19 +01: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
2017-08-23 03:02:33 +02:00
CTxDestination destination = DecodeDestination ( strAddress ) ;
if ( ! IsValidDestination ( destination ) ) {
2013-12-13 16:23:39 +01:00
throw JSONRPCError ( RPC_TYPE_ERROR , " Invalid address " ) ;
2017-08-23 03:02:33 +02:00
}
2013-12-13 16:23:39 +01:00
2017-08-23 03:02:33 +02:00
const CKeyID * keyID = boost : : get < CKeyID > ( & destination ) ;
if ( ! keyID ) {
2013-12-13 16:23:39 +01:00
throw JSONRPCError ( RPC_TYPE_ERROR , " Address does not refer to key " ) ;
2017-08-23 03:02:33 +02:00
}
2013-12-13 16:23:39 +01:00
bool fInvalid = false ;
2017-01-04 05:22:19 +01:00
std : : vector < unsigned char > vchSig = DecodeBase64 ( strSign . c_str ( ) , & fInvalid ) ;
2013-12-13 16:23:39 +01:00
if ( fInvalid )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Malformed base64 encoding " ) ;
CHashWriter ss ( SER_GETHASH , 0 ) ;
ss < < strMessageMagic ;
ss < < strMessage ;
CPubKey pubkey ;
if ( ! pubkey . RecoverCompact ( ss . GetHash ( ) , vchSig ) )
return false ;
2017-08-23 03:02:33 +02:00
return ( pubkey . GetID ( ) = = * keyID ) ;
2013-12-13 16:23:39 +01:00
}
2014-11-13 00:59:41 +01:00
2016-09-22 09:46:41 +02:00
UniValue signmessagewithprivkey ( const JSONRPCRequest & request )
2016-04-26 19:17:00 +02:00
{
2016-09-22 09:46:41 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 2 )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error (
2016-04-26 19:17:00 +02:00
" signmessagewithprivkey \" privkey \" \" message \" \n "
" \n Sign a message with the private key of an address \n "
" \n Arguments: \n "
" 1. \" privkey \" (string, required) The private key to sign the message with. \n "
" 2. \" message \" (string, required) The message to create a signature of. \n "
" \n Result: \n "
" \" signature \" (string) The signature of the message encoded in base 64 \n "
" \n Examples: \n "
" \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 \" " ) +
2016-04-26 19:17:00 +02:00
" \n As json rpc \n "
+ HelpExampleRpc ( " signmessagewithprivkey " , " \" privkey \" , \" my message \" " )
) ;
2017-01-04 05:22:19 +01:00
std : : string strPrivkey = request . params [ 0 ] . get_str ( ) ;
std : : string strMessage = request . params [ 1 ] . get_str ( ) ;
2016-04-26 19:17:00 +02:00
CBitcoinSecret vchSecret ;
bool fGood = vchSecret . SetString ( strPrivkey ) ;
if ( ! fGood )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid private key " ) ;
CKey key = vchSecret . GetKey ( ) ;
if ( ! key . IsValid ( ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Private key outside allowed range " ) ;
CHashWriter ss ( SER_GETHASH , 0 ) ;
ss < < strMessageMagic ;
ss < < strMessage ;
2017-01-04 05:22:19 +01:00
std : : vector < unsigned char > vchSig ;
2016-04-26 19:17:00 +02:00
if ( ! key . SignCompact ( ss . GetHash ( ) , vchSig ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Sign failed " ) ;
2017-07-11 11:37:53 +02:00
return EncodeBase64 ( vchSig . data ( ) , vchSig . size ( ) ) ;
2016-04-26 19:17:00 +02:00
}
2016-09-22 09:46:41 +02:00
UniValue setmocktime ( const JSONRPCRequest & request )
2014-11-13 00:59:41 +01:00
{
2016-09-22 09:46:41 +02:00
if ( request . fHelp | | request . params . size ( ) ! = 1 )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error (
2014-11-13 00:59:41 +01:00
" setmocktime timestamp \n "
" \n Set the local time to given timestamp (-regtest only) \n "
" \n Arguments: \n "
" 1. timestamp (integer, required) Unix seconds-since-epoch timestamp \n "
" Pass 0 to go back to using the system time. "
) ;
if ( ! Params ( ) . MineBlocksOnDemand ( ) )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error ( " setmocktime for regression testing (-regtest mode) only " ) ;
2014-11-13 00:59:41 +01:00
2017-01-19 19:01:18 +01: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-17 01:13:12 +02:00
LOCK ( cs_main ) ;
2014-10-19 10:46:17 +02:00
2017-06-06 21:15:28 +02:00
RPCTypeCheck ( request . params , { UniValue : : VNUM } ) ;
2016-09-22 09:46:41 +02:00
SetMockTime ( request . params [ 0 ] . get_int64 ( ) ) ;
2014-11-13 00:59:41 +01:00
2015-05-10 13:35:44 +02:00
return NullUniValue ;
2014-11-13 00:59:41 +01:00
}
2016-03-29 19:43:02 +02:00
2016-09-18 10:22:30 +02:00
static UniValue RPCLockedMemoryInfo ( )
{
LockedPool : : Stats stats = LockedPoolManager : : Instance ( ) . stats ( ) ;
UniValue obj ( UniValue : : VOBJ ) ;
obj . push_back ( Pair ( " used " , uint64_t ( stats . used ) ) ) ;
obj . push_back ( Pair ( " free " , uint64_t ( stats . free ) ) ) ;
obj . push_back ( Pair ( " total " , uint64_t ( stats . total ) ) ) ;
obj . push_back ( Pair ( " locked " , uint64_t ( stats . locked ) ) ) ;
obj . push_back ( Pair ( " chunks_used " , uint64_t ( stats . chunks_used ) ) ) ;
obj . push_back ( Pair ( " chunks_free " , uint64_t ( stats . chunks_free ) ) ) ;
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
2016-09-18 10:22:30 +02:00
UniValue getmemoryinfo ( const JSONRPCRequest & request )
{
/* Please, avoid using the word "pool" here in the RPC interface or help,
* as users will undoubtedly confuse it with the other " memory pool "
*/
2017-03-20 10:09:01 +01:00
if ( request . fHelp | | request . params . size ( ) > 1 )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error (
2017-03-20 10:09:01 +01:00
" getmemoryinfo ( \" mode \" ) \n "
2016-09-18 10:22:30 +02:00
" Returns an object containing information about memory usage. \n "
2017-03-20 10:09:01 +01:00
" Arguments: \n "
" 1. \" mode \" determines what kind of information is returned. This argument is optional, the default mode is \" stats \" . \n "
" - \" 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+). \n "
" \n Result (mode \" stats \" ): \n "
2016-09-18 10:22:30 +02:00
" { \n "
" \" locked \" : { (json object) Information about locked memory manager \n "
" \" used \" : xxxxx, (numeric) Number of bytes used \n "
" \" free \" : xxxxx, (numeric) Number of bytes available in current arenas \n "
" \" total \" : xxxxxxx, (numeric) Total number of bytes managed \n "
" \" locked \" : xxxxxx, (numeric) 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. \n "
" \" chunks_used \" : xxxxx, (numeric) Number allocated chunks \n "
" \" chunks_free \" : xxxxx, (numeric) Number unused chunks \n "
" } \n "
" } \n "
2017-03-20 10:09:01 +01:00
" \n Result (mode \" mallocinfo \" ): \n "
" \" <malloc version= \" 1 \" >... \" \n "
2016-09-18 10:22:30 +02:00
" \n Examples: \n "
+ HelpExampleCli ( " getmemoryinfo " , " " )
+ HelpExampleRpc ( " getmemoryinfo " , " " )
) ;
2017-03-20 10:09:01 +01:00
2017-08-15 01:38:18 +02: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 ) ;
obj . push_back ( Pair ( " locked " , RPCLockedMemoryInfo ( ) ) ) ;
return obj ;
} else if ( mode = = " mallocinfo " ) {
# ifdef HAVE_MALLOC_INFO
return RPCMallocInfo ( ) ;
# else
throw JSONRPCError ( RPC_INVALID_PARAMETER , " mallocinfo is only available when compiled with glibc 2.10+ " ) ;
# endif
} else {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " unknown mode " + mode ) ;
}
2016-09-18 10:22:30 +02:00
}
2017-04-03 19:39:11 +02:00
uint32_t getCategoryMask ( UniValue cats ) {
cats = cats . get_array ( ) ;
uint32_t mask = 0 ;
for ( unsigned int i = 0 ; i < cats . size ( ) ; + + i ) {
uint32_t flag = 0 ;
std : : string cat = cats [ i ] . get_str ( ) ;
if ( ! GetLogCategory ( & flag , & cat ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " unknown logging category " + cat ) ;
}
2017-08-29 13:32:16 +02:00
if ( flag = = BCLog : : NONE ) {
return 0 ;
}
2017-04-03 19:39:11 +02:00
mask | = flag ;
}
return mask ;
}
UniValue logging ( const JSONRPCRequest & request )
{
if ( request . fHelp | | request . params . size ( ) > 2 ) {
throw std : : runtime_error (
2017-08-29 13:32:16 +02:00
" logging ( <include> <exclude> ) \n "
2017-04-03 19:39:11 +02:00
" Gets and sets the logging configuration. \n "
2017-08-29 13:32:16 +02: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 "
2017-04-03 19:39:11 +02:00
" The valid logging categories are: " + ListLogCategories ( ) + " \n "
2017-08-29 13:32:16 +02: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 "
" \n Arguments: \n "
" 1. \" include \" (array of strings, optional) A json array of categories to add debug logging \n "
" [ \n "
" \" category \" (string) the valid logging category \n "
" ,... \n "
" ] \n "
" 2. \" exclude \" (array of strings, optional) A json array of categories to remove debug logging \n "
" [ \n "
" \" category \" (string) the valid logging category \n "
" ,... \n "
" ] \n "
" \n Result: \n "
" { (json object where keys are the logging categories, and values indicates its status \n "
" \" category \" : 0|1, (numeric) if being debug logged or not. 0:inactive, 1:active \n "
" ... \n "
" } \n "
2017-04-03 19:39:11 +02:00
" \n Examples: \n "
+ HelpExampleCli ( " logging " , " \" [ \\ \" all \\ \" ] \" \" [ \\ \" http \\ \" ] \" " )
+ HelpExampleRpc ( " logging " , " [ \" all \" ], \" [libevent] \" " )
) ;
}
uint32_t originalLogCategories = logCategories ;
2017-08-15 01:38:18 +02:00
if ( request . params [ 0 ] . isArray ( ) ) {
2017-04-03 19:39:11 +02:00
logCategories | = getCategoryMask ( request . params [ 0 ] ) ;
}
2017-08-15 01:38:18 +02:00
if ( request . params [ 1 ] . isArray ( ) ) {
2017-04-03 19:39:11 +02:00
logCategories & = ~ getCategoryMask ( request . params [ 1 ] ) ;
}
2017-04-10 16:34:23 +02: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.
uint32_t changedLogCategories = originalLogCategories ^ logCategories ;
if ( changedLogCategories & BCLog : : LIBEVENT ) {
if ( ! UpdateHTTPServerLogging ( logCategories & BCLog : : LIBEVENT ) ) {
logCategories & = ~ BCLog : : LIBEVENT ;
if ( changedLogCategories = = BCLog : : LIBEVENT ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " libevent logging cannot be updated when using libevent before v2.1.1. " ) ;
}
}
}
2017-04-03 19:39:11 +02:00
UniValue result ( UniValue : : VOBJ ) ;
std : : vector < CLogCategoryActive > vLogCatActive = ListActiveLogCategories ( ) ;
for ( const auto & logCatActive : vLogCatActive ) {
result . pushKV ( logCatActive . category , logCatActive . active ) ;
}
return result ;
}
2016-09-25 20:55:24 +02:00
UniValue echo ( const JSONRPCRequest & request )
{
if ( request . fHelp )
2017-01-04 05:22:19 +01:00
throw std : : runtime_error (
2016-11-22 14:56:29 +01:00
" echo|echojson \" message \" ... \n "
" \n Simply echo back the input arguments. This command is for testing. \n "
" \n The difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in "
" bitcoin-cli and the GUI. There is no server-side difference. "
2016-09-25 20:55:24 +02:00
) ;
return request . params ;
}
2016-03-29 19:43:02 +02:00
static const CRPCCommand commands [ ] =
2017-06-09 02:38:23 +02:00
{ // category name actor (function) argNames
2016-03-29 19:43:02 +02:00
// --------------------- ------------------------ ----------------------- ----------
2017-06-09 02:38:23 +02:00
{ " control " , " getmemoryinfo " , & getmemoryinfo , { " mode " } } ,
2017-11-07 07:50:49 +01:00
{ " control " , " logging " , & logging , { " include " , " exclude " } } ,
2017-06-09 02:38:23 +02:00
{ " util " , " validateaddress " , & validateaddress , { " address " } } , /* uses wallet if enabled */
{ " util " , " createmultisig " , & createmultisig , { " nrequired " , " keys " } } ,
{ " util " , " verifymessage " , & verifymessage , { " address " , " signature " , " message " } } ,
{ " util " , " signmessagewithprivkey " , & signmessagewithprivkey , { " privkey " , " message " } } ,
2016-03-29 19:43:02 +02:00
/* Not shown in help */
2017-06-09 02:38:23 +02:00
{ " hidden " , " setmocktime " , & setmocktime , { " timestamp " } } ,
{ " hidden " , " echo " , & echo , { " arg0 " , " arg1 " , " arg2 " , " arg3 " , " arg4 " , " arg5 " , " arg6 " , " arg7 " , " arg8 " , " arg9 " } } ,
{ " hidden " , " echojson " , & echo , { " arg0 " , " arg1 " , " arg2 " , " arg3 " , " arg4 " , " arg5 " , " arg6 " , " arg7 " , " arg8 " , " arg9 " } } ,
2016-03-29 19:43:02 +02:00
} ;
2016-06-07 18:42:42 +02:00
void RegisterMiscRPCCommands ( CRPCTable & t )
2016-03-29 19:43:02 +02:00
{
for ( unsigned int vcidx = 0 ; vcidx < ARRAYLEN ( commands ) ; vcidx + + )
2016-06-07 18:42:42 +02:00
t . appendCommand ( commands [ vcidx ] . name , & commands [ vcidx ] ) ;
2016-03-29 19:43:02 +02:00
}