Skip to content

Commit

Permalink
miner: adjust clock to timewarp rule
Browse files Browse the repository at this point in the history
  • Loading branch information
Sjors committed Aug 20, 2024
1 parent e929054 commit 59ff17e
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 15 deletions.
7 changes: 7 additions & 0 deletions src/consensus/consensus.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 8 additions & 0 deletions src/node/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
7 changes: 0 additions & 7 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
17 changes: 9 additions & 8 deletions test/functional/mining_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
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,
)
Expand Down Expand Up @@ -139,24 +140,24 @@ def test_timewarp(self):

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]
Expand Down

0 comments on commit 59ff17e

Please sign in to comment.