diff options
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/blockchain.cpp | 144 | ||||
-rw-r--r-- | src/rpc/blockchain.h | 12 | ||||
-rw-r--r-- | src/rpc/mining.cpp | 26 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 30 | ||||
-rw-r--r-- | src/rpc/net.cpp | 4 | ||||
-rw-r--r-- | src/rpc/protocol.cpp | 1 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 38 | ||||
-rw-r--r-- | src/rpc/rawtransaction_util.cpp | 13 | ||||
-rw-r--r-- | src/rpc/rawtransaction_util.h | 22 | ||||
-rw-r--r-- | src/rpc/server.cpp | 2 | ||||
-rw-r--r-- | src/rpc/util.cpp | 24 | ||||
-rw-r--r-- | src/rpc/util.h | 2 |
12 files changed, 173 insertions, 145 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 672fc69673..50c4589d9f 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -6,7 +6,6 @@ #include <rpc/blockchain.h> #include <amount.h> -#include <base58.h> #include <blockfilter.h> #include <chain.h> #include <chainparams.h> @@ -15,7 +14,6 @@ #include <core_io.h> #include <hash.h> #include <index/blockfilterindex.h> -#include <index/txindex.h> #include <key_io.h> #include <policy/feerate.h> #include <policy/policy.h> @@ -28,6 +26,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> @@ -93,6 +92,9 @@ static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* b UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) { + // Serialize passed information without accessing chain state of the active chain! + AssertLockNotHeld(cs_main); // For performance reasons + UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); const CBlockIndex* pnext; @@ -119,6 +121,9 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails) { + // Serialize passed information without accessing chain state of the active chain! + AssertLockNotHeld(cs_main); // For performance reasons + UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); const CBlockIndex* pnext; @@ -176,7 +181,7 @@ static UniValue getblockcount(const JSONRPCRequest& request) }.ToString()); LOCK(cs_main); - return chainActive.Height(); + return ::ChainActive().Height(); } static UniValue getbestblockhash(const JSONRPCRequest& request) @@ -196,7 +201,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) @@ -375,7 +380,7 @@ static UniValue getdifficulty(const JSONRPCRequest& request) }.ToString()); LOCK(cs_main); - return GetDifficulty(chainActive.Tip()); + return GetDifficulty(::ChainActive().Tip()); } static std::string EntryDescriptionString() @@ -479,7 +484,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 { @@ -726,10 +734,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(); } @@ -785,7 +793,7 @@ static UniValue getblockheader(const JSONRPCRequest& request) { LOCK(cs_main); pblockindex = LookupBlockIndex(hash); - tip = chainActive.Tip(); + tip = ::ChainActive().Tip(); } if (!pblockindex) { @@ -822,11 +830,23 @@ 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) { - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw std::runtime_error( - RPCHelpMan{"getblock", + const RPCHelpMan help{"getblock", "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n" "If verbosity is 1, returns an Object with information about block <hash>.\n" "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n", @@ -878,9 +898,11 @@ static UniValue getblock(const JSONRPCRequest& request) HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") }, - }.ToString()); + }; - LOCK(cs_main); + if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { + throw std::runtime_error(help.ToString()); + } uint256 hash(ParseHashV(request.params[0], "blockhash")); @@ -892,12 +914,20 @@ static UniValue getblock(const JSONRPCRequest& request) verbosity = request.params[1].get_bool() ? 1 : 0; } - const CBlockIndex* pblockindex = LookupBlockIndex(hash); - if (!pblockindex) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - } + CBlock block; + const CBlockIndex* pblockindex; + const CBlockIndex* tip; + { + LOCK(cs_main); + pblockindex = LookupBlockIndex(hash); + tip = ::ChainActive().Tip(); + + if (!pblockindex) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + } - const CBlock block = GetBlockChecked(pblockindex); + block = GetBlockChecked(pblockindex); + } if (verbosity <= 0) { @@ -907,7 +937,7 @@ static UniValue getblock(const JSONRPCRequest& request) return strHex; } - return blockToJSON(block, chainActive.Tip(), pblockindex, verbosity >= 2); + return blockToJSON(block, tip, pblockindex, verbosity >= 2); } struct CCoinsStats @@ -1012,7 +1042,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."); } @@ -1020,7 +1050,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) @@ -1031,7 +1061,12 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) } PruneBlockFilesManual(height); - return uint64_t(height); + const CBlockIndex* block = ::ChainActive().Tip(); + assert(block); + while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { + block = block->pprev; + } + return uint64_t(block->nHeight); } static UniValue gettxoutsetinfo(const JSONRPCRequest& request) @@ -1063,7 +1098,7 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request) UniValue ret(UniValue::VOBJ); CCoinsStats stats; - FlushStateToDisk(); + ::ChainstateActive().ForceFlushStateToDisk(); if (GetUTXOStats(pcoinsdbview.get(), stats)) { ret.pushKV("height", (int64_t)stats.nHeight); ret.pushKV("bestblock", stats.hashBlock.GetHex()); @@ -1319,16 +1354,16 @@ 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)); obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast()); obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip)); - obj.pushKV("initialblockdownload", IsInitialBlockDownload()); + obj.pushKV("initialblockdownload", ::ChainstateActive().IsInitialBlockDownload()); obj.pushKV("chainwork", tip->nChainWork.GetHex()); obj.pushKV("size_on_disk", CalculateCurrentUsage()); obj.pushKV("pruned", fPruneMode); @@ -1419,11 +1454,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; @@ -1431,7 +1466,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); } @@ -1445,7 +1480,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); @@ -1455,11 +1490,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) { @@ -1491,6 +1526,7 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool) // Make sure this call is atomic in the pool. LOCK(pool.cs); UniValue ret(UniValue::VOBJ); + ret.pushKV("loaded", pool.IsLoaded()); ret.pushKV("size", (int64_t)pool.size()); ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize()); ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage()); @@ -1511,6 +1547,7 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request) {}, RPCResult{ "{\n" + " \"loaded\": true|false (boolean) True if the mempool is fully loaded\n" " \"size\": xxxxx, (numeric) Current tx count\n" " \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\n" " \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n" @@ -1678,7 +1715,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); @@ -1686,7 +1723,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"); } } @@ -1783,8 +1820,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)", @@ -1847,7 +1883,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)); } @@ -1855,14 +1891,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())); } } @@ -1879,6 +1915,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; @@ -1892,10 +1929,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; @@ -1916,7 +1949,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; @@ -1960,14 +1994,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; @@ -2061,11 +2090,11 @@ static UniValue savemempool(const JSONRPCRequest& request) }.ToString()); } - if (!g_is_mempool_loaded) { + if (!::mempool.IsLoaded()) { throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet"); } - if (!DumpMempool()) { + if (!DumpMempool(::mempool)) { throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk"); } @@ -2228,8 +2257,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"); @@ -2267,7 +2295,7 @@ UniValue scantxoutset(const JSONRPCRequest& request) std::unique_ptr<CCoinsViewCursor> pcursor; { LOCK(cs_main); - FlushStateToDisk(); + ::ChainstateActive().ForceFlushStateToDisk(); pcursor = std::unique_ptr<CCoinsViewCursor>(pcoinsdbview->Cursor()); assert(pcursor); } diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 55d1de453f..ff461fbcbc 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -5,9 +5,13 @@ #ifndef BITCOIN_RPC_BLOCKCHAIN_H #define BITCOIN_RPC_BLOCKCHAIN_H -#include <vector> -#include <stdint.h> #include <amount.h> +#include <sync.h> + +#include <stdint.h> +#include <vector> + +extern RecursiveMutex cs_main; class CBlock; class CBlockIndex; @@ -28,7 +32,7 @@ double GetDifficulty(const CBlockIndex* blockindex); void RPCNotifyBlockChange(bool ibd, const CBlockIndex *); /** Block description to JSON */ -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false); +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false) LOCKS_EXCLUDED(cs_main); /** Mempool information to JSON */ UniValue MempoolInfoToJSON(const CTxMemPool& pool); @@ -37,7 +41,7 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool); UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose = false); /** Block header to JSON */ -UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex); +UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) LOCKS_EXCLUDED(cs_main); /** Used by getblockstats to get feerates at different percentiles by weight */ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 4de738a756..477f05f46c 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"; @@ -442,7 +442,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!"); - if (IsInitialBlockDownload()) + if (::ChainstateActive().IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks..."); static unsigned int nTransactionsUpdatedLast; @@ -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..2b29fd543b 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -3,27 +3,20 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <chain.h> -#include <clientversion.h> -#include <core_io.h> #include <crypto/ripemd160.h> #include <key_io.h> -#include <validation.h> #include <httpserver.h> -#include <net.h> -#include <netbase.h> #include <outputtype.h> #include <rpc/blockchain.h> #include <rpc/server.h> #include <rpc/util.h> #include <script/descriptor.h> -#include <timedata.h> #include <util/system.h> #include <util/strencodings.h> #include <util/validation.h> -#include <warnings.h> #include <stdint.h> +#include <tuple> #ifdef HAVE_MALLOC_INFO #include <malloc.h> #endif @@ -203,7 +196,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request) }, RPCExamples{ "First three native segwit receive addresses\n" + - HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#trd0mf0l\" \"[0,2]\"") + HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu\" \"[0,2]\"") }}.ToString() ); } @@ -215,18 +208,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 +289,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 +308,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/net.cpp b/src/rpc/net.cpp index e8cdce623c..d993a88458 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -5,7 +5,6 @@ #include <rpc/server.h> #include <banman.h> -#include <chainparams.h> #include <clientversion.h> #include <core_io.h> #include <net.h> @@ -17,7 +16,6 @@ #include <rpc/util.h> #include <sync.h> #include <timedata.h> -#include <ui_interface.h> #include <util/strencodings.h> #include <util/system.h> #include <validation.h> @@ -496,7 +494,7 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) obj.pushKV("protocolversion",PROTOCOL_VERSION); if(g_connman) obj.pushKV("localservices", strprintf("%016x", g_connman->GetLocalServices())); - obj.pushKV("localrelay", fRelayTxes); + obj.pushKV("localrelay", g_relay_txes); obj.pushKV("timeoffset", GetTimeOffset()); if (g_connman) { obj.pushKV("networkactive", g_connman->GetNetworkActive()); diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp index 23999b305a..33b0130a94 100644 --- a/src/rpc/protocol.cpp +++ b/src/rpc/protocol.cpp @@ -10,7 +10,6 @@ #include <util/system.h> #include <util/strencodings.h> #include <util/time.h> -#include <version.h> /** * JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility, diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 4b1398d6a1..9da24afe79 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -6,20 +6,16 @@ #include <chain.h> #include <coins.h> #include <compat/byteswap.h> -#include <consensus/tx_verify.h> #include <consensus/validation.h> #include <core_io.h> #include <index/txindex.h> -#include <init.h> -#include <interfaces/chain.h> #include <key_io.h> #include <keystore.h> #include <merkleblock.h> +#include <node/coin.h> #include <node/psbt.h> #include <node/transaction.h> -#include <policy/policy.h> #include <policy/rbf.h> -#include <policy/settings.h> #include <primitives/transaction.h> #include <psbt.h> #include <rpc/rawtransaction_util.h> @@ -30,7 +26,6 @@ #include <script/sign.h> #include <script/standard.h> #include <uint256.h> -#include <util/bip32.h> #include <util/moneystr.h> #include <util/strencodings.h> #include <validation.h> @@ -44,7 +39,7 @@ /** High fee for sendrawtransaction and testmempoolaccept. * By default, transaction with a fee higher than this will be rejected by the - * RPCs. This can be overriden with the maxfeerate argument. + * RPCs. This can be overridden with the maxfeerate argument. */ constexpr static CAmount DEFAULT_MAX_RAW_TX_FEE{COIN / 10}; @@ -63,8 +58,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()); } @@ -183,7 +178,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; @@ -201,7 +196,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) } errmsg = "No such transaction found in the provided block"; } else if (!g_txindex) { - errmsg = "No such mempool transaction. Use -txindex to enable blockchain transaction queries"; + errmsg = "No such mempool transaction. Use -txindex or provide a block hash to enable blockchain transaction queries"; } else if (!f_txindex_ready) { errmsg = "No such mempool transaction. Blockchain transactions are still in the process of being indexed"; } else { @@ -273,7 +268,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; } } @@ -347,7 +342,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"); } @@ -578,7 +573,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") { @@ -605,7 +600,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); } } @@ -754,8 +749,8 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) "}\n" }, RPCExamples{ - HelpExampleCli("signrawtransactionwithkey", "\"myhex\"") - + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\"") + HelpExampleCli("signrawtransactionwithkey", "\"myhex\" \"[\\\"key1\\\",\\\"key2\\\"]\"") + + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\", \"[\\\"key1\\\",\\\"key2\\\"]\"") }, }.ToString()); @@ -777,7 +772,14 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) keystore.AddKey(key); } - return SignTransaction(*g_rpc_interfaces->chain, mtx, request.params[2], &keystore, true, request.params[3]); + // Fetch previous transactions (inputs): + std::map<COutPoint, Coin> coins; + for (const CTxIn& txin : mtx.vin) { + coins[txin.prevout]; // Create empty map entry keyed by prevout. + } + FindCoins(coins); + + return SignTransaction(mtx, request.params[2], &keystore, coins, true, request.params[3]); } static UniValue sendrawtransaction(const JSONRPCRequest& request) diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index 728fc62e25..9c4cdc3a90 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -7,7 +7,6 @@ #include <coins.h> #include <core_io.h> -#include <interfaces/chain.h> #include <key_io.h> #include <keystore.h> #include <policy/policy.h> @@ -149,18 +148,8 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std:: vErrorsRet.push_back(entry); } -// TODO(https://github.com/bitcoin/bitcoin/pull/10973#discussion_r267084237): -// The dependency on interfaces::Chain should be removed, so -// signrawtransactionwithkey doesn't need access to a Chain instance. -UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType) +UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore* keystore, std::map<COutPoint, Coin>& coins, bool is_temp_keystore, const UniValue& hashType) { - // Fetch previous transactions (inputs): - std::map<COutPoint, Coin> coins; - for (const CTxIn& txin : mtx.vin) { - coins[txin.prevout]; // Create empty map entry keyed by prevout. - } - chain.findCoins(coins); - // Add previous txouts given in the RPC call: if (!prevTxsUnival.isNull()) { UniValue prevTxs = prevTxsUnival.get_array(); diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h index 5529dedbd4..c115d33a77 100644 --- a/src/rpc/rawtransaction_util.h +++ b/src/rpc/rawtransaction_util.h @@ -5,16 +5,26 @@ #ifndef BITCOIN_RPC_RAWTRANSACTION_UTIL_H #define BITCOIN_RPC_RAWTRANSACTION_UTIL_H +#include <map> + class CBasicKeyStore; class UniValue; struct CMutableTransaction; +class Coin; +class COutPoint; -namespace interfaces { -class Chain; -} // namespace interfaces - -/** Sign a transaction with the given keystore and previous transactions */ -UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore *keystore, bool tempKeystore, const UniValue& hashType); +/** + * Sign a transaction with the given keystore and previous transactions + * + * @param mtx The transaction to-be-signed + * @param prevTxs Array of previous txns outputs that tx depends on but may not yet be in the block chain + * @param keystore Temporary keystore containing signing keys + * @param coins Map of unspent outputs - coins in mempool and current chain UTXO set, may be extended by previous txns outputs after call + * @param tempKeystore Whether to use temporary keystore + * @param hashType The signature hash type + * @returns JSON object with details of signed transaction + */ +UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore* keystore, std::map<COutPoint, Coin>& coins, bool tempKeystore, const UniValue& hashType); /** Create a transaction from univalue parameters */ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 9df4070cbb..ca17d379bc 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -7,11 +7,9 @@ #include <fs.h> #include <key_io.h> -#include <random.h> #include <rpc/util.h> #include <shutdown.h> #include <sync.h> -#include <ui_interface.h> #include <util/strencodings.h> #include <util/system.h> 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 { |