diff --git a/doc/release-notes.md b/doc/release-notes.md
index 1fcb80455f..2657934770 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,17 +1,28 @@
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")
- 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
- From the config file, if an argument is negated it takes precedent over all the
- previous occurences of this argument (e.g. "foo=2 \n nofoo=1" will set foo=0)
\ No newline at end of file
+ previous occurences of this argument (e.g. "foo=2 \n nofoo=1" will set foo=0)
+ - The configuration files now support assigning options to a specific network.
+ To do so, sections or prefix can be used:
+ main.uacomment=bch-mainnet
+ test.uacomment=bch-testnet
+ regtest.uacomment=bch-regtest
+ [main]
+ mempoolsize=300
+ [test]
+ mempoolsize=200
+ [regtest]
+ mempoolsize=50
\ No newline at end of file
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 1879705ddd..8d24a34960 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -1,81 +1,82 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 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 "chainparamsbase.h"
#include "tinyformat.h"
#include "util.h"
#include
const std::string CBaseChainParams::MAIN = "main";
const std::string CBaseChainParams::TESTNET = "test";
const std::string CBaseChainParams::REGTEST = "regtest";
void AppendParamsHelpMessages(std::string &strUsage, bool debugHelp) {
strUsage += HelpMessageGroup(_("Chain selection options:"));
strUsage += HelpMessageOpt("-testnet", _("Use the test chain"));
if (debugHelp) {
strUsage += HelpMessageOpt(
"-regtest", "Enter regression test mode, which uses a special "
"chain in which blocks can be solved instantly. "
"This is intended for regression testing tools and app "
"development.");
}
}
/**
* Main network
*/
class CBaseMainParams : public CBaseChainParams {
public:
CBaseMainParams() { nRPCPort = 8332; }
};
/**
* Testnet (v3)
*/
class CBaseTestNetParams : public CBaseChainParams {
public:
CBaseTestNetParams() {
nRPCPort = 18332;
strDataDir = "testnet3";
}
};
/*
* Regression test
*/
class CBaseRegTestParams : public CBaseChainParams {
public:
CBaseRegTestParams() {
nRPCPort = 18332;
strDataDir = "regtest";
}
};
static std::unique_ptr globalChainBaseParams;
const CBaseChainParams &BaseParams() {
assert(globalChainBaseParams);
return *globalChainBaseParams;
}
std::unique_ptr
CreateBaseChainParams(const std::string &chain) {
if (chain == CBaseChainParams::MAIN)
return std::unique_ptr(new CBaseMainParams());
else if (chain == CBaseChainParams::TESTNET)
return std::unique_ptr(new CBaseTestNetParams());
else if (chain == CBaseChainParams::REGTEST)
return std::unique_ptr(new CBaseRegTestParams());
else
throw std::runtime_error(
strprintf("%s: Unknown chain %s.", __func__, chain));
}
void SelectBaseParams(const std::string &chain) {
globalChainBaseParams = CreateBaseChainParams(chain);
+ gArgs.SelectConfigNetwork(chain);
}
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 541b42d224..20460f6a5d 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1,1127 +1,1187 @@
// 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> &GetOverrideArgs() {
return m_override_args;
}
std::map> &GetConfigArgs() {
return m_config_args;
}
void ReadConfigString(const std::string str_config) {
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.GetOverrideArgs().empty() &&
testArgs.GetConfigArgs().empty());
testArgs.ParseParameters(1, (char **)argv_test);
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.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.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.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.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, and not marked as negated.
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,
// and the value.
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "1");
// A double negative is a positive, and does not count as negated.
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() == 0);
// 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() == 1 &&
testArgs.GetArgs("-bar").front() == "");
}
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";
+ "i=1\n"
+ "sec1.ccc=extend1\n"
+ "\n"
+ "[sec1]\n"
+ "ccc=extend2\n"
+ "h=1\n"
+ "[sec2]\n"
+ "ccc=extend3\n"
+ "iii=2\n";
TestArgsManager test_args;
test_args.ReadConfigString(str_config);
// expectation: a, b, ccc, d, fff, ggg, h, i end up in map
+ // so do sec1.ccc, sec1.h, sec2.ccc, sec2.iii
BOOST_CHECK(test_args.GetOverrideArgs().empty());
- BOOST_CHECK(test_args.GetConfigArgs().size() == 8);
+ BOOST_CHECK(test_args.GetConfigArgs().size() == 12);
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.GetConfigArgs().count("-sec1.ccc") &&
+ test_args.GetConfigArgs().count("-sec1.h") &&
+ test_args.GetConfigArgs().count("-sec2.ccc") &&
+ test_args.GetConfigArgs().count("-sec2.iii"));
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"));
+ !test_args.IsArgSet("-zzz") && !test_args.IsArgSet("-iii"));
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" &&
test_args.GetArg("-h", "xxx") == "0" &&
test_args.GetArg("-i", "xxx") == "1" &&
- test_args.GetArg("-zzz", "xxx") == "xxx");
+ test_args.GetArg("-zzz", "xxx") == "xxx" &&
+ test_args.GetArg("-iii", "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);
+ test_args.GetBoolArg("-zzz", def) == def &&
+ test_args.GetBoolArg("-iii", 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() == 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() == 0);
BOOST_CHECK(test_args.GetArgs("-noh").size() == 0);
BOOST_CHECK(test_args.GetArgs("-i").size() == 1 &&
test_args.GetArgs("-i").front() == "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"));
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"));
+
+ // Test sections work
+ test_args.SelectConfigNetwork("sec1");
+
+ // same as original
+ BOOST_CHECK(test_args.GetArg("-a", "xxx") == "" &&
+ test_args.GetArg("-b", "xxx") == "1" &&
+ test_args.GetArg("-d", "xxx") == "e" &&
+ test_args.GetArg("-fff", "xxx") == "0" &&
+ test_args.GetArg("-ggg", "xxx") == "1" &&
+ test_args.GetArg("-zzz", "xxx") == "xxx" &&
+ test_args.GetArg("-iii", "xxx") == "xxx");
+ // section-specific setting
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
+ // section takes priority for multiple values
+ BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend1");
+ // check multiple values works
+ const std::vector sec1_ccc_expected = {"extend1", "extend2",
+ "argument", "multiple"};
+ const auto &sec1_ccc_res = test_args.GetArgs("-ccc");
+ BOOST_CHECK_EQUAL_COLLECTIONS(sec1_ccc_res.begin(), sec1_ccc_res.end(),
+ sec1_ccc_expected.begin(),
+ sec1_ccc_expected.end());
+
+ test_args.SelectConfigNetwork("sec2");
+
+ // same as original
+ BOOST_CHECK(test_args.GetArg("-a", "xxx") == "" &&
+ test_args.GetArg("-b", "xxx") == "1" &&
+ test_args.GetArg("-d", "xxx") == "e" &&
+ test_args.GetArg("-fff", "xxx") == "0" &&
+ test_args.GetArg("-ggg", "xxx") == "1" &&
+ test_args.GetArg("-zzz", "xxx") == "xxx" &&
+ test_args.GetArg("-h", "xxx") == "0");
+ // section-specific setting
+ BOOST_CHECK(test_args.GetArg("-iii", "xxx") == "2");
+ // section takes priority for multiple values
+ BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend3");
+ // check multiple values works
+ const std::vector sec2_ccc_expected = {"extend3", "argument",
+ "multiple"};
+ const auto &sec2_ccc_res = test_args.GetArgs("-ccc");
+ BOOST_CHECK_EQUAL_COLLECTIONS(sec2_ccc_res.begin(), sec2_ccc_res.end(),
+ sec2_ccc_expected.begin(),
+ sec2_ccc_expected.end());
}
BOOST_AUTO_TEST_CASE(util_GetArg) {
TestArgsManager testArgs;
testArgs.GetOverrideArgs().clear();
testArgs.GetOverrideArgs()["strtest1"] = {"string..."};
// strtest2 undefined on purpose
testArgs.GetOverrideArgs()["inttest1"] = {"12345"};
testArgs.GetOverrideArgs()["inttest2"] = {"81985529216486895"};
// inttest3 undefined on purpose
testArgs.GetOverrideArgs()["booltest1"] = {""};
// booltest2 undefined on purpose
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.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.GetOverrideArgs()["booltest1"] = {"1"};
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", false), true);
testArgs.ClearArg("booltest1");
BOOST_CHECK_EQUAL(testArgs.GetArg("booltest1", false), false);
// 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 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"), "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"),
"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 8ade4081d2..666b9179d1 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1,849 +1,888 @@
// 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;
+ /** Convert regular argument into the network-specific setting */
+ static inline std::string NetworkArg(const ArgsManager &am,
+ const std::string &arg) {
+ assert(arg.length() > 1 && arg[0] == '-');
+ return "-" + am.m_network + "." + arg.substr(1);
+ }
+
/** 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"}
+ if (!am.m_network.empty()) {
+ found_result = GetArgHelper(am.m_config_args, NetworkArg(am, arg));
+ if (found_result.first) {
+ return found_result;
+ }
+ }
+
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 if so, checks
* whether there was a double-negative (-nofoo=0 -> -foo=1).
*
* If there was not a double negative, it removes the "no" from the key, and
* returns true, indicating the caller should clear the args vector to indicate
* a negated option.
*
* If there was a double negative, it removes "no" from the key, sets the value
* to "1" and returns false.
*
* If there was no "no", it leaves key and value untouched and returns false.
*
* Where an option was negated 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).
*/
static bool InterpretNegatedOption(std::string &key, std::string &val) {
- if (key.substr(0, 3) == "-no") {
+ assert(key[0] == '-');
+
+ size_t option_index = key.find('.');
+ if (option_index == std::string::npos) {
+ option_index = 1;
+ } else {
+ ++option_index;
+ }
+ if (key.substr(option_index, 2) == "no") {
bool bool_val = InterpretBool(val);
- key.erase(1, 2);
+ key.erase(option_index, 2);
if (!bool_val) {
// Double negatives like -nofoo=0 are supported (but discouraged)
LogPrintf(
"Warning: parsed potentially confusing double-negative %s=%s\n",
key, val);
val = "1";
} else {
return true;
}
}
return false;
}
+void ArgsManager::SelectConfigNetwork(const std::string &network) {
+ m_network = network;
+}
+
void ArgsManager::ParseParameters(int argc, const char *const argv[]) {
LOCK(cs_args);
m_override_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);
}
// Check for -nofoo
if (InterpretNegatedOption(key, val)) {
m_override_args[key].clear();
} else {
m_override_args[key].push_back(val);
}
}
}
std::vector ArgsManager::GetArgs(const std::string &strArg) const {
std::vector result = {};
// special case
if (IsArgNegated(strArg)) {
return result;
}
LOCK(cs_args);
ArgsManagerHelper::AddArgs(result, m_override_args, strArg);
+ if (!m_network.empty()) {
+ ArgsManagerHelper::AddArgs(
+ result, m_config_args,
+ ArgsManagerHelper::NetworkArg(*this, strArg));
+ }
ArgsManagerHelper::AddArgs(result, m_config_args, strArg);
return result;
}
bool ArgsManager::IsArgSet(const std::string &strArg) const {
// special case
if (IsArgNegated(strArg)) {
return true;
}
return ArgsManagerHelper::GetArg(*this, strArg).first;
}
bool ArgsManager::IsArgNegated(const std::string &strArg) const {
LOCK(cs_args);
const auto &ov = m_override_args.find(strArg);
if (ov != m_override_args.end()) {
return ov->second.empty();
}
+ if (!m_network.empty()) {
+ const auto &cfs =
+ m_config_args.find(ArgsManagerHelper::NetworkArg(*this, strArg));
+ if (cfs != m_config_args.end()) {
+ return cfs->second.empty();
+ }
+ }
+
const auto &cf = m_config_args.find(strArg);
if (cf != m_config_args.end()) {
return cf->second.empty();
}
return false;
}
std::string ArgsManager::GetArg(const std::string &strArg,
const std::string &strDefault) const {
if (IsArgNegated(strArg)) {
return "0";
}
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 {
if (IsArgNegated(strArg)) {
return 0;
}
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 {
if (IsArgNegated(strArg)) {
return false;
}
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);
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);
m_override_args[strArg].push_back(strValue);
}
void ArgsManager::ClearArg(const std::string &strArg) {
LOCK(cs_args);
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) {
std::string strKey = std::string("-") + it->string_key;
std::string strValue = it->value[0];
if (InterpretNegatedOption(strKey, strValue)) {
m_config_args[strKey].clear();
} else {
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 f3a33713ae..3afb977bae 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,264 +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