Skip to content

Introduce impl_bytelike_traits macro#2861

Merged
apoelstra merged 1 commit intorust-bitcoin:masterfrom
tcharding:06-12-impl_bytelike_traits
Nov 2, 2024
Merged

Introduce impl_bytelike_traits macro#2861
apoelstra merged 1 commit intorust-bitcoin:masterfrom
tcharding:06-12-impl_bytelike_traits

Conversation

@tcharding
Copy link
Copy Markdown
Member

@tcharding tcharding commented Jun 12, 2024

We have a couple of problems:

  1. There are two macros currently for fmt stuff that do similar things, arr_newtype_fmt_impl and hex_fmt_impl - the difference is not immediately obvious, its the way that the byte array is iterated.

  2. Our hash types are missing AsRef<[u8; len]> and Borrow<[u8; len]>.

Introduce a new macro and remove a bunch of other macros. Include extensive docs but hide the macro from public docs because its not really for consumers of the library.

The macro requires $crate::hex to point to hex-conservative.

Note the macro is pretty generic (as in general purpose), hashes might not be the right home for it. Potentially a better place would be in hex itself?

@github-actions github-actions bot added C-bitcoin PRs modifying the bitcoin crate C-hashes PRs modifying the hashes crate test C-base58 PRs modifying the base58 crate labels Jun 12, 2024
@tcharding tcharding force-pushed the 06-12-impl_bytelike_traits branch from 0f4511f to 302c331 Compare June 12, 2024 02:57
@tcharding tcharding force-pushed the 06-12-impl_bytelike_traits branch from dc5a377 to d3f36fe Compare June 19, 2024 23:03
@tcharding tcharding marked this pull request as ready for review June 19, 2024 23:03
@github-actions github-actions bot removed test C-base58 PRs modifying the base58 crate labels Jun 19, 2024
@apoelstra
Copy link
Copy Markdown
Member

In 4287bf2ff35ca21cdd1f1e27341239fbcc499965:

The new as_byte_array method should be const.

Other than that d3f36fe5a76dde18bb9238cd54f9612d6d5e5943 looks great! I wonder if later we will want to extend this macro to also add the as_byte_array etc inherents.

@tcharding tcharding force-pushed the 06-12-impl_bytelike_traits branch from d3f36fe to 9a0a711 Compare June 20, 2024 22:29
@tcharding
Copy link
Copy Markdown
Member Author

Only change is adding the const.

@tcharding
Copy link
Copy Markdown
Member Author

#2893 should fix CI.

apoelstra
apoelstra previously approved these changes Jun 22, 2024
Copy link
Copy Markdown
Member

@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.

ACK 9a0a711462118ccd49683ef5564a0447ce471725

apoelstra
apoelstra previously approved these changes Jun 24, 2024
Copy link
Copy Markdown
Member

@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.

ACK 23c3a40545087084734af85ea0002099576641fe

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Isn't midstate mainly intended for creating tags? It thus shouldn't need all the traits.

But even more seriously, didn't we agree to have length in the midstate? That'd be incompatible with serialization. Do we really want to do this?

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.

Good points. I think we should back up, make the Midstate be a struct with a separate length and byte array (and maybe even a byte array for unhashed bytes? but then it would be identical to the Engine type)

We should provide inherents to access both fields, as well as a convenience function to check whether the length is a full multiple of 64 (or maybe this should be an invariant, and when extracting a midstate from an engine that has a non-multiple-of-64 it should fail?)

I think maybe we need to promote this to its own issue/discussion. Meanwhile I think the existing PR is API-diff-minimizing so we can accept it for now.

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.

Promoted to #2918

I'll leave it up to you whether you want to resolve that before accepting this PR.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we should resolve it before accepting this specific change. The rest of the PR looks fine. (And no, I really don't want to add API that we suspect we will to remove in a subsequent PR potentially in a next release. Too much noise.)

@tcharding tcharding marked this pull request as draft June 26, 2024 04:59
@tcharding
Copy link
Copy Markdown
Member Author

Note to self, pick this up after #3010 merges.

@tcharding tcharding force-pushed the 06-12-impl_bytelike_traits branch from 23c3a40 to 4b63cfe Compare August 9, 2024 02:00
@tcharding tcharding marked this pull request as ready for review August 9, 2024 02:01
@tcharding
Copy link
Copy Markdown
Member Author

Re-basing this after all the recent work on hashes was quite serendipitous. Turns out we missed a few things from siphash::Hash. This is now a nice little clean up.

@tcharding tcharding marked this pull request as draft August 9, 2024 02:04
@tcharding tcharding force-pushed the 06-12-impl_bytelike_traits branch from 4b63cfe to b895bbb Compare August 9, 2024 02:15
@tcharding
Copy link
Copy Markdown
Member Author

There are bugs in siphash still. Will try again another time.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm pretty sure I've already said that the perf limitation is still in this macro. Is this broken rebase?

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.

Ah damn, it was risky rebasing this late yesterday evening, sorry for stealing your time.

@tcharding tcharding force-pushed the 06-12-impl_bytelike_traits branch from 805311c to c128342 Compare September 5, 2024 06:05
apoelstra
apoelstra previously approved these changes Sep 6, 2024
Copy link
Copy Markdown
Member

@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.

ACK c12834230aee70aa716550ce03170b5b7aa40242 successfully ran local tests; though I wonder if we want to move this macro to internals or even to hex?

@tcharding
Copy link
Copy Markdown
Member Author

Some considerations:

  • The "reverse" stuff is bitcoin specific, invalidating it being put in hex, right?
  • internals would then have to depend on hex, so far I had it in mind that internals was a leaf crate but I guess that because hex is not bitcoin specific then it will never be allowed to depend on bitcoin-internals so this is ok.
  • If we want hashes to stabalize we need to be careful not to change the output of this macro (and others) eventually. Having them over in internals makes me nervous that we will want the change somewhere else and forget hashes, I'm inclined to think that as we stabalize we will want to share macros between crates less or somehow mark them as 'used for stable code generation, don't modify the output'

But if none of that matters, I can move it.

@Kixunil
Copy link
Copy Markdown
Collaborator

Kixunil commented Sep 6, 2024

  • The "reverse" stuff is bitcoin specific, invalidating it being put in hex, right?

I prefer keeping it out until there's a good reason (e.g. perf problems reversing the hashes). But I'm not strongly opposed to having it in hex - it should be mostly harmless.

  • internals would then have to depend on hex, so far I had it in mind that internals was a leaf crate but I guess that because hex is not bitcoin specific then it will never be allowed to depend on bitcoin-internals so this is ok.

That's not a problem, internals is allowed to depend on whatever, though it needs to be gated. The idea of enforcing a crate to stay a leaf indefinitely is not useful.

  • or somehow mark them as 'used for stable code generation, don't modify the output'

This was my intention for a while and I still think it's a good approach. But note that we want to also forbid adding items to the generated types because Rust considers them to belong to the caller crate which means orphan rules don't apply and adding any trait impl or associated item later is a breaking change. Versioning them separately might be needed/useful.

@tcharding
Copy link
Copy Markdown
Member Author

Can we do it as a follow up (#3320) or do you guys want it done now?

@apoelstra
Copy link
Copy Markdown
Member

I'd prefer as a followup. It's more risky than I'd considered.

@tcharding
Copy link
Copy Markdown
Member Author

Sweet ,lets go!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can't serde simply call as_ref instead of indexing? Should be a trivial change.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe we should have Mut versions too. At least with some additional macro option.

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.

Agreed, but I do think it should be optional (and for hashes, off). I'd be fine adding in a followup. I guess, whatever followup moves the macro and makes it more generally useable.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

and for hashes, off

Why? I think it should be only off for things like Sighash. I agree it can be in followup. The reason I haven't acked is the SliceIndex stuff.

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.

I guess it's harmless, but why would anybody want to mutate a hash?

Good observation though that with Sighash there would be meaningful harm, so there's a reason to go out of our way to avoid it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why would anybody want to mutate a hash?

I really don't know except for mem::swap, but that'd just swap the entire hash without our support. (Though swapping with something weakly typed doesn't sound too crazy.)

My reason is mainly basic Rust consistency that unless we have a good reason to avoid a trait impl we should have the impl. This is also one of the Rust API guidelines.

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.

Cool. Sounds good to me.

@tcharding
Copy link
Copy Markdown
Member Author

Can't serde simply call as_ref instead of indexing? Should be a trivial change.

This PR does not add SliceIndex, it maintains the current behavour and removal of SliceIndex is unrelated to this PR. FTR I've tried it before and I tried it again this morning. Unless I am being brain dead it is not trivial to remove the SliceIndex impl.

This PR has been stalled for almost three months, can we just get it in and move on?

@tcharding
Copy link
Copy Markdown
Member Author

Holy f***, there is already a draft PR to do the SliceIndex stuff: #3296 (comment)

@tcharding tcharding marked this pull request as draft September 9, 2024 04:27
@tcharding tcharding force-pushed the 06-12-impl_bytelike_traits branch from c128342 to 6524e1c Compare October 16, 2024 02:58
@tcharding
Copy link
Copy Markdown
Member Author

tcharding commented Oct 16, 2024

Currently is broken. Note the first patch was added after I struggled with the compiler only to find the same problem in patch 3.

First one gets this error:

error: expressions must be enclosed in braces to be used as const generic arguments
   --> hashes/src/util.rs:192:49
    |
192 |           $crate::impl_bytelike_traits!($newtype, <$newtype as $crate::Hash>::LEN, <$newtype as $crat...

Then if adding {} as suggested on gets this error:

error[E0308]: mismatched types
   --> hashes/src/util.rs:192:51
    |
192 |           $crate::impl_bytelike_traits!($newtype, { <$newtype as $crate::Hash>::LEN }, <$newtype as $crate::Hash>::DISPLAY_BACKWARD);

Before I rebased I did not see this problem, and I hard reset to double check nothing had changed - well something has changed but I can't work out what.

@tcharding tcharding force-pushed the 06-12-impl_bytelike_traits branch from 6524e1c to 0ab26a0 Compare October 28, 2024 05:32
@tcharding
Copy link
Copy Markdown
Member Author

Hey @apoelstra if you get a second could you take a look at this please, non-urgent though. If you check out the first commit and try and build you'll get

error: expressions must be enclosed in braces to be used as const generic arguments

Looks simple, but I cannot workout how to fix it. The compiler suggestion just leads to another error.

Thank in advance.

@apoelstra
Copy link
Copy Markdown
Member

@tcharding super weird. But this "fixes" it

diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs
index c231b237b..625b8d8d0 100644
--- a/hashes/src/internal_macros.rs
+++ b/hashes/src/internal_macros.rs
@@ -20,7 +20,7 @@
 /// `from_engine` obviously implements the finalization algorithm.
 macro_rules! hash_trait_impls {
     ($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
-        $crate::impl_bytelike_traits!(Hash, $bits / 8, $reverse $(, $gen: $gent)*);
+        $crate::impl_bytelike_traits!(Hash, { $bits / 8 }, $reverse $(, $gen: $gent)*);

         impl<$($gen: $gent),*> $crate::GeneralHash for Hash<$($gen),*> {
             type Engine = HashEngine;
diff --git a/hashes/src/macros.rs b/hashes/src/macros.rs
index fe658b17b..7a0cfdbb5 100644
--- a/hashes/src/macros.rs
+++ b/hashes/src/macros.rs
@@ -41,7 +41,7 @@ fn from_str(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Err>
         $crate::hex::impl_fmt_traits! {
             #[display_backward($reverse)]
             impl<$($gen: $gent),*> fmt_traits for $ty<$($gen),*> {
-                const LENGTH: usize = $len;
+                const LENGTH: usize = ($len); // parens required due to rustc parser weirdness
             }
         }

IMO there is some bug in the rustc parser somewhere.

@tcharding
Copy link
Copy Markdown
Member Author

const LENGTH: usize = ($len); // parens required due to rustc parser weirdness

Nice find, out of interest what led you to try this? I tried putting {} on all the other places that use $len but I did not try to paranthesise this one.

@apoelstra
Copy link
Copy Markdown
Member

The compiler suggested adding {}s as I did. At first I tried putting braces around all the uses of $len but it didn't like that, so I put it on the call site as it suggested. Then it complained that I needed to add ()s at the call site. I tried that and it went back to wanting braces. So instead I tried adding them at the usage sites, and that worked.

We have a couple of problems:

1. There are two macros currently for fmt stuff that do similar things,
`arr_newtype_fmt_impl` and `hex_fmt_impl` - the difference is not
immediately obvious, its the way that the byte array is iterated.

2. Our hash types are missing `AsRef<[u8; len]>` and `Borrow<[u8; len]>`.

Introduce a new macro and remove a bunch of other macros. Include
extensive docs but hide the macro from public docs because its not
really for consumers of the library.

The macro requires `$crate::hex` to point to `hex-conservative`.

Note the macro is pretty generic (as in general purpose), `hashes` might
not be the right home for it. Potentially a better place would be in
`hex` itself?
@tcharding tcharding force-pushed the 06-12-impl_bytelike_traits branch from 0ab26a0 to 90b2ac0 Compare November 1, 2024 21:14
@tcharding tcharding marked this pull request as ready for review November 1, 2024 21:15
@tcharding
Copy link
Copy Markdown
Member Author

So instead I tried adding them at the usage sites, and that worked.

Nice! I did everything else you did but did not make this leap.

assert_eq!(display, format!("{}", &outpoint));

let pretty_debug = "OutPoint {\n txid: 0000000000000000000000000000000000000000000000000000000000000000,\n vout: 4294967295,\n}";
let pretty_debug = "OutPoint {\n txid: 0x0000000000000000000000000000000000000000000000000000000000000000,\n vout: 4294967295,\n}";
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.

In 90b2ac0:

Even though this is just debug output, I think it makes the crate look sloppy and we should find a way to avoid it.

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.

Do you mean the change in this patch looks sloppy or that using 0x in pretty debugout put looks sloppy? (I'm guessing the second one). Notice that this is already the current behaviour for Txids, before this PR we had different behaviour for pretty printing Txid and OutPoint::txid - this PR makes it uniform.

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.

I mean using 0x for txids.

Good catch finding the non-uniformity -- but we should get rid of the 0x in other places rather than adding one here.

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.

Can we merge this as is and fix the Txid as follow up? This PR really just uncovers the issue, it doesn't introduce it.

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.

We have #2498 as well.

Copy link
Copy Markdown
Member

@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.

ACK 90b2ac0; successfully ran local tests

@apoelstra apoelstra merged commit 973071f into rust-bitcoin:master Nov 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API break This PR requires a version bump for the next release C-bitcoin PRs modifying the bitcoin crate C-hashes PRs modifying the hashes crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants