diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/init.cpp | 2 | ||||
-rw-r--r-- | src/qt/qvalidatedlineedit.cpp | 9 | ||||
-rw-r--r-- | src/qt/qvalidatedlineedit.h | 1 | ||||
-rw-r--r-- | src/random.cpp | 20 | ||||
-rw-r--r-- | src/script/script.h | 4 | ||||
-rw-r--r-- | src/streams.h | 67 | ||||
-rw-r--r-- | src/test/coins_tests.cpp | 6 | ||||
-rw-r--r-- | src/test/fuzz/coins_view.cpp | 2 | ||||
-rw-r--r-- | src/test/fuzz/string.cpp | 3 | ||||
-rw-r--r-- | src/test/getarg_tests.cpp | 92 | ||||
-rw-r--r-- | src/test/serialize_tests.cpp | 45 | ||||
-rw-r--r-- | src/test/streams_tests.cpp | 43 | ||||
-rw-r--r-- | src/util/strencodings.cpp | 3 | ||||
-rw-r--r-- | src/util/system.cpp | 54 | ||||
-rw-r--r-- | src/util/system.h | 16 | ||||
-rw-r--r-- | src/validation.cpp | 8 | ||||
-rw-r--r-- | src/validation.h | 17 | ||||
-rw-r--r-- | src/wallet/load.cpp | 2 | ||||
-rw-r--r-- | src/wallet/rpc/wallet.cpp | 2 | ||||
-rw-r--r-- | src/wallet/test/init_tests.cpp | 8 | ||||
-rw-r--r-- | src/wallet/walletutil.cpp | 2 |
21 files changed, 203 insertions, 203 deletions
diff --git a/src/init.cpp b/src/init.cpp index 330aab5184..6aef1f8149 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1150,7 +1150,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD); // Warn about relative -datadir path. - if (args.IsArgSet("-datadir") && !fs::PathFromString(args.GetArg("-datadir", "")).is_absolute()) { + if (args.IsArgSet("-datadir") && !args.GetPathArg("-datadir").is_absolute()) { LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */ "current working directory '%s'. This is fragile, because if bitcoin is started in the future " "from a different location, it will be unable to locate the current data files. There could " diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp index aa936d6b7c..bd4df75d23 100644 --- a/src/qt/qvalidatedlineedit.cpp +++ b/src/qt/qvalidatedlineedit.cpp @@ -15,6 +15,12 @@ QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) : connect(this, &QValidatedLineEdit::textChanged, this, &QValidatedLineEdit::markValid); } +void QValidatedLineEdit::setText(const QString& text) +{ + QLineEdit::setText(text); + checkValidity(); +} + void QValidatedLineEdit::setValid(bool _valid) { if(_valid == this->valid) @@ -28,7 +34,7 @@ void QValidatedLineEdit::setValid(bool _valid) } else { - setStyleSheet(STYLE_INVALID); + setStyleSheet("QValidatedLineEdit { " STYLE_INVALID "}"); } this->valid = _valid; } @@ -106,6 +112,7 @@ void QValidatedLineEdit::checkValidity() void QValidatedLineEdit::setCheckValidator(const QValidator *v) { checkValidator = v; + checkValidity(); } bool QValidatedLineEdit::isValid() diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h index b32305f5e1..12d35aa264 100644 --- a/src/qt/qvalidatedlineedit.h +++ b/src/qt/qvalidatedlineedit.h @@ -29,6 +29,7 @@ private: const QValidator *checkValidator; public Q_SLOTS: + void setText(const QString&); void setValid(bool valid); void setEnabled(bool enabled); diff --git a/src/random.cpp b/src/random.cpp index 5dae80fe31..b862510524 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -32,10 +32,8 @@ #include <sys/syscall.h> #include <linux/random.h> #endif -#if defined(HAVE_GETENTROPY) || (defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)) -#include <unistd.h> -#endif #if defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX) +#include <unistd.h> #include <sys/random.h> #endif #ifdef HAVE_SYSCTL_ARND @@ -305,16 +303,14 @@ void GetOSRand(unsigned char *ent32) RandFailure(); } } -#elif defined(HAVE_GETENTROPY) && defined(__OpenBSD__) - /* On OpenBSD this can return up to 256 bytes of entropy, will return an - * error if more are requested. - * The call cannot return less than the requested number of bytes. - getentropy is explicitly limited to openbsd here, as a similar (but not - the same) function may exist on other platforms via glibc. +#elif defined(__OpenBSD__) + /* OpenBSD. From the arc4random(3) man page: + "Use of these functions is encouraged for almost all random number + consumption because the other interfaces are deficient in either + quality, portability, standardization, or availability." + The function call is always successful. */ - if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) { - RandFailure(); - } + arc4random_buf(ent32, NUM_OS_RANDOM_BYTES); // Silence a compiler warning about unused function. (void)GetDevURandom; #elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX) diff --git a/src/script/script.h b/src/script/script.h index 3425bf8102..8b7a7bb7b3 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -51,10 +51,10 @@ static const uint32_t LOCKTIME_MAX = 0xFFFFFFFFU; static constexpr unsigned int ANNEX_TAG = 0x50; // Validation weight per passing signature (Tapscript only, see BIP 342). -static constexpr uint64_t VALIDATION_WEIGHT_PER_SIGOP_PASSED = 50; +static constexpr int64_t VALIDATION_WEIGHT_PER_SIGOP_PASSED{50}; // How much weight budget is added to the witness size (Tapscript only, see BIP 342). -static constexpr uint64_t VALIDATION_WEIGHT_OFFSET = 50; +static constexpr int64_t VALIDATION_WEIGHT_OFFSET{50}; template <typename T> std::vector<unsigned char> ToByteVector(const T& in) diff --git a/src/streams.h b/src/streams.h index 2f26be6dd8..cf8b4eb96f 100644 --- a/src/streams.h +++ b/src/streams.h @@ -240,76 +240,9 @@ public: const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } reference operator[](size_type pos) { return vch[pos + nReadPos]; } void clear() { vch.clear(); nReadPos = 0; } - iterator insert(iterator it, const value_type x) { return vch.insert(it, x); } - void insert(iterator it, size_type n, const value_type x) { vch.insert(it, n, x); } value_type* data() { return vch.data() + nReadPos; } const value_type* data() const { return vch.data() + nReadPos; } - void insert(iterator it, std::vector<value_type>::const_iterator first, std::vector<value_type>::const_iterator last) - { - if (last == first) return; - assert(last - first > 0); - if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) - { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } - - void insert(iterator it, const value_type* first, const value_type* last) - { - if (last == first) return; - assert(last - first > 0); - if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) - { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } - - iterator erase(iterator it) - { - if (it == vch.begin() + nReadPos) - { - // special case for erasing from the front - if (++nReadPos >= vch.size()) - { - // whenever we reach the end, we take the opportunity to clear the buffer - nReadPos = 0; - return vch.erase(vch.begin(), vch.end()); - } - return vch.begin() + nReadPos; - } - else - return vch.erase(it); - } - - iterator erase(iterator first, iterator last) - { - if (first == vch.begin() + nReadPos) - { - // special case for erasing from the front - if (last == vch.end()) - { - nReadPos = 0; - return vch.erase(vch.begin(), vch.end()); - } - else - { - nReadPos = (last - vch.begin()); - return last; - } - } - else - return vch.erase(first, last); - } - inline void Compact() { vch.erase(vch.begin(), vch.begin() + nReadPos); diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 922fd8e513..82e4e1c90f 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -324,7 +324,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) tx.vout.resize(1); tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate tx.vout[0].scriptPubKey.assign(InsecureRand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting - unsigned int height = InsecureRand32(); + const int height{int(InsecureRand32() >> 1)}; Coin old_coin; // 2/20 times create a new coinbase @@ -393,11 +393,11 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) // Update the expected result to know about the new output coins assert(tx.vout.size() == 1); const COutPoint outpoint(tx.GetHash(), 0); - result[outpoint] = Coin{tx.vout[0], int(height), CTransaction(tx).IsCoinBase()}; + result[outpoint] = Coin{tx.vout[0], height, CTransaction{tx}.IsCoinBase()}; // Call UpdateCoins on the top cache CTxUndo undo; - UpdateCoins(CTransaction(tx), *(stack.back()), undo, int(height)); + UpdateCoins(CTransaction{tx}, *(stack.back()), undo, height); // Update the utxo set for future spends utxoset.insert(outpoint); diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index 994b4b9e49..360dc00307 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -211,7 +211,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view) return; } bool expected_code_path = false; - const int height = fuzzed_data_provider.ConsumeIntegral<int>(); + const int height{int(fuzzed_data_provider.ConsumeIntegral<uint32_t>() >> 1)}; const bool possible_overwrite = fuzzed_data_provider.ConsumeBool(); try { AddCoins(coins_view_cache, transaction, height, possible_overwrite); diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp index 8f071b71fe..ca57af25c4 100644 --- a/src/test/fuzz/string.cpp +++ b/src/test/fuzz/string.cpp @@ -145,7 +145,8 @@ FUZZ_TARGET(string) (void)CopyrightHolders(random_string_1); FeeEstimateMode fee_estimate_mode; (void)FeeModeFromString(random_string_1, fee_estimate_mode); - (void)FormatParagraph(random_string_1, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 1000), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 1000)); + const auto width{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 1000)}; + (void)FormatParagraph(random_string_1, width, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, width)); (void)FormatSubVersion(random_string_1, fuzzed_data_provider.ConsumeIntegral<int>(), random_string_vector); (void)GetDescriptorChecksum(random_string_1); (void)HelpExampleCli(random_string_1, random_string_2); diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index d5142c8d74..597d774673 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -159,6 +159,98 @@ BOOST_AUTO_TEST_CASE(intarg) BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 0); } +BOOST_AUTO_TEST_CASE(patharg) +{ + const auto dir = std::make_pair("-dir", ArgsManager::ALLOW_ANY); + SetupArgs({dir}); + ResetArgs(""); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), fs::path{}); + + const fs::path root_path{"/"}; + ResetArgs("-dir=/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + + ResetArgs("-dir=/."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + + ResetArgs("-dir=/./"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + + ResetArgs("-dir=/.//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + +#ifdef WIN32 + const fs::path win_root_path{"C:\\"}; + ResetArgs("-dir=C:\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\.\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\.\\\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); +#endif + + const fs::path absolute_path{"/home/user/.bitcoin"}; + ResetArgs("-dir=/home/user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/root/../home/user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/./user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/./"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/.//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + const fs::path relative_path{"user/.bitcoin"}; + ResetArgs("-dir=user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=somewhere/../user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/./.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/./"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/.//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); +} + BOOST_AUTO_TEST_CASE(doubledash) { const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY); diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 8b8133b689..2441847f99 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -215,51 +215,6 @@ BOOST_AUTO_TEST_CASE(noncanonical) BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); } -BOOST_AUTO_TEST_CASE(insert_delete) -{ - constexpr auto B2I{[](std::byte b) { return std::to_integer<uint8_t>(b); }}; - - // Test inserting/deleting bytes. - CDataStream ss(SER_DISK, 0); - BOOST_CHECK_EQUAL(ss.size(), 0U); - - ss.write(MakeByteSpan("\x00\x01\x02\xff").first(4)); - BOOST_CHECK_EQUAL(ss.size(), 4U); - - uint8_t c{11}; - - // Inserting at beginning/end/middle: - ss.insert(ss.begin(), std::byte{c}); - BOOST_CHECK_EQUAL(ss.size(), 5U); - BOOST_CHECK_EQUAL(B2I(ss[0]), c); - BOOST_CHECK_EQUAL(B2I(ss[1]), 0); - - ss.insert(ss.end(), std::byte{c}); - BOOST_CHECK_EQUAL(ss.size(), 6U); - BOOST_CHECK_EQUAL(B2I(ss[4]), 0xff); - BOOST_CHECK_EQUAL(B2I(ss[5]), c); - - ss.insert(ss.begin() + 2, std::byte{c}); - BOOST_CHECK_EQUAL(ss.size(), 7U); - BOOST_CHECK_EQUAL(B2I(ss[2]), c); - - // Delete at beginning/end/middle - ss.erase(ss.begin()); - BOOST_CHECK_EQUAL(ss.size(), 6U); - BOOST_CHECK_EQUAL(B2I(ss[0]), 0); - - ss.erase(ss.begin()+ss.size()-1); - BOOST_CHECK_EQUAL(ss.size(), 5U); - BOOST_CHECK_EQUAL(B2I(ss[4]), 0xff); - - ss.erase(ss.begin()+1); - BOOST_CHECK_EQUAL(ss.size(), 4U); - BOOST_CHECK_EQUAL(B2I(ss[0]), 0); - BOOST_CHECK_EQUAL(B2I(ss[1]), 1); - BOOST_CHECK_EQUAL(B2I(ss[2]), 2); - BOOST_CHECK_EQUAL(B2I(ss[3]), 0xff); -} - BOOST_AUTO_TEST_CASE(class_methods) { int intval(100); diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index 6a69fe9840..0925e2e9ee 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -8,6 +8,8 @@ #include <boost/test/unit_test.hpp> +using namespace std::string_literals; + BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(streams_vector_writer) @@ -162,46 +164,35 @@ BOOST_AUTO_TEST_CASE(bitstream_reader_writer) BOOST_AUTO_TEST_CASE(streams_serializedata_xor) { std::vector<std::byte> in; - std::vector<char> expected_xor; - CDataStream ds(in, 0, 0); // Degenerate case - ds.Xor({0x00, 0x00}); - BOOST_CHECK_EQUAL( - std::string(expected_xor.begin(), expected_xor.end()), - ds.str()); + { + CDataStream ds{in, 0, 0}; + ds.Xor({0x00, 0x00}); + BOOST_CHECK_EQUAL(""s, ds.str()); + } in.push_back(std::byte{0x0f}); in.push_back(std::byte{0xf0}); - expected_xor.push_back('\xf0'); - expected_xor.push_back('\x0f'); // Single character key - - ds.clear(); - ds.insert(ds.begin(), in.begin(), in.end()); - - ds.Xor({0xff}); - BOOST_CHECK_EQUAL( - std::string(expected_xor.begin(), expected_xor.end()), - ds.str()); + { + CDataStream ds{in, 0, 0}; + ds.Xor({0xff}); + BOOST_CHECK_EQUAL("\xf0\x0f"s, ds.str()); + } // Multi character key in.clear(); - expected_xor.clear(); in.push_back(std::byte{0xf0}); in.push_back(std::byte{0x0f}); - expected_xor.push_back('\x0f'); - expected_xor.push_back('\x00'); - - ds.clear(); - ds.insert(ds.begin(), in.begin(), in.end()); - ds.Xor({0xff, 0x0f}); - BOOST_CHECK_EQUAL( - std::string(expected_xor.begin(), expected_xor.end()), - ds.str()); + { + CDataStream ds{in, 0, 0}; + ds.Xor({0xff, 0x0f}); + BOOST_CHECK_EQUAL("\x0f\x00"s, ds.str()); + } } BOOST_AUTO_TEST_CASE(streams_buffered_file) diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index a386f2b7b3..940fa90da2 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -113,7 +113,7 @@ void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut) // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator bool fHaveColon = colon != in.npos; bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe - bool fMultiColon = fHaveColon && (in.find_last_of(':', colon - 1) != in.npos); + bool fMultiColon{fHaveColon && colon != 0 && (in.find_last_of(':', colon - 1) != in.npos)}; if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) { uint16_t n; if (ParseUInt16(in.substr(colon + 1), &n)) { @@ -328,6 +328,7 @@ bool ParseUInt64(const std::string& str, uint64_t* out) std::string FormatParagraph(const std::string& in, size_t width, size_t indent) { + assert(width >= indent); std::stringstream out; size_t ptr = 0; size_t indented = 0; diff --git a/src/util/system.cpp b/src/util/system.cpp index 8d0cec249d..5cef2be07a 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -74,6 +74,7 @@ #include <memory> #include <optional> #include <string> +#include <system_error> #include <thread> #include <typeinfo> @@ -245,19 +246,6 @@ static std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, con return value; } -namespace { -fs::path StripRedundantLastElementsOfPath(const fs::path& path) -{ - auto result = path; - while (result.filename().empty() || fs::PathToString(result.filename()) == ".") { - result = result.parent_path(); - } - - assert(fs::equivalent(result, path.lexically_normal())); - return result; -} -} // namespace - // Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to // #include class definitions for all members. // For example, m_settings has an internal dependency on univalue. @@ -399,6 +387,13 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co return std::nullopt; } +fs::path ArgsManager::GetPathArg(std::string pathlike_arg) const +{ + auto result = fs::PathFromString(GetArg(pathlike_arg, "")).lexically_normal(); + // Remove trailing slash, if present. + return result.has_filename() ? result : result.parent_path(); +} + const fs::path& ArgsManager::GetBlocksDirPath() const { LOCK(cs_args); @@ -409,7 +404,7 @@ const fs::path& ArgsManager::GetBlocksDirPath() const if (!path.empty()) return path; if (IsArgSet("-blocksdir")) { - path = fs::absolute(fs::PathFromString(GetArg("-blocksdir", ""))); + path = fs::absolute(GetPathArg("-blocksdir")); if (!fs::is_directory(path)) { path = ""; return path; @@ -433,9 +428,9 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const // this function if (!path.empty()) return path; - std::string datadir = GetArg("-datadir", ""); + const fs::path datadir{GetPathArg("-datadir")}; if (!datadir.empty()) { - path = fs::absolute(StripRedundantLastElementsOfPath(fs::PathFromString(datadir))); + path = fs::absolute(datadir); if (!fs::is_directory(path)) { path = ""; return path; @@ -443,15 +438,18 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const } else { path = GetDefaultDataDir(); } - if (net_specific) - path /= fs::PathFromString(BaseParams().DataDir()); - if (fs::create_directories(path)) { - // This is the first run, create wallets subdirectory too + if (!fs::exists(path)) { fs::create_directories(path / "wallets"); } - path = StripRedundantLastElementsOfPath(path); + if (net_specific && !BaseParams().DataDir().empty()) { + path /= fs::PathFromString(BaseParams().DataDir()); + if (!fs::exists(path)) { + fs::create_directories(path / "wallets"); + } + } + return path; } @@ -812,8 +810,8 @@ fs::path GetDefaultDataDir() bool CheckDataDirOption() { - std::string datadir = gArgs.GetArg("-datadir", ""); - return datadir.empty() || fs::is_directory(fs::absolute(fs::PathFromString(datadir))); + const fs::path datadir{gArgs.GetPathArg("-datadir")}; + return datadir.empty() || fs::is_directory(fs::absolute(datadir)); } fs::path GetConfigFile(const std::string& confPath) @@ -1064,13 +1062,9 @@ void ArgsManager::LogArgs() const bool RenameOver(fs::path src, fs::path dest) { -#ifdef WIN32 - return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(), - MOVEFILE_REPLACE_EXISTING) != 0; -#else - int rc = std::rename(src.c_str(), dest.c_str()); - return (rc == 0); -#endif /* WIN32 */ + std::error_code error; + fs::rename(src, dest, error); + return !error; } /** diff --git a/src/util/system.h b/src/util/system.h index a8fd21fcaa..a72ba3f3ed 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -69,7 +69,13 @@ void DirectoryCommit(const fs::path &dirname); bool TruncateFile(FILE *file, unsigned int length); int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); + +/** + * Rename src to dest. + * @return true if the rename was successful. + */ [[nodiscard]] bool RenameOver(fs::path src, fs::path dest); + bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false); void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name); bool DirIsWritable(const fs::path& directory); @@ -265,6 +271,16 @@ protected: std::optional<const Command> GetCommand() const; /** + * Get a normalized path from a specified pathlike argument + * + * It is guaranteed that the returned path has no trailing slashes. + * + * @param pathlike_arg Pathlike argument to get a path from (e.g., "-datadir", "-blocksdir" or "-walletdir") + * @return Normalized path which is get from a specified pathlike argument + */ + fs::path GetPathArg(std::string pathlike_arg) const; + + /** * Get blocks directory path * * @return Blocks path which is network specific diff --git a/src/validation.cpp b/src/validation.cpp index c12dc9e8b6..e20e2fe523 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1787,8 +1787,9 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI error("DisconnectBlock(): transaction and undo data inconsistent"); return DISCONNECT_FAILED; } - for (unsigned int j = tx.vin.size(); j-- > 0;) { - const COutPoint &out = tx.vin[j].prevout; + for (unsigned int j = tx.vin.size(); j > 0;) { + --j; + const COutPoint& out = tx.vin[j].prevout; int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out); if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED; fClean = fClean && res != DISCONNECT_UNCLEAN; @@ -4493,7 +4494,8 @@ bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mocka } uint64_t num; file >> num; - while (num--) { + while (num) { + --num; CTransactionRef tx; int64_t nTime; int64_t nFeeDelta; diff --git a/src/validation.h b/src/validation.h index fb258005f1..fdfd29d1f8 100644 --- a/src/validation.h +++ b/src/validation.h @@ -597,7 +597,8 @@ public: EXCLUSIVE_LOCKS_REQUIRED(::cs_main); /** Import blocks from an external file */ - void LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp = nullptr); + void LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp = nullptr) + EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex); /** * Update the on-disk chain state. @@ -639,7 +640,9 @@ public: */ bool ActivateBestChain( BlockValidationState& state, - std::shared_ptr<const CBlock> pblock = nullptr) LOCKS_EXCLUDED(m_chainstate_mutex, cs_main); + std::shared_ptr<const CBlock> pblock = nullptr) + EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) + LOCKS_EXCLUDED(::cs_main); bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -657,9 +660,15 @@ public: * * May not be called in a validationinterface callback. */ - bool PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); + bool PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) + EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) + LOCKS_EXCLUDED(::cs_main); + /** Mark a block as invalid. */ - bool InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex) LOCKS_EXCLUDED(m_chainstate_mutex, cs_main); + bool InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex) + EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) + LOCKS_EXCLUDED(::cs_main); + /** Remove invalidity status from a block and its descendants. */ void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 6a74f2eb84..633d8c5450 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -28,7 +28,7 @@ bool VerifyWallets(WalletContext& context) ArgsManager& args = *Assert(context.args); if (args.IsArgSet("-walletdir")) { - fs::path wallet_dir = fs::PathFromString(args.GetArg("-walletdir", "")); + const fs::path wallet_dir{args.GetPathArg("-walletdir")}; std::error_code error; // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory // It also lets the fs::exists and fs::is_directory checks below pass on windows, since they return false diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index 33ec715b51..883a3c102b 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -57,6 +57,7 @@ static RPCHelpMan getwalletinfo() {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"}, }}, {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"}, + {RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"}, }}, }, RPCExamples{ @@ -117,6 +118,7 @@ static RPCHelpMan getwalletinfo() obj.pushKV("scanning", false); } obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)); + obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)); return obj; }, }; diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp index c1cae5c5f6..7fdecc5642 100644 --- a/src/wallet/test/init_tests.cpp +++ b/src/wallet/test/init_tests.cpp @@ -18,7 +18,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default) SetWalletDir(m_walletdir_path_cases["default"]); bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } @@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom) SetWalletDir(m_walletdir_path_cases["custom"]); bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } @@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing) SetWalletDir(m_walletdir_path_cases["trailing"]); bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2) SetWalletDir(m_walletdir_path_cases["trailing2"]); bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index ce276451c3..df1b10a634 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -13,7 +13,7 @@ fs::path GetWalletDir() fs::path path; if (gArgs.IsArgSet("-walletdir")) { - path = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + path = gArgs.GetPathArg("-walletdir"); if (!fs::is_directory(path)) { // If the path specified doesn't exist, we return the deliberately // invalid empty string. |