aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/blockchain.cpp547
-rw-r--r--src/rpc/client.cpp221
-rw-r--r--src/rpc/client.h7
-rw-r--r--src/rpc/mining.cpp330
-rw-r--r--src/rpc/misc.cpp193
-rw-r--r--src/rpc/net.cpp274
-rw-r--r--src/rpc/protocol.cpp13
-rw-r--r--src/rpc/protocol.h59
-rw-r--r--src/rpc/rawtransaction.cpp249
-rw-r--r--src/rpc/register.h12
-rw-r--r--src/rpc/server.cpp127
-rw-r--r--src/rpc/server.h28
12 files changed, 1268 insertions, 792 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 20eefa1c57..368654bfa6 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,7 +9,7 @@
#include "checkpoints.h"
#include "coins.h"
#include "consensus/validation.h"
-#include "main.h"
+#include "validation.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
#include "rpc/server.h"
@@ -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);
@@ -101,22 +113,22 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.push_back(Pair("confirmations", confirmations));
result.push_back(Pair("strippedsize", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
- result.push_back(Pair("cost", (int)::GetBlockCost(block)));
+ result.push_back(Pair("weight", (int)::GetBlockWeight(block)));
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion)));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
UniValue txs(UniValue::VARR);
- BOOST_FOREACH(const CTransaction&tx, block.vtx)
+ for(const auto& tx : block.vtx)
{
if(txDetails)
{
UniValue objTx(UniValue::VOBJ);
- TxToJSON(tx, uint256(), objTx);
+ TxToJSON(*tx, uint256(), objTx);
txs.push_back(objTx);
}
else
- txs.push_back(tx.GetHash().GetHex());
+ txs.push_back(tx->GetHash().GetHex());
}
result.push_back(Pair("tx", txs));
result.push_back(Pair("time", block.GetBlockTime()));
@@ -134,12 +146,12 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
return result;
}
-UniValue getblockcount(const UniValue& params, bool fHelp)
+UniValue getblockcount(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getblockcount\n"
- "\nReturns the number of blocks in the longest block chain.\n"
+ "\nReturns the number of blocks in the longest blockchain.\n"
"\nResult:\n"
"n (numeric) The current block count\n"
"\nExamples:\n"
@@ -151,15 +163,15 @@ UniValue getblockcount(const UniValue& params, bool fHelp)
return chainActive.Height();
}
-UniValue getbestblockhash(const UniValue& params, bool fHelp)
+UniValue getbestblockhash(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getbestblockhash\n"
- "\nReturns the hash of the best (tip) block in the longest block chain.\n"
- "\nResult\n"
+ "\nReturns the hash of the best (tip) block in the longest blockchain.\n"
+ "\nResult:\n"
"\"hex\" (string) the block hash hex encoded\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("getbestblockhash", "")
+ HelpExampleRpc("getbestblockhash", "")
);
@@ -168,9 +180,141 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp)
return chainActive.Tip()->GetBlockHash().GetHex();
}
-UniValue getdifficulty(const UniValue& params, bool fHelp)
+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 JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() > 1)
+ throw runtime_error(
+ "waitfornewblock (timeout)\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 (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\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 (request.params.size() > 0)
+ timeout = request.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 JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ throw runtime_error(
+ "waitforblock <blockhash> (timeout)\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\" (required, string) Block hash to wait for.\n"
+ "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\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(request.params[0].get_str());
+
+ if (request.params.size() > 1)
+ timeout = request.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 JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ throw runtime_error(
+ "waitforblockheight <height> (timeout)\n"
+ "\nWaits for (at least) block height and returns the height and hash\n"
+ "of the current tip.\n"
+ "\nReturns the current block on timeout or exit.\n"
+ "\nArguments:\n"
+ "1. height (required, int) Block height to wait for (int)\n"
+ "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\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 = request.params[0].get_int();
+
+ if (request.params.size() > 1)
+ timeout = request.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 JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getdifficulty\n"
"\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
@@ -187,18 +331,18 @@ UniValue getdifficulty(const UniValue& params, bool fHelp)
std::string EntryDescriptionString()
{
- return " \"size\" : n, (numeric) transaction size in bytes\n"
+ return " \"size\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n"
" \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
" \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
" \"height\" : n, (numeric) block height when transaction entered pool\n"
- " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
- " \"currentpriority\" : n, (numeric) transaction priority now\n"
+ " \"startingpriority\" : n, (numeric) DEPRECATED. Priority when transaction entered pool\n"
+ " \"currentpriority\" : n, (numeric) DEPRECATED. Transaction priority now\n"
" \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n"
- " \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n"
+ " \"descendantsize\" : n, (numeric) virtual transaction size of in-mempool descendants (including this one)\n"
" \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n"
" \"ancestorcount\" : n, (numeric) number of in-mempool ancestor transactions (including this one)\n"
- " \"ancestorsize\" : n, (numeric) size of in-mempool ancestors (including this one)\n"
+ " \"ancestorsize\" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one)\n"
" \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one)\n"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
@@ -267,14 +411,14 @@ UniValue mempoolToJSON(bool fVerbose = false)
}
}
-UniValue getrawmempool(const UniValue& params, bool fHelp)
+UniValue getrawmempool(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 1)
+ if (request.fHelp || request.params.size() > 1)
throw runtime_error(
"getrawmempool ( verbose )\n"
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
"\nArguments:\n"
- "1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
+ "1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
"\nResult: (for verbose = false):\n"
"[ (json array of string)\n"
" \"transactionid\" (string) The transaction id\n"
@@ -286,27 +430,27 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("getrawmempool", "true")
+ HelpExampleRpc("getrawmempool", "true")
);
bool fVerbose = false;
- if (params.size() > 0)
- fVerbose = params[0].get_bool();
+ if (request.params.size() > 0)
+ fVerbose = request.params[0].get_bool();
return mempoolToJSON(fVerbose);
}
-UniValue getmempoolancestors(const UniValue& params, bool fHelp)
+UniValue getmempoolancestors(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2) {
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw runtime_error(
"getmempoolancestors txid (verbose)\n"
"\nIf txid is in the mempool, returns all in-mempool ancestors.\n"
"\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
- "2. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
+ "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
+ "2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
"\nResult (for verbose=false):\n"
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool ancestor transaction\n"
@@ -318,17 +462,17 @@ UniValue getmempoolancestors(const UniValue& params, bool fHelp)
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("getmempoolancestors", "\"mytxid\"")
+ HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
);
}
bool fVerbose = false;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
LOCK(mempool.cs);
@@ -353,24 +497,24 @@ UniValue getmempoolancestors(const UniValue& params, bool fHelp)
UniValue o(UniValue::VOBJ);
BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors) {
const CTxMemPoolEntry &e = *ancestorIt;
- const uint256& hash = e.GetTx().GetHash();
+ const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
entryToJSON(info, e);
- o.push_back(Pair(hash.ToString(), info));
+ o.push_back(Pair(_hash.ToString(), info));
}
return o;
}
}
-UniValue getmempooldescendants(const UniValue& params, bool fHelp)
+UniValue getmempooldescendants(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2) {
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw runtime_error(
"getmempooldescendants txid (verbose)\n"
"\nIf txid is in the mempool, returns all in-mempool descendants.\n"
"\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
- "2. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
+ "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
+ "2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
"\nResult (for verbose=false):\n"
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool descendant transaction\n"
@@ -382,17 +526,17 @@ UniValue getmempooldescendants(const UniValue& params, bool fHelp)
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("getmempooldescendants", "\"mytxid\"")
+ HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
);
}
bool fVerbose = false;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
LOCK(mempool.cs);
@@ -417,18 +561,18 @@ UniValue getmempooldescendants(const UniValue& params, bool fHelp)
UniValue o(UniValue::VOBJ);
BOOST_FOREACH(CTxMemPool::txiter descendantIt, setDescendants) {
const CTxMemPoolEntry &e = *descendantIt;
- const uint256& hash = e.GetTx().GetHash();
+ const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
entryToJSON(info, e);
- o.push_back(Pair(hash.ToString(), info));
+ o.push_back(Pair(_hash.ToString(), info));
}
return o;
}
}
-UniValue getmempoolentry(const UniValue& params, bool fHelp)
+UniValue getmempoolentry(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1) {
+ if (request.fHelp || request.params.size() != 1) {
throw runtime_error(
"getmempoolentry txid\n"
"\nReturns mempool data for given transaction\n"
@@ -438,13 +582,13 @@ UniValue getmempoolentry(const UniValue& params, bool fHelp)
"{ (json object)\n"
+ EntryDescriptionString()
+ "}\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("getmempoolentry", "\"mytxid\"")
+ HelpExampleRpc("getmempoolentry", "\"mytxid\"")
);
}
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
LOCK(mempool.cs);
@@ -459,14 +603,14 @@ UniValue getmempoolentry(const UniValue& params, bool fHelp)
return info;
}
-UniValue getblockhash(const UniValue& params, bool fHelp)
+UniValue getblockhash(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
- "getblockhash index\n"
- "\nReturns hash of block in best-block-chain at index provided.\n"
+ "getblockhash height\n"
+ "\nReturns hash of block in best-block-chain at height provided.\n"
"\nArguments:\n"
- "1. index (numeric, required) The block index\n"
+ "1. height (numeric, required) The height index\n"
"\nResult:\n"
"\"hash\" (string) The block hash\n"
"\nExamples:\n"
@@ -476,7 +620,7 @@ UniValue getblockhash(const UniValue& params, bool fHelp)
LOCK(cs_main);
- int nHeight = params[0].get_int();
+ int nHeight = request.params[0].get_int();
if (nHeight < 0 || nHeight > chainActive.Height())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
@@ -484,9 +628,9 @@ UniValue getblockhash(const UniValue& params, bool fHelp)
return pblockindex->GetBlockHash().GetHex();
}
-UniValue getblockheader(const UniValue& params, bool fHelp)
+UniValue getblockheader(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"getblockheader \"hash\" ( verbose )\n"
"\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
@@ -507,9 +651,9 @@ UniValue getblockheader(const UniValue& params, bool fHelp)
" \"nonce\" : n, (numeric) The nonce\n"
" \"bits\" : \"1d00ffff\", (string) The bits\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\n"
+ " \"chainwork\" : \"0000...1f3\" (string) Expected number of hashes required to produce the current chain (in hex)\n"
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\", (string) The hash of the next block\n"
- " \"chainwork\" : \"0000...1f3\" (string) Expected number of hashes required to produce the current chain (in hex)\n"
"}\n"
"\nResult (for verbose=false):\n"
"\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
@@ -520,12 +664,12 @@ UniValue getblockheader(const UniValue& params, bool fHelp)
LOCK(cs_main);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
bool fVerbose = true;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
@@ -543,23 +687,23 @@ UniValue getblockheader(const UniValue& params, bool fHelp)
return blockheaderToJSON(pblockindex);
}
-UniValue getblock(const UniValue& params, bool fHelp)
+UniValue getblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
- "getblock \"hash\" ( verbose )\n"
+ "getblock \"blockhash\" ( verbose )\n"
"\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
"If verbose is true, returns an Object with information about block <hash>.\n"
"\nArguments:\n"
- "1. \"hash\" (string, required) The block hash\n"
- "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"
+ "1. \"blockhash\" (string, required) The block hash\n"
+ "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"
"\nResult (for verbose = true):\n"
"{\n"
" \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
" \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
" \"size\" : n, (numeric) The block size\n"
" \"strippedsize\" : n, (numeric) The block size excluding witness data\n"
- " \"cost\" : n (numeric) The block cost\n"
+ " \"weight\" : n (numeric) The block weight as defined in BIP 141\n"
" \"height\" : n, (numeric) The block height or index\n"
" \"version\" : n, (numeric) The block version\n"
" \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n"
@@ -586,12 +730,12 @@ UniValue getblock(const UniValue& params, bool fHelp)
LOCK(cs_main);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
bool fVerbose = true;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
@@ -607,7 +751,7 @@ UniValue getblock(const UniValue& params, bool fHelp)
if (!fVerbose)
{
- CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssBlock << block;
std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
return strHex;
@@ -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();
@@ -670,9 +814,56 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
return true;
}
-UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
+UniValue pruneblockchain(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 1)
+ throw runtime_error(
+ "pruneblockchain\n"
+ "\nArguments:\n"
+ "1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or to a unix timestamp to prune based on block time.\n"
+ "\nResult:\n"
+ "n (numeric) Height of the last block pruned.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("pruneblockchain", "1000")
+ + HelpExampleRpc("pruneblockchain", "1000"));
+
+ if (!fPruneMode)
+ throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Cannot prune blocks because node is not in prune mode.");
+
+ LOCK(cs_main);
+
+ int heightParam = request.params[0].get_int();
+ if (heightParam < 0)
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height.");
+
+ // Height value more than a billion is too high to be a block height, and
+ // too low to be a block time (corresponds to timestamp from Sep 2001).
+ if (heightParam > 1000000000) {
+ CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam);
+ if (!pindex) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block with at least the specified timestamp.");
+ }
+ heightParam = pindex->nHeight;
+ }
+
+ unsigned int height = (unsigned int) heightParam;
+ unsigned int chainHeight = (unsigned int) chainActive.Height();
+ if (chainHeight < Params().PruneAfterHeight())
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Blockchain is too short for pruning.");
+ else if (height > chainHeight)
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
+ else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
+ LogPrint("rpc", "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.");
+ height = chainHeight - MIN_BLOCKS_TO_KEEP;
+ }
+
+ PruneBlockFilesManual(height);
+ return uint64_t(height);
+}
+
+UniValue gettxoutsetinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"gettxoutsetinfo\n"
"\nReturns statistics about the unspent transaction output set.\n"
@@ -704,20 +895,22 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize));
ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex()));
ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount)));
+ } else {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
}
return ret;
}
-UniValue gettxout(const UniValue& params, bool fHelp)
+UniValue gettxout(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
throw runtime_error(
- "gettxout \"txid\" n ( includemempool )\n"
+ "gettxout \"txid\" n ( include_mempool )\n"
"\nReturns details about an unspent transaction output.\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
"2. n (numeric, required) vout number\n"
- "3. includemempool (boolean, optional) Whether to include the mem pool\n"
+ "3. include_mempool (boolean, optional) Whether to include the mempool\n"
"\nResult:\n"
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
@@ -729,7 +922,7 @@ UniValue gettxout(const UniValue& params, bool fHelp)
" \"reqSigs\" : n, (numeric) Number of required signatures\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n"
" \"addresses\" : [ (array of string) array of bitcoin addresses\n"
- " \"bitcoinaddress\" (string) bitcoin address\n"
+ " \"address\" (string) bitcoin address\n"
" ,...\n"
" ]\n"
" },\n"
@@ -750,12 +943,12 @@ UniValue gettxout(const UniValue& params, bool fHelp)
UniValue ret(UniValue::VOBJ);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
- int n = params[1].get_int();
+ int n = request.params[1].get_int();
bool fMempool = true;
- if (params.size() > 2)
- fMempool = params[2].get_bool();
+ if (request.params.size() > 2)
+ fMempool = request.params[2].get_bool();
CCoins coins;
if (fMempool) {
@@ -788,17 +981,17 @@ UniValue gettxout(const UniValue& params, bool fHelp)
return ret;
}
-UniValue verifychain(const UniValue& params, bool fHelp)
+UniValue verifychain(const JSONRPCRequest& request)
{
int nCheckLevel = GetArg("-checklevel", DEFAULT_CHECKLEVEL);
int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
- if (fHelp || params.size() > 2)
+ if (request.fHelp || request.params.size() > 2)
throw runtime_error(
- "verifychain ( checklevel numblocks )\n"
+ "verifychain ( checklevel nblocks )\n"
"\nVerifies blockchain database.\n"
"\nArguments:\n"
"1. checklevel (numeric, optional, 0-4, default=" + strprintf("%d", nCheckLevel) + ") How thorough the block verification is.\n"
- "2. numblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n"
+ "2. nblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n"
"\nResult:\n"
"true|false (boolean) Verified or not\n"
"\nExamples:\n"
@@ -808,31 +1001,32 @@ UniValue verifychain(const UniValue& params, bool fHelp)
LOCK(cs_main);
- if (params.size() > 0)
- nCheckLevel = params[0].get_int();
- if (params.size() > 1)
- nCheckDepth = params[1].get_int();
+ if (request.params.size() > 0)
+ nCheckLevel = request.params[0].get_int();
+ if (request.params.size() > 1)
+ nCheckDepth = request.params[1].get_int();
return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth);
}
/** Implementation of IsSuperMajority with better feedback */
-static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams)
+static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
{
- int nFound = 0;
- CBlockIndex* pstart = pindex;
- for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++)
+ UniValue rv(UniValue::VOBJ);
+ bool activated = false;
+ switch(version)
{
- if (pstart->nVersion >= minVersion)
- ++nFound;
- pstart = pstart->pprev;
+ case 2:
+ activated = pindex->nHeight >= consensusParams.BIP34Height;
+ break;
+ case 3:
+ activated = pindex->nHeight >= consensusParams.BIP66Height;
+ break;
+ case 4:
+ activated = pindex->nHeight >= consensusParams.BIP65Height;
+ break;
}
-
- UniValue rv(UniValue::VOBJ);
- rv.push_back(Pair("status", nFound >= nRequired));
- rv.push_back(Pair("found", nFound));
- rv.push_back(Pair("required", nRequired));
- rv.push_back(Pair("window", consensusParams.nMajorityWindow));
+ rv.push_back(Pair("status", activated));
return rv;
}
@@ -841,8 +1035,7 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex*
UniValue rv(UniValue::VOBJ);
rv.push_back(Pair("id", name));
rv.push_back(Pair("version", version));
- rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)));
- rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityRejectBlockOutdated, consensusParams)));
+ rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams)));
return rv;
}
@@ -863,6 +1056,7 @@ static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Conse
}
rv.push_back(Pair("startTime", consensusParams.vDeployments[id].nStartTime));
rv.push_back(Pair("timeout", consensusParams.vDeployments[id].nTimeout));
+ rv.push_back(Pair("since", VersionBitsTipStateSinceHeight(consensusParams, id)));
return rv;
}
@@ -875,12 +1069,12 @@ void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const std::string &name,
bip9_softforks.push_back(Pair(name, BIP9SoftForkDesc(consensusParams, id)));
}
-UniValue getblockchaininfo(const UniValue& params, bool fHelp)
+UniValue getblockchaininfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getblockchaininfo\n"
- "Returns an object containing various state info regarding block chain processing.\n"
+ "Returns an object containing various state info regarding blockchain processing.\n"
"\nResult:\n"
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
@@ -892,18 +1086,14 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
" \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
" \"pruned\": xx, (boolean) if the blocks are subject to pruning\n"
- " \"pruneheight\": xxxxxx, (numeric) heighest block available\n"
+ " \"pruneheight\": xxxxxx, (numeric) lowest-height complete block stored\n"
" \"softforks\": [ (array) status of softforks in progress\n"
" {\n"
" \"id\": \"xxxx\", (string) name of softfork\n"
" \"version\": xx, (numeric) block version\n"
- " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n"
+ " \"reject\": { (object) progress toward rejecting pre-softfork blocks\n"
" \"status\": xx, (boolean) true if threshold reached\n"
- " \"found\": xx, (numeric) number of blocks with the new version found\n"
- " \"required\": xx, (numeric) number of blocks required to trigger\n"
- " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n"
" },\n"
- " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
" }, ...\n"
" ],\n"
" \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n"
@@ -911,7 +1101,8 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n"
" \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\n"
" \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
- " \"timeout\": xx (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
+ " \"timeout\": xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
+ " \"since\": xx (numeric) height of the first block to which the status applies\n"
" }\n"
" }\n"
"}\n"
@@ -929,7 +1120,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast()));
- obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip())));
+ obj.push_back(Pair("verificationprogress", GuessVerificationProgress(Params().TxData(), chainActive.Tip())));
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
obj.push_back(Pair("pruned", fPruneMode));
@@ -971,9 +1162,9 @@ struct CompareBlocksByHeight
}
};
-UniValue getchaintips(const UniValue& params, bool fHelp)
+UniValue getchaintips(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getchaintips\n"
"Return information about all known tips in the block tree,"
@@ -1087,16 +1278,16 @@ UniValue mempoolInfoToJSON()
return ret;
}
-UniValue getmempoolinfo(const UniValue& params, bool fHelp)
+UniValue getmempoolinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getmempoolinfo\n"
"\nReturns details on the active state of the TX memory pool.\n"
"\nResult:\n"
"{\n"
" \"size\": xxxxx, (numeric) Current tx count\n"
- " \"bytes\": xxxxx, (numeric) Sum of all tx sizes\n"
+ " \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\n"
" \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n"
" \"maxmempool\": xxxxx, (numeric) Maximum memory usage for the mempool\n"
" \"mempoolminfee\": xxxxx (numeric) Minimum fee for tx to be accepted\n"
@@ -1109,21 +1300,59 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp)
return mempoolInfoToJSON();
}
-UniValue invalidateblock(const UniValue& params, bool fHelp)
+UniValue preciousblock(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 1)
+ throw runtime_error(
+ "preciousblock \"blockhash\"\n"
+ "\nTreats a block as if it were received before others with the same work.\n"
+ "\nA later preciousblock call can override the effect of an earlier one.\n"
+ "\nThe effects of preciousblock are not retained across restarts.\n"
+ "\nArguments:\n"
+ "1. \"blockhash\" (string, required) the hash of the block to mark as precious\n"
+ "\nResult:\n"
+ "\nExamples:\n"
+ + HelpExampleCli("preciousblock", "\"blockhash\"")
+ + HelpExampleRpc("preciousblock", "\"blockhash\"")
+ );
+
+ std::string strHash = request.params[0].get_str();
+ uint256 hash(uint256S(strHash));
+ CBlockIndex* pblockindex;
+
+ {
+ LOCK(cs_main);
+ if (mapBlockIndex.count(hash) == 0)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+
+ pblockindex = mapBlockIndex[hash];
+ }
+
+ CValidationState state;
+ PreciousBlock(state, Params(), pblockindex);
+
+ if (!state.IsValid()) {
+ throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
+ }
+
+ return NullUniValue;
+}
+
+UniValue invalidateblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
- "invalidateblock \"hash\"\n"
+ "invalidateblock \"blockhash\"\n"
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"
"\nArguments:\n"
- "1. hash (string, required) the hash of the block to mark as invalid\n"
+ "1. \"blockhash\" (string, required) the hash of the block to mark as invalid\n"
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("invalidateblock", "\"blockhash\"")
+ HelpExampleRpc("invalidateblock", "\"blockhash\"")
);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
CValidationState state;
@@ -1147,22 +1376,22 @@ UniValue invalidateblock(const UniValue& params, bool fHelp)
return NullUniValue;
}
-UniValue reconsiderblock(const UniValue& params, bool fHelp)
+UniValue reconsiderblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
- "reconsiderblock \"hash\"\n"
+ "reconsiderblock \"blockhash\"\n"
"\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
"This can be used to undo the effects of invalidateblock.\n"
"\nArguments:\n"
- "1. hash (string, required) the hash of the block to reconsider\n"
+ "1. \"blockhash\" (string, required) the hash of the block to reconsider\n"
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("reconsiderblock", "\"blockhash\"")
+ HelpExampleRpc("reconsiderblock", "\"blockhash\"")
);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
{
@@ -1185,32 +1414,38 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
- // --------------------- ------------------------ ----------------------- ----------
- { "blockchain", "getblockchaininfo", &getblockchaininfo, true },
- { "blockchain", "getbestblockhash", &getbestblockhash, true },
- { "blockchain", "getblockcount", &getblockcount, true },
- { "blockchain", "getblock", &getblock, true },
- { "blockchain", "getblockhash", &getblockhash, true },
- { "blockchain", "getblockheader", &getblockheader, true },
- { "blockchain", "getchaintips", &getchaintips, true },
- { "blockchain", "getdifficulty", &getdifficulty, true },
- { "blockchain", "getmempoolancestors", &getmempoolancestors, true },
- { "blockchain", "getmempooldescendants", &getmempooldescendants, true },
- { "blockchain", "getmempoolentry", &getmempoolentry, true },
- { "blockchain", "getmempoolinfo", &getmempoolinfo, true },
- { "blockchain", "getrawmempool", &getrawmempool, true },
- { "blockchain", "gettxout", &gettxout, true },
- { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
- { "blockchain", "verifychain", &verifychain, true },
+{ // category name actor (function) okSafe argNames
+ // --------------------- ------------------------ ----------------------- ------ ----------
+ { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} },
+ { "blockchain", "getbestblockhash", &getbestblockhash, true, {} },
+ { "blockchain", "getblockcount", &getblockcount, true, {} },
+ { "blockchain", "getblock", &getblock, true, {"blockhash","verbose"} },
+ { "blockchain", "getblockhash", &getblockhash, true, {"height"} },
+ { "blockchain", "getblockheader", &getblockheader, true, {"blockhash","verbose"} },
+ { "blockchain", "getchaintips", &getchaintips, true, {} },
+ { "blockchain", "getdifficulty", &getdifficulty, true, {} },
+ { "blockchain", "getmempoolancestors", &getmempoolancestors, true, {"txid","verbose"} },
+ { "blockchain", "getmempooldescendants", &getmempooldescendants, true, {"txid","verbose"} },
+ { "blockchain", "getmempoolentry", &getmempoolentry, true, {"txid"} },
+ { "blockchain", "getmempoolinfo", &getmempoolinfo, true, {} },
+ { "blockchain", "getrawmempool", &getrawmempool, true, {"verbose"} },
+ { "blockchain", "gettxout", &gettxout, true, {"txid","n","include_mempool"} },
+ { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, {} },
+ { "blockchain", "pruneblockchain", &pruneblockchain, true, {"height"} },
+ { "blockchain", "verifychain", &verifychain, true, {"checklevel","nblocks"} },
+
+ { "blockchain", "preciousblock", &preciousblock, true, {"blockhash"} },
/* Not shown in help */
- { "hidden", "invalidateblock", &invalidateblock, true },
- { "hidden", "reconsiderblock", &reconsiderblock, true },
+ { "hidden", "invalidateblock", &invalidateblock, true, {"blockhash"} },
+ { "hidden", "reconsiderblock", &reconsiderblock, true, {"blockhash"} },
+ { "hidden", "waitfornewblock", &waitfornewblock, true, {"timeout"} },
+ { "hidden", "waitforblock", &waitforblock, true, {"blockhash","timeout"} },
+ { "hidden", "waitforblockheight", &waitforblockheight, true, {"height","timeout"} },
};
-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..5bdd84e555 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -20,96 +20,122 @@ class CRPCConvertParam
public:
std::string methodName; //!< method whose params want conversion
int paramIdx; //!< 0-based idx of param to convert
+ std::string paramName; //!< parameter name
};
+/**
+ * Specifiy a (method, idx, name) here if the argument is a non-string RPC
+ * argument and needs to be converted from JSON.
+ *
+ * @note Parameter indexes start from 0.
+ */
static const CRPCConvertParam vRPCConvertParams[] =
{
- { "stop", 0 },
- { "setmocktime", 0 },
- { "getaddednodeinfo", 0 },
- { "generate", 0 },
- { "generate", 1 },
- { "generatetoaddress", 0 },
- { "generatetoaddress", 2 },
- { "getnetworkhashps", 0 },
- { "getnetworkhashps", 1 },
- { "sendtoaddress", 1 },
- { "sendtoaddress", 4 },
- { "settxfee", 0 },
- { "getreceivedbyaddress", 1 },
- { "getreceivedbyaccount", 1 },
- { "listreceivedbyaddress", 0 },
- { "listreceivedbyaddress", 1 },
- { "listreceivedbyaddress", 2 },
- { "listreceivedbyaccount", 0 },
- { "listreceivedbyaccount", 1 },
- { "listreceivedbyaccount", 2 },
- { "getbalance", 1 },
- { "getbalance", 2 },
- { "getblockhash", 0 },
- { "move", 2 },
- { "move", 3 },
- { "sendfrom", 2 },
- { "sendfrom", 3 },
- { "listtransactions", 1 },
- { "listtransactions", 2 },
- { "listtransactions", 3 },
- { "listaccounts", 0 },
- { "listaccounts", 1 },
- { "walletpassphrase", 1 },
- { "getblocktemplate", 0 },
- { "listsinceblock", 1 },
- { "listsinceblock", 2 },
- { "sendmany", 1 },
- { "sendmany", 2 },
- { "sendmany", 4 },
- { "addmultisigaddress", 0 },
- { "addmultisigaddress", 1 },
- { "createmultisig", 0 },
- { "createmultisig", 1 },
- { "listunspent", 0 },
- { "listunspent", 1 },
- { "listunspent", 2 },
- { "getblock", 1 },
- { "getblockheader", 1 },
- { "gettransaction", 1 },
- { "getrawtransaction", 1 },
- { "createrawtransaction", 0 },
- { "createrawtransaction", 1 },
- { "createrawtransaction", 2 },
- { "signrawtransaction", 1 },
- { "signrawtransaction", 2 },
- { "sendrawtransaction", 1 },
- { "fundrawtransaction", 1 },
- { "gettxout", 1 },
- { "gettxout", 2 },
- { "gettxoutproof", 0 },
- { "lockunspent", 0 },
- { "lockunspent", 1 },
- { "importprivkey", 2 },
- { "importaddress", 2 },
- { "importaddress", 3 },
- { "importpubkey", 2 },
- { "verifychain", 0 },
- { "verifychain", 1 },
- { "keypoolrefill", 0 },
- { "getrawmempool", 0 },
- { "estimatefee", 0 },
- { "estimatepriority", 0 },
- { "estimatesmartfee", 0 },
- { "estimatesmartpriority", 0 },
- { "prioritisetransaction", 1 },
- { "prioritisetransaction", 2 },
- { "setban", 2 },
- { "setban", 3 },
- { "getmempoolancestors", 1 },
- { "getmempooldescendants", 1 },
+ { "setmocktime", 0, "timestamp" },
+ { "generate", 0, "nblocks" },
+ { "generate", 1, "maxtries" },
+ { "generatetoaddress", 0, "nblocks" },
+ { "generatetoaddress", 2, "maxtries" },
+ { "getnetworkhashps", 0, "nblocks" },
+ { "getnetworkhashps", 1, "height" },
+ { "sendtoaddress", 1, "amount" },
+ { "sendtoaddress", 4, "subtractfeefromamount" },
+ { "settxfee", 0, "amount" },
+ { "getreceivedbyaddress", 1, "minconf" },
+ { "getreceivedbyaccount", 1, "minconf" },
+ { "listreceivedbyaddress", 0, "minconf" },
+ { "listreceivedbyaddress", 1, "include_empty" },
+ { "listreceivedbyaddress", 2, "include_watchonly" },
+ { "listreceivedbyaccount", 0, "minconf" },
+ { "listreceivedbyaccount", 1, "include_empty" },
+ { "listreceivedbyaccount", 2, "include_watchonly" },
+ { "getbalance", 1, "minconf" },
+ { "getbalance", 2, "include_watchonly" },
+ { "getblockhash", 0, "height" },
+ { "waitforblockheight", 0, "height" },
+ { "waitforblockheight", 1, "timeout" },
+ { "waitforblock", 1, "timeout" },
+ { "waitfornewblock", 0, "timeout" },
+ { "move", 2, "amount" },
+ { "move", 3, "minconf" },
+ { "sendfrom", 2, "amount" },
+ { "sendfrom", 3, "minconf" },
+ { "listtransactions", 1, "count" },
+ { "listtransactions", 2, "skip" },
+ { "listtransactions", 3, "include_watchonly" },
+ { "listaccounts", 0, "minconf" },
+ { "listaccounts", 1, "include_watchonly" },
+ { "walletpassphrase", 1, "timeout" },
+ { "getblocktemplate", 0, "template_request" },
+ { "listsinceblock", 1, "target_confirmations" },
+ { "listsinceblock", 2, "include_watchonly" },
+ { "sendmany", 1, "amounts" },
+ { "sendmany", 2, "minconf" },
+ { "sendmany", 4, "subtractfeefrom" },
+ { "addmultisigaddress", 0, "nrequired" },
+ { "addmultisigaddress", 1, "keys" },
+ { "createmultisig", 0, "nrequired" },
+ { "createmultisig", 1, "keys" },
+ { "listunspent", 0, "minconf" },
+ { "listunspent", 1, "maxconf" },
+ { "listunspent", 2, "addresses" },
+ { "getblock", 1, "verbose" },
+ { "getblockheader", 1, "verbose" },
+ { "gettransaction", 1, "include_watchonly" },
+ { "getrawtransaction", 1, "verbose" },
+ { "createrawtransaction", 0, "transactions" },
+ { "createrawtransaction", 1, "outputs" },
+ { "createrawtransaction", 2, "locktime" },
+ { "signrawtransaction", 1, "prevtxs" },
+ { "signrawtransaction", 2, "privkeys" },
+ { "sendrawtransaction", 1, "allowhighfees" },
+ { "fundrawtransaction", 1, "options" },
+ { "gettxout", 1, "n" },
+ { "gettxout", 2, "include_mempool" },
+ { "gettxoutproof", 0, "txids" },
+ { "lockunspent", 0, "unlock" },
+ { "lockunspent", 1, "transactions" },
+ { "importprivkey", 2, "rescan" },
+ { "importaddress", 2, "rescan" },
+ { "importaddress", 3, "p2sh" },
+ { "importpubkey", 2, "rescan" },
+ { "importmulti", 0, "requests" },
+ { "importmulti", 1, "options" },
+ { "verifychain", 0, "checklevel" },
+ { "verifychain", 1, "nblocks" },
+ { "pruneblockchain", 0, "height" },
+ { "keypoolrefill", 0, "newsize" },
+ { "getrawmempool", 0, "verbose" },
+ { "estimatefee", 0, "nblocks" },
+ { "estimatepriority", 0, "nblocks" },
+ { "estimatesmartfee", 0, "nblocks" },
+ { "estimatesmartpriority", 0, "nblocks" },
+ { "prioritisetransaction", 1, "priority_delta" },
+ { "prioritisetransaction", 2, "fee_delta" },
+ { "setban", 2, "bantime" },
+ { "setban", 3, "absolute" },
+ { "setnetworkactive", 0, "state" },
+ { "getmempoolancestors", 1, "verbose" },
+ { "getmempooldescendants", 1, "verbose" },
+ { "bumpfee", 1, "options" },
+ // Echo with conversion (For testing only)
+ { "echojson", 0, "arg0" },
+ { "echojson", 1, "arg1" },
+ { "echojson", 2, "arg2" },
+ { "echojson", 3, "arg3" },
+ { "echojson", 4, "arg4" },
+ { "echojson", 5, "arg5" },
+ { "echojson", 6, "arg6" },
+ { "echojson", 7, "arg7" },
+ { "echojson", 8, "arg8" },
+ { "echojson", 9, "arg9" },
};
class CRPCConvertTable
{
private:
- std::set<std::pair<std::string, int> > members;
+ std::set<std::pair<std::string, int>> members;
+ std::set<std::pair<std::string, std::string>> membersByName;
public:
CRPCConvertTable();
@@ -117,6 +143,9 @@ public:
bool convert(const std::string& method, int idx) {
return (members.count(std::make_pair(method, idx)) > 0);
}
+ bool convert(const std::string& method, const std::string& name) {
+ return (membersByName.count(std::make_pair(method, name)) > 0);
+ }
};
CRPCConvertTable::CRPCConvertTable()
@@ -127,6 +156,8 @@ CRPCConvertTable::CRPCConvertTable()
for (unsigned int i = 0; i < n_elem; i++) {
members.insert(std::make_pair(vRPCConvertParams[i].methodName,
vRPCConvertParams[i].paramIdx));
+ membersByName.insert(std::make_pair(vRPCConvertParams[i].methodName,
+ vRPCConvertParams[i].paramName));
}
}
@@ -144,7 +175,6 @@ UniValue ParseNonRFCJSONValue(const std::string& strVal)
return jVal[0];
}
-/** Convert strings to command-specific RPC representation */
UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
{
UniValue params(UniValue::VARR);
@@ -163,3 +193,28 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s
return params;
}
+
+UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams)
+{
+ UniValue params(UniValue::VOBJ);
+
+ for (const std::string &s: strParams) {
+ size_t pos = s.find("=");
+ if (pos == std::string::npos) {
+ throw(std::runtime_error("No '=' in named argument '"+s+"', this needs to be present for every argument (even if it is empty)"));
+ }
+
+ std::string name = s.substr(0, pos);
+ std::string value = s.substr(pos+1);
+
+ if (!rpcCvtTable.convert(strMethod, name)) {
+ // insert string value directly
+ params.pushKV(name, value);
+ } else {
+ // parse string as JSON, insert bool/number/object/etc. value
+ params.pushKV(name, ParseNonRFCJSONValue(value));
+ }
+ }
+
+ return params;
+}
diff --git a/src/rpc/client.h b/src/rpc/client.h
index ae015860b6..e7cf035d8f 100644
--- a/src/rpc/client.h
+++ b/src/rpc/client.h
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,7 +8,12 @@
#include <univalue.h>
+/** Convert positional arguments to command-specific RPC representation */
UniValue RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);
+
+/** Convert named arguments to command-specific RPC representation */
+UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector<std::string>& strParams);
+
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
* as well as objects and arrays.
*/
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 4c4e599781..c594daca0d 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,7 +12,7 @@
#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
-#include "main.h"
+#include "validation.h"
#include "miner.h"
#include "net.h"
#include "pow.h"
@@ -22,6 +22,7 @@
#include "utilstrencodings.h"
#include "validationinterface.h"
+#include <memory>
#include <stdint.h>
#include <boost/assign/list_of.hpp>
@@ -73,17 +74,17 @@ UniValue GetNetworkHashPS(int lookup, int height) {
return workDiff.getdouble() / timeDiff;
}
-UniValue getnetworkhashps(const UniValue& params, bool fHelp)
+UniValue getnetworkhashps(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 2)
+ if (request.fHelp || request.params.size() > 2)
throw runtime_error(
- "getnetworkhashps ( blocks height )\n"
+ "getnetworkhashps ( nblocks height )\n"
"\nReturns the estimated network hashes per second based on the last n blocks.\n"
"Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"
"Pass in [height] to estimate the network speed at the time when a certain block was found.\n"
"\nArguments:\n"
- "1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n"
- "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n"
+ "1. nblocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n"
+ "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n"
"\nResult:\n"
"x (numeric) Hashes per second estimated\n"
"\nExamples:\n"
@@ -92,7 +93,7 @@ UniValue getnetworkhashps(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
+ return GetNetworkHashPS(request.params.size() > 0 ? request.params[0].get_int() : 120, request.params.size() > 1 ? request.params[1].get_int() : -1);
}
UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
@@ -130,8 +131,8 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
if (pblock->nNonce == nInnerLoopCount) {
continue;
}
- CValidationState state;
- if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL))
+ std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
+ if (!ProcessNewBlock(Params(), shared_pblock, true, NULL))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
@@ -145,26 +146,26 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
return blockHashes;
}
-UniValue generate(const UniValue& params, bool fHelp)
+UniValue generate(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
- "generate numblocks ( maxtries )\n"
- "\nMine up to numblocks blocks immediately (before the RPC call returns)\n"
+ "generate nblocks ( maxtries )\n"
+ "\nMine up to nblocks blocks immediately (before the RPC call returns)\n"
"\nArguments:\n"
- "1. numblocks (numeric, required) How many blocks are generated immediately.\n"
+ "1. nblocks (numeric, required) How many blocks are generated immediately.\n"
"2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
- "\nResult\n"
+ "\nResult:\n"
"[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
"\nGenerate 11 blocks\n"
+ HelpExampleCli("generate", "11")
);
- int nGenerate = params[0].get_int();
+ int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
- if (params.size() > 1) {
- nMaxTries = params[1].get_int();
+ if (request.params.size() > 1) {
+ nMaxTries = request.params[1].get_int();
}
boost::shared_ptr<CReserveScript> coinbaseScript;
@@ -181,30 +182,30 @@ UniValue generate(const UniValue& params, bool fHelp)
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true);
}
-UniValue generatetoaddress(const UniValue& params, bool fHelp)
+UniValue generatetoaddress(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
throw runtime_error(
- "generatetoaddress numblocks address (maxtries)\n"
+ "generatetoaddress nblocks address (maxtries)\n"
"\nMine blocks immediately to a specified address (before the RPC call returns)\n"
"\nArguments:\n"
- "1. numblocks (numeric, required) How many blocks are generated immediately.\n"
- "2. address (string, required) The address to send the newly generated bitcoin to.\n"
+ "1. nblocks (numeric, required) How many blocks are generated immediately.\n"
+ "2. address (string, required) The address to send the newly generated bitcoin to.\n"
"3. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
- "\nResult\n"
+ "\nResult:\n"
"[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
"\nGenerate 11 blocks to myaddress\n"
+ HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
);
- int nGenerate = params[0].get_int();
+ int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
- if (params.size() > 2) {
- nMaxTries = params[2].get_int();
+ if (request.params.size() > 2) {
+ nMaxTries = request.params[2].get_int();
}
- CBitcoinAddress address(params[1].get_str());
+ CBitcoinAddress address(request.params[1].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
@@ -214,9 +215,9 @@ UniValue generatetoaddress(const UniValue& params, bool fHelp)
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
}
-UniValue getmininginfo(const UniValue& params, bool fHelp)
+UniValue getmininginfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getmininginfo\n"
"\nReturns a json object containing mining-related information."
@@ -224,13 +225,13 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
"{\n"
" \"blocks\": nnn, (numeric) The current block\n"
" \"currentblocksize\": nnn, (numeric) The last block size\n"
- " \"currentblockcost\": nnn, (numeric) The last block cost\n"
+ " \"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"
- " \"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"
+ " \"errors\": \"...\" (string) Current errors\n"
+ " \"networkhashps\": nnn, (numeric) The network hashes per second\n"
+ " \"pooledtx\": n (numeric) The size of the mempool\n"
+ " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmininginfo", "")
@@ -243,34 +244,33 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
- obj.push_back(Pair("currentblockcost", (uint64_t)nLastBlockCost));
+ obj.push_back(Pair("currentblockweight", (uint64_t)nLastBlockWeight));
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
- obj.push_back(Pair("networkhashps", getnetworkhashps(params, false)));
+ obj.push_back(Pair("networkhashps", getnetworkhashps(request)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
- obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
return obj;
}
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
-UniValue prioritisetransaction(const UniValue& params, bool fHelp)
+UniValue prioritisetransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 3)
+ if (request.fHelp || request.params.size() != 3)
throw runtime_error(
"prioritisetransaction <txid> <priority delta> <fee delta>\n"
"Accepts the transaction into mined blocks at a higher (or lower) priority\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id.\n"
- "2. priority delta (numeric, required) The priority to add or subtract.\n"
+ "2. priority_delta (numeric, required) The priority to add or subtract.\n"
" The transaction selection algorithm considers the tx as it would have a higher priority.\n"
" (priority of a transaction is calculated: coinage * value_in_satoshis / txsize) \n"
- "3. fee delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n"
+ "3. fee_delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n"
" The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
" considers the transaction as it would have paid a higher (or lower) fee.\n"
- "\nResult\n"
+ "\nResult:\n"
"true (boolean) Returns true\n"
"\nExamples:\n"
+ HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
@@ -279,10 +279,10 @@ UniValue prioritisetransaction(const UniValue& params, bool fHelp)
LOCK(cs_main);
- uint256 hash = ParseHashStr(params[0].get_str(), "txid");
- CAmount nAmount = params[2].get_int64();
+ uint256 hash = ParseHashStr(request.params[0].get_str(), "txid");
+ CAmount nAmount = request.params[2].get_int64();
- mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount);
+ mempool.PrioritiseTransaction(hash, request.params[0].get_str(), request.params[1].get_real(), nAmount);
return true;
}
@@ -315,71 +315,77 @@ std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
return s;
}
-UniValue getblocktemplate(const UniValue& params, bool fHelp)
+UniValue getblocktemplate(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 1)
+ if (request.fHelp || request.params.size() > 1)
throw runtime_error(
- "getblocktemplate ( \"jsonrequestobject\" )\n"
+ "getblocktemplate ( TemplateRequest )\n"
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
"It returns data needed to construct a block to work on.\n"
- "For full specification, see BIPs 22 and 9:\n"
+ "For full specification, see BIPs 22, 23, 9, and 145:\n"
" https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n"
+ " https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n"
" https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
+ " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n"
"\nArguments:\n"
- "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n"
+ "1. template_request (json object, optional) A json object in the following spec\n"
" {\n"
- " \"mode\":\"template\" (string, optional) This must be set to \"template\" or omitted\n"
- " \"capabilities\":[ (array, optional) A list of strings\n"
- " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n"
+ " \"mode\":\"template\" (string, optional) This must be set to \"template\", \"proposal\" (see BIP 23), or omitted\n"
+ " \"capabilities\":[ (array, optional) A list of strings\n"
+ " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n"
" ,...\n"
- " ]\n"
+ " ],\n"
+ " \"rules\":[ (array, optional) A list of strings\n"
+ " \"support\" (string) client side supported softfork deployment\n"
+ " ,...\n"
+ " ]\n"
" }\n"
"\n"
"\nResult:\n"
"{\n"
- " \"version\" : n, (numeric) The block version\n"
+ " \"version\" : n, (numeric) The preferred block version\n"
" \"rules\" : [ \"rulename\", ... ], (array of strings) specific block rules that are to be enforced\n"
" \"vbavailable\" : { (json object) set of pending, supported versionbit (BIP 9) softfork deployments\n"
- " \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n"
+ " \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n"
" ,...\n"
" },\n"
" \"vbrequired\" : n, (numeric) bit mask of versionbits the server requires set in submissions\n"
- " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
+ " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
" {\n"
- " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n"
- " \"txid\" : \"xxxx\", (string) transaction id encoded in little-endian hexadecimal\n"
- " \"hash\" : \"xxxx\", (string) hash encoded in little-endian hexadecimal (including witness data)\n"
- " \"depends\" : [ (array) array of numbers \n"
- " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
+ " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n"
+ " \"txid\" : \"xxxx\", (string) transaction id encoded in little-endian hexadecimal\n"
+ " \"hash\" : \"xxxx\", (string) hash encoded in little-endian hexadecimal (including witness data)\n"
+ " \"depends\" : [ (array) array of numbers \n"
+ " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
" ,...\n"
" ],\n"
- " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
- " \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n"
- " \"cost\" : n, (numeric) total transaction size cost, as counted for purposes of block limits\n"
- " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n"
+ " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
+ " \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n"
+ " \"weight\" : n, (numeric) total transaction weight, as counted for purposes of block limits\n"
+ " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n"
" }\n"
" ,...\n"
" ],\n"
- " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
- " \"flags\" : \"flags\" (string) \n"
+ " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
+ " \"flags\" : \"xx\" (string) key name is to be ignored, and value included in scriptSig\n"
" },\n"
- " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
- " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
- " \"target\" : \"xxxx\", (string) The hash target\n"
- " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
- " \"mutable\" : [ (array of string) list of ways the block template may be changed \n"
- " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n"
+ " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
+ " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
+ " \"target\" : \"xxxx\", (string) The hash target\n"
+ " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
+ " \"mutable\" : [ (array of string) list of ways the block template may be changed \n"
+ " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n"
" ,...\n"
" ],\n"
- " \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n"
- " \"sigoplimit\" : n, (numeric) cost limit of sigops in blocks\n"
+ " \"noncerange\" : \"00000000ffffffff\",(string) A range of valid nonces\n"
+ " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n"
" \"sizelimit\" : n, (numeric) limit of block size\n"
- " \"costlimit\" : n, (numeric) limit of block cost\n"
+ " \"weightlimit\" : n, (numeric) limit of block weight\n"
" \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
- " \"bits\" : \"xxx\", (string) compressed target of next block\n"
+ " \"bits\" : \"xxxxxxxx\", (string) compressed target of next block\n"
" \"height\" : n (numeric) The height of the next block\n"
"}\n"
@@ -394,9 +400,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
UniValue lpval = NullUniValue;
std::set<std::string> setClientRules;
int64_t nMaxVersionPreVB = -1;
- if (params.size() > 0)
+ if (request.params.size() > 0)
{
- const UniValue& oparam = params[0].get_obj();
+ const UniValue& oparam = request.params[0].get_obj();
const UniValue& modeval = find_value(oparam, "mode");
if (modeval.isStr())
strMode = modeval.get_str();
@@ -456,7 +462,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())
@@ -513,12 +522,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
// Update block
static CBlockIndex* pindexPrev;
static int64_t nStart;
- static CBlockTemplate* pblocktemplate;
+ static std::unique_ptr<CBlockTemplate> pblocktemplate;
if (pindexPrev != chainActive.Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
- pindexPrev = NULL;
+ pindexPrev = nullptr;
// Store the pindexBest used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
@@ -526,11 +535,6 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
nStart = GetTime();
// Create new block
- if(pblocktemplate)
- {
- delete pblocktemplate;
- pblocktemplate = NULL;
- }
CScript scriptDummy = CScript() << OP_TRUE;
pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy);
if (!pblocktemplate)
@@ -546,12 +550,16 @@ 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);
map<uint256, int64_t> setTxIndex;
int i = 0;
- BOOST_FOREACH (CTransaction& tx, pblock->vtx) {
+ for (const auto& it : pblock->vtx) {
+ const CTransaction& tx = *it;
uint256 txHash = tx.GetHash();
setTxIndex[txHash] = i++;
@@ -574,8 +582,13 @@ 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]));
- entry.push_back(Pair("cost", GetTransactionCost(tx)));
+ 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);
}
@@ -595,8 +608,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
UniValue aRules(UniValue::VARR);
UniValue vbavailable(UniValue::VOBJ);
- for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) {
- Consensus::DeploymentPos pos = Consensus::DeploymentPos(i);
+ for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
+ Consensus::DeploymentPos pos = Consensus::DeploymentPos(j);
ThresholdState state = VersionBitsState(pindexPrev, consensusParams, pos, versionbitscache);
switch (state) {
case THRESHOLD_DEFINED:
@@ -642,7 +655,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");
@@ -651,19 +664,26 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
result.push_back(Pair("transactions", transactions));
result.push_back(Pair("coinbaseaux", aux));
- result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
+ result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue));
result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)));
result.push_back(Pair("target", hashTarget.GetHex()));
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("costlimit", (int64_t)MAX_BLOCK_COST));
+ result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT));
result.push_back(Pair("curtime", pblock->GetBlockTime()));
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
- if (!pblocktemplate->vchCoinbaseCommitment.empty()) {
+
+ const struct BIP9DeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT];
+ if (!pblocktemplate->vchCoinbaseCommitment.empty() && setClientRules.find(segwit_info.name) != setClientRules.end()) {
result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end())));
}
@@ -677,7 +697,7 @@ public:
bool found;
CValidationState state;
- submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {};
+ submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
protected:
virtual void BlockChecked(const CBlock& block, const CValidationState& stateIn) {
@@ -685,12 +705,12 @@ protected:
return;
found = true;
state = stateIn;
- };
+ }
};
-UniValue submitblock(const UniValue& params, bool fHelp)
+UniValue submitblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"submitblock \"hexdata\" ( \"jsonparametersobject\" )\n"
"\nAttempts to submit new block to network.\n"
@@ -698,8 +718,8 @@ UniValue submitblock(const UniValue& params, bool fHelp)
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n"
"\nArguments\n"
- "1. \"hexdata\" (string, required) the hex-encoded block data to submit\n"
- "2. \"jsonparametersobject\" (string, optional) object of optional parameters\n"
+ "1. \"hexdata\" (string, required) the hex-encoded block data to submit\n"
+ "2. \"parameters\" (string, optional) object of optional parameters\n"
" {\n"
" \"workid\" : \"id\" (string, optional) if the server provided a workid, it MUST be included with submissions\n"
" }\n"
@@ -709,8 +729,9 @@ UniValue submitblock(const UniValue& params, bool fHelp)
+ HelpExampleRpc("submitblock", "\"mydata\"")
);
- CBlock block;
- if (!DecodeHexBlk(block, params[0].get_str()))
+ std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
+ CBlock& block = *blockptr;
+ if (!DecodeHexBlk(block, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
uint256 hash = block.GetHash();
@@ -737,10 +758,9 @@ 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(Params(), blockptr, true, NULL);
UnregisterValidationInterface(&sc);
if (fBlockPresent)
{
@@ -748,36 +768,35 @@ UniValue submitblock(const UniValue& params, bool fHelp)
return "duplicate-inconclusive";
return "duplicate";
}
- if (fAccepted)
- {
- if (!sc.found)
- return "inconclusive";
- state = sc.state;
- }
- return BIP22ValidationResult(state);
+ if (!sc.found)
+ return "inconclusive";
+ return BIP22ValidationResult(sc.state);
}
-UniValue estimatefee(const UniValue& params, bool fHelp)
+UniValue estimatefee(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatefee nblocks\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
- "confirmation within nblocks blocks.\n"
+ "confirmation within nblocks blocks. Uses virtual transaction size of transaction\n"
+ "as defined in BIP 141 (witness data is discounted).\n"
"\nArguments:\n"
- "1. nblocks (numeric)\n"
+ "1. nblocks (numeric, required)\n"
"\nResult:\n"
"n (numeric) estimated fee-per-kilobyte\n"
"\n"
"A negative value is returned if not enough transactions and blocks\n"
"have been observed to make an estimate.\n"
+ "-1 is always returned for nblocks == 1 as it is impossible to calculate\n"
+ "a fee that is high enough to get reliably included in the next block.\n"
"\nExample:\n"
+ HelpExampleCli("estimatefee", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
- int nBlocks = params[0].get_int();
+ int nBlocks = request.params[0].get_int();
if (nBlocks < 1)
nBlocks = 1;
@@ -788,15 +807,15 @@ UniValue estimatefee(const UniValue& params, bool fHelp)
return ValueFromAmount(feeRate.GetFeePerK());
}
-UniValue estimatepriority(const UniValue& params, bool fHelp)
+UniValue estimatepriority(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatepriority nblocks\n"
- "\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
+ "\nDEPRECATED. Estimates the approximate priority a zero-fee transaction needs to begin\n"
"confirmation within nblocks blocks.\n"
"\nArguments:\n"
- "1. nblocks (numeric)\n"
+ "1. nblocks (numeric, required)\n"
"\nResult:\n"
"n (numeric) estimated priority\n"
"\n"
@@ -806,24 +825,25 @@ UniValue estimatepriority(const UniValue& params, bool fHelp)
+ HelpExampleCli("estimatepriority", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
- int nBlocks = params[0].get_int();
+ int nBlocks = request.params[0].get_int();
if (nBlocks < 1)
nBlocks = 1;
return mempool.estimatePriority(nBlocks);
}
-UniValue estimatesmartfee(const UniValue& params, bool fHelp)
+UniValue estimatesmartfee(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatesmartfee nblocks\n"
"\nWARNING: This interface is unstable and may disappear or change!\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
"confirmation within nblocks blocks if possible and return the number of blocks\n"
- "for which the estimate is valid.\n"
+ "for which the estimate is valid. Uses virtual transaction size as defined\n"
+ "in BIP 141 (witness data is discounted).\n"
"\nArguments:\n"
"1. nblocks (numeric)\n"
"\nResult:\n"
@@ -839,9 +859,9 @@ UniValue estimatesmartfee(const UniValue& params, bool fHelp)
+ HelpExampleCli("estimatesmartfee", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
- int nBlocks = params[0].get_int();
+ int nBlocks = request.params[0].get_int();
UniValue result(UniValue::VOBJ);
int answerFound;
@@ -851,17 +871,17 @@ UniValue estimatesmartfee(const UniValue& params, bool fHelp)
return result;
}
-UniValue estimatesmartpriority(const UniValue& params, bool fHelp)
+UniValue estimatesmartpriority(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatesmartpriority nblocks\n"
- "\nWARNING: This interface is unstable and may disappear or change!\n"
+ "\nDEPRECATED. WARNING: This interface is unstable and may disappear or change!\n"
"\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
"confirmation within nblocks blocks if possible and return the number of blocks\n"
"for which the estimate is valid.\n"
"\nArguments:\n"
- "1. nblocks (numeric)\n"
+ "1. nblocks (numeric, required)\n"
"\nResult:\n"
"{\n"
" \"priority\" : x.x, (numeric) estimated priority\n"
@@ -875,9 +895,9 @@ UniValue estimatesmartpriority(const UniValue& params, bool fHelp)
+ HelpExampleCli("estimatesmartpriority", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
- int nBlocks = params[0].get_int();
+ int nBlocks = request.params[0].get_int();
UniValue result(UniValue::VOBJ);
int answerFound;
@@ -890,23 +910,23 @@ UniValue estimatesmartpriority(const UniValue& params, bool fHelp)
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
- { "mining", "getnetworkhashps", &getnetworkhashps, true },
- { "mining", "getmininginfo", &getmininginfo, true },
- { "mining", "prioritisetransaction", &prioritisetransaction, true },
- { "mining", "getblocktemplate", &getblocktemplate, true },
- { "mining", "submitblock", &submitblock, true },
-
- { "generating", "generate", &generate, true },
- { "generating", "generatetoaddress", &generatetoaddress, true },
-
- { "util", "estimatefee", &estimatefee, true },
- { "util", "estimatepriority", &estimatepriority, true },
- { "util", "estimatesmartfee", &estimatesmartfee, true },
- { "util", "estimatesmartpriority", &estimatesmartpriority, true },
+ { "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} },
+ { "mining", "getmininginfo", &getmininginfo, true, {} },
+ { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","priority_delta","fee_delta"} },
+ { "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} },
+ { "mining", "submitblock", &submitblock, true, {"hexdata","parameters"} },
+
+ { "generating", "generate", &generate, true, {"nblocks","maxtries"} },
+ { "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
+
+ { "util", "estimatefee", &estimatefee, true, {"nblocks"} },
+ { "util", "estimatepriority", &estimatepriority, true, {"nblocks"} },
+ { "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks"} },
+ { "util", "estimatesmartpriority", &estimatesmartpriority, true, {"nblocks"} },
};
-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..480c45516c 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -1,12 +1,12 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
#include "clientversion.h"
#include "init.h"
-#include "main.h"
+#include "validation.h"
#include "net.h"
#include "netbase.h"
#include "rpc/server.h"
@@ -39,12 +39,12 @@ using namespace std;
*
* Or alternatively, create a specific query method for the information.
**/
-UniValue getinfo(const UniValue& params, bool fHelp)
+UniValue getinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getinfo\n"
- "Returns an object containing various state info.\n"
+ "\nDEPRECATED. Returns an object containing various state info.\n"
"\nResult:\n"
"{\n"
" \"version\": xxxxx, (numeric) the server version\n"
@@ -57,7 +57,7 @@ UniValue getinfo(const UniValue& params, bool fHelp)
" \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
" \"testnet\": true|false, (boolean) if the server is using testnet or not\n"
- " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
+ " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\n"
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
" \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n"
@@ -89,10 +89,11 @@ 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()));
+ obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET));
#ifdef ENABLE_WALLET
if (pwalletMain) {
obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
@@ -147,18 +148,18 @@ public:
};
#endif
-UniValue validateaddress(const UniValue& params, bool fHelp)
+UniValue validateaddress(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
- "validateaddress \"bitcoinaddress\"\n"
+ "validateaddress \"address\"\n"
"\nReturn information about the given bitcoin address.\n"
"\nArguments:\n"
- "1. \"bitcoinaddress\" (string, required) The bitcoin address to validate\n"
+ "1. \"address\" (string, required) The bitcoin address to validate\n"
"\nResult:\n"
"{\n"
" \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
- " \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n"
+ " \"address\" : \"address\", (string) The bitcoin address validated\n"
" \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
" \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
@@ -180,7 +181,7 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
LOCK(cs_main);
#endif
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
bool isValid = address.IsValid();
UniValue ret(UniValue::VOBJ);
@@ -277,9 +278,9 @@ CScript _createmultisig_redeemScript(const UniValue& params)
return result;
}
-UniValue createmultisig(const UniValue& params, bool fHelp)
+UniValue createmultisig(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 2)
{
string msg = "createmultisig nrequired [\"key\",...]\n"
"\nCreates a multi-signature address with n signature of m keys required.\n"
@@ -309,7 +310,7 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
}
// Construct using pay-to-script-hash:
- CScript inner = _createmultisig_redeemScript(params);
+ CScript inner = _createmultisig_redeemScript(request.params);
CScriptID innerID(inner);
CBitcoinAddress address(innerID);
@@ -320,51 +321,14 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
return result;
}
-UniValue createwitnessaddress(const UniValue& params, bool fHelp)
+UniValue verifymessage(const JSONRPCRequest& request)
{
- 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)
+ if (request.fHelp || request.params.size() != 3)
throw runtime_error(
- "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
+ "verifymessage \"address\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
"\nArguments:\n"
- "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the signature.\n"
+ "1. \"address\" (string, required) The bitcoin address to use for the signature.\n"
"2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
"3. \"message\" (string, required) The message that was signed.\n"
"\nResult:\n"
@@ -382,9 +346,9 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
LOCK(cs_main);
- string strAddress = params[0].get_str();
- string strSign = params[1].get_str();
- string strMessage = params[2].get_str();
+ string strAddress = request.params[0].get_str();
+ string strSign = request.params[1].get_str();
+ string strMessage = request.params[2].get_str();
CBitcoinAddress addr(strAddress);
if (!addr.IsValid())
@@ -411,9 +375,9 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
return (pubkey.GetID() == keyID);
}
-UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
+UniValue signmessagewithprivkey(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 2)
+ if (request.fHelp || request.params.size() != 2)
throw runtime_error(
"signmessagewithprivkey \"privkey\" \"message\"\n"
"\nSign a message with the private key of an address\n"
@@ -431,8 +395,8 @@ UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
+ HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
);
- string strPrivkey = params[0].get_str();
- string strMessage = params[1].get_str();
+ string strPrivkey = request.params[0].get_str();
+ string strMessage = request.params[1].get_str();
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strPrivkey);
@@ -453,9 +417,9 @@ UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
return EncodeBase64(&vchSig[0], vchSig.size());
}
-UniValue setmocktime(const UniValue& params, bool fHelp)
+UniValue setmocktime(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"setmocktime timestamp\n"
"\nSet the local time to given timestamp (-regtest only)\n"
@@ -467,39 +431,92 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
if (!Params().MineBlocksOnDemand())
throw runtime_error("setmocktime for regression testing (-regtest mode) only");
- // cs_vNodes is locked and node send/receive times are updated
- // 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);
-
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
- SetMockTime(params[0].get_int64());
+ // For now, don't change mocktime if we're in the middle of validation, as
+ // this could have an effect on mempool time-based eviction, as well as
+ // IsCurrentForFeeEstimation() and IsInitialBlockDownload().
+ // TODO: figure out the right way to synchronize around mocktime, and
+ // ensure all callsites of GetTime() are accessing this safely.
+ LOCK(cs_main);
- uint64_t t = GetTime();
- BOOST_FOREACH(CNode* pnode, vNodes) {
- pnode->nLastSend = pnode->nLastRecv = t;
- }
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
+ SetMockTime(request.params[0].get_int64());
return NullUniValue;
}
+static UniValue RPCLockedMemoryInfo()
+{
+ LockedPool::Stats stats = LockedPoolManager::Instance().stats();
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("used", uint64_t(stats.used)));
+ obj.push_back(Pair("free", uint64_t(stats.free)));
+ obj.push_back(Pair("total", uint64_t(stats.total)));
+ obj.push_back(Pair("locked", uint64_t(stats.locked)));
+ obj.push_back(Pair("chunks_used", uint64_t(stats.chunks_used)));
+ obj.push_back(Pair("chunks_free", uint64_t(stats.chunks_free)));
+ return obj;
+}
+
+UniValue getmemoryinfo(const JSONRPCRequest& request)
+{
+ /* Please, avoid using the word "pool" here in the RPC interface or help,
+ * as users will undoubtedly confuse it with the other "memory pool"
+ */
+ if (request.fHelp || request.params.size() != 0)
+ throw runtime_error(
+ "getmemoryinfo\n"
+ "Returns an object containing information about memory usage.\n"
+ "\nResult:\n"
+ "{\n"
+ " \"locked\": { (json object) Information about locked memory manager\n"
+ " \"used\": xxxxx, (numeric) Number of bytes used\n"
+ " \"free\": xxxxx, (numeric) Number of bytes available in current arenas\n"
+ " \"total\": xxxxxxx, (numeric) Total number of bytes managed\n"
+ " \"locked\": xxxxxx, (numeric) Amount of bytes that succeeded locking. If this number is smaller than total, locking pages failed at some point and key data could be swapped to disk.\n"
+ " \"chunks_used\": xxxxx, (numeric) Number allocated chunks\n"
+ " \"chunks_free\": xxxxx, (numeric) Number unused chunks\n"
+ " }\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getmemoryinfo", "")
+ + HelpExampleRpc("getmemoryinfo", "")
+ );
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("locked", RPCLockedMemoryInfo()));
+ return obj;
+}
+
+UniValue echo(const JSONRPCRequest& request)
+{
+ if (request.fHelp)
+ throw runtime_error(
+ "echo|echojson \"message\" ...\n"
+ "\nSimply echo back the input arguments. This command is for testing.\n"
+ "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in"
+ "bitcoin-cli and the GUI. There is no server-side difference."
+ );
+
+ return request.params;
+}
+
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
- { "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 },
+ { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */
+ { "control", "getmemoryinfo", &getmemoryinfo, true, {} },
+ { "util", "validateaddress", &validateaddress, true, {"address"} }, /* uses wallet if enabled */
+ { "util", "createmultisig", &createmultisig, true, {"nrequired","keys"} },
+ { "util", "verifymessage", &verifymessage, true, {"address","signature","message"} },
+ { "util", "signmessagewithprivkey", &signmessagewithprivkey, true, {"privkey","message"} },
/* Not shown in help */
- { "hidden", "setmocktime", &setmocktime, true },
+ { "hidden", "setmocktime", &setmocktime, true, {"timestamp"}},
+ { "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
};
-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..f590db5efa 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,9 +6,11 @@
#include "chainparams.h"
#include "clientversion.h"
-#include "main.h"
+#include "validation.h"
#include "net.h"
+#include "net_processing.h"
#include "netbase.h"
+#include "policy/policy.h"
#include "protocol.h"
#include "sync.h"
#include "timedata.h"
@@ -23,9 +25,9 @@
using namespace std;
-UniValue getconnectioncount(const UniValue& params, bool fHelp)
+UniValue getconnectioncount(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getconnectioncount\n"
"\nReturns the number of connections to other nodes.\n"
@@ -36,14 +38,15 @@ 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)
+UniValue ping(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"ping\n"
"\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
@@ -54,32 +57,19 @@ 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)
+UniValue getpeerinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getpeerinfo\n"
"\nReturns data about each connected network node as a json array of objects.\n"
@@ -103,6 +93,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
" \"version\": v, (numeric) The peer version, such as 7001\n"
" \"subver\": \"/Satoshi:0.8.5/\", (string) The string version\n"
" \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
+ " \"addnode\": true|false, (boolean) Whether connection was due to addnode and is using an addnode slot\n"
" \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
" \"banscore\": n, (numeric) The ban score\n"
" \"synced_headers\": n, (numeric) The last header we have in common with this peer\n"
@@ -110,13 +101,14 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
" \"inflight\": [\n"
" n, (numeric) The heights of blocks we're currently asking from this peer\n"
" ...\n"
- " ]\n"
+ " ],\n"
+ " \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n"
" \"bytessent_per_msg\": {\n"
- " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
+ " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
" ...\n"
- " }\n"
+ " },\n"
" \"bytesrecv_per_msg\": {\n"
- " \"addr\": n, (numeric) The total bytes received aggregated by message type\n"
+ " \"addr\": n, (numeric) The total bytes received aggregated by message type\n"
" ...\n"
" }\n"
" }\n"
@@ -127,10 +119,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);
@@ -152,16 +145,17 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("timeoffset", stats.nTimeOffset));
if (stats.dPingTime > 0.0)
obj.push_back(Pair("pingtime", stats.dPingTime));
- if (stats.dPingMin < std::numeric_limits<int64_t>::max()/1e6)
- obj.push_back(Pair("minping", stats.dPingMin));
+ if (stats.dMinPing < std::numeric_limits<int64_t>::max()/1e6)
+ obj.push_back(Pair("minping", stats.dMinPing));
if (stats.dPingWait > 0.0)
obj.push_back(Pair("pingwait", stats.dPingWait));
obj.push_back(Pair("version", stats.nVersion));
// Use the sanitized form of subver here, to avoid tricksy remote peers from
- // corrupting or modifiying the JSON output by putting special characters in
+ // corrupting or modifying the JSON output by putting special characters in
// their ver message.
obj.push_back(Pair("subver", stats.cleanSubVer));
obj.push_back(Pair("inbound", stats.fInbound));
+ obj.push_back(Pair("addnode", stats.fAddnode));
obj.push_back(Pair("startingheight", stats.nStartingHeight));
if (fStateStats) {
obj.push_back(Pair("banscore", statestats.nMisbehavior));
@@ -195,12 +189,12 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
return ret;
}
-UniValue addnode(const UniValue& params, bool fHelp)
+UniValue addnode(const JSONRPCRequest& request)
{
string strCommand;
- if (params.size() == 2)
- strCommand = params[1].get_str();
- if (fHelp || params.size() != 2 ||
+ if (request.params.size() == 2)
+ strCommand = request.params[1].get_str();
+ if (request.fHelp || request.params.size() != 2 ||
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
throw runtime_error(
"addnode \"node\" \"add|remove|onetry\"\n"
@@ -214,40 +208,35 @@ UniValue addnode(const UniValue& params, bool fHelp)
+ HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")
);
- string strNode = params[0].get_str();
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
+ string strNode = request.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;
}
-UniValue disconnectnode(const UniValue& params, bool fHelp)
+UniValue disconnectnode(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"disconnectnode \"node\" \n"
"\nImmediately disconnects from the specified node.\n"
@@ -258,25 +247,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(request.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)
+UniValue getaddednodeinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.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 +286,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");
+
+ std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
- if (params.size() == 2) {
+ if (request.params.size() == 1) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
- if (info.strAddedNode == params[1].get_str()) {
+ if (info.strAddedNode == request.params[0].get_str()) {
vInfo.assign(1, info);
found = true;
break;
@@ -333,9 +325,9 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
return ret;
}
-UniValue getnettotals(const UniValue& params, bool fHelp)
+UniValue getnettotals(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 0)
+ if (request.fHelp || request.params.size() > 0)
throw runtime_error(
"getnettotals\n"
"\nReturns information about network traffic, including bytes in, bytes out,\n"
@@ -344,7 +336,7 @@ UniValue getnettotals(const UniValue& params, bool fHelp)
"{\n"
" \"totalbytesrecv\": n, (numeric) Total bytes received\n"
" \"totalbytessent\": n, (numeric) Total bytes sent\n"
- " \"timemillis\": t, (numeric) Total cpu time\n"
+ " \"timemillis\": t, (numeric) Current UNIX time in milliseconds\n"
" \"uploadtarget\":\n"
" {\n"
" \"timeframe\": n, (numeric) Length of the measuring timeframe in seconds\n"
@@ -359,19 +351,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;
}
@@ -397,9 +391,9 @@ static UniValue GetNetworksInfo()
return networks;
}
-UniValue getnetworkinfo(const UniValue& params, bool fHelp)
+UniValue getnetworkinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getnetworkinfo\n"
"Returns an object containing various state info regarding P2P networking.\n"
@@ -412,16 +406,19 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
" \"localrelay\": true|false, (bool) true if transaction relay is requested from peers\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
+ " \"networkactive\": true|false, (bool) whether p2p networking is enabled\n"
" \"networks\": [ (array) information per network\n"
" {\n"
" \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n"
" \"limited\": true|false, (boolean) is the network limited using -onlynet?\n"
" \"reachable\": true|false, (boolean) is the network reachable?\n"
" \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n"
+ " \"proxy_randomize_credentials\": true|false, (string) Whether randomized credentials are used\n"
" }\n"
" ,...\n"
" ],\n"
" \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
+ " \"incrementalfee\": x.xxxxxxxx, (numeric) minimum fee increment for mempool limiting or BIP 125 replacement in " + CURRENCY_UNIT + "/kB\n"
" \"localaddresses\": [ (array) list of local addresses\n"
" {\n"
" \"address\": \"xxxx\", (string) network address\n"
@@ -430,7 +427,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
" }\n"
" ,...\n"
" ]\n"
- " \"warnings\": \"...\" (string) any network warnings (such as alert messages) \n"
+ " \"warnings\": \"...\" (string) any network warnings\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getnetworkinfo", "")
@@ -438,17 +435,21 @@ 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("networkactive", g_connman->GetNetworkActive()));
+ 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())));
+ obj.push_back(Pair("incrementalfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK())));
UniValue localAddresses(UniValue::VARR);
{
LOCK(cs_mapLocalHost);
@@ -466,68 +467,73 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
return obj;
}
-UniValue setban(const UniValue& params, bool fHelp)
+UniValue setban(const JSONRPCRequest& request)
{
string strCommand;
- if (params.size() >= 2)
- strCommand = params[1].get_str();
- if (fHelp || params.size() < 2 ||
+ if (request.params.size() >= 2)
+ strCommand = request.params[1].get_str();
+ if (request.fHelp || request.params.size() < 2 ||
(strCommand != "add" && strCommand != "remove"))
throw runtime_error(
- "setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n"
+ "setban \"subnet\" \"add|remove\" (bantime) (absolute)\n"
"\nAttempts add or remove a IP/Subnet from the banned list.\n"
"\nArguments:\n"
- "1. \"ip(/netmask)\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n"
+ "1. \"subnet\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n"
"2. \"command\" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list\n"
"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"
"4. \"absolute\" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
"\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;
bool isSubnet = false;
- if (params[0].get_str().find("/") != string::npos)
+ if (request.params[0].get_str().find("/") != string::npos)
isSubnet = true;
- if (!isSubnet)
- netAddr = CNetAddr(params[0].get_str());
+ if (!isSubnet) {
+ CNetAddr resolved;
+ LookupHost(request.params[0].get_str().c_str(), resolved, false);
+ netAddr = resolved;
+ }
else
- subNet = CSubNet(params[0].get_str());
+ LookupSubNet(request.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
- if (params.size() >= 3 && !params[2].isNull())
- banTime = params[2].get_int64();
+ if (request.params.size() >= 3 && !request.params[2].isNull())
+ banTime = request.params[2].get_int64();
bool absolute = false;
- if (params.size() == 4 && params[3].isTrue())
+ if (request.params.size() == 4 && request.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;
}
-UniValue listbanned(const UniValue& params, bool fHelp)
+UniValue listbanned(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"listbanned\n"
"\nList all banned IPs/Subnets.\n"
@@ -536,8 +542,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++)
@@ -555,9 +564,9 @@ UniValue listbanned(const UniValue& params, bool fHelp)
return bannedAddresses;
}
-UniValue clearbanned(const UniValue& params, bool fHelp)
+UniValue clearbanned(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"clearbanned\n"
"\nClear all banned IPs.\n"
@@ -565,30 +574,53 @@ 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;
}
+UniValue setnetworkactive(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 1) {
+ throw runtime_error(
+ "setnetworkactive true|false\n"
+ "\nDisable/enable all p2p network activity.\n"
+ "\nArguments:\n"
+ "1. \"state\" (boolean, required) true to enable networking, false to disable\n"
+ );
+ }
+
+ if (!g_connman) {
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ }
+
+ g_connman->SetNetworkActive(request.params[0].get_bool());
+
+ return g_connman->GetNetworkActive();
+}
+
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
- { "network", "getconnectioncount", &getconnectioncount, true },
- { "network", "ping", &ping, true },
- { "network", "getpeerinfo", &getpeerinfo, true },
- { "network", "addnode", &addnode, true },
- { "network", "disconnectnode", &disconnectnode, true },
- { "network", "getaddednodeinfo", &getaddednodeinfo, true },
- { "network", "getnettotals", &getnettotals, true },
- { "network", "getnetworkinfo", &getnetworkinfo, true },
- { "network", "setban", &setban, true },
- { "network", "listbanned", &listbanned, true },
- { "network", "clearbanned", &clearbanned, true },
+ { "network", "getconnectioncount", &getconnectioncount, true, {} },
+ { "network", "ping", &ping, true, {} },
+ { "network", "getpeerinfo", &getpeerinfo, true, {} },
+ { "network", "addnode", &addnode, true, {"node","command"} },
+ { "network", "disconnectnode", &disconnectnode, true, {"node"} },
+ { "network", "getaddednodeinfo", &getaddednodeinfo, true, {"node"} },
+ { "network", "getnettotals", &getnettotals, true, {} },
+ { "network", "getnetworkinfo", &getnetworkinfo, true, {} },
+ { "network", "setban", &setban, true, {"subnet", "command", "bantime", "absolute"} },
+ { "network", "listbanned", &listbanned, true, {} },
+ { "network", "clearbanned", &clearbanned, true, {} },
+ { "network", "setnetworkactive", &setnetworkactive, true, {"state"} },
};
-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.cpp b/src/rpc/protocol.cpp
index f5275062a2..dc710d939f 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -26,13 +26,13 @@ using namespace std;
* 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
*/
-string JSONRPCRequest(const string& strMethod, const UniValue& params, const UniValue& id)
+UniValue JSONRPCRequestObj(const string& strMethod, const UniValue& params, const UniValue& id)
{
UniValue request(UniValue::VOBJ);
request.push_back(Pair("method", strMethod));
request.push_back(Pair("params", params));
request.push_back(Pair("id", id));
- return request.write() + "\n";
+ return request;
}
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
@@ -77,9 +77,10 @@ boost::filesystem::path GetAuthCookieFile()
bool GenerateAuthCookie(std::string *cookie_out)
{
- unsigned char rand_pwd[32];
- GetRandBytes(rand_pwd, 32);
- std::string cookie = COOKIEAUTH_USER + ":" + EncodeBase64(&rand_pwd[0],32);
+ const size_t COOKIE_SIZE = 32;
+ unsigned char rand_pwd[COOKIE_SIZE];
+ GetRandBytes(rand_pwd, COOKIE_SIZE);
+ std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd, rand_pwd+COOKIE_SIZE);
/** the umask determines what permissions are used to create this file -
* these are set to 077 in init.cpp unless overridden with -sysperms.
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 55d0aac68b..47e56e712b 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -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,26 +57,27 @@ 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);
+UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id);
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
UniValue JSONRPCError(int code, const std::string& message);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 3270cd384f..21396ebb09 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,7 +10,7 @@
#include "core_io.h"
#include "init.h"
#include "keystore.h"
-#include "main.h"
+#include "validation.h"
#include "merkleblock.h"
#include "net.h"
#include "policy/policy.h"
@@ -82,16 +82,13 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
in.push_back(Pair("scriptSig", o));
}
- if (!tx.wit.IsNull()) {
- if (!tx.wit.vtxinwit[i].IsNull()) {
+ if (tx.HasWitness()) {
UniValue txinwitness(UniValue::VARR);
- for (unsigned int j = 0; j < tx.wit.vtxinwit[i].scriptWitness.stack.size(); j++) {
- std::vector<unsigned char> item = tx.wit.vtxinwit[i].scriptWitness.stack[j];
+ for (unsigned int j = 0; j < tx.vin[i].scriptWitness.stack.size(); j++) {
+ std::vector<unsigned char> item = tx.vin[i].scriptWitness.stack[j];
txinwitness.push_back(HexStr(item.begin(), item.end()));
}
in.push_back(Pair("txinwitness", txinwitness));
- }
-
}
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
vin.push_back(in);
@@ -126,26 +123,28 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
}
}
-UniValue getrawtransaction(const UniValue& params, bool fHelp)
+UniValue getrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"getrawtransaction \"txid\" ( verbose )\n"
- "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n"
- "or there is an unspent output in the utxo for this transaction. To make it always work,\n"
- "you need to maintain a transaction index, using the -txindex command line option.\n"
+
+ "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n"
+ "enabled, it also works for blockchain transactions.\n"
+ "DEPRECATED: for now, it also works for transactions with unspent outputs.\n"
+
"\nReturn the raw transaction data.\n"
- "\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n"
- "If verbose is non-zero, returns an Object with information about 'txid'.\n"
+ "\nIf verbose is 'true', returns an Object with information about 'txid'.\n"
+ "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
- "2. verbose (numeric, optional, default=0) If 0, return a string, other return a json object\n"
+ "2. verbose (bool, optional, default=false) If true, return a string, other return a json object\n"
- "\nResult (if verbose is not set or set to 0):\n"
+ "\nResult (if verbose is not set or set to false):\n"
"\"data\" (string) The serialized, hex-encoded data for 'txid'\n"
- "\nResult (if verbose > 0):\n"
+ "\nResult (if verbose is set to true):\n"
"{\n"
" \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n"
" \"txid\" : \"id\", (string) The transaction id (same as provided)\n"
@@ -177,7 +176,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
" \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
- " \"bitcoinaddress\" (string) bitcoin address\n"
+ " \"address\" (string) bitcoin address\n"
" ,...\n"
" ]\n"
" }\n"
@@ -192,37 +191,53 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
"\nExamples:\n"
+ HelpExampleCli("getrawtransaction", "\"mytxid\"")
- + HelpExampleCli("getrawtransaction", "\"mytxid\" 1")
- + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
+ + HelpExampleCli("getrawtransaction", "\"mytxid\" true")
+ + HelpExampleRpc("getrawtransaction", "\"mytxid\", true")
);
LOCK(cs_main);
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
+ // Accept either a bool (true) or a num (>=1) to indicate verbose output.
bool fVerbose = false;
- if (params.size() > 1)
- fVerbose = (params[1].get_int() != 0);
+ if (request.params.size() > 1) {
+ if (request.params[1].isNum()) {
+ if (request.params[1].get_int() != 0) {
+ fVerbose = true;
+ }
+ }
+ else if(request.params[1].isBool()) {
+ if(request.params[1].isTrue()) {
+ fVerbose = true;
+ }
+ }
+ else {
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid type provided. Verbose parameter must be a boolean.");
+ }
+ }
- CTransaction tx;
+ CTransactionRef tx;
uint256 hashBlock;
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string(fTxIndex ? "No such mempool or blockchain transaction"
+ : "No such mempool transaction. Use -txindex to enable blockchain transaction queries") +
+ ". Use gettransaction for wallet transactions.");
- string strHex = EncodeHexTx(tx);
+ string strHex = EncodeHexTx(*tx, RPCSerializationFlags());
if (!fVerbose)
return strHex;
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", strHex));
- TxToJSON(tx, hashBlock, result);
+ TxToJSON(*tx, hashBlock, result);
return result;
}
-UniValue gettxoutproof(const UniValue& params, bool fHelp)
+UniValue gettxoutproof(const JSONRPCRequest& request)
{
- if (fHelp || (params.size() != 1 && params.size() != 2))
+ if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
throw runtime_error(
"gettxoutproof [\"txid\",...] ( blockhash )\n"
"\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
@@ -237,14 +252,14 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
" \"txid\" (string) A transaction hash\n"
" ,...\n"
" ]\n"
- "2. \"block hash\" (string, optional) If specified, looks for txid in the block with this hash\n"
+ "2. \"blockhash\" (string, optional) If specified, looks for txid in the block with this hash\n"
"\nResult:\n"
"\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n"
);
set<uint256> setTxids;
uint256 oneTxid;
- UniValue txids = params[0].get_array();
+ UniValue txids = request.params[0].get_array();
for (unsigned int idx = 0; idx < txids.size(); idx++) {
const UniValue& txid = txids[idx];
if (txid.get_str().length() != 64 || !IsHex(txid.get_str()))
@@ -261,9 +276,9 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
CBlockIndex* pblockindex = NULL;
uint256 hashBlock;
- if (params.size() > 1)
+ if (request.params.size() > 1)
{
- hashBlock = uint256S(params[1].get_str());
+ hashBlock = uint256S(request.params[1].get_str());
if (!mapBlockIndex.count(hashBlock))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
pblockindex = mapBlockIndex[hashBlock];
@@ -275,7 +290,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
if (pblockindex == NULL)
{
- CTransaction tx;
+ CTransactionRef tx;
if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
if (!mapBlockIndex.count(hashBlock))
@@ -288,8 +303,8 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
unsigned int ntxFound = 0;
- BOOST_FOREACH(const CTransaction&tx, block.vtx)
- if (setTxids.count(tx.GetHash()))
+ for (const auto& tx : block.vtx)
+ if (setTxids.count(tx->GetHash()))
ntxFound++;
if (ntxFound != setTxids.size())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "(Not all) transactions not found in specified block");
@@ -301,9 +316,9 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
return strHex;
}
-UniValue verifytxoutproof(const UniValue& params, bool fHelp)
+UniValue verifytxoutproof(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"verifytxoutproof \"proof\"\n"
"\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
@@ -314,7 +329,7 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\n"
);
- CDataStream ssMB(ParseHexV(params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
+ CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
@@ -335,9 +350,9 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
return res;
}
-UniValue createrawtransaction(const UniValue& params, bool fHelp)
+UniValue createrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
throw runtime_error(
"createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime )\n"
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
@@ -347,43 +362,43 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
"it is not stored in the wallet or transmitted to the network.\n"
"\nArguments:\n"
- "1. \"transactions\" (string, required) A json array of json objects\n"
+ "1. \"inputs\" (string, required) A json array of json objects\n"
" [\n"
" {\n"
" \"txid\":\"id\", (string, required) The transaction id\n"
- " \"vout\":n (numeric, required) The output number\n"
- " \"sequence\":n (numeric, optional) The sequence number\n"
- " }\n"
+ " \"vout\":n, (numeric, required) The output number\n"
+ " \"sequence\":n (numeric, optional) The sequence number\n"
+ " } \n"
" ,...\n"
" ]\n"
- "2. \"outputs\" (string, required) a json object with outputs\n"
+ "2. \"outputs\" (string, required) a json object with outputs\n"
" {\n"
- " \"address\": x.xxx (numeric or string, required) The key is the bitcoin address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n"
- " \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n"
- " ...\n"
+ " \"address\": x.xxx, (numeric or string, required) The key is the bitcoin address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n"
+ " \"data\": \"hex\" (string, required) The key is \"data\", the value is hex encoded data\n"
+ " ,...\n"
" }\n"
- "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
+ "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
"\nResult:\n"
- "\"transaction\" (string) hex string of the transaction\n"
+ "\"transaction\" (string) hex string of the transaction\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"")
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"data\\\":\\\"00010203\\\"}\"")
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
- if (params[0].isNull() || params[1].isNull())
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
+ if (request.params[0].isNull() || request.params[1].isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
- UniValue inputs = params[0].get_array();
- UniValue sendTo = params[1].get_obj();
+ UniValue inputs = request.params[0].get_array();
+ UniValue sendTo = request.params[1].get_obj();
CMutableTransaction rawTx;
- if (params.size() > 2 && !params[2].isNull()) {
- int64_t nLockTime = params[2].get_int64();
+ if (request.params.size() > 2 && !request.params[2].isNull()) {
+ int64_t nLockTime = request.params[2].get_int64();
if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
rawTx.nLockTime = nLockTime;
@@ -448,15 +463,15 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
return EncodeHexTx(rawTx);
}
-UniValue decoderawtransaction(const UniValue& params, bool fHelp)
+UniValue decoderawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"decoderawtransaction \"hexstring\"\n"
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n"
"\nArguments:\n"
- "1. \"hex\" (string, required) The transaction hex string\n"
+ "1. \"hexstring\" (string, required) The transaction hex string\n"
"\nResult:\n"
"{\n"
@@ -504,27 +519,27 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
- CTransaction tx;
+ CMutableTransaction mtx;
- if (!DecodeHexTx(tx, params[0].get_str(), true))
+ if (!DecodeHexTx(mtx, request.params[0].get_str(), true))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
UniValue result(UniValue::VOBJ);
- TxToJSON(tx, uint256(), result);
+ TxToJSON(CTransaction(std::move(mtx)), uint256(), result);
return result;
}
-UniValue decodescript(const UniValue& params, bool fHelp)
+UniValue decodescript(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
- "decodescript \"hex\"\n"
+ "decodescript \"hexstring\"\n"
"\nDecode a hex-encoded script.\n"
"\nArguments:\n"
- "1. \"hex\" (string) the hex encoded script\n"
+ "1. \"hexstring\" (string) the hex encoded script\n"
"\nResult:\n"
"{\n"
" \"asm\":\"asm\", (string) Script public key\n"
@@ -535,26 +550,34 @@ UniValue decodescript(const UniValue& params, bool fHelp)
" \"address\" (string) bitcoin address\n"
" ,...\n"
" ],\n"
- " \"p2sh\",\"address\" (string) script address\n"
+ " \"p2sh\",\"address\" (string) address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("decodescript", "\"hexstring\"")
+ HelpExampleRpc("decodescript", "\"hexstring\"")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
UniValue r(UniValue::VOBJ);
CScript script;
- if (params[0].get_str().size() > 0){
- vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
+ if (request.params[0].get_str().size() > 0){
+ vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument"));
script = CScript(scriptData.begin(), scriptData.end());
} else {
// Empty scripts are valid
}
ScriptPubKeyToJSON(script, r, false);
- r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
+ UniValue type;
+ type = find_value(r, "type");
+
+ if (type.isStr() && type.get_str() != "scripthash") {
+ // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
+ // don't return the address for a P2SH of the P2SH.
+ r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
+ }
+
return r;
}
@@ -570,9 +593,9 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
vErrorsRet.push_back(entry);
}
-UniValue signrawtransaction(const UniValue& params, bool fHelp)
+UniValue signrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 4)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw runtime_error(
"signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n"
"\nSign inputs for raw transaction (serialized, hex-encoded).\n"
@@ -597,7 +620,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
" }\n"
" ,...\n"
" ]\n"
- "3. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\n"
+ "3. \"privkeys\" (string, optional) A json array of base58-encoded private keys for signing\n"
" [ (json array of strings, or 'null' if none provided)\n"
" \"privatekey\" (string) private key in base58-encoding\n"
" ,...\n"
@@ -636,9 +659,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
#else
LOCK(cs_main);
#endif
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
- vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
+ vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
vector<CMutableTransaction> txVariants;
while (!ssData.empty()) {
@@ -679,9 +702,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
- if (params.size() > 2 && !params[2].isNull()) {
+ if (request.params.size() > 2 && !request.params[2].isNull()) {
fGivenKeys = true;
- UniValue keys = params[2].get_array();
+ UniValue keys = request.params[2].get_array();
for (unsigned int idx = 0; idx < keys.size(); idx++) {
UniValue k = keys[idx];
CBitcoinSecret vchSecret;
@@ -700,8 +723,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
#endif
// Add previous txouts given in the RPC call:
- if (params.size() > 1 && !params[1].isNull()) {
- UniValue prevTxs = params[1].get_array();
+ if (request.params.size() > 1 && !request.params[1].isNull()) {
+ UniValue prevTxs = request.params[1].get_array();
for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
const UniValue& p = prevTxs[idx];
if (!p.isObject())
@@ -769,7 +792,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
#endif
int nHashType = SIGHASH_ALL;
- if (params.size() > 3 && !params[3].isNull()) {
+ if (request.params.size() > 3 && !request.params[3].isNull()) {
static map<string, int> mapSigHashValues =
boost::assign::map_list_of
(string("ALL"), int(SIGHASH_ALL))
@@ -779,7 +802,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
(string("SINGLE"), int(SIGHASH_SINGLE))
(string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
;
- string strHashType = params[3].get_str();
+ string strHashType = request.params[3].get_str();
if (mapSigHashValues.count(strHashType))
nHashType = mapSigHashValues[strHashType];
else
@@ -812,13 +835,15 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
// ... and merge in other signatures:
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
- sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
+ if (txv.vin.size() > i) {
+ sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
+ }
}
UpdateTransaction(mergedTx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK;
- if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx.wit.vtxinwit.size() > i ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
+ if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
}
}
@@ -834,9 +859,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
return result;
}
-UniValue sendrawtransaction(const UniValue& params, bool fHelp)
+UniValue sendrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"sendrawtransaction \"hexstring\" ( allowhighfees )\n"
"\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
@@ -858,16 +883,18 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
// parse hex string from parameter
- CTransaction tx;
- if (!DecodeHexTx(tx, params[0].get_str()))
+ CMutableTransaction mtx;
+ if (!DecodeHexTx(mtx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
- uint256 hashTx = tx.GetHash();
+ CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
+ const uint256& hashTx = tx->GetHash();
+ bool fLimitFree = false;
CAmount nMaxRawTxFee = maxTxFee;
- if (params.size() > 1 && params[1].get_bool())
+ if (request.params.size() > 1 && request.params[1].get_bool())
nMaxRawTxFee = 0;
CCoinsViewCache &view = *pcoinsTip;
@@ -878,7 +905,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, nMaxRawTxFee)) {
+ if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, NULL, false, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
@@ -891,27 +918,33 @@ 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();
}
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "getrawtransaction", &getrawtransaction, true },
- { "rawtransactions", "createrawtransaction", &createrawtransaction, true },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true },
- { "rawtransactions", "decodescript", &decodescript, true },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false },
- { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */
-
- { "blockchain", "gettxoutproof", &gettxoutproof, true },
- { "blockchain", "verifytxoutproof", &verifytxoutproof, true },
+ { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} },
+ { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"transactions","outputs","locktime"} },
+ { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} },
+ { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} },
+ { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} },
+ { "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
+
+ { "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} },
+ { "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} },
};
-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..283d458c8d 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -25,6 +25,9 @@
#include <boost/thread.hpp>
#include <boost/algorithm/string/case_conv.hpp> // for to_upper()
+#include <memory> // for unique_ptr
+#include <unordered_map>
+
using namespace RPCServer;
using namespace std;
@@ -34,9 +37,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
{
@@ -77,16 +79,20 @@ void RPCTypeCheck(const UniValue& params,
break;
const UniValue& v = params[i];
- if (!((v.type() == t) || (fAllowNull && (v.isNull()))))
- {
- string err = strprintf("Expected type %s, got %s",
- uvTypeName(t), uvTypeName(v.type()));
- throw JSONRPCError(RPC_TYPE_ERROR, err);
+ if (!(fAllowNull && v.isNull())) {
+ RPCTypeCheckArgument(v, t);
}
i++;
}
}
+void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected)
+{
+ if (value.type() != typeExpected) {
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected), uvTypeName(value.type())));
+ }
+}
+
void RPCTypeCheckObj(const UniValue& o,
const map<string, UniValueType>& typesExpected,
bool fAllowNull,
@@ -146,6 +152,8 @@ uint256 ParseHashV(const UniValue& v, string strName)
strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
+ if (64 != strHex.length())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length()));
uint256 result;
result.SetHex(strHex);
return result;
@@ -194,10 +202,11 @@ std::string CRPCTable::help(const std::string& strCommand) const
continue;
try
{
- UniValue params;
+ JSONRPCRequest jreq;
+ jreq.fHelp = true;
rpcfn_type pfn = pcmd->actor;
if (setDone.insert(pfn).second)
- (*pfn)(params, true);
+ (*pfn)(jreq);
}
catch (const std::exception& e)
{
@@ -227,9 +236,9 @@ std::string CRPCTable::help(const std::string& strCommand) const
return strRet;
}
-UniValue help(const UniValue& params, bool fHelp)
+UniValue help(const JSONRPCRequest& jsonRequest)
{
- if (fHelp || params.size() > 1)
+ if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
throw runtime_error(
"help ( \"command\" )\n"
"\nList all commands, or get help for a specified command.\n"
@@ -240,17 +249,17 @@ UniValue help(const UniValue& params, bool fHelp)
);
string strCommand;
- if (params.size() > 0)
- strCommand = params[0].get_str();
+ if (jsonRequest.params.size() > 0)
+ strCommand = jsonRequest.params[0].get_str();
return tableRPC.help(strCommand);
}
-UniValue stop(const UniValue& params, bool fHelp)
+UniValue stop(const JSONRPCRequest& jsonRequest)
{
// Accept the deprecated and ignored 'detach' boolean argument
- if (fHelp || params.size() > 1)
+ if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
throw runtime_error(
"stop\n"
"\nStop Bitcoin server.");
@@ -264,11 +273,11 @@ UniValue stop(const UniValue& params, bool fHelp)
* Call Table
*/
static const CRPCCommand vRPCCommands[] =
-{ // category name actor (function) okSafeMode
- // --------------------- ------------------------ ----------------------- ----------
+{ // category name actor (function) okSafe argNames
+ // --------------------- ------------------------ ----------------------- ------ ----------
/* Overall control/query calls */
- { "control", "help", &help, true },
- { "control", "stop", &stop, true },
+ { "control", "help", &help, true, {"command"} },
+ { "control", "stop", &stop, true, {} },
};
CRPCTable::CRPCTable()
@@ -353,7 +362,7 @@ bool RPCIsInWarmup(std::string *outStatus)
return fRPCInWarmup;
}
-void JSONRequest::parse(const UniValue& valRequest)
+void JSONRPCRequest::parse(const UniValue& valRequest)
{
// Parse request
if (!valRequest.isObject())
@@ -375,23 +384,23 @@ void JSONRequest::parse(const UniValue& valRequest)
// Parse params
UniValue valParams = find_value(request, "params");
- if (valParams.isArray())
- params = valParams.get_array();
+ if (valParams.isArray() || valParams.isObject())
+ params = valParams;
else if (valParams.isNull())
params = UniValue(UniValue::VARR);
else
- throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
+ throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
}
static UniValue JSONRPCExecOne(const UniValue& req)
{
UniValue rpc_result(UniValue::VOBJ);
- JSONRequest jreq;
+ JSONRPCRequest jreq;
try {
jreq.parse(req);
- UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
+ UniValue result = tableRPC.execute(jreq);
rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
}
catch (const UniValue& objError)
@@ -416,7 +425,49 @@ std::string JSONRPCExecBatch(const UniValue& vReq)
return ret.write() + "\n";
}
-UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params) const
+/**
+ * Process named arguments into a vector of positional arguments, based on the
+ * passed-in specification for the RPC call's arguments.
+ */
+static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames)
+{
+ JSONRPCRequest out = in;
+ out.params = UniValue(UniValue::VARR);
+ // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if
+ // there is an unknown one.
+ const std::vector<std::string>& keys = in.params.getKeys();
+ const std::vector<UniValue>& values = in.params.getValues();
+ std::unordered_map<std::string, const UniValue*> argsIn;
+ for (size_t i=0; i<keys.size(); ++i) {
+ argsIn[keys[i]] = &values[i];
+ }
+ // Process expected parameters.
+ int hole = 0;
+ for (const std::string &argName: argNames) {
+ auto fr = argsIn.find(argName);
+ if (fr != argsIn.end()) {
+ for (int i = 0; i < hole; ++i) {
+ // Fill hole between specified parameters with JSON nulls,
+ // but not at the end (for backwards compatibility with calls
+ // that act based on number of specified parameters).
+ out.params.push_back(UniValue());
+ }
+ hole = 0;
+ out.params.push_back(*fr->second);
+ argsIn.erase(fr);
+ } else {
+ hole += 1;
+ }
+ }
+ // If there are still arguments in the argsIn map, this is an error.
+ if (!argsIn.empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown named parameter " + argsIn.begin()->first);
+ }
+ // Return request with named arguments transformed to positional arguments
+ return out;
+}
+
+UniValue CRPCTable::execute(const JSONRPCRequest &request) const
{
// Return immediately if in warmup
{
@@ -426,7 +477,7 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params
}
// Find method
- const CRPCCommand *pcmd = tableRPC[strMethod];
+ const CRPCCommand *pcmd = tableRPC[request.strMethod];
if (!pcmd)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
@@ -434,8 +485,12 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params
try
{
- // Execute
- return pcmd->actor(params, false);
+ // Execute, convert arguments to array if necessary
+ if (request.params.isObject()) {
+ return pcmd->actor(transformNamedArguments(request, pcmd->argNames));
+ } else {
+ return pcmd->actor(request);
+ }
}
catch (const std::exception& e)
{
@@ -490,7 +545,15 @@ 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)));
+}
+
+int RPCSerializationFlags()
+{
+ int flag = 0;
+ if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0)
+ flag |= SERIALIZE_TRANSACTION_NO_WITNESS;
+ return flag;
}
CRPCTable tableRPC;
diff --git a/src/rpc/server.h b/src/rpc/server.h
index b5ccc153d0..52f82866dc 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -19,6 +19,8 @@
#include <univalue.h>
+static const unsigned int DEFAULT_RPC_SERIALIZE_VERSION = 1;
+
class CRPCCommand;
namespace RPCServer
@@ -41,14 +43,17 @@ struct UniValueType {
UniValue::VType type;
};
-class JSONRequest
+class JSONRPCRequest
{
public:
UniValue id;
std::string strMethod;
UniValue params;
+ bool fHelp;
+ std::string URI;
+ std::string authUser;
- JSONRequest() { id = NullUniValue; }
+ JSONRPCRequest() { id = NullUniValue; params = NullUniValue; fHelp = false; }
void parse(const UniValue& valRequest);
};
@@ -73,6 +78,11 @@ bool RPCIsInWarmup(std::string *statusOut);
void RPCTypeCheck(const UniValue& params,
const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);
+/**
+ * Type-check one argument; throws JSONRPCError if wrong type given.
+ */
+void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected);
+
/*
Check for expected keys/value types in an Object.
*/
@@ -122,7 +132,7 @@ void RPCUnsetTimerInterface(RPCTimerInterface *iface);
*/
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds);
-typedef UniValue(*rpcfn_type)(const UniValue& params, bool fHelp);
+typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);
class CRPCCommand
{
@@ -131,6 +141,7 @@ public:
std::string name;
rpcfn_type actor;
bool okSafeMode;
+ std::vector<std::string> argNames;
};
/**
@@ -147,12 +158,11 @@ public:
/**
* Execute a method.
- * @param method Method to execute
- * @param params UniValue Array of arguments (JSON objects)
+ * @param request The JSONRPCRequest to execute
* @returns Result of the call.
* @throws an exception (UniValue) when an error happens.
*/
- UniValue execute(const std::string &method, const UniValue &params) const;
+ UniValue execute(const JSONRPCRequest &request) const;
/**
* Returns a list of registered commands
@@ -194,5 +204,9 @@ bool StartRPC();
void InterruptRPC();
void StopRPC();
std::string JSONRPCExecBatch(const UniValue& vReq);
+void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);
+
+// Retrieves any serialization flags requested in command line argument
+int RPCSerializationFlags();
#endif // BITCOIN_RPCSERVER_H