Currently, the Bitcoin Wiki states:

A part of the original Bitcoin implementation, nLockTime is a field that specifies the earliest time a transaction may be added to a valid block. A later Bitcoin soft fork allowed nLockTime to alternatively specify the lowest block height a transaction may be added to a valid block.

Is the ordering correct? It appears that the source code as of v0.1.5 used the block height and v0.1.6 extended this to handle timestamps. Also, does this new ordering make it a hard-fork?

2 Answers 2


The Wiki was incorrect (I wrote the original text and I apologize). As indicated in the question, the ordering on the Wiki was backwards. However, upon investigating, I don't believe it was a hard fork. In the original Bitcoin 0.1 code, we find the following function:

bool IsFinal() const
    if (nLockTime == 0 || nLockTime < nBestHeight)
        return true;

This function is called in the mining code that selects which transactions to mine:

if (tx.IsCoinBase() || !tx.IsFinal())

That means no node running the default Bitcoin 0.1 code would mine a transaction unless its nLockTime was less than the next block's height. However, I don't see any code in 0.1 that rejects blocks with a "non-final" transaction, so this isn't a consensus rule.

Months later, in code that became part of Bitcoin 0.1.6, the timelock feature is added:

-    bool IsFinal() const
+    bool IsFinal(int64 nBlockTime=0) const
-        if (nLockTime == 0 || nLockTime < nBestHeight)
+        // Time based nLockTime implemented in 0.1.6,
+        // do not use time based until most 0.1.5 nodes have upgraded.
+        if (nBlockTime == 0)
+            nBlockTime = GetAdjustedTime();
+        if (nLockTime == 0)
+            return true;
+        if (nLockTime < (nLockTime < 500000000 ? nBestHeight : nBlockTime))

And the same commit also adds consensus enforcement for both heightlocks and timelocks:

+    // Check that all transactions are finalized (starting around 30 Nov 2009)
+    if (nBestHeight > 31000) // 25620 + 5320
+        foreach(const CTransaction& tx, vtx)
+            if (!tx.IsFinal(nTime))
+                return error("AcceptBlock() : contains a non-final transaction");

In short, in version 0.1.0 had no consensus rules about the nLockTime field and version 0.1.6 added a consensus rule that included both heightlocks and timelocks. That's making the rules more strict and so I believe it was a soft fork which activated at block 31,000.

Perhaps of interest, this is the earliest soft fork of which I'm aware (as of this writing, it's earlier than any entries at the time of writing on the Wiki's consensus versions list or BitMex's consensus forks list). Despite being so early, the fork was obviously made with care, giving the network about a month to upgrade and preparing for potential problems ahead of time.


I believe you are correct, both about the fact that height-based logic came first and time was added later, and the fact that this is a hard-forking change. A transaction with a locktime > 500000000 would not have been acceptable before the change, but possibly valid after.

Of course, given that no such transactions occurred (to the best of my knowledge), it isn't exactly a fork; but it was a change that could have led to one.

Also, before the removal of OP_VER, technically speaking every new release had a hard forking change of this nature.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.