aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/misc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc/misc.cpp')
-rw-r--r--src/rpc/misc.cpp398
1 files changed, 398 insertions, 0 deletions
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
new file mode 100644
index 0000000000..0aab9c3043
--- /dev/null
+++ b/src/rpc/misc.cpp
@@ -0,0 +1,398 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "base58.h"
+#include "clientversion.h"
+#include "init.h"
+#include "main.h"
+#include "net.h"
+#include "netbase.h"
+#include "rpc/server.h"
+#include "timedata.h"
+#include "util.h"
+#include "utilstrencodings.h"
+#ifdef ENABLE_WALLET
+#include "wallet/wallet.h"
+#include "wallet/walletdb.h"
+#endif
+
+#include <stdint.h>
+
+#include <boost/assign/list_of.hpp>
+
+#include <univalue.h>
+
+using namespace std;
+
+/**
+ * @note Do not add or change anything in the information returned by this
+ * method. `getinfo` exists for backwards-compatibility only. It combines
+ * 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.
+ **/
+UniValue getinfo(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getinfo\n"
+ "Returns an object containing various state info.\n"
+ "\nResult:\n"
+ "{\n"
+ " \"version\": xxxxx, (numeric) the server version\n"
+ " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
+ " \"walletversion\": xxxxx, (numeric) the wallet version\n"
+ " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n"
+ " \"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"
+ " \"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"
+ " \"errors\": \"...\" (string) any error messages\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getinfo", "")
+ + HelpExampleRpc("getinfo", "")
+ );
+
+#ifdef ENABLE_WALLET
+ LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+#else
+ LOCK(cs_main);
+#endif
+
+ proxyType proxy;
+ GetProxy(NET_IPV4, proxy);
+
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("version", CLIENT_VERSION));
+ obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
+#ifdef ENABLE_WALLET
+ if (pwalletMain) {
+ obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
+ obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
+ }
+#endif
+ obj.push_back(Pair("blocks", (int)chainActive.Height()));
+ obj.push_back(Pair("timeoffset", GetTimeOffset()));
+ obj.push_back(Pair("connections", (int)vNodes.size()));
+ obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
+ obj.push_back(Pair("difficulty", (double)GetDifficulty()));
+ obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
+#ifdef ENABLE_WALLET
+ if (pwalletMain) {
+ obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
+ obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
+ }
+ if (pwalletMain && pwalletMain->IsCrypted())
+ obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
+ obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
+#endif
+ obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
+ obj.push_back(Pair("errors", GetWarnings("statusbar")));
+ return obj;
+}
+
+#ifdef ENABLE_WALLET
+class DescribeAddressVisitor : public boost::static_visitor<UniValue>
+{
+public:
+ UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
+
+ UniValue operator()(const CKeyID &keyID) const {
+ UniValue obj(UniValue::VOBJ);
+ CPubKey vchPubKey;
+ obj.push_back(Pair("isscript", false));
+ if (pwalletMain && pwalletMain->GetPubKey(keyID, vchPubKey)) {
+ obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
+ obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
+ }
+ return obj;
+ }
+
+ UniValue operator()(const CScriptID &scriptID) const {
+ UniValue obj(UniValue::VOBJ);
+ CScript subscript;
+ obj.push_back(Pair("isscript", true));
+ if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) {
+ 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())));
+ UniValue a(UniValue::VARR);
+ 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));
+ }
+ return obj;
+ }
+};
+#endif
+
+UniValue validateaddress(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "validateaddress \"bitcoinaddress\"\n"
+ "\nReturn information about the given bitcoin address.\n"
+ "\nArguments:\n"
+ "1. \"bitcoinaddress\" (string, required) The bitcoin address to validate\n"
+ "\nResult:\n"
+ "{\n"
+ " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
+ " \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n"
+ " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
+ " \"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"
+ " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n"
+ " \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
+ " \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
+ + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
+ );
+
+#ifdef ENABLE_WALLET
+ LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+#else
+ LOCK(cs_main);
+#endif
+
+ CBitcoinAddress address(params[0].get_str());
+ bool isValid = address.IsValid();
+
+ UniValue ret(UniValue::VOBJ);
+ ret.push_back(Pair("isvalid", isValid));
+ if (isValid)
+ {
+ CTxDestination dest = address.Get();
+ string currentAddress = address.ToString();
+ ret.push_back(Pair("address", currentAddress));
+
+ CScript scriptPubKey = GetScriptForDestination(dest);
+ ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
+
+#ifdef ENABLE_WALLET
+ isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
+ ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
+ ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
+ UniValue detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
+ ret.pushKVs(detail);
+ if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
+ ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
+#endif
+ }
+ return ret;
+}
+
+/**
+ * Used by addmultisigaddress / createmultisig:
+ */
+CScript _createmultisig_redeemScript(const UniValue& params)
+{
+ int nRequired = params[0].get_int();
+ const UniValue& keys = params[1].get_array();
+
+ // 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 "
+ "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
+ if (keys.size() > 16)
+ throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
+ 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:
+ CBitcoinAddress address(ks);
+ if (pwalletMain && address.IsValid())
+ {
+ CKeyID keyID;
+ if (!address.GetKeyID(keyID))
+ throw runtime_error(
+ strprintf("%s does not refer to a key",ks));
+ CPubKey vchPubKey;
+ if (!pwalletMain->GetPubKey(keyID, vchPubKey))
+ throw runtime_error(
+ strprintf("no full public key for address %s",ks));
+ 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);
+ }
+ }
+ CScript result = GetScriptForMultisig(nRequired, pubkeys);
+
+ if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
+ throw runtime_error(
+ strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));
+
+ return result;
+}
+
+UniValue createmultisig(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2 || params.size() > 2)
+ {
+ string msg = "createmultisig nrequired [\"key\",...]\n"
+ "\nCreates a multi-signature address with n signature of m keys required.\n"
+ "It returns a json object with the address and redeemScript.\n"
+
+ "\nArguments:\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"
+
+ "\nResult:\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"
+
+ "\nExamples:\n"
+ "\nCreate a multisig address from 2 addresses\n"
+ + HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
+ "\nAs a json rpc call\n"
+ + HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
+ ;
+ throw runtime_error(msg);
+ }
+
+ // Construct using pay-to-script-hash:
+ CScript inner = _createmultisig_redeemScript(params);
+ CScriptID innerID(inner);
+ CBitcoinAddress address(innerID);
+
+ UniValue result(UniValue::VOBJ);
+ result.push_back(Pair("address", address.ToString()));
+ result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
+
+ return result;
+}
+
+UniValue verifymessage(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 3)
+ throw runtime_error(
+ "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
+ "\nVerify a signed message\n"
+ "\nArguments:\n"
+ "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the signature.\n"
+ "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"
+ "\nResult:\n"
+ "true|false (boolean) If the signature is verified or not.\n"
+ "\nExamples:\n"
+ "\nUnlock the wallet for 30 seconds\n"
+ + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
+ "\nCreate the signature\n"
+ + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
+ "\nVerify the signature\n"
+ + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
+ "\nAs json rpc\n"
+ + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
+ );
+
+ LOCK(cs_main);
+
+ 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);
+}
+
+UniValue setmocktime(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "setmocktime timestamp\n"
+ "\nSet the local time to given timestamp (-regtest only)\n"
+ "\nArguments:\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");
+
+ // cs_vNodes is locked and node send/receive times are updated
+ // atomically with the time change to prevent peers from being
+ // disconnected because we think we haven't communicated with them
+ // in a long time.
+ LOCK2(cs_main, cs_vNodes);
+
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ SetMockTime(params[0].get_int64());
+
+ uint64_t t = GetTime();
+ BOOST_FOREACH(CNode* pnode, vNodes) {
+ pnode->nLastSend = pnode->nLastRecv = t;
+ }
+
+ return NullUniValue;
+}