Add hex codec traits for Header and Transaction#5381
Add hex codec traits for Header and Transaction#5381apoelstra merged 2 commits intorust-bitcoin:masterfrom
Conversation
814afda to
af7d6c6
Compare
|
This PR follows the same pattern as used by[0] and suggested in[1] the [0] https://docs.rs/hex-conservative/0.3.1/src/hex_conservative/display.rs.html#207-250 |
|
I can't tell whether you're putting hex-conservative 0.3 stuff into the public API. It looks like it because the Your I'm also not totally confident about implementing |
I did it that way mainly because it was easy. If we want an alloc-less version which works purely off the
I can extend this PR to include that trait too if you'd like. |
Yeah, sorry, I didn't realize that this would (apparently) leak into the public API. |
|
I wonder if we want to back up and add some facility to At the very least we could make a wrapper type which is private to Similarly we should do something for I think that as a first approach we should do this in private structs in |
af7d6c6 to
2d90b1d
Compare
2d90b1d to
f0702e6
Compare
|
I've tried to implement the private wrapper struct. I also reverted the change to the |
So, I think you will need to introduce a public error type no matter what, because as you observe there are (at least) two cases: a hex decoding error and a
|
hex_conservative 1.0 has the same error types (
I specifically made it generic over the |
Rather than having This is ugly and potentially confusing for the user who needs to keep track of which error is which (and there is no
I'm leaning against doing this, but I wanted to remind people that it's an option. |
f0702e6 to
c7f8a68
Compare
|
I've sorted out the use of stable hex errors for the That said, since this is going into 1.0, maybe we should sit on this until we really lock down the error type. |
primitives/src/lib.rs
Outdated
| Self::OddLengthString(odd_err) => write_err!(f, "odd length string"; odd_err), | ||
| Self::InvalidChar(char_err) => write_err!(f, "invalid character"; char_err), | ||
| // Decoder error types don't have Debug, so we only provide this generic error | ||
| Self::Decode(_) => write!(f, "failure decoding hex string into {}", core::any::type_name::<T>()), |
There was a problem hiding this comment.
| Self::OddLengthString(odd_err) => write_err!(f, "odd length string"; odd_err), | |
| Self::InvalidChar(char_err) => write_err!(f, "invalid character"; char_err), | |
| // Decoder error types don't have Debug, so we only provide this generic error | |
| Self::Decode(_) => write!(f, "failure decoding hex string into {}", core::any::type_name::<T>()), | |
| Self::OddLengthString(ref e) => write_err!(f, "odd length string"; e), | |
| Self::InvalidChar(ref e) => write_err!(f, "invalid character"; e), | |
| Self::Decode(ref e) => write_err!(f, "failure decoding hex string into {}", core::any::type_name::<T>(); e), |
There was a problem hiding this comment.
FTR I'm not 100% sure why this works but it builds.
| } | ||
|
|
||
| #[cfg(all(feature = "hex", feature = "alloc"))] | ||
| impl<T: Decodable> From<hex::DecodeVariableLengthBytesError> for ParsePrimitiveError<T> { |
There was a problem hiding this comment.
If we are going to put DecodeVariableLengthBytesError in the public API why have the two variants in ParsePrimitiveError? Why not just have a single HexDecode(DecodeVariableLengthBytesError) (or some other name)?
There was a problem hiding this comment.
I was mainly trying to reduce the error depth so that users won't have to descend into the error types as far to figure out the problem. If a wrapper is preferred though, then I can do that.
tcharding
left a comment
There was a problem hiding this comment.
Firstly, hats off for working this out this far. My gut feeling though is this is too much complexity for primitives. I have very low confidence that we would get this 100% correct. Its only going to be used for Transaction and Header, right? If so I rekon a brain-dead simple implementation would be better even if it requires code duplication.
|
And sorry for being so late to the party. Since I'm so late, @apoelstra please override me if you think I'm wrong. |
I had something like that initially, but @apoelstra suggested something like the private struct that we have now, specifically so that we have a single point at which to make decisions about the encoding style. The main problem that I can see is the error type. Even if we do manual implementations on |
|
hmm, I had a hunch that might have happened. What about we do the same trick we did with |
|
Maybe we can do the generic error type, but keep it private, then expose specific opaque error types for |
c7f8a68 to
a836094
Compare
a836094 to
cb6963f
Compare
abb9bb5 to
38fc6b5
Compare
|
fwiw ack 38fc6b5, I learned a bunch following along on this one. |
primitives/src/lib.rs
Outdated
|
|
||
| /// Writes an Encodable object to the given formatter in the requested case. | ||
| #[inline] | ||
| fn hex_write_tx_with_case<T: Encodable + Decodable>(obj: &HexPrimitive<T>, f: &mut fmt::Formatter, case: Case) -> fmt::Result { |
There was a problem hiding this comment.
Sorry for net mentioning it last review; this has _tx_ in the function name but writes a HexPrimitive. Perhaps just drop the tx` bit. Can be done as a follow up since this is private.
primitives/src/lib.rs
Outdated
| /// Provides default implementations for `Display`, `Debug`, `LowerHex`, and `UpperHex`. | ||
| /// Also provides [`Self::from_str`] for parsing a string to a `T`. | ||
| /// This can be used to implement hex display traits for any encodable types. | ||
| pub struct HexPrimitive<'a, T: Encodable + Decodable>(pub &'a T); |
There was a problem hiding this comment.
| pub struct HexPrimitive<'a, T: Encodable + Decodable>(pub &'a T); | |
| pub(crate) struct HexPrimitive<'a, T: Encodable + Decodable>(pub &'a T); |
Not that it really matters but just for clarity.
|
Hot. Patch 1 made patch 2 a blast to review. |
|
My vote goes for merge and follow up (if you feel like following up that is). |
|
Sounds good! Can one of you file an issue to deal with the allocations in both encoding and decoding? They should be unnecessary, though undoubtedly they'll both be annoying to deal with (encoding may require finally adding encoding to hex-conservative, while decoding will involve a "decode hex to a buffer then pass to push_decode" loop). Everything is encapsulated well so that users will not need to know or care about the change. |
38fc6b5 to
804f812
Compare
|
Rebased on master to fix conflicts, and changed the unaddressed comments from Tobin:
|
Currently, the Transaction type can be easily encoded into bytes using consensus_encoding, but there exists no way to encode it to hex without using the bitcoin crate's serialize_hex or a manual implementation. Neither such solution is elegant or discoverable. In implementing traits to hex, FromStr should also be introduced to decode from a hex string. Implement FromStr, Display, LowerHex, UpperHex and DisplayHex for Transactions.
Currently, the Header type can be easily encoded into bytes using consensus_encoding, but there exists no way to encode it to hex without using the bitcoin crate's serialize_hex or a manual implementation. Neither such solution is elegant or discoverable. In implementing traits to hex, FromStr should also be introduced to decode from a hex string. Implement FromStr, LowerHex, UpperHex and DisplayHex for Header.
804f812 to
17531ce
Compare
Currently, the Header and Transction types can be easily encoded into bytes using consensus_encoding, but there exists no way to encode them to hex without using the bitcoin crate's serialize_hex or a manual implementation. Neither such solution is elegant or discoverable.
Closes #1706, #4807