aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am14
-rw-r--r--src/Makefile.qt.include14
-rw-r--r--src/Makefile.test.include3
-rw-r--r--src/addrdb.cpp20
-rw-r--r--src/bench/rpc_blockchain.cpp4
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/bitcoin-tx.cpp19
-rw-r--r--src/chainparams.cpp28
-rw-r--r--src/core_io.h11
-rw-r--r--src/core_read.cpp53
-rw-r--r--src/core_write.cpp31
-rw-r--r--src/dbwrapper.cpp26
-rw-r--r--src/flatfile.cpp4
-rw-r--r--src/fs.cpp8
-rw-r--r--src/fs.h132
-rw-r--r--src/hash.cpp5
-rw-r--r--src/i2p.cpp2
-rw-r--r--src/init.cpp26
-rw-r--r--src/init/common.cpp14
-rw-r--r--src/interfaces/chain.h2
-rw-r--r--src/ipc/process.cpp4
-rw-r--r--src/key.cpp5
-rw-r--r--src/logging.cpp1
-rw-r--r--src/logging.h1
-rw-r--r--src/node/blockstorage.cpp19
-rw-r--r--src/node/interfaces.cpp2
-rw-r--r--src/policy/fees.cpp4
-rw-r--r--src/policy/policy.cpp7
-rw-r--r--src/pubkey.cpp5
-rw-r--r--src/qt/bitcoin.cpp3
-rw-r--r--src/qt/guiutil.cpp10
-rw-r--r--src/qt/guiutil.h5
-rw-r--r--src/qt/intro.cpp2
-rw-r--r--src/qt/rpcconsole.cpp9
-rw-r--r--src/qt/walletcontroller.cpp24
-rw-r--r--src/qt/walletcontroller.h2
-rw-r--r--src/rest.cpp20
-rw-r--r--src/rpc/blockchain.cpp61
-rw-r--r--src/rpc/blockchain.h3
-rw-r--r--src/rpc/request.cpp8
-rw-r--r--src/rpc/server.cpp2
-rw-r--r--src/test/fs_tests.cpp27
-rw-r--r--src/test/fuzz/addrman.cpp147
-rw-r--r--src/test/fuzz/banman.cpp4
-rw-r--r--src/test/script_parse_tests.cpp55
-rw-r--r--src/test/settings_tests.cpp6
-rw-r--r--src/test/util/chainstate.h2
-rw-r--r--src/test/util/setup_common.cpp4
-rw-r--r--src/test/util_tests.cpp26
-rw-r--r--src/test/validation_chainstate_tests.cpp23
-rw-r--r--src/torcontrol.cpp8
-rw-r--r--src/util/asmap.cpp4
-rw-r--r--src/util/settings.cpp12
-rw-r--r--src/util/strencodings.h4
-rw-r--r--src/util/syscall_sandbox.cpp38
-rw-r--r--src/util/system.cpp28
-rw-r--r--src/validation.cpp34
-rw-r--r--src/wallet/bdb.cpp38
-rw-r--r--src/wallet/bdb.h4
-rw-r--r--src/wallet/coincontrol.h2
-rw-r--r--src/wallet/db.cpp15
-rw-r--r--src/wallet/dump.cpp10
-rw-r--r--src/wallet/interfaces.cpp4
-rw-r--r--src/wallet/load.cpp16
-rw-r--r--src/wallet/rpcdump.cpp8
-rw-r--r--src/wallet/rpcwallet.cpp153
-rw-r--r--src/wallet/scriptpubkeyman.cpp2
-rw-r--r--src/wallet/spend.cpp4
-rw-r--r--src/wallet/sqlite.cpp4
-rw-r--r--src/wallet/test/db_tests.cpp8
-rw-r--r--src/wallet/test/init_test_fixture.cpp8
-rw-r--r--src/wallet/test/init_tests.cpp8
-rw-r--r--src/wallet/test/wallet_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp6
-rw-r--r--src/wallet/walletdb.cpp16
-rw-r--r--src/wallet/wallettool.cpp2
-rw-r--r--src/wallet/walletutil.cpp2
77 files changed, 820 insertions, 529 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 12fdc9ad75..9d15120b72 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -808,20 +808,8 @@ clean-local:
$(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@
check-symbols: $(bin_PROGRAMS)
-if TARGET_DARWIN
- @echo "Checking macOS dynamic libraries..."
+ @echo "Running symbol and dynamic library checks..."
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
-endif
-
-if TARGET_WINDOWS
- @echo "Checking Windows dynamic libraries..."
- $(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
-endif
-
-if TARGET_LINUX
- @echo "Checking glibc back compat..."
- $(AM_V_at) CPPFILT='$(CPPFILT)' $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
-endif
check-security: $(bin_PROGRAMS)
if HARDEN
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index f4b0b3adbe..1e3d75a8d8 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -168,10 +168,10 @@ BITCOIN_QT_H = \
qt/walletview.h \
qt/winshutdownmonitor.h
-RES_FONTS = \
+QT_RES_FONTS = \
qt/res/fonts/RobotoMono-Bold.ttf
-RES_ICONS = \
+QT_RES_ICONS = \
qt/res/icons/add.png \
qt/res/icons/address-book.png \
qt/res/icons/bitcoin.ico \
@@ -287,9 +287,9 @@ if ENABLE_WALLET
BITCOIN_QT_CPP += $(BITCOIN_QT_WALLET_CPP)
endif # ENABLE_WALLET
-RES_ANIMATION = $(wildcard $(srcdir)/qt/res/animation/spinner-*.png)
+QT_RES_ANIMATION = $(wildcard $(srcdir)/qt/res/animation/spinner-*.png)
-BITCOIN_RC = qt/res/bitcoin-qt-res.rc
+BITCOIN_QT_RC = qt/res/bitcoin-qt-res.rc
BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS -DQT_USE_QSTRINGBUILDER
@@ -299,7 +299,7 @@ qt_libbitcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS)
qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
- $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(RES_FONTS) $(RES_ICONS) $(RES_ANIMATION)
+ $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(QT_RES_FONTS) $(QT_RES_ICONS) $(QT_RES_ANIMATION)
if TARGET_DARWIN
qt_libbitcoinqt_a_SOURCES += $(BITCOIN_MM)
endif
@@ -321,7 +321,7 @@ bitcoin_qt_cxxflags = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
bitcoin_qt_sources = qt/main.cpp
if TARGET_WINDOWS
- bitcoin_qt_sources += $(BITCOIN_RC)
+ bitcoin_qt_sources += $(BITCOIN_QT_RC)
endif
bitcoin_qt_ldadd = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER)
if ENABLE_WALLET
@@ -371,7 +371,7 @@ $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM)
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin_locale --format-version 1 $(@D)/temp_$(<F) > $@
@rm $(@D)/temp_$(<F)
-$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_FONTS) $(RES_ICONS) $(RES_ANIMATION)
+$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(QT_RES_FONTS) $(QT_RES_ICONS) $(QT_RES_ANIMATION)
@test -f $(RCC)
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin --format-version 1 $< > $@
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index be63214c23..d70793ffa9 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -119,8 +119,9 @@ BITCOIN_TESTS =\
test/sanity_tests.cpp \
test/scheduler_tests.cpp \
test/script_p2sh_tests.cpp \
- test/script_tests.cpp \
+ test/script_parse_tests.cpp \
test/script_standard_tests.cpp \
+ test/script_tests.cpp \
test/scriptnum_tests.cpp \
test/serfloat_tests.cpp \
test/serialize_tests.cpp \
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 50fd09101e..bdb1fc6b2b 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -58,7 +58,7 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
if (fileout.IsNull()) {
fileout.fclose();
remove(pathTmp);
- return error("%s: Failed to open file %s", __func__, pathTmp.string());
+ return error("%s: Failed to open file %s", __func__, fs::PathToString(pathTmp));
}
// Serialize
@@ -70,7 +70,7 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
if (!FileCommit(fileout.Get())) {
fileout.fclose();
remove(pathTmp);
- return error("%s: Failed to flush file %s", __func__, pathTmp.string());
+ return error("%s: Failed to flush file %s", __func__, fs::PathToString(pathTmp));
}
fileout.fclose();
@@ -122,8 +122,8 @@ void DeserializeFileDB(const fs::path& path, Data& data, int version)
} // namespace
CBanDB::CBanDB(fs::path ban_list_path)
- : m_banlist_dat(ban_list_path.string() + ".dat"),
- m_banlist_json(ban_list_path.string() + ".json")
+ : m_banlist_dat(ban_list_path + ".dat"),
+ m_banlist_json(ban_list_path + ".json")
{
}
@@ -143,7 +143,7 @@ bool CBanDB::Write(const banmap_t& banSet)
bool CBanDB::Read(banmap_t& banSet)
{
if (fs::exists(m_banlist_dat)) {
- LogPrintf("banlist.dat ignored because it can only be read by " PACKAGE_NAME " version 22.x. Remove %s to silence this warning.\n", m_banlist_dat);
+ LogPrintf("banlist.dat ignored because it can only be read by " PACKAGE_NAME " version 22.x. Remove %s to silence this warning.\n", fs::quoted(fs::PathToString(m_banlist_dat)));
}
// If the JSON banlist does not exist, then recreate it
if (!fs::exists(m_banlist_json)) {
@@ -155,7 +155,7 @@ bool CBanDB::Read(banmap_t& banSet)
if (!util::ReadSettings(m_banlist_json, settings, errors)) {
for (const auto& err : errors) {
- LogPrintf("Cannot load banlist %s: %s\n", m_banlist_json.string(), err);
+ LogPrintf("Cannot load banlist %s: %s\n", fs::PathToString(m_banlist_json), err);
}
return false;
}
@@ -163,7 +163,7 @@ bool CBanDB::Read(banmap_t& banSet)
try {
BanMapFromJson(settings[JSON_KEY], banSet);
} catch (const std::runtime_error& e) {
- LogPrintf("Cannot parse banlist %s: %s\n", m_banlist_json.string(), e.what());
+ LogPrintf("Cannot parse banlist %s: %s\n", fs::PathToString(m_banlist_json), e.what());
return false;
}
@@ -194,12 +194,12 @@ std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const A
} catch (const DbNotFoundError&) {
// Addrman can be in an inconsistent state after failure, reset it
addrman = std::make_unique<AddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman);
- LogPrintf("Creating peers.dat because the file was not found (%s)\n", path_addr);
+ LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr)));
DumpPeerAddresses(args, *addrman);
} catch (const std::exception& e) {
addrman = nullptr;
return strprintf(_("Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start."),
- e.what(), PACKAGE_BUGREPORT, path_addr);
+ e.what(), PACKAGE_BUGREPORT, fs::quoted(fs::PathToString(path_addr)));
}
return std::nullopt;
}
@@ -215,7 +215,7 @@ std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
std::vector<CAddress> anchors;
try {
DeserializeFileDB(anchors_db_path, anchors, CLIENT_VERSION | ADDRV2_FORMAT);
- LogPrintf("Loaded %i addresses from %s\n", anchors.size(), anchors_db_path.filename());
+ LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename())));
} catch (const std::exception&) {
anchors.clear();
}
diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp
index c8886a4c23..3bef64f720 100644
--- a/src/bench/rpc_blockchain.cpp
+++ b/src/bench/rpc_blockchain.cpp
@@ -40,7 +40,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench)
{
TestBlockAndIndex data;
bench.run([&] {
- auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, /*verbose*/ true);
+ auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
ankerl::nanobench::doNotOptimizeAway(univalue);
});
}
@@ -50,7 +50,7 @@ BENCHMARK(BlockToJsonVerbose);
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
{
TestBlockAndIndex data;
- auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, /*verbose*/ true);
+ auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
bench.run([&] {
auto str = univalue.write();
ankerl::nanobench::doNotOptimizeAway(str);
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 3c22ee0f67..43e986a765 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -786,7 +786,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
if (failedToGetAuthCookie) {
throw std::runtime_error(strprintf(
"Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)",
- GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string()));
+ fs::PathToString(GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)))));
} else {
throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
}
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index fc3bc6aa71..eb97cfc6f6 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -235,6 +235,16 @@ static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInId
}
}
+template <typename T>
+static T TrimAndParse(const std::string& int_str, const std::string& err)
+{
+ const auto parsed{ToIntegral<T>(TrimString(int_str))};
+ if (!parsed.has_value()) {
+ throw std::runtime_error(err + " '" + int_str + "'");
+ }
+ return parsed.value();
+}
+
static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
{
std::vector<std::string> vStrInputParts;
@@ -261,8 +271,9 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
// extract the optional sequence number
uint32_t nSequenceIn = CTxIn::SEQUENCE_FINAL;
- if (vStrInputParts.size() > 2)
- nSequenceIn = std::stoul(vStrInputParts[2]);
+ if (vStrInputParts.size() > 2) {
+ nSequenceIn = TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid TX sequence id");
+ }
// append to transaction input list
CTxIn txin(txid, vout, CScript(), nSequenceIn);
@@ -352,10 +363,10 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
// Extract REQUIRED
- uint32_t required = stoul(vStrInputParts[1]);
+ const uint32_t required{TrimAndParse<uint32_t>(vStrInputParts.at(1), "invalid multisig required number")};
// Extract NUMKEYS
- uint32_t numkeys = stoul(vStrInputParts[2]);
+ const uint32_t numkeys{TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid multisig total number")};
// Validate there are the correct number of pubkeys
if (vStrInputParts.size() < numkeys + 3)
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index b155745794..2e823c1211 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -118,15 +118,15 @@ public:
// This is fine at runtime as we'll fall back to using them as an addrfetch if they don't support the
// service bits we want, but we should get them updated to support all service bits wanted by any
// release ASAP to avoid it where possible.
- vSeeds.emplace_back("seed.bitcoin.sipa.be"); // Pieter Wuille, only supports x1, x5, x9, and xd
- vSeeds.emplace_back("dnsseed.bluematt.me"); // Matt Corallo, only supports x9
- vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org"); // Luke Dashjr
- vSeeds.emplace_back("seed.bitcoinstats.com"); // Christian Decker, supports x1 - xf
- vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch"); // Jonas Schnelli, only supports x1, x5, x9, and xd
- vSeeds.emplace_back("seed.btc.petertodd.org"); // Peter Todd, only supports x1, x5, x9, and xd
- vSeeds.emplace_back("seed.bitcoin.sprovoost.nl"); // Sjors Provoost
- vSeeds.emplace_back("dnsseed.emzy.de"); // Stephan Oeste
- vSeeds.emplace_back("seed.bitcoin.wiz.biz"); // Jason Maurice
+ vSeeds.emplace_back("seed.bitcoin.sipa.be."); // Pieter Wuille, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("dnsseed.bluematt.me."); // Matt Corallo, only supports x9
+ vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org."); // Luke Dashjr
+ vSeeds.emplace_back("seed.bitcoinstats.com."); // Christian Decker, supports x1 - xf
+ vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch."); // Jonas Schnelli, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("seed.btc.petertodd.org."); // Peter Todd, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("seed.bitcoin.sprovoost.nl."); // Sjors Provoost
+ vSeeds.emplace_back("dnsseed.emzy.de."); // Stephan Oeste
+ vSeeds.emplace_back("seed.bitcoin.wiz.biz."); // Jason Maurice
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
@@ -230,10 +230,10 @@ public:
vFixedSeeds.clear();
vSeeds.clear();
// nodes with support for servicebits filtering should be at the top
- vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch");
- vSeeds.emplace_back("seed.tbtc.petertodd.org");
- vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl");
- vSeeds.emplace_back("testnet-seed.bluematt.me"); // Just a static list of stable node(s), only supports x9
+ vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch.");
+ vSeeds.emplace_back("seed.tbtc.petertodd.org.");
+ vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl.");
+ vSeeds.emplace_back("testnet-seed.bluematt.me."); // Just a static list of stable node(s), only supports x9
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
@@ -280,7 +280,7 @@ public:
if (!args.IsArgSet("-signetchallenge")) {
bin = ParseHex("512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae");
- vSeeds.emplace_back("seed.signet.bitcoin.sprovoost.nl");
+ vSeeds.emplace_back("seed.signet.bitcoin.sprovoost.nl.");
// Hardcoded nodes can be removed once there are more DNS seeds
vSeeds.emplace_back("178.128.221.177");
diff --git a/src/core_io.h b/src/core_io.h
index be93a17efe..4d7199ab12 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -20,6 +20,15 @@ class uint256;
class UniValue;
class CTxUndo;
+/**
+ * Verbose level for block's transaction
+ */
+enum class TxVerbosity {
+ SHOW_TXID, //!< Only TXID for each block's transaction
+ SHOW_DETAILS, //!< Include TXID, inputs, outputs, and other common block's transaction information
+ SHOW_DETAILS_AND_PREVOUT //!< The same as previous option with information about prevouts if available
+};
+
// core_read.cpp
CScript ParseScript(const std::string& s);
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
@@ -46,6 +55,6 @@ std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);
std::string SighashToStr(unsigned char sighash_type);
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool include_hex, bool include_address = true);
void ScriptToUniv(const CScript& script, UniValue& out);
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr);
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr, TxVerbosity verbosity = TxVerbosity::SHOW_DETAILS);
#endif // BITCOIN_CORE_IO_H
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 320811b9e9..2149b428d2 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -26,20 +26,20 @@ opcodetype ParseOpCode(const std::string& s)
{
static std::map<std::string, opcodetype> mapOpNames;
- if (mapOpNames.empty())
- {
- for (unsigned int op = 0; op <= MAX_OPCODE; op++)
- {
+ if (mapOpNames.empty()) {
+ for (unsigned int op = 0; op <= MAX_OPCODE; op++) {
// Allow OP_RESERVED to get into mapOpNames
- if (op < OP_NOP && op != OP_RESERVED)
+ if (op < OP_NOP && op != OP_RESERVED) {
continue;
+ }
std::string strName = GetOpName(static_cast<opcodetype>(op));
- if (strName == "OP_UNKNOWN")
+ if (strName == "OP_UNKNOWN") {
continue;
+ }
mapOpNames[strName] = static_cast<opcodetype>(op);
// Convenience: OP_ADD and just ADD are both recognized:
- if (strName.compare(0, 3, "OP_") == 0) { // strName starts with "OP_"
+ if (strName.compare(0, 3, "OP_") == 0) { // strName starts with "OP_"
mapOpNames[strName.substr(3)] = static_cast<opcodetype>(op);
}
}
@@ -59,44 +59,35 @@ CScript ParseScript(const std::string& s)
std::vector<std::string> words;
boost::algorithm::split(words, s, boost::algorithm::is_any_of(" \t\n"), boost::algorithm::token_compress_on);
- for (std::vector<std::string>::const_iterator w = words.begin(); w != words.end(); ++w)
- {
- if (w->empty())
- {
+ for (const std::string& w : words) {
+ if (w.empty()) {
// Empty string, ignore. (boost::split given '' will return one word)
- }
- else if (std::all_of(w->begin(), w->end(), ::IsDigit) ||
- (w->front() == '-' && w->size() > 1 && std::all_of(w->begin()+1, w->end(), ::IsDigit)))
+ } else if (std::all_of(w.begin(), w.end(), ::IsDigit) ||
+ (w.front() == '-' && w.size() > 1 && std::all_of(w.begin() + 1, w.end(), ::IsDigit)))
{
// Number
- int64_t n = LocaleIndependentAtoi<int64_t>(*w);
+ const auto num{ToIntegral<int64_t>(w)};
- //limit the range of numbers ParseScript accepts in decimal
- //since numbers outside -0xFFFFFFFF...0xFFFFFFFF are illegal in scripts
- if (n > int64_t{0xffffffff} || n < -1 * int64_t{0xffffffff}) {
+ // limit the range of numbers ParseScript accepts in decimal
+ // since numbers outside -0xFFFFFFFF...0xFFFFFFFF are illegal in scripts
+ if (!num.has_value() || num > int64_t{0xffffffff} || num < -1 * int64_t{0xffffffff}) {
throw std::runtime_error("script parse error: decimal numeric value only allowed in the "
"range -0xFFFFFFFF...0xFFFFFFFF");
}
- result << n;
- }
- else if (w->substr(0,2) == "0x" && w->size() > 2 && IsHex(std::string(w->begin()+2, w->end())))
- {
+ result << num.value();
+ } else if (w.substr(0, 2) == "0x" && w.size() > 2 && IsHex(std::string(w.begin() + 2, w.end()))) {
// Raw hex data, inserted NOT pushed onto stack:
- std::vector<unsigned char> raw = ParseHex(std::string(w->begin()+2, w->end()));
+ std::vector<unsigned char> raw = ParseHex(std::string(w.begin() + 2, w.end()));
result.insert(result.end(), raw.begin(), raw.end());
- }
- else if (w->size() >= 2 && w->front() == '\'' && w->back() == '\'')
- {
+ } else if (w.size() >= 2 && w.front() == '\'' && w.back() == '\'') {
// Single-quoted string, pushed as data. NOTE: this is poor-man's
// parsing, spaces/tabs/newlines in single-quoted strings won't work.
- std::vector<unsigned char> value(w->begin()+1, w->end()-1);
+ std::vector<unsigned char> value(w.begin() + 1, w.end() - 1);
result << value;
- }
- else
- {
+ } else {
// opcode, e.g. OP_ADD or ADD:
- result << ParseOpCode(*w);
+ result << ParseOpCode(w);
}
}
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 6b13e4c586..468694b011 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -163,7 +163,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool include
out.pushKV("type", GetTxnOutputType(type));
}
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo)
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo, TxVerbosity verbosity)
{
entry.pushKV("txid", tx.GetHash().GetHex());
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
@@ -179,7 +179,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
// If available, use Undo data to calculate the fee. Note that txundo == nullptr
// for coinbase transactions and for transactions where undo data is unavailable.
- const bool calculate_fee = txundo != nullptr;
+ const bool have_undo = txundo != nullptr;
CAmount amt_total_in = 0;
CAmount amt_total_out = 0;
@@ -203,9 +203,28 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
}
in.pushKV("txinwitness", txinwitness);
}
- if (calculate_fee) {
- const CTxOut& prev_txout = txundo->vprevout[i].out;
+ if (have_undo) {
+ const Coin& prev_coin = txundo->vprevout[i];
+ const CTxOut& prev_txout = prev_coin.out;
+
amt_total_in += prev_txout.nValue;
+ switch (verbosity) {
+ case TxVerbosity::SHOW_TXID:
+ case TxVerbosity::SHOW_DETAILS:
+ break;
+
+ case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
+ UniValue o_script_pub_key(UniValue::VOBJ);
+ ScriptPubKeyToUniv(prev_txout.scriptPubKey, o_script_pub_key, /* includeHex */ true);
+
+ UniValue p(UniValue::VOBJ);
+ p.pushKV("generated", bool(prev_coin.fCoinBase));
+ p.pushKV("height", uint64_t(prev_coin.nHeight));
+ p.pushKV("value", ValueFromAmount(prev_txout.nValue));
+ p.pushKV("scriptPubKey", o_script_pub_key);
+ in.pushKV("prevout", p);
+ break;
+ }
}
in.pushKV("sequence", (int64_t)txin.nSequence);
vin.push_back(in);
@@ -226,13 +245,13 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
out.pushKV("scriptPubKey", o);
vout.push_back(out);
- if (calculate_fee) {
+ if (have_undo) {
amt_total_out += txout.nValue;
}
}
entry.pushKV("vout", vout);
- if (calculate_fee) {
+ if (have_undo) {
const CAmount fee = amt_total_in - amt_total_out;
CHECK_NONFATAL(MoneyRange(fee));
entry.pushKV("fee", ValueFromAmount(fee));
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 3a1086bf4c..2fdc54464a 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -115,7 +115,7 @@ static leveldb::Options GetOptions(size_t nCacheSize)
}
CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
- : m_name{path.stem().string()}
+ : m_name{fs::PathToString(path.stem())}
{
penv = nullptr;
readoptions.verify_checksums = true;
@@ -129,21 +129,21 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo
options.env = penv;
} else {
if (fWipe) {
- LogPrintf("Wiping LevelDB in %s\n", path.string());
- leveldb::Status result = leveldb::DestroyDB(path.string(), options);
+ LogPrintf("Wiping LevelDB in %s\n", fs::PathToString(path));
+ leveldb::Status result = leveldb::DestroyDB(fs::PathToString(path), options);
dbwrapper_private::HandleError(result);
}
TryCreateDirectories(path);
- LogPrintf("Opening LevelDB in %s\n", path.string());
+ LogPrintf("Opening LevelDB in %s\n", fs::PathToString(path));
}
- leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
+ leveldb::Status status = leveldb::DB::Open(options, fs::PathToString(path), &pdb);
dbwrapper_private::HandleError(status);
LogPrintf("Opened LevelDB successfully\n");
if (gArgs.GetBoolArg("-forcecompactdb", false)) {
- LogPrintf("Starting database compaction of %s\n", path.string());
+ LogPrintf("Starting database compaction of %s\n", fs::PathToString(path));
pdb->CompactRange(nullptr, nullptr);
- LogPrintf("Finished database compaction of %s\n", path.string());
+ LogPrintf("Finished database compaction of %s\n", fs::PathToString(path));
}
// The base-case obfuscation key, which is a noop.
@@ -160,10 +160,10 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo
Write(OBFUSCATE_KEY_KEY, new_key);
obfuscate_key = new_key;
- LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), HexStr(obfuscate_key));
+ LogPrintf("Wrote new obfuscate key for %s: %s\n", fs::PathToString(path), HexStr(obfuscate_key));
}
- LogPrintf("Using obfuscation key for %s: %s\n", path.string(), HexStr(obfuscate_key));
+ LogPrintf("Using obfuscation key for %s: %s\n", fs::PathToString(path), HexStr(obfuscate_key));
}
CDBWrapper::~CDBWrapper()
@@ -197,13 +197,15 @@ bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
return true;
}
-size_t CDBWrapper::DynamicMemoryUsage() const {
+size_t CDBWrapper::DynamicMemoryUsage() const
+{
std::string memory;
- if (!pdb->GetProperty("leveldb.approximate-memory-usage", &memory)) {
+ std::optional<size_t> parsed;
+ if (!pdb->GetProperty("leveldb.approximate-memory-usage", &memory) || !(parsed = ToIntegral<size_t>(memory))) {
LogPrint(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n");
return 0;
}
- return stoul(memory);
+ return parsed.value();
}
// Prefixed with null character to avoid collisions with other keys
diff --git a/src/flatfile.cpp b/src/flatfile.cpp
index 151f1a38f1..929808c7fa 100644
--- a/src/flatfile.cpp
+++ b/src/flatfile.cpp
@@ -41,11 +41,11 @@ FILE* FlatFileSeq::Open(const FlatFilePos& pos, bool read_only)
if (!file && !read_only)
file = fsbridge::fopen(path, "wb+");
if (!file) {
- LogPrintf("Unable to open file %s\n", path.string());
+ LogPrintf("Unable to open file %s\n", fs::PathToString(path));
return nullptr;
}
if (pos.nPos && fseek(file, pos.nPos, SEEK_SET)) {
- LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, path.string());
+ LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, fs::PathToString(path));
fclose(file);
return nullptr;
}
diff --git a/src/fs.cpp b/src/fs.cpp
index b9b3c46d8d..8cae7f32c6 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -24,7 +24,7 @@ namespace fsbridge {
FILE *fopen(const fs::path& p, const char *mode)
{
#ifndef WIN32
- return ::fopen(p.string().c_str(), mode);
+ return ::fopen(p.c_str(), mode);
#else
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> utf8_cvt;
return ::_wfopen(p.wstring().c_str(), utf8_cvt.from_bytes(mode).c_str());
@@ -46,7 +46,7 @@ static std::string GetErrorReason()
FileLock::FileLock(const fs::path& file)
{
- fd = open(file.string().c_str(), O_RDWR);
+ fd = open(file.c_str(), O_RDWR);
if (fd == -1) {
reason = GetErrorReason();
}
@@ -249,9 +249,9 @@ void ofstream::close()
#else // __GLIBCXX__
#if BOOST_VERSION >= 107700
-static_assert(sizeof(*BOOST_FILESYSTEM_C_STR(fs::path())) == sizeof(wchar_t),
+static_assert(sizeof(*BOOST_FILESYSTEM_C_STR(boost::filesystem::path())) == sizeof(wchar_t),
#else
-static_assert(sizeof(*fs::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t),
+static_assert(sizeof(*boost::filesystem::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t),
#endif // BOOST_VERSION >= 107700
"Warning: This build is using boost::filesystem ofstream and ifstream "
"implementations which will fail to open paths containing multibyte "
diff --git a/src/fs.h b/src/fs.h
index d77b90be66..4a0bf39e95 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -13,9 +13,132 @@
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
+#include <tinyformat.h>
/** Filesystem operations and types */
-namespace fs = boost::filesystem;
+namespace fs {
+
+using namespace boost::filesystem;
+
+/**
+ * Path class wrapper to prepare application code for transition from
+ * boost::filesystem library to std::filesystem implementation. The main
+ * purpose of the class is to define fs::path::u8string() and fs::u8path()
+ * functions not present in boost. It also blocks calls to the
+ * fs::path(std::string) implicit constructor and the fs::path::string()
+ * method, which worked well in the boost::filesystem implementation, but have
+ * unsafe and unpredictable behavior on Windows in the std::filesystem
+ * implementation (see implementation note in \ref PathToString for details).
+ */
+class path : public boost::filesystem::path
+{
+public:
+ using boost::filesystem::path::path;
+
+ // Allow path objects arguments for compatibility.
+ path(boost::filesystem::path path) : boost::filesystem::path::path(std::move(path)) {}
+ path& operator=(boost::filesystem::path path) { boost::filesystem::path::operator=(std::move(path)); return *this; }
+ path& operator/=(boost::filesystem::path path) { boost::filesystem::path::operator/=(std::move(path)); return *this; }
+
+ // Allow literal string arguments, which are safe as long as the literals are ASCII.
+ path(const char* c) : boost::filesystem::path(c) {}
+ path& operator=(const char* c) { boost::filesystem::path::operator=(c); return *this; }
+ path& operator/=(const char* c) { boost::filesystem::path::operator/=(c); return *this; }
+ path& append(const char* c) { boost::filesystem::path::append(c); return *this; }
+
+ // Disallow std::string arguments to avoid locale-dependent decoding on windows.
+ path(std::string) = delete;
+ path& operator=(std::string) = delete;
+ path& operator/=(std::string) = delete;
+ path& append(std::string) = delete;
+
+ // Disallow std::string conversion method to avoid locale-dependent encoding on windows.
+ std::string string() const = delete;
+
+ // Define UTF-8 string conversion method not present in boost::filesystem but present in std::filesystem.
+ std::string u8string() const { return boost::filesystem::path::string(); }
+};
+
+// Define UTF-8 string conversion function not present in boost::filesystem but present in std::filesystem.
+static inline path u8path(const std::string& string)
+{
+ return boost::filesystem::path(string);
+}
+
+// Disallow implicit std::string conversion for system_complete to avoid
+// locale-dependent encoding on windows.
+static inline path system_complete(const path& p)
+{
+ return boost::filesystem::system_complete(p);
+}
+
+// Disallow implicit std::string conversion for exists to avoid
+// locale-dependent encoding on windows.
+static inline bool exists(const path& p)
+{
+ return boost::filesystem::exists(p);
+}
+
+// Allow explicit quoted stream I/O.
+static inline auto quoted(const std::string& s)
+{
+ return boost::io::quoted(s, '&');
+}
+
+// Allow safe path append operations.
+static inline path operator+(path p1, path p2)
+{
+ p1 += std::move(p2);
+ return p1;
+}
+
+/**
+ * Convert path object to byte string. On POSIX, paths natively are byte
+ * strings so this is trivial. On Windows, paths natively are Unicode, so an
+ * encoding step is necessary.
+ *
+ * The inverse of \ref PathToString is \ref PathFromString. The strings
+ * returned and parsed by these functions can be used to call POSIX APIs, and
+ * for roundtrip conversion, logging, and debugging. But they are not
+ * guaranteed to be valid UTF-8, and are generally meant to be used internally,
+ * not externally. When communicating with external programs and libraries that
+ * require UTF-8, fs::path::u8string() and fs::u8path() methods can be used.
+ * For other applications, if support for non UTF-8 paths is required, or if
+ * higher-level JSON or XML or URI or C-style escapes are preferred, it may be
+ * also be appropriate to use different path encoding functions.
+ *
+ * Implementation note: On Windows, the std::filesystem::path(string)
+ * constructor and std::filesystem::path::string() method are not safe to use
+ * here, because these methods encode the path using C++'s narrow multibyte
+ * encoding, which on Windows corresponds to the current "code page", which is
+ * unpredictable and typically not able to represent all valid paths. So
+ * std::filesystem::path::u8string() and std::filesystem::u8path() functions
+ * are used instead on Windows. On POSIX, u8string/u8path functions are not
+ * safe to use because paths are not always valid UTF-8, so plain string
+ * methods which do not transform the path there are used.
+ */
+static inline std::string PathToString(const path& path)
+{
+#ifdef WIN32
+ return path.u8string();
+#else
+ static_assert(std::is_same<path::string_type, std::string>::value, "PathToString not implemented on this platform");
+ return path.boost::filesystem::path::string();
+#endif
+}
+
+/**
+ * Convert byte string to path object. Inverse of \ref PathToString.
+ */
+static inline path PathFromString(const std::string& string)
+{
+#ifdef WIN32
+ return u8path(string);
+#else
+ return boost::filesystem::path(string);
+#endif
+}
+} // namespace fs
/** Bridge operations to C stdio */
namespace fsbridge {
@@ -103,4 +226,11 @@ namespace fsbridge {
#endif // WIN32 && __GLIBCXX__
};
+// Disallow path operator<< formatting in tinyformat to avoid locale-dependent
+// encoding on windows.
+namespace tinyformat {
+template<> inline void formatValue(std::ostream&, const char*, const char*, int, const boost::filesystem::path&) = delete;
+template<> inline void formatValue(std::ostream&, const char*, const char*, int, const fs::path&) = delete;
+} // namespace tinyformat
+
#endif // BITCOIN_FS_H
diff --git a/src/hash.cpp b/src/hash.cpp
index 92c923fbd2..0e5bd975e4 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -75,10 +75,7 @@ unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vData
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64])
{
unsigned char num[4];
- num[0] = (nChild >> 24) & 0xFF;
- num[1] = (nChild >> 16) & 0xFF;
- num[2] = (nChild >> 8) & 0xFF;
- num[3] = (nChild >> 0) & 0xFF;
+ WriteBE32(num, nChild);
CHMAC_SHA512(chainCode.begin(), chainCode.size()).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output);
}
diff --git a/src/i2p.cpp b/src/i2p.cpp
index 5e7e42fb77..35ac8731f2 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -328,7 +328,7 @@ void Session::GenerateAndSavePrivateKey(const Sock& sock)
if (!WriteBinaryFile(m_private_key_file,
std::string(m_private_key.begin(), m_private_key.end()))) {
throw std::runtime_error(
- strprintf("Cannot save I2P private key to %s", m_private_key_file));
+ strprintf("Cannot save I2P private key to %s", fs::quoted(fs::PathToString(m_private_key_file))));
}
}
diff --git a/src/init.cpp b/src/init.cpp
index 4495ded64d..164b7bb55d 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -113,7 +113,7 @@ static const char* BITCOIN_PID_FILENAME = "bitcoind.pid";
static fs::path GetPidFile(const ArgsManager& args)
{
- return AbsPathForConfigVal(fs::path(args.GetArg("-pid", BITCOIN_PID_FILENAME)));
+ return AbsPathForConfigVal(fs::PathFromString(args.GetArg("-pid", BITCOIN_PID_FILENAME)));
}
[[nodiscard]] static bool CreatePidFile(const ArgsManager& args)
@@ -127,7 +127,7 @@ static fs::path GetPidFile(const ArgsManager& args)
#endif
return true;
} else {
- return InitError(strprintf(_("Unable to create the PID file '%s': %s"), GetPidFile(args).string(), std::strerror(errno)));
+ return InitError(strprintf(_("Unable to create the PID file '%s': %s"), fs::PathToString(GetPidFile(args)), std::strerror(errno)));
}
}
@@ -1062,10 +1062,10 @@ static bool LockDataDirectory(bool probeOnly)
// Make sure only a single Bitcoin process is using the data directory.
fs::path datadir = gArgs.GetDataDirNet();
if (!DirIsWritable(datadir)) {
- return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), datadir.string()));
+ return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir)));
}
if (!LockDirectory(datadir, ".lock", probeOnly)) {
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), datadir.string(), PACKAGE_NAME));
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), fs::PathToString(datadir), PACKAGE_NAME));
}
return true;
}
@@ -1126,12 +1126,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD);
// Warn about relative -datadir path.
- if (args.IsArgSet("-datadir") && !fs::path(args.GetArg("-datadir", "")).is_absolute()) {
+ if (args.IsArgSet("-datadir") && !fs::PathFromString(args.GetArg("-datadir", "")).is_absolute()) {
LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */
"current working directory '%s'. This is fragile, because if bitcoin is started in the future "
"from a different location, it will be unable to locate the current data files. There could "
"also be data loss if bitcoin is started while in a temporary directory.\n",
- args.GetArg("-datadir", ""), fs::current_path().string());
+ args.GetArg("-datadir", ""), fs::PathToString(fs::current_path()));
}
InitSignatureCache();
@@ -1215,20 +1215,20 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// Read asmap file if configured
std::vector<bool> asmap;
if (args.IsArgSet("-asmap")) {
- fs::path asmap_path = fs::path(args.GetArg("-asmap", ""));
+ fs::path asmap_path = fs::PathFromString(args.GetArg("-asmap", ""));
if (asmap_path.empty()) {
- asmap_path = DEFAULT_ASMAP_FILENAME;
+ asmap_path = fs::PathFromString(DEFAULT_ASMAP_FILENAME);
}
if (!asmap_path.is_absolute()) {
asmap_path = gArgs.GetDataDirNet() / asmap_path;
}
if (!fs::exists(asmap_path)) {
- InitError(strprintf(_("Could not find asmap file %s"), asmap_path));
+ InitError(strprintf(_("Could not find asmap file %s"), fs::quoted(fs::PathToString(asmap_path))));
return false;
}
asmap = DecodeAsmap(asmap_path);
if (asmap.size() == 0) {
- InitError(strprintf(_("Could not parse asmap file %s"), asmap_path));
+ InitError(strprintf(_("Could not parse asmap file %s"), fs::quoted(fs::PathToString(asmap_path))));
return false;
}
const uint256 asmap_version = SerializeHash(asmap);
@@ -1653,11 +1653,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 11: import blocks
if (!CheckDiskSpace(gArgs.GetDataDirNet())) {
- InitError(strprintf(_("Error: Disk space is low for %s"), gArgs.GetDataDirNet()));
+ InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(gArgs.GetDataDirNet()))));
return false;
}
if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) {
- InitError(strprintf(_("Error: Disk space is low for %s"), gArgs.GetBlocksDirPath()));
+ InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(gArgs.GetBlocksDirPath()))));
return false;
}
@@ -1685,7 +1685,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
std::vector<fs::path> vImportFiles;
for (const std::string& strFile : args.GetArgs("-loadblock")) {
- vImportFiles.push_back(strFile);
+ vImportFiles.push_back(fs::PathFromString(strFile));
}
chainman.m_load_block = std::thread(&util::TraceThread, "loadblk", [=, &chainman, &args] {
diff --git a/src/init/common.cpp b/src/init/common.cpp
index 5c1f469081..8f9e0ebc87 100644
--- a/src/init/common.cpp
+++ b/src/init/common.cpp
@@ -81,7 +81,7 @@ void AddLoggingArgs(ArgsManager& argsman)
void SetLoggingOptions(const ArgsManager& args)
{
LogInstance().m_print_to_file = !args.IsArgNegated("-debuglogfile");
- LogInstance().m_file_path = AbsPathForConfigVal(args.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
+ LogInstance().m_file_path = AbsPathForConfigVal(fs::PathFromString(args.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)));
LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", !args.GetBoolArg("-daemon", false));
LogInstance().m_log_timestamps = args.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
LogInstance().m_log_time_micros = args.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
@@ -128,24 +128,24 @@ bool StartLogging(const ArgsManager& args)
}
if (!LogInstance().StartLogging()) {
return InitError(strprintf(Untranslated("Could not open debug log file %s"),
- LogInstance().m_file_path.string()));
+ fs::PathToString(LogInstance().m_file_path)));
}
if (!LogInstance().m_log_timestamps)
LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime()));
- LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
- LogPrintf("Using data directory %s\n", gArgs.GetDataDirNet().string());
+ LogPrintf("Default data directory %s\n", fs::PathToString(GetDefaultDataDir()));
+ LogPrintf("Using data directory %s\n", fs::PathToString(gArgs.GetDataDirNet()));
// Only log conf file usage message if conf file actually exists.
fs::path config_file_path = GetConfigFile(args.GetArg("-conf", BITCOIN_CONF_FILENAME));
if (fs::exists(config_file_path)) {
- LogPrintf("Config file: %s\n", config_file_path.string());
+ LogPrintf("Config file: %s\n", fs::PathToString(config_file_path));
} else if (args.IsArgSet("-conf")) {
// Warn if no conf file exists at path provided by user
- InitWarning(strprintf(_("The specified config file %s does not exist"), config_file_path.string()));
+ InitWarning(strprintf(_("The specified config file %s does not exist"), fs::PathToString(config_file_path)));
} else {
// Not categorizing as "Warning" because it's the default behavior
- LogPrintf("Config file: %s (not found, skipping)\n", config_file_path.string());
+ LogPrintf("Config file: %s (not found, skipping)\n", fs::PathToString(config_file_path));
}
// Log the config arguments to debug.log
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index 9a97cad1f8..d4ceb517dd 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -289,7 +289,7 @@ public:
virtual void requestMempoolTransactions(Notifications& notifications) = 0;
//! Check if Taproot has activated
- virtual bool isTaprootActive() const = 0;
+ virtual bool isTaprootActive() = 0;
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
diff --git a/src/ipc/process.cpp b/src/ipc/process.cpp
index 43ed1f1bae..9036b80c45 100644
--- a/src/ipc/process.cpp
+++ b/src/ipc/process.cpp
@@ -30,8 +30,8 @@ public:
return mp::SpawnProcess(pid, [&](int fd) {
fs::path path = argv0_path;
path.remove_filename();
- path.append(new_exe_name);
- return std::vector<std::string>{path.string(), "-ipcfd", strprintf("%i", fd)};
+ path /= fs::PathFromString(new_exe_name);
+ return std::vector<std::string>{fs::PathToString(path), "-ipcfd", strprintf("%i", fd)};
});
}
int waitSpawned(int pid) override { return mp::WaitProcess(pid); }
diff --git a/src/key.cpp b/src/key.cpp
index 40df248e02..39155e4311 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -343,8 +343,7 @@ CExtPubKey CExtKey::Neuter() const {
void CExtKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
code[0] = nDepth;
memcpy(code+1, vchFingerprint, 4);
- code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
- code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
+ WriteBE32(code+5, nChild);
memcpy(code+9, chaincode.begin(), 32);
code[41] = 0;
assert(key.size() == 32);
@@ -354,7 +353,7 @@ void CExtKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
void CExtKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {
nDepth = code[0];
memcpy(vchFingerprint, code+1, 4);
- nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8];
+ nChild = ReadBE32(code+5);
memcpy(chaincode.begin(), code+9, 32);
key.Set(code+42, code+BIP32_EXTKEY_SIZE, true);
if ((nDepth == 0 && (nChild != 0 || ReadLE32(vchFingerprint) != 0)) || code[41] != 0) key = CKey();
diff --git a/src/logging.cpp b/src/logging.cpp
index a352e106e5..1efce21bdb 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -161,6 +161,7 @@ const CLogCategoryDesc LogCategories[] =
{BCLog::IPC, "ipc"},
{BCLog::LOCK, "lock"},
{BCLog::UTIL, "util"},
+ {BCLog::BLOCKSTORE, "blockstorage"},
{BCLog::ALL, "1"},
{BCLog::ALL, "all"},
};
diff --git a/src/logging.h b/src/logging.h
index 02e64a7c48..f46104364c 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -61,6 +61,7 @@ namespace BCLog {
IPC = (1 << 23),
LOCK = (1 << 24),
UTIL = (1 << 25),
+ BLOCKSTORE = (1 << 26),
ALL = ~(uint32_t)0,
};
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 0b7df9bd9a..53bc2b5069 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -68,13 +68,14 @@ void CleanupBlockRevFiles()
LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
fs::path blocksdir = gArgs.GetBlocksDirPath();
for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
+ const std::string path = fs::PathToString(it->path().filename());
if (fs::is_regular_file(*it) &&
- it->path().filename().string().length() == 12 &&
- it->path().filename().string().substr(8,4) == ".dat")
+ path.length() == 12 &&
+ path.substr(8,4) == ".dat")
{
- if (it->path().filename().string().substr(0, 3) == "blk") {
- mapBlockFiles[it->path().filename().string().substr(3, 5)] = it->path();
- } else if (it->path().filename().string().substr(0, 3) == "rev") {
+ if (path.substr(0, 3) == "blk") {
+ mapBlockFiles[path.substr(3, 5)] = it->path();
+ } else if (path.substr(0, 3) == "rev") {
remove(it->path());
}
}
@@ -204,7 +205,7 @@ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
FlatFilePos pos(*it, 0);
fs::remove(BlockFileSeq().FileName(pos));
fs::remove(UndoFileSeq().FileName(pos));
- LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
+ LogPrint(BCLog::BLOCKSTORE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
}
}
@@ -261,7 +262,7 @@ bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight,
if ((int)nFile != nLastBlockFile) {
if (!fKnown) {
- LogPrint(BCLog::VALIDATION, "Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString());
+ LogPrint(BCLog::BLOCKSTORE, "Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString());
}
FlushBlockFile(!fKnown, finalize_undo);
nLastBlockFile = nFile;
@@ -527,14 +528,14 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
for (const fs::path& path : vImportFiles) {
FILE* file = fsbridge::fopen(path, "rb");
if (file) {
- LogPrintf("Importing blocks file %s...\n", path.string());
+ LogPrintf("Importing blocks file %s...\n", fs::PathToString(path));
chainman.ActiveChainstate().LoadExternalBlockFile(file);
if (ShutdownRequested()) {
LogPrintf("Shutdown requested. Exit %s\n", __func__);
return;
}
} else {
- LogPrintf("Warning: Could not open blocks file %s\n", path.string());
+ LogPrintf("Warning: Could not open blocks file %s\n", fs::PathToString(path));
}
}
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 5b6d8416a7..73f4036057 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -698,7 +698,7 @@ public:
notifications.transactionAddedToMempool(entry.GetSharedTx(), 0 /* mempool_sequence */);
}
}
- bool isTaprootActive() const override
+ bool isTaprootActive() override
{
LOCK(::cs_main);
const CBlockIndex* tip = Assert(m_node.chainman)->ActiveChain().Tip();
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 2ae5798ebe..850b4f0439 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -527,7 +527,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME;
CAutoFile est_file(fsbridge::fopen(est_filepath, "rb"), SER_DISK, CLIENT_VERSION);
if (est_file.IsNull() || !Read(est_file)) {
- LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", est_filepath.string());
+ LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(est_filepath));
}
}
@@ -887,7 +887,7 @@ void CBlockPolicyEstimator::Flush() {
fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME;
CAutoFile est_file(fsbridge::fopen(est_filepath, "wb"), SER_DISK, CLIENT_VERSION);
if (est_file.IsNull() || !Write(est_file)) {
- LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", est_filepath.string());
+ LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(est_filepath));
}
}
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 9e433584e7..fced397e51 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -22,7 +22,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
// so dust is a spendable txout less than
// 182*dustRelayFee/1000 (in satoshis).
// 546 satoshis at the default rate of 3000 sat/kvB.
- // A typical spendable segwit txout is 31 bytes big, and will
+ // A typical spendable segwit P2WPKH txout is 31 bytes big, and will
// need a CTxIn of at least 67 bytes to spend:
// so dust is a spendable txout less than
// 98*dustRelayFee/1000 (in satoshis).
@@ -34,6 +34,11 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
+ // Note this computation is for spending a Segwit v0 P2WPKH output (a 33 bytes
+ // public key + an ECDSA signature). For Segwit v1 Taproot outputs the minimum
+ // satisfaction is lower (a single BIP340 signature) but this computation was
+ // kept to not further reduce the dust level.
+ // See discussion in https://github.com/bitcoin/bitcoin/pull/22779 for details.
if (txout.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
// sum the sizes of the parts of a transaction input
// with 75% segwit discount applied to the script size.
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index d14a20b870..956ff2b34a 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -337,8 +337,7 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi
void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
code[0] = nDepth;
memcpy(code+1, vchFingerprint, 4);
- code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
- code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
+ WriteBE32(code+5, nChild);
memcpy(code+9, chaincode.begin(), 32);
assert(pubkey.size() == CPubKey::COMPRESSED_SIZE);
memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_SIZE);
@@ -347,7 +346,7 @@ void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {
nDepth = code[0];
memcpy(vchFingerprint, code+1, 4);
- nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8];
+ nChild = ReadBE32(code+5);
memcpy(chaincode.begin(), code+9, 32);
pubkey.Set(code+41, code+BIP32_EXTKEY_SIZE);
if ((nDepth == 0 && (nChild != 0 || ReadLE32(vchFingerprint) != 0)) || !pubkey.IsFullyValid()) pubkey = CPubKey();
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 00c9fd3059..7de56a648a 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -46,7 +46,6 @@
#include <QApplication>
#include <QDebug>
-#include <QFontDatabase>
#include <QLatin1String>
#include <QLibraryInfo>
#include <QLocale>
@@ -492,7 +491,7 @@ int GuiMain(int argc, char* argv[])
#endif
BitcoinApplication app;
- QFontDatabase::addApplicationFont(":/fonts/monospace");
+ GUIUtil::LoadFont(QStringLiteral(":/fonts/monospace"));
/// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
// Command-line options take precedence:
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 7b1384b485..4262866f32 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -272,6 +272,12 @@ bool hasEntryData(const QAbstractItemView *view, int column, int role)
return !selection.at(0).data(role).toString().isEmpty();
}
+void LoadFont(const QString& file_name)
+{
+ const int id = QFontDatabase::addApplicationFont(file_name);
+ assert(id != -1);
+}
+
QString getDefaultDataDirectory()
{
return boostPathToQString(GetDefaultDataDir());
@@ -647,12 +653,12 @@ void setClipboard(const QString& str)
fs::path qstringToBoostPath(const QString &path)
{
- return fs::path(path.toStdString());
+ return fs::u8path(path.toStdString());
}
QString boostPathToQString(const fs::path &path)
{
- return QString::fromStdString(path.string());
+ return QString::fromStdString(path.u8string());
}
QString NetworkToQString(Network net)
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 6287f95192..211f3f506d 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -114,6 +114,11 @@ namespace GUIUtil
void setClipboard(const QString& str);
/**
+ * Loads the font from the file specified by file_name, aborts if it fails.
+ */
+ void LoadFont(const QString& file_name);
+
+ /**
* Determine default data directory for operating system.
*/
QString getDefaultDataDirectory();
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 4c78fba752..2ca4b6a21e 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -263,7 +263,7 @@ bool Intro::showIfNeeded(bool& did_show_intro, int64_t& prune_MiB)
* (to be consistent with bitcoind behavior)
*/
if(dataDir != GUIUtil::getDefaultDataDirectory()) {
- gArgs.SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
+ gArgs.SoftSetArg("-datadir", fs::PathToString(GUIUtil::qstringToBoostPath(dataDir))); // use OS locale for path setting
}
return true;
}
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 3c0dc5aa40..0c3332ab76 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -247,10 +247,11 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes
UniValue subelement;
if (lastResult.isArray())
{
- for(char argch: curarg)
- if (!IsDigit(argch))
- throw std::runtime_error("Invalid result query");
- subelement = lastResult[LocaleIndependentAtoi<int>(curarg)];
+ const auto parsed{ToIntegral<size_t>(curarg)};
+ if (!parsed) {
+ throw std::runtime_error("Invalid result query");
+ }
+ subelement = lastResult[parsed.value()];
}
else if (lastResult.isObject())
subelement = find_value(lastResult, curarg);
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index 4c74bcd480..a0ad59f12a 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -184,12 +184,13 @@ WalletControllerActivity::WalletControllerActivity(WalletController* wallet_cont
connect(this, &WalletControllerActivity::finished, this, &QObject::deleteLater);
}
-void WalletControllerActivity::showProgressDialog(const QString& label_text)
+void WalletControllerActivity::showProgressDialog(const QString& title_text, const QString& label_text)
{
auto progress_dialog = new QProgressDialog(m_parent_widget);
progress_dialog->setAttribute(Qt::WA_DeleteOnClose);
connect(this, &WalletControllerActivity::finished, progress_dialog, &QWidget::close);
+ progress_dialog->setWindowTitle(title_text);
progress_dialog->setLabelText(label_text);
progress_dialog->setRange(0, 0);
progress_dialog->setCancelButton(nullptr);
@@ -231,7 +232,12 @@ void CreateWalletActivity::askPassphrase()
void CreateWalletActivity::createWallet()
{
- showProgressDialog(tr("Creating Wallet <b>%1</b>…").arg(m_create_wallet_dialog->walletName().toHtmlEscaped()));
+ showProgressDialog(
+ //: Title of window indicating the progress of creation of a new wallet.
+ tr("Create Wallet"),
+ /*: Descriptive text of the create wallet progress window which indicates
+ to the user which wallet is currently being created. */
+ tr("Creating Wallet <b>%1</b>…").arg(m_create_wallet_dialog->walletName().toHtmlEscaped()));
std::string name = m_create_wallet_dialog->walletName().toStdString();
uint64_t flags = 0;
@@ -322,7 +328,12 @@ void OpenWalletActivity::open(const std::string& path)
{
QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
- showProgressDialog(tr("Opening Wallet <b>%1</b>…").arg(name.toHtmlEscaped()));
+ showProgressDialog(
+ //: Title of window indicating the progress of opening of a wallet.
+ tr("Open Wallet"),
+ /*: Descriptive text of the open wallet progress window which indicates
+ to the user which wallet is currently being opened. */
+ tr("Opening Wallet <b>%1</b>…").arg(name.toHtmlEscaped()));
QTimer::singleShot(0, worker(), [this, path] {
std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().loadWallet(path, m_error_message, m_warning_message);
@@ -340,7 +351,12 @@ LoadWalletsActivity::LoadWalletsActivity(WalletController* wallet_controller, QW
void LoadWalletsActivity::load()
{
- showProgressDialog(tr("Loading wallets…"));
+ showProgressDialog(
+ //: Title of progress window which is displayed when wallets are being loaded.
+ tr("Load Wallets"),
+ /*: Descriptive text of the load wallets progress window which indicates to
+ the user that wallets are currently being loaded.*/
+ tr("Loading wallets…"));
QTimer::singleShot(0, worker(), [this] {
for (auto& wallet : node().walletClient().getWallets()) {
diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h
index f97a7a1e84..bbd990228f 100644
--- a/src/qt/walletcontroller.h
+++ b/src/qt/walletcontroller.h
@@ -96,7 +96,7 @@ protected:
interfaces::Node& node() const { return m_wallet_controller->m_node; }
QObject* worker() const { return m_wallet_controller->m_activity_worker; }
- void showProgressDialog(const QString& label_text);
+ void showProgressDialog(const QString& title_text, const QString& label_text);
WalletController* const m_wallet_controller;
QWidget* const m_parent_widget;
diff --git a/src/rest.cpp b/src/rest.cpp
index e50ab33e54..3746fd752a 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -189,9 +189,10 @@ static bool rest_headers(const std::any& context,
if (path.size() != 2)
return RESTERR(req, HTTP_BAD_REQUEST, "No header count specified. Use /rest/headers/<count>/<hash>.<ext>.");
- long count = strtol(path[0].c_str(), nullptr, 10);
- if (count < 1 || count > 2000)
+ const auto parsed_count{ToIntegral<size_t>(path[0])};
+ if (!parsed_count.has_value() || *parsed_count < 1 || *parsed_count > 2000) {
return RESTERR(req, HTTP_BAD_REQUEST, "Header count out of range: " + path[0]);
+ }
std::string hashStr = path[1];
uint256 hash;
@@ -199,8 +200,8 @@ static bool rest_headers(const std::any& context,
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
const CBlockIndex* tip = nullptr;
- std::vector<const CBlockIndex *> headers;
- headers.reserve(count);
+ std::vector<const CBlockIndex*> headers;
+ headers.reserve(*parsed_count);
{
ChainstateManager* maybe_chainman = GetChainman(context, req);
if (!maybe_chainman) return false;
@@ -211,8 +212,9 @@ static bool rest_headers(const std::any& context,
const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
while (pindex != nullptr && active_chain.Contains(pindex)) {
headers.push_back(pindex);
- if (headers.size() == (unsigned long)count)
+ if (headers.size() == *parsed_count) {
break;
+ }
pindex = active_chain.Next(pindex);
}
}
@@ -260,7 +262,7 @@ static bool rest_headers(const std::any& context,
static bool rest_block(const std::any& context,
HTTPRequest* req,
const std::string& strURIPart,
- bool showTxDetails)
+ TxVerbosity tx_verbosity)
{
if (!CheckWarmup(req))
return false;
@@ -312,7 +314,7 @@ static bool rest_block(const std::any& context,
}
case RetFormat::JSON: {
- UniValue objBlock = blockToJSON(block, tip, pblockindex, showTxDetails);
+ UniValue objBlock = blockToJSON(block, tip, pblockindex, tx_verbosity);
std::string strJSON = objBlock.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
@@ -327,12 +329,12 @@ static bool rest_block(const std::any& context,
static bool rest_block_extended(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
- return rest_block(context, req, strURIPart, true);
+ return rest_block(context, req, strURIPart, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
}
static bool rest_block_notxdetails(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
{
- return rest_block(context, req, strURIPart, false);
+ return rest_block(context, req, strURIPart, TxVerbosity::SHOW_TXID);
}
// A bit of a hack - dependency on a function defined in rpc/blockchain.cpp
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index ac746de32f..dadd82e03f 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -200,7 +200,7 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
return result;
}
-UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails)
+UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity)
{
UniValue result = blockheaderToJSON(tip, blockindex);
@@ -208,22 +208,29 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
result.pushKV("weight", (int)::GetBlockWeight(block));
UniValue txs(UniValue::VARR);
- if (txDetails) {
- CBlockUndo blockUndo;
- const bool have_undo = !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex);
- for (size_t i = 0; i < block.vtx.size(); ++i) {
- const CTransactionRef& tx = block.vtx.at(i);
- // coinbase transaction (i == 0) doesn't have undo data
- const CTxUndo* txundo = (have_undo && i) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
- UniValue objTx(UniValue::VOBJ);
- TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags(), txundo);
- txs.push_back(objTx);
- }
- } else {
- for (const CTransactionRef& tx : block.vtx) {
- txs.push_back(tx->GetHash().GetHex());
- }
+
+ switch (verbosity) {
+ case TxVerbosity::SHOW_TXID:
+ for (const CTransactionRef& tx : block.vtx) {
+ txs.push_back(tx->GetHash().GetHex());
+ }
+ break;
+
+ case TxVerbosity::SHOW_DETAILS:
+ case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
+ CBlockUndo blockUndo;
+ const bool have_undo = !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex);
+
+ for (size_t i = 0; i < block.vtx.size(); ++i) {
+ const CTransactionRef& tx = block.vtx.at(i);
+ // coinbase transaction (i.e. i == 0) doesn't have undo data
+ const CTxUndo* txundo = (have_undo && i > 0) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
+ UniValue objTx(UniValue::VOBJ);
+ TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags(), txundo, verbosity);
+ txs.push_back(objTx);
+ }
}
+
result.pushKV("tx", txs);
return result;
@@ -931,7 +938,8 @@ static RPCHelpMan getblock()
return RPCHelpMan{"getblock",
"\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
"If verbosity is 1, returns an Object with information about block <hash>.\n"
- "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n",
+ "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\n"
+ "If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).\n",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
{"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
@@ -1018,7 +1026,16 @@ static RPCHelpMan getblock()
return strHex;
}
- return blockToJSON(block, tip, pblockindex, verbosity >= 2);
+ TxVerbosity tx_verbosity;
+ if (verbosity == 1) {
+ tx_verbosity = TxVerbosity::SHOW_TXID;
+ } else if (verbosity == 2) {
+ tx_verbosity = TxVerbosity::SHOW_DETAILS;
+ } else {
+ tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT;
+ }
+
+ return blockToJSON(block, tip, pblockindex, tx_verbosity);
},
};
}
@@ -2537,15 +2554,15 @@ static RPCHelpMan dumptxoutset()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- const fs::path path = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), request.params[0].get_str());
+ const fs::path path = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
// Write to a temporary path and then move into `path` on completion
// to avoid confusion due to an interruption.
- const fs::path temppath = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), request.params[0].get_str() + ".incomplete");
+ const fs::path temppath = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), fs::u8path(request.params[0].get_str() + ".incomplete"));
if (fs::exists(path)) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
- path.string() + " already exists. If you are sure this is what you want, "
+ path.u8string() + " already exists. If you are sure this is what you want, "
"move it out of the way first");
}
@@ -2555,7 +2572,7 @@ static RPCHelpMan dumptxoutset()
UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), afile);
fs::rename(temppath, path);
- result.pushKV("path", path.string());
+ result.pushKV("path", path.u8string());
return result;
},
};
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 09e471afdd..d9c6761f47 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -6,6 +6,7 @@
#define BITCOIN_RPC_BLOCKCHAIN_H
#include <consensus/amount.h>
+#include <core_io.h>
#include <streams.h>
#include <sync.h>
@@ -38,7 +39,7 @@ double GetDifficulty(const CBlockIndex* blockindex);
void RPCNotifyBlockChange(const CBlockIndex*);
/** Block description to JSON */
-UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false) LOCKS_EXCLUDED(cs_main);
+UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main);
/** Mempool information to JSON */
UniValue MempoolInfoToJSON(const CTxMemPool& pool);
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index a7866474e1..3245e04cdf 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -70,7 +70,7 @@ static fs::path GetAuthCookieFile(bool temp=false)
if (temp) {
arg += ".tmp";
}
- return AbsPathForConfigVal(fs::path(arg));
+ return AbsPathForConfigVal(fs::PathFromString(arg));
}
bool GenerateAuthCookie(std::string *cookie_out)
@@ -87,7 +87,7 @@ bool GenerateAuthCookie(std::string *cookie_out)
fs::path filepath_tmp = GetAuthCookieFile(true);
file.open(filepath_tmp);
if (!file.is_open()) {
- LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string());
+ LogPrintf("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp));
return false;
}
file << cookie;
@@ -95,10 +95,10 @@ bool GenerateAuthCookie(std::string *cookie_out)
fs::path filepath = GetAuthCookieFile(false);
if (!RenameOver(filepath_tmp, filepath)) {
- LogPrintf("Unable to rename cookie authentication file %s to %s\n", filepath_tmp.string(), filepath.string());
+ LogPrintf("Unable to rename cookie authentication file %s to %s\n", fs::PathToString(filepath_tmp), fs::PathToString(filepath));
return false;
}
- LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
+ LogPrintf("Generated RPC authentication cookie %s\n", fs::PathToString(filepath));
if (cookie_out)
*cookie_out = cookie;
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 0d02ec5c47..9bcfba3507 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -239,7 +239,7 @@ static RPCHelpMan getrpcinfo()
UniValue result(UniValue::VOBJ);
result.pushKV("active_commands", active_commands);
- const std::string path = LogInstance().m_file_path.string();
+ const std::string path = LogInstance().m_file_path.u8string();
UniValue log_path(UniValue::VSTR, path);
result.pushKV("logpath", log_path);
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index 526a3c27be..ecb838a7dd 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -11,6 +11,33 @@
BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)
+BOOST_AUTO_TEST_CASE(fsbridge_pathtostring)
+{
+ std::string u8_str = "fs_tests_₿_🏃";
+ BOOST_CHECK_EQUAL(fs::PathToString(fs::PathFromString(u8_str)), u8_str);
+ BOOST_CHECK_EQUAL(fs::u8path(u8_str).u8string(), u8_str);
+ BOOST_CHECK_EQUAL(fs::PathFromString(u8_str).u8string(), u8_str);
+ BOOST_CHECK_EQUAL(fs::PathToString(fs::u8path(u8_str)), u8_str);
+#ifndef WIN32
+ // On non-windows systems, verify that arbitrary byte strings containing
+ // invalid UTF-8 can be round tripped successfully with PathToString and
+ // PathFromString. On non-windows systems, paths are just byte strings so
+ // these functions do not do any encoding. On windows, paths are Unicode,
+ // and these functions do encoding and decoding, so the behavior of this
+ // test would be undefined.
+ std::string invalid_u8_str = "\xf0";
+ BOOST_CHECK_EQUAL(invalid_u8_str.size(), 1);
+ BOOST_CHECK_EQUAL(fs::PathToString(fs::PathFromString(invalid_u8_str)), invalid_u8_str);
+#endif
+}
+
+BOOST_AUTO_TEST_CASE(fsbridge_stem)
+{
+ std::string test_filename = "fs_tests_₿_🏃.dat";
+ std::string expected_stem = "fs_tests_₿_🏃";
+ BOOST_CHECK_EQUAL(fs::PathToString(fs::PathFromString(test_filename).stem()), expected_stem);
+}
+
BOOST_AUTO_TEST_CASE(fsbridge_fstream)
{
fs::path tmpfolder = m_args.GetDataDirBase();
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index cfeab9dcdc..8df3707fc9 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -7,6 +7,7 @@
#include <addrman_impl.h>
#include <chainparams.h>
#include <merkleblock.h>
+#include <random.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
@@ -35,92 +36,86 @@ FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman)
}
}
-class AddrManDeterministic : public AddrMan
+/**
+ * Generate a random address. Always returns a valid address.
+ */
+CNetAddr RandAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext& fast_random_context)
{
-public:
- FuzzedDataProvider& m_fuzzed_data_provider;
-
- explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider)
- : AddrMan(std::move(asmap), /* deterministic */ true, /* consistency_check_ratio */ 0)
- , m_fuzzed_data_provider(fuzzed_data_provider)
- {
- WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
- }
-
- /**
- * Generate a random address. Always returns a valid address.
- */
- CNetAddr RandAddr() EXCLUSIVE_LOCKS_REQUIRED(m_impl->cs)
- {
- CNetAddr addr;
- if (m_fuzzed_data_provider.remaining_bytes() > 1 && m_fuzzed_data_provider.ConsumeBool()) {
- addr = ConsumeNetAddr(m_fuzzed_data_provider);
- } else {
- // The networks [1..6] correspond to CNetAddr::BIP155Network (private).
- static const std::map<uint8_t, uint8_t> net_len_map = {{1, ADDR_IPV4_SIZE},
- {2, ADDR_IPV6_SIZE},
- {4, ADDR_TORV3_SIZE},
- {5, ADDR_I2P_SIZE},
- {6, ADDR_CJDNS_SIZE}};
- uint8_t net = m_impl->insecure_rand.randrange(5) + 1; // [1..5]
- if (net == 3) {
- net = 6;
- }
-
- CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
-
- s << net;
- s << m_impl->insecure_rand.randbytes(net_len_map.at(net));
-
- s >> addr;
- }
-
- // Return a dummy IPv4 5.5.5.5 if we generated an invalid address.
- if (!addr.IsValid()) {
- in_addr v4_addr = {};
- v4_addr.s_addr = 0x05050505;
- addr = CNetAddr{v4_addr};
+ CNetAddr addr;
+ if (fuzzed_data_provider.remaining_bytes() > 1 && fuzzed_data_provider.ConsumeBool()) {
+ addr = ConsumeNetAddr(fuzzed_data_provider);
+ } else {
+ // The networks [1..6] correspond to CNetAddr::BIP155Network (private).
+ static const std::map<uint8_t, uint8_t> net_len_map = {{1, ADDR_IPV4_SIZE},
+ {2, ADDR_IPV6_SIZE},
+ {4, ADDR_TORV3_SIZE},
+ {5, ADDR_I2P_SIZE},
+ {6, ADDR_CJDNS_SIZE}};
+ uint8_t net = fast_random_context.randrange(5) + 1; // [1..5]
+ if (net == 3) {
+ net = 6;
}
- return addr;
- }
-
- /**
- * Fill this addrman with lots of addresses from lots of sources.
- */
- void Fill()
- {
- LOCK(m_impl->cs);
+ CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
- // Add some of the addresses directly to the "tried" table.
+ s << net;
+ s << fast_random_context.randbytes(net_len_map.at(net));
- // 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33%
- const size_t n = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3);
+ s >> addr;
+ }
- const size_t num_sources = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50);
- CNetAddr prev_source;
- // Use insecure_rand inside the loops instead of m_fuzzed_data_provider because when
- // the latter is exhausted it just returns 0.
- for (size_t i = 0; i < num_sources; ++i) {
- const auto source = RandAddr();
- const size_t num_addresses = m_impl->insecure_rand.randrange(500) + 1; // [1..500]
+ // Return a dummy IPv4 5.5.5.5 if we generated an invalid address.
+ if (!addr.IsValid()) {
+ in_addr v4_addr = {};
+ v4_addr.s_addr = 0x05050505;
+ addr = CNetAddr{v4_addr};
+ }
- for (size_t j = 0; j < num_addresses; ++j) {
- const auto addr = CAddress{CService{RandAddr(), 8333}, NODE_NETWORK};
- const auto time_penalty = m_impl->insecure_rand.randrange(100000001);
- m_impl->Add_(addr, source, time_penalty);
+ return addr;
+}
- if (n > 0 && m_impl->mapInfo.size() % n == 0) {
- m_impl->Good_(addr, false, GetTime());
- }
+/** Fill addrman with lots of addresses from lots of sources. */
+void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
+{
+ // Add a fraction of the addresses to the "tried" table.
+ // 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33%
+ const size_t n = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3);
+
+ const size_t num_sources = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50);
+ CNetAddr prev_source;
+ // Generate a FastRandomContext seed to use inside the loops instead of
+ // fuzzed_data_provider. When fuzzed_data_provider is exhausted it
+ // just returns 0.
+ FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};
+ for (size_t i = 0; i < num_sources; ++i) {
+ const auto source = RandAddr(fuzzed_data_provider, fast_random_context);
+ const size_t num_addresses = fast_random_context.randrange(500) + 1; // [1..500]
+
+ for (size_t j = 0; j < num_addresses; ++j) {
+ const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK};
+ const auto time_penalty = fast_random_context.randrange(100000001);
+ addrman.Add({addr}, source, time_penalty);
+
+ if (n > 0 && addrman.size() % n == 0) {
+ addrman.Good(addr, GetTime());
+ }
- // Add 10% of the addresses from more than one source.
- if (m_impl->insecure_rand.randrange(10) == 0 && prev_source.IsValid()) {
- m_impl->Add_({addr}, prev_source, time_penalty);
- }
+ // Add 10% of the addresses from more than one source.
+ if (fast_random_context.randrange(10) == 0 && prev_source.IsValid()) {
+ addrman.Add({addr}, prev_source, time_penalty);
}
- prev_source = source;
}
+ prev_source = source;
+ }
+}
+
+class AddrManDeterministic : public AddrMan
+{
+public:
+ explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider)
+ : AddrMan(std::move(asmap), /* deterministic */ true, /* consistency_check_ratio */ 0)
+ {
+ WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
}
/**
@@ -307,7 +302,7 @@ FUZZ_TARGET_INIT(addrman_serdeser, initialize_addrman)
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);
- addr_man1.Fill();
+ FillAddrman(addr_man1, fuzzed_data_provider);
data_stream << addr_man1;
data_stream >> addr_man2;
assert(addr_man1 == addr_man2);
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index 561cc83c72..fbba25c404 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -48,7 +48,7 @@ FUZZ_TARGET_INIT(banman, initialize_banman)
const bool start_with_corrupted_banlist{fuzzed_data_provider.ConsumeBool()};
bool force_read_and_write_to_err{false};
if (start_with_corrupted_banlist) {
- assert(WriteBinaryFile(banlist_file.string() + ".json",
+ assert(WriteBinaryFile(banlist_file + ".json",
fuzzed_data_provider.ConsumeRandomLengthString()));
} else {
force_read_and_write_to_err = fuzzed_data_provider.ConsumeBool();
@@ -111,5 +111,5 @@ FUZZ_TARGET_INIT(banman, initialize_banman)
assert(banmap == banmap_read);
}
}
- fs::remove(banlist_file.string() + ".json");
+ fs::remove(fs::PathToString(banlist_file + ".json"));
}
diff --git a/src/test/script_parse_tests.cpp b/src/test/script_parse_tests.cpp
new file mode 100644
index 0000000000..004c1a9a84
--- /dev/null
+++ b/src/test/script_parse_tests.cpp
@@ -0,0 +1,55 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <core_io.h>
+#include <script/script.h>
+#include <util/strencodings.h>
+#include <test/util/setup_common.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(script_parse_tests)
+BOOST_AUTO_TEST_CASE(parse_script)
+{
+ const std::vector<std::pair<std::string,std::string>> IN_OUT{
+ // {IN: script string , OUT: hex string }
+ {"", ""},
+ {"0", "00"},
+ {"1", "51"},
+ {"2", "52"},
+ {"3", "53"},
+ {"4", "54"},
+ {"5", "55"},
+ {"6", "56"},
+ {"7", "57"},
+ {"8", "58"},
+ {"9", "59"},
+ {"10", "5a"},
+ {"11", "5b"},
+ {"12", "5c"},
+ {"13", "5d"},
+ {"14", "5e"},
+ {"15", "5f"},
+ {"16", "60"},
+ {"17", "0111"},
+ {"-9", "0189"},
+ {"0x17", "17"},
+ {"'17'", "023137"},
+ {"ELSE", "67"},
+ {"NOP10", "b9"},
+ };
+ std::string all_in;
+ std::string all_out;
+ for (const auto& [in, out] : IN_OUT) {
+ BOOST_CHECK_EQUAL(HexStr(ParseScript(in)), out);
+ all_in += " " + in + " ";
+ all_out += out;
+ }
+ BOOST_CHECK_EQUAL(HexStr(ParseScript(all_in)), all_out);
+
+ BOOST_CHECK_EXCEPTION(ParseScript("11111111111111111111"), std::runtime_error, HasReason("script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF"));
+ BOOST_CHECK_EXCEPTION(ParseScript("11111111111"), std::runtime_error, HasReason("script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF"));
+ BOOST_CHECK_EXCEPTION(ParseScript("OP_CHECKSIGADD"), std::runtime_error, HasReason("script parse error: unknown opcode"));
+}
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index 340ce33d91..15cba9e3e5 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -80,19 +80,19 @@ BOOST_AUTO_TEST_CASE(ReadWrite)
"dupe": "dupe"
})");
BOOST_CHECK(!util::ReadSettings(path, values, errors));
- std::vector<std::string> dup_keys = {strprintf("Found duplicate key dupe in settings file %s", path.string())};
+ std::vector<std::string> dup_keys = {strprintf("Found duplicate key dupe in settings file %s", fs::PathToString(path))};
BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), dup_keys.begin(), dup_keys.end());
// Check non-kv json files not allowed
WriteText(path, R"("non-kv")");
BOOST_CHECK(!util::ReadSettings(path, values, errors));
- std::vector<std::string> non_kv = {strprintf("Found non-object value \"non-kv\" in settings file %s", path.string())};
+ std::vector<std::string> non_kv = {strprintf("Found non-object value \"non-kv\" in settings file %s", fs::PathToString(path))};
BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), non_kv.begin(), non_kv.end());
// Check invalid json not allowed
WriteText(path, R"(invalid json)");
BOOST_CHECK(!util::ReadSettings(path, values, errors));
- std::vector<std::string> fail_parse = {strprintf("Unable to parse settings file %s", path.string())};
+ std::vector<std::string> fail_parse = {strprintf("Unable to parse settings file %s", fs::PathToString(path))};
BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), fail_parse.begin(), fail_parse.end());
}
diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h
index 81ea4c38f5..e95573022c 100644
--- a/src/test/util/chainstate.h
+++ b/src/test/util/chainstate.h
@@ -36,7 +36,7 @@ CreateAndActivateUTXOSnapshot(NodeContext& node, const fs::path root, F malleati
UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), auto_outfile);
BOOST_TEST_MESSAGE(
- "Wrote UTXO snapshot to " << snapshot_path.make_preferred().string() << ": " << result.write());
+ "Wrote UTXO snapshot to " << fs::PathToString(snapshot_path.make_preferred()) << ": " << result.write());
// Read the written snapshot in and then activate it.
//
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index ebefa9974e..a3c7564d76 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -91,8 +91,8 @@ 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());
+ m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
+ gArgs.ForceSetArg("-datadir", fs::PathToString(m_path_root));
gArgs.ClearPathCache();
{
SetupServerArgs(*m_node.args);
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 51707310a2..b1300d06ba 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -51,23 +51,23 @@ BOOST_AUTO_TEST_CASE(util_datadir)
{
// Use local args variable instead of m_args to avoid making assumptions about test setup
ArgsManager args;
- args.ForceSetArg("-datadir", m_path_root.string());
+ args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
const fs::path dd_norm = args.GetDataDirBase();
- args.ForceSetArg("-datadir", dd_norm.string() + "/");
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/");
args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
- args.ForceSetArg("-datadir", dd_norm.string() + "/.");
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/.");
args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
- args.ForceSetArg("-datadir", dd_norm.string() + "/./");
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/./");
args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
- args.ForceSetArg("-datadir", dd_norm.string() + "/.//");
+ args.ForceSetArg("-datadir", fs::PathToString(dd_norm) + "/.//");
args.ClearPathCache();
BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
}
@@ -1181,13 +1181,13 @@ BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
{
// Test writing setting.
TestArgsManager args1;
- args1.ForceSetArg("-datadir", m_path_root.string());
+ args1.ForceSetArg("-datadir", fs::PathToString(m_path_root));
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.ForceSetArg("-datadir", fs::PathToString(m_path_root));
args2.ReadSettingsFile();
args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); });
@@ -1239,6 +1239,11 @@ BOOST_AUTO_TEST_CASE(util_FormatMoney)
BOOST_AUTO_TEST_CASE(util_ParseMoney)
{
BOOST_CHECK_EQUAL(ParseMoney("0.0").value(), 0);
+ BOOST_CHECK_EQUAL(ParseMoney(".").value(), 0);
+ BOOST_CHECK_EQUAL(ParseMoney("0.").value(), 0);
+ BOOST_CHECK_EQUAL(ParseMoney(".0").value(), 0);
+ BOOST_CHECK_EQUAL(ParseMoney(".6789").value(), 6789'0000);
+ BOOST_CHECK_EQUAL(ParseMoney("12345.").value(), COIN * 12345);
BOOST_CHECK_EQUAL(ParseMoney("12345.6789").value(), (COIN/10000)*123456789);
@@ -1276,11 +1281,18 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney)
BOOST_CHECK(!ParseMoney(" "));
// Parsing two numbers should fail
+ BOOST_CHECK(!ParseMoney(".."));
+ BOOST_CHECK(!ParseMoney("0..0"));
BOOST_CHECK(!ParseMoney("1 2"));
BOOST_CHECK(!ParseMoney(" 1 2 "));
BOOST_CHECK(!ParseMoney(" 1.2 3 "));
BOOST_CHECK(!ParseMoney(" 1 2.3 "));
+ // Embedded whitespace should fail
+ BOOST_CHECK(!ParseMoney(" -1 .2 "));
+ BOOST_CHECK(!ParseMoney(" 1 .2 "));
+ BOOST_CHECK(!ParseMoney(" +1 .2 "));
+
// Attempted 63 bit overflow should fail
BOOST_CHECK(!ParseMoney("92233720368.54775808"));
diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp
index 726c9ebbb8..9bb08f774f 100644
--- a/src/test/validation_chainstate_tests.cpp
+++ b/src/test/validation_chainstate_tests.cpp
@@ -107,20 +107,21 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
curr_tip = ::g_best_block;
- CChainState* background_cs;
-
BOOST_CHECK_EQUAL(chainman.GetAll().size(), 2);
- for (CChainState* cs : chainman.GetAll()) {
- if (cs != &chainman.ActiveChainstate()) {
- background_cs = cs;
+
+ CChainState& background_cs{*[&] {
+ for (CChainState* cs : chainman.GetAll()) {
+ if (cs != &chainman.ActiveChainstate()) {
+ return cs;
+ }
}
- }
- BOOST_CHECK(background_cs);
+ assert(false);
+ }()};
// Create a block to append to the validation chain.
std::vector<CMutableTransaction> noTxns;
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
- CBlock validation_block = this->CreateBlock(noTxns, scriptPubKey, *background_cs);
+ CBlock validation_block = this->CreateBlock(noTxns, scriptPubKey, background_cs);
auto pblock = std::make_shared<const CBlock>(validation_block);
BlockValidationState state;
CBlockIndex* pindex = nullptr;
@@ -133,15 +134,15 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
LOCK(::cs_main);
bool checked = CheckBlock(*pblock, state, chainparams.GetConsensus());
BOOST_CHECK(checked);
- bool accepted = background_cs->AcceptBlock(
+ bool accepted = background_cs.AcceptBlock(
pblock, state, &pindex, true, nullptr, &newblock);
BOOST_CHECK(accepted);
}
// UpdateTip is called here
- bool block_added = background_cs->ActivateBestChain(state, pblock);
+ bool block_added = background_cs.ActivateBestChain(state, pblock);
// Ensure tip is as expected
- BOOST_CHECK_EQUAL(background_cs->m_chain.Tip()->GetBlockHash(), validation_block.GetHash());
+ BOOST_CHECK_EQUAL(background_cs.m_chain.Tip()->GetBlockHash(), validation_block.GetHash());
// g_best_block should be unchanged after adding a block to the background
// validation chain.
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index f9caf48df8..55618a5c57 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -318,7 +318,7 @@ TorController::TorController(struct event_base* _base, const std::string& tor_co
// Read service private key if cached
std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile());
if (pkf.first) {
- LogPrint(BCLog::TOR, "tor: Reading cached private key from %s\n", GetPrivateKeyFile().string());
+ LogPrint(BCLog::TOR, "tor: Reading cached private key from %s\n", fs::PathToString(GetPrivateKeyFile()));
private_key = pkf.second;
}
}
@@ -356,9 +356,9 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe
service = LookupNumeric(std::string(service_id+".onion"), Params().GetDefaultPort());
LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString());
if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) {
- LogPrint(BCLog::TOR, "tor: Cached service private key to %s\n", GetPrivateKeyFile().string());
+ LogPrint(BCLog::TOR, "tor: Cached service private key to %s\n", fs::PathToString(GetPrivateKeyFile()));
} else {
- LogPrintf("tor: Error writing service private key to %s\n", GetPrivateKeyFile().string());
+ LogPrintf("tor: Error writing service private key to %s\n", fs::PathToString(GetPrivateKeyFile()));
}
AddLocal(service, LOCAL_MANUAL);
// ... onion requested - keep connection open
@@ -508,7 +508,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
} else if (methods.count("SAFECOOKIE")) {
// Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie
LogPrint(BCLog::TOR, "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile);
- std::pair<bool,std::string> status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE);
+ std::pair<bool,std::string> status_cookie = ReadBinaryFile(fs::PathFromString(cookiefile), TOR_COOKIE_SIZE);
if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) {
// _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2));
cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end());
diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp
index 5695c62012..b696c65e9d 100644
--- a/src/util/asmap.cpp
+++ b/src/util/asmap.cpp
@@ -201,7 +201,7 @@ std::vector<bool> DecodeAsmap(fs::path path)
}
fseek(filestr, 0, SEEK_END);
int length = ftell(filestr);
- LogPrintf("Opened asmap file %s (%d bytes) from disk\n", path, length);
+ LogPrintf("Opened asmap file %s (%d bytes) from disk\n", fs::quoted(fs::PathToString(path)), length);
fseek(filestr, 0, SEEK_SET);
uint8_t cur_byte;
for (int i = 0; i < length; ++i) {
@@ -211,7 +211,7 @@ std::vector<bool> DecodeAsmap(fs::path path)
}
}
if (!SanityCheckASMap(bits, 128)) {
- LogPrintf("Sanity check of asmap file %s failed\n", path);
+ LogPrintf("Sanity check of asmap file %s failed\n", fs::quoted(fs::PathToString(path)));
return {};
}
return bits;
diff --git a/src/util/settings.cpp b/src/util/settings.cpp
index 846b34089d..7fb35c073e 100644
--- a/src/util/settings.cpp
+++ b/src/util/settings.cpp
@@ -66,24 +66,24 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va
fsbridge::ifstream file;
file.open(path);
if (!file.is_open()) {
- errors.emplace_back(strprintf("%s. Please check permissions.", path.string()));
+ errors.emplace_back(strprintf("%s. Please check permissions.", fs::PathToString(path)));
return false;
}
SettingsValue in;
if (!in.read(std::string{std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()})) {
- errors.emplace_back(strprintf("Unable to parse settings file %s", path.string()));
+ errors.emplace_back(strprintf("Unable to parse settings file %s", fs::PathToString(path)));
return false;
}
if (file.fail()) {
- errors.emplace_back(strprintf("Failed reading settings file %s", path.string()));
+ errors.emplace_back(strprintf("Failed reading settings file %s", fs::PathToString(path)));
return false;
}
file.close(); // Done with file descriptor. Release while copying data.
if (!in.isObject()) {
- errors.emplace_back(strprintf("Found non-object value %s in settings file %s", in.write(), path.string()));
+ errors.emplace_back(strprintf("Found non-object value %s in settings file %s", in.write(), fs::PathToString(path)));
return false;
}
@@ -92,7 +92,7 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va
for (size_t i = 0; i < in_keys.size(); ++i) {
auto inserted = values.emplace(in_keys[i], in_values[i]);
if (!inserted.second) {
- errors.emplace_back(strprintf("Found duplicate key %s in settings file %s", in_keys[i], path.string()));
+ errors.emplace_back(strprintf("Found duplicate key %s in settings file %s", in_keys[i], fs::PathToString(path)));
}
}
return errors.empty();
@@ -109,7 +109,7 @@ bool WriteSettings(const fs::path& path,
fsbridge::ofstream file;
file.open(path);
if (file.fail()) {
- errors.emplace_back(strprintf("Error: Unable to open settings file %s for writing", path.string()));
+ errors.emplace_back(strprintf("Error: Unable to open settings file %s for writing", fs::PathToString(path)));
return false;
}
file << out.write(/* prettyIndent= */ 1, /* indentLevel= */ 4) << std::endl;
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index 1f7762aeef..eedb5ec2f8 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -72,7 +72,7 @@ void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut);
// LocaleIndependentAtoi is provided for backwards compatibility reasons.
//
-// New code should use the ParseInt64/ParseUInt64/ParseInt32/ParseUInt32 functions
+// New code should use ToIntegral or the ParseInt* functions
// which provide parse error feedback.
//
// The goal of LocaleIndependentAtoi is to replicate the exact defined behaviour
@@ -125,7 +125,7 @@ constexpr inline bool IsSpace(char c) noexcept {
/**
* Convert string to integral type T. Leading whitespace, a leading +, or any
* trailing character fail the parsing. The required format expressed as regex
- * is `-?[0-9]+`.
+ * is `-?[0-9]+`. The minus sign is only permitted for signed integer types.
*
* @returns std::nullopt if the entire string could not be parsed, or if the
* parsed value is not in the range representable by the type T.
diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp
index 6d62864a4a..b361b09568 100644
--- a/src/util/syscall_sandbox.cpp
+++ b/src/util/syscall_sandbox.cpp
@@ -46,6 +46,12 @@ bool g_syscall_sandbox_log_violation_before_terminating{false};
// Define system call numbers for x86_64 that are referenced in the system call profile
// but not provided by the kernel headers used in the GUIX build.
+// Usually, they can be found via "grep name /usr/include/x86_64-linux-gnu/asm/unistd_64.h"
+
+#ifndef __NR_clone3
+#define __NR_clone3 435
+#endif
+
#ifndef __NR_statx
#define __NR_statx 332
#endif
@@ -58,6 +64,10 @@ bool g_syscall_sandbox_log_violation_before_terminating{false};
#define __NR_membarrier 324
#endif
+#ifndef __NR_copy_file_range
+#define __NR_copy_file_range 326
+#endif
+
// This list of syscalls in LINUX_SYSCALLS is only used to map syscall numbers to syscall names in
// order to be able to print user friendly error messages which include the syscall name in addition
// to the syscall number.
@@ -111,6 +121,7 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_clock_nanosleep, "clock_nanosleep"},
{__NR_clock_settime, "clock_settime"},
{__NR_clone, "clone"},
+ {__NR_clone3, "clone3"},
{__NR_close, "close"},
{__NR_connect, "connect"},
{__NR_copy_file_range, "copy_file_range"},
@@ -268,15 +279,23 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_pipe, "pipe"},
{__NR_pipe2, "pipe2"},
{__NR_pivot_root, "pivot_root"},
+#ifdef __NR_pkey_alloc
{__NR_pkey_alloc, "pkey_alloc"},
+#endif
+#ifdef __NR_pkey_free
{__NR_pkey_free, "pkey_free"},
+#endif
+#ifdef __NR_pkey_mprotect
{__NR_pkey_mprotect, "pkey_mprotect"},
+#endif
{__NR_poll, "poll"},
{__NR_ppoll, "ppoll"},
{__NR_prctl, "prctl"},
{__NR_pread64, "pread64"},
{__NR_preadv, "preadv"},
+#ifdef __NR_preadv2
{__NR_preadv2, "preadv2"},
+#endif
{__NR_prlimit64, "prlimit64"},
{__NR_process_vm_readv, "process_vm_readv"},
{__NR_process_vm_writev, "process_vm_writev"},
@@ -285,7 +304,9 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_putpmsg, "putpmsg"},
{__NR_pwrite64, "pwrite64"},
{__NR_pwritev, "pwritev"},
+#ifdef __NR_pwritev2
{__NR_pwritev2, "pwritev2"},
+#endif
{__NR_query_module, "query_module"},
{__NR_quotactl, "quotactl"},
{__NR_read, "read"},
@@ -523,14 +544,16 @@ public:
void AllowAddressSpaceAccess()
{
- allowed_syscalls.insert(__NR_brk); // change data segment size
- allowed_syscalls.insert(__NR_madvise); // give advice about use of memory
+ allowed_syscalls.insert(__NR_brk); // change data segment size
+ allowed_syscalls.insert(__NR_madvise); // give advice about use of memory
allowed_syscalls.insert(__NR_membarrier); // issue memory barriers on a set of threads
- allowed_syscalls.insert(__NR_mlock); // lock memory
- allowed_syscalls.insert(__NR_mmap); // map files or devices into memory
- allowed_syscalls.insert(__NR_mprotect); // set protection on a region of memory
- allowed_syscalls.insert(__NR_munlock); // unlock memory
- allowed_syscalls.insert(__NR_munmap); // unmap files or devices into memory
+ allowed_syscalls.insert(__NR_mincore); // check if virtual memory is in RAM
+ allowed_syscalls.insert(__NR_mlock); // lock memory
+ allowed_syscalls.insert(__NR_mmap); // map files or devices into memory
+ allowed_syscalls.insert(__NR_mprotect); // set protection on a region of memory
+ allowed_syscalls.insert(__NR_mremap); // remap a file in memory
+ allowed_syscalls.insert(__NR_munlock); // unlock memory
+ allowed_syscalls.insert(__NR_munmap); // unmap files or devices into memory
}
void AllowEpoll()
@@ -690,6 +713,7 @@ public:
void AllowProcessStartOrDeath()
{
allowed_syscalls.insert(__NR_clone); // create a child process
+ allowed_syscalls.insert(__NR_clone3); // create a child process
allowed_syscalls.insert(__NR_exit); // terminate the calling process
allowed_syscalls.insert(__NR_exit_group); // exit all threads in a process
allowed_syscalls.insert(__NR_fork); // create a child process
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 79c08816fa..12d7dc49b2 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -98,7 +98,7 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b
fs::path pathLockFile = directory / lockfile_name;
// If a lock for this directory already exists in the map, don't try to re-lock it
- if (dir_locks.count(pathLockFile.string())) {
+ if (dir_locks.count(fs::PathToString(pathLockFile))) {
return true;
}
@@ -107,11 +107,11 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b
if (file) fclose(file);
auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
if (!lock->TryLock()) {
- return error("Error while attempting to lock directory %s: %s", directory.string(), lock->GetReason());
+ return error("Error while attempting to lock directory %s: %s", fs::PathToString(directory), lock->GetReason());
}
if (!probe_only) {
// Lock successful and we're not just probing, put it into the map
- dir_locks.emplace(pathLockFile.string(), std::move(lock));
+ dir_locks.emplace(fs::PathToString(pathLockFile), std::move(lock));
}
return true;
}
@@ -119,7 +119,7 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b
void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name)
{
LOCK(cs_dir_locks);
- dir_locks.erase((directory / lockfile_name).string());
+ dir_locks.erase(fs::PathToString(directory / lockfile_name));
}
void ReleaseDirectoryLocks()
@@ -242,7 +242,7 @@ namespace {
fs::path StripRedundantLastElementsOfPath(const fs::path& path)
{
auto result = path;
- while (result.filename().string() == ".") {
+ while (fs::PathToString(result.filename()) == ".") {
result = result.parent_path();
}
@@ -402,7 +402,7 @@ const fs::path& ArgsManager::GetBlocksDirPath() const
if (!path.empty()) return path;
if (IsArgSet("-blocksdir")) {
- path = fs::system_complete(GetArg("-blocksdir", ""));
+ path = fs::system_complete(fs::PathFromString(GetArg("-blocksdir", "")));
if (!fs::is_directory(path)) {
path = "";
return path;
@@ -411,7 +411,7 @@ const fs::path& ArgsManager::GetBlocksDirPath() const
path = GetDataDirBase();
}
- path /= BaseParams().DataDir();
+ path /= fs::PathFromString(BaseParams().DataDir());
path /= "blocks";
fs::create_directories(path);
path = StripRedundantLastElementsOfPath(path);
@@ -429,7 +429,7 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const
std::string datadir = GetArg("-datadir", "");
if (!datadir.empty()) {
- path = fs::system_complete(datadir);
+ path = fs::system_complete(fs::PathFromString(datadir));
if (!fs::is_directory(path)) {
path = "";
return path;
@@ -438,7 +438,7 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const
path = GetDefaultDataDir();
}
if (net_specific)
- path /= BaseParams().DataDir();
+ path /= fs::PathFromString(BaseParams().DataDir());
if (fs::create_directories(path)) {
// This is the first run, create wallets subdirectory too
@@ -517,7 +517,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const
}
if (filepath) {
std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
- *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), temp ? settings + ".tmp" : settings);
+ *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), fs::PathFromString(temp ? settings + ".tmp" : settings));
}
return true;
}
@@ -572,7 +572,7 @@ bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors) const
return false;
}
if (!RenameOver(path_tmp, path)) {
- SaveErrors({strprintf("Failed renaming settings file %s to %s\n", path_tmp.string(), path.string())}, errors);
+ SaveErrors({strprintf("Failed renaming settings file %s to %s\n", fs::PathToString(path_tmp), fs::PathToString(path))}, errors);
return false;
}
return true;
@@ -809,12 +809,12 @@ fs::path GetDefaultDataDir()
bool CheckDataDirOption()
{
std::string datadir = gArgs.GetArg("-datadir", "");
- return datadir.empty() || fs::is_directory(fs::system_complete(datadir));
+ return datadir.empty() || fs::is_directory(fs::system_complete(fs::PathFromString(datadir)));
}
fs::path GetConfigFile(const std::string& confPath)
{
- return AbsPathForConfigVal(fs::path(confPath), false);
+ return AbsPathForConfigVal(fs::PathFromString(confPath), false);
}
static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections)
@@ -1065,7 +1065,7 @@ bool RenameOver(fs::path src, fs::path dest)
return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(),
MOVEFILE_REPLACE_EXISTING) != 0;
#else
- int rc = std::rename(src.string().c_str(), dest.string().c_str());
+ int rc = std::rename(src.c_str(), dest.c_str());
return (rc == 0);
#endif /* WIN32 */
}
diff --git a/src/validation.cpp b/src/validation.cpp
index 880a01eb7d..78559a8ee6 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -474,7 +474,6 @@ private:
std::unique_ptr<CTxMemPoolEntry> m_entry;
std::list<CTransactionRef> m_replaced_transactions;
- bool m_replacement_transaction;
CAmount m_base_fees;
CAmount m_modified_fees;
/** Total modified fees of all transactions being replaced. */
@@ -556,7 +555,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
CTxMemPool::setEntries& allConflicting = ws.m_all_conflicting;
CTxMemPool::setEntries& setAncestors = ws.m_ancestors;
std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry;
- bool& fReplacementTransaction = ws.m_replacement_transaction;
CAmount& nModifiedFees = ws.m_modified_fees;
CAmount& nConflictingFees = ws.m_conflicting_fees;
size_t& nConflictingSize = ws.m_conflicting_size;
@@ -779,8 +777,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
- fReplacementTransaction = setConflicts.size();
- if (fReplacementTransaction) {
+ if (!setConflicts.empty()) {
CFeeRate newFeeRate(nModifiedFees, nSize);
// It's possible that the replacement pays more fees than its direct conflicts but not more
// than all conflicts (i.e. the direct conflicts have high-fee descendants). However, if the
@@ -885,7 +882,6 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
const CAmount& nModifiedFees = ws.m_modified_fees;
const CAmount& nConflictingFees = ws.m_conflicting_fees;
const size_t& nConflictingSize = ws.m_conflicting_size;
- const bool fReplacementTransaction = ws.m_replacement_transaction;
std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry;
// Remove conflicting transactions from the mempool
@@ -901,11 +897,10 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
m_pool.RemoveStaged(allConflicting, false, MemPoolRemovalReason::REPLACED);
// This transaction should only count for fee estimation if:
- // - it isn't a BIP 125 replacement transaction (may not be widely supported)
// - it's not being re-added during a reorg which bypasses typical mempool fee limits
// - the node is not behind
// - the transaction is not dependent on any other transactions in the mempool
- bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx);
+ bool validForFeeEstimation = !bypass_limits && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx);
// Store transaction in memory
m_pool.addUnchecked(*entry, setAncestors, validForFeeEstimation);
@@ -1882,14 +1877,13 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4;
LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5 - nTime4), nTimeIndex * MICRO, nTimeIndex * MILLI / nBlocksTotal);
- TRACE7(validation, block_connected,
- block.GetHash().ToString().c_str(),
+ TRACE6(validation, block_connected,
+ block.GetHash().data(),
pindex->nHeight,
block.vtx.size(),
nInputs,
nSigOpsCost,
- GetTimeMicros() - nTimeStart, // in microseconds (µs)
- block.GetHash().data()
+ GetTimeMicros() - nTimeStart // in microseconds (µs)
);
return true;
@@ -2034,8 +2028,8 @@ bool CChainState::FlushStateToDisk(
}
// Flush best chain related state. This can only be done if the blocks / block index write was also done.
if (fDoFullFlush && !CoinsTip().GetBestBlock().IsNull()) {
- LOG_TIME_SECONDS(strprintf("write coins cache to disk (%d coins, %.2fkB)",
- coins_count, coins_mem_usage / 1000));
+ LOG_TIME_MILLIS_WITH_CATEGORY(strprintf("write coins cache to disk (%d coins, %.2fkB)",
+ coins_count, coins_mem_usage / 1000), BCLog::BENCH);
// Typical Coin structures on disk are around 48 bytes in size.
// Pushing a new one to the database can cause it to be written
@@ -3210,7 +3204,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationS
if (ppindex)
*ppindex = pindex;
if (pindex->nStatus & BLOCK_FAILED_MASK) {
- LogPrintf("ERROR: %s: block %s is marked invalid\n", __func__, hash.ToString());
+ LogPrint(BCLog::VALIDATION, "%s: block %s is marked invalid\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_CACHED_INVALID, "duplicate");
}
return true;
@@ -3225,16 +3219,18 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationS
CBlockIndex* pindexPrev = nullptr;
BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock);
if (mi == m_block_index.end()) {
- LogPrintf("ERROR: %s: prev block not found\n", __func__);
+ LogPrint(BCLog::VALIDATION, "%s: %s prev block not found\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_MISSING_PREV, "prev-blk-not-found");
}
pindexPrev = (*mi).second;
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) {
- LogPrintf("ERROR: %s: prev block invalid\n", __func__);
+ LogPrint(BCLog::VALIDATION, "%s: %s prev block invalid\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk");
}
- if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime()))
- return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), state.ToString());
+ if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime())) {
+ LogPrint(BCLog::VALIDATION, "%s: Consensus::ContextualCheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString());
+ return false;
+ }
/* Determine if this block descends from any block which has been found
* invalid (m_failed_blocks), then mark pindexPrev and any blocks between
@@ -3269,7 +3265,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationS
setDirtyBlockIndex.insert(invalid_walk);
invalid_walk = invalid_walk->pprev;
}
- LogPrintf("ERROR: %s: prev block invalid\n", __func__);
+ LogPrint(BCLog::VALIDATION, "%s: %s prev block invalid\n", __func__, hash.ToString());
return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk");
}
}
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 2eb4d3106c..2290e119fd 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -61,9 +61,9 @@ bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const
std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory)
{
LOCK(cs_db);
- auto inserted = g_dbenvs.emplace(env_directory.string(), std::weak_ptr<BerkeleyEnvironment>());
+ auto inserted = g_dbenvs.emplace(fs::PathToString(env_directory), std::weak_ptr<BerkeleyEnvironment>());
if (inserted.second) {
- auto env = std::make_shared<BerkeleyEnvironment>(env_directory.string());
+ auto env = std::make_shared<BerkeleyEnvironment>(env_directory);
inserted.first->second = env;
return env;
}
@@ -101,7 +101,7 @@ void BerkeleyEnvironment::Close()
if (error_file) fclose(error_file);
- UnlockDirectory(strPath, ".walletlock");
+ UnlockDirectory(fs::PathFromString(strPath), ".walletlock");
}
void BerkeleyEnvironment::Reset()
@@ -111,7 +111,7 @@ void BerkeleyEnvironment::Reset()
fMockDb = false;
}
-BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path) : strPath(dir_path.string())
+BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path) : strPath(fs::PathToString(dir_path))
{
Reset();
}
@@ -129,24 +129,24 @@ bool BerkeleyEnvironment::Open(bilingual_str& err)
return true;
}
- fs::path pathIn = strPath;
+ fs::path pathIn = fs::PathFromString(strPath);
TryCreateDirectories(pathIn);
if (!LockDirectory(pathIn, ".walletlock")) {
LogPrintf("Cannot obtain a lock on wallet directory %s. Another instance of bitcoin may be using it.\n", strPath);
- err = strprintf(_("Error initializing wallet database environment %s!"), Directory());
+ err = strprintf(_("Error initializing wallet database environment %s!"), fs::quoted(fs::PathToString(Directory())));
return false;
}
fs::path pathLogDir = pathIn / "database";
TryCreateDirectories(pathLogDir);
fs::path pathErrorFile = pathIn / "db.log";
- LogPrintf("BerkeleyEnvironment::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
+ LogPrintf("BerkeleyEnvironment::Open: LogDir=%s ErrorFile=%s\n", fs::PathToString(pathLogDir), fs::PathToString(pathErrorFile));
unsigned int nEnvFlags = 0;
if (gArgs.GetBoolArg("-privdb", DEFAULT_WALLET_PRIVDB))
nEnvFlags |= DB_PRIVATE;
- dbenv->set_lg_dir(pathLogDir.string().c_str());
+ dbenv->set_lg_dir(fs::PathToString(pathLogDir).c_str());
dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet
dbenv->set_lg_bsize(0x10000);
dbenv->set_lg_max(1048576);
@@ -173,7 +173,7 @@ bool BerkeleyEnvironment::Open(bilingual_str& err)
LogPrintf("BerkeleyEnvironment::Open: Error %d closing failed database environment: %s\n", ret2, DbEnv::strerror(ret2));
}
Reset();
- err = strprintf(_("Error initializing wallet database environment %s!"), Directory());
+ err = strprintf(_("Error initializing wallet database environment %s!"), fs::quoted(fs::PathToString(Directory())));
if (ret == DB_RUNRECOVERY) {
err += Untranslated(" ") + _("This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet");
}
@@ -261,7 +261,7 @@ bool BerkeleyDatabase::Verify(bilingual_str& errorStr)
fs::path file_path = walletDir / strFile;
LogPrintf("Using BerkeleyDB version %s\n", BerkeleyDatabaseVersion());
- LogPrintf("Using wallet %s\n", file_path.string());
+ LogPrintf("Using wallet %s\n", fs::PathToString(file_path));
if (!env->Open(errorStr)) {
return false;
@@ -274,7 +274,7 @@ bool BerkeleyDatabase::Verify(bilingual_str& errorStr)
Db db(env->dbenv.get(), 0);
int result = db.verify(strFile.c_str(), nullptr, nullptr, 0);
if (result != 0) {
- errorStr = strprintf(_("%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup."), file_path);
+ errorStr = strprintf(_("%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup."), fs::quoted(fs::PathToString(file_path)));
return false;
}
}
@@ -566,7 +566,7 @@ void BerkeleyEnvironment::Flush(bool fShutdown)
dbenv->log_archive(&listp, DB_ARCH_REMOVE);
Close();
if (!fMockDb) {
- fs::remove_all(fs::path(strPath) / "database");
+ fs::remove_all(fs::PathFromString(strPath) / "database");
}
}
}
@@ -614,21 +614,21 @@ bool BerkeleyDatabase::Backup(const std::string& strDest) const
// Copy wallet file
fs::path pathSrc = env->Directory() / strFile;
- fs::path pathDest(strDest);
+ fs::path pathDest(fs::PathFromString(strDest));
if (fs::is_directory(pathDest))
- pathDest /= strFile;
+ pathDest /= fs::PathFromString(strFile);
try {
if (fs::equivalent(pathSrc, pathDest)) {
- LogPrintf("cannot backup to wallet source file %s\n", pathDest.string());
+ LogPrintf("cannot backup to wallet source file %s\n", fs::PathToString(pathDest));
return false;
}
fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
- LogPrintf("copied %s to %s\n", strFile, pathDest.string());
+ LogPrintf("copied %s to %s\n", strFile, fs::PathToString(pathDest));
return true;
} catch (const fs::filesystem_error& e) {
- LogPrintf("error copying %s to %s - %s\n", strFile, pathDest.string(), fsbridge::get_filesystem_error_message(e));
+ LogPrintf("error copying %s to %s - %s\n", strFile, fs::PathToString(pathDest), fsbridge::get_filesystem_error_message(e));
return false;
}
}
@@ -828,10 +828,10 @@ std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, con
std::unique_ptr<BerkeleyDatabase> db;
{
LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor
- std::string data_filename = data_file.filename().string();
+ std::string data_filename = fs::PathToString(data_file.filename());
std::shared_ptr<BerkeleyEnvironment> env = GetBerkeleyEnv(data_file.parent_path());
if (env->m_databases.count(data_filename)) {
- error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string()));
+ error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", fs::PathToString(env->Directory() / data_filename)));
status = DatabaseStatus::FAILED_ALREADY_LOADED;
return nullptr;
}
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h
index a8209587d7..b666a8e73a 100644
--- a/src/wallet/bdb.h
+++ b/src/wallet/bdb.h
@@ -63,7 +63,7 @@ public:
bool IsMock() const { return fMockDb; }
bool IsInitialized() const { return fDbEnvInit; }
- fs::path Directory() const { return strPath; }
+ fs::path Directory() const { return fs::PathFromString(strPath); }
bool Open(bilingual_str& error);
void Close();
@@ -141,7 +141,7 @@ public:
bool Verify(bilingual_str& error);
/** Return path to main database filename */
- std::string Filename() override { return (env->Directory() / strFile).string(); }
+ std::string Filename() override { return fs::PathToString(env->Directory() / strFile); }
std::string Format() override { return "bdb"; }
/**
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index c989512d3e..edd81e590f 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -93,7 +93,7 @@ public:
setSelected.insert(output);
}
- void Select(const COutPoint& outpoint, const CTxOut& txout)
+ void SelectExternal(const COutPoint& outpoint, const CTxOut& txout)
{
setSelected.insert(outpoint);
m_external_txouts.emplace(outpoint, txout);
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 8d5316e0af..c74c69ed09 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -12,7 +12,7 @@
std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
{
- const size_t offset = wallet_dir.string().size() + (wallet_dir == wallet_dir.root_name() ? 0 : 1);
+ const size_t offset = wallet_dir.native().size() + (wallet_dir == wallet_dir.root_name() ? 0 : 1);
std::vector<fs::path> paths;
boost::system::error_code ec;
@@ -20,9 +20,9 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
if (ec) {
if (fs::is_directory(*it)) {
it.no_push();
- LogPrintf("%s: %s %s -- skipping.\n", __func__, ec.message(), it->path().string());
+ LogPrintf("%s: %s %s -- skipping.\n", __func__, ec.message(), fs::PathToString(it->path()));
} else {
- LogPrintf("%s: %s %s\n", __func__, ec.message(), it->path().string());
+ LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(it->path()));
}
continue;
}
@@ -30,7 +30,8 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
try {
// Get wallet path relative to walletdir by removing walletdir from the wallet path.
// This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60.
- const fs::path path = it->path().string().substr(offset);
+ const auto path_str = it->path().native().substr(offset);
+ const fs::path path{path_str.begin(), path_str.end()};
if (it->status().type() == fs::directory_file &&
(IsBDBFile(BDBDataFile(it->path())) || IsSQLiteFile(SQLiteDataFile(it->path())))) {
@@ -50,7 +51,7 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
}
}
} catch (const std::exception& e) {
- LogPrintf("%s: Error scanning %s: %s\n", __func__, it->path().string(), e.what());
+ LogPrintf("%s: Error scanning %s: %s\n", __func__, fs::PathToString(it->path()), e.what());
it.no_push();
}
}
@@ -85,7 +86,7 @@ bool IsBDBFile(const fs::path& path)
// This check also prevents opening lock files.
boost::system::error_code ec;
auto size = fs::file_size(path, ec);
- if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
+ if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(path));
if (size < 4096) return false;
fsbridge::ifstream file(path, std::ios::binary);
@@ -109,7 +110,7 @@ bool IsSQLiteFile(const fs::path& path)
// A SQLite Database file is at least 512 bytes.
boost::system::error_code ec;
auto size = fs::file_size(path, ec);
- if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
+ if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(path));
if (size < 512) return false;
fsbridge::ifstream file(path, std::ios::binary);
diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp
index c39c0c7e73..08d94b76d9 100644
--- a/src/wallet/dump.cpp
+++ b/src/wallet/dump.cpp
@@ -19,16 +19,16 @@ bool DumpWallet(CWallet& wallet, bilingual_str& error)
return false;
}
- fs::path path = dump_filename;
+ fs::path path = fs::PathFromString(dump_filename);
path = fs::absolute(path);
if (fs::exists(path)) {
- error = strprintf(_("File %s already exists. If you are sure this is what you want, move it out of the way first."), path.string());
+ error = strprintf(_("File %s already exists. If you are sure this is what you want, move it out of the way first."), fs::PathToString(path));
return false;
}
fsbridge::ofstream dump_file;
dump_file.open(path);
if (dump_file.fail()) {
- error = strprintf(_("Unable to open %s for writing"), path.string());
+ error = strprintf(_("Unable to open %s for writing"), fs::PathToString(path));
return false;
}
@@ -114,10 +114,10 @@ bool CreateFromDump(const std::string& name, const fs::path& wallet_path, biling
return false;
}
- fs::path dump_path = dump_filename;
+ fs::path dump_path = fs::PathFromString(dump_filename);
dump_path = fs::absolute(dump_path);
if (!fs::exists(dump_path)) {
- error = strprintf(_("Dump file %s does not exist."), dump_path.string());
+ error = strprintf(_("Dump file %s does not exist."), fs::PathToString(dump_path));
return false;
}
fsbridge::ifstream dump_file(dump_path);
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 7d0cdb6934..57f1a6a67a 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -551,13 +551,13 @@ public:
}
std::string getWalletDir() override
{
- return GetWalletDir().string();
+ return fs::PathToString(GetWalletDir());
}
std::vector<std::string> listWalletDir() override
{
std::vector<std::string> paths;
for (auto& path : ListDatabases(GetWalletDir())) {
- paths.push_back(path.string());
+ paths.push_back(fs::PathToString(path));
}
return paths;
}
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index 1b841026b8..7ef5a0cf55 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -25,25 +25,25 @@ bool VerifyWallets(WalletContext& context)
ArgsManager& args = *Assert(context.args);
if (args.IsArgSet("-walletdir")) {
- fs::path wallet_dir = args.GetArg("-walletdir", "");
+ fs::path wallet_dir = fs::PathFromString(args.GetArg("-walletdir", ""));
boost::system::error_code error;
// The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
if (error || !fs::exists(wallet_dir)) {
- chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
+ chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), fs::PathToString(wallet_dir)));
return false;
} else if (!fs::is_directory(wallet_dir)) {
- chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
+ chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), fs::PathToString(wallet_dir)));
return false;
// The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
} else if (!wallet_dir.is_absolute()) {
- chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
+ chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), fs::PathToString(wallet_dir)));
return false;
}
- args.ForceSetArg("-walletdir", canonical_wallet_dir.string());
+ args.ForceSetArg("-walletdir", fs::PathToString(canonical_wallet_dir));
}
- LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
+ LogPrintf("Using wallet directory %s\n", fs::PathToString(GetWalletDir()));
chain.initMessage(_("Verifying wallet(s)…").translated);
@@ -70,7 +70,7 @@ bool VerifyWallets(WalletContext& context)
for (const auto& wallet : chain.getSettingsList("wallet")) {
const auto& wallet_file = wallet.get_str();
- const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), wallet_file);
+ const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(wallet_file));
if (!wallet_paths.insert(path).second) {
chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
@@ -102,7 +102,7 @@ bool LoadWallets(WalletContext& context)
std::set<fs::path> wallet_paths;
for (const auto& wallet : chain.getSettingsList("wallet")) {
const auto& name = wallet.get_str();
- if (!wallet_paths.insert(name).second) {
+ if (!wallet_paths.insert(fs::PathFromString(name)).second) {
continue;
}
DatabaseOptions options;
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 4d7fb2d38c..9b09bc23d6 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -550,7 +550,7 @@ RPCHelpMan importwallet()
EnsureWalletIsUnlocked(*pwallet);
fsbridge::ifstream file;
- file.open(request.params[0].get_str(), std::ios::in | std::ios::ate);
+ file.open(fs::u8path(request.params[0].get_str()), std::ios::in | std::ios::ate);
if (!file.is_open()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
}
@@ -745,7 +745,7 @@ RPCHelpMan dumpwallet()
EnsureWalletIsUnlocked(wallet);
- fs::path filepath = request.params[0].get_str();
+ fs::path filepath = fs::u8path(request.params[0].get_str());
filepath = fs::absolute(filepath);
/* Prevent arbitrary files from being overwritten. There have been reports
@@ -754,7 +754,7 @@ RPCHelpMan dumpwallet()
* It may also avoid other security issues.
*/
if (fs::exists(filepath)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.string() + " already exists. If you are sure this is what you want, move it out of the way first");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.u8string() + " already exists. If you are sure this is what you want, move it out of the way first");
}
fsbridge::ofstream file;
@@ -844,7 +844,7 @@ RPCHelpMan dumpwallet()
file.close();
UniValue reply(UniValue::VOBJ);
- reply.pushKV("filename", filepath.string());
+ reply.pushKV("filename", filepath.u8string());
return reply;
},
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 39cde4e4ec..6959466d1d 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1854,7 +1854,7 @@ static RPCHelpMan keypoolrefill()
"\nFills the keypool."+
HELP_REQUIRING_PASSPHRASE,
{
- {"newsize", RPCArg::Type::NUM, RPCArg::Default{100}, "The new keypool size"},
+ {"newsize", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%u, or as set by -keypool", DEFAULT_KEYPOOL_SIZE)}, "The new keypool size"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
@@ -1893,6 +1893,33 @@ static RPCHelpMan keypoolrefill()
}
+static RPCHelpMan newkeypool()
+{
+ return RPCHelpMan{"newkeypool",
+ "\nEntirely clears and refills the keypool."+
+ HELP_REQUIRING_PASSPHRASE,
+ {},
+ RPCResult{RPCResult::Type::NONE, "", ""},
+ RPCExamples{
+ HelpExampleCli("newkeypool", "")
+ + HelpExampleRpc("newkeypool", "")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!pwallet) return NullUniValue;
+
+ LOCK(pwallet->cs_wallet);
+
+ LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
+ spk_man.NewKeyPool();
+
+ return NullUniValue;
+},
+ };
+}
+
+
static RPCHelpMan walletpassphrase()
{
return RPCHelpMan{"walletpassphrase",
@@ -2555,7 +2582,7 @@ static RPCHelpMan listwalletdir()
UniValue wallets(UniValue::VARR);
for (const auto& path : ListDatabases(GetWalletDir())) {
UniValue wallet(UniValue::VOBJ);
- wallet.pushKV("name", path.string());
+ wallet.pushKV("name", path.u8string());
wallets.push_back(wallet);
}
@@ -2856,7 +2883,7 @@ static RPCHelpMan restorewallet()
WalletContext& context = EnsureWalletContext(request.context);
- std::string backup_file = request.params[1].get_str();
+ auto backup_file = fs::u8path(request.params[1].get_str());
if (!fs::exists(backup_file)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Backup file does not exist");
@@ -2864,14 +2891,14 @@ static RPCHelpMan restorewallet()
std::string wallet_name = request.params[0].get_str();
- const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), wallet_name);
+ const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name));
if (fs::exists(wallet_path)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Wallet name already exists.");
}
if (!TryCreateDirectories(wallet_path)) {
- throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Failed to create database path '%s'. Database already exists.", wallet_path.string()));
+ throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Failed to create database path '%s'. Database already exists.", wallet_path.u8string()));
}
auto wallet_file = wallet_path / "wallet.dat";
@@ -3177,6 +3204,34 @@ static RPCHelpMan listunspent()
};
}
+// Only includes key documentation where the key is snake_case in all RPC methods. MixedCase keys can be added later.
+static std::vector<RPCArg> FundTxDoc()
+{
+ return {
+ {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ " \"" + FeeModes("\"\n\"") + "\""},
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n"
+ "Allows this transaction to be replaced by a transaction with higher fees"},
+ {"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "Keys and scripts needed for producing a final transaction with a dummy signature.\n"
+ "Used for fee estimation during coin selection.",
+ {
+ {"pubkeys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Public keys involved in this transaction.",
+ {
+ {"pubkey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A public key"},
+ }},
+ {"scripts", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Scripts involved in this transaction.",
+ {
+ {"script", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A script"},
+ }},
+ {"descriptors", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Descriptors that provide solving data for this transaction.",
+ {
+ {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A descriptor"},
+ }},
+ }},
+ };
+}
+
void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, const UniValue& options, CCoinControl& coinControl, bool override_min_fee)
{
// Make sure the results are valid at least up to the most recent block
@@ -3292,7 +3347,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
}
if (options.exists("solving_data")) {
- UniValue solving_data = options["solving_data"].get_obj();
+ const UniValue solving_data = options["solving_data"].get_obj();
if (solving_data.exists("pubkeys")) {
for (const UniValue& pk_univ : solving_data["pubkeys"].get_array().getValues()) {
const std::string& pk_str = pk_univ.get_str();
@@ -3300,7 +3355,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not hex", pk_str));
}
const std::vector<unsigned char> data(ParseHex(pk_str));
- CPubKey pubkey(data.begin(), data.end());
+ const CPubKey pubkey(data.begin(), data.end());
if (!pubkey.IsFullyValid()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not a valid public key", pk_str));
}
@@ -3365,7 +3420,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
wallet.chain().findCoins(coins);
for (const auto& coin : coins) {
if (!coin.second.out.IsNull()) {
- coinControl.Select(coin.first, coin.second.out);
+ coinControl.SelectExternal(coin.first, coin.second.out);
}
}
@@ -3394,6 +3449,7 @@ static RPCHelpMan fundrawtransaction()
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
+ Cat<std::vector<RPCArg>>(
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
@@ -3416,32 +3472,8 @@ static RPCHelpMan fundrawtransaction()
{"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
},
},
- {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n"
- "Allows this transaction to be replaced by a transaction with higher fees"},
- {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
- " \"" + FeeModes("\"\n\"") + "\""},
- {"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "Keys and scripts needed for producing a final transaction with a dummy signature.\n"
- "Used for fee estimation during coin selection.",
- {
- {"pubkeys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Public keys involved in this transaction.",
- {
- {"pubkey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A public key"},
- },
- },
- {"scripts", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Scripts involved in this transaction.",
- {
- {"script", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A script"},
- },
- },
- {"descriptors", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Descriptors that provide solving data for this transaction.",
- {
- {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A descriptor"},
- },
- }
- }
- },
},
+ FundTxDoc()),
"options"},
{"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n"
"If iswitness is not present, heuristic tests will be used in decoding.\n"
@@ -4250,6 +4282,7 @@ static RPCHelpMan send()
" \"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
+ Cat<std::vector<RPCArg>>(
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
@@ -4259,9 +4292,6 @@ static RPCHelpMan send()
{"change_address", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
{"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
- {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
- " \"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
{"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
@@ -4284,29 +4314,8 @@ static RPCHelpMan send()
{"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
},
},
- {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n"
- "Allows this transaction to be replaced by a transaction with higher fees"},
- {"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "Keys and scripts needed for producing a final transaction with a dummy signature.\n"
- "Used for fee estimation during coin selection.",
- {
- {"pubkeys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Public keys involved in this transaction.",
- {
- {"pubkey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A public key"},
- },
- },
- {"scripts", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Scripts involved in this transaction.",
- {
- {"script", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A script"},
- },
- },
- {"descriptors", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Descriptors that provide solving data for this transaction.",
- {
- {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A descriptor"},
- },
- }
- }
- },
},
+ FundTxDoc()),
"options"},
},
RPCResult{
@@ -4627,6 +4636,7 @@ static RPCHelpMan walletcreatefundedpsbt()
},
{"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
+ Cat<std::vector<RPCArg>>(
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
@@ -4647,32 +4657,8 @@ static RPCHelpMan walletcreatefundedpsbt()
{"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
},
},
- {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n"
- "Allows this transaction to be replaced by a transaction with higher fees"},
- {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
- " \"" + FeeModes("\"\n\"") + "\""},
- {"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "Keys and scripts needed for producing a final transaction with a dummy signature.\n"
- "Used for fee estimation during coin selection.",
- {
- {"pubkeys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Public keys involved in this transaction.",
- {
- {"pubkey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A public key"},
- },
- },
- {"scripts", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Scripts involved in this transaction.",
- {
- {"script", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A script"},
- },
- },
- {"descriptors", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Descriptors that provide solving data for this transaction.",
- {
- {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A descriptor"},
- },
- }
- }
- },
},
+ FundTxDoc()),
"options"},
{"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
},
@@ -4916,6 +4902,7 @@ static const CRPCCommand commands[] =
{ "wallet", &listwallets, },
{ "wallet", &loadwallet, },
{ "wallet", &lockunspent, },
+ { "wallet", &newkeypool, },
{ "wallet", &removeprunedfunds, },
{ "wallet", &rescanblockchain, },
{ "wallet", &send, },
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index fdfb36bb0a..619ebc8b4f 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -489,7 +489,7 @@ bool LegacyScriptPubKeyMan::Upgrade(int prev_version, int new_version, bilingual
}
// Regenerate the keypool if upgraded to HD
if (hd_upgrade) {
- if (!TopUp()) {
+ if (!NewKeyPool()) {
error = _("Unable to generate keys");
return false;
}
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 5bed09e067..5470177440 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -475,7 +475,7 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo
CInputCoin coin(outpoint, txout, input_bytes);
nValueFromPresetInputs += coin.txout.nValue;
- if (coin.m_input_bytes <= 0) {
+ if (coin.m_input_bytes == -1) {
return false; // Not solvable, can't estimate size for fee
}
coin.effective_value = coin.txout.nValue - coin_selection_params.m_effective_feerate.GetFee(coin.m_input_bytes);
@@ -814,7 +814,7 @@ static bool CreateTransactionInternal(
// Calculate the transaction fee
TxSize tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), &wallet, &coin_control);
int nBytes = tx_sizes.vsize;
- if (nBytes < 0) {
+ if (nBytes == -1) {
error = _("Missing solving data for estimating transaction size");
return false;
}
diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp
index 815d17967c..650e083e8e 100644
--- a/src/wallet/sqlite.cpp
+++ b/src/wallet/sqlite.cpp
@@ -67,7 +67,7 @@ static void SetPragma(sqlite3* db, const std::string& key, const std::string& va
}
SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, bool mock)
- : WalletDatabase(), m_mock(mock), m_dir_path(dir_path.string()), m_file_path(file_path.string())
+ : WalletDatabase(), m_mock(mock), m_dir_path(fs::PathToString(dir_path)), m_file_path(fs::PathToString(file_path))
{
{
LOCK(g_sqlite_mutex);
@@ -206,7 +206,7 @@ void SQLiteDatabase::Open()
if (m_db == nullptr) {
if (!m_mock) {
- TryCreateDirectories(m_dir_path);
+ TryCreateDirectories(fs::PathFromString(m_dir_path));
}
int ret = sqlite3_open_v2(m_file_path.c_str(), &m_db, flags, nullptr);
if (ret != SQLITE_OK) {
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index 16cb7e0baf..dba3f35025 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -16,7 +16,7 @@ BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup)
static std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& path, std::string& database_filename)
{
fs::path data_file = BDBDataFile(path);
- database_filename = data_file.filename().string();
+ database_filename = fs::PathToString(data_file.filename());
return GetBerkeleyEnv(data_file.parent_path());
}
@@ -25,11 +25,7 @@ BOOST_AUTO_TEST_CASE(getwalletenv_file)
std::string test_name = "test_name.dat";
const fs::path datadir = gArgs.GetDataDirNet();
fs::path file_path = datadir / test_name;
-#if BOOST_VERSION >= 107700
- std::ofstream f(BOOST_FILESYSTEM_C_STR(file_path));
-#else
- std::ofstream f(file_path.BOOST_FILESYSTEM_C_STR);
-#endif // BOOST_VERSION >= 107700
+ fs::ofstream f(file_path);
f.close();
std::string filename;
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index 53c972c46d..170675c035 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -32,11 +32,7 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainNam
fs::create_directories(m_walletdir_path_cases["default"]);
fs::create_directories(m_walletdir_path_cases["custom"]);
fs::create_directories(m_walletdir_path_cases["relative"]);
-#if BOOST_VERSION >= 107700
- std::ofstream f(BOOST_FILESYSTEM_C_STR(m_walletdir_path_cases["file"]));
-#else
- std::ofstream f(m_walletdir_path_cases["file"].BOOST_FILESYSTEM_C_STR);
-#endif // BOOST_VERSION >= 107700
+ fs::ofstream f(m_walletdir_path_cases["file"]);
f.close();
}
@@ -50,5 +46,5 @@ InitWalletDirTestingSetup::~InitWalletDirTestingSetup()
void InitWalletDirTestingSetup::SetWalletDir(const fs::path& walletdir_path)
{
- gArgs.ForceSetArg("-walletdir", walletdir_path.string());
+ gArgs.ForceSetArg("-walletdir", fs::PathToString(walletdir_path));
}
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
index 45e1b8c4b8..222c2bf4b7 100644
--- a/src/wallet/test/init_tests.cpp
+++ b/src/wallet/test/init_tests.cpp
@@ -17,7 +17,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default)
SetWalletDir(m_walletdir_path_cases["default"]);
bool result = m_wallet_client->verify();
BOOST_CHECK(result == true);
- fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
BOOST_CHECK_EQUAL(walletdir, expected_path);
}
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom)
SetWalletDir(m_walletdir_path_cases["custom"]);
bool result = m_wallet_client->verify();
BOOST_CHECK(result == true);
- fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]);
BOOST_CHECK_EQUAL(walletdir, expected_path);
}
@@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing)
SetWalletDir(m_walletdir_path_cases["trailing"]);
bool result = m_wallet_client->verify();
BOOST_CHECK(result == true);
- fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
BOOST_CHECK_EQUAL(walletdir, expected_path);
}
@@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2)
SetWalletDir(m_walletdir_path_cases["trailing2"]);
bool result = m_wallet_client->verify();
BOOST_CHECK(result == true);
- fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
BOOST_CHECK_EQUAL(walletdir, expected_path);
}
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 9938380369..94b5abfba7 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -258,7 +258,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
SetMockTime(KEY_TIME);
m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
- std::string backup_file = (gArgs.GetDataDirNet() / "wallet.backup").string();
+ std::string backup_file = fs::PathToString(gArgs.GetDataDirNet() / "wallet.backup");
// Import key into wallet and call dumpwallet to create backup file.
{
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index abfe9d7dba..598fce0112 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2515,16 +2515,16 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons
// 2. Path to an existing directory.
// 3. Path to a symlink to a directory.
// 4. For backwards compatibility, the name of a data file in -walletdir.
- const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), name);
+ const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name));
fs::file_type path_type = fs::symlink_status(wallet_path).type();
if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
(path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
- (path_type == fs::regular_file && fs::path(name).filename() == name))) {
+ (path_type == fs::regular_file && fs::PathFromString(name).filename() == fs::PathFromString(name)))) {
error_string = Untranslated(strprintf(
"Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
"database/log.?????????? files can be stored, a location where such a directory could be created, "
"or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
- name, GetWalletDir()));
+ name, fs::quoted(fs::PathToString(GetWalletDir()))));
status = DatabaseStatus::FAILED_BAD_PATH;
return nullptr;
}
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 8ff09a0878..a6839f1f78 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1106,7 +1106,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
try {
exists = fs::symlink_status(path).type() != fs::file_not_found;
} catch (const fs::filesystem_error& e) {
- error = Untranslated(strprintf("Failed to access database path '%s': %s", path.string(), fsbridge::get_filesystem_error_message(e)));
+ error = Untranslated(strprintf("Failed to access database path '%s': %s", fs::PathToString(path), fsbridge::get_filesystem_error_message(e)));
status = DatabaseStatus::FAILED_BAD_PATH;
return nullptr;
}
@@ -1118,33 +1118,33 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
}
if (IsSQLiteFile(SQLiteDataFile(path))) {
if (format) {
- error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", path.string()));
+ error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
format = DatabaseFormat::SQLITE;
}
} else if (options.require_existing) {
- error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string()));
+ error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_NOT_FOUND;
return nullptr;
}
if (!format && options.require_existing) {
- error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", path.string()));
+ error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
if (format && options.require_create) {
- error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", path.string()));
+ error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_ALREADY_EXISTS;
return nullptr;
}
// A db already exists so format is set, but options also specifies the format, so make sure they agree
if (format && options.require_format && format != options.require_format) {
- error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in required format.", path.string()));
+ error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in required format.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
@@ -1166,7 +1166,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
#ifdef USE_SQLITE
return MakeSQLiteDatabase(path, options, status, error);
#endif
- error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support SQLite database format.", path.string()));
+ error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support SQLite database format.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
@@ -1174,7 +1174,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
#ifdef USE_BDB
return MakeBerkeleyDatabase(path, options, status, error);
#endif
- error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", path.string()));
+ error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", fs::PathToString(path)));
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index e3cb5cee5d..788679bbeb 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -125,7 +125,7 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
return false;
}
const std::string name = args.GetArg("-wallet", "");
- const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), name);
+ const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name));
if (command == "create") {
DatabaseOptions options;
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index 1c518daba6..7f813432b3 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -12,7 +12,7 @@ fs::path GetWalletDir()
fs::path path;
if (gArgs.IsArgSet("-walletdir")) {
- path = gArgs.GetArg("-walletdir", "");
+ path = fs::PathFromString(gArgs.GetArg("-walletdir", ""));
if (!fs::is_directory(path)) {
// If the path specified doesn't exist, we return the deliberately
// invalid empty string.