diff options
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/blockchain.cpp | 157 | ||||
-rw-r--r-- | src/rpc/client.cpp | 7 | ||||
-rw-r--r-- | src/rpc/mining.cpp | 37 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 53 | ||||
-rw-r--r-- | src/rpc/net.cpp | 134 | ||||
-rw-r--r-- | src/rpc/protocol.h | 55 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 12 | ||||
-rw-r--r-- | src/rpc/register.h | 12 | ||||
-rw-r--r-- | src/rpc/server.cpp | 9 | ||||
-rw-r--r-- | src/rpc/server.h | 1 |
10 files changed, 310 insertions, 167 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index e3c32d905a..f05f8ff358 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -26,8 +26,20 @@ #include <boost/thread/thread.hpp> // boost::thread::interrupt +#include <mutex> +#include <condition_variable> using namespace std; +struct CUpdatedBlock +{ + uint256 hash; + int height; +}; + +static std::mutex cs_blockchange; +static std::condition_variable cond_blockchange; +static CUpdatedBlock latestblock; + extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); @@ -168,6 +180,138 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp) return chainActive.Tip()->GetBlockHash().GetHex(); } +void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex) +{ + if(pindex) { + std::lock_guard<std::mutex> lock(cs_blockchange); + latestblock.hash = pindex->GetBlockHash(); + latestblock.height = pindex->nHeight; + } + cond_blockchange.notify_all(); +} + +UniValue waitfornewblock(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "waitfornewblock\n" + "\nWaits for a specific new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n" + "\nArguments:\n" + "1. timeout (milliseconds) (int, optional, default=false)\n" + "\nResult::\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + "\nExamples\n" + + HelpExampleCli("waitfornewblock", "1000") + + HelpExampleRpc("waitfornewblock", "1000") + ); + int timeout = 0; + if (params.size() > 0) + timeout = params[0].get_int(); + + CUpdatedBlock block; + { + std::unique_lock<std::mutex> lock(cs_blockchange); + block = latestblock; + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); + else + cond_blockchange.wait(lock, [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); + block = latestblock; + } + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + +UniValue waitforblock(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "waitforblock\n" + "\nWaits for a specific new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n" + "\nArguments:\n" + "1. blockhash to wait for (string)\n" + "2. timeout (milliseconds) (int, optional, default=false)\n" + "\nResult::\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + "\nExamples\n" + + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + ); + int timeout = 0; + + uint256 hash = uint256S(params[0].get_str()); + + if (params.size() > 1) + timeout = params[1].get_int(); + + CUpdatedBlock block; + { + std::unique_lock<std::mutex> lock(cs_blockchange); + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();}); + else + cond_blockchange.wait(lock, [&hash]{return latestblock.hash == hash || !IsRPCRunning(); }); + block = latestblock; + } + + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + +UniValue waitforblockheight(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "waitforblock\n" + "\nWaits for (at least) block height and returns the height and hash\n" + "\nof the current tip.\n" + "\nReturns the current block on timeout or exit.\n" + "\nArguments:\n" + "1. block height to wait for (int)\n" + "2. timeout (milliseconds) (int, optional, default=false)\n" + "\nResult::\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + "\nExamples\n" + + HelpExampleCli("waitforblockheight", "\"100\", 1000") + + HelpExampleRpc("waitforblockheight", "\"100\", 1000") + ); + int timeout = 0; + + int height = params[0].get_int(); + + if (params.size() > 1) + timeout = params[1].get_int(); + + CUpdatedBlock block; + { + std::unique_lock<std::mutex> lock(cs_blockchange); + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();}); + else + cond_blockchange.wait(lock, [&height]{return latestblock.height >= height || !IsRPCRunning(); }); + block = latestblock; + } + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + UniValue getdifficulty(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -632,7 +776,7 @@ struct CCoinsStats //! Calculate statistics about the unspent transaction output set static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats) { - boost::scoped_ptr<CCoinsViewCursor> pcursor(view->Cursor()); + std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor()); CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); stats.hashBlock = pcursor->GetBestBlock(); @@ -1133,7 +1277,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp) } if (state.IsValid()) { - ActivateBestChain(state, Params()); + ActivateBestChain(state, Params(), NULL, g_connman.get()); } if (!state.IsValid()) { @@ -1171,7 +1315,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp) } CValidationState state; - ActivateBestChain(state, Params()); + ActivateBestChain(state, Params(), NULL, g_connman.get()); if (!state.IsValid()) { throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); @@ -1203,10 +1347,13 @@ static const CRPCCommand commands[] = /* Not shown in help */ { "hidden", "invalidateblock", &invalidateblock, true }, { "hidden", "reconsiderblock", &reconsiderblock, true }, + { "hidden", "waitfornewblock", &waitfornewblock, true }, + { "hidden", "waitforblock", &waitforblock, true }, + { "hidden", "waitforblockheight", &waitforblockheight, true }, }; -void RegisterBlockchainRPCCommands(CRPCTable &tableRPC) +void RegisterBlockchainRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index d0675fdb49..c14d9d6747 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -26,7 +26,6 @@ static const CRPCConvertParam vRPCConvertParams[] = { { "stop", 0 }, { "setmocktime", 0 }, - { "getaddednodeinfo", 0 }, { "generate", 0 }, { "generate", 1 }, { "generatetoaddress", 0 }, @@ -47,6 +46,12 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getbalance", 1 }, { "getbalance", 2 }, { "getblockhash", 0 }, + { "waitforblockheight", 0 }, + { "waitforblockheight", 1 }, + { "waitforblock", 1 }, + { "waitforblock", 2 }, + { "waitfornewblock", 0 }, + { "waitfornewblock", 1 }, { "move", 2 }, { "move", 3 }, { "sendfrom", 2 }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 92ca4bab6b..7794ac619d 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -131,7 +131,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG continue; } CValidationState state; - if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, g_connman.get())) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -227,10 +227,11 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) " \"currentblockweight\": nnn, (numeric) The last block weight\n" " \"currentblocktx\": nnn, (numeric) The last block transaction\n" " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" - " \"errors\": \"...\" (string) Current errors\n" + " \"errors\": \"...\" (string) Current errors\n" + " \"networkhashps\": nnn, (numeric) The network hashes per second\n" " \"pooledtx\": n (numeric) The size of the mem pool\n" " \"testnet\": true|false (boolean) If using testnet or not\n" - " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" + " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" "}\n" "\nExamples:\n" + HelpExampleCli("getmininginfo", "") @@ -456,7 +457,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (strMode != "template") throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); - if (vNodes.empty()) + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + + if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!"); if (IsInitialBlockDownload()) @@ -546,6 +550,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) UpdateTime(pblock, consensusParams, pindexPrev); pblock->nNonce = 0; + // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration + const bool fPreSegWit = (THRESHOLD_ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache)); + UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue transactions(UniValue::VARR); @@ -574,7 +581,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) int index_in_template = i - 1; entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); - entry.push_back(Pair("sigops", pblocktemplate->vTxSigOpsCost[index_in_template])); + int64_t nTxSigOps = pblocktemplate->vTxSigOpsCost[index_in_template]; + if (fPreSegWit) { + assert(nTxSigOps % WITNESS_SCALE_FACTOR == 0); + nTxSigOps /= WITNESS_SCALE_FACTOR; + } + entry.push_back(Pair("sigops", nTxSigOps)); entry.push_back(Pair("weight", GetTransactionWeight(tx))); transactions.push_back(entry); @@ -642,7 +654,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (nMaxVersionPreVB >= 2) { // If VB is supported by the client, nMaxVersionPreVB is -1, so we won't get here - // Because BIP 34 changed how the generation transaction is serialised, we can only use version/force back to v2 blocks + // Because BIP 34 changed how the generation transaction is serialized, we can only use version/force back to v2 blocks // This is safe to do [otherwise-]unconditionally only because we are throwing an exception above if a non-force deployment gets activated // Note that this can probably also be removed entirely after the first BIP9 non-force deployment (ie, probably segwit) gets activated aMutable.push_back("version/force"); @@ -657,7 +669,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); result.push_back(Pair("mutable", aMutable)); result.push_back(Pair("noncerange", "00000000ffffffff")); - result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS_COST)); + int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST; + if (fPreSegWit) { + assert(nSigOpLimit % WITNESS_SCALE_FACTOR == 0); + nSigOpLimit /= WITNESS_SCALE_FACTOR; + } + result.push_back(Pair("sigoplimit", nSigOpLimit)); result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE)); result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT)); result.push_back(Pair("curtime", pblock->GetBlockTime())); @@ -740,7 +757,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, g_connman.get()); UnregisterValidationInterface(&sc); if (fBlockPresent) { @@ -905,8 +922,8 @@ static const CRPCCommand commands[] = { "util", "estimatesmartpriority", &estimatesmartpriority, true }, }; -void RegisterMiningRPCCommands(CRPCTable &tableRPC) +void RegisterMiningRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index a8c5bcd177..5afcf6353c 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -89,7 +89,8 @@ UniValue getinfo(const UniValue& params, bool fHelp) #endif obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("timeoffset", GetTimeOffset())); - obj.push_back(Pair("connections", (int)vNodes.size())); + if(g_connman) + obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL))); 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())); @@ -320,43 +321,6 @@ UniValue createmultisig(const UniValue& params, bool fHelp) return result; } -UniValue createwitnessaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 1) - { - string msg = "createwitnessaddress \"script\"\n" - "\nCreates a witness address for a particular script.\n" - "It returns a json object with the address and witness script.\n" - - "\nArguments:\n" - "1. \"script\" (string, required) A hex encoded script\n" - - "\nResult:\n" - "{\n" - " \"address\":\"multisigaddress\", (string) The value of the new address (P2SH of witness script).\n" - " \"witnessScript\":\"script\" (string) The string value of the hex-encoded witness script.\n" - "}\n" - ; - throw runtime_error(msg); - } - - if (!IsHex(params[0].get_str())) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Script must be hex-encoded"); - } - - std::vector<unsigned char> code = ParseHex(params[0].get_str()); - CScript script(code.begin(), code.end()); - CScript witscript = GetScriptForWitness(script); - CScriptID witscriptid(witscript); - CBitcoinAddress address(witscriptid); - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("address", address.ToString())); - result.push_back(Pair("witnessScript", HexStr(witscript.begin(), witscript.end()))); - - return result; -} - UniValue verifymessage(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) @@ -471,14 +435,16 @@ UniValue setmocktime(const UniValue& params, bool fHelp) // 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); + LOCK(cs_main); 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; + if(g_connman) { + g_connman->ForEachNode([t](CNode* pnode) { + pnode->nLastSend = pnode->nLastRecv = t; + }); } return NullUniValue; @@ -490,7 +456,6 @@ static const CRPCCommand commands[] = { "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */ { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */ { "util", "createmultisig", &createmultisig, true }, - { "util", "createwitnessaddress", &createwitnessaddress, true }, { "util", "verifymessage", &verifymessage, true }, { "util", "signmessagewithprivkey", &signmessagewithprivkey, true }, @@ -498,8 +463,8 @@ static const CRPCCommand commands[] = { "hidden", "setmocktime", &setmocktime, true }, }; -void RegisterMiscRPCCommands(CRPCTable &tableRPC) +void RegisterMiscRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index b85c7b2e1a..b011029f51 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -36,9 +36,10 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp) + HelpExampleRpc("getconnectioncount", "") ); - LOCK2(cs_main, cs_vNodes); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - return (int)vNodes.size(); + return (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL); } UniValue ping(const UniValue& params, bool fHelp) @@ -54,29 +55,16 @@ UniValue ping(const UniValue& params, bool fHelp) + HelpExampleRpc("ping", "") ); - // Request that each node send a ping during next message processing pass - LOCK2(cs_main, cs_vNodes); - - BOOST_FOREACH(CNode* pNode, vNodes) { - pNode->fPingQueued = true; - } + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + // Request that each node send a ping during next message processing pass + g_connman->ForEachNode([](CNode* pnode) { + pnode->fPingQueued = true; + }); return NullUniValue; } -static void CopyNodeStats(std::vector<CNodeStats>& vstats) -{ - vstats.clear(); - - LOCK(cs_vNodes); - vstats.reserve(vNodes.size()); - BOOST_FOREACH(CNode* pnode, vNodes) { - CNodeStats stats; - pnode->copyStats(stats); - vstats.push_back(stats); - } -} - UniValue getpeerinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -127,10 +115,11 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) + HelpExampleRpc("getpeerinfo", "") ); - LOCK(cs_main); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); vector<CNodeStats> vstats; - CopyNodeStats(vstats); + g_connman->GetNodeStats(vstats); UniValue ret(UniValue::VARR); @@ -214,32 +203,27 @@ UniValue addnode(const UniValue& params, bool fHelp) + HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + string strNode = params[0].get_str(); if (strCommand == "onetry") { CAddress addr; - OpenNetworkConnection(addr, false, NULL, strNode.c_str()); + g_connman->OpenNetworkConnection(addr, false, NULL, strNode.c_str()); return NullUniValue; } - LOCK(cs_vAddedNodes); - vector<string>::iterator it = vAddedNodes.begin(); - for(; it != vAddedNodes.end(); it++) - if (strNode == *it) - break; - if (strCommand == "add") { - if (it != vAddedNodes.end()) + if(!g_connman->AddNode(strNode)) throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); - vAddedNodes.push_back(strNode); } else if(strCommand == "remove") { - if (it == vAddedNodes.end()) + if(!g_connman->RemoveAddedNode(strNode)) throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); - vAddedNodes.erase(it); } return NullUniValue; @@ -258,25 +242,25 @@ UniValue disconnectnode(const UniValue& params, bool fHelp) + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"") ); - CNode* pNode = FindNode(params[0].get_str()); - if (pNode == NULL) - throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes"); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - pNode->fDisconnect = true; + bool ret = g_connman->DisconnectNode(params[0].get_str()); + if (!ret) + throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes"); return NullUniValue; } UniValue getaddednodeinfo(const UniValue& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() > 1) throw runtime_error( - "getaddednodeinfo dummy ( \"node\" )\n" + "getaddednodeinfo ( \"node\" )\n" "\nReturns information about the given added node, or all added nodes\n" "(note that onetry addnodes are not listed here)\n" "\nArguments:\n" - "1. dummy (boolean, required) Kept for historical purposes but ignored\n" - "2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n" + "1. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n" "\nResult:\n" "[\n" " {\n" @@ -297,12 +281,15 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) + HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"") ); - std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo(); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - if (params.size() == 2) { + std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo(); + + if (params.size() == 1) { bool found = false; for (const AddedNodeInfo& info : vInfo) { - if (info.strAddedNode == params[1].get_str()) { + if (info.strAddedNode == params[0].get_str()) { vInfo.assign(1, info); found = true; break; @@ -359,19 +346,21 @@ UniValue getnettotals(const UniValue& params, bool fHelp) + HelpExampleCli("getnettotals", "") + HelpExampleRpc("getnettotals", "") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); - obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); + obj.push_back(Pair("totalbytesrecv", g_connman->GetTotalBytesRecv())); + obj.push_back(Pair("totalbytessent", g_connman->GetTotalBytesSent())); obj.push_back(Pair("timemillis", GetTimeMillis())); UniValue outboundLimit(UniValue::VOBJ); - outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe())); - outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget())); - outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false))); - outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true))); - outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft())); - outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle())); + outboundLimit.push_back(Pair("timeframe", g_connman->GetMaxOutboundTimeframe())); + outboundLimit.push_back(Pair("target", g_connman->GetMaxOutboundTarget())); + outboundLimit.push_back(Pair("target_reached", g_connman->OutboundTargetReached(false))); + outboundLimit.push_back(Pair("serve_historical_blocks", !g_connman->OutboundTargetReached(true))); + outboundLimit.push_back(Pair("bytes_left_in_cycle", g_connman->GetOutboundTargetBytesLeft())); + outboundLimit.push_back(Pair("time_left_in_cycle", g_connman->GetMaxOutboundTimeLeftInCycle())); obj.push_back(Pair("uploadtarget", outboundLimit)); return obj; } @@ -438,15 +427,16 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) ); LOCK(cs_main); - UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("subversion", strSubVersion)); obj.push_back(Pair("protocolversion",PROTOCOL_VERSION)); - obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); + if(g_connman) + obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices()))); obj.push_back(Pair("localrelay", fRelayTxes)); obj.push_back(Pair("timeoffset", GetTimeOffset())); - obj.push_back(Pair("connections", (int)vNodes.size())); + if(g_connman) + obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL))); obj.push_back(Pair("networks", GetNetworksInfo())); obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); UniValue localAddresses(UniValue::VARR); @@ -484,8 +474,10 @@ UniValue setban(const UniValue& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400") + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") - + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\" 86400") + + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); CSubNet subNet; CNetAddr netAddr; @@ -494,17 +486,20 @@ UniValue setban(const UniValue& params, bool fHelp) if (params[0].get_str().find("/") != string::npos) isSubnet = true; - if (!isSubnet) - netAddr = CNetAddr(params[0].get_str()); + if (!isSubnet) { + CNetAddr resolved; + LookupHost(params[0].get_str().c_str(), resolved, false); + netAddr = resolved; + } else - subNet = CSubNet(params[0].get_str()); + LookupSubNet(params[0].get_str().c_str(), subNet); if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) ) throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet"); if (strCommand == "add") { - if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr)) + if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr)) throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned"); int64_t banTime = 0; //use standard bantime if not specified @@ -515,11 +510,11 @@ UniValue setban(const UniValue& params, bool fHelp) if (params.size() == 4 && params[3].isTrue()) absolute = true; - isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); + isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); } else if(strCommand == "remove") { - if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) )) + if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) )) throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed"); } return NullUniValue; @@ -536,8 +531,11 @@ UniValue listbanned(const UniValue& params, bool fHelp) + HelpExampleRpc("listbanned", "") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + banmap_t banMap; - CNode::GetBanned(banMap); + g_connman->GetBanned(banMap); UniValue bannedAddresses(UniValue::VARR); for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++) @@ -565,8 +563,10 @@ UniValue clearbanned(const UniValue& params, bool fHelp) + HelpExampleCli("clearbanned", "") + HelpExampleRpc("clearbanned", "") ); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - CNode::ClearBanned(); + g_connman->ClearBanned(); return NullUniValue; } @@ -587,8 +587,8 @@ static const CRPCCommand commands[] = { "network", "clearbanned", &clearbanned, true }, }; -void RegisterNetRPCCommands(CRPCTable &tableRPC) +void RegisterNetRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index 55d0aac68b..1d2ef0e41e 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -38,18 +38,18 @@ enum RPCErrorCode RPC_PARSE_ERROR = -32700, //! General application defined errors - RPC_MISC_ERROR = -1, //! std::exception thrown in command handling - RPC_FORBIDDEN_BY_SAFE_MODE = -2, //! Server is in safe mode, and command is not allowed in safe mode - RPC_TYPE_ERROR = -3, //! Unexpected type was passed as parameter - RPC_INVALID_ADDRESS_OR_KEY = -5, //! Invalid address or key - RPC_OUT_OF_MEMORY = -7, //! Ran out of memory during operation - RPC_INVALID_PARAMETER = -8, //! Invalid, missing or duplicate parameter - RPC_DATABASE_ERROR = -20, //! Database error - RPC_DESERIALIZATION_ERROR = -22, //! Error parsing or validating structure in raw format - RPC_VERIFY_ERROR = -25, //! General error during transaction or block submission - RPC_VERIFY_REJECTED = -26, //! Transaction or block was rejected by network rules - RPC_VERIFY_ALREADY_IN_CHAIN = -27, //! Transaction already in chain - RPC_IN_WARMUP = -28, //! Client still warming up + RPC_MISC_ERROR = -1, //!< std::exception thrown in command handling + RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode + RPC_TYPE_ERROR = -3, //!< Unexpected type was passed as parameter + RPC_INVALID_ADDRESS_OR_KEY = -5, //!< Invalid address or key + RPC_OUT_OF_MEMORY = -7, //!< Ran out of memory during operation + RPC_INVALID_PARAMETER = -8, //!< Invalid, missing or duplicate parameter + RPC_DATABASE_ERROR = -20, //!< Database error + RPC_DESERIALIZATION_ERROR = -22, //!< Error parsing or validating structure in raw format + RPC_VERIFY_ERROR = -25, //!< General error during transaction or block submission + RPC_VERIFY_REJECTED = -26, //!< Transaction or block was rejected by network rules + RPC_VERIFY_ALREADY_IN_CHAIN = -27, //!< Transaction already in chain + RPC_IN_WARMUP = -28, //!< Client still warming up //! Aliases for backward compatibility RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR, @@ -57,23 +57,24 @@ enum RPCErrorCode RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN, //! P2P client errors - RPC_CLIENT_NOT_CONNECTED = -9, //! Bitcoin is not connected - RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks - RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added - RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before - RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes - RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet + RPC_CLIENT_NOT_CONNECTED = -9, //!< Bitcoin is not connected + RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //!< Still downloading initial blocks + RPC_CLIENT_NODE_ALREADY_ADDED = -23, //!< Node is already added + RPC_CLIENT_NODE_NOT_ADDED = -24, //!< Node has not been added before + RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes + RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet + RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found //! Wallet errors - RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.) - RPC_WALLET_INSUFFICIENT_FUNDS = -6, //! Not enough funds in wallet or account - RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //! Invalid account name - RPC_WALLET_KEYPOOL_RAN_OUT = -12, //! Keypool ran out, call keypoolrefill first - RPC_WALLET_UNLOCK_NEEDED = -13, //! Enter the wallet passphrase with walletpassphrase first - RPC_WALLET_PASSPHRASE_INCORRECT = -14, //! The wallet passphrase entered was incorrect - RPC_WALLET_WRONG_ENC_STATE = -15, //! Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.) - RPC_WALLET_ENCRYPTION_FAILED = -16, //! Failed to encrypt the wallet - RPC_WALLET_ALREADY_UNLOCKED = -17, //! Wallet is already unlocked + RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.) + RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account + RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //!< Invalid account name + RPC_WALLET_KEYPOOL_RAN_OUT = -12, //!< Keypool ran out, call keypoolrefill first + RPC_WALLET_UNLOCK_NEEDED = -13, //!< Enter the wallet passphrase with walletpassphrase first + RPC_WALLET_PASSPHRASE_INCORRECT = -14, //!< The wallet passphrase entered was incorrect + RPC_WALLET_WRONG_ENC_STATE = -15, //!< Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.) + RPC_WALLET_ENCRYPTION_FAILED = -16, //!< Failed to encrypt the wallet + RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked }; std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 3270cd384f..d2ad0a52b7 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -891,8 +891,14 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) } else if (fHaveChain) { throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); } - RelayTransaction(tx); + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + CInv inv(MSG_TX, hashTx); + g_connman->ForEachNode([&inv](CNode* pnode) + { + pnode->PushInventory(inv); + }); return hashTx.GetHex(); } @@ -910,8 +916,8 @@ static const CRPCCommand commands[] = { "blockchain", "verifytxoutproof", &verifytxoutproof, true }, }; -void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC) +void RegisterRawTransactionRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpc/register.h b/src/rpc/register.h index 01aa58a25d..49aee2365f 100644 --- a/src/rpc/register.h +++ b/src/rpc/register.h @@ -20,13 +20,13 @@ void RegisterMiningRPCCommands(CRPCTable &tableRPC); /** Register raw transaction RPC commands */ void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC); -static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) +static inline void RegisterAllCoreRPCCommands(CRPCTable &t) { - RegisterBlockchainRPCCommands(tableRPC); - RegisterNetRPCCommands(tableRPC); - RegisterMiscRPCCommands(tableRPC); - RegisterMiningRPCCommands(tableRPC); - RegisterRawTransactionRPCCommands(tableRPC); + RegisterBlockchainRPCCommands(t); + RegisterNetRPCCommands(t); + RegisterMiscRPCCommands(t); + RegisterMiningRPCCommands(t); + RegisterRawTransactionRPCCommands(t); } #endif diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 23149baa6d..5fb97f7496 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -25,6 +25,8 @@ #include <boost/thread.hpp> #include <boost/algorithm/string/case_conv.hpp> // for to_upper() +#include <memory> // for unique_ptr + using namespace RPCServer; using namespace std; @@ -34,9 +36,8 @@ static std::string rpcWarmupStatus("RPC server started"); static CCriticalSection cs_rpcWarmup; /* Timer-creating functions */ static RPCTimerInterface* timerInterface = NULL; -/* Map of name to timer. - * @note Can be changed to std::unique_ptr when C++11 */ -static std::map<std::string, boost::shared_ptr<RPCTimerBase> > deadlineTimers; +/* Map of name to timer. */ +static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers; static struct CRPCSignals { @@ -490,7 +491,7 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6 throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC"); deadlineTimers.erase(name); LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name()); - deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)))); + deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))); } CRPCTable tableRPC; diff --git a/src/rpc/server.h b/src/rpc/server.h index b5ccc153d0..4e0aa2c6d6 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -194,5 +194,6 @@ bool StartRPC(); void InterruptRPC(); void StopRPC(); std::string JSONRPCExecBatch(const UniValue& vReq); +void RPCNotifyBlockChange(bool ibd, const CBlockIndex *); #endif // BITCOIN_RPCSERVER_H |