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 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** **Example Qt translation**
```cpp ```cpp
QToolBar *toolbar = addToolBar(tr("Tabs toolbar")); 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 constexpr int DEFAULT_WAIT_CLIENT_TIMEOUT = 0;
static const bool DEFAULT_NAMED=false; static const bool DEFAULT_NAMED=false;
static const int CONTINUE_EXECUTION=-1; static const int CONTINUE_EXECUTION=-1;
static constexpr int8_t UNKNOWN_NETWORK{-1};
/** Default number of blocks to generate for RPC generatetoaddress. */ /** Default number of blocks to generate for RPC generatetoaddress. */
static const std::string DEFAULT_NBLOCKS = "1"; 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("-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("-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("-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("-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("-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); 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; 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 */ /** Process getinfo requests */
class GetinfoRequestHandler: public BaseRequestHandler class GetinfoRequestHandler: public BaseRequestHandler
{ {
@ -318,13 +374,12 @@ public:
class NetinfoRequestHandler : public BaseRequestHandler class NetinfoRequestHandler : public BaseRequestHandler
{ {
private: private:
static constexpr int8_t UNKNOWN_NETWORK{-1}; static constexpr uint8_t MAX_DETAIL_LEVEL{4};
static constexpr uint8_t m_networks_size{3}; static constexpr std::array m_networks{"ipv4", "ipv6", "onion"};
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)
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 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; if (str == m_networks.at(i)) return i;
} }
return UNKNOWN_NETWORK; return UNKNOWN_NETWORK;
@ -437,7 +492,7 @@ public:
if (!args.empty()) { if (!args.empty()) {
uint8_t n{0}; uint8_t n{0};
if (ParseUInt8(args.at(0), &n)) { 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") { } else if (args.at(0) == "help") {
m_is_help_requested = true; m_is_help_requested = true;
} else { } else {
@ -471,13 +526,13 @@ public:
if (network_id == UNKNOWN_NETWORK) continue; if (network_id == UNKNOWN_NETWORK) continue;
const bool is_outbound{!peer["inbound"].get_bool()}; const bool is_outbound{!peer["inbound"].get_bool()};
const bool is_block_relay{!peer["relaytxes"].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(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(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) { if (is_block_relay) {
++m_counts.at(is_outbound).at(m_networks_size + 1); // in/out 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(2).at(m_networks.size() + 1); // total block-relay
} }
if (DetailsRequested()) { if (DetailsRequested()) {
// Push data for this peer to the peers vector. // Push data for this peer to the peers vector.
@ -539,9 +594,9 @@ public:
// Report peer connection totals by type. // Report peer connection totals by type.
result += " ipv4 ipv6 onion total block-relay\n"; result += " ipv4 ipv6 onion total block-relay\n";
const std::array<std::string, 3> rows{{"in", "out", "total"}}; const std::array rows{"in", "out", "total"};
for (uint8_t i = 0; i < m_networks_size; ++i) { 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)); 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. // Report local addresses, ports, and scores.
@ -908,6 +963,8 @@ static int CommandLineRPC(int argc, char *argv[])
} else { } else {
ParseError(error, strPrint, nRet); ParseError(error, strPrint, nRet);
} }
} else if (gArgs.GetBoolArg("-addrinfo", false)) {
rh.reset(new AddrinfoRequestHandler());
} else { } else {
rh.reset(new DefaultRequestHandler()); rh.reset(new DefaultRequestHandler());
if (args.size() < 1) { 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 // Remove the rev files immediately and insert the blk file paths into an
// ordered map keyed by block file index. // ordered map keyed by block file index.
LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n"); 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++) { for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
if (fs::is_regular_file(*it) && if (fs::is_regular_file(*it) &&
it->path().filename().string().length() == 12 && it->path().filename().string().length() == 12 &&
@ -1197,7 +1197,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
InitWarning(warnings); 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", ""))); 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())); InitError(strprintf(_("Error: Disk space is low for %s"), GetDataDir()));
return false; return false;
} }
if (!CheckDiskSpace(GetBlocksDir())) { if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) {
InitError(strprintf(_("Error: Disk space is low for %s"), GetBlocksDir())); InitError(strprintf(_("Error: Disk space is low for %s"), gArgs.GetBlocksDirPath()));
return false; return false;
} }

View File

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

View File

@ -643,7 +643,7 @@ void openConfigfile()
void showBackups() void showBackups()
{ {
fs::path backupsDir = GetBackupsDir(); fs::path backupsDir = gArgs.GetBackupsDirPath();
/* Open folder with default browser */ /* Open folder with default browser */
if (fs::exists(backupsDir)) if (fs::exists(backupsDir))

View File

@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
{ {
// Perform tests both obfuscated and non-obfuscated. // Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) { 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); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
uint8_t key{'k'}; uint8_t key{'k'};
uint256 in = InsecureRand256(); uint256 in = InsecureRand256();
@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_basic_data)
{ {
// Perform tests both obfuscated and non-obfuscated. // Perform tests both obfuscated and non-obfuscated.
for (bool obfuscate : {false, true}) { 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); CDBWrapper dbw(ph, (1 << 20), false, true, obfuscate);
uint256 res; uint256 res;
@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{ {
// Perform tests both obfuscated and non-obfuscated. // Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) { 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); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
uint8_t key{'i'}; uint8_t key{'i'};
@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{ {
// Perform tests both obfuscated and non-obfuscated. // Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) { 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); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
// The two keys are intentionally chosen for ordering // 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) BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
{ {
// We're going to share this fs::path between two wrappers // 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); create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data. // 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) BOOST_AUTO_TEST_CASE(existing_data_reindex)
{ {
// We're going to share this fs::path between two wrappers // 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); create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data. // 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) 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); CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<256; ++x) { for (int x=0x00; x<256; ++x) {
uint8_t key = x; uint8_t key = x;
@ -358,7 +358,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
{ {
char buf[10]; 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); CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<10; ++x) { for (int x=0x00; x<10; ++x) {
for (int y = 0; y < 10; y++) { 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 // On Windows this test will fail if the directory is created using
// the ANSI CreateDirectoryA call and the code page isn't UTF8. // the ANSI CreateDirectoryA call and the code page isn't UTF8.
// It will succeed if created with CreateDirectoryW. // 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)); CDBWrapper dbw(ph, (1 << 20));
fs::path lockPath = ph / "LOCK"; 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) BOOST_AUTO_TEST_CASE(peer_discouragement)
{ {
const CChainParams& chainparams = Params(); 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 connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(), *m_node.scheduler, 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, *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) BOOST_AUTO_TEST_CASE(DoS_bantime)
{ {
const CChainParams& chainparams = Params(); 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 connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(), *m_node.scheduler, 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, *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) BOOST_AUTO_TEST_CASE(flatfile_filename)
{ {
const auto data_dir = GetDataDir(); const auto data_dir = m_args.GetDataDirPath();
FlatFilePos pos(456, 789); FlatFilePos pos(456, 789);
@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(flatfile_filename)
BOOST_AUTO_TEST_CASE(flatfile_open) 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); FlatFileSeq seq(data_dir, "a", 16 * 1024);
std::string line1("A purely peer-to-peer version of electronic cash would allow online " 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) BOOST_AUTO_TEST_CASE(flatfile_allocate)
{ {
const auto data_dir = GetDataDir(); const auto data_dir = m_args.GetDataDirPath();
FlatFileSeq seq(data_dir, "a", 100); FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space; bool out_of_space;
@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(flatfile_allocate)
BOOST_AUTO_TEST_CASE(flatfile_flush) BOOST_AUTO_TEST_CASE(flatfile_flush)
{ {
const auto data_dir = GetDataDir(); const auto data_dir = m_args.GetDataDirPath();
FlatFileSeq seq(data_dir, "a", 100); FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space; bool out_of_space;

View File

@ -13,7 +13,7 @@ BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(fsbridge_fstream) BOOST_AUTO_TEST_CASE(fsbridge_fstream)
{ {
fs::path tmpfolder = GetDataDir(); fs::path tmpfolder = m_args.GetDataDirPath();
// tmpfile1 should be the same as tmpfile2 // tmpfile1 should be the same as tmpfile2
fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃"; fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃";
fs::path tmpfile2 = tmpfolder / "fs_tests_₿_🏃"; fs::path tmpfile2 = tmpfolder / "fs_tests_₿_🏃";

View File

@ -17,7 +17,7 @@ namespace getarg_tests{
protected: protected:
void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args); void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args);
void ResetArgs(const std::string& strArg); 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()); vecChar.push_back(s.c_str());
std::string error; 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) 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) { 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); const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY);
SetupArgs({foo}); SetupArgs({foo});
ResetArgs("-foo"); ResetArgs("-foo");
BOOST_CHECK(m_args.GetBoolArg("-foo", false)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
BOOST_CHECK(m_args.GetBoolArg("-foo", true)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
BOOST_CHECK(!m_args.GetBoolArg("-fo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-fo", false));
BOOST_CHECK(m_args.GetBoolArg("-fo", true)); BOOST_CHECK(m_local_args.GetBoolArg("-fo", true));
BOOST_CHECK(!m_args.GetBoolArg("-fooo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-fooo", false));
BOOST_CHECK(m_args.GetBoolArg("-fooo", true)); BOOST_CHECK(m_local_args.GetBoolArg("-fooo", true));
ResetArgs("-foo=0"); ResetArgs("-foo=0");
BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
ResetArgs("-foo=1"); ResetArgs("-foo=1");
BOOST_CHECK(m_args.GetBoolArg("-foo", false)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
BOOST_CHECK(m_args.GetBoolArg("-foo", true)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
// New 0.6 feature: auto-map -nosomething to !-something: // New 0.6 feature: auto-map -nosomething to !-something:
ResetArgs("-nofoo"); ResetArgs("-nofoo");
BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
ResetArgs("-nofoo=1"); ResetArgs("-nofoo=1");
BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
ResetArgs("-foo -nofoo"); // -nofoo should win ResetArgs("-foo -nofoo"); // -nofoo should win
BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
ResetArgs("-foo=1 -nofoo=1"); // -nofoo should win ResetArgs("-foo=1 -nofoo=1"); // -nofoo should win
BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
ResetArgs("-foo=0 -nofoo=0"); // -nofoo=0 should win ResetArgs("-foo=0 -nofoo=0"); // -nofoo=0 should win
BOOST_CHECK(m_args.GetBoolArg("-foo", false)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
BOOST_CHECK(m_args.GetBoolArg("-foo", true)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
// New 0.6 feature: treat -- same as -: // New 0.6 feature: treat -- same as -:
ResetArgs("--foo=1"); ResetArgs("--foo=1");
BOOST_CHECK(m_args.GetBoolArg("-foo", false)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
BOOST_CHECK(m_args.GetBoolArg("-foo", true)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
ResetArgs("--nofoo=1"); ResetArgs("--nofoo=1");
BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); 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); const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar}); SetupArgs({foo, bar});
ResetArgs(""); ResetArgs("");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), ""); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "eleven"); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "eleven");
ResetArgs("-foo -bar"); ResetArgs("-foo -bar");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), ""); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), ""); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "");
ResetArgs("-foo="); ResetArgs("-foo=");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), ""); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), ""); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "");
ResetArgs("-foo=11"); ResetArgs("-foo=11");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "11"); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "11");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "11"); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "11");
ResetArgs("-foo=eleven"); ResetArgs("-foo=eleven");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "eleven"); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "eleven");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", "eleven"), "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); const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar}); SetupArgs({foo, bar});
ResetArgs(""); ResetArgs("");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 11), 11); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 11), 11);
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 0), 0); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 0), 0);
ResetArgs("-foo -bar"); ResetArgs("-foo -bar");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 11), 0); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 11), 0);
BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 0); BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0);
ResetArgs("-foo=11 -bar=12"); ResetArgs("-foo=11 -bar=12");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 0), 11); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 0), 11);
BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 12); BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 12);
ResetArgs("-foo=NaN -bar=NotANumber"); ResetArgs("-foo=NaN -bar=NotANumber");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", 1), 0); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 1), 0);
BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 11), 0); BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0);
} }
BOOST_AUTO_TEST_CASE(doubledash) BOOST_AUTO_TEST_CASE(doubledash)
@ -159,11 +159,11 @@ BOOST_AUTO_TEST_CASE(doubledash)
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar}); SetupArgs({foo, bar});
ResetArgs("--foo"); 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"); ResetArgs("--foo=verbose --bar=1");
BOOST_CHECK_EQUAL(m_args.GetArg("-foo", ""), "verbose"); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "verbose");
BOOST_CHECK_EQUAL(m_args.GetArg("-bar", 0), 1); BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 0), 1);
} }
BOOST_AUTO_TEST_CASE(boolargno) BOOST_AUTO_TEST_CASE(boolargno)
@ -172,24 +172,24 @@ BOOST_AUTO_TEST_CASE(boolargno)
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
SetupArgs({foo, bar}); SetupArgs({foo, bar});
ResetArgs("-nofoo"); ResetArgs("-nofoo");
BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
ResetArgs("-nofoo=1"); ResetArgs("-nofoo=1");
BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
ResetArgs("-nofoo=0"); ResetArgs("-nofoo=0");
BOOST_CHECK(m_args.GetBoolArg("-foo", true)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
BOOST_CHECK(m_args.GetBoolArg("-foo", false)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
ResetArgs("-foo --nofoo"); // --nofoo should win ResetArgs("-foo --nofoo"); // --nofoo should win
BOOST_CHECK(!m_args.GetBoolArg("-foo", true)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true));
BOOST_CHECK(!m_args.GetBoolArg("-foo", false)); BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false));
ResetArgs("-nofoo -foo"); // foo always wins: ResetArgs("-nofoo -foo"); // foo always wins:
BOOST_CHECK(m_args.GetBoolArg("-foo", true)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", true));
BOOST_CHECK(m_args.GetBoolArg("-foo", false)); BOOST_CHECK(m_local_args.GetBoolArg("-foo", false));
} }
BOOST_AUTO_TEST_CASE(logargs) BOOST_AUTO_TEST_CASE(logargs)
@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(logargs)
}); });
// Log the arguments // Log the arguments
m_args.LogArgs(); m_local_args.LogArgs();
LogInstance().DeleteCallback(print_connection); LogInstance().DeleteCallback(print_connection);
// Check that what should appear does, and what shouldn't doesn't. // 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) BOOST_AUTO_TEST_CASE(ReadWrite)
{ {
fs::path path = GetDataDir() / "settings.json"; fs::path path = m_args.GetDataDirPath() / "settings.json";
WriteText(path, R"({ WriteText(path, R"({
"string": "string", "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) 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( const std::vector<const char*> arguments = Cat(
{ {
@ -152,8 +153,9 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
extra_args); extra_args);
util::ThreadRename("test"); util::ThreadRename("test");
fs::create_directories(m_path_root); fs::create_directories(m_path_root);
m_args.ForceSetArg("-datadir", m_path_root.string());
gArgs.ForceSetArg("-datadir", m_path_root.string()); gArgs.ForceSetArg("-datadir", m_path_root.string());
ClearDatadirCache(); gArgs.ClearPathCache();
{ {
SetupServerArgs(m_node); SetupServerArgs(m_node);
std::string error; std::string error;
@ -283,7 +285,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
throw std::runtime_error("LoadGenesisBlock failed."); 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.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.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, *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 <chainparamsbase.h>
#include <fs.h> #include <fs.h>
#include <key.h> #include <key.h>
#include <util/system.h>
#include <node/context.h> #include <node/context.h>
#include <pubkey.h> #include <pubkey.h>
#include <random.h> #include <random.h>
#include <txmempool.h> #include <txmempool.h>
#include <util/check.h> #include <util/check.h>
#include <util/system.h>
#include <util/string.h> #include <util/string.h>
#include <util/vector.h> #include <util/vector.h>
@ -90,6 +90,7 @@ struct BasicTestingSetup {
std::unique_ptr<CConnman> connman; std::unique_ptr<CConnman> connman;
const fs::path m_path_root; const fs::path m_path_root;
ArgsManager m_args;
}; };
/** Testing setup that performs all steps up until right before /** 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) BOOST_AUTO_TEST_CASE(util_datadir)
{ {
ClearDatadirCache(); // Use local args variable instead of m_args to avoid making assumptions about test setup
const fs::path dd_norm = GetDataDir(); ArgsManager args;
args.ForceSetArg("-datadir", m_path_root.string());
gArgs.ForceSetArg("-datadir", dd_norm.string() + "/"); const fs::path dd_norm = args.GetDataDirPath();
ClearDatadirCache();
BOOST_CHECK_EQUAL(dd_norm, GetDataDir());
gArgs.ForceSetArg("-datadir", dd_norm.string() + "/."); args.ForceSetArg("-datadir", dd_norm.string() + "/");
ClearDatadirCache(); args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
gArgs.ForceSetArg("-datadir", dd_norm.string() + "/./"); args.ForceSetArg("-datadir", dd_norm.string() + "/.");
ClearDatadirCache(); args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
gArgs.ForceSetArg("-datadir", dd_norm.string() + "/.//"); args.ForceSetArg("-datadir", dd_norm.string() + "/./");
ClearDatadirCache(); args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
args.ForceSetArg("-datadir", dd_norm.string() + "/.//");
args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
} }
namespace { namespace {
@ -1256,21 +1259,23 @@ BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
{ {
// Test writing setting. // Test writing setting.
TestArgsManager args1; TestArgsManager args1;
args1.ForceSetArg("-datadir", m_path_root.string());
args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; }); args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; });
args1.WriteSettingsFile(); args1.WriteSettingsFile();
// Test reading setting. // Test reading setting.
TestArgsManager args2; TestArgsManager args2;
args2.ForceSetArg("-datadir", m_path_root.string());
args2.ReadSettingsFile(); args2.ReadSettingsFile();
args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); }); args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); });
// Test error logging, and remove previously written setting. // Test error logging, and remove previously written setting.
{ {
ASSERT_DEBUG_LOG("Failed renaming settings file"); ASSERT_DEBUG_LOG("Failed renaming settings file");
fs::remove(GetDataDir() / "settings.json"); fs::remove(args1.GetDataDirPath() / "settings.json");
fs::create_directory(GetDataDir() / "settings.json"); fs::create_directory(args1.GetDataDirPath() / "settings.json");
args2.WriteSettingsFile(); 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) 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"; const std::string lockname = ".lock";
#ifndef WIN32 #ifndef WIN32
// Revert SIGCHLD to default, otherwise boost.test will catch and fail on // 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) BOOST_AUTO_TEST_CASE(test_DirIsWritable)
{ {
// Should be able to write to the data dir. // 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); BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
// Should not be able to write to a non-existent dir. // 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; 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 // Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to
// #include class definitions for all members. // #include class definitions for all members.
// For example, m_settings has an internal dependency on univalue. // 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; 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> ArgsManager::GetArgs(const std::string& strArg) const
{ {
std::vector<std::string> result; std::vector<std::string> result;
@ -424,7 +511,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const
} }
if (filepath) { if (filepath) {
std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME); 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; return true;
} }
@ -718,87 +805,14 @@ fs::path GetDefaultDataDir()
#endif #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) const fs::path &GetDataDir(bool fNetSpecific)
{ {
LOCK(csPathCached); return gArgs.GetDataDirPath(fNetSpecific);
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;
} }
fs::path GetBackupsDir() fs::path GetBackupsDir()
{ {
if (!gArgs.IsArgSet("-walletbackupsdir")) return gArgs.GetBackupsDirPath();
return GetDataDir() / "backups";
return fs::absolute(gArgs.GetArg("-walletbackupsdir", ""));
} }
bool CheckDataDirOption() bool CheckDataDirOption()
@ -807,15 +821,6 @@ bool CheckDataDirOption()
return datadir.empty() || fs::is_directory(fs::system_complete(datadir)); 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) fs::path GetConfigFile(const std::string& confPath)
{ {
return AbsPathForConfigVal(fs::path(confPath), false); 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: // If datadir is changed in .conf file:
ClearDatadirCache(); gArgs.ClearPathCache();
if (!CheckDataDirOption()) { if (!CheckDataDirOption()) {
error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", "")); error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", ""));
return false; return false;

View File

@ -97,14 +97,9 @@ void ReleaseDirectoryLocks();
bool TryCreateDirectories(const fs::path& p); bool TryCreateDirectories(const fs::path& p);
fs::path GetDefaultDataDir(); fs::path GetDefaultDataDir();
// The blocks directory is always net specific.
const fs::path &GetBlocksDir();
const fs::path &GetDataDir(bool fNetSpecific = true); const fs::path &GetDataDir(bool fNetSpecific = true);
fs::path GetBackupsDir();
// Return true if -datadir option points to a valid directory or is not specified. // Return true if -datadir option points to a valid directory or is not specified.
bool CheckDataDirOption(); bool CheckDataDirOption();
/** Tests only */
void ClearDatadirCache();
fs::path GetConfigFile(const std::string& confPath); fs::path GetConfigFile(const std::string& confPath);
#ifdef WIN32 #ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true); 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::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::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
std::list<SectionInfo> m_config_sections 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); [[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; 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 * 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. // Write blocks and block index to disk.
if (fDoFullFlush || fPeriodicWrite) { if (fDoFullFlush || fPeriodicWrite) {
// Depend on nMinDiskSpace to ensure we can write block index // 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!")); 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. // 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() 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() 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) { 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; return false;
} }
fs::path backupsDir = GetBackupsDir(); fs::path backupsDir = gArgs.GetBackupsDirPath();
backupsDir.make_preferred(); backupsDir.make_preferred();
if (!fs::exists(backupsDir)) if (!fs::exists(backupsDir))

View File

@ -98,6 +98,8 @@ class WalletTest(BitcoinTestFramework):
# but invisible if you include mempool # but invisible if you include mempool
txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False)
assert_equal(txout['value'], 500) 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) txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True)
assert txout is None assert txout is None
# new utxo from mempool should be invisible if you exclude mempool # new utxo from mempool should be invisible if you exclude mempool