the purpose of OP_CHECKLOCKTIMEVERIFY
is kind of the opposite to the purpose of tx.nLockTime
. tx.nLockTime
prevents transactions with future dates from entering the blockchain, whereas OP_CHECKLOCKTIMEVERIFY
enables someone to freeze funds so that they can only be spent after a given timestamp or block height.
tx.nLockTime
tx.nLockTime
is validated by function IsFinalTx()
in src/main.cpp
:
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
{
if (tx.nLockTime == 0)
return true;
if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
return true;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
if (!txin.IsFinal())
return false;
return true;
}
where txin.IsFinal()
is in src/primitives/transaction.h
:
bool IsFinal() const
{
return (nSequence == std::numeric_limits<uint32_t>::max());
}
If the tx locktime is below the threshold then it is treated as a block height and if it is above the threshold then it is treated as a timestamp. Either way, the transaction locktime value must be smaller than the relevant constraint. If it is larger then miners must wait before including the transaction in a block.
The only way to bypass this transaction locktime constraint is to disable the transaction locktime completely by setting all txin sequence numbers to maxint. When this is done then miners will include the transaction straight away, even if the locktime has not yet been reached.
The idea with the transaction locktime is that before the transaction is locked (ie before the block height or timestamp catch up with tx locktime), someone can make amendments to the transaction. Each time they make a change then they must increment the sequence number to let miners know which amendment comes after another.
One use case for this might be a digital will. If you wanted to pass your money on to someone else specifically in the event of your death then you could create a transaction with a locktime of one year from now and then give it to a few friends. In the event of your death they can broadcast this transaction on the network after one year and the funds will be sent accordingly. Broadcasting the transaction before this time period of one year would not enable them to receive funds, since miners will ignore the transaction until the time period becomes valid (and obviously the friends cannot alter the functionality of this transaction since it is signed by your private key which you never disclose).
If you don't die then you can spend the funds to a different address of your own choosing by broadcasting a different transaction on the network. Your friends will then not be able to use the original transaction you gave them since this would be a doublespend, which the miners do not allow. For the transaction which you broadcast to cancel the will you would alter the locktime to make it sooner, and increment the sequence number. Alternatively you could set the locktime to 0 or set the sequence number to maxint to spend straight away.
OP_CHECKLOCKTIMEVERIFY
OP_CHECKLOCKTIMEVERIFY
has a very different use. It is validated in function EvalScript()
in src/script/interpreter.cpp
:
case OP_CHECKLOCKTIMEVERIFY:
{
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
// not enabled; treat as a NOP2
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
}
break;
}
if (stack.size() < 1)
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
// Note that elsewhere numeric opcodes are limited to
// operands in the range -2**31+1 to 2**31-1, however it is
// legal for opcodes to produce results exceeding that
// range. This limitation is implemented by CScriptNum's
// default 4-byte limit.
//
// If we kept to that limit we'd have a year 2038 problem,
// even though the nLockTime field in transactions
// themselves is uint32 which only becomes meaningless
// after the year 2106.
//
// Thus as a special case we tell CScriptNum to accept up
// to 5-byte bignums, which are good until 2**39-1, well
// beyond the 2**32-1 limit of the nLockTime field itself.
const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5);
// In the rare event that the argument may be < 0 due to
// some arithmetic being done first, you can always use
// 0 MAX CHECKLOCKTIMEVERIFY.
if (nLockTime < 0)
return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);
// Actually compare the specified lock time with the transaction.
if (!checker.CheckLockTime(nLockTime))
return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);
break;
}
which relies on function CheckLockTime()
in the same file:
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
{
// There are two kinds of nLockTime: lock-by-blockheight
// and lock-by-blocktime, distinguished by whether
// nLockTime < LOCKTIME_THRESHOLD.
//
// We want to compare apples to apples, so fail the script
// unless the type of nLockTime being tested is the same as
// the nLockTime in the transaction.
if (!(
(txTo->nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
(txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
))
return false;
// Now that we know we're comparing apples-to-apples, the
// comparison is a simple numeric one.
if (nLockTime > (int64_t)txTo->nLockTime)
return false;
// Finally the nLockTime feature can be disabled and thus
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
// finalized by setting nSequence to maxint. The
// transaction would be allowed into the blockchain, making
// the opcode ineffective.
//
// Testing if this vin is not final is sufficient to
// prevent this condition. Alternatively we could test all
// inputs, but testing just this input minimizes the data
// required to prove correct CHECKLOCKTIMEVERIFY execution.
if (txTo->vin[nIn].IsFinal())
return false;
return true;
}
Here the transaction locktime is compared to a value on the stack. To validate successfully, both must be the same side of the theshold (ie both must be interpreted as a block height, or both as a timestamp), and the script will only validate if the stack value is lower than the tx locktime. Or to put it another way, the script will only validate if the transaction locktime has passed the stack value.
Whereas IsFinalTx()
prevents transactions with locktimes in the future from being included into the blockchain in the present, OP_CHECKLOCKTIMEVERIFY
freezes funds in the blockchain so that they can only be spent after a specified time in the future.
Note that the stack value used for comparison is most useful when placed in the scriptPubKey. The locktime used for comparison against the stack value is that of the signing transaction. This forces the spender to wait for the block or timestamp in order to spend the funds.
As previously discussed, IsFinalTx()
does allow transactions with locktimes above the current block height or timestamp to be mined - providing the sequence number is maxxed out, thus disabling the tx locktime. Submitting such a transaction with a maxxed out sequence number would be a sneaky way for the recipient to spend the funds earlier than the time specified by the sender in the txout script. So, to prevent the OP_CHECKLOCKTIMEVERIFY
criteria from being bypassed, the script validation must fail when the tx locktime is disabled by the sequence number.