diff options
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/blockchain.cpp | 89 | ||||
-rw-r--r-- | src/rpc/mining.cpp | 24 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 20 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 14 | ||||
-rw-r--r-- | src/rpc/util.cpp | 24 | ||||
-rw-r--r-- | src/rpc/util.h | 2 |
6 files changed, 95 insertions, 78 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f140999622..56018caf24 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -28,6 +28,7 @@ #include <sync.h> #include <txdb.h> #include <txmempool.h> +#include <undo.h> #include <util/strencodings.h> #include <util/system.h> #include <util/validation.h> @@ -182,7 +183,7 @@ static UniValue getblockcount(const JSONRPCRequest& request) }.ToString()); LOCK(cs_main); - return chainActive.Height(); + return ::ChainActive().Height(); } static UniValue getbestblockhash(const JSONRPCRequest& request) @@ -202,7 +203,7 @@ static UniValue getbestblockhash(const JSONRPCRequest& request) }.ToString()); LOCK(cs_main); - return chainActive.Tip()->GetBlockHash().GetHex(); + return ::ChainActive().Tip()->GetBlockHash().GetHex(); } void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex) @@ -381,7 +382,7 @@ static UniValue getdifficulty(const JSONRPCRequest& request) }.ToString()); LOCK(cs_main); - return GetDifficulty(chainActive.Tip()); + return GetDifficulty(::ChainActive().Tip()); } static std::string EntryDescriptionString() @@ -485,7 +486,10 @@ UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose) const uint256& hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); entryToJSON(pool, info, e); - o.pushKV(hash.ToString(), info); + // Mempool has unique entries so there is no advantage in using + // UniValue::pushKV, which checks if the key already exists in O(N). + // UniValue::__pushKV is used instead which currently is O(1). + o.__pushKV(hash.ToString(), info); } return o; } else { @@ -732,10 +736,10 @@ static UniValue getblockhash(const JSONRPCRequest& request) LOCK(cs_main); int nHeight = request.params[0].get_int(); - if (nHeight < 0 || nHeight > chainActive.Height()) + if (nHeight < 0 || nHeight > ::ChainActive().Height()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); - CBlockIndex* pblockindex = chainActive[nHeight]; + CBlockIndex* pblockindex = ::ChainActive()[nHeight]; return pblockindex->GetBlockHash().GetHex(); } @@ -791,7 +795,7 @@ static UniValue getblockheader(const JSONRPCRequest& request) { LOCK(cs_main); pblockindex = LookupBlockIndex(hash); - tip = chainActive.Tip(); + tip = ::ChainActive().Tip(); } if (!pblockindex) { @@ -828,6 +832,20 @@ static CBlock GetBlockChecked(const CBlockIndex* pblockindex) return block; } +static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) +{ + CBlockUndo blockUndo; + if (IsBlockPruned(pblockindex)) { + throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)"); + } + + if (!UndoReadFromDisk(blockUndo, pblockindex)) { + throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk"); + } + + return blockUndo; +} + static UniValue getblock(const JSONRPCRequest& request) { const RPCHelpMan help{"getblock", @@ -904,7 +922,7 @@ static UniValue getblock(const JSONRPCRequest& request) { LOCK(cs_main); pblockindex = LookupBlockIndex(hash); - tip = chainActive.Tip(); + tip = ::ChainActive().Tip(); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); @@ -1026,7 +1044,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) // too low to be a block time (corresponds to timestamp from Sep 2001). if (heightParam > 1000000000) { // Add a 2 hour buffer to include blocks which might have had old timestamps - CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0); + CBlockIndex* pindex = ::ChainActive().FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0); if (!pindex) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp."); } @@ -1034,7 +1052,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) } unsigned int height = (unsigned int) heightParam; - unsigned int chainHeight = (unsigned int) chainActive.Height(); + unsigned int chainHeight = (unsigned int) ::ChainActive().Height(); if (chainHeight < Params().PruneAfterHeight()) throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning."); else if (height > chainHeight) @@ -1333,10 +1351,10 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) LOCK(cs_main); - const CBlockIndex* tip = chainActive.Tip(); + const CBlockIndex* tip = ::ChainActive().Tip(); UniValue obj(UniValue::VOBJ); obj.pushKV("chain", Params().NetworkIDString()); - obj.pushKV("blocks", (int)chainActive.Height()); + obj.pushKV("blocks", (int)::ChainActive().Height()); obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1); obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); obj.pushKV("difficulty", (double)GetDifficulty(tip)); @@ -1433,11 +1451,11 @@ static UniValue getchaintips(const JSONRPCRequest& request) LOCK(cs_main); /* - * Idea: the set of chain tips is chainActive.tip, plus orphan blocks which do not have another orphan building off of them. + * Idea: the set of chain tips is ::ChainActive().tip, plus orphan blocks which do not have another orphan building off of them. * Algorithm: * - Make one pass through mapBlockIndex, picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers. * - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip. - * - add chainActive.Tip() + * - add ::ChainActive().Tip() */ std::set<const CBlockIndex*, CompareBlocksByHeight> setTips; std::set<const CBlockIndex*> setOrphans; @@ -1445,7 +1463,7 @@ static UniValue getchaintips(const JSONRPCRequest& request) for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex) { - if (!chainActive.Contains(item.second)) { + if (!::ChainActive().Contains(item.second)) { setOrphans.insert(item.second); setPrevs.insert(item.second->pprev); } @@ -1459,7 +1477,7 @@ static UniValue getchaintips(const JSONRPCRequest& request) } // Always report the currently active tip. - setTips.insert(chainActive.Tip()); + setTips.insert(::ChainActive().Tip()); /* Construct the output array. */ UniValue res(UniValue::VARR); @@ -1469,11 +1487,11 @@ static UniValue getchaintips(const JSONRPCRequest& request) obj.pushKV("height", block->nHeight); obj.pushKV("hash", block->phashBlock->GetHex()); - const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight; + const int branchLen = block->nHeight - ::ChainActive().FindFork(block)->nHeight; obj.pushKV("branchlen", branchLen); std::string status; - if (chainActive.Contains(block)) { + if (::ChainActive().Contains(block)) { // This block is part of the currently active chain. status = "active"; } else if (block->nStatus & BLOCK_FAILED_MASK) { @@ -1694,7 +1712,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) if (request.params[1].isNull()) { LOCK(cs_main); - pindex = chainActive.Tip(); + pindex = ::ChainActive().Tip(); } else { uint256 hash(ParseHashV(request.params[1], "blockhash")); LOCK(cs_main); @@ -1702,7 +1720,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - if (!chainActive.Contains(pindex)) { + if (!::ChainActive().Contains(pindex)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain"); } } @@ -1799,8 +1817,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) { const RPCHelpMan help{"getblockstats", "\nCompute per block statistics for a given window. All amounts are in satoshis.\n" - "It won't work for some heights with pruning.\n" - "It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.\n", + "It won't work for some heights with pruning.\n", { {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}}, {"stats", RPCArg::Type::ARR, /* default */ "all values", "Values to plot (see result below)", @@ -1863,7 +1880,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) CBlockIndex* pindex; if (request.params[0].isNum()) { const int height = request.params[0].get_int(); - const int current_tip = chainActive.Height(); + const int current_tip = ::ChainActive().Height(); if (height < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height)); } @@ -1871,14 +1888,14 @@ static UniValue getblockstats(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip)); } - pindex = chainActive[height]; + pindex = ::ChainActive()[height]; } else { const uint256 hash(ParseHashV(request.params[0], "hash_or_height")); pindex = LookupBlockIndex(hash); if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - if (!chainActive.Contains(pindex)) { + if (!::ChainActive().Contains(pindex)) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Block is not in chain %s", Params().NetworkIDString())); } } @@ -1895,6 +1912,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) } const CBlock block = GetBlockChecked(pindex); + const CBlockUndo blockUndo = GetUndoChecked(pindex); const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default) const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0; @@ -1908,10 +1926,6 @@ static UniValue getblockstats(const JSONRPCRequest& request) const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate"); const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight"); - if (loop_inputs && !g_txindex) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more of the selected stats requires -txindex enabled"); - } - CAmount maxfee = 0; CAmount maxfeerate = 0; CAmount minfee = MAX_MONEY; @@ -1932,7 +1946,8 @@ static UniValue getblockstats(const JSONRPCRequest& request) std::vector<std::pair<CAmount, int64_t>> feerate_array; std::vector<int64_t> txsize_array; - for (const auto& tx : block.vtx) { + for (size_t i = 0; i < block.vtx.size(); ++i) { + const auto& tx = block.vtx.at(i); outputs += tx->vout.size(); CAmount tx_total_out = 0; @@ -1976,14 +1991,9 @@ static UniValue getblockstats(const JSONRPCRequest& request) if (loop_inputs) { CAmount tx_total_in = 0; - for (const CTxIn& in : tx->vin) { - CTransactionRef tx_in; - uint256 hashBlock; - if (!GetTransaction(in.prevout.hash, tx_in, Params().GetConsensus(), hashBlock)) { - throw JSONRPCError(RPC_INTERNAL_ERROR, std::string("Unexpected internal error (tx index seems corrupt)")); - } - - CTxOut prevoutput = tx_in->vout[in.prevout.n]; + const auto& txundo = blockUndo.vtxundo.at(i - 1); + for (const Coin& coin: txundo.vprevout) { + const CTxOut& prevoutput = coin.out; tx_total_in += prevoutput.nValue; utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; @@ -2244,8 +2254,7 @@ UniValue scantxoutset(const JSONRPCRequest& request) desc_str = desc_uni.get_str(); UniValue range_uni = find_value(scanobject, "range"); if (!range_uni.isNull()) { - range = ParseRange(range_uni); - if (range.first < 0 || (range.second >> 31) != 0 || range.second >= range.first + 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range"); + range = ParseDescriptorRange(range_uni); } } else { throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object"); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 4de738a756..1831562100 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -40,10 +40,10 @@ * If 'height' is nonnegative, compute the estimate at the time when a given block was found. */ static UniValue GetNetworkHashPS(int lookup, int height) { - CBlockIndex *pb = chainActive.Tip(); + CBlockIndex *pb = ::ChainActive().Tip(); - if (height >= 0 && height < chainActive.Height()) - pb = chainActive[height]; + if (height >= 0 && height < ::ChainActive().Height()) + pb = ::ChainActive()[height]; if (pb == nullptr || !pb->nHeight) return 0; @@ -109,7 +109,7 @@ static UniValue generateBlocks(const CScript& coinbase_script, int nGenerate, ui { // Don't keep cs_main locked LOCK(cs_main); - nHeight = chainActive.Height(); + nHeight = ::ChainActive().Height(); nHeightEnd = nHeight+nGenerate; } unsigned int nExtraNonce = 0; @@ -122,7 +122,7 @@ static UniValue generateBlocks(const CScript& coinbase_script, int nGenerate, ui CBlock *pblock = &pblocktemplate->block; { LOCK(cs_main); - IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); + IncrementExtraNonce(pblock, ::ChainActive().Tip(), nExtraNonce); } while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { ++pblock->nNonce; @@ -210,10 +210,10 @@ static UniValue getmininginfo(const JSONRPCRequest& request) LOCK(cs_main); UniValue obj(UniValue::VOBJ); - obj.pushKV("blocks", (int)chainActive.Height()); + obj.pushKV("blocks", (int)::ChainActive().Height()); if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight); if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs); - obj.pushKV("difficulty", (double)GetDifficulty(chainActive.Tip())); + obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip())); obj.pushKV("networkhashps", getnetworkhashps(request)); obj.pushKV("pooledtx", (uint64_t)mempool.size()); obj.pushKV("chain", Params().NetworkIDString()); @@ -409,7 +409,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) return "duplicate-inconclusive"; } - CBlockIndex* const pindexPrev = chainActive.Tip(); + CBlockIndex* const pindexPrev = ::ChainActive().Tip(); // TestBlockValidity only supports blocks built on the current Tip if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; @@ -465,7 +465,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) else { // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier - hashWatchedChain = chainActive.Tip()->GetBlockHash(); + hashWatchedChain = ::ChainActive().Tip()->GetBlockHash(); nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; } @@ -503,7 +503,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) static CBlockIndex* pindexPrev; static int64_t nStart; static std::unique_ptr<CBlockTemplate> pblocktemplate; - if (pindexPrev != chainActive.Tip() || + if (pindexPrev != ::ChainActive().Tip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) { // Clear pindexPrev so future calls make a new block, despite any failures from here on @@ -511,7 +511,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) // Store the pindexBest used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrevNew = chainActive.Tip(); + CBlockIndex* pindexPrevNew = ::ChainActive().Tip(); nStart = GetTime(); // Create new block @@ -646,7 +646,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) result.pushKV("transactions", transactions); result.pushKV("coinbaseaux", aux); result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue); - result.pushKV("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)); + result.pushKV("longpollid", ::ChainActive().Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)); result.pushKV("target", hashTarget.GetHex()); result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1); result.pushKV("mutable", aMutable); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index bfb559f0db..7008a83143 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -24,6 +24,7 @@ #include <warnings.h> #include <stdint.h> +#include <tuple> #ifdef HAVE_MALLOC_INFO #include <malloc.h> #endif @@ -215,18 +216,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request) int64_t range_end = 0; if (request.params.size() >= 2 && !request.params[1].isNull()) { - auto range = ParseRange(request.params[1]); - if (range.first < 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0"); - } - if ((range.second >> 31) != 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high"); - } - if (range.second >= range.first + 1000000) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large"); - } - range_begin = range.first; - range_end = range.second; + std::tie(range_begin, range_end) = ParseDescriptorRange(request.params[1]); } FlatSigningProvider key_provider; @@ -307,8 +297,8 @@ static UniValue verifymessage(const JSONRPCRequest& request) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } - const CKeyID *keyID = boost::get<CKeyID>(&destination); - if (!keyID) { + const PKHash *pkhash = boost::get<PKHash>(&destination); + if (!pkhash) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); } @@ -326,7 +316,7 @@ static UniValue verifymessage(const JSONRPCRequest& request) if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) return false; - return (pubkey.GetID() == *keyID); + return (pubkey.GetID() == *pkhash); } static UniValue signmessagewithprivkey(const JSONRPCRequest& request) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 78d7bbc80c..b3926786db 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -64,8 +64,8 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry.pushKV("blockhash", hashBlock.GetHex()); CBlockIndex* pindex = LookupBlockIndex(hashBlock); if (pindex) { - if (chainActive.Contains(pindex)) { - entry.pushKV("confirmations", 1 + chainActive.Height() - pindex->nHeight); + if (::ChainActive().Contains(pindex)) { + entry.pushKV("confirmations", 1 + ::ChainActive().Height() - pindex->nHeight); entry.pushKV("time", pindex->GetBlockTime()); entry.pushKV("blocktime", pindex->GetBlockTime()); } @@ -184,7 +184,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) if (!blockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found"); } - in_active_chain = chainActive.Contains(blockindex); + in_active_chain = ::ChainActive().Contains(blockindex); } bool f_txindex_ready = false; @@ -274,7 +274,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) for (const auto& tx : setTxids) { const Coin& coin = AccessByTxid(*pcoinsTip, tx); if (!coin.IsSpent()) { - pblockindex = chainActive[coin.nHeight]; + pblockindex = ::ChainActive()[coin.nHeight]; break; } } @@ -348,7 +348,7 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) LOCK(cs_main); const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash()); - if (!pindex || !chainActive.Contains(pindex) || pindex->nTx == 0) { + if (!pindex || !::ChainActive().Contains(pindex) || pindex->nTx == 0) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); } @@ -572,7 +572,7 @@ static UniValue decodescript(const JSONRPCRequest& request) if (type.isStr() && type.get_str() != "scripthash") { // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH, // don't return the address for a P2SH of the P2SH. - r.pushKV("p2sh", EncodeDestination(CScriptID(script))); + r.pushKV("p2sh", EncodeDestination(ScriptHash(script))); // P2SH and witness programs cannot be wrapped in P2WSH, if this script // is a witness program, don't return addresses for a segwit programs. if (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") { @@ -599,7 +599,7 @@ static UniValue decodescript(const JSONRPCRequest& request) segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script)); } ScriptPubKeyToUniv(segwitScr, sr, /* fIncludeHex */ true); - sr.pushKV("p2sh-segwit", EncodeDestination(CScriptID(segwitScr))); + sr.pushKV("p2sh-segwit", EncodeDestination(ScriptHash(segwitScr))); r.pushKV("segwit", sr); } } diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 1a87c9f935..9cdb22001f 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -8,6 +8,8 @@ #include <tinyformat.h> #include <util/strencodings.h> +#include <tuple> + InitInterfaces* g_rpc_interfaces = nullptr; void RPCTypeCheck(const UniValue& params, @@ -181,7 +183,7 @@ public: return UniValue(UniValue::VOBJ); } - UniValue operator()(const CKeyID& keyID) const + UniValue operator()(const PKHash& keyID) const { UniValue obj(UniValue::VOBJ); obj.pushKV("isscript", false); @@ -189,7 +191,7 @@ public: return obj; } - UniValue operator()(const CScriptID& scriptID) const + UniValue operator()(const ScriptHash& scriptID) const { UniValue obj(UniValue::VOBJ); obj.pushKV("isscript", true); @@ -654,7 +656,7 @@ std::string RPCArg::ToString(const bool oneline) const assert(false); } -std::pair<int64_t, int64_t> ParseRange(const UniValue& value) +static std::pair<int64_t, int64_t> ParseRange(const UniValue& value) { if (value.isNum()) { return {0, value.get_int64()}; @@ -667,3 +669,19 @@ std::pair<int64_t, int64_t> ParseRange(const UniValue& value) } throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified as end or as [begin,end]"); } + +std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value) +{ + int64_t low, high; + std::tie(low, high) = ParseRange(value); + if (low < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0"); + } + if ((high >> 31) != 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high"); + } + if (high >= low + 1000000) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large"); + } + return {low, high}; +} diff --git a/src/rpc/util.h b/src/rpc/util.h index b5b5789253..e4fa8fc3d7 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -81,7 +81,7 @@ RPCErrorCode RPCErrorFromTransactionError(TransactionError terr); UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string = ""); //! Parse a JSON range specified as int64, or [int64, int64] -std::pair<int64_t, int64_t> ParseRange(const UniValue& value); +std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value); struct RPCArg { enum class Type { |