diff --git a/doc/release-notes.md b/doc/release-notes.md
index 111ef4972..19ece3fb4 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,12 +1,15 @@
Bitcoin ABC version 0.18.8 is now available from:
This release includes the following features and fixes:
- `dumpwallet` now includes hex-encoded scripts from the wallet in the dumpfile
- `importwallet` now imports these scripts, but corresponding addresses may not
be added correctly or a manual rescan may be required to find relevant
transactions
- Remove miner policy estimator in favor of minimum fees, also remove `fee_estimates.dat`.
Old copies will be left in place.
- - The log timestamp format is now ISO 8601 (e.g. "2019-01-28T15:41:17Z")
\ No newline at end of file
+ - The log timestamp format is now ISO 8601 (e.g. "2019-01-28T15:41:17Z")
+ - Behavior change: in case of multiple values for an argument, the following rules apply:
+ - From the command line, the *last* value takes precedence
+ - From the config file, the *first* value takes precedence
\ No newline at end of file
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index a3cb6dd3f..62b97d776 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1,1118 +1,1141 @@
// Copyright (c) 2011-2016 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 "util.h"
#include "clientversion.h"
#include "primitives/transaction.h"
#include "sync.h"
#include "test/test_bitcoin.h"
#include "utilmoneystr.h"
#include "utilstrencodings.h"
#include
#include
#include
BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(util_criticalsection) {
CCriticalSection cs;
do {
LOCK(cs);
break;
BOOST_ERROR("break was swallowed!");
} while (0);
do {
TRY_LOCK(cs, lockTest);
if (lockTest) break;
BOOST_ERROR("break was swallowed!");
} while (0);
}
static const uint8_t ParseHex_expected[65] = {
0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67,
0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0,
0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6,
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04,
0xe5, 0x1e, 0xc1, 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b,
0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f};
BOOST_AUTO_TEST_CASE(util_ParseHex) {
std::vector result;
std::vector expected(
ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected));
// Basic test vector
result = ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0"
"ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d"
"578a4c702b6bf11d5f");
BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(),
expected.begin(), expected.end());
// Spaces between bytes must be supported
result = ParseHex("12 34 56 78");
BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 &&
result[2] == 0x56 && result[3] == 0x78);
// Leading space must be supported (used in CDBEnv::Salvage)
result = ParseHex(" 89 34 56 78");
BOOST_CHECK(result.size() == 4 && result[0] == 0x89 && result[1] == 0x34 &&
result[2] == 0x56 && result[3] == 0x78);
// Stop parsing at invalid value
result = ParseHex("1234 invalid 1234");
BOOST_CHECK(result.size() == 2 && result[0] == 0x12 && result[1] == 0x34);
}
BOOST_AUTO_TEST_CASE(util_HexStr) {
BOOST_CHECK_EQUAL(HexStr(ParseHex_expected,
ParseHex_expected + sizeof(ParseHex_expected)),
"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0"
"ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d"
"578a4c702b6bf11d5f");
BOOST_CHECK_EQUAL(HexStr(ParseHex_expected, ParseHex_expected + 5, true),
"04 67 8a fd b0");
BOOST_CHECK_EQUAL(HexStr(ParseHex_expected + sizeof(ParseHex_expected),
ParseHex_expected + sizeof(ParseHex_expected)),
"");
BOOST_CHECK_EQUAL(HexStr(ParseHex_expected + sizeof(ParseHex_expected),
ParseHex_expected + sizeof(ParseHex_expected),
true),
"");
BOOST_CHECK_EQUAL(HexStr(ParseHex_expected, ParseHex_expected), "");
BOOST_CHECK_EQUAL(HexStr(ParseHex_expected, ParseHex_expected, true), "");
std::vector ParseHex_vec(ParseHex_expected, ParseHex_expected + 5);
BOOST_CHECK_EQUAL(HexStr(ParseHex_vec, true), "04 67 8a fd b0");
BOOST_CHECK_EQUAL(HexStr(ParseHex_vec.rbegin(), ParseHex_vec.rend()),
"b0fd8a6704");
BOOST_CHECK_EQUAL(HexStr(ParseHex_vec.rbegin(), ParseHex_vec.rend(), true),
"b0 fd 8a 67 04");
BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator(ParseHex_expected),
std::reverse_iterator(ParseHex_expected)),
"");
BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator(ParseHex_expected),
std::reverse_iterator(ParseHex_expected), true),
"");
BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator(ParseHex_expected + 1),
std::reverse_iterator(ParseHex_expected)),
"04");
BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator(ParseHex_expected + 1),
std::reverse_iterator(ParseHex_expected), true),
"04");
BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator(ParseHex_expected + 5),
std::reverse_iterator(ParseHex_expected)),
"b0fd8a6704");
BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator(ParseHex_expected + 5),
std::reverse_iterator(ParseHex_expected), true),
"b0 fd 8a 67 04");
BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator(ParseHex_expected + 65),
std::reverse_iterator(ParseHex_expected)),
"5f1df16b2b704c8a578d0bbaf74d385cde12c11ee50455f3c438ef4c3fbcf649b6de61"
"1feae06279a60939e028a8d65c10b73071a6f16719274855feb0fd8a6704");
}
BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat) {
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0),
"1970-01-01 00:00:00");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0x7FFFFFFF),
"2038-01-19 03:14:07");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 1317425777),
"2011-09-30 23:36:17");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", 1317425777),
"2011-09-30T23:36:17Z");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%H:%M:%SZ", 1317425777), "23:36:17Z");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M", 1317425777),
"2011-09-30 23:36");
BOOST_CHECK_EQUAL(
DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", 1317425777),
"Fri, 30 Sep 2011 23:36:17 +0000");
}
BOOST_AUTO_TEST_CASE(util_FormatISO8601DateTime) {
BOOST_CHECK_EQUAL(FormatISO8601DateTime(1317425777),
"2011-09-30T23:36:17Z");
}
BOOST_AUTO_TEST_CASE(util_FormatISO8601Date) {
BOOST_CHECK_EQUAL(FormatISO8601Date(1317425777), "2011-09-30");
}
BOOST_AUTO_TEST_CASE(util_FormatISO8601Time) {
BOOST_CHECK_EQUAL(FormatISO8601Time(1317425777), "23:36:17Z");
}
struct TestArgsManager : public ArgsManager {
- std::map &GetMapArgs() { return mapArgs; }
- std::map> &GetMapMultiArgs() {
- return mapMultiArgs;
+ std::map> &GetOverrideArgs() {
+ return m_override_args;
+ }
+ std::map> &GetConfigArgs() {
+ return m_config_args;
}
const std::unordered_set &GetNegatedArgs() {
return m_negated_args;
}
void ReadConfigString(const std::string str_config) {
- std::istringstream stream(str_config);
- ReadConfigStream(stream);
+ std::istringstream streamConfig(str_config);
+ {
+ LOCK(cs_args);
+ m_config_args.clear();
+ }
+ ReadConfigStream(streamConfig);
}
};
BOOST_AUTO_TEST_CASE(util_ParseParameters) {
TestArgsManager testArgs;
const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument",
"-ccc=multiple", "f", "-d=e"};
testArgs.ParseParameters(0, (char **)argv_test);
- BOOST_CHECK(testArgs.GetMapArgs().empty() &&
- testArgs.GetMapMultiArgs().empty());
+ BOOST_CHECK(testArgs.GetOverrideArgs().empty() &&
+ testArgs.GetConfigArgs().empty());
testArgs.ParseParameters(1, (char **)argv_test);
- BOOST_CHECK(testArgs.GetMapArgs().empty() &&
- testArgs.GetMapMultiArgs().empty());
+ BOOST_CHECK(testArgs.GetOverrideArgs().empty() &&
+ testArgs.GetConfigArgs().empty());
testArgs.ParseParameters(5, (char **)argv_test);
// expectation: -ignored is ignored (program name argument),
// -a, -b and -ccc end up in map, -d ignored because it is after
// a non-option argument (non-GNU option parsing)
- BOOST_CHECK(testArgs.GetMapArgs().size() == 3 &&
- testArgs.GetMapMultiArgs().size() == 3);
+ BOOST_CHECK(testArgs.GetOverrideArgs().size() == 3 &&
+ testArgs.GetConfigArgs().empty());
BOOST_CHECK(testArgs.IsArgSet("-a") && testArgs.IsArgSet("-b") &&
testArgs.IsArgSet("-ccc") && !testArgs.IsArgSet("f") &&
!testArgs.IsArgSet("-d"));
- BOOST_CHECK(testArgs.GetMapMultiArgs().count("-a") &&
- testArgs.GetMapMultiArgs().count("-b") &&
- testArgs.GetMapMultiArgs().count("-ccc") &&
- !testArgs.GetMapMultiArgs().count("f") &&
- !testArgs.GetMapMultiArgs().count("-d"));
-
- BOOST_CHECK(testArgs.GetMapArgs()["-a"] == "" &&
- testArgs.GetMapArgs()["-ccc"] == "multiple");
+ BOOST_CHECK(testArgs.GetOverrideArgs().count("-a") &&
+ testArgs.GetOverrideArgs().count("-b") &&
+ testArgs.GetOverrideArgs().count("-ccc") &&
+ !testArgs.GetOverrideArgs().count("f") &&
+ !testArgs.GetOverrideArgs().count("-d"));
+
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-a"].size() == 1);
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-a"].front() == "");
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-ccc"].size() == 2);
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-ccc"].front() == "argument");
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-ccc"].back() == "multiple");
BOOST_CHECK(testArgs.GetArgs("-ccc").size() == 2);
}
BOOST_AUTO_TEST_CASE(util_GetBoolArg) {
TestArgsManager testArgs;
const char *argv_test[] = {"ignored", "-a", "-nob", "-c=0",
"-d=1", "-e=false", "-f=true"};
testArgs.ParseParameters(7, (char **)argv_test);
// Each letter should be set.
for (char opt : "abcdef") {
BOOST_CHECK(testArgs.IsArgSet({'-', opt}) || !opt);
}
// Nothing else should be in the map
- BOOST_CHECK(testArgs.GetMapArgs().size() == 6 &&
- testArgs.GetMapMultiArgs().size() == 6);
+ BOOST_CHECK(testArgs.GetOverrideArgs().size() == 6 &&
+ testArgs.GetConfigArgs().empty());
// The -no prefix should get stripped on the way in.
BOOST_CHECK(!testArgs.IsArgSet("-nob"));
// The -b option is flagged as negated, and nothing else is
BOOST_CHECK(testArgs.IsArgNegated("-b"));
BOOST_CHECK(testArgs.GetNegatedArgs().size() == 1);
BOOST_CHECK(!testArgs.IsArgNegated("-a"));
// Check expected values.
BOOST_CHECK(testArgs.GetBoolArg("-a", false) == true);
BOOST_CHECK(testArgs.GetBoolArg("-b", true) == false);
BOOST_CHECK(testArgs.GetBoolArg("-c", true) == false);
BOOST_CHECK(testArgs.GetBoolArg("-d", false) == true);
BOOST_CHECK(testArgs.GetBoolArg("-e", true) == false);
BOOST_CHECK(testArgs.GetBoolArg("-f", true) == false);
}
BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases) {
// Test some awful edge cases that hopefully no user will ever exercise.
TestArgsManager testArgs;
// Params test
const char *argv_test[] = {"ignored", "-nofoo", "-foo", "-nobar=0"};
testArgs.ParseParameters(4, (char **)argv_test);
// This was passed twice, second one overrides the negative setting.
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "");
// A double negative is a positive.
BOOST_CHECK(testArgs.IsArgNegated("-bar"));
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
// Config test
const char *conf_test = "nofoo=1\nfoo=1\nnobar=0\n";
testArgs.ParseParameters(1, (char **)argv_test);
testArgs.ReadConfigString(conf_test);
// This was passed twice, second one overrides the negative setting,
// but not the value.
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "0");
// A double negative is a positive.
BOOST_CHECK(testArgs.IsArgNegated("-bar"));
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
// Combined test
const char *combo_test_args[] = {"ignored", "-nofoo", "-bar"};
const char *combo_test_conf = "foo=1\nnobar=1\n";
testArgs.ParseParameters(3, (char **)combo_test_args);
testArgs.ReadConfigString(combo_test_conf);
// Command line overrides, but doesn't erase old setting
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "0");
BOOST_CHECK(testArgs.GetArgs("-foo").size() == 2 &&
testArgs.GetArgs("-foo").front() == "0" &&
testArgs.GetArgs("-foo").back() == "1");
// Command line overrides, but doesn't erase old setting
BOOST_CHECK(testArgs.IsArgNegated("-bar"));
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "");
BOOST_CHECK(testArgs.GetArgs("-bar").size() == 2 &&
testArgs.GetArgs("-bar").front() == "" &&
testArgs.GetArgs("-bar").back() == "0");
}
BOOST_AUTO_TEST_CASE(util_ReadConfigStream) {
const char *str_config = "a=\n"
"b=1\n"
"ccc=argument\n"
"ccc=multiple\n"
"d=e\n"
"nofff=1\n"
"noggg=0\n"
"h=1\n"
"noh=1\n"
"noi=1\n"
"i=1\n";
TestArgsManager test_args;
test_args.ReadConfigString(str_config);
// expectation: a, b, ccc, d, fff, ggg, h, i end up in map
- BOOST_CHECK(test_args.GetMapArgs().size() == 8);
- BOOST_CHECK(test_args.GetMapMultiArgs().size() == 8);
+ BOOST_CHECK(test_args.GetOverrideArgs().empty());
+ BOOST_CHECK(test_args.GetConfigArgs().size() == 8);
- BOOST_CHECK(test_args.GetMapArgs().count("-a") &&
- test_args.GetMapArgs().count("-b") &&
- test_args.GetMapArgs().count("-ccc") &&
- test_args.GetMapArgs().count("-d") &&
- test_args.GetMapArgs().count("-fff") &&
- test_args.GetMapArgs().count("-ggg") &&
- test_args.GetMapArgs().count("-h") &&
- test_args.GetMapArgs().count("-i"));
+ BOOST_CHECK(test_args.GetConfigArgs().count("-a") &&
+ test_args.GetConfigArgs().count("-b") &&
+ test_args.GetConfigArgs().count("-ccc") &&
+ test_args.GetConfigArgs().count("-d") &&
+ test_args.GetConfigArgs().count("-fff") &&
+ test_args.GetConfigArgs().count("-ggg") &&
+ test_args.GetConfigArgs().count("-h") &&
+ test_args.GetConfigArgs().count("-i"));
BOOST_CHECK(test_args.IsArgSet("-a") && test_args.IsArgSet("-b") &&
test_args.IsArgSet("-ccc") && test_args.IsArgSet("-d") &&
test_args.IsArgSet("-fff") && test_args.IsArgSet("-ggg") &&
test_args.IsArgSet("-h") && test_args.IsArgSet("-i") &&
!test_args.IsArgSet("-zzz"));
BOOST_CHECK(test_args.GetArg("-a", "xxx") == "" &&
test_args.GetArg("-b", "xxx") == "1" &&
test_args.GetArg("-ccc", "xxx") == "argument" &&
test_args.GetArg("-d", "xxx") == "e" &&
test_args.GetArg("-fff", "xxx") == "0" &&
test_args.GetArg("-ggg", "xxx") == "1" &&
// 1st value takes precedence
test_args.GetArg("-h", "xxx") == "1" &&
// 1st value takes precedence
test_args.GetArg("-i", "xxx") == "0" &&
test_args.GetArg("-zzz", "xxx") == "xxx");
for (bool def : {false, true}) {
BOOST_CHECK(test_args.GetBoolArg("-a", def) &&
test_args.GetBoolArg("-b", def) &&
!test_args.GetBoolArg("-ccc", def) &&
!test_args.GetBoolArg("-d", def) &&
!test_args.GetBoolArg("-fff", def) &&
test_args.GetBoolArg("-ggg", def) &&
test_args.GetBoolArg("-h", def) &&
!test_args.GetBoolArg("-i", def) &&
test_args.GetBoolArg("-zzz", def) == def);
}
BOOST_CHECK(test_args.GetArgs("-a").size() == 1 &&
test_args.GetArgs("-a").front() == "");
BOOST_CHECK(test_args.GetArgs("-b").size() == 1 &&
test_args.GetArgs("-b").front() == "1");
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2 &&
test_args.GetArgs("-ccc").front() == "argument" &&
test_args.GetArgs("-ccc").back() == "multiple");
BOOST_CHECK(test_args.GetArgs("-fff").size() == 1 &&
test_args.GetArgs("-fff").front() == "0");
BOOST_CHECK(test_args.GetArgs("-nofff").size() == 0);
BOOST_CHECK(test_args.GetArgs("-ggg").size() == 1 &&
test_args.GetArgs("-ggg").front() == "1");
BOOST_CHECK(test_args.GetArgs("-noggg").size() == 0);
BOOST_CHECK(test_args.GetArgs("-h").size() == 2 &&
test_args.GetArgs("-h").front() == "1" &&
test_args.GetArgs("-h").back() == "0");
BOOST_CHECK(test_args.GetArgs("-noh").size() == 0);
BOOST_CHECK(test_args.GetArgs("-i").size() == 2 &&
test_args.GetArgs("-i").front() == "0" &&
test_args.GetArgs("-i").back() == "1");
BOOST_CHECK(test_args.GetArgs("-noi").size() == 0);
BOOST_CHECK(test_args.GetArgs("-zzz").size() == 0);
BOOST_CHECK(!test_args.IsArgNegated("-a"));
BOOST_CHECK(!test_args.IsArgNegated("-b"));
BOOST_CHECK(!test_args.IsArgNegated("-ccc"));
BOOST_CHECK(!test_args.IsArgNegated("-d"));
BOOST_CHECK(test_args.IsArgNegated("-fff"));
// IsArgNegated==true when noggg=0
BOOST_CHECK(test_args.IsArgNegated("-ggg"));
// last setting takes precedence
BOOST_CHECK(test_args.IsArgNegated("-h"));
// last setting takes precedence
BOOST_CHECK(!test_args.IsArgNegated("-i"));
BOOST_CHECK(!test_args.IsArgNegated("-zzz"));
}
BOOST_AUTO_TEST_CASE(util_GetArg) {
TestArgsManager testArgs;
- testArgs.GetMapArgs().clear();
- testArgs.GetMapArgs()["strtest1"] = "string...";
+ testArgs.GetOverrideArgs().clear();
+ testArgs.GetOverrideArgs()["strtest1"] = {"string..."};
// strtest2 undefined on purpose
- testArgs.GetMapArgs()["inttest1"] = "12345";
- testArgs.GetMapArgs()["inttest2"] = "81985529216486895";
+ testArgs.GetOverrideArgs()["inttest1"] = {"12345"};
+ testArgs.GetOverrideArgs()["inttest2"] = {"81985529216486895"};
// inttest3 undefined on purpose
- testArgs.GetMapArgs()["booltest1"] = "";
+ testArgs.GetOverrideArgs()["booltest1"] = {""};
// booltest2 undefined on purpose
- testArgs.GetMapArgs()["booltest3"] = "0";
- testArgs.GetMapArgs()["booltest4"] = "1";
+ testArgs.GetOverrideArgs()["booltest3"] = {"0"};
+ testArgs.GetOverrideArgs()["booltest4"] = {"1"};
+
+ // priorities
+ testArgs.GetOverrideArgs()["pritest1"] = {"a", "b"};
+ testArgs.GetConfigArgs()["pritest2"] = {"a", "b"};
+ testArgs.GetOverrideArgs()["pritest3"] = {"a"};
+ testArgs.GetConfigArgs()["pritest3"] = {"b"};
+ testArgs.GetOverrideArgs()["pritest4"] = {"a", "b"};
+ testArgs.GetConfigArgs()["pritest4"] = {"c", "d"};
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "string...");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
BOOST_CHECK_EQUAL(testArgs.GetArg("inttest1", -1), 12345);
BOOST_CHECK_EQUAL(testArgs.GetArg("inttest2", -1), 81985529216486895LL);
BOOST_CHECK_EQUAL(testArgs.GetArg("inttest3", -1), -1);
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", false), true);
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest2", false), false);
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest3", false), false);
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest4", false), true);
+
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest1", "default"), "b");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest2", "default"), "a");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest3", "default"), "a");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest4", "default"), "b");
}
BOOST_AUTO_TEST_CASE(util_ClearArg) {
TestArgsManager testArgs;
// Clear single string arg
- testArgs.GetMapArgs()["strtest1"] = "string...";
+ testArgs.GetOverrideArgs()["strtest1"] = {"string..."};
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "string...");
testArgs.ClearArg("strtest1");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "default");
// Clear boolean arg
- testArgs.GetMapArgs()["booltest1"] = "1";
+ testArgs.GetOverrideArgs()["booltest1"] = {"1"};
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", false), true);
testArgs.ClearArg("booltest1");
BOOST_CHECK_EQUAL(testArgs.GetArg("booltest1", false), false);
- // Clear multi args only
- testArgs.GetMapMultiArgs()["strtest2"].push_back("string...");
- testArgs.GetMapMultiArgs()["strtest2"].push_back("...gnirts");
- BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
+ // Clear config args only
+ testArgs.GetConfigArgs()["strtest2"].push_back("string...");
+ testArgs.GetConfigArgs()["strtest2"].push_back("...gnirts");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").size(), 2);
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").front(), "string...");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").back(), "...gnirts");
testArgs.ClearArg("strtest2");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").size(), 0);
- // Clear both arg and multi args
- testArgs.GetMapArgs()["strtest3"] = "string...";
- testArgs.GetMapMultiArgs()["strtest3"].push_back("string...");
- testArgs.GetMapMultiArgs()["strtest3"].push_back("...gnirts");
- BOOST_CHECK_EQUAL(testArgs.GetArg("strtest3", "default"), "string...");
- BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest3").size(), 2);
- BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest3").front(), "string...");
+ // Clear both cli args and config args
+ testArgs.GetOverrideArgs()["strtest3"].push_back("cli string...");
+ testArgs.GetOverrideArgs()["strtest3"].push_back("...gnirts ilc");
+ testArgs.GetConfigArgs()["strtest3"].push_back("string...");
+ testArgs.GetConfigArgs()["strtest3"].push_back("...gnirts");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("strtest3", "default"), "...gnirts ilc");
+ BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest3").size(), 4);
+ BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest3").front(), "cli string...");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest3").back(), "...gnirts");
testArgs.ClearArg("strtest3");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest3", "default"), "default");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest3").size(), 0);
}
BOOST_AUTO_TEST_CASE(util_SetArg) {
TestArgsManager testArgs;
// SoftSetArg
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "default");
BOOST_CHECK_EQUAL(testArgs.SoftSetArg("strtest1", "string..."), true);
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "string...");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest1").size(), 1);
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest1").front(), "string...");
BOOST_CHECK_EQUAL(testArgs.SoftSetArg("strtest1", "...gnirts"), false);
testArgs.ClearArg("strtest1");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "default");
BOOST_CHECK_EQUAL(testArgs.SoftSetArg("strtest1", "...gnirts"), true);
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "...gnirts");
// SoftSetBoolArg
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", false), false);
BOOST_CHECK_EQUAL(testArgs.SoftSetBoolArg("booltest1", true), true);
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", false), true);
BOOST_CHECK_EQUAL(testArgs.SoftSetBoolArg("booltest1", false), false);
testArgs.ClearArg("booltest1");
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", true), true);
BOOST_CHECK_EQUAL(testArgs.SoftSetBoolArg("booltest1", false), true);
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", true), false);
// ForceSetArg
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
testArgs.ForceSetArg("strtest2", "string...");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "string...");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").size(), 1);
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").front(), "string...");
testArgs.ForceSetArg("strtest2", "...gnirts");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "...gnirts");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").size(), 1);
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").front(), "...gnirts");
// ForceSetMultiArg
testArgs.ForceSetMultiArg("strtest2", "string...");
- BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "...gnirts");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "string...");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").size(), 2);
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").front(), "...gnirts");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").back(), "string...");
testArgs.ClearArg("strtest2");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").size(), 0);
testArgs.ForceSetMultiArg("strtest2", "string...");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "string...");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").size(), 1);
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").front(), "string...");
testArgs.ForceSetMultiArg("strtest2", "one more thing...");
- BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "string...");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"),
+ "one more thing...");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").size(), 2);
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").front(), "string...");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").back(), "one more thing...");
// If there are multi args, ForceSetArg should erase them
testArgs.ForceSetArg("strtest2", "...gnirts");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "...gnirts");
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").size(), 1);
BOOST_CHECK_EQUAL(testArgs.GetArgs("strtest2").front(), "...gnirts");
}
BOOST_AUTO_TEST_CASE(util_GetChainName) {
TestArgsManager test_args;
const char *argv_testnet[] = {"cmd", "-testnet"};
const char *argv_regtest[] = {"cmd", "-regtest"};
const char *argv_test_no_reg[] = {"cmd", "-testnet", "-noregtest"};
const char *argv_both[] = {"cmd", "-testnet", "-regtest"};
// equivalent to "-testnet"
const char *testnetconf = "testnet=1\nregtest=0\n";
test_args.ParseParameters(0, (char **)argv_testnet);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "main");
test_args.ParseParameters(2, (char **)argv_testnet);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
test_args.ParseParameters(2, (char **)argv_regtest);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "regtest");
test_args.ParseParameters(3, (char **)argv_test_no_reg);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
test_args.ParseParameters(3, (char **)argv_both);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
test_args.ParseParameters(0, (char **)argv_testnet);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
test_args.ParseParameters(2, (char **)argv_testnet);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
test_args.ParseParameters(2, (char **)argv_regtest);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
test_args.ParseParameters(3, (char **)argv_test_no_reg);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
test_args.ParseParameters(3, (char **)argv_both);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
}
BOOST_AUTO_TEST_CASE(util_FormatMoney) {
BOOST_CHECK_EQUAL(FormatMoney(Amount::zero()), "0.00");
BOOST_CHECK_EQUAL(FormatMoney(123456789 * (COIN / 10000)), "12345.6789");
BOOST_CHECK_EQUAL(FormatMoney(-1 * COIN), "-1.00");
BOOST_CHECK_EQUAL(FormatMoney(100000000 * COIN), "100000000.00");
BOOST_CHECK_EQUAL(FormatMoney(10000000 * COIN), "10000000.00");
BOOST_CHECK_EQUAL(FormatMoney(1000000 * COIN), "1000000.00");
BOOST_CHECK_EQUAL(FormatMoney(100000 * COIN), "100000.00");
BOOST_CHECK_EQUAL(FormatMoney(10000 * COIN), "10000.00");
BOOST_CHECK_EQUAL(FormatMoney(1000 * COIN), "1000.00");
BOOST_CHECK_EQUAL(FormatMoney(100 * COIN), "100.00");
BOOST_CHECK_EQUAL(FormatMoney(10 * COIN), "10.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN), "1.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN / 10), "0.10");
BOOST_CHECK_EQUAL(FormatMoney(COIN / 100), "0.01");
BOOST_CHECK_EQUAL(FormatMoney(COIN / 1000), "0.001");
BOOST_CHECK_EQUAL(FormatMoney(COIN / 10000), "0.0001");
BOOST_CHECK_EQUAL(FormatMoney(COIN / 100000), "0.00001");
BOOST_CHECK_EQUAL(FormatMoney(COIN / 1000000), "0.000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN / 10000000), "0.0000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN / 100000000), "0.00000001");
}
BOOST_AUTO_TEST_CASE(util_ParseMoney) {
Amount ret = Amount::zero();
BOOST_CHECK(ParseMoney("0.0", ret));
BOOST_CHECK_EQUAL(ret, Amount::zero());
BOOST_CHECK(ParseMoney("12345.6789", ret));
BOOST_CHECK_EQUAL(ret, 123456789 * (COIN / 10000));
BOOST_CHECK(ParseMoney("100000000.00", ret));
BOOST_CHECK_EQUAL(ret, 100000000 * COIN);
BOOST_CHECK(ParseMoney("10000000.00", ret));
BOOST_CHECK_EQUAL(ret, 10000000 * COIN);
BOOST_CHECK(ParseMoney("1000000.00", ret));
BOOST_CHECK_EQUAL(ret, 1000000 * COIN);
BOOST_CHECK(ParseMoney("100000.00", ret));
BOOST_CHECK_EQUAL(ret, 100000 * COIN);
BOOST_CHECK(ParseMoney("10000.00", ret));
BOOST_CHECK_EQUAL(ret, 10000 * COIN);
BOOST_CHECK(ParseMoney("1000.00", ret));
BOOST_CHECK_EQUAL(ret, 1000 * COIN);
BOOST_CHECK(ParseMoney("100.00", ret));
BOOST_CHECK_EQUAL(ret, 100 * COIN);
BOOST_CHECK(ParseMoney("10.00", ret));
BOOST_CHECK_EQUAL(ret, 10 * COIN);
BOOST_CHECK(ParseMoney("1.00", ret));
BOOST_CHECK_EQUAL(ret, COIN);
BOOST_CHECK(ParseMoney("1", ret));
BOOST_CHECK_EQUAL(ret, COIN);
BOOST_CHECK(ParseMoney("0.1", ret));
BOOST_CHECK_EQUAL(ret, COIN / 10);
BOOST_CHECK(ParseMoney("0.01", ret));
BOOST_CHECK_EQUAL(ret, COIN / 100);
BOOST_CHECK(ParseMoney("0.001", ret));
BOOST_CHECK_EQUAL(ret, COIN / 1000);
BOOST_CHECK(ParseMoney("0.0001", ret));
BOOST_CHECK_EQUAL(ret, COIN / 10000);
BOOST_CHECK(ParseMoney("0.00001", ret));
BOOST_CHECK_EQUAL(ret, COIN / 100000);
BOOST_CHECK(ParseMoney("0.000001", ret));
BOOST_CHECK_EQUAL(ret, COIN / 1000000);
BOOST_CHECK(ParseMoney("0.0000001", ret));
BOOST_CHECK_EQUAL(ret, COIN / 10000000);
BOOST_CHECK(ParseMoney("0.00000001", ret));
BOOST_CHECK_EQUAL(ret, COIN / 100000000);
// Attempted 63 bit overflow should fail
BOOST_CHECK(!ParseMoney("92233720368.54775808", ret));
// Parsing negative amounts must fail
BOOST_CHECK(!ParseMoney("-1", ret));
}
BOOST_AUTO_TEST_CASE(util_IsHex) {
BOOST_CHECK(IsHex("00"));
BOOST_CHECK(IsHex("00112233445566778899aabbccddeeffAABBCCDDEEFF"));
BOOST_CHECK(IsHex("ff"));
BOOST_CHECK(IsHex("FF"));
BOOST_CHECK(!IsHex(""));
BOOST_CHECK(!IsHex("0"));
BOOST_CHECK(!IsHex("a"));
BOOST_CHECK(!IsHex("eleven"));
BOOST_CHECK(!IsHex("00xx00"));
BOOST_CHECK(!IsHex("0x0000"));
}
BOOST_AUTO_TEST_CASE(util_IsHexNumber) {
BOOST_CHECK(IsHexNumber("0x0"));
BOOST_CHECK(IsHexNumber("0"));
BOOST_CHECK(IsHexNumber("0x10"));
BOOST_CHECK(IsHexNumber("10"));
BOOST_CHECK(IsHexNumber("0xff"));
BOOST_CHECK(IsHexNumber("ff"));
BOOST_CHECK(IsHexNumber("0xFfa"));
BOOST_CHECK(IsHexNumber("Ffa"));
BOOST_CHECK(IsHexNumber("0x00112233445566778899aabbccddeeffAABBCCDDEEFF"));
BOOST_CHECK(IsHexNumber("00112233445566778899aabbccddeeffAABBCCDDEEFF"));
BOOST_CHECK(!IsHexNumber("")); // empty string not allowed
BOOST_CHECK(!IsHexNumber("0x")); // empty string after prefix not allowed
BOOST_CHECK(!IsHexNumber("0x0 ")); // no spaces at end,
BOOST_CHECK(!IsHexNumber(" 0x0")); // or beginning,
BOOST_CHECK(!IsHexNumber("0x 0")); // or middle,
BOOST_CHECK(!IsHexNumber(" ")); // etc.
BOOST_CHECK(!IsHexNumber("0x0ga")); // invalid character
BOOST_CHECK(!IsHexNumber("x0")); // broken prefix
BOOST_CHECK(!IsHexNumber("0x0x00")); // two prefixes not allowed
}
BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) {
SeedInsecureRand(true);
for (int mod = 2; mod < 11; mod++) {
int mask = 1;
// Really rough binomal confidence approximation.
int err =
30 * 10000. / mod * sqrt((1. / mod * (1 - 1. / mod)) / 10000.);
// mask is 2^ceil(log2(mod))-1
while (mask < mod - 1)
mask = (mask << 1) + 1;
int count = 0;
// How often does it get a zero from the uniform range [0,mod)?
for (int i = 0; i < 10000; i++) {
uint32_t rval;
do {
rval = insecure_rand() & mask;
} while (rval >= (uint32_t)mod);
count += rval == 0;
}
BOOST_CHECK(count <= 10000 / mod + err);
BOOST_CHECK(count >= 10000 / mod - err);
}
}
BOOST_AUTO_TEST_CASE(util_TimingResistantEqual) {
BOOST_CHECK(TimingResistantEqual(std::string(""), std::string("")));
BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("")));
BOOST_CHECK(!TimingResistantEqual(std::string(""), std::string("abc")));
BOOST_CHECK(!TimingResistantEqual(std::string("a"), std::string("aa")));
BOOST_CHECK(!TimingResistantEqual(std::string("aa"), std::string("a")));
BOOST_CHECK(TimingResistantEqual(std::string("abc"), std::string("abc")));
BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("aba")));
}
/* Test strprintf formatting directives.
* Put a string before and after to ensure sanity of element sizes on stack. */
#define B "check_prefix"
#define E "check_postfix"
BOOST_AUTO_TEST_CASE(strprintf_numbers) {
int64_t s64t = -9223372036854775807LL; /* signed 64 bit test value */
uint64_t u64t = 18446744073709551615ULL; /* unsigned 64 bit test value */
BOOST_CHECK(strprintf("%s %d %s", B, s64t, E) == B
" -9223372036854775807 " E);
BOOST_CHECK(strprintf("%s %u %s", B, u64t, E) == B
" 18446744073709551615 " E);
BOOST_CHECK(strprintf("%s %x %s", B, u64t, E) == B " ffffffffffffffff " E);
size_t st = 12345678; /* unsigned size_t test value */
ssize_t sst = -12345678; /* signed size_t test value */
BOOST_CHECK(strprintf("%s %d %s", B, sst, E) == B " -12345678 " E);
BOOST_CHECK(strprintf("%s %u %s", B, st, E) == B " 12345678 " E);
BOOST_CHECK(strprintf("%s %x %s", B, st, E) == B " bc614e " E);
ptrdiff_t pt = 87654321; /* positive ptrdiff_t test value */
ptrdiff_t spt = -87654321; /* negative ptrdiff_t test value */
BOOST_CHECK(strprintf("%s %d %s", B, spt, E) == B " -87654321 " E);
BOOST_CHECK(strprintf("%s %u %s", B, pt, E) == B " 87654321 " E);
BOOST_CHECK(strprintf("%s %x %s", B, pt, E) == B " 5397fb1 " E);
}
#undef B
#undef E
/* Check for mingw/wine issue #3494
* Remove this test before time.ctime(0xffffffff) == 'Sun Feb 7 07:28:15 2106'
*/
BOOST_AUTO_TEST_CASE(gettime) {
BOOST_CHECK((GetTime() & ~0xFFFFFFFFLL) == 0);
}
BOOST_AUTO_TEST_CASE(test_ParseInt32) {
int32_t n;
// Valid values
BOOST_CHECK(ParseInt32("1234", nullptr));
BOOST_CHECK(ParseInt32("0", &n) && n == 0);
BOOST_CHECK(ParseInt32("1234", &n) && n == 1234);
BOOST_CHECK(ParseInt32("01234", &n) && n == 1234); // no octal
BOOST_CHECK(ParseInt32("2147483647", &n) && n == 2147483647);
BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648);
BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234);
// Invalid values
BOOST_CHECK(!ParseInt32("", &n));
BOOST_CHECK(!ParseInt32(" 1", &n)); // no padding inside
BOOST_CHECK(!ParseInt32("1 ", &n));
BOOST_CHECK(!ParseInt32("1a", &n));
BOOST_CHECK(!ParseInt32("aap", &n));
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
const char test_bytes[] = {'1', 0, '1'};
std::string teststr(test_bytes, sizeof(test_bytes));
BOOST_CHECK(!ParseInt32(teststr, &n)); // no embedded NULs
// Overflow and underflow
BOOST_CHECK(!ParseInt32("-2147483649", nullptr));
BOOST_CHECK(!ParseInt32("2147483648", nullptr));
BOOST_CHECK(!ParseInt32("-32482348723847471234", nullptr));
BOOST_CHECK(!ParseInt32("32482348723847471234", nullptr));
}
BOOST_AUTO_TEST_CASE(test_ParseInt64) {
int64_t n;
// Valid values
BOOST_CHECK(ParseInt64("1234", nullptr));
BOOST_CHECK(ParseInt64("0", &n) && n == 0LL);
BOOST_CHECK(ParseInt64("1234", &n) && n == 1234LL);
BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal
BOOST_CHECK(ParseInt64("2147483647", &n) && n == 2147483647LL);
BOOST_CHECK(ParseInt64("-2147483648", &n) && n == -2147483648LL);
BOOST_CHECK(ParseInt64("9223372036854775807", &n) &&
n == (int64_t)9223372036854775807);
BOOST_CHECK(ParseInt64("-9223372036854775808", &n) &&
n == (int64_t)-9223372036854775807 - 1);
BOOST_CHECK(ParseInt64("-1234", &n) && n == -1234LL);
// Invalid values
BOOST_CHECK(!ParseInt64("", &n));
BOOST_CHECK(!ParseInt64(" 1", &n)); // no padding inside
BOOST_CHECK(!ParseInt64("1 ", &n));
BOOST_CHECK(!ParseInt64("1a", &n));
BOOST_CHECK(!ParseInt64("aap", &n));
BOOST_CHECK(!ParseInt64("0x1", &n)); // no hex
const char test_bytes[] = {'1', 0, '1'};
std::string teststr(test_bytes, sizeof(test_bytes));
BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs
// Overflow and underflow
BOOST_CHECK(!ParseInt64("-9223372036854775809", nullptr));
BOOST_CHECK(!ParseInt64("9223372036854775808", nullptr));
BOOST_CHECK(!ParseInt64("-32482348723847471234", nullptr));
BOOST_CHECK(!ParseInt64("32482348723847471234", nullptr));
}
BOOST_AUTO_TEST_CASE(test_ParseUInt32) {
uint32_t n;
// Valid values
BOOST_CHECK(ParseUInt32("1234", nullptr));
BOOST_CHECK(ParseUInt32("0", &n) && n == 0);
BOOST_CHECK(ParseUInt32("1234", &n) && n == 1234);
BOOST_CHECK(ParseUInt32("01234", &n) && n == 1234); // no octal
BOOST_CHECK(ParseUInt32("2147483647", &n) && n == 2147483647);
BOOST_CHECK(ParseUInt32("2147483648", &n) && n == (uint32_t)2147483648);
BOOST_CHECK(ParseUInt32("4294967295", &n) && n == (uint32_t)4294967295);
// Invalid values
BOOST_CHECK(!ParseUInt32("", &n));
BOOST_CHECK(!ParseUInt32(" 1", &n)); // no padding inside
BOOST_CHECK(!ParseUInt32(" -1", &n));
BOOST_CHECK(!ParseUInt32("1 ", &n));
BOOST_CHECK(!ParseUInt32("1a", &n));
BOOST_CHECK(!ParseUInt32("aap", &n));
BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex
BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex
const char test_bytes[] = {'1', 0, '1'};
std::string teststr(test_bytes, sizeof(test_bytes));
BOOST_CHECK(!ParseUInt32(teststr, &n)); // no embedded NULs
// Overflow and underflow
BOOST_CHECK(!ParseUInt32("-2147483648", &n));
BOOST_CHECK(!ParseUInt32("4294967296", &n));
BOOST_CHECK(!ParseUInt32("-1234", &n));
BOOST_CHECK(!ParseUInt32("-32482348723847471234", nullptr));
BOOST_CHECK(!ParseUInt32("32482348723847471234", nullptr));
}
BOOST_AUTO_TEST_CASE(test_ParseUInt64) {
uint64_t n;
// Valid values
BOOST_CHECK(ParseUInt64("1234", nullptr));
BOOST_CHECK(ParseUInt64("0", &n) && n == 0LL);
BOOST_CHECK(ParseUInt64("1234", &n) && n == 1234LL);
BOOST_CHECK(ParseUInt64("01234", &n) && n == 1234LL); // no octal
BOOST_CHECK(ParseUInt64("2147483647", &n) && n == 2147483647LL);
BOOST_CHECK(ParseUInt64("9223372036854775807", &n) &&
n == 9223372036854775807ULL);
BOOST_CHECK(ParseUInt64("9223372036854775808", &n) &&
n == 9223372036854775808ULL);
BOOST_CHECK(ParseUInt64("18446744073709551615", &n) &&
n == 18446744073709551615ULL);
// Invalid values
BOOST_CHECK(!ParseUInt64("", &n));
BOOST_CHECK(!ParseUInt64(" 1", &n)); // no padding inside
BOOST_CHECK(!ParseUInt64(" -1", &n));
BOOST_CHECK(!ParseUInt64("1 ", &n));
BOOST_CHECK(!ParseUInt64("1a", &n));
BOOST_CHECK(!ParseUInt64("aap", &n));
BOOST_CHECK(!ParseUInt64("0x1", &n)); // no hex
const char test_bytes[] = {'1', 0, '1'};
std::string teststr(test_bytes, sizeof(test_bytes));
BOOST_CHECK(!ParseUInt64(teststr, &n)); // no embedded NULs
// Overflow and underflow
BOOST_CHECK(!ParseUInt64("-9223372036854775809", nullptr));
BOOST_CHECK(!ParseUInt64("18446744073709551616", nullptr));
BOOST_CHECK(!ParseUInt64("-32482348723847471234", nullptr));
BOOST_CHECK(!ParseUInt64("-2147483648", &n));
BOOST_CHECK(!ParseUInt64("-9223372036854775808", &n));
BOOST_CHECK(!ParseUInt64("-1234", &n));
}
BOOST_AUTO_TEST_CASE(test_ParseDouble) {
double n;
// Valid values
BOOST_CHECK(ParseDouble("1234", nullptr));
BOOST_CHECK(ParseDouble("0", &n) && n == 0.0);
BOOST_CHECK(ParseDouble("1234", &n) && n == 1234.0);
BOOST_CHECK(ParseDouble("01234", &n) && n == 1234.0); // no octal
BOOST_CHECK(ParseDouble("2147483647", &n) && n == 2147483647.0);
BOOST_CHECK(ParseDouble("-2147483648", &n) && n == -2147483648.0);
BOOST_CHECK(ParseDouble("-1234", &n) && n == -1234.0);
BOOST_CHECK(ParseDouble("1e6", &n) && n == 1e6);
BOOST_CHECK(ParseDouble("-1e6", &n) && n == -1e6);
// Invalid values
BOOST_CHECK(!ParseDouble("", &n));
BOOST_CHECK(!ParseDouble(" 1", &n)); // no padding inside
BOOST_CHECK(!ParseDouble("1 ", &n));
BOOST_CHECK(!ParseDouble("1a", &n));
BOOST_CHECK(!ParseDouble("aap", &n));
BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex
const char test_bytes[] = {'1', 0, '1'};
std::string teststr(test_bytes, sizeof(test_bytes));
BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs
// Overflow and underflow
BOOST_CHECK(!ParseDouble("-1e10000", nullptr));
BOOST_CHECK(!ParseDouble("1e10000", nullptr));
}
BOOST_AUTO_TEST_CASE(test_FormatParagraph) {
BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");
BOOST_CHECK_EQUAL(FormatParagraph("test", 79, 0), "test");
BOOST_CHECK_EQUAL(FormatParagraph(" test", 79, 0), " test");
BOOST_CHECK_EQUAL(FormatParagraph("test test", 79, 0), "test test");
BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 0), "test\ntest");
BOOST_CHECK_EQUAL(FormatParagraph("testerde test", 4, 0), "testerde\ntest");
BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 4), "test\n test");
// Make sure we don't indent a fully-new line following a too-long line
// ending
BOOST_CHECK_EQUAL(FormatParagraph("test test\nabc", 4, 4),
"test\n test\nabc");
BOOST_CHECK_EQUAL(
FormatParagraph("This_is_a_very_long_test_string_without_any_spaces_so_"
"it_should_just_get_returned_as_is_despite_the_length "
"until it gets here",
79),
"This_is_a_very_long_test_string_without_any_spaces_so_it_should_just_"
"get_returned_as_is_despite_the_length\nuntil it gets here");
// Test wrap length is exact
BOOST_CHECK_EQUAL(
FormatParagraph("a b c d e f g h i j k l m n o p q r s t u v w x y z 1 "
"2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p",
79),
"a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 "
"a b c de\nf g h i j k l m n o p");
BOOST_CHECK_EQUAL(
FormatParagraph("x\na b c d e f g h i j k l m n o p q r s t u v w x y "
"z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p",
79),
"x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 "
"8 9 a b c de\nf g h i j k l m n o p");
// Indent should be included in length of lines
BOOST_CHECK_EQUAL(
FormatParagraph("x\na b c d e f g h i j k l m n o p q r s t u v w x y "
"z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p q "
"r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 a b c d e fg h "
"i j k",
79, 4),
"x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 "
"8 9 a b c de\n f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 "
"5 6 7 8 9 a b c d e fg\n h i j k");
BOOST_CHECK_EQUAL(
FormatParagraph("This is a very long test string. This is a second "
"sentence in the very long test string.",
79),
"This is a very long test string. This is a second sentence in the "
"very long\ntest string.");
BOOST_CHECK_EQUAL(
FormatParagraph("This is a very long test string.\nThis is a second "
"sentence in the very long test string. This is a "
"third sentence in the very long test string.",
79),
"This is a very long test string.\nThis is a second sentence in the "
"very long test string. This is a third\nsentence in the very long "
"test string.");
BOOST_CHECK_EQUAL(
FormatParagraph("This is a very long test string.\n\nThis is a second "
"sentence in the very long test string. This is a "
"third sentence in the very long test string.",
79),
"This is a very long test string.\n\nThis is a second sentence in the "
"very long test string. This is a third\nsentence in the very long "
"test string.");
BOOST_CHECK_EQUAL(
FormatParagraph(
"Testing that normal newlines do not get indented.\nLike here.",
79),
"Testing that normal newlines do not get indented.\nLike here.");
}
BOOST_AUTO_TEST_CASE(test_FormatSubVersion) {
std::vector comments;
comments.push_back(std::string("comment1"));
std::vector comments2;
comments2.push_back(std::string("comment1"));
// Semicolon is discouraged but not forbidden by BIP-0014
comments2.push_back(SanitizeString(
std::string("Comment2; .,_?@-; !\"#$%&'()*+/<=>[]\\^`{|}~"),
SAFE_CHARS_UA_COMMENT));
BOOST_CHECK_EQUAL(
FormatSubVersion("Test", 99900, std::vector()),
std::string("/Test:0.9.99/"));
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),
std::string("/Test:0.9.99(comment1)/"));
BOOST_CHECK_EQUAL(
FormatSubVersion("Test", 99900, comments2),
std::string("/Test:0.9.99(comment1; Comment2; .,_?@-; )/"));
}
BOOST_AUTO_TEST_CASE(test_ParseFixedPoint) {
int64_t amount = 0;
BOOST_CHECK(ParseFixedPoint("0", 8, &amount));
BOOST_CHECK_EQUAL(amount, 0LL);
BOOST_CHECK(ParseFixedPoint("1", 8, &amount));
BOOST_CHECK_EQUAL(amount, 100000000LL);
BOOST_CHECK(ParseFixedPoint("0.0", 8, &amount));
BOOST_CHECK_EQUAL(amount, 0LL);
BOOST_CHECK(ParseFixedPoint("-0.1", 8, &amount));
BOOST_CHECK_EQUAL(amount, -10000000LL);
BOOST_CHECK(ParseFixedPoint("1.1", 8, &amount));
BOOST_CHECK_EQUAL(amount, 110000000LL);
BOOST_CHECK(ParseFixedPoint("1.10000000000000000", 8, &amount));
BOOST_CHECK_EQUAL(amount, 110000000LL);
BOOST_CHECK(ParseFixedPoint("1.1e1", 8, &amount));
BOOST_CHECK_EQUAL(amount, 1100000000LL);
BOOST_CHECK(ParseFixedPoint("1.1e-1", 8, &amount));
BOOST_CHECK_EQUAL(amount, 11000000LL);
BOOST_CHECK(ParseFixedPoint("1000", 8, &amount));
BOOST_CHECK_EQUAL(amount, 100000000000LL);
BOOST_CHECK(ParseFixedPoint("-1000", 8, &amount));
BOOST_CHECK_EQUAL(amount, -100000000000LL);
BOOST_CHECK(ParseFixedPoint("0.00000001", 8, &amount));
BOOST_CHECK_EQUAL(amount, 1LL);
BOOST_CHECK(ParseFixedPoint("0.0000000100000000", 8, &amount));
BOOST_CHECK_EQUAL(amount, 1LL);
BOOST_CHECK(ParseFixedPoint("-0.00000001", 8, &amount));
BOOST_CHECK_EQUAL(amount, -1LL);
BOOST_CHECK(ParseFixedPoint("1000000000.00000001", 8, &amount));
BOOST_CHECK_EQUAL(amount, 100000000000000001LL);
BOOST_CHECK(ParseFixedPoint("9999999999.99999999", 8, &amount));
BOOST_CHECK_EQUAL(amount, 999999999999999999LL);
BOOST_CHECK(ParseFixedPoint("-9999999999.99999999", 8, &amount));
BOOST_CHECK_EQUAL(amount, -999999999999999999LL);
BOOST_CHECK(!ParseFixedPoint("", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("a-1000", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-a1000", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-1000a", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-01000", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("00.1", 8, &amount));
BOOST_CHECK(!ParseFixedPoint(".1", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("--0.1", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("0.000000001", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-0.000000001", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("0.00000001000000001", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-10000000000.00000000", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("10000000000.00000000", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-10000000000.00000001", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("10000000000.00000001", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-10000000000.00000009", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("10000000000.00000009", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-99999999999.99999999", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("99999909999.09999999", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("92233720368.54775807", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("92233720368.54775808", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-92233720368.54775808", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-92233720368.54775809", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("1.1e", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("1.1e-", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount));
}
template
static void CheckConvertBits(const std::vector &in,
const std::vector &expected) {
std::vector outpad;
bool ret = ConvertBits(outpad, in.begin(), in.end());
BOOST_CHECK(ret);
BOOST_CHECK(outpad == expected);
const bool dopad = (in.size() * F) % T;
std::vector outnopad;
ret = ConvertBits(outnopad, in.begin(), in.end());
BOOST_CHECK(ret != dopad);
if (dopad) {
// We should have skipped the last digit.
outnopad.push_back(expected.back());
}
BOOST_CHECK(outnopad == expected);
// Check the other way around.
std::vector orignopad;
ret = ConvertBits(orignopad, expected.begin(), expected.end());
BOOST_CHECK(ret == !((expected.size() * T) % F));
BOOST_CHECK(orignopad == in);
// Check with padding. We may get an extra 0 in that case.
std::vector origpad;
ret = ConvertBits(origpad, expected.begin(), expected.end());
BOOST_CHECK(ret);
if (dopad) {
BOOST_CHECK_EQUAL(origpad.back(), 0);
origpad.pop_back();
}
BOOST_CHECK(origpad == in);
}
BOOST_AUTO_TEST_CASE(test_ConvertBits) {
CheckConvertBits<8, 5>({}, {});
CheckConvertBits<8, 5>({0xff}, {0x1f, 0x1c});
CheckConvertBits<8, 5>({0xff, 0xff}, {0x1f, 0x1f, 0x1f, 0x10});
CheckConvertBits<8, 5>({0xff, 0xff, 0xff}, {0x1f, 0x1f, 0x1f, 0x1f, 0x1e});
CheckConvertBits<8, 5>({0xff, 0xff, 0xff, 0xff},
{0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x18});
CheckConvertBits<8, 5>({0xff, 0xff, 0xff, 0xff, 0xff},
{0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f});
CheckConvertBits<8, 5>({0xff, 0xff, 0xff, 0xff, 0xff},
{0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f});
CheckConvertBits<8, 5>({0xff, 0xff, 0xff, 0xff, 0xff},
{0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f});
CheckConvertBits<8, 5>({0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
{0x00, 0x04, 0x11, 0x14, 0x0a, 0x19, 0x1c, 0x09,
0x15, 0x0f, 0x06, 0x1e, 0x1e});
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/util.cpp b/src/util.cpp
index 4dd51bd4b..f037f2539 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1,750 +1,810 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif
#include "util.h"
#include "chainparamsbase.h"
#include "fs.h"
#include "random.h"
#include "serialize.h"
#include "utilstrencodings.h"
#include "utiltime.h"
#include
#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
#include
#include
#endif
#ifndef WIN32
// for posix_fallocate
#ifdef __linux__
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#define _POSIX_C_SOURCE 200112L
#endif // __linux__
#include
#include
#include
#include
#else
#ifdef _MSC_VER
#pragma warning(disable : 4786)
#pragma warning(disable : 4804)
#pragma warning(disable : 4805)
#pragma warning(disable : 4717)
#endif
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
#define _WIN32_IE 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include /* for _commit */
#include
#endif
#ifdef HAVE_SYS_PRCTL_H
#include
#endif
#ifdef HAVE_MALLOPT_ARENA_MAX
#include
#endif
#include
#include
#include
#include
// Application startup time (used for uptime calculation)
const int64_t nStartupTime = GetTime();
const char *const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char *const BITCOIN_PID_FILENAME = "bitcoind.pid";
ArgsManager gArgs;
CTranslationInterface translationInterface;
/** Init OpenSSL library multithreading support */
static CCriticalSection **ppmutexOpenSSL;
void locking_callback(int mode, int i, const char *file,
int line) NO_THREAD_SAFETY_ANALYSIS {
if (mode & CRYPTO_LOCK) {
ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
} else {
LEAVE_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
}
}
// Init
class CInit {
public:
CInit() {
// Init OpenSSL library multithreading support.
ppmutexOpenSSL = (CCriticalSection **)OPENSSL_malloc(
CRYPTO_num_locks() * sizeof(CCriticalSection *));
for (int i = 0; i < CRYPTO_num_locks(); i++) {
ppmutexOpenSSL[i] = new CCriticalSection();
}
CRYPTO_set_locking_callback(locking_callback);
// OpenSSL can optionally load a config file which lists optional
// loadable modules and engines. We don't use them so we don't require
// the config. However some of our libs may call functions which attempt
// to load the config file, possibly resulting in an exit() or crash if
// it is missing or corrupt. Explicitly tell OpenSSL not to try to load
// the file. The result for our libs will be that the config appears to
// have been loaded and there are no modules/engines available.
OPENSSL_no_config();
#ifdef WIN32
// Seed OpenSSL PRNG with current contents of the screen.
RAND_screen();
#endif
// Seed OpenSSL PRNG with performance counter.
RandAddSeed();
}
~CInit() {
// Securely erase the memory used by the PRNG.
RAND_cleanup();
// Shutdown OpenSSL library multithreading support.
CRYPTO_set_locking_callback(nullptr);
for (int i = 0; i < CRYPTO_num_locks(); i++) {
delete ppmutexOpenSSL[i];
}
OPENSSL_free(ppmutexOpenSSL);
}
} instance_of_cinit;
/**
* Interpret a string argument as a boolean.
*
* The definition of atoi() requires that non-numeric string values like "foo",
* return 0. This means that if a user unintentionally supplies a non-integer
* argument here, the return value is always false. This means that -foo=false
* does what the user probably expects, but -foo=true is well defined but does
* not do what they probably expected.
*
* The return value of atoi() is undefined when given input not representable as
* an int. On most systems this means string value between "-2147483648" and
* "2147483647" are well defined (this method will return true). Setting
* -txindex=2147483648 on most systems, however, is probably undefined.
*
* For a more extensive discussion of this topic (and a wide range of opinions
* on the Right Way to change this code), see PR12713.
*/
static bool InterpretBool(const std::string &strValue) {
if (strValue.empty()) {
return true;
}
return (atoi(strValue) != 0);
}
+/** Internal helper functions for ArgsManager */
+class ArgsManagerHelper {
+public:
+ typedef std::map> MapArgs;
+
+ /** Find arguments in a map and add them to a vector */
+ static inline void AddArgs(std::vector &res,
+ const MapArgs &map_args,
+ const std::string &arg) {
+ auto it = map_args.find(arg);
+ if (it != map_args.end()) {
+ res.insert(res.end(), it->second.begin(), it->second.end());
+ }
+ }
+
+ /**
+ * Return true/false if an argument is set in a map, and also
+ * return the first (or last) of the possibly multiple values it has
+ */
+ static inline std::pair
+ GetArgHelper(const MapArgs &map_args, const std::string &arg,
+ bool getLast = false) {
+ auto it = map_args.find(arg);
+
+ if (it == map_args.end() || it->second.empty()) {
+ return std::make_pair(false, std::string());
+ }
+
+ if (getLast) {
+ return std::make_pair(true, it->second.back());
+ } else {
+ return std::make_pair(true, it->second.front());
+ }
+ }
+
+ /**
+ * Get the string value of an argument, returning a pair of a boolean
+ * indicating the argument was found, and the value for the argument
+ * if it was found (or the empty string if not found).
+ */
+ static inline std::pair GetArg(const ArgsManager &am,
+ const std::string &arg) {
+ LOCK(am.cs_args);
+ std::pair found_result(false, std::string());
+
+ // We pass "true" to GetArgHelper in order to return the last
+ // argument value seen from the command line (so "bitcoind -foo=bar
+ // -foo=baz" gives GetArg(am,"foo")=={true,"baz"}
+ found_result = GetArgHelper(am.m_override_args, arg, true);
+ if (found_result.first) {
+ return found_result;
+ }
+
+ // But in contrast we return the first argument seen in a config file,
+ // so "foo=bar \n foo=baz" in the config file gives
+ // GetArg(am,"foo")={true,"bar"}
+ found_result = GetArgHelper(am.m_config_args, arg);
+ if (found_result.first) {
+ return found_result;
+ }
+
+ return found_result;
+ }
+};
+
/**
* Interpret -nofoo as if the user supplied -foo=0.
*
* This method also tracks when the -no form was supplied, and treats "-foo" as
* a negated option when this happens. This can be later checked using the
* IsArgNegated() method. One use case for this is to have a way to disable
* options that are not normally boolean (e.g. using -nodebuglogfile to request
* that debug log output is not sent to any file at all).
*/
void ArgsManager::InterpretNegatedOption(std::string &key, std::string &val) {
if (key.substr(0, 3) == "-no") {
bool bool_val = InterpretBool(val);
if (!bool_val) {
// Double negatives like -nofoo=0 are supported (but discouraged)
LogPrintf(
"Warning: parsed potentially confusing double-negative %s=%s\n",
key, val);
}
key.erase(1, 2);
m_negated_args.insert(key);
val = bool_val ? "0" : "1";
} else {
// In an invocation like "bitcoind -nofoo -foo" we want to unmark -foo
// as negated when we see the second option.
m_negated_args.erase(key);
}
}
void ArgsManager::ParseParameters(int argc, const char *const argv[]) {
LOCK(cs_args);
- mapArgs.clear();
- mapMultiArgs.clear();
+ m_override_args.clear();
m_negated_args.clear();
for (int i = 1; i < argc; i++) {
std::string key(argv[i]);
std::string val;
size_t is_index = key.find('=');
if (is_index != std::string::npos) {
val = key.substr(is_index + 1);
key.erase(is_index);
}
#ifdef WIN32
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
if (key[0] == '/') {
key[0] = '-';
}
#endif
if (key[0] != '-') {
break;
}
// Transform --foo to -foo
if (key.length() > 1 && key[1] == '-') {
key.erase(0, 1);
}
// Transform -nofoo to -foo=0
InterpretNegatedOption(key, val);
- mapArgs[key] = val;
- mapMultiArgs[key].push_back(val);
+ m_override_args[key].push_back(val);
}
}
std::vector ArgsManager::GetArgs(const std::string &strArg) const {
+ std::vector result = {};
+
LOCK(cs_args);
- auto it = mapMultiArgs.find(strArg);
- if (it != mapMultiArgs.end()) {
- return it->second;
- }
- return {};
+ ArgsManagerHelper::AddArgs(result, m_override_args, strArg);
+ ArgsManagerHelper::AddArgs(result, m_config_args, strArg);
+ return result;
}
bool ArgsManager::IsArgSet(const std::string &strArg) const {
- LOCK(cs_args);
- return mapArgs.count(strArg);
+ return ArgsManagerHelper::GetArg(*this, strArg).first;
}
bool ArgsManager::IsArgNegated(const std::string &strArg) const {
LOCK(cs_args);
return m_negated_args.find(strArg) != m_negated_args.end();
}
std::string ArgsManager::GetArg(const std::string &strArg,
const std::string &strDefault) const {
- LOCK(cs_args);
- auto it = mapArgs.find(strArg);
- if (it != mapArgs.end()) {
- return it->second;
+ std::pair found_res =
+ ArgsManagerHelper::GetArg(*this, strArg);
+ if (found_res.first) {
+ return found_res.second;
}
return strDefault;
}
int64_t ArgsManager::GetArg(const std::string &strArg, int64_t nDefault) const {
- LOCK(cs_args);
- auto it = mapArgs.find(strArg);
- if (it != mapArgs.end()) {
- return atoi64(it->second);
+ std::pair found_res =
+ ArgsManagerHelper::GetArg(*this, strArg);
+ if (found_res.first) {
+ return atoi64(found_res.second);
}
return nDefault;
}
bool ArgsManager::GetBoolArg(const std::string &strArg, bool fDefault) const {
- LOCK(cs_args);
- auto it = mapArgs.find(strArg);
- if (it != mapArgs.end()) {
- return InterpretBool(it->second);
+ std::pair found_res =
+ ArgsManagerHelper::GetArg(*this, strArg);
+ if (found_res.first) {
+ return InterpretBool(found_res.second);
}
return fDefault;
}
bool ArgsManager::SoftSetArg(const std::string &strArg,
const std::string &strValue) {
LOCK(cs_args);
if (IsArgSet(strArg)) {
return false;
}
ForceSetArg(strArg, strValue);
return true;
}
bool ArgsManager::SoftSetBoolArg(const std::string &strArg, bool fValue) {
if (fValue) {
return SoftSetArg(strArg, std::string("1"));
} else {
return SoftSetArg(strArg, std::string("0"));
}
}
void ArgsManager::ForceSetArg(const std::string &strArg,
const std::string &strValue) {
LOCK(cs_args);
- mapArgs[strArg] = strValue;
- mapMultiArgs[strArg] = {strValue};
+ m_override_args[strArg] = {strValue};
}
/**
* This function is only used for testing purpose so
* so we should not worry about element uniqueness and
* integrity of mapMultiArgs data structure
*/
void ArgsManager::ForceSetMultiArg(const std::string &strArg,
const std::string &strValue) {
LOCK(cs_args);
- if (mapArgs.count(strArg) == 0) {
- mapArgs[strArg] = strValue;
- }
- mapMultiArgs[strArg].push_back(strValue);
+ m_override_args[strArg].push_back(strValue);
}
void ArgsManager::ClearArg(const std::string &strArg) {
LOCK(cs_args);
- mapArgs.erase(strArg);
- mapMultiArgs.erase(strArg);
+ m_override_args.erase(strArg);
+ m_config_args.erase(strArg);
}
bool HelpRequested(const ArgsManager &args) {
return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help");
}
static const int screenWidth = 79;
static const int optIndent = 2;
static const int msgIndent = 7;
std::string HelpMessageGroup(const std::string &message) {
return std::string(message) + std::string("\n\n");
}
std::string HelpMessageOpt(const std::string &option,
const std::string &message) {
return std::string(optIndent, ' ') + std::string(option) +
std::string("\n") + std::string(msgIndent, ' ') +
FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
std::string("\n\n");
}
static std::string FormatException(const std::exception *pex,
const char *pszThread) {
#ifdef WIN32
char pszModule[MAX_PATH] = "";
GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
#else
const char *pszModule = "bitcoin";
#endif
if (pex) {
return strprintf("EXCEPTION: %s \n%s \n%s in %s \n",
typeid(*pex).name(), pex->what(), pszModule,
pszThread);
} else {
return strprintf("UNKNOWN EXCEPTION \n%s in %s \n",
pszModule, pszThread);
}
}
void PrintExceptionContinue(const std::exception *pex, const char *pszThread) {
std::string message = FormatException(pex, pszThread);
LogPrintf("\n\n************************\n%s\n", message);
fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
}
fs::path GetDefaultDataDir() {
// Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin
// Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin
// Mac: ~/Library/Application Support/Bitcoin
// Unix: ~/.bitcoin
#ifdef WIN32
// Windows
return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
#else
fs::path pathRet;
char *pszHome = getenv("HOME");
if (pszHome == nullptr || strlen(pszHome) == 0) {
pathRet = fs::path("/");
} else {
pathRet = fs::path(pszHome);
}
#ifdef MAC_OSX
// Mac
return pathRet / "Library/Application Support/Bitcoin";
#else
// Unix
return pathRet / ".bitcoin";
#endif
#endif
}
static fs::path pathCached;
static fs::path pathCachedNetSpecific;
static CCriticalSection csPathCached;
const fs::path &GetDataDir(bool fNetSpecific) {
LOCK(csPathCached);
fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
// This can be called during exceptions by LogPrintf(), so we cache the
// value so we don't have to do memory allocations after that.
if (!path.empty()) {
return path;
}
if (gArgs.IsArgSet("-datadir")) {
path = fs::system_complete(gArgs.GetArg("-datadir", ""));
if (!fs::is_directory(path)) {
path = "";
return path;
}
} else {
path = GetDefaultDataDir();
}
if (fNetSpecific) {
path /= BaseParams().DataDir();
}
if (fs::create_directories(path)) {
// This is the first run, create wallets subdirectory too
fs::create_directories(path / "wallets");
}
return path;
}
void ClearDatadirCache() {
LOCK(csPathCached);
pathCached = fs::path();
pathCachedNetSpecific = fs::path();
}
fs::path GetConfigFile(const std::string &confPath) {
fs::path pathConfigFile(confPath);
if (!pathConfigFile.is_complete()) {
pathConfigFile = GetDataDir(false) / pathConfigFile;
}
return pathConfigFile;
}
void ArgsManager::ReadConfigStream(std::istream &stream) {
LOCK(cs_args);
std::set setOptions;
setOptions.insert("*");
for (boost::program_options::detail::config_file_iterator
it(stream, setOptions),
end;
it != end; ++it) {
// Don't overwrite existing settings so command line settings override
// bitcoin.conf
std::string strKey = std::string("-") + it->string_key;
std::string strValue = it->value[0];
InterpretNegatedOption(strKey, strValue);
- if (mapArgs.count(strKey) == 0) {
- mapArgs[strKey] = strValue;
- }
- mapMultiArgs[strKey].push_back(strValue);
+ m_config_args[strKey].push_back(strValue);
}
}
void ArgsManager::ReadConfigFile(const std::string &confPath) {
+ {
+ LOCK(cs_args);
+ m_config_args.clear();
+ }
+
fs::ifstream stream(GetConfigFile(confPath));
// ok to not have a config file
if (stream.good()) {
ReadConfigStream(stream);
}
// If datadir is changed in .conf file:
ClearDatadirCache();
if (!fs::is_directory(GetDataDir(false))) {
throw std::runtime_error(
strprintf("specified data directory \"%s\" does not exist.",
gArgs.GetArg("-datadir", "").c_str()));
}
}
std::string ArgsManager::GetChainName() const {
bool fRegTest = GetBoolArg("-regtest", false);
bool fTestNet = GetBoolArg("-testnet", false);
if (fTestNet && fRegTest) {
throw std::runtime_error(
"Invalid combination of -regtest and -testnet.");
}
if (fRegTest) {
return CBaseChainParams::REGTEST;
}
if (fTestNet) {
return CBaseChainParams::TESTNET;
}
return CBaseChainParams::MAIN;
}
#ifndef WIN32
fs::path GetPidFile() {
fs::path pathPidFile(gArgs.GetArg("-pid", BITCOIN_PID_FILENAME));
if (!pathPidFile.is_complete()) {
pathPidFile = GetDataDir() / pathPidFile;
}
return pathPidFile;
}
void CreatePidFile(const fs::path &path, pid_t pid) {
FILE *file = fsbridge::fopen(path, "w");
if (file) {
fprintf(file, "%d\n", pid);
fclose(file);
}
}
#endif
bool RenameOver(fs::path src, fs::path dest) {
#ifdef WIN32
return MoveFileExA(src.string().c_str(), dest.string().c_str(),
MOVEFILE_REPLACE_EXISTING) != 0;
#else
int rc = std::rename(src.string().c_str(), dest.string().c_str());
return (rc == 0);
#endif /* WIN32 */
}
/**
* Ignores exceptions thrown by Boost's create_directories if the requested
* directory exists. Specifically handles case where path p exists, but it
* wasn't possible for the user to write to the parent directory.
*/
bool TryCreateDirectories(const fs::path &p) {
try {
return fs::create_directories(p);
} catch (const fs::filesystem_error &) {
if (!fs::exists(p) || !fs::is_directory(p)) {
throw;
}
}
// create_directory didn't create the directory, it had to have existed
// already.
return false;
}
void FileCommit(FILE *file) {
// Harmless if redundantly called.
fflush(file);
#ifdef WIN32
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
FlushFileBuffers(hFile);
#else
#if defined(__linux__) || defined(__NetBSD__)
fdatasync(fileno(file));
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
fcntl(fileno(file), F_FULLFSYNC, 0);
#else
fsync(fileno(file));
#endif
#endif
}
bool TruncateFile(FILE *file, unsigned int length) {
#if defined(WIN32)
return _chsize(_fileno(file), length) == 0;
#else
return ftruncate(fileno(file), length) == 0;
#endif
}
/**
* This function tries to raise the file descriptor limit to the requested
* number. It returns the actual file descriptor limit (which may be more or
* less than nMinFD)
*/
int RaiseFileDescriptorLimit(int nMinFD) {
#if defined(WIN32)
return 2048;
#else
struct rlimit limitFD;
if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
if (limitFD.rlim_cur < (rlim_t)nMinFD) {
limitFD.rlim_cur = nMinFD;
if (limitFD.rlim_cur > limitFD.rlim_max) {
limitFD.rlim_cur = limitFD.rlim_max;
}
setrlimit(RLIMIT_NOFILE, &limitFD);
getrlimit(RLIMIT_NOFILE, &limitFD);
}
return limitFD.rlim_cur;
}
// getrlimit failed, assume it's fine.
return nMinFD;
#endif
}
/**
* This function tries to make a particular range of a file allocated
* (corresponding to disk space) it is advisory, and the range specified in the
* arguments will never contain live data.
*/
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
#if defined(WIN32)
// Windows-specific version.
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
LARGE_INTEGER nFileSize;
int64_t nEndPos = (int64_t)offset + length;
nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
nFileSize.u.HighPart = nEndPos >> 32;
SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
SetEndOfFile(hFile);
#elif defined(MAC_OSX)
// OSX specific version.
fstore_t fst;
fst.fst_flags = F_ALLOCATECONTIG;
fst.fst_posmode = F_PEOFPOSMODE;
fst.fst_offset = 0;
fst.fst_length = (off_t)offset + length;
fst.fst_bytesalloc = 0;
if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
fst.fst_flags = F_ALLOCATEALL;
fcntl(fileno(file), F_PREALLOCATE, &fst);
}
ftruncate(fileno(file), fst.fst_length);
#elif defined(__linux__)
// Version using posix_fallocate.
off_t nEndPos = (off_t)offset + length;
posix_fallocate(fileno(file), 0, nEndPos);
#else
// Fallback version
// TODO: just write one byte per block
static const char buf[65536] = {};
fseek(file, offset, SEEK_SET);
while (length > 0) {
unsigned int now = 65536;
if (length < now) {
now = length;
}
// Allowed to fail; this function is advisory anyway.
fwrite(buf, 1, now, file);
length -= now;
}
#endif
}
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate) {
char pszPath[MAX_PATH] = "";
if (SHGetSpecialFolderPathA(nullptr, pszPath, nFolder, fCreate)) {
return fs::path(pszPath);
}
LogPrintf(
"SHGetSpecialFolderPathA() failed, could not obtain requested path.\n");
return fs::path("");
}
#endif
void runCommand(const std::string &strCommand) {
if (strCommand.empty()) {
return;
}
int nErr = ::system(strCommand.c_str());
if (nErr) {
LogPrintf("runCommand error: system(%s) returned %d\n", strCommand,
nErr);
}
}
void RenameThread(const char *name) {
#if defined(PR_SET_NAME)
// Only the first 15 characters are used (16 - NUL terminator)
::prctl(PR_SET_NAME, name, 0, 0, 0);
#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
pthread_set_name_np(pthread_self(), name);
#elif defined(MAC_OSX)
pthread_setname_np(name);
#else
// Prevent warnings for unused parameters...
(void)name;
#endif
}
void SetupEnvironment() {
#ifdef HAVE_MALLOPT_ARENA_MAX
// glibc-specific: On 32-bit systems set the number of arenas to 1. By
// default, since glibc 2.10, the C library will create up to two heap
// arenas per core. This is known to cause excessive virtual address space
// usage in our usage. Work around it by setting the maximum number of
// arenas to 1.
if (sizeof(void *) == 4) {
mallopt(M_ARENA_MAX, 1);
}
#endif
// On most POSIX systems (e.g. Linux, but not BSD) the environment's locale may
// be invalid, in which case the "C" locale is used as fallback.
#if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && \
!defined(__OpenBSD__)
try {
// Raises a runtime error if current locale is invalid.
std::locale("");
} catch (const std::runtime_error &) {
setenv("LC_ALL", "C", 1);
}
#endif
// The path locale is lazy initialized and to avoid deinitialization errors
// in multithreading environments, it is set explicitly by the main thread.
// A dummy locale is used to extract the internal default locale, used by
// fs::path, which is then used to explicitly imbue the path.
std::locale loc = fs::path::imbue(std::locale::classic());
fs::path::imbue(loc);
}
bool SetupNetworking() {
#ifdef WIN32
// Initialize Windows Sockets.
WSADATA wsadata;
int ret = WSAStartup(MAKEWORD(2, 2), &wsadata);
if (ret != NO_ERROR || LOBYTE(wsadata.wVersion) != 2 ||
HIBYTE(wsadata.wVersion) != 2) {
return false;
}
#endif
return true;
}
int GetNumCores() {
return boost::thread::physical_concurrency();
}
std::string CopyrightHolders(const std::string &strPrefix) {
return strPrefix +
strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION));
}
// Obtain the application startup time (used for uptime calculation)
int64_t GetStartupTime() {
return nStartupTime;
}
diff --git a/src/util.h b/src/util.h
index d1fd42d72..c7fd3e15d 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,267 +1,269 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
/**
* Server/client environment: argument handling, config file parsing,
* thread wrappers, startup time
*/
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif
#include "compat.h"
#include "fs.h"
#include "logging.h"
#include "sync.h"
#include "tinyformat.h"
#include "utiltime.h"
#include
#include
#include
#include