Skip to content
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

Conversation

mrmr1993
Copy link
Member

This PR builds upon #14587, using the already-computed hashes for accounts and merkle paths instead of recomputing them when creating Sparse_ledger.ts.

Checklist:

  • Dependency versions are unchanged
    • Notify Velocity team if dependencies must change in CI
  • Modified the current draft of release notes with details on what is completed or incomplete within this project
  • Document code purpose, how to use it
    • Mention expected invariants, implicit constraints
  • Tests were added for the new behavior
    • Document test purpose, significance of failures
    • Test names should reflect their purpose
  • All tests pass (CI will check this if you didn't)
  • Serialized types are in stable-versioned modules
  • Does this close issues? List them

@mrmr1993
Copy link
Member Author

!ci-build-me

@mrmr1993
Copy link
Member Author

!ci-nightly-me

@mrmr1993
Copy link
Member Author

!ci-build-me

let extract_hashes_exn ~direction = function
| sibling :: self :: rest ->
let el =
match direction with
Copy link
Member

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.

@georgeee georgeee force-pushed the feature/sparse-ledger-of-subset-no-mutability branch 2 times, most recently from e5e6099 to 2120e7c Compare November 28, 2023 18:28
@georgeee georgeee force-pushed the feature/sparse-ledger-wide-merkle-paths branch from 5bf9cbe to 21cec0d Compare November 28, 2023 18:31
@georgeee georgeee force-pushed the feature/sparse-ledger-of-subset-no-mutability branch from 2120e7c to 44c86cc Compare November 28, 2023 20:15
@georgeee georgeee force-pushed the feature/sparse-ledger-wide-merkle-paths branch from 21cec0d to 89b8f66 Compare November 28, 2023 20:26
@georgeee georgeee force-pushed the feature/sparse-ledger-of-subset-no-mutability branch from 44c86cc to a8b5b8e Compare November 28, 2023 20:32
@georgeee georgeee force-pushed the feature/sparse-ledger-wide-merkle-paths branch from 89b8f66 to 665b5f8 Compare November 28, 2023 20:35
@georgeee georgeee force-pushed the feature/sparse-ledger-wide-merkle-paths branch 2 times, most recently from 688501b to 99ff560 Compare November 29, 2023 15:43
@@ -173,6 +184,80 @@ end = struct
; indexes = (account_id, index) :: t.indexes
}

let add_wide_path_unsafe tree0 path0 account =
Copy link
Contributor

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)  

Copy link
Member

@nholland94 nholland94 left a 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
Copy link
Member

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.

Copy link
Contributor

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 ->
Copy link
Member

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
Copy link
Member

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.

@ghost-not-in-the-shell
Copy link
Contributor

!ci-build-me

@ghost-not-in-the-shell
Copy link
Contributor

!ci-nightly-me

@georgeee
Copy link
Member

refactor add_wide_path

@ghost-not-in-the-shell this commit reverses version that computes hashes in the add_wide_path_unsafe, one of the purposes of this PR is to avoid it. So I want it to be reworked

@ghost-not-in-the-shell
Copy link
Contributor

!ci-build-me

@ghost-not-in-the-shell
Copy link
Contributor

!ci-nightly-me

@georgeee georgeee force-pushed the feature/sparse-ledger-of-subset-no-mutability branch from c86eced to 9c89cca Compare December 1, 2023 20:57
@georgeee georgeee force-pushed the feature/sparse-ledger-wide-merkle-paths branch from dfa63d5 to d6e6137 Compare December 1, 2023 21:06
@ghost-not-in-the-shell
Copy link
Contributor

!ci-build-me

@ghost-not-in-the-shell
Copy link
Contributor

!ci-nightly-me

@deepthiskumar deepthiskumar merged commit 5364a0f into feature/sparse-ledger-of-subset-no-mutability Dec 5, 2023
1 check passed
@deepthiskumar deepthiskumar deleted the feature/sparse-ledger-wide-merkle-paths branch December 5, 2023 06:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants