-
Notifications
You must be signed in to change notification settings - Fork 14
feat(ffi): add proposal root retrieval #910
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
base: main
Are you sure you want to change the base?
Conversation
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 would have thought that you would just change the code so that propose always returns the hash along with the proposal ID, rather than having to look things up again and dealing with errors.
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 would have thought that you would just change the code so that propose always returns the hash along with the proposal ID, rather than having to look things up again and dealing with errors.
// Get the root hash of the new proposal. | ||
let mut root_hash: Value = match new_proposal.root_hash_sync().map_err(|e| e.to_string())? { | ||
Some(root) => Value::from(root.as_slice()), | ||
None => String::new().into(), |
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.
@rkuris This shouldn't occur in the ethhash case, but it does. Honestly I'd prefer that db.root_hash_sync()
also returns nil in the no hash, but definitely out of scope. However, this must return a root for no data (the failing ethhash test)
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.
Should be addressed in #918
@@ -204,13 +204,19 @@ func kvForTest(i int) KeyValue { | |||
// 1. By calling [Database.Propose] and then [Proposal.Commit]. | |||
// 2. By calling [Database.Update] directly - no proposal storage is needed. | |||
func TestInsert100(t *testing.T) { | |||
type dbView interface { | |||
Get(key []byte) ([]byte, error) |
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.
@aaronbuchwald I think this conflicts with something you're doing, so I can get rid of this or edit if you like
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.
No need to worry about a conflict here, will be easy to fix when we get to it
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.
Rust code is fine, recommended some rewording of comments.
Would be good to get Aaron to look at the go code better than me.
ffi/firewood.h
Outdated
* A `Value` containing {id, root} if creating the proposal succeeded. | ||
* The root will always be 32 bytes, and the id will be non-zero. |
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 had to read this a few times; the second sentence is only true if the proposal succeeds.
* A `Value` containing {id, root} if creating the proposal succeeded. | |
* The root will always be 32 bytes, and the id will be non-zero. | |
* On success, a `Value` containing {len=id, data=hash}. In this case, the | |
* hash will always be 32 bytes, and the id will be non-zero. |
ffi/firewood.h
Outdated
@@ -318,7 +319,8 @@ struct Value fwd_propose_on_db(const struct DatabaseHandle *db, | |||
* | |||
* # Returns | |||
* | |||
* A `Value` containing {id, nil} if creating the proposal succeeded. | |||
* A `Value` containing {id, root} if creating the proposal succeeded. |
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.
same as above
// If the hash is empty, return the empty root hash. | ||
if p.root == nil { | ||
return make([]byte, RootLength), nil | ||
} |
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.
What's the rationale to do this lazily rather than ensure it's populated with the empty root hash if needed?
This may save a memory allocation, but seems that it will likely be simpler if we just guarantee proposals are always fully populated.
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.
There is an issue #918 for this in the ethhash front, but it might be better to enforce this on "normal" firewood as well.
ffi/memory.go
Outdated
} | ||
|
||
// Expected empty case for Rust's `()` | ||
// Ignores the length. | ||
if v.data == nil { | ||
return nil | ||
return nil, uint32(v.len), nil |
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.
What is this case?
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.
ffi/memory.go
Outdated
// extractBytesAndErrorThenFree converts the cgo `Value` payload into either: | ||
// 1. a 32 byte slice, an id and nil error | ||
// 2. a nil byte slice, 0 id, and a non-nil error | ||
// This should only be called when the `Value` is expected to only contain an error or | ||
// an ID and a hash, otherwise the behavior is undefined. | ||
func extractBytesAndErrorThenFree(v *C.struct_Value) ([]byte, uint32, error) { |
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.
This function seems to be a bit overloaded and the comment doesn't quite align with
Line 579 in 0908305
/// - When returning an ID, the length is the ID and the data is null. |
Why do we need to handle each of these cases this way? Is this intended to pass as little data as possible over the FFI boundary?
// TODO: Check proposal root | ||
// Requires #918 | ||
// hash, err := proposal.Root() | ||
// require.NoError(t, err, "%T.Root() after commit", proposal) | ||
// require.Equalf(t, expectedHash, hash, "%T.Root() of empty trie", db) |
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.
Do we need to include this TODO here? If this requires 918, would it make more sense to include the added check in 918?
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.
#918 is an issue, but the code is trivial so we could remove that and fill it in when addressing the issue.
2a69cc4
to
531b32a
Compare
This is needed to enable support of Trie wrapping in geth.