Skip to content

Followups to #4998 (fix TransactionDecoder)#5129

Merged
apoelstra merged 4 commits intorust-bitcoin:masterfrom
apoelstra:2025-10/followup-4998
Oct 14, 2025
Merged

Followups to #4998 (fix TransactionDecoder)#5129
apoelstra merged 4 commits intorust-bitcoin:masterfrom
apoelstra:2025-10/followup-4998

Conversation

@apoelstra
Copy link
Copy Markdown
Member

Refactors the TransactionDecoder state machine in a couple ways, eliminating some unreachable panic paths and also eliminating most of the reachable panic paths in end() (which should have been error returns).

Fixes two of the four followup issues to #4998 -- the other two are optimizing OutpointDecoder which is non-essential/low-priority, and eliminating the From impls required by the composite Decoder types (which is a somewhat-hard API problem and I don't think we want to hold up the rc on it).

Fixes #5125
Fixes #5122

The state machine logic in TransactionDecoder is a bit frustrating. We
need to obtain a mutable reference to the current sub-decoder to attempt
to feed data to it. If this fails, we then need to move the sub-decoder,
attempt to end() it, then replace it if this succeeds. (And the replacement
uses the return value from end() so we can't reorder this.)

Having the end() between the move and replacement means we need a dummy
Transitioning state, and having a mutable borrow before the move means
we need some borrowck trickery.

This commit separates the mutable-borrow logic from the move logic to
avoid the trickery. It retains the Transitioning dummy state which I can't
find a way to avoid.

Refactor only; no observable behavior changes.
Search-and-replace the error variant name, and update all the panic
conditions that are triggered by it. From a user point of view this
state does not represent "transitioning". It represents that we
called end() on a sub-decoder and that call yielded an error,
leaving us with no meaningful state.

The docs for Decoder::end and Decoder::current_chunk say that after
returning the initial error we are allowed to panic; update the panic
message to say that this is what we're doing. (We also have a panic
in read_limit, which we are not allowed to do, so replace that with
a dummy value return.)

No observable behavior changes except that some panic messages change.
…o end

If the data stream ends early we shouldn't panic. This is not a programmer
error. It indicates that we ran out of data.

This one has observable changes. Unit test in next commit.
Copy link
Copy Markdown
Contributor

@nyonson nyonson left a comment

Choose a reason for hiding this comment

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

ACK 27fbdf9

I found the commit message in e86a56c particularly helpful. I think the Decoder2State can be simplified too in a similar way by dropping Transitioning.

}

let decoder = self.state.inputs_transition();
// If the above failed, end the current decoder and go to the next state.
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.

nit: the "failed" in this comment and "success" up on line 391 had me a little confused thinking it was an error. FWIW I thought of the success as "more bytes required" and failure as "sufficient bytes for next state".

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hmm, yeah, that's a good way of looking at it. I was thinking of it like "succeeded means we're done for now".

Copy link
Copy Markdown
Member Author

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

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

On 27fbdf9 successfully ran local tests

Copy link
Copy Markdown
Member

@tcharding tcharding left a comment

Choose a reason for hiding this comment

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

ACK 27fbdf9

@apoelstra apoelstra merged commit 526cd41 into rust-bitcoin:master Oct 14, 2025
25 checks passed
@apoelstra apoelstra deleted the 2025-10/followup-4998 branch October 14, 2025 02:59
apoelstra added a commit that referenced this pull request Oct 14, 2025
144adfc consensus_encoding: remove Transitioning state (Nick Johnson)

Pull request description:

  Inspired by cleanup in #5129, simplify the `Decoder2State` by dropping the unnecessary Transitioning variant. We can just use the `Errored` variant and not change the state of the `Decoder2` if the first decoder fails while transitioning to the second.


ACKs for top commit:
  apoelstra:
    ACK 144adfc; successfully ran local tests
  tcharding:
    ACK 144adfc


Tree-SHA512: 23af024d28fdc8d9f8859c9aaf7ab68cffabb948581dce80ae9d4d0bc66adf01f7455804f6ca67209696a2d74b6857a93208e1595e46c8bef9f7f0a603c77d35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix Decoder::end impl on Transaction consensus_encoding: Improve Transaction decoder state machine

3 participants