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

Height input to block query #7592

Merged
merged 3 commits into from
Jan 21, 2021
Merged
Changes from 1 commit
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
114 changes: 82 additions & 32 deletions src/lib/mina_graphql/mina_graphql.ml
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,19 @@ let result_of_or_error ?error v =
| Some error ->
sprintf "%s (%s)" error str_error )

let result_field_no_inputs ~resolve =
Schema.io_field ~resolve:(fun resolve_info src ->
Deferred.return @@ resolve resolve_info src )

(* one input *)
let result_field ~resolve =
Schema.io_field ~resolve:(fun resolve_info src inputs ->
Deferred.return @@ resolve resolve_info src inputs )

let result_field_no_inputs ~resolve =
Schema.io_field ~resolve:(fun resolve_info src ->
Deferred.return @@ resolve resolve_info src )
(* two inputs *)
let result_field2 ~resolve =
Schema.io_field ~resolve:(fun resolve_info src input1 input2 ->
Deferred.return @@ resolve resolve_info src input1 input2 )

module Doc = struct
let date ?(extra = "") s =
Expand Down Expand Up @@ -2870,41 +2876,85 @@ module Queries = struct
List.map best_chain ~f:(block_of_breadcrumb coda) )

let block =
result_field "block"
result_field2 "block"
~doc:
"Retrieve a block with the given state hash, if contained in the \
transition frontier."
"Retrieve a block with the given state hash or height, if contained \
in the transition frontier."
~typ:(non_null Types.block)
~args:
Arg.
[ arg "stateHash" ~doc:"The state hash of the desired block"
~typ:string ]
~typ:string
; arg "height" ~doc:"The height of the desired block" ~typ:int ]
~resolve:
(fun {ctx= coda; _} () (state_hash_base58_opt : string option) ->
let open Result.Let_syntax in
let%bind state_hash_base58 =
state_hash_base58_opt
|> Result.of_option ~error:"Must provide a state hash"
in
let transition_frontier_pipe = Mina_lib.transition_frontier coda in
let%bind transition_frontier =
Pipe_lib.Broadcast_pipe.Reader.peek transition_frontier_pipe
|> Result.of_option ~error:"Could not obtain transition frontier"
in
let%bind state_hash =
State_hash.of_base58_check state_hash_base58
|> Result.map_error ~f:Error.to_string_hum
in
let%map breadcrumb =
Transition_frontier.find transition_frontier state_hash
|> Result.of_option
~error:
(sprintf
"Breadcrumb for state hash %s not found in transition \
frontier"
state_hash_base58)
in
block_of_breadcrumb coda breadcrumb )
(fun {ctx= coda; _} () (state_hash_base58_opt : string option)
(height_opt : int option) ->
let have_state_hash = Option.is_some state_hash_base58_opt in
let have_height = Option.is_some height_opt in
Copy link
Member

Choose a reason for hiding this comment

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

nit: I think this function would be cleaner using a pattern match on (state_hash_opt, height_opt), then you won't need the value_exn later.

As written, it looks correct to me. But I'm worried that future edits to this function could introduce crashes accidentally when we're relying on the value_exns.

But I won't block the PR on it -- if you do want to change it, let me know and I'll look at it again

if Bool.equal have_state_hash have_height then
Error "Must provide exactly one of state hash, height"
else
let open Result.Let_syntax in
let transition_frontier_pipe = Mina_lib.transition_frontier coda in
let%bind transition_frontier =
Pipe_lib.Broadcast_pipe.Reader.peek transition_frontier_pipe
|> Result.of_option ~error:"Could not obtain transition frontier"
in
let block_from_state_hash state_hash state_hash_base58 =
let%map breadcrumb =
Transition_frontier.find transition_frontier state_hash
|> Result.of_option
~error:
(sprintf
"Breadcrumb for state hash %s not found in transition \
frontier"
state_hash_base58)
in
block_of_breadcrumb coda breadcrumb
in
let block_from_height height =
let height_uint32 =
(* GraphQL int is signed 32-bit
empirically, conversion does not raise even if
- the number is negative
- the number is not representable using 32 bits
*)
Unsigned.UInt32.of_int height
in
let breadcrumbs =
Transition_frontier.all_breadcrumbs transition_frontier
in
let%map desired_breadcrumb =
List.find breadcrumbs ~f:(fun bc ->
let validated_transition =
Transition_frontier.Breadcrumb.validated_transition bc
in
let block_height =
Mina_transition.External_transition.Validated
.blockchain_length validated_transition
in
Unsigned.UInt32.equal block_height height_uint32 )
|> Result.of_option
~error:
(sprintf
"Could not find breadcrumb in transition frontier \
with height %d"
height)
in
block_of_breadcrumb coda desired_breadcrumb
in
if have_state_hash then
let state_hash_base58 = Option.value_exn state_hash_base58_opt in
let%bind state_hash =
State_hash.of_base58_check state_hash_base58
|> Result.map_error ~f:Error.to_string_hum
in
block_from_state_hash state_hash state_hash_base58
else if have_height then
let height = Option.value_exn height_opt in
block_from_height height
else (* unreachable *)
Error "internal error" )

let initial_peers =
field "initialPeers"
Expand Down