diff --git a/contrib/dash-qt.pro b/contrib/dash-qt.pro deleted file mode 100644 index 2c2c45b799..0000000000 --- a/contrib/dash-qt.pro +++ /dev/null @@ -1,26 +0,0 @@ -FORMS += \ - ../src/qt/forms/aboutdialog.ui \ - ../src/qt/forms/addressbookpage.ui \ - ../src/qt/forms/appearancewidget.ui \ - ../src/qt/forms/askpassphrasedialog.ui \ - ../src/qt/forms/coincontroldialog.ui \ - ../src/qt/forms/debugwindow.ui \ - ../src/qt/forms/editaddressdialog.ui \ - ../src/qt/forms/governancelist.ui \ - ../src/qt/forms/helpmessagedialog.ui \ - ../src/qt/forms/intro.ui \ - ../src/qt/forms/masternodelist.ui \ - ../src/qt/forms/qrdialog.ui \ - ../src/qt/forms/openuridialog.ui \ - ../src/qt/forms/optionsdialog.ui \ - ../src/qt/forms/overviewpage.ui \ - ../src/qt/forms/receivecoinsdialog.ui \ - ../src/qt/forms/receiverequestdialog.ui \ - ../src/qt/forms/sendcoinsdialog.ui \ - ../src/qt/forms/sendcoinsentry.ui \ - ../src/qt/forms/signverifymessagedialog.ui \ - ../src/qt/forms/transactiondescdialog.ui \ - ../src/qt/forms/createwalletdialog.ui - -RESOURCES += \ - ../src/qt/dash.qrc diff --git a/doc/release-notes-21595.md b/doc/release-notes-21595.md new file mode 100644 index 0000000000..aa91db6da8 --- /dev/null +++ b/doc/release-notes-21595.md @@ -0,0 +1,9 @@ +Tools and Utilities +------------------- + +- A new CLI `-addrinfo` command returns the number of addresses known to the + node per network type (including Tor v2 versus v3) and total. This can be + useful to see if the node knows enough addresses in a network to use options + like `-onlynet=` or to upgrade to current and future Tor releases + that support Tor v3 addresses only. (#5904) + diff --git a/doc/translation_process.md b/doc/translation_process.md index cad2bc2447..3a85b99d0e 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -22,8 +22,6 @@ cd src/ make translate ``` -`contrib/dash-qt.pro` takes care of generating `.qm` (binary compiled) files from `.ts` (source files) files. It’s mostly automated, and you shouldn’t need to worry about it. - **Example Qt translation** ```cpp QToolBar *toolbar = addToolBar(tr("Tabs toolbar")); diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 92334ba28b..4b2f6e8461 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -46,6 +46,7 @@ static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; static constexpr int DEFAULT_WAIT_CLIENT_TIMEOUT = 0; static const bool DEFAULT_NAMED=false; static const int CONTINUE_EXECUTION=-1; +static constexpr int8_t UNKNOWN_NETWORK{-1}; /** Default number of blocks to generate for RPC generatetoaddress. */ static const std::string DEFAULT_NBLOCKS = "1"; @@ -62,6 +63,7 @@ static void SetupCliArgs(ArgsManager& argsman) argsman.AddArg("-conf=", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-datadir=", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: dash-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -243,6 +245,60 @@ public: virtual UniValue ProcessReply(const UniValue &batch_in) = 0; }; +/** Process addrinfo requests */ +class AddrinfoRequestHandler : public BaseRequestHandler +{ +private: + static constexpr std::array m_networks{"ipv4", "ipv6", "torv2", "torv3", "i2p"}; + int8_t NetworkStringToId(const std::string& str) const + { + for (size_t i = 0; i < m_networks.size(); ++i) { + if (str == m_networks.at(i)) return i; + } + return UNKNOWN_NETWORK; + } + +public: + UniValue PrepareRequest(const std::string& method, const std::vector& args) override + { + if (!args.empty()) { + throw std::runtime_error("-addrinfo takes no arguments"); + } + UniValue params{RPCConvertValues("getnodeaddresses", std::vector{{"0"}})}; + return JSONRPCRequestObj("getnodeaddresses", params, 1); + } + + UniValue ProcessReply(const UniValue& reply) override + { + if (!reply["error"].isNull()) return reply; + const std::vector& nodes{reply["result"].getValues()}; + if (!nodes.empty() && nodes.at(0)["network"].isNull()) { + throw std::runtime_error("-addrinfo requires dashd server to be running v21.0 and up"); + } + // Count the number of peers we know by network, including torv2 versus torv3. + std::array counts{{}}; + for (const UniValue& node : nodes) { + std::string network_name{node["network"].get_str()}; + if (network_name == "onion") { + network_name = node["address"].get_str().size() > 22 ? "torv3" : "torv2"; + } + const int8_t network_id{NetworkStringToId(network_name)}; + if (network_id == UNKNOWN_NETWORK) continue; + ++counts.at(network_id); + } + // Prepare result to return to user. + UniValue result{UniValue::VOBJ}, addresses{UniValue::VOBJ}; + uint64_t total{0}; // Total address count + for (size_t i = 0; i < m_networks.size(); ++i) { + addresses.pushKV(m_networks.at(i), counts.at(i)); + total += counts.at(i); + } + addresses.pushKV("total", total); + result.pushKV("addresses_known", addresses); + return JSONRPCReplyObj(result, NullUniValue, 1); + } +}; + /** Process getinfo requests */ class GetinfoRequestHandler: public BaseRequestHandler { @@ -318,13 +374,12 @@ public: class NetinfoRequestHandler : public BaseRequestHandler { private: - static constexpr int8_t UNKNOWN_NETWORK{-1}; - static constexpr uint8_t m_networks_size{3}; - const std::array m_networks{{"ipv4", "ipv6", "onion"}}; - std::array, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total/block-relay) + static constexpr uint8_t MAX_DETAIL_LEVEL{4}; + static constexpr std::array m_networks{"ipv4", "ipv6", "onion"}; + std::array, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total/block-relay) int8_t NetworkStringToId(const std::string& str) const { - for (uint8_t i = 0; i < m_networks_size; ++i) { + for (size_t i = 0; i < m_networks.size(); ++i) { if (str == m_networks.at(i)) return i; } return UNKNOWN_NETWORK; @@ -437,7 +492,7 @@ public: if (!args.empty()) { uint8_t n{0}; if (ParseUInt8(args.at(0), &n)) { - m_details_level = n; + m_details_level = std::min(n, MAX_DETAIL_LEVEL); } else if (args.at(0) == "help") { m_is_help_requested = true; } else { @@ -471,13 +526,13 @@ public: if (network_id == UNKNOWN_NETWORK) continue; const bool is_outbound{!peer["inbound"].get_bool()}; const bool is_block_relay{!peer["relaytxes"].get_bool()}; - ++m_counts.at(is_outbound).at(network_id); // in/out by network - ++m_counts.at(is_outbound).at(m_networks_size); // in/out overall - ++m_counts.at(2).at(network_id); // total by network - ++m_counts.at(2).at(m_networks_size); // total overall + ++m_counts.at(is_outbound).at(network_id); // in/out by network + ++m_counts.at(is_outbound).at(m_networks.size()); // in/out overall + ++m_counts.at(2).at(network_id); // total by network + ++m_counts.at(2).at(m_networks.size()); // total overall if (is_block_relay) { - ++m_counts.at(is_outbound).at(m_networks_size + 1); // in/out block-relay - ++m_counts.at(2).at(m_networks_size + 1); // total block-relay + ++m_counts.at(is_outbound).at(m_networks.size() + 1); // in/out block-relay + ++m_counts.at(2).at(m_networks.size() + 1); // total block-relay } if (DetailsRequested()) { // Push data for this peer to the peers vector. @@ -539,9 +594,9 @@ public: // Report peer connection totals by type. result += " ipv4 ipv6 onion total block-relay\n"; - const std::array rows{{"in", "out", "total"}}; - for (uint8_t i = 0; i < m_networks_size; ++i) { - result += strprintf("%-5s %5i %5i %5i %5i %5i\n", rows.at(i), m_counts.at(i).at(0), m_counts.at(i).at(1), m_counts.at(i).at(2), m_counts.at(i).at(m_networks_size), m_counts.at(i).at(m_networks_size + 1)); + const std::array rows{"in", "out", "total"}; + for (uint8_t i = 0; i < m_networks.size(); ++i) { + result += strprintf("%-5s %5i %5i %5i %5i %5i\n", rows.at(i), m_counts.at(i).at(0), m_counts.at(i).at(1), m_counts.at(i).at(2), m_counts.at(i).at(m_networks.size()), m_counts.at(i).at(m_networks.size() + 1)); } // Report local addresses, ports, and scores. @@ -908,6 +963,8 @@ static int CommandLineRPC(int argc, char *argv[]) } else { ParseError(error, strPrint, nRet); } + } else if (gArgs.GetBoolArg("-addrinfo", false)) { + rh.reset(new AddrinfoRequestHandler()); } else { rh.reset(new DefaultRequestHandler()); if (args.size() < 1) { diff --git a/src/init.cpp b/src/init.cpp index 5eff0d0b11..6a0d164e17 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -840,7 +840,7 @@ static 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 = GetBlocksDir(); + fs::path blocksdir = gArgs.GetBlocksDirPath(); for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) { if (fs::is_regular_file(*it) && it->path().filename().string().length() == 12 && @@ -1197,7 +1197,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) InitWarning(warnings); } - if (!fs::is_directory(GetBlocksDir())) { + if (!fs::is_directory(gArgs.GetBlocksDirPath())) { return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), args.GetArg("-blocksdir", ""))); } @@ -2338,8 +2338,8 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc InitError(strprintf(_("Error: Disk space is low for %s"), GetDataDir())); return false; } - if (!CheckDiskSpace(GetBlocksDir())) { - InitError(strprintf(_("Error: Disk space is low for %s"), GetBlocksDir())); + if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) { + InitError(strprintf(_("Error: Disk space is low for %s"), gArgs.GetBlocksDirPath())); return false; } diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index a7485b1e71..115554ab21 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -251,7 +251,7 @@ QString ClientModel::dataDir() const QString ClientModel::blocksDir() const { - return GUIUtil::boostPathToQString(GetBlocksDir()); + return GUIUtil::boostPathToQString(gArgs.GetBlocksDirPath()); } void ClientModel::updateBanlist() diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 4cde717efc..22a33bcc33 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -643,7 +643,7 @@ void openConfigfile() void showBackups() { - fs::path backupsDir = GetBackupsDir(); + fs::path backupsDir = gArgs.GetBackupsDirPath(); /* Open folder with default browser */ if (fs::exists(backupsDir)) diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index df3689349f..d38a8e3515 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper) { // Perform tests both obfuscated and non-obfuscated. for (const bool obfuscate : {false, true}) { - fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false"); + fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); uint8_t key{'k'}; uint256 in = InsecureRand256(); @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_basic_data) { // Perform tests both obfuscated and non-obfuscated. for (bool obfuscate : {false, true}) { - fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false"); + fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), false, true, obfuscate); uint256 res; @@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch) { // Perform tests both obfuscated and non-obfuscated. for (const bool obfuscate : {false, true}) { - fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false"); + fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); uint8_t key{'i'}; @@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) { // Perform tests both obfuscated and non-obfuscated. for (const bool obfuscate : {false, true}) { - fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false"); + fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false"); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); // The two keys are intentionally chosen for ordering @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) { // We're going to share this fs::path between two wrappers - fs::path ph = GetDataDir() / "existing_data_no_obfuscate"; + fs::path ph = m_args.GetDataDirPath() / "existing_data_no_obfuscate"; create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. @@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) BOOST_AUTO_TEST_CASE(existing_data_reindex) { // We're going to share this fs::path between two wrappers - fs::path ph = GetDataDir() / "existing_data_reindex"; + fs::path ph = m_args.GetDataDirPath() / "existing_data_reindex"; create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. @@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) BOOST_AUTO_TEST_CASE(iterator_ordering) { - fs::path ph = GetDataDir() / "iterator_ordering"; + fs::path ph = m_args.GetDataDirPath() / "iterator_ordering"; CDBWrapper dbw(ph, (1 << 20), true, false, false); for (int x=0x00; x<256; ++x) { uint8_t key = x; @@ -358,7 +358,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering) { char buf[10]; - fs::path ph = GetDataDir() / "iterator_string_ordering"; + fs::path ph = m_args.GetDataDirPath() / "iterator_string_ordering"; CDBWrapper dbw(ph, (1 << 20), true, false, false); for (int x=0x00; x<10; ++x) { for (int y = 0; y < 10; y++) { @@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(unicodepath) // On Windows this test will fail if the directory is created using // the ANSI CreateDirectoryA call and the code page isn't UTF8. // It will succeed if created with CreateDirectoryW. - fs::path ph = GetDataDir() / "test_runner_₿_🏃_20191128_104644"; + fs::path ph = m_args.GetDataDirPath() / "test_runner_₿_🏃_20191128_104644"; CDBWrapper dbw(ph, (1 << 20)); fs::path lockPath = ph / "LOCK"; diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 352b4b1c0e..43d52ed0be 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -210,7 +210,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) BOOST_AUTO_TEST_CASE(peer_discouragement) { const CChainParams& chainparams = Params(); - auto banman = std::make_unique(GetDataDir() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); + auto banman = std::make_unique(m_args.GetDataDirPath() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto connman = std::make_unique(0x1337, 0x1337, *m_node.addrman); auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, *m_node.mn_metaman, *m_node.mn_sync, @@ -258,7 +258,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) BOOST_AUTO_TEST_CASE(DoS_bantime) { const CChainParams& chainparams = Params(); - auto banman = std::make_unique(GetDataDir() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); + auto banman = std::make_unique(m_args.GetDataDirPath() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto connman = std::make_unique(0x1337, 0x1337, *m_node.addrman); auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, *m_node.mn_metaman, *m_node.mn_sync, diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp index 0c5c19113d..9194ed8130 100644 --- a/src/test/flatfile_tests.cpp +++ b/src/test/flatfile_tests.cpp @@ -14,7 +14,7 @@ BOOST_FIXTURE_TEST_SUITE(flatfile_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(flatfile_filename) { - const auto data_dir = GetDataDir(); + const auto data_dir = m_args.GetDataDirPath(); FlatFilePos pos(456, 789); @@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(flatfile_filename) BOOST_AUTO_TEST_CASE(flatfile_open) { - const auto data_dir = GetDataDir(); + const auto data_dir = m_args.GetDataDirPath(); FlatFileSeq seq(data_dir, "a", 16 * 1024); std::string line1("A purely peer-to-peer version of electronic cash would allow online " @@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open) BOOST_AUTO_TEST_CASE(flatfile_allocate) { - const auto data_dir = GetDataDir(); + const auto data_dir = m_args.GetDataDirPath(); FlatFileSeq seq(data_dir, "a", 100); bool out_of_space; @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(flatfile_allocate) BOOST_AUTO_TEST_CASE(flatfile_flush) { - const auto data_dir = GetDataDir(); + const auto data_dir = m_args.GetDataDirPath(); FlatFileSeq seq(data_dir, "a", 100); bool out_of_space; diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index 8daeb49600..c4e6816484 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -13,7 +13,7 @@ BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(fsbridge_fstream) { - fs::path tmpfolder = GetDataDir(); + fs::path tmpfolder = m_args.GetDataDirPath(); // tmpfile1 should be the same as tmpfile2 fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃"; fs::path tmpfile2 = tmpfolder / "fs_tests_₿_🏃"; diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index cbd8c21cd9..78a314d2ee 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -17,7 +17,7 @@ namespace getarg_tests{ protected: void SetupArgs(const std::vector>& args); void ResetArgs(const std::string& strArg); - ArgsManager m_args; + ArgsManager m_local_args; }; } @@ -39,14 +39,14 @@ void LocalTestingSetup :: ResetArgs(const std::string& strArg) vecChar.push_back(s.c_str()); std::string error; - BOOST_CHECK(m_args.ParseParameters(vecChar.size(), vecChar.data(), error)); + BOOST_CHECK(m_local_args.ParseParameters(vecChar.size(), vecChar.data(), error)); } void LocalTestingSetup :: SetupArgs(const std::vector>& args) { - m_args.ClearArgs(); + m_local_args.ClearArgs(); for (const auto& arg : args) { - m_args.AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS); + m_local_args.AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS); } } @@ -55,52 +55,52 @@ BOOST_AUTO_TEST_CASE(boolarg) const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY); SetupArgs({foo}); ResetArgs("-foo"); - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_args.GetBoolArg("-fo", false)); - BOOST_CHECK(m_args.GetBoolArg("-fo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-fo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-fo", true)); - BOOST_CHECK(!m_args.GetBoolArg("-fooo", false)); - BOOST_CHECK(m_args.GetBoolArg("-fooo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-fooo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-fooo", true)); ResetArgs("-foo=0"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); ResetArgs("-foo=1"); - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); // New 0.6 feature: auto-map -nosomething to !-something: ResetArgs("-nofoo"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); ResetArgs("-nofoo=1"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); ResetArgs("-foo -nofoo"); // -nofoo should win - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); ResetArgs("-foo=1 -nofoo=1"); // -nofoo should win - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); ResetArgs("-foo=0 -nofoo=0"); // -nofoo=0 should win - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); // New 0.6 feature: treat -- same as -: ResetArgs("--foo=1"); - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); ResetArgs("--nofoo=1"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); } @@ -110,24 +110,24 @@ BOOST_AUTO_TEST_CASE(stringarg) const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); SetupArgs({foo, bar}); ResetArgs(""); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "eleven"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "eleven"); ResetArgs("-foo -bar"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), ""); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), ""); ResetArgs("-foo="); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), ""); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), ""); ResetArgs("-foo=11"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "11"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "11"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "11"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "11"); ResetArgs("-foo=eleven"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "eleven"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "eleven"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "eleven"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "eleven"); } @@ -137,20 +137,20 @@ BOOST_AUTO_TEST_CASE(intarg) const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); SetupArgs({foo, bar}); ResetArgs(""); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 11), 11); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 0), 0); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 11), 11); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 0), 0); ResetArgs("-foo -bar"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 11), 0); - BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 0); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 11), 0); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0); ResetArgs("-foo=11 -bar=12"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 0), 11); - BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 12); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 0), 11); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 12); ResetArgs("-foo=NaN -bar=NotANumber"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 1), 0); - BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 0); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 1), 0); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0); } BOOST_AUTO_TEST_CASE(doubledash) @@ -159,11 +159,11 @@ BOOST_AUTO_TEST_CASE(doubledash) const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); SetupArgs({foo, bar}); ResetArgs("--foo"); - BOOST_CHECK_EQUAL(m_args.GetBoolArg("-foo", false), true); + BOOST_CHECK_EQUAL(m_local_args.GetBoolArg("-foo", false), true); ResetArgs("--foo=verbose --bar=1"); - BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "verbose"); - BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 0), 1); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "verbose"); + BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 0), 1); } BOOST_AUTO_TEST_CASE(boolargno) @@ -172,24 +172,24 @@ BOOST_AUTO_TEST_CASE(boolargno) const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); SetupArgs({foo, bar}); ResetArgs("-nofoo"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); ResetArgs("-nofoo=1"); - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); ResetArgs("-nofoo=0"); - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); ResetArgs("-foo --nofoo"); // --nofoo should win - BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); ResetArgs("-nofoo -foo"); // foo always wins: - BOOST_CHECK(m_args.GetBoolArg("-foo", true)); - BOOST_CHECK(m_args.GetBoolArg("-foo", false)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); } BOOST_AUTO_TEST_CASE(logargs) @@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(logargs) }); // Log the arguments - m_args.LogArgs(); + m_local_args.LogArgs(); LogInstance().DeleteCallback(print_connection); // Check that what should appear does, and what shouldn't doesn't. diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp index 548fd020a6..f5ae9f86d1 100644 --- a/src/test/settings_tests.cpp +++ b/src/test/settings_tests.cpp @@ -45,7 +45,7 @@ BOOST_FIXTURE_TEST_SUITE(settings_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(ReadWrite) { - fs::path path = GetDataDir() / "settings.json"; + fs::path path = m_args.GetDataDirPath() / "settings.json"; WriteText(path, R"({ "string": "string", diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 76f32ec3db..76d3ddc189 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -136,7 +136,8 @@ void DashTestSetupClose(NodeContext& node) } BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::vector& extra_args) - : m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()} + : m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()}, + m_args{} { const std::vector arguments = Cat( { @@ -152,8 +153,9 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve extra_args); util::ThreadRename("test"); fs::create_directories(m_path_root); + m_args.ForceSetArg("-datadir", m_path_root.string()); gArgs.ForceSetArg("-datadir", m_path_root.string()); - ClearDatadirCache(); + gArgs.ClearPathCache(); { SetupServerArgs(m_node); std::string error; @@ -283,7 +285,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector(GetDataDir() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); + m_node.banman = std::make_unique(m_args.GetDataDirPath() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman, m_node.banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, *m_node.mn_metaman, *m_node.mn_sync, *m_node.govman, *m_node.sporkman, ::deterministicMNManager, m_node.cj_ctx, m_node.llmq_ctx, diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index 210d35de2a..d3795b5b86 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -9,12 +9,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include @@ -90,6 +90,7 @@ struct BasicTestingSetup { std::unique_ptr connman; const fs::path m_path_root; + ArgsManager m_args; }; /** Testing setup that performs all steps up until right before diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index ee5774e981..3f03c5b153 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -54,24 +54,27 @@ BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(util_datadir) { - ClearDatadirCache(); - const fs::path dd_norm = GetDataDir(); + // Use local args variable instead of m_args to avoid making assumptions about test setup + ArgsManager args; + args.ForceSetArg("-datadir", m_path_root.string()); - gArgs.ForceSetArg("-datadir", dd_norm.string() + "/"); - ClearDatadirCache(); - BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + const fs::path dd_norm = args.GetDataDirPath(); - gArgs.ForceSetArg("-datadir", dd_norm.string() + "/."); - ClearDatadirCache(); - BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + args.ForceSetArg("-datadir", dd_norm.string() + "/"); + args.ClearPathCache(); + BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath()); - gArgs.ForceSetArg("-datadir", dd_norm.string() + "/./"); - ClearDatadirCache(); - BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + args.ForceSetArg("-datadir", dd_norm.string() + "/."); + args.ClearPathCache(); + BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath()); - gArgs.ForceSetArg("-datadir", dd_norm.string() + "/.//"); - ClearDatadirCache(); - BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + args.ForceSetArg("-datadir", dd_norm.string() + "/./"); + args.ClearPathCache(); + BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath()); + + args.ForceSetArg("-datadir", dd_norm.string() + "/.//"); + args.ClearPathCache(); + BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath()); } namespace { @@ -1256,21 +1259,23 @@ BOOST_AUTO_TEST_CASE(util_ReadWriteSettings) { // Test writing setting. TestArgsManager args1; + args1.ForceSetArg("-datadir", m_path_root.string()); args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; }); args1.WriteSettingsFile(); // Test reading setting. TestArgsManager args2; + args2.ForceSetArg("-datadir", m_path_root.string()); args2.ReadSettingsFile(); args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); }); // Test error logging, and remove previously written setting. { ASSERT_DEBUG_LOG("Failed renaming settings file"); - fs::remove(GetDataDir() / "settings.json"); - fs::create_directory(GetDataDir() / "settings.json"); + fs::remove(args1.GetDataDirPath() / "settings.json"); + fs::create_directory(args1.GetDataDirPath() / "settings.json"); args2.WriteSettingsFile(); - fs::remove(GetDataDir() / "settings.json"); + fs::remove(args1.GetDataDirPath() / "settings.json"); } } @@ -2070,7 +2075,7 @@ static constexpr char ExitCommand = 'X'; BOOST_AUTO_TEST_CASE(test_LockDirectory) { - fs::path dirname = GetDataDir() / "lock_dir"; + fs::path dirname = m_args.GetDataDirPath() / "lock_dir"; const std::string lockname = ".lock"; #ifndef WIN32 // Revert SIGCHLD to default, otherwise boost.test will catch and fail on @@ -2159,7 +2164,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory) BOOST_AUTO_TEST_CASE(test_DirIsWritable) { // Should be able to write to the data dir. - fs::path tmpdirname = GetDataDir(); + fs::path tmpdirname = m_args.GetDataDirPath(); BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true); // Should not be able to write to a non-existent dir. diff --git a/src/util/system.cpp b/src/util/system.cpp index 76bb56c628..d36132760c 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -253,6 +253,19 @@ static bool CheckValid(const std::string& key, const util::SettingsValue& val, u return true; } +namespace { +fs::path StripRedundantLastElementsOfPath(const fs::path& path) +{ + auto result = path; + while (result.filename().string() == ".") { + result = result.parent_path(); + } + + assert(fs::equivalent(result, path)); + 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. @@ -385,6 +398,80 @@ std::optional ArgsManager::GetArgFlags(const std::string& name) co return std::nullopt; } +const fs::path& ArgsManager::GetBlocksDirPath() +{ + LOCK(cs_args); + fs::path& path = m_cached_blocks_path; + + // Cache the path to avoid calling fs::create_directories on every call of + // this function + if (!path.empty()) return path; + + if (IsArgSet("-blocksdir")) { + path = fs::system_complete(GetArg("-blocksdir", "")); + if (!fs::is_directory(path)) { + path = ""; + return path; + } + } else { + path = GetDataDirPath(false); + } + + path /= BaseParams().DataDir(); + path /= "blocks"; + fs::create_directories(path); + path = StripRedundantLastElementsOfPath(path); + return path; +} + +const fs::path& ArgsManager::GetDataDirPath(bool net_specific) const +{ + LOCK(cs_args); + fs::path& path = net_specific ? m_cached_network_datadir_path : m_cached_datadir_path; + + // Cache the path to avoid calling fs::create_directories on every call of + // this function + if (!path.empty()) return path; + + std::string datadir = GetArg("-datadir", ""); + if (!datadir.empty()) { + path = fs::system_complete(datadir); + if (!fs::is_directory(path)) { + path = ""; + return path; + } + } else { + path = GetDefaultDataDir(); + } + if (net_specific) + path /= BaseParams().DataDir(); + + if (fs::create_directories(path)) { + // This is the first run, create wallets subdirectory too + fs::create_directories(path / "wallets"); + } + + path = StripRedundantLastElementsOfPath(path); + return path; +} + +fs::path ArgsManager::GetBackupsDirPath() +{ + if (!IsArgSet("-walletbackupsdir")) + return GetDataDirPath() / "backups"; + + return fs::absolute(GetArg("-walletbackupsdir", "")); +} + +void ArgsManager::ClearPathCache() +{ + LOCK(cs_args); + + m_cached_datadir_path = fs::path(); + m_cached_network_datadir_path = fs::path(); + m_cached_blocks_path = fs::path(); +} + std::vector ArgsManager::GetArgs(const std::string& strArg) const { std::vector result; @@ -424,7 +511,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const } if (filepath) { std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME); - *filepath = fsbridge::AbsPathJoin(GetDataDir(/* net_specific= */ true), temp ? settings + ".tmp" : settings); + *filepath = fsbridge::AbsPathJoin(GetDataDirPath(/* net_specific= */ true), temp ? settings + ".tmp" : settings); } return true; } @@ -718,87 +805,14 @@ fs::path GetDefaultDataDir() #endif } -namespace { -fs::path StripRedundantLastElementsOfPath(const fs::path& path) -{ - auto result = path; - while (result.filename().string() == ".") { - result = result.parent_path(); - } - - assert(fs::equivalent(result, path)); - return result; -} -} // namespace - -static fs::path g_blocks_path_cache_net_specific; -static fs::path pathCached; -static fs::path pathCachedNetSpecific; -static RecursiveMutex csPathCached; - -const fs::path &GetBlocksDir() -{ - LOCK(csPathCached); - fs::path &path = g_blocks_path_cache_net_specific; - - // Cache the path to avoid calling fs::create_directories on every call of - // this function - if (!path.empty()) return path; - - if (gArgs.IsArgSet("-blocksdir")) { - path = fs::system_complete(gArgs.GetArg("-blocksdir", "")); - if (!fs::is_directory(path)) { - path = ""; - return path; - } - } else { - path = GetDataDir(false); - } - - path /= BaseParams().DataDir(); - path /= "blocks"; - fs::create_directories(path); - path = StripRedundantLastElementsOfPath(path); - return path; -} - const fs::path &GetDataDir(bool fNetSpecific) { - LOCK(csPathCached); - fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached; - - // Cache the path to avoid calling fs::create_directories on every call of - // this function - if (!path.empty()) return path; - - std::string datadir = gArgs.GetArg("-datadir", ""); - if (!datadir.empty()) { - path = fs::system_complete(datadir); - if (!fs::is_directory(path)) { - path = ""; - return path; - } - } else { - path = GetDefaultDataDir(); - } - if (fNetSpecific) - path /= BaseParams().DataDir(); - - if (fs::create_directories(path)) { - // This is the first run, create wallets subdirectory too - fs::create_directories(path / "wallets"); - } - - path = StripRedundantLastElementsOfPath(path); - return path; + return gArgs.GetDataDirPath(fNetSpecific); } fs::path GetBackupsDir() { - if (!gArgs.IsArgSet("-walletbackupsdir")) - return GetDataDir() / "backups"; - - return fs::absolute(gArgs.GetArg("-walletbackupsdir", "")); + return gArgs.GetBackupsDirPath(); } bool CheckDataDirOption() @@ -807,15 +821,6 @@ bool CheckDataDirOption() return datadir.empty() || fs::is_directory(fs::system_complete(datadir)); } -void ClearDatadirCache() -{ - LOCK(csPathCached); - - pathCached = fs::path(); - pathCachedNetSpecific = fs::path(); - g_blocks_path_cache_net_specific = fs::path(); -} - fs::path GetConfigFile(const std::string& confPath) { return AbsPathForConfigVal(fs::path(confPath), false); @@ -979,7 +984,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) } // If datadir is changed in .conf file: - ClearDatadirCache(); + gArgs.ClearPathCache(); if (!CheckDataDirOption()) { error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", "")); return false; diff --git a/src/util/system.h b/src/util/system.h index 3aa787d766..6b7293ad24 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -97,14 +97,9 @@ void ReleaseDirectoryLocks(); bool TryCreateDirectories(const fs::path& p); fs::path GetDefaultDataDir(); -// The blocks directory is always net specific. -const fs::path &GetBlocksDir(); const fs::path &GetDataDir(bool fNetSpecific = true); -fs::path GetBackupsDir(); // Return true if -datadir option points to a valid directory or is not specified. bool CheckDataDirOption(); -/** Tests only */ -void ClearDatadirCache(); fs::path GetConfigFile(const std::string& confPath); #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true); @@ -210,6 +205,9 @@ protected: std::set m_network_only_args GUARDED_BY(cs_args); std::map> m_available_args GUARDED_BY(cs_args); std::list m_config_sections GUARDED_BY(cs_args); + fs::path m_cached_blocks_path GUARDED_BY(cs_args); + mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args); + mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args); [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false); @@ -264,6 +262,29 @@ public: */ const std::map> GetCommandLineArgs() const; + /** + * Get blocks directory path + * + * @return Blocks path which is network specific + */ + const fs::path& GetBlocksDirPath(); + + /** + * Get data directory path + * + * @param net_specific Append network identifier to the returned path + * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned + * @post Returned directory path is created unless it is empty + */ + const fs::path& GetDataDirPath(bool net_specific = true) const; + + fs::path GetBackupsDirPath(); + + /** + * Clear cached directory paths + */ + void ClearPathCache(); + /** * Return a vector of strings of the given argument * diff --git a/src/validation.cpp b/src/validation.cpp index 3dc6580de3..6a7ecf47db 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2626,7 +2626,7 @@ bool CChainState::FlushStateToDisk( // Write blocks and block index to disk. if (fDoFullFlush || fPeriodicWrite) { // Depend on nMinDiskSpace to ensure we can write block index - if (!CheckDiskSpace(GetBlocksDir())) { + if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) { return AbortNode(state, "Disk space is too low!", _("Disk space is too low!")); } // First make sure all block and undo data is flushed to disk. @@ -4523,12 +4523,12 @@ void BlockManager::FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPr static FlatFileSeq BlockFileSeq() { - return FlatFileSeq(GetBlocksDir(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE); + return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE); } static FlatFileSeq UndoFileSeq() { - return FlatFileSeq(GetBlocksDir(), "rev", UNDOFILE_CHUNK_SIZE); + return FlatFileSeq(gArgs.GetBlocksDirPath(), "rev", UNDOFILE_CHUNK_SIZE); } FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 757c663df8..a5d716c044 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5017,7 +5017,7 @@ bool CWallet::AutoBackupWallet(const fs::path& wallet_path, bilingual_str& error return false; } - fs::path backupsDir = GetBackupsDir(); + fs::path backupsDir = gArgs.GetBackupsDirPath(); backupsDir.make_preferred(); if (!fs::exists(backupsDir)) diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 8963a40fd0..ad80f4d94c 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -98,6 +98,8 @@ class WalletTest(BitcoinTestFramework): # but invisible if you include mempool txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) assert_equal(txout['value'], 500) + txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index) # by default include_mempool=True + assert txout is None txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) assert txout is None # new utxo from mempool should be invisible if you exclude mempool