diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md index 67c5e15a15..32b8189d0c 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -1,180 +1,180 @@ Contents ======== This directory contains tools for developers working on this repository. check-doc.py ============ Check if all command line args are documented. The return value indicates the number of undocumented args. clang-format-diff.py =================== A script to format unified git diffs according to [.clang-format](../../src/.clang-format). For instance, to format the last commit with 0 lines of context, the script should be called from the git root folder as follows. ``` git diff -U0 HEAD~1.. | ./contrib/devtools/clang-format-diff.py -p1 -i -v ``` copyright\_header.py ==================== -Provides utilities for managing copyright headers of `The Bitcoin Core -developers` in repository source files. It has three subcommands: +Provides utilities for managing copyright headers of `The Bitcoin developers` +in repository source files. It has three subcommands: ``` $ ./copyright_header.py report [verbose] $ ./copyright_header.py update $ ./copyright_header.py insert ``` Running these subcommands without arguments displays a usage string. copyright\_header.py report \ [verbose] --------------------------------------------------------- Produces a report of all copyright header notices found inside the source files of a repository. Useful to quickly visualize the state of the headers. Specifying `verbose` will list the full filenames of files of each category. copyright\_header.py update \ [verbose] --------------------------------------------------------- -Updates all the copyright headers of `The Bitcoin Core developers` which were -changed in a year more recent than is listed. For example: +Updates all the copyright headers of `The Bitcoin developers` which were changed +in a year more recent than is listed. For example: ``` -// Copyright (c) - The Bitcoin Core developers +// Copyright (c) - The Bitcoin developers ``` will be updated to: ``` -// Copyright (c) - The Bitcoin Core developers +// Copyright (c) - The Bitcoin developers ``` where `` is obtained from the `git log` history. This subcommand also handles copyright headers that have only a single year. In those cases: ``` -// Copyright (c) The Bitcoin Core developers +// Copyright (c) The Bitcoin developers ``` will be updated to: ``` -// Copyright (c) - The Bitcoin Core developers +// Copyright (c) - The Bitcoin developers ``` where the update is appropriate. copyright\_header.py insert \ ------------------------------------ -Inserts a copyright header for `The Bitcoin Core developers` at the top of the -file in either Python or C++ style as determined by the file extension. If the -file is a Python file and it has `#!` starting the first line, the header is +Inserts a copyright header for `The Bitcoin developers` at the top of the file +in either Python or C++ style as determined by the file extension. If the file +is a Python file and it has `#!` starting the first line, the header is inserted in the line below it. The copyright dates will be set to be `-` where `` is according to the `git log` history. If `` is equal to ``, it will be set as a single year rather than two hyphenated years. -If the file already has a copyright for `The Bitcoin Core developers`, the -script will exit. +If the file already has a copyright for `The Bitcoin developers`, the script +will exit. gen-manpages.sh =============== A small script to automatically create manpages in ../../doc/man by running the release binaries with the -help option. This requires help2man which can be found at: https://www.gnu.org/software/help2man/ git-subtree-check.sh ==================== Run this script from the root of the repository to verify that a subtree matches the contents of the commit it claims to have been updated to. To use, make sure that you have fetched the upstream repository branch in which the subtree is maintained: * for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master) * for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork) * for `src/univalue`: https://github.com/bitcoin-core/univalue.git (branch master) * for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master) Usage: `git-subtree-check.sh DIR (COMMIT)` `COMMIT` may be omitted, in which case `HEAD` is used. github-merge.py =============== A small script to automate merging pull-requests securely and sign them with GPG. For example: ./github-merge.py 3077 (in any git repository) will help you merge pull request #3077 for the bitcoin/bitcoin repository. What it does: * Fetch master and the pull request. * Locally construct a merge commit. * Show the diff that merge results in. * Ask you to verify the resulting source tree (so you can do a make check or whatever). * Ask you whether to GPG sign the merge commit. * Ask you whether to push the result upstream. This means that there are no potential race conditions (where a pullreq gets updated while you're reviewing it, but before you click merge), and when using GPG signatures, that even a compromised GitHub couldn't mess with the sources. Setup --------- Configuring the github-merge tool for the bitcoin repository is done in the following way: git config githubmerge.repository bitcoin/bitcoin git config githubmerge.testcmd "make -j4 check" (adapt to whatever you want to use for testing) git config --global user.signingkey mykeyid (if you want to GPG sign) optimize-pngs.py ================ A script to optimize png files in the bitcoin repository (requires pngcrush). security-check.py and test-security-check.py ============================================ Perform basic ELF security checks on a series of executables. symbol-check.py =============== A script to check that the (Linux) executables produced by gitian only contain allowed gcc, glibc and libstdc++ version symbols. This makes sure they are still compatible with the minimum supported Linux distribution versions. Example usage after a gitian build: find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py If only supported symbols are used the return value will be 0 and the output will be empty. If there are 'unsupported' symbols, the return value will be 1 a list like this will be printed: .../64/test_bitcoin: symbol memcpy from unsupported version GLIBC_2.14 .../64/test_bitcoin: symbol __fdelt_chk from unsupported version GLIBC_2.15 .../64/test_bitcoin: symbol std::out_of_range::~out_of_range() from unsupported version GLIBCXX_3.4.15 .../64/test_bitcoin: symbol _ZNSt8__detail15_List_nod from unsupported version GLIBCXX_3.4.15 update-translations.py ====================== Run this script from the root of the repository to update all translations from transifex. It will do the following automatically: - fetch all translations - post-process them into valid and committable format - add missing translations to the build system (TODO) See doc/translation-process.md for more information. diff --git a/src/script/sighashtype.h b/src/script/sighashtype.h index 881f7cda51..2a893212dd 100644 --- a/src/script/sighashtype.h +++ b/src/script/sighashtype.h @@ -1,90 +1,90 @@ -// Copyright (c) 2017 Bitcoin ABC developers +// Copyright (c) 2017-2018 Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SCRIPT_HASH_TYPE_H #define BITCOIN_SCRIPT_HASH_TYPE_H #include "serialize.h" #include #include /** Signature hash types/flags */ enum { SIGHASH_ALL = 1, SIGHASH_NONE = 2, SIGHASH_SINGLE = 3, SIGHASH_FORKID = 0x40, SIGHASH_ANYONECANPAY = 0x80, }; /** * Base signature hash types * Base sig hash types not defined in this enum may be used, but they will be * represented as UNSUPPORTED. See transaction * c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73 for an * example where an unsupported base sig hash of 0 was used. */ enum class BaseSigHashType : uint8_t { UNSUPPORTED = 0, ALL = SIGHASH_ALL, NONE = SIGHASH_NONE, SINGLE = SIGHASH_SINGLE }; /** Signature hash type wrapper class */ class SigHashType { private: uint32_t sigHash; public: explicit SigHashType() : sigHash(SIGHASH_ALL) {} explicit SigHashType(uint32_t sigHashIn) : sigHash(sigHashIn) {} SigHashType withBaseType(BaseSigHashType baseSigHashType) const { return SigHashType((sigHash & ~0x1f) | uint32_t(baseSigHashType)); } SigHashType withForkValue(uint32_t forkId) const { return SigHashType((forkId << 8) | (sigHash & 0xff)); } SigHashType withForkId(bool forkId = true) const { return SigHashType((sigHash & ~SIGHASH_FORKID) | (forkId ? SIGHASH_FORKID : 0)); } SigHashType withAnyoneCanPay(bool anyoneCanPay = true) const { return SigHashType((sigHash & ~SIGHASH_ANYONECANPAY) | (anyoneCanPay ? SIGHASH_ANYONECANPAY : 0)); } BaseSigHashType getBaseType() const { return BaseSigHashType(sigHash & 0x1f); } uint32_t getForkValue() const { return sigHash >> 8; } bool isDefined() const { auto baseType = BaseSigHashType(sigHash & ~(SIGHASH_FORKID | SIGHASH_ANYONECANPAY)); return baseType >= BaseSigHashType::ALL && baseType <= BaseSigHashType::SINGLE; } bool hasForkId() const { return (sigHash & SIGHASH_FORKID) != 0; } bool hasAnyoneCanPay() const { return (sigHash & SIGHASH_ANYONECANPAY) != 0; } uint32_t getRawSigHashType() const { return sigHash; } template void Serialize(Stream &s) const { ::Serialize(s, getRawSigHashType()); } }; #endif // BITCOIN_SCRIPT_HASH_TYPE_H diff --git a/src/util.cpp b/src/util.cpp index 0b9f23dbce..ff885dc78a 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,653 +1,644 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) #include "config/bitcoin-config.h" #endif #include "util.h" #include "chainparamsbase.h" #include "fs.h" #include "random.h" #include "serialize.h" #include "utilstrencodings.h" #include "utiltime.h" #include #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) #include #include #endif #ifndef WIN32 // for posix_fallocate #ifdef __linux__ #ifdef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #endif #define _POSIX_C_SOURCE 200112L #endif // __linux__ #include #include #include #include #else #ifdef _MSC_VER #pragma warning(disable : 4786) #pragma warning(disable : 4804) #pragma warning(disable : 4805) #pragma warning(disable : 4717) #endif #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT 0x0501 #ifdef _WIN32_IE #undef _WIN32_IE #endif #define _WIN32_IE 0x0501 #define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX #endif #include /* for _commit */ #include #endif #ifdef HAVE_SYS_PRCTL_H #include #endif #ifdef HAVE_MALLOPT_ARENA_MAX #include #endif #include // for to_lower() #include #include // for startswith() and endswith() #include #include #include #include #include #include // Application startup time (used for uptime calculation) const int64_t nStartupTime = GetTime(); const char *const BITCOIN_CONF_FILENAME = "bitcoin.conf"; const char *const BITCOIN_PID_FILENAME = "bitcoind.pid"; ArgsManager gArgs; CTranslationInterface translationInterface; /** Init OpenSSL library multithreading support */ static CCriticalSection **ppmutexOpenSSL; void locking_callback(int mode, int i, const char *file, int line) NO_THREAD_SAFETY_ANALYSIS { if (mode & CRYPTO_LOCK) { ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]); } else { LEAVE_CRITICAL_SECTION(*ppmutexOpenSSL[i]); } } // Init class CInit { public: CInit() { // Init OpenSSL library multithreading support. ppmutexOpenSSL = (CCriticalSection **)OPENSSL_malloc( CRYPTO_num_locks() * sizeof(CCriticalSection *)); for (int i = 0; i < CRYPTO_num_locks(); i++) ppmutexOpenSSL[i] = new CCriticalSection(); CRYPTO_set_locking_callback(locking_callback); // OpenSSL can optionally load a config file which lists optional // loadable modules and engines. We don't use them so we don't require // the config. However some of our libs may call functions which attempt // to load the config file, possibly resulting in an exit() or crash if // it is missing or corrupt. Explicitly tell OpenSSL not to try to load // the file. The result for our libs will be that the config appears to // have been loaded and there are no modules/engines available. OPENSSL_no_config(); #ifdef WIN32 // Seed OpenSSL PRNG with current contents of the screen. RAND_screen(); #endif // Seed OpenSSL PRNG with performance counter. RandAddSeed(); } ~CInit() { // Securely erase the memory used by the PRNG. RAND_cleanup(); // Shutdown OpenSSL library multithreading support. CRYPTO_set_locking_callback(nullptr); for (int i = 0; i < CRYPTO_num_locks(); i++) delete ppmutexOpenSSL[i]; OPENSSL_free(ppmutexOpenSSL); } } instance_of_cinit; /** Interpret 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[]) { LOCK(cs_args); mapArgs.clear(); mapMultiArgs.clear(); 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) { strValue = str.substr(is_index + 1); str = str.substr(0, is_index); } #ifdef WIN32 boost::to_lower(str); if (boost::algorithm::starts_with(str, "/")) str = "-" + str.substr(1); #endif if (str[0] != '-') 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); } } std::vector 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) { LOCK(cs_args); if (mapArgs.count(strArg)) return mapArgs[strArg]; return strDefault; } int64_t ArgsManager::GetArg(const std::string &strArg, int64_t nDefault) { LOCK(cs_args); if (mapArgs.count(strArg)) return atoi64(mapArgs[strArg]); return nDefault; } bool ArgsManager::GetBoolArg(const std::string &strArg, bool fDefault) { LOCK(cs_args); if (mapArgs.count(strArg)) return InterpretBool(mapArgs[strArg]); 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); } /** * This function is only used for testing purpose so * so we should not worry about element uniqueness and * integrity of mapMultiArgs data structure */ void ArgsManager::ForceSetMultiArg(const std::string &strArg, const std::string &strValue) { LOCK(cs_args); if (mapArgs.count(strArg) == 0) { mapArgs[strArg] = strValue; } mapMultiArgs[strArg].push_back(strValue); } void ArgsManager::ClearArg(const std::string &strArg) { LOCK(cs_args); mapArgs.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 *pex, const char *pszThread) { #ifdef WIN32 char pszModule[MAX_PATH] = ""; GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule)); #else const char *pszModule = "bitcoin"; #endif if (pex) return strprintf("EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread); else return strprintf("UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); } void PrintExceptionContinue(const std::exception *pex, const char *pszThread) { std::string message = FormatException(pex, pszThread); LogPrintf("\n\n************************\n%s\n", message); fprintf(stderr, "\n\n************************\n%s\n", message.c_str()); } fs::path GetDefaultDataDir() { // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin // Mac: ~/Library/Application Support/Bitcoin // Unix: ~/.bitcoin #ifdef WIN32 // Windows return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin"; #else fs::path pathRet; char *pszHome = getenv("HOME"); if (pszHome == nullptr || strlen(pszHome) == 0) pathRet = fs::path("/"); else pathRet = fs::path(pszHome); #ifdef MAC_OSX // Mac return pathRet / "Library/Application Support/Bitcoin"; #else // Unix return pathRet / ".bitcoin"; #endif #endif } static fs::path pathCached; static fs::path pathCachedNetSpecific; static CCriticalSection csPathCached; const fs::path &GetDataDir(bool fNetSpecific) { LOCK(csPathCached); fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached; // This can be called during exceptions by LogPrintf(), so we cache the // value so we don't have to do memory allocations after that. if (!path.empty()) return path; if (gArgs.IsArgSet("-datadir")) { path = fs::system_complete(gArgs.GetArg("-datadir", "")); if (!fs::is_directory(path)) { path = ""; return path; } } else { path = GetDefaultDataDir(); } if (fNetSpecific) path /= BaseParams().DataDir(); fs::create_directories(path); return path; } void ClearDatadirCache() { LOCK(csPathCached); pathCached = fs::path(); pathCachedNetSpecific = fs::path(); } fs::path GetConfigFile(const std::string &confPath) { fs::path pathConfigFile(confPath); if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; return pathConfigFile; } void ArgsManager::ReadConfigFile(const std::string &confPath) { fs::ifstream streamConfig(GetConfigFile(confPath)); // No bitcoin.conf file is OK if (!streamConfig.good()) return; { LOCK(cs_args); std::set 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 bitcoin.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); } } // If datadir is changed in .conf file: ClearDatadirCache(); } #ifndef WIN32 fs::path GetPidFile() { fs::path pathPidFile(gArgs.GetArg("-pid", BITCOIN_PID_FILENAME)); if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile; return pathPidFile; } void CreatePidFile(const fs::path &path, pid_t pid) { FILE *file = fsbridge::fopen(path, "w"); if (file) { fprintf(file, "%d\n", pid); fclose(file); } } #endif bool RenameOver(fs::path src, fs::path dest) { #ifdef WIN32 return MoveFileExA(src.string().c_str(), dest.string().c_str(), MOVEFILE_REPLACE_EXISTING) != 0; #else int rc = std::rename(src.string().c_str(), dest.string().c_str()); return (rc == 0); #endif /* WIN32 */ } /** * Ignores exceptions thrown by Boost's create_directories if the requested * directory exists. Specifically handles case where path p exists, but it * wasn't possible for the user to write to the parent directory. */ bool TryCreateDirectories(const fs::path &p) { try { return fs::create_directories(p); } catch (const fs::filesystem_error &) { if (!fs::exists(p) || !fs::is_directory(p)) { throw; } } // create_directory didn't create the directory, it had to have existed // already. return false; } void FileCommit(FILE *file) { // Harmless if redundantly called. fflush(file); #ifdef WIN32 HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); FlushFileBuffers(hFile); #else #if defined(__linux__) || defined(__NetBSD__) fdatasync(fileno(file)); #elif defined(__APPLE__) && defined(F_FULLFSYNC) fcntl(fileno(file), F_FULLFSYNC, 0); #else fsync(fileno(file)); #endif #endif } bool TruncateFile(FILE *file, unsigned int length) { #if defined(WIN32) return _chsize(_fileno(file), length) == 0; #else return ftruncate(fileno(file), length) == 0; #endif } /** * This function tries to raise the file descriptor limit to the requested * number. It returns the actual file descriptor limit (which may be more or * less than nMinFD) */ int RaiseFileDescriptorLimit(int nMinFD) { #if defined(WIN32) return 2048; #else struct rlimit limitFD; if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) { if (limitFD.rlim_cur < (rlim_t)nMinFD) { limitFD.rlim_cur = nMinFD; if (limitFD.rlim_cur > limitFD.rlim_max) limitFD.rlim_cur = limitFD.rlim_max; setrlimit(RLIMIT_NOFILE, &limitFD); getrlimit(RLIMIT_NOFILE, &limitFD); } return limitFD.rlim_cur; } // getrlimit failed, assume it's fine. return nMinFD; #endif } /** * This function tries to make a particular range of a file allocated * (corresponding to disk space) it is advisory, and the range specified in the * arguments will never contain live data. */ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { #if defined(WIN32) // Windows-specific version. HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); LARGE_INTEGER nFileSize; int64_t nEndPos = (int64_t)offset + length; nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF; nFileSize.u.HighPart = nEndPos >> 32; SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN); SetEndOfFile(hFile); #elif defined(MAC_OSX) // OSX specific version. fstore_t fst; fst.fst_flags = F_ALLOCATECONTIG; fst.fst_posmode = F_PEOFPOSMODE; fst.fst_offset = 0; fst.fst_length = (off_t)offset + length; fst.fst_bytesalloc = 0; if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) { fst.fst_flags = F_ALLOCATEALL; fcntl(fileno(file), F_PREALLOCATE, &fst); } ftruncate(fileno(file), fst.fst_length); #elif defined(__linux__) // Version using posix_fallocate. off_t nEndPos = (off_t)offset + length; posix_fallocate(fileno(file), 0, nEndPos); #else // Fallback version // TODO: just write one byte per block static const char buf[65536] = {}; fseek(file, offset, SEEK_SET); while (length > 0) { unsigned int now = 65536; if (length < now) now = length; // Allowed to fail; this function is advisory anyway. fwrite(buf, 1, now, file); length -= now; } #endif } #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate) { char pszPath[MAX_PATH] = ""; if (SHGetSpecialFolderPathA(nullptr, pszPath, nFolder, fCreate)) { return fs::path(pszPath); } LogPrintf( "SHGetSpecialFolderPathA() failed, could not obtain requested path.\n"); return fs::path(""); } #endif void runCommand(const std::string &strCommand) { int nErr = ::system(strCommand.c_str()); if (nErr) LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr); } void RenameThread(const char *name) { #if defined(PR_SET_NAME) // Only the first 15 characters are used (16 - NUL terminator) ::prctl(PR_SET_NAME, name, 0, 0, 0); #elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) pthread_set_name_np(pthread_self(), name); #elif defined(MAC_OSX) pthread_setname_np(name); #else // Prevent warnings for unused parameters... (void)name; #endif } void SetupEnvironment() { #ifdef HAVE_MALLOPT_ARENA_MAX // glibc-specific: On 32-bit systems set the number of arenas to 1. By // default, since glibc 2.10, the C library will create up to two heap // arenas per core. This is known to cause excessive virtual address space // usage in our usage. Work around it by setting the maximum number of // arenas to 1. if (sizeof(void *) == 4) { mallopt(M_ARENA_MAX, 1); } #endif // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale may // be invalid, in which case the "C" locale is used as fallback. #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && \ !defined(__OpenBSD__) try { // Raises a runtime error if current locale is invalid. std::locale(""); } catch (const std::runtime_error &) { setenv("LC_ALL", "C", 1); } #endif // The path locale is lazy initialized and to avoid deinitialization errors // in multithreading environments, it is set explicitly by the main thread. // A dummy locale is used to extract the internal default locale, used by // fs::path, which is then used to explicitly imbue the path. std::locale loc = fs::path::imbue(std::locale::classic()); fs::path::imbue(loc); } bool SetupNetworking() { #ifdef WIN32 // Initialize Windows Sockets. WSADATA wsadata; int ret = WSAStartup(MAKEWORD(2, 2), &wsadata); if (ret != NO_ERROR || LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2) return false; #endif return true; } int GetNumCores() { #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 } std::string CopyrightHolders(const std::string &strPrefix) { - std::string strCopyrightHolders = - strPrefix + - strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION)); - - // Check for untranslated substitution to make sure Bitcoin ABC copyright - // is not removed by accident. - if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION) - .find("Bitcoin ABC") == std::string::npos) { - strCopyrightHolders += "\n" + strPrefix + "The Bitcoin ABC developers"; - } - return strCopyrightHolders; + return strPrefix + + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION)); } // Obtain the application startup time (used for uptime calculation) int64_t GetStartupTime() { return nStartupTime; }