1 // Copyright (c) 2009-2014 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or https://www.opensource.org/licenses/mit-license.php .
5 #include "rpc/server.h"
7 #include "clientversion.h"
16 #include "deprecation.h"
18 #include <boost/foreach.hpp>
24 UniValue getconnectioncount(const UniValue& params, bool fHelp)
26 if (fHelp || params.size() != 0)
28 "getconnectioncount\n"
29 "\nReturns the number of connections to other nodes.\n"
31 "n (numeric) The connection count\n"
33 + HelpExampleCli("getconnectioncount", "")
34 + HelpExampleRpc("getconnectioncount", "")
37 LOCK2(cs_main, cs_vNodes);
39 return (int)vNodes.size();
42 UniValue ping(const UniValue& params, bool fHelp)
44 if (fHelp || params.size() != 0)
47 "\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
48 "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
49 "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n"
51 + HelpExampleCli("ping", "")
52 + HelpExampleRpc("ping", "")
55 // Request that each node send a ping during next message processing pass
56 LOCK2(cs_main, cs_vNodes);
58 BOOST_FOREACH(CNode* pNode, vNodes) {
59 pNode->fPingQueued = true;
65 static void CopyNodeStats(std::vector<CNodeStats>& vstats)
70 vstats.reserve(vNodes.size());
71 BOOST_FOREACH(CNode* pnode, vNodes) {
73 pnode->copyStats(stats);
74 vstats.push_back(stats);
78 UniValue getpeerinfo(const UniValue& params, bool fHelp)
80 if (fHelp || params.size() != 0)
83 "\nReturns data about each connected network node as a json array of objects.\n"
87 " \"id\": n, (numeric) Peer index\n"
88 " \"addr\":\"host:port\", (string) The ip address and port of the peer\n"
89 " \"addrlocal\":\"ip:port\", (string) local address\n"
90 " \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
91 " \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
92 " \"lastrecv\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n"
93 " \"bytessent\": n, (numeric) The total bytes sent\n"
94 " \"bytesrecv\": n, (numeric) The total bytes received\n"
95 " \"conntime\": ttt, (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT)\n"
96 " \"timeoffset\": ttt, (numeric) The time offset in seconds\n"
97 " \"pingtime\": n, (numeric) ping time\n"
98 " \"pingwait\": n, (numeric) ping wait\n"
99 " \"version\": v, (numeric) The peer version, such as 170002\n"
100 " \"subver\": \"/MagicBean:x.y.z[-v]/\", (string) The string version\n"
101 " \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
102 " \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
103 " \"banscore\": n, (numeric) The ban score\n"
104 " \"synced_headers\": n, (numeric) The last header we have in common with this peer\n"
105 " \"synced_blocks\": n, (numeric) The last block we have in common with this peer\n"
107 " n, (numeric) The heights of blocks we're currently asking from this peer\n"
114 + HelpExampleCli("getpeerinfo", "")
115 + HelpExampleRpc("getpeerinfo", "")
120 vector<CNodeStats> vstats;
121 CopyNodeStats(vstats);
123 UniValue ret(UniValue::VARR);
125 BOOST_FOREACH(const CNodeStats& stats, vstats) {
126 UniValue obj(UniValue::VOBJ);
127 CNodeStateStats statestats;
128 bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
129 obj.push_back(Pair("id", stats.nodeid));
130 obj.push_back(Pair("addr", stats.addrName));
131 if (!(stats.addrLocal.empty()))
132 obj.push_back(Pair("addrlocal", stats.addrLocal));
133 obj.push_back(Pair("services", strprintf("%016x", stats.nServices)));
134 obj.push_back(Pair("lastsend", stats.nLastSend));
135 obj.push_back(Pair("lastrecv", stats.nLastRecv));
136 obj.push_back(Pair("bytessent", stats.nSendBytes));
137 obj.push_back(Pair("bytesrecv", stats.nRecvBytes));
138 obj.push_back(Pair("conntime", stats.nTimeConnected));
139 obj.push_back(Pair("timeoffset", stats.nTimeOffset));
140 obj.push_back(Pair("pingtime", stats.dPingTime));
141 if (stats.dPingWait > 0.0)
142 obj.push_back(Pair("pingwait", stats.dPingWait));
143 obj.push_back(Pair("version", stats.nVersion));
144 // Use the sanitized form of subver here, to avoid tricksy remote peers from
145 // corrupting or modifying the JSON output by putting special characters in
146 // their ver message.
147 obj.push_back(Pair("subver", stats.cleanSubVer));
148 obj.push_back(Pair("inbound", stats.fInbound));
149 obj.push_back(Pair("startingheight", stats.nStartingHeight));
151 obj.push_back(Pair("banscore", statestats.nMisbehavior));
152 obj.push_back(Pair("synced_headers", statestats.nSyncHeight));
153 obj.push_back(Pair("synced_blocks", statestats.nCommonHeight));
154 UniValue heights(UniValue::VARR);
155 BOOST_FOREACH(int height, statestats.vHeightInFlight) {
156 heights.push_back(height);
158 obj.push_back(Pair("inflight", heights));
160 obj.push_back(Pair("whitelisted", stats.fWhitelisted));
168 int32_t KOMODO_LONGESTCHAIN;
169 int32_t komodo_longestchain()
171 int32_t ht,n=0,num=0,maxheight=0,height = 0;
172 vector<CNodeStats> vstats;
175 CopyNodeStats(vstats);
177 BOOST_FOREACH(const CNodeStats& stats, vstats)
179 //fprintf(stderr,"komodo_longestchain iter.%d\n",n);
180 CNodeStateStats statestats;
181 bool fStateStats = GetNodeStateStats(stats.nodeid,statestats);
183 if ( stats.nStartingHeight > ht )
184 ht = stats.nStartingHeight;
185 if ( statestats.nSyncHeight > ht )
186 ht = statestats.nSyncHeight;
187 if ( statestats.nCommonHeight > ht )
188 ht = statestats.nCommonHeight;
189 if ( maxheight == 0 || ht > maxheight*1.01 )
190 maxheight = ht, num = 1;
191 else if ( ht > maxheight*0.99 )
197 if ( num > (n >> 1) )
199 extern char ASSETCHAINS_SYMBOL[];
200 if ( 0 && height != KOMODO_LONGESTCHAIN )
201 fprintf(stderr,"set %s KOMODO_LONGESTCHAIN <- %d\n",ASSETCHAINS_SYMBOL,height);
202 KOMODO_LONGESTCHAIN = height;
205 KOMODO_LONGESTCHAIN = 0;
209 UniValue addnode(const UniValue& params, bool fHelp)
212 if (params.size() == 2)
213 strCommand = params[1].get_str();
214 if (fHelp || params.size() != 2 ||
215 (strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
217 "addnode \"node\" \"add|remove|onetry\"\n"
218 "\nAttempts add or remove a node from the addnode list.\n"
219 "Or try a connection to a node once.\n"
221 "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
222 "2. \"command\" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once\n"
224 + HelpExampleCli("addnode", "\"192.168.0.6:8233\" \"onetry\"")
225 + HelpExampleRpc("addnode", "\"192.168.0.6:8233\", \"onetry\"")
228 string strNode = params[0].get_str();
230 if (strCommand == "onetry")
233 OpenNetworkConnection(addr, NULL, strNode.c_str());
237 LOCK(cs_vAddedNodes);
238 vector<string>::iterator it = vAddedNodes.begin();
239 for(; it != vAddedNodes.end(); it++)
243 if (strCommand == "add")
245 if (it != vAddedNodes.end())
246 throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
247 vAddedNodes.push_back(strNode);
249 else if(strCommand == "remove")
251 if (it == vAddedNodes.end())
252 throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
253 vAddedNodes.erase(it);
259 UniValue disconnectnode(const UniValue& params, bool fHelp)
261 if (fHelp || params.size() != 1)
263 "disconnectnode \"node\" \n"
264 "\nImmediately disconnects from the specified node.\n"
266 "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
268 + HelpExampleCli("disconnectnode", "\"192.168.0.6:8233\"")
269 + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8233\"")
272 CNode* pNode = FindNode(params[0].get_str());
274 throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
276 pNode->fDisconnect = true;
281 UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
283 if (fHelp || params.size() < 1 || params.size() > 2)
285 "getaddednodeinfo dns ( \"node\" )\n"
286 "\nReturns information about the given added node, or all added nodes\n"
287 "(note that onetry addnodes are not listed here)\n"
288 "If dns is false, only a list of added nodes will be provided,\n"
289 "otherwise connected information will also be available.\n"
291 "1. dns (boolean, required) If false, only a list of added nodes will be provided, otherwise connected information will also be available.\n"
292 "2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
296 " \"addednode\" : \"192.168.0.201\", (string) The node ip address\n"
297 " \"connected\" : true|false, (boolean) If connected\n"
298 " \"addresses\" : [\n"
300 " \"address\" : \"192.168.0.201:8233\", (string) The Komodo server host and port\n"
301 " \"connected\" : \"outbound\" (string) connection, inbound or outbound\n"
309 + HelpExampleCli("getaddednodeinfo", "true")
310 + HelpExampleCli("getaddednodeinfo", "true \"192.168.0.201\"")
311 + HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"")
314 bool fDns = params[0].get_bool();
316 list<string> laddedNodes(0);
317 if (params.size() == 1)
319 LOCK(cs_vAddedNodes);
320 BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
321 laddedNodes.push_back(strAddNode);
325 string strNode = params[1].get_str();
326 LOCK(cs_vAddedNodes);
327 BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) {
328 if (strAddNode == strNode)
330 laddedNodes.push_back(strAddNode);
334 if (laddedNodes.size() == 0)
335 throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
338 UniValue ret(UniValue::VARR);
341 BOOST_FOREACH (const std::string& strAddNode, laddedNodes) {
342 UniValue obj(UniValue::VOBJ);
343 obj.push_back(Pair("addednode", strAddNode));
349 list<pair<string, vector<CService> > > laddedAddreses(0);
350 BOOST_FOREACH(const std::string& strAddNode, laddedNodes) {
351 vector<CService> vservNode(0);
352 if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
353 laddedAddreses.push_back(make_pair(strAddNode, vservNode));
356 UniValue obj(UniValue::VOBJ);
357 obj.push_back(Pair("addednode", strAddNode));
358 obj.push_back(Pair("connected", false));
359 UniValue addresses(UniValue::VARR);
360 obj.push_back(Pair("addresses", addresses));
365 for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++)
367 UniValue obj(UniValue::VOBJ);
368 obj.push_back(Pair("addednode", it->first));
370 UniValue addresses(UniValue::VARR);
371 bool fConnected = false;
372 BOOST_FOREACH(const CService& addrNode, it->second) {
374 UniValue node(UniValue::VOBJ);
375 node.push_back(Pair("address", addrNode.ToString()));
376 BOOST_FOREACH(CNode* pnode, vNodes) {
377 if (pnode->addr == addrNode)
381 node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound"));
386 node.push_back(Pair("connected", "false"));
387 addresses.push_back(node);
389 obj.push_back(Pair("connected", fConnected));
390 obj.push_back(Pair("addresses", addresses));
397 UniValue getnettotals(const UniValue& params, bool fHelp)
399 if (fHelp || params.size() > 0)
402 "\nReturns information about network traffic, including bytes in, bytes out,\n"
403 "and current time.\n"
406 " \"totalbytesrecv\": n, (numeric) Total bytes received\n"
407 " \"totalbytessent\": n, (numeric) Total bytes sent\n"
408 " \"timemillis\": t (numeric) Total cpu time\n"
411 + HelpExampleCli("getnettotals", "")
412 + HelpExampleRpc("getnettotals", "")
415 UniValue obj(UniValue::VOBJ);
416 obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv()));
417 obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent()));
418 obj.push_back(Pair("timemillis", GetTimeMillis()));
422 static UniValue GetNetworksInfo()
424 UniValue networks(UniValue::VARR);
425 for(int n=0; n<NET_MAX; ++n)
427 enum Network network = static_cast<enum Network>(n);
428 if(network == NET_UNROUTABLE)
431 UniValue obj(UniValue::VOBJ);
432 GetProxy(network, proxy);
433 obj.push_back(Pair("name", GetNetworkName(network)));
434 obj.push_back(Pair("limited", IsLimited(network)));
435 obj.push_back(Pair("reachable", IsReachable(network)));
436 obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()));
437 obj.push_back(Pair("proxy_randomize_credentials", proxy.randomize_credentials));
438 networks.push_back(obj);
443 UniValue getdeprecationinfo(const UniValue& params, bool fHelp)
445 const CChainParams& chainparams = Params();
446 if (fHelp || params.size() != 0 || chainparams.NetworkIDString() != "main")
448 "getdeprecationinfo\n"
449 "Returns an object containing current version and deprecation block height. Applicable only on mainnet.\n"
452 " \"version\": xxxxx, (numeric) the server version\n"
453 " \"subversion\": \"/MagicBean:x.y.z[-v]/\", (string) the server subversion string\n"
454 " \"deprecationheight\": xxxxx, (numeric) the block height at which this version will deprecate and shut down\n"
457 + HelpExampleCli("getdeprecationinfo", "")
458 + HelpExampleRpc("getdeprecationinfo", "")
461 UniValue obj(UniValue::VOBJ);
462 obj.push_back(Pair("version", CLIENT_VERSION));
463 obj.push_back(Pair("subversion",
464 FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>())));
465 obj.push_back(Pair("deprecationheight", DEPRECATION_HEIGHT));
470 UniValue getnetworkinfo(const UniValue& params, bool fHelp)
472 if (fHelp || params.size() != 0)
475 "Returns an object containing various state info regarding P2P networking.\n"
478 " \"version\": xxxxx, (numeric) the server version\n"
479 " \"subversion\": \"/MagicBean:x.y.z[-v]/\", (string) the server subversion string\n"
480 " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
481 " \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
482 " \"timeoffset\": xxxxx, (numeric) the time offset\n"
483 " \"connections\": xxxxx, (numeric) the number of connections\n"
484 " \"networks\": [ (array) information per network\n"
486 " \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n"
487 " \"limited\": true|false, (boolean) is the network limited using -onlynet?\n"
488 " \"reachable\": true|false, (boolean) is the network reachable?\n"
489 " \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n"
493 " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
494 " \"localaddresses\": [ (array) list of local addresses\n"
496 " \"address\": \"xxxx\", (string) network address\n"
497 " \"port\": xxx, (numeric) network port\n"
498 " \"score\": xxx (numeric) relative score\n"
502 " \"warnings\": \"...\" (string) any network warnings (such as alert messages) \n"
505 + HelpExampleCli("getnetworkinfo", "")
506 + HelpExampleRpc("getnetworkinfo", "")
511 UniValue obj(UniValue::VOBJ);
512 obj.push_back(Pair("version", CLIENT_VERSION));
513 obj.push_back(Pair("subversion", strSubVersion));
514 obj.push_back(Pair("protocolversion",PROTOCOL_VERSION));
515 obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
516 obj.push_back(Pair("timeoffset", GetTimeOffset()));
517 obj.push_back(Pair("connections", (int)vNodes.size()));
518 obj.push_back(Pair("networks", GetNetworksInfo()));
519 obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
520 UniValue localAddresses(UniValue::VARR);
522 LOCK(cs_mapLocalHost);
523 BOOST_FOREACH(const PAIRTYPE(CNetAddr, LocalServiceInfo) &item, mapLocalHost)
525 UniValue rec(UniValue::VOBJ);
526 rec.push_back(Pair("address", item.first.ToString()));
527 rec.push_back(Pair("port", item.second.nPort));
528 rec.push_back(Pair("score", item.second.nScore));
529 localAddresses.push_back(rec);
532 obj.push_back(Pair("localaddresses", localAddresses));
533 obj.push_back(Pair("warnings", GetWarnings("statusbar")));
537 UniValue setban(const UniValue& params, bool fHelp)
540 if (params.size() >= 2)
541 strCommand = params[1].get_str();
542 if (fHelp || params.size() < 2 ||
543 (strCommand != "add" && strCommand != "remove"))
545 "setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n"
546 "\nAttempts add or remove a IP/Subnet from the banned list.\n"
548 "1. \"ip(/netmask)\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n"
549 "2. \"command\" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list\n"
550 "3. \"bantime\" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\n"
551 "4. \"absolute\" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
553 + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
554 + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
555 + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\" 86400")
560 bool isSubnet = false;
562 if (params[0].get_str().find("/") != string::npos)
566 netAddr = CNetAddr(params[0].get_str());
568 subNet = CSubNet(params[0].get_str());
570 if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )
571 throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet");
573 if (strCommand == "add")
575 if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr))
576 throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
578 int64_t banTime = 0; //use standard bantime if not specified
579 if (params.size() >= 3 && !params[2].isNull())
580 banTime = params[2].get_int64();
582 bool absolute = false;
583 if (params.size() == 4 && params[3].isTrue())
586 isSubnet ? CNode::Ban(subNet, banTime, absolute) : CNode::Ban(netAddr, banTime, absolute);
588 //disconnect possible nodes
589 while(CNode *bannedNode = (isSubnet ? FindNode(subNet) : FindNode(netAddr)))
590 bannedNode->fDisconnect = true;
592 else if(strCommand == "remove")
594 if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) ))
595 throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
601 UniValue listbanned(const UniValue& params, bool fHelp)
603 if (fHelp || params.size() != 0)
606 "\nList all banned IPs/Subnets.\n"
608 + HelpExampleCli("listbanned", "")
609 + HelpExampleRpc("listbanned", "")
612 std::map<CSubNet, int64_t> banMap;
613 CNode::GetBanned(banMap);
615 UniValue bannedAddresses(UniValue::VARR);
616 for (std::map<CSubNet, int64_t>::iterator it = banMap.begin(); it != banMap.end(); it++)
618 UniValue rec(UniValue::VOBJ);
619 rec.push_back(Pair("address", (*it).first.ToString()));
620 rec.push_back(Pair("banned_until", (*it).second));
621 bannedAddresses.push_back(rec);
624 return bannedAddresses;
627 UniValue clearbanned(const UniValue& params, bool fHelp)
629 if (fHelp || params.size() != 0)
632 "\nClear all banned IPs.\n"
634 + HelpExampleCli("clearbanned", "")
635 + HelpExampleRpc("clearbanned", "")
638 CNode::ClearBanned();
643 static const CRPCCommand commands[] =
644 { // category name actor (function) okSafeMode
645 // --------------------- ------------------------ ----------------------- ----------
646 { "network", "getconnectioncount", &getconnectioncount, true },
647 { "network", "getdeprecationinfo", &getdeprecationinfo, true },
648 { "network", "ping", &ping, true },
649 { "network", "getpeerinfo", &getpeerinfo, true },
650 { "network", "addnode", &addnode, true },
651 { "network", "disconnectnode", &disconnectnode, true },
652 { "network", "getaddednodeinfo", &getaddednodeinfo, true },
653 { "network", "getnettotals", &getnettotals, true },
654 { "network", "getnetworkinfo", &getnetworkinfo, true },
655 { "network", "setban", &setban, true },
656 { "network", "listbanned", &listbanned, true },
657 { "network", "clearbanned", &clearbanned, true },
660 void RegisterNetRPCCommands(CRPCTable &tableRPC)
662 for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
663 tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);