2011-05-14 17:25:05 +02:00
|
|
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
2015-12-13 14:51:43 +01:00
|
|
|
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
2019-01-29 15:53:14 +01:00
|
|
|
// Copyright (c) 2014-2019 The Dash Core developers
|
2014-11-17 04:04:01 +01:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2012-05-18 16:02:28 +02:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2012-03-31 15:22:45 +02:00
|
|
|
|
2014-08-12 13:03:56 +02:00
|
|
|
#if defined(HAVE_CONFIG_H)
|
2015-04-03 00:51:08 +02:00
|
|
|
#include "config/dash-config.h"
|
2014-08-12 13:03:56 +02:00
|
|
|
#endif
|
|
|
|
|
2013-04-13 07:13:08 +02:00
|
|
|
#include "util.h"
|
|
|
|
|
2016-02-02 16:28:56 +01:00
|
|
|
#include "support/allocators/secure.h"
|
2014-06-19 15:10:04 +02:00
|
|
|
#include "chainparamsbase.h"
|
2018-05-24 13:57:36 +02:00
|
|
|
#include "ctpl.h"
|
2017-04-06 20:19:21 +02:00
|
|
|
#include "fs.h"
|
2014-06-26 14:41:53 +02:00
|
|
|
#include "random.h"
|
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
|
|
|
#include "serialize.h"
|
2019-02-21 19:37:16 +01:00
|
|
|
#include "stacktraces.h"
|
2013-04-13 07:13:08 +02:00
|
|
|
#include "sync.h"
|
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
|
|
|
#include "utilstrencodings.h"
|
|
|
|
#include "utiltime.h"
|
2013-04-13 07:13:08 +02:00
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
2015-03-27 13:19:49 +01:00
|
|
|
#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <pthread_np.h>
|
|
|
|
#endif
|
2014-12-26 12:53:29 +01:00
|
|
|
|
2013-01-28 00:07:51 +01:00
|
|
|
#ifndef WIN32
|
|
|
|
// for posix_fallocate
|
2014-08-12 12:05:03 +02:00
|
|
|
#ifdef __linux__
|
2013-04-13 07:13:08 +02:00
|
|
|
|
|
|
|
#ifdef _POSIX_C_SOURCE
|
|
|
|
#undef _POSIX_C_SOURCE
|
|
|
|
#endif
|
|
|
|
|
2013-01-28 00:07:51 +01:00
|
|
|
#define _POSIX_C_SOURCE 200112L
|
2013-04-13 07:13:08 +02:00
|
|
|
|
2014-08-12 12:05:03 +02:00
|
|
|
#endif // __linux__
|
2013-04-13 07:13:08 +02:00
|
|
|
|
2013-07-17 04:20:09 +02:00
|
|
|
#include <algorithm>
|
2013-01-28 00:07:51 +01:00
|
|
|
#include <fcntl.h>
|
2013-04-26 00:46:47 +02:00
|
|
|
#include <sys/resource.h>
|
2013-04-13 07:13:08 +02:00
|
|
|
#include <sys/stat.h>
|
2012-04-15 11:42:40 +02:00
|
|
|
|
2013-04-13 07:13:08 +02:00
|
|
|
#else
|
2012-04-15 22:10:54 +02:00
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(disable:4786)
|
|
|
|
#pragma warning(disable:4804)
|
|
|
|
#pragma warning(disable:4805)
|
|
|
|
#pragma warning(disable:4717)
|
|
|
|
#endif
|
2013-04-13 07:13:08 +02:00
|
|
|
|
2012-04-15 22:10:54 +02:00
|
|
|
#ifdef _WIN32_WINNT
|
|
|
|
#undef _WIN32_WINNT
|
|
|
|
#endif
|
|
|
|
#define _WIN32_WINNT 0x0501
|
2013-04-13 07:13:08 +02:00
|
|
|
|
2012-04-15 22:10:54 +02:00
|
|
|
#ifdef _WIN32_IE
|
|
|
|
#undef _WIN32_IE
|
|
|
|
#endif
|
2012-05-03 02:21:43 +02:00
|
|
|
#define _WIN32_IE 0x0501
|
2013-04-13 07:13:08 +02:00
|
|
|
|
2012-04-15 22:10:54 +02:00
|
|
|
#define WIN32_LEAN_AND_MEAN 1
|
|
|
|
#ifndef NOMINMAX
|
|
|
|
#define NOMINMAX
|
|
|
|
#endif
|
2013-04-13 07:13:08 +02:00
|
|
|
|
2012-05-17 18:30:09 +02:00
|
|
|
#include <io.h> /* for _commit */
|
2013-04-13 07:13:08 +02:00
|
|
|
#include <shlobj.h>
|
2012-04-15 22:10:54 +02:00
|
|
|
#endif
|
2011-05-14 17:25:05 +02:00
|
|
|
|
2014-08-12 13:03:56 +02:00
|
|
|
#ifdef HAVE_SYS_PRCTL_H
|
|
|
|
#include <sys/prctl.h>
|
|
|
|
#endif
|
|
|
|
|
2017-03-31 10:36:18 +02:00
|
|
|
#ifdef HAVE_MALLOPT_ARENA_MAX
|
|
|
|
#include <malloc.h>
|
|
|
|
#endif
|
|
|
|
|
2013-04-13 07:13:08 +02:00
|
|
|
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
|
|
|
|
#include <boost/algorithm/string/join.hpp>
|
|
|
|
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
|
2017-07-04 19:31:57 +02:00
|
|
|
#include <boost/algorithm/string/split.hpp>
|
|
|
|
#include <boost/algorithm/string/classification.hpp>
|
2013-04-13 07:13:08 +02:00
|
|
|
#include <boost/foreach.hpp>
|
|
|
|
#include <boost/program_options/detail/config_file.hpp>
|
|
|
|
#include <boost/program_options/parsers.hpp>
|
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
|
|
|
#include <boost/thread.hpp>
|
2013-04-13 07:13:08 +02:00
|
|
|
#include <openssl/crypto.h>
|
|
|
|
#include <openssl/rand.h>
|
2015-07-14 23:38:03 +02:00
|
|
|
#include <openssl/conf.h>
|
2013-04-13 07:13:08 +02:00
|
|
|
|
2011-05-14 17:25:05 +02:00
|
|
|
|
2015-03-18 00:06:58 +01:00
|
|
|
//Dash only features
|
2018-01-26 02:11:01 +01:00
|
|
|
bool fMasternodeMode = false;
|
2015-01-18 16:28:16 +01:00
|
|
|
bool fLiteMode = false;
|
2016-06-15 21:13:04 +02:00
|
|
|
/**
|
|
|
|
nWalletBackups:
|
|
|
|
1..10 - number of automatic backups to keep
|
|
|
|
0 - disabled by command-line
|
|
|
|
-1 - disabled because of some error during run-time
|
|
|
|
-2 - disabled because wallet was locked and we were not able to replenish keypool
|
|
|
|
*/
|
|
|
|
int nWalletBackups = 10;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2016-02-02 16:28:56 +01:00
|
|
|
const char * const BITCOIN_CONF_FILENAME = "dash.conf";
|
2016-05-11 11:30:52 +02:00
|
|
|
const char * const BITCOIN_PID_FILENAME = "dashd.pid";
|
2015-06-27 21:21:41 +02:00
|
|
|
|
2016-12-27 19:11:21 +01:00
|
|
|
CCriticalSection cs_args;
|
Collection of minor performance optimizations (#2855)
* Merge #13176: Improve CRollingBloomFilter performance: replace modulus with FastMod
9aac9f90d5e56752cc6cbfac48063ad29a01143c replace modulus with FastMod (Martin Ankerl)
Pull request description:
Not sure if this is optimization is necessary, but anyway I have some spare time so here it is. This replaces the slow modulo operation with a much faster 64bit multiplication & shift. This works when the hash is uniformly distributed between 0 and 2^32-1. This speeds up the benchmark by a factor of about 1.3:
```
RollingBloom, 5, 1500000, 3.73733, 4.97569e-07, 4.99002e-07, 4.98372e-07 # before
RollingBloom, 5, 1500000, 2.86842, 3.81630e-07, 3.83730e-07, 3.82473e-07 # FastMod
```
Be aware that this changes the internal data of the filter, so this should probably
not be used for CBloomFilter because of interoperability problems.
Tree-SHA512: 04104f3fb09f56c9d14458a6aad919aeb0a5af944e8ee6a31f00e93c753e22004648c1cd65bf36752b6addec528d19fb665c27b955ce1666a85a928e17afa47a
* Use unordered_map in CSporkManager
In one of my profiling sessions with many InstantSend transactions
happening, calls into CSporkManager added up to about 1% of total CPU time.
This is easily avoidable by using unordered maps.
* Use std::unordered_map instead of std::map in limitedmap
* Use unordered_set for CNode::setAskFor
* Add serialization support for unordered maps and sets
* Use unordered_map for mapArgs and mapMultiArgs
* Let limitedmap prune in batches and use unordered_multimap
Due to the batched pruning, there is no need to maintain an ordered map
of values anymore. Only when nPruneAfterSize, there is a need to create
a temporary ordered vector of values to figure out what can be removed.
* Instead of using a multimap for mapAskFor, use a vector which we sort on demand
CNode::AskFor will now push entries into an initially unordered vector
instead of an ordered multimap. Only when we later want to use vecAskFor in
SendMessages, we sort the vector.
The vector will actually be mostly sorted in most cases as insertion order
usually mimics the desired ordering. Only the last few entries might need
some shuffling around. Doing the sort on-demand should be less wasteful
then trying to maintain correct order all the time.
* Fix compilation of tests
* Fix limitedmap tests
* Rename limitedmap to unordered_limitedmap to ensure backports conflict
This ensures that future backports that depends on limitedmap's ordering
conflict so that we are made aware of needed action.
* Fix compilation error on Travis
2019-04-11 14:42:14 +02:00
|
|
|
std::unordered_map<std::string, std::string> mapArgs;
|
|
|
|
static std::unordered_map<std::string, std::vector<std::string> > _mapMultiArgs;
|
|
|
|
const std::unordered_map<std::string, std::vector<std::string> >& mapMultiArgs = _mapMultiArgs;
|
2011-05-14 17:25:05 +02:00
|
|
|
bool fPrintToConsole = false;
|
2013-12-14 13:51:11 +01:00
|
|
|
bool fPrintToDebugLog = true;
|
2016-12-19 12:38:35 +01:00
|
|
|
|
2015-11-09 19:16:38 +01:00
|
|
|
bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
|
2015-10-23 19:07:36 +02:00
|
|
|
bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
|
2016-03-14 22:04:48 +01:00
|
|
|
bool fLogThreadNames = DEFAULT_LOGTHREADNAMES;
|
2015-11-09 19:16:38 +01:00
|
|
|
bool fLogIPs = DEFAULT_LOGIPS;
|
2016-06-01 20:23:11 +02:00
|
|
|
std::atomic<bool> fReopenDebugLog(false);
|
2015-04-16 16:20:01 +02:00
|
|
|
CTranslationInterface translationInterface;
|
2011-05-14 17:25:05 +02:00
|
|
|
|
2017-04-12 17:48:58 +02:00
|
|
|
/** Log categories bitfield. */
|
2019-05-22 23:51:39 +02:00
|
|
|
std::atomic<uint64_t> logCategories(0);
|
|
|
|
|
2014-11-17 04:04:01 +01:00
|
|
|
/** Init OpenSSL library multithreading support */
|
2017-04-03 12:05:43 +02:00
|
|
|
static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL;
|
2015-06-16 10:02:25 +02:00
|
|
|
void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2012-05-11 17:00:03 +02:00
|
|
|
if (mode & CRYPTO_LOCK) {
|
2017-04-03 12:05:43 +02:00
|
|
|
ENTER_CRITICAL_SECTION(ppmutexOpenSSL[i]);
|
2012-05-11 17:00:03 +02:00
|
|
|
} else {
|
2017-04-03 12:05:43 +02:00
|
|
|
LEAVE_CRITICAL_SECTION(ppmutexOpenSSL[i]);
|
2012-05-11 17:00:03 +02:00
|
|
|
}
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
|
2017-04-03 12:05:43 +02:00
|
|
|
// Singleton for wrapping OpenSSL setup/teardown.
|
2011-05-14 17:25:05 +02:00
|
|
|
class CInit
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CInit()
|
|
|
|
{
|
2012-07-21 12:44:54 +02:00
|
|
|
// Init OpenSSL library multithreading support
|
2017-04-03 12:05:43 +02:00
|
|
|
ppmutexOpenSSL.reset(new CCriticalSection[CRYPTO_num_locks()]);
|
2011-05-14 17:25:05 +02:00
|
|
|
CRYPTO_set_locking_callback(locking_callback);
|
|
|
|
|
2015-07-14 23:38:03 +02:00
|
|
|
// 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();
|
|
|
|
|
2011-10-07 17:02:21 +02:00
|
|
|
#ifdef WIN32
|
2014-06-24 14:41:26 +02:00
|
|
|
// Seed OpenSSL PRNG with current contents of the screen
|
2011-05-14 17:25:05 +02:00
|
|
|
RAND_screen();
|
|
|
|
#endif
|
|
|
|
|
2014-06-24 14:41:26 +02:00
|
|
|
// Seed OpenSSL PRNG with performance counter
|
2011-05-14 17:25:05 +02:00
|
|
|
RandAddSeed();
|
|
|
|
}
|
|
|
|
~CInit()
|
|
|
|
{
|
2014-06-24 14:41:26 +02:00
|
|
|
// Securely erase the memory used by the PRNG
|
|
|
|
RAND_cleanup();
|
2012-07-21 12:44:54 +02:00
|
|
|
// Shutdown OpenSSL library multithreading support
|
2011-05-14 17:25:05 +02:00
|
|
|
CRYPTO_set_locking_callback(NULL);
|
2017-04-03 12:05:43 +02:00
|
|
|
// Clear the set of locks now to maintain symmetry with the constructor.
|
|
|
|
ppmutexOpenSSL.reset();
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
instance_of_cinit;
|
|
|
|
|
2014-11-17 04:04:01 +01:00
|
|
|
/**
|
|
|
|
* LogPrintf() has been broken a couple of times now
|
|
|
|
* by well-meaning people adding mutexes in the most straightforward way.
|
|
|
|
* It breaks because it may be called by global destructors during shutdown.
|
|
|
|
* Since the order of destruction of static/global objects is undefined,
|
|
|
|
* defining a mutex as a global object doesn't work (the mutex gets
|
|
|
|
* destroyed, and then some later destructor calls OutputDebugStringF,
|
|
|
|
* maybe indirectly, and you get a core dump at shutdown trying to lock
|
|
|
|
* the mutex).
|
|
|
|
*/
|
2011-05-14 17:25:05 +02:00
|
|
|
|
2013-01-01 23:12:30 +01:00
|
|
|
static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
|
2015-05-15 21:31:14 +02:00
|
|
|
|
2014-11-17 04:04:01 +01:00
|
|
|
/**
|
2015-05-15 21:31:14 +02:00
|
|
|
* We use boost::call_once() to make sure mutexDebugLog and
|
|
|
|
* vMsgsBeforeOpenLog are initialized in a thread-safe manner.
|
|
|
|
*
|
|
|
|
* NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
|
|
|
|
* are leaked on exit. This is ugly, but will be cleaned up by
|
|
|
|
* the OS/libc. When the shutdown sequence is fully audited and
|
|
|
|
* tested, explicit destruction of these objects can be implemented.
|
2014-11-17 04:04:01 +01:00
|
|
|
*/
|
2013-01-01 23:12:30 +01:00
|
|
|
static FILE* fileout = NULL;
|
|
|
|
static boost::mutex* mutexDebugLog = NULL;
|
2017-03-09 08:10:09 +01:00
|
|
|
static std::list<std::string>* vMsgsBeforeOpenLog;
|
2015-05-15 21:31:14 +02:00
|
|
|
|
|
|
|
static int FileWriteStr(const std::string &str, FILE *fp)
|
|
|
|
{
|
|
|
|
return fwrite(str.data(), 1, str.size(), fp);
|
|
|
|
}
|
2013-01-01 23:12:30 +01:00
|
|
|
|
|
|
|
static void DebugPrintInit()
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2013-01-01 23:12:30 +01:00
|
|
|
assert(mutexDebugLog == NULL);
|
2015-05-15 21:31:14 +02:00
|
|
|
mutexDebugLog = new boost::mutex();
|
2017-03-09 08:10:09 +01:00
|
|
|
vMsgsBeforeOpenLog = new std::list<std::string>;
|
2015-05-15 21:31:14 +02:00
|
|
|
}
|
2013-01-01 23:12:30 +01:00
|
|
|
|
2015-05-15 21:31:14 +02:00
|
|
|
void OpenDebugLog()
|
|
|
|
{
|
|
|
|
boost::call_once(&DebugPrintInit, debugPrintInitFlag);
|
|
|
|
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
|
2013-01-01 23:12:30 +01:00
|
|
|
|
2015-05-15 21:31:14 +02:00
|
|
|
assert(fileout == NULL);
|
|
|
|
assert(vMsgsBeforeOpenLog);
|
2017-04-06 20:19:21 +02:00
|
|
|
fs::path pathDebug = GetDataDir() / "debug.log";
|
|
|
|
fileout = fsbridge::fopen(pathDebug, "a");
|
2017-02-21 14:32:44 +01:00
|
|
|
if (fileout) {
|
|
|
|
setbuf(fileout, NULL); // unbuffered
|
|
|
|
// dump buffered messages from before we opened the log
|
|
|
|
while (!vMsgsBeforeOpenLog->empty()) {
|
|
|
|
FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
|
|
|
|
vMsgsBeforeOpenLog->pop_front();
|
|
|
|
}
|
2015-05-15 21:31:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
delete vMsgsBeforeOpenLog;
|
|
|
|
vMsgsBeforeOpenLog = NULL;
|
2013-01-01 23:12:30 +01:00
|
|
|
}
|
|
|
|
|
2019-05-22 23:51:39 +02:00
|
|
|
struct CLogCategoryDesc
|
2013-01-01 23:12:30 +01:00
|
|
|
{
|
2019-05-22 23:51:39 +02:00
|
|
|
uint64_t flag;
|
|
|
|
std::string category;
|
|
|
|
};
|
2016-03-14 23:56:55 +01:00
|
|
|
|
2019-05-22 23:51:39 +02:00
|
|
|
const CLogCategoryDesc LogCategories[] =
|
|
|
|
{
|
|
|
|
{BCLog::NONE, "0"},
|
|
|
|
{BCLog::NET, "net"},
|
|
|
|
{BCLog::TOR, "tor"},
|
|
|
|
{BCLog::MEMPOOL, "mempool"},
|
|
|
|
{BCLog::HTTP, "http"},
|
|
|
|
{BCLog::BENCHMARK, "bench"},
|
|
|
|
{BCLog::ZMQ, "zmq"},
|
|
|
|
{BCLog::DB, "db"},
|
|
|
|
{BCLog::RPC, "rpc"},
|
|
|
|
{BCLog::ESTIMATEFEE, "estimatefee"},
|
|
|
|
{BCLog::ADDRMAN, "addrman"},
|
|
|
|
{BCLog::SELECTCOINS, "selectcoins"},
|
|
|
|
{BCLog::REINDEX, "reindex"},
|
|
|
|
{BCLog::CMPCTBLOCK, "cmpctblock"},
|
|
|
|
{BCLog::RANDOM, "rand"},
|
|
|
|
{BCLog::PRUNE, "prune"},
|
|
|
|
{BCLog::PROXY, "proxy"},
|
|
|
|
{BCLog::MEMPOOLREJ, "mempoolrej"},
|
|
|
|
{BCLog::LIBEVENT, "libevent"},
|
|
|
|
{BCLog::COINDB, "coindb"},
|
|
|
|
{BCLog::QT, "qt"},
|
|
|
|
{BCLog::LEVELDB, "leveldb"},
|
|
|
|
{BCLog::ALL, "1"},
|
|
|
|
{BCLog::ALL, "all"},
|
|
|
|
|
|
|
|
//Start Dash
|
|
|
|
{BCLog::CHAINLOCKS, "chainlocks"},
|
|
|
|
{BCLog::GOBJECT, "gobject"},
|
|
|
|
{BCLog::INSTANTSEND, "instantsend"},
|
|
|
|
{BCLog::KEEPASS, "keepass"},
|
|
|
|
{BCLog::LLMQ, "llmq"},
|
|
|
|
{BCLog::LLMQ_DKG, "llmq-dkg"},
|
|
|
|
{BCLog::LLMQ_SIGS, "llmq-sigs"},
|
|
|
|
{BCLog::MNPAYMENTS, "mnpayments"},
|
|
|
|
{BCLog::MNSYNC, "mnsync"},
|
|
|
|
{BCLog::PRIVATESEND, "privatesend"},
|
|
|
|
{BCLog::SPORK, "spork"},
|
|
|
|
{BCLog::ALERT, "alert"},
|
|
|
|
//End Dash
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
bool GetLogCategory(uint64_t *f, const std::string *str)
|
|
|
|
{
|
|
|
|
if (f && str) {
|
|
|
|
if (*str == "") {
|
|
|
|
*f = BCLog::ALL;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (*str == "dash") {
|
|
|
|
*f = BCLog::CHAINLOCKS
|
|
|
|
| BCLog::GOBJECT
|
|
|
|
| BCLog::INSTANTSEND
|
|
|
|
| BCLog::KEEPASS
|
|
|
|
| BCLog::LLMQ
|
|
|
|
| BCLog::LLMQ_DKG
|
|
|
|
| BCLog::LLMQ_SIGS
|
|
|
|
| BCLog::MNPAYMENTS
|
|
|
|
| BCLog::MNSYNC
|
|
|
|
| BCLog::PRIVATESEND
|
|
|
|
| BCLog::SPORK;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
|
|
|
|
if (LogCategories[i].category == *str) {
|
|
|
|
*f = LogCategories[i].flag;
|
|
|
|
return true;
|
2015-08-03 22:23:30 +02:00
|
|
|
}
|
2013-10-08 12:09:40 +02:00
|
|
|
}
|
2019-05-22 23:51:39 +02:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-12-10 04:19:18 +01:00
|
|
|
|
2019-05-22 23:51:39 +02:00
|
|
|
std::string ListLogCategories()
|
|
|
|
{
|
|
|
|
std::string ret;
|
|
|
|
int outcount = 0;
|
|
|
|
for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
|
|
|
|
// Omit the special cases.
|
|
|
|
if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
|
|
|
|
if (outcount != 0) ret += ", ";
|
|
|
|
ret += LogCategories[i].category;
|
|
|
|
outcount++;
|
|
|
|
}
|
2013-09-18 10:03:21 +02:00
|
|
|
}
|
2019-05-22 23:51:39 +02:00
|
|
|
return ret;
|
2014-01-16 15:52:37 +01:00
|
|
|
}
|
2013-09-18 10:03:21 +02:00
|
|
|
|
2017-04-12 17:48:58 +02:00
|
|
|
std::vector<CLogCategoryActive> ListActiveLogCategories()
|
|
|
|
{
|
|
|
|
std::vector<CLogCategoryActive> ret;
|
|
|
|
for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
|
|
|
|
// Omit the special cases.
|
|
|
|
if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
|
|
|
|
CLogCategoryActive catActive;
|
|
|
|
catActive.category = LogCategories[i].category;
|
|
|
|
catActive.active = LogAcceptCategory(LogCategories[i].flag);
|
|
|
|
ret.push_back(catActive);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string ListActiveLogCategoriesString()
|
2019-03-25 16:32:21 +01:00
|
|
|
{
|
2019-05-22 23:51:39 +02:00
|
|
|
if (logCategories == BCLog::NONE)
|
|
|
|
return "0";
|
|
|
|
if (logCategories == BCLog::ALL)
|
|
|
|
return "1";
|
|
|
|
|
|
|
|
std::string ret;
|
|
|
|
int outcount = 0;
|
|
|
|
for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
|
|
|
|
// Omit the special cases.
|
|
|
|
if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL && LogAcceptCategory(LogCategories[i].flag)) {
|
|
|
|
if (outcount != 0) ret += ", ";
|
|
|
|
ret += LogCategories[i].category;
|
|
|
|
outcount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
2019-03-25 16:32:21 +01:00
|
|
|
}
|
|
|
|
|
2015-05-15 21:31:14 +02:00
|
|
|
/**
|
|
|
|
* fStartedNewLine is a state variable held by the calling context that will
|
|
|
|
* suppress printing of the timestamp when multiple calls are made that don't
|
2016-03-25 00:15:03 +01:00
|
|
|
* end in a newline. Initialize it to true, and hold/manage it, in the calling context.
|
2015-05-15 21:31:14 +02:00
|
|
|
*/
|
2016-12-01 11:47:39 +01:00
|
|
|
static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)
|
2015-05-15 21:31:14 +02:00
|
|
|
{
|
2017-03-09 08:10:09 +01:00
|
|
|
std::string strStamped;
|
2015-05-15 21:31:14 +02:00
|
|
|
|
|
|
|
if (!fLogTimestamps)
|
|
|
|
return str;
|
|
|
|
|
2015-10-23 19:07:36 +02:00
|
|
|
if (*fStartedNewLine) {
|
2019-01-03 10:21:19 +01:00
|
|
|
if (IsMockTime()) {
|
|
|
|
int64_t nRealTimeMicros = GetTimeMicros();
|
|
|
|
strStamped = DateTimeStrFormat("(real %Y-%m-%d %H:%M:%S) ", nRealTimeMicros/1000000);
|
|
|
|
}
|
2015-10-23 19:07:36 +02:00
|
|
|
int64_t nTimeMicros = GetLogTimeMicros();
|
2019-01-03 10:21:19 +01:00
|
|
|
strStamped += DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros/1000000);
|
2015-10-23 19:07:36 +02:00
|
|
|
if (fLogTimeMicros)
|
|
|
|
strStamped += strprintf(".%06d", nTimeMicros%1000000);
|
|
|
|
strStamped += ' ' + str;
|
|
|
|
} else
|
2015-05-15 21:31:14 +02:00
|
|
|
strStamped = str;
|
|
|
|
|
|
|
|
return strStamped;
|
|
|
|
}
|
|
|
|
|
2016-03-14 22:04:48 +01:00
|
|
|
/**
|
|
|
|
* fStartedNewLine is a state variable held by the calling context that will
|
|
|
|
* suppress printing of the thread name when multiple calls are made that don't
|
2016-03-25 00:15:03 +01:00
|
|
|
* end in a newline. Initialize it to true, and hold/manage it, in the calling context.
|
2016-03-14 22:04:48 +01:00
|
|
|
*/
|
2016-12-01 11:47:39 +01:00
|
|
|
static std::string LogThreadNameStr(const std::string &str, std::atomic_bool *fStartedNewLine)
|
2016-03-14 22:04:48 +01:00
|
|
|
{
|
2017-03-09 08:10:09 +01:00
|
|
|
std::string strThreadLogged;
|
2016-03-14 22:04:48 +01:00
|
|
|
|
|
|
|
if (!fLogThreadNames)
|
|
|
|
return str;
|
|
|
|
|
|
|
|
std::string strThreadName = GetThreadName();
|
|
|
|
|
|
|
|
if (*fStartedNewLine)
|
|
|
|
strThreadLogged = strprintf("%16s | %s", strThreadName.c_str(), str.c_str());
|
|
|
|
else
|
|
|
|
strThreadLogged = str;
|
|
|
|
|
|
|
|
return strThreadLogged;
|
|
|
|
}
|
|
|
|
|
2014-01-16 15:52:37 +01:00
|
|
|
int LogPrintStr(const std::string &str)
|
|
|
|
{
|
2013-01-01 23:12:30 +01:00
|
|
|
int ret = 0; // Returns total number of characters written
|
2016-12-01 11:47:39 +01:00
|
|
|
static std::atomic_bool fStartedNewLine(true);
|
2015-09-30 17:57:28 +02:00
|
|
|
|
2016-03-14 22:04:48 +01:00
|
|
|
std::string strThreadLogged = LogThreadNameStr(str, &fStartedNewLine);
|
|
|
|
std::string strTimestamped = LogTimestampStr(strThreadLogged, &fStartedNewLine);
|
2015-09-30 17:57:28 +02:00
|
|
|
|
2016-03-25 00:15:03 +01:00
|
|
|
if (!str.empty() && str[str.size()-1] == '\n')
|
|
|
|
fStartedNewLine = true;
|
|
|
|
else
|
|
|
|
fStartedNewLine = false;
|
|
|
|
|
2011-05-14 17:25:05 +02:00
|
|
|
if (fPrintToConsole)
|
|
|
|
{
|
|
|
|
// print to console
|
2015-09-30 17:57:28 +02:00
|
|
|
ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout);
|
2014-09-10 18:26:59 +02:00
|
|
|
fflush(stdout);
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
2015-05-15 21:31:14 +02:00
|
|
|
else if (fPrintToDebugLog)
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2013-01-01 23:12:30 +01:00
|
|
|
boost::call_once(&DebugPrintInit, debugPrintInitFlag);
|
|
|
|
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
|
|
|
|
|
2015-05-15 21:31:14 +02:00
|
|
|
// buffer if we haven't opened the log yet
|
|
|
|
if (fileout == NULL) {
|
|
|
|
assert(vMsgsBeforeOpenLog);
|
|
|
|
ret = strTimestamped.length();
|
|
|
|
vMsgsBeforeOpenLog->push_back(strTimestamped);
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
2013-01-01 23:12:30 +01:00
|
|
|
else
|
2015-05-15 21:31:14 +02:00
|
|
|
{
|
|
|
|
// reopen the log file, if requested
|
|
|
|
if (fReopenDebugLog) {
|
|
|
|
fReopenDebugLog = false;
|
2017-04-06 20:19:21 +02:00
|
|
|
fs::path pathDebug = GetDataDir() / "debug.log";
|
|
|
|
if (fsbridge::freopen(pathDebug,"a",fileout) != NULL)
|
2015-05-15 21:31:14 +02:00
|
|
|
setbuf(fileout, NULL); // unbuffered
|
|
|
|
}
|
2011-05-14 17:25:05 +02:00
|
|
|
|
2015-05-15 21:31:14 +02:00
|
|
|
ret = FileWriteStr(strTimestamped, fileout);
|
|
|
|
}
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-06-15 17:17:23 +02:00
|
|
|
/** Interpret string as boolean, for argument parsing */
|
|
|
|
static bool InterpretBool(const std::string& strValue)
|
2012-02-16 21:08:32 +01:00
|
|
|
{
|
2015-06-15 17:17:23 +02:00
|
|
|
if (strValue.empty())
|
|
|
|
return true;
|
|
|
|
return (atoi(strValue) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Turn -noX into -X=0 */
|
|
|
|
static void InterpretNegativeSetting(std::string& strKey, std::string& strValue)
|
2012-02-16 21:08:32 +01:00
|
|
|
{
|
2015-06-15 17:17:23 +02:00
|
|
|
if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o')
|
2012-02-16 21:08:32 +01:00
|
|
|
{
|
2015-06-15 17:17:23 +02:00
|
|
|
strKey = "-" + strKey.substr(3);
|
|
|
|
strValue = InterpretBool(strValue) ? "0" : "1";
|
2012-02-16 21:08:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-22 16:22:45 +02:00
|
|
|
void ParseParameters(int argc, const char* const argv[])
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2016-12-27 19:11:21 +01:00
|
|
|
LOCK(cs_args);
|
2011-05-14 17:25:05 +02:00
|
|
|
mapArgs.clear();
|
2016-12-27 19:11:21 +01:00
|
|
|
_mapMultiArgs.clear();
|
2014-06-04 06:36:45 +02:00
|
|
|
|
2011-05-14 17:25:05 +02:00
|
|
|
for (int i = 1; i < argc; i++)
|
|
|
|
{
|
2012-10-02 21:36:39 +02:00
|
|
|
std::string str(argv[i]);
|
|
|
|
std::string strValue;
|
|
|
|
size_t is_index = str.find('=');
|
|
|
|
if (is_index != std::string::npos)
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2012-10-02 21:36:39 +02:00
|
|
|
strValue = str.substr(is_index+1);
|
|
|
|
str = str.substr(0, is_index);
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
2012-10-02 21:36:39 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
boost::to_lower(str);
|
|
|
|
if (boost::algorithm::starts_with(str, "/"))
|
|
|
|
str = "-" + str.substr(1);
|
|
|
|
#endif
|
2014-06-04 06:36:45 +02:00
|
|
|
|
2012-10-02 21:36:39 +02:00
|
|
|
if (str[0] != '-')
|
2011-05-14 17:25:05 +02:00
|
|
|
break;
|
2012-02-06 19:55:11 +01:00
|
|
|
|
2014-06-04 06:36:45 +02:00
|
|
|
// Interpret --foo as -foo.
|
|
|
|
// If both --foo and -foo are set, the last takes effect.
|
|
|
|
if (str.length() > 1 && str[1] == '-')
|
|
|
|
str = str.substr(1);
|
2015-06-15 17:17:23 +02:00
|
|
|
InterpretNegativeSetting(str, strValue);
|
2014-06-04 06:36:45 +02:00
|
|
|
|
2012-10-02 21:36:39 +02:00
|
|
|
mapArgs[str] = strValue;
|
2016-12-27 19:11:21 +01:00
|
|
|
_mapMultiArgs[str].push_back(strValue);
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-27 19:11:21 +01:00
|
|
|
bool IsArgSet(const std::string& strArg)
|
|
|
|
{
|
|
|
|
LOCK(cs_args);
|
|
|
|
return mapArgs.count(strArg);
|
|
|
|
}
|
|
|
|
|
2012-02-06 18:37:49 +01:00
|
|
|
std::string GetArg(const std::string& strArg, const std::string& strDefault)
|
|
|
|
{
|
2016-12-27 19:11:21 +01:00
|
|
|
LOCK(cs_args);
|
2012-02-06 18:37:49 +01:00
|
|
|
if (mapArgs.count(strArg))
|
|
|
|
return mapArgs[strArg];
|
|
|
|
return strDefault;
|
|
|
|
}
|
|
|
|
|
2013-04-13 07:13:08 +02:00
|
|
|
int64_t GetArg(const std::string& strArg, int64_t nDefault)
|
2012-02-06 18:37:49 +01:00
|
|
|
{
|
2016-12-27 19:11:21 +01:00
|
|
|
LOCK(cs_args);
|
2012-02-06 18:37:49 +01:00
|
|
|
if (mapArgs.count(strArg))
|
|
|
|
return atoi64(mapArgs[strArg]);
|
|
|
|
return nDefault;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GetBoolArg(const std::string& strArg, bool fDefault)
|
|
|
|
{
|
2016-12-27 19:11:21 +01:00
|
|
|
LOCK(cs_args);
|
2012-02-06 18:37:49 +01:00
|
|
|
if (mapArgs.count(strArg))
|
2015-06-15 17:17:23 +02:00
|
|
|
return InterpretBool(mapArgs[strArg]);
|
2012-02-06 18:37:49 +01:00
|
|
|
return fDefault;
|
|
|
|
}
|
|
|
|
|
2012-01-03 16:14:22 +01:00
|
|
|
bool SoftSetArg(const std::string& strArg, const std::string& strValue)
|
|
|
|
{
|
2016-12-27 19:11:21 +01:00
|
|
|
LOCK(cs_args);
|
2012-01-03 16:14:22 +01:00
|
|
|
if (mapArgs.count(strArg))
|
|
|
|
return false;
|
|
|
|
mapArgs[strArg] = strValue;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-02-06 21:48:00 +01:00
|
|
|
bool SoftSetBoolArg(const std::string& strArg, bool fValue)
|
2012-01-03 16:14:22 +01:00
|
|
|
{
|
|
|
|
if (fValue)
|
|
|
|
return SoftSetArg(strArg, std::string("1"));
|
|
|
|
else
|
|
|
|
return SoftSetArg(strArg, std::string("0"));
|
|
|
|
}
|
|
|
|
|
2016-12-27 19:11:21 +01:00
|
|
|
void ForceSetArg(const std::string& strArg, const std::string& strValue)
|
|
|
|
{
|
|
|
|
LOCK(cs_args);
|
|
|
|
mapArgs[strArg] = strValue;
|
|
|
|
}
|
|
|
|
|
2017-09-21 01:18:39 +02:00
|
|
|
void ForceSetMultiArgs(const std::string& strArg, const std::vector<std::string>& values)
|
|
|
|
{
|
|
|
|
LOCK(cs_args);
|
|
|
|
_mapMultiArgs[strArg] = values;
|
|
|
|
}
|
2016-12-27 19:11:21 +01:00
|
|
|
|
|
|
|
void ForceRemoveArg(const std::string& strArg)
|
|
|
|
{
|
|
|
|
LOCK(cs_args);
|
|
|
|
mapArgs.erase(strArg);
|
|
|
|
_mapMultiArgs.erase(strArg);
|
|
|
|
}
|
|
|
|
|
2015-02-04 09:11:49 +01:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2019-02-21 19:37:16 +01:00
|
|
|
static std::string FormatException(const std::exception_ptr pex, const char* pszThread)
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2019-02-21 19:37:16 +01:00
|
|
|
return strprintf("EXCEPTION: %s", GetPrettyExceptionStr(pex));
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
|
2019-02-21 19:37:16 +01:00
|
|
|
void PrintExceptionContinue(const std::exception_ptr pex, const char* pszThread)
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2012-05-14 19:53:02 +02:00
|
|
|
std::string message = FormatException(pex, pszThread);
|
2014-01-16 16:15:27 +01:00
|
|
|
LogPrintf("\n\n************************\n%s\n", message);
|
2012-05-14 19:53:02 +02:00
|
|
|
fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
|
2017-04-06 20:19:21 +02:00
|
|
|
fs::path GetDefaultDataDir()
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2016-07-06 20:44:33 +02:00
|
|
|
// Windows < Vista: C:\Documents and Settings\Username\Application Data\DashCore
|
|
|
|
// Windows >= Vista: C:\Users\Username\AppData\Roaming\DashCore
|
|
|
|
// Mac: ~/Library/Application Support/DashCore
|
|
|
|
// Unix: ~/.dashcore
|
2011-10-07 17:02:21 +02:00
|
|
|
#ifdef WIN32
|
2011-05-14 17:25:05 +02:00
|
|
|
// Windows
|
2016-07-06 20:44:33 +02:00
|
|
|
return GetSpecialFolderPath(CSIDL_APPDATA) / "DashCore";
|
2011-05-14 17:25:05 +02:00
|
|
|
#else
|
2012-04-09 23:50:56 +02:00
|
|
|
fs::path pathRet;
|
2011-05-14 17:25:05 +02:00
|
|
|
char* pszHome = getenv("HOME");
|
|
|
|
if (pszHome == NULL || strlen(pszHome) == 0)
|
2012-04-09 23:50:56 +02:00
|
|
|
pathRet = fs::path("/");
|
|
|
|
else
|
|
|
|
pathRet = fs::path(pszHome);
|
2011-10-07 17:02:21 +02:00
|
|
|
#ifdef MAC_OSX
|
2011-05-14 17:25:05 +02:00
|
|
|
// Mac
|
2016-08-26 03:00:27 +02:00
|
|
|
return pathRet / "Library/Application Support/DashCore";
|
2011-05-14 17:25:05 +02:00
|
|
|
#else
|
|
|
|
// Unix
|
2016-07-06 20:44:33 +02:00
|
|
|
return pathRet / ".dashcore";
|
2011-05-14 17:25:05 +02:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-04-06 20:19:21 +02:00
|
|
|
static fs::path pathCached;
|
|
|
|
static fs::path pathCachedNetSpecific;
|
2013-07-17 04:20:09 +02:00
|
|
|
static CCriticalSection csPathCached;
|
|
|
|
|
2017-04-06 20:19:21 +02:00
|
|
|
const fs::path &GetDataDir(bool fNetSpecific)
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2012-04-09 23:50:56 +02:00
|
|
|
|
2013-07-17 04:20:09 +02:00
|
|
|
LOCK(csPathCached);
|
|
|
|
|
2014-10-11 20:56:27 +02:00
|
|
|
fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
|
2012-04-09 23:50:56 +02:00
|
|
|
|
2013-09-19 14:47:21 +02:00
|
|
|
// This can be called during exceptions by LogPrintf(), so we cache the
|
2012-04-09 23:50:56 +02:00
|
|
|
// value so we don't have to do memory allocations after that.
|
2013-07-17 04:20:09 +02:00
|
|
|
if (!path.empty())
|
2012-04-09 23:50:56 +02:00
|
|
|
return path;
|
|
|
|
|
2016-12-27 19:11:21 +01:00
|
|
|
if (IsArgSet("-datadir")) {
|
|
|
|
path = fs::system_complete(GetArg("-datadir", ""));
|
2012-04-22 14:35:22 +02:00
|
|
|
if (!fs::is_directory(path)) {
|
|
|
|
path = "";
|
|
|
|
return path;
|
|
|
|
}
|
2012-04-09 23:50:56 +02:00
|
|
|
} else {
|
|
|
|
path = GetDefaultDataDir();
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
2013-05-07 15:16:25 +02:00
|
|
|
if (fNetSpecific)
|
2014-06-19 15:10:04 +02:00
|
|
|
path /= BaseParams().DataDir();
|
2011-05-14 17:25:05 +02:00
|
|
|
|
2013-06-08 10:03:23 +02:00
|
|
|
fs::create_directories(path);
|
2012-04-09 23:50:56 +02:00
|
|
|
|
|
|
|
return path;
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
|
2019-05-24 14:53:24 +02:00
|
|
|
fs::path GetBackupsDir()
|
2016-06-15 21:13:04 +02:00
|
|
|
{
|
2018-01-18 17:55:51 +01:00
|
|
|
if (!IsArgSet("-walletbackupsdir"))
|
|
|
|
return GetDataDir() / "backups";
|
2016-06-15 21:13:04 +02:00
|
|
|
|
2018-01-18 17:55:51 +01:00
|
|
|
return fs::absolute(GetArg("-walletbackupsdir", ""));
|
2016-06-15 21:13:04 +02:00
|
|
|
}
|
|
|
|
|
2013-07-17 04:20:09 +02:00
|
|
|
void ClearDatadirCache()
|
|
|
|
{
|
2016-12-27 19:11:21 +01:00
|
|
|
LOCK(csPathCached);
|
|
|
|
|
2017-04-06 20:19:21 +02:00
|
|
|
pathCached = fs::path();
|
|
|
|
pathCachedNetSpecific = fs::path();
|
2013-07-17 04:20:09 +02:00
|
|
|
}
|
|
|
|
|
2017-04-06 20:19:21 +02:00
|
|
|
fs::path GetConfigFile(const std::string& confPath)
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2017-04-06 20:19:21 +02:00
|
|
|
fs::path pathConfigFile(confPath);
|
2014-05-10 14:54:20 +02:00
|
|
|
if (!pathConfigFile.is_complete())
|
|
|
|
pathConfigFile = GetDataDir(false) / pathConfigFile;
|
|
|
|
|
2012-04-09 23:50:56 +02:00
|
|
|
return pathConfigFile;
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
|
2016-12-27 19:11:21 +01:00
|
|
|
void ReadConfigFile(const std::string& confPath)
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2017-04-06 20:19:21 +02:00
|
|
|
fs::ifstream streamConfig(GetConfigFile(confPath));
|
2015-03-28 14:22:57 +01:00
|
|
|
if (!streamConfig.good()){
|
|
|
|
// Create empty dash.conf if it does not excist
|
2016-10-03 13:16:40 +02:00
|
|
|
FILE* configFile = fopen(GetConfigFile(confPath).string().c_str(), "a");
|
2015-03-28 14:22:57 +01:00
|
|
|
if (configFile != NULL)
|
|
|
|
fclose(configFile);
|
|
|
|
return; // Nothing to read, so just return
|
|
|
|
}
|
2011-05-14 17:25:05 +02:00
|
|
|
|
|
|
|
{
|
2016-12-27 19:11:21 +01:00
|
|
|
LOCK(cs_args);
|
2017-03-09 08:10:09 +01:00
|
|
|
std::set<std::string> setOptions;
|
2016-12-27 19:11:21 +01:00
|
|
|
setOptions.insert("*");
|
|
|
|
|
|
|
|
for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
|
|
|
|
{
|
|
|
|
// Don't overwrite existing settings so command line settings override dash.conf
|
2017-03-09 08:10:09 +01:00
|
|
|
std::string strKey = std::string("-") + it->string_key;
|
|
|
|
std::string strValue = it->value[0];
|
2016-12-27 19:11:21 +01:00
|
|
|
InterpretNegativeSetting(strKey, strValue);
|
|
|
|
if (mapArgs.count(strKey) == 0)
|
|
|
|
mapArgs[strKey] = strValue;
|
|
|
|
_mapMultiArgs[strKey].push_back(strValue);
|
|
|
|
}
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
2013-07-17 04:20:09 +02:00
|
|
|
// If datadir is changed in .conf file:
|
|
|
|
ClearDatadirCache();
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
|
2014-09-20 10:56:25 +02:00
|
|
|
#ifndef WIN32
|
2017-04-06 20:19:21 +02:00
|
|
|
fs::path GetPidFile()
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2017-04-06 20:19:21 +02:00
|
|
|
fs::path pathPidFile(GetArg("-pid", BITCOIN_PID_FILENAME));
|
2012-04-09 23:50:56 +02:00
|
|
|
if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
|
|
|
|
return pathPidFile;
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
|
2017-04-06 20:19:21 +02:00
|
|
|
void CreatePidFile(const fs::path &path, pid_t pid)
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2017-04-06 20:19:21 +02:00
|
|
|
FILE* file = fsbridge::fopen(path, "w");
|
2011-06-24 20:03:16 +02:00
|
|
|
if (file)
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
|
|
|
fprintf(file, "%d\n", pid);
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
}
|
2013-07-24 09:30:09 +02:00
|
|
|
#endif
|
2011-05-14 17:25:05 +02:00
|
|
|
|
2017-04-06 20:19:21 +02:00
|
|
|
bool RenameOver(fs::path src, fs::path dest)
|
2012-05-12 07:24:27 +02:00
|
|
|
{
|
|
|
|
#ifdef WIN32
|
2012-05-17 18:30:09 +02:00
|
|
|
return MoveFileExA(src.string().c_str(), dest.string().c_str(),
|
2014-09-06 21:59:59 +02:00
|
|
|
MOVEFILE_REPLACE_EXISTING) != 0;
|
2012-05-12 07:24:27 +02:00
|
|
|
#else
|
|
|
|
int rc = std::rename(src.string().c_str(), dest.string().c_str());
|
|
|
|
return (rc == 0);
|
|
|
|
#endif /* WIN32 */
|
|
|
|
}
|
|
|
|
|
2014-11-17 04:04:01 +01:00
|
|
|
/**
|
|
|
|
* Ignores exceptions thrown by Boost's create_directory 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.
|
|
|
|
*/
|
2017-04-06 20:19:21 +02:00
|
|
|
bool TryCreateDirectory(const fs::path& p)
|
2014-03-24 02:14:43 +01:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2017-04-06 20:19:21 +02:00
|
|
|
return fs::create_directory(p);
|
|
|
|
} catch (const fs::filesystem_error&) {
|
|
|
|
if (!fs::exists(p) || !fs::is_directory(p))
|
2014-03-24 02:14:43 +01:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create_directory didn't create the directory, it had to have existed already
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-21 14:13:33 +02:00
|
|
|
void FileCommit(FILE *file)
|
2012-05-12 07:24:27 +02:00
|
|
|
{
|
2016-09-21 14:13:33 +02:00
|
|
|
fflush(file); // harmless if redundantly called
|
2012-05-12 07:24:27 +02:00
|
|
|
#ifdef WIN32
|
2016-09-21 14:13:33 +02:00
|
|
|
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
|
2013-12-20 15:55:01 +01:00
|
|
|
FlushFileBuffers(hFile);
|
2012-05-12 07:24:27 +02:00
|
|
|
#else
|
2012-09-28 14:27:20 +02:00
|
|
|
#if defined(__linux__) || defined(__NetBSD__)
|
2016-09-21 14:13:33 +02:00
|
|
|
fdatasync(fileno(file));
|
2013-09-16 05:14:06 +02:00
|
|
|
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
|
2016-09-21 14:13:33 +02:00
|
|
|
fcntl(fileno(file), F_FULLFSYNC, 0);
|
2012-09-28 14:27:20 +02:00
|
|
|
#else
|
2016-09-21 14:13:33 +02:00
|
|
|
fsync(fileno(file));
|
2012-09-28 14:27:20 +02:00
|
|
|
#endif
|
2012-05-12 07:24:27 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-01-30 04:17:33 +01:00
|
|
|
bool TruncateFile(FILE *file, unsigned int length) {
|
|
|
|
#if defined(WIN32)
|
|
|
|
return _chsize(_fileno(file), length) == 0;
|
|
|
|
#else
|
|
|
|
return ftruncate(fileno(file), length) == 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-11-17 04:04:01 +01:00
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
*/
|
2013-04-26 00:46:47 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
return nMinFD; // getrlimit failed, assume it's fine
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-11-17 04:04:01 +01:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2012-08-16 02:21:28 +02:00
|
|
|
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
|
2013-01-28 00:07:51 +01:00
|
|
|
#if defined(WIN32)
|
|
|
|
// Windows-specific version
|
|
|
|
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
|
|
|
|
LARGE_INTEGER nFileSize;
|
2013-04-13 07:13:08 +02:00
|
|
|
int64_t nEndPos = (int64_t)offset + length;
|
2013-01-28 00:07:51 +01:00
|
|
|
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
|
2012-08-16 02:21:28 +02:00
|
|
|
static const char buf[65536] = {};
|
|
|
|
fseek(file, offset, SEEK_SET);
|
|
|
|
while (length > 0) {
|
|
|
|
unsigned int now = 65536;
|
|
|
|
if (length < now)
|
|
|
|
now = length;
|
|
|
|
fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
|
|
|
|
length -= now;
|
|
|
|
}
|
2013-01-28 00:07:51 +01:00
|
|
|
#endif
|
2012-08-16 02:21:28 +02:00
|
|
|
}
|
|
|
|
|
2011-05-14 17:25:05 +02:00
|
|
|
void ShrinkDebugFile()
|
|
|
|
{
|
2017-05-31 05:49:22 +02:00
|
|
|
// Amount of debug.log to save at end when shrinking (must fit in memory)
|
|
|
|
constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
|
2011-05-14 17:25:05 +02:00
|
|
|
// Scroll debug.log if it's getting too big
|
2017-04-06 20:19:21 +02:00
|
|
|
fs::path pathLog = GetDataDir() / "debug.log";
|
|
|
|
FILE* file = fsbridge::fopen(pathLog, "r");
|
2017-05-31 05:49:22 +02:00
|
|
|
// If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
|
|
|
|
// trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
|
2017-04-06 20:19:21 +02:00
|
|
|
if (file && fs::file_size(pathLog) > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
|
|
|
// Restart the file with some of the end
|
2017-05-31 05:49:22 +02:00
|
|
|
std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
|
2014-09-02 23:36:45 +02:00
|
|
|
fseek(file, -((long)vch.size()), SEEK_END);
|
2016-12-13 12:20:26 +01:00
|
|
|
int nBytes = fread(vch.data(), 1, vch.size(), file);
|
2011-05-14 17:25:05 +02:00
|
|
|
fclose(file);
|
2011-06-24 20:03:16 +02:00
|
|
|
|
2017-04-06 20:19:21 +02:00
|
|
|
file = fsbridge::fopen(pathLog, "w");
|
2011-06-24 20:03:16 +02:00
|
|
|
if (file)
|
2011-05-14 17:25:05 +02:00
|
|
|
{
|
2016-12-13 12:20:26 +01:00
|
|
|
fwrite(vch.data(), 1, nBytes, file);
|
2011-05-14 17:25:05 +02:00
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
}
|
2013-04-28 17:37:50 +02:00
|
|
|
else if (file != NULL)
|
|
|
|
fclose(file);
|
2011-05-14 17:25:05 +02:00
|
|
|
}
|
|
|
|
|
2012-04-15 22:10:54 +02:00
|
|
|
#ifdef WIN32
|
2017-04-06 20:19:21 +02:00
|
|
|
fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
|
2012-04-22 16:22:45 +02:00
|
|
|
{
|
|
|
|
char pszPath[MAX_PATH] = "";
|
|
|
|
|
|
|
|
if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
|
|
|
|
{
|
|
|
|
return fs::path(pszPath);
|
|
|
|
}
|
|
|
|
|
2013-09-18 12:38:08 +02:00
|
|
|
LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n");
|
2012-04-22 16:22:45 +02:00
|
|
|
return fs::path("");
|
|
|
|
}
|
2012-04-15 22:10:54 +02:00
|
|
|
#endif
|
2012-05-24 05:10:59 +02:00
|
|
|
|
2015-05-31 15:36:44 +02:00
|
|
|
void runCommand(const std::string& strCommand)
|
2012-05-24 05:10:59 +02:00
|
|
|
{
|
|
|
|
int nErr = ::system(strCommand.c_str());
|
|
|
|
if (nErr)
|
2014-01-16 16:15:27 +01:00
|
|
|
LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
|
2012-05-24 05:10:59 +02:00
|
|
|
}
|
|
|
|
|
2012-06-24 17:03:57 +02:00
|
|
|
void RenameThread(const char* name)
|
|
|
|
{
|
2012-06-30 20:11:27 +02:00
|
|
|
#if defined(PR_SET_NAME)
|
2012-06-24 17:03:57 +02:00
|
|
|
// Only the first 15 characters are used (16 - NUL terminator)
|
|
|
|
::prctl(PR_SET_NAME, name, 0, 0, 0);
|
2015-04-29 15:04:34 +02:00
|
|
|
#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
|
2012-06-30 17:23:04 +02:00
|
|
|
pthread_set_name_np(pthread_self(), name);
|
2012-08-21 17:59:24 +02:00
|
|
|
|
2014-11-25 09:12:55 +01:00
|
|
|
#elif defined(MAC_OSX)
|
2013-03-07 04:16:05 +01:00
|
|
|
pthread_setname_np(name);
|
2012-06-24 17:03:57 +02:00
|
|
|
#else
|
|
|
|
// Prevent warnings for unused parameters...
|
|
|
|
(void)name;
|
|
|
|
#endif
|
2019-04-30 14:48:21 +02:00
|
|
|
LogPrintf("%s: thread new name %s\n", __func__, name);
|
2012-06-24 17:03:57 +02:00
|
|
|
}
|
2013-11-27 15:41:12 +01:00
|
|
|
|
2016-03-14 22:04:48 +01:00
|
|
|
std::string GetThreadName()
|
|
|
|
{
|
|
|
|
char name[16];
|
|
|
|
#if defined(PR_GET_NAME)
|
|
|
|
// Only the first 15 characters are used (16 - NUL terminator)
|
|
|
|
::prctl(PR_GET_NAME, name, 0, 0, 0);
|
|
|
|
#elif defined(MAC_OSX)
|
|
|
|
pthread_getname_np(pthread_self(), name, 16);
|
|
|
|
// #elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
|
|
|
|
// #else
|
|
|
|
// no get_name here
|
|
|
|
#endif
|
|
|
|
return std::string(name);
|
|
|
|
}
|
|
|
|
|
2018-05-24 13:57:36 +02:00
|
|
|
void RenameThreadPool(ctpl::thread_pool& tp, const char* baseName)
|
|
|
|
{
|
|
|
|
auto cond = std::make_shared<std::condition_variable>();
|
|
|
|
auto mutex = std::make_shared<std::mutex>();
|
|
|
|
std::atomic<int> doneCnt(0);
|
2019-02-01 08:49:31 +01:00
|
|
|
std::map<int, std::future<void> > futures;
|
|
|
|
|
|
|
|
for (int i = 0; i < tp.size(); i++) {
|
|
|
|
futures[i] = tp.push([baseName, i, cond, mutex, &doneCnt](int threadId) {
|
2018-05-24 13:57:36 +02:00
|
|
|
RenameThread(strprintf("%s-%d", baseName, i).c_str());
|
|
|
|
std::unique_lock<std::mutex> l(*mutex);
|
2019-02-01 08:49:31 +01:00
|
|
|
doneCnt++;
|
2018-05-24 13:57:36 +02:00
|
|
|
cond->wait(l);
|
|
|
|
});
|
|
|
|
}
|
2019-02-01 08:49:31 +01:00
|
|
|
|
|
|
|
do {
|
|
|
|
// Always sleep to let all threads acquire locks
|
2018-05-24 13:57:36 +02:00
|
|
|
MilliSleep(10);
|
2019-02-01 08:49:31 +01:00
|
|
|
// `doneCnt` should be at least `futures.size()` if tp size was increased (for whatever reason),
|
|
|
|
// or at least `tp.size()` if tp size was decreased and queue was cleared
|
|
|
|
// (which can happen on `stop()` if we were not fast enough to get all jobs to their threads).
|
|
|
|
} while (doneCnt < futures.size() && doneCnt < tp.size());
|
|
|
|
|
2018-05-24 13:57:36 +02:00
|
|
|
cond->notify_all();
|
2019-02-01 08:49:31 +01:00
|
|
|
|
|
|
|
// Make sure no one is left behind, just in case
|
|
|
|
for (auto& pair : futures) {
|
|
|
|
auto& f = pair.second;
|
|
|
|
if (f.valid() && f.wait_for(std::chrono::milliseconds(2000)) == std::future_status::timeout) {
|
|
|
|
LogPrintf("%s: %s-%d timed out\n", __func__, baseName, pair.first);
|
|
|
|
// Notify everyone again
|
|
|
|
cond->notify_all();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-05-24 13:57:36 +02:00
|
|
|
}
|
|
|
|
|
2014-05-13 12:15:00 +02:00
|
|
|
void SetupEnvironment()
|
|
|
|
{
|
2017-03-31 10:36:18 +02:00
|
|
|
#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
|
2015-03-11 13:34:20 +01:00
|
|
|
// 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 {
|
|
|
|
std::locale(""); // Raises a runtime error if current locale is invalid
|
|
|
|
} catch (const std::runtime_error&) {
|
2015-03-27 01:07:49 +01:00
|
|
|
setenv("LC_ALL", "C", 1);
|
2014-05-13 12:15:00 +02:00
|
|
|
}
|
2014-05-10 14:54:20 +02:00
|
|
|
#endif
|
2015-05-01 13:32:25 +02:00
|
|
|
// The path locale is lazy initialized and to avoid deinitialization errors
|
2015-03-11 13:34:20 +01:00
|
|
|
// in multithreading environments, it is set explicitly by the main thread.
|
2015-05-01 13:32:25 +02:00
|
|
|
// A dummy locale is used to extract the internal default locale, used by
|
2017-04-06 20:19:21 +02:00
|
|
|
// fs::path, which is then used to explicitly imbue the path.
|
|
|
|
std::locale loc = fs::path::imbue(std::locale::classic());
|
|
|
|
fs::path::imbue(loc);
|
2014-05-13 12:15:00 +02:00
|
|
|
}
|
2014-05-08 18:01:10 +02:00
|
|
|
|
2015-09-02 16:18:16 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-07-01 17:38:15 +02:00
|
|
|
int GetNumCores()
|
|
|
|
{
|
|
|
|
#if BOOST_VERSION >= 105600
|
|
|
|
return boost::thread::physical_concurrency();
|
|
|
|
#else // Must fall back to hardware_concurrency, which unfortunately counts virtual cores
|
|
|
|
return boost::thread::hardware_concurrency();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-12-11 15:20:11 +01:00
|
|
|
std::string CopyrightHolders(const std::string& strPrefix, unsigned int nStartYear, unsigned int nEndYear)
|
2016-02-04 13:41:58 +01:00
|
|
|
{
|
2016-08-31 16:14:43 +02:00
|
|
|
std::string strCopyrightHolders = strPrefix + strprintf(" %u-%u ", nStartYear, nEndYear) + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION));
|
|
|
|
|
|
|
|
// Check for untranslated substitution to make sure Bitcoin Core copyright is not removed by accident
|
|
|
|
if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Bitcoin Core") == std::string::npos) {
|
2017-12-11 15:20:11 +01:00
|
|
|
strCopyrightHolders += "\n" + strPrefix + strprintf(" %u-%u ", 2009, nEndYear) + "The Bitcoin Core developers";
|
2016-02-04 13:41:58 +01:00
|
|
|
}
|
|
|
|
return strCopyrightHolders;
|
|
|
|
}
|
2017-07-04 19:31:57 +02:00
|
|
|
|
|
|
|
uint32_t StringVersionToInt(const std::string& strVersion)
|
|
|
|
{
|
|
|
|
std::vector<std::string> tokens;
|
|
|
|
boost::split(tokens, strVersion, boost::is_any_of("."));
|
|
|
|
if(tokens.size() != 3)
|
|
|
|
throw std::bad_cast();
|
|
|
|
uint32_t nVersion = 0;
|
|
|
|
for(unsigned idx = 0; idx < 3; idx++)
|
|
|
|
{
|
|
|
|
if(tokens[idx].length() == 0)
|
|
|
|
throw std::bad_cast();
|
|
|
|
uint32_t value = boost::lexical_cast<uint32_t>(tokens[idx]);
|
|
|
|
if(value > 255)
|
|
|
|
throw std::bad_cast();
|
|
|
|
nVersion <<= 8;
|
|
|
|
nVersion |= value;
|
|
|
|
}
|
|
|
|
return nVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string IntVersionToString(uint32_t nVersion)
|
|
|
|
{
|
|
|
|
if((nVersion >> 24) > 0) // MSB is always 0
|
|
|
|
throw std::bad_cast();
|
|
|
|
if(nVersion == 0)
|
|
|
|
throw std::bad_cast();
|
|
|
|
std::array<std::string, 3> tokens;
|
|
|
|
for(unsigned idx = 0; idx < 3; idx++)
|
|
|
|
{
|
|
|
|
unsigned shift = (2 - idx) * 8;
|
|
|
|
uint32_t byteValue = (nVersion >> shift) & 0xff;
|
|
|
|
tokens[idx] = boost::lexical_cast<std::string>(byteValue);
|
|
|
|
}
|
|
|
|
return boost::join(tokens, ".");
|
|
|
|
}
|
2017-07-10 16:41:42 +02:00
|
|
|
|
|
|
|
std::string SafeIntVersionToString(uint32_t nVersion)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
return IntVersionToString(nVersion);
|
|
|
|
}
|
|
|
|
catch(const std::bad_cast&)
|
|
|
|
{
|
2017-07-17 16:38:32 +02:00
|
|
|
return "invalid_version";
|
2017-07-10 16:41:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|