-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update rust bindings to use runtime field count #363
Update rust bindings to use runtime field count #363
Conversation
Would be nice to get a review by @pawanjay176 et al. here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good, minor nits
Co-authored-by: Pawan Dhananjay <pawandhananjay@gmail.com>
Thanks @pawanjay176. All should be fixed now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks so much for this.
Might need to run cargo fmt --all
once before merging
Just ran, no changes. So all good I think. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks!
Hmm. I'm not sure of the best way to fix this serde issue. How can we pass @DaniPopes any ideas? |
I don't think it's possible to do this, serde functions are just supposed to do the serialization / deserialization, not validation. Since the size is no longer known based solely on the |
@Rjected good idea! I think that's a decent (and simple) approach. Since the interface functions check blob lengths, it should be safe to use. The last commit implements this change. @asn-d6, @pawanjay176: thoughts? |
bindings/rust/src/bindings/mod.rs
Outdated
@@ -70,6 +42,10 @@ pub struct KZGProof { | |||
bytes: [u8; BYTES_PER_PROOF], | |||
} | |||
|
|||
pub struct Blob { | |||
bytes: Vec<u8>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a concern about these Blob
types defined here and also in all the other bindings PRs.
The problem is that we need to manually length-check them everytime they are used. This manual length check was not done in the past because a Blob was always a blob, whereas now with the variable length, it's not necessary that a byte vector is a blob.
I feel like this use of the Blob
type when you don't actually know that it's a blob (until you validate it with a length check) is a dangerous pattern. Maybe in these PRs we have performed all the length checks required, but I think it sets us in a bad state for future changes because a dev could reasonably think that an input Blob is a blob and forget to do the length check.
This also is an anti-pattern in our code base where we have established the (IMO good) Bytes32
/Bytes48
convention for pre-validation objects. Because now this new Blob
type is pre-validated and it's still called Blob.
I think The Right Thing would have been to introduce a new Bytes type that can be turned into a Blob if it's valid (i.e. its size is right). Same way that a Bytes32
can be turned into a KZGCommitment
if it's valid.
(moved this from TG here so that it doesn't get lost)
Based on @asn-d6's comment, I've made some more changes to this PR. Notably, I've replaced |
@asn-d6 Agree that doing the length check repeatedly isn't the best. Basically my changes make it such that we export 2 separate modules from the rust bindings: By doing this, for each preset module:
I haven't fully cleaned up my commits (still needs some work in terms of error handling), but just trying to get feedback on the idea. |
Hey @pawanjay176 thanks. I like this idea. Wasn't a fan of this in Lighthouse, but it makes sense here. I had two thoughts while reviewing those changes:
You are welcome to push your changes to this PR if you can. If not, we'll give you access. |
I have some concerns with both the current PR and making
Using a generic causes a very poor UX/DX, for example in reth this would require us to change our blob type to the following, and handle each variant separately everywhere: pub enum Blob {
Mainnet(c_kzg::mainnet::Kzg::Blob),
Minimal(c_kzg::minimal::Kzg::Blob),
} Without using an enum, the only other way to consume the To properly implement the unvalidated / validated type pattern, the validated pub struct Blob(bytes::Bytes); The unvalidated type can be anything, either a new type that wraps As long as all constructors for I also do not think the following type of API misuse is a large concern:
|
@Rjected Thanks a lot for the feedback. I was a bit concerned about the API misuse that you described:
However, agree with your point now. I overestimated the requirement of providing fewer checks at runtime at the expense of cleaner end user api. |
I've extended @pawanjay176's proposal to include types that would fit the bill for this use case PR jtraglia#5 |
I don't have a strong opinion on the direction of the Rust bindings. But if we end up going this route, I think it would be best to create a new PR in |
Ok so I talked with @pawanjay176 more about this. I think what we're looking for is more flexibility in the interface between client codebase and rust bindings. And more strictness/safety between rust bindings and C-code. So we thought about the following pattern (edging closer to #363 (comment) just obfuscating some of it from the end user, and making the public interface maximally flexible):
Basically we wouldn't support creating an intermediate Reasons for this from LH perspective:
Questions for Reth (@Rjected ):
A more fleshed out example:
@pawanjay176 is going to work on an implementation tomorrow |
This PR updates the Rust bindings to work with runtime field counts.