diff options
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/blockchain.cpp | 25 | ||||
-rw-r--r-- | src/rpc/client.cpp | 1 | ||||
-rw-r--r-- | src/rpc/mining.cpp | 9 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 39 | ||||
-rw-r--r-- | src/rpc/protocol.h | 4 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 83 | ||||
-rw-r--r-- | src/rpc/safemode.cpp | 14 | ||||
-rw-r--r-- | src/rpc/safemode.h | 12 |
8 files changed, 110 insertions, 77 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 06c68ea27c..5593cc9acc 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -47,8 +47,6 @@ static std::mutex cs_blockchange; static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock; -extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); - /* Calculate the difficulty for a given block index, * or the block index of the given chain. */ @@ -360,17 +358,23 @@ UniValue getdifficulty(const JSONRPCRequest& request) std::string EntryDescriptionString() { return " \"size\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n" - " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n" - " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n" + " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + " (DEPRECATED)\n" + " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority (DEPRECATED)\n" " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" " \"height\" : n, (numeric) block height when transaction entered pool\n" " \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n" " \"descendantsize\" : n, (numeric) virtual transaction size of in-mempool descendants (including this one)\n" - " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n" + " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) (DEPRECATED)\n" " \"ancestorcount\" : n, (numeric) number of in-mempool ancestor transactions (including this one)\n" " \"ancestorsize\" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one)\n" - " \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one)\n" + " \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) (DEPRECATED)\n" " \"wtxid\" : hash, (string) hash of serialized transaction, including witness data\n" + " \"fees\" : {\n" + " \"base\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n" + " \"modified\" : n, (numeric) transaction fee with fee deltas used for mining priority in " + CURRENCY_UNIT + "\n" + " \"ancestor\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) in " + CURRENCY_UNIT + "\n" + " \"descendant\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) in " + CURRENCY_UNIT + "\n" + " }\n" " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n" " \"transactionid\", (string) parent transaction id\n" " ... ]\n" @@ -383,6 +387,13 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) { AssertLockHeld(mempool.cs); + UniValue fees(UniValue::VOBJ); + fees.pushKV("base", ValueFromAmount(e.GetFee())); + fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee())); + fees.pushKV("ancestor", ValueFromAmount(e.GetModFeesWithAncestors())); + fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants())); + info.pushKV("fees", fees); + info.pushKV("size", (int)e.GetTxSize()); info.pushKV("fee", ValueFromAmount(e.GetFee())); info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee())); @@ -929,7 +940,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request) else if (height > chainHeight) throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height."); else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { - LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks."); + LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n"); height = chainHeight - MIN_BLOCKS_TO_KEEP; } diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 01f932dbb4..34c41b3b6b 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -51,6 +51,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "listreceivedbylabel", 0, "minconf" }, { "listreceivedbylabel", 1, "include_empty" }, { "listreceivedbylabel", 2, "include_watchonly" }, + { "getlabeladdress", 1, "force" }, { "getbalance", 1, "minconf" }, { "getbalance", 2, "include_watchonly" }, { "getblockhash", 0, "height" }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 06882c0dfd..b4bb78e689 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -116,7 +116,7 @@ UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGen } unsigned int nExtraNonce = 0; UniValue blockHashes(UniValue::VARR); - while (nHeight < nHeightEnd) + while (nHeight < nHeightEnd && !ShutdownRequested()) { std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(coinbaseScript->reserveScript)); if (!pblocktemplate.get()) @@ -235,6 +235,7 @@ UniValue prioritisetransaction(const JSONRPCRequest& request) "2. dummy (numeric, optional) API-Compatibility for previous API. Must be zero or null.\n" " DEPRECATED. For forward compatibility use named arguments and omit this parameter.\n" "3. fee_delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n" + " Note, that this value is not a fee rate. It is a value to modify absolute fee of the TX.\n" " The fee is not actually paid, only the algorithm for selecting transactions into a block\n" " considers the transaction as it would have paid a higher (or lower) fee.\n" "\nResult:\n" @@ -470,10 +471,10 @@ UniValue getblocktemplate(const JSONRPCRequest& request) { checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); - WaitableLock lock(csBestBlock); - while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) + WaitableLock lock(g_best_block_mutex); + while (g_best_block == hashWatchedChain && IsRPCRunning()) { - if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout) + if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout) { // Timeout: Check transactions for update if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 49e865a64a..0c93108bce 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -69,7 +69,7 @@ UniValue validateaddress(const JSONRPCRequest& request) { #ifdef ENABLE_WALLET - if (!::vpwallets.empty() && IsDeprecatedRPCEnabled("validateaddress")) { + if (HasWallets() && IsDeprecatedRPCEnabled("validateaddress")) { ret.pushKVs(getaddressinfo(request)); } #endif @@ -346,21 +346,22 @@ UniValue getmemoryinfo(const JSONRPCRequest& request) } } -uint32_t getCategoryMask(UniValue cats) { +void EnableOrDisableLogCategories(UniValue cats, bool enable) { cats = cats.get_array(); - uint32_t mask = 0; for (unsigned int i = 0; i < cats.size(); ++i) { - uint32_t flag = 0; std::string cat = cats[i].get_str(); - if (!GetLogCategory(&flag, &cat)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat); + + bool success; + if (enable) { + success = g_logger->EnableCategory(cat); + } else { + success = g_logger->DisableCategory(cat); } - if (flag == BCLog::NONE) { - return 0; + + if (!success) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat); } - mask |= flag; } - return mask; } UniValue logging(const JSONRPCRequest& request) @@ -399,25 +400,25 @@ UniValue logging(const JSONRPCRequest& request) ); } - uint32_t originalLogCategories = logCategories; + uint32_t original_log_categories = g_logger->GetCategoryMask(); if (request.params[0].isArray()) { - logCategories |= getCategoryMask(request.params[0]); + EnableOrDisableLogCategories(request.params[0], true); } - if (request.params[1].isArray()) { - logCategories &= ~getCategoryMask(request.params[1]); + EnableOrDisableLogCategories(request.params[1], false); } + uint32_t updated_log_categories = g_logger->GetCategoryMask(); + uint32_t changed_log_categories = original_log_categories ^ updated_log_categories; // Update libevent logging if BCLog::LIBEVENT has changed. // If the library version doesn't allow it, UpdateHTTPServerLogging() returns false, // in which case we should clear the BCLog::LIBEVENT flag. // Throw an error if the user has explicitly asked to change only the libevent // flag and it failed. - uint32_t changedLogCategories = originalLogCategories ^ logCategories; - if (changedLogCategories & BCLog::LIBEVENT) { - if (!UpdateHTTPServerLogging(logCategories & BCLog::LIBEVENT)) { - logCategories &= ~BCLog::LIBEVENT; - if (changedLogCategories == BCLog::LIBEVENT) { + if (changed_log_categories & BCLog::LIBEVENT) { + if (!UpdateHTTPServerLogging(g_logger->WillLogCategory(BCLog::LIBEVENT))) { + g_logger->DisableCategory(BCLog::LIBEVENT); + if (changed_log_categories == BCLog::LIBEVENT) { throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1."); } } diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index 4a265735d2..6954aed252 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -46,7 +46,6 @@ enum RPCErrorCode //! General application defined errors RPC_MISC_ERROR = -1, //!< std::exception thrown in command handling - RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode RPC_TYPE_ERROR = -3, //!< Unexpected type was passed as parameter RPC_INVALID_ADDRESS_OR_KEY = -5, //!< Invalid address or key RPC_OUT_OF_MEMORY = -7, //!< Ran out of memory during operation @@ -88,6 +87,9 @@ enum RPCErrorCode //! Backwards compatible aliases RPC_WALLET_INVALID_ACCOUNT_NAME = RPC_WALLET_INVALID_LABEL_NAME, + + //! Unused reserved codes, kept around for backwards compatibility. Do not reuse. + RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode }; UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 9d7aa58894..102ff3b443 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -7,6 +7,7 @@ #include <coins.h> #include <consensus/validation.h> #include <core_io.h> +#include <index/txindex.h> #include <init.h> #include <keystore.h> #include <validation.h> @@ -18,7 +19,6 @@ #include <policy/rbf.h> #include <primitives/transaction.h> #include <rpc/rawtransaction.h> -#include <rpc/safemode.h> #include <rpc/server.h> #include <script/script.h> #include <script/script_error.h> @@ -47,6 +47,8 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) TxToUniv(tx, uint256(), entry, true, RPCSerializationFlags()); if (!hashBlock.IsNull()) { + LOCK(cs_main); + entry.pushKV("blockhash", hashBlock.GetHex()); CBlockIndex* pindex = LookupBlockIndex(hashBlock); if (pindex) { @@ -94,6 +96,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request) " \"hash\" : \"id\", (string) The transaction hash (differs from txid for witness transactions)\n" " \"size\" : n, (numeric) The serialized transaction size\n" " \"vsize\" : n, (numeric) The virtual transaction size (differs from size for witness transactions)\n" + " \"weight\" : n, (numeric) The transaction's weight (between vsize*4-3 and vsize*4)\n" " \"version\" : n, (numeric) The version\n" " \"locktime\" : ttt, (numeric) The lock time\n" " \"vin\" : [ (array of json objects)\n" @@ -140,8 +143,6 @@ UniValue getrawtransaction(const JSONRPCRequest& request) + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"") ); - LOCK(cs_main); - bool in_active_chain = true; uint256 hash = ParseHashV(request.params[0], "parameter 1"); CBlockIndex* blockindex = nullptr; @@ -158,6 +159,8 @@ UniValue getrawtransaction(const JSONRPCRequest& request) } if (!request.params[2].isNull()) { + LOCK(cs_main); + uint256 blockhash = ParseHashV(request.params[2], "parameter 3"); blockindex = LookupBlockIndex(blockhash); if (!blockindex) { @@ -166,6 +169,11 @@ UniValue getrawtransaction(const JSONRPCRequest& request) in_active_chain = chainActive.Contains(blockindex); } + bool f_txindex_ready = false; + if (g_txindex && !blockindex) { + f_txindex_ready = g_txindex->BlockUntilSyncedToCurrentChain(); + } + CTransactionRef tx; uint256 hash_block; if (!GetTransaction(hash, tx, Params().GetConsensus(), hash_block, true, blockindex)) { @@ -175,10 +183,12 @@ UniValue getrawtransaction(const JSONRPCRequest& request) throw JSONRPCError(RPC_MISC_ERROR, "Block not available"); } 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"; + } else if (!f_txindex_ready) { + errmsg = "No such mempool transaction. Blockchain transactions are still in the process of being indexed"; } else { - errmsg = fTxIndex - ? "No such mempool or blockchain transaction" - : "No such mempool transaction. Use -txindex to enable blockchain transaction queries"; + errmsg = "No such mempool or blockchain transaction"; } throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errmsg + ". Use gettransaction for wallet transactions."); } @@ -228,19 +238,18 @@ UniValue gettxoutproof(const JSONRPCRequest& request) oneTxid = hash; } - LOCK(cs_main); - CBlockIndex* pblockindex = nullptr; - uint256 hashBlock; - if (!request.params[1].isNull()) - { + if (!request.params[1].isNull()) { + LOCK(cs_main); hashBlock = uint256S(request.params[1].get_str()); pblockindex = LookupBlockIndex(hashBlock); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } } else { + LOCK(cs_main); + // Loop through txids and try to find which block they're in. Exit loop once a block is found. for (const auto& tx : setTxids) { const Coin& coin = AccessByTxid(*pcoinsTip, tx); @@ -251,6 +260,14 @@ UniValue gettxoutproof(const JSONRPCRequest& request) } } + + // Allow txindex to catch up if we need to query it and before we acquire cs_main. + if (g_txindex && !pblockindex) { + g_txindex->BlockUntilSyncedToCurrentChain(); + } + + LOCK(cs_main); + if (pblockindex == nullptr) { CTransactionRef tx; @@ -494,6 +511,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request) " \"hash\" : \"id\", (string) The transaction hash (differs from txid for witness transactions)\n" " \"size\" : n, (numeric) The transaction size\n" " \"vsize\" : n, (numeric) The virtual transaction size (differs from size for witness transactions)\n" + " \"weight\" : n, (numeric) The transaction's weight (between vsize*4 - 3 and vsize*4)\n" " \"version\" : n, (numeric) The version\n" " \"locktime\" : ttt, (numeric) The lock time\n" " \"vin\" : [ (array of json objects)\n" @@ -595,6 +613,38 @@ UniValue decodescript(const JSONRPCRequest& request) // 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))); + // 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") { + txnouttype which_type; + std::vector<std::vector<unsigned char>> solutions_data; + Solver(script, which_type, solutions_data); + // Uncompressed pubkeys cannot be used with segwit checksigs. + // If the script contains an uncompressed pubkey, skip encoding of a segwit program. + if ((which_type == TX_PUBKEY) || (which_type == TX_MULTISIG)) { + for (const auto& solution : solutions_data) { + if ((solution.size() != 1) && !CPubKey(solution).IsCompressed()) { + return r; + } + } + } + UniValue sr(UniValue::VOBJ); + CScript segwitScr; + if (which_type == TX_PUBKEY) { + segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0].begin(), solutions_data[0].end()))); + } else if (which_type == TX_PUBKEYHASH) { + segwitScr = GetScriptForDestination(WitnessV0KeyHash(solutions_data[0])); + } else { + // Scripts that are not fit for P2WPKH are encoded as P2WSH. + // Newer segwit program versions should be considered when then become available. + uint256 scriptHash; + CSHA256().Write(script.data(), script.size()).Finalize(scriptHash.begin()); + segwitScr = GetScriptForDestination(WitnessV0ScriptHash(scriptHash)); + } + ScriptPubKeyToUniv(segwitScr, sr, true); + sr.pushKV("p2sh-segwit", EncodeDestination(CScriptID(segwitScr))); + r.pushKV("segwit", sr); + } } return r; @@ -774,9 +824,6 @@ UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival if (is_temp_keystore && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash())) { RPCTypeCheckObj(prevOut, { - {"txid", UniValueType(UniValue::VSTR)}, - {"vout", UniValueType(UniValue::VNUM)}, - {"scriptPubKey", UniValueType(UniValue::VSTR)}, {"redeemScript", UniValueType(UniValue::VSTR)}, }); UniValue v = find_value(prevOut, "redeemScript"); @@ -831,7 +878,7 @@ UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival SignatureData sigdata; // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mtx.vout.size())) { - ProduceSignature(MutableTransactionSignatureCreator(keystore, &mtx, i, amount, nHashType), prevPubKey, sigdata); + ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata); } sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(mtx, i)); @@ -1060,8 +1107,6 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") ); - ObserveSafeMode(); - std::promise<void> promise; RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}); @@ -1169,8 +1214,6 @@ UniValue testmempoolaccept(const JSONRPCRequest& request) ); } - ObserveSafeMode(); - RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VBOOL}); if (request.params[0].get_array().size() != 1) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Array must contain exactly one raw transaction for now"); @@ -1198,7 +1241,7 @@ UniValue testmempoolaccept(const JSONRPCRequest& request) { LOCK(cs_main); test_accept_res = AcceptToMemoryPool(mempool, state, std::move(tx), &missing_inputs, - nullptr /* plTxnReplaced */, false /* bypass_limits */, max_raw_tx_fee, /* test_accpet */ true); + nullptr /* plTxnReplaced */, false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true); } result_0.pushKV("allowed", test_accept_res); if (!test_accept_res) { diff --git a/src/rpc/safemode.cpp b/src/rpc/safemode.cpp deleted file mode 100644 index 9f3a9d30b8..0000000000 --- a/src/rpc/safemode.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include <rpc/safemode.h> - -#include <rpc/protocol.h> -#include <util.h> -#include <warnings.h> - -void ObserveSafeMode() -{ - std::string warning = GetWarnings("rpc"); - if (warning != "" && !gArgs.GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE)) { - throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + warning); - } -} - diff --git a/src/rpc/safemode.h b/src/rpc/safemode.h deleted file mode 100644 index 8466d6b2f9..0000000000 --- a/src/rpc/safemode.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2017 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_RPC_SAFEMODE_H -#define BITCOIN_RPC_SAFEMODE_H - -static const bool DEFAULT_DISABLE_SAFEMODE = true; - -void ObserveSafeMode(); - -#endif // BITCOIN_RPC_SAFEMODE_H |