From b20bbbbcb47f8835bee884e9c11e43e933a64aee Mon Sep 17 00:00:00 2001 From: 216k155 <216k155@luxcore.io> Date: Tue, 3 Apr 2018 09:23:45 +1000 Subject: [PATCH 01/17] Add getblockhashes --- src/rpcblockchain.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++ src/rpcclient.cpp | 3 +++ src/rpcserver.cpp | 1 + src/rpcserver.h | 4 ++- src/util.h | 10 +++++++- 5 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 296cc213..42ddbab1 100755 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -215,6 +215,64 @@ Value getrawmempool(const Array& params, bool fHelp) } } +Value getblockhashes(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2) + throw runtime_error( + "getblockhashes timestamp\n" + "\nReturns array of hashes of blocks within the timestamp range provided.\n" + "\nArguments:\n" + "1. high (numeric, required) The newer block timestamp\n" + "2. low (numeric, required) The older block timestamp\n" + "3. options (string, required) A json object\n" + " {\n" + " \"noOrphans\":true (boolean) will only include blocks on the main chain\n" + " \"logicalTimes\":true (boolean) will include logical timestamps with hashes\n" + " }\n" + "\nResult:\n" + "[\n" + " \"hash\" (string) The block hash\n" + "]\n" + "[\n" + " {\n" + " \"blockhash\": (string) The block hash\n" + " \"logicalts\": (numeric) The logical timestamp\n" + " }\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("getblockhashes", "1522073246 1521473246") + + HelpExampleRpc("getblockhashes", "1522073246, 1521473246") + + HelpExampleCli("getblockhashes", "1522073246 1521473246 '{\"noOrphans\":false, \"logicalTimes\":true}'") + ); + + unsigned int high = params[0].get_int(); + unsigned int low = params[1].get_int(); + bool fActiveOnly = false; + bool fLogicalTS = false; + Array a; + int nHeight = chainActive.Height(); + + unsigned time = GetTime(); + for (int i = 0; i <= nHeight; i++) { + int blockTime = getBlockTimeByHeight(i); + if(blockTime>low && blockTimeGetBlockHash().GetHex()); + } + } + return a; + +} + +int getBlockTimeByHeight(int nHeight){ + CBlock block; + CBlockIndex* pblockindex =chainActive[nHeight]; + std::string strHash = pblockindex->GetBlockHash().GetHex(); + uint256 hash(strHash); + CBlockIndex* pblockindex2 = mapBlockIndex[hash]; + return pblockindex2->GetBlockTime(); + } + Value getblockhash(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index e6f55d6d..7466ed6a 100755 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -72,6 +72,9 @@ static const CRPCConvertParam vRPCConvertParams[] = {"listunspent", 2}, {"getblock", 1}, {"getblockheader", 1}, + { "getblockhashes", 0 }, + { "getblockhashes", 1 }, + { "getblockhashes", 2 }, {"gettransaction", 1}, {"getrawtransaction", 1}, {"createrawtransaction", 0}, diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index cd75b349..85a209c8 100755 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -253,6 +253,7 @@ static const CRPCCommand vRPCCommands[] = {"blockchain", "getblockcount", &getblockcount, true, false, false}, {"blockchain", "getblock", &getblock, true, false, false}, {"blockchain", "getblockhash", &getblockhash, true, false, false}, + {"blockchain", "getblockhashes", &getblockhashes, true, false, false}, {"blockchain", "getblockheader", &getblockheader, false, false, false}, {"blockchain", "getchaintips", &getchaintips, true, false, false}, {"blockchain", "getpowdifficulty", &getpowdifficulty, true, false, false}, diff --git a/src/rpcserver.h b/src/rpcserver.h index ebcbab01..2bc8d8d5 100755 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -132,6 +132,7 @@ extern void InitRPCMining(); extern void ShutdownRPCMining(); extern int64_t nWalletUnlockTime; +extern int getBlockTimeByHeight(int nHeight); extern CAmount AmountFromValue(const json_spirit::Value& value); extern json_spirit::Value ValueFromAmount(const CAmount& amount); extern double GetPoWDifficulty(const CBlockIndex* blockindex = NULL); @@ -155,7 +156,6 @@ extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHel extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value bip38encrypt(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value bip38decrypt(const json_spirit::Array& params, bool fHelp); - extern json_spirit::Value setstakesplitthreshold(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getstakesplitthreshold(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp @@ -165,6 +165,7 @@ extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp); + extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value estimatefee(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value estimatepriority(const json_spirit::Array& params, bool fHelp); @@ -223,6 +224,7 @@ extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, b extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp +extern json_spirit::Value getblockhashes(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getpowdifficulty(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp); diff --git a/src/util.h b/src/util.h index 205e39a1..86894ae3 100755 --- a/src/util.h +++ b/src/util.h @@ -165,10 +165,18 @@ bool GetBoolArg(const std::string& strArg, bool fDefault); /** * Set an argument if it doesn't already have a value * - * @param strArg Argument to set (e.g. "-foo") + CBlock block; + CBlockIndex* pblockindex =chainActive[nHeight]; + std::string strHash = pblockindex->GetBlockHash().GetHex(); + uint256 hash(strHash); + CBlockIndex* pblockindex2 = mapBlockIndex[hash]; + // a.push_back(); + return pblockindex2; +} to set (e.g. "-foo") * @param strValue Value (e.g. "1") * @return true if argument gets set, false if it already had a value */ + bool SoftSetArg(const std::string& strArg, const std::string& strValue); /** From 2cc688fc5541b0d604c93af60e4b16a0cbc45ec4 Mon Sep 17 00:00:00 2001 From: 216k155 <216k155@luxcore.io> Date: Tue, 3 Apr 2018 09:58:46 +1000 Subject: [PATCH 02/17] reconsiderblock automatically applies to all descendants of a block, so this is working as intended. There is no such thing as priorities when invalidating/reconsidering. Only the first, setmocktime, required a change, the other two are thread safe. --- src/init.cpp | 22 +++++++++++ src/rpcblockchain.cpp | 17 ++++++++ src/rpcdump.cpp | 14 +++++++ src/rpcmining.cpp | 4 ++ src/rpcmisc.cpp | 13 ++++-- src/rpcnet.cpp | 8 +++- src/rpcrawtransaction.cpp | 11 +++++- src/rpcserver.cpp | 83 +++++++++++++++++---------------------- src/rpcserver.h | 10 +++++ src/rpcwallet.cpp | 36 +++++++++++++++++ 10 files changed, 166 insertions(+), 52 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 050733f2..8ddca311 100755 --- a/src/init.cpp +++ b/src/init.cpp @@ -290,6 +290,26 @@ bool static Bind(const CService& addr, unsigned int flags) return true; } +void OnRPCStopped() +{ + cvBlockChange.notify_all(); + LogPrint("rpc", "RPC stopped.\n"); +} + +void OnRPCPreCommand(const CRPCCommand& cmd) +{ +#ifdef ENABLE_WALLET + if (cmd.reqWallet && !pwalletMain) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); +#endif + + // Observe safe mode + string strWarning = GetWarnings("rpc"); + if (strWarning != "" && !GetBoolArg("-disablesafemode", false) && + !cmd.okSafeMode) + throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning); +} + std::string HelpMessage(HelpMessageMode mode) { // When adding new options to the categories, please keep and ensure alphabetical ordering. @@ -919,6 +939,8 @@ bool AppInit2(boost::thread_group& threadGroup) */ if (fServer) { uiInterface.InitMessage.connect(SetRPCWarmupStatus); + RPCServer::OnStopped(&OnRPCStopped); + RPCServer::OnPreCommand(&OnRPCPreCommand); StartRPCThreads(); } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 42ddbab1..29a12735 100755 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -113,6 +113,7 @@ Value getblockcount(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getblockcount", "") + HelpExampleRpc("getblockcount", "")); + LOCK(cs_main); return chainActive.Height(); } @@ -127,6 +128,7 @@ Value getbestblockhash(const Array& params, bool fHelp) "\nExamples\n" + HelpExampleCli("getbestblockhash", "") + HelpExampleRpc("getbestblockhash", "")); + LOCK(cs_main); return chainActive.Tip()->GetBlockHash().GetHex(); } @@ -141,6 +143,7 @@ Value getpowdifficulty(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getpowdifficulty", "") + HelpExampleRpc("getpowdifficulty", "")); + LOCK(cs_main); return GetPoWDifficulty(); } @@ -175,6 +178,8 @@ Value getrawmempool(const Array& params, bool fHelp) "\nExamples\n" + HelpExampleCli("getrawmempool", "true") + HelpExampleRpc("getrawmempool", "true")); + LOCK(cs_main); + bool fVerbose = false; if (params.size() > 0) fVerbose = params[0].get_bool(); @@ -245,6 +250,8 @@ Value getblockhashes(const Array& params, bool fHelp) + HelpExampleCli("getblockhashes", "1522073246 1521473246 '{\"noOrphans\":false, \"logicalTimes\":true}'") ); + LOCK(cs_main); + unsigned int high = params[0].get_int(); unsigned int low = params[1].get_int(); bool fActiveOnly = false; @@ -286,6 +293,8 @@ Value getblockhash(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getblockhash", "1000") + HelpExampleRpc("getblockhash", "1000")); + LOCK(cs_main); + int nHeight = params[0].get_int(); if (nHeight < 0 || nHeight > chainActive.Height()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); @@ -328,6 +337,8 @@ Value getblock(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") + HelpExampleRpc("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"")); + LOCK(cs_main); + std::string strHash = params[0].get_str(); uint256 hash(strHash); @@ -378,6 +389,8 @@ Value getblockheader(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getblockheader", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") + HelpExampleRpc("getblockheader", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"")); + LOCK(cs_main); + std::string strHash = params[0].get_str(); uint256 hash(strHash); @@ -424,6 +437,8 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("gettxoutsetinfo", "") + HelpExampleRpc("gettxoutsetinfo", "")); + LOCK(cs_main); + Object ret; CCoinsStats stats; @@ -529,6 +544,8 @@ Value verifychain(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("verifychain", "") + HelpExampleRpc("verifychain", "")); + LOCK(cs_main); + int nCheckLevel = GetArg("-checklevel", 3); int nCheckDepth = GetArg("-checkblocks", 288); if (params.size() > 0) diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 9d24c040..cdd8572f 100755 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -97,6 +97,8 @@ Value importprivkey(const Array& params, bool fHelp) "\nImport using a label and without rescan\n" + HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")); + LOCK2(cs_main, pwalletMain->cs_wallet); + EnsureWalletIsUnlocked(); string strSecret = params[0].get_str(); @@ -161,6 +163,8 @@ Value importaddress(const Array& params, bool fHelp) "\nImport using a label without rescan\n" + HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")); + LOCK2(cs_main, pwalletMain->cs_wallet); + CScript script; CBitcoinAddress address(params[0].get_str()); @@ -222,6 +226,8 @@ Value importwallet(const Array& params, bool fHelp) "\nImport the wallet\n" + HelpExampleCli("importwallet", "\"test\"") + "\nImport using the json rpc call\n" + HelpExampleRpc("importwallet", "\"test\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + EnsureWalletIsUnlocked(); ifstream file; @@ -318,6 +324,8 @@ Value dumpprivkey(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("dumpprivkey", "\"myaddress\"") + HelpExampleCli("importprivkey", "\"mykey\"") + HelpExampleRpc("dumpprivkey", "\"myaddress\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + EnsureWalletIsUnlocked(); string strAddress = params[0].get_str(); @@ -345,6 +353,8 @@ Value dumpwallet(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("dumpwallet", "\"test\"") + HelpExampleRpc("dumpwallet", "\"test\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + EnsureWalletIsUnlocked(); ofstream file; @@ -405,6 +415,8 @@ Value bip38encrypt(const Array& params, bool fHelp) "\"key\" (string) The encrypted private key\n" "\nExamples:\n"); + LOCK2(cs_main, pwalletMain->cs_wallet); + EnsureWalletIsUnlocked(); string strAddress = params[0].get_str(); @@ -444,6 +456,8 @@ Value bip38decrypt(const Array& params, bool fHelp) "\"key\" (string) The decrypted private key\n" "\nExamples:\n"); + LOCK2(cs_main, pwalletMain->cs_wallet); + EnsureWalletIsUnlocked(); /** Collect private key and passphrase **/ diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 692f12f6..e4ab65cd 100755 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -90,6 +90,8 @@ Value getnetworkhashps(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getnetworkhashps", "") + HelpExampleRpc("getnetworkhashps", "")); + LOCK(cs_main); + return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); } @@ -375,6 +377,8 @@ Value getblocktemplate(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getblocktemplate", "") + HelpExampleRpc("getblocktemplate", "")); + LOCK(cs_main); + std::string strMode = "template"; Value lpval = Value::null; if (params.size() > 0) { diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 0dbbd41e..b7d8289a 100755 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -75,6 +75,8 @@ Value getinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getinfo", "") + HelpExampleRpc("getinfo", "")); + LOCK(cs_main); + proxyType proxy; GetProxy(NET_IPV4, proxy); @@ -216,6 +218,8 @@ Value validateaddress(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")); + LOCK(cs_main); + CBitcoinAddress address(params[0].get_str()); bool isValid = address.IsValid(); @@ -359,9 +363,10 @@ Value verifymessage(const Array& params, bool fHelp) "\nVerify the signature\n" + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") + "\nAs json rpc\n" + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")); - string strAddress = params[0].get_str(); - string strSign = params[1].get_str(); - string strMessage = params[2].get_str(); + LOCK(cs_main); + string strAddress = params[0].get_str(); + string strSign = params[1].get_str(); + string strMessage = params[2].get_str(); CBitcoinAddress addr(strAddress); if (!addr.IsValid()) @@ -401,6 +406,8 @@ Value setmocktime(const Array& params, bool fHelp) if (!Params().MineBlocksOnDemand()) throw runtime_error("setmocktime for regression testing (-regtest mode) only"); + LOCK(cs_main); + RPCTypeCheck(params, boost::assign::list_of(int_type)); SetMockTime(params[0].get_int64()); diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index c003df67..cf310ab9 100755 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -34,7 +34,7 @@ Value getconnectioncount(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getconnectioncount", "") + HelpExampleRpc("getconnectioncount", "")); - LOCK(cs_vNodes); + LOCK2(cs_main, cs_vNodes); return (int)vNodes.size(); } @@ -50,7 +50,7 @@ Value ping(const Array& params, bool fHelp) HelpExampleCli("ping", "") + HelpExampleRpc("ping", "")); // Request that each node send a ping during next message processing pass - LOCK(cs_vNodes); + LOCK2(cs_main, cs_vNodes); BOOST_FOREACH (CNode* pNode, vNodes) { pNode->fPingQueued = true; } @@ -108,6 +108,8 @@ Value getpeerinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getpeerinfo", "") + HelpExampleRpc("getpeerinfo", "")); + LOCK(cs_main); + vector vstats; CopyNodeStats(vstats); @@ -380,6 +382,8 @@ Value getnetworkinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getnetworkinfo", "") + HelpExampleRpc("getnetworkinfo", "")); + LOCK(cs_main); + Object obj; obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("subversion", diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index f7471862..d75b8477 100755 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -169,6 +169,8 @@ Value getrawtransaction(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getrawtransaction", "\"mytxid\"") + HelpExampleCli("getrawtransaction", "\"mytxid\" 1") + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")); + LOCK(cs_main); + uint256 hash = ParseHashV(params[0], "parameter 1"); bool fVerbose = false; @@ -253,6 +255,7 @@ Value listunspent(const Array& params, bool fHelp) Array results; vector vecOutputs; assert(pwalletMain != NULL); + LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false); BOOST_FOREACH (const COutput& out, vecOutputs) { if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) @@ -421,6 +424,8 @@ Value decoderawtransaction(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("decoderawtransaction", "\"hexstring\"") + HelpExampleRpc("decoderawtransaction", "\"hexstring\"")); + LOCK(cs_main); + RPCTypeCheck(params, list_of(str_type)); CTransaction tx; @@ -457,6 +462,8 @@ Value decodescript(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("decodescript", "\"hexstring\"") + HelpExampleRpc("decodescript", "\"hexstring\"")); + LOCK(cs_main); + RPCTypeCheck(params, list_of(str_type)); Object r; @@ -579,7 +586,7 @@ Value signrawtransaction(const Array& params, bool fHelp) } } #ifdef ENABLE_WALLET - else + else if (pwalletMain) EnsureWalletIsUnlocked(); #endif @@ -699,6 +706,8 @@ Value sendrawtransaction(const Array& params, bool fHelp) "\nSend the transaction (signed hex)\n" + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + "\nAs a json rpc call\n" + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")); + LOCK(cs_main); + RPCTypeCheck(params, list_of(str_type)(bool_type)); // parse hex string from parameter diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 85a209c8..c5c44f2d 100755 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -12,6 +12,9 @@ #include "main.h" #include "ui_interface.h" #include "util.h" +#include "random.h" +#include "sync.h" +#include "utilstrencodings.h" #ifdef ENABLE_WALLET #include "wallet.h" #endif @@ -27,6 +30,7 @@ #include #include #include +#include using namespace boost; using namespace boost::asio; @@ -49,6 +53,34 @@ static boost::asio::io_service::work* rpc_dummy_work = NULL; static std::vector rpc_allow_subnets; //!< List of subnets to allow RPC connections from static std::vector > rpc_acceptors; +static struct CRPCSignals +{ + boost::signals2::signal Started; + boost::signals2::signal Stopped; + boost::signals2::signal PreCommand; + boost::signals2::signal PostCommand; +} g_rpcSignals; + +void RPCServer::OnStarted(boost::function slot) +{ + g_rpcSignals.Started.connect(slot); +} + +void RPCServer::OnStopped(boost::function slot) +{ + g_rpcSignals.Stopped.connect(slot); +} + +void RPCServer::OnPreCommand(boost::function slot) +{ + g_rpcSignals.PreCommand.connect(boost::bind(slot, _1)); +} + +void RPCServer::OnPostCommand(boost::function slot) +{ + g_rpcSignals.PostCommand.connect(boost::bind(slot, _1)); +} + void RPCTypeCheck(const Array& params, const list& typesExpected, bool fAllowNull) @@ -732,7 +764,7 @@ void StopRPCThreads() deadlineTimers.clear(); rpc_io_service->stop(); - cvBlockChange.notify_all(); + g_rpcSignals.Stopped(); if (rpc_worker_group != NULL) rpc_worker_group->join_all(); delete rpc_dummy_work; @@ -966,57 +998,16 @@ json_spirit::Value CRPCTable::execute(const std::string& strMethod, const json_s const CRPCCommand* pcmd = tableRPC[strMethod]; if (!pcmd) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); -#ifdef ENABLE_WALLET - if (pcmd->reqWallet && !pwalletMain) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); -#endif - - // Observe safe mode - string strWarning = GetWarnings("rpc"); - if (strWarning != "" && !GetBoolArg("-disablesafemode", false) && - !pcmd->okSafeMode) - throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning); + g_rpcSignals.PreCommand(*pcmd); try { // Execute - Value result; - { - if (pcmd->threadSafe) - result = pcmd->actor(params, false); -#ifdef ENABLE_WALLET - else if (!pwalletMain) { - LOCK(cs_main); - result = pcmd->actor(params, false); - } else { - while (true) { - TRY_LOCK(cs_main, lockMain); - if (!lockMain) { - MilliSleep(50); - continue; - } - while (true) { - TRY_LOCK(pwalletMain->cs_wallet, lockWallet); - if (!lockMain) { - MilliSleep(50); - continue; - } - result = pcmd->actor(params, false); - break; - } - break; - } - } -#else // ENABLE_WALLET - else { - LOCK(cs_main); - result = pcmd->actor(params, false); - } -#endif // !ENABLE_WALLET - } - return result; + return pcmd->actor(params, false); + } catch (std::exception& e) { throw JSONRPCError(RPC_MISC_ERROR, e.what()); } + g_rpcSignals.PostCommand(*pcmd); } std::string HelpExampleCli(string methodname, string args) diff --git a/src/rpcserver.h b/src/rpcserver.h index 2bc8d8d5..042f73db 100755 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -19,6 +19,16 @@ #include "json/json_spirit_utils.h" #include "json/json_spirit_writer_template.h" +class CRPCCommand; + +namespace RPCServer +{ + void OnStarted(boost::function slot); + void OnStopped(boost::function slot); + void OnPreCommand(boost::function slot); + void OnPostCommand(boost::function slot); +} + class CBlockIndex; class CNetAddr; diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index c71dd961..38ddc6c2 100755 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -92,6 +92,8 @@ Value getnewaddress(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getnewaddress", "") + HelpExampleCli("getnewaddress", "\"\"") + HelpExampleCli("getnewaddress", "\"myaccount\"") + HelpExampleRpc("getnewaddress", "\"myaccount\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + // Parse the account first so we don't generate a key if there's an error string strAccount; if (params.size() > 0) @@ -159,6 +161,8 @@ Value getaccountaddress(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getaccountaddress", "") + HelpExampleCli("getaccountaddress", "\"\"") + HelpExampleCli("getaccountaddress", "\"myaccount\"") + HelpExampleRpc("getaccountaddress", "\"myaccount\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + // Parse the account first so we don't generate a key if there's an error string strAccount = AccountFromValue(params[0]); @@ -182,6 +186,8 @@ Value getrawchangeaddress(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getrawchangeaddress", "") + HelpExampleRpc("getrawchangeaddress", "")); + LOCK2(cs_main, pwalletMain->cs_wallet); + if (!pwalletMain->IsLocked()) pwalletMain->TopUpKeyPool(); @@ -210,6 +216,8 @@ Value setaccount(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("setaccount", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\" \"tabby\"") + HelpExampleRpc("setaccount", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\", \"tabby\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + CBitcoinAddress address(params[0].get_str()); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid LUX address"); @@ -248,6 +256,8 @@ Value getaccount(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getaccount", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\"") + HelpExampleRpc("getaccount", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + CBitcoinAddress address(params[0].get_str()); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid LUX address"); @@ -276,6 +286,8 @@ Value getaddressesbyaccount(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getaddressesbyaccount", "\"tabby\"") + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + string strAccount = AccountFromValue(params[0]); // Find all addresses that have the given account @@ -510,6 +522,8 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) "\nThe amount with at least 6 confirmation, very safe\n" + HelpExampleCli("getreceivedbyaddress", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\" 6") + "\nAs a json rpc call\n" + HelpExampleRpc("getreceivedbyaddress", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\", 6")); + LOCK2(cs_main, pwalletMain->cs_wallet); + // lux address CBitcoinAddress address = CBitcoinAddress(params[0].get_str()); if (!address.IsValid()) @@ -558,6 +572,8 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) "\nThe amount with at least 6 confirmation, very safe\n" + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") + "\nAs a json rpc call\n" + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")); + LOCK2(cs_main, pwalletMain->cs_wallet); + // Minimum confirmations int nMinDepth = 1; if (params.size() > 1) @@ -640,6 +656,8 @@ Value getbalance(const Array& params, bool fHelp) "\nThe total amount in the account named tabby with at least 6 confirmations\n" + HelpExampleCli("getbalance", "\"tabby\" 6") + "\nAs a json rpc call\n" + HelpExampleRpc("getbalance", "\"tabby\", 6")); + LOCK2(cs_main, pwalletMain->cs_wallet); + if (params.size() == 0) return ValueFromAmount(pwalletMain->GetBalance()); @@ -782,6 +800,8 @@ Value sendfrom(const Array& params, bool fHelp) "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n" + HelpExampleCli("sendfrom", "\"tabby\" \"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\" 0.01 6 \"donation\" \"seans outpost\"") + "\nAs a json rpc call\n" + HelpExampleRpc("sendfrom", "\"tabby\", \"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\", 0.01, 6, \"donation\", \"seans outpost\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + string strAccount = AccountFromValue(params[0]); CBitcoinAddress address(params[1].get_str()); if (!address.IsValid()) @@ -835,6 +855,8 @@ Value sendmany(const Array& params, bool fHelp) "\nSend two amounts to two different addresses setting the confirmation and comment:\n" + HelpExampleCli("sendmany", "\"tabby\" \"{\\\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\\\":0.01,\\\"LcnqiuG9q6WS5K6dR5tYtthMfJh9Uxopxg\\\":0.02}\" 6 \"testing\"") + "\nAs a json rpc call\n" + HelpExampleRpc("sendmany", "\"tabby\", \"{\\\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\\\":0.01,\\\"LcnqiuG9q6WS5K6dR5tYtthMfJh9Uxopxg\\\":0.02}\", 6, \"testing\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + string strAccount = AccountFromValue(params[0]); Object sendTo = params[1].get_obj(); int nMinDepth = 1; @@ -916,6 +938,8 @@ Value addmultisigaddress(const Array& params, bool fHelp) throw runtime_error(msg); } + LOCK2(cs_main, pwalletMain->cs_wallet); + string strAccount; if (params.size() > 2) strAccount = AccountFromValue(params[2]); @@ -1509,6 +1533,8 @@ Value gettransaction(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("gettransaction", "\"3efa8c583a6b3f17b1f424a86c5ae65d98baff0292b760c9e64951f1823abfbd\"") + HelpExampleCli("gettransaction", "\"3efa8c583a6b3f17b1f424a86c5ae65d98baff0292b760c9e64951f1823abfbd\" true") + HelpExampleRpc("gettransaction", "\"3efa8c583a6b3f17b1f424a86c5ae65d98baff0292b760c9e64951f1823abfbd\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + uint256 hash; hash.SetHex(params[0].get_str()); @@ -1555,6 +1581,8 @@ Value backupwallet(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("backupwallet", "\"backup.dat\"") + HelpExampleRpc("backupwallet", "\"backup.dat\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + string strDest = params[0].get_str(); if (!BackupWallet(*pwalletMain, strDest)) throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); @@ -1575,6 +1603,8 @@ Value keypoolrefill(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("keypoolrefill", "") + HelpExampleRpc("keypoolrefill", "")); + LOCK2(cs_main, pwalletMain->cs_wallet); + // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool unsigned int kpSize = 0; if (params.size() > 0) { @@ -1671,6 +1701,8 @@ Value walletpassphrasechange(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"") + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + if (fHelp) return true; if (!pwalletMain->IsCrypted()) @@ -1808,6 +1840,8 @@ Value lockunspent(const Array& params, bool fHelp) "\nUnlock the transaction again\n" + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"bd4b76f46a6aef596c135d28e2a84c21546a9da8c2c75b272a5763a2718f1cb1\\\",\\\"vout\\\":1}]\"") + "\nAs a json rpc call\n" + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"bd4b76f46a6aef596c135d28e2a84c21546a9da8c2c75b272a5763a2718f1cb1\\\",\\\"vout\\\":1}]\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + if (params.size() == 1) RPCTypeCheck(params, list_of(bool_type)); else @@ -1927,6 +1961,8 @@ Value getwalletinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", "")); + LOCK2(cs_main, pwalletMain->cs_wallet); + Object obj; obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); From 2823b54738131b7d938ead783c1b8ea1011b840b Mon Sep 17 00:00:00 2001 From: 216k155 <216k155@luxcore.io> Date: Tue, 3 Apr 2018 11:10:58 +1000 Subject: [PATCH 03/17] Add consensus params --- src/Makefile.am | 1 + src/chainparams.h | 3 +++ src/checkpoints.cpp | 16 ++++++++-------- src/checkpoints.h | 8 ++++---- src/consensus/params.h | 32 ++++++++++++++++++++++++++++++++ src/main.cpp | 24 +++++++++++++++++------- src/miner.cpp | 4 ++++ src/qt/clientmodel.cpp | 2 +- src/rpcblockchain.cpp | 2 +- src/wallet.cpp | 9 +++++---- 10 files changed, 76 insertions(+), 25 deletions(-) create mode 100755 src/consensus/params.h diff --git a/src/Makefile.am b/src/Makefile.am index e8fefae2..f2794cd0 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -94,6 +94,7 @@ BITCOIN_CORE_H = \ compat.h \ compat/sanity.h \ compressor.h \ + consensus/params.h \ primitives/block.h \ primitives/transaction.h \ core_io.h \ diff --git a/src/chainparams.h b/src/chainparams.h index 52a21fff..693e3681 100755 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -11,6 +11,7 @@ #include "primitives/block.h" #include "protocol.h" #include "uint256.h" +#include "consensus/params.h" #include @@ -43,6 +44,7 @@ class CChainParams }; const uint256& HashGenesisBlock() const { return hashGenesisBlock; } + const Consensus::Params& GetConsensus() const { return consensus; } const MessageStartChars& MessageStart() const { return pchMessageStart; } const std::vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } @@ -101,6 +103,7 @@ class CChainParams CChainParams() {} uint256 hashGenesisBlock; + Consensus::Params consensus; MessageStartChars pchMessageStart; //! Raw pub key bytes for the broadcast alert signing key. std::vector vAlertPubKey; diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 021a77d0..d29ecaf3 100755 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -27,12 +27,12 @@ static const double SIGCHECK_VERIFICATION_FACTOR = 5.0; bool fEnabled = true; -bool CheckBlock(int nHeight, const uint256& hash) +bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash) { if (!fEnabled) return true; - const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints; + const MapCheckpoints& checkpoints = *data.mapCheckpoints; MapCheckpoints::const_iterator i = checkpoints.find(nHeight); if (i == checkpoints.end()) return true; @@ -40,7 +40,7 @@ bool CheckBlock(int nHeight, const uint256& hash) } //! Guess how far we are in the verification process at the given block index -double GuessVerificationProgress(CBlockIndex* pindex, bool fSigchecks) +double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) { if (pindex == NULL) return 0.0; @@ -53,7 +53,7 @@ double GuessVerificationProgress(CBlockIndex* pindex, bool fSigchecks) // Work is defined as: 1.0 per transaction before the last checkpoint, and // fSigcheckVerificationFactor per transaction after. - const CCheckpointData& data = Params().Checkpoints(); + // const CCheckpointData& data = Params().Checkpoints(); if (pindex->nChainTx <= data.nTransactionsLastCheckpoint) { double nCheapBefore = pindex->nChainTx; @@ -72,22 +72,22 @@ double GuessVerificationProgress(CBlockIndex* pindex, bool fSigchecks) return fWorkBefore / (fWorkBefore + fWorkAfter); } -int GetTotalBlocksEstimate() +int GetTotalBlocksEstimate(const CCheckpointData& data) { if (!fEnabled) return 0; - const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints; + const MapCheckpoints& checkpoints = *data.mapCheckpoints; return checkpoints.rbegin()->first; } -CBlockIndex* GetLastCheckpoint() +CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) { if (!fEnabled) return NULL; - const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints; + const MapCheckpoints& checkpoints = *data.mapCheckpoints; BOOST_REVERSE_FOREACH (const MapCheckpoints::value_type& i, checkpoints) { const uint256& hash = i.second; diff --git a/src/checkpoints.h b/src/checkpoints.h index efef4c1c..a04bb343 100755 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -27,15 +27,15 @@ struct CCheckpointData { }; //! Returns true if block passes checkpoint checks -bool CheckBlock(int nHeight, const uint256& hash); +bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash); //! Return conservative estimate of total number of blocks, 0 if unknown -int GetTotalBlocksEstimate(); +int GetTotalBlocksEstimate(const CCheckpointData& data); //! Returns last CBlockIndex* in mapBlockIndex that is a checkpoint -CBlockIndex* GetLastCheckpoint(); +CBlockIndex* GetLastCheckpoint(const CCheckpointData& data); -double GuessVerificationProgress(CBlockIndex* pindex, bool fSigchecks = true); +double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex* pindex, bool fSigchecks = true); extern bool fEnabled; diff --git a/src/consensus/params.h b/src/consensus/params.h new file mode 100755 index 00000000..85c38d5b --- /dev/null +++ b/src/consensus/params.h @@ -0,0 +1,32 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2017-2018 The Luxcore developers + +#ifndef BITCOIN_CONSENSUS_PARAMS_H +#define BITCOIN_CONSENSUS_PARAMS_H + +#include "uint256.h" + +namespace Consensus { + /** + * Parameters that influence chain consensus. + */ + struct Params { + uint256 hashGenesisBlock; + int nSubsidyHalvingInterval; + /** Used to check majorities for block version upgrade */ + int nEnforceBlockUpgradeMajority; + int nRejectBlockOutdatedMajority; + int nToCheckBlockUpgradeMajority; + /** Proof of work parameters */ + int nLastPOWBlock; + int64_t nTargetSpacing; + int64_t nTargetTimespan; + /** Proof of stake parameters */ + int64_t nStakingRoundPeriod; + int64_t nStakingInterval; + int64_t nStakingMinAge; + }; +} // namespace Consensus + +#endif // BITCOIN_CONSENSUS_PARAMS_H diff --git a/src/main.cpp b/src/main.cpp index 169fe96d..cfa433cb 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -1654,8 +1654,9 @@ CAmount GetMasternodePayment(int nHeight, int64_t blockValue, int nMasternodeCou bool IsInitialBlockDownload() { + const CChainParams& chainParams = Params(); LOCK(cs_main); - if (fImporting || fReindex || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate()) + if (fImporting || fReindex || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints())) return true; static bool lockIBDState = false; if (lockIBDState) @@ -2082,6 +2083,7 @@ static int64_t nTimeTotal = 0; bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) { + const CChainParams& chainParams = Params(); AssertLockHeld(cs_main); // Check it again in case a previous version let a bad block in @@ -2115,7 +2117,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("%s: PoW period ended", __func__), REJECT_INVALID, "PoW-ended"); - bool fScriptChecks = pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(); + bool fScriptChecks = pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints()); // Do not allow blocks that contain transactions which 'overwrite' older transactions, // unless those are already completely spent. @@ -2386,6 +2388,7 @@ void FlushStateToDisk() /** Update chainActive and related internal data structures. */ void static UpdateTip(CBlockIndex* pindexNew) { + const CChainParams& chainParams = Params(); chainActive.SetTip(pindexNew); // New best block @@ -2395,7 +2398,7 @@ void static UpdateTip(CBlockIndex* pindexNew) LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n", chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0), (unsigned long)chainActive.Tip()->nChainTx, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize()); + Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize()); cvBlockChange.notify_all(); @@ -2776,6 +2779,7 @@ static bool ActivateBestChainStep(CValidationState& state, CBlockIndex* pindexMo */ bool ActivateBestChain(CValidationState& state, CBlock* pblock) { + const CChainParams& chainParams = Params(); CBlockIndex* pindexNewTip = NULL; CBlockIndex* pindexMostWork = NULL; do { @@ -2808,7 +2812,7 @@ bool ActivateBestChain(CValidationState& state, CBlock* pblock) if (!fInitialDownload) { uint256 hashNewTip = pindexNewTip->GetBlockHash(); // Relay inventory, but don't relay old inventory during initial block download. - int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); + int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints()); { LOCK(cs_vNodes); BOOST_FOREACH (CNode* pnode, vNodes) @@ -3204,6 +3208,10 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo bool CheckWork(const CBlock &block, CBlockIndex* const pindexPrev) { +#if 0 + const CChainParams& chainParams = Params(); + const Consensus::Params& consensusParams = chainParams.GetConsensus(); +#endif if (pindexPrev == NULL) return error("%s: null pindexPrev for block %s", __func__, block.GetHash().GetHex()); @@ -3244,6 +3252,7 @@ bool CheckWork(const CBlock &block, CBlockIndex* const pindexPrev) bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex* const pindexPrev) { + const CChainParams& chainParams = Params(); uint256 hash = block.GetHash(); if (hash == Params().HashGenesisBlock()) @@ -3265,12 +3274,12 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta // } // Check that the block chain matches the known block chain up to a checkpoint - if (!Checkpoints::CheckBlock(nHeight, hash)) + if (!Checkpoints::CheckBlock(chainParams.Checkpoints(), nHeight, hash)) return state.DoS(100, error("%s : rejected by checkpoint lock-in at %d", __func__, nHeight), REJECT_CHECKPOINT, "checkpoint mismatch"); // Don't accept any forks from the main chain prior to last checkpoint - CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(); + CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints()); if (pcheckpoint && nHeight < pcheckpoint->nHeight) return state.DoS(0, error("%s : forked chain older than last checkpoint (height %d)", __func__, nHeight)); @@ -3680,6 +3689,7 @@ CBlockIndex* InsertBlockIndex(uint256 hash) bool static LoadBlockIndexDB() { + const CChainParams& chainparams = Params(); if (!pblocktree->LoadBlockIndexGuts()) return false; @@ -3859,7 +3869,7 @@ bool static LoadBlockIndexDB() LogPrintf("%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__, chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainActive.Tip())); + Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.Tip())); return true; } diff --git a/src/miner.cpp b/src/miner.cpp index e7dd077a..0bee73b1 100755 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -92,6 +92,10 @@ class TxPriorityCompare void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) { +#if 0 + const CChainParams& chainParams = Params(); + const Consensus::Params& consensusParams = chainParams.GetConsensus(); +#endif pblock->nTime = std::max(pindexPrev->GetMedianTimePast() + 1, GetAdjustedTime()); // Updating time can change work required on testnet: diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 7c14c3c9..944917cc 100755 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -100,7 +100,7 @@ QDateTime ClientModel::getLastBlockDate() const double ClientModel::getVerificationProgress() const { LOCK(cs_main); - return Checkpoints::GuessVerificationProgress(chainActive.Tip()); + return Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()); } void ClientModel::updateTimer() diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 29a12735..147341d0 100755 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -581,7 +581,7 @@ Value getblockchaininfo(const Array& params, bool fHelp) obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); obj.push_back(Pair("peak", chainActive.Tip()->GetBlockHash().GetHex())); obj.push_back(Pair("difficulty", (double)GetPoWDifficulty())); - obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(chainActive.Tip()))); + obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); return obj; } diff --git a/src/wallet.cpp b/src/wallet.cpp index 64d0f1be..5ee5f900 100755 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1048,6 +1048,7 @@ bool CWalletTx::WriteToDisk() */ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) { + const CChainParams& chainParams = Params(); int ret = 0; int64_t nNow = GetTime(); @@ -1061,11 +1062,11 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) pindex = chainActive.Next(pindex); ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup - double dProgressStart = Checkpoints::GuessVerificationProgress(pindex, false); - double dProgressTip = Checkpoints::GuessVerificationProgress(chainActive.Tip(), false); + double dProgressStart = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false); + double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip(), false); while (pindex) { if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) - ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); + ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); CBlock block; ReadBlockFromDisk(block, pindex); @@ -1076,7 +1077,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) pindex = chainActive.Next(pindex); if (GetTime() >= nNow + 60) { nNow = GetTime(); - LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(pindex)); + LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex)); } } ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI From fa51df6ce3074b5fd7cd72d402c2bfb57b7bcfbe Mon Sep 17 00:00:00 2001 From: 216k155 <216k155@luxcore.io> Date: Tue, 3 Apr 2018 12:05:37 +1000 Subject: [PATCH 04/17] Allow disconnect peer manually in rpcconsole peertab --- src/qt/forms/rpcconsole.ui | 114 ++++++++++++++++++++++++++++++------- src/qt/guiutil.cpp | 13 +++++ src/qt/guiutil.h | 2 + src/qt/rpcconsole.cpp | 35 +++++++++++- src/qt/rpcconsole.h | 7 ++- 5 files changed, 147 insertions(+), 24 deletions(-) diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index a70c16c7..ddfe029b 100755 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -748,13 +748,36 @@ + + + Whitelisted + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + Direction - + IBeamCursor @@ -770,14 +793,14 @@ - + Protocol - + IBeamCursor @@ -793,14 +816,14 @@ - + Version - + IBeamCursor @@ -816,14 +839,14 @@ - + Services - + IBeamCursor @@ -886,13 +909,36 @@ + + + Synced Blocks + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + Ban Score - + IBeamCursor @@ -908,14 +954,14 @@ - + Connection Time - + IBeamCursor @@ -931,14 +977,14 @@ - + Last Send - + IBeamCursor @@ -954,14 +1000,14 @@ - + Last Receive - + IBeamCursor @@ -977,14 +1023,14 @@ - + Bytes Sent - + IBeamCursor @@ -1000,14 +1046,14 @@ - + Bytes Received - + IBeamCursor @@ -1023,14 +1069,14 @@ - + Ping Time - + IBeamCursor @@ -1046,7 +1092,33 @@ - + + + + The duration of a currently outstanding ping. + + + Ping Wait + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + Qt::Vertical diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 0968b072..ddd92f37 100755 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -254,6 +254,19 @@ void copyEntryData(QAbstractItemView* view, int column, int role) } } + QString getEntryData(QAbstractItemView *view, int column, int role) + { + if(!view || !view->selectionModel()) + return QString(); + QModelIndexList selection = view->selectionModel()->selectedRows(column); + + if(!selection.isEmpty()) { + // Return first item + return (selection.at(0).data(role).toString()); + } + return QString(); +} + QString getSaveFileName(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedSuffixOut) { QString selectedFilter; diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index dab8e774..d83d5d31 100755 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -65,6 +65,8 @@ QString HtmlEscape(const std::string& str, bool fMultiLine = false); */ void copyEntryData(QAbstractItemView* view, int column, int role = Qt::EditRole); + QString getEntryData(QAbstractItemView *view, int column, int role); + void setClipboard(const QString& str); /** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 0ec6698e..04fea3a1 100755 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -30,7 +30,7 @@ #include #include #include - +#include #if QT_VERSION < 0x050000 #include #endif @@ -220,7 +220,8 @@ RPCConsole::RPCConsole(QWidget* parent) : QDialog(parent), ui(new Ui::RPCConsole), clientModel(0), historyPtr(0), - cachedNodeid(-1) + cachedNodeid(-1), + contextMenu(0) { ui->setupUi(this); GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this); @@ -339,10 +340,22 @@ void RPCConsole::setClientModel(ClientModel* model) ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows); ui->peerWidget->setSelectionMode(QAbstractItemView::SingleSelection); + ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu); ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH); ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH); ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH); + // create context menu actions + QAction* disconnectAction = new QAction(tr("&Disconnect Node"), this); + + // create context menu + contextMenu = new QMenu(); + contextMenu->addAction(disconnectAction); + + // context menu signals + connect(ui->peerWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showMenu(const QPoint&))); + connect(disconnectAction, SIGNAL(triggered()), this, SLOT(disconnectSelectedNode())); + // connect the peerWidget selection model to our peerSelected() handler connect(ui->peerWidget->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(peerSelected(const QItemSelection&, const QItemSelection&))); @@ -793,6 +806,24 @@ void RPCConsole::hideEvent(QHideEvent* event) clientModel->getPeerTableModel()->stopAutoRefresh(); } +void RPCConsole::showMenu(const QPoint& point) +{ + QModelIndex index = ui->peerWidget->indexAt(point); + if (index.isValid()) + contextMenu->exec(QCursor::pos()); +} + +void RPCConsole::disconnectSelectedNode() +{ + // Get currently selected peer address + QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address); + // Find the node, disconnect it and clear the selected node + if (CNode *bannedNode = FindNode(strNode.toStdString())) { + bannedNode->CloseSocketDisconnect(); + ui->peerWidget->selectionModel()->clearSelection(); + } +} + void RPCConsole::showBackups() { GUIUtil::showBackups(); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 08bc93e8..cd4bac80 100755 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -11,7 +11,7 @@ #include "net.h" #include - +class QMenu; class ClientModel; namespace Ui @@ -57,6 +57,8 @@ private slots: void resizeEvent(QResizeEvent* event); void showEvent(QShowEvent* event); void hideEvent(QHideEvent* event); + /** Show custom context menu on Peers tab */ + void showMenu(const QPoint& point); public slots: void clear(); @@ -99,6 +101,8 @@ public slots: void peerSelected(const QItemSelection& selected, const QItemSelection& deselected); /** Handle updated peer information */ void peerLayoutChanged(); + /** Disconnect a selected node on the Peers tab */ + void disconnectSelectedNode(); /** Show folder with wallet backups in default browser */ void showBackups(); @@ -129,6 +133,7 @@ public slots: QStringList history; int historyPtr; NodeId cachedNodeid; + QMenu *contextMenu; }; #endif // BITCOIN_QT_RPCCONSOLE_H From f0d5d16e22a8410cda1c89d240ced7c9957245a8 Mon Sep 17 00:00:00 2001 From: 216k155 <216k155@luxcore.io> Date: Tue, 3 Apr 2018 12:27:46 +1000 Subject: [PATCH 05/17] Update version 4.3.1 --- configure.ac | 2 +- src/clientversion.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index aa0cf85c..3c8bc734 100755 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 4) define(_CLIENT_VERSION_MINOR, 3) -define(_CLIENT_VERSION_REVISION, 0) +define(_CLIENT_VERSION_REVISION, 1) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2018) diff --git a/src/clientversion.h b/src/clientversion.h index 099c505e..9dd0a8cf 100755 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -16,7 +16,7 @@ //! These need to be macros, as clientversion.cpp's and lux*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 4 #define CLIENT_VERSION_MINOR 3 -#define CLIENT_VERSION_REVISION 0 +#define CLIENT_VERSION_REVISION 1 #define CLIENT_VERSION_BUILD 0 //! Set to true for release, false for prerelease or test build From 79e7b27ecbf43cbb174a4e486bc49efb3e02a76b Mon Sep 17 00:00:00 2001 From: 216k155 <216k155@luxcore.io> Date: Tue, 3 Apr 2018 20:14:59 +1000 Subject: [PATCH 06/17] update json_spirit to univalue --- src/Makefile.am | 13 +- .../test/libtesteth/ImportTest.cpp | 4 +- .../test/libtesteth/TestHelper.cpp | 4 +- src/lux-cli.cpp | 31 +-- src/lux-tx.cpp | 8 +- src/qt/rpcconsole.cpp | 21 +- src/rest.cpp | 19 +- src/rpcblockchain.cpp | 103 +++---- src/rpcclient.cpp | 32 ++- src/rpcclient.h | 10 +- src/rpcdarksend.cpp | 37 +-- src/rpcdump.cpp | 33 ++- src/rpcmining.cpp | 128 ++++++--- src/rpcmisc.cpp | 54 ++-- src/rpcnet.cpp | 57 ++-- src/rpcprotocol.cpp | 28 +- src/rpcprotocol.h | 12 +- src/rpcrawtransaction.cpp | 133 +++++---- src/rpcserver.cpp | 132 +++++---- src/rpcserver.h | 257 +++++++++--------- src/rpcwallet.cpp | 232 +++++++++------- src/univalue/univalue.cpp | 106 +++++++- src/univalue/univalue.h | 96 ++++++- src/univalue/univalue_write.cpp | 9 + src/utilstrencodings.cpp | 52 +++- src/utilstrencodings.h | 18 +- 26 files changed, 1001 insertions(+), 628 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index f2794cd0..972a0498 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -159,17 +159,6 @@ BITCOIN_CORE_H = \ zmq/zmqnotificationinterface.h \ zmq/zmqpublishnotifier.h -JSON_H = \ - json/json_spirit.h \ - json/json_spirit_error_position.h \ - json/json_spirit_reader.h \ - json/json_spirit_reader_template.h \ - json/json_spirit_stream_reader.h \ - json/json_spirit_utils.h \ - json/json_spirit_value.h \ - json/json_spirit_writer.h \ - json/json_spirit_writer_template.h - obj/build.h: FORCE @$(MKDIR_P) $(builddir)/obj @$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \ @@ -205,7 +194,6 @@ libbitcoin_server_a_SOURCES = \ txdb.cpp \ txmempool.cpp \ validationinterface.cpp \ - $(JSON_H) \ $(BITCOIN_CORE_H) if ENABLE_ZMQ @@ -383,6 +371,7 @@ luxd_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) # lux-cli binary # lux_cli_LDADD = \ $(LIBBITCOIN_CLI) \ + $(LIBBITCOIN_UNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(BOOST_LIBS) \ $(SSL_LIBS) \ diff --git a/src/cpp-ethereum/test/libtesteth/ImportTest.cpp b/src/cpp-ethereum/test/libtesteth/ImportTest.cpp index b6642c8c..858ad0ea 100644 --- a/src/cpp-ethereum/test/libtesteth/ImportTest.cpp +++ b/src/cpp-ethereum/test/libtesteth/ImportTest.cpp @@ -433,7 +433,7 @@ int ImportTest::compareStates(State const& _stateExpect, State const& _statePost void parseJsonStrValueIntoVector(json_spirit::mValue const& _json, vector& _out) { - if (_json.type() == json_spirit::array_type) + if (_json.type() == UniValue_type) { for (auto const& val: _json.get_array()) _out.push_back(val.get_str()); @@ -444,7 +444,7 @@ void parseJsonStrValueIntoVector(json_spirit::mValue const& _json, vector& _out) { - if (_json.type() == json_spirit::array_type) + if (_json.type() == UniValue_type) { for (auto const& val: _json.get_array()) _out.push_back(val.get_int()); diff --git a/src/cpp-ethereum/test/libtesteth/TestHelper.cpp b/src/cpp-ethereum/test/libtesteth/TestHelper.cpp index b661001e..f0e40770 100644 --- a/src/cpp-ethereum/test/libtesteth/TestHelper.cpp +++ b/src/cpp-ethereum/test/libtesteth/TestHelper.cpp @@ -286,7 +286,7 @@ bytes importCode(json_spirit::mObject& _o) code = fromHex(compileLLL(_o["code"].get_str())); else code = fromHex(_o["code"].get_str().substr(2)); - else if (_o["code"].type() == json_spirit::array_type) + else if (_o["code"].type() == UniValue_type) { code.clear(); for (auto const& j: _o["code"].get_array()) @@ -322,7 +322,7 @@ void checkOutput(bytesConstRef _output, json_spirit::mObject& _o) if (expectedOutput.find("#") == 0) BOOST_CHECK(_output.size() == toInt(expectedOutput.substr(1))); - else if (_o["out"].type() == json_spirit::array_type) + else if (_o["out"].type() == UniValue_type) for (auto const& d: _o["out"].get_array()) { BOOST_CHECK_MESSAGE(_output[j] == toInt(d), "Output byte [" << j << "] different!"); diff --git a/src/lux-cli.cpp b/src/lux-cli.cpp index 983e5b47..eaba85ca 100755 --- a/src/lux-cli.cpp +++ b/src/lux-cli.cpp @@ -11,7 +11,7 @@ #include "rpcprotocol.h" #include "util.h" #include "utilstrencodings.h" - +#include "univalue/univalue.h" #include #define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */ @@ -19,7 +19,6 @@ using namespace std; using namespace boost; using namespace boost::asio; -using namespace json_spirit; std::string HelpMessageCli() { @@ -99,7 +98,7 @@ static bool AppInitRPC(int argc, char* argv[]) return true; } -Object CallRPC(const string& strMethod, const Array& params) +UniValue CallRPC(const string& strMethod, const UniValue& params) { if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") throw runtime_error(strprintf( @@ -147,10 +146,10 @@ Object CallRPC(const string& strMethod, const Array& params) throw runtime_error("no response from server"); // Parse reply - Value valReply; - if (!read_string(strReply, valReply)) + UniValue valReply(UniValue::VSTR); + if (!valReply.read(strReply)) throw runtime_error("couldn't parse reply from server"); - const Object& reply = valReply.get_obj(); + const UniValue& reply = valReply.get_obj(); if (reply.empty()) throw runtime_error("expected reply to have result, error and id properties"); @@ -175,33 +174,33 @@ int CommandLineRPC(int argc, char* argv[]) // Parameters default to strings std::vector strParams(&argv[2], &argv[argc]); - Array params = RPCConvertValues(strMethod, strParams); + UniValue params = RPCConvertValues(strMethod, strParams); // Execute and handle connection failures with -rpcwait const bool fWait = GetBoolArg("-rpcwait", false); do { try { - const Object reply = CallRPC(strMethod, params); + const UniValue reply = CallRPC(strMethod, params); // Parse reply - const Value& result = find_value(reply, "result"); - const Value& error = find_value(reply, "error"); + const UniValue& result = find_value(reply, "result"); + const UniValue& 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(); + int code = error["code"].get_int(); if (fWait && code == RPC_IN_WARMUP) throw CConnectionFailed("server in warmup"); - strPrint = "error: " + write_string(error, false); + strPrint = "error: " + error.write(); 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. diff --git a/src/lux-tx.cpp b/src/lux-tx.cpp index 2c0af314..b8159b98 100755 --- a/src/lux-tx.cpp +++ b/src/lux-tx.cpp @@ -315,7 +315,7 @@ static bool findSighashFlags(int& flags, const string& flagStr) uint256 ParseHashUO(map& o, string strKey) { if (!o.count(strKey)) - return 0; + return uint256(); return ParseHashUV(o[strKey], strKey); } @@ -353,7 +353,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) UniValue keysObj = registers["privatekeys"]; fGivenKeys = true; - for (unsigned int kidx = 0; kidx < keysObj.count(); kidx++) { + for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) { if (!keysObj[kidx].isStr()) throw runtime_error("privatekey not a string"); CBitcoinSecret vchSecret; @@ -370,7 +370,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) throw runtime_error("prevtxs register variable must be set."); UniValue prevtxsObj = registers["prevtxs"]; { - for (unsigned int previdx = 0; previdx < prevtxsObj.count(); previdx++) { + for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) { UniValue prevOut = prevtxsObj[previdx]; if (!prevOut.isObject()) throw runtime_error("expected prevtxs internal object"); @@ -484,7 +484,7 @@ static void MutateTx(CMutableTransaction& tx, const string& command, const strin static void OutputTxJSON(const CTransaction& tx) { UniValue entry(UniValue::VOBJ); - TxToUniv(tx, 0, entry); + TxToUniv(tx, uint256(), entry); string jsonOutput = entry.write(4); fprintf(stdout, "%s\n", jsonOutput.c_str()); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 04fea3a1..4d50cbe9 100755 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -17,10 +17,10 @@ #include "rpcserver.h" #include "util.h" -#include "json/json_spirit_value.h" - #include +#include "univalue/univalue.h" + #ifdef ENABLE_WALLET #include #endif @@ -30,7 +30,8 @@ #include #include #include -#include +#include + #if QT_VERSION < 0x050000 #include #endif @@ -188,28 +189,28 @@ 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)); - } catch (json_spirit::Object& objError) { + } catch (UniValue& objError) { try // Nice formatting for standard-format error { int code = find_value(objError, "code").get_int(); std::string message = find_value(objError, "message").get_str(); emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); } catch (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))); + {// Show raw JSON object + emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write())); } } catch (std::exception& e) { emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what())); diff --git a/src/rest.cpp b/src/rest.cpp index 170eacb3..e61a840c 100755 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -14,8 +14,10 @@ #include +#include "univalue/univalue.h" + using namespace std; -using namespace json_spirit; + enum RetFormat { RF_UNDEF, @@ -41,8 +43,9 @@ class RestErr string message; }; -extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry); -extern Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); +extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); +extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); +extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); static RestErr RESTERR(enum HTTPStatusCode status, string message) { @@ -132,8 +135,8 @@ static bool rest_block(AcceptedConnection* conn, } case RF_JSON: { - Object objBlock = blockToJSON(block, pblockindex, showTxDetails); - string strJSON = write_string(Value(objBlock), false) + "\n"; + UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails); + string strJSON = objBlock.write() + "\n"; conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush; return true; } @@ -177,7 +180,7 @@ static bool rest_tx(AcceptedConnection* conn, throw RESTERR(HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); CTransaction tx; - uint256 hashBlock = 0; + uint256 hashBlock = uint256(); if (!GetTransaction(hash, tx, hashBlock, true)) throw RESTERR(HTTP_NOT_FOUND, hashStr + " not found"); @@ -198,9 +201,9 @@ static bool rest_tx(AcceptedConnection* conn, } case RF_JSON: { - Object objTx; + UniValue objTx(UniValue::VOBJ); TxToJSON(tx, hashBlock, objTx); - string strJSON = write_string(Value(objTx), false) + "\n"; + string strJSON = objTx.write() + "\n"; conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush; return true; } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 147341d0..f6e264c3 100755 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -7,19 +7,19 @@ #include "checkpoints.h" #include "main.h" +#include "primitives/transaction.h" #include "rpcserver.h" #include "sync.h" #include "util.h" #include -#include "json/json_spirit_value.h" +#include "univalue/univalue.h" -using namespace json_spirit; using namespace std; -extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry); -void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex); +extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); +void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); double GetPoWDifficulty(const CBlockIndex* blockindex) { @@ -50,9 +50,9 @@ double GetPoWDifficulty(const CBlockIndex* blockindex) } -Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) +UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain @@ -63,11 +63,11 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); - Array txs; + UniValue txs(UniValue::VARR); BOOST_FOREACH (const CTransaction& tx, block.vtx) { if (txDetails) { - Object objTx; - TxToJSON(tx, uint256(0), objTx); + UniValue objTx(UniValue::VOBJ); + TxToJSON(tx, uint256(), objTx); txs.push_back(objTx); } else txs.push_back(tx.GetHash().GetHex()); @@ -88,9 +88,9 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe } -Object blockHeaderToJSON(const CBlock& block, const CBlockIndex* blockindex) +UniValue blockHeaderToJSON(const CBlock& block, const CBlockIndex* blockindex) { - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("version", block.nVersion)); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); @@ -102,7 +102,7 @@ Object blockHeaderToJSON(const CBlock& block, const CBlockIndex* blockindex) } -Value getblockcount(const Array& params, bool fHelp) +UniValue getblockcount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -117,7 +117,7 @@ Value getblockcount(const Array& params, bool fHelp) return chainActive.Height(); } -Value getbestblockhash(const Array& params, bool fHelp) +UniValue getbestblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -132,7 +132,7 @@ Value getbestblockhash(const Array& params, bool fHelp) return chainActive.Tip()->GetBlockHash().GetHex(); } -Value getpowdifficulty(const Array& params, bool fHelp) +UniValue getpowdifficulty(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -148,7 +148,7 @@ Value getpowdifficulty(const Array& params, bool fHelp) } -Value getrawmempool(const Array& params, bool fHelp) +UniValue getrawmempool(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -186,11 +186,11 @@ Value getrawmempool(const Array& params, bool fHelp) if (fVerbose) { LOCK(mempool.cs); - Object o; + UniValue o(UniValue::VOBJ); BOOST_FOREACH (const PAIRTYPE(uint256, CTxMemPoolEntry) & entry, mempool.mapTx) { const uint256& hash = entry.first; const CTxMemPoolEntry& e = entry.second; - Object info; + UniValue info(UniValue::VOBJ); info.push_back(Pair("size", (int)e.GetTxSize())); info.push_back(Pair("fee", ValueFromAmount(e.GetFee()))); info.push_back(Pair("time", e.GetTime())); @@ -203,7 +203,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(UniValue::VARR); + + BOOST_FOREACH(const string& dep, setDepends) + { + depends.push_back(dep); + } + info.push_back(Pair("depends", depends)); o.push_back(Pair(hash.ToString(), info)); } @@ -212,7 +218,7 @@ Value getrawmempool(const Array& params, bool fHelp) vector vtxid; mempool.queryHashes(vtxid); - Array a; + UniValue a(UniValue::VARR); BOOST_FOREACH (const uint256& hash, vtxid) a.push_back(hash.ToString()); @@ -220,7 +226,7 @@ Value getrawmempool(const Array& params, bool fHelp) } } -Value getblockhashes(const Array& params, bool fHelp) +UniValue getblockhashes(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2) throw runtime_error( @@ -256,7 +262,6 @@ Value getblockhashes(const Array& params, bool fHelp) unsigned int low = params[1].get_int(); bool fActiveOnly = false; bool fLogicalTS = false; - Array a; int nHeight = chainActive.Height(); unsigned time = GetTime(); @@ -267,8 +272,6 @@ Value getblockhashes(const Array& params, bool fHelp) a.push_back(pblockindex->GetBlockHash().GetHex()); } } - return a; - } int getBlockTimeByHeight(int nHeight){ @@ -280,7 +283,7 @@ int getBlockTimeByHeight(int nHeight){ return pblockindex2->GetBlockTime(); } -Value getblockhash(const Array& params, bool fHelp) +UniValue getblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -303,7 +306,7 @@ Value getblockhash(const Array& params, bool fHelp) return pblockindex->GetBlockHash().GetHex(); } -Value getblock(const Array& params, bool fHelp) +UniValue getblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -365,7 +368,7 @@ Value getblock(const Array& params, bool fHelp) return blockToJSON(block, pblockindex); } -Value getblockheader(const Array& params, bool fHelp) +UniValue getblockheader(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -417,7 +420,7 @@ Value getblockheader(const Array& params, bool fHelp) return blockHeaderToJSON(block, pblockindex); } -Value gettxoutsetinfo(const Array& params, bool fHelp) +UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -439,7 +442,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) LOCK(cs_main); - Object ret; + UniValue ret(UniValue::VOBJ); CCoinsStats stats; FlushStateToDisk(); @@ -455,7 +458,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) return ret; } -Value gettxout(const Array& params, bool fHelp) +UniValue gettxout(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( @@ -490,7 +493,9 @@ Value gettxout(const Array& params, bool fHelp) "\nView the details\n" + HelpExampleCli("gettxout", "\"txid\" 1") + "\nAs a json rpc call\n" + HelpExampleRpc("gettxout", "\"txid\", 1")); - Object ret; + LOCK(cs_main); + + UniValue ret(UniValue::VOBJ); std::string strHash = params[0].get_str(); uint256 hash(strHash); @@ -504,14 +509,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; @@ -521,7 +526,7 @@ Value gettxout(const Array& params, bool fHelp) else ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1)); ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue))); - Object o; + UniValue o(UniValue::VOBJ); ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true); ret.push_back(Pair("scriptPubKey", o)); ret.push_back(Pair("version", coins.nVersion)); @@ -530,7 +535,7 @@ Value gettxout(const Array& params, bool fHelp) return ret; } -Value verifychain(const Array& params, bool fHelp) +UniValue verifychain(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( @@ -556,7 +561,7 @@ Value verifychain(const Array& params, bool fHelp) return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth); } -Value getblockchaininfo(const Array& params, bool fHelp) +UniValue getblockchaininfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -575,7 +580,9 @@ Value getblockchaininfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getblockchaininfo", "") + HelpExampleRpc("getblockchaininfo", "")); - Object obj; + LOCK(cs_main); + + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("chain", Params().NetworkIDString())); obj.push_back(Pair("height", (int)chainActive.Height())); obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); @@ -600,7 +607,7 @@ struct CompareBlocksByHeight { } }; -Value getchaintips(const Array& params, bool fHelp) +UniValue getchaintips(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -631,6 +638,8 @@ Value getchaintips(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getchaintips", "") + HelpExampleRpc("getchaintips", "")); + LOCK(cs_main); + /* Build up a list of chain tips. We start with the list of all known blocks, and successively remove blocks that appear as pprev of another block. */ @@ -647,9 +656,9 @@ Value getchaintips(const Array& params, bool fHelp) setTips.insert(chainActive.Tip()); /* Construct the output array. */ - Array res; + UniValue res(UniValue::VARR); BOOST_FOREACH (const CBlockIndex* block, setTips) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("height", block->nHeight)); obj.push_back(Pair("hash", block->phashBlock->GetHex())); @@ -684,7 +693,7 @@ Value getchaintips(const Array& params, bool fHelp) return res; } -Value getmempoolinfo(const Array& params, bool fHelp) +UniValue getmempoolinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -698,14 +707,16 @@ Value getmempoolinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getmempoolinfo", "") + HelpExampleRpc("getmempoolinfo", "")); - Object ret; + LOCK(cs_main); + + UniValue ret(UniValue::VOBJ); ret.push_back(Pair("size", (int64_t)mempool.size())); ret.push_back(Pair("bytes", (int64_t)mempool.GetTotalTxSize())); return ret; } -Value invalidateblock(const Array& params, bool fHelp) +UniValue invalidateblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -738,10 +749,10 @@ Value invalidateblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); } - return Value::null; + return NullUniValue; } -Value reconsiderblock(const Array& params, bool fHelp) +UniValue reconsiderblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -775,5 +786,5 @@ Value reconsiderblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); } - return Value::null; + return NullUniValue; } diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 7466ed6a..4450f69e 100755 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -14,8 +14,10 @@ #include #include +#include // for to_lower() +#include "univalue/univalue.h" + using namespace std; -using namespace json_spirit; class CRPCConvertParam { @@ -135,10 +137,25 @@ CRPCConvertTable::CRPCConvertTable() static CRPCConvertTable rpcCvtTable; + + +/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) + * as well as objects and arrays. + */ +UniValue ParseNonRFCJSONValue(const std::string& strVal) +{ + UniValue jVal; + if (!jVal.read(std::string("[")+strVal+std::string("]")) || + !jVal.isArray() || jVal.size()!=1) + throw runtime_error(string("Error parsing JSON:")+strVal); + return jVal[0]; +} + + /** Convert strings to command-specific RPC representation */ -Array RPCConvertValues(const std::string& strMethod, const std::vector& strParams) +UniValue RPCConvertValues(const std::string& strMethod, const std::vector& strParams) { - Array params; + UniValue params(UniValue::VARR);; for (unsigned int idx = 0; idx < strParams.size(); idx++) { const std::string& strVal = strParams[idx]; @@ -146,14 +163,9 @@ Array RPCConvertValues(const std::string& strMethod, const std::vector& strParams); +UniValue RPCConvertValues(const std::string& strMethod, const std::vector& strParams); +/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) + * as well as objects and arrays. + */ +UniValue ParseNonRFCJSONValue(const std::string& strVal); #endif // BITCOIN_RPCCLIENT_H diff --git a/src/rpcdarksend.cpp b/src/rpcdarksend.cpp index b1acf321..d892c876 100644 --- a/src/rpcdarksend.cpp +++ b/src/rpcdarksend.cpp @@ -16,9 +16,11 @@ #include "util.h" #include "utilmoneystr.h" +#include + +#include "univalue/univalue.h" + #include -using namespace json_spirit; -using namespace std; void SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx& wtxNew, AvailableCoinsType coin_type) { @@ -52,7 +54,7 @@ void SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx& wtxNew, throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); } -Value darksend(const Array& params, bool fHelp) +UniValue darksend(const UniValue& params, bool fHelp) { if (fHelp || params.size() == 0) throw runtime_error( @@ -100,14 +102,14 @@ Value darksend(const Array& params, bool fHelp) } -Value getpoolinfo(const Array& params, bool fHelp) +UniValue getpoolinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getpoolinfo\n" "Returns an object containing anonymous pool-related information."); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("current_masternode", GetCurrentMasterNode())); obj.push_back(Pair("state", darkSendPool.GetState())); obj.push_back(Pair("entries", darkSendPool.GetEntriesCount())); @@ -116,7 +118,7 @@ Value getpoolinfo(const Array& params, bool fHelp) } -Value masternode(const Array& params, bool fHelp) +UniValue masternode(const UniValue& params, bool fHelp) { string strCommand; if (params.size() >= 1) @@ -187,7 +189,7 @@ Value masternode(const Array& params, bool fHelp) bool found = false; - Object statusObj; + UniValue resultsObj(UniValue::VARR); statusObj.push_back(Pair("alias", alias)); BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { @@ -235,8 +237,7 @@ Value masternode(const Array& params, bool fHelp) int successful = 0; int fail = 0; - - Object resultsObj; + UniValue resultsObj(UniValue::VARR); BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { total++; @@ -244,7 +245,7 @@ Value masternode(const Array& params, bool fHelp) std::string errorMessage; bool result = activeMasternode.StopMasterNode(mne.getIp(), mne.getPrivKey(), errorMessage); - Object statusObj; + UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", mne.getAlias())); statusObj.push_back(Pair("result", result ? "successful" : "failed")); @@ -259,7 +260,7 @@ Value masternode(const Array& params, bool fHelp) } pwalletMain->Lock(); - Object returnObj; + UniValue returnObj(UniValue::VOBJ); returnObj.push_back(Pair("overall", "Successfully stopped " + boost::lexical_cast(successful) + " masternodes, failed to stop " + boost::lexical_cast(fail) + ", total " + boost::lexical_cast(total))); returnObj.push_back(Pair("detail", resultsObj)); @@ -281,7 +282,7 @@ Value masternode(const Array& params, bool fHelp) "list supports 'active', 'vin', 'pubkey', 'lastseen', 'activeseconds', 'rank', 'protocol'\n"); } - Object obj; + UniValue resultsObj(UniValue::VARR); BOOST_FOREACH(CMasterNode mn, vecMasternodes) { mn.Check(); @@ -375,7 +376,9 @@ Value masternode(const Array& params, bool fHelp) bool found = false; - Object statusObj; + UniValue resultsObj(UniValue::VARR); + UniValue statusObj(UniValue::VOBJ); + statusObj.push_back(Pair("alias", alias)); BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { @@ -398,7 +401,7 @@ Value masternode(const Array& params, bool fHelp) } pwalletMain->Lock(); - return statusObj; + resultsObj.push_back(statusObj); } @@ -427,7 +430,7 @@ Value masternode(const Array& params, bool fHelp) int successful = 0; int fail = 0; - Object resultsObj; + UniValue resultsObj(UniValue::VARR); BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { total++; @@ -435,7 +438,7 @@ Value masternode(const Array& params, bool fHelp) std::string errorMessage; bool result = activeMasternode.Register(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage); - Object statusObj; + UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", mne.getAlias())); statusObj.push_back(Pair("result", result ? "succesful" : "failed")); @@ -551,7 +554,7 @@ Value masternode(const Array& params, bool fHelp) std::vector mnEntries; mnEntries = masternodeConfig.getEntries(); - Object resultObj; + UniValue resultsObj(UniValue::VARR); BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { Object mnObj; diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index cdd8572f..a2d2648c 100755 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -25,9 +25,8 @@ #include #include -#include "json/json_spirit_value.h" +#include "univalue/univalue.h" -using namespace json_spirit; using namespace std; void EnsureWalletIsUnlocked(); @@ -79,7 +78,7 @@ std::string DecodeDumpString(const std::string& str) return ret.str(); } -Value importprivkey(const Array& params, bool fHelp) +UniValue importprivkey(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( @@ -128,7 +127,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; @@ -143,10 +142,10 @@ Value importprivkey(const Array& params, bool fHelp) } } - return Value::null; + return NullUniValue; } -Value importaddress(const Array& params, bool fHelp) +UniValue importaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( @@ -196,7 +195,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(); @@ -209,10 +208,10 @@ Value importaddress(const Array& params, bool fHelp) } } - return Value::null; + return NullUniValue; } -Value importwallet(const Array& params, bool fHelp) +UniValue importwallet(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -307,10 +306,10 @@ 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) +UniValue dumpprivkey(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -342,7 +341,7 @@ Value dumpprivkey(const Array& params, bool fHelp) } -Value dumpwallet(const Array& params, bool fHelp) +UniValue dumpwallet(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -399,10 +398,10 @@ Value dumpwallet(const Array& params, bool fHelp) file << "\n"; file << "# End of dump\n"; file.close(); - return Value::null; + return NullUniValue; } -Value bip38encrypt(const Array& params, bool fHelp) +UniValue bip38encrypt(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) throw runtime_error( @@ -435,14 +434,14 @@ Value bip38encrypt(const Array& params, bool fHelp) uint256 privKey = vchSecret.GetPrivKey_256(); string encryptedOut = BIP38_Encrypt(strAddress, strPassphrase, privKey); - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("Addess", strAddress)); result.push_back(Pair("Encrypted Key", encryptedOut)); return result; } -Value bip38decrypt(const Array& params, bool fHelp) +UniValue bip38decrypt(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) throw runtime_error( @@ -469,7 +468,7 @@ Value bip38decrypt(const Array& params, bool fHelp) if (!BIP38_Decrypt(strPassphrase, strKey, privKey, fCompressed)) throw JSONRPCError(RPC_WALLET_ERROR, "Failed To Decrypt"); - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("privatekey", HexStr(privKey))); CKey key; diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index e4ab65cd..26fb0e3c 100755 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -14,8 +14,11 @@ #include "miner.h" #include "net.h" #include "pow.h" +#include "primitives/transaction.h" #include "rpcserver.h" #include "util.h" +#include "script/script.h" +#include "script/script_error.h" #ifdef ENABLE_WALLET #include "db.h" #include "wallet.h" @@ -25,10 +28,8 @@ #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" +#include "univalue/univalue.h" -using namespace json_spirit; using namespace std; /** @@ -36,7 +37,7 @@ using namespace std; * or from the last difficulty change if 'lookup' is nonpositive. * If 'height' is nonnegative, compute the estimate at the time when a given block was found. */ -Value GetNetworkHashPS(int lookup, int height) +UniValue GetNetworkHashPS(int lookup, int height) { CBlockIndex* pb = chainActive.Tip(); @@ -74,7 +75,7 @@ Value GetNetworkHashPS(int lookup, int height) return (int64_t)(workDiff.getdouble() / timeDiff); } -Value getnetworkhashps(const Array& params, bool fHelp) +UniValue getnetworkhashps(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( @@ -96,7 +97,7 @@ Value getnetworkhashps(const Array& params, bool fHelp) } #ifdef ENABLE_WALLET -Value getgenerate(const Array& params, bool fHelp) +UniValue getgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -109,11 +110,13 @@ Value getgenerate(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getgenerate", "") + HelpExampleRpc("getgenerate", "")); + LOCK(cs_main); + return GetBoolArg("-gen", false); } -Value setgenerate(const Array& params, bool fHelp) +UniValue setgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -163,9 +166,9 @@ Value setgenerate(const Array& params, bool fHelp) nHeightEnd = nHeightStart + nGenerate; } unsigned int nExtraNonce = 0; - Array blockHashes; - while (!ShutdownRequested() && nHeight < nHeightEnd) { - std::unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, false)); + UniValue blockHashes(UniValue::VARR); + while (nHeight < nHeightEnd) { + auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, false)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); CBlock* pblock = &pblocktemplate->block; @@ -191,10 +194,10 @@ Value setgenerate(const Array& params, bool fHelp) GenerateBitcoins(pwalletMain, nGenProcLimit); } - return Value::null; + return NullUniValue; } -Value gethashespersec(const Array& params, bool fHelp) +UniValue gethashespersec(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -213,7 +216,7 @@ Value gethashespersec(const Array& params, bool fHelp) #endif -Value getmininginfo(const Array& params, bool fHelp) +UniValue getmininginfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -236,7 +239,7 @@ Value getmininginfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getmininginfo", "") + HelpExampleRpc("getmininginfo", "")); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); @@ -256,7 +259,7 @@ Value getmininginfo(const Array& params, bool fHelp) // NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts -Value prioritisetransaction(const Array& params, bool fHelp) +UniValue prioritisetransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) throw runtime_error( @@ -275,6 +278,8 @@ Value prioritisetransaction(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")); + LOCK(cs_main); + uint256 hash = ParseHashStr(params[0].get_str(), "txid"); CAmount nAmount = params[2].get_int64(); @@ -285,10 +290,10 @@ Value prioritisetransaction(const Array& params, bool fHelp) // NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller -static Value BIP22ValidationResult(const CValidationState& state) +static UniValue BIP22ValidationResult(const CValidationState& state) { if (state.IsValid()) - return Value::null; + return NullUniValue; std::string strRejectReason = state.GetRejectReason(); if (state.IsError()) @@ -302,7 +307,7 @@ static Value BIP22ValidationResult(const CValidationState& state) return "valid?"; } -Value getblocktemplate(const Array& params, bool fHelp) +UniValue getblocktemplate(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -380,21 +385,21 @@ Value getblocktemplate(const Array& params, bool fHelp) LOCK(cs_main); std::string strMode = "template"; - Value lpval = Value::null; + UniValue 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) + const UniValue& oparam = params[0].get_obj(); + const UniValue& modeval = find_value(oparam, "mode"); + if (modeval.isStr()) strMode = modeval.get_str(); - else if (modeval.type() == null_type) { + else if (modeval.isNull()) { /* Do nothing */ } else throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); lpval = find_value(oparam, "longpollid"); - if (strMode == "proposal") { - const Value& dataval = find_value(oparam, "data"); - if (dataval.type() != str_type) + if (strMode == "proposal" || strMode == "submit") { + const UniValue& dataval = find_value(oparam, "data"); + if (!dataval.isStr()) throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); CBlock block; @@ -433,13 +438,13 @@ 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(); @@ -514,9 +519,9 @@ Value getblocktemplate(const Array& params, bool fHelp) UpdateTime(pblock, pindexPrev); pblock->nNonce = 0; - static const Array aCaps = boost::assign::list_of("proposal"); + UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); - Array transactions; + UniValue transactions(UniValue::VARR); map setTxIndex; int i = 0; BOOST_FOREACH (CTransaction& tx, pblock->vtx) { @@ -526,13 +531,13 @@ Value getblocktemplate(const Array& params, bool fHelp) if (tx.IsCoinBase()) continue; - Object entry; + UniValue entry(UniValue::VOBJ); entry.push_back(Pair("data", EncodeHexTx(tx))); entry.push_back(Pair("hash", txHash.GetHex())); - Array deps; + UniValue deps(UniValue::VARR); BOOST_FOREACH (const CTxIn& in, tx.vin) { if (setTxIndex.count(in.prevout.hash)) deps.push_back(setTxIndex[in.prevout.hash]); @@ -546,27 +551,61 @@ Value getblocktemplate(const Array& params, bool fHelp) transactions.push_back(entry); } - Object aux; + UniValue coinbasetxn(UniValue::VARR); + map setTxIndex1; + int j = 0; + BOOST_FOREACH (CTransaction& tx, pblock->vtx) {//Incase if multi coinbase + if(tx.IsCoinBase()){ + uint256 txHash = tx.GetHash(); + setTxIndex1[txHash] = j++; + + /* if (tx.IsCoinBase()) + continue; */ + + UniValue entry(UniValue::VOBJ); + + entry.push_back(Pair("data", EncodeHexTx(tx))); + + entry.push_back(Pair("hash", txHash.GetHex())); + + UniValue deps(UniValue::VARR); + BOOST_FOREACH (const CTxIn& in, tx.vin) { + if (setTxIndex.count(in.prevout.hash)) + deps.push_back(setTxIndex[in.prevout.hash]); + } + entry.push_back(Pair("depends", deps)); + + int index_in_template = j - 1; + entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); + entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[index_in_template])); + + coinbasetxn.push_back(entry); + } + } + + UniValue aux(UniValue::VOBJ); aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); uint256 hashTarget = uint256().SetCompact(pblock->nBits); - static Array aMutable; + static UniValue aMutable(UniValue::VARR); if (aMutable.empty()) { aMutable.push_back("time"); aMutable.push_back("transactions"); aMutable.push_back("prevblock"); } - Array aVotes; + UniValue aVotes(UniValue::VARR); + UniValue superBlock(UniValue::VARR); - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("capabilities", aCaps)); result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); result.push_back(Pair("coinbaseaux", aux)); result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].GetValueOut())); + result.push_back(Pair("coinbasetxn", coinbasetxn[0])); result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", hashTarget.GetHex())); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast() + 1)); @@ -579,7 +618,7 @@ Value getblocktemplate(const Array& params, bool fHelp) result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight + 1))); result.push_back(Pair("votes", aVotes)); - Object aMasternode; + UniValue aMasternode(UniValue::VOBJ); if (pblock->payee != CScript()) { CTxDestination address1; ExtractDestination(pblock->payee, address1); @@ -589,9 +628,8 @@ Value getblocktemplate(const Array& params, bool fHelp) aMasternode.push_back(Pair("payee", address2.ToString().c_str())); aMasternode.push_back(Pair("script", HexStr(pblock->vtx[0].vout[1].scriptPubKey))); aMasternode.push_back(Pair("amount", (int64_t)pblock->vtx[0].vout[1].nValue)); - } - else - { + + } else { result.push_back(Pair("payee", "")); result.push_back(Pair("payee_amount", "")); } @@ -624,7 +662,7 @@ class submitblock_StateCatcher : public CValidationInterface }; }; -Value submitblock(const Array& params, bool fHelp) +UniValue submitblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -681,7 +719,7 @@ Value submitblock(const Array& params, bool fHelp) return BIP22ValidationResult(state); } -Value estimatefee(const Array& params, bool fHelp) +UniValue estimatefee(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -699,7 +737,7 @@ Value estimatefee(const Array& params, bool fHelp) "\nExample:\n" + 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) @@ -712,7 +750,7 @@ Value estimatefee(const Array& params, bool fHelp) return ValueFromAmount(feeRate.GetFeePerK()); } -Value estimatepriority(const Array& params, bool fHelp) +UniValue estimatepriority(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -730,7 +768,7 @@ Value estimatepriority(const Array& params, bool fHelp) "\nExample:\n" + 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 b7d8289a..76470234 100755 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -23,13 +23,11 @@ #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" #include +#include "univalue/univalue.h" using namespace boost; using namespace boost::assign; -using namespace json_spirit; using namespace std; /** @@ -45,7 +43,7 @@ using namespace std; * * Or alternatively, create a specific query method for the information. **/ -Value getinfo(const Array& params, bool fHelp) +UniValue getinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -80,7 +78,7 @@ Value getinfo(const Array& params, bool fHelp) proxyType proxy; GetProxy(NET_IPV4, proxy); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); #ifdef ENABLE_WALLET @@ -111,7 +109,7 @@ Value getinfo(const Array& params, bool fHelp) } #ifdef ENABLE_WALLET -class DescribeAddressVisitor : public boost::static_visitor +class DescribeAddressVisitor : public boost::static_visitor { private: isminetype mine; @@ -119,11 +117,11 @@ class DescribeAddressVisitor : public boost::static_visitor public: DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {} - Object operator()(const CNoDestination& dest) const { return Object(); } + UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); } - Object operator()(const CKeyID& keyID) const + UniValue operator()(const CKeyID& keyID) const { - Object obj; + UniValue obj(UniValue::VOBJ); CPubKey vchPubKey; obj.push_back(Pair("isscript", false)); if (mine == ISMINE_SPENDABLE) { @@ -134,9 +132,9 @@ class DescribeAddressVisitor : public boost::static_visitor return obj; } - Object operator()(const CScriptID& scriptID) const + UniValue operator()(const CScriptID& scriptID) const { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("isscript", true)); if (mine != ISMINE_NO) { CScript subscript; @@ -147,7 +145,7 @@ class DescribeAddressVisitor : public boost::static_visitor ExtractDestinations(subscript, whichType, addresses, nRequired); obj.push_back(Pair("script", GetTxnOutputType(whichType))); obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); - Array a; + UniValue a(UniValue::VARR); BOOST_FOREACH (const CTxDestination& addr, addresses) a.push_back(CBitcoinAddress(addr).ToString()); obj.push_back(Pair("addresses", a)); @@ -162,10 +160,10 @@ class DescribeAddressVisitor : public boost::static_visitor /* Used for updating/reading spork settings on the network */ -Value spork(const Array& params, bool fHelp) +UniValue spork(const UniValue& params, bool fHelp) { if (params.size() == 1 && params[0].get_str() == "show") { - Object ret; + UniValue ret(UniValue::VOBJ); std::map::iterator it = mapSporksActive.begin(); while (it != mapSporksActive.end()) { ret.push_back(Pair(sporkManager.GetSporkNameByID(it->second.nSporkID), it->second.nValue)); @@ -197,7 +195,7 @@ Value spork(const Array& params, bool fHelp) HelpRequiringPassphrase()); } -Value validateaddress(const Array& params, bool fHelp) +UniValue validateaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -223,7 +221,7 @@ Value validateaddress(const Array& params, bool fHelp) CBitcoinAddress address(params[0].get_str()); bool isValid = address.IsValid(); - Object ret; + UniValue ret(UniValue::VOBJ); ret.push_back(Pair("isvalid", isValid)); if (isValid) { CTxDestination dest = address.Get(); @@ -234,8 +232,8 @@ Value validateaddress(const Array& params, bool fHelp) ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false)); 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()); + UniValue detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest); + ret.pushKVs(detail); } if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); @@ -247,10 +245,10 @@ Value validateaddress(const Array& params, bool fHelp) /** * Used by addmultisigaddress / createmultisig: */ -CScript _createmultisig_redeemScript(const Array& params) +CScript _createmultisig_redeemScript(const UniValue& params) { int nRequired = params[0].get_int(); - const Array& keys = params[1].get_array(); + const UniValue& keys = params[1].get_array(); // Gather public keys if (nRequired < 1) @@ -304,7 +302,7 @@ CScript _createmultisig_redeemScript(const Array& params) return result; } -Value createmultisig(const Array& params, bool fHelp) +UniValue createmultisig(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 2) { string msg = "createmultisig nrequired [\"key\",...]\n" @@ -337,14 +335,14 @@ Value createmultisig(const Array& params, bool fHelp) CScriptID innerID(inner); CBitcoinAddress address(innerID); - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("address", address.ToString())); result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end()))); return result; } -Value verifymessage(const Array& params, bool fHelp) +UniValue verifymessage(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) throw runtime_error( @@ -393,7 +391,7 @@ Value verifymessage(const Array& params, bool fHelp) return (pubkey.GetID() == keyID); } -Value setmocktime(const Array& params, bool fHelp) +UniValue setmocktime(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -408,14 +406,14 @@ Value setmocktime(const Array& params, bool fHelp) LOCK(cs_main); - RPCTypeCheck(params, boost::assign::list_of(int_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); SetMockTime(params[0].get_int64()); - return Value::null; + return NullUniValue; } #ifdef ENABLE_WALLET -Value getstakingstatus(const Array& params, bool fHelp) +UniValue getstakingstatus(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -432,7 +430,7 @@ Value getstakingstatus(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getstakingstatus", "") + HelpExampleRpc("getstakingstatus", "")); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("validtime", chainActive.Tip()->nTime > 1471482000)); obj.push_back(Pair("haveconnections", !vNodes.empty())); if (pwalletMain) { diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index cf310ab9..93f761ab 100755 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -18,12 +18,11 @@ #include -#include "json/json_spirit_value.h" +#include "univalue/univalue.h" -using namespace json_spirit; using namespace std; -Value getconnectioncount(const Array& params, bool fHelp) +UniValue getconnectioncount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -38,7 +37,7 @@ Value getconnectioncount(const Array& params, bool fHelp) return (int)vNodes.size(); } -Value ping(const Array& params, bool fHelp) +UniValue ping(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -55,7 +54,7 @@ Value ping(const Array& params, bool fHelp) pNode->fPingQueued = true; } - return Value::null; + return NullUniValue; } static void CopyNodeStats(std::vector& vstats) @@ -71,7 +70,7 @@ static void CopyNodeStats(std::vector& vstats) } } -Value getpeerinfo(const Array& params, bool fHelp) +UniValue getpeerinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -113,10 +112,10 @@ Value getpeerinfo(const Array& params, bool fHelp) vector vstats; CopyNodeStats(vstats); - Array ret; + UniValue ret(UniValue::VARR); BOOST_FOREACH (const CNodeStats& stats, vstats) { - Object obj; + UniValue obj(UniValue::VOBJ); CNodeStateStats statestats; bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); obj.push_back(Pair("id", stats.nodeid)); @@ -143,7 +142,7 @@ Value getpeerinfo(const Array& params, bool fHelp) obj.push_back(Pair("banscore", statestats.nMisbehavior)); obj.push_back(Pair("synced_headers", statestats.nSyncHeight)); obj.push_back(Pair("synced_blocks", statestats.nCommonHeight)); - Array heights; + UniValue heights(UniValue::VARR); BOOST_FOREACH (int height, statestats.vHeightInFlight) { heights.push_back(height); } @@ -157,7 +156,7 @@ Value getpeerinfo(const Array& params, bool fHelp) return ret; } -Value addnode(const Array& params, bool fHelp) +UniValue addnode(const UniValue& params, bool fHelp) { string strCommand; if (params.size() == 2) @@ -179,7 +178,7 @@ Value addnode(const Array& params, bool fHelp) if (strCommand == "onetry") { CAddress addr; OpenNetworkConnection(addr, NULL, strNode.c_str()); - return Value::null; + return NullUniValue; } LOCK(cs_vAddedNodes); @@ -198,10 +197,10 @@ Value addnode(const Array& params, bool fHelp) vAddedNodes.erase(it); } - return Value::null; + return NullUniValue; } -Value getaddednodeinfo(const Array& params, bool fHelp) +UniValue getaddednodeinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -250,10 +249,10 @@ Value getaddednodeinfo(const Array& params, bool fHelp) throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); } - Array ret; + UniValue ret(UniValue::VARR); if (!fDns) { BOOST_FOREACH (string& strAddNode, laddedNodes) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", strAddNode)); ret.push_back(obj); } @@ -266,24 +265,24 @@ Value getaddednodeinfo(const Array& params, bool fHelp) if (Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) laddedAddreses.push_back(make_pair(strAddNode, vservNode)); else { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", strAddNode)); obj.push_back(Pair("connected", false)); - Array addresses; + UniValue addresses(UniValue::VARR); obj.push_back(Pair("addresses", addresses)); } } LOCK(cs_vNodes); for (list > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", it->first)); - Array addresses; + UniValue addresses(UniValue::VARR); bool fConnected = false; BOOST_FOREACH (CService& addrNode, it->second) { bool fFound = false; - Object node; + UniValue node(UniValue::VOBJ); node.push_back(Pair("address", addrNode.ToString())); BOOST_FOREACH (CNode* pnode, vNodes) if (pnode->addr == addrNode) { @@ -304,7 +303,7 @@ Value getaddednodeinfo(const Array& params, bool fHelp) return ret; } -Value getnettotals(const Array& params, bool fHelp) +UniValue getnettotals(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 0) throw runtime_error( @@ -320,22 +319,22 @@ Value getnettotals(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getnettotals", "") + HelpExampleRpc("getnettotals", "")); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); obj.push_back(Pair("timemillis", GetTimeMillis())); return obj; } -static Array GetNetworksInfo() +static UniValue GetNetworksInfo() { - Array networks; + UniValue networks; for (int n = 0; n < NET_MAX; ++n) { enum Network network = static_cast(n); if (network == NET_UNROUTABLE) continue; proxyType proxy; - Object obj; + UniValue obj(UniValue::VOBJ); GetProxy(network, proxy); obj.push_back(Pair("name", GetNetworkName(network))); obj.push_back(Pair("limited", IsLimited(network))); @@ -346,7 +345,7 @@ static Array GetNetworksInfo() return networks; } -Value getnetworkinfo(const Array& params, bool fHelp) +UniValue getnetworkinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -384,7 +383,7 @@ Value getnetworkinfo(const Array& params, bool fHelp) LOCK(cs_main); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("subversion", FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()))); @@ -394,11 +393,11 @@ Value getnetworkinfo(const Array& params, bool fHelp) obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("networks", GetNetworksInfo())); obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); - Array localAddresses; + UniValue localAddresses(UniValue::VARR); { LOCK(cs_mapLocalHost); BOOST_FOREACH (const PAIRTYPE(CNetAddr, LocalServiceInfo) & item, mapLocalHost) { - Object rec; + UniValue rec(UniValue::VOBJ); rec.push_back(Pair("address", item.first.ToString())); rec.push_back(Pair("port", item.second.nPort)); rec.push_back(Pair("score", item.second.nScore)); diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp index 4183775f..256a2ce6 100755 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -27,10 +27,12 @@ #include #include +#include "univalue/univalue.h" + using namespace std; using namespace boost; using namespace boost::asio; -using namespace json_spirit; + //! Number of bytes to allocate and read at most at once in post data const size_t POST_READ_SIZE = 256 * 1024; @@ -257,20 +259,20 @@ int ReadHTTPMessage(std::basic_istream& stream, map& mapHe * http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx */ -string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id) +string JSONRPCRequest(const string& strMethod, const UniValue& params, const UniValue& id) { - Object request; + UniValue request(UniValue::VOBJ); 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) +UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id) { - Object reply; - if (error.type() != null_type) - reply.push_back(Pair("result", Value::null)); + UniValue reply(UniValue::VOBJ); + if (!error.isNull()) + reply.push_back(Pair("result", NullUniValue)); else reply.push_back(Pair("result", result)); reply.push_back(Pair("error", error)); @@ -278,15 +280,15 @@ Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id) return reply; } -string JSONRPCReply(const Value& result, const Value& error, const Value& id) +string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id) { - Object reply = JSONRPCReplyObj(result, error, id); - return write_string(Value(reply), false) + "\n"; + UniValue reply = JSONRPCReplyObj(result, error, id); + return reply.write() + "\n"; } -Object JSONRPCError(int code, const string& message) +UniValue JSONRPCError(int code, const string& message) { - Object error; + UniValue error(UniValue::VOBJ); error.push_back(Pair("code", code)); error.push_back(Pair("message", message)); return error; diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h index 0f0814f3..0c30dfcc 100755 --- 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 "univalue/univalue.h" //! HTTP status codes enum HTTPStatusCode { @@ -152,9 +150,9 @@ bool ReadHTTPRequestLine(std::basic_istream& stream, int& proto, std::stri int ReadHTTPStatus(std::basic_istream& stream, int& proto); int ReadHTTPHeaders(std::basic_istream& stream, std::map& mapHeadersRet); int ReadHTTPMessage(std::basic_istream& stream, std::map& mapHeadersRet, std::string& strMessageRet, int nProto, size_t max_size); -std::string JSONRPCRequest(const std::string& strMethod, const json_spirit::Array& params, const json_spirit::Value& id); -json_spirit::Object JSONRPCReplyObj(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id); -std::string JSONRPCReply(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id); -json_spirit::Object JSONRPCError(int code, const std::string& message); +std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id); +UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id); +std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id); +UniValue JSONRPCError(int code, const std::string& message); #endif // BITCOIN_RPCPROTOCOL_H diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index d75b8477..9770fbf9 100755 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -17,22 +17,22 @@ #include "script/sign.h" #include "script/standard.h" #include "uint256.h" +#include "univalue/univalue.h" + #ifdef ENABLE_WALLET #include "wallet.h" #endif #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" #include + using namespace boost; using namespace boost::assign; -using namespace json_spirit; using namespace std; -void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex) +void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex) { txnouttype type; vector addresses; @@ -50,26 +50,26 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeH out.push_back(Pair("reqSigs", nRequired)); out.push_back(Pair("type", GetTxnOutputType(type))); - Array a; + UniValue a(UniValue::VARR); BOOST_FOREACH (const CTxDestination& addr, addresses) a.push_back(CBitcoinAddress(addr).ToString()); out.push_back(Pair("addresses", a)); } -void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) +void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) { entry.push_back(Pair("txid", tx.GetHash().GetHex())); entry.push_back(Pair("version", tx.nVersion)); entry.push_back(Pair("locktime", (int64_t)tx.nLockTime)); - Array vin; + UniValue vin(UniValue::VARR); BOOST_FOREACH (const CTxIn& txin, tx.vin) { - Object in; + UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); else { in.push_back(Pair("txid", txin.prevout.hash.GetHex())); in.push_back(Pair("vout", (int64_t)txin.prevout.n)); - Object o; + UniValue o(UniValue::VOBJ); o.push_back(Pair("asm", txin.scriptSig.ToString())); o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); in.push_back(Pair("scriptSig", o)); @@ -78,20 +78,20 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) vin.push_back(in); } entry.push_back(Pair("vin", vin)); - Array vout; + UniValue vout(UniValue::VARR); for (unsigned int i = 0; i < tx.vout.size(); i++) { const CTxOut& txout = tx.vout[i]; - Object out; + UniValue out(UniValue::VOBJ); out.push_back(Pair("value", ValueFromAmount(txout.nValue))); out.push_back(Pair("n", (int64_t)i)); - Object o; + UniValue o(UniValue::VOBJ); ScriptPubKeyToJSON(txout.scriptPubKey, o, true); out.push_back(Pair("scriptPubKey", o)); vout.push_back(out); } entry.push_back(Pair("vout", vout)); - if (hashBlock != 0) { + if (!hashBlock.IsNull()) { entry.push_back(Pair("blockhash", hashBlock.GetHex())); BlockMap::iterator mi = mapBlockIndex.find(hashBlock); if (mi != mapBlockIndex.end() && (*mi).second) { @@ -106,7 +106,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) } } -Value getrawtransaction(const Array& params, bool fHelp) +UniValue getrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -187,14 +187,14 @@ Value getrawtransaction(const Array& params, bool fHelp) if (!fVerbose) return strHex; - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("hex", strHex)); TxToJSON(tx, hashBlock, result); return result; } #ifdef ENABLE_WALLET -Value listunspent(const Array& params, bool fHelp) +UniValue listunspent(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) throw runtime_error( @@ -229,7 +229,7 @@ Value listunspent(const Array& params, bool fHelp) "\nExamples\n" + HelpExampleCli("listunspent", "") + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")); - RPCTypeCheck(params, list_of(int_type)(int_type)(array_type)); + RPCTypeCheck(params, list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR)); int nMinDepth = 1; if (params.size() > 0) @@ -241,18 +241,18 @@ Value listunspent(const Array& params, bool fHelp) set setAddress; if (params.size() > 2) { - Array inputs = params[2].get_array(); - BOOST_FOREACH (Value& input, inputs) { + Univalue inputs = params[2].get_array(); + BOOST_FOREACH (UniValue& input, inputs) { CBitcoinAddress address(input.get_str()); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid LUX address: ") + input.get_str()); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid lux address: ") + input.get_str()); if (setAddress.count(address)) throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + input.get_str()); setAddress.insert(address); } } - Array results; + UniValue results(UniValue::VARR); vector vecOutputs; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -272,7 +272,7 @@ Value listunspent(const Array& params, bool fHelp) CAmount nValue = out.tx->vout[out.i].nValue; const CScript& pk = out.tx->vout[out.i].scriptPubKey; - Object entry; + UniValue entry(UniValue::VOBJ); entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); entry.push_back(Pair("vout", out.i)); CTxDestination address; @@ -301,7 +301,7 @@ Value listunspent(const Array& params, bool fHelp) } #endif -Value createrawtransaction(const Array& params, bool fHelp) +UniValue createrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) throw runtime_error( @@ -332,20 +332,25 @@ Value createrawtransaction(const Array& params, bool fHelp) "\nExamples\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")); - RPCTypeCheck(params, list_of(array_type)(obj_type)); + LOCK(cs_main); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)); - Array inputs = params[0].get_array(); - Object sendTo = params[1].get_obj(); + UniValue inputs = params[0].get_array(); + UniValue sendTo = params[1].get_obj(); CMutableTransaction rawTx; - BOOST_FOREACH (const Value& input, inputs) { - const Object& o = input.get_obj(); + + for (unsigned int i = 0; i < inputs.size(); i++) { + UniValue input = inputs[i]; + + const UniValue& o = input.get_obj(); uint256 txid = ParseHashO(o, "txid"); - const Value& vout_v = find_value(o, "vout"); - if (vout_v.type() != int_type) + const UniValue& vout_v = find_value(o, "vout"); + if (!vout_v.isNum()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); int nOutput = vout_v.get_int(); if (nOutput < 0) @@ -356,17 +361,19 @@ 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 LUX address: ") + s.name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid LUX 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); @@ -375,7 +382,7 @@ Value createrawtransaction(const Array& params, bool fHelp) return EncodeHexTx(rawTx); } -Value decoderawtransaction(const Array& params, bool fHelp) +UniValue decoderawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -426,20 +433,20 @@ Value decoderawtransaction(const Array& params, bool fHelp) LOCK(cs_main); - RPCTypeCheck(params, list_of(str_type)); + RPCTypeCheck(params, list_of(UniValue::VSTR)); CTransaction tx; if (!DecodeHexTx(tx, params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); - Object result; - TxToJSON(tx, 0, result); + UniValue result(UniValue::VOBJ); + TxToJSON(tx, uint256(), result); return result; } -Value decodescript(const Array& params, bool fHelp) +UniValue decodescript(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -464,9 +471,9 @@ Value decodescript(const Array& params, bool fHelp) LOCK(cs_main); - RPCTypeCheck(params, list_of(str_type)); + RPCTypeCheck(params, list_of(UniValue::VSTR)); - Object r; + UniValue r(UniValue::VOBJ); CScript script; if (params[0].get_str().size() > 0) { vector scriptData(ParseHexV(params[0], "argument")); @@ -480,7 +487,7 @@ Value decodescript(const Array& params, bool fHelp) return r; } -Value signrawtransaction(const Array& params, bool fHelp) +UniValue signrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) throw runtime_error( @@ -528,7 +535,10 @@ Value signrawtransaction(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("signrawtransaction", "\"myhex\"") + HelpExampleRpc("signrawtransaction", "\"myhex\"")); - RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true); + LOCK(cs_main); + + + RPCTypeCheck(params, 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); @@ -571,10 +581,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) { + UniValue keys = params[2].get_array(); + for (unsigned int idx = 0; idx < keys.size(); idx++) { + UniValue k = keys[idx]; CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(k.get_str()); if (!fGood) @@ -591,15 +602,17 @@ 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) { - Array prevTxs = params[1].get_array(); - BOOST_FOREACH (Value& p, prevTxs) { - if (p.type() != obj_type) + if (params.size() > 1 && !params[1].isNull()) { + UniValue prevTxs = params[1].get_array(); + for (unsigned int idx = 0; idx < prevTxs.size(); idx++) { + + UniValue p = prevTxs[idx]; + if (!p.isObject()) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); - Object prevOut = p.get_obj(); + UniValue prevOut = p.get_obj(); - RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)); + RPCTypeCheckObj(prevOut, map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)); uint256 txid = ParseHashO(prevOut, "txid"); @@ -627,9 +640,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, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript", str_type)); - Value v = find_value(prevOut, "redeemScript"); - if (!(v == Value::null)) { + RPCTypeCheckObj(prevOut, map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript", UniValue::VSTR)); + UniValue v = find_value(prevOut, "redeemScript"); + if (!(v.isNull())) { vector rsData(ParseHexV(v, "redeemScript")); CScript redeemScript(rsData.begin(), rsData.end()); tempKeystore.AddCScript(redeemScript); @@ -645,7 +658,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))(string("ALL|ANYONECANPAY"), int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))(string("NONE"), int(SIGHASH_NONE))(string("NONE|ANYONECANPAY"), int(SIGHASH_NONE | SIGHASH_ANYONECANPAY))(string("SINGLE"), int(SIGHASH_SINGLE))(string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY)); string strHashType = params[3].get_str(); @@ -680,14 +693,14 @@ Value signrawtransaction(const Array& params, bool fHelp) fComplete = false; } - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("hex", EncodeHexTx(mergedTx))); result.push_back(Pair("complete", fComplete)); return result; } -Value sendrawtransaction(const Array& params, bool fHelp) +UniValue sendrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -708,7 +721,7 @@ Value sendrawtransaction(const Array& params, bool fHelp) LOCK(cs_main); - RPCTypeCheck(params, list_of(str_type)(bool_type)); + RPCTypeCheck(params, list_of(UniValue::VSTR)(UniValue::VBOOL)); // parse hex string from parameter CTransaction tx; diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index c5c44f2d..450a8d0c 100755 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -15,11 +15,12 @@ #include "random.h" #include "sync.h" #include "utilstrencodings.h" +#include "univalue/univalue.h" + #ifdef ENABLE_WALLET #include "wallet.h" #endif -#include "json/json_spirit_writer_template.h" #include #include #include @@ -34,7 +35,6 @@ using namespace boost; using namespace boost::asio; -using namespace json_spirit; using namespace std; static std::string strRPCUserColonPass; @@ -81,37 +81,38 @@ void RPCServer::OnPostCommand(boost::function slot) g_rpcSignals.PostCommand.connect(boost::bind(slot, _1)); } -void RPCTypeCheck(const Array& params, - const list& typesExpected, + +void RPCTypeCheck(const UniValue& params, + const list& typesExpected, bool fAllowNull) { unsigned int i = 0; - BOOST_FOREACH (Value_type t, typesExpected) { + BOOST_FOREACH (UniValue::VType t, typesExpected) { if (params.size() <= i) break; - const Value& v = params[i]; - if (!((v.type() == t) || (fAllowNull && (v.type() == null_type)))) { + const UniValue& v = params[i]; + 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) + BOOST_FOREACH (const PAIRTYPE(string, UniValue::VType) & t, typesExpected) { + const UniValue& v = find_value(o, t.first); + 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); } } @@ -122,7 +123,7 @@ static inline int64_t roundint64(double d) return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); } -CAmount AmountFromValue(const Value& value) +CAmount AmountFromValue(const UniValue& value) { double dAmount = value.get_real(); if (dAmount <= 0.0 || dAmount > 500000000.0) @@ -133,15 +134,15 @@ CAmount AmountFromValue(const Value& value) return nAmount; } -Value ValueFromAmount(const CAmount& amount) +UniValue ValueFromAmount(const CAmount& amount) { return (double)amount / (double)COIN; } -uint256 ParseHashV(const Value& v, string strName) +uint256 ParseHashV(const UniValue& 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 + "')"); @@ -149,20 +150,20 @@ uint256 ParseHashV(const Value& v, string strName) result.SetHex(strHex); return result; } -uint256 ParseHashO(const Object& o, string strKey) +uint256 ParseHashO(const UniValue& o, string strKey) { return ParseHashV(find_value(o, strKey), strKey); } -vector ParseHexV(const Value& v, string strName) +vector ParseHexV(const UniValue& 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 + "')"); return ParseHex(strHex); } -vector ParseHexO(const Object& o, string strKey) +vector ParseHexO(const UniValue& o, string strKey) { return ParseHexV(find_value(o, strKey), strKey); } @@ -197,7 +198,7 @@ string CRPCTable::help(string strCommand) const #endif try { - Array params; + UniValue params; rpcfn_type pfn = pcmd->actor; if (setDone.insert(pfn).second) (*pfn)(params, true); @@ -226,7 +227,7 @@ string CRPCTable::help(string strCommand) const return strRet; } -Value help(const Array& params, bool fHelp) +UniValue help(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -245,7 +246,7 @@ Value help(const Array& params, bool fHelp) } -Value stop(const Array& params, bool fHelp) +UniValue stop(const UniValue& params, bool fHelp) { // Accept the deprecated and ignored 'detach' boolean argument if (fHelp || params.size() > 1) @@ -423,7 +424,7 @@ bool HTTPAuthorized(map& mapHeaders) return TimingResistantEqual(strUserPass, strRPCUserColonPass); } -void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) +void ErrorReply(std::ostream& stream, const UniValue& objError, const UniValue& id) { // Send error reply from json-rpc error object int nStatus = HTTP_INTERNAL_SERVER_ERROR; @@ -432,7 +433,7 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) 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; } @@ -824,72 +825,72 @@ void RPCRunLater(const std::string& name, boost::function func, int6 class JSONRequest { public: - Value id; + UniValue id; string strMethod; - Array params; + UniValue params; - JSONRequest() { id = Value::null; } - void parse(const Value& valRequest); + JSONRequest() { id = NullUniValue; } + void parse(const UniValue& valRequest); }; -void JSONRequest::parse(const Value& valRequest) +void JSONRequest::parse(const UniValue& 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(); + const UniValue& request = valRequest.get_obj(); // Parse id now so errors from here on will have the id id = find_value(request, "id"); // Parse method - Value valMethod = find_value(request, "method"); - if (valMethod.type() == null_type) + UniValue valMethod = find_value(request, "method"); + 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") LogPrint("rpc", "ThreadRPCServer method=%s\n", SanitizeString(strMethod)); // Parse params - Value valParams = find_value(request, "params"); - if (valParams.type() == array_type) + UniValue valParams = find_value(request, "params"); + if (valParams.isArray()) params = valParams.get_array(); - else if (valParams.type() == null_type) - params = Array(); + else if (valParams.isNull()) + params = UniValue(UniValue::VARR); else throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array"); } -static Object JSONRPCExecOne(const Value& req) +static UniValue JSONRPCExecOne(const UniValue& req) { - Object rpc_result; + UniValue rpc_result(UniValue::VOBJ); JSONRequest jreq; try { jreq.parse(req); - Value result = tableRPC.execute(jreq.strMethod, jreq.params); - rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id); - } catch (Object& objError) { - rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id); + UniValue result = tableRPC.execute(jreq.strMethod, jreq.params); + rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id); + } catch (UniValue& objError) { + rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id); } catch (std::exception& e) { - rpc_result = JSONRPCReplyObj(Value::null, + rpc_result = JSONRPCReplyObj(NullUniValue, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); } return rpc_result; } -static string JSONRPCExecBatch(const Array& vReq) +static string JSONRPCExecBatch(const UniValue& vReq) { - Array ret; + UniValue ret(UniValue::VARR); 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, @@ -917,8 +918,8 @@ static bool HTTPReq_JSONRPC(AcceptedConnection* conn, JSONRequest jreq; try { // Parse request - Value valRequest; - if (!read_string(strRequest, valRequest)) + UniValue valRequest; + if (!valRequest.read(strRequest)) throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); // Return immediately if in warmup @@ -931,22 +932,22 @@ 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); + UniValue 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"); conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, strReply.size()) << strReply << std::flush; - } catch (Object& objError) { + } catch (UniValue& objError) { ErrorReply(conn->stream(), objError, jreq.id); return false; } catch (std::exception& e) { @@ -992,7 +993,7 @@ void ServiceConnection(AcceptedConnection* conn) } } -json_spirit::Value CRPCTable::execute(const std::string& strMethod, const json_spirit::Array& params) const +UniValue CRPCTable::execute(const std::string& strMethod, const UniValue& params) const { // Find method const CRPCCommand* pcmd = tableRPC[strMethod]; @@ -1010,6 +1011,17 @@ json_spirit::Value CRPCTable::execute(const std::string& strMethod, const json_s g_rpcSignals.PostCommand(*pcmd); } +std::vector CRPCTable::listCommands() const +{ + std::vector commandList; + typedef std::map commandMap; + + std::transform( mapCommands.begin(), mapCommands.end(), + std::back_inserter(commandList), + boost::bind(&commandMap::UniValue::VType::first,_1) ); + return commandList; +} + std::string HelpExampleCli(string methodname, string args) { return "> lux-cli " + methodname + " " + args + "\n"; diff --git a/src/rpcserver.h b/src/rpcserver.h index 042f73db..7db00335 100755 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -15,9 +15,9 @@ #include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" +#include + +#include "univalue/univalue.h" class CRPCCommand; @@ -71,15 +71,15 @@ bool RPCIsInWarmup(std::string* statusOut); * the right number of arguments are passed, just that any passed are the correct type. * Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type)); */ -void RPCTypeCheck(const json_spirit::Array& params, - const std::list& typesExpected, +void RPCTypeCheck(const UniValue& 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, +void RPCTypeCheckObj(const UniValue& o, + const std::map& typesExpected, bool fAllowNull = false); /** @@ -91,7 +91,7 @@ void RPCRunLater(const std::string& name, boost::function func, int6 //! Convert boost::asio address to CNetAddr extern CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address); -typedef json_spirit::Value (*rpcfn_type)(const json_spirit::Array& params, bool fHelp); +typedef UniValue (*rpcfn_type)(const UniValue& params, bool fHelp); class CRPCCommand { @@ -122,9 +122,15 @@ class CRPCTable * @param method Method to execute * @param params Array of arguments (JSON objects) * @returns Result of the call. - * @throws an exception (json_spirit::Value) when an error happens. + * @throws an exception (UniValue) when an error happens. */ - json_spirit::Value execute(const std::string& method, const json_spirit::Array& params) const; + UniValue execute(const std::string& method, const UniValue& params) const; + + /** + * Returns a list of registered commands + * @returns List of registered commands. + */ + std::vector listCommands() const; }; extern const CRPCTable tableRPC; @@ -133,18 +139,17 @@ extern const CRPCTable tableRPC; * Utilities: convert hex-encoded Values * (throws error if not hex). */ -extern uint256 ParseHashV(const json_spirit::Value& v, std::string strName); -extern uint256 ParseHashO(const json_spirit::Object& o, std::string strKey); -extern std::vector ParseHexV(const json_spirit::Value& v, std::string strName); -extern std::vector ParseHexO(const json_spirit::Object& o, std::string strKey); +extern uint256 ParseHashV(const UniValue& v, std::string strName); +extern uint256 ParseHashO(const UniValue& o, std::string strKey); +extern std::vector ParseHexV(const UniValue& v, std::string strName); +extern std::vector ParseHexO(const UniValue& o, std::string strKey); extern void InitRPCMining(); extern void ShutdownRPCMining(); extern int64_t nWalletUnlockTime; -extern int getBlockTimeByHeight(int nHeight); -extern CAmount AmountFromValue(const json_spirit::Value& value); -extern json_spirit::Value ValueFromAmount(const CAmount& amount); +extern CAmount AmountFromValue(const UniValue& value); +extern UniValue ValueFromAmount(const CAmount& amount); extern double GetPoWDifficulty(const CBlockIndex* blockindex = NULL); extern std::string HelpRequiringPassphrase(); extern std::string HelpExampleCli(std::string methodname, std::string args); @@ -152,111 +157,119 @@ extern std::string HelpExampleRpc(std::string methodname, std::string args); extern void EnsureWalletIsUnlocked(); -extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, bool fHelp); // in rpcnet.cpp -extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value ping(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getnettotals(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp -extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value importaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value bip38encrypt(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value bip38decrypt(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value setstakesplitthreshold(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getstakesplitthreshold(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp -extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value estimatefee(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value estimatepriority(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp -extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getrawchangeaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value setaccount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getaccount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getaddressesbyaccount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value sendtoaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value sendtoaddressix(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value signmessage(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value verifymessage(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getreceivedbyaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getreceivedbyaccount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getbalance(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getunconfirmedbalance(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value movecmd(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value sendfrom(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value sendmany(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value addmultisigaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value createmultisig(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listreceivedbyaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listreceivedbyaccount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listtransactions(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listaddressgroupings(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listaccounts(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listsinceblock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value gettransaction(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value backupwallet(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value keypoolrefill(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value walletpassphrase(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value walletpassphrasechange(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value walletlock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value encryptwallet(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value validateaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getwalletinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getblockchaininfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getnetworkinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value setmocktime(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value reservebalance(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value multisend(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value autocombinerewards(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getstakingstatus(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp -extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value lockunspent(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listlockunspent(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value decodescript(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp -extern json_spirit::Value getblockhashes(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getpowdifficulty(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getmempoolinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getblockheader(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getchaintips(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value invalidateblock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value reconsiderblock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value darksend(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value spork(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value masternode(const json_spirit::Array& params, bool fHelp); -//extern json_spirit::Value masternodelist(const json_spirit::Array& params, bool fHelp); -//extern json_spirit::Value mnbudget(const json_spirit::Array& params, bool fHelp); -//extern json_spirit::Value mnbudgetvoteraw(const json_spirit::Array& params, bool fHelp); -//extern json_spirit::Value mnfinalbudget(const json_spirit::Array& params, bool fHelp); -//extern json_spirit::Value mnsync(const json_spirit::Array& params, bool fHelp); +extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp +extern UniValue getpeerinfo(const UniValue& params, bool fHelp); +extern UniValue ping(const UniValue& params, bool fHelp); +extern UniValue addnode(const UniValue& params, bool fHelp); +extern UniValue getaddednodeinfo(const UniValue& params, bool fHelp); +extern UniValue getnettotals(const UniValue& params, bool fHelp); + +extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp +extern UniValue importprivkey(const UniValue& params, bool fHelp); +extern UniValue importaddress(const UniValue& params, bool fHelp); +extern UniValue dumpwallet(const UniValue& params, bool fHelp); +extern UniValue importwallet(const UniValue& params, bool fHelp); +extern UniValue bip38encrypt(const UniValue& params, bool fHelp); +extern UniValue bip38decrypt(const UniValue& params, bool fHelp); + +extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp +extern UniValue importprivkey(const UniValue& params, bool fHelp); +extern UniValue importaddress(const UniValue& params, bool fHelp); +extern UniValue dumpwallet(const UniValue& params, bool fHelp); +extern UniValue importwallet(const UniValue& params, bool fHelp); +extern UniValue bip38encrypt(const UniValue& params, bool fHelp); +extern UniValue bip38decrypt(const UniValue& params, bool fHelp); +extern UniValue setstakesplitthreshold(const UniValue& params, bool fHelp); +extern UniValue getstakesplitthreshold(const UniValue& params, bool fHelp); +extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp +extern UniValue setgenerate(const UniValue& params, bool fHelp); +extern UniValue getnetworkhashps(const UniValue& params, bool fHelp); +extern UniValue gethashespersec(const UniValue& params, bool fHelp); +extern UniValue getmininginfo(const UniValue& params, bool fHelp); +extern UniValue prioritisetransaction(const UniValue& params, bool fHelp); +extern UniValue getblocktemplate(const UniValue& params, bool fHelp); + +extern UniValue submitblock(const UniValue& params, bool fHelp); +extern UniValue estimatefee(const UniValue& params, bool fHelp); +extern UniValue estimatepriority(const UniValue& params, bool fHelp); + +extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp +extern UniValue getaccountaddress(const UniValue& params, bool fHelp); +extern UniValue getrawchangeaddress(const UniValue& params, bool fHelp); +extern UniValue setaccount(const UniValue& params, bool fHelp); +extern UniValue getaccount(const UniValue& params, bool fHelp); +extern UniValue getaddressesbyaccount(const UniValue& params, bool fHelp); +extern UniValue sendtoaddress(const UniValue& params, bool fHelp); +extern UniValue sendtoaddressix(const UniValue& params, bool fHelp); +extern UniValue signmessage(const UniValue& params, bool fHelp); +extern UniValue verifymessage(const UniValue& params, bool fHelp); +extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp); +extern UniValue getreceivedbyaccount(const UniValue& params, bool fHelp); +extern UniValue getbalance(const UniValue& params, bool fHelp); +extern UniValue getunconfirmedbalance(const UniValue& params, bool fHelp); +extern UniValue movecmd(const UniValue& params, bool fHelp); +extern UniValue sendfrom(const UniValue& params, bool fHelp); +extern UniValue sendmany(const UniValue& params, bool fHelp); +extern UniValue addmultisigaddress(const UniValue& params, bool fHelp); +extern UniValue createmultisig(const UniValue& params, bool fHelp); +extern UniValue listreceivedbyaddress(const UniValue& params, bool fHelp); +extern UniValue listreceivedbyaccount(const UniValue& params, bool fHelp); +extern UniValue listtransactions(const UniValue& params, bool fHelp); +extern UniValue listaddressgroupings(const UniValue& params, bool fHelp); +extern UniValue listaccounts(const UniValue& params, bool fHelp); +extern UniValue listsinceblock(const UniValue& params, bool fHelp); +extern UniValue gettransaction(const UniValue& params, bool fHelp); +extern UniValue backupwallet(const UniValue& params, bool fHelp); +extern UniValue keypoolrefill(const UniValue& params, bool fHelp); +extern UniValue walletpassphrase(const UniValue& params, bool fHelp); +extern UniValue walletpassphrasechange(const UniValue& params, bool fHelp); +extern UniValue walletlock(const UniValue& params, bool fHelp); +extern UniValue encryptwallet(const UniValue& params, bool fHelp); +extern UniValue validateaddress(const UniValue& params, bool fHelp); +extern UniValue getinfo(const UniValue& params, bool fHelp); +extern UniValue getwalletinfo(const UniValue& params, bool fHelp); +extern UniValue getblockchaininfo(const UniValue& params, bool fHelp); +extern UniValue getnetworkinfo(const UniValue& params, bool fHelp); +extern UniValue setmocktime(const UniValue& params, bool fHelp); +extern UniValue reservebalance(const UniValue& params, bool fHelp); +extern UniValue multisend(const UniValue& params, bool fHelp); +extern UniValue autocombinerewards(const UniValue& params, bool fHelp); +extern UniValue getstakingstatus(const UniValue& params, bool fHelp); + +extern UniValue getrawtransaction(const UniValue& params, bool fHelp); // in rcprawtransaction.cpp +extern UniValue listunspent(const UniValue& params, bool fHelp); +extern UniValue lockunspent(const UniValue& params, bool fHelp); +extern UniValue listlockunspent(const UniValue& params, bool fHelp); +extern UniValue createrawtransaction(const UniValue& params, bool fHelp); +extern UniValue decoderawtransaction(const UniValue& params, bool fHelp); +extern UniValue decodescript(const UniValue& params, bool fHelp); +extern UniValue signrawtransaction(const UniValue& params, bool fHelp); +extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); + +extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpcblockchain.cpp +extern UniValue getblockhashes(const UniValue& params, bool fHelp); +extern UniValue getbestblockhash(const UniValue& params, bool fHelp); +extern UniValue getpowdifficulty(const UniValue& params, bool fHelp); +extern UniValue settxfee(const UniValue& params, bool fHelp); +extern UniValue getmempoolinfo(const UniValue& params, bool fHelp); +extern UniValue getrawmempool(const UniValue& params, bool fHelp); +extern UniValue getblockhash(const UniValue& params, bool fHelp); +extern UniValue getblock(const UniValue& params, bool fHelp); +extern UniValue getblockheader(const UniValue& params, bool fHelp); +extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp); +extern UniValue gettxout(const UniValue& params, bool fHelp); +extern UniValue verifychain(const UniValue& params, bool fHelp); +extern UniValue getchaintips(const UniValue& params, bool fHelp); +extern UniValue invalidateblock(const UniValue& params, bool fHelp); +extern UniValue reconsiderblock(const UniValue& params, bool fHelp); +extern UniValue darksend(const UniValue& params, bool fHelp); +extern UniValue spork(const UniValue& params, bool fHelp); +extern UniValue masternode(const UniValue& params, bool fHelp); +//extern UniValue masternodelist(const UniValue& params, bool fHelp); +//extern UniValue mnbudget(const UniValue& params, bool fHelp); +//extern UniValue mnbudgetvoteraw(const UniValue& params, bool fHelp); +//extern UniValue mnfinalbudget(const UniValue& params, bool fHelp); +//extern UniValue mnsync(const UniValue& params, bool fHelp); // in rest.cpp extern bool HTTPReq_REST(AcceptedConnection* conn, diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 38ddc6c2..5f81fad2 100755 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -21,14 +21,13 @@ #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" +#include "univalue/univalue.h" #include using namespace std; using namespace boost; using namespace boost::assign; -using namespace json_spirit; + int64_t nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -44,7 +43,7 @@ void EnsureWalletIsUnlocked() throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); } -void WalletTxToJSON(const CWalletTx& wtx, Object& entry) +void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) { int confirms = wtx.GetDepthInMainChain(false); int confirmsTotal = GetIXConfirmations(wtx.GetHash()) + confirms; @@ -59,7 +58,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) } uint256 hash = wtx.GetHash(); entry.push_back(Pair("txid", hash.GetHex())); - Array conflicts; + UniValue conflicts(UniValue::VARR); BOOST_FOREACH (const uint256& conflict, wtx.GetConflicts()) conflicts.push_back(conflict.GetHex()); entry.push_back(Pair("walletconflicts", conflicts)); @@ -69,7 +68,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) entry.push_back(Pair(item.first, item.second)); } -string AccountFromValue(const Value& value) +string AccountFromValue(const UniValue& value) { string strAccount = value.get_str(); if (strAccount == "*") @@ -77,7 +76,7 @@ string AccountFromValue(const Value& value) return strAccount; } -Value getnewaddress(const Array& params, bool fHelp) +UniValue getnewaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -148,7 +147,7 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew = false) return CBitcoinAddress(account.vchPubKey.GetID()); } -Value getaccountaddress(const Array& params, bool fHelp) +UniValue getaccountaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -166,7 +165,7 @@ Value getaccountaddress(const Array& params, bool fHelp) // Parse the account first so we don't generate a key if there's an error string strAccount = AccountFromValue(params[0]); - Value ret; + UniValue ret(UniValue::VSTR); ret = GetAccountAddress(strAccount).ToString(); @@ -174,7 +173,7 @@ Value getaccountaddress(const Array& params, bool fHelp) } -Value getrawchangeaddress(const Array& params, bool fHelp) +UniValue getrawchangeaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -204,7 +203,7 @@ Value getrawchangeaddress(const Array& params, bool fHelp) } -Value setaccount(const Array& params, bool fHelp) +UniValue setaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -239,11 +238,11 @@ 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; } -Value getaccount(const Array& params, bool fHelp) +UniValue getaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -270,7 +269,7 @@ Value getaccount(const Array& params, bool fHelp) } -Value getaddressesbyaccount(const Array& params, bool fHelp) +UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -291,7 +290,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp) string strAccount = AccountFromValue(params[0]); // Find all addresses that have the given account - Array ret; + UniValue ret(UniValue::VARR); BOOST_FOREACH (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item, pwalletMain->mapAddressBook) { const CBitcoinAddress& address = item.first; const string& strName = item.second.name; @@ -333,7 +332,7 @@ void SendMoney(const CTxDestination& address, CAmount nValue, CWalletTx& wtxNew, throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); } -Value sendtoaddress(const Array& params, bool fHelp) +UniValue sendtoaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) throw runtime_error( @@ -353,6 +352,8 @@ Value sendtoaddress(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("sendtoaddress", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\" 0.1") + HelpExampleCli("sendtoaddress", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\" 0.1 \"donation\" \"seans outpost\"") + HelpExampleRpc("sendtoaddress", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\", 0.1, \"donation\", \"seans outpost\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + CBitcoinAddress address(params[0].get_str()); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid LUX address"); @@ -374,7 +375,7 @@ Value sendtoaddress(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } -Value sendtoaddressix(const Array& params, bool fHelp) +UniValue sendtoaddressix(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) throw runtime_error( @@ -414,7 +415,7 @@ Value sendtoaddressix(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } -Value listaddressgroupings(const Array& params, bool fHelp) +UniValue listaddressgroupings(const UniValue& params, bool fHelp) { if (fHelp) throw runtime_error( @@ -437,12 +438,14 @@ Value listaddressgroupings(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("listaddressgroupings", "") + HelpExampleRpc("listaddressgroupings", "")); - Array jsonGroupings; + LOCK2(cs_main, pwalletMain->cs_wallet); + + UniValue jsonGroupings(UniValue::VARR); map balances = pwalletMain->GetAddressBalances(); BOOST_FOREACH (set grouping, pwalletMain->GetAddressGroupings()) { - Array jsonGrouping; + UniValue jsonGrouping(UniValue::VARR); BOOST_FOREACH (CTxDestination address, grouping) { - Array addressInfo; + UniValue addressInfo(UniValue::VARR); addressInfo.push_back(CBitcoinAddress(address).ToString()); addressInfo.push_back(ValueFromAmount(balances[address])); { @@ -457,7 +460,7 @@ Value listaddressgroupings(const Array& params, bool fHelp) return jsonGroupings; } -Value signmessage(const Array& params, bool fHelp) +UniValue signmessage(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) throw runtime_error( @@ -476,6 +479,8 @@ Value signmessage(const Array& params, bool fHelp) "\nVerify the signature\n" + HelpExampleCli("verifymessage", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\" \"signature\" \"my message\"") + "\nAs json rpc\n" + HelpExampleRpc("signmessage", "\"LgAskSorXfCYUweZcCTpGNtpcFotS2rqDF\", \"my message\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + EnsureWalletIsUnlocked(); string strAddress = params[0].get_str(); @@ -504,7 +509,7 @@ Value signmessage(const Array& params, bool fHelp) return EncodeBase64(&vchSig[0], vchSig.size()); } -Value getreceivedbyaddress(const Array& params, bool fHelp) +UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -554,7 +559,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) } -Value getreceivedbyaccount(const Array& params, bool fHelp) +UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -633,7 +638,7 @@ CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminef } -Value getbalance(const Array& params, bool fHelp) +UniValue getbalance(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) throw runtime_error( @@ -702,7 +707,7 @@ Value getbalance(const Array& params, bool fHelp) return ValueFromAmount(nBalance); } -Value getunconfirmedbalance(const Array& params, bool fHelp) +UniValue getunconfirmedbalance(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 0) throw runtime_error( @@ -712,7 +717,7 @@ Value getunconfirmedbalance(const Array& params, bool fHelp) } -Value movecmd(const Array& params, bool fHelp) +UniValue movecmd(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 3 || params.size() > 5) throw runtime_error( @@ -731,6 +736,8 @@ Value movecmd(const Array& params, bool fHelp) "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n" + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") + "\nAs a json rpc call\n" + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + string strFrom = AccountFromValue(params[0]); string strTo = AccountFromValue(params[1]); CAmount nAmount = AmountFromValue(params[2]); @@ -774,7 +781,7 @@ Value movecmd(const Array& params, bool fHelp) } -Value sendfrom(const Array& params, bool fHelp) +UniValue sendfrom(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 3 || params.size() > 6) throw runtime_error( @@ -830,7 +837,8 @@ Value sendfrom(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } -Value sendmany(const Array& params, bool fHelp) + +UniValue sendmany(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) throw runtime_error( @@ -858,7 +866,7 @@ Value sendmany(const Array& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); string strAccount = AccountFromValue(params[0]); - Object sendTo = params[1].get_obj(); + Univalue sendTo = params[1].get_obj(); int nMinDepth = 1; if (params.size() > 2) nMinDepth = params[2].get_int(); @@ -909,9 +917,9 @@ Value sendmany(const Array& params, bool fHelp) } // Defined in rpcmisc.cpp -extern CScript _createmultisig_redeemScript(const Array& params); +extern CScript _createmultisig_redeemScript(const UniValue& params); -Value addmultisigaddress(const Array& params, bool fHelp) +UniValue addmultisigaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) { string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" @@ -969,7 +977,7 @@ struct tallyitem { } }; -Value ListReceived(const Array& params, bool fByAccounts) +UniValue ListReceived(const UniValue& params, bool fByAccounts) { // Minimum confirmations int nMinDepth = 1; @@ -1019,7 +1027,7 @@ Value ListReceived(const Array& params, bool fByAccounts) } // Reply - Array ret; + UniValue ret(UniValue::VARR); map mapAccountTally; BOOST_FOREACH (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item, pwalletMain->mapAddressBook) { const CBitcoinAddress& address = item.first; @@ -1046,7 +1054,7 @@ Value ListReceived(const Array& params, bool fByAccounts) item.nBCConf = min(item.nBCConf, nBCConf); item.fIsWatchonly = fIsWatchonly; } else { - Object obj; + UniValue obj(UniValue::VOBJ); if (fIsWatchonly) obj.push_back(Pair("involvesWatchonly", true)); obj.push_back(Pair("address", address.ToString())); @@ -1054,7 +1062,7 @@ Value ListReceived(const Array& params, bool fByAccounts) obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); obj.push_back(Pair("bcconfirmations", (nBCConf == std::numeric_limits::max() ? 0 : nBCConf))); - Array transactions; + UniValue transactions(UniValue::VARR);; if (it != mapTally.end()) { BOOST_FOREACH (const uint256& item, (*it).second.txids) { transactions.push_back(item.GetHex()); @@ -1070,7 +1078,7 @@ Value ListReceived(const Array& params, bool fByAccounts) CAmount nAmount = (*it).second.nAmount; int nConf = (*it).second.nConf; int nBCConf = (*it).second.nBCConf; - Object obj; + UniValue obj(UniValue::VOBJ); if ((*it).second.fIsWatchonly) obj.push_back(Pair("involvesWatchonly", true)); obj.push_back(Pair("account", (*it).first)); @@ -1084,7 +1092,7 @@ Value ListReceived(const Array& params, bool fByAccounts) return ret; } -Value listreceivedbyaddress(const Array& params, bool fHelp) +UniValue listreceivedbyaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) throw runtime_error( @@ -1111,10 +1119,12 @@ Value listreceivedbyaddress(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("listreceivedbyaddress", "") + HelpExampleCli("listreceivedbyaddress", "6 true") + HelpExampleRpc("listreceivedbyaddress", "6, true, true")); + LOCK2(cs_main, pwalletMain->cs_wallet); + return ListReceived(params, false); } -Value listreceivedbyaccount(const Array& params, bool fHelp) +UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) throw runtime_error( @@ -1140,17 +1150,19 @@ Value listreceivedbyaccount(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("listreceivedbyaccount", "") + HelpExampleCli("listreceivedbyaccount", "6 true") + HelpExampleRpc("listreceivedbyaccount", "6, true, true")); + LOCK2(cs_main, pwalletMain->cs_wallet); + return ListReceived(params, true); } -static void MaybePushAddress(Object& entry, const CTxDestination& dest) +static void MaybePushAddress(UniValue& entry, const CTxDestination& dest) { CBitcoinAddress addr; if (addr.Set(dest)) entry.push_back(Pair("address", addr.ToString())); } -void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter) +void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) { CAmount nFee; string strSentAccount; @@ -1165,7 +1177,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe // Sent if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) { BOOST_FOREACH (const COutputEntry& s, listSent) { - Object entry; + UniValue entry(UniValue::VOBJ); if (involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY)) entry.push_back(Pair("involvesWatchonly", true)); entry.push_back(Pair("account", strSentAccount)); @@ -1188,7 +1200,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe if (pwalletMain->mapAddressBook.count(r.destination)) account = pwalletMain->mapAddressBook[r.destination].name; if (fAllAccounts || (account == strAccount)) { - Object entry; + UniValue entry(UniValue::VOBJ); if (involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY)) entry.push_back(Pair("involvesWatchonly", true)); entry.push_back(Pair("account", account)); @@ -1213,12 +1225,12 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe } } -void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret) +void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret) { bool fAllAccounts = (strAccount == string("*")); if (fAllAccounts || acentry.strAccount == strAccount) { - Object entry; + UniValue entry(UniValue::VOBJ); entry.push_back(Pair("account", acentry.strAccount)); entry.push_back(Pair("category", "move")); entry.push_back(Pair("time", acentry.nTime)); @@ -1229,7 +1241,7 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar } } -Value listtransactions(const Array& params, bool fHelp) +UniValue listtransactions(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 4) throw runtime_error( @@ -1284,6 +1296,8 @@ Value listtransactions(const Array& params, bool fHelp) "\nList transactions 100 to 120 from the tabby account\n" + HelpExampleCli("listtransactions", "\"tabby\" 20 100") + "\nAs a json rpc call\n" + HelpExampleRpc("listtransactions", "\"tabby\", 20, 100")); + LOCK2(cs_main, pwalletMain->cs_wallet); + string strAccount = "*"; if (params.size() > 0) strAccount = params[0].get_str(); @@ -1303,7 +1317,7 @@ Value listtransactions(const Array& params, bool fHelp) if (nFrom < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); - Array ret; + UniValue ret(UniValue::VARR); std::list acentries; CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); @@ -1325,20 +1339,24 @@ 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.setArray(); + ret.push_backV(arrTmp); return ret; } -Value listaccounts(const Array& params, bool fHelp) +UniValue listaccounts(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( @@ -1359,6 +1377,8 @@ Value listaccounts(const Array& params, bool fHelp) "\nList account balances for 6 or more confirmations\n" + HelpExampleCli("listaccounts", "6") + "\nAs json rpc call\n" + HelpExampleRpc("listaccounts", "6")); + LOCK2(cs_main, pwalletMain->cs_wallet); + int nMinDepth = 1; if (params.size() > 0) nMinDepth = params[0].get_int(); @@ -1403,7 +1423,7 @@ Value listaccounts(const Array& params, bool fHelp) BOOST_FOREACH (const CAccountingEntry& entry, acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; - Object ret, imm; + UniValue ret(UniValue::VOBJ); BOOST_FOREACH (const PAIRTYPE(string, CAmount) & accountBalance, mapAccountBalances) { ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); } @@ -1416,7 +1436,7 @@ Value listaccounts(const Array& params, bool fHelp) return ret; } -Value listsinceblock(const Array& params, bool fHelp) +UniValue listsinceblock(const UniValue& params, bool fHelp) { if (fHelp) throw runtime_error( @@ -1452,12 +1472,14 @@ Value listsinceblock(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("listsinceblock", "") + HelpExampleCli("listsinceblock", "\"3efa8c583a6b3f17b1f424a86c5ae65d98baff0292b760c9e64951f1823abfbd\" 6") + HelpExampleRpc("listsinceblock", "\"3efa8c583a6b3f17b1f424a86c5ae65d98baff0292b760c9e64951f1823abfbd\", 6")); + LOCK2(cs_main, pwalletMain->cs_wallet); + CBlockIndex* pindex = NULL; int target_confirms = 1; isminefilter filter = ISMINE_SPENDABLE; if (params.size() > 0) { - uint256 blockId = 0; + uint256 blockId; blockId.SetHex(params[0].get_str()); BlockMap::iterator it = mapBlockIndex.find(blockId); @@ -1478,7 +1500,7 @@ Value listsinceblock(const Array& params, bool fHelp) int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1; - Array transactions; + UniValue transactions(UniValue::VARR);; for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { CWalletTx tx = (*it).second; @@ -1488,16 +1510,16 @@ Value listsinceblock(const Array& params, bool fHelp) } CBlockIndex* pblockLast = chainActive[chainActive.Height() + 1 - target_confirms]; - uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : 0; + uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256(); - Object ret; + UniValue ret(UniValue::VOBJ); ret.push_back(Pair("transactions", transactions)); ret.push_back(Pair("lastblock", lastblock.GetHex())); return ret; } -Value gettransaction(const Array& params, bool fHelp) +UniValue gettransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -1543,7 +1565,7 @@ Value gettransaction(const Array& params, bool fHelp) if (params[1].get_bool()) filter = filter | ISMINE_WATCH_ONLY; - Object entry; + UniValue entry(UniValue::VOBJ); if (!pwalletMain->mapWallet.count(hash)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); const CWalletTx& wtx = pwalletMain->mapWallet[hash]; @@ -1559,7 +1581,7 @@ Value gettransaction(const Array& params, bool fHelp) WalletTxToJSON(wtx, entry); - Array details; + UniValue details(UniValue::VARR); ListTransactions(wtx, "*", 0, false, details, filter); entry.push_back(Pair("details", details)); @@ -1570,7 +1592,7 @@ Value gettransaction(const Array& params, bool fHelp) } -Value backupwallet(const Array& params, bool fHelp) +UniValue backupwallet(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -1587,11 +1609,11 @@ 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; } -Value keypoolrefill(const Array& params, bool fHelp) +UniValue keypoolrefill(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -1619,7 +1641,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; } @@ -1631,7 +1653,7 @@ static void LockWallet(CWallet* pWallet) pWallet->Lock(); } -Value walletpassphrase(const Array& params, bool fHelp) +UniValue walletpassphrase(const UniValue& params, bool fHelp) { if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3)) throw runtime_error( @@ -1652,6 +1674,8 @@ Value walletpassphrase(const Array& params, bool fHelp) "\nLock the wallet again (before 60 seconds)\n" + HelpExampleCli("walletlock", "") + "\nAs json rpc call\n" + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")); + LOCK2(cs_main, pwalletMain->cs_wallet); + if (fHelp) return true; if (!pwalletMain->IsCrypted()) @@ -1685,7 +1709,7 @@ Value walletpassphrase(const Array& params, bool fHelp) RPCRunLater ("lockwallet", boost::bind (LockWallet, pwalletMain), nSleepTime); }; - return Value::null; + return NullUniValue; } @@ -1726,11 +1750,11 @@ 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; } -Value walletlock(const Array& params, bool fHelp) +UniValue walletlock(const UniValue& params, bool fHelp) { if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0)) throw runtime_error( @@ -1745,6 +1769,8 @@ Value walletlock(const Array& params, bool fHelp) "\nClear the passphrase since we are done before 2 minutes is up\n" + HelpExampleCli("walletlock", "") + "\nAs json rpc call\n" + HelpExampleRpc("walletlock", "")); + LOCK2(cs_main, pwalletMain->cs_wallet); + if (fHelp) return true; if (!pwalletMain->IsCrypted()) @@ -1756,11 +1782,11 @@ Value walletlock(const Array& params, bool fHelp) nWalletUnlockTime = 0; } - return Value::null; + return NullUniValue; } -Value encryptwallet(const Array& params, bool fHelp) +UniValue encryptwallet(const UniValue& params, bool fHelp) { if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) throw runtime_error( @@ -1781,6 +1807,8 @@ Value encryptwallet(const Array& params, bool fHelp) "\nNow lock the wallet again by removing the passphrase\n" + HelpExampleCli("walletlock", "") + "\nAs a json rpc call\n" + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + if (fHelp) return true; if (pwalletMain->IsCrypted()) @@ -1807,7 +1835,7 @@ Value encryptwallet(const Array& params, bool fHelp) return "wallet encrypted; lux server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup."; } -Value lockunspent(const Array& params, bool fHelp) +UniValue lockunspent(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -1855,11 +1883,11 @@ Value lockunspent(const Array& params, bool fHelp) return true; } - Array outputs = params[1].get_array(); + UniValue outputs = params[1].get_array(); BOOST_FOREACH (Value& output, outputs) { if (output.type() != obj_type) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object"); - const Object& o = output.get_obj(); + const UniValue& o = output.get_obj(); RPCTypeCheck(o, map_list_of("txid", str_type)("vout", int_type)); @@ -1882,7 +1910,7 @@ Value lockunspent(const Array& params, bool fHelp) return true; } -Value listlockunspent(const Array& params, bool fHelp) +UniValue listlockunspent(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 0) throw runtime_error( @@ -1905,13 +1933,15 @@ Value listlockunspent(const Array& params, bool fHelp) "\nUnlock the transaction again\n" + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"bd4b76f46a6aef596c135d28e2a84c21546a9da8c2c75b272a5763a2718f1cb1\\\",\\\"vout\\\":1}]\"") + "\nAs a json rpc call\n" + HelpExampleRpc("listlockunspent", "")); + LOCK2(cs_main, pwalletMain->cs_wallet); + vector vOutpts; pwalletMain->ListLockedCoins(vOutpts); - Array ret; + UniValue ret(UniValue::VARR); BOOST_FOREACH (COutPoint& outpt, vOutpts) { - Object o; + UniValue o(UniValue::VOBJ); o.push_back(Pair("txid", outpt.hash.GetHex())); o.push_back(Pair("vout", (int)outpt.n)); @@ -1921,7 +1951,7 @@ Value listlockunspent(const Array& params, bool fHelp) return ret; } -Value settxfee(const Array& params, bool fHelp) +UniValue settxfee(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 1) throw runtime_error( @@ -1934,6 +1964,8 @@ Value settxfee(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("settxfee", "0.00001") + HelpExampleRpc("settxfee", "0.00001")); + LOCK2(cs_main, pwalletMain->cs_wallet); + // Amount CAmount nAmount = 0; if (params[0].get_real() != 0.0) @@ -1943,7 +1975,7 @@ Value settxfee(const Array& params, bool fHelp) return true; } -Value getwalletinfo(const Array& params, bool fHelp) +UniValue getwalletinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -1963,7 +1995,7 @@ Value getwalletinfo(const Array& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size())); @@ -1975,7 +2007,7 @@ Value getwalletinfo(const Array& params, bool fHelp) } // ppcoin: reserve balance from being staked for network protection -Value reservebalance(const Array& params, bool fHelp) +UniValue reservebalance(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( @@ -2002,7 +2034,7 @@ Value reservebalance(const Array& params, bool fHelp) } } - Object result; + UniValue result; result.push_back(Pair("reserve", (stake->GetReservedBalance() > 0))); result.push_back(Pair("amount", ValueFromAmount(stake->GetReservedBalance()))); return result; @@ -2052,7 +2084,7 @@ Value getstakesplitthreshold(const Array& params, bool fHelp) return result; } */ -Value autocombinerewards(const Array& params, bool fHelp) +UniValue autocombinerewards(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1) throw runtime_error( @@ -2077,19 +2109,19 @@ Value autocombinerewards(const Array& params, bool fHelp) if (!walletdb.WriteAutoCombineSettings(fEnable, nThreshold)) throw runtime_error("Changed settings in wallet but failed to save to database\n"); - return "Auto Combine Rewards Threshold Set"; + return NullUniValue; } -Array printMultiSend() +UniValue printMultiSend() { - Array ret; - Object act; + UniValue ret(UniValue::VARR); + UniValue act(UniValue::VOBJ); act.push_back(Pair("MultiSendStake Activated?", pwalletMain->fMultiSendStake)); act.push_back(Pair("MultiSendMasternode Activated?", pwalletMain->fMultiSendMasternodeReward)); ret.push_back(act); if (pwalletMain->vDisabledAddresses.size() >= 1) { - Object disAdd; + UniValue disAdd(UniValue::VOBJ); for (unsigned int i = 0; i < pwalletMain->vDisabledAddresses.size(); i++) { disAdd.push_back(Pair("Disabled From Sending", pwalletMain->vDisabledAddresses[i])); } @@ -2098,7 +2130,7 @@ Array printMultiSend() ret.push_back("MultiSend Addresses to Send To:"); - Object vMS; + UniValue vMS(UniValue::VOBJ); for (unsigned int i = 0; i < pwalletMain->vMultiSend.size(); i++) { vMS.push_back(Pair("Address " + boost::lexical_cast(i), pwalletMain->vMultiSend[i].first)); vMS.push_back(Pair("Percent", pwalletMain->vMultiSend[i].second)); @@ -2108,7 +2140,7 @@ Array printMultiSend() return ret; } -Array printAddresses() +UniValue printAddresses() { std::vector vCoins; pwalletMain->AvailableCoins(vCoins); @@ -2124,9 +2156,9 @@ Array printAddresses() mapAddresses[strAdd] += (double)out.tx->vout[out.i].nValue / (double)COIN; } - Array ret; + UniValue ret(UniValue::VARR); for (map::const_iterator it = mapAddresses.begin(); it != mapAddresses.end(); ++it) { - Object obj; + UniValue obj(UniValue::VOBJ); const std::string* strAdd = &(*it).first; const double* nBalance = &(*it).second; obj.push_back(Pair("Address ", *strAdd)); @@ -2145,14 +2177,14 @@ unsigned int sumMultiSend() return sum; } -Value multisend(const Array& params, bool fHelp) +UniValue multisend(const UniValue& params, bool fHelp) { CWalletDB walletdb(pwalletMain->strWalletFile); bool fFileBacked; //MultiSend Commands if (params.size() == 1) { string strCommand = params[0].get_str(); - Object ret; + UniValue ret(UniValue::VOBJ); if (strCommand == "print") { return printMultiSend(); } else if (strCommand == "printaddress" || strCommand == "printaddresses") { @@ -2169,7 +2201,7 @@ Value multisend(const Array& params, bool fHelp) pwalletMain->vMultiSend.clear(); pwalletMain->setMultiSendDisabled(); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("Erased from database", erased)); obj.push_back(Pair("Erased from RAM", true)); @@ -2182,9 +2214,9 @@ Value multisend(const Array& params, bool fHelp) if (CBitcoinAddress(pwalletMain->vMultiSend[0].first).IsValid()) { pwalletMain->fMultiSendStake = true; if (!walletdb.WriteMSettings(true, pwalletMain->fMultiSendMasternodeReward, pwalletMain->nLastMultiSendHeight)) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("error", "MultiSend activated but writing settings to DB failed")); - Array arr; + UniValue arr(UniValue::VARR); arr.push_back(obj); arr.push_back(printMultiSend()); return arr; @@ -2201,9 +2233,9 @@ Value multisend(const Array& params, bool fHelp) pwalletMain->fMultiSendMasternodeReward = true; if (!walletdb.WriteMSettings(pwalletMain->fMultiSendStake, true, pwalletMain->nLastMultiSendHeight)) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("error", "MultiSend activated but writing settings to DB failed")); - Array arr; + UniValue arr(UniValue::VARR); arr.push_back(obj); arr.push_back(printMultiSend()); return arr; diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp index b0171e48..53b11058 100755 --- a/src/univalue/univalue.cpp +++ b/src/univalue/univalue.cpp @@ -4,12 +4,16 @@ #include #include +#include #include +#include // std::runtime_error #include "univalue.h" +#include "utilstrencodings.h" // ParseXX + using namespace std; -static const UniValue nullValue; +const UniValue NullUniValue; void UniValue::clear() { @@ -58,9 +62,11 @@ bool UniValue::setInt(uint64_t val) string s; ostringstream oss; - oss << val; + oss << std::setprecision(16) << val; - return setNumStr(oss.str()); + bool ret = setNumStr(oss.str()); + typ = VREAL; + return ret; } bool UniValue::setInt(int64_t val) @@ -175,11 +181,11 @@ bool UniValue::checkObject(const std::map& t) const UniValue& UniValue::operator[](const std::string& key) const { if (typ != VOBJ) - return nullValue; + return NullUniValue; int index = findKey(key); if (index < 0) - return nullValue; + return NullUniValue; return values[index]; } @@ -187,9 +193,9 @@ const UniValue& UniValue::operator[](const std::string& key) const const UniValue& UniValue::operator[](unsigned int index) const { if (typ != VOBJ && typ != VARR) - return nullValue; + return NullUniValue; if (index >= values.size()) - return nullValue; + return NullUniValue; return values[index]; } @@ -203,9 +209,95 @@ const char *uvTypeName(UniValue::VType t) case UniValue::VARR: return "array"; case UniValue::VSTR: return "string"; case UniValue::VNUM: return "number"; + case UniValue::VREAL: return "number"; + } // not reached return NULL; } +const UniValue& find_value( const UniValue& obj, const std::string& name) +{ + for (unsigned int i = 0; i < obj.keys.size(); i++) + { + if( obj.keys[i] == name ) + { + return obj.values[i]; + } + } + + return NullUniValue; +} + +std::vector UniValue::getKeys() const +{ + if (typ != VOBJ) + throw std::runtime_error("JSON value is not an object as expected"); + return keys; +} + +std::vector UniValue::getValues() const +{ + if (typ != VOBJ && typ != VARR) + throw std::runtime_error("JSON value is not an object or array as expected"); + return values; +} + +bool UniValue::get_bool() const +{ + if (typ != VBOOL) + throw std::runtime_error("JSON value is not a boolean as expected"); + return getBool(); +} + +std::string UniValue::get_str() const +{ + if (typ != VSTR) + throw std::runtime_error("JSON value is not a string as expected"); + return getValStr(); +} + +int UniValue::get_int() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not an integer as expected"); + int32_t retval; + if (!ParseInt32(getValStr(), &retval)) + throw std::runtime_error("JSON integer out of range"); + return retval; +} + +int64_t UniValue::get_int64() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not an integer as expected"); + int64_t retval; + if (!ParseInt64(getValStr(), &retval)) + throw std::runtime_error("JSON integer out of range"); + return retval; +} + +double UniValue::get_real() const +{ + if (typ != VREAL && typ != VNUM) + throw std::runtime_error("JSON value is not a number as expected"); + double retval; + if (!ParseDouble(getValStr(), &retval)) + throw std::runtime_error("JSON double out of range"); + return retval; +} + +const UniValue& UniValue::get_obj() const +{ + if (typ != VOBJ) + throw std::runtime_error("JSON value is not an object as expected"); + return *this; +} + +const UniValue& UniValue::get_array() const +{ + if (typ != VARR) + throw std::runtime_error("JSON value is not an array as expected"); + return *this; +} \ No newline at end of file diff --git a/src/univalue/univalue.h b/src/univalue/univalue.h index 5ac301d9..ff3365fe 100755 --- a/src/univalue/univalue.h +++ b/src/univalue/univalue.h @@ -13,7 +13,7 @@ class UniValue { public: - enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; + enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VREAL, VBOOL, }; UniValue() { typ = VNULL; } UniValue(UniValue::VType initialType, const std::string& initialStr = "") { @@ -26,6 +26,9 @@ class UniValue { UniValue(int64_t val_) { setInt(val_); } + UniValue(bool val_) { + setBool(val_); + } UniValue(int val_) { setInt(val_); } @@ -58,7 +61,7 @@ class UniValue { std::string getValStr() const { return val; } bool empty() const { return (values.size() == 0); } - size_t count() const { return values.size(); } + size_t size() const { return values.size(); } bool getBool() const { return isTrue(); } bool checkObject(const std::map& memberTypes); @@ -68,7 +71,7 @@ class UniValue { bool isNull() const { return (typ == VNULL); } bool isTrue() const { return (typ == VBOOL) && (val == "1"); } - bool isFalse() const { return (!isTrue()); } + bool isFalse() const { return (typ == VBOOL) && (val != "1"); } bool isBool() const { return (typ == VBOOL); } bool isStr() const { return (typ == VSTR); } bool isNum() const { return (typ == VNUM); } @@ -130,8 +133,91 @@ class UniValue { 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: + // Strict type-specific getters, these throw std::runtime_error if the + // value is of unexpected type + std::vector getKeys() const; + std::vector getValues() const; + bool get_bool() const; + std::string get_str() const; + int get_int() const; + int64_t get_int64() const; + double get_real() const; + const UniValue& get_obj() const; + const UniValue& get_array() const; + + enum VType type() const { return getType(); } + bool push_back(std::pair pear) { + return pushKV(pear.first, pear.second); + } + friend const UniValue& find_value( const UniValue& obj, const std::string& name); }; +// +// 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, bool iVal) +{ + std::string key(cKey); + UniValue uVal(iVal); + 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 @@ -152,4 +238,8 @@ extern enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed, const char *raw); extern const char *uvTypeName(UniValue::VType t); +extern const UniValue NullUniValue; + +const UniValue& find_value( const UniValue& obj, const std::string& name); + #endif // BITCOIN_UNIVALUE_UNIVALUE_H diff --git a/src/univalue/univalue_write.cpp b/src/univalue/univalue_write.cpp index 9565cfa1..eb2becd6 100755 --- a/src/univalue/univalue_write.cpp +++ b/src/univalue/univalue_write.cpp @@ -3,6 +3,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include +#include #include #include "univalue.h" #include "univalue_escapes.h" @@ -59,6 +61,13 @@ string UniValue::write(unsigned int prettyIndent, case VSTR: s += "\"" + json_escape(val) + "\""; break; + case VREAL: + { + std::stringstream ss; + ss << std::showpoint << std::fixed << std::setprecision(8) << get_real(); + s += ss.str(); + } + break; case VNUM: s += val; break; diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 6f49af5f..23f76d43 100755 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -463,18 +463,60 @@ string DecodeBase32(const string& str) return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); } -bool ParseInt32(const std::string& str, int32_t* out) +static bool ParsePrechecks(const std::string& str) { - char* endp = NULL; + if (str.empty()) // No empty string allowed + return false; + if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed + return false; + if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed + return false; + return true; +} + +bool ParseInt32(const std::string& str, int32_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = NULL; + errno = 0; // strtol will not set errno if valid long int n = strtol(str.c_str(), &endp, 10); - if (out) *out = (int)n; + if(out) *out = (int32_t)n; // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit // platforms the size of these types may be different. return endp && *endp == 0 && !errno && - n >= std::numeric_limits::min() && - n <= std::numeric_limits::max(); + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseInt64(const std::string& str, int64_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = NULL; + errno = 0; // strtoll will not set errno if valid + long long int n = strtoll(str.c_str(), &endp, 10); + if(out) *out = (int64_t)n; + // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int64_t*. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseDouble(const std::string& str, double *out) +{ + if (!ParsePrechecks(str)) + return false; + if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed + return false; + char *endp = NULL; + errno = 0; // strtod will not set errno if valid + double n = strtod(str.c_str(), &endp); + if(out) *out = n; + return endp && *endp == 0 && !errno; } std::string FormatParagraph(const std::string in, size_t width, size_t indent) diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index f3e04522..cd9a63d1 100755 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -50,7 +50,23 @@ int atoi(const std::string& str); * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -bool ParseInt32(const std::string& str, int32_t* out); + +bool ParseInt32(const std::string& str, int32_t *out); + +/** + * Convert string to signed 64-bit integer with strict parse error feedback. + * @returns true if the entire string could be parsed as valid integer, + * false if not the entire string could be parsed or when overflow or underflow occurred. + */ +bool ParseInt64(const std::string& str, int64_t *out); + +/** + * Convert string to double with strict parse error feedback. + * @returns true if the entire string could be parsed as valid double, + * false if not the entire string could be parsed or when overflow or underflow occurred. + */ +bool ParseDouble(const std::string& str, double *out); + template std::string HexStr(const T itbegin, const T itend, bool fSpaces = false) From ccf40716979c10efd44b12e6ae2c12ee0cd43fa8 Mon Sep 17 00:00:00 2001 From: tran Date: Wed, 4 Apr 2018 02:30:26 +0700 Subject: [PATCH 07/17] WIP:Update LUX processing by using UniValue Signed-off-by: tran --- src/rpcblockchain.cpp | 10 +++++----- src/rpcdarksend.cpp | 35 +++++++++++++++++------------------ src/rpcrawtransaction.cpp | 4 ++-- src/rpcserver.cpp | 2 +- src/rpcwallet.cpp | 2 +- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index f6e264c3..8917f23e 100755 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -20,6 +20,7 @@ using namespace std; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); +int getBlockTimeByHeight(int nHeight); double GetPoWDifficulty(const CBlockIndex* blockindex) { @@ -260,18 +261,17 @@ UniValue getblockhashes(const UniValue& params, bool fHelp) unsigned int high = params[0].get_int(); unsigned int low = params[1].get_int(); - bool fActiveOnly = false; - bool fLogicalTS = false; + UniValue a(UniValue::VARR); int nHeight = chainActive.Height(); - unsigned time = GetTime(); for (int i = 0; i <= nHeight; i++) { - int blockTime = getBlockTimeByHeight(i); - if(blockTime>low && blockTime low && blockTime < high) { CBlockIndex* pblockindex =chainActive[i]; a.push_back(pblockindex->GetBlockHash().GetHex()); } } + return a; } int getBlockTimeByHeight(int nHeight){ diff --git a/src/rpcdarksend.cpp b/src/rpcdarksend.cpp index d892c876..99a5e3d1 100644 --- a/src/rpcdarksend.cpp +++ b/src/rpcdarksend.cpp @@ -189,8 +189,8 @@ UniValue masternode(const UniValue& params, bool fHelp) bool found = false; - UniValue resultsObj(UniValue::VARR); - statusObj.push_back(Pair("alias", alias)); + UniValue resultsObj(UniValue::VOBJ); + resultsObj.push_back(Pair("alias", alias)); BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { if(mne.getAlias() == alias) { @@ -198,21 +198,21 @@ UniValue masternode(const UniValue& params, bool fHelp) std::string errorMessage; bool result = activeMasternode.StopMasterNode(mne.getIp(), mne.getPrivKey(), errorMessage); - statusObj.push_back(Pair("result", result ? "successful" : "failed")); + resultsObj.push_back(Pair("result", result ? "successful" : "failed")); if(!result) { - statusObj.push_back(Pair("errorMessage", errorMessage)); + resultsObj.push_back(Pair("errorMessage", errorMessage)); } break; } } if(!found) { - statusObj.push_back(Pair("result", "failed")); - statusObj.push_back(Pair("errorMessage", "could not find alias in config. Verify with list-conf.")); + resultsObj.push_back(Pair("result", "failed")); + resultsObj.push_back(Pair("errorMessage", "could not find alias in config. Verify with list-conf.")); } pwalletMain->Lock(); - return statusObj; + return resultsObj; } if (strCommand == "stop-many") @@ -237,7 +237,7 @@ UniValue masternode(const UniValue& params, bool fHelp) int successful = 0; int fail = 0; - UniValue resultsObj(UniValue::VARR); + UniValue resultsObj(UniValue::VOBJ); BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { total++; @@ -282,7 +282,7 @@ UniValue masternode(const UniValue& params, bool fHelp) "list supports 'active', 'vin', 'pubkey', 'lastseen', 'activeseconds', 'rank', 'protocol'\n"); } - UniValue resultsObj(UniValue::VARR); + UniValue obj(UniValue::VOBJ); BOOST_FOREACH(CMasterNode mn, vecMasternodes) { mn.Check(); @@ -376,7 +376,6 @@ UniValue masternode(const UniValue& params, bool fHelp) bool found = false; - UniValue resultsObj(UniValue::VARR); UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", alias)); @@ -401,7 +400,7 @@ UniValue masternode(const UniValue& params, bool fHelp) } pwalletMain->Lock(); - resultsObj.push_back(statusObj); + return statusObj; } @@ -430,7 +429,7 @@ UniValue masternode(const UniValue& params, bool fHelp) int successful = 0; int fail = 0; - UniValue resultsObj(UniValue::VARR); + UniValue resultsObj(UniValue::VOBJ); BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { total++; @@ -453,7 +452,7 @@ UniValue masternode(const UniValue& params, bool fHelp) } pwalletMain->Lock(); - Object returnObj; + UniValue returnObj(UniValue::VOBJ); returnObj.push_back(Pair("overall", "Successfully started " + boost::lexical_cast(successful) + " masternodes, failed to start " + boost::lexical_cast(fail) + ", total " + boost::lexical_cast(total))); returnObj.push_back(Pair("detail", resultsObj)); @@ -507,7 +506,7 @@ UniValue masternode(const UniValue& params, bool fHelp) if (strCommand == "winners") { - Object obj; + UniValue obj(UniValue::VOBJ); for(int nHeight = chainActive.Tip()->nHeight-10; nHeight < chainActive.Tip()->nHeight+20; nHeight++) { @@ -554,10 +553,10 @@ UniValue masternode(const UniValue& params, bool fHelp) std::vector mnEntries; mnEntries = masternodeConfig.getEntries(); - UniValue resultsObj(UniValue::VARR); + UniValue resultObj(UniValue::VOBJ); BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { - Object mnObj; + UniValue mnObj(UniValue::VOBJ); mnObj.push_back(Pair("alias", mne.getAlias())); mnObj.push_back(Pair("address", mne.getIp())); mnObj.push_back(Pair("privateKey", mne.getPrivKey())); @@ -573,7 +572,7 @@ UniValue masternode(const UniValue& params, bool fHelp) // Find possible candidates vector possibleCoins = activeMasternode.SelectCoinsMasternode(); - Object obj; + UniValue obj(UniValue::VOBJ); BOOST_FOREACH(COutput& out, possibleCoins) { obj.push_back(Pair(out.tx->GetHash().ToString().c_str(), boost::lexical_cast(out.i))); } @@ -582,6 +581,6 @@ UniValue masternode(const UniValue& params, bool fHelp) } - return Value::null; + return NullUniValue; } diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 9770fbf9..e80b8063 100755 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -91,7 +91,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) } entry.push_back(Pair("vout", vout)); - if (!hashBlock.IsNull()) { + if (hashBlock != uint256()) { entry.push_back(Pair("blockhash", hashBlock.GetHex())); BlockMap::iterator mi = mapBlockIndex.find(hashBlock); if (mi != mapBlockIndex.end() && (*mi).second) { @@ -241,7 +241,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) set setAddress; if (params.size() > 2) { - Univalue inputs = params[2].get_array(); + UniValue inputs = params[2].get_array(); BOOST_FOREACH (UniValue& input, inputs) { CBitcoinAddress address(input.get_str()); if (!address.IsValid()) diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 450a8d0c..de14dd42 100755 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -198,7 +198,7 @@ string CRPCTable::help(string strCommand) const #endif try { - UniValue params; + UniValue params(UniValue::VARR); rpcfn_type pfn = pcmd->actor; if (setDone.insert(pfn).second) (*pfn)(params, true); diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 5f81fad2..88cb0674 100755 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -2034,7 +2034,7 @@ UniValue reservebalance(const UniValue& params, bool fHelp) } } - UniValue result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("reserve", (stake->GetReservedBalance() > 0))); result.push_back(Pair("amount", ValueFromAmount(stake->GetReservedBalance()))); return result; From 1276574c2107864a35acd3efb50d7c5e74575992 Mon Sep 17 00:00:00 2001 From: 216k155 <216k155@luxcore.io> Date: Tue, 3 Apr 2018 18:12:52 -0700 Subject: [PATCH 08/17] Update rpc command from old json_spirit to UniValue Add ParseInt64 and ParseDouble functions Simplify RPClient Remove JSON Spirit wrapper Remove JSON Spirit UniValue wrapper Correct bool support Add support for precision and make json_spirit compatible Special threading for null,true,false Clearly set UniValue type to avoid empty values Extend conversion to UniValue Convert tree to using UniValue. Remove all json_spirit uses Export NullUniValue global constants Change count() to size() to harmonize existing tree --- src/qt/masternodemanager.cpp | 2 +- src/qt/rpcconsole.cpp | 2 ++ src/rpcrawtransaction.cpp | 6 ++-- src/rpcserver.cpp | 3 +- src/rpcwallet.cpp | 68 +++++++++++++++++++----------------- 5 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/qt/masternodemanager.cpp b/src/qt/masternodemanager.cpp index 8c8440d9..41194b4c 100644 --- a/src/qt/masternodemanager.cpp +++ b/src/qt/masternodemanager.cpp @@ -16,7 +16,6 @@ #include #include -using namespace json_spirit; using namespace std; #include @@ -32,6 +31,7 @@ using namespace std; #include #include #include +#include MasternodeManager::MasternodeManager(QWidget *parent) : QWidget(parent), diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 4d50cbe9..cb8f8416 100755 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -27,7 +27,9 @@ #include #include +#include #include +#include #include #include #include diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index e80b8063..196d43fe 100755 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -178,7 +178,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) fVerbose = (params[1].get_int() != 0); CTransaction tx; - uint256 hashBlock = 0; + uint256 hashBlock; if (!GetTransaction(hash, tx, hashBlock, true)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); @@ -242,7 +242,9 @@ UniValue listunspent(const UniValue& params, bool fHelp) set setAddress; if (params.size() > 2) { UniValue inputs = params[2].get_array(); - BOOST_FOREACH (UniValue& input, inputs) { + for (unsigned int i = 0; i < inputs.size(); i++) { + + UniValue input = inputs[i]; CBitcoinAddress address(input.get_str()); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid lux address: ") + input.get_str()); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index de14dd42..1e0d8aa9 100755 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -1015,10 +1015,11 @@ std::vector CRPCTable::listCommands() const { std::vector commandList; typedef std::map commandMap; - +#if 0 // TODO fix warning: typedef ‘commandMap’ locally defined but not used std::transform( mapCommands.begin(), mapCommands.end(), std::back_inserter(commandList), boost::bind(&commandMap::UniValue::VType::first,_1) ); +#endif return commandList; } diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 88cb0674..4bc69ef0 100755 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -363,9 +363,9 @@ UniValue sendtoaddress(const UniValue& 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(); EnsureWalletIsUnlocked(); @@ -404,9 +404,9 @@ UniValue sendtoaddressix(const UniValue& 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(); EnsureWalletIsUnlocked(); @@ -415,6 +415,7 @@ UniValue sendtoaddressix(const UniValue& params, bool fHelp) return wtx.GetHash().GetHex(); } + UniValue listaddressgroupings(const UniValue& params, bool fHelp) { if (fHelp) @@ -707,12 +708,15 @@ UniValue getbalance(const UniValue& params, bool fHelp) return ValueFromAmount(nBalance); } -UniValue getunconfirmedbalance(const UniValue& params, bool fHelp) +UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp) { if (fHelp || params.size() > 0) throw runtime_error( "getunconfirmedbalance\n" "Returns the server's total unconfirmed balance\n"); + + LOCK2(cs_main, pwalletMain->cs_wallet); + return ValueFromAmount(pwalletMain->GetUnconfirmedBalance()); } @@ -820,9 +824,9 @@ UniValue sendfrom(const UniValue& 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(); @@ -866,31 +870,32 @@ UniValue sendmany(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); string strAccount = AccountFromValue(params[0]); - Univalue sendTo = params[1].get_obj(); + UniValue sendTo = params[1].get_obj(); int nMinDepth = 1; if (params.size() > 2) nMinDepth = params[2].get_int(); 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(); set setAddress; vector > vecSend; CAmount totalAmount = 0; - BOOST_FOREACH (const Pair& s, sendTo) { - CBitcoinAddress address(s.name_); + vector keys = sendTo.getKeys(); + BOOST_FOREACH(const string& name_, keys) { + CBitcoinAddress address(name_); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid LUX address: ") + s.name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid LUX 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; vecSend.push_back(make_pair(scriptPubKey, nAmount)); @@ -1062,7 +1067,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); obj.push_back(Pair("bcconfirmations", (nBCConf == std::numeric_limits::max() ? 0 : nBCConf))); - UniValue transactions(UniValue::VARR);; + UniValue transactions(UniValue::VARR); if (it != mapTally.end()) { BOOST_FOREACH (const uint256& item, (*it).second.txids) { transactions.push_back(item.GetHex()); @@ -1155,7 +1160,7 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) return ListReceived(params, true); } -static void MaybePushAddress(UniValue& entry, const CTxDestination& dest) +static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) { CBitcoinAddress addr; if (addr.Set(dest)) @@ -1323,7 +1328,7 @@ UniValue listtransactions(const UniValue& params, bool fHelp) CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); // iterate backwards until we have nCount items to return: - for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { + for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx* const pwtx = (*it).second.first; if (pwtx != 0) ListTransactions(*pwtx, strAccount, 0, true, ret, filter); @@ -1343,7 +1348,7 @@ UniValue listtransactions(const UniValue& params, bool fHelp) vector::iterator first = arrTmp.begin(); std::advance(first, nFrom); vector::iterator last = arrTmp.begin(); - std::advance(last, nFrom + nCount); + std::advance(last, nFrom+nCount); if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end()); if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first); @@ -1423,7 +1428,7 @@ UniValue listaccounts(const UniValue& params, bool fHelp) BOOST_FOREACH (const CAccountingEntry& entry, acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; - UniValue ret(UniValue::VOBJ); + UniValue ret(UniValue::VOBJ), imm; BOOST_FOREACH (const PAIRTYPE(string, CAmount) & accountBalance, mapAccountBalances) { ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); } @@ -1431,7 +1436,6 @@ UniValue listaccounts(const UniValue& params, bool fHelp) for (auto const &i : immatureBalances) { imm.push_back(Pair(i.first, ValueFromAmount(i.second))); } - ret.emplace_back("immature", imm); } return ret; } @@ -1479,7 +1483,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) isminefilter filter = ISMINE_SPENDABLE; if (params.size() > 0) { - uint256 blockId; + uint256 blockId = 0; blockId.SetHex(params[0].get_str()); BlockMap::iterator it = mapBlockIndex.find(blockId); @@ -1500,7 +1504,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1; - UniValue transactions(UniValue::VARR);; + UniValue transactions(UniValue::VARR); for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { CWalletTx tx = (*it).second; @@ -1510,7 +1514,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) } CBlockIndex* pblockLast = chainActive[chainActive.Height() + 1 - target_confirms]; - uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256(); + uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : 0; UniValue ret(UniValue::VOBJ); ret.push_back(Pair("transactions", transactions)); @@ -1703,17 +1707,16 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp) int64_t nSleepTime = params[1].get_int64(); LOCK(cs_nWalletUnlockTime); nWalletUnlockTime = GetTime() + nSleepTime; - if (nSleepTime > 0) - { + if (nSleepTime > 0) { nWalletUnlockTime = GetTime () + nSleepTime; RPCRunLater ("lockwallet", boost::bind (LockWallet, pwalletMain), nSleepTime); - }; + } return NullUniValue; } -Value walletpassphrasechange(const Array& params, bool fHelp) +UniValue walletpassphrasechange(const UniValue& params, bool fHelp) { if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) throw runtime_error( @@ -1871,9 +1874,9 @@ UniValue lockunspent(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); if (params.size() == 1) - RPCTypeCheck(params, list_of(bool_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)); else - RPCTypeCheck(params, list_of(bool_type)(array_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR)); bool fUnlock = params[0].get_bool(); @@ -1884,12 +1887,13 @@ UniValue lockunspent(const UniValue& params, bool fHelp) } UniValue 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 UniValue& o = output.get_obj(); - RPCTypeCheck(o, 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)) From ffde3ebac769b0559fbf71681d5d8ae388c52d0a Mon Sep 17 00:00:00 2001 From: tran Date: Wed, 4 Apr 2018 15:07:06 +0700 Subject: [PATCH 09/17] Fix minor bug on UniValue migration Signed-off-by: tran --- src/rpcmining.cpp | 4 ++-- src/rpcrawtransaction.cpp | 2 +- src/rpcserver.cpp | 4 ++-- src/rpcwallet.cpp | 7 ++++--- src/univalue/univalue.cpp | 3 ++- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 26fb0e3c..4157d55f 100755 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -168,7 +168,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp) unsigned int nExtraNonce = 0; UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd) { - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, false)); + unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, false)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); CBlock* pblock = &pblocktemplate->block; @@ -440,7 +440,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions - uint256 hashWatchedChain; + uint256 hashWatchedChain = uint256(); boost::system_time checktxtime; unsigned int nTransactionsUpdatedLastLP; diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 196d43fe..7af0be2c 100755 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -178,7 +178,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) fVerbose = (params[1].get_int() != 0); CTransaction tx; - uint256 hashBlock; + uint256 hashBlock = uint256(); if (!GetTransaction(hash, tx, hashBlock, true)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 1e0d8aa9..7b7880bc 100755 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -146,7 +146,7 @@ uint256 ParseHashV(const UniValue& v, string strName) strHex = v.get_str(); if (!IsHex(strHex)) // Note: IsHex("") is false throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be hexadecimal string (not '" + strHex + "')"); - uint256 result; + uint256 result = uint256(); result.SetHex(strHex); return result; } @@ -1014,8 +1014,8 @@ UniValue CRPCTable::execute(const std::string& strMethod, const UniValue& params std::vector CRPCTable::listCommands() const { std::vector commandList; - typedef std::map commandMap; #if 0 // TODO fix warning: typedef ‘commandMap’ locally defined but not used + typedef std::map commandMap; std::transform( mapCommands.begin(), mapCommands.end(), std::back_inserter(commandList), boost::bind(&commandMap::UniValue::VType::first,_1) ); diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 4bc69ef0..52861708 100755 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1428,7 +1428,8 @@ UniValue listaccounts(const UniValue& params, bool fHelp) BOOST_FOREACH (const CAccountingEntry& entry, acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; - UniValue ret(UniValue::VOBJ), imm; + UniValue ret(UniValue::VOBJ); + UniValue imm(UniValue::VOBJ); BOOST_FOREACH (const PAIRTYPE(string, CAmount) & accountBalance, mapAccountBalances) { ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); } @@ -1483,7 +1484,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) isminefilter filter = ISMINE_SPENDABLE; if (params.size() > 0) { - uint256 blockId = 0; + uint256 blockId = uint256(); blockId.SetHex(params[0].get_str()); BlockMap::iterator it = mapBlockIndex.find(blockId); @@ -1514,7 +1515,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp) } CBlockIndex* pblockLast = chainActive[chainActive.Height() + 1 - target_confirms]; - uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : 0; + uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256(); UniValue ret(UniValue::VOBJ); ret.push_back(Pair("transactions", transactions)); diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp index 53b11058..3b7aad60 100755 --- a/src/univalue/univalue.cpp +++ b/src/univalue/univalue.cpp @@ -300,4 +300,5 @@ const UniValue& UniValue::get_array() const if (typ != VARR) throw std::runtime_error("JSON value is not an array as expected"); return *this; -} \ No newline at end of file +} + From 504eb52d0a3e814c8c427df7f9d7a1910a0819f0 Mon Sep 17 00:00:00 2001 From: tran Date: Wed, 4 Apr 2018 21:28:15 +0700 Subject: [PATCH 10/17] Fix app crash when 'Master node' tab is disabled Signed-off-by: tran --- src/qt/bitcoingui.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 323649b7..ee44957a 100755 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -375,7 +375,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) tabGroup->addAction(masternodeAction); connect(masternodeAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(masternodeAction, SIGNAL(triggered()), this, SLOT(gotoMasternodePage())); - + } smartToken = new QAction(QIcon(":/icons/smartcontract"), tr("&Smart Contracts"), this); smartToken->setStatusTip(tr("Add Smart Contracts")); @@ -388,7 +388,6 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) #endif tabGroup->addAction(smartToken); - } // These showNormalIfMinimized are needed because Send Coins and Receive Coins From 7c9fcf952e5873f286cdb64cbedde4f56b9a2a31 Mon Sep 17 00:00:00 2001 From: tran Date: Fri, 6 Apr 2018 01:56:27 +0700 Subject: [PATCH 11/17] Fix app crash when tx doesn't exist in mem pool Signed-off-by: tran --- src/txmempool.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 3e7bba20..774c8da7 100755 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -711,10 +711,13 @@ bool CCoinsViewMemPool::GetCoins(const uint256& txid, CCoins& coins) const coins = CCoins(tx, MEMPOOL_HEIGHT); return true; } - return base->GetCoins(txid, coins); + + return (CCoinsViewBacked::GetCoins(txid, coins) && !coins.IsPruned()); } bool CCoinsViewMemPool::HaveCoins(const uint256& txid) const { - return mempool.exists(txid) || base->HaveCoins(txid); + return mempool.exists(txid) || CCoinsViewBacked::HaveCoins(txid); } + + From 92192c8bedcd61ac12a70e053bedfa592de93e79 Mon Sep 17 00:00:00 2001 From: tran Date: Fri, 6 Apr 2018 02:05:42 +0700 Subject: [PATCH 12/17] Fix app crash on re-enabling "masternode" tab Signed-off-by: tran --- src/qt/bitcoingui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index ee44957a..8ecbce90 100755 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -361,9 +361,9 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) #ifdef ENABLE_WALLET + masternodeAction = new QAction(QIcon(":/icons/masternodes"), tr("&Masternodes"), this); QSettings settings; if (settings.value("fShowMasternodesTab").toBool()) { - masternodeAction = new QAction(QIcon(":/icons/masternodes"), tr("&Masternodes"), this); masternodeAction->setStatusTip(tr("Browse masternodes")); masternodeAction->setToolTip(masternodeAction->statusTip()); masternodeAction->setCheckable(true); From 0fcd462b65933ca2937986d9962bb276cb0ef2e8 Mon Sep 17 00:00:00 2001 From: tran Date: Fri, 6 Apr 2018 22:13:53 +0700 Subject: [PATCH 13/17] Re-distribute hot key for qt wallet Signed-off-by: tran --- src/qt/bitcoingui.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 8ecbce90..919cdad7 100755 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -324,19 +324,17 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) #endif tabGroup->addAction(receiveCoinsAction); - // Qt::Key_4 is reserved for Staking tab - historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this); historyAction->setStatusTip(tr("Browse transaction history")); historyAction->setToolTip(historyAction->statusTip()); historyAction->setCheckable(true); #ifdef Q_OS_MAC - historyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_5)); + historyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_4)); #else - historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); + historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4)); #endif tabGroup->addAction(historyAction); - + stakingAction = new QAction(QIcon(":/icons/stake"), tr("&Staking"), this); stakingAction->setStatusTip(tr("Show your staking capacity")); stakingAction->setToolTip(stakingAction->statusTip()); @@ -361,6 +359,12 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) #ifdef ENABLE_WALLET + smartToken = new QAction(QIcon(":/icons/smartcontract"), tr("&Smart Contracts"), this); + smartToken->setStatusTip(tr("Add Smart Contracts")); + smartToken->setToolTip(smartToken->statusTip()); + smartToken->setCheckable(true); + tabGroup->addAction(smartToken); + masternodeAction = new QAction(QIcon(":/icons/masternodes"), tr("&Masternodes"), this); QSettings settings; if (settings.value("fShowMasternodesTab").toBool()) { @@ -369,26 +373,23 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) masternodeAction->setCheckable(true); #ifdef Q_OS_MAC masternodeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_7)); + smartToken->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_8)); #else masternodeAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_7)); + smartToken->setShortcut(QKeySequence(Qt::ALT + Qt::Key_8)); #endif tabGroup->addAction(masternodeAction); connect(masternodeAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(masternodeAction, SIGNAL(triggered()), this, SLOT(gotoMasternodePage())); } - - smartToken = new QAction(QIcon(":/icons/smartcontract"), tr("&Smart Contracts"), this); - smartToken->setStatusTip(tr("Add Smart Contracts")); - smartToken->setToolTip(smartToken->statusTip()); - smartToken->setCheckable(true); - #ifdef Q_OS_MAC - smartToken->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_8)); - #else - smartToken->setShortcut(QKeySequence(Qt::ALT + Qt::Key_8)); - #endif - - tabGroup->addAction(smartToken); - + else + { +#ifdef Q_OS_MAC + smartToken->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_7)); +#else + smartToken->setShortcut(QKeySequence(Qt::ALT + Qt::Key_7)); +#endif + } // These showNormalIfMinimized are needed because Send Coins and Receive Coins // can be triggered from the tray menu, and need to show the GUI to be useful. From 024f59b76eca2f260a0515862d588919804a7838 Mon Sep 17 00:00:00 2001 From: tran Date: Sun, 8 Apr 2018 01:28:10 +0700 Subject: [PATCH 14/17] Fix app crash on Window version Signed-off-by: tran --- depends/build-wins.sh | 1 + src/config/condition_variable.hpp | 567 ++++++++++++++++++++++++++++++ 2 files changed, 568 insertions(+) create mode 100644 src/config/condition_variable.hpp diff --git a/depends/build-wins.sh b/depends/build-wins.sh index 6fd46ba4..5cd2bdb6 100755 --- a/depends/build-wins.sh +++ b/depends/build-wins.sh @@ -37,6 +37,7 @@ cp -r "$LEVELDB_DIR/include/leveldb" "$INCLUDE_DIR" mkdir "$INCLUDE_DIR/leveldb/helpers" cp -r "$LEVELDB_DIR/helpers/memenv/memenv.h" "$INCLUDE_DIR/leveldb/helpers/memenv.h" cp ../src/config/implementation.hpp "$INCLUDE_DIR/boost/unordered/detail/implementation.hpp" +cp ../src/config/condition_variable.hpp "$INCLUDE_DIR/boost/thread/win32/condition_variable.hpp" # Build eth dependencies cd .. diff --git a/src/config/condition_variable.hpp b/src/config/condition_variable.hpp new file mode 100644 index 00000000..3bd4b86b --- /dev/null +++ b/src/config/condition_variable.hpp @@ -0,0 +1,567 @@ +#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP +#define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#include +#include +#include +#include +#include +#if defined BOOST_THREAD_USES_DATETIME +#include +#endif +#include +#include +#include +#include + +#include +#include + +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif + +#include +#include +#include + +#include + +namespace boost +{ + namespace detail + { + class basic_cv_list_entry; + void intrusive_ptr_add_ref(basic_cv_list_entry * p); + void intrusive_ptr_release(basic_cv_list_entry * p); + + class basic_cv_list_entry + { + private: + detail::win32::handle_manager semaphore; + detail::win32::handle_manager wake_sem; + long waiters; + bool notified; + long references; + + public: + BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry) + explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_): + semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)), + wake_sem(wake_sem_.duplicate()), + waiters(1),notified(false),references(0) + {} + + static bool no_waiters(boost::intrusive_ptr const& entry) + { + return !detail::interlocked_read_acquire(&entry->waiters); + } + + void add_waiter() + { + BOOST_INTERLOCKED_INCREMENT(&waiters); + } + + void remove_waiter() + { + BOOST_INTERLOCKED_DECREMENT(&waiters); + } + + void release(unsigned count_to_release) + { + notified=true; + detail::win32::ReleaseSemaphore(semaphore,count_to_release,0); + } + + void release_waiters() + { + release(detail::interlocked_read_acquire(&waiters)); + } + + bool is_notified() const + { + return notified; + } + + bool wait(timeout abs_time) + { + return this_thread::interruptible_wait(semaphore,abs_time); + } + + bool woken() + { + unsigned long const woken_result=detail::win32::WaitForSingleObjectEx(wake_sem,0,0); + //BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0)); + return woken_result==0; + } + + friend void intrusive_ptr_add_ref(basic_cv_list_entry * p); + friend void intrusive_ptr_release(basic_cv_list_entry * p); + }; + + inline void intrusive_ptr_add_ref(basic_cv_list_entry * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->references); + } + + inline void intrusive_ptr_release(basic_cv_list_entry * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) + { + delete p; + } + } + + class basic_condition_variable + { + boost::mutex internal_mutex; + long total_count; + unsigned active_generation_count; + + typedef basic_cv_list_entry list_entry; + + typedef boost::intrusive_ptr entry_ptr; + typedef std::vector generation_list; + + generation_list generations; + detail::win32::handle_manager wake_sem; + + void wake_waiters(long count_to_wake) + { + detail::interlocked_write_release(&total_count,total_count-count_to_wake); + detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0); + } + + template + struct relocker + { + BOOST_THREAD_NO_COPYABLE(relocker) + lock_type& lock; + bool unlocked; + + relocker(lock_type& lock_): + lock(lock_),unlocked(false) + {} + void unlock() + { + lock.unlock(); + unlocked=true; + } + ~relocker() + { + if(unlocked) + { + lock.lock(); + } + + } + }; + + + entry_ptr get_wait_entry() + { + boost::lock_guard internal_lock(internal_mutex); + + if(!wake_sem) + { + wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + //BOOST_ASSERT(wake_sem); + } + + detail::interlocked_write_release(&total_count,total_count+1); + if(generations.empty() || generations.back()->is_notified()) + { + entry_ptr new_entry(new list_entry(wake_sem)); + generations.push_back(new_entry); + return new_entry; + } + else + { + generations.back()->add_waiter(); + return generations.back(); + } + } + + struct entry_manager + { + entry_ptr const entry; + boost::mutex& internal_mutex; + + BOOST_THREAD_NO_COPYABLE(entry_manager) + entry_manager(entry_ptr const& entry_, boost::mutex& mutex_): + entry(entry_), internal_mutex(mutex_) + {} + + ~entry_manager() + { + boost::lock_guard internal_lock(internal_mutex); + entry->remove_waiter(); + } + + list_entry* operator->() + { + return entry.get(); + } + }; + + + protected: + template + bool do_wait(lock_type& lock,timeout abs_time) + { + relocker locker(lock); + + entry_manager entry(get_wait_entry(), internal_mutex); + + locker.unlock(); + + bool woken=false; + while(!woken) + { + if(!entry->wait(abs_time)) + { + return false; + } + + woken=entry->woken(); + } + return woken; + } + + template + bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred) + { + while (!pred()) + { + if(!do_wait(m, abs_time)) + return pred(); + } + return true; + } + + basic_condition_variable(const basic_condition_variable& other); + basic_condition_variable& operator=(const basic_condition_variable& other); + + public: + basic_condition_variable(): + total_count(0),active_generation_count(0),wake_sem(0) + {} + + ~basic_condition_variable() + {} + + void notify_one() BOOST_NOEXCEPT + { + if(detail::interlocked_read_acquire(&total_count)) + { + boost::lock_guard internal_lock(internal_mutex); + if(!total_count) + { + return; + } + wake_waiters(1); + + for(generation_list::iterator it=generations.begin(), + end=generations.end(); + it!=end;++it) + { + (*it)->release(1); + } + generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end()); + } + } + + void notify_all() BOOST_NOEXCEPT + { + if(detail::interlocked_read_acquire(&total_count)) + { + boost::lock_guard internal_lock(internal_mutex); + if(!total_count) + { + return; + } + wake_waiters(total_count); + for(generation_list::iterator it=generations.begin(), + end=generations.end(); + it!=end;++it) + { + (*it)->release_waiters(); + } + generations.clear(); + wake_sem=detail::win32::handle(0); + } + } + + }; + } + + class condition_variable: + private detail::basic_condition_variable + { + public: + BOOST_THREAD_NO_COPYABLE(condition_variable) + condition_variable() + {} + + using detail::basic_condition_variable::notify_one; + using detail::basic_condition_variable::notify_all; + + void wait(unique_lock& m) + { + do_wait(m,detail::timeout::sentinel()); + } + + template + void wait(unique_lock& m,predicate_type pred) + { + while(!pred()) wait(m); + } + + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_wait(unique_lock& m,boost::system_time const& abs_time) + { + return do_wait(m,abs_time); + } + + bool timed_wait(unique_lock& m,boost::xtime const& abs_time) + { + return do_wait(m,system_time(abs_time)); + } + template + bool timed_wait(unique_lock& m,duration_type const& wait_duration) + { + if (wait_duration.is_pos_infinity()) + { + wait(m); // or do_wait(m,detail::timeout::sentinel()); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + return do_wait(m,wait_duration.total_milliseconds()); + } + + template + bool timed_wait(unique_lock& m,boost::system_time const& abs_time,predicate_type pred) + { + return do_wait(m,abs_time,pred); + } + template + bool timed_wait(unique_lock& m,boost::xtime const& abs_time,predicate_type pred) + { + return do_wait(m,system_time(abs_time),pred); + } + template + bool timed_wait(unique_lock& m,duration_type const& wait_duration,predicate_type pred) + { + if (wait_duration.is_pos_infinity()) + { + while (!pred()) + { + wait(m); // or do_wait(m,detail::timeout::sentinel()); + } + return true; + } + if (wait_duration.is_special()) + { + return pred(); + } + return do_wait(m,wait_duration.total_milliseconds(),pred); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + + template + cv_status + wait_until( + unique_lock& lock, + const chrono::time_point& t) + { + using namespace chrono; + chrono::time_point now = Clock::now(); + if (t<=now) { + return cv_status::timeout; + } + do_wait(lock, ceil(t-now).count()); + return Clock::now() < t ? cv_status::no_timeout : + cv_status::timeout; + } + + template + cv_status + wait_for( + unique_lock& lock, + const chrono::duration& d) + { + using namespace chrono; + if (d<=chrono::duration::zero()) { + return cv_status::timeout; + } + + steady_clock::time_point c_now = steady_clock::now(); + do_wait(lock, ceil(d).count()); + return steady_clock::now() - c_now < d ? cv_status::no_timeout : + cv_status::timeout; + } + + template + bool + wait_until( + unique_lock& lock, + const chrono::time_point& t, + Predicate pred) + { + while (!pred()) + { + if (wait_until(lock, t) == cv_status::timeout) + return pred(); + } + return true; + } + template + bool + wait_for( + unique_lock& lock, + const chrono::duration& d, + Predicate pred) + { + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); + } +#endif + }; + + class condition_variable_any: + private detail::basic_condition_variable + { + public: + BOOST_THREAD_NO_COPYABLE(condition_variable_any) + condition_variable_any() + {} + + using detail::basic_condition_variable::notify_one; + using detail::basic_condition_variable::notify_all; + + template + void wait(lock_type& m) + { + do_wait(m,detail::timeout::sentinel()); + } + + template + void wait(lock_type& m,predicate_type pred) + { + while(!pred()) wait(m); + } + +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_wait(lock_type& m,boost::system_time const& abs_time) + { + return do_wait(m,abs_time); + } + + template + bool timed_wait(lock_type& m,boost::xtime const& abs_time) + { + return do_wait(m,system_time(abs_time)); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration) + { + return do_wait(m,wait_duration.total_milliseconds()); + } + + template + bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred) + { + return do_wait(m,abs_time,pred); + } + + template + bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred) + { + return do_wait(m,system_time(abs_time),pred); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) + { + return do_wait(m,wait_duration.total_milliseconds(),pred); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + + template + cv_status + wait_until( + lock_type& lock, + const chrono::time_point& t) + { + using namespace chrono; + chrono::time_point now = Clock::now(); + if (t<=now) { + return cv_status::timeout; + } + do_wait(lock, ceil(t-now).count()); + return Clock::now() < t ? cv_status::no_timeout : + cv_status::timeout; + } + + template + cv_status + wait_for( + lock_type& lock, + const chrono::duration& d) + { + using namespace chrono; + if (d<=chrono::duration::zero()) { + return cv_status::timeout; + } + steady_clock::time_point c_now = steady_clock::now(); + do_wait(lock, ceil(d).count()); + return steady_clock::now() - c_now < d ? cv_status::no_timeout : + cv_status::timeout; + } + + template + bool + wait_until( + lock_type& lock, + const chrono::time_point& t, + Predicate pred) + { + while (!pred()) + { + if (wait_until(lock, t) == cv_status::timeout) + return pred(); + } + return true; + } + + template + bool + wait_for( + lock_type& lock, + const chrono::duration& d, + Predicate pred) + { + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); + } +#endif + }; + + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); +} + +#include + +#endif From 60646ff9e1d22c372294629941a9210078d94f02 Mon Sep 17 00:00:00 2001 From: tran Date: Sun, 8 Apr 2018 01:39:23 +0700 Subject: [PATCH 15/17] Fix "click-to-pay" handler issue Signed-off-by: tran --- src/qt/paymentserver.cpp | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 5fa5044a..42903434 100755 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -291,14 +291,33 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(p if (startLocalServer) { uriServer = new QLocalServer(this); - if (!uriServer->listen(name)) { - // constructor is called early in init, so don't use "emit message()" here - QMessageBox::critical(0, tr("Payment request error"), - tr("Cannot start lux: click-to-pay handler")); - } else { - connect(uriServer, SIGNAL(newConnection()), this, SLOT(handleURIConnection())); - connect(this, SIGNAL(receivedPaymentACK(QString)), this, SLOT(handlePaymentACK(QString))); + // In some case, it takes time to cleaning up old sokets leftover from a crash + // So, we need to retry it a couple of time + int max_tries = 20; + + while (max_tries > 0) + { + if (uriServer->listen(name)) + { + connect(uriServer, SIGNAL(newConnection()), this, SLOT(handleURIConnection())); + connect(this, SIGNAL(receivedPaymentACK(QString)), this, SLOT(handlePaymentACK(QString))); + return; + } + + max_tries -= 1; + if ((max_tries % 5) == 0) + { + // Retry to clean up old socket leftover from a crash + // after 5 seconds + QLocalServer::removeServer(name); + } + + MilliSleep(1000); } + + // constructor is called early in init, so don't use "emit message()" here + QMessageBox::critical(0, tr("Payment request error"), + tr("Cannot start lux: click-to-pay handler")); } } From 70a0ce812facbb3521d6f0f75c3aa00fd1131a7e Mon Sep 17 00:00:00 2001 From: tran Date: Sun, 8 Apr 2018 22:54:04 +0700 Subject: [PATCH 16/17] 1) Fix "rebuilding block database" issue 2) Allow fast shutdown when block index is running Signed-off-by: tran --- src/init.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 8ddca311..9c116fff 100755 --- a/src/init.cpp +++ b/src/init.cpp @@ -1223,12 +1223,14 @@ bool AppInit2(boost::thread_group& threadGroup) nCoinCacheSize = nTotalCache / 300; // coins in memory require around 300 bytes bool fLoaded = false; - while (!fLoaded) { + while (!fLoaded && !fRequestShutdown) { bool fReset = fReindex; std::string strLoadError; uiInterface.InitMessage(_("Loading block index...")); + LOCK(cs_main); + nStart = GetTimeMillis(); do { try { @@ -1246,6 +1248,17 @@ bool AppInit2(boost::thread_group& threadGroup) if (fReindex) pblocktree->WriteReindexing(true); + if (fRequestShutdown) + { + LogPrintf("Shutdown requested. Exiting.\n"); + return false; + } + + // LoadBlockIndex will load fTxIndex from the db, or set it if + // we're reindexing. It will also load fHavePruned if we've + // ever removed a block file from disk. + // Note that it also sets fReindex based on the disk flag! + // From here on out fReindex and fReset mean something different! if (!LoadBlockIndex()) { strLoadError = _("Error loading block database"); break; @@ -1275,7 +1288,7 @@ bool AppInit2(boost::thread_group& threadGroup) break; } } catch (std::exception& e) { - if (fDebug) LogPrintf("%s\n", e.what()); + LogPrintf("%s\n", e.what()); strLoadError = _("Error opening block database"); break; } @@ -1283,7 +1296,7 @@ bool AppInit2(boost::thread_group& threadGroup) fLoaded = true; } while (false); - if (!fLoaded) { + if (!fLoaded && !fRequestShutdown) { // first suggest a reindex if (!fReset) { bool fRet = uiInterface.ThreadSafeMessageBox( From a4709e8e9fe9be30bc9e7739dfbbcfbcd78d91e2 Mon Sep 17 00:00:00 2001 From: tran Date: Mon, 9 Apr 2018 02:24:38 +0700 Subject: [PATCH 17/17] Fix: Error initializing wallet db env Signed-off-by: tran --- src/db.cpp | 23 ++++++++++++++++++++++- src/init.cpp | 16 +++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index eeec283e..303100aa 100755 --- a/src/db.cpp +++ b/src/db.cpp @@ -103,7 +103,18 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn) nEnvFlags, S_IRUSR | S_IWUSR); if (ret != 0) + { + LogPrintf("CDBEnv::Open : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret)); + + // According to Berkeley DB specification, we must call dbenv.close() method on failure + int ret = dbenv.close(0); + if (ret != 0) + { + LogPrintf("CDBEnv::Open : Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret)); + } + return error("CDBEnv::Open : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret)); + } fDbEnvInit = true; fMockDb = false; @@ -135,8 +146,18 @@ void CDBEnv::MakeMock() DB_THREAD | DB_PRIVATE, S_IRUSR | S_IWUSR); - if (ret > 0) + if (ret != 0) + { + LogPrintf("CDBEnv::MakeMock : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret)); + + // According to Berkeley DB specification, we must call dbenv.close() method on failure + int ret = dbenv.close(0); + if (ret != 0) + { + LogPrintf("CDBEnv::MakeMock : Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret)); + } throw runtime_error(strprintf("CDBEnv::MakeMock : Error %d opening database environment.", ret)); + } fDbEnvInit = true; fMockDb = true; diff --git a/src/init.cpp b/src/init.cpp index 9c116fff..a7a9f298 100755 --- a/src/init.cpp +++ b/src/init.cpp @@ -1042,8 +1042,22 @@ bool AppInit2(boost::thread_group& threadGroup) // failure is ok (well, not really, but it's not worse than what we started with) } + int max_tries = 10; + bool isSuccess = false; // try again - if (!bitdb.Open(GetDataDir())) { + while (max_tries > 0) + { + if (bitdb.Open(GetDataDir())) { + isSuccess = true; + break; + } + + max_tries--; + MilliSleep(300); + } + + if (!isSuccess) + { // if it still fails, it probably means we can't even create the database env string msg = strprintf(_("Error initializing wallet database environment %s!"), strDataDir); return InitError(msg);