Skip to content

fix(iter): translate_pk to iterate in left-to-right order - #1025

Open
trevarj wants to merge 1 commit into
rust-bitcoin:masterfrom
trevarj:fix-1022-translate-pk-ltr
Open

fix(iter): translate_pk to iterate in left-to-right order#1025
trevarj wants to merge 1 commit into
rust-bitcoin:masterfrom
trevarj:fix-1022-translate-pk-ltr

Conversation

@trevarj

@trevarj trevarj commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

First commit is the actual conversion. Deleted all the
RtlPostOrderIter stuff, which is a breaking change. Let me know if you
want that in a separate commit.

Second commit with the Ext trait can be dropped, but I didn't want to
ruin the readability of Terminal mappings.

Closes #1022

@apoelstra

Copy link
Copy Markdown
Member

In 66c6c9e:

Let's keep rtl_post_order_iter. It's part of the API and implementors of TreeLike get it for free. (And I use TreeLike in a bunch of downstream projects, though I don't know that I ever use the rtl iterator..)

@trevarj
trevarj force-pushed the fix-1022-translate-pk-ltr branch from 6b3e854 to b413b93 Compare August 16, 2026 14:47
@trevarj

trevarj commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

In 66c6c9e:

Let's keep rtl_post_order_iter. It's part of the API and implementors of TreeLike get it for free. (And I use TreeLike in a bunch of downstream projects, though I don't know that I ever use the rtl iterator..)

restored it and amended into the first commit.

@apoelstra

Copy link
Copy Markdown
Member

In b413b93:

I'd suggest squashing these two commits since the second largely overwrites the first. I like the idea of pulling this into a StackExt trait. Though all the methods should be #[inline] I think.

Then, I don't like the use of split_off, which allocates a whole new vector. You should be able to use Vec::drain to "directly" turn the end of the stack vector into an iterator.

@trevarj

trevarj commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

In b413b93:

I'd suggest squashing these two commits since the second largely overwrites the first. I like the idea of pulling this into a StackExt trait. Though all the methods should be #[inline] I think.

Then, I don't like the use of split_off, which allocates a whole new vector. You should be able to use Vec::drain to "directly" turn the end of the stack vector into an iterator.

roger that. i had it separate in case i needed to drop it off

`Miniscript::translate_pk` and `Descriptor::translate_pk`, along with
the concrete and semantic policy equivalents, drove their
reconstruction from a right-to-left post-order iterator. That existed
only so a node could be rebuilt as
`Terminal::AndB(stack.pop().unwrap(), stack.pop().unwrap())`.

- iterate with `post_order_iter` everywhere `rtl_post_order_iter` was used
- add a crate-private `StackExt` trait on `Vec<T>`; `pop2`/`pop3` pop the
  top two or three elements and pass them, left to right, to a constructor
  or closure
- `pop_n` drains the top `n` elements in order, for the `Vec`-shaped policy
  nodes, and `pop_thresh` rebuilds a threshold with the same `k`

Fixes rust-bitcoin#1022
@trevarj
trevarj force-pushed the fix-1022-translate-pk-ltr branch from b413b93 to ec491c4 Compare August 17, 2026 09:10

@apoelstra apoelstra left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ACK ec491c4; successfully ran local tests

@portlandhodl

portlandhodl commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

ACK ec491c4: tests pass.

Notes: For stateless translators output is bit-identical, but a translator whose result depends on visitation order — e.g. one that assigns keys from a list by counter — will now attach the same keys to different leaves, silently producing a different descriptor/scriptPubKey/address for identical inputs (verified: filling wsh(and_v(v:pk(A),pk(B))) from a fixed key list yields bcrt1qqx5nrr8… before, bcrt1qkr42lc9… after, no error anywhere). I am not aware of any project that implements a custom Translator, but it might be worth noting.

Nit: I think it would be worth adding a CHANGELOG entry calling out the behavior change explicitly.

@apoelstra

Copy link
Copy Markdown
Member

Yeah, agreed on the changelog entry. Ok to wait until we actually cut a release. I'll notice this PR title as a "meaningful behavior change" worth calling out, and try to remember to bold it.

I think that if anybody was depending on the order, they'd probably have already complained about it. But even most kinds of stateful translators (e.g. ones that are maintaining a counter) are still order independent, I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

We should fix translate_pk to iterate in left-to-right order

3 participants