From 15982a8b69ec6ab3c3a6bf71fc6a9b681d3ff541 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 20 Aug 2014 15:15:16 -0400 Subject: [PATCH] Convert tree to using univalue. Eliminate all json_spirit uses. --- src/Makefile.am | 1 + src/bitcoin-cli.cpp | 20 ++++---- src/json_spirit_wrapper.h | 17 +++++++ src/qt/rpcconsole.cpp | 18 +++++--- src/rpcblockchain.cpp | 16 +++++-- src/rpcclient.cpp | 2 +- src/rpcclient.h | 4 +- src/rpcmining.cpp | 19 ++++---- src/rpcmisc.cpp | 5 +- src/rpcnet.cpp | 8 ++-- src/rpcprotocol.cpp | 10 ++-- src/rpcprotocol.h | 4 +- src/rpcrawtransaction.cpp | 47 ++++++++++--------- src/rpcserver.cpp | 51 +++++++++++---------- src/rpcserver.h | 18 ++++---- src/test/base58_tests.cpp | 40 +++++++--------- src/test/rpc_tests.cpp | 18 ++++---- src/test/script_tests.cpp | 22 ++++----- src/test/sighash_tests.cpp | 11 ++--- src/test/transaction_tests.cpp | 33 +++++++++---- src/univalue/univalue.h | 84 ++++++++++++++++++++++++++++++++++ src/wallet/rpcdump.cpp | 14 +++--- src/wallet/rpcwallet.cpp | 64 ++++++++++++++------------ 23 files changed, 321 insertions(+), 205 deletions(-) create mode 100644 src/json_spirit_wrapper.h diff --git a/src/Makefile.am b/src/Makefile.am index 1c2f77041..63332f9ac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -342,6 +342,7 @@ endif bitcoin_cli_LDADD = \ $(LIBBITCOIN_CLI) \ + $(LIBBITCOIN_UNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBSECP256K1) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 1269d7a11..9950153a6 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -143,7 +143,7 @@ Object CallRPC(const string& strMethod, const Array& params) // Parse reply Value valReply; - if (!read_string(strReply, valReply)) + if (!valReply.read(strReply)) throw runtime_error("couldn't parse reply from server"); const Object& reply = valReply.get_obj(); if (reply.empty()) @@ -176,29 +176,27 @@ int CommandLineRPC(int argc, char *argv[]) const bool fWait = GetBoolArg("-rpcwait", false); do { try { - const Object reply = CallRPC(strMethod, params); + // Execute + Object reply = CallRPC(strMethod, params); // Parse reply const Value& result = find_value(reply, "result"); const Value& error = find_value(reply, "error"); - if (error.type() != null_type) { + if (!error.isNull()) { // Error - const int code = find_value(error.get_obj(), "code").get_int(); - if (fWait && code == RPC_IN_WARMUP) - throw CConnectionFailed("server in warmup"); - strPrint = "error: " + write_string(error, false); + strPrint = "error: " + error.write(); + int code = error["code"].get_int(); nRet = abs(code); } else { // Result - if (result.type() == null_type) + if (result.isNull()) strPrint = ""; - else if (result.type() == str_type) + else if (result.isStr()) strPrint = result.get_str(); else - strPrint = write_string(result, true); + strPrint = result.write(2); } - // Connection succeeded, no need to retry. break; } diff --git a/src/json_spirit_wrapper.h b/src/json_spirit_wrapper.h new file mode 100644 index 000000000..1962cf643 --- /dev/null +++ b/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__ diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 29c971ec7..29b1e8f26 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -16,10 +16,10 @@ #include "rpcclient.h" #include "util.h" -#include "json/json_spirit_value.h" - #include +#include "univalue/univalue.h" + #ifdef ENABLE_WALLET #include #endif @@ -167,21 +167,25 @@ void RPCExecutor::request(const QString &command) std::string strPrint; // Convert argument list to JSON objects in method-dependent way, // and pass it along with the method name to the dispatcher. - json_spirit::Value result = tableRPC.execute( + UniValue result = tableRPC.execute( args[0], RPCConvertValues(args[0], std::vector(args.begin() + 1, args.end()))); // Format result reply - if (result.type() == json_spirit::null_type) + if (result.isNull()) strPrint = ""; - else if (result.type() == json_spirit::str_type) + else if (result.isStr()) strPrint = result.get_str(); else - strPrint = write_string(result, true); + strPrint = result.write(2); emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); } +<<<<<<< HEAD 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 { @@ -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 { // 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) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 79528db2f..2f9fd5e04 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -13,7 +13,7 @@ #include -#include "json/json_spirit_value.h" +#include "json_spirit_wrapper.h" using namespace json_spirit; using namespace std; @@ -206,7 +206,13 @@ Value getrawmempool(const Array& params, bool fHelp) if (mempool.exists(txin.prevout.hash)) 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)); o.push_back(Pair(hash.ToString(), info)); } @@ -412,14 +418,14 @@ Value gettxout(const Array& params, bool fHelp) LOCK(mempool.cs); CCoinsViewMemPool view(pcoinsTip, mempool); if (!view.GetCoins(hash, coins)) - return Value::null; + return NullUniValue; mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool } else { if (!pcoinsTip->GetCoins(hash, coins)) - return Value::null; + return NullUniValue; } 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()); CBlockIndex *pindex = it->second; diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 4b576b370..d8c4da420 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -135,7 +135,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector& strParams); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 528d5406f..4571269c3 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -24,8 +24,7 @@ #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" +#include "json_spirit_wrapper.h" using namespace json_spirit; using namespace std; @@ -216,7 +215,7 @@ Value setgenerate(const Array& params, bool fHelp) mapArgs ["-genproclimit"] = itostr(nGenProcLimit); GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); - return Value::null; + return NullUniValue; } #endif @@ -382,14 +381,14 @@ Value getblocktemplate(const Array& params, bool fHelp) LOCK(cs_main); std::string strMode = "template"; - Value lpval = Value::null; + Value lpval = NullUniValue; if (params.size() > 0) { const Object& oparam = params[0].get_obj(); const Value& modeval = find_value(oparam, "mode"); - if (modeval.type() == str_type) + if (modeval.isStr()) strMode = modeval.get_str(); - else if (modeval.type() == null_type) + else if (modeval.isNull()) { /* Do nothing */ } @@ -439,14 +438,14 @@ Value getblocktemplate(const Array& params, bool fHelp) 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 uint256 hashWatchedChain; boost::system_time checktxtime; unsigned int nTransactionsUpdatedLastLP; - if (lpval.type() == str_type) + if (lpval.isStr()) { // Format: std::string lpstr = lpval.get_str(); @@ -686,7 +685,7 @@ Value estimatefee(const Array& params, bool fHelp) + 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(); if (nBlocks < 1) @@ -718,7 +717,7 @@ Value estimatepriority(const Array& params, bool fHelp) + 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(); if (nBlocks < 1) diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index f5bef2a07..f7bd3e0d5 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -20,8 +20,7 @@ #include #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" +#include "json_spirit_wrapper.h" using namespace json_spirit; using namespace std; @@ -204,7 +203,7 @@ Value validateaddress(const Array& params, bool fHelp) if (mine != ISMINE_NO) { ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false)); 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)) ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index bdee5b9f2..3f46be0cc 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -16,7 +16,7 @@ #include -#include "json/json_spirit_value.h" +#include "json_spirit_wrapper.h" using namespace json_spirit; using namespace std; @@ -59,7 +59,7 @@ Value ping(const Array& params, bool fHelp) pNode->fPingQueued = true; } - return Value::null; + return NullUniValue; } static void CopyNodeStats(std::vector& vstats) @@ -190,7 +190,7 @@ Value addnode(const Array& params, bool fHelp) { CAddress addr; OpenNetworkConnection(addr, NULL, strNode.c_str()); - return Value::null; + return NullUniValue; } LOCK(cs_vAddedNodes); @@ -212,7 +212,7 @@ Value addnode(const Array& params, bool fHelp) vAddedNodes.erase(it); } - return Value::null; + return NullUniValue; } Value getaddednodeinfo(const Array& params, bool fHelp) diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp index 95d6b9e53..72a7b7634 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -23,7 +23,7 @@ #include #include #include -#include "json/json_spirit_writer_template.h" +#include "json_spirit_wrapper.h" using namespace std; 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("params", params)); 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 reply; - if (error.type() != null_type) - reply.push_back(Pair("result", Value::null)); + if (!error.isNull()) + reply.push_back(Pair("result", NullUniValue)); else reply.push_back(Pair("result", result)); 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) { Object reply = JSONRPCReplyObj(result, error, id); - return write_string(Value(reply), false) + "\n"; + return reply.write() + "\n"; } Object JSONRPCError(int code, const string& message) diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h index 4f3f70fb3..496e19ed5 100644 --- a/src/rpcprotocol.h +++ b/src/rpcprotocol.h @@ -15,9 +15,7 @@ #include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" +#include "json_spirit_wrapper.h" //! HTTP status codes enum HTTPStatusCode diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 3e37b797e..8d2b035f3 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -25,8 +25,7 @@ #include #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" +#include "json_spirit_wrapper.h" using namespace json_spirit; using namespace std; @@ -343,20 +342,21 @@ Value createrawtransaction(const Array& params, bool fHelp) ); 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(); Object sendTo = params[1].get_obj(); 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(); uint256 txid = ParseHashO(o, "txid"); 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"); int nOutput = vout_v.get_int(); if (nOutput < 0) @@ -367,17 +367,18 @@ Value createrawtransaction(const Array& params, bool fHelp) } set setAddress; - BOOST_FOREACH(const Pair& s, sendTo) { - CBitcoinAddress address(s.name_); + vector addrList = sendTo.getKeys(); + BOOST_FOREACH(const string& name_, addrList) { + CBitcoinAddress address(name_); 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)) - 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); CScript scriptPubKey = GetScriptForDestination(address.Get()); - CAmount nAmount = AmountFromValue(s.value_); + CAmount nAmount = AmountFromValue(sendTo[name_]); CTxOut out(nAmount, scriptPubKey); rawTx.vout.push_back(out); @@ -438,7 +439,7 @@ Value decoderawtransaction(const Array& params, bool fHelp) ); LOCK(cs_main); - RPCTypeCheck(params, boost::assign::list_of(str_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); CTransaction tx; @@ -570,7 +571,7 @@ Value signrawtransaction(const Array& params, bool fHelp) #else LOCK(cs_main); #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 txData(ParseHexV(params[0], "argument 1")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); @@ -613,10 +614,11 @@ Value signrawtransaction(const Array& params, bool fHelp) bool fGivenKeys = false; CBasicKeyStore tempKeystore; - if (params.size() > 2 && params[2].type() != null_type) { + if (params.size() > 2 && !params[2].isNull()) { fGivenKeys = true; 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; bool fGood = vchSecret.SetString(k.get_str()); if (!fGood) @@ -633,15 +635,16 @@ Value signrawtransaction(const Array& params, bool fHelp) #endif // 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(); - BOOST_FOREACH(Value& p, prevTxs) { - if (p.type() != obj_type) + for (unsigned int idx = 0; idx < prevTxs.size(); idx++) { + const Value& p = prevTxs[idx]; + if (!p.isObject()) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); 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"); @@ -669,9 +672,9 @@ Value signrawtransaction(const Array& params, bool fHelp) // if redeemScript given and not using the local wallet (private keys // given), add redeemScript to the tempKeystore so it can be signed: 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"); - if (!(v == Value::null)) { + if (!v.isNull()) { vector rsData(ParseHexV(v, "redeemScript")); CScript redeemScript(rsData.begin(), rsData.end()); tempKeystore.AddCScript(redeemScript); @@ -687,7 +690,7 @@ Value signrawtransaction(const Array& params, bool fHelp) #endif int nHashType = SIGHASH_ALL; - if (params.size() > 3 && params[3].type() != null_type) { + if (params.size() > 3 && !params[3].isNull()) { static map mapSigHashValues = boost::assign::map_list_of (string("ALL"), int(SIGHASH_ALL)) @@ -769,7 +772,7 @@ Value sendrawtransaction(const Array& params, bool fHelp) ); 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 CTransaction tx; diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 3f74517a6..da0a8048b 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -27,7 +27,8 @@ #include #include #include -#include "json/json_spirit_writer_template.h" + +#include "json_spirit_wrapper.h" using namespace boost::asio; using namespace json_spirit; @@ -89,30 +90,30 @@ void RPCTypeCheck(const Array& params, break; 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", - Value_type_name[t], Value_type_name[v.type()]); + uvTypeName(t), uvTypeName(v.type())); throw JSONRPCError(RPC_TYPE_ERROR, err); } i++; } } -void RPCTypeCheck(const Object& o, - const map& typesExpected, +void RPCTypeCheckObj(const UniValue& o, + const map& typesExpected, bool fAllowNull) { BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected) { 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)); - 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", - 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); } } @@ -142,7 +143,7 @@ Value ValueFromAmount(const CAmount& amount) uint256 ParseHashV(const Value& v, string strName) { string strHex; - if (v.type() == str_type) + if (v.isStr()) strHex = v.get_str(); if (!IsHex(strHex)) // Note: IsHex("") is false throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); @@ -157,7 +158,7 @@ uint256 ParseHashO(const Object& o, string strKey) vector ParseHexV(const Value& v, string strName) { string strHex; - if (v.type() == str_type) + if (v.isStr()) strHex = v.get_str(); if (!IsHex(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(); if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST; 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; } @@ -828,14 +829,14 @@ public: string strMethod; Array params; - JSONRequest() { id = Value::null; } + JSONRequest() { id = NullUniValue; } void parse(const Value& valRequest); }; void JSONRequest::parse(const Value& valRequest) { // Parse request - if (valRequest.type() != obj_type) + if (!valRequest.isObject()) throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object"); const Object& request = valRequest.get_obj(); @@ -844,9 +845,9 @@ void JSONRequest::parse(const Value& valRequest) // Parse method Value valMethod = find_value(request, "method"); - if (valMethod.type() == null_type) + if (valMethod.isNull()) 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"); strMethod = valMethod.get_str(); if (strMethod != "getblocktemplate") @@ -854,9 +855,9 @@ void JSONRequest::parse(const Value& valRequest) // Parse params Value valParams = find_value(request, "params"); - if (valParams.type() == array_type) + if (valParams.isArray()) params = valParams.get_array(); - else if (valParams.type() == null_type) + else if (valParams.isNull()) params = Array(); else throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array"); @@ -872,15 +873,15 @@ static Object JSONRPCExecOne(const Value& req) jreq.parse(req); 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) { - rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id); + rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id); } catch (const std::exception& e) { - rpc_result = JSONRPCReplyObj(Value::null, + rpc_result = JSONRPCReplyObj(NullUniValue, 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++) ret.push_back(JSONRPCExecOne(vReq[reqIdx])); - return write_string(Value(ret), false) + "\n"; + return ret.write() + "\n"; } static bool HTTPReq_JSONRPC(AcceptedConnection *conn, @@ -925,7 +926,7 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, { // Parse request Value valRequest; - if (!read_string(strRequest, valRequest)) + if (!valRequest.read(strRequest)) throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); // Return immediately if in warmup @@ -938,16 +939,16 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, string strReply; // singleton request - if (valRequest.type() == obj_type) { + if (valRequest.isObject()) { jreq.parse(valRequest); Value result = tableRPC.execute(jreq.strMethod, jreq.params); // Send reply - strReply = JSONRPCReply(result, Value::null, jreq.id); + strReply = JSONRPCReply(result, NullUniValue, jreq.id); // array of requests - } else if (valRequest.type() == array_type) + } else if (valRequest.isArray()) strReply = JSONRPCExecBatch(valRequest.get_array()); else throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); diff --git a/src/rpcserver.h b/src/rpcserver.h index 30a5b28db..c9982bb8c 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -15,9 +15,8 @@ #include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" +#include +#include "json_spirit_wrapper.h" class CRPCCommand; @@ -73,12 +72,13 @@ bool RPCIsInWarmup(std::string *statusOut); */ void RPCTypeCheck(const json_spirit::Array& params, const std::list& 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)); - */ -void RPCTypeCheck(const json_spirit::Object& o, - const std::map& typesExpected, bool fAllowNull=false); + +/* + 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 RPCTypeCheckObj(const UniValue& o, + const std::map& typesExpected, bool fAllowNull=false); /** * Run func nSeconds from now. Uses boost deadline timers. diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index f07dd7a7d..a806fe7b0 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -17,9 +17,7 @@ #include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" +#include "json_spirit_wrapper.h" using namespace json_spirit; 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) { 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) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + Array test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 2) // Allow for extra stuff (useful for comments) { 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))); std::vector result; - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + Array test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 2) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -130,10 +126,9 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) CBitcoinAddress addr; SelectParams(CBaseChainParams::MAIN); - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + Array test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 3) // Allow for extra stuff (useful for comments) { 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))); std::vector result; - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + + for (unsigned int idx = 0; idx < tests.size(); idx++) { + Array test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 3) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -256,10 +251,9 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid) CBitcoinSecret secret; CBitcoinAddress addr; - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + Array test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 1) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 5899671d2..fea826b65 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -111,20 +111,20 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) BOOST_AUTO_TEST_CASE(rpc_format_monetary_values) { - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(0LL), false), "0.00000000"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(1LL), false), "0.00000001"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(17622195LL), false), "0.17622195"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(50000000LL), false), "0.50000000"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(89898989LL), false), "0.89898989"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(100000000LL), false), "1.00000000"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999990LL), false), "20999999.99999990"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999999LL), false), "20999999.99999999"); + BOOST_CHECK(ValueFromAmount(0LL).write() == "0.00000000"); + BOOST_CHECK(ValueFromAmount(1LL).write() == "0.00000001"); + BOOST_CHECK(ValueFromAmount(17622195LL).write() == "0.17622195"); + BOOST_CHECK(ValueFromAmount(50000000LL).write() == "0.50000000"); + BOOST_CHECK(ValueFromAmount(89898989LL).write() == "0.89898989"); + BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000"); + BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990"); + BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999"); } static Value ValueFromString(const std::string &str) { Value value; - BOOST_CHECK(read_string(str, value)); + BOOST_CHECK(value.read(str)); return value; } diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index c0614cca4..b4cab3245 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -26,9 +26,7 @@ #include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" +#include "json_spirit_wrapper.h" using namespace std; using namespace json_spirit; @@ -46,7 +44,7 @@ read_json(const std::string& jsondata) { Value v; - if (!read_string(jsondata, v) || v.type() != array_type) + if (!v.read(jsondata) || !v.isArray()) { BOOST_ERROR("Parse error."); return Array(); @@ -636,10 +634,9 @@ BOOST_AUTO_TEST_CASE(script_valid) // scripts. Array tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid))); - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + Array test = tests[idx]; + string strTest = test.write(); if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments) { if (test.size() != 1) { @@ -662,11 +659,10 @@ BOOST_AUTO_TEST_CASE(script_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))); - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - string strTest = write_string(tv, false); - if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments) + for (unsigned int idx = 0; idx < tests.size(); idx++) { + Array test = tests[idx]; + string strTest = test.write(); + if (test.size() < 3) // Allow size > 2; extra stuff ignored (useful for comments) { if (test.size() != 1) { BOOST_ERROR("Bad test: " << strTest); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 87be2217c..121644ddc 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -16,9 +16,7 @@ #include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" +#include "json_spirit_wrapper.h" using namespace json_spirit; 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))); - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + Array test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 1) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index d12535e43..cdd88f348 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -22,7 +22,8 @@ #include #include #include -#include "json/json_spirit_writer_template.h" + +#include "json_spirit_wrapper.h" using namespace std; 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" Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); +<<<<<<< HEAD ScriptError err; BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); string strTest = write_string(tv, false); 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); continue; @@ -106,9 +114,9 @@ BOOST_AUTO_TEST_CASE(tx_valid) map mapprevOutScriptPubKeys; Array inputs = test[0].get_array(); bool fValid = true; - BOOST_FOREACH(Value& input, inputs) - { - if (input.type() != array_type) + for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { + const Value& input = inputs[inpIdx]; + if (!input.isArray()) { fValid = false; 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" Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid))); +<<<<<<< HEAD ScriptError err; BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); string strTest = write_string(tv, false); 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); continue; @@ -182,9 +197,9 @@ BOOST_AUTO_TEST_CASE(tx_invalid) map mapprevOutScriptPubKeys; Array inputs = test[0].get_array(); bool fValid = true; - BOOST_FOREACH(Value& input, inputs) - { - if (input.type() != array_type) + for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { + const Value& input = inputs[inpIdx]; + if (!input.isArray()) { fValid = false; break; diff --git a/src/univalue/univalue.h b/src/univalue/univalue.h index afe751ed9..28d6e3d3c 100644 --- a/src/univalue/univalue.h +++ b/src/univalue/univalue.h @@ -11,6 +11,10 @@ #include #include +#include // .get_int64() +#include // std::pair +#include // atoi(), atof() TODO: remove + class UniValue { public: enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; @@ -130,8 +134,88 @@ private: int findKey(const std::string& key) 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; + +public: + // + // The following were added for compatibility with json_spirit. + // Most duplicate other methods, and should be removed. + // + std::vector getKeys() const { return keys; } + std::vector 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 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 Pair(const char *cKey, const char *cVal) +{ + std::string key(cKey); + UniValue uVal(cVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, std::string strVal) +{ + std::string key(cKey); + UniValue uVal(strVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, uint64_t u64Val) +{ + std::string key(cKey); + UniValue uVal(u64Val); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, int64_t i64Val) +{ + std::string key(cKey); + UniValue uVal(i64Val); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, int iVal) +{ + std::string key(cKey); + UniValue uVal(iVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, double dVal) +{ + std::string key(cKey); + UniValue uVal(dVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, const UniValue& uVal) +{ + std::string key(cKey); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(std::string key, const UniValue& uVal) +{ + return std::make_pair(key, uVal); +} + enum jtokentype { JTOK_ERR = -1, JTOK_NONE = 0, // eof diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index ab951d1d7..68d2a21c4 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -19,7 +19,7 @@ #include #include -#include "json/json_spirit_value.h" +#include "json_spirit_wrapper.h" using namespace json_spirit; 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 if (pwalletMain->HaveKey(vchAddress)) - return Value::null; + return NullUniValue; 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) @@ -200,7 +200,7 @@ Value importaddress(const Array& params, bool fHelp) // Don't throw error in case an address is already there if (pwalletMain->HaveWatchOnly(script)) - return Value::null; + return NullUniValue; 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) @@ -318,7 +318,7 @@ Value importwallet(const Array& params, bool fHelp) if (!fGood) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); - return Value::null; + return NullUniValue; } Value dumpprivkey(const Array& params, bool fHelp) @@ -421,5 +421,5 @@ Value dumpwallet(const Array& params, bool fHelp) file << "\n"; file << "# End of dump\n"; file.close(); - return Value::null; + return NullUniValue; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3f55b0427..e743b1fa1 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -21,8 +21,7 @@ #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" +#include "json_spirit_wrapper.h" using namespace std; using namespace json_spirit; @@ -275,7 +274,7 @@ Value setaccount(const Array& params, bool fHelp) else 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 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(); - 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(); bool fSubtractFeeFromAmount = false; @@ -896,9 +895,9 @@ Value sendfrom(const Array& params, bool fHelp) CWalletTx wtx; 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(); - 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(); EnsureWalletIsUnlocked(); @@ -965,7 +964,7 @@ Value sendmany(const Array& params, bool fHelp) CWalletTx wtx; 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(); Array subtractFeeFromAmount; @@ -976,18 +975,19 @@ Value sendmany(const Array& params, bool fHelp) vector vecSend; CAmount totalAmount = 0; - BOOST_FOREACH(const Pair& s, sendTo) + vector keys = sendTo.getKeys(); + BOOST_FOREACH(const string& name_, keys) { - CBitcoinAddress address(s.name_); + CBitcoinAddress address(name_); 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)) - 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); CScript scriptPubKey = GetScriptForDestination(address.Get()); - CAmount nAmount = AmountFromValue(s.value_); + CAmount nAmount = AmountFromValue(sendTo[name_]); totalAmount += nAmount; bool fSubtractFeeFromAmount = false; @@ -1472,15 +1472,21 @@ Value listtransactions(const Array& params, bool fHelp) nFrom = ret.size(); if ((nFrom + nCount) > (int)ret.size()) nCount = ret.size() - nFrom; - Array::iterator first = ret.begin(); + + vector arrTmp = ret.getValues(); + + vector::iterator first = arrTmp.begin(); std::advance(first, nFrom); - Array::iterator last = ret.begin(); + vector::iterator last = arrTmp.begin(); std::advance(last, nFrom+nCount); - if (last != ret.end()) ret.erase(last, ret.end()); - if (first != ret.begin()) ret.erase(ret.begin(), first); + if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end()); + 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; } @@ -1756,7 +1762,7 @@ Value backupwallet(const Array& params, bool fHelp) if (!BackupWallet(*pwalletMain, strDest)) 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) 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; 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)) 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; } - return Value::null; + return NullUniValue; } @@ -2050,9 +2056,9 @@ Value lockunspent(const Array& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); if (params.size() == 1) - RPCTypeCheck(params, boost::assign::list_of(bool_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)); 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(); @@ -2063,13 +2069,13 @@ Value lockunspent(const Array& params, bool fHelp) } Array outputs = params[1].get_array(); - BOOST_FOREACH(Value& output, outputs) - { - if (output.type() != obj_type) + for (unsigned int idx = 0; idx < outputs.size(); idx++) { + const UniValue& output = outputs[idx]; + if (!output.isObject()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object"); 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(); if (!IsHex(txid))