diff --git a/.cirrus.yml b/.cirrus.yml index f2b8bf666ef..067d118edf3 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -86,10 +86,10 @@ win64_native_common: &win64_native_common windows_container: cpu: 4 memory: 8G - image: cirrusci/windowsservercore:visualstudio2019 + image: cirrusci/windowsservercore:visualstudio2022 timeout_in: 120m env: - PATH: 'C:\jom;C:\Python39;C:\Python39\Scripts;C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin;%PATH%' + PATH: 'C:\jom;C:\Python39;C:\Python39\Scripts;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin;%PATH%' PYTHONUTF8: 1 CI_VCPKG_TAG: '2021.05.12' VCPKG_DOWNLOADS: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\downloads' @@ -98,7 +98,7 @@ win64_native_common: &win64_native_common QT_LOCAL_PATH: 'C:\qt-everywhere-opensource-src-5.15.3.zip' QT_SOURCE_DIR: 'C:\qt-everywhere-src-5.15.3' QTBASEDIR: 'C:\Qt_static' - x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat"' + x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"' IgnoreWarnIntDirInTempDetected: 'true' merge_script: - git config --global user.email "ci@ci.ci" @@ -161,19 +161,25 @@ win64_native_common: &win64_native_common - msbuild build_msvc\bitcoin.sln -property:Configuration=Release -maxCpuCount -verbosity:minimal -noLogo task: - name: "Win64 native [msvc] (Short running functional tests)" + name: "Win64 native [vs2022] (Short running functional tests)" <<: *win64_native_common functional_tests_script: # Increase the dynamic port range to the maximum allowed value to mitigate "OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted". # See: https://docs.microsoft.com/en-us/biztalk/technical-guides/settings-that-can-be-modified-to-improve-network-performance - netsh int ipv4 set dynamicport tcp start=1025 num=64511 - netsh int ipv6 set dynamicport tcp start=1025 num=64511 + - mkdir artifactsdir # Heavier tests are moved to a secondary task # Exclude feature_dbcrash and feature_fee_estimation, failing https://github.com/ElementsProject/elements/pull/1298 - - python test\functional\test_runner.py --nocleanup --ci --quiet --combinedlogslen=4000 --jobs=4 --timeout-factor=8 --extended --exclude wallet_avoidreuse,feature_trim_headers,feature_dbcrash,feature_fee_estimation + - python test\functional\test_runner.py --tmpdirprefix=artifactsdir/ --ci --quiet --combinedlogslen=4000 --jobs=4 --timeout-factor=8 --extended --exclude wallet_avoidreuse,feature_trim_headers,feature_dbcrash,feature_fee_estimation + artifacts: + paths: + - artifactsdir/**/*.log + - artifactsdir/**/tmp* + - artifactsdir/**/*.conf task: - name: "Win64 native [msvc] (Long running functional tests + unit tests)" + name: "Win64 native [vs2022] (Long running functional tests + unit tests)" <<: *win64_native_common unit_tests_script: - src\test_elements.exe -l test_suite @@ -185,9 +191,15 @@ task: # See: https://docs.microsoft.com/en-us/biztalk/technical-guides/settings-that-can-be-modified-to-improve-network-performance - netsh int ipv4 set dynamicport tcp start=1025 num=64511 - netsh int ipv6 set dynamicport tcp start=1025 num=64511 + - mkdir artifactsdir # Execute tests excluded from the main task # Ignore failures for now until https://github.com/ElementsProject/elements/pull/1298 is merged - - python test\functional\test_runner.py --nocleanup --ci --quiet --combinedlogslen=4000 --jobs=4 --timeout-factor=8 wallet_avoidreuse feature_trim_headers feature_dbcrash feature_fee_estimation || true + - python test\functional\test_runner.py --tmpdirprefix=artifactsdir/ --ci --quiet --combinedlogslen=4000 --jobs=4 --timeout-factor=8 wallet_avoidreuse feature_trim_headers feature_dbcrash feature_fee_estimation || true + artifacts: + paths: + - artifactsdir/**/*.log + - artifactsdir/**/tmp* + - artifactsdir/**/*.conf task: name: 'ARM [unit tests, no functional tests] [bullseye]' diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh index 52d434afef5..65c80222270 100755 --- a/ci/lint/06_script.sh +++ b/ci/lint/06_script.sh @@ -19,7 +19,6 @@ test/lint/git-subtree-check.sh src/crypto/ctaes test/lint/git-subtree-check.sh src/secp256k1 test/lint/git-subtree-check.sh src/simplicity test/lint/git-subtree-check.sh src/minisketch -test/lint/git-subtree-check.sh src/univalue test/lint/git-subtree-check.sh src/leveldb test/lint/git-subtree-check.sh src/crc32c test/lint/check-doc.py diff --git a/configure.ac b/configure.ac index 04b0f2de830..c6fa9757e6d 100644 --- a/configure.ac +++ b/configure.ac @@ -445,6 +445,7 @@ if test "$CXXFLAGS_overridden" = "no"; then AX_CHECK_COMPILE_FLAG([-Wthread-safety], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wthread-safety"], [], [$CXXFLAG_WERROR]) AX_CHECK_COMPILE_FLAG([-Wloop-analysis], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wrange-loop-analysis"], [], [$CXXFLAG_WERROR]) AX_CHECK_COMPILE_FLAG([-Wredundant-decls], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wredundant-decls"], [], [$CXXFLAG_WERROR]) + AX_CHECK_COMPILE_FLAG([-Wunused-result],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-result"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wunused-member-function], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wunused-member-function"], [], [$CXXFLAG_WERROR]) AX_CHECK_COMPILE_FLAG([-Wdate-time], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wdate-time"], [], [$CXXFLAG_WERROR]) AX_CHECK_COMPILE_FLAG([-Wconditional-uninitialized], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wconditional-uninitialized"], [], [$CXXFLAG_WERROR]) diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 0fa8f3c3da9..0d687194789 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -33,10 +33,9 @@ bool SerializeDB(Stream& stream, const Data& data) { // Write and commit header, data try { - CHashWriter hasher(stream.GetType(), stream.GetVersion()); - stream << Params().MessageStart() << data; - hasher << Params().MessageStart() << data; - stream << hasher.GetHash(); + HashedSourceWriter hashwriter{stream}; + hashwriter << Params().MessageStart() << data; + stream << hashwriter.GetHash(); } catch (const std::exception& e) { return error("%s: Serialize or I/O error - %s", __func__, e.what()); } diff --git a/src/addrman.cpp b/src/addrman.cpp index ead862519f6..f5f2dfa6651 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -1171,8 +1171,7 @@ void AddrMan::Unserialize(Stream& s_) } // explicit instantiation -template void AddrMan::Serialize(CHashWriter& s) const; -template void AddrMan::Serialize(CAutoFile& s) const; +template void AddrMan::Serialize(HashedSourceWriter& s) const; template void AddrMan::Serialize(CDataStream& s) const; template void AddrMan::Unserialize(CAutoFile& s); template void AddrMan::Unserialize(CHashVerifier& s); diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index efc3b5b2505..85048028d5f 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -848,7 +848,7 @@ static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& str try { response = CallRPC(rh, strMethod, args, rpcwallet); if (fWait) { - const UniValue& error = find_value(response, "error"); + const UniValue& error = response.find_value("error"); if (!error.isNull() && error["code"].get_int() == RPC_IN_WARMUP) { throw CConnectionFailed("server in warmup"); } @@ -877,8 +877,8 @@ static void ParseResult(const UniValue& result, std::string& strPrint) static void ParseError(const UniValue& error, std::string& strPrint, int& nRet) { if (error.isObject()) { - const UniValue& err_code = find_value(error, "code"); - const UniValue& err_msg = find_value(error, "message"); + const UniValue& err_code = error.find_value("code"); + const UniValue& err_msg = error.find_value("message"); if (!err_code.isNull()) { strPrint = "error code: " + err_code.getValStr() + "\n"; } @@ -904,15 +904,15 @@ static void GetWalletBalances(UniValue& result) { DefaultRequestHandler rh; const UniValue listwallets = ConnectAndCallRPC(&rh, "listwallets", /* args=*/{}); - if (!find_value(listwallets, "error").isNull()) return; - const UniValue& wallets = find_value(listwallets, "result"); + if (!listwallets.find_value("error").isNull()) return; + const UniValue& wallets = listwallets.find_value("result"); if (wallets.size() <= 1) return; UniValue balances(UniValue::VOBJ); for (const UniValue& wallet : wallets.getValues()) { const std::string wallet_name = wallet.get_str(); const UniValue getbalances = ConnectAndCallRPC(&rh, "getbalances", /* args=*/{}, wallet_name); - const UniValue& balance = find_value(getbalances, "result")["mine"]["trusted"]; + const UniValue& balance = getbalances.find_value("result")["mine"]["trusted"]; balances.pushKV(wallet_name, balance); } result.pushKV("balances", balances); @@ -948,7 +948,7 @@ static void GetProgressBar(double progress, std::string& progress_bar) */ static void ParseGetInfoResult(UniValue& result) { - if (!find_value(result, "error").isNull()) return; + if (!result.find_value("error").isNull()) return; std::string RESET, GREEN, BLUE, YELLOW, MAGENTA, CYAN; bool should_colorize = false; @@ -1157,9 +1157,9 @@ static int CommandLineRPC(int argc, char *argv[]) rh.reset(new NetinfoRequestHandler()); } else if (gArgs.GetBoolArg("-generate", false)) { const UniValue getnewaddress{GetNewAddress()}; - const UniValue& error{find_value(getnewaddress, "error")}; + const UniValue& error{getnewaddress.find_value("error")}; if (error.isNull()) { - SetGenerateToAddressArgs(find_value(getnewaddress, "result").get_str(), args); + SetGenerateToAddressArgs(getnewaddress.find_value("result").get_str(), args); rh.reset(new GenerateToAddressRequestHandler()); } else { ParseError(error, strPrint, nRet); @@ -1181,8 +1181,8 @@ static int CommandLineRPC(int argc, char *argv[]) const UniValue reply = ConnectAndCallRPC(rh.get(), method, args, wallet_name); // Parse reply - UniValue result = find_value(reply, "result"); - const UniValue& error = find_value(reply, "error"); + UniValue result = reply.find_value("result"); + const UniValue& error = reply.find_value("error"); if (error.isNull()) { if (gArgs.GetBoolArg("-getinfo", false)) { if (!gArgs.IsArgSet("-rpcwallet")) { diff --git a/src/external_signer.cpp b/src/external_signer.cpp index 75070899c6a..a16e2e6afc4 100644 --- a/src/external_signer.cpp +++ b/src/external_signer.cpp @@ -30,7 +30,7 @@ bool ExternalSigner::Enumerate(const std::string& command, std::vector +class HashedSourceWriter : public CHashWriter +{ +private: + Source& m_source; + +public: + explicit HashedSourceWriter(Source& source LIFETIMEBOUND) : CHashWriter{source.GetType(), source.GetVersion()}, m_source{source} {} + + void write(Span src) + { + m_source.write(src); + CHashWriter::write(src); + } + + template + HashedSourceWriter& operator<<(const T& obj) + { + ::Serialize(*this, obj); + return *this; + } +}; + /** Compute the 256-bit hash of an object's serialization, with optional sighash byte. */ template uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 5d0b59f7cb7..2f5493ed420 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -79,7 +79,7 @@ static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const Uni { // Send error reply from json-rpc error object int nStatus = HTTP_INTERNAL_SERVER_ERROR; - int code = find_value(objError, "code").get_int(); + int code = objError.find_value("code").get_int(); if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST; @@ -213,7 +213,7 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req) } else { const UniValue& request = valRequest[reqIdx].get_obj(); // Parse method - std::string strMethod = find_value(request, "method").get_str(); + std::string strMethod = request.find_value("method").get_str(); if (!g_rpc_whitelist[jreq.authUser].count(strMethod)) { LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, strMethod); req->WriteReply(HTTP_FORBIDDEN); diff --git a/src/mainchainrpc.cpp b/src/mainchainrpc.cpp index 8ac0605f9ba..f6bcbc9bb6c 100644 --- a/src/mainchainrpc.cpp +++ b/src/mainchainrpc.cpp @@ -158,18 +158,18 @@ bool IsConfirmedBitcoinBlock(const uint256& hash, const int nMinConfirmationDept UniValue params(UniValue::VARR); params.push_back(hash.GetHex()); UniValue reply = CallMainChainRPC("getblockheader", params); - UniValue errval = find_value(reply, "error"); + UniValue errval = reply.find_value("error"); if (!errval.isNull()) { LogPrintf("WARNING: Got error reply from bitcoind getblockheader: %s\n", errval.write()); return false; } - UniValue result = find_value(reply, "result"); + UniValue result = reply.find_value("result"); if (!result.isObject()) { LogPrintf("ERROR: bitcoind getblockheader result was malformed (not object): %s\n", result.write()); return false; } - UniValue confirmations = find_value(result.get_obj(), "confirmations"); + UniValue confirmations = result.get_obj().find_value("confirmations"); if (!confirmations.isNum() || confirmations.get_int64() < nMinConfirmationDepth) { LogPrintf("Insufficient confirmations (got %s, need at least %d).\n", confirmations.write(), nMinConfirmationDepth); return false; @@ -177,7 +177,7 @@ bool IsConfirmedBitcoinBlock(const uint256& hash, const int nMinConfirmationDept // Only perform extra test if nbTxs has been provided (non-zero). if (nbTxs != 0) { - UniValue nTx = find_value(result.get_obj(), "nTx"); + UniValue nTx = result.get_obj().find_value("nTx"); if (!nTx.isNum() || nTx.get_int64() != nbTxs) { LogPrintf("ERROR: Invalid number of transactions in merkle block for %s (got %s, need exactly %d)\n", hash.GetHex(), nTx.write(), nbTxs); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 9fd3b8b6fe6..b22d25d5072 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -257,7 +257,7 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes subelement = lastResult[parsed.value()]; } else if (lastResult.isObject()) - subelement = find_value(lastResult, curarg); + subelement = lastResult.find_value( curarg); else throw std::runtime_error("Invalid result query"); //no array or object: abort lastResult = subelement; @@ -456,8 +456,8 @@ void RPCExecutor::request(const QString &command, const WalletModel* wallet_mode { try // Nice formatting for standard-format error { - int code = find_value(objError, "code").get_int(); - std::string message = find_value(objError, "message").get_str(); + int code = objError.find_value("code").get_int(); + std::string message = objError.find_value("message").get_str(); Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); } catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index dd5ae4af44b..fce1395e10a 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -646,7 +646,7 @@ static RPCHelpMan getblocktemplate() if (!request.params[0].isNull()) { const UniValue& oparam = request.params[0].get_obj(); - const UniValue& modeval = find_value(oparam, "mode"); + const UniValue& modeval = oparam.find_value("mode"); if (modeval.isStr()) strMode = modeval.get_str(); else if (modeval.isNull()) @@ -655,11 +655,11 @@ static RPCHelpMan getblocktemplate() } else throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); - lpval = find_value(oparam, "longpollid"); + lpval = oparam.find_value("longpollid"); if (strMode == "proposal") { - const UniValue& dataval = find_value(oparam, "data"); + const UniValue& dataval = oparam.find_value("data"); if (!dataval.isStr()) throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); @@ -686,7 +686,7 @@ static RPCHelpMan getblocktemplate() return BIP22ValidationResult(state); } - const UniValue& aClientRules = find_value(oparam, "rules"); + const UniValue& aClientRules = oparam.find_value("rules"); if (aClientRules.isArray()) { for (unsigned int i = 0; i < aClientRules.size(); ++i) { const UniValue& v = aClientRules[i]; @@ -694,7 +694,7 @@ static RPCHelpMan getblocktemplate() } } else { // NOTE: It is important that this NOT be read if versionbits is supported - const UniValue& uvMaxVersion = find_value(oparam, "maxversion"); + const UniValue& uvMaxVersion = oparam.find_value("maxversion"); if (uvMaxVersion.isNum()) { nMaxVersionPreVB = uvMaxVersion.get_int64(); } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index d1497c19c1e..609d107c43b 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -2166,7 +2166,7 @@ static RPCHelpMan createpsbt() std::set new_reissuance; for (unsigned int i = 0; i < rawTx.vin.size(); ++i) { if (!rawTx.vin[i].assetIssuance.IsNull()) { - const UniValue& blind_reissuance_v = find_value(request.params[0].get_array()[i].get_obj(), "blind_reissuance"); + const UniValue& blind_reissuance_v = request.params[0].get_array()[i].get_obj().find_value("blind_reissuance"); bool blind_reissuance = blind_reissuance_v.isNull() ? true : blind_reissuance_v.get_bool(); uint256 entropy; CAsset asset; diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index 56a472a44c5..f4d61bb2835 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -175,7 +175,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal uint256 txid = ParseHashO(o, "txid"); - const UniValue& vout_v = find_value(o, "vout"); + const UniValue& vout_v = o.find_value("vout"); if (!vout_v.isNum()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); int nOutput = vout_v.get_int(); @@ -192,7 +192,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal } // set the sequence number if passed in the parameters object - const UniValue& sequenceObj = find_value(o, "sequence"); + const UniValue& sequenceObj = o.find_value("sequence"); if (sequenceObj.isNum()) { int64_t seqNr64 = sequenceObj.get_int64(); if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL) { @@ -205,11 +205,11 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence); // Get issuance stuff if it's there - const UniValue& blinding_nonce_v = find_value(o, "asset_blinding_nonce"); - const UniValue& entropy_v = find_value(o, "asset_entropy"); - const UniValue& amount_v = find_value(o, "issuance_amount"); - const UniValue& issuance_tokens_v = find_value(o, "issuance_tokens"); - const UniValue& blind_reissuance_v = find_value(o, "blind_reissuance"); + const UniValue& blinding_nonce_v = o.find_value("asset_blinding_nonce"); + const UniValue& entropy_v = o.find_value("asset_entropy"); + const UniValue& amount_v = o.find_value("issuance_amount"); + const UniValue& issuance_tokens_v = o.find_value("issuance_tokens"); + const UniValue& blind_reissuance_v = o.find_value("blind_reissuance"); if (!amount_v.isNull() && allow_issuance) { if (!amount_v.isNum()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "issuance_amount is not a number"); @@ -242,9 +242,9 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal rawTx.vin.push_back(in); // Get the pegin stuff if it's there - const UniValue& pegin_tx = find_value(o, "pegin_bitcoin_tx"); - const UniValue& pegin_tx_proof = find_value(o, "pegin_txout_proof"); - const UniValue& pegin_script = find_value(o, "pegin_claim_script"); + const UniValue& pegin_tx = o.find_value("pegin_bitcoin_tx"); + const UniValue& pegin_tx_proof = o.find_value("pegin_txout_proof"); + const UniValue& pegin_script = o.find_value("pegin_claim_script"); if (!pegin_tx.isNull() && !pegin_tx_proof.isNull() && !pegin_script.isNull() && allow_peg_in) { if (!IsHex(pegin_script.get_str())) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Given claim_script is not hex."); @@ -335,7 +335,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal out.nAsset = CAsset(ParseHashO(output, name_)); } else if (name_ == "blinder_index") { // For PSET - psbt_out.m_blinder_index = find_value(output, name_).get_int(); + psbt_out.m_blinder_index = output.find_value(name_).get_int(); } else { CTxDestination destination = DecodeDestination(name_); if (!IsValidDestination(destination)) { @@ -429,7 +429,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst uint256 txid = ParseHashO(prevOut, "txid"); - int nOut = find_value(prevOut, "vout").get_int(); + int nOut = prevOut.find_value("vout").get_int(); if (nOut < 0) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout cannot be negative"); } @@ -450,7 +450,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst newcoin.out.scriptPubKey = scriptPubKey; newcoin.out.nValue = CConfidentialValue(MAX_MONEY); if (prevOut.exists("amount")) { - newcoin.out.nValue = CConfidentialValue(AmountFromValue(find_value(prevOut, "amount"))); + newcoin.out.nValue = CConfidentialValue(AmountFromValue(prevOut.find_value("amount"))); } else if (prevOut.exists("amountcommitment")) { // Segwit sigs require the amount commitment to be sighashed newcoin.out.nValue.vchCommitment = ParseHexO(prevOut, "amountcommitment"); @@ -468,8 +468,8 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst {"redeemScript", UniValueType(UniValue::VSTR)}, {"witnessScript", UniValueType(UniValue::VSTR)}, }, true); - UniValue rs = find_value(prevOut, "redeemScript"); - UniValue ws = find_value(prevOut, "witnessScript"); + UniValue rs = prevOut.find_value("redeemScript"); + UniValue ws = prevOut.find_value("witnessScript"); if (rs.isNull() && ws.isNull()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing redeemScript/witnessScript"); } diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp index f332eaa46b0..90ff4b995ca 100644 --- a/src/rpc/request.cpp +++ b/src/rpc/request.cpp @@ -202,10 +202,10 @@ void JSONRPCRequest::parse(const UniValue& valRequest) const UniValue& request = valRequest.get_obj(); // Parse id now so errors from here on will have the id - id = find_value(request, "id"); + id = request.find_value("id"); // Parse method - UniValue valMethod = find_value(request, "method"); + UniValue valMethod = request.find_value("method"); if (valMethod.isNull()) throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method"); if (!valMethod.isStr()) @@ -218,7 +218,7 @@ void JSONRPCRequest::parse(const UniValue& valRequest) LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser); // Parse params - UniValue valParams = find_value(request, "params"); + UniValue valParams = request.find_value("params"); if (valParams.isArray() || valParams.isObject()) params = valParams; else if (valParams.isNull()) diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 71e896951c4..149f9ff85a1 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -66,7 +66,7 @@ void RPCTypeCheckObj(const UniValue& o, bool fStrict) { for (const auto& t : typesExpected) { - const UniValue& v = find_value(o, t.first); + const UniValue& v = o.find_value(t.first); if (!fAllowNull && v.isNull()) throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first)); @@ -113,7 +113,7 @@ uint256 ParseHashV(const UniValue& v, std::string strName) } uint256 ParseHashO(const UniValue& o, std::string strKey) { - return ParseHashV(find_value(o, strKey), strKey); + return ParseHashV(o.find_value(strKey), strKey); } std::vector ParseHexV(const UniValue& v, std::string strName) { @@ -126,7 +126,7 @@ std::vector ParseHexV(const UniValue& v, std::string strName) } std::vector ParseHexO(const UniValue& o, std::string strKey) { - return ParseHexV(find_value(o, strKey), strKey); + return ParseHexV(o.find_value(strKey), strKey); } namespace { @@ -1032,10 +1032,10 @@ std::vector EvalDescriptorStringOrObject(const UniValue& scanobject, Fl if (scanobject.isStr()) { desc_str = scanobject.get_str(); } else if (scanobject.isObject()) { - UniValue desc_uni = find_value(scanobject, "desc"); + UniValue desc_uni = scanobject.find_value("desc"); if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object"); desc_str = desc_uni.get_str(); - UniValue range_uni = find_value(scanobject, "range"); + UniValue range_uni = scanobject.find_value("range"); if (!range_uni.isNull()) { range = ParseDescriptorRange(range_uni); } diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp index 150616d79b2..4cddc89d6d4 100644 --- a/src/test/fuzz/rpc.cpp +++ b/src/test/fuzz/rpc.cpp @@ -382,7 +382,7 @@ FUZZ_TARGET_INIT(rpc, initialize_rpc) try { rpc_testing_setup->CallRPC(rpc_command, arguments); } catch (const UniValue& json_rpc_error) { - const std::string error_msg{find_value(json_rpc_error, "message").get_str()}; + const std::string error_msg{json_rpc_error.find_value( "message").get_str()}; // Once c++20 is allowed, starts_with can be used. // if (error_msg.starts_with("Internal bug detected")) { if (0 == error_msg.rfind("Internal bug detected", 0)) { diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp index b06157e99f9..30eb45f2680 100644 --- a/src/test/key_io_tests.cpp +++ b/src/test/key_io_tests.cpp @@ -37,11 +37,11 @@ BOOST_AUTO_TEST_CASE(key_io_valid_parse) std::string exp_base58string = test[0].get_str(); std::vector exp_payload = ParseHex(test[1].get_str()); const UniValue &metadata = test[2].get_obj(); - bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); - SelectParams(find_value(metadata, "chain").get_str()); - bool try_case_flip = find_value(metadata, "tryCaseFlip").isNull() ? false : find_value(metadata, "tryCaseFlip").get_bool(); + bool isPrivkey = metadata.find_value( "isPrivkey").get_bool(); + SelectParams(metadata.find_value( "chain").get_str()); + bool try_case_flip = metadata.find_value( "tryCaseFlip").isNull() ? false : metadata.find_value( "tryCaseFlip").get_bool(); if (isPrivkey) { - bool isCompressed = find_value(metadata, "isCompressed").get_bool(); + bool isCompressed = metadata.find_value( "isCompressed").get_bool(); // Must be valid private key privkey = DecodeSecret(exp_base58string); BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest); @@ -96,10 +96,10 @@ BOOST_AUTO_TEST_CASE(key_io_valid_gen) std::string exp_base58string = test[0].get_str(); std::vector exp_payload = ParseHex(test[1].get_str()); const UniValue &metadata = test[2].get_obj(); - bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); - SelectParams(find_value(metadata, "chain").get_str()); + bool isPrivkey = metadata.find_value( "isPrivkey").get_bool(); + SelectParams(metadata.find_value( "chain").get_str()); if (isPrivkey) { - bool isCompressed = find_value(metadata, "isCompressed").get_bool(); + bool isCompressed = metadata.find_value( "isCompressed").get_bool(); CKey key; key.Set(exp_payload.begin(), exp_payload.end(), isCompressed); assert(key.IsValid()); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 2af68839b1d..bb140fede64 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -43,7 +43,7 @@ UniValue RPCTestingSetup::CallRPC(std::string args) return result; } catch (const UniValue& objError) { - throw std::runtime_error(find_value(objError, "message").get_str()); + throw std::runtime_error(objError.find_value("message").get_str()); } } @@ -71,9 +71,9 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams) BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), std::runtime_error); std::string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx)); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 193); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0); + BOOST_CHECK_EQUAL(r.get_obj().find_value( "size").get_int(), 193); + BOOST_CHECK_EQUAL(r.get_obj().find_value( "version").get_int(), 1); + BOOST_CHECK_EQUAL(r.get_obj().find_value( "locktime").get_int(), 0); BOOST_CHECK_THROW(CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" false")); BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" false extra"), std::runtime_error); @@ -90,20 +90,20 @@ BOOST_AUTO_TEST_CASE(rpc_togglenetwork) UniValue r; r = CallRPC("getnetworkinfo"); - bool netState = find_value(r.get_obj(), "networkactive").get_bool(); + bool netState = r.get_obj().find_value( "networkactive").get_bool(); BOOST_CHECK_EQUAL(netState, true); BOOST_CHECK_NO_THROW(CallRPC("setnetworkactive false")); r = CallRPC("getnetworkinfo"); - int numConnection = find_value(r.get_obj(), "connections").get_int(); + int numConnection = r.get_obj().find_value( "connections").get_int(); BOOST_CHECK_EQUAL(numConnection, 0); - netState = find_value(r.get_obj(), "networkactive").get_bool(); + netState = r.get_obj().find_value( "networkactive").get_bool(); BOOST_CHECK_EQUAL(netState, false); BOOST_CHECK_NO_THROW(CallRPC("setnetworkactive true")); r = CallRPC("getnetworkinfo"); - netState = find_value(r.get_obj(), "networkactive").get_bool(); + netState = r.get_obj().find_value( "networkactive").get_bool(); BOOST_CHECK_EQUAL(netState, true); } @@ -121,9 +121,9 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) std::string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\""; std::string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\""; r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" [] "+prevout); - BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false); + BOOST_CHECK(r.get_obj().find_value( "complete").get_bool() == false); r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" ["+privkey1+","+privkey2+"] "+prevout); - BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true); + BOOST_CHECK(r.get_obj().find_value( "complete").get_bool() == true); } BOOST_AUTO_TEST_CASE(rpc_createraw_op_return) @@ -257,7 +257,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); UniValue ar = r.get_array(); UniValue o1 = ar[0].get_obj(); - UniValue adr = find_value(o1, "address"); + UniValue adr = o1.find_value( "address"); BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/32"); BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0 remove"))); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); @@ -268,8 +268,8 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); - adr = find_value(o1, "address"); - int64_t banned_until{find_value(o1, "banned_until").get_int64()}; + adr = o1.find_value( "address"); + int64_t banned_until{o1.find_value( "banned_until").get_int64()}; BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); BOOST_CHECK_EQUAL(banned_until, 9907731200); // absolute time check @@ -283,11 +283,11 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); - adr = find_value(o1, "address"); - banned_until = find_value(o1, "banned_until").get_int64(); - const int64_t ban_created{find_value(o1, "ban_created").get_int64()}; - const int64_t ban_duration{find_value(o1, "ban_duration").get_int64()}; - const int64_t time_remaining{find_value(o1, "time_remaining").get_int64()}; + adr = o1.find_value( "address"); + banned_until = o1.find_value( "banned_until").get_int64(); + const int64_t ban_created{o1.find_value( "ban_created").get_int64()}; + const int64_t ban_duration{o1.find_value( "ban_duration").get_int64()}; + const int64_t time_remaining{o1.find_value( "time_remaining").get_int64()}; BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); BOOST_CHECK_EQUAL(banned_until, time_remaining_expected + now.count()); BOOST_CHECK_EQUAL(ban_duration, banned_until - ban_created); @@ -317,7 +317,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); - adr = find_value(o1, "address"); + adr = o1.find_value( "address"); BOOST_CHECK_EQUAL(adr.get_str(), "fe80::202:b3ff:fe1e:8329/128"); BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); @@ -325,7 +325,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); - adr = find_value(o1, "address"); + adr = o1.find_value( "address"); BOOST_CHECK_EQUAL(adr.get_str(), "2001:db8::/30"); BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); @@ -333,7 +333,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); - adr = find_value(o1, "address"); + adr = o1.find_value( "address"); BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128"); } diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index 0925e2e9ee4..e30ae845ef0 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -441,4 +441,18 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) fs::remove(streams_test_filename); } +BOOST_AUTO_TEST_CASE(streams_hashed) +{ + CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION); + HashedSourceWriter hash_writer{stream}; + const std::string data{"bitcoin"}; + hash_writer << data; + + CHashVerifier hash_verifier{&stream}; + std::string result; + hash_verifier >> result; + BOOST_CHECK_EQUAL(data, result); + BOOST_CHECK_EQUAL(hash_writer.GetHash(), hash_verifier.GetHash()); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp index 3f5353b5a2b..5aaf7742c24 100644 --- a/src/test/system_tests.cpp +++ b/src/test/system_tests.cpp @@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE(run_command) const UniValue result = RunCommandParseJSON("echo \"{\"success\": true}\""); #endif BOOST_CHECK(result.isObject()); - const UniValue& success = find_value(result, "success"); + const UniValue& success = result.find_value("success"); BOOST_CHECK(!success.isNull()); BOOST_CHECK_EQUAL(success.getBool(), true); } @@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(run_command) { const UniValue result = RunCommandParseJSON("cat", "{\"success\": true}"); BOOST_CHECK(result.isObject()); - const UniValue& success = find_value(result, "success"); + const UniValue& success = result.find_value("success"); BOOST_CHECK(!success.isNull()); BOOST_CHECK_EQUAL(success.getBool(), true); } diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index fc5cf402be3..b216d4035b3 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -177,7 +177,7 @@ class UniValue { const UniValue& get_array() const; enum VType type() const { return getType(); } - friend const UniValue& find_value( const UniValue& obj, const std::string& name); + const UniValue& find_value(std::string_view key) const; }; enum jtokentype { @@ -235,6 +235,6 @@ static inline bool json_isspace(int ch) extern const UniValue NullUniValue; -const UniValue& find_value( const UniValue& obj, const std::string& name); +inline const UniValue& find_value(const UniValue& obj, const std::string& name) { return obj.find_value(name); } #endif // __UNIVALUE_H__ diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp index c4e59fae744..0bc58ebd918 100644 --- a/src/univalue/lib/univalue.cpp +++ b/src/univalue/lib/univalue.cpp @@ -233,12 +233,13 @@ const char *uvTypeName(UniValue::VType t) return nullptr; } -const UniValue& find_value(const UniValue& obj, const std::string& name) +const UniValue& UniValue::find_value(std::string_view key) const { - for (unsigned int i = 0; i < obj.keys.size(); i++) - if (obj.keys[i] == name) - return obj.values.at(i); - + for (unsigned int i = 0; i < keys.size(); ++i) { + if (keys[i] == key) { + return values.at(i); + } + } return NullUniValue; } diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index 0068e5819dc..d3102317b5a 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -378,7 +378,7 @@ RPCHelpMan lockunspent() }); const uint256 txid(ParseHashO(o, "txid")); - const int nOutput = find_value(o, "vout").get_int(); + const int nOutput = o.find_value("vout").get_int(); if (nOutput < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); } diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index 0ead021dbbc..022c4f681ba 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -634,7 +634,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, for (const UniValue& input : options["input_weights"].get_array().getValues()) { uint256 txid = ParseHashO(input, "txid"); - const UniValue& vout_v = find_value(input, "vout"); + const UniValue& vout_v = input.find_value("vout"); if (!vout_v.isNum()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); } @@ -643,7 +643,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); } - const UniValue& weight_v = find_value(input, "weight"); + const UniValue& weight_v = input.find_value("weight"); if (!weight_v.isNum()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing weight key"); } @@ -1617,7 +1617,7 @@ RPCHelpMan walletcreatefundedpsbt() std::set new_reissuance; for (unsigned int i = 0; i < rawTx.vin.size(); ++i) { if (!rawTx.vin[i].assetIssuance.IsNull()) { - const UniValue& blind_reissuance_v = find_value(request.params[0].get_array()[i].get_obj(), "blind_reissuance"); + const UniValue& blind_reissuance_v = request.params[0].get_array()[i].get_obj().find_value("blind_reissuance"); bool blind_reissuance = blind_reissuance_v.isNull() ? true : blind_reissuance_v.get_bool(); uint256 entropy; CAsset asset; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0bc17e30fa0..e066716a1a6 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3706,7 +3706,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans() if (!signer_res.isObject()) throw std::runtime_error(std::string(__func__) + ": Unexpected result"); for (bool internal : {false, true}) { - const UniValue& descriptor_vals = find_value(signer_res, internal ? "internal" : "receive"); + const UniValue& descriptor_vals = signer_res.find_value(internal ? "internal" : "receive"); if (!descriptor_vals.isArray()) throw std::runtime_error(std::string(__func__) + ": Unexpected result"); for (const UniValue& desc_val : descriptor_vals.get_array().getValues()) { std::string desc_str = desc_val.getValStr(); diff --git a/test/functional/feature_dynafed.py b/test/functional/feature_dynafed.py index 83fb5fb341d..ba25e7cbd76 100755 --- a/test/functional/feature_dynafed.py +++ b/test/functional/feature_dynafed.py @@ -305,6 +305,7 @@ def test_all_vote(self): assert comb_result["complete"] self.nodes[0].submitblock(comb_result["hex"]) assert_equal(self.nodes[0].getblockcount(), cur_height+11) + self.sync_blocks() def test_transition_mempool_eject(self): self.log.info("Testing mempool (r)ejection policy on transitions...") diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index bdebbda19c3..3885b4ef533 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -88,6 +88,7 @@ BASE_SCRIPTS = [ # Scripts that are run by default. # vv First elements tests vv + 'feature_trim_headers.py', 'example_elements_code_tutorial.py', 'feature_fedpeg.py --legacy-wallet', 'feature_fedpeg.py --pre_transition --legacy-wallet', @@ -114,7 +115,6 @@ 'wallet_elements_regression_1259.py --legacy-wallet', 'wallet_elements_21million.py', 'wallet_elements_dust_relay.py', - 'feature_trim_headers.py', # Longest test should go first, to favor running tests in parallel 'wallet_hd.py --legacy-wallet', 'wallet_hd.py --descriptors',