diff --git a/CHANGES.rst b/CHANGES.rst index 6ebf7c9da3425adf34ee003854ac5e39a6eaac12..4399dd64e4e31ae2e26f268cc8c8493c2ce57fd5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -249,6 +249,13 @@ Smart Rollup node - Support ``remote`` signer scheme and check remote signer available on startup. (MR :gl:`!16651`) +- Add query parameter ``outbox_level`` for RPCs + ``/local/outbox/pending/executable`` and + ``/local/outbox/pending/unexecutable``. (MR :gl:`!16831`) + +- Add a new RPC RPC ``/local/outbox/pending`` to fetch all known outbox messages + with their status. (MR :gl:`!16831`) + Smart Rollup WASM Debugger -------------------------- diff --git a/src/lib_smart_rollup/rollup_node_services.ml b/src/lib_smart_rollup/rollup_node_services.ml index 93d51062dc3e16d8d6b81a6ec63e95147fe7c2cc..ec28f552d0ee1c80745562a28235849db0da2917 100644 --- a/src/lib_smart_rollup/rollup_node_services.ml +++ b/src/lib_smart_rollup/rollup_node_services.ml @@ -254,6 +254,10 @@ module Encodings = struct (req "message_index" int31) (opt "message" Outbox_message.summary_encoding)))) + let outbox_msg_status : [`Executable | `Lost | `Pending] t = + string_enum + [("executable", `Executable); ("pending", `Pending); ("lost", `Lost)] + let queued_message = L2_message.encoding let batcher_queue = list queued_message @@ -914,6 +918,12 @@ module Query = struct q#drop_duplicate) |> seal + let outbox_level_query = + let open Tezos_rpc.Query in + query (fun l -> l) + |+ opt_field "outbox_level" Tezos_rpc.Arg.int32 (fun k -> k) + |> seal + let outbox_query : bool Tezos_rpc.Query.t = let open Tezos_rpc.Query in query (fun b -> b) @@ -1128,17 +1138,31 @@ module Local = struct (Data_encoding.option Encodings.commitment_with_hash_and_level_infos) (path / "commitments" /: Arg.commitment_hash) + let outbox_pending = + Tezos_rpc.Service.get_service + ~description: + "Pending outbox messages with their status (executable, pending, or \ + lost)" + ~query:Query.outbox_level_query + ~output: + Data_encoding.( + list + (merge_objs + Encodings.outbox + (obj1 (req "status" Encodings.outbox_msg_status)))) + (path / "outbox" / "pending") + let outbox_pending_executable = Tezos_rpc.Service.get_service ~description:"Pending outbox messages which can be executed" - ~query:Tezos_rpc.Query.empty + ~query:Query.outbox_level_query ~output:(Data_encoding.list Encodings.outbox) (path / "outbox" / "pending" / "executable") let outbox_pending_unexecutable = Tezos_rpc.Service.get_service ~description:"Pending outbox messages which cannot yet be executed" - ~query:Tezos_rpc.Query.empty + ~query:Query.outbox_level_query ~output:(Data_encoding.list Encodings.outbox) (path / "outbox" / "pending" / "unexecutable") diff --git a/src/lib_smart_rollup_node/node_context.ml b/src/lib_smart_rollup_node/node_context.ml index 43386829bac5d192b8c376cccdb916e307e32528..8c3aa2971c331451ac5733c6bb2df0f23b72b563 100644 --- a/src/lib_smart_rollup_node/node_context.ml +++ b/src/lib_smart_rollup_node/node_context.ml @@ -668,7 +668,9 @@ let register_outbox_messages {store; _} ~outbox_level ~indexes = let*? indexes = Bitset.from_list indexes in Store.Outbox_messages.register_outbox_messages store ~outbox_level ~indexes -let get_executable_pending_outbox_messages {store; lcc; current_protocol; _} = +let get_executable_pending_outbox_messages ?outbox_level + {store; lcc; current_protocol; _} = + let open Lwt_result_syntax in let max_level = (Reference.get lcc).level in let constants = (Reference.get current_protocol).constants.sc_rollup in let min_level = @@ -678,9 +680,19 @@ let get_executable_pending_outbox_messages {store; lcc; current_protocol; _} = (constants.max_number_of_stored_cemented_commitments * constants.commitment_period_in_blocks)) in - Store.Outbox_messages.pending store ~min_level ~max_level - -let get_unexecutable_pending_outbox_messages ({store; lcc; _} as node_ctxt) = + match outbox_level with + | None -> Store.Outbox_messages.pending store ~min_level ~max_level + | Some outbox_level when outbox_level > max_level || outbox_level < min_level + -> + return_nil + | Some outbox_level -> + Store.Outbox_messages.pending + store + ~min_level:outbox_level + ~max_level:outbox_level + +let get_unexecutable_pending_outbox_messages ?outbox_level + ({store; lcc; _} as node_ctxt) = let open Lwt_result_syntax in let* head = last_processed_head_opt node_ctxt in let*? max_level = @@ -689,7 +701,55 @@ let get_unexecutable_pending_outbox_messages ({store; lcc; _} as node_ctxt) = | Some h -> Ok h.header.level in let min_level = Int32.succ (Reference.get lcc).level in - Store.Outbox_messages.pending store ~min_level ~max_level + match outbox_level with + | None -> Store.Outbox_messages.pending store ~min_level ~max_level + | Some outbox_level when outbox_level > max_level || outbox_level < min_level + -> + return_nil + | Some outbox_level -> + Store.Outbox_messages.pending + store + ~min_level:outbox_level + ~max_level:outbox_level + +let get_pending_outbox_messages ?outbox_level + ({store; lcc; current_protocol; _} as node_ctxt) = + let open Lwt_result_syntax in + let* head = last_processed_head_opt node_ctxt in + let*? max_level = + match head with + | None -> error_with "No L2 head" + | Some h -> Ok h.header.level + in + let lcc = (Reference.get lcc).level in + let constants = (Reference.get current_protocol).constants.sc_rollup in + let lost_level = + Int32.sub + lcc + (Int32.of_int + (constants.max_number_of_stored_cemented_commitments + * constants.commitment_period_in_blocks)) + in + let+ messages = + match outbox_level with + | None -> Store.Outbox_messages.pending store ~min_level:0l ~max_level + | Some outbox_level when outbox_level > max_level -> return_nil + | Some outbox_level -> + Store.Outbox_messages.pending + store + ~min_level:outbox_level + ~max_level:outbox_level + in + List.rev_map + (fun ((outbox_level, _) as msg) -> + let status = + if outbox_level < lost_level then `Lost + else if outbox_level <= lcc then `Executable + else `Pending + in + (msg, status)) + messages + |> List.rev let get_full_l2_block ?get_outbox_messages node_ctxt block_hash = let open Lwt_result_syntax in diff --git a/src/lib_smart_rollup_node/node_context.mli b/src/lib_smart_rollup_node/node_context.mli index b22b510f54af00cc04dbf53fef22892a2926b8ad..25da4cf76316bb95fcbc71a8aaf6f506d853ce66 100644 --- a/src/lib_smart_rollup_node/node_context.mli +++ b/src/lib_smart_rollup_node/node_context.mli @@ -473,13 +473,19 @@ val register_outbox_messages : The returned list contains outbox levels and indexes for each level (in order). *) val get_executable_pending_outbox_messages : - _ t -> (int32 * int list) list tzresult Lwt.t + ?outbox_level:int32 -> _ t -> (int32 * int list) list tzresult Lwt.t (** Returns the pending messages (i.e. unexecuted) that cannot be executed yet. The returned list contains outbox levels and indexes for each level (in order). *) val get_unexecutable_pending_outbox_messages : - _ t -> (int32 * int list) list tzresult Lwt.t + ?outbox_level:int32 -> _ t -> (int32 * int list) list tzresult Lwt.t + +(** Returns all pending messages with their status. *) +val get_pending_outbox_messages : + ?outbox_level:int32 -> + _ t -> + ((int32 * int list) * [`Executable | `Lost | `Pending]) list tzresult Lwt.t (** {3 Protocol} *) diff --git a/src/lib_smart_rollup_node/rpc_directory.ml b/src/lib_smart_rollup_node/rpc_directory.ml index 7c89ffff47370108c9c433f9773cb8f86e59057c..0adf1e5356c851d76961d4bd29c5363445c43547 100644 --- a/src/lib_smart_rollup_node/rpc_directory.ml +++ b/src/lib_smart_rollup_node/rpc_directory.ml @@ -522,23 +522,38 @@ let get_outbox_content (node_ctxt : _ Node_context.t) let () = Local_directory.register0 Rollup_node_services.Local.outbox_pending_executable - @@ fun node_ctxt () () -> + @@ fun node_ctxt outbox_level () -> let open Lwt_result_syntax in let* outbox_messages = - Node_context.get_executable_pending_outbox_messages node_ctxt + Node_context.get_executable_pending_outbox_messages ?outbox_level node_ctxt in List.map_ep (get_outbox_content node_ctxt) outbox_messages let () = Local_directory.register0 Rollup_node_services.Local.outbox_pending_unexecutable - @@ fun node_ctxt () () -> + @@ fun node_ctxt outbox_level () -> let open Lwt_result_syntax in let* outbox_messages = - Node_context.get_unexecutable_pending_outbox_messages node_ctxt + Node_context.get_unexecutable_pending_outbox_messages + ?outbox_level + node_ctxt in List.map_ep (get_outbox_content node_ctxt) outbox_messages +let () = + Local_directory.register0 Rollup_node_services.Local.outbox_pending + @@ fun node_ctxt outbox_level () -> + let open Lwt_result_syntax in + let* outbox_messages = + Node_context.get_pending_outbox_messages ?outbox_level node_ctxt + in + List.map_ep + (fun (outbox_msg, status) -> + let+ outbos_msg = get_outbox_content node_ctxt outbox_msg in + (outbos_msg, status)) + outbox_messages + let () = Local_directory.register0 Rollup_node_services.Local.gc_info @@ fun node_ctxt () () ->