diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py index 9f970ee5c8..d965b87f62 100755 --- a/contrib/linearize/linearize-data.py +++ b/contrib/linearize/linearize-data.py @@ -242,8 +242,11 @@ class BlockDataCopier: inMagic = inhdr[:4] if (inMagic != self.settings['netmagic']): - print("Invalid magic: " + inMagic.hex()) - return + # Seek backwards 7 bytes (skipping the first byte in the previous search) + # and continue searching from the new position if the magic bytes are not + # found. + self.inF.seek(-7, os.SEEK_CUR) + continue inLenLE = inhdr[4:] su = struct.unpack(" -static inline void LogPrint(const BCLog::LogFlags& category, const Args&... args) -{ - if (LogAcceptCategory((category))) { - LogPrintf(args...); - } -} +// Use a macro instead of a function for conditional logging to prevent +// evaluating arguments when logging for the category is not enabled. +#define LogPrint(category, ...) \ + do { \ + if (LogAcceptCategory((category))) { \ + LogPrintf(__VA_ARGS__); \ + } \ + } while (0) #endif // BITCOIN_LOGGING_H diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 0595fac6f4..aa4b4bbf30 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -540,24 +540,16 @@ void BitcoinGUI::createMenuBar() connect(qApp, &QApplication::focusWindowChanged, [zoom_action] (QWindow* window) { zoom_action->setEnabled(window != nullptr); }); -#else - QAction* restore_action = window_menu->addAction(tr("Restore")); - connect(restore_action, &QAction::triggered, [] { - qApp->focusWindow()->showNormal(); - }); - - connect(qApp, &QApplication::focusWindowChanged, [restore_action] (QWindow* window) { - restore_action->setEnabled(window != nullptr); - }); #endif if (walletFrame) { +#ifdef Q_OS_MAC window_menu->addSeparator(); QAction* main_window_action = window_menu->addAction(tr("Main Window")); connect(main_window_action, &QAction::triggered, [this] { GUIUtil::bringToFront(this); }); - +#endif window_menu->addSeparator(); window_menu->addAction(usedSendingAddressesAction); window_menu->addAction(usedReceivingAddressesAction); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index a0716efa7c..603339ace4 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -42,8 +42,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -453,9 +453,9 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) certList = QSslCertificate::fromPath(certFile); // Use those certificates when fetching payment requests, too: - QSslSocket::setDefaultCaCertificates(certList); + QSslConfiguration::defaultConfiguration().setCaCertificates(certList); } else - certList = QSslSocket::systemCaCertificates(); + certList = QSslConfiguration::systemCaCertificates(); int nRootCerts = 0; const QDateTime currentTime = QDateTime::currentDateTime(); diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index daf1fcd01e..f48d7881e8 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -71,11 +71,6 @@ void WalletFrame::addWallet(WalletModel *walletModel) walletStack->addWidget(walletView); mapWalletViews[walletModel] = walletView; - // Ensure a walletView is able to show the main window - connect(walletView, &WalletView::showNormalIfMinimized, [this]{ - gui->showNormalIfMinimized(); - }); - connect(walletView, &WalletView::outOfSyncWarningClicked, this, &WalletFrame::outOfSyncWarningClicked); } diff --git a/src/qt/walletview.h b/src/qt/walletview.h index a6ba03d744..30f138d907 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -127,8 +127,6 @@ public Q_SLOTS: /** Update selected DASH amount from transactionview */ void trxAmount(QString amount); Q_SIGNALS: - /** Signal that we want to show the main window */ - void showNormalIfMinimized(); /** Fired when a message should be reported to the user */ void message(const QString &title, const QString &message, unsigned int style); /** Encryption status of wallet changed */ diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp index 6c08613b1d..b6f9cec05b 100644 --- a/src/qt/winshutdownmonitor.cpp +++ b/src/qt/winshutdownmonitor.cpp @@ -6,14 +6,11 @@ #if defined(Q_OS_WIN) #include -#include #include #include -#include - // If we don't want a message to be processed by Qt, return true and set result to // the value that the window procedure should return. Otherwise return false. bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void *pMessage, long *pnResult) @@ -22,16 +19,6 @@ bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void *pM MSG *pMsg = static_cast(pMessage); - // Seed OpenSSL PRNG with Windows event data (e.g. mouse movements and other user interactions) - if (RAND_event(pMsg->message, pMsg->wParam, pMsg->lParam) == 0) { - // Warn only once as this is performance-critical - static bool warned = false; - if (!warned) { - LogPrintf("%s: OpenSSL RAND_event() failed to seed OpenSSL PRNG with enough data.\n", __func__); - warned = true; - } - } - switch(pMsg->message) { case WM_QUERYENDSESSION: diff --git a/src/random.cpp b/src/random.cpp index 36df10e888..9007eac2c8 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -146,6 +146,34 @@ static bool GetHardwareRand(unsigned char* ent32) noexcept { return false; } +/** Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */ +static void Strengthen(const unsigned char (&seed)[32], int microseconds, CSHA512& hasher) noexcept +{ + CSHA512 inner_hasher; + inner_hasher.Write(seed, sizeof(seed)); + + // Hash loop + unsigned char buffer[64]; + int64_t stop = GetTimeMicros() + microseconds; + do { + for (int i = 0; i < 1000; ++i) { + inner_hasher.Finalize(buffer); + inner_hasher.Reset(); + inner_hasher.Write(buffer, sizeof(buffer)); + } + // Benchmark operation and feed it into outer hasher. + int64_t perf = GetPerformanceCounter(); + hasher.Write((const unsigned char*)&perf, sizeof(perf)); + } while (GetTimeMicros() < stop); + + // Produce output from inner state and feed it to outer hasher. + inner_hasher.Finalize(buffer); + hasher.Write(buffer, sizeof(buffer)); + // Try to clean up. + inner_hasher.Reset(); + memory_cleanse(buffer, sizeof(buffer)); +} + static void RandAddSeedPerfmon(CSHA512& hasher) { #ifdef WIN32 @@ -432,7 +460,23 @@ static void SeedSlow(CSHA512& hasher) noexcept SeedTimestamp(hasher); } -static void SeedSleep(CSHA512& hasher) +/** Extract entropy from rng, strengthen it, and feed it into hasher. */ +static void SeedStrengthen(CSHA512& hasher, RNGState& rng) noexcept +{ + static std::atomic last_strengthen{0}; + int64_t last_time = last_strengthen.load(); + int64_t current_time = GetTimeMicros(); + if (current_time > last_time + 60000000) { // Only run once a minute + // Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher. + unsigned char strengthen_seed[32]; + rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false); + // Strengthen it for 10ms (100ms on first run), and feed it into hasher. + Strengthen(strengthen_seed, last_time == 0 ? 100000 : 10000, hasher); + last_strengthen = current_time; + } +} + +static void SeedSleep(CSHA512& hasher, RNGState& rng) { // Everything that the 'fast' seeder includes SeedFast(hasher); @@ -448,9 +492,12 @@ static void SeedSleep(CSHA512& hasher) // Windows performance monitor data (once every 10 minutes) RandAddSeedPerfmon(hasher); + + // Strengthen every minute + SeedStrengthen(hasher, rng); } -static void SeedStartup(CSHA512& hasher) noexcept +static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept { #ifdef WIN32 RAND_screen(); @@ -461,6 +508,9 @@ static void SeedStartup(CSHA512& hasher) noexcept // Windows performance monitor data. RandAddSeedPerfmon(hasher); + + // Strengthen + SeedStrengthen(hasher, rng); } enum class RNGLevel { @@ -485,7 +535,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level) SeedSlow(hasher); break; case RNGLevel::SLEEP: - SeedSleep(hasher); + SeedSleep(hasher, rng); break; } @@ -493,7 +543,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level) if (!rng.MixExtract(out, num, std::move(hasher), false)) { // On the first invocation, also seed with SeedStartup(). CSHA512 startup_hasher; - SeedStartup(startup_hasher); + SeedStartup(startup_hasher, rng); rng.MixExtract(out, num, std::move(startup_hasher), true); } diff --git a/src/random.h b/src/random.h index 2510df8693..316aedc597 100644 --- a/src/random.h +++ b/src/random.h @@ -44,6 +44,7 @@ * - RandAddSeedSleep() seeds everything that fast seeding includes, but additionally: * - A high-precision timestamp before and after sleeping 1ms. * - (On Windows) Once every 10 minutes, performance monitoring data from the OS. + - - Once every minute, strengthen the entropy for 10 ms using repeated SHA512. * These just exploit the fact the system is idle to improve the quality of the RNG * slightly. * @@ -51,6 +52,7 @@ * sources used in the 'slow' seeder are included, but also: * - (On Windows) Performance monitoring data from the OS. * - (On Windows) Through OpenSSL, the screen contents. + * - Strengthen the entropy for 100 ms using repeated SHA512. * * When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and * (up to) the first 32 bytes of H are produced as output, while the last 32 bytes diff --git a/src/script/sign.cpp b/src/script/sign.cpp index db258a63e8..79f533939d 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -198,6 +198,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato return sigdata.complete; } +namespace { class SignatureExtractorChecker final : public BaseSignatureChecker { private: @@ -206,21 +207,17 @@ private: public: SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override + { + if (checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion)) { + CPubKey pubkey(vchPubKey); + sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig)); + return true; + } + return false; + } }; -bool SignatureExtractorChecker::CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const -{ - if (checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion)) { - CPubKey pubkey(vchPubKey); - sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig)); - return true; - } - return false; -} - -namespace -{ struct Stacks { std::vector script; diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 688a736dfb..e0013a6dba 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -746,6 +746,43 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) pool.GetTransactionAncestry(ty6->GetHash(), ancestors, descendants); BOOST_CHECK_EQUAL(ancestors, 9ULL); BOOST_CHECK_EQUAL(descendants, 6ULL); + + /* Ancestors represented more than once ("diamond") */ + // + // [ta].0 <- [tb].0 -----<------- [td].0 + // | | + // \---1 <- [tc].0 --<--/ + // + CTransactionRef ta, tb, tc, td; + ta = make_tx(/* output_values */ {10 * COIN}); + tb = make_tx(/* output_values */ {5 * COIN, 3 * COIN}, /* inputs */ {ta}); + tc = make_tx(/* output_values */ {2 * COIN}, /* inputs */ {tb}, /* input_indices */ {1}); + td = make_tx(/* output_values */ {6 * COIN}, /* inputs */ {tb, tc}, /* input_indices */ {0, 0}); + pool.clear(); + pool.addUnchecked(entry.Fee(10000LL).FromTx(ta)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tb)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tc)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(td)); + + // Ancestors / descendants should be: + // transaction ancestors descendants + // ============ =================== =========== + // ta 1 (ta 4 (ta,tb,tc,td) + // tb 2 (ta,tb) 4 (ta,tb,tc,td) + // tc 3 (ta,tb,tc) 4 (ta,tb,tc,td) + // td 4 (ta,tb,tc,td) 4 (ta,tb,tc,td) + pool.GetTransactionAncestry(ta->GetHash(), ancestors, descendants); + BOOST_CHECK_EQUAL(ancestors, 1ULL); + BOOST_CHECK_EQUAL(descendants, 4ULL); + pool.GetTransactionAncestry(tb->GetHash(), ancestors, descendants); + BOOST_CHECK_EQUAL(ancestors, 2ULL); + BOOST_CHECK_EQUAL(descendants, 4ULL); + pool.GetTransactionAncestry(tc->GetHash(), ancestors, descendants); + BOOST_CHECK_EQUAL(ancestors, 3ULL); + BOOST_CHECK_EQUAL(descendants, 4ULL); + pool.GetTransactionAncestry(td->GetHash(), ancestors, descendants); + BOOST_CHECK_EQUAL(ancestors, 4ULL); + BOOST_CHECK_EQUAL(descendants, 4ULL); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/util/fees.cpp b/src/util/fees.cpp index 5fdaa1284c..4379b559c7 100644 --- a/src/util/fees.cpp +++ b/src/util/fees.cpp @@ -3,8 +3,11 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include + #include +#include #include std::string StringForFeeReason(FeeReason reason) { diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index b04e5bee2a..47fe3ad75b 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -243,7 +243,7 @@ BerkeleyEnvironment::BerkeleyEnvironment() { Reset(); - LogPrint(BCLog::DB, "BerkeleyEnvironment::MakeMock\n"); + LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::MakeMock\n"); dbenv->set_cachesize(1, 0, 1); dbenv->set_lg_bsize(10485760 * 4); @@ -725,7 +725,7 @@ void BerkeleyEnvironment::Flush(bool fShutdown) { int64_t nStart = GetTimeMillis(); // Flush log data to the actual data file on all files that are not in use - LogPrint(BCLog::DB, "BerkeleyEnvironment::Flush: [%s] Flush(%s)%s\n", strPath, fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started"); + LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: [%s] Flush(%s)%s\n", strPath, fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started"); if (!fDbEnvInit) return; { @@ -734,21 +734,21 @@ void BerkeleyEnvironment::Flush(bool fShutdown) while (mi != mapFileUseCount.end()) { std::string strFile = (*mi).first; int nRefCount = (*mi).second; - LogPrint(BCLog::DB, "BerkeleyEnvironment::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount); + LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount); if (nRefCount == 0) { // Move log data to the dat file CloseDb(strFile); - LogPrint(BCLog::DB, "BerkeleyEnvironment::Flush: %s checkpoint\n", strFile); + LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s checkpoint\n", strFile); dbenv->txn_checkpoint(0, 0, 0); - LogPrint(BCLog::DB, "BerkeleyEnvironment::Flush: %s detach\n", strFile); + LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s detach\n", strFile); if (!fMockDb) dbenv->lsn_reset(strFile.c_str(), 0); - LogPrint(BCLog::DB, "BerkeleyEnvironment::Flush: %s closed\n", strFile); + LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s closed\n", strFile); mapFileUseCount.erase(mi++); } else mi++; } - LogPrint(BCLog::DB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart); + LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart); if (fShutdown) { char** listp; if (mapFileUseCount.empty()) { @@ -787,7 +787,7 @@ bool BerkeleyBatch::PeriodicFlush(BerkeleyDatabase& database) std::map::iterator mi = env->mapFileUseCount.find(strFile); if (mi != env->mapFileUseCount.end()) { - LogPrint(BCLog::DB, "Flushing %s\n", strFile); + LogPrint(BCLog::WALLETDB, "Flushing %s\n", strFile); int64_t nStart = GetTimeMillis(); // Flush wallet file so it's self contained @@ -795,7 +795,7 @@ bool BerkeleyBatch::PeriodicFlush(BerkeleyDatabase& database) env->CheckpointLSN(strFile); env->mapFileUseCount.erase(mi++); - LogPrint(BCLog::DB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); + LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); ret = true; } } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 19ad2f2370..ff36270470 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -100,13 +100,14 @@ std::shared_ptr GetWallet(const std::string& name) static Mutex g_wallet_release_mutex; static std::condition_variable g_wallet_release_cv; -static std::set g_unloading_wallet_set; +static std::set g_unloading_wallet_set; // Custom deleter for shared_ptr. static void ReleaseWallet(CWallet* wallet) { // Unregister and delete the wallet right after BlockUntilSyncedToCurrentChain // so that it's in sync with the current chainstate. + const std::string name = wallet->GetName(); wallet->WalletLogPrintf("Releasing wallet\n"); wallet->BlockUntilSyncedToCurrentChain(); wallet->Flush(); @@ -115,7 +116,7 @@ static void ReleaseWallet(CWallet* wallet) // Wallet is now released, notify UnloadWallet, if any. { LOCK(g_wallet_release_mutex); - if (g_unloading_wallet_set.erase(wallet) == 0) { + if (g_unloading_wallet_set.erase(name) == 0) { // UnloadWallet was not called for this wallet, all done. return; } @@ -126,21 +127,21 @@ static void ReleaseWallet(CWallet* wallet) void UnloadWallet(std::shared_ptr&& wallet) { // Mark wallet for unloading. - CWallet* pwallet = wallet.get(); + const std::string name = wallet->GetName(); { LOCK(g_wallet_release_mutex); - auto it = g_unloading_wallet_set.insert(pwallet); + auto it = g_unloading_wallet_set.insert(name); assert(it.second); } // The wallet can be in use so it's not possible to explicitly unload here. // Notify the unload intent so that all remaining shared pointers are // released. - pwallet->NotifyUnload(); + wallet->NotifyUnload(); // Time to ditch our shared_ptr and wait for ReleaseWallet call. wallet.reset(); { WAIT_LOCK(g_wallet_release_mutex, lock); - while (g_unloading_wallet_set.count(pwallet) == 1) { + while (g_unloading_wallet_set.count(name) == 1) { g_wallet_release_cv.wait(lock); } } diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 52d8f57f97..8b7ff2ae27 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -791,7 +791,7 @@ DBErrors WalletBatch::ZapSelectTx(std::vector& vTxHashIn, std::vector /dev/null; then - echo "Skipping Python linting since flake8 is not installed. Install by running \"pip3 install flake8\"" + echo "Skipping Python linting since flake8 is not installed." exit 0 elif PYTHONWARNINGS="ignore" flake8 --version | grep -q "Python 2"; then - echo "Skipping Python linting since flake8 is running under Python 2. Install the Python 3 version of flake8 by running \"pip3 install flake8\"" + echo "Skipping Python linting since flake8 is running under Python 2. Install the Python 3 version of flake8." exit 0 fi