From 04339a805d0bd007e562ea471e8286c4df367a8a Mon Sep 17 00:00:00 2001 From: Pithosian Date: Thu, 15 May 2025 00:00:00 +0000 Subject: [PATCH 1/3] Improve softwareexpiry error in bitcoind, and add override prompt in qt --- src/bitcoind.cpp | 2 +- src/qt/bitcoin.cpp | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index b8e67dccbc69f..7cae8580f27b1 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -131,7 +131,7 @@ static bool ParseArgs(ArgsManager& args, int argc, char* argv[]) g_software_expiry = args.GetIntArg("-softwareexpiry", DEFAULT_SOFTWARE_EXPIRY); if (IsThisSoftwareExpired(GetTime())) { - tfm::format(std::cerr, "This software is expired, and may be out of consensus. You must choose to upgrade or override this expiration.\n"); + tfm::format(std::cerr, "This software is expired, and may be out of consensus. You must choose to upgrade, or override this expiration with the 'softwareexpiry' option (Unix datetime, or 0 for no expiry).\n"); exit(EXIT_FAILURE); } diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index f835ef62b3a94..615e31aabc9a9 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -53,6 +53,7 @@ #include #include +#include #include #include #include @@ -655,8 +656,20 @@ int GuiMain(int argc, char* argv[]) g_software_expiry = gArgs.GetIntArg("-softwareexpiry", DEFAULT_SOFTWARE_EXPIRY); if (IsThisSoftwareExpired(GetTime())) { - QMessageBox::critical(nullptr, QObject::tr("Software expired"), QObject::tr("This software is expired, and may be out of consensus. You must choose to upgrade or override this expiration.")); - return EXIT_FAILURE; + bool override_expiry_ok; + QString override_expiry = QInputDialog::getText( + nullptr, + QObject::tr("Software Expired"), + QObject::tr("This software is expired, and may be out of consensus.\nYou must choose to upgrade, or override this expiration by typing:\nI accept this software may be unsafe."), + QLineEdit::Normal, + "", + &override_expiry_ok); + if (!override_expiry_ok || override_expiry != QObject::tr("I accept this software may be unsafe.")) { + return EXIT_FAILURE; + } + + gArgs.ModifyRWConfigFile("softwareexpiry", "0"); + g_software_expiry = 0; } #ifdef ENABLE_WALLET From 3a3f1e6faff39448a8ea6e9cf92bbfb2465b591c Mon Sep 17 00:00:00 2001 From: Pithosian Date: Thu, 15 May 2025 00:00:00 +0000 Subject: [PATCH 2/3] Add expiry warnings to bitcoind and bitcoin-qt startup --- src/bitcoind.cpp | 4 +++- src/clientversion.cpp | 9 +++++++++ src/clientversion.h | 5 +++++ src/qt/bitcoin.cpp | 4 +++- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 7cae8580f27b1..6462e0e1deeaa 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -130,7 +130,9 @@ static bool ParseArgs(ArgsManager& args, int argc, char* argv[]) } g_software_expiry = args.GetIntArg("-softwareexpiry", DEFAULT_SOFTWARE_EXPIRY); - if (IsThisSoftwareExpired(GetTime())) { + if (IsThisSoftwareExpiringSoon(GetTime())) { + tfm::format(std::cerr, "Warning: This software expires soon, and may fall out of consensus. You must choose to upgrade, or override this expiration with the 'softwareexpiry' option (Unix datetime, or 0 for no expiry).\n"); + } else if (IsThisSoftwareExpired(GetTime())) { tfm::format(std::cerr, "This software is expired, and may be out of consensus. You must choose to upgrade, or override this expiration with the 'softwareexpiry' option (Unix datetime, or 0 for no expiry).\n"); exit(EXIT_FAILURE); } diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 6bf7ef640661d..e6f87faad391c 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -113,3 +113,12 @@ bool IsThisSoftwareExpired(int64_t nTime) } return (nTime > g_software_expiry); } + +bool IsThisSoftwareExpiringSoon(int64_t ntime) +{ + if (g_software_expiry <= 0) { + return false; + } + + return (ntime <= g_software_expiry && ntime > g_software_expiry - SOFTWARE_EXPIRY_WARN_PERIOD); +} diff --git a/src/clientversion.h b/src/clientversion.h index 0d3fd033a37f9..c154ff29a6ae1 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -49,9 +49,14 @@ static constexpr int64_t SECONDS_PER_YEAR = 31558060; static constexpr int POSIX_EPOCH_YEAR = 1970; static constexpr int64_t DEFAULT_SOFTWARE_EXPIRY_OFFSET = 26784000; // Around Nov 7 static constexpr int64_t DEFAULT_SOFTWARE_EXPIRY = ((COPYRIGHT_YEAR - POSIX_EPOCH_YEAR) * SECONDS_PER_YEAR) + (SECONDS_PER_YEAR * 2) + DEFAULT_SOFTWARE_EXPIRY_OFFSET; + +static constexpr int64_t SECONDS_PER_WEEK = 604800; +static constexpr int64_t SOFTWARE_EXPIRY_WARN_PERIOD = SECONDS_PER_WEEK * 4; + extern int64_t g_software_expiry; bool IsThisSoftwareExpired(int64_t nTime); +bool IsThisSoftwareExpiringSoon(int64_t nTime); #endif // WINDRES_PREPROC diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 615e31aabc9a9..ab772bd481152 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -655,7 +655,9 @@ int GuiMain(int argc, char* argv[]) initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); g_software_expiry = gArgs.GetIntArg("-softwareexpiry", DEFAULT_SOFTWARE_EXPIRY); - if (IsThisSoftwareExpired(GetTime())) { + if (IsThisSoftwareExpiringSoon(GetTime())) { + QMessageBox::warning(nullptr, QObject::tr("Software expires soon"), QObject::tr("This software expires soon, and may fall out of consensus. You must choose to upgrade, or override this expiration with the 'softwareexpiry' option (Unix datetime, or 0 for no expiry).")); + } else if (IsThisSoftwareExpired(GetTime())) { bool override_expiry_ok; QString override_expiry = QInputDialog::getText( nullptr, From 226de11ea2b3c7bcaf96033ae44d9325d528d943 Mon Sep 17 00:00:00 2001 From: Pithosian Date: Thu, 15 May 2025 00:00:00 +0000 Subject: [PATCH 3/3] Add fatal error for expired software at runtime --- src/validation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 388ba9de56af9..b90f66339b52a 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4458,12 +4458,13 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio if (IsThisSoftwareExpired(block.nTime)) { // Wait an extra day before we start rejecting blocks CBlockIndex const *blockindex_old = pindexPrev; - for (int i = 0; i < 144; ++i) { + for (int i = 0; i < std::min(144, pindexPrev->nHeight); ++i) { assert(blockindex_old); blockindex_old = blockindex_old->pprev; } assert(blockindex_old); if (IsThisSoftwareExpired(blockindex_old->GetMedianTimePast())) { + chainman.GetNotifications().fatalError(_("This software is expired, and may be out of consensus. You must choose to upgrade, or override this expiration with the 'softwareexpiry' option (Unix datetime, or 0 for no expiry).")); return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "node-expired", "node software has expired"); } }