primitives: remove Ord from AbsLockTime and RelLockTime#982
Conversation
This is supposed to be testing mixed timelocks, but it uses descriptors
that are invalid for several unrelated reasons. These will be enforced
in a later PR, so fix the issues now.
Specifically:
* It is not allowed to use the same `unavailable_key` multiple times
* The rightmost branch must not be sigless; the timelock needs to have a
pubkey and'ed with it. Otherwise the whole script is malleable.
* Similarly the "cheap dissatisfaction" of v:after(144),pk({})) must
not be sigless. We turn it into v:after(144),and_v(v:pk({})),pk({}))
which requires a signature even to be dissatisfied.
* Also, the giant comments don't accurately reflect what's going on in
this test. They claim that post-rust-bitcoin#895, we will refuse to create a
satisfaction if we'd be forced into mixing timelocks. But we don't.
We actually do the same wrong thing as before, just for different
reasons.
The resulting test now passes even when all `ValidationParams` are turned
on, though in this PR we don't confirm this.
HOWEVER, despite the test working with a non-malleable descriptor now, the
satisfaction that this test produces is malleable. For this I have filed
rust-bitcoin#976, which will be
fixed in the next commit.
…ions ...unless the user has explicitly requested a malleable satisfaction. Fixes rust-bitcoin#976
|
concept ACK. Will wait for #980 to merge before reviewing in detail.
lmao. This timelock-mixing thing (and I think instead we should return If you think it's too big a diff, we can just accept this PR as-is, update the regression test with even more explanation/history, and file a bug to improve it later. Eventually I kinda think we should do two parallel satisfactions: one with height-based timelocks and one with time-based ones. This will be a little bit tricky to implement since there are four possibilities (time vs height for both relative and absolute locktimes) and we don't want to waste time or space in the case of a "normal descriptor" that has only one kind (or no kinds) of timelocks.
I'm don't think it's actually impossible. The docs for I'd like to just remove this warning, or at least weaken it. |
|
Pushed 2c0d98b: mixed height/time in concatenate_rev now yields Witness::Impossible, with max_same_kind on the locktime types and updated regression_895 / satisfier docs. PR description updated to match. |
|
In 1140b69: I think we should sort locktimes numerically by their u32 representation. I could be convinced either way...but the numeric comparison is cheaper to implement and I suspect it matches user intuition a bit better. In this commit we should also update the ord impls for |
|
Addressed in 66b99c2: same-kind locktime ordering in Policy::Ord and Terminal::cmp now uses consensus u32 instead of display strings. Miniscript::Ord already delegates to Terminal::cmp via self.node.cmp, so no separate change there. |
|
Please don't add commits which change other commits. Use git-rebase to edit the original commits in-place. This helps us review code commit by commit. |
66b99c2 to
5cd8ab8
Compare
Rebased so that review feedback is folded into the original commits, not added as fix-ups on top. Each commit builds cleanly. |
|
In bd68e35: It would be a better abstraction to have |
Replace derive(Ord) with variant-name ordering and same-kind locktime comparison via cmp_by_consensus on the locktime types, and add regression tests.
5cd8ab8 to
c170d55
Compare
Done — cmp_by_consensus on AbsLockTime and RelLockTime, folded into the original commit. I was about to step out the door to go to my wedding; we're leaving in two hours! I'll be gone about a week, no service, camping out in the wilderness for the celebration. So if it seems like I drop off the map, don't give up on me, I'll be back in seven days. =) |
|
Nice! Almost there. In c170d55 can you update the doccomments (where you removed "which implements The nonzero invariant is ultimately why we have these wrapper types. The Ord thing was just a bonus. |
c170d55 to
67f2b2d
Compare
|
Updated the struct docs in c170d55 to say "that cannot be zero." |
|
Henry Romp ***@***.***> writes:
I was about to step out the door to go to my wedding; we're leaving in two hours! I'll be gone about a week, no service, camping out in the wilderness for the celebration. So if it seems like I drop off the map, don't give up on me, I'll be back in seven days. =)
LOL what the heck...congratulations and enjoy!
|
Compare After and Older nodes via cmp_by_consensus rather than locktime Ord, and add a Miniscript ordering regression test.
Mixed height/time merges now invalidate the whole satisfaction path instead of leaving a valid stack with None timelock metadata. Add max helpers on locktime types and update satisfier docs.
Drop the consensus-u32 ordering that incorrectly compared height-based and time-based locktimes against each other.
67f2b2d to
476dac5
Compare
|
While updating the PR description I noticed |
|
queued up an ack/merge. Enjoy your wedding! If CI passes it'll be merged when you're back, or else it'll wait for you. |
|
Lol, dammit, I didn't realize that this built on #980. I did not intend to merge #980 since it hasn't been reviewed by anyone but its author (me). Interesting process failure here... my reviewing system saw that the two commits from 980 were "already reviewed" and skipped over them, so when I ran |
This PR implements #979 by removing
OrdandPartialOrdfromAbsLockTimeandRelLockTime. Those impls compared height- and time-based locktimes as raw consensusu32values, which is not a meaningful total order. The wrapper types exist because Miniscript locktimes cannot be zero; ordering was incidental.Policy types still need a total order, so we replace
derive(Ord)on concrete and semanticPolicywith explicit variant-name ordering and consensus-u32 comparison of matchingAfter/Oldernodes viacmp_by_consensuson the locktime types.Terminal::cmpuses the same method, andMiniscript::Ordpicks that up throughnode.cmp. Policy and Miniscript ordering may change; that ordering was never a stable public contract.In
concatenate_rev, same-unit locktimes merge viamax(bitcoinpartial_cmp); mixed height/time on one path yieldsWitness::Impossible, so plan building fails or picks another branch. Composite satisfiers may still expose both locktime kinds.regression_895expectsinto_plan_mallto fail on the height-vs-time case whileinto_planstill succeeds with the time-based locktime.Stacked on PR #980 (
2026-06/mallsat) — merge #980 first. Breaking changes; changelog and version bump left to maintainers.Fixes #979
Tested with:
cargo test --all-features— passedjust fmt-check— passedjust sane— passed