Skip to content

Commit 992f37f

Browse files
committed
Merge bitcoin/bitcoin#31600: rpc: have getblocktemplate mintime account for timewarp
e1676b0 doc: release notes (Sjors Provoost) 0082f6a rpc: have mintime account for timewarp rule (Sjors Provoost) 79d45b1 rpc: clarify BIP94 behavior for curtime (Sjors Provoost) 0713548 refactor: add GetMinimumTime() helper (Sjors Provoost) Pull request description: #30681 fixed the `curtime` field of `getblocktemplate` to take the timewarp rule into account. However I forgot to do the same for the `mintime` field, which was hardcoded to use `pindexPrev->GetMedianTimePast()+1`. This PR adds a helper `GetMinimumTime()` and uses it for the `mintime` field. #31376 changed the `curtime` field to always account for the timewarp rule. This PR maintains that behavior. Note that `mintime` now always applies BIP94, including on mainnet. This makes future softfork activation safer. It could be backported to v28. ACKs for top commit: fjahr: tACK e1676b0 achow101: ACK e1676b0 darosior: utACK e1676b0 on the code changes tdb3: brief code review re ACK e1676b0 TheCharlatan: ACK e1676b0 Tree-SHA512: 0e322d8cc3b8ff770849bce211edcb5b6f55d04e5e0dee0657805049663d758f27423b047ee6363bd8f6c6fead13f974760f48b3321ea86f514f446e1b23231c
2 parents 8fa10ed + e1676b0 commit 992f37f

File tree

5 files changed

+39
-9
lines changed

5 files changed

+39
-9
lines changed

doc/release-notes-31600.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Updated RPCs
2+
---
3+
- the `getblocktemplate` RPC `curtime` (BIP22) and `mintime` (BIP23) fields now
4+
account for the timewarp fix proposed in BIP94 on all networks. This ensures
5+
that, in the event a timewarp fix softfork activates on mainnet, un-upgraded
6+
miners will not accidentally violate the timewarp rule. (#31376, #31600)
7+
8+
As a reminder, it's important that any software which uses the `getblocktemplate`
9+
RPC takes these values into account (either `curtime` or `mintime` is fine).
10+
Relying only on a clock can lead to invalid blocks under some circumstances,
11+
especially once a timewarp fix is deployed.

src/node/miner.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,25 @@
2828
#include <utility>
2929

3030
namespace node {
31-
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
32-
{
33-
int64_t nOldTime = pblock->nTime;
34-
int64_t nNewTime{std::max<int64_t>(pindexPrev->GetMedianTimePast() + 1, TicksSinceEpoch<std::chrono::seconds>(NodeClock::now()))};
3531

32+
int64_t GetMinimumTime(const CBlockIndex* pindexPrev, const int64_t difficulty_adjustment_interval)
33+
{
34+
int64_t min_time{pindexPrev->GetMedianTimePast() + 1};
3635
// Height of block to be mined.
3736
const int height{pindexPrev->nHeight + 1};
38-
if (height % consensusParams.DifficultyAdjustmentInterval() == 0) {
39-
nNewTime = std::max<int64_t>(nNewTime, pindexPrev->GetBlockTime() - MAX_TIMEWARP);
37+
// Account for BIP94 timewarp rule on all networks. This makes future
38+
// activation safer.
39+
if (height % difficulty_adjustment_interval == 0) {
40+
min_time = std::max<int64_t>(min_time, pindexPrev->GetBlockTime() - MAX_TIMEWARP);
4041
}
42+
return min_time;
43+
}
44+
45+
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
46+
{
47+
int64_t nOldTime = pblock->nTime;
48+
int64_t nNewTime{std::max<int64_t>(GetMinimumTime(pindexPrev, consensusParams.DifficultyAdjustmentInterval()),
49+
TicksSinceEpoch<std::chrono::seconds>(NodeClock::now()))};
4150

4251
if (nOldTime < nNewTime) {
4352
pblock->nTime = nNewTime;

src/node/miner.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,13 @@ class BlockAssembler
211211
void SortForBlock(const CTxMemPool::setEntries& package, std::vector<CTxMemPool::txiter>& sortedEntries);
212212
};
213213

214+
/**
215+
* Get the minimum time a miner should use in the next block. This always
216+
* accounts for the BIP94 timewarp rule, so does not necessarily reflect the
217+
* consensus limit.
218+
*/
219+
int64_t GetMinimumTime(const CBlockIndex* pindexPrev, const int64_t difficulty_adjustment_interval);
220+
214221
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
215222

216223
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */

src/rpc/mining.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
using interfaces::BlockTemplate;
5050
using interfaces::Mining;
5151
using node::BlockAssembler;
52+
using node::GetMinimumTime;
5253
using node::NodeContext;
5354
using node::RegenerateCommitments;
5455
using node::UpdateTime;
@@ -674,7 +675,7 @@ static RPCHelpMan getblocktemplate()
674675
{RPCResult::Type::NUM, "coinbasevalue", "maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)"},
675676
{RPCResult::Type::STR, "longpollid", "an id to include with a request to longpoll on an update to this template"},
676677
{RPCResult::Type::STR, "target", "The hash target"},
677-
{RPCResult::Type::NUM_TIME, "mintime", "The minimum timestamp appropriate for the next block time, expressed in " + UNIX_EPOCH_TIME},
678+
{RPCResult::Type::NUM_TIME, "mintime", "The minimum timestamp appropriate for the next block time, expressed in " + UNIX_EPOCH_TIME + ". Adjusted for the proposed BIP94 timewarp rule."},
678679
{RPCResult::Type::ARR, "mutable", "list of ways the block template may be changed",
679680
{
680681
{RPCResult::Type::STR, "value", "A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'"},
@@ -683,7 +684,7 @@ static RPCHelpMan getblocktemplate()
683684
{RPCResult::Type::NUM, "sigoplimit", "limit of sigops in blocks"},
684685
{RPCResult::Type::NUM, "sizelimit", "limit of block size"},
685686
{RPCResult::Type::NUM, "weightlimit", /*optional=*/true, "limit of block weight"},
686-
{RPCResult::Type::NUM_TIME, "curtime", "current timestamp in " + UNIX_EPOCH_TIME},
687+
{RPCResult::Type::NUM_TIME, "curtime", "current timestamp in " + UNIX_EPOCH_TIME + ". Adjusted for the proposed BIP94 timewarp rule."},
687688
{RPCResult::Type::STR, "bits", "compressed target of next block"},
688689
{RPCResult::Type::NUM, "height", "The height of the next block"},
689690
{RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "Only on signet"},
@@ -977,7 +978,7 @@ static RPCHelpMan getblocktemplate()
977978
result.pushKV("coinbasevalue", (int64_t)block.vtx[0]->vout[0].nValue);
978979
result.pushKV("longpollid", tip.GetHex() + ToString(nTransactionsUpdatedLast));
979980
result.pushKV("target", hashTarget.GetHex());
980-
result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1);
981+
result.pushKV("mintime", GetMinimumTime(pindexPrev, consensusParams.DifficultyAdjustmentInterval()));
981982
result.pushKV("mutable", std::move(aMutable));
982983
result.pushKV("noncerange", "00000000ffffffff");
983984
int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST;

test/functional/mining_basic.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ def test_timewarp(self):
153153
# The template will have an adjusted timestamp, which we then modify
154154
tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
155155
assert_greater_than_or_equal(tmpl['curtime'], t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP)
156+
# mintime and curtime should match
157+
assert_equal(tmpl['mintime'], tmpl['curtime'])
156158

157159
block = CBlock()
158160
block.nVersion = tmpl["version"]

0 commit comments

Comments
 (0)