diff options
36 files changed, 127 insertions, 57 deletions
diff --git a/build_msvc/common.init.vcxproj.in b/build_msvc/common.init.vcxproj.in index ff3b390d0e..7f623c6296 100644 --- a/build_msvc/common.init.vcxproj.in +++ b/build_msvc/common.init.vcxproj.in @@ -90,7 +90,7 @@ <AdditionalOptions>/utf-8 /Zc:__cplusplus /std:c++20 %(AdditionalOptions)</AdditionalOptions> <DisableSpecificWarnings>4018;4244;4267;4334;4715;4805;4834</DisableSpecificWarnings> <TreatWarningAsError>true</TreatWarningAsError> - <PreprocessorDefinitions>_SILENCE_CXX20_U8PATH_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;ZMQ_STATIC;NOMINMAX;WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;_WIN32_WINNT=0x0601;_WIN32_IE=0x0501;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;ZMQ_STATIC;NOMINMAX;WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;_WIN32_WINNT=0x0601;_WIN32_IE=0x0501;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>..\..\src;..\..\src\minisketch\include;..\..\src\univalue\include;..\..\src\secp256k1\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> diff --git a/configure.ac b/configure.ac index 713b8a1ab9..1752fda344 100644 --- a/configure.ac +++ b/configure.ac @@ -519,7 +519,7 @@ if test "$enable_clmul" = "yes"; then fi TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$CXXFLAGS $SSE42_CXXFLAGS" +CXXFLAGS="$SSE42_CXXFLAGS $CXXFLAGS" AC_MSG_CHECKING([for SSE4.2 intrinsics]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdint.h> @@ -541,7 +541,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ CXXFLAGS="$TEMP_CXXFLAGS" TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$CXXFLAGS $SSE41_CXXFLAGS" +CXXFLAGS="$SSE41_CXXFLAGS $CXXFLAGS" AC_MSG_CHECKING([for SSE4.1 intrinsics]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdint.h> @@ -556,7 +556,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ CXXFLAGS="$TEMP_CXXFLAGS" TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$CXXFLAGS $AVX2_CXXFLAGS" +CXXFLAGS="$AVX2_CXXFLAGS $CXXFLAGS" AC_MSG_CHECKING([for AVX2 intrinsics]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdint.h> @@ -571,7 +571,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ CXXFLAGS="$TEMP_CXXFLAGS" TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$CXXFLAGS $X86_SHANI_CXXFLAGS" +CXXFLAGS="$X86_SHANI_CXXFLAGS $CXXFLAGS" AC_MSG_CHECKING([for x86 SHA-NI intrinsics]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdint.h> @@ -592,7 +592,7 @@ AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_CRC_CXXFLAGS="-march=arm AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_SHANI_CXXFLAGS="-march=armv8-a+crc+crypto"], [], [$CXXFLAG_WERROR]) TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$CXXFLAGS $ARM_CRC_CXXFLAGS" +CXXFLAGS="$ARM_CRC_CXXFLAGS $CXXFLAGS" AC_MSG_CHECKING([for ARMv8 CRC32 intrinsics]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <arm_acle.h> @@ -611,7 +611,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ CXXFLAGS="$TEMP_CXXFLAGS" TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$CXXFLAGS $ARM_SHANI_CXXFLAGS" +CXXFLAGS="$ARM_SHANI_CXXFLAGS $CXXFLAGS" AC_MSG_CHECKING([for ARMv8 SHA-NI intrinsics]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <arm_acle.h> diff --git a/src/.clang-tidy b/src/.clang-tidy index b9371b147b..f59f80f8ce 100644 --- a/src/.clang-tidy +++ b/src/.clang-tidy @@ -4,6 +4,8 @@ bugprone-argument-comment, misc-unused-using-decls, modernize-use-default-member-init, modernize-use-nullptr, +performance-for-range-copy, +performance-unnecessary-copy-initialization, readability-redundant-declaration, readability-redundant-string-init, ' @@ -12,6 +14,8 @@ bugprone-argument-comment, misc-unused-using-decls, modernize-use-default-member-init, modernize-use-nullptr, +performance-for-range-copy, +performance-unnecessary-copy-initialization, readability-redundant-declaration, readability-redundant-string-init, ' diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 6ce4e05e4d..e64e2202ba 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -911,7 +911,7 @@ static void GetWalletBalances(UniValue& result) UniValue balances(UniValue::VOBJ); for (const UniValue& wallet : wallets.getValues()) { - const std::string wallet_name = wallet.get_str(); + 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"]; balances.pushKV(wallet_name, balance); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index b006353cb0..c2bb89b8cf 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -596,7 +596,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) UniValue prevtxsObj = registers["prevtxs"]; { for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) { - UniValue prevOut = prevtxsObj[previdx]; + const UniValue& prevOut = prevtxsObj[previdx]; if (!prevOut.isObject()) throw std::runtime_error("expected prevtxs internal object"); diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp index 0ff79bb3ca..43d88df720 100644 --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -169,7 +169,7 @@ const std::set<BlockFilterType>& AllBlockFilterTypes() static std::once_flag flag; std::call_once(flag, []() { - for (auto entry : g_filter_types) { + for (const auto& entry : g_filter_types) { types.insert(entry.first); } }); @@ -185,7 +185,7 @@ const std::string& ListBlockFilterTypes() std::call_once(flag, []() { std::stringstream ret; bool first = true; - for (auto entry : g_filter_types) { + for (const auto& entry : g_filter_types) { if (!first) ret << ", "; ret << entry.second; first = false; diff --git a/src/coins.cpp b/src/coins.cpp index 1753d33b71..5983a8a39f 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -296,7 +296,7 @@ bool CCoinsViewErrorCatcher::GetCoin(const COutPoint &outpoint, Coin &coin) cons try { return CCoinsViewBacked::GetCoin(outpoint, coin); } catch(const std::runtime_error& e) { - for (auto f : m_err_callbacks) { + for (const auto& f : m_err_callbacks) { f(); } LogPrintf("Error reading from database: %s\n", e.what()); diff --git a/src/core_read.cpp b/src/core_read.cpp index 77c516427a..ec21a2f7f4 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -265,7 +265,7 @@ int ParseSighashString(const UniValue& sighash) {std::string("SINGLE"), int(SIGHASH_SINGLE)}, {std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)}, }; - std::string strHashType = sighash.get_str(); + const std::string& strHashType = sighash.get_str(); const auto& it = map_sighash_values.find(strHashType); if (it != map_sighash_values.end()) { hash_type = it->second; diff --git a/src/external_signer.cpp b/src/external_signer.cpp index 6bab0a856c..094314e878 100644 --- a/src/external_signer.cpp +++ b/src/external_signer.cpp @@ -28,7 +28,7 @@ bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalS if (!result.isArray()) { throw std::runtime_error(strprintf("'%s' received invalid response, expected array of signers", command)); } - for (UniValue signer : result.getValues()) { + for (const UniValue& signer : result.getValues()) { // Check for error const UniValue& error = find_value(signer, "error"); if (!error.isNull()) { @@ -69,7 +69,11 @@ public: static inline path u8path(const std::string& utf8_str) { +#if __cplusplus < 202002L return std::filesystem::u8path(utf8_str); +#else + return std::filesystem::path(std::u8string{utf8_str.begin(), utf8_str.end()}); +#endif } // Disallow implicit std::string conversion for absolute to avoid diff --git a/src/init.cpp b/src/init.cpp index 488c754e95..480b8c7705 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1046,7 +1046,7 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb static bool LockDataDirectory(bool probeOnly) { // Make sure only a single Bitcoin process is using the data directory. - fs::path datadir = gArgs.GetDataDirNet(); + const fs::path& datadir = gArgs.GetDataDirNet(); if (!DirIsWritable(datadir)) { return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir))); } diff --git a/src/logging.cpp b/src/logging.cpp index 1e2c1d5a77..73c4e458bd 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -364,7 +364,7 @@ void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& loggi } if (m_log_threadnames && m_started_new_line) { - const auto threadname = util::ThreadGetInternalName(); + const auto& threadname = util::ThreadGetInternalName(); str_prefixed.insert(0, "[" + (threadname.empty() ? "unknown" : threadname) + "] "); } diff --git a/src/netbase.cpp b/src/netbase.cpp index 4b8d2f8d0c..a5f7bda875 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -387,7 +387,7 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a return error("Error sending to proxy"); } uint8_t pchRet1[2]; - if ((recvr = InterruptibleRecv(pchRet1, 2, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { + if (InterruptibleRecv(pchRet1, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port); return false; } @@ -410,7 +410,7 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a } LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); uint8_t pchRetA[2]; - if ((recvr = InterruptibleRecv(pchRetA, 2, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { + if (InterruptibleRecv(pchRetA, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { return error("Error reading proxy authentication response"); } if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) { @@ -476,7 +476,7 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a if (recvr != IntrRecvError::OK) { return error("Error reading from proxy"); } - if ((recvr = InterruptibleRecv(pchRet3, 2, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { + if (InterruptibleRecv(pchRet3, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { return error("Error reading from proxy"); } LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest); diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 601d0bdf58..42b6b017fe 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -415,7 +415,7 @@ void CleanupBlockRevFiles() // Remove the rev files immediately and insert the blk file paths into an // ordered map keyed by block file index. LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n"); - fs::path blocksdir = gArgs.GetBlocksDirPath(); + const fs::path& blocksdir = gArgs.GetBlocksDirPath(); for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) { const std::string path = fs::PathToString(it->path().filename()); if (fs::is_regular_file(*it) && diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index a4dfffa387..bf04a6dd5f 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -44,7 +44,7 @@ SplashScreen::SplashScreen(const NetworkStyle* networkStyle) QString titleText = PACKAGE_NAME; QString versionText = QString("Version %1").arg(QString::fromStdString(FormatFullVersion())); QString copyrightText = QString::fromUtf8(CopyrightHolders(strprintf("\xc2\xA9 %u-%u ", 2009, COPYRIGHT_YEAR)).c_str()); - QString titleAddText = networkStyle->getTitleAddText(); + const QString& titleAddText = networkStyle->getTitleAddText(); QString font = QApplication::font().toString(); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index e9663d38b4..91feb2c24b 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -679,7 +679,7 @@ static RPCHelpMan getblocktemplate() if (lpval.isStr()) { // Format: <hashBestChain><nTransactionsUpdatedLast> - std::string lpstr = lpval.get_str(); + const std::string& lpstr = lpval.get_str(); hashWatchedChain = ParseHashV(lpstr.substr(0, 64), "longpollid"); nTransactionsUpdatedLastLP = LocaleIndependentAtoi<int64_t>(lpstr.substr(64)); diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index b06e9f6e4b..b078ee8b29 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -160,14 +160,14 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std:: void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins) { if (!prevTxsUnival.isNull()) { - UniValue prevTxs = prevTxsUnival.get_array(); + const UniValue& prevTxs = prevTxsUnival.get_array(); for (unsigned int idx = 0; idx < prevTxs.size(); ++idx) { const UniValue& p = prevTxs[idx]; if (!p.isObject()) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); } - UniValue prevOut = p.get_obj(); + const UniValue& prevOut = p.get_obj(); RPCTypeCheckObj(prevOut, { diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 7517f64ea1..24ab21a947 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -98,7 +98,7 @@ CAmount AmountFromValue(const UniValue& value, int decimals) uint256 ParseHashV(const UniValue& v, std::string strName) { - std::string strHex(v.get_str()); + const std::string& strHex(v.get_str()); if (64 != strHex.length()) throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", strName, 64, strHex.length(), strHex)); if (!IsHex(strHex)) // Note: IsHex("") is false diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 8ace9c3136..434e106dad 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -1472,6 +1472,10 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const } if (ctx == ParseScriptContext::TOP && Func("rawtr", expr)) { auto arg = Expr(expr); + if (expr.size()) { + error = strprintf("rawtr(): only one key expected."); + return nullptr; + } auto output_key = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error); if (!output_key) return nullptr; ++key_exp_index; diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 00f32ddcee..249f89ae2f 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58) { UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode))); for (unsigned int idx = 0; idx < tests.size(); idx++) { - UniValue test = tests[idx]; + const UniValue& test = tests[idx]; std::string strTest = test.write(); if (test.size() < 2) // Allow for extra stuff (useful for comments) { @@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58) std::vector<unsigned char> result; for (unsigned int idx = 0; idx < tests.size(); idx++) { - UniValue test = tests[idx]; + const UniValue& test = tests[idx]; std::string strTest = test.write(); if (test.size() < 2) // Allow for extra stuff (useful for comments) { diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp index 178757e7b4..0831188327 100644 --- a/src/test/blockfilter_tests.cpp +++ b/src/test/blockfilter_tests.cpp @@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test) const UniValue& tests = json.get_array(); for (unsigned int i = 0; i < tests.size(); i++) { - UniValue test = tests[i]; + const UniValue& test = tests[i]; std::string strTest = test.write(); if (test.size() == 1) { diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index d9503d7624..d0ad037228 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -464,6 +464,31 @@ Check("sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGN CheckUnparsable("", "raw(asdf)", "Raw script is not hex"); // Invalid script CheckUnparsable("", "raw(Ü)#00000000", "Invalid characters in payload"); // Invalid chars + Check( + "rawtr(xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/86'/1'/0'/1/*)#a5gn3t7k", + "rawtr(xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/86'/1'/0'/1/*)#4ur3xhft", + "", + "rawtr([5a61ff8e/86'/1'/0']xpub6DtZpc9PRL2B6pwoNGysmHAaBofDmWv5S6KQEKKGPKhf5fV62ywDtSziSApYVK3JnYY5KUSgiCwiXW5wtd8z7LNBxT9Mu5sEro8itdGfTeA/1/*)#llheyd9x", + RANGE | HARDENED | XONLY_KEYS, + {{"51205172af752f057d543ce8e4a6f8dcf15548ec6be44041bfa93b72e191cfc8c1ee"}, {"51201b66f20b86f700c945ecb9ad9b0ad1662b73084e2bfea48bee02126350b8a5b1"}, {"512063e70f66d815218abcc2306aa930aaca07c5cde73b75127eb27b5e8c16b58a25"}}, + OutputType::BECH32M, + {{0x80000056, 0x80000001, 0x80000000, 1, 0}, {0x80000056, 0x80000001, 0x80000000, 1, 1}, {0x80000056, 0x80000001, 0x80000000, 1, 2}}); + + + Check( + "rawtr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", + "rawtr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", + "rawtr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", + "rawtr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", + SIGNABLE | XONLY_KEYS, + {{"5120a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd"}}, + OutputType::BECH32M); + + CheckUnparsable( + "", + "rawtr(xpub68FQ9imX6mCWacw6eNRjaa8q8ynnHmUd5i7MVR51ZMPP5JycyfVHSLQVFPHMYiTybWJnSBL2tCBpy6aJTR2DYrshWYfwAxs8SosGXd66d8/*, xpub69Mvq3QMipdvnd9hAyeTnT5jrkcBuLErV212nsGf3qr7JPWysc9HnNhCsazdzj1etSx28hPSE8D7DnceFbNdw4Kg8SyRfjE2HFLv1P8TSGc/*)", + "rawtr(): only one key expected."); + // A 2of4 but using a direct push rather than OP_2 CScript nonminimalmultisig; CKey keys[4]; diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp index e70b8b3dfd..1eac68de14 100644 --- a/src/test/key_io_tests.cpp +++ b/src/test/key_io_tests.cpp @@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE(key_io_valid_parse) SelectParams(CBaseChainParams::MAIN); for (unsigned int idx = 0; idx < tests.size(); idx++) { - UniValue test = tests[idx]; + const UniValue& test = tests[idx]; std::string strTest = test.write(); if (test.size() < 3) { // Allow for extra stuff (useful for comments) BOOST_ERROR("Bad test: " << strTest); @@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(key_io_valid_gen) UniValue tests = read_json(std::string(json_tests::key_io_valid, json_tests::key_io_valid + sizeof(json_tests::key_io_valid))); for (unsigned int idx = 0; idx < tests.size(); idx++) { - UniValue test = tests[idx]; + const UniValue& test = tests[idx]; std::string strTest = test.write(); if (test.size() < 3) // Allow for extra stuff (useful for comments) { @@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(key_io_invalid) CTxDestination destination; for (unsigned int idx = 0; idx < tests.size(); idx++) { - UniValue test = tests[idx]; + const UniValue& test = tests[idx]; std::string strTest = test.write(); if (test.size() < 1) // Allow for extra stuff (useful for comments) { diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 9e7a376d6b..935194057c 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -942,7 +942,7 @@ BOOST_AUTO_TEST_CASE(script_json_test) UniValue tests = read_json(std::string(json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); for (unsigned int idx = 0; idx < tests.size(); idx++) { - UniValue test = tests[idx]; + const UniValue& test = tests[idx]; std::string strTest = test.write(); CScriptWitness witness; CAmount nValue = 0; diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 7376f2ff5c..514798d8fa 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data) UniValue tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash))); for (unsigned int idx = 0; idx < tests.size(); idx++) { - UniValue test = tests[idx]; + const UniValue& test = tests[idx]; std::string strTest = test.write(); if (test.size() < 1) // Allow for extra stuff (useful for comments) { diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index cd6bf11327..952598f745 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); for (unsigned int idx = 0; idx < tests.size(); idx++) { - UniValue test = tests[idx]; + const UniValue& test = tests[idx]; std::string strTest = test.write(); if (test[0].isArray()) { @@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) fValid = false; break; } - UniValue vinput = input.get_array(); + const UniValue& vinput = input.get_array(); if (vinput.size() < 3 || vinput.size() > 4) { fValid = false; @@ -282,7 +282,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) UniValue tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid))); for (unsigned int idx = 0; idx < tests.size(); idx++) { - UniValue test = tests[idx]; + const UniValue& test = tests[idx]; std::string strTest = test.write(); if (test[0].isArray()) { @@ -302,7 +302,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) fValid = false; break; } - UniValue vinput = input.get_array(); + const UniValue& vinput = input.get_array(); if (vinput.size() < 3 || vinput.size() > 4) { fValid = false; diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 7a82e1a736..1c5ca18759 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -183,7 +183,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering) } // to make sure that eventually we process the full chain - do it here - for (auto block : blocks) { + for (const auto& block : blocks) { if (block->vtx.size() == 1) { bool processed = Assert(m_node.chainman)->ProcessNewBlock(block, true, &ignored); assert(processed); diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index 60715ff3c8..deb1293cd4 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -432,7 +432,7 @@ void BerkeleyEnvironment::ReloadDbEnv() }); std::vector<fs::path> filenames; - for (auto it : m_databases) { + for (const auto& it : m_databases) { filenames.push_back(it.first); } // Close the individual Db's diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index db169aad12..7fbf2ff8cf 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -416,7 +416,7 @@ std::set< std::set<CTxDestination> > GetAddressGroupings(const CWallet& wallet) std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it - for (std::set<CTxDestination> _grouping : groupings) + for (const std::set<CTxDestination>& _grouping : groupings) { // make a set of all the groups hit by this new group std::set< std::set<CTxDestination>* > hits; diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index 8bbb862a7b..c6e7588fb4 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -1407,7 +1407,7 @@ RPCHelpMan sendall() } CAmount output_amounts_claimed{0}; - for (CTxOut out : rawTx.vout) { + for (const CTxOut& out : rawTx.vout) { output_amounts_claimed += out.nValue; } diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 8d40846332..40d5ecd755 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1788,7 +1788,7 @@ std::map<CKeyID, CKey> DescriptorScriptPubKeyMan::GetKeys() const AssertLockHeld(cs_desc_man); if (m_storage.HasEncryptionKeys() && !m_storage.IsLocked()) { KeyMap keys; - for (auto key_pair : m_map_crypted_keys) { + for (const auto& key_pair : m_map_crypted_keys) { const CPubKey& pubkey = key_pair.second.first; const std::vector<unsigned char>& crypted_secret = key_pair.second.second; CKey key; diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index d6362c1f14..001acd04e2 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -569,8 +569,12 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a if (!coin_control.GetExternalOutput(outpoint, txout)) { return std::nullopt; } + } + + if (input_bytes == -1) { input_bytes = CalculateMaximumSignedInputSize(txout, outpoint, &coin_control.m_external_provider, &coin_control); } + // If available, override calculated size with coin control specified size if (coin_control.HasInputWeight(outpoint)) { input_bytes = GetVirtualTransactionSize(coin_control.GetInputWeight(outpoint), 0, 0); @@ -1127,12 +1131,16 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet, wallet.chain().findCoins(coins); for (const CTxIn& txin : tx.vin) { - // if it's not in the wallet and corresponding UTXO is found than select as external output const auto& outPoint = txin.prevout; - if (wallet.mapWallet.find(outPoint.hash) == wallet.mapWallet.end() && !coins[outPoint].out.IsNull()) { - coinControl.SelectExternal(outPoint, coins[outPoint].out); - } else { + if (wallet.IsMine(outPoint)) { + // The input was found in the wallet, so select as internal coinControl.Select(outPoint); + } else if (coins[outPoint].out.IsNull()) { + error = _("Unable to find UTXO for external input"); + return false; + } else { + // The input was not in the wallet, but is in the UTXO set, so select as external + coinControl.SelectExternal(outPoint, coins[outPoint].out); } } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 553adcc3a2..de787ae421 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1428,6 +1428,19 @@ bool CWallet::IsMine(const CTransaction& tx) const return false; } +isminetype CWallet::IsMine(const COutPoint& outpoint) const +{ + AssertLockHeld(cs_wallet); + auto wtx = GetWalletTx(outpoint.hash); + if (!wtx) { + return ISMINE_NO; + } + if (outpoint.n >= wtx->tx->vout.size()) { + return ISMINE_NO; + } + return IsMine(wtx->tx->vout[outpoint.n]); +} + bool CWallet::IsFromMe(const CTransaction& tx) const { return (GetDebit(tx, ISMINE_ALL) > 0); @@ -3460,7 +3473,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans() const UniValue& descriptor_vals = find_value(signer_res, 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(); + const std::string& desc_str = desc_val.getValStr(); FlatSigningProvider keys; std::string desc_error; std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, desc_error, false); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 4fc41b2f53..3a46d0a987 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -685,6 +685,7 @@ public: CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const; isminetype IsMine(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + isminetype IsMine(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** should probably be renamed to IsRelevantToMe */ bool IsFromMe(const CTransaction& tx) const; CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 8afd3f416d..0d85652c0c 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -856,18 +856,18 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) } // Set the descriptor caches - for (auto desc_cache_pair : wss.m_descriptor_caches) { + for (const auto& desc_cache_pair : wss.m_descriptor_caches) { auto spk_man = pwallet->GetScriptPubKeyMan(desc_cache_pair.first); assert(spk_man); ((DescriptorScriptPubKeyMan*)spk_man)->SetCache(desc_cache_pair.second); } // Set the descriptor keys - for (auto desc_key_pair : wss.m_descriptor_keys) { + for (const auto& desc_key_pair : wss.m_descriptor_keys) { auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first); ((DescriptorScriptPubKeyMan*)spk_man)->AddKey(desc_key_pair.first.second, desc_key_pair.second); } - for (auto desc_key_pair : wss.m_descriptor_crypt_keys) { + for (const auto& desc_key_pair : wss.m_descriptor_crypt_keys) { auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first); ((DescriptorScriptPubKeyMan*)spk_man)->AddCryptedKey(desc_key_pair.first.second, desc_key_pair.second.first, desc_key_pair.second.second); } diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index cf9ad3f458..5a870de6c7 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -408,7 +408,7 @@ class RawTransactionsTest(BitcoinTestFramework): inputs = [ {'txid' : "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1", 'vout' : 0} ] #invalid vin! outputs = { self.nodes[0].getnewaddress() : 1.0} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) - assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx) + assert_raises_rpc_error(-4, "Unable to find UTXO for external input", self.nodes[2].fundrawtransaction, rawtx) def test_fee_p2pkh(self): """Compare fee of a standard pubkeyhash transaction.""" @@ -1079,17 +1079,28 @@ class RawTransactionsTest(BitcoinTestFramework): self.nodes[2].createwallet("test_weight_calculation") wallet = self.nodes[2].get_wallet_rpc("test_weight_calculation") - addr = wallet.getnewaddress() - txid = self.nodes[0].sendtoaddress(addr, 5) + addr = wallet.getnewaddress(address_type="bech32") + ext_addr = self.nodes[0].getnewaddress(address_type="bech32") + txid = self.nodes[0].send([{addr: 5}, {ext_addr: 5}])["txid"] vout = find_vout_for_address(self.nodes[0], txid, addr) + ext_vout = find_vout_for_address(self.nodes[0], txid, ext_addr) - self.nodes[0].sendtoaddress(wallet.getnewaddress(), 5) + self.nodes[0].sendtoaddress(wallet.getnewaddress(address_type="bech32"), 5) self.generate(self.nodes[0], 1) - rawtx = wallet.createrawtransaction([{'txid': txid, 'vout': vout}], [{self.nodes[0].getnewaddress(): 9.999}]) - fundedtx = wallet.fundrawtransaction(rawtx, {'fee_rate': 10}) + rawtx = wallet.createrawtransaction([{'txid': txid, 'vout': vout}], [{self.nodes[0].getnewaddress(address_type="bech32"): 8}]) + fundedtx = wallet.fundrawtransaction(rawtx, {'fee_rate': 10, "change_type": "bech32"}) # with 71-byte signatures we should expect following tx size - tx_size = 10 + 41*2 + 31*2 + (2 + 107*2)/4 + # tx overhead (10) + 2 inputs (41 each) + 2 p2wpkh (31 each) + (segwit marker and flag (2) + 2 p2wpkh 71 byte sig witnesses (107 each)) / witness scaling factor (4) + tx_size = ceil(10 + 41*2 + 31*2 + (2 + 107*2)/4) + assert_equal(fundedtx['fee'] * COIN, tx_size * 10) + + # Using the other output should have 72 byte sigs + rawtx = wallet.createrawtransaction([{'txid': txid, 'vout': ext_vout}], [{self.nodes[0].getnewaddress(): 13}]) + ext_desc = self.nodes[0].getaddressinfo(ext_addr)["desc"] + fundedtx = wallet.fundrawtransaction(rawtx, {'fee_rate': 10, "change_type": "bech32", "solving_data": {"descriptors": [ext_desc]}}) + # tx overhead (10) + 3 inputs (41 each) + 2 p2wpkh(31 each) + (segwit marker and flag (2) + 2 p2wpkh 71 bytes sig witnesses (107 each) + p2wpkh 72 byte sig witness (108)) / witness scaling factor (4) + tx_size = ceil(10 + 41*3 + 31*2 + (2 + 107*2 + 108)/4) assert_equal(fundedtx['fee'] * COIN, tx_size * 10) self.nodes[2].unloadwallet("test_weight_calculation") |