// Copyright (c) 2010 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #include "headers.h" #undef printf #include #include #include #ifdef USE_SSL #include typedef boost::asio::ssl::stream SSLStream; #endif #include "json/json_spirit_reader_template.h" #include "json/json_spirit_writer_template.h" #include "json/json_spirit_utils.h" #define printf OutputDebugStringF // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are // precompiled in headers.h. The problem might be when the pch file goes over // a certain size around 145MB. If we need access to json_spirit outside this // file, we could use the compiled json_spirit option. using namespace boost::asio; using namespace json_spirit; void ThreadRPCServer2(void* parg); typedef Value(*rpcfn_type)(const Array& params, bool fHelp); extern map mapCallTable; Object JSONRPCError(int code, const string& message) { Object error; error.push_back(Pair("code", code)); error.push_back(Pair("message", message)); return error; } void PrintConsole(const char* format, ...) { char buffer[50000]; int limit = sizeof(buffer); va_list arg_ptr; va_start(arg_ptr, format); int ret = _vsnprintf(buffer, limit, format, arg_ptr); va_end(arg_ptr); if (ret < 0 || ret >= limit) { ret = limit - 1; buffer[limit-1] = 0; } #if defined(__WXMSW__) && defined(GUI) MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION); #else fprintf(stdout, "%s", buffer); #endif } /// /// Note: This interface may still be subject to change. /// Value help(const Array& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( "help [command]\n" "List commands, or get help for a command."); string strCommand; if (params.size() > 0) strCommand = params[0].get_str(); string strRet; set setDone; for (map::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi) { string strMethod = (*mi).first; // We already filter duplicates, but these deprecated screw up the sort order if (strMethod == "getamountreceived" || strMethod == "getallreceived") continue; if (strCommand != "" && strMethod != strCommand) continue; try { Array params; rpcfn_type pfn = (*mi).second; if (setDone.insert(pfn).second) (*pfn)(params, true); } catch (std::exception& e) { // Help text is returned in an exception string strHelp = string(e.what()); if (strCommand == "") if (strHelp.find('\n') != -1) strHelp = strHelp.substr(0, strHelp.find('\n')); strRet += strHelp + "\n"; } } if (strRet == "") strRet = strprintf("help: unknown command: %s\n", strCommand.c_str()); strRet = strRet.substr(0,strRet.size()-1); return strRet; } Value stop(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "stop\n" "Stop bitcoin server."); // Shutdown will take long enough that the response should get back CreateThread(Shutdown, NULL); return "bitcoin server stopping"; } Value getblockcount(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getblockcount\n" "Returns the number of blocks in the longest block chain."); return nBestHeight; } Value getblocknumber(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getblocknumber\n" "Returns the block number of the latest block in the longest block chain."); return nBestHeight; } Value getconnectioncount(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getconnectioncount\n" "Returns the number of connections to other nodes."); return (int)vNodes.size(); } double GetDifficulty() { // Floating point number that is a multiple of the minimum difficulty, // minimum difficulty = 1.0. if (pindexBest == NULL) return 1.0; int nShift = 256 - 32 - 31; // to fit in a uint double dMinimum = (CBigNum().SetCompact(bnProofOfWorkLimit.GetCompact()) >> nShift).getuint(); double dCurrently = (CBigNum().SetCompact(pindexBest->nBits) >> nShift).getuint(); return dMinimum / dCurrently; } Value getdifficulty(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getdifficulty\n" "Returns the proof-of-work difficulty as a multiple of the minimum difficulty."); return GetDifficulty(); } Value getbalance(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getbalance\n" "Returns the server's available balance."); return ((double)GetBalance() / (double)COIN); } Value getgenerate(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getgenerate\n" "Returns true or false."); return (bool)fGenerateBitcoins; } Value setgenerate(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "setgenerate [genproclimit]\n" " is true or false to turn generation on or off.\n" "Generation is limited to [genproclimit] processors, -1 is unlimited."); bool fGenerate = true; if (params.size() > 0) fGenerate = params[0].get_bool(); if (params.size() > 1) { int nGenProcLimit = params[1].get_int(); fLimitProcessors = (nGenProcLimit != -1); CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors); if (nGenProcLimit != -1) CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit); } GenerateBitcoins(fGenerate); return Value::null; } Value gethashespersec(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "gethashespersec\n" "Returns a recent hashes per second performance measurement while generating."); if (GetTimeMillis() - nHPSTimerStart > 8000) return (boost::int64_t)0; return (boost::int64_t)dHashesPerSec; } Value getinfo(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getinfo\n" "Returns an object containing various state info."); Object obj; obj.push_back(Pair("version", (int)VERSION)); obj.push_back(Pair("balance", (double)GetBalance() / (double)COIN)); obj.push_back(Pair("blocks", (int)nBestHeight)); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string()))); obj.push_back(Pair("generate", (bool)fGenerateBitcoins)); obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("testnet", fTestNet)); obj.push_back(Pair("keypoololdest", (boost::int64_t)CWalletDB().GetOldestKeyPoolTime())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); return obj; } Value getnewaddress(const Array& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( "getnewaddress [label]\n" "Returns a new bitcoin address for receiving payments. " "If [label] is specified (recommended), it is added to the address book " "so payments received with the address will be labeled."); // Parse the label first so we don't generate a key if there's an error string strLabel; if (params.size() > 0) strLabel = params[0].get_str(); // Generate a new key that is added to wallet string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool()); SetAddressBookName(strAddress, strLabel); return strAddress; } Value setlabel(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "setlabel