1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
7 #include "clientversion.h"
12 #include "rpcserver.h"
16 #include "wallet/wallet.h"
17 #include "wallet/walletdb.h"
22 #include <boost/assign/list_of.hpp>
23 #include "json/json_spirit_utils.h"
24 #include "json/json_spirit_value.h"
26 using namespace json_spirit;
30 * @note Do not add or change anything in the information returned by this
31 * method. `getinfo` exists for backwards-compatibility only. It combines
32 * information from wildly different sources in the program, which is a mess,
33 * and is thus planned to be deprecated eventually.
35 * Based on the source of the information, new information should be added to:
36 * - `getblockchaininfo`,
37 * - `getnetworkinfo` or
40 * Or alternatively, create a specific query method for the information.
42 uint64_t komodo_interestsum();
43 int32_t komodo_longestchain();
44 int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp);
45 int32_t komodo_whoami(char *pubkeystr,int32_t height);
47 Value getinfo(const Array& params, bool fHelp)
49 uint256 notarized_hash,notarized_desttxid;
50 int32_t notarized_height,longestchain;
51 if (fHelp || params.size() != 0)
54 "Returns an object containing various state info.\n"
57 " \"version\": xxxxx, (numeric) the server version\n"
58 " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
59 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
60 " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n"
61 " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
62 " \"timeoffset\": xxxxx, (numeric) the time offset\n"
63 " \"connections\": xxxxx, (numeric) the number of connections\n"
64 " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
65 " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
66 " \"testnet\": true|false, (boolean) if the server is using testnet or not\n"
67 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
68 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
69 " \"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"
70 " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in btc/kb\n"
71 " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
72 " \"errors\": \"...\" (string) any error messages\n"
75 + HelpExampleCli("getinfo", "")
76 + HelpExampleRpc("getinfo", "")
80 LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
86 GetProxy(NET_IPV4, proxy);
87 notarized_height = komodo_notarized_height(¬arized_hash,¬arized_desttxid);
90 obj.push_back(Pair("version", CLIENT_VERSION));
91 obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
92 obj.push_back(Pair("notarized", notarized_height));
93 obj.push_back(Pair("notarizedhash", notarized_hash.ToString()));
94 obj.push_back(Pair("notarizedtxid", notarized_desttxid.ToString()));
97 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
98 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
99 obj.push_back(Pair("interest", ValueFromAmount(komodo_interestsum())));
102 obj.push_back(Pair("blocks", (int)chainActive.Height()));
103 if ( (longestchain= komodo_longestchain()) != 0 && chainActive.Height() > longestchain )
104 longestchain = chainActive.Height();
105 obj.push_back(Pair("longestchain", longestchain));
106 obj.push_back(Pair("timeoffset", GetTimeOffset()));
107 if ( chainActive.Tip() != 0 )
108 obj.push_back(Pair("tiptime", (int)chainActive.Tip()->nTime));
109 obj.push_back(Pair("connections", (int)vNodes.size()));
110 obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
111 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
112 obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
115 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
116 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
118 if (pwalletMain && pwalletMain->IsCrypted())
119 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
120 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
122 obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
123 obj.push_back(Pair("errors", GetWarnings("statusbar")));
125 char pubkeystr[65]; int32_t notaryid;
126 notaryid = komodo_whoami(pubkeystr,longestchain);
127 obj.push_back(Pair("notaryid", notaryid));
128 obj.push_back(Pair("pubkey", pubkeystr));
134 class DescribeAddressVisitor : public boost::static_visitor<Object>
140 DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
142 Object operator()(const CNoDestination &dest) const { return Object(); }
144 Object operator()(const CKeyID &keyID) const {
147 obj.push_back(Pair("isscript", false));
148 if (mine == ISMINE_SPENDABLE) {
149 pwalletMain->GetPubKey(keyID, vchPubKey);
150 obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
151 obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
156 Object operator()(const CScriptID &scriptID) const {
158 obj.push_back(Pair("isscript", true));
159 if (mine != ISMINE_NO) {
161 pwalletMain->GetCScript(scriptID, subscript);
162 std::vector<CTxDestination> addresses;
163 txnouttype whichType;
165 ExtractDestinations(subscript, whichType, addresses, nRequired);
166 obj.push_back(Pair("script", GetTxnOutputType(whichType)));
167 obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
169 BOOST_FOREACH(const CTxDestination& addr, addresses)
170 a.push_back(CBitcoinAddress(addr).ToString());
171 obj.push_back(Pair("addresses", a));
172 if (whichType == TX_MULTISIG)
173 obj.push_back(Pair("sigsrequired", nRequired));
180 Value validateaddress(const Array& params, bool fHelp)
182 if (fHelp || params.size() != 1)
184 "validateaddress \"bitcoinaddress\"\n"
185 "\nReturn information about the given bitcoin address.\n"
187 "1. \"bitcoinaddress\" (string, required) The bitcoin address to validate\n"
190 " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
191 " \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n"
192 " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
193 " \"ismine\" : true|false, (boolean) If the address is yours or not\n"
194 " \"isscript\" : true|false, (boolean) If the key is a script\n"
195 " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n"
196 " \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
197 " \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n"
200 + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
201 + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
205 LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
210 CBitcoinAddress address(params[0].get_str());
211 bool isValid = address.IsValid();
214 ret.push_back(Pair("isvalid", isValid));
217 CTxDestination dest = address.Get();
218 string currentAddress = address.ToString();
219 ret.push_back(Pair("address", currentAddress));
221 CScript scriptPubKey = GetScriptForDestination(dest);
222 ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
225 isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
226 ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
227 if (mine != ISMINE_NO) {
228 ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
229 Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
230 ret.insert(ret.end(), detail.begin(), detail.end());
232 if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
233 ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
240 * Used by addmultisigaddress / createmultisig:
242 CScript _createmultisig_redeemScript(const Array& params)
244 int nRequired = params[0].get_int();
245 const Array& keys = params[1].get_array();
247 // Gather public keys
249 throw runtime_error("a multisignature address must require at least one key to redeem");
250 if ((int)keys.size() < nRequired)
252 strprintf("not enough keys supplied "
253 "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
254 if (keys.size() > 16)
255 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
256 std::vector<CPubKey> pubkeys;
257 pubkeys.resize(keys.size());
258 for (unsigned int i = 0; i < keys.size(); i++)
260 const std::string& ks = keys[i].get_str();
262 // Case 1: Bitcoin address and we have full public key:
263 CBitcoinAddress address(ks);
264 if (pwalletMain && address.IsValid())
267 if (!address.GetKeyID(keyID))
269 strprintf("%s does not refer to a key",ks));
271 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
273 strprintf("no full public key for address %s",ks));
274 if (!vchPubKey.IsFullyValid())
275 throw runtime_error(" Invalid public key: "+ks);
276 pubkeys[i] = vchPubKey;
279 // Case 2: hex public key
284 CPubKey vchPubKey(ParseHex(ks));
285 if (!vchPubKey.IsFullyValid())
286 throw runtime_error(" Invalid public key: "+ks);
287 pubkeys[i] = vchPubKey;
291 throw runtime_error(" Invalid public key: "+ks);
294 CScript result = GetScriptForMultisig(nRequired, pubkeys);
296 if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
298 strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));
303 Value createmultisig(const Array& params, bool fHelp)
305 if (fHelp || params.size() < 2 || params.size() > 2)
307 string msg = "createmultisig nrequired [\"key\",...]\n"
308 "\nCreates a multi-signature address with n signature of m keys required.\n"
309 "It returns a json object with the address and redeemScript.\n"
312 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
313 "2. \"keys\" (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys\n"
315 " \"key\" (string) bitcoin address or hex-encoded public key\n"
321 " \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n"
322 " \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n"
326 "\nCreate a multisig address from 2 addresses\n"
327 + HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
328 "\nAs a json rpc call\n"
329 + HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
331 throw runtime_error(msg);
334 // Construct using pay-to-script-hash:
335 CScript inner = _createmultisig_redeemScript(params);
336 CScriptID innerID(inner);
337 CBitcoinAddress address(innerID);
340 result.push_back(Pair("address", address.ToString()));
341 result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
346 Value verifymessage(const Array& params, bool fHelp)
348 if (fHelp || params.size() != 3)
350 "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
351 "\nVerify a signed message\n"
353 "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the signature.\n"
354 "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
355 "3. \"message\" (string, required) The message that was signed.\n"
357 "true|false (boolean) If the signature is verified or not.\n"
359 "\nUnlock the wallet for 30 seconds\n"
360 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
361 "\nCreate the signature\n"
362 + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
363 "\nVerify the signature\n"
364 + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
366 + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
371 string strAddress = params[0].get_str();
372 string strSign = params[1].get_str();
373 string strMessage = params[2].get_str();
375 CBitcoinAddress addr(strAddress);
377 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
380 if (!addr.GetKeyID(keyID))
381 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
383 bool fInvalid = false;
384 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
387 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
389 CHashWriter ss(SER_GETHASH, 0);
390 ss << strMessageMagic;
394 if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
397 return (pubkey.GetID() == keyID);
400 Value setmocktime(const Array& params, bool fHelp)
402 if (fHelp || params.size() != 1)
404 "setmocktime timestamp\n"
405 "\nSet the local time to given timestamp (-regtest only)\n"
407 "1. timestamp (integer, required) Unix seconds-since-epoch timestamp\n"
408 " Pass 0 to go back to using the system time."
411 if (!Params().MineBlocksOnDemand())
412 throw runtime_error("setmocktime for regression testing (-regtest mode) only");
416 RPCTypeCheck(params, boost::assign::list_of(int_type));
417 SetMockTime(params[0].get_int64());