primitives: Implement decoding traits #4998
Conversation
|
cc @nyonson, here is a quick and dirty go at starting on |
f5cc627 to
b2a6a6b
Compare
|
I am a little confused by the commit message in 3adce0b for the error type wrappers. You said "If two encoders return the same error it is not currently possible to compose them with our decoders", but I don't think that is true? Couldn't a composed decoder define a new type which just maps |
|
I was trying to describe the same problem we have in the composite error in your PR, if |
Can't you just do I think this is enabled by a identity From blanket impl. |
|
I'm not sure what we disagree about. If two decoders return the same error then there is currently no way when using the |
0fcd759 to
838adc0
Compare
|
Ah, my bad man, misinterpreted. We are on the same page. |
f01fb47 to
a2bfedf
Compare
a2bfedf to
4331cc6
Compare
consensus_encoding/src/decode/mod.rs
Outdated
| /// # Errors | ||
| /// | ||
| /// Errors if `slice` is empty or encoding is invalid. | ||
| pub fn decode_compact_size(slice: &mut &[u8]) -> Result<u64, CompactSizeDecodeError> { |
There was a problem hiding this comment.
Kix wrote a pretty slick compact size decoder back in the day here: https://github.com/rust-bitcoin/rust-bitcoin/pull/2184/files#diff-97b1ea49ecd9b6b576f8f6dbd640e6d317da31348297d14cfbbdf47b909ae34bR12
Even though this is only used internally by a vec decoder, I think it makes sense to make it a full fledged decoder to handle weird cases when only a handful of bytes are read for some reason.
There was a problem hiding this comment.
Ah yeah, my version does not correctly handle passing in a byte slice that is only part of the compact size. Nice reviewing Nick!
| /// | ||
| /// The encoding is expected to start with the number of encoded bytes (length prefix). | ||
| #[cfg(feature = "alloc")] | ||
| pub struct VecDecoder { |
There was a problem hiding this comment.
Should this just be VecBytesDecoder to differentiate from VecDecoder?
There was a problem hiding this comment.
Those are the names I briefly thought of also so that is a reasonable metric for their merit. @apoelstra want to opine on these names?
VecBytesDecoderVecDecoder<T> where T: Decodable
There was a problem hiding this comment.
Perhaps ByteVecDecoder is better since an AmountDecoder decodes an Amount and the ByteVecDecoder decodes a byte vector?
There was a problem hiding this comment.
Or does it decode a vector of bytes? - drats.
There was a problem hiding this comment.
If you want me to make a decision I like ByteVecDecoder best. But I don't really care and don't think it matters. Almost nobody will ever name this type.
There was a problem hiding this comment.
Lets call it two votes for ByteVecDecoder and one for VecBytesDecoder. ByteVecDecoder in is. Thanks
4331cc6 to
363d3ff
Compare
5b6fab8 to
64608f2
Compare
|
The test failure (name |
There was a problem hiding this comment.
ACK 15b4f4c
Some minor comments, but I was able to wrap my head around the transaction state machine. I was hoping to think up some alternative which handled the Inputs/SegwitFlag dance and then passed it off to some simpler Decoder4/6s. But handling the "backtracking" kinda lead me back to where you landed.
primitives/src/transaction.rs
Outdated
| match &self.state { | ||
| State::Version(decoder) => decoder.min_bytes_needed(), | ||
| State::Inputs(_, _, decoder) => decoder.min_bytes_needed(), | ||
| State::SegwitFlag(_) => 2, |
There was a problem hiding this comment.
In 15b4f4c, given how the state machine flows, I believe this should only be 1 since the marker has already been consumed and we are only analyzing the flag in this state.
There was a problem hiding this comment.
BOOM! Good reviewing bro, you are a useful bloke to have on the team, for real.
primitives/src/transaction.rs
Outdated
|
|
||
| /// The state of the transiting decoder. | ||
| #[cfg(feature = "alloc")] | ||
| pub enum TransactionDecoderState { |
There was a problem hiding this comment.
In 15b4f4c, do we have to expose TransactionDecoderState/Attempt/IsSegwit? Would be nice to give us the flexibility to tweak them in the future if we can hide them.
There was a problem hiding this comment.
Oh BOOM! I thought I tried that before, that's nice!
primitives/src/transaction.rs
Outdated
| /// Boolean used to track whether or not this transaction uses segwit encoding. | ||
| #[cfg(feature = "alloc")] | ||
| #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| pub enum IsSegwit { |
There was a problem hiding this comment.
In 15b4f4c, another minor clarity idea for the state machine is to fold Attempt into IsSegwit by adding some sort of initial Unknown variant. Might make the Inputs/SegwitFlag dance a little clearer.
There was a problem hiding this comment.
So with all these types private, your idea (which I'm not exactly understanding right now) becomes an internal change, right? So I can punt it down the field?
There was a problem hiding this comment.
Yep, can punt.
And said another way, instead of having the Attempt enum for the Inputs state, just use the IsSegwit state.
enum IsSegwit {
/// Yes so uses segwit encoding.
Yes,
/// No segwit flag, marker, or witnesses.
No,
/// Initial state, inputs have not been decoded yet.
Unknown,
}This isn't a massive change, just maps well in my mind to how there are really 3 Segwit states when decoding.
There was a problem hiding this comment.
Ah yeah that looks good.
15b4f4c to
24e7b35
Compare
|
Changes in force push:
|
6f78cf7 Use correct name in rustdocs (Tobin C. Harding) Pull request description: Cut'n'pasta error slipped in, notice during review of #4998. ACKs for top commit: apoelstra: ACK 6f78cf7; successfully ran local tests Tree-SHA512: a5b3a5d3f7a724fff51973c73cb89b6f42095950ab076422c524d00029d1b0ef4c9fe71fb4f7c0aaf4abfaac963a296a3cb01a1df25573ba857f8e25fe38269d
a4be941 Feature gate unused const (Jamil Lambert, PhD) 5e2eeb8 Fix clippy error: struct is never constructed (Jamil Lambert, PhD) fdce327 Fix explicit lifetime clippy lints (Jamil Lambert, PhD) f38221c Fix lint error: passing a unit value to a function (Jamil Lambert, PhD) Pull request description: In preparation for adding crate specific clippy runs in CI with no-default-features, fix all the current lint errors when running it locally in each crate. There is one clippy error locally in primitives from an unused import (only used with alloc), but it is fixed in #4998. ACKs for top commit: apoelstra: ACK a4be941; successfully ran local tests tcharding: ACK a4be941 Tree-SHA512: e5f601213782e7ccceecfbdd022020f830dc321d6e31d522a1b93cf56c15735bccb72f3987d8fc6f633dba7ec8b88369aa65429992d97a3c15883c4622c5fd90
|
Will need rebase because #5107 renamed |
3400588 to
0e97331
Compare
|
Needs rebase again since #5108 (which rearranged some imports). Stupid that we still need to manually resolve these kinds of conflicts.. |
0e97331 to
28b7509
Compare
|
|
This terminology is not that widely used, lets use `scriptPubkey` instead as is more common.
28b7509 to
39bf86b
Compare
|
Followups:
Also lmao Kix would hate the |
|
The impl of |
|
Nice! thanks. I split up your comments into a bunch of bite sized issues. |
|
@nyonson in the interest of moving forward I'm gonna merge this, and any future review you do we can address in followups. |
27fbdf9 primitives: add unit test for incomplete transaction decoding (Andrew Poelstra) 93db1e0 primitives: fix TransactionDecoder::end to not panic on early calls to end (Andrew Poelstra) e86a56c primitives: renamed TransactionDecoderError::Transitioning to Errored (Andrew Poelstra) 681af66 primitives: remove a bunch of panics from Transaction::decoder (Andrew Poelstra) Pull request description: 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 ACKs for top commit: nyonson: ACK 27fbdf9 tcharding: ACK 27fbdf9 Tree-SHA512: 1fa7556cc8f47f578ff1293a09c76b07ae2a2de53a76eb0b52b0846ca73b203878791fd8bad350590aa9197ec173c007857059f2991515c9224d35686094f1b3
Things that need careful attention please:
TransactionDecoderWitnessDecoder::emptykludge