Browse Source

Convert tree to using univalue. Eliminate all json_spirit uses.

0.13
Jeff Garzik 10 years ago committed by Jonas Schnelli
parent
commit
15982a8b69
  1. 1
      src/Makefile.am
  2. 20
      src/bitcoin-cli.cpp
  3. 17
      src/json_spirit_wrapper.h
  4. 18
      src/qt/rpcconsole.cpp
  5. 16
      src/rpcblockchain.cpp
  6. 2
      src/rpcclient.cpp
  7. 4
      src/rpcclient.h
  8. 19
      src/rpcmining.cpp
  9. 5
      src/rpcmisc.cpp
  10. 8
      src/rpcnet.cpp
  11. 10
      src/rpcprotocol.cpp
  12. 4
      src/rpcprotocol.h
  13. 47
      src/rpcrawtransaction.cpp
  14. 51
      src/rpcserver.cpp
  15. 18
      src/rpcserver.h
  16. 40
      src/test/base58_tests.cpp
  17. 18
      src/test/rpc_tests.cpp
  18. 22
      src/test/script_tests.cpp
  19. 11
      src/test/sighash_tests.cpp
  20. 33
      src/test/transaction_tests.cpp
  21. 84
      src/univalue/univalue.h
  22. 14
      src/wallet/rpcdump.cpp
  23. 64
      src/wallet/rpcwallet.cpp

1
src/Makefile.am

@ -342,6 +342,7 @@ endif
bitcoin_cli_LDADD = \ bitcoin_cli_LDADD = \
$(LIBBITCOIN_CLI) \ $(LIBBITCOIN_CLI) \
$(LIBBITCOIN_UNIVALUE) \
$(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_UTIL) \
$(LIBSECP256K1) $(LIBSECP256K1)

20
src/bitcoin-cli.cpp

@ -143,7 +143,7 @@ Object CallRPC(const string& strMethod, const Array& params)
// Parse reply // Parse reply
Value valReply; Value valReply;
if (!read_string(strReply, valReply)) if (!valReply.read(strReply))
throw runtime_error("couldn't parse reply from server"); throw runtime_error("couldn't parse reply from server");
const Object& reply = valReply.get_obj(); const Object& reply = valReply.get_obj();
if (reply.empty()) if (reply.empty())
@ -176,29 +176,27 @@ int CommandLineRPC(int argc, char *argv[])
const bool fWait = GetBoolArg("-rpcwait", false); const bool fWait = GetBoolArg("-rpcwait", false);
do { do {
try { try {
const Object reply = CallRPC(strMethod, params); // Execute
Object reply = CallRPC(strMethod, params);
// Parse reply // Parse reply
const Value& result = find_value(reply, "result"); const Value& result = find_value(reply, "result");
const Value& error = find_value(reply, "error"); const Value& error = find_value(reply, "error");
if (error.type() != null_type) { if (!error.isNull()) {
// Error // Error
const int code = find_value(error.get_obj(), "code").get_int(); strPrint = "error: " + error.write();
if (fWait && code == RPC_IN_WARMUP) int code = error["code"].get_int();
throw CConnectionFailed("server in warmup");
strPrint = "error: " + write_string(error, false);
nRet = abs(code); nRet = abs(code);
} else { } else {
// Result // Result
if (result.type() == null_type) if (result.isNull())
strPrint = ""; strPrint = "";
else if (result.type() == str_type) else if (result.isStr())
strPrint = result.get_str(); strPrint = result.get_str();
else else
strPrint = write_string(result, true); strPrint = result.write(2);
} }
// Connection succeeded, no need to retry. // Connection succeeded, no need to retry.
break; break;
} }

17
src/json_spirit_wrapper.h

@ -0,0 +1,17 @@
#ifndef __JSON_SPIRIT_WRAPPER_H__
#define __JSON_SPIRIT_WRAPPER_H__
#include "univalue/univalue.h"
namespace json_spirit {
typedef UniValue Value;
typedef UniValue Array;
typedef UniValue Object;
typedef UniValue::VType Value_type;
}
#define find_value(val,key) (val[key])
#endif // __JSON_SPIRIT_WRAPPER_H__

18
src/qt/rpcconsole.cpp

@ -16,10 +16,10 @@
#include "rpcclient.h" #include "rpcclient.h"
#include "util.h" #include "util.h"
#include "json/json_spirit_value.h"
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include "univalue/univalue.h"
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
#include <db_cxx.h> #include <db_cxx.h>
#endif #endif
@ -167,21 +167,25 @@ void RPCExecutor::request(const QString &command)
std::string strPrint; std::string strPrint;
// Convert argument list to JSON objects in method-dependent way, // Convert argument list to JSON objects in method-dependent way,
// and pass it along with the method name to the dispatcher. // and pass it along with the method name to the dispatcher.
json_spirit::Value result = tableRPC.execute( UniValue result = tableRPC.execute(
args[0], args[0],
RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end()))); RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));
// Format result reply // Format result reply
if (result.type() == json_spirit::null_type) if (result.isNull())
strPrint = ""; strPrint = "";
else if (result.type() == json_spirit::str_type) else if (result.isStr())
strPrint = result.get_str(); strPrint = result.get_str();
else else
strPrint = write_string(result, true); strPrint = result.write(2);
emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
} }
<<<<<<< HEAD
catch (const json_spirit::Object& objError) catch (const json_spirit::Object& objError)
=======
catch (UniValue& objError)
>>>>>>> Convert tree to using univalue. Eliminate all json_spirit uses.
{ {
try // Nice formatting for standard-format error try // Nice formatting for standard-format error
{ {
@ -191,7 +195,7 @@ void RPCExecutor::request(const QString &command)
} }
catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message
{ // Show raw JSON object { // Show raw JSON object
emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false))); emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write()));
} }
} }
catch (const std::exception& e) catch (const std::exception& e)

16
src/rpcblockchain.cpp

@ -13,7 +13,7 @@
#include <stdint.h> #include <stdint.h>
#include "json/json_spirit_value.h" #include "json_spirit_wrapper.h"
using namespace json_spirit; using namespace json_spirit;
using namespace std; using namespace std;
@ -206,7 +206,13 @@ Value getrawmempool(const Array& params, bool fHelp)
if (mempool.exists(txin.prevout.hash)) if (mempool.exists(txin.prevout.hash))
setDepends.insert(txin.prevout.hash.ToString()); setDepends.insert(txin.prevout.hash.ToString());
} }
Array depends(setDepends.begin(), setDepends.end());
UniValue depends;
BOOST_FOREACH(const string& dep, setDepends)
{
depends.push_back(dep);
}
info.push_back(Pair("depends", depends)); info.push_back(Pair("depends", depends));
o.push_back(Pair(hash.ToString(), info)); o.push_back(Pair(hash.ToString(), info));
} }
@ -412,14 +418,14 @@ Value gettxout(const Array& params, bool fHelp)
LOCK(mempool.cs); LOCK(mempool.cs);
CCoinsViewMemPool view(pcoinsTip, mempool); CCoinsViewMemPool view(pcoinsTip, mempool);
if (!view.GetCoins(hash, coins)) if (!view.GetCoins(hash, coins))
return Value::null; return NullUniValue;
mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
} else { } else {
if (!pcoinsTip->GetCoins(hash, coins)) if (!pcoinsTip->GetCoins(hash, coins))
return Value::null; return NullUniValue;
} }
if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull()) if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull())
return Value::null; return NullUniValue;
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
CBlockIndex *pindex = it->second; CBlockIndex *pindex = it->second;

2
src/rpcclient.cpp

@ -135,7 +135,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
// parse string as JSON, insert bool/number/object/etc. value // parse string as JSON, insert bool/number/object/etc. value
else { else {
Value jVal; Value jVal;
if (!read_string(strVal, jVal)) if (!jVal.read(strVal))
throw runtime_error(string("Error parsing JSON:")+strVal); throw runtime_error(string("Error parsing JSON:")+strVal);
params.push_back(jVal); params.push_back(jVal);
} }

4
src/rpcclient.h

@ -6,9 +6,7 @@
#ifndef BITCOIN_RPCCLIENT_H #ifndef BITCOIN_RPCCLIENT_H
#define BITCOIN_RPCCLIENT_H #define BITCOIN_RPCCLIENT_H
#include "json/json_spirit_reader_template.h" #include "json_spirit_wrapper.h"
#include "json/json_spirit_utils.h"
#include "json/json_spirit_writer_template.h"
json_spirit::Array RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams); json_spirit::Array RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);

19
src/rpcmining.cpp

@ -24,8 +24,7 @@
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h" #include "json_spirit_wrapper.h"
#include "json/json_spirit_value.h"
using namespace json_spirit; using namespace json_spirit;
using namespace std; using namespace std;
@ -216,7 +215,7 @@ Value setgenerate(const Array& params, bool fHelp)
mapArgs ["-genproclimit"] = itostr(nGenProcLimit); mapArgs ["-genproclimit"] = itostr(nGenProcLimit);
GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit);
return Value::null; return NullUniValue;
} }
#endif #endif
@ -382,14 +381,14 @@ Value getblocktemplate(const Array& params, bool fHelp)
LOCK(cs_main); LOCK(cs_main);
std::string strMode = "template"; std::string strMode = "template";
Value lpval = Value::null; Value lpval = NullUniValue;
if (params.size() > 0) if (params.size() > 0)
{ {
const Object& oparam = params[0].get_obj(); const Object& oparam = params[0].get_obj();
const Value& modeval = find_value(oparam, "mode"); const Value& modeval = find_value(oparam, "mode");
if (modeval.type() == str_type) if (modeval.isStr())
strMode = modeval.get_str(); strMode = modeval.get_str();
else if (modeval.type() == null_type) else if (modeval.isNull())
{ {
/* Do nothing */ /* Do nothing */
} }
@ -439,14 +438,14 @@ Value getblocktemplate(const Array& params, bool fHelp)
static unsigned int nTransactionsUpdatedLast; static unsigned int nTransactionsUpdatedLast;
if (lpval.type() != null_type) if (!lpval.isNull())
{ {
// Wait to respond until either the best block changes, OR a minute has passed and there are more transactions // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions
uint256 hashWatchedChain; uint256 hashWatchedChain;
boost::system_time checktxtime; boost::system_time checktxtime;
unsigned int nTransactionsUpdatedLastLP; unsigned int nTransactionsUpdatedLastLP;
if (lpval.type() == str_type) if (lpval.isStr())
{ {
// Format: <hashBestChain><nTransactionsUpdatedLast> // Format: <hashBestChain><nTransactionsUpdatedLast>
std::string lpstr = lpval.get_str(); std::string lpstr = lpval.get_str();
@ -686,7 +685,7 @@ Value estimatefee(const Array& params, bool fHelp)
+ HelpExampleCli("estimatefee", "6") + HelpExampleCli("estimatefee", "6")
); );
RPCTypeCheck(params, boost::assign::list_of(int_type)); RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = params[0].get_int(); int nBlocks = params[0].get_int();
if (nBlocks < 1) if (nBlocks < 1)
@ -718,7 +717,7 @@ Value estimatepriority(const Array& params, bool fHelp)
+ HelpExampleCli("estimatepriority", "6") + HelpExampleCli("estimatepriority", "6")
); );
RPCTypeCheck(params, boost::assign::list_of(int_type)); RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = params[0].get_int(); int nBlocks = params[0].get_int();
if (nBlocks < 1) if (nBlocks < 1)

5
src/rpcmisc.cpp

@ -20,8 +20,7 @@
#include <stdint.h> #include <stdint.h>
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h" #include "json_spirit_wrapper.h"
#include "json/json_spirit_value.h"
using namespace json_spirit; using namespace json_spirit;
using namespace std; using namespace std;
@ -204,7 +203,7 @@ Value validateaddress(const Array& params, bool fHelp)
if (mine != ISMINE_NO) { if (mine != ISMINE_NO) {
ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false)); ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest); Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
ret.insert(ret.end(), detail.begin(), detail.end()); ret.pushKVs(detail);
} }
if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));

8
src/rpcnet.cpp

@ -16,7 +16,7 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include "json/json_spirit_value.h" #include "json_spirit_wrapper.h"
using namespace json_spirit; using namespace json_spirit;
using namespace std; using namespace std;
@ -59,7 +59,7 @@ Value ping(const Array& params, bool fHelp)
pNode->fPingQueued = true; pNode->fPingQueued = true;
} }
return Value::null; return NullUniValue;
} }
static void CopyNodeStats(std::vector<CNodeStats>& vstats) static void CopyNodeStats(std::vector<CNodeStats>& vstats)
@ -190,7 +190,7 @@ Value addnode(const Array& params, bool fHelp)
{ {
CAddress addr; CAddress addr;
OpenNetworkConnection(addr, NULL, strNode.c_str()); OpenNetworkConnection(addr, NULL, strNode.c_str());
return Value::null; return NullUniValue;
} }
LOCK(cs_vAddedNodes); LOCK(cs_vAddedNodes);
@ -212,7 +212,7 @@ Value addnode(const Array& params, bool fHelp)
vAddedNodes.erase(it); vAddedNodes.erase(it);
} }
return Value::null; return NullUniValue;
} }
Value getaddednodeinfo(const Array& params, bool fHelp) Value getaddednodeinfo(const Array& params, bool fHelp)

10
src/rpcprotocol.cpp

@ -23,7 +23,7 @@
#include <boost/iostreams/concepts.hpp> #include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp> #include <boost/iostreams/stream.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include "json/json_spirit_writer_template.h" #include "json_spirit_wrapper.h"
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;
@ -260,14 +260,14 @@ string JSONRPCRequest(const string& strMethod, const Array& params, const Value&
request.push_back(Pair("method", strMethod)); request.push_back(Pair("method", strMethod));
request.push_back(Pair("params", params)); request.push_back(Pair("params", params));
request.push_back(Pair("id", id)); request.push_back(Pair("id", id));
return write_string(Value(request), false) + "\n"; return request.write() + "\n";
} }
Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id) Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
{ {
Object reply; Object reply;
if (error.type() != null_type) if (!error.isNull())
reply.push_back(Pair("result", Value::null)); reply.push_back(Pair("result", NullUniValue));
else else
reply.push_back(Pair("result", result)); reply.push_back(Pair("result", result));
reply.push_back(Pair("error", error)); reply.push_back(Pair("error", error));
@ -278,7 +278,7 @@ Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
string JSONRPCReply(const Value& result, const Value& error, const Value& id) string JSONRPCReply(const Value& result, const Value& error, const Value& id)
{ {
Object reply = JSONRPCReplyObj(result, error, id); Object reply = JSONRPCReplyObj(result, error, id);
return write_string(Value(reply), false) + "\n"; return reply.write() + "\n";
} }
Object JSONRPCError(int code, const string& message) Object JSONRPCError(int code, const string& message)

4
src/rpcprotocol.h

@ -15,9 +15,7 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#include "json/json_spirit_reader_template.h" #include "json_spirit_wrapper.h"
#include "json/json_spirit_utils.h"
#include "json/json_spirit_writer_template.h"
//! HTTP status codes //! HTTP status codes
enum HTTPStatusCode enum HTTPStatusCode

47
src/rpcrawtransaction.cpp

@ -25,8 +25,7 @@
#include <stdint.h> #include <stdint.h>
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h" #include "json_spirit_wrapper.h"
#include "json/json_spirit_value.h"
using namespace json_spirit; using namespace json_spirit;
using namespace std; using namespace std;
@ -343,20 +342,21 @@ Value createrawtransaction(const Array& params, bool fHelp)
); );
LOCK(cs_main); LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(array_type)(obj_type)); RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ));
Array inputs = params[0].get_array(); Array inputs = params[0].get_array();
Object sendTo = params[1].get_obj(); Object sendTo = params[1].get_obj();
CMutableTransaction rawTx; CMutableTransaction rawTx;
BOOST_FOREACH(const Value& input, inputs) { for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const Value& input = inputs[idx];
const Object& o = input.get_obj(); const Object& o = input.get_obj();
uint256 txid = ParseHashO(o, "txid"); uint256 txid = ParseHashO(o, "txid");
const Value& vout_v = find_value(o, "vout"); const Value& vout_v = find_value(o, "vout");
if (vout_v.type() != int_type) if (!vout_v.isNum())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
int nOutput = vout_v.get_int(); int nOutput = vout_v.get_int();
if (nOutput < 0) if (nOutput < 0)
@ -367,17 +367,18 @@ Value createrawtransaction(const Array& params, bool fHelp)
} }
set<CBitcoinAddress> setAddress; set<CBitcoinAddress> setAddress;
BOOST_FOREACH(const Pair& s, sendTo) { vector<string> addrList = sendTo.getKeys();
CBitcoinAddress address(s.name_); BOOST_FOREACH(const string& name_, addrList) {
CBitcoinAddress address(name_);
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
if (setAddress.count(address)) if (setAddress.count(address))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
setAddress.insert(address); setAddress.insert(address);
CScript scriptPubKey = GetScriptForDestination(address.Get()); CScript scriptPubKey = GetScriptForDestination(address.Get());
CAmount nAmount = AmountFromValue(s.value_); CAmount nAmount = AmountFromValue(sendTo[name_]);
CTxOut out(nAmount, scriptPubKey); CTxOut out(nAmount, scriptPubKey);
rawTx.vout.push_back(out); rawTx.vout.push_back(out);
@ -438,7 +439,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
); );
LOCK(cs_main); LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type)); RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
CTransaction tx; CTransaction tx;
@ -570,7 +571,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
#else #else
LOCK(cs_main); LOCK(cs_main);
#endif #endif
RPCTypeCheck(params, boost::assign::list_of(str_type)(array_type)(array_type)(str_type), true); RPCTypeCheck(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(params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
@ -613,10 +614,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fGivenKeys = false; bool fGivenKeys = false;
CBasicKeyStore tempKeystore; CBasicKeyStore tempKeystore;
if (params.size() > 2 && params[2].type() != null_type) { if (params.size() > 2 && !params[2].isNull()) {
fGivenKeys = true; fGivenKeys = true;
Array keys = params[2].get_array(); Array keys = params[2].get_array();
BOOST_FOREACH(Value k, keys) { for (unsigned int idx = 0; idx < keys.size(); idx++) {
Value k = keys[idx];
CBitcoinSecret vchSecret; CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(k.get_str()); bool fGood = vchSecret.SetString(k.get_str());
if (!fGood) if (!fGood)
@ -633,15 +635,16 @@ Value signrawtransaction(const Array& params, bool fHelp)
#endif #endif
// Add previous txouts given in the RPC call: // Add previous txouts given in the RPC call:
if (params.size() > 1 && params[1].type() != null_type) { if (params.size() > 1 && !params[1].isNull()) {
Array prevTxs = params[1].get_array(); Array prevTxs = params[1].get_array();
BOOST_FOREACH(Value& p, prevTxs) { for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
if (p.type() != obj_type) const Value& p = prevTxs[idx];
if (!p.isObject())
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
Object prevOut = p.get_obj(); Object prevOut = p.get_obj();
RPCTypeCheck(prevOut, boost::assign::map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)); RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR));
uint256 txid = ParseHashO(prevOut, "txid"); uint256 txid = ParseHashO(prevOut, "txid");
@ -669,9 +672,9 @@ Value signrawtransaction(const Array& params, bool fHelp)
// if redeemScript given and not using the local wallet (private keys // if redeemScript given and not using the local wallet (private keys
// given), add redeemScript to the tempKeystore so it can be signed: // given), add redeemScript to the tempKeystore so it can be signed:
if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) { if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) {
RPCTypeCheck(prevOut, boost::assign::map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type)); RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript",UniValue::VSTR));
Value v = find_value(prevOut, "redeemScript"); Value v = find_value(prevOut, "redeemScript");
if (!(v == Value::null)) { if (!v.isNull()) {
vector<unsigned char> rsData(ParseHexV(v, "redeemScript")); vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end()); CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript); tempKeystore.AddCScript(redeemScript);
@ -687,7 +690,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
#endif #endif
int nHashType = SIGHASH_ALL; int nHashType = SIGHASH_ALL;
if (params.size() > 3 && params[3].type() != null_type) { if (params.size() > 3 && !params[3].isNull()) {
static map<string, int> mapSigHashValues = static map<string, int> mapSigHashValues =
boost::assign::map_list_of boost::assign::map_list_of
(string("ALL"), int(SIGHASH_ALL)) (string("ALL"), int(SIGHASH_ALL))
@ -769,7 +772,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
); );
LOCK(cs_main); LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type)(bool_type)); RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
// parse hex string from parameter // parse hex string from parameter
CTransaction tx; CTransaction tx;

51
src/rpcserver.cpp

@ -27,7 +27,8 @@
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/signals2/signal.hpp> #include <boost/signals2/signal.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include "json/json_spirit_writer_template.h"
#include "json_spirit_wrapper.h"
using namespace boost::asio; using namespace boost::asio;
using namespace json_spirit; using namespace json_spirit;
@ -89,30 +90,30 @@ void RPCTypeCheck(const Array& params,
break; break;
const Value& v = params[i]; const Value& v = params[i];
if (!((v.type() == t) || (fAllowNull && (v.type() == null_type)))) if (!((v.type() == t) || (fAllowNull && (v.isNull()))))
{ {
string err = strprintf("Expected type %s, got %s", string err = strprintf("Expected type %s, got %s",
Value_type_name[t], Value_type_name[v.type()]); uvTypeName(t), uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err); throw JSONRPCError(RPC_TYPE_ERROR, err);
} }
i++; i++;
} }
} }
void RPCTypeCheck(const Object& o, void RPCTypeCheckObj(const UniValue& o,
const map<string, Value_type>& typesExpected, const map<string, UniValue::VType>& typesExpected,
bool fAllowNull) bool fAllowNull)
{ {
BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected) BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected)
{ {
const Value& v = find_value(o, t.first); const Value& v = find_value(o, t.first);
if (!fAllowNull && v.type() == null_type) if (!fAllowNull && v.isNull())
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first)); throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type)))) if (!((v.type() == t.second) || (fAllowNull && (v.isNull()))))
{ {
string err = strprintf("Expected type %s for %s, got %s", string err = strprintf("Expected type %s for %s, got %s",
Value_type_name[t.second], t.first, Value_type_name[v.type()]); uvTypeName(t.second), t.first, uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err); throw JSONRPCError(RPC_TYPE_ERROR, err);
} }
} }
@ -142,7 +143,7 @@ Value ValueFromAmount(const CAmount& amount)
uint256 ParseHashV(const Value& v, string strName) uint256 ParseHashV(const Value& v, string strName)
{ {
string strHex; string strHex;
if (v.type() == str_type) if (v.isStr())
strHex = v.get_str(); strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
@ -157,7 +158,7 @@ uint256 ParseHashO(const Object& o, string strKey)
vector<unsigned char> ParseHexV(const Value& v, string strName) vector<unsigned char> ParseHexV(const Value& v, string strName)
{ {
string strHex; string strHex;
if (v.type() == str_type) if (v.isStr())
strHex = v.get_str(); strHex = v.get_str();
if (!IsHex(strHex)) if (!IsHex(strHex))
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
@ -417,7 +418,7 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
int code = find_value(objError, "code").get_int(); int code = find_value(objError, "code").get_int();
if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST; if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST;
else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND; else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND;
string strReply = JSONRPCReply(Value::null, objError, id); string strReply = JSONRPCReply(NullUniValue, objError, id);
stream << HTTPReply(nStatus, strReply, false) << std::flush; stream << HTTPReply(nStatus, strReply, false) << std::flush;
} }
@ -828,14 +829,14 @@ public:
string strMethod; string strMethod;
Array params; Array params;
JSONRequest() { id = Value::null; } JSONRequest() { id = NullUniValue; }
void parse(const Value& valRequest); void parse(const Value& valRequest);
}; };
void JSONRequest::parse(const Value& valRequest) void JSONRequest::parse(const Value& valRequest)
{ {
// Parse request // Parse request
if (valRequest.type() != obj_type) if (!valRequest.isObject())
throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object"); throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
const Object& request = valRequest.get_obj(); const Object& request = valRequest.get_obj();
@ -844,9 +845,9 @@ void JSONRequest::parse(const Value& valRequest)
// Parse method // Parse method
Value valMethod = find_value(request, "method"); Value valMethod = find_value(request, "method");
if (valMethod.type() == null_type) if (valMethod.isNull())
throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method"); throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
if (valMethod.type() != str_type) if (!valMethod.isStr())
throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string"); throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
strMethod = valMethod.get_str(); strMethod = valMethod.get_str();
if (strMethod != "getblocktemplate") if (strMethod != "getblocktemplate")
@ -854,9 +855,9 @@ void JSONRequest::parse(const Value& valRequest)
// Parse params // Parse params
Value valParams = find_value(request, "params"); Value valParams = find_value(request, "params");
if (valParams.type() == array_type) if (valParams.isArray())
params = valParams.get_array(); params = valParams.get_array();
else if (valParams.type() == null_type) else if (valParams.isNull())
params = Array(); params = Array();
else else
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array"); throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
@ -872,15 +873,15 @@ static Object JSONRPCExecOne(const Value& req)
jreq.parse(req); jreq.parse(req);
Value result = tableRPC.execute(jreq.strMethod, jreq.params); Value result = tableRPC.execute(jreq.strMethod, jreq.params);
rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id); rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
} }
catch (const Object& objError) catch (const Object& objError)
{ {
rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id); rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
rpc_result = JSONRPCReplyObj(Value::null, rpc_result = JSONRPCReplyObj(NullUniValue,
JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
} }
@ -893,7 +894,7 @@ static string JSONRPCExecBatch(const Array& vReq)
for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++) for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
ret.push_back(JSONRPCExecOne(vReq[reqIdx])); ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
return write_string(Value(ret), false) + "\n"; return ret.write() + "\n";
} }
static bool HTTPReq_JSONRPC(AcceptedConnection *conn, static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
@ -925,7 +926,7 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
{ {
// Parse request // Parse request
Value valRequest; Value valRequest;
if (!read_string(strRequest, valRequest)) if (!valRequest.read(strRequest))
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
// Return immediately if in warmup // Return immediately if in warmup
@ -938,16 +939,16 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
string strReply; string strReply;
// singleton request // singleton request
if (valRequest.type() == obj_type) { if (valRequest.isObject()) {
jreq.parse(valRequest); jreq.parse(valRequest);
Value result = tableRPC.execute(jreq.strMethod, jreq.params); Value result = tableRPC.execute(jreq.strMethod, jreq.params);
// Send reply // Send reply
strReply = JSONRPCReply(result, Value::null, jreq.id); strReply = JSONRPCReply(result, NullUniValue, jreq.id);
// array of requests // array of requests
} else if (valRequest.type() == array_type) } else if (valRequest.isArray())
strReply = JSONRPCExecBatch(valRequest.get_array()); strReply = JSONRPCExecBatch(valRequest.get_array());
else else
throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");

18
src/rpcserver.h

@ -15,9 +15,8 @@
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include "json/json_spirit_reader_template.h" #include <boost/function.hpp>
#include "json/json_spirit_utils.h" #include "json_spirit_wrapper.h"
#include "json/json_spirit_writer_template.h"
class CRPCCommand; class CRPCCommand;
@ -73,12 +72,13 @@ bool RPCIsInWarmup(std::string *statusOut);
*/ */
void RPCTypeCheck(const json_spirit::Array& params, void RPCTypeCheck(const json_spirit::Array& params,
const std::list<json_spirit::Value_type>& typesExpected, bool fAllowNull=false); const std::list<json_spirit::Value_type>& typesExpected, bool fAllowNull=false);
/**
* Check for expected keys/value types in an Object. /*
* Use like: RPCTypeCheck(object, boost::assign::map_list_of("name", str_type)("value", int_type)); Check for expected keys/value types in an Object.
*/ Use like: RPCTypeCheckObj(object, boost::assign::map_list_of("name", str_type)("value", int_type));
void RPCTypeCheck(const json_spirit::Object& o, */
const std::map<std::string, json_spirit::Value_type>& typesExpected, bool fAllowNull=false); void RPCTypeCheckObj(const UniValue& o,
const std::map<std::string, UniValue::VType>& typesExpected, bool fAllowNull=false);
/** /**
* Run func nSeconds from now. Uses boost deadline timers. * Run func nSeconds from now. Uses boost deadline timers.

40
src/test/base58_tests.cpp

@ -17,9 +17,7 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include "json/json_spirit_reader_template.h" #include "json_spirit_wrapper.h"
#include "json/json_spirit_utils.h"
#include "json/json_spirit_writer_template.h"
using namespace json_spirit; using namespace json_spirit;
extern Array read_json(const std::string& jsondata); extern Array read_json(const std::string& jsondata);
@ -30,10 +28,9 @@ BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(base58_EncodeBase58) BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
{ {
Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode))); Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
BOOST_FOREACH(Value& tv, tests) for (unsigned int idx = 0; idx < tests.size(); idx++) {
{ Array test = tests[idx];
Array test = tv.get_array(); std::string strTest = test.write();
std::string strTest = write_string(tv, false);
if (test.size() < 2) // Allow for extra stuff (useful for comments) if (test.size() < 2) // Allow for extra stuff (useful for comments)
{ {
BOOST_ERROR("Bad test: " << strTest); BOOST_ERROR("Bad test: " << strTest);
@ -53,10 +50,9 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode))); Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
std::vector<unsigned char> result; std::vector<unsigned char> result;
BOOST_FOREACH(Value& tv, tests) for (unsigned int idx = 0; idx < tests.size(); idx++) {
{ Array test = tests[idx];
Array test = tv.get_array(); std::string strTest = test.write();
std::string strTest = write_string(tv, false);
if (test.size() < 2) // Allow for extra stuff (useful for comments) if (test.size() < 2) // Allow for extra stuff (useful for comments)
{ {
BOOST_ERROR("Bad test: " << strTest); BOOST_ERROR("Bad test: " << strTest);
@ -130,10 +126,9 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
CBitcoinAddress addr; CBitcoinAddress addr;
SelectParams(CBaseChainParams::MAIN); SelectParams(CBaseChainParams::MAIN);
BOOST_FOREACH(Value& tv, tests) for (unsigned int idx = 0; idx < tests.size(); idx++) {
{ Array test = tests[idx];
Array test = tv.get_array(); std::string strTest = test.write();
std::string strTest = write_string(tv, false);
if (test.size() < 3) // Allow for extra stuff (useful for comments) if (test.size() < 3) // Allow for extra stuff (useful for comments)
{ {
BOOST_ERROR("Bad test: " << strTest); BOOST_ERROR("Bad test: " << strTest);
@ -185,10 +180,10 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
{ {
Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
std::vector<unsigned char> result; std::vector<unsigned char> result;
BOOST_FOREACH(Value& tv, tests)
{ for (unsigned int idx = 0; idx < tests.size(); idx++) {
Array test = tv.get_array(); Array test = tests[idx];
std::string strTest = write_string(tv, false); std::string strTest = test.write();
if (test.size() < 3) // Allow for extra stuff (useful for comments) if (test.size() < 3) // Allow for extra stuff (useful for comments)
{ {
BOOST_ERROR("Bad test: " << strTest); BOOST_ERROR("Bad test: " << strTest);
@ -256,10 +251,9 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
CBitcoinSecret secret; CBitcoinSecret secret;
CBitcoinAddress addr; CBitcoinAddress addr;
BOOST_FOREACH(Value& tv, tests) for (unsigned int idx = 0; idx < tests.size(); idx++) {
{ Array test = tests[idx];
Array test = tv.get_array(); std::string strTest = test.write();
std::string strTest = write_string(tv, false);
if (test.size() < 1) // Allow for extra stuff (useful for comments) if (test.size() < 1) // Allow for extra stuff (useful for comments)
{ {
BOOST_ERROR("Bad test: " << strTest); BOOST_ERROR("Bad test: " << strTest);

18
src/test/rpc_tests.cpp

@ -111,20 +111,20 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign)
BOOST_AUTO_TEST_CASE(rpc_format_monetary_values) BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
{ {
BOOST_CHECK_EQUAL(write_string(ValueFromAmount(0LL), false), "0.00000000"); BOOST_CHECK(ValueFromAmount(0LL).write() == "0.00000000");
BOOST_CHECK_EQUAL(write_string(ValueFromAmount(1LL), false), "0.00000001"); BOOST_CHECK(ValueFromAmount(1LL).write() == "0.00000001");
BOOST_CHECK_EQUAL(write_string(ValueFromAmount(17622195LL), false), "0.17622195"); BOOST_CHECK(ValueFromAmount(17622195LL).write() == "0.17622195");
BOOST_CHECK_EQUAL(write_string(ValueFromAmount(50000000LL), false), "0.50000000"); BOOST_CHECK(ValueFromAmount(50000000LL).write() == "0.50000000");
BOOST_CHECK_EQUAL(write_string(ValueFromAmount(89898989LL), false), "0.89898989"); BOOST_CHECK(ValueFromAmount(89898989LL).write() == "0.89898989");
BOOST_CHECK_EQUAL(write_string(ValueFromAmount(100000000LL), false), "1.00000000"); BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000");
BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999990LL), false), "20999999.99999990"); BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990");
BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999999LL), false), "20999999.99999999"); BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999");
} }
static Value ValueFromString(const std::string &str) static Value ValueFromString(const std::string &str)
{ {
Value value; Value value;
BOOST_CHECK(read_string(str, value)); BOOST_CHECK(value.read(str));
return value; return value;
} }

22
src/test/script_tests.cpp

@ -26,9 +26,7 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include "json/json_spirit_reader_template.h" #include "json_spirit_wrapper.h"
#include "json/json_spirit_utils.h"
#include "json/json_spirit_writer_template.h"
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;
@ -46,7 +44,7 @@ read_json(const std::string& jsondata)
{ {
Value v; Value v;
if (!read_string(jsondata, v) || v.type() != array_type) if (!v.read(jsondata) || !v.isArray())
{ {
BOOST_ERROR("Parse error."); BOOST_ERROR("Parse error.");
return Array(); return Array();
@ -636,10 +634,9 @@ BOOST_AUTO_TEST_CASE(script_valid)
// scripts. // scripts.
Array tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid))); Array tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
BOOST_FOREACH(Value& tv, tests) for (unsigned int idx = 0; idx < tests.size(); idx++) {
{ Array test = tests[idx];
Array test = tv.get_array(); string strTest = test.write();
string strTest = write_string(tv, false);
if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments) if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments)
{ {
if (test.size() != 1) { if (test.size() != 1) {
@ -662,11 +659,10 @@ BOOST_AUTO_TEST_CASE(script_invalid)
// Scripts that should evaluate as invalid // Scripts that should evaluate as invalid
Array tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); Array tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
BOOST_FOREACH(Value& tv, tests) for (unsigned int idx = 0; idx < tests.size(); idx++) {
{ Array test = tests[idx];
Array test = tv.get_array(); string strTest = test.write();
string strTest = write_string(tv, false); if (test.size() < 3) // Allow size > 2; extra stuff ignored (useful for comments)
if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments)
{ {
if (test.size() != 1) { if (test.size() != 1) {
BOOST_ERROR("Bad test: " << strTest); BOOST_ERROR("Bad test: " << strTest);

11
src/test/sighash_tests.cpp

@ -16,9 +16,7 @@
#include <iostream> #include <iostream>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include "json/json_spirit_reader_template.h" #include "json_spirit_wrapper.h"
#include "json/json_spirit_utils.h"
#include "json/json_spirit_writer_template.h"
using namespace json_spirit; using namespace json_spirit;
extern Array read_json(const std::string& jsondata); extern Array read_json(const std::string& jsondata);
@ -170,10 +168,9 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
{ {
Array tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash))); Array tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash)));
BOOST_FOREACH(Value& tv, tests) for (unsigned int idx = 0; idx < tests.size(); idx++) {
{ Array test = tests[idx];
Array test = tv.get_array(); std::string strTest = test.write();
std::string strTest = write_string(tv, false);
if (test.size() < 1) // Allow for extra stuff (useful for comments) if (test.size() < 1) // Allow for extra stuff (useful for comments)
{ {
BOOST_ERROR("Bad test: " << strTest); BOOST_ERROR("Bad test: " << strTest);

33
src/test/transaction_tests.cpp

@ -22,7 +22,8 @@
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
#include "json/json_spirit_writer_template.h"
#include "json_spirit_wrapper.h"
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;
@ -90,14 +91,21 @@ BOOST_AUTO_TEST_CASE(tx_valid)
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE" // verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
<<<<<<< HEAD
ScriptError err; ScriptError err;
BOOST_FOREACH(Value& tv, tests) BOOST_FOREACH(Value& tv, tests)
{ {
Array test = tv.get_array(); Array test = tv.get_array();
string strTest = write_string(tv, false); string strTest = write_string(tv, false);
if (test[0].type() == array_type) if (test[0].type() == array_type)
=======
for (unsigned int idx = 0; idx < tests.size(); idx++) {
Array test = tests[idx];
string strTest = test.write();
if (test[0].isArray())
>>>>>>> Convert tree to using univalue. Eliminate all json_spirit uses.
{ {
if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type) if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
{ {
BOOST_ERROR("Bad test: " << strTest); BOOST_ERROR("Bad test: " << strTest);
continue; continue;
@ -106,9 +114,9 @@ BOOST_AUTO_TEST_CASE(tx_valid)
map<COutPoint, CScript> mapprevOutScriptPubKeys; map<COutPoint, CScript> mapprevOutScriptPubKeys;
Array inputs = test[0].get_array(); Array inputs = test[0].get_array();
bool fValid = true; bool fValid = true;
BOOST_FOREACH(Value& input, inputs) for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
{ const Value& input = inputs[inpIdx];
if (input.type() != array_type) if (!input.isArray())
{ {
fValid = false; fValid = false;
break; break;
@ -166,14 +174,21 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE" // verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid))); Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
<<<<<<< HEAD
ScriptError err; ScriptError err;
BOOST_FOREACH(Value& tv, tests) BOOST_FOREACH(Value& tv, tests)
{ {
Array test = tv.get_array(); Array test = tv.get_array();
string strTest = write_string(tv, false); string strTest = write_string(tv, false);
if (test[0].type() == array_type) if (test[0].type() == array_type)
=======
for (unsigned int idx = 0; idx < tests.size(); idx++) {
Array test = tests[idx];
string strTest = test.write();
if (test[0].isArray())
>>>>>>> Convert tree to using univalue. Eliminate all json_spirit uses.
{ {
if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type) if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
{ {
BOOST_ERROR("Bad test: " << strTest); BOOST_ERROR("Bad test: " << strTest);
continue; continue;
@ -182,9 +197,9 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
map<COutPoint, CScript> mapprevOutScriptPubKeys; map<COutPoint, CScript> mapprevOutScriptPubKeys;
Array inputs = test[0].get_array(); Array inputs = test[0].get_array();
bool fValid = true; bool fValid = true;
BOOST_FOREACH(Value& input, inputs) for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
{ const Value& input = inputs[inpIdx];
if (input.type() != array_type) if (!input.isArray())
{ {
fValid = false; fValid = false;
break; break;

84
src/univalue/univalue.h

@ -11,6 +11,10 @@
#include <map> #include <map>
#include <cassert> #include <cassert>
#include <sstream> // .get_int64()
#include <utility> // std::pair
#include <stdlib.h> // atoi(), atof() TODO: remove
class UniValue { class UniValue {
public: public:
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
@ -130,8 +134,88 @@ private:
int findKey(const std::string& key) const; int findKey(const std::string& key) const;
void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
public:
//
// The following were added for compatibility with json_spirit.
// Most duplicate other methods, and should be removed.
//
std::vector<std::string> getKeys() const { return keys; }
std::vector<UniValue> getValues() const { return values; }
bool get_bool() const { return getBool(); }
std::string get_str() const { return getValStr(); }
int get_int() const { return atoi(getValStr().c_str()); }
double get_real() const { return atof(getValStr().c_str()); }
const UniValue& get_obj() const { return *this; }
const UniValue& get_array() const { return *this; }
enum VType type() const { return getType(); }
bool push_back(std::pair<std::string,UniValue> pear) {
return pushKV(pear.first, pear.second);
}
int64_t get_int64() const {
int64_t ret;
std::istringstream(getValStr()) >> ret;
return ret;
}
}; };
//
// The following were added for compatibility with json_spirit.
// Most duplicate other methods, and should be removed.
//
static inline std::pair<std::string,UniValue> Pair(const char *cKey, const char *cVal)
{
std::string key(cKey);
UniValue uVal(cVal);
return std::make_pair(key, uVal);
}
static inline std::pair<std::string,UniValue> Pair(const char *cKey, std::string strVal)
{
std::string key(cKey);
UniValue uVal(strVal);
return std::make_pair(key, uVal);
}
static inline std::pair<std::string,UniValue> Pair(const char *cKey, uint64_t u64Val)
{
std::string key(cKey);
UniValue uVal(u64Val);
return std::make_pair(key, uVal);
}
static inline std::pair<std::string,UniValue> Pair(const char *cKey, int64_t i64Val)
{
std::string key(cKey);
UniValue uVal(i64Val);
return std::make_pair(key, uVal);
}
static inline std::pair<std::string,UniValue> Pair(const char *cKey, int iVal)
{
std::string key(cKey);
UniValue uVal(iVal);
return std::make_pair(key, uVal);
}
static inline std::pair<std::string,UniValue> Pair(const char *cKey, double dVal)
{
std::string key(cKey);
UniValue uVal(dVal);
return std::make_pair(key, uVal);
}
static inline std::pair<std::string,UniValue> Pair(const char *cKey, const UniValue& uVal)
{
std::string key(cKey);
return std::make_pair(key, uVal);
}
static inline std::pair<std::string,UniValue> Pair(std::string key, const UniValue& uVal)
{
return std::make_pair(key, uVal);
}
enum jtokentype { enum jtokentype {
JTOK_ERR = -1, JTOK_ERR = -1,
JTOK_NONE = 0, // eof JTOK_NONE = 0, // eof

14
src/wallet/rpcdump.cpp

@ -19,7 +19,7 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include "json/json_spirit_value.h" #include "json_spirit_wrapper.h"
using namespace json_spirit; using namespace json_spirit;
using namespace std; using namespace std;
@ -126,7 +126,7 @@ Value importprivkey(const Array& params, bool fHelp)
// Don't throw error in case a key is already there // Don't throw error in case a key is already there
if (pwalletMain->HaveKey(vchAddress)) if (pwalletMain->HaveKey(vchAddress))
return Value::null; return NullUniValue;
pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;
@ -141,7 +141,7 @@ Value importprivkey(const Array& params, bool fHelp)
} }
} }
return Value::null; return NullUniValue;
} }
Value importaddress(const Array& params, bool fHelp) Value importaddress(const Array& params, bool fHelp)
@ -200,7 +200,7 @@ Value importaddress(const Array& params, bool fHelp)
// Don't throw error in case an address is already there // Don't throw error in case an address is already there
if (pwalletMain->HaveWatchOnly(script)) if (pwalletMain->HaveWatchOnly(script))
return Value::null; return NullUniValue;
pwalletMain->MarkDirty(); pwalletMain->MarkDirty();
@ -214,7 +214,7 @@ Value importaddress(const Array& params, bool fHelp)
} }
} }
return Value::null; return NullUniValue;
} }
Value importwallet(const Array& params, bool fHelp) Value importwallet(const Array& params, bool fHelp)
@ -318,7 +318,7 @@ Value importwallet(const Array& params, bool fHelp)
if (!fGood) if (!fGood)
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
return Value::null; return NullUniValue;
} }
Value dumpprivkey(const Array& params, bool fHelp) Value dumpprivkey(const Array& params, bool fHelp)
@ -421,5 +421,5 @@ Value dumpwallet(const Array& params, bool fHelp)
file << "\n"; file << "\n";
file << "# End of dump\n"; file << "# End of dump\n";
file.close(); file.close();
return Value::null; return NullUniValue;
} }

64
src/wallet/rpcwallet.cpp

@ -21,8 +21,7 @@
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h" #include "json_spirit_wrapper.h"
#include "json/json_spirit_value.h"
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;
@ -275,7 +274,7 @@ Value setaccount(const Array& params, bool fHelp)
else else
throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address"); throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
return Value::null; return NullUniValue;
} }
@ -419,9 +418,9 @@ Value sendtoaddress(const Array& params, bool fHelp)
// Wallet comments // Wallet comments
CWalletTx wtx; CWalletTx wtx;
if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty()) if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
wtx.mapValue["comment"] = params[2].get_str(); wtx.mapValue["comment"] = params[2].get_str();
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
wtx.mapValue["to"] = params[3].get_str(); wtx.mapValue["to"] = params[3].get_str();
bool fSubtractFeeFromAmount = false; bool fSubtractFeeFromAmount = false;
@ -896,9 +895,9 @@ Value sendfrom(const Array& params, bool fHelp)
CWalletTx wtx; CWalletTx wtx;
wtx.strFromAccount = strAccount; wtx.strFromAccount = strAccount;
if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty()) if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
wtx.mapValue["comment"] = params[4].get_str(); wtx.mapValue["comment"] = params[4].get_str();
if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty()) if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
wtx.mapValue["to"] = params[5].get_str(); wtx.mapValue["to"] = params[5].get_str();
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked();
@ -965,7 +964,7 @@ Value sendmany(const Array& params, bool fHelp)
CWalletTx wtx; CWalletTx wtx;
wtx.strFromAccount = strAccount; wtx.strFromAccount = strAccount;
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
wtx.mapValue["comment"] = params[3].get_str(); wtx.mapValue["comment"] = params[3].get_str();
Array subtractFeeFromAmount; Array subtractFeeFromAmount;
@ -976,18 +975,19 @@ Value sendmany(const Array& params, bool fHelp)
vector<CRecipient> vecSend; vector<CRecipient> vecSend;
CAmount totalAmount = 0; CAmount totalAmount = 0;
BOOST_FOREACH(const Pair& s, sendTo) vector<string> keys = sendTo.getKeys();
BOOST_FOREACH(const string& name_, keys)
{ {
CBitcoinAddress address(s.name_); CBitcoinAddress address(name_);
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
if (setAddress.count(address)) if (setAddress.count(address))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
setAddress.insert(address); setAddress.insert(address);
CScript scriptPubKey = GetScriptForDestination(address.Get()); CScript scriptPubKey = GetScriptForDestination(address.Get());
CAmount nAmount = AmountFromValue(s.value_); CAmount nAmount = AmountFromValue(sendTo[name_]);
totalAmount += nAmount; totalAmount += nAmount;
bool fSubtractFeeFromAmount = false; bool fSubtractFeeFromAmount = false;
@ -1472,15 +1472,21 @@ Value listtransactions(const Array& params, bool fHelp)
nFrom = ret.size(); nFrom = ret.size();
if ((nFrom + nCount) > (int)ret.size()) if ((nFrom + nCount) > (int)ret.size())
nCount = ret.size() - nFrom; nCount = ret.size() - nFrom;
Array::iterator first = ret.begin();
vector<UniValue> arrTmp = ret.getValues();
vector<UniValue>::iterator first = arrTmp.begin();
std::advance(first, nFrom); std::advance(first, nFrom);
Array::iterator last = ret.begin(); vector<UniValue>::iterator last = arrTmp.begin();
std::advance(last, nFrom+nCount); std::advance(last, nFrom+nCount);
if (last != ret.end()) ret.erase(last, ret.end()); if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
if (first != ret.begin()) ret.erase(ret.begin(), first); if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
std::reverse(ret.begin(), ret.end()); // Return oldest to newest std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
ret.clear();
ret.push_backV(arrTmp);
return ret; return ret;
} }
@ -1756,7 +1762,7 @@ Value backupwallet(const Array& params, bool fHelp)
if (!BackupWallet(*pwalletMain, strDest)) if (!BackupWallet(*pwalletMain, strDest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
return Value::null; return NullUniValue;
} }
@ -1793,7 +1799,7 @@ Value keypoolrefill(const Array& params, bool fHelp)
if (pwalletMain->GetKeyPoolSize() < kpSize) if (pwalletMain->GetKeyPoolSize() < kpSize)
throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool."); throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
return Value::null; return NullUniValue;
} }
@ -1860,7 +1866,7 @@ Value walletpassphrase(const Array& params, bool fHelp)
nWalletUnlockTime = GetTime() + nSleepTime; nWalletUnlockTime = GetTime() + nSleepTime;
RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime); RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
return Value::null; return NullUniValue;
} }
@ -1906,7 +1912,7 @@ Value walletpassphrasechange(const Array& params, bool fHelp)
if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
return Value::null; return NullUniValue;
} }
@ -1945,7 +1951,7 @@ Value walletlock(const Array& params, bool fHelp)
nWalletUnlockTime = 0; nWalletUnlockTime = 0;
} }
return Value::null; return NullUniValue;
} }
@ -2050,9 +2056,9 @@ Value lockunspent(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
if (params.size() == 1) if (params.size() == 1)
RPCTypeCheck(params, boost::assign::list_of(bool_type)); RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
else else
RPCTypeCheck(params, boost::assign::list_of(bool_type)(array_type)); RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
bool fUnlock = params[0].get_bool(); bool fUnlock = params[0].get_bool();
@ -2063,13 +2069,13 @@ Value lockunspent(const Array& params, bool fHelp)
} }
Array outputs = params[1].get_array(); Array outputs = params[1].get_array();
BOOST_FOREACH(Value& output, outputs) for (unsigned int idx = 0; idx < outputs.size(); idx++) {
{ const UniValue& output = outputs[idx];
if (output.type() != obj_type) if (!output.isObject())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
const Object& o = output.get_obj(); const Object& o = output.get_obj();
RPCTypeCheck(o, boost::assign::map_list_of("txid", str_type)("vout", int_type)); RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
string txid = find_value(o, "txid").get_str(); string txid = find_value(o, "txid").get_str();
if (!IsHex(txid)) if (!IsHex(txid))

Loading…
Cancel
Save