-
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
Use 'wide merkle paths' to optimize Sparse_ledger.of_ledger_subset_exn
#14594
Use 'wide merkle paths' to optimize Sparse_ledger.of_ledger_subset_exn
#14594
Conversation
!ci-build-me |
!ci-nightly-me |
!ci-build-me |
d2f3c8d
to
dbfe750
Compare
bd19650
to
9955562
Compare
src/lib/merkle_ledger/database.ml
Outdated
let extract_hashes_exn ~direction = function | ||
| sibling :: self :: rest -> | ||
let el = | ||
match direction 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.
Here the bug was fixed, version before refactoring had a different order in tuple.
Arguably, refactoring made the concern easier to identify.
e5e6099
to
2120e7c
Compare
5bf9cbe
to
21cec0d
Compare
2120e7c
to
44c86cc
Compare
21cec0d
to
89b8f66
Compare
44c86cc
to
a8b5b8e
Compare
89b8f66
to
665b5f8
Compare
688501b
to
99ff560
Compare
@@ -173,6 +184,80 @@ end = struct | |||
; indexes = (account_id, index) :: t.indexes | |||
} | |||
|
|||
let add_wide_path_unsafe tree0 path0 account = |
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 propose that we stick with the original control flow because it's easier to understand plus the original implementation has some assertion to check the correctness of the merkle path. If you want to skip the assertions, you could also easily do that:
let add_wide_path depth0 tree0 path0 account =
let rec build_tree h height p =
match p with
| `Left (h_l, h_r) :: path ->
let l = build_tree h_l (height - 1) path in
Tree.Node (h, l, Hash h_r)
| `Right (h_l, h_r) :: path ->
let r = build_tree h_r (height - 1) path in
Node (h, Hash h_l, r)
| [] ->
assert (height = -1) ;
Account account
in
let rec union height tree path =
match (tree, path) with
| Tree.Hash h, path ->
let t = build_tree h height path in
[%test_result: Hash.t]
~message:
"Hashes in union are not equal, something is wrong with your \
ledger"
~expect:h (hash t) ;
t
| Node (h, l, r), `Left _ :: path ->
let l = union (height - 1) l path in
Node (h, l, r)
| Node (h, l, r), `Right _ :: path ->
let r = union (height - 1) r path in
Node (h, l, r)
| Node _, [] ->
failwith "Path too short"
| Account _, _ :: _ ->
failwith "Path too long"
| Account a, [] ->
assert (Account.equal a account) ;
tree
in
union (depth0 - 1) tree0 (List.rev path0)
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 overall, but had a couple of nits and a question.
path_batch_impl ~expand_query:ident | ||
~compute_path:(fun all_hashes loc_and_dir_list -> | ||
let len = List.length loc_and_dir_list in | ||
let sibling_hashes, rest_hashes = List.split_n all_hashes len in |
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.
The logic for splitting hashes during the fold is shared across both specializations of the compute_path function. It would be better to lift this part of the logic up into the path_batch_impl function.
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 oppose to do that. The splitting is actually different for merkle_path
and wide_merkle_path
. And the splitting of hashes goes together with how we compute the path. For merkle_path
we split once and then combine the result with directions using List.map2_exn
. For wide_merkle_path
we split twice and then combine the result with directions using List.map3_exn
. If we separate those 2 processes, then we would essentially do some unnecessary packing + unpacking for tuples of hashes and directions.
|
||
let add_wide_path_unsafe (t : t) path account_id account = | ||
let index = | ||
List.foldi path ~init:0 ~f:(fun i acc x -> |
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 surprised me a bit. I would think this would work if the path was in reverse order only, but I think the path is traversing from the root down to the leaf, in which case this seems wrong to me at first glance.
in | ||
Debug_assert.debug_assert (fun () -> | ||
[%test_eq: Ledger_hash.t] | ||
(Ledger.merkle_root oledger) | ||
((merkle_root sl :> Random_oracle.Digest.t) |> Ledger_hash.of_hash) ) ; | ||
sl | ||
|
||
let of_ledger_subset_exn = | ||
of_ledger_subset_exn_impl ~path_query:Ledger.wide_merkle_path_batch |
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.
Why do we have a separate impl helper for this function? It seems we only call it in this one location.
!ci-build-me |
!ci-nightly-me |
@ghost-not-in-the-shell this commit reverses version that computes hashes in the |
!ci-build-me |
!ci-nightly-me |
c86eced
to
9c89cca
Compare
Includes a bugfix in Merkle_ledger.Database.wide_merkle_path_batch
dfa63d5
to
d6e6137
Compare
!ci-build-me |
!ci-nightly-me |
…ture/sparse-ledger-wide-merkle-paths
Replace tables with maps in merkle masks
5364a0f
into
feature/sparse-ledger-of-subset-no-mutability
This PR builds upon #14587, using the already-computed hashes for accounts and merkle paths instead of recomputing them when creating
Sparse_ledger.t
s.Checklist: