2013-12-13 16:01:22 +01:00
// Copyright (c) 2010 Satoshi Nakamoto
2015-12-13 14:51:43 +01:00
// Copyright (c) 2009-2015 The Bitcoin Core developers
2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash 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.
# include "base58.h"
2014-10-29 02:33:23 +01:00
# include "clientversion.h"
2013-12-13 16:01:22 +01:00
# include "init.h"
# include "net.h"
# include "netbase.h"
2017-07-03 15:13:34 +02:00
# include "rpc/server.h"
2014-06-19 15:08:37 +02:00
# include "timedata.h"
2016-04-04 22:37:43 +02:00
# include "txmempool.h"
2013-12-13 16:01:22 +01:00
# include "util.h"
2015-07-05 14:17:46 +02:00
# include "utilstrencodings.h"
2017-12-01 19:53:34 +01:00
# include "validation.h"
2013-12-13 16:01:22 +01:00
# ifdef ENABLE_WALLET
2015-02-03 21:09:47 +01:00
# include "wallet/wallet.h"
# include "wallet/walletdb.h"
2013-12-13 16:01:22 +01:00
# endif
2017-12-01 19:53:34 +01:00
# include "masternode-sync.h"
# include "spork.h"
2013-12-13 16:01:22 +01:00
# include <stdint.h>
# include <boost/assign/list_of.hpp>
2016-03-14 23:56:55 +01:00
# include <boost/algorithm/string.hpp>
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
2014-06-27 11:13:25 +02:00
using namespace std ;
2013-12-13 16:01:22 +01:00
2014-07-28 19:30:43 +02:00
/**
* @ note Do not add or change anything in the information returned by this
2014-11-20 03:19:29 +01:00
* method . ` getinfo ` exists for backwards - compatibility only . It combines
2014-07-28 19:30:43 +02:00
* information from wildly different sources in the program , which is a mess ,
* and is thus planned to be deprecated eventually .
*
* Based on the source of the information , new information should be added to :
* - ` getblockchaininfo ` ,
* - ` getnetworkinfo ` or
* - ` getwalletinfo `
*
* Or alternatively , create a specific query method for the information .
* */
2015-05-18 14:02:18 +02:00
UniValue getinfo ( const UniValue & params , bool fHelp )
2013-12-13 16:03:57 +01:00
{
if ( fHelp | | params . size ( ) ! = 0 )
throw runtime_error (
" getinfo \n "
" Returns an object containing various state info. \n "
" \n Result: \n "
" { \n "
" \" version \" : xxxxx, (numeric) the server version \n "
" \" protocolversion \" : xxxxx, (numeric) the protocol version \n "
" \" walletversion \" : xxxxx, (numeric) the wallet version \n "
2015-03-19 15:15:08 +01:00
" \" balance \" : xxxxxxx, (numeric) the total dash balance of the wallet \n "
2016-05-25 08:39:23 +02:00
" \" privatesend_balance \" : xxxxxx, (numeric) the anonymized dash balance of the wallet \n "
2013-12-13 16:03:57 +01:00
" \" blocks \" : xxxxxx, (numeric) the current number of blocks processed in the server \n "
" \" timeoffset \" : xxxxx, (numeric) the time offset \n "
" \" connections \" : xxxxx, (numeric) the number of connections \n "
" \" proxy \" : \" host:port \" , (string, optional) the proxy used by the server \n "
" \" difficulty \" : xxxxxx, (numeric) the current difficulty \n "
" \" testnet \" : true|false, (boolean) if the server is using testnet or not \n "
" \" keypoololdest \" : xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool \n "
" \" keypoolsize \" : xxxx, (numeric) how many new keys are pre-generated \n "
" \" unlocked_until \" : ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked \n "
2015-08-01 21:15:23 +02:00
" \" paytxfee \" : x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + " /kB \n "
" \" relayfee \" : x.xxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + " /kB \n "
2013-12-13 16:03:57 +01:00
" \" errors \" : \" ... \" (string) any error messages \n "
" } \n "
" \n Examples: \n "
+ HelpExampleCli ( " getinfo " , " " )
+ HelpExampleRpc ( " getinfo " , " " )
) ;
2014-10-19 10:46:17 +02:00
# ifdef ENABLE_WALLET
LOCK2 ( cs_main , pwalletMain ? & pwalletMain - > cs_wallet : NULL ) ;
# else
LOCK ( cs_main ) ;
# endif
2013-12-13 16:03:57 +01:00
proxyType proxy ;
GetProxy ( NET_IPV4 , proxy ) ;
2015-05-10 14:48:35 +02:00
UniValue obj ( UniValue : : VOBJ ) ;
2014-09-09 10:09:59 +02:00
obj . push_back ( Pair ( " version " , CLIENT_VERSION ) ) ;
obj . push_back ( Pair ( " protocolversion " , PROTOCOL_VERSION ) ) ;
2013-12-13 16:03:57 +01:00
# ifdef ENABLE_WALLET
if ( pwalletMain ) {
obj . push_back ( Pair ( " walletversion " , pwalletMain - > GetVersion ( ) ) ) ;
obj . push_back ( Pair ( " balance " , ValueFromAmount ( pwalletMain - > GetBalance ( ) ) ) ) ;
2015-02-19 19:22:00 +01:00
if ( ! fLiteMode )
2016-05-25 08:39:23 +02:00
obj . push_back ( Pair ( " privatesend_balance " , ValueFromAmount ( pwalletMain - > GetAnonymizedBalance ( ) ) ) ) ;
2013-12-13 16:03:57 +01:00
}
# endif
obj . push_back ( Pair ( " blocks " , ( int ) chainActive . Height ( ) ) ) ;
2014-05-05 20:08:13 +02:00
obj . push_back ( Pair ( " timeoffset " , GetTimeOffset ( ) ) ) ;
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
if ( g_connman )
obj . push_back ( Pair ( " connections " , ( int ) g_connman - > GetNodeCount ( CConnman : : CONNECTIONS_ALL ) ) ) ;
2015-03-16 16:30:49 +01:00
obj . push_back ( Pair ( " proxy " , ( proxy . IsValid ( ) ? proxy . proxy . ToStringIPPort ( ) : string ( ) ) ) ) ;
2013-12-13 16:03:57 +01:00
obj . push_back ( Pair ( " difficulty " , ( double ) GetDifficulty ( ) ) ) ;
2014-08-31 22:32:52 +02:00
obj . push_back ( Pair ( " testnet " , Params ( ) . TestnetToBeDeprecatedFieldRPC ( ) ) ) ;
2013-12-13 16:03:57 +01:00
# ifdef ENABLE_WALLET
if ( pwalletMain ) {
2014-05-05 20:08:13 +02:00
obj . push_back ( Pair ( " keypoololdest " , pwalletMain - > GetOldestKeyPoolTime ( ) ) ) ;
2013-12-13 16:03:57 +01:00
obj . push_back ( Pair ( " keypoolsize " , ( int ) pwalletMain - > GetKeyPoolSize ( ) ) ) ;
}
if ( pwalletMain & & pwalletMain - > IsCrypted ( ) )
2014-05-05 20:08:13 +02:00
obj . push_back ( Pair ( " unlocked_until " , nWalletUnlockTime ) ) ;
2014-04-10 20:14:18 +02:00
obj . push_back ( Pair ( " paytxfee " , ValueFromAmount ( payTxFee . GetFeePerK ( ) ) ) ) ;
2013-12-13 16:03:57 +01:00
# endif
2014-07-03 20:25:32 +02:00
obj . push_back ( Pair ( " relayfee " , ValueFromAmount ( : : minRelayTxFee . GetFeePerK ( ) ) ) ) ;
2013-12-13 16:03:57 +01:00
obj . push_back ( Pair ( " errors " , GetWarnings ( " statusbar " ) ) ) ;
return obj ;
}
2016-03-14 23:56:55 +01:00
UniValue debug ( const UniValue & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" debug ( 0|1|addrman|alert|bench|coindb|db|lock|rand|rpc|selectcoins|mempool "
" |mempoolrej|net|proxy|prune|http|libevent|tor|zmq| "
2016-09-15 08:50:16 +02:00
" dash|privatesend|instantsend|masternode|spork|keepass|mnpayments|gobject ) \n "
2016-03-14 23:56:55 +01:00
" Change debug category on the fly. Specify single category or use comma to specify many. \n "
" \n Examples: \n "
+ HelpExampleCli ( " debug " , " dash " )
+ HelpExampleRpc ( " debug " , " dash,net " )
) ;
std : : string strMode = params [ 0 ] . get_str ( ) ;
mapMultiArgs [ " -debug " ] . clear ( ) ;
boost : : split ( mapMultiArgs [ " -debug " ] , strMode , boost : : is_any_of ( " , " ) ) ;
mapArgs [ " -debug " ] = mapMultiArgs [ " -debug " ] [ mapMultiArgs [ " -debug " ] . size ( ) - 1 ] ;
fDebug = mapArgs [ " -debug " ] ! = " 0 " ;
return " Debug mode: " + ( fDebug ? strMode : " off " ) ;
}
2016-02-02 16:28:56 +01:00
UniValue mnsync ( const UniValue & params , bool fHelp )
2015-08-05 16:24:58 +02:00
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
2016-06-08 08:57:16 +02:00
" mnsync [status|next|reset] \n "
" Returns the sync status, updates to the next step or resets it entirely. \n "
2015-08-05 16:24:58 +02:00
) ;
std : : string strMode = params [ 0 ] . get_str ( ) ;
if ( strMode = = " status " ) {
2016-08-28 12:12:14 +02:00
UniValue objStatus ( UniValue : : VOBJ ) ;
objStatus . push_back ( Pair ( " AssetID " , masternodeSync . GetAssetID ( ) ) ) ;
objStatus . push_back ( Pair ( " AssetName " , masternodeSync . GetAssetName ( ) ) ) ;
2017-05-31 05:49:09 +02:00
objStatus . push_back ( Pair ( " AssetStartTime " , masternodeSync . GetAssetStartTime ( ) ) ) ;
2016-08-28 12:12:14 +02:00
objStatus . push_back ( Pair ( " Attempt " , masternodeSync . GetAttempt ( ) ) ) ;
objStatus . push_back ( Pair ( " IsBlockchainSynced " , masternodeSync . IsBlockchainSynced ( ) ) ) ;
2016-08-29 21:11:34 +02:00
objStatus . push_back ( Pair ( " IsMasternodeListSynced " , masternodeSync . IsMasternodeListSynced ( ) ) ) ;
objStatus . push_back ( Pair ( " IsWinnersListSynced " , masternodeSync . IsWinnersListSynced ( ) ) ) ;
2016-08-28 12:12:14 +02:00
objStatus . push_back ( Pair ( " IsSynced " , masternodeSync . IsSynced ( ) ) ) ;
objStatus . push_back ( Pair ( " IsFailed " , masternodeSync . IsFailed ( ) ) ) ;
return objStatus ;
2015-08-05 16:24:58 +02:00
}
2016-06-08 08:57:16 +02:00
if ( strMode = = " next " )
{
2017-09-19 16:51:38 +02:00
masternodeSync . SwitchToNextAsset ( * g_connman ) ;
2016-06-08 08:57:16 +02:00
return " sync updated to " + masternodeSync . GetAssetName ( ) ;
}
2015-08-05 16:24:58 +02:00
if ( strMode = = " reset " )
{
masternodeSync . Reset ( ) ;
2017-09-19 16:51:38 +02:00
masternodeSync . SwitchToNextAsset ( * g_connman ) ;
2015-08-05 16:24:58 +02:00
return " success " ;
}
return " failure " ;
}
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 :
2015-05-18 14:02:18 +02:00
UniValue operator ( ) ( const CNoDestination & dest ) const { return UniValue ( UniValue : : VOBJ ) ; }
2013-07-26 01:06:01 +02: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 ) ) ;
2015-11-09 08:40:46 +01:00
if ( pwalletMain & & pwalletMain - > 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 ) ) ;
2015-11-09 08:40:46 +01:00
if ( pwalletMain & & pwalletMain - > 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 ) ;
2013-07-26 01:06:01 +02:00
BOOST_FOREACH ( const CTxDestination & addr , addresses )
a . push_back ( CBitcoinAddress ( addr ) . ToString ( ) ) ;
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 ;
}
} ;
# endif
2015-02-09 20:28:29 +01:00
/*
Used for updating / reading spork settings on the network
*/
2016-02-02 16:28:56 +01:00
UniValue spork ( const UniValue & params , bool fHelp )
2015-02-09 20:28:29 +01:00
{
if ( params . size ( ) = = 1 & & params [ 0 ] . get_str ( ) = = " show " ) {
2016-02-02 16:28:56 +01:00
UniValue ret ( UniValue : : VOBJ ) ;
2015-06-25 21:59:11 +02:00
for ( int nSporkID = SPORK_START ; nSporkID < = SPORK_END ; nSporkID + + ) {
if ( sporkManager . GetSporkNameByID ( nSporkID ) ! = " Unknown " )
2016-07-30 13:04:27 +02:00
ret . push_back ( Pair ( sporkManager . GetSporkNameByID ( nSporkID ) , sporkManager . GetSporkValue ( nSporkID ) ) ) ;
2015-06-25 17:17:53 +02:00
}
return ret ;
} else if ( params . size ( ) = = 1 & & params [ 0 ] . get_str ( ) = = " active " ) {
2016-02-02 16:28:56 +01:00
UniValue ret ( UniValue : : VOBJ ) ;
2015-06-25 21:59:11 +02:00
for ( int nSporkID = SPORK_START ; nSporkID < = SPORK_END ; nSporkID + + ) {
if ( sporkManager . GetSporkNameByID ( nSporkID ) ! = " Unknown " )
2016-07-30 13:04:27 +02:00
ret . push_back ( Pair ( sporkManager . GetSporkNameByID ( nSporkID ) , sporkManager . IsSporkActive ( nSporkID ) ) ) ;
2015-02-09 20:28:29 +01:00
}
return ret ;
2017-12-01 19:53:34 +01:00
}
# ifdef ENABLE_WALLET
else if ( params . size ( ) = = 2 ) {
2015-02-09 20:28:29 +01:00
int nSporkID = sporkManager . GetSporkIDByName ( params [ 0 ] . get_str ( ) ) ;
if ( nSporkID = = - 1 ) {
return " Invalid spork name " ;
}
2017-09-07 17:58:38 +02:00
if ( ! g_connman )
throw JSONRPCError ( RPC_CLIENT_P2P_DISABLED , " Error: Peer-to-peer functionality missing or disabled " ) ;
2015-02-11 15:47:21 +01:00
// SPORK VALUE
2017-02-10 01:51:47 +01:00
int64_t nValue = params [ 1 ] . get_int64 ( ) ;
2015-02-09 20:28:29 +01:00
//broadcast new spork
2017-09-07 17:58:38 +02:00
if ( sporkManager . UpdateSpork ( nSporkID , nValue , * g_connman ) ) {
2016-07-30 13:04:27 +02:00
sporkManager . ExecuteSpork ( nSporkID , nValue ) ;
2015-02-09 20:28:29 +01:00
return " success " ;
} else {
return " failure " ;
}
}
throw runtime_error (
" spork <name> [<value>] \n "
2017-12-01 19:53:34 +01:00
" <name> is the corresponding spork name, or 'show' to show all current spork settings, active to show which sporks are active \n "
" <value> is a epoch datetime to enable or disable spork \n "
2015-02-09 20:28:29 +01:00
+ HelpRequiringPassphrase ( ) ) ;
2017-12-01 19:53:34 +01:00
# else // ENABLE_WALLET
throw runtime_error (
" spork <name> \n "
" <name> is the corresponding spork name, or 'show' to show all current spork settings, active to show which sporks are active \n " ) ;
# endif // ENABLE_WALLET
2015-02-09 20:28:29 +01:00
}
2015-05-18 14:02:18 +02:00
UniValue validateaddress ( const UniValue & params , bool fHelp )
2013-12-13 16:18:00 +01:00
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
2015-03-19 15:15:08 +01:00
" validateaddress \" dashaddress \" \n "
" \n Return information about the given dash address. \n "
2013-12-13 16:18:00 +01:00
" \n Arguments: \n "
2015-03-19 15:15:08 +01:00
" 1. \" dashaddress \" (string, required) The dash 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 "
2015-03-19 15:15:08 +01:00
" \" address \" : \" dashaddress \" , (string) The dash 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 "
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-05-29 13:51:40 +02:00
" \" hdkeypath \" : \" keypath \" (string, optional) The HD keypath if the key is HD and available \n "
" \" hdchainid \" : \" <hash> \" (string, optional) The ID of the HD chain \n "
2013-12-13 16:18:00 +01:00
" } \n "
" \n Examples: \n "
2016-09-02 14:17:58 +02:00
+ HelpExampleCli ( " validateaddress " , " \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" " )
+ HelpExampleRpc ( " validateaddress " , " \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" " )
2013-12-13 16:18:00 +01:00
) ;
2014-10-19 10:46:17 +02:00
# ifdef ENABLE_WALLET
LOCK2 ( cs_main , pwalletMain ? & pwalletMain - > cs_wallet : NULL ) ;
# else
LOCK ( cs_main ) ;
# endif
2013-12-13 16:18:00 +01:00
CBitcoinAddress address ( params [ 0 ] . get_str ( ) ) ;
bool isValid = address . IsValid ( ) ;
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 )
{
CTxDestination dest = address . Get ( ) ;
string currentAddress = address . ToString ( ) ;
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
2014-07-01 11:00:22 +02:00
isminetype mine = pwalletMain ? IsMine ( * pwalletMain , dest ) : ISMINE_NO ;
ret . push_back ( Pair ( " ismine " , ( mine & ISMINE_SPENDABLE ) ? true : false ) ) ;
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 . push_back ( Pair ( " iswatchonly " , ( mine & ISMINE_WATCH_ONLY ) ? true : false ) ) ;
UniValue detail = boost : : apply_visitor ( DescribeAddressVisitor ( ) , dest ) ;
ret . pushKVs ( detail ) ;
2013-12-13 16:18:00 +01:00
if ( pwalletMain & & pwalletMain - > mapAddressBook . count ( dest ) )
ret . push_back ( Pair ( " account " , pwalletMain - > mapAddressBook [ dest ] . name ) ) ;
2017-05-29 13:51:40 +02:00
CKeyID keyID ;
CHDChain hdChainCurrent ;
if ( pwalletMain & & address . GetKeyID ( keyID ) & & pwalletMain - > mapHdPubKeys . count ( keyID ) & & pwalletMain - > GetHDChain ( hdChainCurrent ) )
{
ret . push_back ( Pair ( " hdkeypath " , pwalletMain - > mapHdPubKeys [ keyID ] . GetKeyPath ( ) ) ) ;
ret . push_back ( Pair ( " hdchainid " , hdChainCurrent . GetID ( ) . GetHex ( ) ) ) ;
}
2013-12-13 16:18:00 +01:00
# endif
}
return ret ;
}
2014-11-20 03:19:29 +01:00
/**
* Used by addmultisigaddress / createmultisig :
*/
2015-05-18 14:02:18 +02:00
CScript _createmultisig_redeemScript ( 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 )
throw runtime_error ( " a multisignature address must require at least one key to redeem " ) ;
if ( ( int ) keys . size ( ) < nRequired )
throw runtime_error (
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 )
throw 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
2015-03-18 00:06:58 +01:00
// Case 1: Dash address and we have full public key:
2013-12-13 16:21:38 +01:00
CBitcoinAddress address ( ks ) ;
if ( pwalletMain & & address . IsValid ( ) )
{
CKeyID keyID ;
if ( ! address . GetKeyID ( keyID ) )
throw runtime_error (
2014-01-16 16:15:27 +01:00
strprintf ( " %s does not refer to a key " , ks ) ) ;
2013-12-13 16:21:38 +01:00
CPubKey vchPubKey ;
if ( ! pwalletMain - > GetPubKey ( keyID , vchPubKey ) )
throw runtime_error (
2014-01-16 16:15:27 +01:00
strprintf ( " no full public key for address %s " , ks ) ) ;
2013-12-13 16:21:38 +01:00
if ( ! vchPubKey . IsFullyValid ( ) )
throw runtime_error ( " Invalid public key: " + ks ) ;
pubkeys [ i ] = vchPubKey ;
}
// Case 2: hex public key
else
# endif
if ( IsHex ( ks ) )
{
CPubKey vchPubKey ( ParseHex ( ks ) ) ;
if ( ! vchPubKey . IsFullyValid ( ) )
throw runtime_error ( " Invalid public key: " + ks ) ;
pubkeys [ i ] = vchPubKey ;
}
else
{
throw runtime_error ( " Invalid public key: " + ks ) ;
}
}
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 )
throw runtime_error (
strprintf ( " redeemScript exceeds size limit: %d > %d " , result . size ( ) , MAX_SCRIPT_ELEMENT_SIZE ) ) ;
2013-12-13 16:21:38 +01:00
return result ;
}
2015-05-18 14:02:18 +02:00
UniValue createmultisig ( const UniValue & params , bool fHelp )
2013-12-13 16:21:38 +01:00
{
if ( fHelp | | params . size ( ) < 2 | | params . size ( ) > 2 )
{
string msg = " createmultisig nrequired [ \" key \" ,...] \n "
" \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 "
2015-03-19 15:15:08 +01:00
" 2. \" keys \" (string, required) A json array of keys which are dash addresses or hex-encoded public keys \n "
2013-12-13 16:21:38 +01:00
" [ \n "
2015-03-19 15:15:08 +01:00
" \" key \" (string) dash address or hex-encoded public key \n "
2013-12-13 16:21:38 +01:00
" ,... \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 "
2016-09-02 14:17:58 +02:00
+ HelpExampleCli ( " createmultisig " , " 2 \" [ \\ \" Xt4qk9uKvQYAonVGSZNXqxeDmtjaEWgfrs \\ \" , \\ \" XoSoWQkpgLpppPoyyzbUFh1fq2RBvW6UK1 \\ \" ] \" " ) +
2013-12-13 16:21:38 +01:00
" \n As a json rpc call \n "
2016-09-02 14:17:58 +02:00
+ HelpExampleRpc ( " createmultisig " , " 2, \" [ \\ \" Xt4qk9uKvQYAonVGSZNXqxeDmtjaEWgfrs \\ \" , \\ \" XoSoWQkpgLpppPoyyzbUFh1fq2RBvW6UK1 \\ \" ] \" " )
2013-12-13 16:21:38 +01:00
;
throw runtime_error ( msg ) ;
}
// Construct using pay-to-script-hash:
2014-03-11 03:43:15 +01:00
CScript inner = _createmultisig_redeemScript ( params ) ;
2014-09-25 04:24:46 +02:00
CScriptID innerID ( inner ) ;
2013-12-13 16:21:38 +01:00
CBitcoinAddress address ( innerID ) ;
2015-06-02 12:28:54 +02:00
UniValue result ( UniValue : : VOBJ ) ;
2013-12-13 16:21:38 +01:00
result . push_back ( Pair ( " address " , address . ToString ( ) ) ) ;
result . push_back ( Pair ( " redeemScript " , HexStr ( inner . begin ( ) , inner . end ( ) ) ) ) ;
return result ;
}
2015-05-18 14:02:18 +02:00
UniValue verifymessage ( const UniValue & params , bool fHelp )
2013-12-13 16:23:39 +01:00
{
if ( fHelp | | params . size ( ) ! = 3 )
throw runtime_error (
2015-03-19 15:15:08 +01:00
" verifymessage \" dashaddress \" \" signature \" \" message \" \n "
2013-12-13 16:23:39 +01:00
" \n Verify a signed message \n "
" \n Arguments: \n "
2015-03-19 15:15:08 +01:00
" 1. \" dashaddress \" (string, required) The dash 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 "
2016-09-02 14:17:58 +02:00
+ HelpExampleCli ( " signmessage " , " \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" \" my message \" " ) +
2013-12-13 16:23:39 +01:00
" \n Verify the signature \n "
2016-09-02 14:17:58 +02:00
+ HelpExampleCli ( " verifymessage " , " \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" \" signature \" \" my message \" " ) +
2013-12-13 16:23:39 +01:00
" \n As json rpc \n "
2016-09-02 14:17:58 +02:00
+ HelpExampleRpc ( " verifymessage " , " \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" , \" signature \" , \" my message \" " )
2013-12-13 16:23:39 +01:00
) ;
2014-10-19 10:46:17 +02:00
LOCK ( cs_main ) ;
2013-12-13 16:23:39 +01:00
string strAddress = params [ 0 ] . get_str ( ) ;
string strSign = params [ 1 ] . get_str ( ) ;
string strMessage = params [ 2 ] . get_str ( ) ;
CBitcoinAddress addr ( strAddress ) ;
if ( ! addr . IsValid ( ) )
throw JSONRPCError ( RPC_TYPE_ERROR , " Invalid address " ) ;
CKeyID keyID ;
if ( ! addr . GetKeyID ( keyID ) )
throw JSONRPCError ( RPC_TYPE_ERROR , " Address does not refer to key " ) ;
bool fInvalid = false ;
vector < unsigned char > vchSig = DecodeBase64 ( strSign . c_str ( ) , & fInvalid ) ;
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 ;
return ( pubkey . GetID ( ) = = keyID ) ;
}
2014-11-13 00:59:41 +01:00
2015-05-18 14:02:18 +02:00
UniValue setmocktime ( const UniValue & params , bool fHelp )
2014-11-13 00:59:41 +01:00
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" 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 ( ) )
throw runtime_error ( " setmocktime for regression testing (-regtest mode) only " ) ;
2017-08-24 01:38:29 +02: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
// ensure all callsites of GetTime() are accessing this safely.
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
LOCK ( cs_main ) ;
2014-10-19 10:46:17 +02:00
2015-05-10 13:35:44 +02:00
RPCTypeCheck ( params , boost : : assign : : list_of ( UniValue : : VNUM ) ) ;
2014-11-13 00:59:41 +01:00
SetMockTime ( params [ 0 ] . get_int64 ( ) ) ;
2015-05-10 13:35:44 +02:00
return NullUniValue ;
2014-11-13 00:59:41 +01:00
}
2016-03-05 22:31:10 +01:00
2016-04-21 21:59:51 +02:00
bool getAddressFromIndex ( const int & type , const uint160 & hash , std : : string & address )
{
if ( type = = 2 ) {
address = CBitcoinAddress ( CScriptID ( hash ) ) . ToString ( ) ;
} else if ( type = = 1 ) {
address = CBitcoinAddress ( CKeyID ( hash ) ) . ToString ( ) ;
} else {
return false ;
}
return true ;
}
2016-03-17 21:06:08 +01:00
bool getAddressesFromParams ( const UniValue & params , std : : vector < std : : pair < uint160 , int > > & addresses )
2016-03-05 22:31:10 +01:00
{
2016-03-15 20:25:01 +01:00
if ( params [ 0 ] . isStr ( ) ) {
CBitcoinAddress address ( params [ 0 ] . get_str ( ) ) ;
uint160 hashBytes ;
int type = 0 ;
if ( ! address . GetIndexKey ( hashBytes , type ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid address " ) ;
}
addresses . push_back ( std : : make_pair ( hashBytes , type ) ) ;
} else if ( params [ 0 ] . isObject ( ) ) {
UniValue addressValues = find_value ( params [ 0 ] . get_obj ( ) , " addresses " ) ;
if ( ! addressValues . isArray ( ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Addresses is expected to be an array " ) ;
}
std : : vector < UniValue > values = addressValues . getValues ( ) ;
for ( std : : vector < UniValue > : : iterator it = values . begin ( ) ; it ! = values . end ( ) ; + + it ) {
CBitcoinAddress address ( it - > get_str ( ) ) ;
uint160 hashBytes ;
int type = 0 ;
if ( ! address . GetIndexKey ( hashBytes , type ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid address " ) ;
}
addresses . push_back ( std : : make_pair ( hashBytes , type ) ) ;
}
} else {
2016-03-05 22:31:10 +01:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid address " ) ;
2016-03-09 23:40:40 +01:00
}
2016-03-05 22:31:10 +01:00
2016-03-17 21:06:08 +01:00
return true ;
2016-03-30 22:42:37 +02:00
}
2016-03-17 21:06:08 +01:00
2016-03-30 22:42:37 +02:00
bool heightSort ( std : : pair < CAddressUnspentKey , CAddressUnspentValue > a ,
std : : pair < CAddressUnspentKey , CAddressUnspentValue > b ) {
return a . second . blockHeight < b . second . blockHeight ;
2016-03-17 21:06:08 +01:00
}
2016-04-04 22:37:43 +02:00
bool timestampSort ( std : : pair < CMempoolAddressDeltaKey , CMempoolAddressDelta > a ,
std : : pair < CMempoolAddressDeltaKey , CMempoolAddressDelta > b ) {
return a . second . time < b . second . time ;
}
UniValue getaddressmempool ( const UniValue & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" getaddressmempool \n "
" \n Returns all mempool deltas for an address (requires addressindex to be enabled). \n "
2016-05-12 00:33:22 +02:00
" \n Arguments: \n "
" { \n "
" \" addresses \" \n "
" [ \n "
" \" address \" (string) The base58check encoded address \n "
" ,... \n "
" ] \n "
" } \n "
" \n Result: \n "
" [ \n "
" { \n "
" \" address \" (string) The base58check encoded address \n "
" \" txid \" (string) The related txid \n "
" \" index \" (number) The related input or output index \n "
2017-11-02 10:16:00 +01:00
" \" satoshis \" (number) The difference of duffs \n "
2016-05-12 00:33:22 +02:00
" \" timestamp \" (number) The time the transaction entered the mempool (seconds) \n "
" \" prevtxid \" (string) The previous txid (if spending) \n "
" \" prevout \" (string) The previous transaction output index (if spending) \n "
" } \n "
" ] \n "
" \n Examples: \n "
2016-09-02 14:17:58 +02:00
+ HelpExampleCli ( " getaddressmempool " , " '{ \" addresses \" : [ \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" ]}' " )
+ HelpExampleRpc ( " getaddressmempool " , " { \" addresses \" : [ \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" ]} " )
2016-05-12 00:33:22 +02:00
) ;
2016-04-04 22:37:43 +02:00
std : : vector < std : : pair < uint160 , int > > addresses ;
if ( ! getAddressesFromParams ( params , addresses ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid address " ) ;
}
std : : vector < std : : pair < CMempoolAddressDeltaKey , CMempoolAddressDelta > > indexes ;
if ( ! mempool . getAddressIndex ( addresses , indexes ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " No information available for address " ) ;
}
std : : sort ( indexes . begin ( ) , indexes . end ( ) , timestampSort ) ;
UniValue result ( UniValue : : VARR ) ;
for ( std : : vector < std : : pair < CMempoolAddressDeltaKey , CMempoolAddressDelta > > : : iterator it = indexes . begin ( ) ;
it ! = indexes . end ( ) ; it + + ) {
2016-04-21 21:59:51 +02:00
std : : string address ;
if ( ! getAddressFromIndex ( it - > first . type , it - > first . addressBytes , address ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Unknown address type " ) ;
}
2016-04-04 22:37:43 +02:00
UniValue delta ( UniValue : : VOBJ ) ;
2016-04-21 21:59:51 +02:00
delta . push_back ( Pair ( " address " , address ) ) ;
2016-04-04 22:37:43 +02:00
delta . push_back ( Pair ( " txid " , it - > first . txhash . GetHex ( ) ) ) ;
delta . push_back ( Pair ( " index " , ( int ) it - > first . index ) ) ;
delta . push_back ( Pair ( " satoshis " , it - > second . amount ) ) ;
delta . push_back ( Pair ( " timestamp " , it - > second . time ) ) ;
2016-04-21 21:07:01 +02:00
if ( it - > second . amount < 0 ) {
delta . push_back ( Pair ( " prevtxid " , it - > second . prevhash . GetHex ( ) ) ) ;
delta . push_back ( Pair ( " prevout " , ( int ) it - > second . prevout ) ) ;
}
2016-04-04 22:37:43 +02:00
result . push_back ( delta ) ;
}
return result ;
}
2016-03-29 21:17:30 +02:00
UniValue getaddressutxos ( const UniValue & params , bool fHelp )
{
2016-03-29 23:46:59 +02:00
if ( fHelp | | params . size ( ) ! = 1 )
2016-03-29 21:17:30 +02:00
throw runtime_error (
" getaddressutxos \n "
" \n Returns all unspent outputs for an address (requires addressindex to be enabled). \n "
2016-05-12 00:33:22 +02:00
" \n Arguments: \n "
" { \n "
" \" addresses \" \n "
" [ \n "
" \" address \" (string) The base58check encoded address \n "
" ,... \n "
" ] \n "
" } \n "
2016-03-29 21:17:30 +02:00
" \n Result \n "
" [ \n "
" { \n "
" \" address \" (string) The address base58check encoded \n "
" \" txid \" (string) The output txid \n "
" \" outputIndex \" (number) The output index \n "
2017-10-09 20:24:56 +02:00
" \" script \" (string) The script hex encoded \n "
2017-11-02 10:16:00 +01:00
" \" satoshis \" (number) The number of duffs of the output \n "
2017-10-09 20:24:56 +02:00
" \" height \" (number) The block height \n "
2016-03-29 21:17:30 +02:00
" } \n "
" ] \n "
2016-05-12 00:33:22 +02:00
" \n Examples: \n "
2016-09-02 14:17:58 +02:00
+ HelpExampleCli ( " getaddressutxos " , " '{ \" addresses \" : [ \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" ]}' " )
+ HelpExampleRpc ( " getaddressutxos " , " { \" addresses \" : [ \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" ]} " )
2016-05-12 00:33:22 +02:00
) ;
2016-03-29 21:17:30 +02:00
std : : vector < std : : pair < uint160 , int > > addresses ;
if ( ! getAddressesFromParams ( params , addresses ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid address " ) ;
}
std : : vector < std : : pair < CAddressUnspentKey , CAddressUnspentValue > > unspentOutputs ;
for ( std : : vector < std : : pair < uint160 , int > > : : iterator it = addresses . begin ( ) ; it ! = addresses . end ( ) ; it + + ) {
if ( ! GetAddressUnspent ( ( * it ) . first , ( * it ) . second , unspentOutputs ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " No information available for address " ) ;
}
}
2016-03-30 22:42:37 +02:00
std : : sort ( unspentOutputs . begin ( ) , unspentOutputs . end ( ) , heightSort ) ;
2016-03-29 21:17:30 +02:00
UniValue result ( UniValue : : VARR ) ;
for ( std : : vector < std : : pair < CAddressUnspentKey , CAddressUnspentValue > > : : const_iterator it = unspentOutputs . begin ( ) ; it ! = unspentOutputs . end ( ) ; it + + ) {
UniValue output ( UniValue : : VOBJ ) ;
2016-04-05 16:49:11 +02:00
std : : string address ;
2016-04-21 21:59:51 +02:00
if ( ! getAddressFromIndex ( it - > first . type , it - > first . hashBytes , address ) ) {
2016-04-05 16:49:11 +02:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Unknown address type " ) ;
}
output . push_back ( Pair ( " address " , address ) ) ;
2016-03-29 21:17:30 +02:00
output . push_back ( Pair ( " txid " , it - > first . txhash . GetHex ( ) ) ) ;
2016-04-07 19:52:40 +02:00
output . push_back ( Pair ( " outputIndex " , ( int ) it - > first . index ) ) ;
2016-03-29 21:17:30 +02:00
output . push_back ( Pair ( " script " , HexStr ( it - > second . script . begin ( ) , it - > second . script . end ( ) ) ) ) ;
output . push_back ( Pair ( " satoshis " , it - > second . satoshis ) ) ;
2016-03-30 22:42:37 +02:00
output . push_back ( Pair ( " height " , it - > second . blockHeight ) ) ;
2016-03-29 21:17:30 +02:00
result . push_back ( output ) ;
}
return result ;
}
2016-03-24 20:44:23 +01:00
UniValue getaddressdeltas ( const UniValue & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 | | ! params [ 0 ] . isObject ( ) )
throw runtime_error (
" getaddressdeltas \n "
" \n Returns all changes for an address (requires addressindex to be enabled). \n "
2016-05-12 00:33:22 +02:00
" \n Arguments: \n "
" { \n "
" \" addresses \" \n "
" [ \n "
" \" address \" (string) The base58check encoded address \n "
" ,... \n "
" ] \n "
" \" start \" (number) The start block height \n "
" \" end \" (number) The end block height \n "
" } \n "
" \n Result: \n "
2016-03-24 20:44:23 +01:00
" [ \n "
" { \n "
2017-11-02 10:16:00 +01:00
" \" satoshis \" (number) The difference of duffs \n "
2016-03-24 20:44:23 +01:00
" \" txid \" (string) The related txid \n "
" \" index \" (number) The related input or output index \n "
2017-10-09 20:24:56 +02:00
" \" blockindex \" (number) The related block index \n "
2016-03-24 20:44:23 +01:00
" \" height \" (number) The block height \n "
2016-04-21 21:59:51 +02:00
" \" address \" (string) The base58check encoded address \n "
2016-03-24 20:44:23 +01:00
" } \n "
" ] \n "
2016-05-12 00:33:22 +02:00
" \n Examples: \n "
2016-09-02 14:17:58 +02:00
+ HelpExampleCli ( " getaddressdeltas " , " '{ \" addresses \" : [ \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" ]}' " )
+ HelpExampleRpc ( " getaddressdeltas " , " { \" addresses \" : [ \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" ]} " )
2016-03-24 20:44:23 +01:00
) ;
UniValue startValue = find_value ( params [ 0 ] . get_obj ( ) , " start " ) ;
UniValue endValue = find_value ( params [ 0 ] . get_obj ( ) , " end " ) ;
2016-04-21 22:07:42 +02:00
int start = 0 ;
int end = 0 ;
if ( startValue . isNum ( ) & & endValue . isNum ( ) ) {
start = startValue . get_int ( ) ;
end = endValue . get_int ( ) ;
if ( end < start ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " End value is expected to be greater than start " ) ;
}
2016-03-24 20:44:23 +01:00
}
std : : vector < std : : pair < uint160 , int > > addresses ;
if ( ! getAddressesFromParams ( params , addresses ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid address " ) ;
}
std : : vector < std : : pair < CAddressIndexKey , CAmount > > addressIndex ;
for ( std : : vector < std : : pair < uint160 , int > > : : iterator it = addresses . begin ( ) ; it ! = addresses . end ( ) ; it + + ) {
2016-04-21 22:07:42 +02:00
if ( start > 0 & & end > 0 ) {
if ( ! GetAddressIndex ( ( * it ) . first , ( * it ) . second , addressIndex , start , end ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " No information available for address " ) ;
}
} else {
if ( ! GetAddressIndex ( ( * it ) . first , ( * it ) . second , addressIndex ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " No information available for address " ) ;
}
2016-03-24 20:44:23 +01:00
}
}
UniValue result ( UniValue : : VARR ) ;
for ( std : : vector < std : : pair < CAddressIndexKey , CAmount > > : : const_iterator it = addressIndex . begin ( ) ; it ! = addressIndex . end ( ) ; it + + ) {
2016-04-21 21:59:51 +02:00
std : : string address ;
if ( ! getAddressFromIndex ( it - > first . type , it - > first . hashBytes , address ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Unknown address type " ) ;
}
2016-03-24 20:44:23 +01:00
UniValue delta ( UniValue : : VOBJ ) ;
delta . push_back ( Pair ( " satoshis " , it - > second ) ) ;
delta . push_back ( Pair ( " txid " , it - > first . txhash . GetHex ( ) ) ) ;
2016-04-07 19:52:40 +02:00
delta . push_back ( Pair ( " index " , ( int ) it - > first . index ) ) ;
2016-05-10 16:27:03 +02:00
delta . push_back ( Pair ( " blockindex " , ( int ) it - > first . txindex ) ) ;
2016-03-24 20:44:23 +01:00
delta . push_back ( Pair ( " height " , it - > first . blockHeight ) ) ;
2016-04-21 21:59:51 +02:00
delta . push_back ( Pair ( " address " , address ) ) ;
2016-03-24 20:44:23 +01:00
result . push_back ( delta ) ;
}
return result ;
}
2016-03-17 21:06:08 +01:00
UniValue getaddressbalance ( const UniValue & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" getaddressbalance \n "
2016-05-12 00:33:22 +02:00
" \n Returns the balance for an address(es) (requires addressindex to be enabled). \n "
" \n Arguments: \n "
2016-03-17 21:06:08 +01:00
" { \n "
2016-05-12 00:33:22 +02:00
" \" addresses \" \n "
" [ \n "
" \" address \" (string) The base58check encoded address \n "
" ,... \n "
" ] \n "
2016-03-17 21:06:08 +01:00
" } \n "
2016-05-12 00:33:22 +02:00
" \n Result: \n "
" { \n "
2017-10-09 20:24:56 +02:00
" \" balance \" (string) The current balance in duffs \n "
" \" received \" (string) The total number of duffs received (including change) \n "
2016-05-12 00:33:22 +02:00
" } \n "
" \n Examples: \n "
2016-09-02 14:17:58 +02:00
+ HelpExampleCli ( " getaddressbalance " , " '{ \" addresses \" : [ \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" ]}' " )
+ HelpExampleRpc ( " getaddressbalance " , " { \" addresses \" : [ \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" ]} " )
2016-03-17 21:06:08 +01:00
) ;
std : : vector < std : : pair < uint160 , int > > addresses ;
if ( ! getAddressesFromParams ( params , addresses ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid address " ) ;
}
std : : vector < std : : pair < CAddressIndexKey , CAmount > > addressIndex ;
for ( std : : vector < std : : pair < uint160 , int > > : : iterator it = addresses . begin ( ) ; it ! = addresses . end ( ) ; it + + ) {
if ( ! GetAddressIndex ( ( * it ) . first , ( * it ) . second , addressIndex ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " No information available for address " ) ;
}
}
CAmount balance = 0 ;
2016-03-17 21:40:16 +01:00
CAmount received = 0 ;
2016-03-17 21:06:08 +01:00
for ( std : : vector < std : : pair < CAddressIndexKey , CAmount > > : : const_iterator it = addressIndex . begin ( ) ; it ! = addressIndex . end ( ) ; it + + ) {
2016-03-17 21:40:16 +01:00
if ( it - > second > 0 ) {
received + = it - > second ;
}
2016-03-17 21:06:08 +01:00
balance + = it - > second ;
}
UniValue result ( UniValue : : VOBJ ) ;
result . push_back ( Pair ( " balance " , balance ) ) ;
2016-03-17 21:40:16 +01:00
result . push_back ( Pair ( " received " , received ) ) ;
2016-03-17 21:06:08 +01:00
return result ;
}
UniValue getaddresstxids ( const UniValue & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" getaddresstxids \n "
2016-05-12 00:33:22 +02:00
" \n Returns the txids for an address(es) (requires addressindex to be enabled). \n "
" \n Arguments: \n "
" { \n "
" \" addresses \" \n "
" [ \n "
" \" address \" (string) The base58check encoded address \n "
" ,... \n "
" ] \n "
" \" start \" (number) The start block height \n "
" \" end \" (number) The end block height \n "
" } \n "
" \n Result: \n "
2016-03-17 21:06:08 +01:00
" [ \n "
" \" transactionid \" (string) The transaction id \n "
" ,... \n "
" ] \n "
2016-05-12 00:33:22 +02:00
" \n Examples: \n "
2016-09-02 14:17:58 +02:00
+ HelpExampleCli ( " getaddresstxids " , " '{ \" addresses \" : [ \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" ]}' " )
+ HelpExampleRpc ( " getaddresstxids " , " { \" addresses \" : [ \" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg \" ]} " )
2016-03-17 21:06:08 +01:00
) ;
std : : vector < std : : pair < uint160 , int > > addresses ;
if ( ! getAddressesFromParams ( params , addresses ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid address " ) ;
}
2016-04-12 22:04:10 +02:00
int start = 0 ;
int end = 0 ;
if ( params [ 0 ] . isObject ( ) ) {
UniValue startValue = find_value ( params [ 0 ] . get_obj ( ) , " start " ) ;
UniValue endValue = find_value ( params [ 0 ] . get_obj ( ) , " end " ) ;
if ( startValue . isNum ( ) & & endValue . isNum ( ) ) {
start = startValue . get_int ( ) ;
2016-04-13 02:33:18 +02:00
end = endValue . get_int ( ) ;
2016-04-12 22:04:10 +02:00
}
}
2016-03-05 22:31:10 +01:00
std : : vector < std : : pair < CAddressIndexKey , CAmount > > addressIndex ;
2016-03-17 21:06:08 +01:00
for ( std : : vector < std : : pair < uint160 , int > > : : iterator it = addresses . begin ( ) ; it ! = addresses . end ( ) ; it + + ) {
2016-04-12 22:04:10 +02:00
if ( start > 0 & & end > 0 ) {
if ( ! GetAddressIndex ( ( * it ) . first , ( * it ) . second , addressIndex , start , end ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " No information available for address " ) ;
}
} else {
if ( ! GetAddressIndex ( ( * it ) . first , ( * it ) . second , addressIndex ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " No information available for address " ) ;
}
2016-03-15 20:25:01 +01:00
}
}
2016-03-05 22:31:10 +01:00
2016-03-25 19:52:45 +01:00
std : : set < std : : pair < int , std : : string > > txids ;
UniValue result ( UniValue : : VARR ) ;
2016-03-10 01:45:08 +01:00
for ( std : : vector < std : : pair < CAddressIndexKey , CAmount > > : : const_iterator it = addressIndex . begin ( ) ; it ! = addressIndex . end ( ) ; it + + ) {
2016-03-15 21:24:55 +01:00
int height = it - > first . blockHeight ;
2016-03-10 01:45:08 +01:00
std : : string txid = it - > first . txhash . GetHex ( ) ;
2016-03-25 19:52:45 +01:00
if ( addresses . size ( ) > 1 ) {
txids . insert ( std : : make_pair ( height , txid ) ) ;
} else {
if ( txids . insert ( std : : make_pair ( height , txid ) ) . second ) {
result . push_back ( txid ) ;
}
2016-03-10 01:45:08 +01:00
}
}
2016-03-05 22:31:10 +01:00
2016-03-16 19:50:19 +01:00
if ( addresses . size ( ) > 1 ) {
2016-03-25 19:52:45 +01:00
for ( std : : set < std : : pair < int , std : : string > > : : const_iterator it = txids . begin ( ) ; it ! = txids . end ( ) ; it + + ) {
result . push_back ( it - > second ) ;
}
2016-03-15 21:24:55 +01:00
}
2016-03-05 22:31:10 +01:00
return result ;
}
2016-04-05 21:53:38 +02:00
UniValue getspentinfo ( const UniValue & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 | | ! params [ 0 ] . isObject ( ) )
throw runtime_error (
" getspentinfo \n "
" \n Returns the txid and index where an output is spent. \n "
2016-05-12 00:33:22 +02:00
" \n Arguments: \n "
" { \n "
" \" txid \" (string) The hex string of the txid \n "
" \" index \" (number) The start block height \n "
" } \n "
" \n Result: \n "
2016-04-05 21:53:38 +02:00
" { \n "
" \" txid \" (string) The transaction id \n "
" \" index \" (number) The spending input index \n "
" ,... \n "
" } \n "
2016-05-12 00:33:22 +02:00
" \n Examples: \n "
+ HelpExampleCli ( " getspentinfo " , " '{ \" txid \" : \" 0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9 \" , \" index \" : 0}' " )
+ HelpExampleRpc ( " getspentinfo " , " { \" txid \" : \" 0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9 \" , \" index \" : 0} " )
2016-04-05 21:53:38 +02:00
) ;
UniValue txidValue = find_value ( params [ 0 ] . get_obj ( ) , " txid " ) ;
UniValue indexValue = find_value ( params [ 0 ] . get_obj ( ) , " index " ) ;
if ( ! txidValue . isStr ( ) | | ! indexValue . isNum ( ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid txid or index " ) ;
}
uint256 txid = ParseHashV ( txidValue , " txid " ) ;
int outputIndex = indexValue . get_int ( ) ;
CSpentIndexKey key ( txid , outputIndex ) ;
CSpentIndexValue value ;
if ( ! GetSpentIndex ( key , value ) ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Unable to get spent info " ) ;
}
UniValue obj ( UniValue : : VOBJ ) ;
obj . push_back ( Pair ( " txid " , value . txid . GetHex ( ) ) ) ;
obj . push_back ( Pair ( " index " , ( int ) value . inputIndex ) ) ;
2016-04-12 21:31:19 +02:00
obj . push_back ( Pair ( " height " , value . blockHeight ) ) ;
2016-04-05 21:53:38 +02:00
return obj ;
}
2016-03-31 10:55:06 +02:00
static const CRPCCommand commands [ ] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
{ " control " , " debug " , & debug , true } ,
{ " control " , " getinfo " , & getinfo , true } , /* uses wallet if enabled */
{ " util " , " validateaddress " , & validateaddress , true } , /* uses wallet if enabled */
{ " util " , " createmultisig " , & createmultisig , true } ,
{ " util " , " verifymessage " , & verifymessage , true } ,
{ " blockchain " , " getspentinfo " , & getspentinfo , false } ,
/* Address index */
{ " addressindex " , " getaddressmempool " , & getaddressmempool , true } ,
{ " addressindex " , " getaddressutxos " , & getaddressutxos , false } ,
{ " addressindex " , " getaddressdeltas " , & getaddressdeltas , false } ,
{ " addressindex " , " getaddresstxids " , & getaddresstxids , false } ,
{ " addressindex " , " getaddressbalance " , & getaddressbalance , false } ,
/* Dash features */
{ " dash " , " mnsync " , & mnsync , true } ,
{ " dash " , " spork " , & spork , true } ,
/* Not shown in help */
{ " hidden " , " setmocktime " , & setmocktime , true } ,
} ;
void RegisterMiscRPCCommands ( CRPCTable & tableRPC )
{
for ( unsigned int vcidx = 0 ; vcidx < ARRAYLEN ( commands ) ; vcidx + + )
tableRPC . appendCommand ( commands [ vcidx ] . name , & commands [ vcidx ] ) ;
}