PIVX Core  5.6.99
P2P Digital Currency
system.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin developers
3 // Copyright (c) 2014-2015 The Dash developers
4 // Copyright (c) 2015-2022 The PIVX Core developers
5 // Distributed under the MIT software license, see the accompanying
6 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
7 
8 #if defined(HAVE_CONFIG_H)
9 #include "config/pivx-config.h"
10 #endif
11 
12 #include "util/system.h"
13 
14 #include "chainparamsbase.h"
15 #include "random.h"
17 #include "utilstrencodings.h"
18 #include "utiltime.h"
19 
20 #include <librustzcash.h>
21 
22 #include <stdarg.h>
23 #include <thread>
24 
25 #ifndef WIN32
26 // for posix_fallocate
27 #ifdef __linux__
28 
29 #ifdef _POSIX_C_SOURCE
30 #undef _POSIX_C_SOURCE
31 #endif
32 
33 #define _POSIX_C_SOURCE 200112L
34 
35 #endif // __linux__
36 
37 #include <algorithm>
38 #include <fcntl.h>
39 #include <sched.h>
40 #include <sys/resource.h>
41 #include <sys/stat.h>
42 
43 #else
44 
45 #ifdef _MSC_VER
46 #pragma warning(disable : 4786)
47 #pragma warning(disable : 4804)
48 #pragma warning(disable : 4805)
49 #pragma warning(disable : 4717)
50 #endif
51 
52 #ifdef _WIN32_WINNT
53 #undef _WIN32_WINNT
54 #endif
55 #define _WIN32_WINNT 0x0501
56 
57 #ifdef _WIN32_IE
58 #undef _WIN32_IE
59 #endif
60 #define _WIN32_IE 0x0501
61 
62 #define WIN32_LEAN_AND_MEAN 1
63 #ifndef NOMINMAX
64 #define NOMINMAX
65 #endif
66 #include <codecvt>
67 
68 #include <io.h> /* for _commit */
69 #include <shellapi.h>
70 #include <shlobj.h>
71 #endif
72 
73 #ifdef HAVE_SYS_PRCTL_H
74 #include <sys/prctl.h>
75 #endif
76 
77 #ifdef MAC_OSX
78 #include <CoreFoundation/CoreFoundation.h>
79 #endif
80 
81 const char * const PIVX_CONF_FILENAME = "pivx.conf";
82 const char * const PIVX_MASTERNODE_CONF_FILENAME = "masternode.conf";
83 
84 
85 // PIVX only features
86 // Masternode
87 std::atomic<bool> fMasterNode{false};
88 
90 
92 
93 bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes)
94 {
95  constexpr uint64_t min_disk_space = 52428800; // 50 MiB
96 
97  uint64_t free_bytes_available = fs::space(dir).available;
98  return free_bytes_available >= min_disk_space + additional_bytes;
99 }
100 
106 static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks;
108 static std::mutex cs_dir_locks;
109 
110 bool LockDirectory(const fs::path& directory, const std::string& lockfile_name, bool probe_only)
111 {
112  std::lock_guard<std::mutex> ulock(cs_dir_locks);
113  fs::path pathLockFile = directory / lockfile_name;
114 
115  // If a lock for this directory already exists in the map, don't try to re-lock it
116  if (dir_locks.count(pathLockFile.string())) {
117  return true;
118  }
119 
120  // Create empty lock file if it doesn't exist.
121  FILE* file = fsbridge::fopen(pathLockFile, "a");
122  if (file) fclose(file);
123  auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
124  if (!lock->TryLock()) {
125  return error("Error while attempting to lock directory %s: %s", directory.string(), lock->GetReason());
126  }
127  if (!probe_only) {
128  // Lock successful and we're not just probing, put it into the map
129  dir_locks.emplace(pathLockFile.string(), std::move(lock));
130  }
131  return true;
132 }
133 
135 {
136  std::lock_guard<std::mutex> ulock(cs_dir_locks);
137  dir_locks.clear();
138 }
139 
140 bool DirIsWritable(const fs::path& directory)
141 {
142  fs::path tmpFile = directory / fs::unique_path();
143 
144  FILE* file = fsbridge::fopen(tmpFile, "a");
145  if (!file) return false;
146 
147  fclose(file);
148  remove(tmpFile);
149 
150  return true;
151 }
152 
170 static bool InterpretBool(const std::string& strValue)
171 {
172  if (strValue.empty())
173  return true;
174  return (atoi(strValue) != 0);
175 }
176 
179 public:
180  typedef std::map<std::string, std::vector<std::string>> MapArgs;
181 
184  static inline bool UseDefaultSection(const ArgsManager& am, const std::string& arg)
185  {
186  return (am.m_network == CBaseChainParams::MAIN || am.m_network_only_args.count(arg) == 0);
187  }
188 
190  static inline std::string NetworkArg(const ArgsManager& am, const std::string& arg)
191  {
192  assert(arg.length() > 1 && arg[0] == '-');
193  return "-" + am.m_network + "." + arg.substr(1);
194  }
195 
197  static inline void AddArgs(std::vector<std::string>& res, const MapArgs& map_args, const std::string& arg)
198  {
199  auto it = map_args.find(arg);
200  if (it != map_args.end()) {
201  res.insert(res.end(), it->second.begin(), it->second.end());
202  }
203  }
204 
208  static inline std::pair<bool,std::string> GetArgHelper(const MapArgs& map_args, const std::string& arg, bool getLast = false)
209  {
210  auto it = map_args.find(arg);
211 
212  if (it == map_args.end() || it->second.empty()) {
213  return std::make_pair(false, std::string());
214  }
215 
216  if (getLast) {
217  return std::make_pair(true, it->second.back());
218  } else {
219  return std::make_pair(true, it->second.front());
220  }
221  }
222 
223  /* Get the string value of an argument, returning a pair of a boolean
224  * indicating the argument was found, and the value for the argument
225  * if it was found (or the empty string if not found).
226  */
227  static inline std::pair<bool,std::string> GetArg(const ArgsManager& am, const std::string& arg)
228  {
229  LOCK(am.cs_args);
230  std::pair<bool,std::string> found_result(false, std::string());
231 
232  // We pass "true" to GetArgHelper in order to return the last
233  // argument value seen from the command line (so "pivxd -foo=bar
234  // -foo=baz" gives GetArg(am,"foo")=={true,"baz"}
235  found_result = GetArgHelper(am.m_override_args, arg, true);
236  if (found_result.first) {
237  return found_result;
238  }
239 
240  // But in contrast we return the first argument seen in a config file,
241  // so "foo=bar \n foo=baz" in the config file gives
242  // GetArg(am,"foo")={true,"bar"}
243  if (!am.m_network.empty()) {
244  found_result = GetArgHelper(am.m_config_args, NetworkArg(am, arg));
245  if (found_result.first) {
246  return found_result;
247  }
248  }
249 
250  if (UseDefaultSection(am, arg)) {
251  found_result = GetArgHelper(am.m_config_args, arg);
252  if (found_result.first) {
253  return found_result;
254  }
255  }
256 
257  return found_result;
258  }
259 
260  /* Special test for -testnet and -regtest args, because we
261  * don't want to be confused by craziness like "[regtest] testnet=1"
262  */
263  static inline bool GetNetBoolArg(const ArgsManager &am, const std::string& net_arg)
264  {
265  std::pair<bool,std::string> found_result(false,std::string());
266  found_result = GetArgHelper(am.m_override_args, net_arg, true);
267  if (!found_result.first) {
268  found_result = GetArgHelper(am.m_config_args, net_arg, true);
269  if (!found_result.first) {
270  return false; // not set
271  }
272  }
273  return InterpretBool(found_result.second); // is set, so evaluate
274  }
275 };
276 
298 static bool InterpretNegatedOption(std::string& key, std::string& val)
299 {
300  assert(key[0] == '-');
301 
302  size_t option_index = key.find('.');
303  if (option_index == std::string::npos) {
304  option_index = 1;
305  } else {
306  ++option_index;
307  }
308  if (key.substr(option_index, 2) == "no") {
309  bool bool_val = InterpretBool(val);
310  key.erase(option_index, 2);
311  if (!bool_val ) {
312  // Double negatives like -nofoo=0 are supported (but discouraged)
313  LogPrintf("Warning: parsed potentially confusing double-negative %s=%s\n", key, val);
314  val = "1";
315  } else {
316  return true;
317  }
318  }
319  return false;
320 }
321 
323  /* These options would cause cross-contamination if values for
324  * mainnet were used while running on regtest/testnet (or vice-versa).
325  * Setting them as section_only_args ensures that sharing a config file
326  * between mainnet and regtest/testnet won't cause problems due to these
327  * parameters by accident. */
328  m_network_only_args{
329  "-addnode", "-connect",
330  "-port", "-bind",
331  "-rpcport", "-rpcbind",
332  "-wallet",
333  }
334 {
335  // nothing to do
336 }
337 
339 {
340  // if there's no section selected, don't worry
341  if (m_network.empty()) return;
342 
343  // if it's okay to use the default section for this network, don't worry
344  if (m_network == CBaseChainParams::MAIN) return;
345 
346  for (const auto& arg : m_network_only_args) {
347  std::pair<bool, std::string> found_result;
348 
349  // if this option is overridden it's fine
351  if (found_result.first) continue;
352 
353  // if there's a network-specific value for this option, it's fine
355  if (found_result.first) continue;
356 
357  // if there isn't a default value for this option, it's fine
358  found_result = ArgsManagerHelper::GetArgHelper(m_config_args, arg);
359  if (!found_result.first) continue;
360 
361  // otherwise, issue a warning
362  LogPrintf("Warning: Config setting for %s only applied on %s network when in [%s] section.\n", arg, m_network, m_network);
363  }
364 }
365 
366 void ArgsManager::SelectConfigNetwork(const std::string& network)
367 {
368  m_network = network;
369 }
370 
371 void ArgsManager::ParseParameters(int argc, const char* const argv[])
372 {
373  LOCK(cs_args);
374  m_override_args.clear();
375 
376  for (int i = 1; i < argc; i++) {
377  std::string key(argv[i]);
378  std::string val;
379  size_t is_index = key.find('=');
380  if (is_index != std::string::npos) {
381  val = key.substr(is_index + 1);
382  key.erase(is_index);
383  }
384 #ifdef WIN32
385  std::transform(key.begin(), key.end(), key.begin(), ::tolower);
386  if (key[0] == '/')
387  key[0] = '-';
388 #endif
389 
390  if (key[0] != '-')
391  break;
392 
393  // Transform --foo to -foo
394  if (key.length() > 1 && key[1] == '-')
395  key.erase(0, 1);
396 
397  // Check for -nofoo
398  if (InterpretNegatedOption(key, val)) {
399  m_override_args[key].clear();
400  } else {
401  m_override_args[key].push_back(val);
402  }
403  }
404 }
405 
406 std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
407 {
408  std::vector<std::string> result = {};
409  if (IsArgNegated(strArg)) return result; // special case
410 
411  LOCK(cs_args);
412 
414  if (!m_network.empty()) {
416  }
417 
418  if (ArgsManagerHelper::UseDefaultSection(*this, strArg)) {
419  ArgsManagerHelper::AddArgs(result, m_config_args, strArg);
420  }
421 
422  return result;
423 }
424 
425 bool ArgsManager::IsArgSet(const std::string& strArg) const
426 {
427  if (IsArgNegated(strArg)) return true; // special case
428  return ArgsManagerHelper::GetArg(*this, strArg).first;
429 }
430 
431 bool ArgsManager::IsArgNegated(const std::string& strArg) const
432 {
433  LOCK(cs_args);
434 
435  const auto& ov = m_override_args.find(strArg);
436  if (ov != m_override_args.end()) return ov->second.empty();
437 
438  if (!m_network.empty()) {
439  const auto& cfs = m_config_args.find(ArgsManagerHelper::NetworkArg(*this, strArg));
440  if (cfs != m_config_args.end()) return cfs->second.empty();
441  }
442 
443  const auto& cf = m_config_args.find(strArg);
444  if (cf != m_config_args.end()) return cf->second.empty();
445 
446  return false;
447 }
448 
449 std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
450 {
451  if (IsArgNegated(strArg)) return "0";
452  std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
453  if (found_res.first) return found_res.second;
454  return strDefault;
455 }
456 
457 int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault) const
458 {
459  if (IsArgNegated(strArg)) return 0;
460  std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
461  if (found_res.first) return atoi64(found_res.second);
462  return nDefault;
463 }
464 
465 bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
466 {
467  if (IsArgNegated(strArg)) return false;
468  std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
469  if (found_res.first) return InterpretBool(found_res.second);
470  return fDefault;
471 }
472 
473 bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
474 {
475  LOCK(cs_args);
476  if (IsArgSet(strArg)) return false;
477  ForceSetArg(strArg, strValue);
478  return true;
479 }
480 
481 bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
482 {
483  if (fValue)
484  return SoftSetArg(strArg, std::string("1"));
485  else
486  return SoftSetArg(strArg, std::string("0"));
487 }
488 
489 void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
490 {
491  LOCK(cs_args);
492  m_override_args[strArg] = {strValue};
493 }
494 
495 static const int screenWidth = 79;
496 static const int optIndent = 2;
497 static const int msgIndent = 7;
498 
499 std::string HelpMessageGroup(const std::string &message) {
500  return std::string(message) + std::string("\n\n");
501 }
502 
503 std::string HelpMessageOpt(const std::string &option, const std::string &message) {
504  return std::string(optIndent,' ') + std::string(option) +
505  std::string("\n") + std::string(msgIndent,' ') +
506  FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
507  std::string("\n\n");
508 }
509 
510 static std::string FormatException(const std::exception* pex, const char* pszThread)
511 {
512 #ifdef WIN32
513  char pszModule[MAX_PATH] = "";
514  GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
515 #else
516  const char* pszModule = "pivx";
517 #endif
518  if (pex)
519  return strprintf(
520  "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
521  else
522  return strprintf(
523  "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
524 }
525 
526 void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
527 {
528  std::string message = FormatException(pex, pszThread);
529  LogPrintf("\n\n************************\n%s\n", message);
530  fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
531 }
532 
534 {
535 // Windows < Vista: C:\Documents and Settings\Username\Application Data\PIVX
536 // Windows >= Vista: C:\Users\Username\AppData\Roaming\PIVX
537 // Mac: ~/Library/Application Support/PIVX
538 // Unix: ~/.pivx
539 #ifdef WIN32
540  // Windows
541  return GetSpecialFolderPath(CSIDL_APPDATA) / "PIVX";
542 #else
543  fs::path pathRet;
544  char* pszHome = getenv("HOME");
545  if (pszHome == nullptr || strlen(pszHome) == 0)
546  pathRet = fs::path("/");
547  else
548  pathRet = fs::path(pszHome);
549 #ifdef MAC_OSX
550  // Mac
551  pathRet /= "Library/Application Support";
552  TryCreateDirectories(pathRet);
553  return pathRet / "PIVX";
554 #else
555  // Unix
556  return pathRet / ".pivx";
557 #endif
558 #endif
559 }
560 
561 static fs::path g_blocks_path_cache_net_specific;
562 static fs::path pathCached;
563 static fs::path pathCachedNetSpecific;
564 static fs::path zc_paramsPathCached;
565 static RecursiveMutex csPathCached;
566 
567 static fs::path ZC_GetBaseParamsDir()
568 {
569  // Copied from GetDefaultDataDir and adapter for zcash params.
570  // Windows < Vista: C:\Documents and Settings\Username\Application Data\PIVXParams
571  // Windows >= Vista: C:\Users\Username\AppData\Roaming\PIVXParams
572  // Mac: ~/Library/Application Support/PIVXParams
573  // Unix: ~/.pivx-params
574 #ifdef WIN32
575  // Windows
576  return GetSpecialFolderPath(CSIDL_APPDATA) / "PIVXParams";
577 #else
578  fs::path pathRet;
579  char* pszHome = getenv("HOME");
580  if (pszHome == nullptr || strlen(pszHome) == 0)
581  pathRet = fs::path("/");
582  else
583  pathRet = fs::path(pszHome);
584 #ifdef MAC_OSX
585  // Mac
586  pathRet /= "Library/Application Support";
587  TryCreateDirectories(pathRet);
588  return pathRet / "PIVXParams";
589 #else
590  // Unix
591  return pathRet / ".pivx-params";
592 #endif
593 #endif
594 }
595 
596 const fs::path &ZC_GetParamsDir()
597 {
598  LOCK(csPathCached); // Reuse the same lock as upstream.
599 
600  fs::path &path = zc_paramsPathCached;
601 
602  // This can be called during exceptions by LogPrintf(), so we cache the
603  // value so we don't have to do memory allocations after that.
604  if (!path.empty())
605  return path;
606 
607 #ifdef USE_CUSTOM_PARAMS
608  path = fs::system_complete(PARAMS_DIR);
609 #else
610  if (gArgs.IsArgSet("-paramsdir")) {
611  path = fs::system_complete(gArgs.GetArg("-paramsdir", ""));
612  if (!fs::is_directory(path)) {
613  path = "";
614  return path;
615  }
616  } else {
617  path = ZC_GetBaseParamsDir();
618  }
619 #endif
620 
621  return path;
622 }
623 
625 {
626  const fs::path& path = ZC_GetParamsDir();
627  fs::path sapling_spend = path / "sapling-spend.params";
628  fs::path sapling_output = path / "sapling-output.params";
629 
630  bool fParamsFound = false;
631  if (fs::exists(sapling_spend) && fs::exists(sapling_output)) {
632  fParamsFound = true;
633  } else {
634 #ifdef MAC_OSX
635  // macOS fallback path for params located within the app bundle
636  // This is a somewhat convoluted series of CoreFoundation calls
637  // that will result in the full path to the app bundle's "Resources"
638  // directory, which will contain the sapling params.
639  LogPrintf("Attempting to find params in app bundle...\n");
640  CFBundleRef mainBundle = CFBundleGetMainBundle();
641  CFURLRef bundleURL = CFBundleCopyBundleURL(mainBundle);
642 
643  CFStringRef strBundlePath = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
644  const char* pathBundle = CFStringGetCStringPtr(strBundlePath, CFStringGetSystemEncoding());
645 
646  fs::path bundle_path = fs::path(pathBundle);
647  LogPrintf("App bundle Resources path: %s\n", bundle_path);
648  sapling_spend = bundle_path / "Contents/Resources/sapling-spend.params";
649  sapling_output = bundle_path / "Contents/Resources/sapling-output.params";
650 
651  // Release the CF objects
652  CFRelease(strBundlePath);
653  CFRelease(bundleURL);
654  CFRelease(mainBundle);
655 #else
656  // Linux fallback path for debuild/ppa based installs
657  sapling_spend = "/usr/share/pivx/sapling-spend.params";
658  sapling_output = "/usr/share/pivx/sapling-output.params";
659  if (fs::exists(sapling_spend) && fs::exists(sapling_output)) {
660  fParamsFound = true;
661  } else {
662  // Linux fallback for local installs
663  sapling_spend = "/usr/local/share/pivx/sapling-spend.params";
664  sapling_output = "/usr/local/share/pivx/sapling-output.params";
665  }
666 #endif
667  if (fs::exists(sapling_spend) && fs::exists(sapling_output))
668  fParamsFound = true;
669  }
670  if (!fParamsFound)
671  throw std::runtime_error("Sapling params don't exist");
672 
673  static_assert(
674  sizeof(fs::path::value_type) == sizeof(codeunit),
675  "librustzcash not configured correctly");
676  auto sapling_spend_str = sapling_spend.native();
677  auto sapling_output_str = sapling_output.native();
678 
679  //LogPrintf("Loading Sapling (Spend) parameters from %s\n", sapling_spend.string().c_str());
680 
682  reinterpret_cast<const codeunit*>(sapling_spend_str.c_str()),
683  sapling_spend_str.length(),
684  "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c",
685  reinterpret_cast<const codeunit*>(sapling_output_str.c_str()),
686  sapling_output_str.length(),
687  "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028",
688  nullptr, // sprout_path
689  0, // sprout_path_len
690  "" // sprout_hash
691  );
692 
693  //std::cout << "### Sapling params initialized ###" << std::endl;
694 }
695 
696 const fs::path &GetBlocksDir()
697 {
698 
699  LOCK(csPathCached);
700 
701  fs::path &path = g_blocks_path_cache_net_specific;
702 
703  // This can be called during exceptions by LogPrintf(), so we cache the
704  // value so we don't have to do memory allocations after that.
705  if (!path.empty())
706  return path;
707 
708  if (gArgs.IsArgSet("-blocksdir")) {
709  path = fs::system_complete(gArgs.GetArg("-blocksdir", ""));
710  if (!fs::is_directory(path)) {
711  path = "";
712  return path;
713  }
714  } else {
715  path = GetDataDir(false);
716  }
717 
718  path /= BaseParams().DataDir();
719  path /= "blocks";
720  fs::create_directories(path);
721  return path;
722 }
723 
724 const fs::path& GetDataDir(bool fNetSpecific)
725 {
726  LOCK(csPathCached);
727 
728  fs::path& path = fNetSpecific ? pathCachedNetSpecific : pathCached;
729 
730  // This can be called during exceptions by LogPrintf(), so we cache the
731  // value so we don't have to do memory allocations after that.
732  if (!path.empty()) return path;
733 
734  std::string datadir = gArgs.GetArg("-datadir", "");
735  if (!datadir.empty()) {
736  path = fs::system_complete(datadir);
737  if (!fs::is_directory(path)) {
738  path = "";
739  return path;
740  }
741  } else {
742  path = GetDefaultDataDir();
743  }
744  if (fNetSpecific)
745  path /= BaseParams().DataDir();
746 
747  if (fs::create_directories(path)) {
748  // This is the first run, create wallets subdirectory too
749  fs::create_directories(path / "wallets");
750  }
751 
752  return path;
753 }
754 
756 {
757  std::string datadir = gArgs.GetArg("-datadir", "");
758  return datadir.empty() || fs::is_directory(fs::system_complete(datadir));
759 }
760 
762 {
763  LOCK(csPathCached);
764 
765  pathCached = fs::path();
766  pathCachedNetSpecific = fs::path();
767  g_blocks_path_cache_net_specific = fs::path();
768 }
769 
770 fs::path GetConfigFile(const std::string& confPath)
771 {
772  fs::path pathConfigFile(confPath);
773  return AbsPathForConfigVal(pathConfigFile, false);
774 }
775 
777 {
778  fs::path pathConfigFile(gArgs.GetArg("-mnconf", PIVX_MASTERNODE_CONF_FILENAME));
779  return AbsPathForConfigVal(pathConfigFile);
780 }
781 
782 static std::string TrimString(const std::string& str, const std::string& pattern)
783 {
784  std::string::size_type front = str.find_first_not_of(pattern);
785  if (front == std::string::npos) {
786  return std::string();
787  }
788  std::string::size_type end = str.find_last_not_of(pattern);
789  return str.substr(front, end - front + 1);
790 }
791 
792 static std::vector<std::pair<std::string, std::string>> GetConfigOptions(std::istream& stream)
793 {
794  std::vector<std::pair<std::string, std::string>> options;
795  std::string str, prefix;
796  std::string::size_type pos;
797  while (std::getline(stream, str)) {
798  if ((pos = str.find('#')) != std::string::npos) {
799  str = str.substr(0, pos);
800  }
801  const static std::string pattern = " \t\r\n";
802  str = TrimString(str, pattern);
803  if (!str.empty()) {
804  if (*str.begin() == '[' && *str.rbegin() == ']') {
805  prefix = str.substr(1, str.size() - 2) + '.';
806  } else if ((pos = str.find('=')) != std::string::npos) {
807  std::string name = prefix + TrimString(str.substr(0, pos), pattern);
808  std::string value = TrimString(str.substr(pos + 1), pattern);
809  options.emplace_back(name, value);
810  }
811  }
812  }
813  return options;
814 }
815 
816 void ArgsManager::ReadConfigStream(std::istream& stream)
817 {
818  LOCK(cs_args);
819 
820  for (const std::pair<std::string, std::string>& option : GetConfigOptions(stream)) {
821  std::string strKey = std::string("-") + option.first;
822  std::string strValue = option.second;
823 
824  if (InterpretNegatedOption(strKey, strValue)) {
825  m_config_args[strKey].clear();
826  } else {
827  m_config_args[strKey].push_back(strValue);
828  }
829  }
830 }
831 
832 void ArgsManager::ReadConfigFile(const std::string& confPath)
833 {
834  {
835  LOCK(cs_args);
836  m_config_args.clear();
837  }
838 
839  fsbridge::ifstream stream(GetConfigFile(confPath));
840 
841  // ok to not have a config file
842  if (stream.good()) {
843  ReadConfigStream(stream);
844  }
845 
846  // If datadir is changed in .conf file:
848  if (!CheckDataDirOption()) {
849  throw std::runtime_error(strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str()));
850  }
851 }
852 
853 fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific)
854 {
855  if (path.is_absolute()) {
856  return path;
857  }
858  return fs::absolute(path, GetDataDir(net_specific));
859 }
860 
861 std::string ArgsManager::GetChainName() const
862 {
863  bool fRegTest = ArgsManagerHelper::GetNetBoolArg(*this, "-regtest");
864  bool fTestNet = ArgsManagerHelper::GetNetBoolArg(*this, "-testnet");
865 
866  if (fTestNet && fRegTest)
867  throw std::runtime_error("Invalid combination of -regtest and -testnet.");
868  if (fRegTest)
870  if (fTestNet)
872  return CBaseChainParams::MAIN;
873 }
874 
875 bool RenameOver(fs::path src, fs::path dest)
876 {
877 #ifdef WIN32
878  return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(),
879  MOVEFILE_REPLACE_EXISTING) != 0;
880 #else
881  int rc = std::rename(src.string().c_str(), dest.string().c_str());
882  return (rc == 0);
883 #endif /* WIN32 */
884 }
885 
891 bool TryCreateDirectories(const fs::path& p)
892 {
893  try {
894  return fs::create_directories(p);
895  } catch (const fs::filesystem_error&) {
896  if (!fs::exists(p) || !fs::is_directory(p))
897  throw;
898  }
899 
900  // create_directories didn't create the directory, it had to have existed already
901  return false;
902 }
903 
904 bool FileCommit(FILE* file)
905 {
906  if (fflush(file) != 0) { // harmless if redundantly called
907  LogPrintf("%s: fflush failed: %d\n", __func__, errno);
908  return false;
909  }
910 #ifdef WIN32
911  HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
912  if (FlushFileBuffers(hFile) == 0) {
913  LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
914  return false;
915  }
916 #else
917  #if defined(__linux__) || defined(__NetBSD__)
918  if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
919  LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
920  return false;
921  }
922  #elif defined(MAC_OSX) && defined(F_FULLFSYNC)
923  if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
924  LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
925  return false;
926  }
927  #else
928  if (fsync(fileno(file)) != 0 && errno != EINVAL) {
929  LogPrintf("%s: fsync failed: %d\n", __func__, errno);
930  return false;
931  }
932  #endif
933 #endif
934  return true;
935 }
936 
937 bool TruncateFile(FILE* file, unsigned int length)
938 {
939 #if defined(WIN32)
940  return _chsize(_fileno(file), length) == 0;
941 #else
942  return ftruncate(fileno(file), length) == 0;
943 #endif
944 }
945 
951 {
952 #if defined(WIN32)
953  return 2048;
954 #else
955  struct rlimit limitFD;
956  if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
957  if (limitFD.rlim_cur < (rlim_t)nMinFD) {
958  limitFD.rlim_cur = nMinFD;
959  if (limitFD.rlim_cur > limitFD.rlim_max)
960  limitFD.rlim_cur = limitFD.rlim_max;
961  setrlimit(RLIMIT_NOFILE, &limitFD);
962  getrlimit(RLIMIT_NOFILE, &limitFD);
963  }
964  return limitFD.rlim_cur;
965  }
966  return nMinFD; // getrlimit failed, assume it's fine
967 #endif
968 }
969 
974 void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length)
975 {
976 #if defined(WIN32)
977  // Windows-specific version
978  HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
979  LARGE_INTEGER nFileSize;
980  int64_t nEndPos = (int64_t)offset + length;
981  nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
982  nFileSize.u.HighPart = nEndPos >> 32;
983  SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
984  SetEndOfFile(hFile);
985 #elif defined(MAC_OSX)
986  // OSX specific version
987  fstore_t fst;
988  fst.fst_flags = F_ALLOCATECONTIG;
989  fst.fst_posmode = F_PEOFPOSMODE;
990  fst.fst_offset = 0;
991  fst.fst_length = (off_t)offset + length;
992  fst.fst_bytesalloc = 0;
993  if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
994  fst.fst_flags = F_ALLOCATEALL;
995  fcntl(fileno(file), F_PREALLOCATE, &fst);
996  }
997  ftruncate(fileno(file), fst.fst_length);
998 #elif defined(__linux__)
999  // Version using posix_fallocate
1000  off_t nEndPos = (off_t)offset + length;
1001  posix_fallocate(fileno(file), 0, nEndPos);
1002 #else
1003  // Fallback version
1004  // TODO: just write one byte per block
1005  static const char buf[65536] = {};
1006  fseek(file, offset, SEEK_SET);
1007  while (length > 0) {
1008  unsigned int now = 65536;
1009  if (length < now)
1010  now = length;
1011  fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
1012  length -= now;
1013  }
1014 #endif
1015 }
1016 
1017 #ifdef WIN32
1018 fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
1019 {
1020  WCHAR pszPath[MAX_PATH] = L"";
1021 
1022  if (SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate)) {
1023  return fs::path(pszPath);
1024  }
1025 
1026  LogPrintf("SHGetSpecialFolderPathW() failed, could not obtain requested path.\n");
1027  return fs::path("");
1028 }
1029 #endif
1030 
1031 void runCommand(std::string strCommand)
1032 {
1033  if (strCommand.empty()) return;
1034 #ifndef WIN32
1035  int nErr = ::system(strCommand.c_str());
1036 #else
1037  int nErr = ::_wsystem(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().from_bytes(strCommand).c_str());
1038 #endif
1039  if (nErr)
1040  LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
1041 }
1042 
1044 {
1045 // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale
1046 // may be invalid, in which case the "C" locale is used as fallback.
1047 #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
1048  try {
1049  std::locale(""); // Raises a runtime error if current locale is invalid
1050  } catch (const std::runtime_error&) {
1051  setenv("LC_ALL", "C", 1);
1052  }
1053 #elif defined(WIN32)
1054  // Set the default input/output charset is utf-8
1055  SetConsoleCP(CP_UTF8);
1056  SetConsoleOutputCP(CP_UTF8);
1057 #endif
1058  // The path locale is lazy initialized and to avoid deinitialization errors
1059  // in multithreading environments, it is set explicitly by the main thread.
1060  // A dummy locale is used to extract the internal default locale, used by
1061  // fs::path, which is then used to explicitly imbue the path.
1062  std::locale loc = fs::path::imbue(std::locale::classic());
1063 #ifndef WIN32
1064  fs::path::imbue(loc);
1065 #else
1066  fs::path::imbue(std::locale(loc, new std::codecvt_utf8_utf16<wchar_t>()));
1067 #endif
1068 }
1069 
1071 {
1072 #ifdef WIN32
1073  // Initialize Windows Sockets
1074  WSADATA wsadata;
1075  int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
1076  if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
1077  return false;
1078 #endif
1079  return true;
1080 }
1081 
1082 void SetThreadPriority(int nPriority)
1083 {
1084 #ifdef WIN32
1085  SetThreadPriority(GetCurrentThread(), nPriority);
1086 #else // WIN32
1087 #ifdef PRIO_THREAD
1088  setpriority(PRIO_THREAD, 0, nPriority);
1089 #else // PRIO_THREAD
1090  setpriority(PRIO_PROCESS, 0, nPriority);
1091 #endif // PRIO_THREAD
1092 #endif // WIN32
1093 }
1094 
1096 {
1097  return std::thread::hardware_concurrency();
1098 }
1099 
1100 
1102 {
1103 #ifdef SCHED_BATCH
1104  const static sched_param param{0};
1105  if (int ret = pthread_setschedparam(pthread_self(), SCHED_BATCH, &param)) {
1106  LogPrintf("Failed to pthread_setschedparam: %s\n", strerror(errno));
1107  return ret;
1108  }
1109  return 0;
1110 #else
1111  return 1;
1112 #endif
1113 }
1114 
1115 namespace util {
1116 #ifdef WIN32
1117  WinCmdLineArgs::WinCmdLineArgs()
1118 {
1119  wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
1120  std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt;
1121  argv = new char*[argc];
1122  args.resize(argc);
1123  for (int i = 0; i < argc; i++) {
1124  args[i] = utf8_cvt.to_bytes(wargv[i]);
1125  argv[i] = &*args[i].begin();
1126  }
1127  LocalFree(wargv);
1128 }
1129 
1130 WinCmdLineArgs::~WinCmdLineArgs()
1131 {
1132  delete[] argv;
1133 }
1134 
1135 std::pair<int, char**> WinCmdLineArgs::get()
1136 {
1137  return std::make_pair(argc, argv);
1138 }
1139 #endif
1140 } // namespace util
1141 
const CBaseChainParams & BaseParams()
Return the currently selected parameters.
Internal helper functions for ArgsManager.
Definition: system.cpp:178
static std::pair< bool, std::string > GetArgHelper(const MapArgs &map_args, const std::string &arg, bool getLast=false)
Return true/false if an argument is set in a map, and also return the first (or last) of the possibly...
Definition: system.cpp:208
std::map< std::string, std::vector< std::string > > MapArgs
Definition: system.cpp:180
static void AddArgs(std::vector< std::string > &res, const MapArgs &map_args, const std::string &arg)
Find arguments in a map and add them to a vector.
Definition: system.cpp:197
static std::string NetworkArg(const ArgsManager &am, const std::string &arg)
Convert regular argument into the network-specific setting.
Definition: system.cpp:190
static std::pair< bool, std::string > GetArg(const ArgsManager &am, const std::string &arg)
Definition: system.cpp:227
static bool UseDefaultSection(const ArgsManager &am, const std::string &arg)
Determine whether to use config settings in the default section, See also comments around ArgsManager...
Definition: system.cpp:184
static bool GetNetBoolArg(const ArgsManager &am, const std::string &net_arg)
Definition: system.cpp:263
void ReadConfigFile(const std::string &confPath)
Definition: system.cpp:832
bool IsArgNegated(const std::string &strArg) const
Return true if the argument was originally passed as a negated option, i.e.
Definition: system.cpp:431
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: system.cpp:489
void ParseParameters(int argc, const char *const argv[])
Definition: system.cpp:371
std::vector< std::string > GetArgs(const std::string &strArg) const
Return a vector of strings of the given argument.
Definition: system.cpp:406
std::map< std::string, std::vector< std::string > > m_override_args
Definition: system.h:133
std::set< std::string > m_network_only_args
Definition: system.h:136
bool SoftSetArg(const std::string &strArg, const std::string &strValue)
Set an argument if it doesn't already have a value.
Definition: system.cpp:473
void SelectConfigNetwork(const std::string &network)
Select the network in use.
Definition: system.cpp:366
std::map< std::string, std::vector< std::string > > m_config_args
Definition: system.h:134
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: system.cpp:425
void WarnForSectionOnlyArgs()
Log warnings for options in m_section_only_args when they are specified in the default section but no...
Definition: system.cpp:338
void ReadConfigStream(std::istream &stream)
Definition: system.cpp:816
std::string m_network
Definition: system.h:135
RecursiveMutex cs_args
Definition: system.h:132
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:449
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
Definition: system.cpp:481
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: system.cpp:465
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
Definition: system.cpp:861
static const std::string REGTEST
const std::string & DataDir() const
static const std::string TESTNET
static const std::string MAIN
Chain name strings.
Server/client environment: argument handling, config file parsing, thread wrappers.
Definition: system.h:44
#define MAX_PATH
Definition: compat.h:74
char ** argv
Definition: fuzz.cpp:52
#define L(x0, x1, x2, x3, x4, x5, x6, x7)
Definition: jh.c:501
void librustzcash_init_zksnark_params(const codeunit *spend_path, size_t spend_path_len, const char *spend_hash, const codeunit *output_path, size_t output_path_len, const char *output_hash, const codeunit *sprout_path, size_t sprout_path_len, const char *sprout_hash)
Loads the zk-SNARK parameters into memory and saves paths as necessary.
uint8_t codeunit
Definition: librustzcash.h:10
@ LOCK
Definition: lockunlock.h:16
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:23
fs::ifstream ifstream
Definition: fs.h:92
#define PARAMS_DIR
Definition: pivx-config.h:381
const char * prefix
Definition: rest.cpp:564
const char * name
Definition: rest.cpp:37
CTranslationInterface translationInterface
Definition: system.cpp:91
fs::path GetDefaultDataDir()
Definition: system.cpp:533
fs::path AbsPathForConfigVal(const fs::path &path, bool net_specific)
Definition: system.cpp:853
const char *const PIVX_CONF_FILENAME
Definition: system.cpp:81
void initZKSNARKS()
Definition: system.cpp:624
bool CheckDataDirOption()
Definition: system.cpp:755
bool DirIsWritable(const fs::path &directory)
Definition: system.cpp:140
bool RenameOver(fs::path src, fs::path dest)
Definition: system.cpp:875
bool SetupNetworking()
Definition: system.cpp:1070
const fs::path & ZC_GetParamsDir()
Definition: system.cpp:596
int RaiseFileDescriptorLimit(int nMinFD)
this function tries to raise the file descriptor limit to the requested number.
Definition: system.cpp:950
const fs::path & GetDataDir(bool fNetSpecific)
Definition: system.cpp:724
void ReleaseDirectoryLocks()
Release all directory locks.
Definition: system.cpp:134
int ScheduleBatchPriority(void)
On platforms that support it, tell the kernel the calling thread is CPU-intensive and non-interactive...
Definition: system.cpp:1101
void SetThreadPriority(int nPriority)
Definition: system.cpp:1082
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by Boost's create_directories if the requested directory exists.
Definition: system.cpp:891
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length)
this function tries to make a particular range of a file allocated (corresponding to disk space) it i...
Definition: system.cpp:974
ArgsManager gArgs
Definition: system.cpp:89
const char *const PIVX_MASTERNODE_CONF_FILENAME
Definition: system.cpp:82
std::atomic< bool > fMasterNode
Definition: system.cpp:87
void SetupEnvironment()
Definition: system.cpp:1043
fs::path GetConfigFile(const std::string &confPath)
Definition: system.cpp:770
void PrintExceptionContinue(const std::exception *pex, const char *pszThread)
Definition: system.cpp:526
std::string HelpMessageGroup(const std::string &message)
Format a string to be used as group of options in help messages.
Definition: system.cpp:499
bool CheckDiskSpace(const fs::path &dir, uint64_t additional_bytes)
Definition: system.cpp:93
bool LockDirectory(const fs::path &directory, const std::string &lockfile_name, bool probe_only)
Definition: system.cpp:110
void ClearDatadirCache()
Definition: system.cpp:761
fs::path GetMasternodeConfigFile()
Definition: system.cpp:776
bool TruncateFile(FILE *file, unsigned int length)
Definition: system.cpp:937
const fs::path & GetBlocksDir()
Definition: system.cpp:696
void runCommand(std::string strCommand)
Definition: system.cpp:1031
int GetNumCores()
Return the number of cores available on the current system.
Definition: system.cpp:1095
std::string HelpMessageOpt(const std::string &option, const std::string &message)
Format a string to be used as option description in help messages.
Definition: system.cpp:503
bool FileCommit(FILE *file)
Definition: system.cpp:904
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
#define strprintf
Definition: tinyformat.h:1056
int64_t atoi64(const char *psz)
std::string FormatParagraph(const std::string in, size_t width, size_t indent)
Format a paragraph of text to a fixed width, adding spaces for indentation to any added line.
int atoi(const std::string &str)