aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSjors Provoost <sjors@sprovoost.nl>2024-08-20 10:45:04 +0200
committerSjors Provoost <sjors@sprovoost.nl>2024-08-20 18:51:37 +0200
commit59ff17e5af4e382cbe16f183767beef1bdcd9131 (patch)
treeb0680f22dfb41f8fba0139b23ef7e55e8e368924
parente929054e12210353812f440c685a23329e7040f7 (diff)
miner: adjust clock to timewarp rule
-rw-r--r--src/consensus/consensus.h7
-rw-r--r--src/node/miner.cpp8
-rw-r--r--src/validation.cpp7
-rwxr-xr-xtest/functional/mining_basic.py17
4 files changed, 24 insertions, 15 deletions
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index 384f70bc10..cffe9cdafd 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -27,4 +27,11 @@ static const size_t MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR *
/** Interpret sequence numbers as relative lock-time constraints. */
static constexpr unsigned int LOCKTIME_VERIFY_SEQUENCE = (1 << 0);
+/**
+ * Maximum number of seconds that the timestamp of the first
+ * block of a difficulty adjustment period is allowed to
+ * be earlier than the last block of the previous period (BIP94).
+ */
+static constexpr int64_t MAX_TIMEWARP = 600;
+
#endif // BITCOIN_CONSENSUS_CONSENSUS_H
diff --git a/src/node/miner.cpp b/src/node/miner.cpp
index fa2d979b86..5c476e154f 100644
--- a/src/node/miner.cpp
+++ b/src/node/miner.cpp
@@ -33,6 +33,14 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
int64_t nOldTime = pblock->nTime;
int64_t nNewTime{std::max<int64_t>(pindexPrev->GetMedianTimePast() + 1, TicksSinceEpoch<std::chrono::seconds>(NodeClock::now()))};
+ if (consensusParams.enforce_BIP94) {
+ // Height of block to be mined.
+ const int height{pindexPrev->nHeight + 1};
+ if (height % consensusParams.DifficultyAdjustmentInterval() == 0) {
+ nNewTime = std::max<int64_t>(nNewTime, pindexPrev->GetBlockTime() - MAX_TIMEWARP);
+ }
+ }
+
if (nOldTime < nNewTime) {
pblock->nTime = nNewTime;
}
diff --git a/src/validation.cpp b/src/validation.cpp
index 8c80e35c01..8f75b2e30a 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -107,13 +107,6 @@ const std::vector<std::string> CHECKLEVEL_DOC {
* */
static constexpr int PRUNE_LOCK_BUFFER{10};
-/**
- * Maximum number of seconds that the timestamp of the first
- * block of a difficulty adjustment period is allowed to
- * be earlier than the last block of the previous period (BIP94).
- */
-static constexpr int64_t MAX_TIMEWARP = 600;
-
GlobalMutex g_best_block_mutex;
std::condition_variable g_best_block_cv;
uint256 g_best_block;
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
index b183023b2f..c0df120c65 100755
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -28,6 +28,7 @@ from test_framework.p2p import P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
+ assert_greater_than_or_equal,
assert_raises_rpc_error,
get_fee,
)
@@ -139,24 +140,24 @@ class MiningTest(BitcoinTestFramework):
self.log.info("First block template of retarget period can't use wall clock time")
self.nodes[0].setmocktime(t)
- assert_raises_rpc_error(-1, "time-timewarp-attack, block's timestamp is too early on diff adjustment block",
- lambda: node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
-
- # Create template with an acceptable timestamp and then modify it
- self.nodes[0].setmocktime(t + MAX_FUTURE_BLOCK_TIME)
+ # The template will have an adjusted timestamp, which we then modify
tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
+ assert_greater_than_or_equal(tmpl['curtime'], t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP)
block = CBlock()
block.nVersion = tmpl["version"]
block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
- block.nTime = t
+ block.nTime = tmpl["curtime"]
block.nBits = int(tmpl["bits"], 16)
block.nNonce = 0
block.vtx = [create_coinbase(height=int(tmpl["height"]))]
block.solve()
+ assert_template(node, block, None)
- self.nodes[0].setmocktime(t)
- assert_raises_rpc_error(-25, 'time-timewarp-attack', lambda: node.submitheader(hexdata=CBlockHeader(block).serialize().hex()))
+ bad_block = copy.deepcopy(block)
+ bad_block.nTime = t
+ bad_block.solve()
+ assert_raises_rpc_error(-25, 'time-timewarp-attack', lambda: node.submitheader(hexdata=CBlockHeader(bad_block).serialize().hex()))
def run_test(self):
node = self.nodes[0]