Input-triggered transaction expiry

I might suggest an alternative framing. The difference here is that this approach establishes an invariant on nLockTime, such that all timelocks expire by nLockTime if every BIP68 input is height-based and enforces bit 21.

This implies what you are suggesting. The transaction becomes invalid if the input transaction was not confirmed before some height.

I agree, and thank you for sharing. I was not previously aware of your post.

As you allude to, script-based coin-height introspection is a legitimate alternative, but I would argue that this approach would be like using a hammer to push down a pin. Two drawbacks come straight to mind:

  1. No scriptless expiry: With the proposed approach, a scriptless spend can enforce input-triggered expiry. This is useful in presigned transactions, key-path spends, and (potential) bare output scripts enforcing a TEMPLATEHASH or CTV commitment.
  2. More powerful than needed: The fundamental capability we care about is an absolute cap on an input’s confirmation height. Coin-height introspection enables other behavior, like a minimum or exact confirmation height, which may prove unwanted.

Other less pressing but legitimate reasons to prefer the described approach include:

  1. Transaction readability: With bit 21, all time-related information remains visible in the txid-commitment. This is useful when displaying transactions to users to sign, creating PSBTs, or writing relay policies that require knowledge of expiry. Script-based enforcement would lack these properties by default.
  2. Separation of concerns: With the proposed approach, the existing separation of concerns between context validation and script validation would remain unchanged. Adding coin-height introspection to script would violate the existing separation of concerns, introduce new code paths, and demand a change in downstream projects like the kernel.

I am uncertain if the script you are suggesting works as you describe. CLTV enforces a minimum nLockTime, and the true nLockTime could be anywhere between that value and the current height. To get the behavior you desire, I think you would need a NONE|ACP presignature which commits to the nSequence and nLockTime values.

For this reason, if script-based max-coin-height enforcement is a goal, I would probably suggest an explicit OP_SEQUENCE and OP_LOCKTIME introspection capability. You could then enforce bit 21 in script and set an explicit maximum value on nLockTime using LESSTHAN.

I think you may be right. I felt it best to be conservative and stick with the same 100-block delay as the OP_EXPIRE proposal, but the more I think about it the more I come to the conclusion that the delay is unnecessary.

I plan to write a dedicated follow-up on this issue.

Short-duration HTLCs is definitely an interesting primitive, and it is good motivation for a shorter delay than the current 100-block minimum. See above.

1 Like