From 4eafc91917669deaa0adb9c58c8e1da7aca082f6 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 3 Jan 2023 19:06:03 +0100 Subject: [PATCH 1/6] SCORU/Node: Store uses indexed files DAL data remains in an irmin store for now. (cherry picked from commit fba95e94855a76343fb6454c224071b83e5c8313) --- src/proto_alpha/bin_sc_rollup_node/store.ml | 343 ++++++++++++------- src/proto_alpha/bin_sc_rollup_node/store.mli | 124 +++---- 2 files changed, 274 insertions(+), 193 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/store.ml b/src/proto_alpha/bin_sc_rollup_node/store.ml index 5c22868889fb..9b459d85b7ed 100644 --- a/src/proto_alpha/bin_sc_rollup_node/store.ml +++ b/src/proto_alpha/bin_sc_rollup_node/store.ml @@ -30,123 +30,124 @@ include Store_utils (** Aggregated collection of messages from the L1 inbox *) open Alpha_context -module IStore = Irmin_store.Make (struct - let name = "Tezos smart rollup node" -end) +module Irmin_store = struct + module IStore = Irmin_store.Make (struct + let name = "Tezos smart rollup node" + end) -include Store_utils.Make (IStore) + include IStore + include Store_utils.Make (IStore) +end -type 'a store = 'a IStore.t +module Empty_header = struct + type t = unit -type 'a t = ([< `Read | `Write > `Read] as 'a) store + let name = "empty" -type rw = Store_sigs.rw t + let encoding = Data_encoding.unit -type ro = Store_sigs.ro t + let fixed_size = 0 +end -let close = IStore.close +module Add_empty_header = struct + module Header = Empty_header -let load = IStore.load + let header _ = () +end -let readonly = IStore.readonly +module Make_hash_index_key (H : Environment.S.HASH) = +Indexed_store.Make_index_key (struct + include Indexed_store.Make_fixed_encodable (H) + + let equal = H.equal +end) (** L2 blocks *) module L2_blocks = - Make_append_only_map + Indexed_store.Make_indexed_file (struct - let path = ["state_info"] + let name = "l2_blocks" end) + (Tezos_store_shared.Block_key) (struct - type key = Block_hash.t + type t = (unit, unit) Sc_rollup_block.block - let to_path_representation = Block_hash.to_b58check - end) - (struct - type value = Sc_rollup_block.t + let name = "sc_rollup_block_info" + + let encoding = + Sc_rollup_block.block_encoding Data_encoding.unit Data_encoding.unit - let name = "sc_rollup_block" + module Header = struct + type t = Sc_rollup_block.header - let encoding = Sc_rollup_block.encoding + let name = "sc_rollup_block_header" + + let encoding = Sc_rollup_block.header_encoding + + let fixed_size = Sc_rollup_block.header_size + end end) (** Unaggregated messages per block *) -module Messages = struct - type info = { - predecessor : Block_hash.t; - predecessor_timestamp : Timestamp.t; - messages : Sc_rollup.Inbox_message.t list; - } +module Messages = + Indexed_store.Make_indexed_file + (struct + let name = "messages" + end) + (Make_hash_index_key (Sc_rollup.Inbox_merkelized_payload_hashes.Hash)) + (struct + type t = Sc_rollup.Inbox_message.t list - let encoding = - let open Data_encoding in - conv - (fun {predecessor; predecessor_timestamp; messages} -> - (predecessor, predecessor_timestamp, messages)) - (fun (predecessor, predecessor_timestamp, messages) -> - {predecessor; predecessor_timestamp; messages}) - @@ obj3 - (req "predecessor" Block_hash.encoding) - (req "predecessor_timestamp" Timestamp.encoding) - (req - "messages" - (list @@ dynamic_size Sc_rollup.Inbox_message.encoding)) + let name = "messages_list" - include - Make_append_only_map - (struct - let path = ["messages"] - end) - (struct - type key = Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t + let encoding = + Data_encoding.(list @@ dynamic_size Sc_rollup.Inbox_message.encoding) - let to_path_representation = - Sc_rollup.Inbox_merkelized_payload_hashes.Hash.to_b58check - end) - (struct - type value = info + module Header = struct + type t = Block_hash.t * Timestamp.t - let name = "messages" + let name = "messages_inbox_info" - let encoding = encoding - end) -end + let encoding = + let open Data_encoding in + obj2 + (req "predecessor" Block_hash.encoding) + (req "predecessor_timestamp" Timestamp.encoding) + + let fixed_size = + WithExceptions.Option.get ~loc:__LOC__ + @@ Data_encoding.Binary.fixed_length encoding + end + end) (** Inbox state for each block *) module Inboxes = - Make_append_only_map + Indexed_store.Make_simple_indexed_file (struct - let path = ["inboxes"] + let name = "inboxes" end) + (Make_hash_index_key (Sc_rollup.Inbox.Hash)) (struct - type key = Sc_rollup.Inbox.Hash.t - - let to_path_representation = Sc_rollup.Inbox.Hash.to_b58check - end) - (struct - type value = Sc_rollup.Inbox.t + type t = Sc_rollup.Inbox.t let name = "inbox" let encoding = Sc_rollup.Inbox.encoding + + include Add_empty_header end) module Commitments = - Make_append_only_map + Indexed_store.Make_indexable (struct - let path = ["commitments"; "computed"] + let name = "commitments" end) - (struct - type key = Sc_rollup.Commitment.Hash.t - - let to_path_representation = Sc_rollup.Commitment.Hash.to_b58check - end) - (struct - type value = Sc_rollup.Commitment.t + (Make_hash_index_key (Sc_rollup.Commitment.Hash)) + (Indexed_store.Make_index_value (Indexed_store.Make_fixed_encodable (struct + include Sc_rollup.Commitment let name = "commitment" - - let encoding = Sc_rollup.Commitment.encoding - end) + end))) module Commitments_published_at_level = struct type element = { @@ -156,6 +157,12 @@ module Commitments_published_at_level = struct let element_encoding = let open Data_encoding in + let opt_level_encoding = + conv + (function None -> -1l | Some l -> Raw_level.to_int32 l) + (fun l -> if l = -1l then None else Some (Raw_level.of_int32_exn l)) + Data_encoding.int32 + in conv (fun {first_published_at_level; published_at_level} -> (first_published_at_level, published_at_level)) @@ -163,82 +170,64 @@ module Commitments_published_at_level = struct {first_published_at_level; published_at_level}) @@ obj2 (req "first_published_at_level" Raw_level.encoding) - (opt "published_at_level" Raw_level.encoding) + (req "published_at_level" opt_level_encoding) include - Make_updatable_map + Indexed_store.Make_indexable (struct - let path = ["commitments"; "published_at_level"] + let name = "commitments" end) - (struct - type key = Sc_rollup.Commitment.Hash.t - - let to_path_representation = Sc_rollup.Commitment.Hash.to_b58check - end) - (struct - type value = element + (Make_hash_index_key (Sc_rollup.Commitment.Hash)) + (Indexed_store.Make_index_value (Indexed_store.Make_fixed_encodable (struct + type t = element let name = "published_levels" let encoding = element_encoding - end) + end))) end -(* TODO: https://gitlab.com/tezos/tezos/-/issues/4392 - Use file. *) -module L2_head = - Make_mutable_value - (struct - let path = ["l2_head"] - end) - (struct - type value = Sc_rollup_block.t +module L2_head = Indexed_store.Make_singleton (struct + type t = Sc_rollup_block.t - let name = "l2_block" + let name = "l2_head" - let encoding = Sc_rollup_block.encoding - end) + let encoding = Sc_rollup_block.encoding +end) -(* TODO: https://gitlab.com/tezos/tezos/-/issues/4392 - Use file. *) -module Last_finalized_head = - Make_mutable_value - (struct - let path = ["finalized_head"] - end) - (struct - type value = Sc_rollup_block.t +module Last_finalized_head = Indexed_store.Make_singleton (struct + type t = Sc_rollup_block.t - let name = "l2_block" + let name = "finalized_head" - let encoding = Sc_rollup_block.encoding - end) + let encoding = Sc_rollup_block.encoding +end) (** Table from L1 levels to blocks hashes. *) module Levels_to_hashes = - Make_updatable_map + Indexed_store.Make_indexable (struct - let path = ["tezos"; "levels"] + let name = "tezos_levels" end) - (struct - type key = int32 + (Indexed_store.Make_index_key (struct + type t = int32 - let to_path_representation = Int32.to_string - end) - (struct - type value = Block_hash.t + let encoding = Data_encoding.int32 - let name = "block_hash" + let name = "level" - let encoding = Block_hash.encoding - end) + let fixed_size = 4 + + let equal = Int32.equal + end)) + (Tezos_store_shared.Block_key) (* Published slot headers per block hash, stored as a list of bindings from `Dal_slot_index.t` to `Dal.Slot.t`. The encoding function converts this list into a `Dal.Slot_index.t`-indexed map. *) module Dal_slot_pages = - Make_nested_map + Irmin_store.Make_nested_map (struct let path = ["dal"; "slot_pages"] end) @@ -270,7 +259,7 @@ module Dal_slot_pages = (** stores slots whose data have been considered and pages stored to disk (if they are confirmed). *) module Dal_processed_slots = - Make_nested_map + Irmin_store.Make_nested_map (struct let path = ["dal"; "processed_slots"] end) @@ -312,7 +301,7 @@ module Dal_processed_slots = end) module Dal_slots_headers = - Make_nested_map + Irmin_store.Make_nested_map (struct let path = ["dal"; "slot_headers"] end) @@ -348,7 +337,7 @@ module Dal_slots_headers = (** Confirmed DAL slots history. See documentation of {Dal_slot_repr.Slots_history} for more details. *) module Dal_confirmed_slots_history = - Make_append_only_map + Irmin_store.Make_append_only_map (struct let path = ["dal"; "confirmed_slots_history"] end) @@ -370,7 +359,7 @@ module Dal_confirmed_slots_history = module Dal_confirmed_slots_histories = (* TODO: https://gitlab.com/tezos/tezos/-/issues/4390 Store single history points in map instead of whole history. *) - Make_append_only_map + Irmin_store.Make_append_only_map (struct let path = ["dal"; "confirmed_slots_histories_cache"] end) @@ -386,3 +375,105 @@ module Dal_confirmed_slots_histories = let encoding = Dal.Slots_history.History_cache.encoding end) + +type 'a store = { + l2_blocks : 'a L2_blocks.t; + messages : 'a Messages.t; + inboxes : 'a Inboxes.t; + commitments : 'a Commitments.t; + commitments_published_at_level : 'a Commitments_published_at_level.t; + l2_head : 'a L2_head.t; + last_finalized_head : 'a Last_finalized_head.t; + levels_to_hashes : 'a Levels_to_hashes.t; + irmin_store : 'a Irmin_store.t; +} + +type 'a t = ([< `Read | `Write > `Read] as 'a) store + +type rw = Store_sigs.rw t + +type ro = Store_sigs.ro t + +let readonly + ({ + l2_blocks; + messages; + inboxes; + commitments; + commitments_published_at_level; + l2_head; + last_finalized_head; + levels_to_hashes; + irmin_store; + } : + _ t) : ro = + { + l2_blocks = L2_blocks.readonly l2_blocks; + messages = Messages.readonly messages; + inboxes = Inboxes.readonly inboxes; + commitments = Commitments.readonly commitments; + commitments_published_at_level = + Commitments_published_at_level.readonly commitments_published_at_level; + l2_head = L2_head.readonly l2_head; + last_finalized_head = Last_finalized_head.readonly last_finalized_head; + levels_to_hashes = Levels_to_hashes.readonly levels_to_hashes; + irmin_store = Irmin_store.readonly irmin_store; + } + +let close + ({ + l2_blocks; + messages; + inboxes; + commitments; + commitments_published_at_level; + l2_head = _; + last_finalized_head = _; + levels_to_hashes; + irmin_store; + } : + _ t) = + let open Lwt_result_syntax in + let+ () = L2_blocks.close l2_blocks + and+ () = Messages.close messages + and+ () = Inboxes.close inboxes + and+ () = Commitments.close commitments + and+ () = Commitments_published_at_level.close commitments_published_at_level + and+ () = Levels_to_hashes.close levels_to_hashes + and+ () = Irmin_store.close irmin_store |> Lwt_result.ok in + () + +let load (type a) (mode : a mode) data_dir : a store tzresult Lwt.t = + let open Lwt_result_syntax in + let path name = Filename.concat data_dir name in + let cache_size = 10_000 in + let* l2_blocks = L2_blocks.load mode ~path:(path "l2_blocks") ~cache_size in + let* messages = Messages.load mode ~path:(path "messages") ~cache_size in + let* inboxes = Inboxes.load mode ~path:(path "inboxes") ~cache_size in + let* commitments = Commitments.load mode ~path:(path "commitments") in + let* commitments_published_at_level = + Commitments_published_at_level.load + mode + ~path:(path "commitments_published_at_level") + in + let* l2_head = L2_head.load mode ~path:(path "l2_head") in + let* last_finalized_head = + Last_finalized_head.load mode ~path:(path "last_finalized_head") + in + let* levels_to_hashes = + Levels_to_hashes.load mode ~path:(path "levels_to_hashes") + in + let+ irmin_store = + Irmin_store.load mode (path "irmin_store") |> Lwt_result.ok + in + { + l2_blocks; + messages; + inboxes; + commitments; + commitments_published_at_level; + l2_head; + last_finalized_head; + levels_to_hashes; + irmin_store; + } diff --git a/src/proto_alpha/bin_sc_rollup_node/store.mli b/src/proto_alpha/bin_sc_rollup_node/store.mli index 4c2d9524da08..9af7a1b7731d 100644 --- a/src/proto_alpha/bin_sc_rollup_node/store.mli +++ b/src/proto_alpha/bin_sc_rollup_node/store.mli @@ -23,74 +23,38 @@ (* *) (*****************************************************************************) -(* TODO: https://gitlab.com/tezos/tezos/-/issues/3471 - Use indexed file for append-only instead of Irmin. *) - -(* TODO: https://gitlab.com/tezos/tezos/-/issues/3739 - Refactor the store file to have functors in their own - separate module, and return errors within the Error monad. *) - open Protocol open Alpha_context +open Indexed_store -type +'a store - -include Store_sigs.Store with type 'a t = 'a store - -(** Type of store. The parameter indicates if the store can be written or only - read. *) -type 'a t = ([< `Read | `Write > `Read] as 'a) store - -(** Read/write store {!t}. *) -type rw = Store_sigs.rw t - -(** Read only store {!t}. *) -type ro = Store_sigs.ro t - -(** [close store] closes the store. *) -val close : _ t -> unit Lwt.t - -(** [load mode directory] loads a store from the data persisted in [directory].*) -val load : 'a Store_sigs.mode -> string -> 'a store Lwt.t - -(** [readonly store] returns a read-only version of [store]. *) -val readonly : _ t -> ro +module Irmin_store : Store_sigs.Store module L2_blocks : - Store_sigs.Append_only_map + INDEXED_FILE with type key := Block_hash.t - and type value := Sc_rollup_block.t - and type 'a store := 'a store + and type value := (unit, unit) Sc_rollup_block.block + and type header := Sc_rollup_block.header (** Storage for persisting messages downloaded from the L1 node. *) -module Messages : sig - type info = { - predecessor : Block_hash.t; - predecessor_timestamp : Timestamp.t; - messages : Sc_rollup.Inbox_message.t list; - } - - include - Store_sigs.Append_only_map - with type key := Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t - and type value := info - and type 'a store := 'a store -end +module Messages : + INDEXED_FILE + with type key := Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t + and type value := Sc_rollup.Inbox_message.t list + and type header := Block_hash.t * Timestamp.t (** Aggregated collection of messages from the L1 inbox *) module Inboxes : - Store_sigs.Append_only_map + SIMPLE_INDEXED_FILE with type key := Sc_rollup.Inbox.Hash.t and type value := Sc_rollup.Inbox.t - and type 'a store := 'a store + and type header := unit (** Storage containing commitments and corresponding commitment hashes that the rollup node has knowledge of. *) module Commitments : - Store_sigs.Append_only_map + INDEXABLE_STORE with type key := Sc_rollup.Commitment.Hash.t and type value := Sc_rollup.Commitment.t - and type 'a store := 'a store (** Storage mapping commitment hashes to the level when they were published by the rollup node. It only contains hashes of commitments published by this @@ -106,27 +70,18 @@ module Commitments_published_at_level : sig } include - Store_sigs.Map + INDEXABLE_STORE with type key := Sc_rollup.Commitment.Hash.t and type value := element - and type 'a store := 'a store end -module L2_head : - Store_sigs.Mutable_value - with type value := Sc_rollup_block.t - and type 'a store := 'a store +module L2_head : SINGLETON_STORE with type value := Sc_rollup_block.t module Last_finalized_head : - Store_sigs.Mutable_value - with type value := Sc_rollup_block.t - and type 'a store := 'a store + SINGLETON_STORE with type value := Sc_rollup_block.t module Levels_to_hashes : - Store_sigs.Map - with type key := int32 - and type value := Block_hash.t - and type 'a store := 'a store + INDEXABLE_STORE with type key := int32 and type value := Block_hash.t (** Published slot headers per block hash, stored as a list of bindings from [Dal_slot_index.t] @@ -137,13 +92,13 @@ module Dal_slots_headers : with type primary_key := Block_hash.t and type secondary_key := Dal.Slot_index.t and type value := Dal.Slot.Header.t - and type 'a store := 'a store + and type 'a store := 'a Irmin_store.t module Dal_confirmed_slots_history : Store_sigs.Append_only_map with type key := Block_hash.t and type value := Dal.Slots_history.t - and type 'a store := 'a store + and type 'a store := 'a Irmin_store.t (** Confirmed DAL slots histories cache. See documentation of {Dal_slot_repr.Slots_history} for more details. *) @@ -151,7 +106,7 @@ module Dal_confirmed_slots_histories : Store_sigs.Append_only_map with type key := Block_hash.t and type value := Dal.Slots_history.History_cache.t - and type 'a store := 'a store + and type 'a store := 'a Irmin_store.t (** [Dal_slot_pages] is a [Store_utils.Nested_map] used to store the contents of dal slots fetched by the rollup node, as a list of pages. The values of @@ -164,7 +119,7 @@ module Dal_slot_pages : with type primary_key := Block_hash.t and type secondary_key := Dal.Slot_index.t * Dal.Page.Index.t and type value := Dal.Page.content - and type 'a store := 'a store + and type 'a store := 'a Irmin_store.t (** [Dal_processed_slots] is a [Store_utils.Nested_map] used to store the processing status of dal slots content fetched by the rollup node. The values of @@ -178,4 +133,39 @@ module Dal_processed_slots : with type primary_key := Block_hash.t and type secondary_key := Dal.Slot_index.t and type value := [`Confirmed | `Unconfirmed] - and type 'a store := 'a store + and type 'a store := 'a Irmin_store.t + +type +'a store = { + l2_blocks : 'a L2_blocks.t; + messages : 'a Messages.t; + inboxes : 'a Inboxes.t; + commitments : 'a Commitments.t; + commitments_published_at_level : 'a Commitments_published_at_level.t; + l2_head : 'a L2_head.t; + last_finalized_head : 'a Last_finalized_head.t; + levels_to_hashes : 'a Levels_to_hashes.t; + irmin_store : 'a Irmin_store.t; +} + +(** Type of store. The parameter indicates if the store can be written or only + read. *) +type 'a t = ([< `Read | `Write > `Read] as 'a) store + +(** Read/write store {!t}. *) +type rw = Store_sigs.rw t + +(** Read only store {!t}. *) +type ro = Store_sigs.ro t + +(** [close store] closes the store. *) +val close : _ t -> unit tzresult Lwt.t + +(** [load mode directory] loads a store from the data persisted in + [directory]. If [mode] is {!Store_sigs.Read_only}, then the indexes and + irmin store will be opened in readonly mode and only read operations will be + permitted. This allows to open a store for read access that is already + opened in {!Store_sigs.Read_write} mode in another process. *) +val load : 'a Store_sigs.mode -> string -> 'a store tzresult Lwt.t + +(** [readonly store] returns a read-only version of [store]. *) +val readonly : _ t -> ro -- GitLab From 6234bcb9d745f62e266daf28431e29c5a6102870 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Mon, 23 Jan 2023 17:15:08 +0100 Subject: [PATCH 2/6] SCORU/Node: new interface for store access through node context (cherry picked from commit c788783358686c9fd6129877eb1b26e59b78597c) --- .../bin_sc_rollup_node/RPC_server.ml | 100 ++++--- .../bin_sc_rollup_node/commitment.ml | 52 ++-- src/proto_alpha/bin_sc_rollup_node/daemon.ml | 18 +- src/proto_alpha/bin_sc_rollup_node/inbox.ml | 4 +- .../bin_sc_rollup_node/node_context.ml | 266 +++++++++++------- .../bin_sc_rollup_node/node_context.mli | 65 +++-- .../bin_sc_rollup_node/refutation_game.ml | 13 +- 7 files changed, 308 insertions(+), 210 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml b/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml index 454e1e15d14e..18c8b1a7c999 100644 --- a/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml +++ b/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml @@ -52,18 +52,19 @@ let get_last_cemented (node_ctxt : _ Node_context.t) = return lcc_hash let get_head_hash_opt node_ctxt = - let open Lwt_option_syntax in - let+ {header = {block_hash; _}; _} = - Node_context.last_processed_head_opt node_ctxt - in - block_hash + let open Lwt_result_syntax in + let+ res = Node_context.last_processed_head_opt node_ctxt in + Option.map + (fun Sc_rollup_block.{header = {block_hash; _}; _} -> block_hash) + res let get_head_level_opt node_ctxt = - let open Lwt_option_syntax in - let+ {header = {level; _}; _} = - Node_context.last_processed_head_opt node_ctxt - in - Alpha_context.Raw_level.to_int32 level + let open Lwt_result_syntax in + let+ res = Node_context.last_processed_head_opt node_ctxt in + Option.map + (fun Sc_rollup_block.{header = {level; _}; _} -> + Alpha_context.Raw_level.to_int32 level) + res module Slot_pages_map = struct open Protocol @@ -219,9 +220,7 @@ module Common = struct let () = Block_directory.register0 Sc_rollup_services.Global.Block.block @@ fun (node_ctxt, block) () () -> - let open Lwt_result_syntax in - let*! b = Node_context.get_full_l2_block node_ctxt block in - return b + Node_context.get_full_l2_block node_ctxt block let () = Block_directory.register0 Sc_rollup_services.Global.Block.num_messages @@ -239,11 +238,11 @@ module Common = struct let () = Global_directory.register0 Sc_rollup_services.Global.current_tezos_head - @@ fun node_ctxt () () -> get_head_hash_opt node_ctxt >>= return + @@ fun node_ctxt () () -> get_head_hash_opt node_ctxt let () = Global_directory.register0 Sc_rollup_services.Global.current_tezos_level - @@ fun node_ctxt () () -> get_head_level_opt node_ctxt >>= return + @@ fun node_ctxt () () -> get_head_level_opt node_ctxt let () = Block_directory.register0 Sc_rollup_services.Global.Block.hash @@ -370,44 +369,41 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct Global_directory.register0 Sc_rollup_services.Global.last_stored_commitment @@ fun node_ctxt () () -> let open Lwt_result_syntax in - let*! res = - let open Lwt_option_syntax in - let* head = Node_context.last_processed_head_opt node_ctxt in - let commitment_hash = - Sc_rollup_block.most_recent_commitment head.header - in - let* commitment = - Node_context.find_commitment node_ctxt commitment_hash - in - return (commitment, commitment_hash) - in - return res + let* head = Node_context.last_processed_head_opt node_ctxt in + match head with + | None -> return_none + | Some head -> + let commitment_hash = + Sc_rollup_block.most_recent_commitment head.header + in + let+ commitment = + Node_context.find_commitment node_ctxt commitment_hash + in + Option.map (fun c -> (c, commitment_hash)) commitment let () = Local_directory.register0 Sc_rollup_services.Local.last_published_commitment @@ fun node_ctxt () () -> let open Lwt_result_syntax in - let*! result = - let open Lwt_option_syntax in - let*? commitment = node_ctxt.lpc in - let hash = - Alpha_context.Sc_rollup.Commitment.hash_uncarbonated commitment - in - (* The corresponding level in Store.Commitments.published_at_level is - available only when the commitment has been published and included - in a block. *) - let*! published_at_level_info = - Node_context.commitment_published_at_level node_ctxt hash - in - let first_published, published = - match published_at_level_info with - | None -> (None, None) - | Some {first_published_at_level; published_at_level} -> - (Some first_published_at_level, published_at_level) - in - return (commitment, hash, first_published, published) - in - return result + match node_ctxt.lpc with + | None -> return_none + | Some commitment -> + let hash = + Alpha_context.Sc_rollup.Commitment.hash_uncarbonated commitment + in + (* The corresponding level in Store.Commitments.published_at_level is + available only when the commitment has been published and included + in a block. *) + let* published_at_level_info = + Node_context.commitment_published_at_level node_ctxt hash + in + let first_published, published = + match published_at_level_info with + | None -> (None, None) + | Some {first_published_at_level; published_at_level} -> + (Some first_published_at_level, published_at_level) + in + return_some (commitment, hash, first_published, published) let () = Block_directory.register0 Sc_rollup_services.Global.Block.status @@ -497,7 +493,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct let inbox_info_of_level (node_ctxt : _ Node_context.t) inbox_level = let open Alpha_context in - let open Lwt_syntax in + let open Lwt_result_syntax in let+ finalized_head = Node_context.get_finalized_head_opt node_ctxt in let finalized = match finalized_head with @@ -530,7 +526,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct | Some (Injected info) -> return (Sc_rollup_services.Injected info) | Some (Included info) -> ( - let*! inbox_info = + let* inbox_info = inbox_info_of_level node_ctxt info.l1_level in let commitment_level = @@ -540,7 +536,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct | None -> return (Sc_rollup_services.Included (info, inbox_info)) | Some commitment_level -> ( - let*! block = + let* block = Node_context.find_l2_block_by_level node_ctxt (Alpha_context.Raw_level.to_int32 commitment_level) @@ -557,7 +553,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct block.header.commitment_hash in (* Commitment computed *) - let*! published_at = + let* published_at = Node_context.commitment_published_at_level node_ctxt commitment_hash diff --git a/src/proto_alpha/bin_sc_rollup_node/commitment.ml b/src/proto_alpha/bin_sc_rollup_node/commitment.ml index 264d970213bc..a0e6952917e7 100644 --- a/src/proto_alpha/bin_sc_rollup_node/commitment.ml +++ b/src/proto_alpha/bin_sc_rollup_node/commitment.ml @@ -44,6 +44,21 @@ open Protocol open Alpha_context +module Lwt_result_option_syntax = struct + let ( let** ) a f = + let open Lwt_result_syntax in + let* a = a in + match a with None -> return_none | Some a -> f a +end + +module Lwt_result_option_list_syntax = struct + (** A small monadic combinator to return an empty list on None results. *) + let ( let*& ) x f = + let open Lwt_result_syntax in + let* x = x in + match x with None -> return_nil | Some x -> f x +end + let add_level level increment = (* We only use this function with positive increments so it is safe *) if increment < 0 then invalid_arg "Commitment.add_level negative increment" ; @@ -161,13 +176,13 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct match commitment with | None -> return_none | Some commitment -> - let*! commitment_hash = + let* commitment_hash = Node_context.save_commitment node_ctxt commitment in return_some commitment_hash let missing_commitments (node_ctxt : _ Node_context.t) = - let open Lwt_syntax in + let open Lwt_result_syntax in let lpc_level = match node_ctxt.lpc with | None -> node_ctxt.genesis_info.level @@ -246,11 +261,12 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct (* Commitments can only be cemented after [sc_rollup_challenge_window] has passed since they were first published. *) let earliest_cementing_level node_ctxt commitment_hash = - let open Lwt_option_syntax in - let+ {first_published_at_level; _} = + let open Lwt_result_option_syntax in + let** {first_published_at_level; _} = Node_context.commitment_published_at_level node_ctxt commitment_hash in - add_level first_published_at_level (sc_rollup_challenge_window node_ctxt) + return_some + @@ add_level first_published_at_level (sc_rollup_challenge_window node_ctxt) (** [latest_cementable_commitment node_ctxt head] is the most recent commitment hash that could be cemented in [head]'s successor if: @@ -262,15 +278,17 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct start the search for cementable commitments. *) let latest_cementable_commitment (node_ctxt : _ Node_context.t) (head : Sc_rollup_block.t) = - let open Lwt_option_syntax in + let open Lwt_result_option_syntax in let commitment_hash = Sc_rollup_block.most_recent_commitment head.header in - let* commitment = Node_context.find_commitment node_ctxt commitment_hash in - let*? cementable_level_bound = - sub_level commitment.inbox_level (sc_rollup_challenge_window node_ctxt) + let** commitment = Node_context.find_commitment node_ctxt commitment_hash in + let** cementable_level_bound = + return + @@ sub_level commitment.inbox_level (sc_rollup_challenge_window node_ctxt) in - if Raw_level.(cementable_level_bound <= node_ctxt.lcc.level) then fail + if Raw_level.(cementable_level_bound <= node_ctxt.lcc.level) then + return_none else - let* cementable_bound_block = + let** cementable_bound_block = Node_context.find_l2_block_by_level node_ctxt (Raw_level.to_int32 cementable_level_bound) @@ -278,20 +296,14 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct let cementable_commitment = Sc_rollup_block.most_recent_commitment cementable_bound_block.header in - return cementable_commitment + return_some cementable_commitment let cementable_commitments (node_ctxt : _ Node_context.t) = let open Lwt_result_syntax in - let ( let*& ) x f = - (* A small monadic combinator to return an empty list of cementable - commitments on None results. *) - let*! x = x in - match x with None -> return_nil | Some x -> f x - in + let open Lwt_result_option_list_syntax in let*& head = Node_context.last_processed_head_opt node_ctxt in let head_level = head.header.level in let rec gather acc (commitment_hash : Sc_rollup.Commitment.Hash.t) = - let open Lwt_syntax in let* commitment = Node_context.find_commitment node_ctxt commitment_hash in @@ -325,7 +337,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct let*& latest_cementable_commitment = latest_cementable_commitment node_ctxt head in - let*! cementable = gather [] latest_cementable_commitment in + let* cementable = gather [] latest_cementable_commitment in match cementable with | [] -> return_nil | first_cementable :: _ -> diff --git a/src/proto_alpha/bin_sc_rollup_node/daemon.ml b/src/proto_alpha/bin_sc_rollup_node/daemon.ml index b46e5b40eb66..a4993399142d 100644 --- a/src/proto_alpha/bin_sc_rollup_node/daemon.ml +++ b/src/proto_alpha/bin_sc_rollup_node/daemon.ml @@ -51,7 +51,7 @@ module Make (PVM : Pvm.S) = struct let commitment_hash = Sc_rollup.Commitment.hash_uncarbonated commitment in - let*! () = + let* () = Node_context.set_commitment_published_at_level node_ctxt commitment_hash @@ -68,12 +68,12 @@ module Make (PVM : Pvm.S) = struct let commitment_hash = Sc_rollup.Commitment.hash_uncarbonated commitment in - let*! known_commitment = + let* known_commitment = Node_context.commitment_exists node_ctxt commitment_hash in if not known_commitment then return_unit else - let*! republication = + let* republication = Node_context.commitment_was_published node_ctxt ~source:Anyone @@ -228,7 +228,7 @@ module Make (PVM : Pvm.S) = struct let rec processed_finalized_block (node_ctxt : _ Node_context.t) Layer1.({hash; level} as block) = let open Lwt_result_syntax in - let*! last_finalized = Node_context.get_finalized_head_opt node_ctxt in + let* last_finalized = Node_context.get_finalized_head_opt node_ctxt in let already_finalized = match last_finalized with | Some finalized -> level <= Raw_level.to_int32 finalized.header.level @@ -242,14 +242,14 @@ module Make (PVM : Pvm.S) = struct in let*! () = Daemon_event.head_processing hash level ~finalized:true in let* () = process_l1_block_operations ~finalized:true node_ctxt block in - let*! () = Node_context.mark_finalized_head node_ctxt hash in + let* () = Node_context.mark_finalized_head node_ctxt hash in return_unit let process_head (node_ctxt : _ Node_context.t) Layer1.({hash; level} as head) = let open Lwt_result_syntax in let*! () = Daemon_event.head_processing hash level ~finalized:false in - let*! () = Node_context.save_level node_ctxt head in + let* () = Node_context.save_level node_ctxt head in let* inbox_hash, inbox, inbox_witness, messages, ctxt = Inbox.process_head node_ctxt head in @@ -303,7 +303,7 @@ module Make (PVM : Pvm.S) = struct head in let* () = processed_finalized_block node_ctxt finalized_block in - let*! () = Node_context.save_l2_head node_ctxt l2_block in + let* () = Node_context.save_l2_head node_ctxt l2_block in let*! () = Daemon_event.new_head_processed hash (Raw_level.to_int32 level) in @@ -331,7 +331,7 @@ module Make (PVM : Pvm.S) = struct imply the processing of head~3, etc). *) let on_layer_1_head node_ctxt head = let open Lwt_result_syntax in - let*! old_head = Node_context.last_processed_head_opt node_ctxt in + let* old_head = Node_context.last_processed_head_opt node_ctxt in let old_head = match old_head with | Some h -> @@ -432,7 +432,7 @@ module Make (PVM : Pvm.S) = struct let* () = Injector.shutdown () in let* () = message "Shutting down Batcher@." in let* () = Components.Batcher.shutdown () in - let* () = Node_context.close node_ctxt in + let* (_ : unit tzresult) = Node_context.close node_ctxt in let* () = Event.shutdown_node exit_status in Tezos_base_unix.Internal_event_unix.close () diff --git a/src/proto_alpha/bin_sc_rollup_node/inbox.ml b/src/proto_alpha/bin_sc_rollup_node/inbox.ml index 32eae4f34640..c1db7fda7d65 100644 --- a/src/proto_alpha/bin_sc_rollup_node/inbox.ml +++ b/src/proto_alpha/bin_sc_rollup_node/inbox.ml @@ -167,7 +167,7 @@ let process_head (node_ctxt : _ Node_context.t) in Metrics.Inbox.Stats.head_messages_list := messages_with_protocol_internal_messages ; - let*! () = + let* () = Node_context.save_messages node_ctxt witness_hash @@ -178,7 +178,7 @@ let process_head (node_ctxt : _ Node_context.t) } in let* () = same_inbox_as_layer_1 node_ctxt head_hash inbox in - let*! inbox_hash = Node_context.save_inbox node_ctxt inbox in + let* inbox_hash = Node_context.save_inbox node_ctxt inbox in return ( inbox_hash, inbox, diff --git a/src/proto_alpha/bin_sc_rollup_node/node_context.ml b/src/proto_alpha/bin_sc_rollup_node/node_context.ml index c7d2d10a0fac..83afc346b999 100644 --- a/src/proto_alpha/bin_sc_rollup_node/node_context.ml +++ b/src/proto_alpha/bin_sc_rollup_node/node_context.ml @@ -121,7 +121,7 @@ let init (cctxt : Protocol_client_context.full) dal_cctxt ~data_dir mode _; } as configuration) = let open Lwt_result_syntax in - let*! store = Store.load mode Configuration.(default_storage_dir data_dir) in + let* store = Store.load mode Configuration.(default_storage_dir data_dir) in let*! context = Context.load mode (Configuration.default_context_dir data_dir) in @@ -156,24 +156,26 @@ let init (cctxt : Protocol_client_context.full) dal_cctxt ~data_dir mode } let close {cctxt; store; context; l1_ctxt; _} = - let open Lwt_syntax in + let open Lwt_result_syntax in let message = cctxt#message in - let* () = message "Shutting down L1@." in - let* () = Layer1.shutdown l1_ctxt in - let* () = message "Closing context@." in - let* () = Context.close context in - let* () = message "Closing store@." in + let*! () = message "Shutting down L1@." in + let*! () = Layer1.shutdown l1_ctxt in + let*! () = message "Closing context@." in + let*! () = Context.close context in + let*! () = message "Closing store@." in let* () = Store.close store in return_unit let checkout_context node_ctxt block_hash = let open Lwt_result_syntax in - let*! l2_block = Store.L2_blocks.find node_ctxt.store block_hash in + let* l2_header = + Store.L2_blocks.header node_ctxt.store.l2_blocks block_hash + in let*? context_hash = - match l2_block with + match l2_header with | None -> error (Sc_rollup_node_errors.Cannot_checkout_context (block_hash, None)) - | Some {header = {context; _}; _} -> ok context + | Some {context; _} -> ok context in let*! ctxt = Context.checkout node_ctxt.context context_hash in match ctxt with @@ -213,161 +215,188 @@ let trace_lwt_result_with x = x let hash_of_level_opt {store; cctxt; _} level = - let open Lwt_syntax in - let* hash = Store.Levels_to_hashes.find store level in + let open Lwt_result_syntax in + let* hash = Store.Levels_to_hashes.find store.levels_to_hashes level in match hash with | Some hash -> return_some hash | None -> - let+ hash = + let*! hash = Tezos_shell_services.Shell_services.Blocks.hash cctxt ~chain:cctxt#chain ~block:(`Level level) () in - Result.to_option hash + return (Result.to_option hash) let hash_of_level node_ctxt level = let open Lwt_result_syntax in - let*! hash = hash_of_level_opt node_ctxt level in + let* hash = hash_of_level_opt node_ctxt level in match hash with | Some h -> return h | None -> failwith "Cannot retrieve hash of level %ld" level let level_of_hash {l1_ctxt; store; _} hash = let open Lwt_result_syntax in - let*! block = Store.L2_blocks.find store hash in - match block with - | Some {header = {level; _}; _} -> return (Raw_level.to_int32 level) + let* l2_header = Store.L2_blocks.header store.l2_blocks hash in + match l2_header with + | Some {level; _} -> return (Raw_level.to_int32 level) | None -> let+ {level; _} = Layer1.fetch_tezos_shell_header l1_ctxt hash in level let save_level {store; _} Layer1.{hash; level} = - Store.Levels_to_hashes.add store level hash + Store.Levels_to_hashes.add store.levels_to_hashes level hash let save_l2_head {store; _} (head : Sc_rollup_block.t) = - let open Lwt_syntax in - let* () = Store.L2_blocks.add store head.header.block_hash head in - Store.L2_head.set store head + let open Lwt_result_syntax in + let head_info = {head with header = (); content = ()} in + let* () = + Store.L2_blocks.append + store.l2_blocks + ~key:head.header.block_hash + ~header:head.header + ~value:head_info + in + Store.L2_head.write store.l2_head head -let is_processed {store; _} head = Store.L2_blocks.mem store head +let is_processed {store; _} head = Store.L2_blocks.mem store.l2_blocks head -let last_processed_head_opt {store; _} = Store.L2_head.find store +let last_processed_head_opt {store; _} = Store.L2_head.read store.l2_head let mark_finalized_head {store; _} head_hash = - let open Lwt_syntax in - let* block = Store.L2_blocks.find store head_hash in + let open Lwt_result_syntax in + let* block = Store.L2_blocks.read store.l2_blocks head_hash in match block with | None -> return_unit - | Some block -> Store.Last_finalized_head.set store block + | Some (block_info, header) -> + let block = {block_info with header} in + Store.Last_finalized_head.write store.last_finalized_head block -let get_finalized_head_opt {store; _} = Store.Last_finalized_head.find store +let get_finalized_head_opt {store; _} = + Store.Last_finalized_head.read store.last_finalized_head (* TODO: https://gitlab.com/tezos/tezos/-/issues/4532 Make this logarithmic, by storing pointers to muliple predecessor and by dichotomy. *) let block_before {store; _} tick = let open Lwt_result_syntax in - let*! head = Store.L2_head.find store in + let* head = Store.L2_head.read store.l2_head in match head with | None -> return_none | Some head -> let rec search block_hash = - let*! block = Store.L2_blocks.find store block_hash in + let* block = Store.L2_blocks.read store.l2_blocks block_hash in match block with | None -> failwith "Missing block %a" Block_hash.pp block_hash - | Some block -> - if Sc_rollup.Tick.(block.initial_tick <= tick) then - return_some block - else search block.header.predecessor + | Some (info, header) -> + if Sc_rollup.Tick.(info.initial_tick <= tick) then + return_some {info with header} + else search header.predecessor in search head.header.block_hash let get_l2_block {store; _} block_hash = - trace_lwt_with "Could not retrieve L2 block for %a" Block_hash.pp block_hash - @@ Store.L2_blocks.get store block_hash + let open Lwt_result_syntax in + let* block = Store.L2_blocks.read store.l2_blocks block_hash in + match block with + | None -> + failwith "Could not retrieve L2 block for %a" Block_hash.pp block_hash + | Some (info, header) -> return {info with Sc_rollup_block.header} -let find_l2_block {store; _} block_hash = Store.L2_blocks.find store block_hash +let find_l2_block {store; _} block_hash = + let open Lwt_result_syntax in + let+ block = Store.L2_blocks.read store.l2_blocks block_hash in + Option.map (fun (info, header) -> {info with Sc_rollup_block.header}) block let get_l2_block_by_level node_ctxt level = let open Lwt_result_syntax in trace_lwt_result_with "Could not retrieve L2 block at level %ld" level @@ let* block_hash = hash_of_level node_ctxt level in - let*! block = Store.L2_blocks.get node_ctxt.store block_hash in - return block + get_l2_block node_ctxt block_hash let find_l2_block_by_level node_ctxt level = - let open Lwt_option_syntax in + let open Lwt_result_syntax in let* block_hash = hash_of_level_opt node_ctxt level in - Store.L2_blocks.find node_ctxt.store block_hash - -let get_full_l2_block {store; _} block_hash = - let open Lwt_syntax in - let* block = Store.L2_blocks.get store block_hash in - let* inbox = Store.Inboxes.get store block.header.inbox_hash - and* {messages; _} = Store.Messages.get store block.header.inbox_witness - and* commitment = - Option.map_s (Store.Commitments.get store) block.header.commitment_hash - in - return {block with content = {Sc_rollup_block.inbox; messages; commitment}} + match block_hash with + | None -> return_none + | Some block_hash -> find_l2_block node_ctxt block_hash let get_commitment {store; _} commitment_hash = - trace_lwt_with - "Could not retrieve commitment %a" - Sc_rollup.Commitment.Hash.pp - commitment_hash - @@ Store.Commitments.get store commitment_hash + let open Lwt_result_syntax in + let* commitment = Store.Commitments.find store.commitments commitment_hash in + match commitment with + | None -> + failwith + "Could not retrieve commitment %a" + Sc_rollup.Commitment.Hash.pp + commitment_hash + | Some c -> return c -let find_commitment {store; _} hash = Store.Commitments.find store hash +let find_commitment {store; _} hash = + Store.Commitments.find store.commitments hash -let commitment_exists {store; _} hash = Store.Commitments.mem store hash +let commitment_exists {store; _} hash = + Store.Commitments.mem store.commitments hash let save_commitment {store; _} commitment = - let open Lwt_syntax in + let open Lwt_result_syntax in let hash = Sc_rollup.Commitment.hash_uncarbonated commitment in - let+ () = Store.Commitments.add store hash commitment in + let+ () = Store.Commitments.add store.commitments hash commitment in hash let commitment_published_at_level {store; _} commitment = - Store.Commitments_published_at_level.find store commitment + Store.Commitments_published_at_level.find + store.commitments_published_at_level + commitment let set_commitment_published_at_level {store; _} = - Store.Commitments_published_at_level.add store + Store.Commitments_published_at_level.add store.commitments_published_at_level type commitment_source = Anyone | Us let commitment_was_published {store; _} ~source commitment_hash = - let open Lwt_syntax in + let open Lwt_result_syntax in match source with - | Anyone -> Store.Commitments_published_at_level.mem store commitment_hash + | Anyone -> + Store.Commitments_published_at_level.mem + store.commitments_published_at_level + commitment_hash | Us -> ( let+ info = - Store.Commitments_published_at_level.find store commitment_hash + Store.Commitments_published_at_level.find + store.commitments_published_at_level + commitment_hash in match info with | Some {published_at_level = Some _; _} -> true | _ -> false) let get_inbox {store; _} inbox_hash = - trace_lwt_with - "Could not retrieve inbox %a" - Sc_rollup.Inbox.Hash.pp - inbox_hash - @@ Store.Inboxes.get store inbox_hash + let open Lwt_result_syntax in + let* inbox = Store.Inboxes.read store.inboxes inbox_hash in + match inbox with + | None -> + failwith "Could not retrieve inbox %a" Sc_rollup.Inbox.Hash.pp inbox_hash + | Some (i, ()) -> return i -let find_inbox {store; _} hash = Store.Inboxes.find store hash +let find_inbox {store; _} hash = + let open Lwt_result_syntax in + let+ inbox = Store.Inboxes.read store.inboxes hash in + Option.map fst inbox let save_inbox {store; _} inbox = - let open Lwt_syntax in + let open Lwt_result_syntax in let hash = Sc_rollup.Inbox.hash inbox in - let+ () = Store.Inboxes.add store hash inbox in + let+ () = Store.Inboxes.append store.inboxes ~key:hash ~value:inbox in hash -let find_inbox_by_block_hash {store; _} block_hash = - let open Lwt_option_syntax in - let* l2_block = Store.L2_blocks.find store block_hash in - Store.Inboxes.find store l2_block.header.inbox_hash +let find_inbox_by_block_hash ({store; _} as node_ctxt) block_hash = + let open Lwt_result_syntax in + let* header = Store.L2_blocks.header store.l2_blocks block_hash in + match header with + | None -> return_none + | Some {inbox_hash; _} -> find_inbox node_ctxt inbox_hash let genesis_inbox node_ctxt = let genesis_level = Raw_level.to_int32 node_ctxt.genesis_info.level in @@ -377,7 +406,7 @@ let genesis_inbox node_ctxt = let inbox_of_head node_ctxt Layer1.{hash = block_hash; level = block_level} = let open Lwt_result_syntax in - let*! possible_inbox = find_inbox_by_block_hash node_ctxt block_hash in + let* possible_inbox = find_inbox_by_block_hash node_ctxt block_hash in (* Pre-condition: forall l. (l > genesis_level) => inbox[l] <> None. *) match possible_inbox with | None -> @@ -408,16 +437,49 @@ let get_inbox_by_block_hash node_ctxt hash = let* level = level_of_hash node_ctxt hash in inbox_of_head node_ctxt {hash; level} -let get_messages {store; _} messages_hash = - trace_lwt_with - "Could not retrieve messages with payloads merkelized hash %a" - Sc_rollup.Inbox_merkelized_payload_hashes.Hash.pp - messages_hash - @@ Store.Messages.get store messages_hash - -let find_messages {store; _} hash = Store.Messages.find store hash +type messages_info = { + predecessor : Block_hash.t; + predecessor_timestamp : Timestamp.t; + messages : Sc_rollup.Inbox_message.t list; +} -let save_messages {store; _} = Store.Messages.add store +let get_messages {store; _} messages_hash = + let open Lwt_result_syntax in + let* msg = Store.Messages.read store.messages messages_hash in + match msg with + | None -> + failwith + "Could not retrieve messages with payloads merkelized hash %a" + Sc_rollup.Inbox_merkelized_payload_hashes.Hash.pp + messages_hash + | Some (messages, (predecessor, predecessor_timestamp)) -> + return {predecessor; predecessor_timestamp; messages} + +let find_messages {store; _} hash = + let open Lwt_result_syntax in + let+ msgs = Store.Messages.read store.messages hash in + Option.map + (fun (messages, (predecessor, predecessor_timestamp)) -> + {predecessor; predecessor_timestamp; messages}) + msgs + +let save_messages {store; _} key {predecessor; predecessor_timestamp; messages} + = + Store.Messages.append + store.messages + ~key + ~header:(predecessor, predecessor_timestamp) + ~value:messages + +let get_full_l2_block node_ctxt block_hash = + let open Lwt_result_syntax in + let* block = get_l2_block node_ctxt block_hash in + let* inbox = get_inbox node_ctxt block.header.inbox_hash + and* {messages; _} = get_messages node_ctxt block.header.inbox_witness + and* commitment = + Option.map_es (get_commitment node_ctxt) block.header.commitment_hash + in + return {block with content = {Sc_rollup_block.inbox; messages; commitment}} let get_slot_header {store; _} ~published_in_block_hash slot_index = trace_lwt_with @@ -427,47 +489,49 @@ let get_slot_header {store; _} ~published_in_block_hash slot_index = Block_hash.pp published_in_block_hash @@ Store.Dal_slots_headers.get - store + store.irmin_store ~primary_key:published_in_block_hash ~secondary_key:slot_index let get_all_slot_headers {store; _} ~published_in_block_hash = - Store.Dal_slots_headers.list_values store ~primary_key:published_in_block_hash + Store.Dal_slots_headers.list_values + store.irmin_store + ~primary_key:published_in_block_hash let get_slot_indexes {store; _} ~published_in_block_hash = Store.Dal_slots_headers.list_secondary_keys - store + store.irmin_store ~primary_key:published_in_block_hash let save_slot_header {store; _} ~published_in_block_hash (slot_header : Dal.Slot.Header.t) = Store.Dal_slots_headers.add - store + store.irmin_store ~primary_key:published_in_block_hash ~secondary_key:slot_header.id.index slot_header let processed_slot {store; _} ~confirmed_in_block_hash slot_index = Store.Dal_processed_slots.find - store + store.irmin_store ~primary_key:confirmed_in_block_hash ~secondary_key:slot_index let list_slot_pages {store; _} ~confirmed_in_block_hash = Store.Dal_slot_pages.list_secondary_keys_with_values - store + store.irmin_store ~primary_key:confirmed_in_block_hash let find_slot_page {store; _} ~confirmed_in_block_hash ~slot_index ~page_index = Store.Dal_slot_pages.find - store + store.irmin_store ~primary_key:confirmed_in_block_hash ~secondary_key:(slot_index, page_index) let save_unconfirmed_slot {store; _} current_block_hash slot_index = (* No page is actually saved *) Store.Dal_processed_slots.add - store + store.irmin_store ~primary_key:current_block_hash ~secondary_key:slot_index `Unconfirmed @@ -480,26 +544,26 @@ let save_confirmed_slot {store; _} current_block_hash slot_index pages = List.iteri_s (fun page_number page -> Store.Dal_slot_pages.add - store + store.irmin_store ~primary_key:current_block_hash ~secondary_key:(slot_index, page_number) page) pages in Store.Dal_processed_slots.add - store + store.irmin_store ~primary_key:current_block_hash ~secondary_key:slot_index `Confirmed let find_confirmed_slots_history {store; _} = - Store.Dal_confirmed_slots_history.find store + Store.Dal_confirmed_slots_history.find store.irmin_store let save_confirmed_slots_history {store; _} = - Store.Dal_confirmed_slots_history.add store + Store.Dal_confirmed_slots_history.add store.irmin_store let find_confirmed_slots_histories {store; _} = - Store.Dal_confirmed_slots_histories.find store + Store.Dal_confirmed_slots_histories.find store.irmin_store let save_confirmed_slots_histories {store; _} = - Store.Dal_confirmed_slots_histories.add store + Store.Dal_confirmed_slots_histories.add store.irmin_store diff --git a/src/proto_alpha/bin_sc_rollup_node/node_context.mli b/src/proto_alpha/bin_sc_rollup_node/node_context.mli index 4b255f17e7ad..637e50cd232c 100644 --- a/src/proto_alpha/bin_sc_rollup_node/node_context.mli +++ b/src/proto_alpha/bin_sc_rollup_node/node_context.mli @@ -104,7 +104,7 @@ val init : 'a t tzresult Lwt.t (** Closes the store, context and Layer 1 monitor. *) -val close : _ t -> unit Lwt.t +val close : _ t -> unit tzresult Lwt.t (** [checkout_context node_ctxt block_hash] returns the context at block [block_hash]. *) @@ -130,7 +130,7 @@ type 'a delayed_write = ('a, rw) Delayed_write_monad.t (** [is_processed store hash] returns [true] if the block with [hash] has already been processed by the daemon. *) -val is_processed : _ t -> Block_hash.t -> bool Lwt.t +val is_processed : _ t -> Block_hash.t -> bool tzresult Lwt.t (** [get_l2_block t hash] returns the Layer 2 block known by the rollup node for Layer 1 block [hash]. *) @@ -138,39 +138,42 @@ val get_l2_block : _ t -> Block_hash.t -> Sc_rollup_block.t tzresult Lwt.t (** Same as {!get_l2_block} but returns [None] when the Layer 2 block is not available. *) -val find_l2_block : _ t -> Block_hash.t -> Sc_rollup_block.t option Lwt.t +val find_l2_block : + _ t -> Block_hash.t -> Sc_rollup_block.t option tzresult Lwt.t (** Same as {!get_l2_block} but retrieves the Layer 2 block by its level. *) val get_l2_block_by_level : _ t -> int32 -> Sc_rollup_block.t tzresult Lwt.t (** Same as {!get_l2_block_by_level} but returns [None] when the Layer 2 block is not available. *) -val find_l2_block_by_level : _ t -> int32 -> Sc_rollup_block.t option Lwt.t +val find_l2_block_by_level : + _ t -> int32 -> Sc_rollup_block.t option tzresult Lwt.t (** [get_full_l2_block node_ctxt hash] returns the full L2 block for L1 block hash [hash]. The result contains the L2 block and its content (inbox, messages, commitment). *) -val get_full_l2_block : _ t -> Block_hash.t -> Sc_rollup_block.full Lwt.t +val get_full_l2_block : + _ t -> Block_hash.t -> Sc_rollup_block.full tzresult Lwt.t (** [save_level t head] registers the correspondences [head.level |-> head.hash] in the store. *) -val save_level : rw -> Layer1.head -> unit Lwt.t +val save_level : rw -> Layer1.head -> unit tzresult Lwt.t -(** [save_l2_head t l2_block] remembers that the [l2_block.head] is +(** [save_l2_head t l2_block] remembers that the [l2_block.head] is processed. The system should not have to come back to it. *) -val save_l2_head : rw -> Sc_rollup_block.t -> unit Lwt.t +val save_l2_head : rw -> Sc_rollup_block.t -> unit tzresult Lwt.t (** [last_processed_head_opt store] returns the last processed head if it exists. *) -val last_processed_head_opt : _ t -> Sc_rollup_block.t option Lwt.t +val last_processed_head_opt : _ t -> Sc_rollup_block.t option tzresult Lwt.t (** [mark_finalized_head store head] remembers that the [head] is finalized. By construction, every block whose level is smaller than [head]'s is also finalized. *) -val mark_finalized_head : rw -> Block_hash.t -> unit Lwt.t +val mark_finalized_head : rw -> Block_hash.t -> unit tzresult Lwt.t (** [last_finalized_head_opt store] returns the last finalized head if it exists. *) -val get_finalized_head_opt : _ t -> Sc_rollup_block.t option Lwt.t +val get_finalized_head_opt : _ t -> Sc_rollup_block.t option tzresult Lwt.t (** [hash_of_level node_ctxt level] returns the current block hash for a given [level]. *) @@ -178,7 +181,7 @@ val hash_of_level : _ t -> int32 -> Block_hash.t tzresult Lwt.t (** [hash_of_level_opt] is like {!hash_of_level} but returns [None] if the [level] is not known. *) -val hash_of_level_opt : _ t -> int32 -> Block_hash.t option Lwt.t +val hash_of_level_opt : _ t -> int32 -> Block_hash.t option tzresult Lwt.t (** [level_of_hash node_ctxt hash] returns the level for Tezos block hash [hash] if it is known by the Tezos Layer 1 node. *) @@ -199,16 +202,19 @@ val get_commitment : (** Same as {!get_commitment} but returns [None] if this commitment hash is not known by the rollup node. *) val find_commitment : - _ t -> Sc_rollup.Commitment.Hash.t -> Sc_rollup.Commitment.t option Lwt.t + _ t -> + Sc_rollup.Commitment.Hash.t -> + Sc_rollup.Commitment.t option tzresult Lwt.t (** [commitment_exists t hash] returns [true] if the commitment with [hash] is known (i.e. stored) by the rollup node. *) -val commitment_exists : _ t -> Sc_rollup.Commitment.Hash.t -> bool Lwt.t +val commitment_exists : + _ t -> Sc_rollup.Commitment.Hash.t -> bool tzresult Lwt.t (** [save_commitment t commitment] saves a commitment in the store an returns is hash. *) val save_commitment : - rw -> Sc_rollup.Commitment.t -> Sc_rollup.Commitment.Hash.t Lwt.t + rw -> Sc_rollup.Commitment.t -> Sc_rollup.Commitment.Hash.t tzresult Lwt.t (** [commitment_published_at_level t hash] returns the levels at which the commitment was first published and the one at which it was included by in a @@ -218,7 +224,7 @@ val save_commitment : val commitment_published_at_level : _ t -> Sc_rollup.Commitment.Hash.t -> - Store.Commitments_published_at_level.element option Lwt.t + Store.Commitments_published_at_level.element option tzresult Lwt.t (** [save_commitment_published_at_level t hash levels] saves the publication/inclusion information for a commitment with [hash]. *) @@ -226,7 +232,7 @@ val set_commitment_published_at_level : rw -> Sc_rollup.Commitment.Hash.t -> Store.Commitments_published_at_level.element -> - unit Lwt.t + unit tzresult Lwt.t type commitment_source = Anyone | Us @@ -235,21 +241,32 @@ type commitment_source = Anyone | Us the publication status for commitments we published ourselves [`Us] or that [`Anyone] published. *) val commitment_was_published : - _ t -> source:commitment_source -> Sc_rollup.Commitment.Hash.t -> bool Lwt.t + _ t -> + source:commitment_source -> + Sc_rollup.Commitment.Hash.t -> + bool tzresult Lwt.t (** {3 Inboxes} *) +type messages_info = { + predecessor : Block_hash.t; + predecessor_timestamp : Timestamp.t; + messages : Sc_rollup.Inbox_message.t list; +} + (** [get_inbox t inbox_hash] retrieves the inbox whose hash is [inbox_hash] from the rollup node's storage. *) val get_inbox : _ t -> Sc_rollup.Inbox.Hash.t -> Sc_rollup.Inbox.t tzresult Lwt.t (** Same as {!get_inbox} but returns [None] if this inbox is not known. *) -val find_inbox : _ t -> Sc_rollup.Inbox.Hash.t -> Sc_rollup.Inbox.t option Lwt.t +val find_inbox : + _ t -> Sc_rollup.Inbox.Hash.t -> Sc_rollup.Inbox.t option tzresult Lwt.t (** [save_inbox t inbox] remembers the [inbox] in the storage. It is associated to its hash which is returned. *) -val save_inbox : rw -> Sc_rollup.Inbox.t -> Sc_rollup.Inbox.Hash.t Lwt.t +val save_inbox : + rw -> Sc_rollup.Inbox.t -> Sc_rollup.Inbox.Hash.t tzresult Lwt.t (** [inbox_of_head node_ctxt block] returns the latest inbox at the given [block]. This function always returns [inbox] for all levels at and @@ -269,13 +286,13 @@ val genesis_inbox : _ t -> Sc_rollup.Inbox.t tzresult Lwt.t val get_messages : _ t -> Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t -> - Store.Messages.info tzresult Lwt.t + messages_info tzresult Lwt.t (** Same as {!get_messages} but returns [None] if the payloads hash is not known. *) val find_messages : _ t -> Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t -> - Store.Messages.info option Lwt.t + messages_info option tzresult Lwt.t (** [save_messages t payloads_hash messages] associates the list of [messages] to the [payloads_hash]. The payload hash must be computed by calling, @@ -283,8 +300,8 @@ val find_messages : val save_messages : rw -> Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t -> - Store.Messages.info -> - unit Lwt.t + messages_info -> + unit tzresult Lwt.t (** {3 DAL} *) diff --git a/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml b/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml index cafd561296a1..e231d517da4e 100644 --- a/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml +++ b/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml @@ -224,9 +224,18 @@ module Make (Interpreter : Interpreter.S) : let inbox = snapshot let get_history inbox_hash = - let open Lwt_option_syntax in + let open Lwt_syntax in let+ inbox = Node_context.find_inbox node_ctxt inbox_hash in - Sc_rollup.Inbox.take_snapshot inbox + match inbox with + | Error err -> + Format.kasprintf + Stdlib.failwith + "Refutation game: Cannot get inbox history for %a, %a" + Sc_rollup.Inbox.Hash.pp + inbox_hash + pp_print_trace + err + | Ok inbox -> Option.map Sc_rollup.Inbox.take_snapshot inbox let get_payloads_history witness = Lwt.map -- GitLab From 9fcce51fc7a39fcb7c531d863270111fe7bb7d8e Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Fri, 6 Jan 2023 11:16:24 +0100 Subject: [PATCH 3/6] SCORU/Node: store number of messages in index (header) for efficiency This allows to not read all messages from the disk when we care only about their number. (cherry picked from commit ddd2a2dfeea4247a8f9b151ccb86eb89e25f1801) --- .../bin_sc_rollup_node/RPC_server.ml | 6 +++--- .../bin_sc_rollup_node/node_context.ml | 18 +++++++++++++++--- .../bin_sc_rollup_node/node_context.mli | 6 ++++++ src/proto_alpha/bin_sc_rollup_node/store.ml | 5 +++-- src/proto_alpha/bin_sc_rollup_node/store.mli | 2 +- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml b/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml index 18c8b1a7c999..b8002f3890a4 100644 --- a/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml +++ b/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml @@ -227,10 +227,10 @@ module Common = struct @@ fun (node_ctxt, block) () () -> let open Lwt_result_syntax in let* l2_block = Node_context.get_l2_block node_ctxt block in - let* {messages; _} = - Node_context.get_messages node_ctxt l2_block.header.inbox_witness + let+ num_messages = + Node_context.get_num_messages node_ctxt l2_block.header.inbox_witness in - return @@ Z.of_int (List.length messages) + Z.of_int num_messages let () = Global_directory.register0 Sc_rollup_services.Global.sc_rollup_address diff --git a/src/proto_alpha/bin_sc_rollup_node/node_context.ml b/src/proto_alpha/bin_sc_rollup_node/node_context.ml index 83afc346b999..12ae125a43a4 100644 --- a/src/proto_alpha/bin_sc_rollup_node/node_context.ml +++ b/src/proto_alpha/bin_sc_rollup_node/node_context.ml @@ -452,23 +452,35 @@ let get_messages {store; _} messages_hash = "Could not retrieve messages with payloads merkelized hash %a" Sc_rollup.Inbox_merkelized_payload_hashes.Hash.pp messages_hash - | Some (messages, (predecessor, predecessor_timestamp)) -> + | Some (messages, (predecessor, predecessor_timestamp, _num_messages)) -> return {predecessor; predecessor_timestamp; messages} let find_messages {store; _} hash = let open Lwt_result_syntax in let+ msgs = Store.Messages.read store.messages hash in Option.map - (fun (messages, (predecessor, predecessor_timestamp)) -> + (fun (messages, (predecessor, predecessor_timestamp, _num_messages)) -> {predecessor; predecessor_timestamp; messages}) msgs +let get_num_messages {store; _} hash = + let open Lwt_result_syntax in + let* header = Store.Messages.header store.messages hash in + match header with + | None -> + failwith + "Could not retrieve number of messages for inbox witness %a" + Sc_rollup.Inbox_merkelized_payload_hashes.Hash.pp + hash + | Some (_predecessor, _predecessor_timestamp, num_messages) -> + return num_messages + let save_messages {store; _} key {predecessor; predecessor_timestamp; messages} = Store.Messages.append store.messages ~key - ~header:(predecessor, predecessor_timestamp) + ~header:(predecessor, predecessor_timestamp, List.length messages) ~value:messages let get_full_l2_block node_ctxt block_hash = diff --git a/src/proto_alpha/bin_sc_rollup_node/node_context.mli b/src/proto_alpha/bin_sc_rollup_node/node_context.mli index 637e50cd232c..252c3191ea7d 100644 --- a/src/proto_alpha/bin_sc_rollup_node/node_context.mli +++ b/src/proto_alpha/bin_sc_rollup_node/node_context.mli @@ -294,6 +294,12 @@ val find_messages : Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t -> messages_info option tzresult Lwt.t +(** [get_num_messages t witness_hash] retrieves (without reading all the messages + from disk) the number of messages for the inbox witness [witness_hash] + stored by the rollup node. *) +val get_num_messages : + _ t -> Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t -> int tzresult Lwt.t + (** [save_messages t payloads_hash messages] associates the list of [messages] to the [payloads_hash]. The payload hash must be computed by calling, e.g. {!Sc_rollup.Inbox.add_all_messages}. *) diff --git a/src/proto_alpha/bin_sc_rollup_node/store.ml b/src/proto_alpha/bin_sc_rollup_node/store.ml index 9b459d85b7ed..5eb38c22c5f5 100644 --- a/src/proto_alpha/bin_sc_rollup_node/store.ml +++ b/src/proto_alpha/bin_sc_rollup_node/store.ml @@ -104,15 +104,16 @@ module Messages = Data_encoding.(list @@ dynamic_size Sc_rollup.Inbox_message.encoding) module Header = struct - type t = Block_hash.t * Timestamp.t + type t = Block_hash.t * Timestamp.t * int let name = "messages_inbox_info" let encoding = let open Data_encoding in - obj2 + obj3 (req "predecessor" Block_hash.encoding) (req "predecessor_timestamp" Timestamp.encoding) + (req "num_messages" int31) let fixed_size = WithExceptions.Option.get ~loc:__LOC__ diff --git a/src/proto_alpha/bin_sc_rollup_node/store.mli b/src/proto_alpha/bin_sc_rollup_node/store.mli index 9af7a1b7731d..11baf20ca241 100644 --- a/src/proto_alpha/bin_sc_rollup_node/store.mli +++ b/src/proto_alpha/bin_sc_rollup_node/store.mli @@ -40,7 +40,7 @@ module Messages : INDEXED_FILE with type key := Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t and type value := Sc_rollup.Inbox_message.t list - and type header := Block_hash.t * Timestamp.t + and type header := Block_hash.t * Timestamp.t * int (** Aggregated collection of messages from the L1 inbox *) module Inboxes : -- GitLab From 7c3bad485b3f44a59a73c2609c28a5a03f6934d2 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Mon, 23 Jan 2023 18:07:34 +0100 Subject: [PATCH 4/6] SCORU/Node: configurable L2 blocks cache size (cherry picked from commit 7377419a75b136f8d65496786a977e25234ce390) --- .../bin_sc_rollup_node/configuration.ml | 22 +++++++++++++++---- .../bin_sc_rollup_node/configuration.mli | 5 +++++ .../main_sc_rollup_node_alpha.ml | 1 + .../bin_sc_rollup_node/node_context.ml | 8 ++++++- src/proto_alpha/bin_sc_rollup_node/store.ml | 5 +++-- src/proto_alpha/bin_sc_rollup_node/store.mli | 18 ++++++++++----- 6 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/configuration.ml b/src/proto_alpha/bin_sc_rollup_node/configuration.ml index a599a2cf6f92..5f9cabd156fc 100644 --- a/src/proto_alpha/bin_sc_rollup_node/configuration.ml +++ b/src/proto_alpha/bin_sc_rollup_node/configuration.ml @@ -64,6 +64,7 @@ type t = { dal_node_port : int; batcher : batcher; injector_retention_period : int; + l2_blocks_cache_size : int; } let default_data_dir = @@ -225,6 +226,8 @@ let max_injector_retention_period = let default_injector_retention_period = 2048 +let default_l2_blocks_cache_size = 64 + let string_of_purpose = function | Publish -> "publish" | Add_messages -> "add_messages" @@ -490,6 +493,7 @@ let encoding : t Data_encoding.t = dal_node_port; batcher; injector_retention_period; + l2_blocks_cache_size; } -> ( ( sc_rollup_address, sc_rollup_node_operators, @@ -500,7 +504,11 @@ let encoding : t Data_encoding.t = fee_parameters, mode, loser_mode ), - (dal_node_addr, dal_node_port, batcher, injector_retention_period) )) + ( dal_node_addr, + dal_node_port, + batcher, + injector_retention_period, + l2_blocks_cache_size ) )) (fun ( ( sc_rollup_address, sc_rollup_node_operators, rpc_addr, @@ -510,7 +518,11 @@ let encoding : t Data_encoding.t = fee_parameters, mode, loser_mode ), - (dal_node_addr, dal_node_port, batcher, injector_retention_period) ) -> + ( dal_node_addr, + dal_node_port, + batcher, + injector_retention_period, + l2_blocks_cache_size ) ) -> if injector_retention_period > max_injector_retention_period then Format.ksprintf Stdlib.failwith @@ -530,6 +542,7 @@ let encoding : t Data_encoding.t = dal_node_port; batcher; injector_retention_period; + l2_blocks_cache_size; }) (merge_objs (obj9 @@ -569,14 +582,15 @@ let encoding : t Data_encoding.t = test only!)" Loser_mode.encoding Loser_mode.no_failures)) - (obj4 + (obj5 (dft "DAL node address" string default_dal_node_addr) (dft "DAL node port" int16 default_dal_node_port) (dft "batcher" batcher_encoding default_batcher) (dft "injector_retention_period" uint16 - default_injector_retention_period))) + default_injector_retention_period) + (dft "l2_blocks_cache_size" int31 default_l2_blocks_cache_size))) let check_mode config = let open Result_syntax in diff --git a/src/proto_alpha/bin_sc_rollup_node/configuration.mli b/src/proto_alpha/bin_sc_rollup_node/configuration.mli index 73237ec9044b..5cab9d3af0eb 100644 --- a/src/proto_alpha/bin_sc_rollup_node/configuration.mli +++ b/src/proto_alpha/bin_sc_rollup_node/configuration.mli @@ -82,6 +82,7 @@ type t = { dal_node_port : int; batcher : batcher; injector_retention_period : int; + l2_blocks_cache_size : int; } (** [make_purpose_map ~default purposes] constructs a purpose map from a list of @@ -143,6 +144,10 @@ val default_batcher : batcher injector will keep in memory. *) val default_injector_retention_period : int +(** [default_l2_blocks_cache_size] is the default number of L2 blocks that are + cached by the rollup node *) +val default_l2_blocks_cache_size : int + (** [max_injector_retention_period] is the maximum allowed value for [injector_retention_period]. *) val max_injector_retention_period : int diff --git a/src/proto_alpha/bin_sc_rollup_node/main_sc_rollup_node_alpha.ml b/src/proto_alpha/bin_sc_rollup_node/main_sc_rollup_node_alpha.ml index 73630aba5c02..7b403a013ca7 100644 --- a/src/proto_alpha/bin_sc_rollup_node/main_sc_rollup_node_alpha.ml +++ b/src/proto_alpha/bin_sc_rollup_node/main_sc_rollup_node_alpha.ml @@ -293,6 +293,7 @@ let config_init_command = loser_mode; batcher = Configuration.default_batcher; injector_retention_period; + l2_blocks_cache_size = Configuration.default_l2_blocks_cache_size; } in let*? config = check_mode config in diff --git a/src/proto_alpha/bin_sc_rollup_node/node_context.ml b/src/proto_alpha/bin_sc_rollup_node/node_context.ml index 12ae125a43a4..660b1f868b12 100644 --- a/src/proto_alpha/bin_sc_rollup_node/node_context.ml +++ b/src/proto_alpha/bin_sc_rollup_node/node_context.ml @@ -118,10 +118,16 @@ let init (cctxt : Protocol_client_context.full) dal_cctxt ~data_dir mode sc_rollup_node_operators = operators; fee_parameters; loser_mode; + l2_blocks_cache_size; _; } as configuration) = let open Lwt_result_syntax in - let* store = Store.load mode Configuration.(default_storage_dir data_dir) in + let* store = + Store.load + mode + ~l2_blocks_cache_size + Configuration.(default_storage_dir data_dir) + in let*! context = Context.load mode (Configuration.default_context_dir data_dir) in diff --git a/src/proto_alpha/bin_sc_rollup_node/store.ml b/src/proto_alpha/bin_sc_rollup_node/store.ml index 5eb38c22c5f5..62b2404dd3ce 100644 --- a/src/proto_alpha/bin_sc_rollup_node/store.ml +++ b/src/proto_alpha/bin_sc_rollup_node/store.ml @@ -444,10 +444,11 @@ let close and+ () = Irmin_store.close irmin_store |> Lwt_result.ok in () -let load (type a) (mode : a mode) data_dir : a store tzresult Lwt.t = +let load (type a) (mode : a mode) ~l2_blocks_cache_size data_dir : + a store tzresult Lwt.t = let open Lwt_result_syntax in let path name = Filename.concat data_dir name in - let cache_size = 10_000 in + let cache_size = l2_blocks_cache_size in let* l2_blocks = L2_blocks.load mode ~path:(path "l2_blocks") ~cache_size in let* messages = Messages.load mode ~path:(path "messages") ~cache_size in let* inboxes = Inboxes.load mode ~path:(path "inboxes") ~cache_size in diff --git a/src/proto_alpha/bin_sc_rollup_node/store.mli b/src/proto_alpha/bin_sc_rollup_node/store.mli index 11baf20ca241..252c0f25c100 100644 --- a/src/proto_alpha/bin_sc_rollup_node/store.mli +++ b/src/proto_alpha/bin_sc_rollup_node/store.mli @@ -160,12 +160,18 @@ type ro = Store_sigs.ro t (** [close store] closes the store. *) val close : _ t -> unit tzresult Lwt.t -(** [load mode directory] loads a store from the data persisted in - [directory]. If [mode] is {!Store_sigs.Read_only}, then the indexes and - irmin store will be opened in readonly mode and only read operations will be - permitted. This allows to open a store for read access that is already - opened in {!Store_sigs.Read_write} mode in another process. *) -val load : 'a Store_sigs.mode -> string -> 'a store tzresult Lwt.t +(** [load mode ~l2_blocks_cache_size directory] loads a store from the data + persisted in [directory]. If [mode] is {!Store_sigs.Read_only}, then the + indexes and irmin store will be opened in readonly mode and only read + operations will be permitted. This allows to open a store for read access + that is already opened in {!Store_sigs.Read_write} mode in another + process. [l2_blocks_cache_size] is the number of L2 blocks the rollup node + will keep in memory. *) +val load : + 'a Store_sigs.mode -> + l2_blocks_cache_size:int -> + string -> + 'a store tzresult Lwt.t (** [readonly store] returns a read-only version of [store]. *) val readonly : _ t -> ro -- GitLab From b67193bbfbc26c82c07e1e23a5026eebb0ff9db9 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 3 Jan 2023 19:06:03 +0100 Subject: [PATCH 5/6] SCORU/Node: Backport !7251 to Mumbai - SCORU/Node: Store uses indexed files - SCORU/Node: new interface for store access through node context - SCORU/Node: store number of messages in index (header) for efficiency - SCORU/Node: configurable L2 blocks cache size (cherry picked from commit 2dc0269ba3002cb14daf8bc5dd78edabe8a6fb39) --- .../bin_sc_rollup_node/RPC_server.ml | 106 +++--- .../bin_sc_rollup_node/commitment.ml | 52 ++- .../bin_sc_rollup_node/configuration.ml | 22 +- .../bin_sc_rollup_node/configuration.mli | 5 + .../bin_sc_rollup_node/daemon.ml | 18 +- .../bin_sc_rollup_node/inbox.ml | 4 +- .../main_sc_rollup_node_016_PtMumbai.ml | 1 + .../bin_sc_rollup_node/node_context.ml | 282 +++++++++----- .../bin_sc_rollup_node/node_context.mli | 71 ++-- .../bin_sc_rollup_node/refutation_game.ml | 13 +- .../bin_sc_rollup_node/store.ml | 345 +++++++++++------- .../bin_sc_rollup_node/store.mli | 130 ++++--- 12 files changed, 640 insertions(+), 409 deletions(-) diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml index 454e1e15d14e..b8002f3890a4 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml @@ -52,18 +52,19 @@ let get_last_cemented (node_ctxt : _ Node_context.t) = return lcc_hash let get_head_hash_opt node_ctxt = - let open Lwt_option_syntax in - let+ {header = {block_hash; _}; _} = - Node_context.last_processed_head_opt node_ctxt - in - block_hash + let open Lwt_result_syntax in + let+ res = Node_context.last_processed_head_opt node_ctxt in + Option.map + (fun Sc_rollup_block.{header = {block_hash; _}; _} -> block_hash) + res let get_head_level_opt node_ctxt = - let open Lwt_option_syntax in - let+ {header = {level; _}; _} = - Node_context.last_processed_head_opt node_ctxt - in - Alpha_context.Raw_level.to_int32 level + let open Lwt_result_syntax in + let+ res = Node_context.last_processed_head_opt node_ctxt in + Option.map + (fun Sc_rollup_block.{header = {level; _}; _} -> + Alpha_context.Raw_level.to_int32 level) + res module Slot_pages_map = struct open Protocol @@ -219,19 +220,17 @@ module Common = struct let () = Block_directory.register0 Sc_rollup_services.Global.Block.block @@ fun (node_ctxt, block) () () -> - let open Lwt_result_syntax in - let*! b = Node_context.get_full_l2_block node_ctxt block in - return b + Node_context.get_full_l2_block node_ctxt block let () = Block_directory.register0 Sc_rollup_services.Global.Block.num_messages @@ fun (node_ctxt, block) () () -> let open Lwt_result_syntax in let* l2_block = Node_context.get_l2_block node_ctxt block in - let* {messages; _} = - Node_context.get_messages node_ctxt l2_block.header.inbox_witness + let+ num_messages = + Node_context.get_num_messages node_ctxt l2_block.header.inbox_witness in - return @@ Z.of_int (List.length messages) + Z.of_int num_messages let () = Global_directory.register0 Sc_rollup_services.Global.sc_rollup_address @@ -239,11 +238,11 @@ module Common = struct let () = Global_directory.register0 Sc_rollup_services.Global.current_tezos_head - @@ fun node_ctxt () () -> get_head_hash_opt node_ctxt >>= return + @@ fun node_ctxt () () -> get_head_hash_opt node_ctxt let () = Global_directory.register0 Sc_rollup_services.Global.current_tezos_level - @@ fun node_ctxt () () -> get_head_level_opt node_ctxt >>= return + @@ fun node_ctxt () () -> get_head_level_opt node_ctxt let () = Block_directory.register0 Sc_rollup_services.Global.Block.hash @@ -370,44 +369,41 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct Global_directory.register0 Sc_rollup_services.Global.last_stored_commitment @@ fun node_ctxt () () -> let open Lwt_result_syntax in - let*! res = - let open Lwt_option_syntax in - let* head = Node_context.last_processed_head_opt node_ctxt in - let commitment_hash = - Sc_rollup_block.most_recent_commitment head.header - in - let* commitment = - Node_context.find_commitment node_ctxt commitment_hash - in - return (commitment, commitment_hash) - in - return res + let* head = Node_context.last_processed_head_opt node_ctxt in + match head with + | None -> return_none + | Some head -> + let commitment_hash = + Sc_rollup_block.most_recent_commitment head.header + in + let+ commitment = + Node_context.find_commitment node_ctxt commitment_hash + in + Option.map (fun c -> (c, commitment_hash)) commitment let () = Local_directory.register0 Sc_rollup_services.Local.last_published_commitment @@ fun node_ctxt () () -> let open Lwt_result_syntax in - let*! result = - let open Lwt_option_syntax in - let*? commitment = node_ctxt.lpc in - let hash = - Alpha_context.Sc_rollup.Commitment.hash_uncarbonated commitment - in - (* The corresponding level in Store.Commitments.published_at_level is - available only when the commitment has been published and included - in a block. *) - let*! published_at_level_info = - Node_context.commitment_published_at_level node_ctxt hash - in - let first_published, published = - match published_at_level_info with - | None -> (None, None) - | Some {first_published_at_level; published_at_level} -> - (Some first_published_at_level, published_at_level) - in - return (commitment, hash, first_published, published) - in - return result + match node_ctxt.lpc with + | None -> return_none + | Some commitment -> + let hash = + Alpha_context.Sc_rollup.Commitment.hash_uncarbonated commitment + in + (* The corresponding level in Store.Commitments.published_at_level is + available only when the commitment has been published and included + in a block. *) + let* published_at_level_info = + Node_context.commitment_published_at_level node_ctxt hash + in + let first_published, published = + match published_at_level_info with + | None -> (None, None) + | Some {first_published_at_level; published_at_level} -> + (Some first_published_at_level, published_at_level) + in + return_some (commitment, hash, first_published, published) let () = Block_directory.register0 Sc_rollup_services.Global.Block.status @@ -497,7 +493,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct let inbox_info_of_level (node_ctxt : _ Node_context.t) inbox_level = let open Alpha_context in - let open Lwt_syntax in + let open Lwt_result_syntax in let+ finalized_head = Node_context.get_finalized_head_opt node_ctxt in let finalized = match finalized_head with @@ -530,7 +526,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct | Some (Injected info) -> return (Sc_rollup_services.Injected info) | Some (Included info) -> ( - let*! inbox_info = + let* inbox_info = inbox_info_of_level node_ctxt info.l1_level in let commitment_level = @@ -540,7 +536,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct | None -> return (Sc_rollup_services.Included (info, inbox_info)) | Some commitment_level -> ( - let*! block = + let* block = Node_context.find_l2_block_by_level node_ctxt (Alpha_context.Raw_level.to_int32 commitment_level) @@ -557,7 +553,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct block.header.commitment_hash in (* Commitment computed *) - let*! published_at = + let* published_at = Node_context.commitment_published_at_level node_ctxt commitment_hash diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/commitment.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/commitment.ml index 264d970213bc..a0e6952917e7 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/commitment.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/commitment.ml @@ -44,6 +44,21 @@ open Protocol open Alpha_context +module Lwt_result_option_syntax = struct + let ( let** ) a f = + let open Lwt_result_syntax in + let* a = a in + match a with None -> return_none | Some a -> f a +end + +module Lwt_result_option_list_syntax = struct + (** A small monadic combinator to return an empty list on None results. *) + let ( let*& ) x f = + let open Lwt_result_syntax in + let* x = x in + match x with None -> return_nil | Some x -> f x +end + let add_level level increment = (* We only use this function with positive increments so it is safe *) if increment < 0 then invalid_arg "Commitment.add_level negative increment" ; @@ -161,13 +176,13 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct match commitment with | None -> return_none | Some commitment -> - let*! commitment_hash = + let* commitment_hash = Node_context.save_commitment node_ctxt commitment in return_some commitment_hash let missing_commitments (node_ctxt : _ Node_context.t) = - let open Lwt_syntax in + let open Lwt_result_syntax in let lpc_level = match node_ctxt.lpc with | None -> node_ctxt.genesis_info.level @@ -246,11 +261,12 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct (* Commitments can only be cemented after [sc_rollup_challenge_window] has passed since they were first published. *) let earliest_cementing_level node_ctxt commitment_hash = - let open Lwt_option_syntax in - let+ {first_published_at_level; _} = + let open Lwt_result_option_syntax in + let** {first_published_at_level; _} = Node_context.commitment_published_at_level node_ctxt commitment_hash in - add_level first_published_at_level (sc_rollup_challenge_window node_ctxt) + return_some + @@ add_level first_published_at_level (sc_rollup_challenge_window node_ctxt) (** [latest_cementable_commitment node_ctxt head] is the most recent commitment hash that could be cemented in [head]'s successor if: @@ -262,15 +278,17 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct start the search for cementable commitments. *) let latest_cementable_commitment (node_ctxt : _ Node_context.t) (head : Sc_rollup_block.t) = - let open Lwt_option_syntax in + let open Lwt_result_option_syntax in let commitment_hash = Sc_rollup_block.most_recent_commitment head.header in - let* commitment = Node_context.find_commitment node_ctxt commitment_hash in - let*? cementable_level_bound = - sub_level commitment.inbox_level (sc_rollup_challenge_window node_ctxt) + let** commitment = Node_context.find_commitment node_ctxt commitment_hash in + let** cementable_level_bound = + return + @@ sub_level commitment.inbox_level (sc_rollup_challenge_window node_ctxt) in - if Raw_level.(cementable_level_bound <= node_ctxt.lcc.level) then fail + if Raw_level.(cementable_level_bound <= node_ctxt.lcc.level) then + return_none else - let* cementable_bound_block = + let** cementable_bound_block = Node_context.find_l2_block_by_level node_ctxt (Raw_level.to_int32 cementable_level_bound) @@ -278,20 +296,14 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct let cementable_commitment = Sc_rollup_block.most_recent_commitment cementable_bound_block.header in - return cementable_commitment + return_some cementable_commitment let cementable_commitments (node_ctxt : _ Node_context.t) = let open Lwt_result_syntax in - let ( let*& ) x f = - (* A small monadic combinator to return an empty list of cementable - commitments on None results. *) - let*! x = x in - match x with None -> return_nil | Some x -> f x - in + let open Lwt_result_option_list_syntax in let*& head = Node_context.last_processed_head_opt node_ctxt in let head_level = head.header.level in let rec gather acc (commitment_hash : Sc_rollup.Commitment.Hash.t) = - let open Lwt_syntax in let* commitment = Node_context.find_commitment node_ctxt commitment_hash in @@ -325,7 +337,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct let*& latest_cementable_commitment = latest_cementable_commitment node_ctxt head in - let*! cementable = gather [] latest_cementable_commitment in + let* cementable = gather [] latest_cementable_commitment in match cementable with | [] -> return_nil | first_cementable :: _ -> diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/configuration.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/configuration.ml index 92e338776b9c..0be028d6a578 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/configuration.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/configuration.ml @@ -64,6 +64,7 @@ type t = { dal_node_port : int; batcher : batcher; injector_retention_period : int; + l2_blocks_cache_size : int; } let default_data_dir = @@ -225,6 +226,8 @@ let max_injector_retention_period = let default_injector_retention_period = 2048 +let default_l2_blocks_cache_size = 64 + let string_of_purpose = function | Publish -> "publish" | Add_messages -> "add_messages" @@ -491,6 +494,7 @@ let encoding : t Data_encoding.t = dal_node_port; batcher; injector_retention_period; + l2_blocks_cache_size; } -> ( ( sc_rollup_address, sc_rollup_node_operators, @@ -501,7 +505,11 @@ let encoding : t Data_encoding.t = fee_parameters, mode, loser_mode ), - (dal_node_addr, dal_node_port, batcher, injector_retention_period) )) + ( dal_node_addr, + dal_node_port, + batcher, + injector_retention_period, + l2_blocks_cache_size ) )) (fun ( ( sc_rollup_address, sc_rollup_node_operators, rpc_addr, @@ -511,7 +519,11 @@ let encoding : t Data_encoding.t = fee_parameters, mode, loser_mode ), - (dal_node_addr, dal_node_port, batcher, injector_retention_period) ) -> + ( dal_node_addr, + dal_node_port, + batcher, + injector_retention_period, + l2_blocks_cache_size ) ) -> if injector_retention_period > max_injector_retention_period then Format.ksprintf Stdlib.failwith @@ -531,6 +543,7 @@ let encoding : t Data_encoding.t = dal_node_port; batcher; injector_retention_period; + l2_blocks_cache_size; }) (merge_objs (obj9 @@ -570,14 +583,15 @@ let encoding : t Data_encoding.t = test only!)" Loser_mode.encoding Loser_mode.no_failures)) - (obj4 + (obj5 (dft "DAL node address" string default_dal_node_addr) (dft "DAL node port" int16 default_dal_node_port) (dft "batcher" batcher_encoding default_batcher) (dft "injector_retention_period" uint16 - default_injector_retention_period))) + default_injector_retention_period) + (dft "l2_blocks_cache_size" int31 default_l2_blocks_cache_size))) let check_mode config = let open Result_syntax in diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/configuration.mli b/src/proto_016_PtMumbai/bin_sc_rollup_node/configuration.mli index 22058666b750..cc0a21c8caa6 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/configuration.mli +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/configuration.mli @@ -82,6 +82,7 @@ type t = { dal_node_port : int; batcher : batcher; injector_retention_period : int; + l2_blocks_cache_size : int; } (** [make_purpose_map ~default purposes] constructs a purpose map from a list of @@ -143,6 +144,10 @@ val default_batcher : batcher injector will keep in memory. *) val default_injector_retention_period : int +(** [default_l2_blocks_cache_size] is the default number of L2 blocks that are + cached by the rollup node *) +val default_l2_blocks_cache_size : int + (** [max_injector_retention_period] is the maximum allowed value for [injector_retention_period]. *) val max_injector_retention_period : int diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/daemon.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/daemon.ml index 6e1284961044..b220d0c7c7d8 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/daemon.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/daemon.ml @@ -51,7 +51,7 @@ module Make (PVM : Pvm.S) = struct let commitment_hash = Sc_rollup.Commitment.hash_uncarbonated commitment in - let*! () = + let* () = Node_context.set_commitment_published_at_level node_ctxt commitment_hash @@ -68,12 +68,12 @@ module Make (PVM : Pvm.S) = struct let commitment_hash = Sc_rollup.Commitment.hash_uncarbonated commitment in - let*! known_commitment = + let* known_commitment = Node_context.commitment_exists node_ctxt commitment_hash in if not known_commitment then return_unit else - let*! republication = + let* republication = Node_context.commitment_was_published node_ctxt ~source:Anyone @@ -227,7 +227,7 @@ module Make (PVM : Pvm.S) = struct let rec processed_finalized_block (node_ctxt : _ Node_context.t) Layer1.({hash; level} as block) = let open Lwt_result_syntax in - let*! last_finalized = Node_context.get_finalized_head_opt node_ctxt in + let* last_finalized = Node_context.get_finalized_head_opt node_ctxt in let already_finalized = match last_finalized with | Some finalized -> level <= Raw_level.to_int32 finalized.header.level @@ -241,14 +241,14 @@ module Make (PVM : Pvm.S) = struct in let*! () = Daemon_event.head_processing hash level ~finalized:true in let* () = process_l1_block_operations ~finalized:true node_ctxt block in - let*! () = Node_context.mark_finalized_head node_ctxt hash in + let* () = Node_context.mark_finalized_head node_ctxt hash in return_unit let process_head (node_ctxt : _ Node_context.t) Layer1.({hash; level} as head) = let open Lwt_result_syntax in let*! () = Daemon_event.head_processing hash level ~finalized:false in - let*! () = Node_context.save_level node_ctxt head in + let* () = Node_context.save_level node_ctxt head in let* inbox_hash, inbox, inbox_witness, messages, ctxt = Inbox.process_head node_ctxt head in @@ -302,7 +302,7 @@ module Make (PVM : Pvm.S) = struct head in let* () = processed_finalized_block node_ctxt finalized_block in - let*! () = Node_context.save_l2_head node_ctxt l2_block in + let* () = Node_context.save_l2_head node_ctxt l2_block in let*! () = Daemon_event.new_head_processed hash (Raw_level.to_int32 level) in @@ -330,7 +330,7 @@ module Make (PVM : Pvm.S) = struct imply the processing of head~3, etc). *) let on_layer_1_head node_ctxt head = let open Lwt_result_syntax in - let*! old_head = Node_context.last_processed_head_opt node_ctxt in + let* old_head = Node_context.last_processed_head_opt node_ctxt in let old_head = match old_head with | Some h -> @@ -431,7 +431,7 @@ module Make (PVM : Pvm.S) = struct let* () = Injector.shutdown () in let* () = message "Shutting down Batcher@." in let* () = Components.Batcher.shutdown () in - let* () = Node_context.close node_ctxt in + let* (_ : unit tzresult) = Node_context.close node_ctxt in let* () = Event.shutdown_node exit_status in Tezos_base_unix.Internal_event_unix.close () diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/inbox.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/inbox.ml index 32eae4f34640..c1db7fda7d65 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/inbox.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/inbox.ml @@ -167,7 +167,7 @@ let process_head (node_ctxt : _ Node_context.t) in Metrics.Inbox.Stats.head_messages_list := messages_with_protocol_internal_messages ; - let*! () = + let* () = Node_context.save_messages node_ctxt witness_hash @@ -178,7 +178,7 @@ let process_head (node_ctxt : _ Node_context.t) } in let* () = same_inbox_as_layer_1 node_ctxt head_hash inbox in - let*! inbox_hash = Node_context.save_inbox node_ctxt inbox in + let* inbox_hash = Node_context.save_inbox node_ctxt inbox in return ( inbox_hash, inbox, diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/main_sc_rollup_node_016_PtMumbai.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/main_sc_rollup_node_016_PtMumbai.ml index 9cb01ac09326..064765e8e6ba 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/main_sc_rollup_node_016_PtMumbai.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/main_sc_rollup_node_016_PtMumbai.ml @@ -293,6 +293,7 @@ let config_init_command = loser_mode; batcher = Configuration.default_batcher; injector_retention_period; + l2_blocks_cache_size = Configuration.default_l2_blocks_cache_size; } in let*? config = check_mode config in diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/node_context.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/node_context.ml index baaa4fd6a1eb..96aefda12b4a 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/node_context.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/node_context.ml @@ -118,10 +118,16 @@ let init (cctxt : Protocol_client_context.full) dal_cctxt ~data_dir mode sc_rollup_node_operators = operators; fee_parameters; loser_mode; + l2_blocks_cache_size; _; } as configuration) = let open Lwt_result_syntax in - let*! store = Store.load mode Configuration.(default_storage_dir data_dir) in + let* store = + Store.load + mode + ~l2_blocks_cache_size + Configuration.(default_storage_dir data_dir) + in let*! context = Context.load mode (Configuration.default_context_dir data_dir) in @@ -156,24 +162,26 @@ let init (cctxt : Protocol_client_context.full) dal_cctxt ~data_dir mode } let close {cctxt; store; context; l1_ctxt; _} = - let open Lwt_syntax in + let open Lwt_result_syntax in let message = cctxt#message in - let* () = message "Shutting down L1@." in - let* () = Layer1.shutdown l1_ctxt in - let* () = message "Closing context@." in - let* () = Context.close context in - let* () = message "Closing store@." in + let*! () = message "Shutting down L1@." in + let*! () = Layer1.shutdown l1_ctxt in + let*! () = message "Closing context@." in + let*! () = Context.close context in + let*! () = message "Closing store@." in let* () = Store.close store in return_unit let checkout_context node_ctxt block_hash = let open Lwt_result_syntax in - let*! l2_block = Store.L2_blocks.find node_ctxt.store block_hash in + let* l2_header = + Store.L2_blocks.header node_ctxt.store.l2_blocks block_hash + in let*? context_hash = - match l2_block with + match l2_header with | None -> error (Sc_rollup_node_errors.Cannot_checkout_context (block_hash, None)) - | Some {header = {context; _}; _} -> ok context + | Some {context; _} -> ok context in let*! ctxt = Context.checkout node_ctxt.context context_hash in match ctxt with @@ -213,161 +221,188 @@ let trace_lwt_result_with x = x let hash_of_level_opt {store; cctxt; _} level = - let open Lwt_syntax in - let* hash = Store.Levels_to_hashes.find store level in + let open Lwt_result_syntax in + let* hash = Store.Levels_to_hashes.find store.levels_to_hashes level in match hash with | Some hash -> return_some hash | None -> - let+ hash = + let*! hash = Tezos_shell_services.Shell_services.Blocks.hash cctxt ~chain:cctxt#chain ~block:(`Level level) () in - Result.to_option hash + return (Result.to_option hash) let hash_of_level node_ctxt level = let open Lwt_result_syntax in - let*! hash = hash_of_level_opt node_ctxt level in + let* hash = hash_of_level_opt node_ctxt level in match hash with | Some h -> return h | None -> failwith "Cannot retrieve hash of level %ld" level let level_of_hash {l1_ctxt; store; _} hash = let open Lwt_result_syntax in - let*! block = Store.L2_blocks.find store hash in - match block with - | Some {header = {level; _}; _} -> return (Raw_level.to_int32 level) + let* l2_header = Store.L2_blocks.header store.l2_blocks hash in + match l2_header with + | Some {level; _} -> return (Raw_level.to_int32 level) | None -> let+ {level; _} = Layer1.fetch_tezos_shell_header l1_ctxt hash in level let save_level {store; _} Layer1.{hash; level} = - Store.Levels_to_hashes.add store level hash + Store.Levels_to_hashes.add store.levels_to_hashes level hash let save_l2_head {store; _} (head : Sc_rollup_block.t) = - let open Lwt_syntax in - let* () = Store.L2_blocks.add store head.header.block_hash head in - Store.L2_head.set store head + let open Lwt_result_syntax in + let head_info = {head with header = (); content = ()} in + let* () = + Store.L2_blocks.append + store.l2_blocks + ~key:head.header.block_hash + ~header:head.header + ~value:head_info + in + Store.L2_head.write store.l2_head head -let is_processed {store; _} head = Store.L2_blocks.mem store head +let is_processed {store; _} head = Store.L2_blocks.mem store.l2_blocks head -let last_processed_head_opt {store; _} = Store.L2_head.find store +let last_processed_head_opt {store; _} = Store.L2_head.read store.l2_head let mark_finalized_head {store; _} head_hash = - let open Lwt_syntax in - let* block = Store.L2_blocks.find store head_hash in + let open Lwt_result_syntax in + let* block = Store.L2_blocks.read store.l2_blocks head_hash in match block with | None -> return_unit - | Some block -> Store.Last_finalized_head.set store block + | Some (block_info, header) -> + let block = {block_info with header} in + Store.Last_finalized_head.write store.last_finalized_head block -let get_finalized_head_opt {store; _} = Store.Last_finalized_head.find store +let get_finalized_head_opt {store; _} = + Store.Last_finalized_head.read store.last_finalized_head (* TODO: https://gitlab.com/tezos/tezos/-/issues/4532 Make this logarithmic, by storing pointers to muliple predecessor and by dichotomy. *) let block_before {store; _} tick = let open Lwt_result_syntax in - let*! head = Store.L2_head.find store in + let* head = Store.L2_head.read store.l2_head in match head with | None -> return_none | Some head -> let rec search block_hash = - let*! block = Store.L2_blocks.find store block_hash in + let* block = Store.L2_blocks.read store.l2_blocks block_hash in match block with | None -> failwith "Missing block %a" Block_hash.pp block_hash - | Some block -> - if Sc_rollup.Tick.(block.initial_tick <= tick) then - return_some block - else search block.header.predecessor + | Some (info, header) -> + if Sc_rollup.Tick.(info.initial_tick <= tick) then + return_some {info with header} + else search header.predecessor in search head.header.block_hash let get_l2_block {store; _} block_hash = - trace_lwt_with "Could not retrieve L2 block for %a" Block_hash.pp block_hash - @@ Store.L2_blocks.get store block_hash + let open Lwt_result_syntax in + let* block = Store.L2_blocks.read store.l2_blocks block_hash in + match block with + | None -> + failwith "Could not retrieve L2 block for %a" Block_hash.pp block_hash + | Some (info, header) -> return {info with Sc_rollup_block.header} -let find_l2_block {store; _} block_hash = Store.L2_blocks.find store block_hash +let find_l2_block {store; _} block_hash = + let open Lwt_result_syntax in + let+ block = Store.L2_blocks.read store.l2_blocks block_hash in + Option.map (fun (info, header) -> {info with Sc_rollup_block.header}) block let get_l2_block_by_level node_ctxt level = let open Lwt_result_syntax in trace_lwt_result_with "Could not retrieve L2 block at level %ld" level @@ let* block_hash = hash_of_level node_ctxt level in - let*! block = Store.L2_blocks.get node_ctxt.store block_hash in - return block + get_l2_block node_ctxt block_hash let find_l2_block_by_level node_ctxt level = - let open Lwt_option_syntax in + let open Lwt_result_syntax in let* block_hash = hash_of_level_opt node_ctxt level in - Store.L2_blocks.find node_ctxt.store block_hash - -let get_full_l2_block {store; _} block_hash = - let open Lwt_syntax in - let* block = Store.L2_blocks.get store block_hash in - let* inbox = Store.Inboxes.get store block.header.inbox_hash - and* {messages; _} = Store.Messages.get store block.header.inbox_witness - and* commitment = - Option.map_s (Store.Commitments.get store) block.header.commitment_hash - in - return {block with content = {Sc_rollup_block.inbox; messages; commitment}} + match block_hash with + | None -> return_none + | Some block_hash -> find_l2_block node_ctxt block_hash let get_commitment {store; _} commitment_hash = - trace_lwt_with - "Could not retrieve commitment %a" - Sc_rollup.Commitment.Hash.pp - commitment_hash - @@ Store.Commitments.get store commitment_hash + let open Lwt_result_syntax in + let* commitment = Store.Commitments.find store.commitments commitment_hash in + match commitment with + | None -> + failwith + "Could not retrieve commitment %a" + Sc_rollup.Commitment.Hash.pp + commitment_hash + | Some c -> return c -let find_commitment {store; _} hash = Store.Commitments.find store hash +let find_commitment {store; _} hash = + Store.Commitments.find store.commitments hash -let commitment_exists {store; _} hash = Store.Commitments.mem store hash +let commitment_exists {store; _} hash = + Store.Commitments.mem store.commitments hash let save_commitment {store; _} commitment = - let open Lwt_syntax in + let open Lwt_result_syntax in let hash = Sc_rollup.Commitment.hash_uncarbonated commitment in - let+ () = Store.Commitments.add store hash commitment in + let+ () = Store.Commitments.add store.commitments hash commitment in hash let commitment_published_at_level {store; _} commitment = - Store.Commitments_published_at_level.find store commitment + Store.Commitments_published_at_level.find + store.commitments_published_at_level + commitment let set_commitment_published_at_level {store; _} = - Store.Commitments_published_at_level.add store + Store.Commitments_published_at_level.add store.commitments_published_at_level type commitment_source = Anyone | Us let commitment_was_published {store; _} ~source commitment_hash = - let open Lwt_syntax in + let open Lwt_result_syntax in match source with - | Anyone -> Store.Commitments_published_at_level.mem store commitment_hash + | Anyone -> + Store.Commitments_published_at_level.mem + store.commitments_published_at_level + commitment_hash | Us -> ( let+ info = - Store.Commitments_published_at_level.find store commitment_hash + Store.Commitments_published_at_level.find + store.commitments_published_at_level + commitment_hash in match info with | Some {published_at_level = Some _; _} -> true | _ -> false) let get_inbox {store; _} inbox_hash = - trace_lwt_with - "Could not retrieve inbox %a" - Sc_rollup.Inbox.Hash.pp - inbox_hash - @@ Store.Inboxes.get store inbox_hash + let open Lwt_result_syntax in + let* inbox = Store.Inboxes.read store.inboxes inbox_hash in + match inbox with + | None -> + failwith "Could not retrieve inbox %a" Sc_rollup.Inbox.Hash.pp inbox_hash + | Some (i, ()) -> return i -let find_inbox {store; _} hash = Store.Inboxes.find store hash +let find_inbox {store; _} hash = + let open Lwt_result_syntax in + let+ inbox = Store.Inboxes.read store.inboxes hash in + Option.map fst inbox let save_inbox {store; _} inbox = - let open Lwt_syntax in + let open Lwt_result_syntax in let hash = Sc_rollup.Inbox.hash inbox in - let+ () = Store.Inboxes.add store hash inbox in + let+ () = Store.Inboxes.append store.inboxes ~key:hash ~value:inbox in hash -let find_inbox_by_block_hash {store; _} block_hash = - let open Lwt_option_syntax in - let* l2_block = Store.L2_blocks.find store block_hash in - Store.Inboxes.find store l2_block.header.inbox_hash +let find_inbox_by_block_hash ({store; _} as node_ctxt) block_hash = + let open Lwt_result_syntax in + let* header = Store.L2_blocks.header store.l2_blocks block_hash in + match header with + | None -> return_none + | Some {inbox_hash; _} -> find_inbox node_ctxt inbox_hash let genesis_inbox node_ctxt = let genesis_level = Raw_level.to_int32 node_ctxt.genesis_info.level in @@ -377,7 +412,7 @@ let genesis_inbox node_ctxt = let inbox_of_head node_ctxt Layer1.{hash = block_hash; level = block_level} = let open Lwt_result_syntax in - let*! possible_inbox = find_inbox_by_block_hash node_ctxt block_hash in + let* possible_inbox = find_inbox_by_block_hash node_ctxt block_hash in (* Pre-condition: forall l. (l > genesis_level) => inbox[l] <> None. *) match possible_inbox with | None -> @@ -408,16 +443,61 @@ let get_inbox_by_block_hash node_ctxt hash = let* level = level_of_hash node_ctxt hash in inbox_of_head node_ctxt {hash; level} -let get_messages {store; _} messages_hash = - trace_lwt_with - "Could not retrieve messages with payloads merkelized hash %a" - Sc_rollup.Inbox_merkelized_payload_hashes.Hash.pp - messages_hash - @@ Store.Messages.get store messages_hash +type messages_info = { + predecessor : Block_hash.t; + predecessor_timestamp : Timestamp.t; + messages : Sc_rollup.Inbox_message.t list; +} -let find_messages {store; _} hash = Store.Messages.find store hash +let get_messages {store; _} messages_hash = + let open Lwt_result_syntax in + let* msg = Store.Messages.read store.messages messages_hash in + match msg with + | None -> + failwith + "Could not retrieve messages with payloads merkelized hash %a" + Sc_rollup.Inbox_merkelized_payload_hashes.Hash.pp + messages_hash + | Some (messages, (predecessor, predecessor_timestamp, _num_messages)) -> + return {predecessor; predecessor_timestamp; messages} + +let find_messages {store; _} hash = + let open Lwt_result_syntax in + let+ msgs = Store.Messages.read store.messages hash in + Option.map + (fun (messages, (predecessor, predecessor_timestamp, _num_messages)) -> + {predecessor; predecessor_timestamp; messages}) + msgs -let save_messages {store; _} = Store.Messages.add store +let get_num_messages {store; _} hash = + let open Lwt_result_syntax in + let* header = Store.Messages.header store.messages hash in + match header with + | None -> + failwith + "Could not retrieve number of messages for inbox witness %a" + Sc_rollup.Inbox_merkelized_payload_hashes.Hash.pp + hash + | Some (_predecessor, _predecessor_timestamp, num_messages) -> + return num_messages + +let save_messages {store; _} key {predecessor; predecessor_timestamp; messages} + = + Store.Messages.append + store.messages + ~key + ~header:(predecessor, predecessor_timestamp, List.length messages) + ~value:messages + +let get_full_l2_block node_ctxt block_hash = + let open Lwt_result_syntax in + let* block = get_l2_block node_ctxt block_hash in + let* inbox = get_inbox node_ctxt block.header.inbox_hash + and* {messages; _} = get_messages node_ctxt block.header.inbox_witness + and* commitment = + Option.map_es (get_commitment node_ctxt) block.header.commitment_hash + in + return {block with content = {Sc_rollup_block.inbox; messages; commitment}} let get_slot_header {store; _} ~published_in_block_hash slot_index = trace_lwt_with @@ -427,47 +507,49 @@ let get_slot_header {store; _} ~published_in_block_hash slot_index = Block_hash.pp published_in_block_hash @@ Store.Dal_slots_headers.get - store + store.irmin_store ~primary_key:published_in_block_hash ~secondary_key:slot_index let get_all_slot_headers {store; _} ~published_in_block_hash = - Store.Dal_slots_headers.list_values store ~primary_key:published_in_block_hash + Store.Dal_slots_headers.list_values + store.irmin_store + ~primary_key:published_in_block_hash let get_slot_indexes {store; _} ~published_in_block_hash = Store.Dal_slots_headers.list_secondary_keys - store + store.irmin_store ~primary_key:published_in_block_hash let save_slot_header {store; _} ~published_in_block_hash (slot_header : Dal.Slot.Header.t) = Store.Dal_slots_headers.add - store + store.irmin_store ~primary_key:published_in_block_hash ~secondary_key:slot_header.id.index slot_header let processed_slot {store; _} ~confirmed_in_block_hash slot_index = Store.Dal_processed_slots.find - store + store.irmin_store ~primary_key:confirmed_in_block_hash ~secondary_key:slot_index let list_slot_pages {store; _} ~confirmed_in_block_hash = Store.Dal_slot_pages.list_secondary_keys_with_values - store + store.irmin_store ~primary_key:confirmed_in_block_hash let find_slot_page {store; _} ~confirmed_in_block_hash ~slot_index ~page_index = Store.Dal_slot_pages.find - store + store.irmin_store ~primary_key:confirmed_in_block_hash ~secondary_key:(slot_index, page_index) let save_unconfirmed_slot {store; _} current_block_hash slot_index = (* No page is actually saved *) Store.Dal_processed_slots.add - store + store.irmin_store ~primary_key:current_block_hash ~secondary_key:slot_index `Unconfirmed @@ -480,26 +562,26 @@ let save_confirmed_slot {store; _} current_block_hash slot_index pages = List.iteri_s (fun page_number page -> Store.Dal_slot_pages.add - store + store.irmin_store ~primary_key:current_block_hash ~secondary_key:(slot_index, page_number) page) pages in Store.Dal_processed_slots.add - store + store.irmin_store ~primary_key:current_block_hash ~secondary_key:slot_index `Confirmed let find_confirmed_slots_history {store; _} = - Store.Dal_confirmed_slots_history.find store + Store.Dal_confirmed_slots_history.find store.irmin_store let save_confirmed_slots_history {store; _} = - Store.Dal_confirmed_slots_history.add store + Store.Dal_confirmed_slots_history.add store.irmin_store let find_confirmed_slots_histories {store; _} = - Store.Dal_confirmed_slots_histories.find store + Store.Dal_confirmed_slots_histories.find store.irmin_store let save_confirmed_slots_histories {store; _} = - Store.Dal_confirmed_slots_histories.add store + Store.Dal_confirmed_slots_histories.add store.irmin_store diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/node_context.mli b/src/proto_016_PtMumbai/bin_sc_rollup_node/node_context.mli index 83fdb0420a28..a7fa59880c82 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/node_context.mli +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/node_context.mli @@ -106,7 +106,7 @@ val init : 'a t tzresult Lwt.t (** Closes the store, context and Layer 1 monitor. *) -val close : _ t -> unit Lwt.t +val close : _ t -> unit tzresult Lwt.t (** [checkout_context node_ctxt block_hash] returns the context at block [block_hash]. *) @@ -132,7 +132,7 @@ type 'a delayed_write = ('a, rw) Delayed_write_monad.t (** [is_processed store hash] returns [true] if the block with [hash] has already been processed by the daemon. *) -val is_processed : _ t -> Block_hash.t -> bool Lwt.t +val is_processed : _ t -> Block_hash.t -> bool tzresult Lwt.t (** [get_l2_block t hash] returns the Layer 2 block known by the rollup node for Layer 1 block [hash]. *) @@ -140,39 +140,42 @@ val get_l2_block : _ t -> Block_hash.t -> Sc_rollup_block.t tzresult Lwt.t (** Same as {!get_l2_block} but returns [None] when the Layer 2 block is not available. *) -val find_l2_block : _ t -> Block_hash.t -> Sc_rollup_block.t option Lwt.t +val find_l2_block : + _ t -> Block_hash.t -> Sc_rollup_block.t option tzresult Lwt.t (** Same as {!get_l2_block} but retrieves the Layer 2 block by its level. *) val get_l2_block_by_level : _ t -> int32 -> Sc_rollup_block.t tzresult Lwt.t (** Same as {!get_l2_block_by_level} but returns [None] when the Layer 2 block is not available. *) -val find_l2_block_by_level : _ t -> int32 -> Sc_rollup_block.t option Lwt.t +val find_l2_block_by_level : + _ t -> int32 -> Sc_rollup_block.t option tzresult Lwt.t (** [get_full_l2_block node_ctxt hash] returns the full L2 block for L1 block hash [hash]. The result contains the L2 block and its content (inbox, messages, commitment). *) -val get_full_l2_block : _ t -> Block_hash.t -> Sc_rollup_block.full Lwt.t +val get_full_l2_block : + _ t -> Block_hash.t -> Sc_rollup_block.full tzresult Lwt.t (** [save_level t head] registers the correspondences [head.level |-> head.hash] in the store. *) -val save_level : rw -> Layer1.head -> unit Lwt.t +val save_level : rw -> Layer1.head -> unit tzresult Lwt.t -(** [save_l2_head t l2_block] remembers that the [l2_block.head] is +(** [save_l2_head t l2_block] remembers that the [l2_block.head] is processed. The system should not have to come back to it. *) -val save_l2_head : rw -> Sc_rollup_block.t -> unit Lwt.t +val save_l2_head : rw -> Sc_rollup_block.t -> unit tzresult Lwt.t (** [last_processed_head_opt store] returns the last processed head if it exists. *) -val last_processed_head_opt : _ t -> Sc_rollup_block.t option Lwt.t +val last_processed_head_opt : _ t -> Sc_rollup_block.t option tzresult Lwt.t (** [mark_finalized_head store head] remembers that the [head] is finalized. By construction, every block whose level is smaller than [head]'s is also finalized. *) -val mark_finalized_head : rw -> Block_hash.t -> unit Lwt.t +val mark_finalized_head : rw -> Block_hash.t -> unit tzresult Lwt.t (** [last_finalized_head_opt store] returns the last finalized head if it exists. *) -val get_finalized_head_opt : _ t -> Sc_rollup_block.t option Lwt.t +val get_finalized_head_opt : _ t -> Sc_rollup_block.t option tzresult Lwt.t (** [hash_of_level node_ctxt level] returns the current block hash for a given [level]. *) @@ -180,7 +183,7 @@ val hash_of_level : _ t -> int32 -> Block_hash.t tzresult Lwt.t (** [hash_of_level_opt] is like {!hash_of_level} but returns [None] if the [level] is not known. *) -val hash_of_level_opt : _ t -> int32 -> Block_hash.t option Lwt.t +val hash_of_level_opt : _ t -> int32 -> Block_hash.t option tzresult Lwt.t (** [level_of_hash node_ctxt hash] returns the level for Tezos block hash [hash] if it is known by the Tezos Layer 1 node. *) @@ -201,16 +204,19 @@ val get_commitment : (** Same as {!get_commitment} but returns [None] if this commitment hash is not known by the rollup node. *) val find_commitment : - _ t -> Sc_rollup.Commitment.Hash.t -> Sc_rollup.Commitment.t option Lwt.t + _ t -> + Sc_rollup.Commitment.Hash.t -> + Sc_rollup.Commitment.t option tzresult Lwt.t (** [commitment_exists t hash] returns [true] if the commitment with [hash] is known (i.e. stored) by the rollup node. *) -val commitment_exists : _ t -> Sc_rollup.Commitment.Hash.t -> bool Lwt.t +val commitment_exists : + _ t -> Sc_rollup.Commitment.Hash.t -> bool tzresult Lwt.t (** [save_commitment t commitment] saves a commitment in the store an returns is hash. *) val save_commitment : - rw -> Sc_rollup.Commitment.t -> Sc_rollup.Commitment.Hash.t Lwt.t + rw -> Sc_rollup.Commitment.t -> Sc_rollup.Commitment.Hash.t tzresult Lwt.t (** [commitment_published_at_level t hash] returns the levels at which the commitment was first published and the one at which it was included by in a @@ -220,7 +226,7 @@ val save_commitment : val commitment_published_at_level : _ t -> Sc_rollup.Commitment.Hash.t -> - Store.Commitments_published_at_level.element option Lwt.t + Store.Commitments_published_at_level.element option tzresult Lwt.t (** [save_commitment_published_at_level t hash levels] saves the publication/inclusion information for a commitment with [hash]. *) @@ -228,7 +234,7 @@ val set_commitment_published_at_level : rw -> Sc_rollup.Commitment.Hash.t -> Store.Commitments_published_at_level.element -> - unit Lwt.t + unit tzresult Lwt.t type commitment_source = Anyone | Us @@ -237,21 +243,32 @@ type commitment_source = Anyone | Us the publication status for commitments we published ourselves [`Us] or that [`Anyone] published. *) val commitment_was_published : - _ t -> source:commitment_source -> Sc_rollup.Commitment.Hash.t -> bool Lwt.t + _ t -> + source:commitment_source -> + Sc_rollup.Commitment.Hash.t -> + bool tzresult Lwt.t (** {3 Inboxes} *) +type messages_info = { + predecessor : Block_hash.t; + predecessor_timestamp : Timestamp.t; + messages : Sc_rollup.Inbox_message.t list; +} + (** [get_inbox t inbox_hash] retrieves the inbox whose hash is [inbox_hash] from the rollup node's storage. *) val get_inbox : _ t -> Sc_rollup.Inbox.Hash.t -> Sc_rollup.Inbox.t tzresult Lwt.t (** Same as {!get_inbox} but returns [None] if this inbox is not known. *) -val find_inbox : _ t -> Sc_rollup.Inbox.Hash.t -> Sc_rollup.Inbox.t option Lwt.t +val find_inbox : + _ t -> Sc_rollup.Inbox.Hash.t -> Sc_rollup.Inbox.t option tzresult Lwt.t (** [save_inbox t inbox] remembers the [inbox] in the storage. It is associated to its hash which is returned. *) -val save_inbox : rw -> Sc_rollup.Inbox.t -> Sc_rollup.Inbox.Hash.t Lwt.t +val save_inbox : + rw -> Sc_rollup.Inbox.t -> Sc_rollup.Inbox.Hash.t tzresult Lwt.t (** [inbox_of_head node_ctxt block] returns the latest inbox at the given [block]. This function always returns [inbox] for all levels at and @@ -271,13 +288,19 @@ val genesis_inbox : _ t -> Sc_rollup.Inbox.t tzresult Lwt.t val get_messages : _ t -> Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t -> - Store.Messages.info tzresult Lwt.t + messages_info tzresult Lwt.t (** Same as {!get_messages} but returns [None] if the payloads hash is not known. *) val find_messages : _ t -> Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t -> - Store.Messages.info option Lwt.t + messages_info option tzresult Lwt.t + +(** [get_num_messages t witness_hash] retrieves (without reading all the messages + from disk) the number of messages for the inbox witness [witness_hash] + stored by the rollup node. *) +val get_num_messages : + _ t -> Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t -> int tzresult Lwt.t (** [save_messages t payloads_hash messages] associates the list of [messages] to the [payloads_hash]. The payload hash must be computed by calling, @@ -285,8 +308,8 @@ val find_messages : val save_messages : rw -> Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t -> - Store.Messages.info -> - unit Lwt.t + messages_info -> + unit tzresult Lwt.t (** {3 DAL} *) diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/refutation_game.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/refutation_game.ml index fed8e13eb443..c71b2b9614cd 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/refutation_game.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/refutation_game.ml @@ -224,9 +224,18 @@ module Make (Interpreter : Interpreter.S) : let inbox = snapshot let get_history inbox_hash = - let open Lwt_option_syntax in + let open Lwt_syntax in let+ inbox = Node_context.find_inbox node_ctxt inbox_hash in - Sc_rollup.Inbox.take_snapshot inbox + match inbox with + | Error err -> + Format.kasprintf + Stdlib.failwith + "Refutation game: Cannot get inbox history for %a, %a" + Sc_rollup.Inbox.Hash.pp + inbox_hash + pp_print_trace + err + | Ok inbox -> Option.map Sc_rollup.Inbox.take_snapshot inbox let get_payloads_history witness = Lwt.map diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/store.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/store.ml index 5c22868889fb..62b2404dd3ce 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/store.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/store.ml @@ -30,123 +30,125 @@ include Store_utils (** Aggregated collection of messages from the L1 inbox *) open Alpha_context -module IStore = Irmin_store.Make (struct - let name = "Tezos smart rollup node" -end) +module Irmin_store = struct + module IStore = Irmin_store.Make (struct + let name = "Tezos smart rollup node" + end) -include Store_utils.Make (IStore) + include IStore + include Store_utils.Make (IStore) +end -type 'a store = 'a IStore.t +module Empty_header = struct + type t = unit -type 'a t = ([< `Read | `Write > `Read] as 'a) store + let name = "empty" -type rw = Store_sigs.rw t + let encoding = Data_encoding.unit -type ro = Store_sigs.ro t + let fixed_size = 0 +end -let close = IStore.close +module Add_empty_header = struct + module Header = Empty_header -let load = IStore.load + let header _ = () +end -let readonly = IStore.readonly +module Make_hash_index_key (H : Environment.S.HASH) = +Indexed_store.Make_index_key (struct + include Indexed_store.Make_fixed_encodable (H) + + let equal = H.equal +end) (** L2 blocks *) module L2_blocks = - Make_append_only_map + Indexed_store.Make_indexed_file (struct - let path = ["state_info"] + let name = "l2_blocks" end) + (Tezos_store_shared.Block_key) (struct - type key = Block_hash.t + type t = (unit, unit) Sc_rollup_block.block - let to_path_representation = Block_hash.to_b58check - end) - (struct - type value = Sc_rollup_block.t + let name = "sc_rollup_block_info" + + let encoding = + Sc_rollup_block.block_encoding Data_encoding.unit Data_encoding.unit - let name = "sc_rollup_block" + module Header = struct + type t = Sc_rollup_block.header - let encoding = Sc_rollup_block.encoding + let name = "sc_rollup_block_header" + + let encoding = Sc_rollup_block.header_encoding + + let fixed_size = Sc_rollup_block.header_size + end end) (** Unaggregated messages per block *) -module Messages = struct - type info = { - predecessor : Block_hash.t; - predecessor_timestamp : Timestamp.t; - messages : Sc_rollup.Inbox_message.t list; - } +module Messages = + Indexed_store.Make_indexed_file + (struct + let name = "messages" + end) + (Make_hash_index_key (Sc_rollup.Inbox_merkelized_payload_hashes.Hash)) + (struct + type t = Sc_rollup.Inbox_message.t list - let encoding = - let open Data_encoding in - conv - (fun {predecessor; predecessor_timestamp; messages} -> - (predecessor, predecessor_timestamp, messages)) - (fun (predecessor, predecessor_timestamp, messages) -> - {predecessor; predecessor_timestamp; messages}) - @@ obj3 - (req "predecessor" Block_hash.encoding) - (req "predecessor_timestamp" Timestamp.encoding) - (req - "messages" - (list @@ dynamic_size Sc_rollup.Inbox_message.encoding)) + let name = "messages_list" - include - Make_append_only_map - (struct - let path = ["messages"] - end) - (struct - type key = Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t + let encoding = + Data_encoding.(list @@ dynamic_size Sc_rollup.Inbox_message.encoding) - let to_path_representation = - Sc_rollup.Inbox_merkelized_payload_hashes.Hash.to_b58check - end) - (struct - type value = info + module Header = struct + type t = Block_hash.t * Timestamp.t * int - let name = "messages" + let name = "messages_inbox_info" - let encoding = encoding - end) -end + let encoding = + let open Data_encoding in + obj3 + (req "predecessor" Block_hash.encoding) + (req "predecessor_timestamp" Timestamp.encoding) + (req "num_messages" int31) + + let fixed_size = + WithExceptions.Option.get ~loc:__LOC__ + @@ Data_encoding.Binary.fixed_length encoding + end + end) (** Inbox state for each block *) module Inboxes = - Make_append_only_map + Indexed_store.Make_simple_indexed_file (struct - let path = ["inboxes"] + let name = "inboxes" end) + (Make_hash_index_key (Sc_rollup.Inbox.Hash)) (struct - type key = Sc_rollup.Inbox.Hash.t - - let to_path_representation = Sc_rollup.Inbox.Hash.to_b58check - end) - (struct - type value = Sc_rollup.Inbox.t + type t = Sc_rollup.Inbox.t let name = "inbox" let encoding = Sc_rollup.Inbox.encoding + + include Add_empty_header end) module Commitments = - Make_append_only_map + Indexed_store.Make_indexable (struct - let path = ["commitments"; "computed"] + let name = "commitments" end) - (struct - type key = Sc_rollup.Commitment.Hash.t - - let to_path_representation = Sc_rollup.Commitment.Hash.to_b58check - end) - (struct - type value = Sc_rollup.Commitment.t + (Make_hash_index_key (Sc_rollup.Commitment.Hash)) + (Indexed_store.Make_index_value (Indexed_store.Make_fixed_encodable (struct + include Sc_rollup.Commitment let name = "commitment" - - let encoding = Sc_rollup.Commitment.encoding - end) + end))) module Commitments_published_at_level = struct type element = { @@ -156,6 +158,12 @@ module Commitments_published_at_level = struct let element_encoding = let open Data_encoding in + let opt_level_encoding = + conv + (function None -> -1l | Some l -> Raw_level.to_int32 l) + (fun l -> if l = -1l then None else Some (Raw_level.of_int32_exn l)) + Data_encoding.int32 + in conv (fun {first_published_at_level; published_at_level} -> (first_published_at_level, published_at_level)) @@ -163,82 +171,64 @@ module Commitments_published_at_level = struct {first_published_at_level; published_at_level}) @@ obj2 (req "first_published_at_level" Raw_level.encoding) - (opt "published_at_level" Raw_level.encoding) + (req "published_at_level" opt_level_encoding) include - Make_updatable_map + Indexed_store.Make_indexable (struct - let path = ["commitments"; "published_at_level"] + let name = "commitments" end) - (struct - type key = Sc_rollup.Commitment.Hash.t - - let to_path_representation = Sc_rollup.Commitment.Hash.to_b58check - end) - (struct - type value = element + (Make_hash_index_key (Sc_rollup.Commitment.Hash)) + (Indexed_store.Make_index_value (Indexed_store.Make_fixed_encodable (struct + type t = element let name = "published_levels" let encoding = element_encoding - end) + end))) end -(* TODO: https://gitlab.com/tezos/tezos/-/issues/4392 - Use file. *) -module L2_head = - Make_mutable_value - (struct - let path = ["l2_head"] - end) - (struct - type value = Sc_rollup_block.t +module L2_head = Indexed_store.Make_singleton (struct + type t = Sc_rollup_block.t - let name = "l2_block" + let name = "l2_head" - let encoding = Sc_rollup_block.encoding - end) + let encoding = Sc_rollup_block.encoding +end) -(* TODO: https://gitlab.com/tezos/tezos/-/issues/4392 - Use file. *) -module Last_finalized_head = - Make_mutable_value - (struct - let path = ["finalized_head"] - end) - (struct - type value = Sc_rollup_block.t +module Last_finalized_head = Indexed_store.Make_singleton (struct + type t = Sc_rollup_block.t - let name = "l2_block" + let name = "finalized_head" - let encoding = Sc_rollup_block.encoding - end) + let encoding = Sc_rollup_block.encoding +end) (** Table from L1 levels to blocks hashes. *) module Levels_to_hashes = - Make_updatable_map + Indexed_store.Make_indexable (struct - let path = ["tezos"; "levels"] + let name = "tezos_levels" end) - (struct - type key = int32 + (Indexed_store.Make_index_key (struct + type t = int32 - let to_path_representation = Int32.to_string - end) - (struct - type value = Block_hash.t + let encoding = Data_encoding.int32 - let name = "block_hash" + let name = "level" - let encoding = Block_hash.encoding - end) + let fixed_size = 4 + + let equal = Int32.equal + end)) + (Tezos_store_shared.Block_key) (* Published slot headers per block hash, stored as a list of bindings from `Dal_slot_index.t` to `Dal.Slot.t`. The encoding function converts this list into a `Dal.Slot_index.t`-indexed map. *) module Dal_slot_pages = - Make_nested_map + Irmin_store.Make_nested_map (struct let path = ["dal"; "slot_pages"] end) @@ -270,7 +260,7 @@ module Dal_slot_pages = (** stores slots whose data have been considered and pages stored to disk (if they are confirmed). *) module Dal_processed_slots = - Make_nested_map + Irmin_store.Make_nested_map (struct let path = ["dal"; "processed_slots"] end) @@ -312,7 +302,7 @@ module Dal_processed_slots = end) module Dal_slots_headers = - Make_nested_map + Irmin_store.Make_nested_map (struct let path = ["dal"; "slot_headers"] end) @@ -348,7 +338,7 @@ module Dal_slots_headers = (** Confirmed DAL slots history. See documentation of {Dal_slot_repr.Slots_history} for more details. *) module Dal_confirmed_slots_history = - Make_append_only_map + Irmin_store.Make_append_only_map (struct let path = ["dal"; "confirmed_slots_history"] end) @@ -370,7 +360,7 @@ module Dal_confirmed_slots_history = module Dal_confirmed_slots_histories = (* TODO: https://gitlab.com/tezos/tezos/-/issues/4390 Store single history points in map instead of whole history. *) - Make_append_only_map + Irmin_store.Make_append_only_map (struct let path = ["dal"; "confirmed_slots_histories_cache"] end) @@ -386,3 +376,106 @@ module Dal_confirmed_slots_histories = let encoding = Dal.Slots_history.History_cache.encoding end) + +type 'a store = { + l2_blocks : 'a L2_blocks.t; + messages : 'a Messages.t; + inboxes : 'a Inboxes.t; + commitments : 'a Commitments.t; + commitments_published_at_level : 'a Commitments_published_at_level.t; + l2_head : 'a L2_head.t; + last_finalized_head : 'a Last_finalized_head.t; + levels_to_hashes : 'a Levels_to_hashes.t; + irmin_store : 'a Irmin_store.t; +} + +type 'a t = ([< `Read | `Write > `Read] as 'a) store + +type rw = Store_sigs.rw t + +type ro = Store_sigs.ro t + +let readonly + ({ + l2_blocks; + messages; + inboxes; + commitments; + commitments_published_at_level; + l2_head; + last_finalized_head; + levels_to_hashes; + irmin_store; + } : + _ t) : ro = + { + l2_blocks = L2_blocks.readonly l2_blocks; + messages = Messages.readonly messages; + inboxes = Inboxes.readonly inboxes; + commitments = Commitments.readonly commitments; + commitments_published_at_level = + Commitments_published_at_level.readonly commitments_published_at_level; + l2_head = L2_head.readonly l2_head; + last_finalized_head = Last_finalized_head.readonly last_finalized_head; + levels_to_hashes = Levels_to_hashes.readonly levels_to_hashes; + irmin_store = Irmin_store.readonly irmin_store; + } + +let close + ({ + l2_blocks; + messages; + inboxes; + commitments; + commitments_published_at_level; + l2_head = _; + last_finalized_head = _; + levels_to_hashes; + irmin_store; + } : + _ t) = + let open Lwt_result_syntax in + let+ () = L2_blocks.close l2_blocks + and+ () = Messages.close messages + and+ () = Inboxes.close inboxes + and+ () = Commitments.close commitments + and+ () = Commitments_published_at_level.close commitments_published_at_level + and+ () = Levels_to_hashes.close levels_to_hashes + and+ () = Irmin_store.close irmin_store |> Lwt_result.ok in + () + +let load (type a) (mode : a mode) ~l2_blocks_cache_size data_dir : + a store tzresult Lwt.t = + let open Lwt_result_syntax in + let path name = Filename.concat data_dir name in + let cache_size = l2_blocks_cache_size in + let* l2_blocks = L2_blocks.load mode ~path:(path "l2_blocks") ~cache_size in + let* messages = Messages.load mode ~path:(path "messages") ~cache_size in + let* inboxes = Inboxes.load mode ~path:(path "inboxes") ~cache_size in + let* commitments = Commitments.load mode ~path:(path "commitments") in + let* commitments_published_at_level = + Commitments_published_at_level.load + mode + ~path:(path "commitments_published_at_level") + in + let* l2_head = L2_head.load mode ~path:(path "l2_head") in + let* last_finalized_head = + Last_finalized_head.load mode ~path:(path "last_finalized_head") + in + let* levels_to_hashes = + Levels_to_hashes.load mode ~path:(path "levels_to_hashes") + in + let+ irmin_store = + Irmin_store.load mode (path "irmin_store") |> Lwt_result.ok + in + { + l2_blocks; + messages; + inboxes; + commitments; + commitments_published_at_level; + l2_head; + last_finalized_head; + levels_to_hashes; + irmin_store; + } diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/store.mli b/src/proto_016_PtMumbai/bin_sc_rollup_node/store.mli index 4c2d9524da08..252c0f25c100 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/store.mli +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/store.mli @@ -23,74 +23,38 @@ (* *) (*****************************************************************************) -(* TODO: https://gitlab.com/tezos/tezos/-/issues/3471 - Use indexed file for append-only instead of Irmin. *) - -(* TODO: https://gitlab.com/tezos/tezos/-/issues/3739 - Refactor the store file to have functors in their own - separate module, and return errors within the Error monad. *) - open Protocol open Alpha_context +open Indexed_store -type +'a store - -include Store_sigs.Store with type 'a t = 'a store - -(** Type of store. The parameter indicates if the store can be written or only - read. *) -type 'a t = ([< `Read | `Write > `Read] as 'a) store - -(** Read/write store {!t}. *) -type rw = Store_sigs.rw t - -(** Read only store {!t}. *) -type ro = Store_sigs.ro t - -(** [close store] closes the store. *) -val close : _ t -> unit Lwt.t - -(** [load mode directory] loads a store from the data persisted in [directory].*) -val load : 'a Store_sigs.mode -> string -> 'a store Lwt.t - -(** [readonly store] returns a read-only version of [store]. *) -val readonly : _ t -> ro +module Irmin_store : Store_sigs.Store module L2_blocks : - Store_sigs.Append_only_map + INDEXED_FILE with type key := Block_hash.t - and type value := Sc_rollup_block.t - and type 'a store := 'a store + and type value := (unit, unit) Sc_rollup_block.block + and type header := Sc_rollup_block.header (** Storage for persisting messages downloaded from the L1 node. *) -module Messages : sig - type info = { - predecessor : Block_hash.t; - predecessor_timestamp : Timestamp.t; - messages : Sc_rollup.Inbox_message.t list; - } - - include - Store_sigs.Append_only_map - with type key := Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t - and type value := info - and type 'a store := 'a store -end +module Messages : + INDEXED_FILE + with type key := Sc_rollup.Inbox_merkelized_payload_hashes.Hash.t + and type value := Sc_rollup.Inbox_message.t list + and type header := Block_hash.t * Timestamp.t * int (** Aggregated collection of messages from the L1 inbox *) module Inboxes : - Store_sigs.Append_only_map + SIMPLE_INDEXED_FILE with type key := Sc_rollup.Inbox.Hash.t and type value := Sc_rollup.Inbox.t - and type 'a store := 'a store + and type header := unit (** Storage containing commitments and corresponding commitment hashes that the rollup node has knowledge of. *) module Commitments : - Store_sigs.Append_only_map + INDEXABLE_STORE with type key := Sc_rollup.Commitment.Hash.t and type value := Sc_rollup.Commitment.t - and type 'a store := 'a store (** Storage mapping commitment hashes to the level when they were published by the rollup node. It only contains hashes of commitments published by this @@ -106,27 +70,18 @@ module Commitments_published_at_level : sig } include - Store_sigs.Map + INDEXABLE_STORE with type key := Sc_rollup.Commitment.Hash.t and type value := element - and type 'a store := 'a store end -module L2_head : - Store_sigs.Mutable_value - with type value := Sc_rollup_block.t - and type 'a store := 'a store +module L2_head : SINGLETON_STORE with type value := Sc_rollup_block.t module Last_finalized_head : - Store_sigs.Mutable_value - with type value := Sc_rollup_block.t - and type 'a store := 'a store + SINGLETON_STORE with type value := Sc_rollup_block.t module Levels_to_hashes : - Store_sigs.Map - with type key := int32 - and type value := Block_hash.t - and type 'a store := 'a store + INDEXABLE_STORE with type key := int32 and type value := Block_hash.t (** Published slot headers per block hash, stored as a list of bindings from [Dal_slot_index.t] @@ -137,13 +92,13 @@ module Dal_slots_headers : with type primary_key := Block_hash.t and type secondary_key := Dal.Slot_index.t and type value := Dal.Slot.Header.t - and type 'a store := 'a store + and type 'a store := 'a Irmin_store.t module Dal_confirmed_slots_history : Store_sigs.Append_only_map with type key := Block_hash.t and type value := Dal.Slots_history.t - and type 'a store := 'a store + and type 'a store := 'a Irmin_store.t (** Confirmed DAL slots histories cache. See documentation of {Dal_slot_repr.Slots_history} for more details. *) @@ -151,7 +106,7 @@ module Dal_confirmed_slots_histories : Store_sigs.Append_only_map with type key := Block_hash.t and type value := Dal.Slots_history.History_cache.t - and type 'a store := 'a store + and type 'a store := 'a Irmin_store.t (** [Dal_slot_pages] is a [Store_utils.Nested_map] used to store the contents of dal slots fetched by the rollup node, as a list of pages. The values of @@ -164,7 +119,7 @@ module Dal_slot_pages : with type primary_key := Block_hash.t and type secondary_key := Dal.Slot_index.t * Dal.Page.Index.t and type value := Dal.Page.content - and type 'a store := 'a store + and type 'a store := 'a Irmin_store.t (** [Dal_processed_slots] is a [Store_utils.Nested_map] used to store the processing status of dal slots content fetched by the rollup node. The values of @@ -178,4 +133,45 @@ module Dal_processed_slots : with type primary_key := Block_hash.t and type secondary_key := Dal.Slot_index.t and type value := [`Confirmed | `Unconfirmed] - and type 'a store := 'a store + and type 'a store := 'a Irmin_store.t + +type +'a store = { + l2_blocks : 'a L2_blocks.t; + messages : 'a Messages.t; + inboxes : 'a Inboxes.t; + commitments : 'a Commitments.t; + commitments_published_at_level : 'a Commitments_published_at_level.t; + l2_head : 'a L2_head.t; + last_finalized_head : 'a Last_finalized_head.t; + levels_to_hashes : 'a Levels_to_hashes.t; + irmin_store : 'a Irmin_store.t; +} + +(** Type of store. The parameter indicates if the store can be written or only + read. *) +type 'a t = ([< `Read | `Write > `Read] as 'a) store + +(** Read/write store {!t}. *) +type rw = Store_sigs.rw t + +(** Read only store {!t}. *) +type ro = Store_sigs.ro t + +(** [close store] closes the store. *) +val close : _ t -> unit tzresult Lwt.t + +(** [load mode ~l2_blocks_cache_size directory] loads a store from the data + persisted in [directory]. If [mode] is {!Store_sigs.Read_only}, then the + indexes and irmin store will be opened in readonly mode and only read + operations will be permitted. This allows to open a store for read access + that is already opened in {!Store_sigs.Read_write} mode in another + process. [l2_blocks_cache_size] is the number of L2 blocks the rollup node + will keep in memory. *) +val load : + 'a Store_sigs.mode -> + l2_blocks_cache_size:int -> + string -> + 'a store tzresult Lwt.t + +(** [readonly store] returns a read-only version of [store]. *) +val readonly : _ t -> ro -- GitLab From 928a6b5c9580ed05003a5a20611de07e30625750 Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Thu, 26 Jan 2023 11:22:40 +0100 Subject: [PATCH 6/6] SCORU/Node: Fix discrepancies between master and v16-release --- src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml | 4 ++-- src/proto_016_PtMumbai/bin_sc_rollup_node/commitment.ml | 2 +- src/proto_016_PtMumbai/bin_sc_rollup_node/daemon.ml | 2 +- src/proto_alpha/bin_sc_rollup_node/RPC_server.ml | 4 ++-- src/proto_alpha/bin_sc_rollup_node/commitment.ml | 2 +- src/proto_alpha/bin_sc_rollup_node/daemon.ml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml index b8002f3890a4..493039bd0358 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/RPC_server.ml @@ -29,14 +29,14 @@ open Protocol let get_head store = let open Lwt_result_syntax in - let*! head = Node_context.last_processed_head_opt store in + let* head = Node_context.last_processed_head_opt store in match head with | None -> failwith "No head" | Some {header = {block_hash; _}; _} -> return block_hash let get_finalized node_ctxt = let open Lwt_result_syntax in - let*! head = Node_context.get_finalized_head_opt node_ctxt in + let* head = Node_context.get_finalized_head_opt node_ctxt in match head with | None -> failwith "No finalized head" | Some {header = {block_hash; _}; _} -> return block_hash diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/commitment.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/commitment.ml index a0e6952917e7..d2e69695f9dc 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/commitment.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/commitment.ml @@ -255,7 +255,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct (* Configured to not publish commitments *) return_unit | Some source -> - let*! commitments = missing_commitments node_ctxt in + let* commitments = missing_commitments node_ctxt in List.iter_es (publish_commitment node_ctxt ~source) commitments (* Commitments can only be cemented after [sc_rollup_challenge_window] has diff --git a/src/proto_016_PtMumbai/bin_sc_rollup_node/daemon.ml b/src/proto_016_PtMumbai/bin_sc_rollup_node/daemon.ml index b220d0c7c7d8..feff9f2c5b67 100644 --- a/src/proto_016_PtMumbai/bin_sc_rollup_node/daemon.ml +++ b/src/proto_016_PtMumbai/bin_sc_rollup_node/daemon.ml @@ -81,7 +81,7 @@ module Make (PVM : Pvm.S) = struct in if republication then return_unit else - let*! () = + let* () = Node_context.set_commitment_published_at_level node_ctxt commitment_hash diff --git a/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml b/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml index b8002f3890a4..493039bd0358 100644 --- a/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml +++ b/src/proto_alpha/bin_sc_rollup_node/RPC_server.ml @@ -29,14 +29,14 @@ open Protocol let get_head store = let open Lwt_result_syntax in - let*! head = Node_context.last_processed_head_opt store in + let* head = Node_context.last_processed_head_opt store in match head with | None -> failwith "No head" | Some {header = {block_hash; _}; _} -> return block_hash let get_finalized node_ctxt = let open Lwt_result_syntax in - let*! head = Node_context.get_finalized_head_opt node_ctxt in + let* head = Node_context.get_finalized_head_opt node_ctxt in match head with | None -> failwith "No finalized head" | Some {header = {block_hash; _}; _} -> return block_hash diff --git a/src/proto_alpha/bin_sc_rollup_node/commitment.ml b/src/proto_alpha/bin_sc_rollup_node/commitment.ml index a0e6952917e7..d2e69695f9dc 100644 --- a/src/proto_alpha/bin_sc_rollup_node/commitment.ml +++ b/src/proto_alpha/bin_sc_rollup_node/commitment.ml @@ -255,7 +255,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct (* Configured to not publish commitments *) return_unit | Some source -> - let*! commitments = missing_commitments node_ctxt in + let* commitments = missing_commitments node_ctxt in List.iter_es (publish_commitment node_ctxt ~source) commitments (* Commitments can only be cemented after [sc_rollup_challenge_window] has diff --git a/src/proto_alpha/bin_sc_rollup_node/daemon.ml b/src/proto_alpha/bin_sc_rollup_node/daemon.ml index a4993399142d..cb626681e16a 100644 --- a/src/proto_alpha/bin_sc_rollup_node/daemon.ml +++ b/src/proto_alpha/bin_sc_rollup_node/daemon.ml @@ -81,7 +81,7 @@ module Make (PVM : Pvm.S) = struct in if republication then return_unit else - let*! () = + let* () = Node_context.set_commitment_published_at_level node_ctxt commitment_hash -- GitLab