From d10b1b59a11f6ebf22671a077d210445df98cc8e Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 14 Dec 2020 23:22:43 -0300 Subject: [PATCH 01/22] scripted-diff: Avoid `interface` keyword. Rename `interface` dir to `interfaces` -BEGIN VERIFY SCRIPT- git mv src/interface src/interfaces git grep -l "interface/" | xargs sed -i "s,interface/,interfaces/,g"; -END VERIFY SCRIPT- --- CMakeLists.txt | 2 +- src/Makefile.am | 4 ++-- src/{interface => interfaces}/wallet.cpp | 2 +- src/{interface => interfaces}/wallet.h | 0 src/qt/walletmodel.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename src/{interface => interfaces}/wallet.cpp (97%) rename src/{interface => interfaces}/wallet.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 00de5c2a9128..8950cd49bdac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,7 +194,7 @@ set(SERVER_SOURCES ./src/httprpc.cpp ./src/httpserver.cpp ./src/init.cpp - ./src/interface/wallet.cpp + ./src/interfaces/wallet.cpp ./src/dbwrapper.cpp ./src/legacy/validation_zerocoin_legacy.cpp ./src/merkleblock.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 513a08125860..b6e42c786c90 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -190,7 +190,7 @@ BITCOIN_CORE_H = \ httprpc.h \ httpserver.h \ init.h \ - interface/wallet.h \ + interfaces/wallet.h \ invalid.h \ invalid_outpoints.json.h \ invalid_serials.json.h \ @@ -373,7 +373,7 @@ libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ activemasternode.cpp \ bip38.cpp \ - interface/wallet.cpp \ + interfaces/wallet.cpp \ addressbook.cpp \ crypter.cpp \ key_io.cpp \ diff --git a/src/interface/wallet.cpp b/src/interfaces/wallet.cpp similarity index 97% rename from src/interface/wallet.cpp rename to src/interfaces/wallet.cpp index ca9abcac0c3d..52fa57150613 100644 --- a/src/interface/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -3,7 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://www.opensource.org/licenses/mit-license.php. -#include "interface/wallet.h" +#include "interfaces/wallet.h" #include "wallet.h" namespace interfaces { diff --git a/src/interface/wallet.h b/src/interfaces/wallet.h similarity index 100% rename from src/interface/wallet.h rename to src/interfaces/wallet.h diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index df21188762cb..a2a1ee82b258 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -11,7 +11,7 @@ #include "paymentrequestplus.h" #include "walletmodeltransaction.h" -#include "interface/wallet.h" +#include "interfaces/wallet.h" #include "allocators.h" /* for SecureString */ #include "operationresult.h" From 4d58fd2d5ee38ba43b45df6e773c6a1d02e7b7f9 Mon Sep 17 00:00:00 2001 From: furszy Date: Tue, 15 Dec 2020 22:25:00 -0300 Subject: [PATCH 02/22] init: Split up AppInit2 into multiple phases This allows doing some of the steps before e.g. daemonization and some fater. Coming from btc@0cc8b6bc44bea29e24fa4e13d8a9bbe4f1483680 --- src/init.cpp | 81 ++++++++++++++++++++++++++++++++----------------- src/init.h | 19 +++++++++++- src/pivxd.cpp | 23 +++++++++++--- src/qt/pivx.cpp | 14 ++++++++- 4 files changed, 104 insertions(+), 33 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 01bd0f90963e..631eab04d6a0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -776,6 +776,18 @@ bool AppInitServers() std::terminate(); }; +namespace { // Variables internal to initialization process only + + ServiceFlags nRelevantServices = NODE_NETWORK; + int nMaxConnections; + int nUserMaxConnections; + int nFD; + ServiceFlags nLocalServices = NODE_NETWORK; + + std::string strWalletFile; + bool fDisableWallet = false; +} + bool AppInitBasicSetup() { // ********************************************************* Step 1: setup @@ -969,16 +981,10 @@ void InitLogging() LogPrintf("PIVX version %s (%s)\n", version_string, CLIENT_DATE); } -/** Initialize pivx. - * @pre Parameters should be parsed and config file should be read. - */ -bool AppInit2() +bool AppInitParameterInteraction() { - // ********************************************************* Step 1: setup - if (!AppInitBasicSetup()) - return false; - // ********************************************************* Step 2: parameter interactions + // Make sure enough file descriptors are available // -bind and -whitebind can't be set when not listening @@ -988,12 +994,12 @@ bool AppInit2() } int nBind = std::max(nUserBind, size_t(1)); - int nUserMaxConnections = gArgs.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); - int nMaxConnections = std::max(nUserMaxConnections, 0); + nUserMaxConnections = gArgs.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); + nMaxConnections = std::max(nUserMaxConnections, 0); // Trim requested connection counts, to fit into system limitations - nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); - int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); + nMaxConnections = std::max(std::min(nMaxConnections, (int) (FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); + nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); if (nFD < MIN_CORE_FILEDESCRIPTORS) return UIError(_("Not enough file descriptors available.")); if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections) @@ -1005,7 +1011,7 @@ bool AppInit2() const std::vector& categories = gArgs.GetArgs("-debug"); if (!(gArgs.GetBoolArg("-nodebug", false) || - find(categories.begin(), categories.end(), std::string("0")) != categories.end())) { + find(categories.begin(), categories.end(), std::string("0")) != categories.end())) { for (const auto& cat : categories) { if (!g_logger->EnableCategory(cat)) { UIWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat)); @@ -1025,7 +1031,8 @@ bool AppInit2() UIWarning(_("Warning: Unsupported argument -debugnet ignored, use -debug=net.")); // Check for -socks - as this is a privacy risk to continue, exit here if (gArgs.IsArgSet("-socks")) - return UIError(_("Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.")); + return UIError( + _("Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.")); // Check for -tor - as this is a privacy risk to continue, exit here if (gArgs.GetBoolArg("-tor", false)) return UIError(_("Error: Unsupported argument -tor found, use -onion.")); @@ -1036,15 +1043,18 @@ bool AppInit2() if (gArgs.GetBoolArg("-masternode", DEFAULT_MASTERNODE) && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) return UIError(_("Error: -listen must be true if -masternode is set.")); // Exit early if -masternode=1 and -port is not the default port - if (gArgs.GetBoolArg("-masternode", DEFAULT_MASTERNODE) && (GetListenPort() != Params().GetDefaultPort() && !Params().IsRegTestNet())) + if (gArgs.GetBoolArg("-masternode", DEFAULT_MASTERNODE) && + (GetListenPort() != Params().GetDefaultPort() && !Params().IsRegTestNet())) return UIError(strprintf(_("Error: Invalid port %d for running a masternode."), GetListenPort()) + "\n\n" + - strprintf(_("Masternodes are required to run on port %d for %s-net"), Params().GetDefaultPort(), Params().NetworkIDString())); + strprintf(_("Masternodes are required to run on port %d for %s-net"), Params().GetDefaultPort(), + Params().NetworkIDString())); if (gArgs.GetBoolArg("-benchmark", false)) UIWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench.")); // Checkmempool and checkblockindex default to true in regtest mode - int ratio = std::min(std::max(gArgs.GetArg("-checkmempool", Params().DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); + int ratio = std::min( + std::max(gArgs.GetArg("-checkmempool", Params().DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); if (ratio != 0) { mempool.setSanityCheck(1.0 / ratio); } @@ -1055,7 +1065,8 @@ bool AppInit2() int64_t nMempoolSizeLimit = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; int64_t nMempoolDescendantSizeLimit = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000; if (nMempoolSizeLimit < 0 || nMempoolSizeLimit < nMempoolDescendantSizeLimit * 40) - return UIError(strprintf(_("Error: -maxmempool must be at least %d MB"), gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) / 25)); + return UIError(strprintf(_("Error: -maxmempool must be at least %d MB"), + gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) / 25)); // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency nScriptCheckThreads = gArgs.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); @@ -1102,7 +1113,7 @@ bool AppInit2() } #ifdef ENABLE_WALLET - std::string strWalletFile = gArgs.GetArg("-wallet", DEFAULT_WALLET_DAT); + strWalletFile = gArgs.GetArg("-wallet", DEFAULT_WALLET_DAT); if (!CWallet::ParameterInteraction()) return false; #endif // ENABLE_WALLET @@ -1115,9 +1126,6 @@ bool AppInit2() SetMockTime(gArgs.GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op } - ServiceFlags nLocalServices = NODE_NETWORK; - ServiceFlags nRelevantServices = NODE_NETWORK; - if (gArgs.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); @@ -1126,7 +1134,12 @@ bool AppInit2() if (!InitNUParams()) return false; - // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log + return true; +} + +bool AppInitSanityChecks() +{ + // ********************************************************* Step 4: sanity checks // Initialize elliptic curve code RandomInit(); @@ -1145,9 +1158,23 @@ bool AppInit2() if (file) fclose(file); static boost::interprocess::file_lock lock(pathLockFile.string().c_str()); - // Wait maximum 10 seconds if an old wallet is still running. Avoids lockup during restart - if (!lock.timed_lock(boost::get_system_time() + boost::posix_time::seconds(10))) - return UIError(strprintf(_("Cannot obtain a lock on data directory %s. PIVX Core is probably already running."), strDataDir)); + try { + // Wait maximum 10 seconds if an old wallet is still running. Avoids lockup during restart + if (!lock.timed_lock(boost::get_system_time() + boost::posix_time::seconds(10))) { + return UIError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), + strDataDir, _(PACKAGE_NAME))); + } + } catch (const boost::interprocess::interprocess_exception& e) { + return UIError( + strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.") + " %s.", + strDataDir, _(PACKAGE_NAME), e.what())); + } + return true; +} + +bool AppInitMain() +{ + // ********************************************************* Step 4a: application initialization #ifndef WIN32 CreatePidFile(GetPidFile(), getpid()); @@ -1164,7 +1191,7 @@ bool AppInit2() if (!g_logger->m_log_timestamps) LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime())); LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); - LogPrintf("Using data directory %s\n", strDataDir); + LogPrintf("Using data directory %s\n", GetDataDir().string()); LogPrintf("Using config file %s\n", GetConfigFile().string()); LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD); std::ostringstream strErrors; diff --git a/src/init.h b/src/init.h index 65f4dbd742c7..2af4673eb84b 100644 --- a/src/init.h +++ b/src/init.h @@ -27,13 +27,30 @@ void PrepareShutdown(); void InitLogging(); //!Parameter interaction: change current parameters depending on various rules void InitParameterInteraction(); -bool AppInit2(); /** Initialize PIVX core: Basic context setup. * @note This can be done before daemonization. Do not call Shutdown() if this function fails. * @pre Parameters should be parsed and config file should be read. */ bool AppInitBasicSetup(); +/** + * Initialization: parameter interaction. + * @note This can be done before daemonization. + * @pre Parameters should be parsed and config file should be read, AppInitBasicSetup should have been called. + */ +bool AppInitParameterInteraction(); +/** + * Initialization sanity checks: ecc init, sanity checks, dir lock. + * @note This can be done before daemonization. + * @pre Parameters should be parsed and config file should be read, AppInitParameterInteraction should have been called. + */ +bool AppInitSanityChecks(); +/** + * Bitcoin core main initialization. + * @note This should only be done after daemonization. + * @pre Parameters should be parsed and config file should be read, AppInitSanityChecks should have been called. + */ +bool AppInitMain(); /** The help message mode determines what help message to show */ enum HelpMessageMode { diff --git a/src/pivxd.cpp b/src/pivxd.cpp index e864228ef037..c144ff0a815e 100644 --- a/src/pivxd.cpp +++ b/src/pivxd.cpp @@ -108,6 +108,24 @@ bool AppInit(int argc, char* argv[]) } } + // -server defaults to true for bitcoind but not for the GUI so do this here + gArgs.SoftSetBoolArg("-server", true); + // Set this early so that parameter interactions go to console + InitLogging(); + InitParameterInteraction(); + if (!AppInitBasicSetup()) { + // InitError will have been called with detailed error, which ends up on console + exit(1); + } + if (!AppInitParameterInteraction()) { + // InitError will have been called with detailed error, which ends up on console + exit(1); + } + if (!AppInitSanityChecks()) { + // InitError will have been called with detailed error, which ends up on console + exit(1); + } + #ifndef WIN32 fDaemon = gArgs.GetBoolArg("-daemon", false); if (fDaemon) { @@ -130,12 +148,9 @@ bool AppInit(int argc, char* argv[]) fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno); } #endif - gArgs.SoftSetBoolArg("-server", true); // Set this early so that parameter interactions go to console - InitLogging(); - InitParameterInteraction(); - fRet = AppInit2(); + fRet = AppInitMain(); } catch (const std::exception& e) { PrintExceptionContinue(&e, "AppInit()"); } catch (...) { diff --git a/src/qt/pivx.cpp b/src/qt/pivx.cpp index bb0c07decb0e..ef99ca8bcc8f 100644 --- a/src/qt/pivx.cpp +++ b/src/qt/pivx.cpp @@ -257,7 +257,19 @@ void BitcoinCore::initialize() try { qDebug() << __func__ << ": Running AppInit2 in thread"; - int rv = AppInit2(); + if (!AppInitBasicSetup()) { + Q_EMIT initializeResult(false); + return; + } + if (!AppInitParameterInteraction()) { + Q_EMIT initializeResult(false); + return; + } + if (!AppInitSanityChecks()) { + Q_EMIT initializeResult(false); + return; + } + int rv = AppInitMain(); Q_EMIT initializeResult(rv); } catch (const std::exception& e) { handleRunawayException(&e); From 52a621b72570dd5625c2eaf89e2384a80372c6a3 Mon Sep 17 00:00:00 2001 From: furszy Date: Tue, 15 Dec 2020 22:30:13 -0300 Subject: [PATCH 03/22] init: Try to aquire datadir lock before and after daemonization Before daemonization, just probe the data directory lock and print an early error message if possible. After daemonization get the data directory lock again and hold on to it until exit This creates a slight window for a race condition to happen, however this condition is harmless: it will at most make us exit without printing a message to console. $ src/pivxd -testnet -daemon PIVX server starting $ src/pivxd -testnet -daemon Error: Cannot obtain a lock on data directory /home/orion/.pivx/testnet4. PIVX Core is probably already running. Coming from btc@16ca0bfd2848424de7deae307283d9eb9de8a978 --- src/init.cpp | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 631eab04d6a0..a7102dd560fb 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1137,19 +1137,8 @@ bool AppInitParameterInteraction() return true; } -bool AppInitSanityChecks() +static bool LockDataDirectory(bool probeOnly) { - // ********************************************************* Step 4: sanity checks - - // Initialize elliptic curve code - RandomInit(); - ECC_Start(); - globalVerifyHandle.reset(new ECCVerifyHandle()); - - // Sanity check - if (!InitSanityCheck()) - return UIError(_("Initialization sanity check failed. PIVX Core is shutting down.")); - std::string strDataDir = GetDataDir().string(); // Make sure only a single PIVX process is using the data directory. @@ -1164,6 +1153,9 @@ bool AppInitSanityChecks() return UIError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), strDataDir, _(PACKAGE_NAME))); } + if (probeOnly) { + lock.unlock(); + } } catch (const boost::interprocess::interprocess_exception& e) { return UIError( strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.") + " %s.", @@ -1172,9 +1164,33 @@ bool AppInitSanityChecks() return true; } +bool AppInitSanityChecks() +{ + // ********************************************************* Step 4: sanity checks + + // Initialize elliptic curve code + RandomInit(); + ECC_Start(); + globalVerifyHandle.reset(new ECCVerifyHandle()); + + // Sanity check + if (!InitSanityCheck()) + return UIError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME))); + + // Probe the data directory lock to give an early error message, if possible + return LockDataDirectory(true); +} + bool AppInitMain() { // ********************************************************* Step 4a: application initialization + // After daemonization get the data directory lock again and hold on to it until exit + // This creates a slight window for a race condition to happen, however this condition is harmless: it + // will at most make us exit without printing a message to console. + if (!LockDataDirectory(false)) { + // Detailed error printed inside LockDataDirectory + return false; + } #ifndef WIN32 CreatePidFile(GetPidFile(), getpid()); From 140db37dcb31c6564b45b70c4ae5b64f99832dc7 Mon Sep 17 00:00:00 2001 From: furszy Date: Thu, 17 Dec 2020 12:03:38 -0300 Subject: [PATCH 04/22] Migrating signal placeholders to correct boost naming scheme. (solving +1.74 boost deployment issues) --- src/qt/clientmodel.cpp | 12 +++++------ src/qt/pivx/pivxgui.cpp | 4 ++-- src/qt/pivx/splash.cpp | 14 ++++++------- src/qt/transactiontablemodel.cpp | 8 +++---- src/qt/walletmodel.cpp | 24 ++++++++++----------- src/rpc/server.cpp | 6 +++--- src/torcontrol.cpp | 22 +++++++++---------- src/validationinterface.cpp | 36 ++++++++++++++++---------------- src/wallet/walletdb.cpp | 4 +++- 9 files changed, 66 insertions(+), 64 deletions(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 6756008e4a22..ac9d3ce255ae 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -303,21 +303,21 @@ static void BannedListChanged(ClientModel *clientmodel) void ClientModel::subscribeToCoreSignals() { // Connect signals to client - uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); - uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); + uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, boost::placeholders::_1)); uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this)); uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this)); - uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2)); + uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, boost::placeholders::_1, boost::placeholders::_2)); } void ClientModel::unsubscribeFromCoreSignals() { // Disconnect signals from client - uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); - uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); + uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, boost::placeholders::_1)); uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this)); uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); - uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2)); + uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, boost::placeholders::_1, boost::placeholders::_2)); } bool ClientModel::getTorInfo(std::string& ip_port) const diff --git a/src/qt/pivx/pivxgui.cpp b/src/qt/pivx/pivxgui.cpp index 08b79a36f64a..ff61cd013361 100644 --- a/src/qt/pivx/pivxgui.cpp +++ b/src/qt/pivx/pivxgui.cpp @@ -689,11 +689,11 @@ static bool ThreadSafeMessageBox(PIVXGUI* gui, const std::string& message, const void PIVXGUI::subscribeToCoreSignals() { // Connect signals to client - uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3)); + uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); } void PIVXGUI::unsubscribeFromCoreSignals() { // Disconnect signals from client - uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3)); + uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); } diff --git a/src/qt/pivx/splash.cpp b/src/qt/pivx/splash.cpp index 9a91fb2aa6ab..c78d3deaeff7 100644 --- a/src/qt/pivx/splash.cpp +++ b/src/qt/pivx/splash.cpp @@ -77,26 +77,26 @@ static void ShowProgress(Splash* splash, const std::string& title, int nProgress #ifdef ENABLE_WALLET static void ConnectWallet(Splash* splash, CWallet* wallet){ - wallet->ShowProgress.connect(boost::bind(ShowProgress, splash, _1, _2)); + wallet->ShowProgress.connect(boost::bind(ShowProgress, splash, boost::placeholders::_1, boost::placeholders::_2)); } #endif void Splash::subscribeToCoreSignals(){ // Connect signals to client - uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1)); - uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); + uiInterface.InitMessage.connect(boost::bind(InitMessage, this, boost::placeholders::_1)); + uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); #ifdef ENABLE_WALLET - uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, _1)); + uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, boost::placeholders::_1)); #endif } void Splash::unsubscribeFromCoreSignals(){ // Disconnect signals from client - uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1)); - uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); + uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, boost::placeholders::_1)); + uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); #ifdef ENABLE_WALLET if (pwalletMain) - pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); + pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); #endif } diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 1b1871e36155..f9056908d150 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -879,13 +879,13 @@ static void ShowProgress(TransactionTableModel* ttm, const std::string& title, i void TransactionTableModel::subscribeToCoreSignals() { // Connect signals to wallet - wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); - wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); + wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + wallet->ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); } void TransactionTableModel::unsubscribeFromCoreSignals() { // Disconnect signals from wallet - wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); - wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); + wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 70b6f013752f..67e0a3ecaf93 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -761,23 +761,23 @@ static void NotifyWalletBacked(WalletModel* model, const bool& fSuccess, const s void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet - wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); - wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); - wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); - wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); - wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, _1)); - wallet->NotifyWalletBacked.connect(boost::bind(NotifyWalletBacked, this, _1, _2)); + wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, boost::placeholders::_1)); + wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5, boost::placeholders::_6)); + wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + wallet->ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, boost::placeholders::_1)); + wallet->NotifyWalletBacked.connect(boost::bind(NotifyWalletBacked, this, boost::placeholders::_1, boost::placeholders::_2)); } void WalletModel::unsubscribeFromCoreSignals() { // Disconnect signals from wallet - wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); - wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); - wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); - wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); - wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, _1)); - wallet->NotifyWalletBacked.disconnect(boost::bind(NotifyWalletBacked, this, _1, _2)); + wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, boost::placeholders::_1)); + wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5, boost::placeholders::_6)); + wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, boost::placeholders::_1)); + wallet->NotifyWalletBacked.disconnect(boost::bind(NotifyWalletBacked, this, boost::placeholders::_1, boost::placeholders::_2)); } // WalletModel::UnlockContext implementation diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 419c04c90c9b..bf897b92a1ac 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -58,12 +58,12 @@ void RPCServer::OnStopped(std::function slot) void RPCServer::OnPreCommand(std::function slot) { - g_rpcSignals.PreCommand.connect(boost::bind(slot, _1)); + g_rpcSignals.PreCommand.connect(boost::bind(slot, boost::placeholders::_1)); } void RPCServer::OnPostCommand(std::function slot) { - g_rpcSignals.PostCommand.connect(boost::bind(slot, _1)); + g_rpcSignals.PostCommand.connect(boost::bind(slot, boost::placeholders::_1)); } void RPCTypeCheck(const UniValue& params, @@ -458,7 +458,7 @@ std::vector CRPCTable::listCommands() const std::transform( mapCommands.begin(), mapCommands.end(), std::back_inserter(commandList), - boost::bind(&commandMap::value_type::first,_1) ); + boost::bind(&commandMap::value_type::first,boost::placeholders::_1) ); return commandList; } diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 6e698bfd6cd2..3ad5607a2354 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -463,8 +463,8 @@ TorController::TorController(struct event_base* _base, const std::string& _targe if (!reconnect_ev) LogPrintf("tor: Failed to create event for reconnection: out of memory?\n"); // Start connection attempts immediately - if (!conn.Connect(_target, boost::bind(&TorController::connected_cb, this, _1), - boost::bind(&TorController::disconnected_cb, this, _1) )) { + if (!conn.Connect(_target, boost::bind(&TorController::connected_cb, this, boost::placeholders::_1), + boost::bind(&TorController::disconnected_cb, this, boost::placeholders::_1) )) { LogPrintf("tor: Initiating connection to Tor control port %s failed\n", _target); } // Read service private key if cached @@ -541,7 +541,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& // Request hidden service, redirect port. // Note that the 'virtual' port is always the default port to avoid decloaking nodes using other ports. _conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, Params().GetDefaultPort(), GetListenPort()), - boost::bind(&TorController::add_onion_cb, this, _1, _2)); + boost::bind(&TorController::add_onion_cb, this, boost::placeholders::_1, boost::placeholders::_2)); } else { LogPrintf("tor: Authentication failed\n"); } @@ -600,7 +600,7 @@ void TorController::authchallenge_cb(TorControlConnection& _conn, const TorContr } std::vector computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce); - _conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2)); + _conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, boost::placeholders::_1, boost::placeholders::_2)); } else { LogPrintf("tor: Invalid reply to AUTHCHALLENGE\n"); } @@ -649,23 +649,23 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro if (methods.count("HASHEDPASSWORD")) { LogPrint(BCLog::TOR, "tor: Using HASHEDPASSWORD authentication\n"); boost::replace_all(torpassword, "\"", "\\\""); - _conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2)); + _conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, boost::placeholders::_1, boost::placeholders::_2)); } else { LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n"); } } else if (methods.count("NULL")) { LogPrint(BCLog::TOR, "tor: Using NULL authentication\n"); - _conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2)); + _conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, boost::placeholders::_1, boost::placeholders::_2)); } else if (methods.count("SAFECOOKIE")) { // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie LogPrint(BCLog::TOR, "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); std::pair status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE); if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) { - // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2)); + // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, boost::placeholders::_1, boost::placeholders::_2)); cookie = std::vector(status_cookie.second.begin(), status_cookie.second.end()); clientNonce = std::vector(TOR_NONCE_SIZE, 0); GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE); - _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2)); + _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, boost::placeholders::_1, boost::placeholders::_2)); } else { if (status_cookie.first) { LogPrintf("tor: Authentication cookie %s is not exactly %i bytes, as is required by the spec\n", cookiefile, TOR_COOKIE_SIZE); @@ -687,7 +687,7 @@ void TorController::connected_cb(TorControlConnection& _conn) { reconnect_timeout = RECONNECT_TIMEOUT_START; // First send a PROTOCOLINFO command to figure out what authentication is expected - if (!_conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2))) + if (!_conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, boost::placeholders::_1, boost::placeholders::_2))) LogPrintf("tor: Error sending initial protocolinfo command\n"); } @@ -714,8 +714,8 @@ void TorController::Reconnect() /* Try to reconnect and reestablish if we get booted - for example, Tor * may be restarting. */ - if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1), - boost::bind(&TorController::disconnected_cb, this, _1) )) { + if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, boost::placeholders::_1), + boost::bind(&TorController::disconnected_cb, this, boost::placeholders::_1) )) { LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", target); } } diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 5cade2edc83f..b40e2d2ede14 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -15,28 +15,28 @@ CMainSignals& GetMainSignals() void RegisterValidationInterface(CValidationInterface* pwalletIn) { - g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3)); - g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3)); - g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3)); - g_signals.NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1)); - g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); - g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); - g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); - g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); - g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); + g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, boost::placeholders::_1)); + g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, boost::placeholders::_1)); + g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, boost::placeholders::_1)); + g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, boost::placeholders::_1)); + g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, boost::placeholders::_1, boost::placeholders::_2)); + g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, boost::placeholders::_1)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { - g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); - g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); - g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); - g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); - g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); - g_signals.NotifyTransactionLock.disconnect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1)); - g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3)); - g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3)); - g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3)); + g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, boost::placeholders::_1)); + g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, boost::placeholders::_1, boost::placeholders::_2)); + g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, boost::placeholders::_1)); + g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, boost::placeholders::_1)); + g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, boost::placeholders::_1)); + g_signals.NotifyTransactionLock.disconnect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, boost::placeholders::_1)); + g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); } void UnregisterAllValidationInterfaces() diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 16b1d9b4ed85..79b6a4e752cc 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1043,7 +1043,9 @@ bool AttemptBackupWallet(const CWallet& wallet, const fs::path& pathSrc, const f LogPrintf("cannot backup to wallet source file %s\n", pathDest.string()); return false; } -#if BOOST_VERSION >= 105800 /* BOOST_LIB_VERSION 1_58 */ +#if BOOST_VERSION >= 107400 + fs::copy_file(pathSrc.c_str(), pathDest, fs::copy_options::overwrite_existing); +#elif BOOST_VERSION >= 105800 /* BOOST_LIB_VERSION 1_58 */ fs::copy_file(pathSrc.c_str(), pathDest, fs::copy_option::overwrite_if_exists); #else std::ifstream src(pathSrc.c_str(), std::ios::binary | std::ios::in); From 343d94d0fa6b6275793d7ae4c80b2437c2dc684b Mon Sep 17 00:00:00 2001 From: furszy Date: Thu, 17 Dec 2020 12:40:15 -0300 Subject: [PATCH 05/22] GUI: Event handler generic interface. --- CMakeLists.txt | 1 + src/Makefile.am | 2 ++ src/interfaces/handler.cpp | 33 +++++++++++++++++++++++++++++ src/interfaces/handler.h | 36 ++++++++++++++++++++++++++++++++ src/qt/clientmodel.cpp | 22 +++++++++---------- src/qt/clientmodel.h | 13 +++++++++++- src/qt/pivx/pivxgui.cpp | 5 +++-- src/qt/pivx/pivxgui.h | 7 ++++++- src/qt/pivx/splash.cpp | 20 +++++++++++------- src/qt/pivx/splash.h | 11 ++++++++++ src/qt/transactiontablemodel.cpp | 9 ++++---- src/qt/transactiontablemodel.h | 10 +++++++++ src/qt/walletmodel.cpp | 25 +++++++++++----------- src/qt/walletmodel.h | 12 +++++++++++ 14 files changed, 167 insertions(+), 39 deletions(-) create mode 100644 src/interfaces/handler.cpp create mode 100644 src/interfaces/handler.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8950cd49bdac..931aebf4b275 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,6 +194,7 @@ set(SERVER_SOURCES ./src/httprpc.cpp ./src/httpserver.cpp ./src/init.cpp + ./src/interfaces/handler.cpp ./src/interfaces/wallet.cpp ./src/dbwrapper.cpp ./src/legacy/validation_zerocoin_legacy.cpp diff --git a/src/Makefile.am b/src/Makefile.am index b6e42c786c90..6482a20d2a13 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -190,6 +190,7 @@ BITCOIN_CORE_H = \ httprpc.h \ httpserver.h \ init.h \ + interfaces/handler.h \ interfaces/wallet.h \ invalid.h \ invalid_outpoints.json.h \ @@ -533,6 +534,7 @@ libbitcoin_util_a_SOURCES = \ compat/glibcxx_sanity.cpp \ compat/strnlen.cpp \ fs.cpp \ + interfaces/handler.cpp \ logging.cpp \ random.cpp \ rpc/protocol.cpp \ diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp new file mode 100644 index 000000000000..c2e33080f87b --- /dev/null +++ b/src/interfaces/handler.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2020 The PIVX Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#include +#include + +namespace interfaces { +namespace { + +class HandlerImpl : public Handler +{ +public: + explicit HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {} + + void disconnect() override { m_connection.disconnect(); } + + boost::signals2::scoped_connection m_connection; +}; + +} // namespace + +std::unique_ptr MakeHandler(boost::signals2::connection connection) +{ + return MakeUnique(std::move(connection)); +} + +} // namespace interfaces diff --git a/src/interfaces/handler.h b/src/interfaces/handler.h new file mode 100644 index 000000000000..b15d06c39315 --- /dev/null +++ b/src/interfaces/handler.h @@ -0,0 +1,36 @@ +// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2020 The PIVX Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php. + +#ifndef PIVX_INTERFACES_HANDLER_H +#define PIVX_INTERFACES_HANDLER_H + +#include + +namespace boost { +namespace signals2 { +class connection; +} // namespace signals2 +} // namespace boost + +namespace interfaces { + +//! Generic interface for managing an event handler or callback function +//! registered with another interface. Has a single disconnect method to cancel +//! the registration and prevent any future notifications. +class Handler +{ +public: + virtual ~Handler() {} + + //! Disconnect the handler. + virtual void disconnect() = 0; +}; + +//! Return handler wrapping a boost signal connection. +std::unique_ptr MakeHandler(boost::signals2::connection connection); + +} // namespace interfaces + +#endif // PIVX_INTERFACES_HANDLER_H diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index ac9d3ce255ae..5e0ee3a1c8b5 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -14,7 +14,7 @@ #include "chainparams.h" #include "checkpoints.h" #include "clientversion.h" -#include "masternode-sync.h" +#include "interfaces/handler.h" #include "masternodeman.h" #include "net.h" #include "netbase.h" @@ -303,21 +303,21 @@ static void BannedListChanged(ClientModel *clientmodel) void ClientModel::subscribeToCoreSignals() { // Connect signals to client - uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); - uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, boost::placeholders::_1)); - uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this)); - uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this)); - uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_show_progress = interfaces::MakeHandler(uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2))); + m_handler_notify_num_connections_changed = interfaces::MakeHandler(uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, boost::placeholders::_1))); + m_handler_notify_alert_changed = interfaces::MakeHandler(uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this))); + m_handler_banned_list_changed = interfaces::MakeHandler(uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this))); + m_handler_notify_block_tip = interfaces::MakeHandler(uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, boost::placeholders::_1, boost::placeholders::_2))); } void ClientModel::unsubscribeFromCoreSignals() { // Disconnect signals from client - uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); - uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, boost::placeholders::_1)); - uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this)); - uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); - uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_show_progress->disconnect(); + m_handler_notify_num_connections_changed->disconnect(); + m_handler_notify_alert_changed->disconnect(); + m_handler_banned_list_changed->disconnect(); + m_handler_notify_block_tip->disconnect(); } bool ClientModel::getTorInfo(std::string& ip_port) const diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 9940aeb40605..bb89343f02d2 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -12,13 +12,17 @@ #include #include +#include + class AddressTableModel; class BanTableModel; class OptionsModel; class PeerTableModel; class TransactionTableModel; -class CWallet; +namespace interfaces { + class Handler; +} QT_BEGIN_NAMESPACE class QDateTime; @@ -91,6 +95,13 @@ class ClientModel : public QObject void stopMasternodesTimer(); private: + // Listeners + std::unique_ptr m_handler_show_progress; + std::unique_ptr m_handler_notify_num_connections_changed; + std::unique_ptr m_handler_notify_alert_changed; + std::unique_ptr m_handler_banned_list_changed; + std::unique_ptr m_handler_notify_block_tip; + QString getMasternodeCountString() const; OptionsModel* optionsModel; PeerTableModel* peerTableModel; diff --git a/src/qt/pivx/pivxgui.cpp b/src/qt/pivx/pivxgui.cpp index ff61cd013361..87c4abd925c8 100644 --- a/src/qt/pivx/pivxgui.cpp +++ b/src/qt/pivx/pivxgui.cpp @@ -10,6 +10,7 @@ #include "qt/guiutil.h" #include "clientmodel.h" +#include "interfaces/handler.h" #include "optionsmodel.h" #include "networkstyle.h" #include "notificator.h" @@ -689,11 +690,11 @@ static bool ThreadSafeMessageBox(PIVXGUI* gui, const std::string& message, const void PIVXGUI::subscribeToCoreSignals() { // Connect signals to client - uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + m_handler_message_box = interfaces::MakeHandler(uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3))); } void PIVXGUI::unsubscribeFromCoreSignals() { // Disconnect signals from client - uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + m_handler_message_box->disconnect(); } diff --git a/src/qt/pivx/pivxgui.h b/src/qt/pivx/pivxgui.h index 148fbd0830bb..e343e9030c6a 100644 --- a/src/qt/pivx/pivxgui.h +++ b/src/qt/pivx/pivxgui.h @@ -27,6 +27,9 @@ #include "qt/pivx/settings/settingsfaqwidget.h" #include "qt/rpcconsole.h" +namespace interfaces { + class Handler; +} class ClientModel; class NetworkStyle; @@ -114,6 +117,9 @@ public Q_SLOTS: */ private: + // Handlers + std::unique_ptr m_handler_message_box; + bool enableWallet; ClientModel* clientModel = nullptr; @@ -121,7 +127,6 @@ public Q_SLOTS: QAction* quitAction = nullptr; QAction* toggleHideAction = nullptr; - // Frame NavMenuWidget *navMenu = nullptr; TopBar *topBar = nullptr; diff --git a/src/qt/pivx/splash.cpp b/src/qt/pivx/splash.cpp index c78d3deaeff7..c90cb4da98fb 100644 --- a/src/qt/pivx/splash.cpp +++ b/src/qt/pivx/splash.cpp @@ -6,6 +6,7 @@ #include "qt/pivx/forms/ui_splash.h" #include "QFile" +#include "interfaces/handler.h" #include "init.h" #include "guiinterface.h" #include "networkstyle.h" @@ -76,27 +77,30 @@ static void ShowProgress(Splash* splash, const std::string& title, int nProgress } #ifdef ENABLE_WALLET +std::unique_ptr m_handler_show_progress_wallet; static void ConnectWallet(Splash* splash, CWallet* wallet){ - wallet->ShowProgress.connect(boost::bind(ShowProgress, splash, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_show_progress_wallet = interfaces::MakeHandler(wallet->ShowProgress.connect(boost::bind(ShowProgress, splash, boost::placeholders::_1, boost::placeholders::_2))); } #endif void Splash::subscribeToCoreSignals(){ // Connect signals to client - uiInterface.InitMessage.connect(boost::bind(InitMessage, this, boost::placeholders::_1)); - uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_init_message = interfaces::MakeHandler(uiInterface.InitMessage.connect(boost::bind(InitMessage, this, boost::placeholders::_1))); + m_handler_show_progress = interfaces::MakeHandler(uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2))); #ifdef ENABLE_WALLET - uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, boost::placeholders::_1)); + m_handler_load_wallet = interfaces::MakeHandler(uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, boost::placeholders::_1))); #endif } void Splash::unsubscribeFromCoreSignals(){ // Disconnect signals from client - uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, boost::placeholders::_1)); - uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_init_message->disconnect(); + m_handler_show_progress->disconnect(); #ifdef ENABLE_WALLET - if (pwalletMain) - pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + if (pwalletMain) { + m_handler_load_wallet->disconnect(); + if (m_handler_show_progress_wallet) m_handler_show_progress_wallet->disconnect(); + } #endif } diff --git a/src/qt/pivx/splash.h b/src/qt/pivx/splash.h index b6db30427e5a..cc6a667a36ed 100644 --- a/src/qt/pivx/splash.h +++ b/src/qt/pivx/splash.h @@ -7,8 +7,14 @@ #include +#include + class NetworkStyle; +namespace interfaces { + class Handler; +}; + namespace Ui { class Splash; } @@ -34,6 +40,11 @@ public Q_SLOTS: private: Ui::Splash *ui; + // Listeners + std::unique_ptr m_handler_init_message; + std::unique_ptr m_handler_show_progress; + std::unique_ptr m_handler_load_wallet; + /** Connect core signals to splash screen */ void subscribeToCoreSignals(); /** Disconnect core signals to splash screen */ diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index f9056908d150..3306579d1f9c 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -13,6 +13,7 @@ #include "transactionrecord.h" #include "walletmodel.h" +#include "interfaces/handler.h" #include "sync.h" #include "uint256.h" #include "util.h" @@ -879,13 +880,13 @@ static void ShowProgress(TransactionTableModel* ttm, const std::string& title, i void TransactionTableModel::subscribeToCoreSignals() { // Connect signals to wallet - wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - wallet->ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_transaction_changed = interfaces::MakeHandler(wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3))); + m_handler_show_progress = interfaces::MakeHandler(wallet->ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2))); } void TransactionTableModel::unsubscribeFromCoreSignals() { // Disconnect signals from wallet - wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_transaction_changed->disconnect(); + m_handler_show_progress->disconnect(); } diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 4922bc31057f..b5f925472b2d 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -11,6 +11,12 @@ #include #include +#include + +namespace interfaces { + class Handler; +} + class TransactionRecord; class TransactionTablePriv; class WalletModel; @@ -83,6 +89,10 @@ class TransactionTableModel : public QAbstractTableModel void txArrived(const QString& hash, const bool& isCoinStake, const bool& isCSAnyType); private: + // Listeners + std::unique_ptr m_handler_transaction_changed; + std::unique_ptr m_handler_show_progress; + CWallet* wallet; WalletModel* walletModel; QStringList columns; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 67e0a3ecaf93..e822b44e3607 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -16,6 +16,7 @@ #include "coincontrol.h" #include "db.h" #include "keystore.h" +#include "interfaces/handler.h" #include "sapling/key_io_sapling.h" #include "sapling/sapling_operation.h" #include "spork.h" @@ -761,23 +762,23 @@ static void NotifyWalletBacked(WalletModel* model, const bool& fSuccess, const s void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet - wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, boost::placeholders::_1)); - wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5, boost::placeholders::_6)); - wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - wallet->ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); - wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, boost::placeholders::_1)); - wallet->NotifyWalletBacked.connect(boost::bind(NotifyWalletBacked, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_notify_status_changed = interfaces::MakeHandler(wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, boost::placeholders::_1))); + m_handler_notify_addressbook_changed = interfaces::MakeHandler(wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5, boost::placeholders::_6))); + m_handler_notify_transaction_changed = interfaces::MakeHandler(wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3))); + m_handler_show_progress = interfaces::MakeHandler(wallet->ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2))); + m_handler_notify_watch_only_changed = interfaces::MakeHandler(wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, boost::placeholders::_1))); + m_handler_notify_walletbacked = interfaces::MakeHandler(wallet->NotifyWalletBacked.connect(boost::bind(NotifyWalletBacked, this, boost::placeholders::_1, boost::placeholders::_2))); } void WalletModel::unsubscribeFromCoreSignals() { // Disconnect signals from wallet - wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, boost::placeholders::_1)); - wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5, boost::placeholders::_6)); - wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); - wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, boost::placeholders::_1)); - wallet->NotifyWalletBacked.disconnect(boost::bind(NotifyWalletBacked, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_notify_status_changed->disconnect(); + m_handler_notify_addressbook_changed->disconnect(); + m_handler_notify_transaction_changed->disconnect(); + m_handler_show_progress->disconnect(); + m_handler_notify_watch_only_changed->disconnect(); + m_handler_notify_walletbacked->disconnect(); } // WalletModel::UnlockContext implementation diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index a2a1ee82b258..02d3a43cfc14 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -38,6 +38,10 @@ class CPubKey; class CWallet; class uint256; +namespace interfaces { + class Handler; +}; + QT_BEGIN_NAMESPACE class QTimer; QT_END_NAMESPACE @@ -330,6 +334,14 @@ class WalletModel : public QObject // in the model only perform the data organization (and QT wrappers) to be presented on the UI. interfaces::Wallet walletWrapper; + // Listeners + std::unique_ptr m_handler_notify_status_changed; + std::unique_ptr m_handler_notify_addressbook_changed; + std::unique_ptr m_handler_notify_transaction_changed; + std::unique_ptr m_handler_show_progress; + std::unique_ptr m_handler_notify_watch_only_changed; + std::unique_ptr m_handler_notify_walletbacked; + bool fHaveWatchOnly; bool fForceCheckBalanceChanged; From 92b975f1ae99edf91998d108caa90949705e139a Mon Sep 17 00:00:00 2001 From: furszy Date: Sun, 15 Nov 2020 00:06:08 -0300 Subject: [PATCH 06/22] Make ValidationInterface signals-type-agnostic (by hiding boost::signals stuff in the .cpp) coming from btc@3a19fed9db558a5f666d965b6f602f7faf74ab73 --- src/validationinterface.cpp | 121 ++++++++++++++++++++++++++++-------- src/validationinterface.h | 45 +++++++------- 2 files changed, 117 insertions(+), 49 deletions(-) diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index b40e2d2ede14..8b4b9e4d3ebf 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -6,8 +6,39 @@ #include "validationinterface.h" +#include + +struct MainSignalsInstance { +// XX42 boost::signals2::signal EraseTransaction; + /** Notifies listeners of updated block chain tip */ + boost::signals2::signal UpdatedBlockTip; + /** A posInBlock value for SyncTransaction which indicates the transaction was conflicted, disconnected, or not in a block */ + static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1; + /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ + boost::signals2::signal SyncTransaction; + /** Notifies listeners of an updated transaction lock without new data. */ + boost::signals2::signal NotifyTransactionLock; + /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ + boost::signals2::signal UpdatedTransaction; + /** Notifies listeners of a new active block chain. */ + boost::signals2::signal SetBestChain; + /** Tells listeners to broadcast their data. */ + boost::signals2::signal Broadcast; + /** Notifies listeners of a block validation result */ + boost::signals2::signal BlockChecked; + /** Notifies listeners that a block has been successfully mined */ + boost::signals2::signal BlockFound; + + /** Notifies listeners of a change to the tip of the active block chain. */ + boost::signals2::signal)> ChainTip; +}; + static CMainSignals g_signals; +CMainSignals::CMainSignals() { + m_internals.reset(new MainSignalsInstance()); +} + CMainSignals& GetMainSignals() { return g_signals; @@ -15,39 +46,75 @@ CMainSignals& GetMainSignals() void RegisterValidationInterface(CValidationInterface* pwalletIn) { - g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - g_signals.NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, boost::placeholders::_1)); - g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, boost::placeholders::_1)); - g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, boost::placeholders::_1)); - g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, boost::placeholders::_1)); - g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, boost::placeholders::_1, boost::placeholders::_2)); - g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, boost::placeholders::_1)); + g_signals.m_internals->UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.m_internals->SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.m_internals->ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.m_internals->NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, boost::placeholders::_1)); + g_signals.m_internals->UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, boost::placeholders::_1)); + g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, boost::placeholders::_1)); + g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, boost::placeholders::_1)); + g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, boost::placeholders::_1, boost::placeholders::_2)); + g_signals.m_internals->BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, boost::placeholders::_1)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { - g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, boost::placeholders::_1)); - g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, boost::placeholders::_1, boost::placeholders::_2)); - g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, boost::placeholders::_1)); - g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, boost::placeholders::_1)); - g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, boost::placeholders::_1)); - g_signals.NotifyTransactionLock.disconnect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, boost::placeholders::_1)); - g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.m_internals->BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, boost::placeholders::_1)); + g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, boost::placeholders::_1, boost::placeholders::_2)); + g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, boost::placeholders::_1)); + g_signals.m_internals->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, boost::placeholders::_1)); + g_signals.m_internals->UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, boost::placeholders::_1)); + g_signals.m_internals->NotifyTransactionLock.disconnect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, boost::placeholders::_1)); + g_signals.m_internals->SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.m_internals->ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.m_internals->UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); } void UnregisterAllValidationInterfaces() { - g_signals.BlockFound.disconnect_all_slots(); - g_signals.BlockChecked.disconnect_all_slots(); - g_signals.Broadcast.disconnect_all_slots(); - g_signals.SetBestChain.disconnect_all_slots(); - g_signals.UpdatedTransaction.disconnect_all_slots(); - g_signals.NotifyTransactionLock.disconnect_all_slots(); - g_signals.SyncTransaction.disconnect_all_slots(); - g_signals.ChainTip.disconnect_all_slots(); - g_signals.UpdatedBlockTip.disconnect_all_slots(); + g_signals.m_internals->BlockFound.disconnect_all_slots(); + g_signals.m_internals->BlockChecked.disconnect_all_slots(); + g_signals.m_internals->Broadcast.disconnect_all_slots(); + g_signals.m_internals->SetBestChain.disconnect_all_slots(); + g_signals.m_internals->UpdatedTransaction.disconnect_all_slots(); + g_signals.m_internals->NotifyTransactionLock.disconnect_all_slots(); + g_signals.m_internals->SyncTransaction.disconnect_all_slots(); + g_signals.m_internals->ChainTip.disconnect_all_slots(); + g_signals.m_internals->UpdatedBlockTip.disconnect_all_slots(); +} + +void CMainSignals::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) { + m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); +} + +void CMainSignals::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int posInBlock) { + m_internals->SyncTransaction(tx, pindex, posInBlock); +} + +void CMainSignals::NotifyTransactionLock(const CTransaction& tx) { + m_internals->NotifyTransactionLock(tx); } + +void CMainSignals::UpdatedTransaction(const uint256& hash) { + m_internals->UpdatedTransaction(hash); +} + +void CMainSignals::SetBestChain(const CBlockLocator& locator) { + m_internals->SetBestChain(locator); +} + +void CMainSignals::Broadcast(CConnman* connman) { + m_internals->Broadcast(connman); +} + +void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) { + m_internals->BlockChecked(block, state); +} + +void CMainSignals::BlockFound(const uint256& hash) { + m_internals->BlockFound(hash); +} + +void CMainSignals::ChainTip(const CBlockIndex* pindex, const CBlock* block, Optional tree) { + m_internals->ChainTip(pindex, block, tree); +} \ No newline at end of file diff --git a/src/validationinterface.h b/src/validationinterface.h index f50349eb645b..386efe6fe291 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -10,8 +10,6 @@ #include "optional.h" #include "sapling/incrementalmerkletree.hpp" -#include - class CBlock; struct CBlockLocator; class CBlockIndex; @@ -33,12 +31,15 @@ void UnregisterAllValidationInterfaces(); class CValidationInterface { protected: + /** Notifies listeners of updated block chain tip */ virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {} virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) {} virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, Optional added) {} virtual void NotifyTransactionLock(const CTransaction &tx) {} + /** Notifies listeners of the new active block chain on-disk. */ virtual void SetBestChain(const CBlockLocator &locator) {} virtual bool UpdatedTransaction(const uint256 &hash) { return false;} + /** Tells listeners to broadcast their data. */ virtual void ResendWalletTransactions(CConnman* connman) {} virtual void BlockChecked(const CBlock&, const CValidationState&) {} virtual void ResetRequestCount(const uint256 &hash) {}; @@ -47,29 +48,29 @@ class CValidationInterface { friend void ::UnregisterAllValidationInterfaces(); }; -struct CMainSignals { -// XX42 boost::signals2::signal EraseTransaction; - /** Notifies listeners of updated block chain tip */ - boost::signals2::signal UpdatedBlockTip; +struct MainSignalsInstance; +class CMainSignals { +private: + std::unique_ptr m_internals; + + friend void ::RegisterValidationInterface(CValidationInterface*); + friend void ::UnregisterValidationInterface(CValidationInterface*); + friend void ::UnregisterAllValidationInterfaces(); +public: + CMainSignals(); + /** A posInBlock value for SyncTransaction which indicates the transaction was conflicted, disconnected, or not in a block */ static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1; - /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ - boost::signals2::signal SyncTransaction; - /** Notifies listeners of an updated transaction lock without new data. */ - boost::signals2::signal NotifyTransactionLock; - /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ - boost::signals2::signal UpdatedTransaction; - /** Notifies listeners of a new active block chain. */ - boost::signals2::signal SetBestChain; - /** Tells listeners to broadcast their data. */ - boost::signals2::signal Broadcast; - /** Notifies listeners of a block validation result */ - boost::signals2::signal BlockChecked; - /** Notifies listeners that a block has been successfully mined */ - boost::signals2::signal BlockFound; - /** Notifies listeners of a change to the tip of the active block chain. */ - boost::signals2::signal)> ChainTip; + void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload); + void SyncTransaction(const CTransaction &, const CBlockIndex *pindex, int posInBlock); + void NotifyTransactionLock(const CTransaction&); + void UpdatedTransaction(const uint256 &); + void SetBestChain(const CBlockLocator &); + void Broadcast(CConnman* connman); + void BlockChecked(const CBlock&, const CValidationState&); + void BlockFound(const uint256&); + void ChainTip(const CBlockIndex *, const CBlock *, Optional); }; CMainSignals& GetMainSignals(); From 115f4848df4a2b7bfc4d199c7ec4cf725dcd7ff4 Mon Sep 17 00:00:00 2001 From: furszy Date: Sun, 15 Nov 2020 00:17:25 -0300 Subject: [PATCH 07/22] Give CMainSignals a reference to the global scheduler so that it can run some signals in the background later coming from btc@cda1429d5bfee129a0d1f6f1c65962b30251bafb --- src/init.cpp | 3 +++ src/test/test_pivx.cpp | 7 +++++++ src/test/test_pivx.h | 2 ++ src/validationinterface.cpp | 12 ++++++++++++ src/validationinterface.h | 7 +++++++ 5 files changed, 31 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index a7102dd560fb..7e3c99eaa401 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -294,6 +294,7 @@ void PrepareShutdown() // Disconnect all slots UnregisterAllValidationInterfaces(); + GetMainSignals().UnregisterBackgroundSignalScheduler(); #ifndef WIN32 try { @@ -1230,6 +1231,8 @@ bool AppInitMain() CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler); threadGroup.create_thread(boost::bind(&TraceThread, "scheduler", serviceLoop)); + GetMainSignals().RegisterBackgroundSignalScheduler(scheduler); + // Initialize Sapling circuit parameters LoadSaplingParams(); diff --git a/src/test/test_pivx.cpp b/src/test/test_pivx.cpp index c483520f10ee..e678d654a434 100644 --- a/src/test/test_pivx.cpp +++ b/src/test/test_pivx.cpp @@ -50,6 +50,12 @@ TestingSetup::TestingSetup() pathTemp = GetTempPath() / strprintf("test_pivx_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000))); fs::create_directories(pathTemp); gArgs.ForceSetArg("-datadir", pathTemp.string()); + + // Note that because we don't bother running a scheduler thread here, + // callbacks via CValidationInterface are unreliable, but that's OK, + // our unit tests aren't testing multiple parts of the code at once. + GetMainSignals().RegisterBackgroundSignalScheduler(scheduler); + // Ideally we'd move all the RPC tests to the functional testing framework // instead of unit tests, but for now we need these here. RegisterAllCoreRPCCommands(tableRPC); @@ -75,6 +81,7 @@ TestingSetup::~TestingSetup() UnregisterNodeSignals(GetNodeSignals()); threadGroup.interrupt_all(); threadGroup.join_all(); + GetMainSignals().UnregisterBackgroundSignalScheduler(); UnloadBlockIndex(); delete pcoinsTip; delete pcoinsdbview; diff --git a/src/test/test_pivx.h b/src/test/test_pivx.h index 7b8ed9cb381a..69d706c90647 100644 --- a/src/test/test_pivx.h +++ b/src/test/test_pivx.h @@ -6,6 +6,7 @@ #define PIVX_TEST_TEST_PIVX_H #include "fs.h" +#include "scheduler.h" #include "txdb.h" #include @@ -48,6 +49,7 @@ struct TestingSetup: public BasicTestingSetup { fs::path pathTemp; boost::thread_group threadGroup; CConnman* connman; + CScheduler scheduler; ECCVerifyHandle globalVerifyHandle; TestingSetup(); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 8b4b9e4d3ebf..efb2cd055eba 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -5,6 +5,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "validationinterface.h" +#include "scheduler.h" #include @@ -31,6 +32,8 @@ struct MainSignalsInstance { /** Notifies listeners of a change to the tip of the active block chain. */ boost::signals2::signal)> ChainTip; + + CScheduler *m_scheduler = nullptr; }; static CMainSignals g_signals; @@ -39,6 +42,15 @@ CMainSignals::CMainSignals() { m_internals.reset(new MainSignalsInstance()); } +void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler) { + assert(!m_internals->m_scheduler); + m_internals->m_scheduler = &scheduler; +} + +void CMainSignals::UnregisterBackgroundSignalScheduler() { + m_internals->m_scheduler = nullptr; +} + CMainSignals& GetMainSignals() { return g_signals; diff --git a/src/validationinterface.h b/src/validationinterface.h index 386efe6fe291..cd1bbb3f549c 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -19,6 +19,7 @@ class CTransaction; class CValidationInterface; class CValidationState; class uint256; +class CScheduler; // These functions dispatch to one or all registered wallets @@ -56,12 +57,18 @@ class CMainSignals { friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterAllValidationInterfaces(); + public: CMainSignals(); /** A posInBlock value for SyncTransaction which indicates the transaction was conflicted, disconnected, or not in a block */ static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1; + /** Register a CScheduler to give callbacks which should run in the background (may only be called once) */ + void RegisterBackgroundSignalScheduler(CScheduler& scheduler); + /** Unregister a CScheduler to give callbacks which should run in the background - these callbacks will now be dropped! */ + void UnregisterBackgroundSignalScheduler(); + void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload); void SyncTransaction(const CTransaction &, const CBlockIndex *pindex, int posInBlock); void NotifyTransactionLock(const CTransaction&); From 6f5edaa5a947fe6b7a230fcd3183f8850407ccdf Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 20 Jan 2017 15:10:43 -0500 Subject: [PATCH 08/22] Add default arg to CScheduler to schedule() a callback now --- src/scheduler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scheduler.h b/src/scheduler.h index 9c1a62cc9308..1c0f8d4be85a 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -42,7 +42,7 @@ class CScheduler typedef std::function Function; // Call func at/after time t - void schedule(Function f, boost::chrono::system_clock::time_point t); + void schedule(Function f, boost::chrono::system_clock::time_point t=boost::chrono::system_clock::now()); // Convenience method: call f once deltaSeconds from now void scheduleFromNow(Function f, int64_t deltaSeconds); From 79e283f172bdf57f74811b3981fad8efa0d90c42 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 10 Apr 2017 14:55:49 -0400 Subject: [PATCH 09/22] Support more than one CScheduler thread for serial clients This will be used by CValidationInterface soon. This requires a bit of work as we need to ensure that most of our callbacks happen in-order (to avoid synchronization issues in wallet) - we keep our own internal queue and push things onto it, scheduling a queue-draining function immediately upon new callbacks. --- src/scheduler.cpp | 52 +++++++++++++++++++++++++++++++++++++ src/scheduler.h | 24 +++++++++++++++++ src/validationinterface.cpp | 23 +++++++++------- src/validationinterface.h | 2 -- 4 files changed, 90 insertions(+), 11 deletions(-) diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 90110f20750c..4a06d98d8be9 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -121,3 +121,55 @@ size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first, } return result; } + + +void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue() { + { + LOCK(m_cs_callbacks_pending); + // Try to avoid scheduling too many copies here, but if we + // accidentally have two ProcessQueue's scheduled at once its + // not a big deal. + if (m_are_callbacks_running) return; + if (m_callbacks_pending.empty()) return; + } + m_pscheduler->schedule(std::bind(&SingleThreadedSchedulerClient::ProcessQueue, this)); +} + +void SingleThreadedSchedulerClient::ProcessQueue() { + std::function callback; + { + LOCK(m_cs_callbacks_pending); + if (m_are_callbacks_running) return; + if (m_callbacks_pending.empty()) return; + m_are_callbacks_running = true; + + callback = std::move(m_callbacks_pending.front()); + m_callbacks_pending.pop_front(); + } + + // RAII the setting of fCallbacksRunning and calling MaybeScheduleProcessQueue + // to ensure both happen safely even if callback() throws. + struct RAIICallbacksRunning { + SingleThreadedSchedulerClient* instance; + RAIICallbacksRunning(SingleThreadedSchedulerClient* _instance) : instance(_instance) {} + ~RAIICallbacksRunning() { + { + LOCK(instance->m_cs_callbacks_pending); + instance->m_are_callbacks_running = false; + } + instance->MaybeScheduleProcessQueue(); + } + } raiicallbacksrunning(this); + + callback(); +} + +void SingleThreadedSchedulerClient::AddToProcessQueue(std::function func) { + assert(m_pscheduler); + + { + LOCK(m_cs_callbacks_pending); + m_callbacks_pending.emplace_back(std::move(func)); + } + MaybeScheduleProcessQueue(); +} diff --git a/src/scheduler.h b/src/scheduler.h index 1c0f8d4be85a..bb5bd76d4c1d 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -15,6 +15,8 @@ #include #include +#include "sync.h" + // // Simple class for background tasks that should be run // periodically or once "after a while" @@ -80,4 +82,26 @@ class CScheduler bool shouldStop() { return stopRequested || (stopWhenEmpty && taskQueue.empty()); } }; +/** + * Class used by CScheduler clients which may schedule multiple jobs + * which are required to be run serially. Does not require such jobs + * to be executed on the same thread, but no two jobs will be executed + * at the same time. + */ +class SingleThreadedSchedulerClient { +private: + CScheduler *m_pscheduler; + + RecursiveMutex m_cs_callbacks_pending; + std::list> m_callbacks_pending; + bool m_are_callbacks_running = false; + + void MaybeScheduleProcessQueue(); + void ProcessQueue(); + +public: + SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {} + void AddToProcessQueue(std::function func); +}; + #endif diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index efb2cd055eba..1a8de1892ed5 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -6,6 +6,11 @@ #include "validationinterface.h" #include "scheduler.h" +#include "sync.h" +#include "util.h" + +#include +#include #include @@ -29,26 +34,26 @@ struct MainSignalsInstance { boost::signals2::signal BlockChecked; /** Notifies listeners that a block has been successfully mined */ boost::signals2::signal BlockFound; - /** Notifies listeners of a change to the tip of the active block chain. */ boost::signals2::signal)> ChainTip; - CScheduler *m_scheduler = nullptr; + // We are not allowed to assume the scheduler only runs in one thread, + // but must ensure all callbacks happen in-order, so we end up creating + // our own queue here :( + SingleThreadedSchedulerClient m_schedulerClient; + + MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {} }; static CMainSignals g_signals; -CMainSignals::CMainSignals() { - m_internals.reset(new MainSignalsInstance()); -} - void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler) { - assert(!m_internals->m_scheduler); - m_internals->m_scheduler = &scheduler; + assert(!m_internals); + m_internals.reset(new MainSignalsInstance(&scheduler)); } void CMainSignals::UnregisterBackgroundSignalScheduler() { - m_internals->m_scheduler = nullptr; + m_internals.reset(nullptr); } CMainSignals& GetMainSignals() diff --git a/src/validationinterface.h b/src/validationinterface.h index cd1bbb3f549c..cb3b07bdfc47 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -59,8 +59,6 @@ class CMainSignals { friend void ::UnregisterAllValidationInterfaces(); public: - CMainSignals(); - /** A posInBlock value for SyncTransaction which indicates the transaction was conflicted, disconnected, or not in a block */ static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1; From 385a9755cf5309d1b4337599292eb033c0d4419a Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 27 Jun 2017 19:07:52 -0400 Subject: [PATCH 10/22] Flush CValidationInterface callbacks prior to destruction Note that the CScheduler thread cant be running at this point, it has already been stopped with the rest of the init threadgroup. Thus, just calling any remaining loose callbacks during Shutdown() is sane. --- src/init.cpp | 13 +++++++++++++ src/scheduler.cpp | 9 +++++++++ src/scheduler.h | 3 +++ src/test/test_pivx.cpp | 1 + src/validationinterface.cpp | 4 ++++ src/validationinterface.h | 2 ++ 6 files changed, 32 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index 7e3c99eaa401..3e59bd952fd4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -258,6 +258,19 @@ void PrepareShutdown() fFeeEstimatesInitialized = false; } + // FlushStateToDisk generates a SetBestChain callback, which we should avoid missing + FlushStateToDisk(); + + // After there are no more peers/RPC left to give us new data which may generate + // CValidationInterface callbacks, flush them... + GetMainSignals().FlushBackgroundCallbacks(); + + // Any future callbacks will be dropped. This should absolutely be safe - if + // missing a callback results in an unrecoverable situation, unclean shutdown + // would too. The only reason to do the above flushes is to let the wallet catch + // up with our current chain to avoid any strange pruning edge cases and make + // next startup faster by avoiding rescan. + { LOCK(cs_main); if (pcoinsTip != NULL) { diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 4a06d98d8be9..3420a8edac9b 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -173,3 +173,12 @@ void SingleThreadedSchedulerClient::AddToProcessQueue(std::function } MaybeScheduleProcessQueue(); } + +void SingleThreadedSchedulerClient::EmptyQueue() { + bool should_continue = true; + while (should_continue) { + ProcessQueue(); + LOCK(m_cs_callbacks_pending); + should_continue = !m_callbacks_pending.empty(); + } +} diff --git a/src/scheduler.h b/src/scheduler.h index bb5bd76d4c1d..47fe288b0ce1 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -102,6 +102,9 @@ class SingleThreadedSchedulerClient { public: SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {} void AddToProcessQueue(std::function func); + + // Processes all remaining queue members on the calling thread, blocking until queue is empty + void EmptyQueue(); }; #endif diff --git a/src/test/test_pivx.cpp b/src/test/test_pivx.cpp index e678d654a434..4e7a61c92fe7 100644 --- a/src/test/test_pivx.cpp +++ b/src/test/test_pivx.cpp @@ -81,6 +81,7 @@ TestingSetup::~TestingSetup() UnregisterNodeSignals(GetNodeSignals()); threadGroup.interrupt_all(); threadGroup.join_all(); + GetMainSignals().FlushBackgroundCallbacks(); GetMainSignals().UnregisterBackgroundSignalScheduler(); UnloadBlockIndex(); delete pcoinsTip; diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 1a8de1892ed5..30fcb04265ec 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -56,6 +56,10 @@ void CMainSignals::UnregisterBackgroundSignalScheduler() { m_internals.reset(nullptr); } +void CMainSignals::FlushBackgroundCallbacks() { + m_internals->m_schedulerClient.EmptyQueue(); +} + CMainSignals& GetMainSignals() { return g_signals; diff --git a/src/validationinterface.h b/src/validationinterface.h index cb3b07bdfc47..9866a38754d9 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -66,6 +66,8 @@ class CMainSignals { void RegisterBackgroundSignalScheduler(CScheduler& scheduler); /** Unregister a CScheduler to give callbacks which should run in the background - these callbacks will now be dropped! */ void UnregisterBackgroundSignalScheduler(); + /** Call any remaining callbacks on the calling thread */ + void FlushBackgroundCallbacks(); void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload); void SyncTransaction(const CTransaction &, const CBlockIndex *pindex, int posInBlock); From 344937a67bdafbf7884e5aeaa8fe761e5bc4a7ce Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 10 Jul 2017 21:08:19 -0400 Subject: [PATCH 11/22] Expose if CScheduler is being serviced, assert its not in EmptyQueue --- src/scheduler.cpp | 5 +++++ src/scheduler.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 3420a8edac9b..57063d40b57b 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -122,6 +122,10 @@ size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first, return result; } +bool CScheduler::AreThreadsServicingQueue() const { + return nThreadsServicingQueue; +} + void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue() { { @@ -175,6 +179,7 @@ void SingleThreadedSchedulerClient::AddToProcessQueue(std::function } void SingleThreadedSchedulerClient::EmptyQueue() { + assert(!m_pscheduler->AreThreadsServicingQueue()); bool should_continue = true; while (should_continue) { ProcessQueue(); diff --git a/src/scheduler.h b/src/scheduler.h index 47fe288b0ce1..48b031aec5aa 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -72,6 +72,9 @@ class CScheduler size_t getQueueInfo(boost::chrono::system_clock::time_point &first, boost::chrono::system_clock::time_point &last) const; + // Returns true if there are threads actively running in serviceQueue() + bool AreThreadsServicingQueue() const; + private: std::multimap taskQueue; boost::condition_variable newTaskScheduled; @@ -104,6 +107,7 @@ class SingleThreadedSchedulerClient { void AddToProcessQueue(std::function func); // Processes all remaining queue members on the calling thread, blocking until queue is empty + // Must be called after the CScheduler has no remaining processing threads! void EmptyQueue(); }; From 4188f0475fe61ebbf11ee591c6d06b7dfffeb06f Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 28 Nov 2017 12:08:09 +0100 Subject: [PATCH 12/22] Fix shutdown in case of errors during initialization PR #10286 introduced a few steps which are not robust to early shutdown in initialization. Stumbled upon this with #11781, not sure if there are other scenarios that can trigger it, but it's harden against this in any case. --- src/init.cpp | 5 ++++- src/validationinterface.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 3e59bd952fd4..904e8e1437e7 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -232,7 +232,10 @@ void PrepareShutdown() #endif StopMapPort(); - UnregisterValidationInterface(peerLogic.get()); + // Because these depend on each-other, we make sure that neither can be + // using the other before destroying them. + if (peerLogic) UnregisterValidationInterface(peerLogic.get()); + if (g_connman) g_connman->Stop(); peerLogic.reset(); g_connman.reset(); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 30fcb04265ec..bf59ed008061 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -57,7 +57,9 @@ void CMainSignals::UnregisterBackgroundSignalScheduler() { } void CMainSignals::FlushBackgroundCallbacks() { - m_internals->m_schedulerClient.EmptyQueue(); + if (m_internals) { + m_internals->m_schedulerClient.EmptyQueue(); + } } CMainSignals& GetMainSignals() @@ -93,6 +95,9 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) void UnregisterAllValidationInterfaces() { + if (!g_signals.m_internals) { + return; + } g_signals.m_internals->BlockFound.disconnect_all_slots(); g_signals.m_internals->BlockChecked.disconnect_all_slots(); g_signals.m_internals->Broadcast.disconnect_all_slots(); From 7e42dc7e5723a2aeabf950e58e61c0c0db7e530f Mon Sep 17 00:00:00 2001 From: furszy Date: Sun, 15 Nov 2020 00:52:30 -0300 Subject: [PATCH 13/22] refactor: Use boost::scoped_connection in signal/slot, also prefer range-based loop instead of std::transform coming from btc@2196c51821e340c9a9d2c76c30f9402370f84994 --- src/rpc/server.cpp | 6 +---- src/validationinterface.cpp | 53 ++++++++++++++++++------------------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index bf897b92a1ac..be719cba0f9b 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -454,11 +454,7 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const std::vector CRPCTable::listCommands() const { std::vector commandList; - typedef std::map commandMap; - - std::transform( mapCommands.begin(), mapCommands.end(), - std::back_inserter(commandList), - boost::bind(&commandMap::value_type::first,boost::placeholders::_1) ); + for (const auto& i : mapCommands) commandList.emplace_back(i.first); return commandList; } diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index bf59ed008061..c63b3293bbfd 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -12,8 +12,21 @@ #include #include +#include #include +struct ValidationInterfaceConnections { + boost::signals2::scoped_connection UpdatedBlockTip; + boost::signals2::scoped_connection SyncTransaction; + boost::signals2::scoped_connection NotifyTransactionLock; + boost::signals2::scoped_connection UpdatedTransaction; + boost::signals2::scoped_connection SetBestChain; + boost::signals2::scoped_connection Broadcast; + boost::signals2::scoped_connection BlockChecked; + boost::signals2::scoped_connection BlockFound; + boost::signals2::scoped_connection ChainTip; +}; + struct MainSignalsInstance { // XX42 boost::signals2::signal EraseTransaction; /** Notifies listeners of updated block chain tip */ @@ -41,6 +54,7 @@ struct MainSignalsInstance { // but must ensure all callbacks happen in-order, so we end up creating // our own queue here :( SingleThreadedSchedulerClient m_schedulerClient; + std::unordered_map m_connMainSignals; MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {} }; @@ -69,28 +83,21 @@ CMainSignals& GetMainSignals() void RegisterValidationInterface(CValidationInterface* pwalletIn) { - g_signals.m_internals->UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - g_signals.m_internals->SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - g_signals.m_internals->ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - g_signals.m_internals->NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, boost::placeholders::_1)); - g_signals.m_internals->UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, boost::placeholders::_1)); - g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, boost::placeholders::_1)); - g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, boost::placeholders::_1)); - g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, boost::placeholders::_1, boost::placeholders::_2)); - g_signals.m_internals->BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, boost::placeholders::_1)); + ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn]; + conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + conns.SyncTransaction = g_signals.m_internals->SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + conns.ChainTip = g_signals.m_internals->ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + conns.NotifyTransactionLock = g_signals.m_internals->NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, boost::placeholders::_1)); + conns.UpdatedTransaction = g_signals.m_internals->UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, boost::placeholders::_1)); + conns.SetBestChain = g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, boost::placeholders::_1)); + conns.Broadcast = g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, boost::placeholders::_1)); + conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, boost::placeholders::_1, boost::placeholders::_2)); + conns.BlockFound = g_signals.m_internals->BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, boost::placeholders::_1)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { - g_signals.m_internals->BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, boost::placeholders::_1)); - g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, boost::placeholders::_1, boost::placeholders::_2)); - g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, boost::placeholders::_1)); - g_signals.m_internals->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, boost::placeholders::_1)); - g_signals.m_internals->UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, boost::placeholders::_1)); - g_signals.m_internals->NotifyTransactionLock.disconnect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, boost::placeholders::_1)); - g_signals.m_internals->SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - g_signals.m_internals->ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - g_signals.m_internals->UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + g_signals.m_internals->m_connMainSignals.erase(pwalletIn); } void UnregisterAllValidationInterfaces() @@ -98,15 +105,7 @@ void UnregisterAllValidationInterfaces() if (!g_signals.m_internals) { return; } - g_signals.m_internals->BlockFound.disconnect_all_slots(); - g_signals.m_internals->BlockChecked.disconnect_all_slots(); - g_signals.m_internals->Broadcast.disconnect_all_slots(); - g_signals.m_internals->SetBestChain.disconnect_all_slots(); - g_signals.m_internals->UpdatedTransaction.disconnect_all_slots(); - g_signals.m_internals->NotifyTransactionLock.disconnect_all_slots(); - g_signals.m_internals->SyncTransaction.disconnect_all_slots(); - g_signals.m_internals->ChainTip.disconnect_all_slots(); - g_signals.m_internals->UpdatedBlockTip.disconnect_all_slots(); + g_signals.m_internals->m_connMainSignals.clear(); } void CMainSignals::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) { From 89c968e51cdbe902e1f33e84797d27d9932f446a Mon Sep 17 00:00:00 2001 From: furszy Date: Sun, 15 Nov 2020 01:11:22 -0300 Subject: [PATCH 14/22] scripted-diff: Replace boost::bind with std::bind -BEGIN VERIFY SCRIPT- for j in $(seq 1 6) do sed -i "s/ boost::placeholders::_${j}/ std::placeholders::_${j}/g" $(git grep --name-only " boost::placeholders::_${j}" -- '*.cpp' '*.h') done sed -i "s/boost::bind/std::bind/g" $(git grep --name-only boost::bind -- '*.cpp' '*.h') sed -i "s/boost::ref/std::ref/g" $(git grep --name-only boost::ref -- '*.cpp' '*.h') sed -i '/boost\/bind/d' $(git grep --name-only boost/bind) -END VERIFY SCRIPT- --- src/init.cpp | 10 +++++----- src/miner.cpp | 2 +- src/net.cpp | 2 +- src/qt/clientmodel.cpp | 10 +++++----- src/qt/pivx/pivxgui.cpp | 2 +- src/qt/pivx/splash.cpp | 8 ++++---- src/qt/transactiontablemodel.cpp | 4 ++-- src/qt/walletmodel.cpp | 12 ++++++------ src/rpc/server.cpp | 5 ++--- src/scheduler.cpp | 5 ++--- src/scheduler.h | 4 ++-- src/test/reverselock_tests.cpp | 1 - src/test/scheduler_tests.cpp | 15 +++++++-------- src/test/transaction_tests.cpp | 2 +- src/torcontrol.cpp | 23 +++++++++++------------ src/validationinterface.cpp | 18 +++++++++--------- src/wallet/rpcwallet.cpp | 2 +- 17 files changed, 60 insertions(+), 65 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 904e8e1437e7..44a16e9c4510 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1244,8 +1244,8 @@ bool AppInitMain() } // Start the lightweight task scheduler thread - CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler); - threadGroup.create_thread(boost::bind(&TraceThread, "scheduler", serviceLoop)); + CScheduler::Function serviceLoop = std::bind(&CScheduler::serviceQueue, &scheduler); + threadGroup.create_thread(std::bind(&TraceThread, "scheduler", serviceLoop)); GetMainSignals().RegisterBackgroundSignalScheduler(scheduler); @@ -1758,7 +1758,7 @@ bool AppInitMain() for (const std::string& strFile : gArgs.GetArgs("-loadblock")) { vImportFiles.push_back(strFile);; } - threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); + threadGroup.create_thread(std::bind(&ThreadImport, vImportFiles)); // Wait for genesis block to be processed LogPrintf("Waiting for genesis block to be imported...\n"); @@ -1867,7 +1867,7 @@ bool AppInitMain() LogPrintf("fLiteMode %d\n", fLiteMode); LogPrintf("Budget Mode %s\n", strBudgetMode.c_str()); - threadGroup.create_thread(boost::bind(&ThreadCheckMasternodes)); + threadGroup.create_thread(std::bind(&ThreadCheckMasternodes)); if (ShutdownRequested()) { LogPrintf("Shutdown requested. Exiting.\n"); @@ -1935,7 +1935,7 @@ bool AppInitMain() // StakeMiner thread disabled by default on regtest if (gArgs.GetBoolArg("-staking", !Params().IsRegTestNet() && DEFAULT_STAKING)) { - threadGroup.create_thread(boost::bind(&ThreadStakeMinter)); + threadGroup.create_thread(std::bind(&ThreadStakeMinter)); } } #endif diff --git a/src/miner.cpp b/src/miner.cpp index fb77c93fb269..38b89e628247 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -738,7 +738,7 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) minerThreads = new boost::thread_group(); for (int i = 0; i < nThreads; i++) - minerThreads->create_thread(boost::bind(&ThreadBitcoinMiner, pwallet)); + minerThreads->create_thread(std::bind(&ThreadBitcoinMiner, pwallet)); } // ppcoin: stake minter thread diff --git a/src/net.cpp b/src/net.cpp index 277559bc1cfa..9505f2d7476b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2180,7 +2180,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c threadMessageHandler = std::thread(&TraceThread >, "msghand", std::function(std::bind(&CConnman::ThreadMessageHandler, this))); // Dump network addresses - scheduler.scheduleEvery(boost::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL); + scheduler.scheduleEvery(std::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL); return true; } diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 5e0ee3a1c8b5..a54f62e83e03 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -303,11 +303,11 @@ static void BannedListChanged(ClientModel *clientmodel) void ClientModel::subscribeToCoreSignals() { // Connect signals to client - m_handler_show_progress = interfaces::MakeHandler(uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2))); - m_handler_notify_num_connections_changed = interfaces::MakeHandler(uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, boost::placeholders::_1))); - m_handler_notify_alert_changed = interfaces::MakeHandler(uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this))); - m_handler_banned_list_changed = interfaces::MakeHandler(uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this))); - m_handler_notify_block_tip = interfaces::MakeHandler(uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, boost::placeholders::_1, boost::placeholders::_2))); + m_handler_show_progress = interfaces::MakeHandler(uiInterface.ShowProgress.connect(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2))); + m_handler_notify_num_connections_changed = interfaces::MakeHandler(uiInterface.NotifyNumConnectionsChanged.connect(std::bind(NotifyNumConnectionsChanged, this, std::placeholders::_1))); + m_handler_notify_alert_changed = interfaces::MakeHandler(uiInterface.NotifyAlertChanged.connect(std::bind(NotifyAlertChanged, this))); + m_handler_banned_list_changed = interfaces::MakeHandler(uiInterface.BannedListChanged.connect(std::bind(BannedListChanged, this))); + m_handler_notify_block_tip = interfaces::MakeHandler(uiInterface.NotifyBlockTip.connect(std::bind(BlockTipChanged, this, std::placeholders::_1, std::placeholders::_2))); } void ClientModel::unsubscribeFromCoreSignals() diff --git a/src/qt/pivx/pivxgui.cpp b/src/qt/pivx/pivxgui.cpp index 87c4abd925c8..c8800cb60045 100644 --- a/src/qt/pivx/pivxgui.cpp +++ b/src/qt/pivx/pivxgui.cpp @@ -690,7 +690,7 @@ static bool ThreadSafeMessageBox(PIVXGUI* gui, const std::string& message, const void PIVXGUI::subscribeToCoreSignals() { // Connect signals to client - m_handler_message_box = interfaces::MakeHandler(uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3))); + m_handler_message_box = interfaces::MakeHandler(uiInterface.ThreadSafeMessageBox.connect(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); } void PIVXGUI::unsubscribeFromCoreSignals() diff --git a/src/qt/pivx/splash.cpp b/src/qt/pivx/splash.cpp index c90cb4da98fb..eca2c3bc8c18 100644 --- a/src/qt/pivx/splash.cpp +++ b/src/qt/pivx/splash.cpp @@ -79,16 +79,16 @@ static void ShowProgress(Splash* splash, const std::string& title, int nProgress #ifdef ENABLE_WALLET std::unique_ptr m_handler_show_progress_wallet; static void ConnectWallet(Splash* splash, CWallet* wallet){ - m_handler_show_progress_wallet = interfaces::MakeHandler(wallet->ShowProgress.connect(boost::bind(ShowProgress, splash, boost::placeholders::_1, boost::placeholders::_2))); + m_handler_show_progress_wallet = interfaces::MakeHandler(wallet->ShowProgress.connect(std::bind(ShowProgress, splash, std::placeholders::_1, std::placeholders::_2))); } #endif void Splash::subscribeToCoreSignals(){ // Connect signals to client - m_handler_init_message = interfaces::MakeHandler(uiInterface.InitMessage.connect(boost::bind(InitMessage, this, boost::placeholders::_1))); - m_handler_show_progress = interfaces::MakeHandler(uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2))); + m_handler_init_message = interfaces::MakeHandler(uiInterface.InitMessage.connect(std::bind(InitMessage, this, std::placeholders::_1))); + m_handler_show_progress = interfaces::MakeHandler(uiInterface.ShowProgress.connect(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2))); #ifdef ENABLE_WALLET - m_handler_load_wallet = interfaces::MakeHandler(uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, boost::placeholders::_1))); + m_handler_load_wallet = interfaces::MakeHandler(uiInterface.LoadWallet.connect(std::bind(ConnectWallet, this, std::placeholders::_1))); #endif } diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 3306579d1f9c..ddb5c9fe3ab8 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -880,8 +880,8 @@ static void ShowProgress(TransactionTableModel* ttm, const std::string& title, i void TransactionTableModel::subscribeToCoreSignals() { // Connect signals to wallet - m_handler_transaction_changed = interfaces::MakeHandler(wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3))); - m_handler_show_progress = interfaces::MakeHandler(wallet->ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2))); + m_handler_transaction_changed = interfaces::MakeHandler(wallet->NotifyTransactionChanged.connect(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); + m_handler_show_progress = interfaces::MakeHandler(wallet->ShowProgress.connect(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2))); } void TransactionTableModel::unsubscribeFromCoreSignals() diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index e822b44e3607..c8e981c1f31f 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -762,12 +762,12 @@ static void NotifyWalletBacked(WalletModel* model, const bool& fSuccess, const s void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet - m_handler_notify_status_changed = interfaces::MakeHandler(wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, boost::placeholders::_1))); - m_handler_notify_addressbook_changed = interfaces::MakeHandler(wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5, boost::placeholders::_6))); - m_handler_notify_transaction_changed = interfaces::MakeHandler(wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3))); - m_handler_show_progress = interfaces::MakeHandler(wallet->ShowProgress.connect(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2))); - m_handler_notify_watch_only_changed = interfaces::MakeHandler(wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, boost::placeholders::_1))); - m_handler_notify_walletbacked = interfaces::MakeHandler(wallet->NotifyWalletBacked.connect(boost::bind(NotifyWalletBacked, this, boost::placeholders::_1, boost::placeholders::_2))); + m_handler_notify_status_changed = interfaces::MakeHandler(wallet->NotifyStatusChanged.connect(std::bind(&NotifyKeyStoreStatusChanged, this, std::placeholders::_1))); + m_handler_notify_addressbook_changed = interfaces::MakeHandler(wallet->NotifyAddressBookChanged.connect(std::bind(NotifyAddressBookChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6))); + m_handler_notify_transaction_changed = interfaces::MakeHandler(wallet->NotifyTransactionChanged.connect(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); + m_handler_show_progress = interfaces::MakeHandler(wallet->ShowProgress.connect(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2))); + m_handler_notify_watch_only_changed = interfaces::MakeHandler(wallet->NotifyWatchonlyChanged.connect(std::bind(NotifyWatchonlyChanged, this, std::placeholders::_1))); + m_handler_notify_walletbacked = interfaces::MakeHandler(wallet->NotifyWalletBacked.connect(std::bind(NotifyWalletBacked, this, std::placeholders::_1, std::placeholders::_2))); } void WalletModel::unsubscribeFromCoreSignals() diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index be719cba0f9b..1baaa3db65e9 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -20,7 +20,6 @@ #include "wallet/wallet.h" #endif // ENABLE_WALLET -#include #include #include @@ -58,12 +57,12 @@ void RPCServer::OnStopped(std::function slot) void RPCServer::OnPreCommand(std::function slot) { - g_rpcSignals.PreCommand.connect(boost::bind(slot, boost::placeholders::_1)); + g_rpcSignals.PreCommand.connect(std::bind(slot, std::placeholders::_1)); } void RPCServer::OnPostCommand(std::function slot) { - g_rpcSignals.PostCommand.connect(boost::bind(slot, boost::placeholders::_1)); + g_rpcSignals.PostCommand.connect(std::bind(slot, std::placeholders::_1)); } void RPCTypeCheck(const UniValue& params, diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 57063d40b57b..a59a003fd0ac 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -9,7 +9,6 @@ #include "reverselock.h" #include -#include #include CScheduler::CScheduler() : nThreadsServicingQueue(0), stopRequested(false), stopWhenEmpty(false) @@ -102,12 +101,12 @@ void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaSeconds) static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaSeconds) { f(); - s->scheduleFromNow(boost::bind(&Repeat, s, f, deltaSeconds), deltaSeconds); + s->scheduleFromNow(std::bind(&Repeat, s, f, deltaSeconds), deltaSeconds); } void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaSeconds) { - scheduleFromNow(boost::bind(&Repeat, this, f, deltaSeconds), deltaSeconds); + scheduleFromNow(std::bind(&Repeat, this, f, deltaSeconds), deltaSeconds); } size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first, diff --git a/src/scheduler.h b/src/scheduler.h index 48b031aec5aa..33e51500c5b7 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -25,8 +25,8 @@ // // CScheduler* s = new CScheduler(); // s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { } -// s->scheduleFromNow(boost::bind(Class::func, this, argument), 3); -// boost::thread* t = new boost::thread(boost::bind(CScheduler::serviceQueue, s)); +// s->scheduleFromNow(std::bind(Class::func, this, argument), 3); +// boost::thread* t = new boost::thread(std::bind(CScheduler::serviceQueue, s)); // // ... then at program shutdown, clean up the thread running serviceQueue: // t->interrupt(); diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp index 99c63c55f6d8..6777a5298474 100644 --- a/src/test/reverselock_tests.cpp +++ b/src/test/reverselock_tests.cpp @@ -5,7 +5,6 @@ #include "reverselock.h" -#include #include #include #include diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index a413877e08aa..ce46cbf5887f 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -9,7 +9,6 @@ #include "config/pivx-config.h" #endif -#include #include #include #include @@ -25,7 +24,7 @@ static void microTask(CScheduler& s, boost::mutex& mutex, int& counter, int delt } boost::chrono::system_clock::time_point noTime = boost::chrono::system_clock::time_point::min(); if (rescheduleTime != noTime) { - CScheduler::Function f = boost::bind(µTask, boost::ref(s), boost::ref(mutex), boost::ref(counter), -delta + 1, noTime); + CScheduler::Function f = std::bind(µTask, std::ref(s), std::ref(mutex), std::ref(counter), -delta + 1, noTime); s.schedule(f, rescheduleTime); } } @@ -66,8 +65,8 @@ BOOST_AUTO_TEST_CASE(manythreads) boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng)); boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng)); int whichCounter = zeroToNine(rng); - CScheduler::Function f = boost::bind(µTask, boost::ref(microTasks), - boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]), + CScheduler::Function f = std::bind(µTask, std::ref(microTasks), + std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]), randomDelta(rng), tReschedule); microTasks.schedule(f, t); } @@ -79,20 +78,20 @@ BOOST_AUTO_TEST_CASE(manythreads) // As soon as these are created they will start running and servicing the queue boost::thread_group microThreads; for (int i = 0; i < 5; i++) - microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, µTasks)); + microThreads.create_thread(std::bind(&CScheduler::serviceQueue, µTasks)); MicroSleep(600); now = boost::chrono::system_clock::now(); // More threads and more tasks: for (int i = 0; i < 5; i++) - microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, µTasks)); + microThreads.create_thread(std::bind(&CScheduler::serviceQueue, µTasks)); for (int i = 0; i < 100; i++) { boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng)); boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng)); int whichCounter = zeroToNine(rng); - CScheduler::Function f = boost::bind(µTask, boost::ref(microTasks), - boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]), + CScheduler::Function f = std::bind(µTask, std::ref(microTasks), + std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]), randomDelta(rng), tReschedule); microTasks.schedule(f, t); } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 1da983ae5694..0be88c2f1faf 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -374,7 +374,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) { CCheckQueueControl control(&scriptcheckqueue); for (int i=0; i<20; i++) - threadGroup.create_thread(boost::bind(&CCheckQueue::Thread, boost::ref(scriptcheckqueue))); + threadGroup.create_thread(std::bind(&CCheckQueue::Thread, std::ref(scriptcheckqueue))); std::vector coins; for(uint32_t i = 0; i < mtx.vin.size(); i++) { diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 3ad5607a2354..e35a43b79658 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -463,8 +462,8 @@ TorController::TorController(struct event_base* _base, const std::string& _targe if (!reconnect_ev) LogPrintf("tor: Failed to create event for reconnection: out of memory?\n"); // Start connection attempts immediately - if (!conn.Connect(_target, boost::bind(&TorController::connected_cb, this, boost::placeholders::_1), - boost::bind(&TorController::disconnected_cb, this, boost::placeholders::_1) )) { + if (!conn.Connect(_target, std::bind(&TorController::connected_cb, this, std::placeholders::_1), + std::bind(&TorController::disconnected_cb, this, std::placeholders::_1) )) { LogPrintf("tor: Initiating connection to Tor control port %s failed\n", _target); } // Read service private key if cached @@ -541,7 +540,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& // Request hidden service, redirect port. // Note that the 'virtual' port is always the default port to avoid decloaking nodes using other ports. _conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, Params().GetDefaultPort(), GetListenPort()), - boost::bind(&TorController::add_onion_cb, this, boost::placeholders::_1, boost::placeholders::_2)); + std::bind(&TorController::add_onion_cb, this, std::placeholders::_1, std::placeholders::_2)); } else { LogPrintf("tor: Authentication failed\n"); } @@ -600,7 +599,7 @@ void TorController::authchallenge_cb(TorControlConnection& _conn, const TorContr } std::vector computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce); - _conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, boost::placeholders::_1, boost::placeholders::_2)); + _conn.Command("AUTHENTICATE " + HexStr(computedClientHash), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); } else { LogPrintf("tor: Invalid reply to AUTHCHALLENGE\n"); } @@ -649,23 +648,23 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro if (methods.count("HASHEDPASSWORD")) { LogPrint(BCLog::TOR, "tor: Using HASHEDPASSWORD authentication\n"); boost::replace_all(torpassword, "\"", "\\\""); - _conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, boost::placeholders::_1, boost::placeholders::_2)); + _conn.Command("AUTHENTICATE \"" + torpassword + "\"", std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); } else { LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n"); } } else if (methods.count("NULL")) { LogPrint(BCLog::TOR, "tor: Using NULL authentication\n"); - _conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, boost::placeholders::_1, boost::placeholders::_2)); + _conn.Command("AUTHENTICATE", std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); } else if (methods.count("SAFECOOKIE")) { // Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie LogPrint(BCLog::TOR, "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile); std::pair status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE); if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) { - // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, boost::placeholders::_1, boost::placeholders::_2)); + // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); cookie = std::vector(status_cookie.second.begin(), status_cookie.second.end()); clientNonce = std::vector(TOR_NONCE_SIZE, 0); GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE); - _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, boost::placeholders::_1, boost::placeholders::_2)); + _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), std::bind(&TorController::authchallenge_cb, this, std::placeholders::_1, std::placeholders::_2)); } else { if (status_cookie.first) { LogPrintf("tor: Authentication cookie %s is not exactly %i bytes, as is required by the spec\n", cookiefile, TOR_COOKIE_SIZE); @@ -687,7 +686,7 @@ void TorController::connected_cb(TorControlConnection& _conn) { reconnect_timeout = RECONNECT_TIMEOUT_START; // First send a PROTOCOLINFO command to figure out what authentication is expected - if (!_conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, boost::placeholders::_1, boost::placeholders::_2))) + if (!_conn.Command("PROTOCOLINFO 1", std::bind(&TorController::protocolinfo_cb, this, std::placeholders::_1, std::placeholders::_2))) LogPrintf("tor: Error sending initial protocolinfo command\n"); } @@ -714,8 +713,8 @@ void TorController::Reconnect() /* Try to reconnect and reestablish if we get booted - for example, Tor * may be restarting. */ - if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, boost::placeholders::_1), - boost::bind(&TorController::disconnected_cb, this, boost::placeholders::_1) )) { + if (!conn.Connect(target, std::bind(&TorController::connected_cb, this, std::placeholders::_1), + std::bind(&TorController::disconnected_cb, this, std::placeholders::_1) )) { LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", target); } } diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index c63b3293bbfd..5de257413bd9 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -84,15 +84,15 @@ CMainSignals& GetMainSignals() void RegisterValidationInterface(CValidationInterface* pwalletIn) { ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn]; - conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - conns.SyncTransaction = g_signals.m_internals->SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - conns.ChainTip = g_signals.m_internals->ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); - conns.NotifyTransactionLock = g_signals.m_internals->NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, boost::placeholders::_1)); - conns.UpdatedTransaction = g_signals.m_internals->UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, boost::placeholders::_1)); - conns.SetBestChain = g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, boost::placeholders::_1)); - conns.Broadcast = g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, boost::placeholders::_1)); - conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, boost::placeholders::_1, boost::placeholders::_2)); - conns.BlockFound = g_signals.m_internals->BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, boost::placeholders::_1)); + conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + conns.SyncTransaction = g_signals.m_internals->SyncTransaction.connect(std::bind(&CValidationInterface::SyncTransaction, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + conns.ChainTip = g_signals.m_internals->ChainTip.connect(std::bind(&CValidationInterface::ChainTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + conns.NotifyTransactionLock = g_signals.m_internals->NotifyTransactionLock.connect(std::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, std::placeholders::_1)); + conns.UpdatedTransaction = g_signals.m_internals->UpdatedTransaction.connect(std::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, std::placeholders::_1)); + conns.SetBestChain = g_signals.m_internals->SetBestChain.connect(std::bind(&CValidationInterface::SetBestChain, pwalletIn, std::placeholders::_1)); + conns.Broadcast = g_signals.m_internals->Broadcast.connect(std::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, std::placeholders::_1)); + conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2)); + conns.BlockFound = g_signals.m_internals->BlockFound.connect(std::bind(&CValidationInterface::ResetRequestCount, pwalletIn, std::placeholders::_1)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 53b0301aa83a..bb9ae542886a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3143,7 +3143,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request) if (nSleepTime > 0) { nWalletUnlockTime = GetTime () + nSleepTime; - RPCRunLater ("lockwallet", boost::bind (LockWallet, pwalletMain), nSleepTime); + RPCRunLater ("lockwallet", std::bind (LockWallet, pwalletMain), nSleepTime); } return NullUniValue; From 2a3980b6207a7f718a820ea3e6aab615b46275c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Tue, 29 Jan 2019 01:08:30 +0000 Subject: [PATCH 15/22] Check m_internals in UnregisterValidationInterface When a wallet is created it is registered in the validation interface (in CWallet::CreateWalletFromFile) but it is not immediately added to the wallets list. If a shutdown is requested before AddWallet (case more evident when -rescan is set) then m_internals can be released (in Shutdown -> UnregisterBackgroundSignalScheduler) before the wallet and then ReleaseWallet would call UnregisterValidationInterface with m_internals already released. --- src/validationinterface.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 5de257413bd9..e14c8ab24f18 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -97,7 +97,9 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) void UnregisterValidationInterface(CValidationInterface* pwalletIn) { - g_signals.m_internals->m_connMainSignals.erase(pwalletIn); + if (g_signals.m_internals) { + g_signals.m_internals->m_connMainSignals.erase(pwalletIn); + } } void UnregisterAllValidationInterfaces() From 0cb53c1dda119332e516746196bbdd165f7b6f5a Mon Sep 17 00:00:00 2001 From: furszy Date: Tue, 24 Nov 2020 05:01:26 -0300 Subject: [PATCH 16/22] Removing boost::signals from validationinterface --- src/validationinterface.cpp | 133 ++++++++++++++++++++---------------- src/validationinterface.h | 4 +- 2 files changed, 79 insertions(+), 58 deletions(-) diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index e14c8ab24f18..1aa009aa22da 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -15,48 +15,75 @@ #include #include -struct ValidationInterfaceConnections { - boost::signals2::scoped_connection UpdatedBlockTip; - boost::signals2::scoped_connection SyncTransaction; - boost::signals2::scoped_connection NotifyTransactionLock; - boost::signals2::scoped_connection UpdatedTransaction; - boost::signals2::scoped_connection SetBestChain; - boost::signals2::scoped_connection Broadcast; - boost::signals2::scoped_connection BlockChecked; - boost::signals2::scoped_connection BlockFound; - boost::signals2::scoped_connection ChainTip; -}; - +//! The MainSignalsInstance manages a list of shared_ptr +//! callbacks. +//! +//! A std::unordered_map is used to track what callbacks are currently +//! registered, and a std::list is to used to store the callbacks that are +//! currently registered as well as any callbacks that are just unregistered +//! and about to be deleted when they are done executing. struct MainSignalsInstance { -// XX42 boost::signals2::signal EraseTransaction; - /** Notifies listeners of updated block chain tip */ - boost::signals2::signal UpdatedBlockTip; - /** A posInBlock value for SyncTransaction which indicates the transaction was conflicted, disconnected, or not in a block */ - static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1; - /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ - boost::signals2::signal SyncTransaction; - /** Notifies listeners of an updated transaction lock without new data. */ - boost::signals2::signal NotifyTransactionLock; - /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ - boost::signals2::signal UpdatedTransaction; - /** Notifies listeners of a new active block chain. */ - boost::signals2::signal SetBestChain; - /** Tells listeners to broadcast their data. */ - boost::signals2::signal Broadcast; - /** Notifies listeners of a block validation result */ - boost::signals2::signal BlockChecked; - /** Notifies listeners that a block has been successfully mined */ - boost::signals2::signal BlockFound; - /** Notifies listeners of a change to the tip of the active block chain. */ - boost::signals2::signal)> ChainTip; - +private: + Mutex m_mutex; + //! List entries consist of a callback pointer and reference count. The + //! count is equal to the number of current executions of that entry, plus 1 + //! if it's registered. It cannot be 0 because that would imply it is + //! unregistered and also not being executed (so shouldn't exist). + struct ListEntry { std::shared_ptr callbacks; int count = 1; }; + std::list m_list GUARDED_BY(m_mutex); + std::unordered_map::iterator> m_map GUARDED_BY(m_mutex); + +public: // We are not allowed to assume the scheduler only runs in one thread, // but must ensure all callbacks happen in-order, so we end up creating // our own queue here :( SingleThreadedSchedulerClient m_schedulerClient; - std::unordered_map m_connMainSignals; - MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {} + explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {} + + void Register(std::shared_ptr callbacks) + { + LOCK(m_mutex); + auto inserted = m_map.emplace(callbacks.get(), m_list.end()); + if (inserted.second) inserted.first->second = m_list.emplace(m_list.end()); + inserted.first->second->callbacks = std::move(callbacks); + } + + void Unregister(CValidationInterface* callbacks) + { + LOCK(m_mutex); + auto it = m_map.find(callbacks); + if (it != m_map.end()) { + if (!--it->second->count) m_list.erase(it->second); + m_map.erase(it); + } + } + + //! Clear unregisters every previously registered callback, erasing every + //! map entry. After this call, the list may still contain callbacks that + //! are currently executing, but it will be cleared when they are done + //! executing. + void Clear() + { + LOCK(m_mutex); + for (auto it = m_list.begin(); it != m_list.end();) { + it = --it->count ? std::next(it) : m_list.erase(it); + } + m_map.clear(); + } + + template void Iterate(F&& f) + { + WAIT_LOCK(m_mutex, lock); + for (auto it = m_list.begin(); it != m_list.end();) { + ++it->count; + { + REVERSE_LOCK(lock); + f(*it->callbacks); + } + it = --it->count ? std::next(it) : m_list.erase(it); + } + } }; static CMainSignals g_signals; @@ -83,22 +110,14 @@ CMainSignals& GetMainSignals() void RegisterValidationInterface(CValidationInterface* pwalletIn) { - ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn]; - conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - conns.SyncTransaction = g_signals.m_internals->SyncTransaction.connect(std::bind(&CValidationInterface::SyncTransaction, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - conns.ChainTip = g_signals.m_internals->ChainTip.connect(std::bind(&CValidationInterface::ChainTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - conns.NotifyTransactionLock = g_signals.m_internals->NotifyTransactionLock.connect(std::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, std::placeholders::_1)); - conns.UpdatedTransaction = g_signals.m_internals->UpdatedTransaction.connect(std::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, std::placeholders::_1)); - conns.SetBestChain = g_signals.m_internals->SetBestChain.connect(std::bind(&CValidationInterface::SetBestChain, pwalletIn, std::placeholders::_1)); - conns.Broadcast = g_signals.m_internals->Broadcast.connect(std::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, std::placeholders::_1)); - conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2)); - conns.BlockFound = g_signals.m_internals->BlockFound.connect(std::bind(&CValidationInterface::ResetRequestCount, pwalletIn, std::placeholders::_1)); + std::shared_ptr sharedValidation = std::make_shared(*pwalletIn); + g_signals.m_internals->Register(std::move(sharedValidation)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { if (g_signals.m_internals) { - g_signals.m_internals->m_connMainSignals.erase(pwalletIn); + g_signals.m_internals->Unregister(pwalletIn); } } @@ -107,41 +126,41 @@ void UnregisterAllValidationInterfaces() if (!g_signals.m_internals) { return; } - g_signals.m_internals->m_connMainSignals.clear(); + g_signals.m_internals->Clear(); } void CMainSignals::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) { - m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); }); } void CMainSignals::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int posInBlock) { - m_internals->SyncTransaction(tx, pindex, posInBlock); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.SyncTransaction(tx, pindex, posInBlock); }); } void CMainSignals::NotifyTransactionLock(const CTransaction& tx) { - m_internals->NotifyTransactionLock(tx); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyTransactionLock(tx); }); } void CMainSignals::UpdatedTransaction(const uint256& hash) { - m_internals->UpdatedTransaction(hash); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedTransaction(hash); }); } void CMainSignals::SetBestChain(const CBlockLocator& locator) { - m_internals->SetBestChain(locator); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.SetBestChain(locator); }); } void CMainSignals::Broadcast(CConnman* connman) { - m_internals->Broadcast(connman); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.Broadcast(connman); }); } void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) { - m_internals->BlockChecked(block, state); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); }); } void CMainSignals::BlockFound(const uint256& hash) { - m_internals->BlockFound(hash); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockFound(hash); }); } void CMainSignals::ChainTip(const CBlockIndex* pindex, const CBlock* block, Optional tree) { - m_internals->ChainTip(pindex, block, tree); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainTip(pindex, block, tree); }); } \ No newline at end of file diff --git a/src/validationinterface.h b/src/validationinterface.h index 9866a38754d9..d392de5b66bb 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -31,7 +31,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn); void UnregisterAllValidationInterfaces(); class CValidationInterface { -protected: +public: /** Notifies listeners of updated block chain tip */ virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {} virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) {} @@ -41,8 +41,10 @@ class CValidationInterface { virtual void SetBestChain(const CBlockLocator &locator) {} virtual bool UpdatedTransaction(const uint256 &hash) { return false;} /** Tells listeners to broadcast their data. */ + virtual void Broadcast(CConnman* connman) { } virtual void ResendWalletTransactions(CConnman* connman) {} virtual void BlockChecked(const CBlock&, const CValidationState&) {} + virtual void BlockFound(const uint256&) {} virtual void ResetRequestCount(const uint256 &hash) {}; friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); From d25e34178455906b8f341af34052c7baa949a247 Mon Sep 17 00:00:00 2001 From: furszy Date: Tue, 24 Nov 2020 05:21:52 -0300 Subject: [PATCH 17/22] back port REVERSE_LOCK --- src/sync.cpp | 18 ++++++++++++ src/sync.h | 39 ++++++++++++++++++++++++ src/test/reverselock_tests.cpp | 54 +++++++++++++++++++++++++--------- 3 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/sync.cpp b/src/sync.cpp index 01403b72d4f3..430bd4db94f8 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -5,6 +5,7 @@ #include "sync.h" +#include #include #include @@ -57,6 +58,11 @@ struct CLockLocation { mutexName, sourceFile, itostr(sourceLine), (fTry ? " (TRY)" : ""), m_thread_name); } + std::string Name() const + { + return mutexName; + } + private: bool fTry; std::string mutexName; @@ -152,6 +158,18 @@ void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry, util::ThreadGetInternalName())); } +void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) +{ + if (!g_lockstack.empty()) { + const auto& lastlock = g_lockstack.back(); + if (lastlock.first == cs) { + lockname = lastlock.second.Name(); + return; + } + } + throw std::system_error(EPERM, std::generic_category(), strprintf("%s:%s %s was not most recent critical section locked", file, line, guardname)); +} + void LeaveCritical() { pop_lock(); diff --git a/src/sync.h b/src/sync.h index 3b3ae3868830..0ba99e200ab5 100644 --- a/src/sync.h +++ b/src/sync.h @@ -51,6 +51,7 @@ LEAVE_CRITICAL_SECTION(mutex); // no RAII #ifdef DEBUG_LOCKORDER void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); void LeaveCritical(); +void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line); std::string LocksHeld(); void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); @@ -65,6 +66,7 @@ extern bool g_debug_lockorder_abort; #else void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} void static inline LeaveCritical() {} +void static inline CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {} void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} void static inline DeleteLock(void* cs) {} @@ -172,8 +174,45 @@ class SCOPED_LOCKABLE UniqueLock : public Base { return Base::owns_lock(); } + +protected: + // needed for reverse_lock + UniqueLock() { } + +public: + /** + * An RAII-style reverse lock. Unlocks on construction and locks on destruction. + */ + class reverse_lock { + public: + explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) { + CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line); + lock.unlock(); + LeaveCritical(); + lock.swap(templock); + } + + ~reverse_lock() { + templock.swap(lock); + EnterCritical(lockname.c_str(), file.c_str(), line, (void*)lock.mutex()); + lock.lock(); + } + + private: + reverse_lock(reverse_lock const&); + reverse_lock& operator=(reverse_lock const&); + + UniqueLock& lock; + UniqueLock templock; + std::string lockname; + const std::string file; + const int line; + }; + friend class reverse_lock; }; +#define REVERSE_LOCK(g) decltype(g)::reverse_lock PASTE2(revlock, __COUNTER__)(g, #g, __FILE__, __LINE__) + template using DebugLock = UniqueLock::type>::type>; diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp index 6777a5298474..22a9db28625e 100644 --- a/src/test/reverselock_tests.cpp +++ b/src/test/reverselock_tests.cpp @@ -1,34 +1,60 @@ -// Copyright (c) 2015 The Bitcoin Core developers -// Copyright (c) 2017-2019 The PIVX developers +// Copyright (c) 2015-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "reverselock.h" +#include "sync.h" +#include "test/test_pivx.h" -#include -#include -#include #include -BOOST_AUTO_TEST_SUITE(reverselock_tests) +BOOST_FIXTURE_TEST_SUITE(reverselock_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(reverselock_basics) { - boost::mutex mutex; - boost::unique_lock lock(mutex); + Mutex mutex; + WAIT_LOCK(mutex, lock); BOOST_CHECK(lock.owns_lock()); { - reverse_lock > rlock(lock); + REVERSE_LOCK(lock); BOOST_CHECK(!lock.owns_lock()); } BOOST_CHECK(lock.owns_lock()); } +BOOST_AUTO_TEST_CASE(reverselock_multiple) +{ + Mutex mutex2; + Mutex mutex; + WAIT_LOCK(mutex2, lock2); + WAIT_LOCK(mutex, lock); + + // Make sure undoing two locks succeeds + { + REVERSE_LOCK(lock); + BOOST_CHECK(!lock.owns_lock()); + REVERSE_LOCK(lock2); + BOOST_CHECK(!lock2.owns_lock()); + } + BOOST_CHECK(lock.owns_lock()); + BOOST_CHECK(lock2.owns_lock()); +} + BOOST_AUTO_TEST_CASE(reverselock_errors) { - boost::mutex mutex; - boost::unique_lock lock(mutex); + Mutex mutex2; + Mutex mutex; + WAIT_LOCK(mutex2, lock2); + WAIT_LOCK(mutex, lock); + +#ifdef DEBUG_LOCKORDER + // Make sure trying to reverse lock a previous lock fails + try { + REVERSE_LOCK(lock2); + BOOST_CHECK(false); // REVERSE_LOCK(lock2) succeeded + } catch(...) { } + BOOST_CHECK(lock2.owns_lock()); +#endif // Make sure trying to reverse lock an unlocked lock fails lock.unlock(); @@ -37,7 +63,7 @@ BOOST_AUTO_TEST_CASE(reverselock_errors) bool failed = false; try { - reverse_lock > rlock(lock); + REVERSE_LOCK(lock); } catch(...) { failed = true; } @@ -52,7 +78,7 @@ BOOST_AUTO_TEST_CASE(reverselock_errors) lock.lock(); BOOST_CHECK(lock.owns_lock()); { - reverse_lock > rlock(lock); + REVERSE_LOCK(lock); BOOST_CHECK(!lock.owns_lock()); } From c5c8e04352a369f0afd8e347cbb2cdb371c842fa Mon Sep 17 00:00:00 2001 From: furszy Date: Thu, 3 Dec 2020 14:06:57 -0300 Subject: [PATCH 18/22] validationInterface fix shared_ptr destructor warning. --- src/validationinterface.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/validationinterface.h b/src/validationinterface.h index d392de5b66bb..1bfd0b5b73d9 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -32,6 +32,12 @@ void UnregisterAllValidationInterfaces(); class CValidationInterface { public: + /** + * Protected destructor so that instances can only be deleted by derived classes. + * If that restriction is no longer desired, this should be made public and virtual. + */ + ~CValidationInterface() = default; + /** Notifies listeners of updated block chain tip */ virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {} virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) {} From 719cce9286954418ecb88614f3fc24f5a6a8fc74 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sun, 23 Jul 2017 14:51:22 -0400 Subject: [PATCH 19/22] Add missing lock in CScheduler::AreThreadsServicingQueue() Not an actual bug as this is only used in asserts right now, but nice to not have a missing lock. --- src/scheduler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scheduler.cpp b/src/scheduler.cpp index a59a003fd0ac..a709b0ffeaac 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -122,6 +122,7 @@ size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first, } bool CScheduler::AreThreadsServicingQueue() const { + boost::unique_lock lock(newTaskMutex); return nThreadsServicingQueue; } From f4bdbcfa7ad776794304490f1e6fd8c3e02cca47 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 20 Jan 2017 15:36:13 -0500 Subject: [PATCH 20/22] CScheduler boost->std::function, use millisecs for times, not secs --- src/net.cpp | 2 +- src/scheduler.cpp | 12 ++++++------ src/scheduler.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 9505f2d7476b..5e6992c9f8f4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2180,7 +2180,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c threadMessageHandler = std::thread(&TraceThread >, "msghand", std::function(std::bind(&CConnman::ThreadMessageHandler, this))); // Dump network addresses - scheduler.scheduleEvery(std::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL); + scheduler.scheduleEvery(std::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL * 1000); return true; } diff --git a/src/scheduler.cpp b/src/scheduler.cpp index a709b0ffeaac..0d1d281eb9e5 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -93,20 +93,20 @@ void CScheduler::schedule(CScheduler::Function f, boost::chrono::system_clock::t newTaskScheduled.notify_one(); } -void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaSeconds) +void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaMilliSeconds) { - schedule(f, boost::chrono::system_clock::now() + boost::chrono::seconds(deltaSeconds)); + schedule(f, boost::chrono::system_clock::now() + boost::chrono::milliseconds(deltaMilliSeconds)); } -static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaSeconds) +static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaMilliSeconds) { f(); - s->scheduleFromNow(std::bind(&Repeat, s, f, deltaSeconds), deltaSeconds); + s->scheduleFromNow(std::bind(&Repeat, s, f, deltaMilliSeconds), deltaMilliSeconds); } -void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaSeconds) +void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaMilliSeconds) { - scheduleFromNow(std::bind(&Repeat, this, f, deltaSeconds), deltaSeconds); + scheduleFromNow(std::bind(&Repeat, this, f, deltaMilliSeconds), deltaMilliSeconds); } size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first, diff --git a/src/scheduler.h b/src/scheduler.h index 33e51500c5b7..1642ec3cfea5 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -47,14 +47,14 @@ class CScheduler void schedule(Function f, boost::chrono::system_clock::time_point t=boost::chrono::system_clock::now()); // Convenience method: call f once deltaSeconds from now - void scheduleFromNow(Function f, int64_t deltaSeconds); + void scheduleFromNow(Function f, int64_t deltaMilliSeconds); // Another convenience method: call f approximately // every deltaSeconds forever, starting deltaSeconds from now. // To be more precise: every time f is finished, it // is rescheduled to run deltaSeconds later. If you // need more accurate scheduling, don't use this method. - void scheduleEvery(Function f, int64_t deltaSeconds); + void scheduleEvery(Function f, int64_t deltaMilliSeconds); // To keep things as simple as possible, there is no unschedule. From 69aaca5d4dedac8ab64c7c1d2ea05c97aaff6c08 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 4 Dec 2017 18:31:36 -0500 Subject: [PATCH 21/22] Add an interface to get the queue depth out of CValidationInterface --- src/scheduler.cpp | 5 +++++ src/scheduler.h | 2 ++ src/validationinterface.cpp | 5 +++++ src/validationinterface.h | 2 ++ 4 files changed, 14 insertions(+) diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 0d1d281eb9e5..6748bd13080b 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -187,3 +187,8 @@ void SingleThreadedSchedulerClient::EmptyQueue() { should_continue = !m_callbacks_pending.empty(); } } + +size_t SingleThreadedSchedulerClient::CallbacksPending() { + LOCK(m_cs_callbacks_pending); + return m_callbacks_pending.size(); +} diff --git a/src/scheduler.h b/src/scheduler.h index 1642ec3cfea5..0801dd8dd6f2 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -109,6 +109,8 @@ class SingleThreadedSchedulerClient { // Processes all remaining queue members on the calling thread, blocking until queue is empty // Must be called after the CScheduler has no remaining processing threads! void EmptyQueue(); + + size_t CallbacksPending(); }; #endif diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 1aa009aa22da..4af42937476d 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -103,6 +103,11 @@ void CMainSignals::FlushBackgroundCallbacks() { } } +size_t CMainSignals::CallbacksPending() { + if (!m_internals) return 0; + return m_internals->m_schedulerClient.CallbacksPending(); +} + CMainSignals& GetMainSignals() { return g_signals; diff --git a/src/validationinterface.h b/src/validationinterface.h index 1bfd0b5b73d9..b69bb17fbfc6 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -77,6 +77,8 @@ class CMainSignals { /** Call any remaining callbacks on the calling thread */ void FlushBackgroundCallbacks(); + size_t CallbacksPending(); + void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload); void SyncTransaction(const CTransaction &, const CBlockIndex *pindex, int posInBlock); void NotifyTransactionLock(const CTransaction&); From 2a999ee6b03e12cf5caee529f0432796a21adc87 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 8 Jun 2017 11:13:46 -0400 Subject: [PATCH 22/22] Add CallFunctionInQueue to wait on validation interface queue drain --- src/validationinterface.cpp | 4 ++++ src/validationinterface.h | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 4af42937476d..da8516ee3a03 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -126,6 +126,10 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) } } +void CallFunctionInValidationInterfaceQueue(std::function func) { + g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func)); +} + void UnregisterAllValidationInterfaces() { if (!g_signals.m_internals) { diff --git a/src/validationinterface.h b/src/validationinterface.h index b69bb17fbfc6..a210f8cd7f04 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -10,6 +10,9 @@ #include "optional.h" #include "sapling/incrementalmerkletree.hpp" +#include +#include + class CBlock; struct CBlockLocator; class CBlockIndex; @@ -29,6 +32,16 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn); void UnregisterValidationInterface(CValidationInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllValidationInterfaces(); +/** + * Pushes a function to callback onto the notification queue, guaranteeing any + * callbacks generated prior to now are finished when the function is called. + * + * Be very careful blocking on func to be called if any locks are held - + * validation interface clients may not be able to make progress as they often + * wait for things like cs_main, so blocking until func is called with cs_main + * will result in a deadlock (that DEBUG_LOCKORDER will miss). + */ +void CallFunctionInValidationInterfaceQueue(std::function func); class CValidationInterface { public: @@ -65,6 +78,7 @@ class CMainSignals { friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterAllValidationInterfaces(); + friend void ::CallFunctionInValidationInterfaceQueue(std::function func); public: /** A posInBlock value for SyncTransaction which indicates the transaction was conflicted, disconnected, or not in a block */