Merge #5904: backport: Merge bitcoin#21712,21192, 21695,21244,21595

262fe0ada6 (followup) bitcoin#21244: Move GetBackupsDir to ArgsManager (Vijay)
1f4e26baf9 Merge #21595: cli: create -addrinfo (W. J. van der Laan)
6a45e72edd Merge #21244: Move GetDataDir to ArgsManager (fanquake)
4d28f3a67b Merge #21695: Remove no longer used contrib/bitcoin-qt.pro from the repo (fanquake)
9de77e8f46 Merge #21192: cli: Treat high detail levels as maximum in -netinfo (Wladimir J. van der Laan)
e22ebca746 Merge #21712: qa: Test default include_mempool value of gettxout (MarcoFalke)

Pull request description:

  backport: Merge bitcoin#21712,21192, 21695,21244,21595

Top commit has no ACKs.

Tree-SHA512: 61e72fa6db7aa0234cdccca91b3639dbfed6eabea4d9d65d25e89ac17de0b1d1b5eddf41985b1335bbd34ca71465a9760bf62ed33418a8d79a3d742156c52f35
This commit is contained in:
pasta 2024-04-16 09:20:46 -05:00
commit 44d9ac76f3
No known key found for this signature in database
GPG Key ID: 52527BEDABE87984
21 changed files with 318 additions and 244 deletions

View File

@ -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

View File

@ -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=<network>` or to upgrade to current and future Tor releases
that support Tor v3 addresses only. (#5904)

View File

@ -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. Its mostly automated, and you shouldnt need to worry about it.
**Example Qt translation**
```cpp
QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));

View File

@ -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=<file>", 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=<dir>", "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<std::string>& args) override
{
if (!args.empty()) {
throw std::runtime_error("-addrinfo takes no arguments");
}
UniValue params{RPCConvertValues("getnodeaddresses", std::vector<std::string>{{"0"}})};
return JSONRPCRequestObj("getnodeaddresses", params, 1);
}
UniValue ProcessReply(const UniValue& reply) override
{
if (!reply["error"].isNull()) return reply;
const std::vector<UniValue>& 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<uint64_t, m_networks.size()> 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<std::string, m_networks_size> m_networks{{"ipv4", "ipv6", "onion"}};
std::array<std::array<uint16_t, m_networks_size + 2>, 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<std::array<uint16_t, m_networks.size() + 2>, 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 {
@ -472,12 +527,12 @@ public:
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(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(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<std::string, 3> 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) {

View File

@ -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;
}

View File

@ -251,7 +251,7 @@ QString ClientModel::dataDir() const
QString ClientModel::blocksDir() const
{
return GUIUtil::boostPathToQString(GetBlocksDir());
return GUIUtil::boostPathToQString(gArgs.GetBlocksDirPath());
}
void ClientModel::updateBanlist()

View File

@ -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))

View File

@ -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";

View File

@ -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<BanMan>(GetDataDir() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = std::make_unique<CConnman>(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<BanMan>(GetDataDir() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = std::make_unique<CConnman>(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,

View File

@ -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;

View File

@ -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_₿_🏃";

View File

@ -17,7 +17,7 @@ namespace getarg_tests{
protected:
void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& 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<std::pair<std::string, unsigned int>>& 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.

View File

@ -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",

View File

@ -136,7 +136,8 @@ void DashTestSetupClose(NodeContext& node)
}
BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::vector<const char*>& 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<const char*> 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<const
throw std::runtime_error("LoadGenesisBlock failed.");
}
m_node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.banman = std::make_unique<BanMan>(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,

View File

@ -9,12 +9,12 @@
#include <chainparamsbase.h>
#include <fs.h>
#include <key.h>
#include <util/system.h>
#include <node/context.h>
#include <pubkey.h>
#include <random.h>
#include <txmempool.h>
#include <util/check.h>
#include <util/system.h>
#include <util/string.h>
#include <util/vector.h>
@ -90,6 +90,7 @@ struct BasicTestingSetup {
std::unique_ptr<CConnman> connman;
const fs::path m_path_root;
ArgsManager m_args;
};
/** Testing setup that performs all steps up until right before

View File

@ -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.

View File

@ -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<unsigned int> 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<std::string> ArgsManager::GetArgs(const std::string& strArg) const
{
std::vector<std::string> 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;

View File

@ -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<std::string> m_network_only_args GUARDED_BY(cs_args);
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
std::list<SectionInfo> 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<std::string, std::vector<util::SettingsValue>> 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
*

View File

@ -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<int>& 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) {

View File

@ -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))

View File

@ -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