You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

server.cpp 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. // Copyright (c) 2010 Satoshi Nakamoto
  2. // Copyright (c) 2009-2016 The Starwels developers
  3. // Distributed under the MIT software license, see the accompanying
  4. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5. #include "rpc/server.h"
  6. #include "base58.h"
  7. #include "fs.h"
  8. #include "init.h"
  9. #include "random.h"
  10. #include "sync.h"
  11. #include "ui_interface.h"
  12. #include "util.h"
  13. #include "utilstrencodings.h"
  14. #include <univalue.h>
  15. #include <boost/bind.hpp>
  16. #include <boost/signals2/signal.hpp>
  17. #include <boost/algorithm/string/case_conv.hpp> // for to_upper()
  18. #include <boost/algorithm/string/classification.hpp>
  19. #include <boost/algorithm/string/split.hpp>
  20. #include <memory> // for unique_ptr
  21. #include <unordered_map>
  22. static bool fRPCRunning = false;
  23. static bool fRPCInWarmup = true;
  24. static std::string rpcWarmupStatus("RPC server started");
  25. static CCriticalSection cs_rpcWarmup;
  26. /* Timer-creating functions */
  27. static RPCTimerInterface* timerInterface = nullptr;
  28. /* Map of name to timer. */
  29. static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
  30. static struct CRPCSignals
  31. {
  32. boost::signals2::signal<void ()> Started;
  33. boost::signals2::signal<void ()> Stopped;
  34. boost::signals2::signal<void (const CRPCCommand&)> PreCommand;
  35. } g_rpcSignals;
  36. void RPCServer::OnStarted(std::function<void ()> slot)
  37. {
  38. g_rpcSignals.Started.connect(slot);
  39. }
  40. void RPCServer::OnStopped(std::function<void ()> slot)
  41. {
  42. g_rpcSignals.Stopped.connect(slot);
  43. }
  44. void RPCServer::OnPreCommand(std::function<void (const CRPCCommand&)> slot)
  45. {
  46. g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
  47. }
  48. void RPCTypeCheck(const UniValue& params,
  49. const std::list<UniValue::VType>& typesExpected,
  50. bool fAllowNull)
  51. {
  52. unsigned int i = 0;
  53. for (UniValue::VType t : typesExpected)
  54. {
  55. if (params.size() <= i)
  56. break;
  57. const UniValue& v = params[i];
  58. if (!(fAllowNull && v.isNull())) {
  59. RPCTypeCheckArgument(v, t);
  60. }
  61. i++;
  62. }
  63. }
  64. void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected)
  65. {
  66. if (value.type() != typeExpected) {
  67. throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected), uvTypeName(value.type())));
  68. }
  69. }
  70. void RPCTypeCheckObj(const UniValue& o,
  71. const std::map<std::string, UniValueType>& typesExpected,
  72. bool fAllowNull,
  73. bool fStrict)
  74. {
  75. for (const auto& t : typesExpected) {
  76. const UniValue& v = find_value(o, t.first);
  77. if (!fAllowNull && v.isNull())
  78. throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
  79. if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
  80. std::string err = strprintf("Expected type %s for %s, got %s",
  81. uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
  82. throw JSONRPCError(RPC_TYPE_ERROR, err);
  83. }
  84. }
  85. if (fStrict)
  86. {
  87. for (const std::string& k : o.getKeys())
  88. {
  89. if (typesExpected.count(k) == 0)
  90. {
  91. std::string err = strprintf("Unexpected key %s", k);
  92. throw JSONRPCError(RPC_TYPE_ERROR, err);
  93. }
  94. }
  95. }
  96. }
  97. CAmount AmountFromValue(const UniValue& value)
  98. {
  99. if (!value.isNum() && !value.isStr())
  100. throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
  101. CAmount amount;
  102. if (!ParseFixedPoint(value.getValStr(), 8, &amount))
  103. throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
  104. if (!MoneyRange(amount))
  105. throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
  106. return amount;
  107. }
  108. uint256 ParseHashV(const UniValue& v, std::string strName)
  109. {
  110. std::string strHex;
  111. if (v.isStr())
  112. strHex = v.get_str();
  113. if (!IsHex(strHex)) // Note: IsHex("") is false
  114. throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
  115. if (64 != strHex.length())
  116. throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length()));
  117. uint256 result;
  118. result.SetHex(strHex);
  119. return result;
  120. }
  121. uint256 ParseHashO(const UniValue& o, std::string strKey)
  122. {
  123. return ParseHashV(find_value(o, strKey), strKey);
  124. }
  125. std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
  126. {
  127. std::string strHex;
  128. if (v.isStr())
  129. strHex = v.get_str();
  130. if (!IsHex(strHex))
  131. throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
  132. return ParseHex(strHex);
  133. }
  134. std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
  135. {
  136. return ParseHexV(find_value(o, strKey), strKey);
  137. }
  138. /**
  139. * Note: This interface may still be subject to change.
  140. */
  141. std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const
  142. {
  143. std::string strRet;
  144. std::string category;
  145. std::set<rpcfn_type> setDone;
  146. std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
  147. for (std::map<std::string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
  148. vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second));
  149. sort(vCommands.begin(), vCommands.end());
  150. JSONRPCRequest jreq(helpreq);
  151. jreq.fHelp = true;
  152. jreq.params = UniValue();
  153. for (const std::pair<std::string, const CRPCCommand*>& command : vCommands)
  154. {
  155. const CRPCCommand *pcmd = command.second;
  156. std::string strMethod = pcmd->name;
  157. if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
  158. continue;
  159. jreq.strMethod = strMethod;
  160. try
  161. {
  162. rpcfn_type pfn = pcmd->actor;
  163. if (setDone.insert(pfn).second)
  164. (*pfn)(jreq);
  165. }
  166. catch (const std::exception& e)
  167. {
  168. // Help text is returned in an exception
  169. std::string strHelp = std::string(e.what());
  170. if (strCommand == "")
  171. {
  172. if (strHelp.find('\n') != std::string::npos)
  173. strHelp = strHelp.substr(0, strHelp.find('\n'));
  174. if (category != pcmd->category)
  175. {
  176. if (!category.empty())
  177. strRet += "\n";
  178. category = pcmd->category;
  179. std::string firstLetter = category.substr(0,1);
  180. boost::to_upper(firstLetter);
  181. strRet += "== " + firstLetter + category.substr(1) + " ==\n";
  182. }
  183. }
  184. strRet += strHelp + "\n";
  185. }
  186. }
  187. if (strRet == "")
  188. strRet = strprintf("help: unknown command: %s\n", strCommand);
  189. strRet = strRet.substr(0,strRet.size()-1);
  190. return strRet;
  191. }
  192. UniValue help(const JSONRPCRequest& jsonRequest)
  193. {
  194. if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
  195. throw std::runtime_error(
  196. "help ( \"command\" )\n"
  197. "\nList all commands, or get help for a specified command.\n"
  198. "\nArguments:\n"
  199. "1. \"command\" (string, optional) The command to get help on\n"
  200. "\nResult:\n"
  201. "\"text\" (string) The help text\n"
  202. );
  203. std::string strCommand;
  204. if (jsonRequest.params.size() > 0)
  205. strCommand = jsonRequest.params[0].get_str();
  206. return tableRPC.help(strCommand, jsonRequest);
  207. }
  208. UniValue stop(const JSONRPCRequest& jsonRequest)
  209. {
  210. // Accept the deprecated and ignored 'detach' boolean argument
  211. if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
  212. throw std::runtime_error(
  213. "stop\n"
  214. "\nStop Starwels server.");
  215. // Event loop will exit after current HTTP requests have been handled, so
  216. // this reply will get back to the client.
  217. StartShutdown();
  218. return "Starwels server stopping";
  219. }
  220. UniValue uptime(const JSONRPCRequest& jsonRequest)
  221. {
  222. if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
  223. throw std::runtime_error(
  224. "uptime\n"
  225. "\nReturns the total uptime of the server.\n"
  226. "\nResult:\n"
  227. "ttt (numeric) The number of seconds that the server has been running\n"
  228. "\nExamples:\n"
  229. + HelpExampleCli("uptime", "")
  230. + HelpExampleRpc("uptime", "")
  231. );
  232. return GetTime() - GetStartupTime();
  233. }
  234. /**
  235. * Call Table
  236. */
  237. static const CRPCCommand vRPCCommands[] =
  238. { // category name actor (function) okSafe argNames
  239. // --------------------- ------------------------ ----------------------- ------ ----------
  240. /* Overall control/query calls */
  241. { "control", "help", &help, true, {"command"} },
  242. { "control", "stop", &stop, true, {} },
  243. { "control", "uptime", &uptime, true, {} },
  244. };
  245. CRPCTable::CRPCTable()
  246. {
  247. unsigned int vcidx;
  248. for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
  249. {
  250. const CRPCCommand *pcmd;
  251. pcmd = &vRPCCommands[vcidx];
  252. mapCommands[pcmd->name] = pcmd;
  253. }
  254. }
  255. const CRPCCommand *CRPCTable::operator[](const std::string &name) const
  256. {
  257. std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
  258. if (it == mapCommands.end())
  259. return nullptr;
  260. return (*it).second;
  261. }
  262. bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
  263. {
  264. if (IsRPCRunning())
  265. return false;
  266. // don't allow overwriting for now
  267. std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
  268. if (it != mapCommands.end())
  269. return false;
  270. mapCommands[name] = pcmd;
  271. return true;
  272. }
  273. bool StartRPC()
  274. {
  275. LogPrint(BCLog::RPC, "Starting RPC\n");
  276. fRPCRunning = true;
  277. g_rpcSignals.Started();
  278. return true;
  279. }
  280. void InterruptRPC()
  281. {
  282. LogPrint(BCLog::RPC, "Interrupting RPC\n");
  283. // Interrupt e.g. running longpolls
  284. fRPCRunning = false;
  285. }
  286. void StopRPC()
  287. {
  288. LogPrint(BCLog::RPC, "Stopping RPC\n");
  289. deadlineTimers.clear();
  290. DeleteAuthCookie();
  291. g_rpcSignals.Stopped();
  292. }
  293. bool IsRPCRunning()
  294. {
  295. return fRPCRunning;
  296. }
  297. void SetRPCWarmupStatus(const std::string& newStatus)
  298. {
  299. LOCK(cs_rpcWarmup);
  300. rpcWarmupStatus = newStatus;
  301. }
  302. void SetRPCWarmupFinished()
  303. {
  304. LOCK(cs_rpcWarmup);
  305. assert(fRPCInWarmup);
  306. fRPCInWarmup = false;
  307. }
  308. bool RPCIsInWarmup(std::string *outStatus)
  309. {
  310. LOCK(cs_rpcWarmup);
  311. if (outStatus)
  312. *outStatus = rpcWarmupStatus;
  313. return fRPCInWarmup;
  314. }
  315. void JSONRPCRequest::parse(const UniValue& valRequest)
  316. {
  317. // Parse request
  318. if (!valRequest.isObject())
  319. throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
  320. const UniValue& request = valRequest.get_obj();
  321. // Parse id now so errors from here on will have the id
  322. id = find_value(request, "id");
  323. // Parse method
  324. UniValue valMethod = find_value(request, "method");
  325. if (valMethod.isNull())
  326. throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
  327. if (!valMethod.isStr())
  328. throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
  329. strMethod = valMethod.get_str();
  330. LogPrint(BCLog::RPC, "ThreadRPCServer method=%s\n", SanitizeString(strMethod));
  331. // Parse params
  332. UniValue valParams = find_value(request, "params");
  333. if (valParams.isArray() || valParams.isObject())
  334. params = valParams;
  335. else if (valParams.isNull())
  336. params = UniValue(UniValue::VARR);
  337. else
  338. throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
  339. }
  340. static UniValue JSONRPCExecOne(JSONRPCRequest jreq, const UniValue& req)
  341. {
  342. UniValue rpc_result(UniValue::VOBJ);
  343. try {
  344. jreq.parse(req);
  345. UniValue result = tableRPC.execute(jreq);
  346. rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
  347. }
  348. catch (const UniValue& objError)
  349. {
  350. rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
  351. }
  352. catch (const std::exception& e)
  353. {
  354. rpc_result = JSONRPCReplyObj(NullUniValue,
  355. JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
  356. }
  357. return rpc_result;
  358. }
  359. std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq)
  360. {
  361. UniValue ret(UniValue::VARR);
  362. for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
  363. ret.push_back(JSONRPCExecOne(jreq, vReq[reqIdx]));
  364. return ret.write() + "\n";
  365. }
  366. /**
  367. * Process named arguments into a vector of positional arguments, based on the
  368. * passed-in specification for the RPC call's arguments.
  369. */
  370. static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames)
  371. {
  372. JSONRPCRequest out = in;
  373. out.params = UniValue(UniValue::VARR);
  374. // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if
  375. // there is an unknown one.
  376. const std::vector<std::string>& keys = in.params.getKeys();
  377. const std::vector<UniValue>& values = in.params.getValues();
  378. std::unordered_map<std::string, const UniValue*> argsIn;
  379. for (size_t i=0; i<keys.size(); ++i) {
  380. argsIn[keys[i]] = &values[i];
  381. }
  382. // Process expected parameters.
  383. int hole = 0;
  384. for (const std::string &argNamePattern: argNames) {
  385. std::vector<std::string> vargNames;
  386. boost::algorithm::split(vargNames, argNamePattern, boost::algorithm::is_any_of("|"));
  387. auto fr = argsIn.end();
  388. for (const std::string & argName : vargNames) {
  389. fr = argsIn.find(argName);
  390. if (fr != argsIn.end()) {
  391. break;
  392. }
  393. }
  394. if (fr != argsIn.end()) {
  395. for (int i = 0; i < hole; ++i) {
  396. // Fill hole between specified parameters with JSON nulls,
  397. // but not at the end (for backwards compatibility with calls
  398. // that act based on number of specified parameters).
  399. out.params.push_back(UniValue());
  400. }
  401. hole = 0;
  402. out.params.push_back(*fr->second);
  403. argsIn.erase(fr);
  404. } else {
  405. hole += 1;
  406. }
  407. }
  408. // If there are still arguments in the argsIn map, this is an error.
  409. if (!argsIn.empty()) {
  410. throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown named parameter " + argsIn.begin()->first);
  411. }
  412. // Return request with named arguments transformed to positional arguments
  413. return out;
  414. }
  415. UniValue CRPCTable::execute(const JSONRPCRequest &request) const
  416. {
  417. // Return immediately if in warmup
  418. {
  419. LOCK(cs_rpcWarmup);
  420. if (fRPCInWarmup)
  421. throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
  422. }
  423. // Find method
  424. const CRPCCommand *pcmd = tableRPC[request.strMethod];
  425. if (!pcmd)
  426. throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
  427. g_rpcSignals.PreCommand(*pcmd);
  428. try
  429. {
  430. // Execute, convert arguments to array if necessary
  431. if (request.params.isObject()) {
  432. return pcmd->actor(transformNamedArguments(request, pcmd->argNames));
  433. } else {
  434. return pcmd->actor(request);
  435. }
  436. }
  437. catch (const std::exception& e)
  438. {
  439. throw JSONRPCError(RPC_MISC_ERROR, e.what());
  440. }
  441. }
  442. std::vector<std::string> CRPCTable::listCommands() const
  443. {
  444. std::vector<std::string> commandList;
  445. typedef std::map<std::string, const CRPCCommand*> commandMap;
  446. std::transform( mapCommands.begin(), mapCommands.end(),
  447. std::back_inserter(commandList),
  448. boost::bind(&commandMap::value_type::first,_1) );
  449. return commandList;
  450. }
  451. std::string HelpExampleCli(const std::string& methodname, const std::string& args)
  452. {
  453. return "> starwels-cli " + methodname + " " + args + "\n";
  454. }
  455. std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
  456. {
  457. return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
  458. "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8342/\n";
  459. }
  460. void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
  461. {
  462. if (!timerInterface)
  463. timerInterface = iface;
  464. }
  465. void RPCSetTimerInterface(RPCTimerInterface *iface)
  466. {
  467. timerInterface = iface;
  468. }
  469. void RPCUnsetTimerInterface(RPCTimerInterface *iface)
  470. {
  471. if (timerInterface == iface)
  472. timerInterface = nullptr;
  473. }
  474. void RPCRunLater(const std::string& name, std::function<void(void)> func, int64_t nSeconds)
  475. {
  476. if (!timerInterface)
  477. throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
  478. deadlineTimers.erase(name);
  479. LogPrint(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
  480. deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)));
  481. }
  482. int RPCSerializationFlags()
  483. {
  484. int flag = 0;
  485. if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0)
  486. flag |= SERIALIZE_TRANSACTION_NO_WITNESS;
  487. return flag;
  488. }
  489. CRPCTable tableRPC;