Skip to content

fix(afs): require zero locktime for the nSequence path - #87

Merged
evanlinjin merged 1 commit into
bitcoindevkit:masterfrom
evanlinjin:fix/afs-sequence-branch-locktime
Aug 21, 2026
Merged

fix(afs): require zero locktime for the nSequence path#87
evanlinjin merged 1 commit into
bitcoindevkit:masterfrom
evanlinjin:fix/afs-sequence-branch-locktime

Conversation

@evanlinjin

@evanlinjin evanlinjin commented Aug 20, 2026

Copy link
Copy Markdown
Member

Description

Fixes #65 (comment) — point 2 of #73 (comment).

The nSequence path exists so the tx resembles an off-chain settlement spending a timelock path, and those carry nLockTime = 0 with a CSV-driven sequence.

#65 removed the tx.lock_time = LockTime::ZERO that path used to perform — correctly, since it regressed input CLTVs — but added no precondition in its place. So a tx whose locktime is already pinned, by an input's CLTV or by min_locktime, can come out with both a near-tip locktime and a confirmation-depth sequence. That matches neither an ordinary wallet spend nor a contract close: a third fingerprint, worse than either branch alone.

The path is only coherent at lock_time == 0, so make that a precondition:

let must_use_locktime = tx.lock_time != LockTime::ZERO
    || taproot_inputs.is_empty()
    || inputs.iter().any(|input| { /* ... */ });

Changelog notice

Fixed:
- Anti-fee-sniping only takes the `nSequence` path when `tx.lock_time` is zero. A locktime pinned by an input's CLTV or by `min_locktime` now always takes the `nLockTime` path.

Before submitting

🤖 Generated with Claude Code

@evanlinjin
evanlinjin force-pushed the fix/afs-sequence-branch-locktime branch from 5119b64 to 147a6e7 Compare August 20, 2026 08:09
The nSequence path exists so the tx resembles an off-chain settlement
spending a timelock path, and those carry nLockTime = 0. bitcoindevkit#65 dropped the
`tx.lock_time = ZERO` that the path used to perform (correctly, since it
regressed input CLTVs) but added no precondition in its place, so a tx whose
locktime was already pinned — by an input's CLTV or by `min_locktime` — could
come out with both a near-tip locktime and a confirmation-depth sequence.
That matches neither an ordinary wallet spend nor a contract close: a third
fingerprint, worse than either branch alone.

Co-Authored-By: ValuedMammal <95981133+ValuedMammal@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@evanlinjin
evanlinjin force-pushed the fix/afs-sequence-branch-locktime branch from 147a6e7 to e05146e Compare August 20, 2026 08:12
@evanlinjin evanlinjin self-assigned this Aug 20, 2026
@evanlinjin evanlinjin added the bug Something isn't working label Aug 20, 2026
evanlinjin added a commit to evanlinjin/bdk-tx that referenced this pull request Aug 20, 2026
…fee-sniping

discourage_fee_sniping now consumes the template and returns a SealedTxTemplate
exposing only reads + emission, so version/locktime/sequence/ordering can't be
changed after AFS. TxTemplate wraps SealedTxTemplate and derefs to it for the
shared read/emit surface.

The concrete case this rules out: AFS may protect the transaction by setting an
input's nSequence instead of the locktime, which it only does while lock_time is
zero. A set_locktime afterwards would rebuild a tx carrying both a near-tip
locktime and a confirmation-depth sequence — the fingerprint bitcoindevkit#87 exists to
prevent. A compile_fail doctest pins that.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@ValuedMammal ValuedMammal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK e05146e

@evanlinjin
evanlinjin merged commit b00f35b into bitcoindevkit:master Aug 21, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants