aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/init.cpp8
-rw-r--r--[-rwxr-xr-x]src/net_processing.cpp0
-rw-r--r--src/qt/clientmodel.cpp2
-rw-r--r--src/script/descriptor.cpp189
-rw-r--r--src/test/dbwrapper_tests.cpp18
-rw-r--r--src/test/denialofservice_tests.cpp4
-rw-r--r--src/test/descriptor_tests.cpp12
-rw-r--r--src/test/flatfile_tests.cpp8
-rw-r--r--src/test/fs_tests.cpp2
-rw-r--r--src/test/getarg_tests.cpp120
-rw-r--r--src/test/settings_tests.cpp2
-rw-r--r--src/test/util/setup_common.cpp8
-rw-r--r--src/test/util/setup_common.h2
-rw-r--r--src/test/util_tests.cpp43
-rw-r--r--src/test/versionbits_tests.cpp64
-rw-r--r--src/util/system.cpp164
-rw-r--r--src/util/system.h28
-rw-r--r--src/validation.cpp6
18 files changed, 359 insertions, 321 deletions
diff --git a/src/init.cpp b/src/init.cpp
index 07e882c9df..741e70f748 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -637,7 +637,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 &&
@@ -919,7 +919,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", "")));
}
@@ -1759,8 +1759,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
InitError(strprintf(_("Error: Disk space is low for %s"), GetDataDir()));
return false;
}
- if (!CheckDiskSpace(GetBlocksDir())) {
- InitError(strprintf(_("Error: Disk space is low for %s"), GetBlocksDir()));
+ if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) {
+ InitError(strprintf(_("Error: Disk space is low for %s"), gArgs.GetBlocksDirPath()));
return false;
}
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index b3927b5ec5..b3927b5ec5 100755..100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index b244bc94f2..f2c555de52 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -216,7 +216,7 @@ QString ClientModel::dataDir() const
QString ClientModel::blocksDir() const
{
- return GUIUtil::boostPathToQString(GetBlocksDir());
+ return GUIUtil::boostPathToQString(gArgs.GetBlocksDirPath());
}
void ClientModel::updateBanlist()
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 30399dca51..f1433553bc 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -481,34 +481,35 @@ class DescriptorImpl : public Descriptor
const std::string m_name;
protected:
- //! The sub-descriptor argument (nullptr for everything but SH and WSH).
+ //! The sub-descriptor arguments (empty for everything but SH and WSH).
//! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT)
//! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions.
- const std::unique_ptr<DescriptorImpl> m_subdescriptor_arg;
+ //! Subdescriptors can only ever generate a single script.
+ const std::vector<std::unique_ptr<DescriptorImpl>> m_subdescriptor_args;
//! Return a serialization of anything except pubkey and script arguments, to be prepended to those.
virtual std::string ToStringExtra() const { return ""; }
/** A helper function to construct the scripts for this descriptor.
*
- * This function is invoked once for every CScript produced by evaluating
- * m_subdescriptor_arg, or just once in case m_subdescriptor_arg is nullptr.
-
+ * This function is invoked once by ExpandHelper.
+ *
* @param pubkeys The evaluations of the m_pubkey_args field.
- * @param script The evaluation of m_subdescriptor_arg (or nullptr when m_subdescriptor_arg is nullptr).
+ * @param scripts The evaluations of m_subdescriptor_args (one for each m_subdescriptor_args element).
* @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver.
- * The script arguments to this function are automatically added, as is the origin info of the provided pubkeys.
+ * The origin info of the provided pubkeys is automatically added.
* @return A vector with scriptPubKeys for this descriptor.
*/
- virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0;
+ virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, Span<const CScript> scripts, FlatSigningProvider& out) const = 0;
public:
- DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_arg(std::move(script)) {}
+ DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args() {}
+ DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args(Vector(std::move(script))) {}
bool IsSolvable() const override
{
- if (m_subdescriptor_arg) {
- if (!m_subdescriptor_arg->IsSolvable()) return false;
+ for (const auto& arg : m_subdescriptor_args) {
+ if (!arg->IsSolvable()) return false;
}
return true;
}
@@ -518,12 +519,24 @@ public:
for (const auto& pubkey : m_pubkey_args) {
if (pubkey->IsRange()) return true;
}
- if (m_subdescriptor_arg) {
- if (m_subdescriptor_arg->IsRange()) return true;
+ for (const auto& arg : m_subdescriptor_args) {
+ if (arg->IsRange()) return true;
}
return false;
}
+ virtual bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, bool priv, bool normalized) const
+ {
+ size_t pos = 0;
+ for (const auto& scriptarg : m_subdescriptor_args) {
+ if (pos++) ret += ",";
+ std::string tmp;
+ if (!scriptarg->ToStringHelper(arg, tmp, priv, normalized)) return false;
+ ret += std::move(tmp);
+ }
+ return true;
+ }
+
bool ToStringHelper(const SigningProvider* arg, std::string& out, bool priv, bool normalized) const
{
std::string extra = ToStringExtra();
@@ -541,13 +554,10 @@ public:
}
ret += std::move(tmp);
}
- if (m_subdescriptor_arg) {
- if (pos++) ret += ",";
- std::string tmp;
- if (!m_subdescriptor_arg->ToStringHelper(arg, tmp, priv, normalized)) return false;
- ret += std::move(tmp);
- }
- out = std::move(ret) + ")";
+ std::string subscript;
+ if (!ToStringSubScriptHelper(arg, subscript, priv, normalized)) return false;
+ if (pos && subscript.size()) ret += ',';
+ out = std::move(ret) + std::move(subscript) + ")";
return true;
}
@@ -577,17 +587,20 @@ public:
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
entries.reserve(m_pubkey_args.size());
- // Construct temporary data in `entries` and `subscripts`, to avoid producing output in case of failure.
+ // Construct temporary data in `entries`, `subscripts`, and `subprovider` to avoid producing output in case of failure.
for (const auto& p : m_pubkey_args) {
entries.emplace_back();
if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second, read_cache, write_cache)) return false;
}
std::vector<CScript> subscripts;
- if (m_subdescriptor_arg) {
- FlatSigningProvider subprovider;
- if (!m_subdescriptor_arg->ExpandHelper(pos, arg, read_cache, subscripts, subprovider, write_cache)) return false;
- out = Merge(out, subprovider);
+ FlatSigningProvider subprovider;
+ for (const auto& subarg : m_subdescriptor_args) {
+ std::vector<CScript> outscripts;
+ if (!subarg->ExpandHelper(pos, arg, read_cache, outscripts, subprovider, write_cache)) return false;
+ assert(outscripts.size() == 1);
+ subscripts.emplace_back(std::move(outscripts[0]));
}
+ out = Merge(std::move(out), std::move(subprovider));
std::vector<CPubKey> pubkeys;
pubkeys.reserve(entries.size());
@@ -595,17 +608,8 @@ public:
pubkeys.push_back(entry.first);
out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
}
- if (m_subdescriptor_arg) {
- for (const auto& subscript : subscripts) {
- out.scripts.emplace(CScriptID(subscript), subscript);
- std::vector<CScript> addscripts = MakeScripts(pubkeys, &subscript, out);
- for (auto& addscript : addscripts) {
- output_scripts.push_back(std::move(addscript));
- }
- }
- } else {
- output_scripts = MakeScripts(pubkeys, nullptr, out);
- }
+
+ output_scripts = MakeScripts(pubkeys, MakeSpan(subscripts), out);
return true;
}
@@ -626,10 +630,8 @@ public:
if (!p->GetPrivKey(pos, provider, key)) continue;
out.keys.emplace(key.GetPubKey().GetID(), key);
}
- if (m_subdescriptor_arg) {
- FlatSigningProvider subprovider;
- m_subdescriptor_arg->ExpandPrivate(pos, provider, subprovider);
- out = Merge(out, subprovider);
+ for (const auto& arg : m_subdescriptor_args) {
+ arg->ExpandPrivate(pos, provider, out);
}
}
@@ -642,9 +644,9 @@ class AddressDescriptor final : public DescriptorImpl
const CTxDestination m_destination;
protected:
std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
public:
- AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
+ AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, "addr"), m_destination(std::move(destination)) {}
bool IsSolvable() const final { return false; }
std::optional<OutputType> GetOutputType() const override
@@ -668,9 +670,9 @@ class RawDescriptor final : public DescriptorImpl
const CScript m_script;
protected:
std::string ToStringExtra() const override { return HexStr(m_script); }
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(m_script); }
public:
- RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
+ RawDescriptor(CScript script) : DescriptorImpl({}, "raw"), m_script(std::move(script)) {}
bool IsSolvable() const final { return false; }
std::optional<OutputType> GetOutputType() const override
@@ -694,9 +696,9 @@ public:
class PKDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
public:
- PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pk") {}
+ PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pk") {}
bool IsSingleType() const final { return true; }
};
@@ -704,14 +706,14 @@ public:
class PKHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
{
CKeyID id = keys[0].GetID();
out.pubkeys.emplace(id, keys[0]);
return Vector(GetScriptForDestination(PKHash(id)));
}
public:
- PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {}
+ PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pkh") {}
std::optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; }
bool IsSingleType() const final { return true; }
};
@@ -720,14 +722,14 @@ public:
class WPKHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
{
CKeyID id = keys[0].GetID();
out.pubkeys.emplace(id, keys[0]);
return Vector(GetScriptForDestination(WitnessV0KeyHash(id)));
}
public:
- WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "wpkh") {}
+ WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "wpkh") {}
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
bool IsSingleType() const final { return true; }
};
@@ -736,7 +738,7 @@ public:
class ComboDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
{
std::vector<CScript> ret;
CKeyID id = keys[0].GetID();
@@ -752,7 +754,7 @@ protected:
return ret;
}
public:
- ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "combo") {}
+ ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "combo") {}
bool IsSingleType() const final { return false; }
};
@@ -763,7 +765,7 @@ class MultisigDescriptor final : public DescriptorImpl
const bool m_sorted;
protected:
std::string ToStringExtra() const override { return strprintf("%i", m_threshold); }
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override {
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override {
if (m_sorted) {
std::vector<CPubKey> sorted_keys(keys);
std::sort(sorted_keys.begin(), sorted_keys.end());
@@ -772,7 +774,7 @@ protected:
return Vector(GetScriptForMultisig(m_threshold, keys));
}
public:
- MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), {}, sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
+ MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
bool IsSingleType() const final { return true; }
};
@@ -780,14 +782,19 @@ public:
class SHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(ScriptHash(*script))); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override
+ {
+ auto ret = Vector(GetScriptForDestination(ScriptHash(scripts[0])));
+ if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]);
+ return ret;
+ }
public:
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
std::optional<OutputType> GetOutputType() const override
{
- assert(m_subdescriptor_arg);
- if (m_subdescriptor_arg->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
+ assert(m_subdescriptor_args.size() == 1);
+ if (m_subdescriptor_args[0]->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
return OutputType::LEGACY;
}
bool IsSingleType() const final { return true; }
@@ -797,7 +804,12 @@ public:
class WSHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(WitnessV0ScriptHash(*script))); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override
+ {
+ auto ret = Vector(GetScriptForDestination(WitnessV0ScriptHash(scripts[0])));
+ if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]);
+ return ret;
+ }
public:
WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
@@ -809,9 +821,10 @@ public:
////////////////////////////////////////////////////////////////////////////
enum class ParseScriptContext {
- TOP,
- P2SH,
- P2WSH,
+ TOP, //!< Top-level context (script goes directly in scriptPubKey)
+ P2SH, //!< Inside sh() (script becomes P2SH redeemScript)
+ P2WPKH, //!< Inside wpkh() (no script, pubkey only)
+ P2WSH, //!< Inside wsh() (script becomes v0 witness script)
};
/** Parse a key path, being passed a split list of elements (the first element is ignored). */
@@ -838,10 +851,11 @@ enum class ParseScriptContext {
}
/** Parse a public key that excludes origin information. */
-std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
+std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
{
using namespace spanparsing;
+ bool permit_uncompressed = ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH;
auto split = Split(sp, '/');
std::string str(split[0].begin(), split[0].end());
if (str.size() == 0) {
@@ -899,7 +913,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
}
/** Parse a public key including origin information (if enabled). */
-std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
+std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
{
using namespace spanparsing;
@@ -908,7 +922,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
error = "Multiple ']' characters found for a single pubkey";
return nullptr;
}
- if (origin_split.size() == 1) return ParsePubkeyInner(key_exp_index, origin_split[0], permit_uncompressed, out, error);
+ if (origin_split.size() == 1) return ParsePubkeyInner(key_exp_index, origin_split[0], ctx, out, error);
if (origin_split[0].empty() || origin_split[0][0] != '[') {
error = strprintf("Key origin start '[ character expected but not found, got '%c' instead",
origin_split[0].empty() ? /** empty, implies split char */ ']' : origin_split[0][0]);
@@ -930,34 +944,37 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
assert(fpr_bytes.size() == 4);
std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint);
if (!ParseKeyPath(slash_split, info.path, error)) return nullptr;
- auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], permit_uncompressed, out, error);
+ auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, error);
if (!provider) return nullptr;
return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider));
}
/** Parse a script in a particular context. */
-std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
+std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
{
using namespace spanparsing;
auto expr = Expr(sp);
bool sorted_multi = false;
if (Func("pk", expr)) {
- auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2WSH, out, error);
+ auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error);
if (!pubkey) return nullptr;
+ ++key_exp_index;
return std::make_unique<PKDescriptor>(std::move(pubkey));
}
if (Func("pkh", expr)) {
- auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2WSH, out, error);
+ auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error);
if (!pubkey) return nullptr;
+ ++key_exp_index;
return std::make_unique<PKHDescriptor>(std::move(pubkey));
}
if (ctx == ParseScriptContext::TOP && Func("combo", expr)) {
- auto pubkey = ParsePubkey(key_exp_index, expr, true, out, error);
+ auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error);
if (!pubkey) return nullptr;
+ ++key_exp_index;
return std::make_unique<ComboDescriptor>(std::move(pubkey));
- } else if (ctx != ParseScriptContext::TOP && Func("combo", expr)) {
- error = "Cannot have combo in non-top level";
+ } else if (Func("combo", expr)) {
+ error = "Can only have combo() at top level";
return nullptr;
}
if ((sorted_multi = Func("sortedmulti", expr)) || Func("multi", expr)) {
@@ -975,7 +992,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
return nullptr;
}
auto arg = Expr(expr);
- auto pk = ParsePubkey(key_exp_index, arg, ctx != ParseScriptContext::P2WSH, out, error);
+ auto pk = ParsePubkey(key_exp_index, arg, ctx, out, error);
if (!pk) return nullptr;
script_size += pk->GetSize() + 1;
providers.emplace_back(std::move(pk));
@@ -1005,28 +1022,29 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
}
return std::make_unique<MultisigDescriptor>(thres, std::move(providers), sorted_multi);
}
- if (ctx != ParseScriptContext::P2WSH && Func("wpkh", expr)) {
- auto pubkey = ParsePubkey(key_exp_index, expr, false, out, error);
+ if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wpkh", expr)) {
+ auto pubkey = ParsePubkey(key_exp_index, expr, ParseScriptContext::P2WPKH, out, error);
if (!pubkey) return nullptr;
+ key_exp_index++;
return std::make_unique<WPKHDescriptor>(std::move(pubkey));
- } else if (ctx == ParseScriptContext::P2WSH && Func("wpkh", expr)) {
- error = "Cannot have wpkh within wsh";
+ } else if (Func("wpkh", expr)) {
+ error = "Can only have wpkh() at top level or inside sh()";
return nullptr;
}
if (ctx == ParseScriptContext::TOP && Func("sh", expr)) {
auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error);
if (!desc || expr.size()) return nullptr;
return std::make_unique<SHDescriptor>(std::move(desc));
- } else if (ctx != ParseScriptContext::TOP && Func("sh", expr)) {
- error = "Cannot have sh in non-top level";
+ } else if (Func("sh", expr)) {
+ error = "Can only have sh() at top level";
return nullptr;
}
- if (ctx != ParseScriptContext::P2WSH && Func("wsh", expr)) {
+ if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wsh", expr)) {
auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2WSH, out, error);
if (!desc || expr.size()) return nullptr;
return std::make_unique<WSHDescriptor>(std::move(desc));
- } else if (ctx == ParseScriptContext::P2WSH && Func("wsh", expr)) {
- error = "Cannot have wsh within wsh";
+ } else if (Func("wsh", expr)) {
+ error = "Can only have wsh() at top level or inside sh()";
return nullptr;
}
if (ctx == ParseScriptContext::TOP && Func("addr", expr)) {
@@ -1036,6 +1054,9 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
return nullptr;
}
return std::make_unique<AddressDescriptor>(std::move(dest));
+ } else if (Func("addr", expr)) {
+ error = "Can only have addr() at top level";
+ return nullptr;
}
if (ctx == ParseScriptContext::TOP && Func("raw", expr)) {
std::string str(expr.begin(), expr.end());
@@ -1045,6 +1066,9 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const c
}
auto bytes = ParseHex(str);
return std::make_unique<RawDescriptor>(CScript(bytes.begin(), bytes.end()));
+ } else if (Func("raw", expr)) {
+ error = "Can only have raw() at top level";
+ return nullptr;
}
if (ctx == ParseScriptContext::P2SH) {
error = "A function is needed within P2SH";
@@ -1174,7 +1198,8 @@ std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProv
{
Span<const char> sp{descriptor};
if (!CheckChecksum(sp, require_checksum, error)) return nullptr;
- auto ret = ParseScript(0, sp, ParseScriptContext::TOP, out, error);
+ uint32_t key_exp_index = 0;
+ auto ret = ParseScript(key_exp_index, sp, ParseScriptContext::TOP, out, error);
if (sp.size() == 0 && ret) return std::unique_ptr<Descriptor>(std::move(ret));
return nullptr;
}
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index a6080ad3dd..b5f3bb2fa4 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false");
+ fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char 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);
char key = 'i';
@@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");
+ fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
// The two keys are intentionally chosen for ordering
@@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
{
// We're going to share this fs::path between two wrappers
- fs::path ph = GetDataDir() / "existing_data_no_obfuscate";
+ fs::path ph = m_args.GetDataDirPath() / "existing_data_no_obfuscate";
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
@@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
BOOST_AUTO_TEST_CASE(existing_data_reindex)
{
// We're going to share this fs::path between two wrappers
- fs::path ph = GetDataDir() / "existing_data_reindex";
+ fs::path ph = m_args.GetDataDirPath() / "existing_data_reindex";
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
@@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_AUTO_TEST_CASE(iterator_ordering)
{
- fs::path ph = GetDataDir() / "iterator_ordering";
+ fs::path ph = m_args.GetDataDirPath() / "iterator_ordering";
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<256; ++x) {
uint8_t key = x;
@@ -358,7 +358,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
{
char buf[10];
- fs::path ph = GetDataDir() / "iterator_string_ordering";
+ fs::path ph = m_args.GetDataDirPath() / "iterator_string_ordering";
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<10; ++x) {
for (int y = 0; y < 10; y++) {
@@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(unicodepath)
// On Windows this test will fail if the directory is created using
// the ANSI CreateDirectoryA call and the code page isn't UTF8.
// It will succeed if created with CreateDirectoryW.
- fs::path ph = GetDataDir() / "test_runner_₿_🏃_20191128_104644";
+ fs::path ph = m_args.GetDataDirPath() / "test_runner_₿_🏃_20191128_104644";
CDBWrapper dbw(ph, (1 << 20));
fs::path lockPath = ph / "LOCK";
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 599e628685..ddf0e0ca90 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -208,7 +208,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.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = std::make_unique<CConnmanTest>(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, false);
@@ -302,7 +302,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.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", 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, false);
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index aecf955fee..ea41a03728 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -24,7 +24,7 @@ void CheckUnparsable(const std::string& prv, const std::string& pub, const std::
auto parse_pub = Parse(pub, keys_pub, error);
BOOST_CHECK_MESSAGE(!parse_priv, prv);
BOOST_CHECK_MESSAGE(!parse_pub, pub);
- BOOST_CHECK(error == expected_error);
+ BOOST_CHECK_EQUAL(error, expected_error);
}
constexpr int DEFAULT = 0;
@@ -355,12 +355,12 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
// Check for invalid nesting of structures
CheckUnparsable("sh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2SH"); // P2SH needs a script, not a key
- CheckUnparsable("sh(combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Cannot have combo in non-top level"); // Old must be top level
+ CheckUnparsable("sh(combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Can only have combo() at top level"); // Old must be top level
CheckUnparsable("wsh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wsh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2WSH"); // P2WSH needs a script, not a key
- CheckUnparsable("wsh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Cannot have wpkh within wsh"); // Cannot embed witness inside witness
- CheckUnparsable("wsh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have sh in non-top level"); // Cannot embed P2SH inside P2WSH
- CheckUnparsable("sh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have sh in non-top level"); // Cannot embed P2SH inside P2SH
- CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Cannot have wsh within wsh"); // Cannot embed P2WSH inside P2WSH
+ CheckUnparsable("wsh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Can only have wpkh() at top level or inside sh()"); // Cannot embed witness inside witness
+ CheckUnparsable("wsh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have sh() at top level"); // Cannot embed P2SH inside P2WSH
+ CheckUnparsable("sh(sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have sh() at top level"); // Cannot embed P2SH inside P2SH
+ CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have wsh() at top level or inside sh()"); // Cannot embed P2WSH inside P2WSH
// Checksums
Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index 0c5c19113d..9194ed8130 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -14,7 +14,7 @@ BOOST_FIXTURE_TEST_SUITE(flatfile_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(flatfile_filename)
{
- const auto data_dir = GetDataDir();
+ const auto data_dir = m_args.GetDataDirPath();
FlatFilePos pos(456, 789);
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(flatfile_filename)
BOOST_AUTO_TEST_CASE(flatfile_open)
{
- const auto data_dir = GetDataDir();
+ const auto data_dir = m_args.GetDataDirPath();
FlatFileSeq seq(data_dir, "a", 16 * 1024);
std::string line1("A purely peer-to-peer version of electronic cash would allow online "
@@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
BOOST_AUTO_TEST_CASE(flatfile_allocate)
{
- const auto data_dir = GetDataDir();
+ const auto data_dir = m_args.GetDataDirPath();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
@@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(flatfile_allocate)
BOOST_AUTO_TEST_CASE(flatfile_flush)
{
- const auto data_dir = GetDataDir();
+ const auto data_dir = m_args.GetDataDirPath();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index e52cd5230c..452bc06bbb 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -13,7 +13,7 @@ BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(fsbridge_fstream)
{
- fs::path tmpfolder = GetDataDir();
+ fs::path tmpfolder = m_args.GetDataDirPath();
// tmpfile1 should be the same as tmpfile2
fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃";
fs::path tmpfile2 = tmpfolder / "fs_tests_₿_🏃";
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 45c9b90ee9..2a217f3455 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -18,7 +18,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.
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index 548fd020a6..f5ae9f86d1 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -45,7 +45,7 @@ BOOST_FIXTURE_TEST_SUITE(settings_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(ReadWrite)
{
- fs::path path = GetDataDir() / "settings.json";
+ fs::path path = m_args.GetDataDirPath() / "settings.json";
WriteText(path, R"({
"string": "string",
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 2e7f64a444..ffc5115145 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -71,7 +71,8 @@ std::ostream& operator<<(std::ostream& os, const uint256& num)
}
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(
{
@@ -87,8 +88,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;
@@ -191,7 +193,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
}
m_node.addrman = std::make_unique<CAddrMan>();
- m_node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman,
m_node.banman.get(), *m_node.scheduler, *m_node.chainman,
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index a32f1f3805..b19dd75765 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -8,6 +8,7 @@
#include <chainparamsbase.h>
#include <fs.h>
#include <key.h>
+#include <util/system.h>
#include <node/context.h>
#include <pubkey.h>
#include <random.h>
@@ -80,6 +81,7 @@ struct BasicTestingSetup {
~BasicTestingSetup();
const fs::path m_path_root;
+ ArgsManager m_args;
};
/** Testing setup that performs all steps up until right before
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index a1ac9ead69..04b908829b 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -49,24 +49,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());
}
BOOST_AUTO_TEST_CASE(util_check)
@@ -1143,21 +1146,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");
}
}
@@ -1796,7 +1801,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
@@ -1885,7 +1890,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
BOOST_AUTO_TEST_CASE(test_DirIsWritable)
{
// Should be able to write to the data dir.
- fs::path tmpdirname = GetDataDir();
+ fs::path tmpdirname = m_args.GetDataDirPath();
BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
// Should not be able to write to a non-existent dir.
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index 05838ec19a..304cd8feb0 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -81,11 +81,9 @@ class VersionBitsTester
TestNeverActiveConditionChecker checker_never[CHECKERS];
// Test counter (to identify failures)
- int num;
+ int num{1000};
public:
- VersionBitsTester() : num(1000) {}
-
VersionBitsTester& Reset() {
// Have each group of tests be counted by the 1000s part, starting at 1000
num = num - (num % 1000) + 1000;
@@ -257,39 +255,6 @@ BOOST_AUTO_TEST_CASE(versionbits_test)
}
}
-BOOST_AUTO_TEST_CASE(versionbits_sanity)
-{
- // Sanity checks of version bit deployments
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
- const Consensus::Params &mainnetParams = chainParams->GetConsensus();
- for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
- uint32_t bitmask = VersionBitsMask(mainnetParams, static_cast<Consensus::DeploymentPos>(i));
- // Make sure that no deployment tries to set an invalid bit.
- BOOST_CHECK_EQUAL(bitmask & ~(uint32_t)VERSIONBITS_TOP_MASK, bitmask);
-
- // Check min_activation_height is on a retarget boundary
- BOOST_CHECK_EQUAL(mainnetParams.vDeployments[i].min_activation_height % mainnetParams.nMinerConfirmationWindow, 0);
- // Check min_activation_height is 0 for ALWAYS_ACTIVE and never active deployments
- if (mainnetParams.vDeployments[i].nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE || mainnetParams.vDeployments[i].nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) {
- BOOST_CHECK_EQUAL(mainnetParams.vDeployments[i].min_activation_height, 0);
- }
-
- // Verify that the deployment windows of different deployment using the
- // same bit are disjoint.
- // This test may need modification at such time as a new deployment
- // is proposed that reuses the bit of an activated soft fork, before the
- // end time of that soft fork. (Alternatively, the end time of that
- // activated soft fork could be later changed to be earlier to avoid
- // overlap.)
- for (int j=i+1; j<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; j++) {
- if (VersionBitsMask(mainnetParams, static_cast<Consensus::DeploymentPos>(j)) == bitmask) {
- BOOST_CHECK(mainnetParams.vDeployments[j].nStartTime > mainnetParams.vDeployments[i].nTimeout ||
- mainnetParams.vDeployments[i].nStartTime > mainnetParams.vDeployments[j].nTimeout);
- }
- }
- }
-}
-
/** Check that ComputeBlockVersion will set the appropriate bit correctly */
static void check_computeblockversion(const Consensus::Params& params, Consensus::DeploymentPos dep)
{
@@ -305,16 +270,25 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus
BOOST_CHECK_EQUAL(ComputeBlockVersion(nullptr, params), VERSIONBITS_TOP_BITS);
// always/never active deployments shouldn't need to be tested further
- if (nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE) return;
- if (nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) return;
+ if (nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE ||
+ nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE)
+ {
+ BOOST_CHECK_EQUAL(min_activation_height, 0);
+ return;
+ }
BOOST_REQUIRE(nStartTime < nTimeout);
BOOST_REQUIRE(nStartTime >= 0);
BOOST_REQUIRE(nTimeout <= std::numeric_limits<uint32_t>::max() || nTimeout == Consensus::BIP9Deployment::NO_TIMEOUT);
BOOST_REQUIRE(0 <= bit && bit < 32);
+ // Make sure that no deployment tries to set an invalid bit.
BOOST_REQUIRE(((1 << bit) & VERSIONBITS_TOP_MASK) == 0);
BOOST_REQUIRE(min_activation_height >= 0);
- BOOST_REQUIRE_EQUAL(min_activation_height % params.nMinerConfirmationWindow, 0);
+ // Check min_activation_height is on a retarget boundary
+ BOOST_REQUIRE_EQUAL(min_activation_height % params.nMinerConfirmationWindow, 0U);
+
+ const uint32_t bitmask{VersionBitsMask(params, dep)};
+ BOOST_CHECK_EQUAL(bitmask, uint32_t{1} << bit);
// In the first chain, test that the bit is set by CBV until it has failed.
// In the second chain, test the bit is set by CBV while STARTED and
@@ -443,8 +417,18 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// ACTIVE and FAILED states in roughly the way we expect
for (const auto& chain_name : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET, CBaseChainParams::REGTEST}) {
const auto chainParams = CreateChainParams(*m_node.args, chain_name);
+ uint32_t chain_all_vbits{0};
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) {
- check_computeblockversion(chainParams->GetConsensus(), static_cast<Consensus::DeploymentPos>(i));
+ const auto dep = static_cast<Consensus::DeploymentPos>(i);
+ // Check that no bits are re-used (within the same chain). This is
+ // disallowed because the transition to FAILED (on timeout) does
+ // not take precedence over STARTED/LOCKED_IN. So all softforks on
+ // the same bit might overlap, even when non-overlapping start-end
+ // times are picked.
+ const uint32_t dep_mask{VersionBitsMask(chainParams->GetConsensus(), dep)};
+ BOOST_CHECK(!(chain_all_vbits & dep_mask));
+ chain_all_vbits |= dep_mask;
+ check_computeblockversion(chainParams->GetConsensus(), dep);
}
}
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 0b83a76504..9b3bd46b38 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -235,6 +235,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.
@@ -375,6 +388,72 @@ 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;
+}
+
+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::optional<const ArgsManager::Command> ArgsManager::GetCommand() const
{
Command ret;
@@ -434,7 +513,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;
}
@@ -723,79 +802,9 @@ 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);
}
bool CheckDataDirOption()
@@ -804,15 +813,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);
@@ -971,7 +971,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
}
// If datadir is changed in .conf file:
- ClearDatadirCache();
+ gArgs.ClearPathCache();
if (!CheckDataDirOption()) {
error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", ""));
return false;
diff --git a/src/util/system.h b/src/util/system.h
index 29657e56e2..61f862c93a 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -91,13 +91,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);
// 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);
@@ -200,6 +196,9 @@ protected:
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
bool m_accept_any_command GUARDED_BY(cs_args){true};
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 +263,27 @@ public:
std::optional<const Command> GetCommand() 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;
+
+ /**
+ * Clear cached directory paths
+ */
+ void ClearPathCache();
+
+ /**
* Return a vector of strings of the given argument
*
* @param strArg Argument to get (e.g. "-foo")
diff --git a/src/validation.cpp b/src/validation.cpp
index 332cb581b8..2bf505e26b 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2204,7 +2204,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!"));
}
{
@@ -3890,12 +3890,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) {