Skip to content

Commit b109fe6

Browse files
committed
Expire bitcoind & bitcoin-qt 1-2 years after its last change
COPYRIGHT_YEAR + 2 years is used as the basis for expiration, to achieve a constantly-moving-forward expiration date. The expiration can be disabled or extended with a debug-visibility "softwareexpiry" configuration option.
1 parent 2e41886 commit b109fe6

File tree

7 files changed

+39
-1
lines changed

7 files changed

+39
-1
lines changed

src/bitcoind.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ static bool ParseArgs(ArgsManager& args, int argc, char* argv[])
128128
return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.", argv[i])));
129129
}
130130
}
131+
132+
if (IsThisSoftwareExpired(GetTime())) {
133+
tfm::format(std::cerr, "This software is expired, and may be out of consensus. You must choose to upgrade or override this expiration.\n");
134+
exit(EXIT_FAILURE);
135+
}
136+
131137
return true;
132138
}
133139

src/clientversion.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
#include <util/string.h>
99
#include <util/translation.h>
1010

11+
#include <common/args.h>
1112
#include <tinyformat.h>
13+
#include <util/time.h>
1214

1315
#include <string>
1416
#include <vector>
@@ -99,3 +101,12 @@ std::string LicenseInfo()
99101
strprintf(_("Distributed under the MIT software license, see the accompanying file %s or %s").translated, "COPYING", "<https://opensource.org/licenses/MIT>") +
100102
"\n";
101103
}
104+
105+
bool IsThisSoftwareExpired(int64_t nTime)
106+
{
107+
int64_t nSoftwareExpiry = gArgs.GetIntArg("-softwareexpiry", DEFAULT_SOFTWARE_EXPIRY);
108+
if (nSoftwareExpiry <= 0) {
109+
nSoftwareExpiry = std::numeric_limits<int64_t>::max();
110+
}
111+
return (nTime > nSoftwareExpiry);
112+
}

src/clientversion.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#if !defined(WINDRES_PREPROC)
2727

28+
#include <cstdint>
2829
#include <string>
2930
#include <vector>
3031

@@ -44,6 +45,12 @@ std::string CopyrightHolders(const std::string& strPrefix);
4445
/** Returns licensing information (for -version) */
4546
std::string LicenseInfo();
4647

48+
static const int64_t SECONDS_PER_YEAR = 31558060;
49+
static const int POSIX_EPOCH_YEAR = 1970;
50+
static const int64_t DEFAULT_SOFTWARE_EXPIRY = ((COPYRIGHT_YEAR - POSIX_EPOCH_YEAR) * SECONDS_PER_YEAR) + (SECONDS_PER_YEAR * 2);
51+
52+
bool IsThisSoftwareExpired(int64_t nTime);
53+
4754
#endif // WINDRES_PREPROC
4855

4956
#endif // BITCOIN_CLIENTVERSION_H

src/init.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ void SetupServerArgs(ArgsManager& argsman)
511511
argsman.AddArg("-reindex", "If enabled, wipe chain state and block index, and rebuild them from blk*.dat files on disk. Also wipe and rebuild other optional indexes that are active. If an assumeutxo snapshot was loaded, its chainstate will be wiped as well. The snapshot can then be reloaded via RPC.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
512512
argsman.AddArg("-reindex-chainstate", "If enabled, wipe chain state, and rebuild it from blk*.dat files on disk. If an assumeutxo snapshot was loaded, its chainstate will be wiped as well. The snapshot can then be reloaded via RPC.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
513513
argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
514+
argsman.AddArg("-softwareexpiry", strprintf("Stop working after this POSIX timestamp (default: %s)", DEFAULT_SOFTWARE_EXPIRY), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
514515
#if HAVE_SYSTEM
515516
argsman.AddArg("-startupnotify=<cmd>", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
516517
argsman.AddArg("-shutdownnotify=<cmd>", "Execute command immediately before beginning shutdown. The need for shutdown may be urgent, so be careful not to delay it long (if the command doesn't require interaction with the server, consider having it fork into the background).", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);

src/qt/bitcoin.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <qt/bitcoin.h>
88

99
#include <chainparams.h>
10+
#include <clientversion.h>
1011
#include <common/args.h>
1112
#include <common/init.h>
1213
#include <common/system.h>
@@ -644,6 +645,11 @@ int GuiMain(int argc, char* argv[])
644645
// Re-initialize translations after changing application name (language in network-specific settings can be different)
645646
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
646647

648+
if (IsThisSoftwareExpired(GetTime())) {
649+
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."));
650+
return EXIT_FAILURE;
651+
}
652+
647653
#ifdef ENABLE_WALLET
648654
/// 8. URI IPC sending
649655
// - Do this early as we don't want to bother initializing if we are just calling IPC

src/validation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3911,6 +3911,10 @@ static bool CheckBlockHeader(const CBlockHeader& block, BlockValidationState& st
39113911
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
39123912
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "high-hash", "proof of work failed");
39133913

3914+
if (IsThisSoftwareExpired(block.nTime)) {
3915+
return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "node-expired", "node software has expired");
3916+
}
3917+
39143918
return true;
39153919
}
39163920

test/functional/test_framework/test_node.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,10 @@ def __init__(self, i, datadir_path, *, chain, rpchost, timewait, timeout_factor,
130130
"--error-exitcode=1", "--quiet"] + self.args
131131

132132
if self.version is None:
133-
self.args.append("-walletimplicitsegwit")
133+
self.args += [
134+
"-softwareexpiry=0",
135+
"-walletimplicitsegwit",
136+
]
134137

135138
if self.version_is_at_least(190000):
136139
self.args.append("-logthreadnames")

0 commit comments

Comments
 (0)