dash/src/util.cpp

1102 lines
32 KiB
C++
Raw Normal View History

2011-05-14 17:25:05 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2014-2019 The Dash 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)
2015-04-03 00:51:08 +02:00
#include "config/dash-config.h"
#endif
#include "util.h"
#include "support/allocators/secure.h"
#include "chainparamsbase.h"
#include "ctpl.h"
#include "fs.h"
#include "random.h"
#include "serialize.h"
#include "stacktraces.h"
#include "utilstrencodings.h"
#include "utiltime.h"
#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
Implemented KeePass Integration More info regarding KeePass: http://keepass.info/ KeePass integration will use KeePassHttp (https://github.com/pfn/keepasshttp/) to facilitate communications between the client and KeePass. KeePassHttp is a plugin for KeePass 2.x and provides a secure means of exposing KeePass entries via HTTP for clients to consume. The implementation is dependent on the following: - crypter.h for AES encryption helper functions. - rpcprotocol.h for handling RPC communications. Could only be used partially however due some static values in the code. - OpenSSL for base64 encoding. regular util.h libraries were not used for base64 encoding/decoding since they do not use secure allocation. - JSON Spirit for reading / writing RPC communications The following changes were made: - Added CLI options in help - Added RPC commands: keepass <genkey|init|setpassphrase> - Added keepass.h and keepass.cpp which hold the integration routines - Modified rpcwallet.cpp to support RPC commands The following new options are available for darkcoind and darkcoin-qt: -keepass Use KeePass 2 integration using KeePassHttp plugin (default: 0) -keepassport=<port> Connect to KeePassHttp on port <port> (default: 19455) -keepasskey=<key> KeePassHttp key for AES encrypted communication with KeePass -keepassid=<name> KeePassHttp id for the established association -keepassname=<name> Name to construct url for KeePass entry that stores the wallet passphrase The following rpc commands are available: - keepass genkey: generates a base64 encoded 256 bit AES key that can be used for the communication with KeePassHttp. Only necessary for manual configuration. Use init for automatic configuration. - keepass init: sets up the association between darkcoind and keepass by generating an AES key and sending an association message to KeePassHttp. This will trigger KeePass to ask for an Id for the association. Returns the association and the base64 encoded string for the AES key. - keepass setpassphrase <passphrase>: updates the passphrase in KeePassHttp to a new value. This should match the passphrase you intend to use for the wallet. Please note that the standard RPC commands walletpassphrasechange and the wallet encrption from the QT GUI already send the updates to KeePassHttp, so this is only necessary for manual manipulation of the password. Sample initialization flow from darkcoin-qt console (this needs to be done only once to set up the association): - Have KeePass running with an open database - Start darkcoin-qt - Open console - type: "keepass init" in darkcoin-qt console - (keepass pops up and asks for an association id, fill that in). Example: mydrkwallet - response: Association successful. Id: mydrkwalletdarkcoin - Key: AgQkcs6cI7v9tlSYKjG/+s8wJrGALHl3jLosJpPLzUE= - Edit darkcoin.conf and fill in these values keepass=1 keepasskey=AgQkcs6cI7v9tlSYKjG/+s8wJrGALHl3jLosJpPLzUE= keepassid=mydrkwallet keepassname=testwallet - Restart darkcoin-qt At this point, the association is made. The next action depends on your particular situation: - current wallet is not yet encrypted. Encrypting the wallet will trigger the integration and stores the password in KeePass (Under the 'KeePassHttp Passwords' group, named after keepassname. - current wallet is already encrypted: use "keepass setpassphrase <passphrase>" to store the passphrase in KeePass. At this point, the passphrase is stored in KeePassHttp. When Unlocking the wallet, one can use keepass as the passphrase to trigger retrieval of the password. This works from the RPC commands as well as the GUI.
2014-12-26 12:53:29 +01:00
#ifndef WIN32
// for posix_fallocate
#ifdef __linux__
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#define _POSIX_C_SOURCE 200112L
#endif // __linux__
#include <algorithm>
#include <fcntl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#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
2012-04-15 22:10:54 +02:00
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
2012-04-15 22:10:54 +02:00
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
#define _WIN32_IE 0x0501
2012-04-15 22:10:54 +02:00
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <io.h> /* for _commit */
#include <shlobj.h>
2012-04-15 22:10:54 +02:00
#endif
2011-05-14 17:25:05 +02:00
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
#ifdef HAVE_MALLOPT_ARENA_MAX
#include <malloc.h>
#endif
#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()
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/foreach.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include <openssl/rand.h>
#include <openssl/conf.h>
2011-05-14 17:25:05 +02:00
2015-03-18 00:06:58 +01:00
//Dash only features
bool fMasternodeMode = false;
bool fLiteMode = false;
/**
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;
const char * const BITCOIN_CONF_FILENAME = "dash.conf";
2016-05-11 11:30:52 +02:00
const char * const BITCOIN_PID_FILENAME = "dashd.pid";
ArgsManager gArgs;
2011-05-14 17:25:05 +02:00
bool fPrintToConsole = false;
bool fPrintToDebugLog = true;
bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
bool fLogThreadNames = DEFAULT_LOGTHREADNAMES;
bool fLogIPs = DEFAULT_LOGIPS;
std::atomic<bool> fReopenDebugLog(false);
CTranslationInterface translationInterface;
2011-05-14 17:25:05 +02:00
/** Log categories bitfield. */
Backport Bitcoin#9424, Bitcoin#10123 and Bitcoin#10153 (#2918) * Contains dashification. disables `-debug dash` Merge #9424: Change LogAcceptCategory to use uint32_t rather than sets of strings. 6b3bb3d Change LogAcceptCategory to use uint32_t rather than sets of strings. (Gregory Maxwell) Tree-SHA512: ebb5bcf9a7d00a32dd1390b727ff4d29330a038423611da01268d8e1d2c0229e52a1098e751d4e6db73ef4ae862e1e96d38249883fcaf12b68f55ebb01035b34 Signed-off-by: Pasta <Pasta@dash.org> 31 -> 32 Signed-off-by: Pasta <Pasta@dash.org> * Merge #10123: Allow debug logs to be excluded from specified component 3bde556 Add -debugexclude option to switch off logging for specified components (John Newbery) Tree-SHA512: 30202e3f2085fc2fc5dd4bedb92988f4cb162c612a42cf8f6395a7da326f34975ddc347f82bc4ddca6c84c438dc0cc6e87869f90c7ff88105dbeaa52a947fa43 * bump to uint64_t due to added Dash codes Signed-off-by: Pasta <Pasta@dash.org> * bump to uint64_t due to added Dash codes cont. Signed-off-by: Pasta <Pasta@dash.org> * string -> BCLog format Signed-off-by: Pasta <Pasta@dash.org> * uint32_t -> uint64_t Signed-off-by: Pasta <Pasta@dash.org> * Fix CBatchedLogger * Fix most fDebug-s * Fix `debug` rpc * Fix BENCH and RAND conflicts * Add ALERT and use it * Update LogPrint-s in dash-specific code * Tweak few log categories Specifically: - use PRIVATESEND in `CPrivateSendClientManager::GetRandomNotUsedMasternode()` - use ZMQ in `CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote()` and `CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject()` * Drop no longer used MASTERNODE category * Merge #10153: logging: Fix off-by-one for shrinkdebugfile default faab624 logging: Fix off-by-one for shrinkdebugfile (MarcoFalke) Tree-SHA512: d6153e06067906172ff0611af9e585a3ecf0a7d56925b6ad7c12e75aa802441047059b9b6f6c78e79916c3f2abc8f1998bfd2d5b84201ec6421f727c08da3c21 * Shift dash-specific log categories to start from `1ul << 32` to avoid potential future conflicts with bitcoin ones * Fix `dash` category * remove debugCategories Signed-off-by: Pasta <Pasta@dash.org> * Prepend "std::" to find call * Check for BCLog::PRIVATESEND instead of logCategories != BCLog::NONE * Use BCLog::MNPAYMENTS category instead of checking for logCategories != BCLog::NONE * Move "End Dash" comment below "ALERT" When adding new entries here, we'll otherwise get confused with ordering and might end up forgetting that adding something Dash specific must continue with the bit after 43.
2019-05-22 23:51:39 +02:00
std::atomic<uint64_t> logCategories(0);
/** Init OpenSSL library multithreading support */
static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL;
void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
2011-05-14 17:25:05 +02:00
{
if (mode & CRYPTO_LOCK) {
ENTER_CRITICAL_SECTION(ppmutexOpenSSL[i]);
} else {
LEAVE_CRITICAL_SECTION(ppmutexOpenSSL[i]);
}
2011-05-14 17:25:05 +02:00
}
// Singleton for wrapping OpenSSL setup/teardown.
2011-05-14 17:25:05 +02:00
class CInit
{
public:
CInit()
{
// Init OpenSSL library multithreading support
ppmutexOpenSSL.reset(new CCriticalSection[CRYPTO_num_locks()]);
2011-05-14 17:25:05 +02:00
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
2011-05-14 17:25:05 +02:00
RAND_screen();
#endif
// Seed OpenSSL PRNG with performance counter
2011-05-14 17:25:05 +02:00
RandAddSeed();
}
~CInit()
{
// Securely erase the memory used by the PRNG
RAND_cleanup();
// Shutdown OpenSSL library multithreading support
2011-05-14 17:25:05 +02:00
CRYPTO_set_locking_callback(NULL);
// 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;
/**
* 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
static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
/**
* 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.
*/
static FILE* fileout = NULL;
static boost::mutex* mutexDebugLog = NULL;
static std::list<std::string>* vMsgsBeforeOpenLog;
static int FileWriteStr(const std::string &str, FILE *fp)
{
return fwrite(str.data(), 1, str.size(), fp);
}
static void DebugPrintInit()
2011-05-14 17:25:05 +02:00
{
assert(mutexDebugLog == NULL);
mutexDebugLog = new boost::mutex();
vMsgsBeforeOpenLog = new std::list<std::string>;
}
void OpenDebugLog()
{
boost::call_once(&DebugPrintInit, debugPrintInitFlag);
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
assert(fileout == NULL);
assert(vMsgsBeforeOpenLog);
fs::path pathDebug = GetDataDir() / "debug.log";
fileout = fsbridge::fopen(pathDebug, "a");
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();
}
}
delete vMsgsBeforeOpenLog;
vMsgsBeforeOpenLog = NULL;
}
Backport Bitcoin#9424, Bitcoin#10123 and Bitcoin#10153 (#2918) * Contains dashification. disables `-debug dash` Merge #9424: Change LogAcceptCategory to use uint32_t rather than sets of strings. 6b3bb3d Change LogAcceptCategory to use uint32_t rather than sets of strings. (Gregory Maxwell) Tree-SHA512: ebb5bcf9a7d00a32dd1390b727ff4d29330a038423611da01268d8e1d2c0229e52a1098e751d4e6db73ef4ae862e1e96d38249883fcaf12b68f55ebb01035b34 Signed-off-by: Pasta <Pasta@dash.org> 31 -> 32 Signed-off-by: Pasta <Pasta@dash.org> * Merge #10123: Allow debug logs to be excluded from specified component 3bde556 Add -debugexclude option to switch off logging for specified components (John Newbery) Tree-SHA512: 30202e3f2085fc2fc5dd4bedb92988f4cb162c612a42cf8f6395a7da326f34975ddc347f82bc4ddca6c84c438dc0cc6e87869f90c7ff88105dbeaa52a947fa43 * bump to uint64_t due to added Dash codes Signed-off-by: Pasta <Pasta@dash.org> * bump to uint64_t due to added Dash codes cont. Signed-off-by: Pasta <Pasta@dash.org> * string -> BCLog format Signed-off-by: Pasta <Pasta@dash.org> * uint32_t -> uint64_t Signed-off-by: Pasta <Pasta@dash.org> * Fix CBatchedLogger * Fix most fDebug-s * Fix `debug` rpc * Fix BENCH and RAND conflicts * Add ALERT and use it * Update LogPrint-s in dash-specific code * Tweak few log categories Specifically: - use PRIVATESEND in `CPrivateSendClientManager::GetRandomNotUsedMasternode()` - use ZMQ in `CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote()` and `CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject()` * Drop no longer used MASTERNODE category * Merge #10153: logging: Fix off-by-one for shrinkdebugfile default faab624 logging: Fix off-by-one for shrinkdebugfile (MarcoFalke) Tree-SHA512: d6153e06067906172ff0611af9e585a3ecf0a7d56925b6ad7c12e75aa802441047059b9b6f6c78e79916c3f2abc8f1998bfd2d5b84201ec6421f727c08da3c21 * Shift dash-specific log categories to start from `1ul << 32` to avoid potential future conflicts with bitcoin ones * Fix `dash` category * remove debugCategories Signed-off-by: Pasta <Pasta@dash.org> * Prepend "std::" to find call * Check for BCLog::PRIVATESEND instead of logCategories != BCLog::NONE * Use BCLog::MNPAYMENTS category instead of checking for logCategories != BCLog::NONE * Move "End Dash" comment below "ALERT" When adding new entries here, we'll otherwise get confused with ordering and might end up forgetting that adding something Dash specific must continue with the bit after 43.
2019-05-22 23:51:39 +02:00
struct CLogCategoryDesc
{
Backport Bitcoin#9424, Bitcoin#10123 and Bitcoin#10153 (#2918) * Contains dashification. disables `-debug dash` Merge #9424: Change LogAcceptCategory to use uint32_t rather than sets of strings. 6b3bb3d Change LogAcceptCategory to use uint32_t rather than sets of strings. (Gregory Maxwell) Tree-SHA512: ebb5bcf9a7d00a32dd1390b727ff4d29330a038423611da01268d8e1d2c0229e52a1098e751d4e6db73ef4ae862e1e96d38249883fcaf12b68f55ebb01035b34 Signed-off-by: Pasta <Pasta@dash.org> 31 -> 32 Signed-off-by: Pasta <Pasta@dash.org> * Merge #10123: Allow debug logs to be excluded from specified component 3bde556 Add -debugexclude option to switch off logging for specified components (John Newbery) Tree-SHA512: 30202e3f2085fc2fc5dd4bedb92988f4cb162c612a42cf8f6395a7da326f34975ddc347f82bc4ddca6c84c438dc0cc6e87869f90c7ff88105dbeaa52a947fa43 * bump to uint64_t due to added Dash codes Signed-off-by: Pasta <Pasta@dash.org> * bump to uint64_t due to added Dash codes cont. Signed-off-by: Pasta <Pasta@dash.org> * string -> BCLog format Signed-off-by: Pasta <Pasta@dash.org> * uint32_t -> uint64_t Signed-off-by: Pasta <Pasta@dash.org> * Fix CBatchedLogger * Fix most fDebug-s * Fix `debug` rpc * Fix BENCH and RAND conflicts * Add ALERT and use it * Update LogPrint-s in dash-specific code * Tweak few log categories Specifically: - use PRIVATESEND in `CPrivateSendClientManager::GetRandomNotUsedMasternode()` - use ZMQ in `CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote()` and `CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject()` * Drop no longer used MASTERNODE category * Merge #10153: logging: Fix off-by-one for shrinkdebugfile default faab624 logging: Fix off-by-one for shrinkdebugfile (MarcoFalke) Tree-SHA512: d6153e06067906172ff0611af9e585a3ecf0a7d56925b6ad7c12e75aa802441047059b9b6f6c78e79916c3f2abc8f1998bfd2d5b84201ec6421f727c08da3c21 * Shift dash-specific log categories to start from `1ul << 32` to avoid potential future conflicts with bitcoin ones * Fix `dash` category * remove debugCategories Signed-off-by: Pasta <Pasta@dash.org> * Prepend "std::" to find call * Check for BCLog::PRIVATESEND instead of logCategories != BCLog::NONE * Use BCLog::MNPAYMENTS category instead of checking for logCategories != BCLog::NONE * Move "End Dash" comment below "ALERT" When adding new entries here, we'll otherwise get confused with ordering and might end up forgetting that adding something Dash specific must continue with the bit after 43.
2019-05-22 23:51:39 +02:00
uint64_t flag;
std::string category;
};
Backport Bitcoin#9424, Bitcoin#10123 and Bitcoin#10153 (#2918) * Contains dashification. disables `-debug dash` Merge #9424: Change LogAcceptCategory to use uint32_t rather than sets of strings. 6b3bb3d Change LogAcceptCategory to use uint32_t rather than sets of strings. (Gregory Maxwell) Tree-SHA512: ebb5bcf9a7d00a32dd1390b727ff4d29330a038423611da01268d8e1d2c0229e52a1098e751d4e6db73ef4ae862e1e96d38249883fcaf12b68f55ebb01035b34 Signed-off-by: Pasta <Pasta@dash.org> 31 -> 32 Signed-off-by: Pasta <Pasta@dash.org> * Merge #10123: Allow debug logs to be excluded from specified component 3bde556 Add -debugexclude option to switch off logging for specified components (John Newbery) Tree-SHA512: 30202e3f2085fc2fc5dd4bedb92988f4cb162c612a42cf8f6395a7da326f34975ddc347f82bc4ddca6c84c438dc0cc6e87869f90c7ff88105dbeaa52a947fa43 * bump to uint64_t due to added Dash codes Signed-off-by: Pasta <Pasta@dash.org> * bump to uint64_t due to added Dash codes cont. Signed-off-by: Pasta <Pasta@dash.org> * string -> BCLog format Signed-off-by: Pasta <Pasta@dash.org> * uint32_t -> uint64_t Signed-off-by: Pasta <Pasta@dash.org> * Fix CBatchedLogger * Fix most fDebug-s * Fix `debug` rpc * Fix BENCH and RAND conflicts * Add ALERT and use it * Update LogPrint-s in dash-specific code * Tweak few log categories Specifically: - use PRIVATESEND in `CPrivateSendClientManager::GetRandomNotUsedMasternode()` - use ZMQ in `CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote()` and `CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject()` * Drop no longer used MASTERNODE category * Merge #10153: logging: Fix off-by-one for shrinkdebugfile default faab624 logging: Fix off-by-one for shrinkdebugfile (MarcoFalke) Tree-SHA512: d6153e06067906172ff0611af9e585a3ecf0a7d56925b6ad7c12e75aa802441047059b9b6f6c78e79916c3f2abc8f1998bfd2d5b84201ec6421f727c08da3c21 * Shift dash-specific log categories to start from `1ul << 32` to avoid potential future conflicts with bitcoin ones * Fix `dash` category * remove debugCategories Signed-off-by: Pasta <Pasta@dash.org> * Prepend "std::" to find call * Check for BCLog::PRIVATESEND instead of logCategories != BCLog::NONE * Use BCLog::MNPAYMENTS category instead of checking for logCategories != BCLog::NONE * Move "End Dash" comment below "ALERT" When adding new entries here, we'll otherwise get confused with ordering and might end up forgetting that adding something Dash specific must continue with the bit after 43.
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;
}
}
Backport Bitcoin#9424, Bitcoin#10123 and Bitcoin#10153 (#2918) * Contains dashification. disables `-debug dash` Merge #9424: Change LogAcceptCategory to use uint32_t rather than sets of strings. 6b3bb3d Change LogAcceptCategory to use uint32_t rather than sets of strings. (Gregory Maxwell) Tree-SHA512: ebb5bcf9a7d00a32dd1390b727ff4d29330a038423611da01268d8e1d2c0229e52a1098e751d4e6db73ef4ae862e1e96d38249883fcaf12b68f55ebb01035b34 Signed-off-by: Pasta <Pasta@dash.org> 31 -> 32 Signed-off-by: Pasta <Pasta@dash.org> * Merge #10123: Allow debug logs to be excluded from specified component 3bde556 Add -debugexclude option to switch off logging for specified components (John Newbery) Tree-SHA512: 30202e3f2085fc2fc5dd4bedb92988f4cb162c612a42cf8f6395a7da326f34975ddc347f82bc4ddca6c84c438dc0cc6e87869f90c7ff88105dbeaa52a947fa43 * bump to uint64_t due to added Dash codes Signed-off-by: Pasta <Pasta@dash.org> * bump to uint64_t due to added Dash codes cont. Signed-off-by: Pasta <Pasta@dash.org> * string -> BCLog format Signed-off-by: Pasta <Pasta@dash.org> * uint32_t -> uint64_t Signed-off-by: Pasta <Pasta@dash.org> * Fix CBatchedLogger * Fix most fDebug-s * Fix `debug` rpc * Fix BENCH and RAND conflicts * Add ALERT and use it * Update LogPrint-s in dash-specific code * Tweak few log categories Specifically: - use PRIVATESEND in `CPrivateSendClientManager::GetRandomNotUsedMasternode()` - use ZMQ in `CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote()` and `CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject()` * Drop no longer used MASTERNODE category * Merge #10153: logging: Fix off-by-one for shrinkdebugfile default faab624 logging: Fix off-by-one for shrinkdebugfile (MarcoFalke) Tree-SHA512: d6153e06067906172ff0611af9e585a3ecf0a7d56925b6ad7c12e75aa802441047059b9b6f6c78e79916c3f2abc8f1998bfd2d5b84201ec6421f727c08da3c21 * Shift dash-specific log categories to start from `1ul << 32` to avoid potential future conflicts with bitcoin ones * Fix `dash` category * remove debugCategories Signed-off-by: Pasta <Pasta@dash.org> * Prepend "std::" to find call * Check for BCLog::PRIVATESEND instead of logCategories != BCLog::NONE * Use BCLog::MNPAYMENTS category instead of checking for logCategories != BCLog::NONE * Move "End Dash" comment below "ALERT" When adding new entries here, we'll otherwise get confused with ordering and might end up forgetting that adding something Dash specific must continue with the bit after 43.
2019-05-22 23:51:39 +02:00
}
return false;
}
Backport Bitcoin#9424, Bitcoin#10123 and Bitcoin#10153 (#2918) * Contains dashification. disables `-debug dash` Merge #9424: Change LogAcceptCategory to use uint32_t rather than sets of strings. 6b3bb3d Change LogAcceptCategory to use uint32_t rather than sets of strings. (Gregory Maxwell) Tree-SHA512: ebb5bcf9a7d00a32dd1390b727ff4d29330a038423611da01268d8e1d2c0229e52a1098e751d4e6db73ef4ae862e1e96d38249883fcaf12b68f55ebb01035b34 Signed-off-by: Pasta <Pasta@dash.org> 31 -> 32 Signed-off-by: Pasta <Pasta@dash.org> * Merge #10123: Allow debug logs to be excluded from specified component 3bde556 Add -debugexclude option to switch off logging for specified components (John Newbery) Tree-SHA512: 30202e3f2085fc2fc5dd4bedb92988f4cb162c612a42cf8f6395a7da326f34975ddc347f82bc4ddca6c84c438dc0cc6e87869f90c7ff88105dbeaa52a947fa43 * bump to uint64_t due to added Dash codes Signed-off-by: Pasta <Pasta@dash.org> * bump to uint64_t due to added Dash codes cont. Signed-off-by: Pasta <Pasta@dash.org> * string -> BCLog format Signed-off-by: Pasta <Pasta@dash.org> * uint32_t -> uint64_t Signed-off-by: Pasta <Pasta@dash.org> * Fix CBatchedLogger * Fix most fDebug-s * Fix `debug` rpc * Fix BENCH and RAND conflicts * Add ALERT and use it * Update LogPrint-s in dash-specific code * Tweak few log categories Specifically: - use PRIVATESEND in `CPrivateSendClientManager::GetRandomNotUsedMasternode()` - use ZMQ in `CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote()` and `CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject()` * Drop no longer used MASTERNODE category * Merge #10153: logging: Fix off-by-one for shrinkdebugfile default faab624 logging: Fix off-by-one for shrinkdebugfile (MarcoFalke) Tree-SHA512: d6153e06067906172ff0611af9e585a3ecf0a7d56925b6ad7c12e75aa802441047059b9b6f6c78e79916c3f2abc8f1998bfd2d5b84201ec6421f727c08da3c21 * Shift dash-specific log categories to start from `1ul << 32` to avoid potential future conflicts with bitcoin ones * Fix `dash` category * remove debugCategories Signed-off-by: Pasta <Pasta@dash.org> * Prepend "std::" to find call * Check for BCLog::PRIVATESEND instead of logCategories != BCLog::NONE * Use BCLog::MNPAYMENTS category instead of checking for logCategories != BCLog::NONE * Move "End Dash" comment below "ALERT" When adding new entries here, we'll otherwise get confused with ordering and might end up forgetting that adding something Dash specific must continue with the bit after 43.
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++;
}
}
Backport Bitcoin#9424, Bitcoin#10123 and Bitcoin#10153 (#2918) * Contains dashification. disables `-debug dash` Merge #9424: Change LogAcceptCategory to use uint32_t rather than sets of strings. 6b3bb3d Change LogAcceptCategory to use uint32_t rather than sets of strings. (Gregory Maxwell) Tree-SHA512: ebb5bcf9a7d00a32dd1390b727ff4d29330a038423611da01268d8e1d2c0229e52a1098e751d4e6db73ef4ae862e1e96d38249883fcaf12b68f55ebb01035b34 Signed-off-by: Pasta <Pasta@dash.org> 31 -> 32 Signed-off-by: Pasta <Pasta@dash.org> * Merge #10123: Allow debug logs to be excluded from specified component 3bde556 Add -debugexclude option to switch off logging for specified components (John Newbery) Tree-SHA512: 30202e3f2085fc2fc5dd4bedb92988f4cb162c612a42cf8f6395a7da326f34975ddc347f82bc4ddca6c84c438dc0cc6e87869f90c7ff88105dbeaa52a947fa43 * bump to uint64_t due to added Dash codes Signed-off-by: Pasta <Pasta@dash.org> * bump to uint64_t due to added Dash codes cont. Signed-off-by: Pasta <Pasta@dash.org> * string -> BCLog format Signed-off-by: Pasta <Pasta@dash.org> * uint32_t -> uint64_t Signed-off-by: Pasta <Pasta@dash.org> * Fix CBatchedLogger * Fix most fDebug-s * Fix `debug` rpc * Fix BENCH and RAND conflicts * Add ALERT and use it * Update LogPrint-s in dash-specific code * Tweak few log categories Specifically: - use PRIVATESEND in `CPrivateSendClientManager::GetRandomNotUsedMasternode()` - use ZMQ in `CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote()` and `CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject()` * Drop no longer used MASTERNODE category * Merge #10153: logging: Fix off-by-one for shrinkdebugfile default faab624 logging: Fix off-by-one for shrinkdebugfile (MarcoFalke) Tree-SHA512: d6153e06067906172ff0611af9e585a3ecf0a7d56925b6ad7c12e75aa802441047059b9b6f6c78e79916c3f2abc8f1998bfd2d5b84201ec6421f727c08da3c21 * Shift dash-specific log categories to start from `1ul << 32` to avoid potential future conflicts with bitcoin ones * Fix `dash` category * remove debugCategories Signed-off-by: Pasta <Pasta@dash.org> * Prepend "std::" to find call * Check for BCLog::PRIVATESEND instead of logCategories != BCLog::NONE * Use BCLog::MNPAYMENTS category instead of checking for logCategories != BCLog::NONE * Move "End Dash" comment below "ALERT" When adding new entries here, we'll otherwise get confused with ordering and might end up forgetting that adding something Dash specific must continue with the bit after 43.
2019-05-22 23:51:39 +02:00
return ret;
}
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()
{
Backport Bitcoin#9424, Bitcoin#10123 and Bitcoin#10153 (#2918) * Contains dashification. disables `-debug dash` Merge #9424: Change LogAcceptCategory to use uint32_t rather than sets of strings. 6b3bb3d Change LogAcceptCategory to use uint32_t rather than sets of strings. (Gregory Maxwell) Tree-SHA512: ebb5bcf9a7d00a32dd1390b727ff4d29330a038423611da01268d8e1d2c0229e52a1098e751d4e6db73ef4ae862e1e96d38249883fcaf12b68f55ebb01035b34 Signed-off-by: Pasta <Pasta@dash.org> 31 -> 32 Signed-off-by: Pasta <Pasta@dash.org> * Merge #10123: Allow debug logs to be excluded from specified component 3bde556 Add -debugexclude option to switch off logging for specified components (John Newbery) Tree-SHA512: 30202e3f2085fc2fc5dd4bedb92988f4cb162c612a42cf8f6395a7da326f34975ddc347f82bc4ddca6c84c438dc0cc6e87869f90c7ff88105dbeaa52a947fa43 * bump to uint64_t due to added Dash codes Signed-off-by: Pasta <Pasta@dash.org> * bump to uint64_t due to added Dash codes cont. Signed-off-by: Pasta <Pasta@dash.org> * string -> BCLog format Signed-off-by: Pasta <Pasta@dash.org> * uint32_t -> uint64_t Signed-off-by: Pasta <Pasta@dash.org> * Fix CBatchedLogger * Fix most fDebug-s * Fix `debug` rpc * Fix BENCH and RAND conflicts * Add ALERT and use it * Update LogPrint-s in dash-specific code * Tweak few log categories Specifically: - use PRIVATESEND in `CPrivateSendClientManager::GetRandomNotUsedMasternode()` - use ZMQ in `CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote()` and `CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject()` * Drop no longer used MASTERNODE category * Merge #10153: logging: Fix off-by-one for shrinkdebugfile default faab624 logging: Fix off-by-one for shrinkdebugfile (MarcoFalke) Tree-SHA512: d6153e06067906172ff0611af9e585a3ecf0a7d56925b6ad7c12e75aa802441047059b9b6f6c78e79916c3f2abc8f1998bfd2d5b84201ec6421f727c08da3c21 * Shift dash-specific log categories to start from `1ul << 32` to avoid potential future conflicts with bitcoin ones * Fix `dash` category * remove debugCategories Signed-off-by: Pasta <Pasta@dash.org> * Prepend "std::" to find call * Check for BCLog::PRIVATESEND instead of logCategories != BCLog::NONE * Use BCLog::MNPAYMENTS category instead of checking for logCategories != BCLog::NONE * Move "End Dash" comment below "ALERT" When adding new entries here, we'll otherwise get confused with ordering and might end up forgetting that adding something Dash specific must continue with the bit after 43.
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;
}
/**
* 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
* end in a newline. Initialize it to true, and hold/manage it, in the calling context.
*/
static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)
{
std::string strStamped;
if (!fLogTimestamps)
return str;
if (*fStartedNewLine) {
int64_t nTimeMicros = GetTimeMicros();
strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros/1000000);
if (fLogTimeMicros)
strStamped += strprintf(".%06d", nTimeMicros%1000000);
int64_t mocktime = GetMockTime();
if (mocktime) {
strStamped += " (mocktime: " + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", mocktime) + ")";
}
strStamped += ' ' + str;
} else
strStamped = str;
return strStamped;
}
/**
* 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
* end in a newline. Initialize it to true, and hold/manage it, in the calling context.
*/
static std::string LogThreadNameStr(const std::string &str, std::atomic_bool *fStartedNewLine)
{
std::string strThreadLogged;
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;
}
int LogPrintStr(const std::string &str)
{
int ret = 0; // Returns total number of characters written
static std::atomic_bool fStartedNewLine(true);
std::string strThreadLogged = LogThreadNameStr(str, &fStartedNewLine);
std::string strTimestamped = LogTimestampStr(strThreadLogged, &fStartedNewLine);
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
ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout);
fflush(stdout);
2011-05-14 17:25:05 +02:00
}
else if (fPrintToDebugLog)
2011-05-14 17:25:05 +02:00
{
boost::call_once(&DebugPrintInit, debugPrintInitFlag);
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
// 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
}
else
{
// reopen the log file, if requested
if (fReopenDebugLog) {
fReopenDebugLog = false;
fs::path pathDebug = GetDataDir() / "debug.log";
if (fsbridge::freopen(pathDebug,"a",fileout) != NULL)
setbuf(fileout, NULL); // unbuffered
}
2011-05-14 17:25:05 +02:00
ret = FileWriteStr(strTimestamped, fileout);
}
2011-05-14 17:25:05 +02:00
}
return ret;
}
/** Interpret string as boolean, for argument parsing */
static bool InterpretBool(const std::string& strValue)
{
if (strValue.empty())
return true;
return (atoi(strValue) != 0);
}
/** Turn -noX into -X=0 */
static void InterpretNegativeSetting(std::string& strKey, std::string& strValue)
{
if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o')
{
strKey = "-" + strKey.substr(3);
strValue = InterpretBool(strValue) ? "0" : "1";
}
}
void ArgsManager::ParseParameters(int argc, const char* const argv[])
2011-05-14 17:25:05 +02:00
{
LOCK(cs_args);
2011-05-14 17:25:05 +02:00
mapArgs.clear();
mapMultiArgs.clear();
2011-05-14 17:25:05 +02:00
for (int i = 1; i < argc; i++)
{
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
{
strValue = str.substr(is_index+1);
str = str.substr(0, is_index);
2011-05-14 17:25:05 +02:00
}
#ifdef WIN32
boost::to_lower(str);
if (boost::algorithm::starts_with(str, "/"))
str = "-" + str.substr(1);
#endif
if (str[0] != '-')
2011-05-14 17:25:05 +02:00
break;
// 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);
InterpretNegativeSetting(str, strValue);
mapArgs[str] = strValue;
mapMultiArgs[str].push_back(strValue);
2011-05-14 17:25:05 +02:00
}
}
std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg)
{
LOCK(cs_args);
return mapMultiArgs.at(strArg);
}
bool ArgsManager::IsArgSet(const std::string& strArg)
{
LOCK(cs_args);
return mapArgs.count(strArg);
}
std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault)
2012-02-06 18:37:49 +01:00
{
LOCK(cs_args);
2012-02-06 18:37:49 +01:00
if (mapArgs.count(strArg))
return mapArgs[strArg];
return strDefault;
}
int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault)
2012-02-06 18:37:49 +01:00
{
LOCK(cs_args);
2012-02-06 18:37:49 +01:00
if (mapArgs.count(strArg))
return atoi64(mapArgs[strArg]);
return nDefault;
}
bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault)
2012-02-06 18:37:49 +01:00
{
LOCK(cs_args);
2012-02-06 18:37:49 +01:00
if (mapArgs.count(strArg))
return InterpretBool(mapArgs[strArg]);
2012-02-06 18:37:49 +01:00
return fDefault;
}
bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
{
LOCK(cs_args);
if (mapArgs.count(strArg))
return false;
ForceSetArg(strArg, strValue);
return true;
}
bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
{
if (fValue)
return SoftSetArg(strArg, std::string("1"));
else
return SoftSetArg(strArg, std::string("0"));
}
void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
{
LOCK(cs_args);
mapArgs[strArg] = strValue;
mapMultiArgs[strArg].push_back(strValue);
}
void ArgsManager::ForceSetMultiArgs(const std::string& strArg, const std::vector<std::string>& values)
{
LOCK(cs_args);
mapMultiArgs[strArg] = values;
}
void ArgsManager::ForceRemoveArg(const std::string& strArg)
{
LOCK(cs_args);
mapArgs.erase(strArg);
mapMultiArgs.erase(strArg);
}
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_ptr pex, const char* pszThread)
2011-05-14 17:25:05 +02:00
{
return strprintf("EXCEPTION: %s", GetPrettyExceptionStr(pex));
2011-05-14 17:25:05 +02:00
}
void PrintExceptionContinue(const std::exception_ptr pex, const char* pszThread)
2011-05-14 17:25:05 +02:00
{
std::string message = FormatException(pex, pszThread);
LogPrintf("\n\n************************\n%s\n", message);
fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
2011-05-14 17:25:05 +02:00
}
fs::path GetDefaultDataDir()
2011-05-14 17:25:05 +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
#ifdef WIN32
2011-05-14 17:25:05 +02:00
// Windows
return GetSpecialFolderPath(CSIDL_APPDATA) / "DashCore";
2011-05-14 17:25:05 +02:00
#else
fs::path pathRet;
2011-05-14 17:25:05 +02:00
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
pathRet = fs::path("/");
else
pathRet = fs::path(pszHome);
#ifdef MAC_OSX
2011-05-14 17:25:05 +02:00
// Mac
return pathRet / "Library/Application Support/DashCore";
2011-05-14 17:25:05 +02:00
#else
// Unix
return pathRet / ".dashcore";
2011-05-14 17:25:05 +02:00
#endif
#endif
}
static fs::path pathCached;
static fs::path pathCachedNetSpecific;
static CCriticalSection csPathCached;
const fs::path &GetDataDir(bool fNetSpecific)
2011-05-14 17:25:05 +02:00
{
LOCK(csPathCached);
fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
2013-09-19 14:47:21 +02:00
// 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;
2017-06-15 22:45:55 +02:00
if (gArgs.IsArgSet("-datadir")) {
path = fs::system_complete(gArgs.GetArg("-datadir", ""));
2012-04-22 14:35:22 +02:00
if (!fs::is_directory(path)) {
path = "";
return path;
}
} else {
path = GetDefaultDataDir();
2011-05-14 17:25:05 +02:00
}
if (fNetSpecific)
path /= BaseParams().DataDir();
2011-05-14 17:25:05 +02:00
fs::create_directories(path);
return path;
2011-05-14 17:25:05 +02:00
}
fs::path GetBackupsDir()
{
if (!IsArgSet("-walletbackupsdir"))
return GetDataDir() / "backups";
return fs::absolute(GetArg("-walletbackupsdir", ""));
}
void ClearDatadirCache()
{
LOCK(csPathCached);
pathCached = fs::path();
pathCachedNetSpecific = fs::path();
}
fs::path GetConfigFile(const std::string& confPath)
2011-05-14 17:25:05 +02:00
{
fs::path pathConfigFile(confPath);
if (!pathConfigFile.is_complete())
pathConfigFile = GetDataDir(false) / pathConfigFile;
return pathConfigFile;
2011-05-14 17:25:05 +02:00
}
void ArgsManager::ReadConfigFile(const std::string& confPath)
2011-05-14 17:25:05 +02:00
{
fs::ifstream streamConfig(GetConfigFile(confPath));
if (!streamConfig.good()){
// Create empty dash.conf if it does not excist
FILE* configFile = fopen(GetConfigFile(confPath).string().c_str(), "a");
if (configFile != NULL)
fclose(configFile);
return; // Nothing to read, so just return
}
2011-05-14 17:25:05 +02:00
{
LOCK(cs_args);
std::set<std::string> setOptions;
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
std::string strKey = std::string("-") + it->string_key;
std::string strValue = it->value[0];
InterpretNegativeSetting(strKey, strValue);
if (mapArgs.count(strKey) == 0)
mapArgs[strKey] = strValue;
mapMultiArgs[strKey].push_back(strValue);
}
2011-05-14 17:25:05 +02:00
}
// If datadir is changed in .conf file:
ClearDatadirCache();
2011-05-14 17:25:05 +02:00
}
#ifndef WIN32
fs::path GetPidFile()
2011-05-14 17:25:05 +02:00
{
2017-06-15 22:45:55 +02:00
fs::path pathPidFile(gArgs.GetArg("-pid", BITCOIN_PID_FILENAME));
if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
return pathPidFile;
2011-05-14 17:25:05 +02:00
}
void CreatePidFile(const fs::path &path, pid_t pid)
2011-05-14 17:25:05 +02:00
{
FILE* file = fsbridge::fopen(path, "w");
if (file)
2011-05-14 17:25:05 +02:00
{
fprintf(file, "%d\n", pid);
fclose(file);
}
}
#endif
2011-05-14 17:25:05 +02:00
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_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.
*/
bool TryCreateDirectory(const fs::path& p)
{
try
{
return fs::create_directory(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)
{
fflush(file); // harmless if redundantly called
#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;
}
return nMinFD; // getrlimit failed, assume it's fine
#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;
fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
length -= now;
}
#endif
}
2011-05-14 17:25:05 +02:00
void ShrinkDebugFile()
{
// 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
fs::path pathLog = GetDataDir() / "debug.log";
FILE* file = fsbridge::fopen(pathLog, "r");
// 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
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
std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
fseek(file, -((long)vch.size()), SEEK_END);
int nBytes = fread(vch.data(), 1, vch.size(), file);
2011-05-14 17:25:05 +02:00
fclose(file);
file = fsbridge::fopen(pathLog, "w");
if (file)
2011-05-14 17:25:05 +02:00
{
fwrite(vch.data(), 1, nBytes, file);
2011-05-14 17:25:05 +02:00
fclose(file);
}
}
else if (file != NULL)
fclose(file);
2011-05-14 17:25:05 +02:00
}
2012-04-15 22:10:54 +02:00
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
{
char pszPath[MAX_PATH] = "";
if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
{
return fs::path(pszPath);
}
LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n");
return fs::path("");
}
2012-04-15 22:10:54 +02:00
#endif
2015-05-31 15:36:44 +02:00
void runCommand(const std::string& strCommand)
{
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);
2015-04-29 15:04:34 +02:00
#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
LogPrintf("%s: thread new name %s\n", __func__, name);
}
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);
}
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);
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) {
RenameThread(strprintf("%s-%d", baseName, i).c_str());
std::unique_lock<std::mutex> l(*mutex);
doneCnt++;
cond->wait(l);
});
}
do {
// Always sleep to let all threads acquire locks
MilliSleep(10);
// `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());
cond->notify_all();
// 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;
}
}
}
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 {
std::locale(""); // Raises a runtime error if current locale is invalid
} 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()
{
#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)
Merge #7192: Unify product name to as few places as possible 027fdb8 When/if the copyright line does not mention Bitcoin Core developers, add a second line to copyrights in -version, About dialog, and splash screen (Luke Dashjr) cc2095e Rewrite FormatParagraph to handle newlines within input strings correctly (Luke Dashjr) cddffaf Bugfix: Include COPYRIGHT_HOLDERS_SUBSTITUTION in Makefile substitutions so it gets passed to extract-strings correctly (Luke Dashjr) 29598e4 Move PACKAGE_URL to configure.ac (Luke Dashjr) 78ec83d splashscreen: Resize text to fit exactly (Luke Dashjr) 3cae140 Bugfix: Actually use _COPYRIGHT_HOLDERS_SUBSTITUTION everywhere (Luke Dashjr) 4d5a3df Bugfix: gitian-descriptors: Add missing python-setuptools requirement for OS X (biplist module) (Luke Dashjr) e4ab5e5 Bugfix: Correct copyright year in Mac DMG background image (Luke Dashjr) 917b1d0 Set copyright holders displayed in notices separately from the package name (Luke Dashjr) c39a6ff Travis & gitian-osx: Use depends for ds_store and mac_alias modules (Luke Dashjr) 902ccde depends: Add mac_alias to depends (Luke Dashjr) 82a2d98 depends: Add ds_store to depends (Cory Fields) de619a3 depends: Pass PYTHONPATH along to configure (Cory Fields) e611b6e macdeploy: Use rsvg-convert rather than cairosvg (Luke Dashjr) 63bcdc5 More complicated package name substitution for Mac deployment (Luke Dashjr) 1a6c67c Parameterise 2009 in translatable copyright strings (Luke Dashjr) d5f4683 Unify package name to as few places as possible without major changes (Luke Dashjr)
2016-02-04 13:41:58 +01: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";
Merge #7192: Unify product name to as few places as possible 027fdb8 When/if the copyright line does not mention Bitcoin Core developers, add a second line to copyrights in -version, About dialog, and splash screen (Luke Dashjr) cc2095e Rewrite FormatParagraph to handle newlines within input strings correctly (Luke Dashjr) cddffaf Bugfix: Include COPYRIGHT_HOLDERS_SUBSTITUTION in Makefile substitutions so it gets passed to extract-strings correctly (Luke Dashjr) 29598e4 Move PACKAGE_URL to configure.ac (Luke Dashjr) 78ec83d splashscreen: Resize text to fit exactly (Luke Dashjr) 3cae140 Bugfix: Actually use _COPYRIGHT_HOLDERS_SUBSTITUTION everywhere (Luke Dashjr) 4d5a3df Bugfix: gitian-descriptors: Add missing python-setuptools requirement for OS X (biplist module) (Luke Dashjr) e4ab5e5 Bugfix: Correct copyright year in Mac DMG background image (Luke Dashjr) 917b1d0 Set copyright holders displayed in notices separately from the package name (Luke Dashjr) c39a6ff Travis & gitian-osx: Use depends for ds_store and mac_alias modules (Luke Dashjr) 902ccde depends: Add mac_alias to depends (Luke Dashjr) 82a2d98 depends: Add ds_store to depends (Cory Fields) de619a3 depends: Pass PYTHONPATH along to configure (Cory Fields) e611b6e macdeploy: Use rsvg-convert rather than cairosvg (Luke Dashjr) 63bcdc5 More complicated package name substitution for Mac deployment (Luke Dashjr) 1a6c67c Parameterise 2009 in translatable copyright strings (Luke Dashjr) d5f4683 Unify package name to as few places as possible without major changes (Luke Dashjr)
2016-02-04 13:41:58 +01:00
}
return strCopyrightHolders;
}
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, ".");
}
std::string SafeIntVersionToString(uint32_t nVersion)
{
try
{
return IntVersionToString(nVersion);
}
catch(const std::bad_cast&)
{
return "invalid_version";
}
}