-
Notifications
You must be signed in to change notification settings - Fork 549
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
Allow merkle masks to handle empty accounts directly #14585
Allow merkle masks to handle empty accounts directly #14585
Conversation
!ci-build-me |
!ci-nightly-me |
!ci-build-me |
@@ -188,17 +188,6 @@ module Make (Test : Test_intf) = struct | |||
(* verify all hashes to root are same in mask and parent *) | |||
compare_maskable_mask_hashes maskable attached_mask dummy_address ) | |||
|
|||
let%test "mask delegates to parent" = |
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.
Remove invalid test: mask parents should not be changed
Is this actually an invalid test ? Masks parents are sometimes changed/modified.
It is the reason why there is the method Mask.Attached.parent_set_notify
:
Mask.Attached.parent_set_notify mask account ) |
Removing this test means we're breaking the relation parent/child described in specs/merkle_tree.md
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.
@georgeee Can we add this test back? If the dummy account is added before the child mask is attached, it should do as expected, right?
@@ -181,7 +181,16 @@ module Make (Inputs : Inputs_intf.S) = struct | |||
| Some account -> | |||
Some account | |||
| None -> | |||
Base.get (get_parent t) location | |||
let is_empty = | |||
match t.current_location with |
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.
match t.current_location with | |
match (last_filled t) with |
(last_filled t)
should probably be used here ? to get updated location from all the parents.
This would allow to keep the test above to pass.
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'll defer to @nholland94, but IMO we break a bunch of invariants (e.g. merkle paths) if we allow incompatible writes to the parent ledger, and the test is misguided.
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 affects masks behavior: that would break this property of masks, which is quite important IMO:
Whenever a read occurs on a mask, the mask will first attempt to retrieve the node from its internal sparse collection, and if it does not exist there, will forward the read request to its parent.
(text from specs/merkle_tree.md)
If the performance of (last_filled t)
is the concern, it could be called only once in get_batch
and self_merkle_path
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.
Hmm, this is confusing. We should probably update the mask interface to not allow updating parent masks if it breaks the invariants. I'm seeing calls to parent_set_notify
which is to notify child masks about updates in the parent mask?
Re the test, if the dummy account was added to the parent mask before creating the child mask, then it should pass?
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.
We should probably update the mask interface to not allow updating parent masks if it breaks the invariants.
This was my suggestion last week, but I believe consensus was that this will be too big of a change to implement right now.
But in general I agree with this, though supposedly related functionalities are just dead code (the riskiness of a change lies in the fact that it'd require a complicated analysis of the whole codebase to prove it's actually dead, though I'd argue seeing it alive is worse and we'd better throw a runtime error when such things occur).
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.
Ok. created #14631 to track this. We should address this before making any planned changes to this library
df57650
to
344a10d
Compare
e26350e
to
64e75d1
Compare
self_find_or_batch_lookup self_find_location | ||
Base.location_of_account_batch | ||
let location_of_account_batch t = | ||
(* TODO consider handling special case of empty addresses *) |
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.
@mrmr1993 looks like this is needed. self_find_or_batch_lookup
would end up accessing disk for empty accounts otherwise, no?
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.
P.S. this is my TODO which I left when doing rebases
I believe we need it, I will be able to implement it 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.
We can have a follow-up PR for this, 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.
@deepthiskumar I guess we don't have a choice in this function because unlike loading an account by location here we can't tell of an account whether it's a new one or just wasn't loaded from parent.
It might have an implication to performance of transaction processing (I do see some db lookups despite the fact that we preload a lot of stuff). But I think we'll handle it via special-casing unsafe_preload
function, not right here.
P.S. I removed the TODO
a0c92df
to
576bc95
Compare
e8ee28a
to
4a9f96f
Compare
576bc95
to
d530750
Compare
4a9f96f
to
4a490a8
Compare
d530750
to
b3525d3
Compare
4a490a8
to
94cfcd1
Compare
b3525d3
to
5e71099
Compare
Justification: we don't have a choice in this function because unlike loading an account by location here we can't tell of an account whether it's a new one or just wasn't loaded from parent. It might have an implication to performance of transaction processing (I do see some db lookups despite the fact that we preload a lot of stuff). But I think we'll handle it via special-casing unsafe_preload function, not right here.
94cfcd1
to
df631b4
Compare
!ci-build-me |
Includes a bugfix in Merkle_ledger.Database.wide_merkle_path_batch
…k-empty-account-preloading
…ure/sparse-ledger-of-subset-no-mutability
…ture/sparse-ledger-wide-merkle-paths
Replace tables with maps in merkle masks
…e-merkle-paths Use 'wide merkle paths' to optimize `Sparse_ledger.of_ledger_subset_exn`
…subset-no-mutability Avoid ledger copy and mutation in `Sparse_ledger.of_ledger_subset_exn`
This PR builds upon #14571, implementing a similar preloading mechanism for empty accounts to avoid falling back to the database.
Checklist: