text: // Copyright (c) 2010 Satoshi Nakamoto
  // Copyright (c) 2009-2013 The Bitcoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #include "base58.h"
  #include "init.h"
  #include "main.h"
  #include "net.h"
  #include "netbase.h"
  #include "rpcserver.h"
  #include "timedata.h"
  #include "util.h"
  #ifdef ENABLE_WALLET
  #include "wallet.h"
  #include "walletdb.h"
  #endif
  
  #include <stdint.h>
  
  #include <boost/assign/list_of.hpp>
  #include "json/json_spirit_utils.h"
  #include "json/json_spirit_value.h"
  
  using namespace std;
  using namespace boost;
  using namespace boost::assign;
  using namespace json_spirit;
  
  Value getinfo(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 0)
          throw runtime_error(
              "getinfo\n"
              "Returns an object containing various state info.");
  
      proxyType proxy;
      GetProxy(NET_IPV4, proxy);
  
      Object obj, diff;
      obj.push_back(Pair("version",       FormatFullVersion()));
      obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
  #ifdef ENABLE_WALLET
      if (pwalletMain) {
          obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
          obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
          obj.push_back(Pair("newmint",       ValueFromAmount(pwalletMain->GetNewMint())));
          obj.push_back(Pair("stake",         ValueFromAmount(pwalletMain->GetStake())));
      }
  #endif
      obj.push_back(Pair("blocks",        (int)nBestHeight));
      obj.push_back(Pair("timeoffset",    (int64_t)GetTimeOffset()));
      obj.push_back(Pair("moneysupply",   ValueFromAmount(pindexBest->nMoneySupply)));
      obj.push_back(Pair("connections",   (int)vNodes.size()));
      obj.push_back(Pair("proxy",         (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
      obj.push_back(Pair("ip",            GetLocalAddress(NULL).ToStringIP()));
  
      diff.push_back(Pair("proof-of-work",  GetDifficulty()));
      diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
      obj.push_back(Pair("difficulty",    diff));
  
      obj.push_back(Pair("testnet",       TestNet()));
  #ifdef ENABLE_WALLET
      if (pwalletMain) {
          obj.push_back(Pair("keypoololdest", (int64_t)pwalletMain->GetOldestKeyPoolTime()));
          obj.push_back(Pair("keypoolsize",   (int)pwalletMain->GetKeyPoolSize()));
      }
      obj.push_back(Pair("paytxfee",      ValueFromAmount(nTransactionFee)));
      obj.push_back(Pair("mininput",      ValueFromAmount(nMinimumInputValue)));
      if (pwalletMain && pwalletMain->IsCrypted())
          obj.push_back(Pair("unlocked_until", (int64_t)nWalletUnlockTime));
  #endif
      obj.push_back(Pair("errors",        GetWarnings("statusbar")));
      return obj;
  }
  
  #ifdef ENABLE_WALLET
  class DescribeAddressVisitor : public boost::static_visitor<Object>
  {
  public:
      Object operator()(const CNoDestination &dest) const { return Object(); }
  
      Object operator()(const CKeyID &keyID) const {
          Object obj;
          CPubKey vchPubKey;
          pwalletMain->GetPubKey(keyID, vchPubKey);
          obj.push_back(Pair("isscript", false));
          obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
          obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
          return obj;
      }
  
      Object operator()(const CScriptID &scriptID) const {
          Object obj;
          obj.push_back(Pair("isscript", true));
          CScript subscript;
          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())));
          Array a;
          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
  
  Value validateaddress(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 1)
          throw runtime_error(
              "validateaddress <Mxdumaddress>\n"
              "Return information about <Mxdumaddress>.");
  
      CBitcoinAddress address(params[0].get_str());
      bool isValid = address.IsValid();
  
      Object ret;
      ret.push_back(Pair("isvalid", isValid));
      if (isValid)
      {
          CTxDestination dest = address.Get();
          string currentAddress = address.ToString();
          ret.push_back(Pair("address", currentAddress));
  #ifdef ENABLE_WALLET
          bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false;
          ret.push_back(Pair("ismine", fMine));
          if (fMine) {
              Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
              ret.insert(ret.end(), detail.begin(), detail.end());
          }
          if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
              ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
  #endif
      }
      return ret;
  }
  
  Value validatepubkey(const Array& params, bool fHelp)
  {
      if (fHelp || !params.size() || params.size() > 2)
          throw runtime_error(
              "validatepubkey <Mxdumpubkey>\n"
              "Return information about <Mxdumpubkey>.");
  
      std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
      CPubKey pubKey(vchPubKey);
  
      bool isValid = pubKey.IsValid();
      bool isCompressed = pubKey.IsCompressed();
      CKeyID keyID = pubKey.GetID();
  
      CBitcoinAddress address;
      address.Set(keyID);
  
      Object ret;
      ret.push_back(Pair("isvalid", isValid));
      if (isValid)
      {
          CTxDestination dest = address.Get();
          string currentAddress = address.ToString();
          ret.push_back(Pair("address", currentAddress));
          ret.push_back(Pair("iscompressed", isCompressed));
  #ifdef ENABLE_WALLET
          bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false;
          ret.push_back(Pair("ismine", fMine));
          if (fMine) {
              Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
              ret.insert(ret.end(), detail.begin(), detail.end());
          }
          if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
              ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
  #endif
      }
      return ret;
  }
  
  Value verifymessage(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 3)
          throw runtime_error(
              "verifymessage <Mxdumaddress> <signature> <message>\n"
              "Verify a signed message");
  
      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);
  }
  