diff --git a/configure.ac b/configure.ac index 7a373f8e28eb..ad7707bdf0f0 100644 --- a/configure.ac +++ b/configure.ac @@ -1091,6 +1091,29 @@ if test x$use_reduce_exports = xyes; then [AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduce-exports.])]) fi +AC_MSG_CHECKING([for std::system]) +AC_LINK_IFELSE( + [ AC_LANG_PROGRAM( + [[ #include ]], + [[ int nErr = std::system(""); ]] + )], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_STD__SYSTEM, 1, Define to 1 if you have the `std::system' function.)], + [ AC_MSG_RESULT(no) ] +) + +AC_MSG_CHECKING([for ::_wsystem]) +AC_LINK_IFELSE( + [ AC_LANG_PROGRAM( + [[ ]], + [[ int nErr = ::_wsystem(""); ]] + )], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_WSYSTEM, 1, Define to 1 if you have the `::wsystem' function.)], + [ AC_MSG_RESULT(no) ] +) + +# Define to 1 if std::system or ::wsystem (Windows) is available +AC_DEFINE([HAVE_SYSTEM], [HAVE_STD__SYSTEM || HAVE_WSYSTEM], [std::system or ::wsystem]) + LEVELDB_CPPFLAGS= LIBLEVELDB= LIBMEMENV= diff --git a/depends/packages/dbus.mk b/depends/packages/dbus.mk deleted file mode 100644 index bbe03754099f..000000000000 --- a/depends/packages/dbus.mk +++ /dev/null @@ -1,23 +0,0 @@ -package=dbus -$(package)_version=1.10.18 -$(package)_download_path=https://dbus.freedesktop.org/releases/dbus -$(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=6049ddd5f3f3e2618f615f1faeda0a115104423a7996b7aa73e2f36e38cc514a -$(package)_dependencies=expat - -define $(package)_set_vars - $(package)_config_opts=--disable-tests --disable-doxygen-docs --disable-xml-docs --disable-static --without-x -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -C dbus libdbus-1.la -endef - -define $(package)_stage_cmds - $(MAKE) -C dbus DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-dbusincludeHEADERS install-nodist_dbusarchincludeHEADERS && \ - $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA -endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index bcabf33b15a3..ae3018b61ad9 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -3,7 +3,7 @@ packages:=boost openssl libevent zeromq gmp bls-dash backtrace cmake immer qt_native_packages = native_protobuf qt_packages = qrencode protobuf zlib -qt_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig +qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig qt_darwin_packages=qt qt_mingw32_packages=qt diff --git a/src/dashd.cpp b/src/dashd.cpp index db0846c6002b..579c98060329 100644 --- a/src/dashd.cpp +++ b/src/dashd.cpp @@ -12,21 +12,20 @@ #include #include #include -#include #include #include +#include #include #include +#include +#include #include #include #include -#include #include #include #include -#include - const std::function G_TRANSLATION_FUN = nullptr; /* Introduction text for doxygen: */ @@ -74,8 +73,7 @@ static bool AppInit(int argc, char* argv[]) SetupServerArgs(); std::string error; if (!gArgs.ParseParameters(argc, argv, error)) { - fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str()); - return false; + return InitError(strprintf("Error parsing command line arguments: %s\n", error)); } if (gArgs.IsArgSet("-printcrashinfo")) { @@ -106,12 +104,10 @@ static bool AppInit(int argc, char* argv[]) bool datadirFromCmdLine = gArgs.IsArgSet("-datadir"); if (datadirFromCmdLine && !fs::is_directory(GetDataDir(false))) { - fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str()); - return false; + return InitError(strprintf("Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""))); } if (!gArgs.ReadConfigFiles(error, true)) { - fprintf(stderr, "Error reading configuration file: %s\n", error.c_str()); - return false; + return InitError(strprintf("Error reading configuration file: %s\n", error)); } if (!datadirFromCmdLine && !fs::is_directory(GetDataDir(false))) { @@ -122,15 +118,13 @@ static bool AppInit(int argc, char* argv[]) try { SelectParams(gArgs.GetChainName()); } catch (const std::exception& e) { - fprintf(stderr, "Error: %s\n", e.what()); - return false; + return InitError(strprintf("%s\n", e.what())); } // Error out when loose non-argument tokens are encountered on command line for (int i = 1; i < argc; i++) { if (!IsSwitchChar(argv[i][0])) { - fprintf(stderr, "Error: Command line contains unexpected token '%s', see dashd -h for a list of options.\n", argv[i]); - return false; + return InitError(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i])); } } @@ -161,19 +155,17 @@ static bool AppInit(int argc, char* argv[]) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif - fprintf(stdout, "Dash Core server starting\n"); + tfm::format(std::cout, PACKAGE_NAME "daemon starting\n"); // Daemonize if (daemon(1, 0)) { // don't chdir (1), do close FDs (0) - fprintf(stderr, "Error: daemon() failed: %s\n", strerror(errno)); - return false; + return InitError(strprintf("daemon() failed: %s\n", strerror(errno))); } #if defined(MAC_OSX) #pragma GCC diagnostic pop #endif #else - fprintf(stderr, "Error: -daemon is not supported on this operating system\n"); - return false; + return InitError("-daemon is not supported on this operating system\n"); #endif // HAVE_DECL_DAEMON } // Lock data directory after daemonization diff --git a/src/init.cpp b/src/init.cpp index d837a483e5e1..225fae676968 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -492,10 +492,14 @@ void SetupServerArgs() // Set all of the args and their help // When adding new options to the categories, please keep and ensure alphabetical ordering. gArgs.AddArg("-?", "Print this help message and exit", false, OptionsCategory::OPTIONS); +#if HAVE_SYSTEM gArgs.AddArg("-alertnotify=", "Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)", false, OptionsCategory::OPTIONS); +#endif gArgs.AddArg("-assumevalid=", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()), false, OptionsCategory::OPTIONS); gArgs.AddArg("-blocksdir=", "Specify directory to hold blocks subdirectory for *.dat files (default: )", false, OptionsCategory::OPTIONS); +#if HAVE_SYSTEM gArgs.AddArg("-blocknotify=", "Execute command when the best block changes (%s in cmd is replaced by block hash)", false, OptionsCategory::OPTIONS); +#endif gArgs.AddArg("-blockreconstructionextratxn=", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), false, OptionsCategory::OPTIONS); gArgs.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Transactions from the wallet or RPC are not affected. (default: %u)", DEFAULT_BLOCKSONLY), false, OptionsCategory::OPTIONS); gArgs.AddArg("-conf=", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS); @@ -784,6 +788,7 @@ std::string LicenseInfo() "\n"; } +#if HAVE_SYSTEM static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex) { if (initialSync || !pBlockIndex) @@ -796,6 +801,7 @@ static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex t.detach(); // thread runs free } } +#endif static bool fHaveGenesis = false; static Mutex g_genesis_wait_mutex; @@ -2388,8 +2394,10 @@ bool AppInitMain(InitInterfaces& interfaces) fHaveGenesis = true; } +#if HAVE_SYSTEM if (gArgs.IsArgSet("-blocknotify")) uiInterface.NotifyBlockTip_connect(BlockNotifyCallback); +#endif std::vector vImportFiles; for (const std::string& strFile : gArgs.GetArgs("-loadblock")) { diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 4da114d66595..8219a4c80c54 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -159,6 +159,7 @@ class NodeImpl : public Node { public: NodeImpl() { m_interfaces.chain = MakeChain(); } + void initError(const std::string& message) override { InitError(message); } EVOImpl m_evo; LLMQImpl m_llmq; diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 40f68e30521c..b393d6fdbf42 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -93,6 +93,9 @@ class Node public: virtual ~Node() {} + //! Send init error. + virtual void initError(const std::string& message) = 0; + //! Set command line arguments. virtual bool parseParameters(int argc, const char* const argv[], std::string& error) = 0; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index bb982547a303..8ce244246fca 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -37,9 +37,6 @@ #include #include -#include -#include - #include #include #include diff --git a/src/qt/dash.cpp b/src/qt/dash.cpp index 01471ea04e70..78dc70097712 100644 --- a/src/qt/dash.cpp +++ b/src/qt/dash.cpp @@ -11,8 +11,8 @@ #include #include -#include #include +#include #include #include #include @@ -41,9 +41,6 @@ #include #include -#include - -#include #include #include @@ -486,8 +483,11 @@ int GuiMain(int argc, char* argv[]) SetupUIArgs(); std::string error; if (!node->parseParameters(argc, argv, error)) { + node->initError(strprintf("Error parsing command line arguments: %s\n", error)); + // Create a message box, because the gui has neither been created nor has subscribed to core signals QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), - QObject::tr("Error parsing command line arguments: %1.").arg(QString::fromStdString(error))); + // message can not be translated because translations have not been initialized + QString::fromStdString("Error parsing command line arguments: %1.").arg(QString::fromStdString(error))); return EXIT_FAILURE; } @@ -530,11 +530,13 @@ int GuiMain(int argc, char* argv[]) /// - Do not call GetDataDir(true) before this step finishes if (!fs::is_directory(GetDataDir(false))) { + node->initError(strprintf("Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""))); QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", "")))); return EXIT_FAILURE; } if (!node->readConfigFiles(error)) { + node->initError(strprintf("Error reading configuration file: %s\n", error)); QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error))); return EXIT_FAILURE; @@ -550,6 +552,7 @@ int GuiMain(int argc, char* argv[]) try { node->selectParams(gArgs.GetChainName()); } catch(std::exception &e) { + node->initError(strprintf("%s\n", e.what())); QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what())); return EXIT_FAILURE; } diff --git a/src/qt/dash.h b/src/qt/dash.h index 276b0e794df2..c48a2ac1b565 100644 --- a/src/qt/dash.h +++ b/src/qt/dash.h @@ -11,7 +11,6 @@ #include #include -#include class BitcoinGUI; class ClientModel; diff --git a/src/uint256.cpp b/src/uint256.cpp index 2872901a6523..7fdaf34b722b 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -41,16 +41,15 @@ void base_blob::SetHex(const char* psz) psz += 2; // hex string to uint - const char* pbegin = psz; - while (::HexDigit(*psz) != -1) - psz++; - psz--; + size_t digits = 0; + while (::HexDigit(psz[digits]) != -1) + digits++; unsigned char* p1 = (unsigned char*)m_data; unsigned char* pend = p1 + WIDTH; - while (psz >= pbegin && p1 < pend) { - *p1 = ::HexDigit(*psz--); - if (psz >= pbegin) { - *p1 |= ((unsigned char)::HexDigit(*psz--) << 4); + while (digits > 0 && p1 < pend) { + *p1 = ::HexDigit(psz[--digits]); + if (digits > 0) { + *p1 |= ((unsigned char)::HexDigit(psz[--digits]) << 4); p1++; } } diff --git a/src/util/system.cpp b/src/util/system.cpp index 551c41ea868f..f6839c19aebe 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -1205,6 +1205,7 @@ fs::path GetSpecialFolderPath(int nFolder, bool fCreate) } #endif +#if HAVE_SYSTEM void runCommand(const std::string& strCommand) { if (strCommand.empty()) return; @@ -1216,6 +1217,7 @@ void runCommand(const std::string& strCommand) if (nErr) LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr); } +#endif void RenameThreadPool(ctpl::thread_pool& tp, const char* baseName) { diff --git a/src/util/system.h b/src/util/system.h index de58651f0fa1..99472605f34c 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -112,7 +112,9 @@ fs::path GetConfigFile(const std::string& confPath); #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif +#if HAVE_SYSTEM void runCommand(const std::string& strCommand); +#endif /** * Most paths passed as configuration arguments are treated as relative to diff --git a/src/validation.cpp b/src/validation.cpp index 6d281e53b513..76eeabb7c3dd 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1278,6 +1278,7 @@ CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr; static void AlertNotify(const std::string& strMessage) { uiInterface.NotifyAlertChanged(); +#if HAVE_SYSTEM std::string strCmd = gArgs.GetArg("-alertnotify", ""); if (strCmd.empty()) return; @@ -1291,6 +1292,7 @@ static void AlertNotify(const std::string& strMessage) std::thread t(runCommand, strCmd); t.detach(); // thread runs free +#endif } static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main) diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 23e6ec48f46b..a84a02031287 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -62,7 +62,9 @@ void WalletInit::AddWalletOptions() const gArgs.AddArg("-walletbackupsdir=", "Specify full path to directory for automatic wallet backups (must exist)", false, OptionsCategory::WALLET); gArgs.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), false, OptionsCategory::WALLET); gArgs.AddArg("-walletdir=", "Specify directory to hold wallets (default: /wallets if it exists, otherwise )", false, OptionsCategory::WALLET); +#if HAVE_SYSTEM gArgs.AddArg("-walletnotify=", "Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)", false, OptionsCategory::WALLET); +#endif gArgs.AddArg("-zapwallettxes=", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup" " (1 = keep tx meta data e.g. payment request information, 2 = drop tx meta data)", false, OptionsCategory::WALLET); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 80d7d6642b52..5e022e095519 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1125,6 +1125,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) // Notify UI of new or updated transaction NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); +#if HAVE_SYSTEM // notify an external script when a wallet transaction comes in or is updated std::string strCmd = gArgs.GetArg("-walletnotify", ""); @@ -1134,6 +1135,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) std::thread t(runCommand, strCmd); t.detach(); // thread runs free } +#endif fAnonymizableTallyCached = false; fAnonymizableTallyCachedNonDenom = false; diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 2c2904aa29fc..ec454cecbb6b 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -22,7 +22,7 @@ def test_config_file_parser(self): conf.write('includeconf={}\n'.format(inc_conf_file_path)) self.nodes[0].assert_start_raises_init_error( - expected_msg='Error parsing command line arguments: Invalid parameter -dash_cli', + expected_msg='Error: Error parsing command line arguments: Invalid parameter -dash_cli', extra_args=['-dash_cli=1'], ) with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: @@ -33,7 +33,7 @@ def test_config_file_parser(self): with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('-dash=1\n') - self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -') + self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -') with open(inc_conf_file_path, 'w', encoding='utf8') as conf: conf.write("wallet=foo\n") @@ -41,19 +41,19 @@ def test_config_file_parser(self): with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('nono\n') - self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: nono, if you intended to specify a negated option, use nono=1 instead') + self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Error reading configuration file: parse error on line 1: nono, if you intended to specify a negated option, use nono=1 instead') with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('server=1\nrpcuser=someuser\nrpcpassword=some#pass') - self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided') + self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided') with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('server=1\nrpcuser=someuser\nmain.rpcpassword=some#pass') - self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided') + self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided') with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('server=1\nrpcuser=someuser\n[main]\nrpcpassword=some#pass') - self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 4, using # in rpcpassword can be ambiguous and should be avoided') + self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Error reading configuration file: parse error on line 4, using # in rpcpassword can be ambiguous and should be avoided') inc_conf_file2_path = os.path.join(self.nodes[0].datadir, 'include2.conf') with open(os.path.join(self.nodes[0].datadir, 'dash.conf'), 'a', encoding='utf-8') as conf: diff --git a/test/functional/feature_includeconf.py b/test/functional/feature_includeconf.py index e497d4211467..ab93b1373465 100755 --- a/test/functional/feature_includeconf.py +++ b/test/functional/feature_includeconf.py @@ -43,7 +43,7 @@ def run_test(self): self.log.info("-includeconf cannot be used as command-line arg") self.stop_node(0) - self.nodes[0].assert_start_raises_init_error(extra_args=["-includeconf=relative2.conf"], expected_msg="Error parsing command line arguments: -includeconf cannot be used from commandline; -includeconf=relative2.conf") + self.nodes[0].assert_start_raises_init_error(extra_args=["-includeconf=relative2.conf"], expected_msg="Error: Error parsing command line arguments: -includeconf cannot be used from commandline; -includeconf=relative2.conf") self.log.info("-includeconf cannot be used recursively. subversion should end with 'main; relative)/'") with open(os.path.join(self.options.tmpdir, "node0", "relative.conf"), "a", encoding="utf8") as f: @@ -59,11 +59,11 @@ def run_test(self): # Commented out as long as we ignore invalid arguments in configuration files #with open(os.path.join(self.options.tmpdir, "node0", "relative.conf"), "w", encoding="utf8") as f: # f.write("foo=bar\n") - #self.nodes[0].assert_start_raises_init_error(expected_msg="Error reading configuration file: Invalid configuration value foo") + #self.nodes[0].assert_start_raises_init_error(expected_msg="Error: Error reading configuration file: Invalid configuration value foo") self.log.info("-includeconf cannot be invalid path") os.remove(os.path.join(self.options.tmpdir, "node0", "relative.conf")) - self.nodes[0].assert_start_raises_init_error(expected_msg="Error reading configuration file: Failed to include configuration file relative.conf") + self.nodes[0].assert_start_raises_init_error(expected_msg="Error: Error reading configuration file: Failed to include configuration file relative.conf") self.log.info("multiple -includeconf args can be used from the base config file. subversion should end with 'main; relative; relative2)/'") with open(os.path.join(self.options.tmpdir, "node0", "relative.conf"), "w", encoding="utf8") as f: