diff --git a/CHANGES.rst b/CHANGES.rst index 01af8413b21795abbffa280a2602a01893247614..6f7046219e56523657020873076068ec3e44c860 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -141,6 +141,10 @@ Smart Rollup node - Improved error messages for RPC ``/global/block//helpers/proofs/outbox//messages?index=``. (MR :gl:`!15507`) +- RPCs ``/global/block//committed_status`` and to retrieve commitment + and cementation status for a given block (or an estimated timestamp + otherwise). (MR :gl:`!15409`) + 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 5f3d080344b542bb7ea2ca1db50eabb57e40b658..fac782e74eb9c7f679f94c5ec7bd7355f4e8320f 100644 --- a/src/lib_smart_rollup/rollup_node_services.ml +++ b/src/lib_smart_rollup/rollup_node_services.ml @@ -125,6 +125,38 @@ type injector_operation = { last_error : tztrace option; } +type committed_status = + | Uncommitted of { + commitment_level : int32; + (** Level at which the following commitment will be produced. *) + estimated_commitment_time : Time.System.t; + (** Estimated time at which the commitment will be published. *) + estimated_cementation_time : Time.System.t; + (** Estimated time at which the commitment will be cemented. *) + } + | Committed_ of { + commitment_hash : Commitment.Hash.t; (** Hash of following commitment. *) + commitment_level : int32; (** Level of following commitment. *) + first_published_level : int32; + (** Level at which commitment was first published. *) + published_level : int32 option; + (** Level at which commitment was published by operator (may be None + if e.g. rollup node does not publish). *) + estimated_cementation_time : Time.System.t; + (** Estimated time at which the commitment will be cemented. *) + } + | Cemented of { + commitment_hash : Commitment.Hash.t; (** Hash of following commitment. *) + commitment_level : int32; (** Level of following commitment. *) + first_published_level : int32; + (** Level at which commitment was first published. *) + published_level : int32 option; + (** Level at which commitment was published by operator (may be None + if e.g. rollup node does not publish). *) + blocks_since_cemented : int32; + (** Number of blocks since commitment was cemented *) + } + module Encodings = struct open Data_encoding @@ -600,6 +632,159 @@ module Encodings = struct (obj2 (req "tags" (list Operation_kind.encoding)) (req "queue" (list injector_operation))) + + let committed_status = + union + [ + case + (Tag 0) + ~title:"uncommitted" + ~description:"L2 Block content is not yet committed on L1" + (obj1 + (req + "uncommitted" + (obj3 + (req + "commitment_level" + int32 + ~description: + "Level at which the following commitment will be \ + produced.") + (req + "estimated_commitment_time" + Time.System.encoding + ~description: + "Estimated time at which the commitment will be \ + published.") + (req + "estimated_cementation_time" + Time.System.encoding + ~description: + "Estimated time at which the commitment will be \ + cemented.")))) + (function + | Uncommitted + { + commitment_level = l; + estimated_commitment_time = pt; + estimated_cementation_time = ct; + } -> + Some (l, pt, ct) + | _ -> None) + (fun (l, pt, ct) -> + Uncommitted + { + commitment_level = l; + estimated_commitment_time = pt; + estimated_cementation_time = ct; + }); + case + (Tag 1) + ~title:"committed" + ~description: + "L2 Block content is already committed on L1 but not yet cemented" + (obj1 + (req + "committed" + (obj5 + (req + "commitment_hash" + Commitment.Hash.encoding + ~description:"Hash of following commitment.") + (req + "commitment_level" + int32 + ~description:"Level of following commitment.") + (req + "first_published_level" + int32 + ~description: + "Level at which commitment was first published.") + (req + "published_level" + (option int32) + ~description: + "Level at which commitment was published by operator \ + (may be null if e.g. rollup node does not publish).") + (req + "estimated_cementation_time" + Time.System.encoding + ~description: + "Estimated time at which the commitment will be \ + cemented.")))) + (function + | Committed_ + { + commitment_hash = h; + commitment_level = l; + first_published_level = f; + published_level = p; + estimated_cementation_time = ct; + } -> + Some (h, l, f, p, ct) + | _ -> None) + (fun (h, l, f, p, ct) -> + Committed_ + { + commitment_hash = h; + commitment_level = l; + first_published_level = f; + published_level = p; + estimated_cementation_time = ct; + }); + case + (Tag 2) + ~title:"cemented" + ~description:"L2 Block content is already cemented" + (obj1 + (req + "cemented" + (obj5 + (req + "commitment_hash" + Commitment.Hash.encoding + ~description:"Hash of following commitment.") + (req + "commitment_level" + int32 + ~description:"Level of following commitment.") + (req + "first_published_level" + int32 + ~description: + "Level at which commitment was first published.") + (req + "published_level" + (option int32) + ~description: + "Level at which commitment was published by operator \ + (may be null if e.g. rollup node does not publish).") + (req + "blocks_since_cemented" + int32 + ~description: + "Number of blocks since commitment was cemented.")))) + (function + | Cemented + { + commitment_hash = h; + commitment_level = l; + first_published_level = f; + published_level = p; + blocks_since_cemented = b; + } -> + Some (h, l, f, p, b) + | _ -> None) + (fun (h, l, f, p, b) -> + Cemented + { + commitment_hash = h; + commitment_level = l; + first_published_level = f; + published_level = p; + blocks_since_cemented = b; + }); + ] end module Arg = struct diff --git a/src/lib_smart_rollup_node/publisher.ml b/src/lib_smart_rollup_node/publisher.ml index f25c3a6fbc61e65bd041469de641e790460e90a9..79da853800db4e83ecb5f5dc2fa4ad79fb8bd7ee 100644 --- a/src/lib_smart_rollup_node/publisher.ml +++ b/src/lib_smart_rollup_node/publisher.ml @@ -444,6 +444,123 @@ let cementable_commitments (node_ctxt : _ Node_context.t) = in gather [] latest_cementable_commitment +module Helpers = struct + let estimated_time_of_level (head : Sc_rollup_block.t) + (constants : Rollup_constants.protocol_constants) l = + let blocks_till = Int32.sub l head.header.level in + let secs_till = + Int32.to_int blocks_till * Int64.to_int constants.minimal_block_delay + in + let now_s = Time.System.now () |> Ptime.to_float_s |> int_of_float in + Ptime.of_float_s (now_s + secs_till |> float_of_int) + |> WithExceptions.Option.get ~loc:__LOC__ + + let finalized_level l = + (* In tenderbake, level l is finalized at l + 2. *) + Int32.add l 2l + + let next_commitment (node_ctxt : _ Node_context.t) (block : Sc_rollup_block.t) + = + let open Lwt_result_syntax in + let constants = (Reference.get node_ctxt.current_protocol).constants in + let* prev_commitment = + Node_context.get_commitment + node_ctxt + block.header.previous_commitment_hash + in + let next_commitment_level = + Int32.add + prev_commitment.inbox_level + (Int32.of_int constants.sc_rollup.commitment_period_in_blocks) + in + let* next_commitment_block = + Node_context.find_l2_block_by_level node_ctxt next_commitment_level + in + match next_commitment_block with + | Some next -> + (* Commitment has already been produced *) + return (next.header.commitment_hash, next.header.level) + | _ -> + (* Commitment not yet produced. *) + return (None, next_commitment_level) + + let committed_status (node_ctxt : _ Node_context.t) + (block : Sc_rollup_block.t) = + let open Lwt_result_syntax in + let lcc = Reference.get node_ctxt.lcc in + let constants = (Reference.get node_ctxt.current_protocol).constants in + let* head = Node_context.last_processed_head_opt node_ctxt in + let head = WithExceptions.Option.get ~loc:__LOC__ head in + let* next_commitment, next_commitment_level = + next_commitment node_ctxt block + in + let* pub_info = + Option.map_es + (fun c -> + let+ info = Node_context.commitment_published_at_level node_ctxt c in + (c, info)) + next_commitment + in + match pub_info with + | Some + ( next_commitment_hash, + Some {first_published_at_level; published_at_level} ) -> + (* Commitment already published *) + if block.header.level <= lcc.level then + (* Cemented *) + return + (Rollup_node_services.Cemented + { + commitment_hash = next_commitment_hash; + commitment_level = next_commitment_level; + first_published_level = first_published_at_level; + published_level = published_at_level; + blocks_since_cemented = Int32.sub lcc.level block.header.level; + }) + else + (* Commitment published but not cemented *) + let estimated_cementation_level = + Int32.add + first_published_at_level + (Int32.of_int constants.sc_rollup.challenge_window_in_blocks) + in + let estimated_cementation_time = + estimated_time_of_level head constants estimated_cementation_level + in + return + (Rollup_node_services.Committed_ + { + commitment_hash = next_commitment_hash; + commitment_level = next_commitment_level; + first_published_level = first_published_at_level; + published_level = published_at_level; + estimated_cementation_time; + }) + | _ -> + (* Commitment not yet published *) + let estimated_commitment_time = + estimated_time_of_level + head + constants + (finalized_level next_commitment_level) + in + let estimated_cementation_level = + Int32.add + next_commitment_level + (Int32.of_int constants.sc_rollup.challenge_window_in_blocks) + in + let estimated_cementation_time = + estimated_time_of_level head constants estimated_cementation_level + in + return + (Rollup_node_services.Uncommitted + { + commitment_level = next_commitment_level; + estimated_commitment_time; + estimated_cementation_time; + }) +end + let cement_commitment (node_ctxt : _ Node_context.t) commitment = let open Lwt_result_syntax in let cement_operation = diff --git a/src/lib_smart_rollup_node/publisher.mli b/src/lib_smart_rollup_node/publisher.mli index 32ca5080e93d418e5166f9bd356b08102968e83c..92f0edcb11f02fa38f203a3161e7dcc667b8bef0 100644 --- a/src/lib_smart_rollup_node/publisher.mli +++ b/src/lib_smart_rollup_node/publisher.mli @@ -104,3 +104,13 @@ val shutdown : unit -> unit Lwt.t (** Returns the status of the publisher worker. *) val worker_status : unit -> [`Running | `Not_running | `Crashed of exn] + +(** {2 Helper module} *) + +module Helpers : sig + (** Returns the committed/cemented status for a block's content. *) + val committed_status : + _ Node_context.t -> + Sc_rollup_block.t -> + Rollup_node_services.committed_status tzresult Lwt.t +end diff --git a/src/proto_019_PtParisB/lib_sc_rollup_layer2/sc_rollup_services.ml b/src/proto_019_PtParisB/lib_sc_rollup_layer2/sc_rollup_services.ml index d982430b7806fd66c8b561e9ad8879f22bb5a287..525575b29db6482d61238133ebb4fdef41725ce1 100644 --- a/src/proto_019_PtParisB/lib_sc_rollup_layer2/sc_rollup_services.ml +++ b/src/proto_019_PtParisB/lib_sc_rollup_layer2/sc_rollup_services.ml @@ -436,6 +436,15 @@ module Block = struct ~output:Data_encoding.(list Sc_rollup.output_encoding) (path / "outbox" /: level_param / "messages") + let committed_status = + Tezos_rpc.Service.get_service + ~description: + "Commitment status of the rollup state which will include content of \ + this block" + ~query:Tezos_rpc.Query.empty + ~output:Rollup_node_services.Encodings.committed_status + (path / "committed_status") + module Helpers = struct type nonrec prefix = prefix diff --git a/src/proto_019_PtParisB/lib_sc_rollup_node/RPC_directory.ml b/src/proto_019_PtParisB/lib_sc_rollup_node/RPC_directory.ml index 22f21cd8d05d8d93928ec2b4dd9fd2abfccd0acf..10530517bc167b85095be451d3d9993057e7565a 100644 --- a/src/proto_019_PtParisB/lib_sc_rollup_node/RPC_directory.ml +++ b/src/proto_019_PtParisB/lib_sc_rollup_node/RPC_directory.ml @@ -328,6 +328,13 @@ let () = ~log_kernel_debug_file messages +let () = + Block_directory.register0 Sc_rollup_services.Block.committed_status + @@ fun (node_ctxt, block) () () -> + let open Lwt_result_syntax in + let* block = Node_context.get_l2_block node_ctxt block in + Publisher.Helpers.committed_status node_ctxt block + let block_directory (node_ctxt : _ Node_context.t) = let module PVM = (val Pvm_rpc.of_kind node_ctxt.kind) in List.fold_left diff --git a/src/proto_020_PsParisC/lib_sc_rollup_layer2/sc_rollup_services.ml b/src/proto_020_PsParisC/lib_sc_rollup_layer2/sc_rollup_services.ml index d982430b7806fd66c8b561e9ad8879f22bb5a287..525575b29db6482d61238133ebb4fdef41725ce1 100644 --- a/src/proto_020_PsParisC/lib_sc_rollup_layer2/sc_rollup_services.ml +++ b/src/proto_020_PsParisC/lib_sc_rollup_layer2/sc_rollup_services.ml @@ -436,6 +436,15 @@ module Block = struct ~output:Data_encoding.(list Sc_rollup.output_encoding) (path / "outbox" /: level_param / "messages") + let committed_status = + Tezos_rpc.Service.get_service + ~description: + "Commitment status of the rollup state which will include content of \ + this block" + ~query:Tezos_rpc.Query.empty + ~output:Rollup_node_services.Encodings.committed_status + (path / "committed_status") + module Helpers = struct type nonrec prefix = prefix diff --git a/src/proto_020_PsParisC/lib_sc_rollup_node/RPC_directory.ml b/src/proto_020_PsParisC/lib_sc_rollup_node/RPC_directory.ml index 22f21cd8d05d8d93928ec2b4dd9fd2abfccd0acf..10530517bc167b85095be451d3d9993057e7565a 100644 --- a/src/proto_020_PsParisC/lib_sc_rollup_node/RPC_directory.ml +++ b/src/proto_020_PsParisC/lib_sc_rollup_node/RPC_directory.ml @@ -328,6 +328,13 @@ let () = ~log_kernel_debug_file messages +let () = + Block_directory.register0 Sc_rollup_services.Block.committed_status + @@ fun (node_ctxt, block) () () -> + let open Lwt_result_syntax in + let* block = Node_context.get_l2_block node_ctxt block in + Publisher.Helpers.committed_status node_ctxt block + let block_directory (node_ctxt : _ Node_context.t) = let module PVM = (val Pvm_rpc.of_kind node_ctxt.kind) in List.fold_left diff --git a/src/proto_021_PsQuebec/lib_sc_rollup_layer2/sc_rollup_services.ml b/src/proto_021_PsQuebec/lib_sc_rollup_layer2/sc_rollup_services.ml index 06e2622363db19018eb940c4c419c49c9c1c65e5..751efeaa62ebbc0feac50902b1430ca34815e337 100644 --- a/src/proto_021_PsQuebec/lib_sc_rollup_layer2/sc_rollup_services.ml +++ b/src/proto_021_PsQuebec/lib_sc_rollup_layer2/sc_rollup_services.ml @@ -395,6 +395,15 @@ module Block = struct ~output:Data_encoding.(list Sc_rollup.output_encoding) (path / "outbox" /: level_param / "messages") + let committed_status = + Tezos_rpc.Service.get_service + ~description: + "Commitment status of the rollup state which will include content of \ + this block" + ~query:Tezos_rpc.Query.empty + ~output:Rollup_node_services.Encodings.committed_status + (path / "committed_status") + module Helpers = struct type nonrec prefix = prefix diff --git a/src/proto_021_PsQuebec/lib_sc_rollup_node/RPC_directory.ml b/src/proto_021_PsQuebec/lib_sc_rollup_node/RPC_directory.ml index d9abbde7131b0fdff201ed3d4f89d80f73bc7a9d..fbde3daa9af1bb486395acbe46364538f1ebd888 100644 --- a/src/proto_021_PsQuebec/lib_sc_rollup_node/RPC_directory.ml +++ b/src/proto_021_PsQuebec/lib_sc_rollup_node/RPC_directory.ml @@ -320,6 +320,13 @@ let () = ~log_kernel_debug_file messages +let () = + Block_directory.register0 Sc_rollup_services.Block.committed_status + @@ fun (node_ctxt, block) () () -> + let open Lwt_result_syntax in + let* block = Node_context.get_l2_block node_ctxt block in + Publisher.Helpers.committed_status node_ctxt block + let block_directory (node_ctxt : _ Node_context.t) = let module PVM = (val Pvm_rpc.of_kind node_ctxt.kind) in List.fold_left diff --git a/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_services.ml b/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_services.ml index 06e2622363db19018eb940c4c419c49c9c1c65e5..751efeaa62ebbc0feac50902b1430ca34815e337 100644 --- a/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_services.ml +++ b/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_services.ml @@ -395,6 +395,15 @@ module Block = struct ~output:Data_encoding.(list Sc_rollup.output_encoding) (path / "outbox" /: level_param / "messages") + let committed_status = + Tezos_rpc.Service.get_service + ~description: + "Commitment status of the rollup state which will include content of \ + this block" + ~query:Tezos_rpc.Query.empty + ~output:Rollup_node_services.Encodings.committed_status + (path / "committed_status") + module Helpers = struct type nonrec prefix = prefix diff --git a/src/proto_alpha/lib_sc_rollup_node/RPC_directory.ml b/src/proto_alpha/lib_sc_rollup_node/RPC_directory.ml index d9abbde7131b0fdff201ed3d4f89d80f73bc7a9d..fbde3daa9af1bb486395acbe46364538f1ebd888 100644 --- a/src/proto_alpha/lib_sc_rollup_node/RPC_directory.ml +++ b/src/proto_alpha/lib_sc_rollup_node/RPC_directory.ml @@ -320,6 +320,13 @@ let () = ~log_kernel_debug_file messages +let () = + Block_directory.register0 Sc_rollup_services.Block.committed_status + @@ fun (node_ctxt, block) () () -> + let open Lwt_result_syntax in + let* block = Node_context.get_l2_block node_ctxt block in + Publisher.Helpers.committed_status node_ctxt block + let block_directory (node_ctxt : _ Node_context.t) = let module PVM = (val Pvm_rpc.of_kind node_ctxt.kind) in List.fold_left