Modifying BIP54 to Support Future nTime Soft Fork

TLDR

BIP54 prevents the “timewarp attack” but inadvertently also precludes a future soft fork that could resolve the nTime overflow problem, which is expected to halt the chain in 2106. Modifying BIP54 slightly by including a u64 timestamp in the coinbase can resolve timewarp concerns, while leaving the door open for a soft fork that resolves the nTime problem, rather than a hard fork.

The Problem

Active work is underway to implement BIP54, also known as the Great Consensus Cleanup. One of the goals of BIP54 is to prevent the “timewarp attack,” whereby an attacker artificially suppresses the median time past (MTP) in order to artificially reduce the difficulty target.

The proposed solution in BIP54 is:

Given a block of height N:

  • If N\ \%\ 2016 is equal to 0, nTime must be set to a value higher than or equal to the nTime at height N-1 minus 7200 (T_N ≥ T_{N−1} − 7200)

This eliminates the attack vector, but it inadvertently precludes a future generation from resolving the nTime overflow problem via a soft fork, rather than a hard fork.

A Possible nTime Soft Fork

Imagine that it is the year 2080. Developers want to use immutable software that can run for the next 100 years (ex: an SPV bridge on a L2), but a hard fork to increase the nTime field from u32 to u64 is not yet pressing enough to be viable. Instead, users adopt the following soft fork:

Given a block of height N and a timestamp T_A at activation height H:

  • Miners store the timestamp T_N in a u64 field in the coinbase.

  • If N \ \% \ 2016 < 2015: miners set nTime to T_A+N-H.

  • If N \ \% \ 2016 = 2015: miners set nTime to (T_A + N - H - 2015) + T_N - T_{N-2015}.

Consequently, MTP increases by at most 1 each block, ensuring the chain effectively never halts (assuming T_H is sufficiently low).

In addition, the difficulty adjustment remains the same for legacy nodes and upgraded nodes. This resolves a DOS concern @gmaxwell raised in my original post on the mailing list.

Modifying BIP54

I would not venture to propose that we fix the nTime problem today. The nTime problem is still too far in the future, and it may turn out that a hard fork is the better option. But I would tend to prefer a fix to the timewarp problem that does not bind the hands of future generations.

A simply modification to BIP54 would resolve the problem:

Given a block of height N:

  • Miners store the timestamp T_N in a u64 field in the coinbase.

  • If N\ \%\ 2016 is equal to 0, T_N must be set to a value higher than or equal to T_{N-1} minus 7200 (T_N ≥ T_{N−1} − 7200).

  • If N\ \%\ 2016 is equal to 2015, nTime must be set to the nTime at height N-2015 plus T_N - T_{N-2015}.

This effectively prevents a timewarp attack while keeping the door open to a soft fork that fixes the nTime problem. The cost is a few bytes in the coinbase, which can be removed if a hard fork ends up being the preferred option.

Request for Feedback

Has the proposed modification to BIP54 been considered before? If not, would the flexibility of the proposed change be worth pursuing further?

That’s not “really” a soft fork, in that it would make the chain’s mediantime lag signficantly behind real time, so that transactions with an nTimeLock set by timestamp rather than block height would not be spendable at the time they were expected to be. That’s somewhat confiscatory, particularly if the timelock setting is enforced by OP_CLTV.

The “obvious” fix to the nTime overflow issue is to calculate a 64 bit nTime64 from the 32 bit nTime something like:

    uint64_t mediantime = pindexPrev->GetMedianTime();
    uint64_t nTimeHigh = mediantime & 0xFFFFFFFF00000000ull;
    uint64_t blockntime = nTimeHigh | uint32_t{block.nTime};
    if (blockntime < mediantime) blockntime + 0x100000000ull;

That’s a hard fork (but only compared to the chain stopping entirely), and means that a 64 bit replacement for timestamp-based nLockTime would be needed for that feature to still be usable, but otherwise seems pretty straightforward and non-intrusive.

1 Like