Conversation
|
Overall 6c7e143af7b05ff4176530d583a21592be0c2f60 looks good. The duplication of the merkle root code I don't like (but I don't think it's necessary ... in fact I suspect we could pull it into the We should have some public type aliases for HMAC-SHA256 and HMAC-SHA512 since those are the overwhelmingly most common forms of HMAC. As for "hash newtypes should not be generic hash types" I am leaning strongly into implementing this by adding visibility specifiers to the |
|
Leave it with me, I'm going to go for the least tricky solution that does exactly what we want.
Will look into this. |
lol, double lol - look at the diff required to get this functionality, 5 changed lines. diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs
index 1a660fb8..98074e10 100644
--- a/bitcoin/src/blockdata/block.rs
+++ b/bitcoin/src/blockdata/block.rs
@@ -26,7 +26,7 @@ hashes::hash_newtype! {
/// A bitcoin block hash.
pub struct BlockHash(sha256d);
/// A hash of the Merkle tree branch or root for transactions.
- pub struct TxMerkleNode(sha256d);
+ pub struct TxMerkleNode(pub(crate) sha256d);
/// A hash corresponding to the Merkle tree root for witness data.
pub struct WitnessMerkleNode(sha256d);
/// A hash corresponding to the witness structure commitment in the coinbase transaction.
diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs
index 4916e43a..2834be04 100644
--- a/bitcoin/src/blockdata/transaction.rs
+++ b/bitcoin/src/blockdata/transaction.rs
@@ -44,10 +44,10 @@ hashes::hash_newtype! {
/// versions of the Bitcoin Core software itself, this and other [`sha256d::Hash`] types, are
/// serialized in reverse byte order when converted to a hex string via [`std::fmt::Display`]
/// trait operations. See [`hashes::Hash::DISPLAY_BACKWARD`] for more details.
- pub struct Txid(sha256d);
+ pub struct Txid(pub(crate) sha256d);
/// A bitcoin witness transaction ID.
- pub struct Wtxid(sha256d);
+ pub struct Wtxid(pub(crate) sha256d);
}
impl_hashencode!(Txid);
impl_hashencode!(Wtxid);
diff --git a/hashes/src/macros.rs b/hashes/src/macros.rs
index 45b53ae1..6a32c935 100644
--- a/hashes/src/macros.rs
+++ b/hashes/src/macros.rs
@@ -128,11 +128,11 @@ macro_rules! hash_newtype {
/// Constructs a new engine.
#[inline]
- pub fn engine() -> $hash::Engine { $hash::Hash::engine() }
+ $field_vis fn engine() -> $hash::Engine { $hash::Hash::engine() }
/// Produces a hash froam the current state of a given engine.
#[inline]
- pub fn from_engine(e: $hash::Engine) -> Self { Self($hash::Hash::from_engine(e)) }
+ $field_vis fn from_engine(e: $hash::Engine) -> Self { Self($hash::Hash::from_engine(e)) }
/// Copies a byte slice into a hash object.
#[inline] |
I've used public functions in the /// Returns an engine for computing `HMAC-SHA256`.
///
/// Equivalent to `hmac::Engine::<sha256::Engine>::new(key)`.
pub fn new_engine_sha256(key: &[u8]) -> Engine<sha256::Engine> {
Engine::<sha256::Engine>::new(key)
}
/// Returns an engine for computing `HMAC-SHA512`.
///
/// Equivalent to `hmac::Engine::<sha512::Engine>::new(key)`.
pub fn new_engine_sha512(key: &[u8]) -> Engine<sha512::Engine> {
Engine::<sha512::Engine>::new(key)
} |
I agree its ugly, before we fix it we should ask how much change we are willing to accept to de-duplicate something that is two exact copies and likely never changes? AFIACT there is no way of doing this generically without an invasive change, hence the question. Said another way, there is no way of going from a generic type (we only have The quick obvious thing is to use a macro but I don't know if its possible or the implications of calling a macro recursively. |
f8c33e0 to
5f57240
Compare
|
This isn't going to pass CI because it has a patched manifest to use rust-bitcoin/hex-conservative#90 In case it gets past you, this PR is hot as f**k. Check out the Massive props @apoelstra for sticking to your guns and refusing to accept the split out of |
I'll play with it. Fine for now if we have to duplicate the code. But I think/hope we can somehow be generic over the engine.
I'd rather add a dummy trait before I added a macro. (Or a new |
|
Well that was pretty easy with a fresh set of eyes, I just threw this into the /// Trait used for types that can be hashed into a merkle tree.
pub trait Hash {
/// Constructs a new [`sha256d`] hash engine.
fn engine() -> sha256d::Engine { sha256d::Engine::new() }
/// Produces a hash froam the current state of a given engine.
fn from_engine(e: sha256d::Engine) -> Self;
}
impl Hash for Txid {
fn from_engine(e: sha256d::Engine) -> Self { Self::from_engine(e) }
}
impl Hash for Wtxid {
fn from_engine(e: sha256d::Engine) -> Self { Self::from_engine(e) }
}And changed the trait bounds on all the functions to Wallah, the original |
0a10c43 to
4622bf8
Compare
|
I'm happy with this now, I'll just leave it sitting here until the I had an idea - although the PR title is |
d187b12 to
442239d
Compare
Yes, pretty common but it still seems uncommon enough that it's okay for users to need to import a trait to do it. But agreed, just like everything we should have inherents for this.
Yeah :/ agreed it may be strictly better to have a marker trait, but I continue to think it's not worth it. I think siphash is the only non-cryptographic hash in this crate (other than sha1 which needs to be used in cryptographic contexts for legacy/compatibility reasons, even though I would definitely not recommend its use as a crypto hash).
Yeah, exactly. I'd like to have a
Yeah :( earlier in this thread I thought there was a way with "trigger traits" that we could do this without macros. It turns out that you can use these to implement inherent methods on
Yeah, great points. Need to think about what our Merkle tree computation function should look like then.. unfortunately we need to resolve this as step 1 of this project (well, maybe step 2, after just splitting |
|
I think we should open a new PR since github has started hiding comments on this one. |
|
I also think that "new PR" should be one that just splits up |
|
I think we can provide generic merkle tree over non-wrapped hashes (maybe in |
|
I think you're right. That's the approach I'd try first. |
|
Thanks for the input fellas, just wanted to say that I read everything (multiple times) but the PRs that fell out today may not seem like I did. There are six hundred things going on, not exactly sure how to pull everything together. (I did read and grok you list in #2770 (comment) @apoelstra, but I went a different way - no disrespect intended). |
|
There has been so much discussion on the I believe the correct observation from @Kixunil that a past state did not correctly tie the Hmac to the hash engine was correct (we used to only have the (Note that this PR should be re-done on top of what ever is decided for the merkle tree stuff.) |
There are a few niggling problems with the current `hashes` API that we would like to improve: - Its not that discoverable - It is annoying to have to import the `Hash` trait all the time. - New hash types (created with `hash_newtype`) are general purpose but we'd like to hide this from users of `rust-bitcoin`. - The API of the `hmac` module is different to the other hash types. - The `hash_newtype` and `sha256t_hash_newtype` macros are a bit hard to read and work on This re-write of the `hashes` API is an attempt to address all these issues. Note that the public API surface of `hashes` does not change all that much.
It needs to be generic over the hash type. If it is only generic over If it's now generic over both |
If you can get rid of it then I'll be happy to see how that was achieved, as far as I can tell you are going to hit all the associated const problems I've been hitting - its a language limitation. But by all means please do try to solve it if you think I've missed something.
So we've been having API design discussions, with you giving me directives of things to explore, and ways you want it done, and you never looked at the latest state. That is pretty frustrating man. Even when I repeatedly said that we are hitting language limitations and that associated const don't "just work" as one would expect. There are so many problems with |
It has to be. If we try to do tons of things at once, in a PR that makes compromises due to language limitations, then it will just be stuck forever in iterations of "why did you make this ugly-looking decision" and "it was a language limitation, I don't remember the details because there were tons of them". Compare to #2864 where we were trying to do a single thing, there was disagreement about whether the language would let us do the thing I wanted, and I was able to try it without my attempt requiring 1000 other changes just to get the code to compile. And then it turned out we'd been talking past each other about the There's not much I can say about comments I made "when I hadn't even looked at the latest state" because Github is now hiding most of the history of this thread, so I can't see the order of specific pushes and comments. But I apologize if I was complaining about an outdated state. |
|
Oh, I see. I found a branch where I was hacking on your existing state -- I immediately found that I wanted to split the But I can't relitigate this here because we're talking about too many things at once, in an unreadably-long thread implicitly contextualized by the changing state of a 4000-line diff. The piecemeal approach lets us have digestible conversations and make progress. |
|
Righto, good points about the conversation difficulty. I guess we just chalk this whole thread and the development associated with it as learning. FTR I'm not exactly sure of the target we are aiming for. |
The issues we have with this right now are:
Where we can definitely unambiguously start are:
Where we are hitting difficulty is trying to do stuff generically over general hashes which might have arbitrary digest sizes. I think this will be much more tractable if we do the "easy" stuff first. |
|
Thanks for writing that up man, appreciate the effort. That is something concrete to work towards. |
|
At the risk of sounding like a whinging bitch, I achieved all these goals that you wrote up with this PR, I added regression tests so that it was plausibly reliable to do a massive patch merge, I stated my intentions the whole way along, and I only ever used |
|
FTR I also attempted some gradual approach to splitting the trait before but got tangled in rebases & stuff. I think to introduce it gradually we need to first bound things by |
|
@tcharding I hear you, and I apologize for how much stress and apparent lack of foward progress there was on this. But. This PR has consistently been a single commit that does multiple changes that cannot be tweaked independently and (almost?) none of which are optimal by themselves. And when I went to change things, I would find other issues (the abuse of Adding to this, there were multiple parallel conversations that Github could not keep track of (and several serial conversations -- e.g. the dead-end about trigger traits, the back-and-forth about whether we wanted zero one or two |
|
Thanks man. I'm still not convinced that we are going to be able to tease it apart gradually but I'll give it a shot. I have a feeling some of the changes are not going to be clear steps forward. If we argue over things like #2860 its going to make this more painful than it needs to be. |
Thanks @Kixunil but while you've been away I have literally attempted cutting this crate up and re-doing it so many times I cannot remember. I have hit so many dead ends that have gotten to a stage where I am not taking any suggestions unless they are backed up by patches that I can see actually work. Sorry about that. |
|
No problem! I wanted to do the exact thing I suggested here a few months before but IIRC I also hit some limitations. I know first hand this stuff is very messy. What might help is what I did: I commented-out some APIs to make sure I correctly modify the rest of the code (so I let the compiler guide me). It mostly worked but still took quite some time. |
8bd5c64 api changes for "drop GeneralHash from wrapped hash types" (Andrew Poelstra) 9126597 hashes: stop exposing engine/from_engine and general hashing methods in hash_newtype (Andrew Poelstra) 8c4899f bitcoin: remove all direct use of hashing/engines in unit tests (Andrew Poelstra) b8d85a1 bitcoin: remove all use of engine/from_engine on opaque hash types (Andrew Poelstra) 0aa539f hashes: remove engine/from_engine from embedded test (Andrew Poelstra) 46dad84 api changes for split between Hash/GeneralHash (Andrew Poelstra) 73dcc79 hashes: split Hash trait into two (Andrew Poelstra) 1fe4c63 hashes: remove unused Hash import in embedded test (Andrew Poelstra) Pull request description: I'm not thrilled with these names. Personally I would prefer having `ByteArrayWrapper` (for non-general hashes) and `Hash` (for general hashes). But using `Hash` and `GeneralHash` greatly minimizes the diff because most of our use of the `Hash` trait was only for non-general stuff. Maybe that tradeoff will change as we move stuff to inherents? I hope to do that in the next PR (or maybe the one after that, since I still have some "drop `GeneralHash` work to do for tagged hashes). And after that the hashing API should be "clean" enough that we can figure out HashEngine, possibly even folding GeneralHash into it. But that's the part of #2770 that we didn't finish nailing down so I'm not sure. But other than naming, I like this PR. I think, if you approve of this PR except the naming, it would be best to ACK it and then we can do a followup rename-only PR, rather than dealing with the review pain of mass-renaming in rebases. ACKs for top commit: tcharding: ACK 8bd5c64 Kixunil: ACK 8bd5c64 Tree-SHA512: 3754f0f7ffae487e9f826fb6ecc48a6d9f606204a981bc56b98e118813a881b905e38a3cf5d6c3b3142aa0876ce2efc2ab75ec5a2f59fcc36fd86d148ab253bb
Re-write the
hashesAPI for fun and profit.Please note, this removes the ability to display tagged hashes backward.
Resolves the following issues:
Close: #1481
Close: #1552
Close: #1689
Close: #2197
Close: #2377
Close: #2665
Close: #2811
TODO
QUESTIONSinhashes/examples/*.rs