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

Sai/snark ledger query serialized #16000

Merged
merged 4 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 81 additions & 56 deletions src/lib/mina_graphql/mina_graphql.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2192,61 +2192,85 @@ module Queries = struct
let (module S) = Mina_lib.work_selection_method mina in
S.pending_work_statements ~snark_pool ~fee_opt snark_job_state )

let snarked_ledger_account_membership =
io_field "snarkedLedgerAccountMembership"
~doc:
"obtain a membership proof for an account in the snarked ledger along \
with the account's balance, timing information, and nonce"
~args:
Arg.
[ arg "accountInfos" ~doc:"Token id of the account to check"
~typ:(non_null (list (non_null Types.Input.AccountInfo.arg_typ)))
; arg "stateHash" ~doc:"Hash of the snarked ledger to check"
~typ:(non_null string)
]
~typ:(non_null (list (non_null Types.SnarkedLedgerMembership.obj)))
~resolve:(fun { ctx = mina; _ } () account_infos state_hash ->
let open Deferred.Let_syntax in
let state_hash = State_hash.of_base58_check_exn state_hash in
let%bind ledger =
Mina_lib.get_snarked_ledger_full mina (Some state_hash)
in
let ledger =
match ledger with
| Ok ledger ->
ledger
| Error err ->
raise
(Failure
("Failed to get snarked ledger: " ^ Error.to_string_hum err)
)
in
let%map memberships =
Deferred.List.map account_infos ~f:(fun (pk, token) ->
let token = Option.value ~default:Token_id.default token in
let account_id = Account_id.create pk token in
let location = Ledger.location_of_account ledger account_id in
match location with
| None ->
raise (Failure "Account not found in snarked ledger")
| Some location -> (
let account = Ledger.get ledger location in
match account with
| None ->
raise (Failure "Account not found in snarked ledger")
| Some account ->
let account_balance = account.balance in
let timing_info = account.timing in
let nonce = account.nonce in
let proof = Ledger.merkle_path ledger location in
{ Types.SnarkedLedgerMembership.account_balance
; timing_info
; nonce
; proof
}
|> Deferred.return ) )
in
Ok memberships )
module SnarkedLedgerMembership = struct
let resolve_membership :
mapper:(Ledger.path -> Account.t -> 'a)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: it would be more natural/readable to return a Ledger.path * Account.t and then map over the results in the individual resolvers.

-> Mina_lib.t resolve_info
-> unit
-> (Account.key * Token_id.t option) list
-> string
-> ('a list, string) result Io.t =
fun ~mapper { ctx = mina; _ } () account_infos state_hash ->
let open Deferred.Let_syntax in
let state_hash = State_hash.of_base58_check_exn state_hash in
let%bind ledger =
Mina_lib.get_snarked_ledger_full mina (Some state_hash)
in
let ledger =
match ledger with
| Ok ledger ->
ledger
| Error err ->
raise
(Failure
("Failed to get snarked ledger: " ^ Error.to_string_hum err) )
in
let%map memberships =
Deferred.List.map account_infos ~f:(fun (pk, token) ->
let token = Option.value ~default:Token_id.default token in
let account_id = Account_id.create pk token in
let location = Ledger.location_of_account ledger account_id in
match location with
| None ->
raise (Failure "Account not found in snarked ledger")
| Some location -> (
let account = Ledger.get ledger location in
match account with
| None ->
raise (Failure "Account not found in snarked ledger")
| Some account ->
let proof = Ledger.merkle_path ledger location in
mapper proof account |> Deferred.return ) )
in
Ok memberships

let snarked_ledger_account_membership =
io_field "snarkedLedgerAccountMembership"
~doc:
"obtain a membership proof for an account in the snarked ledger \
along with the account's balance, timing information, and nonce"
~args:
Arg.
[ arg "accountInfos" ~doc:"Token id of the account to check"
~typ:
(non_null (list (non_null Types.Input.AccountInfo.arg_typ)))
; arg "stateHash" ~doc:"Hash of the snarked ledger to check"
~typ:(non_null string)
]
~typ:(non_null (list (non_null Types.SnarkedLedgerMembership.obj)))
~resolve:
(resolve_membership ~mapper:Types.SnarkedLedgerMembership.of_account)

let encoded_snarked_ledger_account_membership =
io_field "encodedSnarkedLedgerAccountMembership"
~doc:
"obtain a membership proof for an account in the snarked ledger \
along with the accounts full information encoded as base64 binable \
type"
~args:
Arg.
[ arg "accountInfos" ~doc:"Token id of the account to check"
~typ:
(non_null (list (non_null Types.Input.AccountInfo.arg_typ)))
; arg "stateHash" ~doc:"Hash of the snarked ledger to check"
~typ:(non_null string)
]
~typ:
(non_null (list (non_null Types.SnarkedLedgerMembership.encoded_obj)))
~resolve:
(resolve_membership
~mapper:Types.SnarkedLedgerMembership.of_encoded_account )
end

let genesis_constants =
field "genesisConstants"
Expand Down Expand Up @@ -2733,7 +2757,8 @@ module Queries = struct
; trust_status_all
; snark_pool
; pending_snark_work
; snarked_ledger_account_membership
; SnarkedLedgerMembership.snarked_ledger_account_membership
; SnarkedLedgerMembership.encoded_snarked_ledger_account_membership
; genesis_constants
; time_offset
; validate_payment
Expand Down
31 changes: 31 additions & 0 deletions src/lib/mina_graphql/types.ml
Original file line number Diff line number Diff line change
Expand Up @@ -772,13 +772,44 @@ let snarked_ledger_state :
] )

module SnarkedLedgerMembership = struct
type encoded_account = { account : string; proof : Ledger.path }

let encoded_obj =
obj "EncodedAccount" ~fields:(fun _ ->
[ field "account"
~args:Arg.[]
~doc:"Base64 encoded account as binable wire type"
~typ:(non_null string)
~resolve:(fun _ { account; _ } -> account)
; field "merklePath"
~args:Arg.[]
~doc:"Membership proof in the snarked ledger"
~typ:(non_null (list (non_null merkle_path_element)))
~resolve:(fun _ { proof; _ } -> proof)
] )

let of_encoded_account (proof : Ledger.path) (account : Account.t) :
encoded_account =
let account =
Binable.to_string (module Account.Binable_arg.Stable.Latest) account
|> Base64.encode_exn
in
{ account; proof }

type t =
{ account_balance : Currency.Balance.t
; timing_info : Account_timing.t
; nonce : Account.Nonce.t
; proof : Ledger.path
}

let of_account (proof : Ledger.path) (account : Account.t) : t =
{ account_balance = account.balance
; timing_info = account.timing
; nonce = account.nonce
; proof
}

let obj =
obj "MembershipInfo" ~fields:(fun _ ->
[ field "accountBalance"
Expand Down