From 868c2b2ba86d32737c621785d210b241591a0e50 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 19 Jul 2022 15:37:47 +0200 Subject: [PATCH 01/11] SCORU/Node: implement injector Co-Authored-By: Pierrick Couderc Co-Authored-By: Alain Mebsout --- .../bin_sc_rollup_node/injector.ml | 137 ++++++++++++++++++ .../bin_sc_rollup_node/injector.mli | 29 ++++ src/proto_alpha/lib_injector/l1_operation.ml | 24 +++ 3 files changed, 190 insertions(+) create mode 100644 src/proto_alpha/bin_sc_rollup_node/injector.ml create mode 100644 src/proto_alpha/bin_sc_rollup_node/injector.mli diff --git a/src/proto_alpha/bin_sc_rollup_node/injector.ml b/src/proto_alpha/bin_sc_rollup_node/injector.ml new file mode 100644 index 000000000000..135882e5744a --- /dev/null +++ b/src/proto_alpha/bin_sc_rollup_node/injector.ml @@ -0,0 +1,137 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs, *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +open Protocol.Alpha_context +open Injector_sigs + +module Parameters : + PARAMETERS + with type rollup_node_state = Node_context.t + and type Tag.t = Configuration.purpose = struct + type rollup_node_state = Node_context.t + + let events_section = ["sc_rollup.injector"] + + module Tag : TAG with type t = Configuration.purpose = struct + type t = Configuration.purpose + + let compare = Stdlib.compare + + let equal = Stdlib.( = ) + + let hash = Hashtbl.hash + + let string_of_tag = Configuration.string_of_purpose + + let pp ppf t = Format.pp_print_string ppf (string_of_tag t) + + let encoding : t Data_encoding.t = + let open Data_encoding in + string_enum + (List.map (fun t -> (string_of_tag t, t)) Configuration.purposes) + end + + (* TODO: https://gitlab.com/tezos/tezos/-/issues/3459 + Very coarse approximation for the number of operation we + expect for each block *) + let table_estimated_size : Tag.t -> int = function + | Publish -> 1 + | Add_messages -> 100 + | Cement -> 1 + + let fee_parameter {Node_context.fee_parameter; _} _ = fee_parameter + + (* Below are dummy values that are only used to approximate the + size. It is thus important that they remain above the real + values if we want the computed size to be an over_approximation + (without having to do a simulation first). *) + (* TODO: https://gitlab.com/tezos/tezos/-/issues/3461 + Fee parameter per operation. + + See TORU issue: https://gitlab.com/tezos/tezos/-/issues/2812 + check the size, or compute them wrt operation kind *) + let approximate_fee_bound _ _ = + { + fee = Tez.of_mutez_exn 3_000_000L; + counter = Z.of_int 500_000; + gas_limit = Gas.Arith.integral_of_int_exn 500_000; + storage_limit = Z.of_int 500_000; + } + + (* TODO: https://gitlab.com/tezos/tezos/-/issues/3459 + Decide if some batches must have all the operations succeed. See + {!Injector_sigs.Parameter.batch_must_succeed}. *) + let batch_must_succeed _ = `At_least_one + + let ignore_failing_operation : + type kind. + kind manager_operation -> [`Ignore_keep | `Ignore_drop | `Don't_ignore] = + function + | _ -> `Don't_ignore + + (** Returns [true] if an included operation should be re-queued for injection + when the block in which it is included is reverted (due to a + reorganization). *) + let requeue_reverted_operation (type kind) _ + (operation : kind manager_operation) = + let open Lwt_syntax in + match operation with + | Sc_rollup_publish _ -> + (* Commitments are always produced on finalized blocks. They don't need + to be recomputed. *) + return_true + | Sc_rollup_cement _ -> + (* TODO: https://gitlab.com/tezos/tezos/-/issues/3348 + The cementation operations should be re-injected because the node only + keeps track of the last cemented level and the last published + commitment, without rollbacks. + *) + return_true + | Sc_rollup_add_messages _ -> + (* Messages posted to an inbox should be re-emitted (i.e. re-queued) in + case of a fork. *) + return_true + | Reveal _ | Transaction _ | Origination _ | Delegation _ + | Register_global_constant _ | Set_deposits_limit _ + | Increase_paid_storage _ | Tx_rollup_origination | Tx_rollup_submit_batch _ + | Tx_rollup_commit _ | Tx_rollup_return_bond _ + | Tx_rollup_finalize_commitment _ | Tx_rollup_remove_commitment _ + | Tx_rollup_rejection _ | Tx_rollup_dispatch_tickets _ | Transfer_ticket _ + | Dal_publish_slot_header _ | Sc_rollup_originate _ + | Sc_rollup_execute_outbox_message _ | Sc_rollup_recover_bond _ + | Sc_rollup_dal_slot_subscribe _ | Sc_rollup_timeout _ | Sc_rollup_refute _ -> + (* These operations should never be handled by this injector *) + assert false + + let operation_tag (type kind) (operation : kind manager_operation) : + Tag.t option = + match operation with + | Sc_rollup_add_messages _ -> Some Add_messages + | Sc_rollup_cement _ -> Some Cement + | Sc_rollup_publish _ -> Some Publish + | _ -> None +end + +include Injector_functor.Make (Parameters) diff --git a/src/proto_alpha/bin_sc_rollup_node/injector.mli b/src/proto_alpha/bin_sc_rollup_node/injector.mli new file mode 100644 index 000000000000..c08bb06e06d7 --- /dev/null +++ b/src/proto_alpha/bin_sc_rollup_node/injector.mli @@ -0,0 +1,29 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs, *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +include + Injector_sigs.S + with type rollup_node_state := Node_context.t + and type tag := Configuration.purpose diff --git a/src/proto_alpha/lib_injector/l1_operation.ml b/src/proto_alpha/lib_injector/l1_operation.ml index e801c9a852b1..e426875631cb 100644 --- a/src/proto_alpha/lib_injector/l1_operation.ml +++ b/src/proto_alpha/lib_injector/l1_operation.ml @@ -157,6 +157,30 @@ module Manager_operation = struct level (Format.pp_print_list pp_rollup_reveal) tickets_info + | Sc_rollup_add_messages {rollup; messages} -> + Format.fprintf + ppf + "publishing %d messages to rollup %a inbox" + (List.length messages) + Sc_rollup.Address.pp + rollup + | Sc_rollup_cement {rollup; commitment} -> + Format.fprintf + ppf + "cementing commitment %a of rollup %a" + Sc_rollup.Commitment.Hash.pp + commitment + Sc_rollup.Address.pp + rollup + | Sc_rollup_publish + {rollup; commitment = Sc_rollup.Commitment.{inbox_level; _}} -> + Format.fprintf + ppf + "publish commitment for level %a of rollup %a" + Raw_level.pp + inbox_level + Sc_rollup.Address.pp + rollup | _ -> pp_kind ppf op end -- GitLab From b1d3e7ee2338add49de8a2e8b2f6a01cce60e22f Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 19 Jul 2022 15:39:32 +0200 Subject: [PATCH 02/11] SCORU/Node: plug injector in daemon Co-Authored-By: Pierrick Couderc Co-Authored-By: Alain Mebsout --- src/proto_alpha/bin_sc_rollup_node/daemon.ml | 33 ++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/proto_alpha/bin_sc_rollup_node/daemon.ml b/src/proto_alpha/bin_sc_rollup_node/daemon.ml index d25ebbc93488..76377c663739 100644 --- a/src/proto_alpha/bin_sc_rollup_node/daemon.ml +++ b/src/proto_alpha/bin_sc_rollup_node/daemon.ml @@ -205,6 +205,15 @@ module Make (PVM : Pvm.S) = struct let*! () = Layer1.mark_processed_head store head in return ()) + let notify_injector l1_ctxt store chain_event = + let open Lwt_result_syntax in + let open Layer1 in + let hash = chain_event_head_hash chain_event in + let* head = fetch_tezos_block l1_ctxt hash in + let* reorg = get_tezos_reorg_for_new_head l1_ctxt store hash in + let*! () = Injector.new_tezos_head head reorg in + return_unit + (* [on_layer_1_chain_event node_ctxt store chain_event] processes a list of heads, coming either from a list of [old_heads] persisted in the store, or from the current [chain_event]. [old_heads] is a list of heads @@ -237,6 +246,7 @@ module Make (PVM : Pvm.S) = struct node_ctxt store in + let* () = notify_injector node_ctxt.l1_ctxt store chain_event in let* non_final_heads = match chain_event with | SameBranch {new_head; intermediate_heads} -> @@ -285,6 +295,7 @@ module Make (PVM : Pvm.S) = struct in let*! () = Layer1.set_heads_not_finalized store non_final_heads in let*! () = Layer1.processed chain_event in + let*! () = Injector.inject () in return_unit let is_connection_error trace = @@ -381,6 +392,28 @@ module Make (PVM : Pvm.S) = struct in let*! () = Inbox.start () in let*! () = Components.Commitment.start () in + let signers = + Configuration.Operator_purpose_map.bindings node_ctxt.operators + |> List.fold_left + (fun acc (purpose, operator) -> + let purposes = + match Signature.Public_key_hash.Map.find operator acc with + | None -> [purpose] + | Some ps -> purpose :: ps + in + Signature.Public_key_hash.Map.add operator purposes acc) + Signature.Public_key_hash.Map.empty + |> Signature.Public_key_hash.Map.bindings + |> List.map (fun (operator, purposes) -> + (operator, `Each_block, purposes)) + in + let* () = + Injector.init + node_ctxt.cctxt + node_ctxt + ~data_dir:configuration.data_dir + ~signers + in let*! () = Event.node_is_ready -- GitLab From 0b4566be6ba27667c713b5aea0f2f2db8fb0c34f Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Mon, 4 Jul 2022 10:01:51 +0200 Subject: [PATCH 03/11] SCORU/Node: use injector for commitment Co-Authored-By: Pierrick Couderc Co-Authored-By: Alain Mebsout --- .../bin_sc_rollup_node/commitment.ml | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/commitment.ml b/src/proto_alpha/bin_sc_rollup_node/commitment.ml index bb61b46a1a17..e6559bb535ea 100644 --- a/src/proto_alpha/bin_sc_rollup_node/commitment.ml +++ b/src/proto_alpha/bin_sc_rollup_node/commitment.ml @@ -323,20 +323,16 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct | None -> (* Configured to not publish commitments *) return_unit - | Some (source, src_pk, src_sk) -> - let* _oph, _op, _results = - Client_proto_context.sc_rollup_publish - cctxt - ~chain:cctxt#chain - ~block:cctxt#block - ~commitment - ~source - ~rollup:rollup_address - ~src_pk - ~src_sk - ~fee_parameter:Configuration.default_fee_parameter - () + | Some (source, _src_pk, _src_sk) -> + let publish_operation = + Sc_rollup_publish {rollup = node_ctxt.rollup_address; commitment} in + let* () = Injector.add_pending_operation ~source publish_operation in + (* TODO: https://gitlab.com/tezos/tezos/-/issues/3462 + Decouple commitments from head processing + + Move the following, in a part where we know the operation is + included. *) let*! () = Store.Last_published_commitment_level.set store @@ -350,8 +346,6 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct return_unit else return_unit - (* TODO: https://gitlab.com/tezos/tezos/-/issues/2869 - use the Injector to publish commitments. *) let publish_commitment node_ctxt store = let open Lwt_result_syntax in (* Check level of next publishable commitment and avoid publishing if it is -- GitLab From 2170eab1934d57d89f55d545c1b2c4ab8fa5126e Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Thu, 28 Jul 2022 17:11:15 +0200 Subject: [PATCH 04/11] SCORU/Node: use injector for cementation --- .../bin_sc_rollup_node/commitment.ml | 27 +++++-------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/commitment.ml b/src/proto_alpha/bin_sc_rollup_node/commitment.ml index e6559bb535ea..aa980a40846b 100644 --- a/src/proto_alpha/bin_sc_rollup_node/commitment.ml +++ b/src/proto_alpha/bin_sc_rollup_node/commitment.ml @@ -408,35 +408,22 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct () else return_false - let cement_commitment ({Node_context.cctxt; rollup_address; _} as node_ctxt) - commitment commitment_hash = + let cement_commitment (node_ctxt : Node_context.t) commitment_hash = let open Lwt_result_syntax in let* operator = Node_context.get_operator_keys node_ctxt Cement in match operator with | None -> (* Configured to not cement commitments *) return_unit - | Some (source, src_pk, src_sk) -> - let* _oph, _op, _results = - Client_proto_context.sc_rollup_cement - cctxt - ~chain:cctxt#chain - ~block:cctxt#block - ~commitment:commitment_hash - ~source - ~rollup:rollup_address - ~src_pk - ~src_sk - ~fee_parameter:Configuration.default_fee_parameter - () - in - let*! () = - Commitment_event.cement_commitment_injected commitment_hash commitment + | Some (source, _src_pk, _src_sk) -> + let cement_operation = + Sc_rollup_cement + {rollup = node_ctxt.rollup_address; commitment = commitment_hash} in + let* () = Injector.add_pending_operation ~source cement_operation in + let*! () = Commitment_event.cement_commitment_injected commitment in return_unit - (* TODO: https://gitlab.com/tezos/tezos/-/issues/3008 - Use the injector to cement commitments. *) let cement_commitment_if_possible node_ctxt store (Layer1.Head {level = head_level; _}) = let open Lwt_result_syntax in -- GitLab From f8dc3e1cae948658bbdeca3eac96d4a741784808 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Mon, 4 Jul 2022 10:20:58 +0200 Subject: [PATCH 05/11] SCORU/Node/doc: fix imprecision in documentation --- src/proto_alpha/bin_sc_rollup_node/commitment.ml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/commitment.ml b/src/proto_alpha/bin_sc_rollup_node/commitment.ml index aa980a40846b..b776ce438486 100644 --- a/src/proto_alpha/bin_sc_rollup_node/commitment.ml +++ b/src/proto_alpha/bin_sc_rollup_node/commitment.ml @@ -27,10 +27,11 @@ (** The rollup node stores and publishes commitments for the PVM every [Constants.sc_rollup_commitment_period_in_blocks] levels. - Every time a finalized block is processed by the rollup node, - the latter determines whether the last commitment that the node - has produced referred to 20 blocks earlier. In this case, it - computes and stores a new commitment in a level-indexed map. + Every time a finalized block is processed by the rollup node, the latter + determines whether the last commitment that the node has produced referred + to [sc_rollup.commitment_period_in_blocks] blocks earlier. For mainnet, + [sc_rollup.commitment_period_in_blocks = 30]. In this case, it computes and + stores a new commitment in a level-indexed map. Stored commitments are signed by the rollup node operator and published on the layer1 chain. To ensure that commitments -- GitLab From f0d70162cbf646f75e2bda63026c29abacee3b14 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 19 Jul 2022 15:40:38 +0200 Subject: [PATCH 06/11] SCORU,Node: use injector for refutation games --- .../bin_sc_rollup_node/injector.ml | 24 ++++++- .../bin_sc_rollup_node/refutation_game.ml | 66 ++++--------------- 2 files changed, 33 insertions(+), 57 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/injector.ml b/src/proto_alpha/bin_sc_rollup_node/injector.ml index 135882e5744a..484e2fc26313 100644 --- a/src/proto_alpha/bin_sc_rollup_node/injector.ml +++ b/src/proto_alpha/bin_sc_rollup_node/injector.ml @@ -60,6 +60,8 @@ module Parameters : | Publish -> 1 | Add_messages -> 100 | Cement -> 1 + | Timeout -> 1 + | Refute -> 1 let fee_parameter {Node_context.fee_parameter; _} _ = fee_parameter @@ -89,18 +91,21 @@ module Parameters : type kind. kind manager_operation -> [`Ignore_keep | `Ignore_drop | `Don't_ignore] = function + | Sc_rollup_timeout _ | Sc_rollup_refute _ -> + (* Failing timeout and refutation operations can be ignored. *) + `Ignore_drop | _ -> `Don't_ignore (** Returns [true] if an included operation should be re-queued for injection when the block in which it is included is reverted (due to a reorganization). *) - let requeue_reverted_operation (type kind) _ + let requeue_reverted_operation (type kind) _node_ctxt (operation : kind manager_operation) = let open Lwt_syntax in match operation with | Sc_rollup_publish _ -> (* Commitments are always produced on finalized blocks. They don't need - to be recomputed. *) + to be recomputed, and as such are valid in another branch. *) return_true | Sc_rollup_cement _ -> (* TODO: https://gitlab.com/tezos/tezos/-/issues/3348 @@ -113,6 +118,17 @@ module Parameters : (* Messages posted to an inbox should be re-emitted (i.e. re-queued) in case of a fork. *) return_true + | Sc_rollup_timeout _ -> + (* Timeout should be re-submitted as the timeout may be reached as well + on the other branch *) + return_true + | Sc_rollup_refute _ -> + (* TODO: https://gitlab.com/tezos/tezos/-/issues/3459 + maybe check if game exists on other branch as well. + + Refutation should be re-submitted in case of fork. + *) + return_true | Reveal _ | Transaction _ | Origination _ | Delegation _ | Register_global_constant _ | Set_deposits_limit _ | Increase_paid_storage _ | Tx_rollup_origination | Tx_rollup_submit_batch _ @@ -121,7 +137,7 @@ module Parameters : | Tx_rollup_rejection _ | Tx_rollup_dispatch_tickets _ | Transfer_ticket _ | Dal_publish_slot_header _ | Sc_rollup_originate _ | Sc_rollup_execute_outbox_message _ | Sc_rollup_recover_bond _ - | Sc_rollup_dal_slot_subscribe _ | Sc_rollup_timeout _ | Sc_rollup_refute _ -> + | Sc_rollup_dal_slot_subscribe _ -> (* These operations should never be handled by this injector *) assert false @@ -131,6 +147,8 @@ module Parameters : | Sc_rollup_add_messages _ -> Some Add_messages | Sc_rollup_cement _ -> Some Cement | Sc_rollup_publish _ -> Some Publish + | Sc_rollup_timeout _ -> Some Timeout + | Sc_rollup_refute _ -> Some Refute | _ -> None end 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 45b4c1d7a070..c033f99ce139 100644 --- a/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml +++ b/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml @@ -76,27 +76,13 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct (** [inject_next_move node_ctxt signer ~refuation ~opponent] submits an L1 operation (signed by [signer]) to issue the next move in the refutation - game. [node_ctxt] provides the connection to the Tezos node. *) - let inject_next_move node_ctxt (source, src_pk, src_sk) ~refutation ~opponent - = - let open Node_context in - let open Lwt_result_syntax in - let {rollup_address; cctxt; _} = node_ctxt in - let* _oph, _op, _results = - Client_proto_context.sc_rollup_refute - cctxt - ~chain:cctxt#chain - ~block:cctxt#block - ~refutation - ~opponent - ~source - ~rollup:rollup_address - ~src_pk - ~src_sk - ~fee_parameter:Configuration.default_fee_parameter - () + game. *) + let inject_next_move (node_ctxt : Node_context.t) (source, _src_pk, _src_sk) + ~refutation ~opponent = + let refute_operation = + Sc_rollup_refute {rollup = node_ctxt.rollup_address; refutation; opponent} in - return_unit + Injector.add_pending_operation ~source refute_operation let generate_proof node_ctxt store game start_state = let open Lwt_result_syntax in @@ -226,44 +212,17 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct if Z.(equal chosen_section_len one) then final_move choice else return {choice; step = Dissection dissection} - let try_ f = - let open Lwt_result_syntax in - let*! _res = f () in - return_unit - let play_next_move node_ctxt store game signer opponent = let open Lwt_result_syntax in let* refutation = next_move node_ctxt store game in - (* FIXME: #3008 - - We currently do not remember that we already have - injected a refutation move but it is not included yet. - Hence, we ignore errors here temporarily, waiting for - the injector to enter the scene. - *) - try_ @@ fun () -> inject_next_move node_ctxt signer ~refutation:(Some refutation) ~opponent - let play_timeout node_ctxt (source, src_pk, src_sk) players = - let Sc_rollup.Game.Index.{alice; bob} = players in - let open Node_context in - let open Lwt_result_syntax in - let {rollup_address; cctxt; _} = node_ctxt in - let* _oph, _op, _results = - Client_proto_context.sc_rollup_timeout - cctxt - ~chain:cctxt#chain - ~block:cctxt#block - ~source - ~alice - ~bob - ~rollup:rollup_address - ~src_pk - ~src_sk - ~fee_parameter:Configuration.default_fee_parameter - () + let play_timeout (node_ctxt : Node_context.t) (source, _src_pk, _src_sk) + stakers = + let timeout_operation = + Sc_rollup_timeout {rollup = node_ctxt.rollup_address; stakers} in - return_unit + Injector.add_pending_operation ~source timeout_operation let timeout_reached ~self head_block node_ctxt players = let open Lwt_result_syntax in @@ -295,8 +254,7 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct let* timeout_reached = timeout_reached ~self head_block node_ctxt players in - unless timeout_reached @@ fun () -> - try_ @@ fun () -> play_timeout node_ctxt signer index + unless timeout_reached @@ fun () -> play_timeout node_ctxt signer index let ongoing_game head_block node_ctxt self = let Node_context.{rollup_address; cctxt; _} = node_ctxt in -- GitLab From 34753d235102b386329de98cf86433b4b43d5261 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 19 Jul 2022 15:35:37 +0200 Subject: [PATCH 07/11] SCORU,Node: remove unused events --- .../bin_sc_rollup_node/commitment.ml | 16 ++++---------- .../bin_sc_rollup_node/commitment_event.ml | 22 ------------------- .../bin_sc_rollup_node/commitment_event.mli | 9 -------- 3 files changed, 4 insertions(+), 43 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/commitment.ml b/src/proto_alpha/bin_sc_rollup_node/commitment.ml index b776ce438486..93a78344fdac 100644 --- a/src/proto_alpha/bin_sc_rollup_node/commitment.ml +++ b/src/proto_alpha/bin_sc_rollup_node/commitment.ml @@ -290,7 +290,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct Store.Commitments.mem store next_level_to_publish in if is_commitment_available then - let*! commitment, commitment_hash = + let*! commitment, _commitment_hash = Store.Commitments.get store next_level_to_publish in let* predecessor_published = @@ -339,11 +339,6 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct store commitment.inbox_level in - let*! () = - Commitment_event.publish_commitment_injected - commitment_hash - commitment - in return_unit else return_unit @@ -421,9 +416,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct Sc_rollup_cement {rollup = node_ctxt.rollup_address; commitment = commitment_hash} in - let* () = Injector.add_pending_operation ~source cement_operation in - let*! () = Commitment_event.cement_commitment_injected commitment in - return_unit + Injector.add_pending_operation ~source cement_operation let cement_commitment_if_possible node_ctxt store (Layer1.Head {level = head_level; _}) = @@ -441,7 +434,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct match commitment_with_hash with (* If `commitment_with_hash` is defined, the commitment to be cemented has been stored but not necessarily published by the rollup node. *) - | Some (commitment, commitment_hash) -> ( + | Some (_commitment, commitment_hash) -> ( let*! earliest_cementing_level = earliest_cementing_level node_ctxt store commitment_hash in @@ -457,8 +450,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct head_level commitment_hash in - if green_flag then - cement_commitment node_ctxt commitment commitment_hash + if green_flag then cement_commitment node_ctxt commitment_hash else return () | None -> return ()) | None -> return () diff --git a/src/proto_alpha/bin_sc_rollup_node/commitment_event.ml b/src/proto_alpha/bin_sc_rollup_node/commitment_event.ml index 21e3b871dde3..cabbeba01348 100644 --- a/src/proto_alpha/bin_sc_rollup_node/commitment_event.ml +++ b/src/proto_alpha/bin_sc_rollup_node/commitment_event.ml @@ -113,22 +113,6 @@ module Simple = struct ("inbox_level", Raw_level.encoding) ("compressed_state", Sc_rollup.State_hash.encoding) ("number_of_ticks", Sc_rollup.Number_of_ticks.encoding) - - let commitment_injected kind = - declare_5 - ~section - ~name:(Printf.sprintf "sc_rollup_%s_commitment_injected" kind) - ~msg: - (kind - ^ " commitment {commitment_hash} was injected - predecessor: \ - {predecessor}, inbox_level: {inbox_level}, compressed_state: \ - {compressed_state}, number_of_ticks: {number_of_ticks}") - ~level:Notice - ("commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("predecessor", Sc_rollup.Commitment.Hash.encoding) - ("inbox_level", Raw_level.encoding) - ("compressed_state", Sc_rollup.State_hash.encoding) - ("number_of_ticks", Sc_rollup.Number_of_ticks.encoding) end let starting = Simple.(emit starting) @@ -157,12 +141,6 @@ let commitment_will_not_be_published lcc_level let commitment_stored = emit_commitment_event Simple.commitment_stored -let publish_commitment_injected = - emit_commitment_event (Simple.commitment_injected "publish") - -let cement_commitment_injected = - emit_commitment_event (Simple.commitment_injected "cement") - let last_cemented_commitment_updated head level = Simple.(emit last_cemented_commitment_updated (head, level)) diff --git a/src/proto_alpha/bin_sc_rollup_node/commitment_event.mli b/src/proto_alpha/bin_sc_rollup_node/commitment_event.mli index ed11abd1caad..d818ad4d4931 100644 --- a/src/proto_alpha/bin_sc_rollup_node/commitment_event.mli +++ b/src/proto_alpha/bin_sc_rollup_node/commitment_event.mli @@ -32,15 +32,6 @@ val starting : unit -> unit Lwt.t val stopping : unit -> unit Lwt.t -(** The functions below emit commitment events depending on whether they are - being published or cemented. *) - -val publish_commitment_injected : - Sc_rollup.Commitment.Hash.t -> Sc_rollup.Commitment.t -> unit Lwt.t - -val cement_commitment_injected : - Sc_rollup.Commitment.Hash.t -> Sc_rollup.Commitment.t -> unit Lwt.t - (** [commitment_stored commitment_hash commitment] emits the event that the [commitment] was stored. *) val commitment_stored : -- GitLab From 8abfb38e79096dedbf1220b1bec5014fb05420a9 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 19 Jul 2022 19:19:17 +0200 Subject: [PATCH 08/11] Injector: fix issue where we may remove non injected operations --- src/proto_alpha/lib_injector/injector_functor.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proto_alpha/lib_injector/injector_functor.ml b/src/proto_alpha/lib_injector/injector_functor.ml index b5d351877957..fb59e8ed1338 100644 --- a/src/proto_alpha/lib_injector/injector_functor.ml +++ b/src/proto_alpha/lib_injector/injector_functor.ml @@ -709,7 +709,7 @@ module Make (Rollup : PARAMETERS) = struct (fun op -> Op_queue.remove state.queue op.L1_operation.hash) injected_operations in - add_injected_operations state oph operations_to_inject + add_injected_operations state oph injected_operations | `Ignored operations_to_drop -> (* Injection failed but we ignore the failure. *) let* () = -- GitLab From 1bc645e16c342db53dd3adecc88c6573ac7440d1 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 26 Jul 2022 15:05:12 +0200 Subject: [PATCH 09/11] SCORU,Node: add purpose Timeout Although most of the time, one would use the same key for refute and timeout steps in refutation games. --- src/proto_alpha/bin_sc_rollup_node/configuration.ml | 6 ++++-- src/proto_alpha/bin_sc_rollup_node/configuration.mli | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/configuration.ml b/src/proto_alpha/bin_sc_rollup_node/configuration.ml index 1bf62dae3f4d..3dd34b696899 100644 --- a/src/proto_alpha/bin_sc_rollup_node/configuration.ml +++ b/src/proto_alpha/bin_sc_rollup_node/configuration.ml @@ -28,9 +28,9 @@ open Protocol.Alpha_context type mode = Observer | Batcher | Maintenance | Operator | Custom -type purpose = Publish | Add_messages | Cement | Refute +type purpose = Publish | Add_messages | Cement | Timeout | Refute -let purposes = [Publish; Add_messages; Cement; Refute] +let purposes = [Publish; Add_messages; Cement; Timeout; Refute] module Operator_purpose_map = Map.Make (struct type t = purpose @@ -104,12 +104,14 @@ let string_of_purpose = function | Publish -> "publish" | Add_messages -> "add_messages" | Cement -> "cement" + | Timeout -> "timeout" | Refute -> "refute" let purpose_of_string = function | "publish" -> Some Publish | "add_messages" -> Some Add_messages | "cement" -> Some Cement + | "timeout" -> Some Timeout | "refute" -> Some Refute | _ -> None diff --git a/src/proto_alpha/bin_sc_rollup_node/configuration.mli b/src/proto_alpha/bin_sc_rollup_node/configuration.mli index f1101793810d..0e7334060cb0 100644 --- a/src/proto_alpha/bin_sc_rollup_node/configuration.mli +++ b/src/proto_alpha/bin_sc_rollup_node/configuration.mli @@ -35,7 +35,7 @@ type mode = the signers *) (** Purposes for operators, indicating the kind of operations that they sign. *) -type purpose = Publish | Add_messages | Cement | Refute +type purpose = Publish | Add_messages | Cement | Timeout | Refute module Operator_purpose_map : Map.S with type key = purpose -- GitLab From 62dd7fcbac9b469d5eb83e61be5b2266fb909918 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 26 Jul 2022 15:41:26 +0200 Subject: [PATCH 10/11] SCORU,Node: Don't retrieve operator keys from disk each time --- .../bin_sc_rollup_node/commitment.ml | 8 ++-- .../bin_sc_rollup_node/node_context.ml | 9 +--- .../bin_sc_rollup_node/node_context.mli | 13 ++---- .../bin_sc_rollup_node/refutation_game.ml | 44 ++++++++++--------- 4 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/proto_alpha/bin_sc_rollup_node/commitment.ml b/src/proto_alpha/bin_sc_rollup_node/commitment.ml index 93a78344fdac..cd1bd5599a30 100644 --- a/src/proto_alpha/bin_sc_rollup_node/commitment.ml +++ b/src/proto_alpha/bin_sc_rollup_node/commitment.ml @@ -319,12 +319,12 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct commitment) else return_unit in - let* operator = Node_context.get_operator_keys node_ctxt Publish in + let operator = Node_context.get_operator node_ctxt Publish in match operator with | None -> (* Configured to not publish commitments *) return_unit - | Some (source, _src_pk, _src_sk) -> + | Some source -> let publish_operation = Sc_rollup_publish {rollup = node_ctxt.rollup_address; commitment} in @@ -406,12 +406,12 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct let cement_commitment (node_ctxt : Node_context.t) commitment_hash = let open Lwt_result_syntax in - let* operator = Node_context.get_operator_keys node_ctxt Cement in + let operator = Node_context.get_operator node_ctxt Cement in match operator with | None -> (* Configured to not cement commitments *) return_unit - | Some (source, _src_pk, _src_sk) -> + | Some source -> let cement_operation = Sc_rollup_cement {rollup = node_ctxt.rollup_address; commitment = commitment_hash} 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 c1da77faab23..38712b2d60e5 100644 --- a/src/proto_alpha/bin_sc_rollup_node/node_context.ml +++ b/src/proto_alpha/bin_sc_rollup_node/node_context.ml @@ -39,13 +39,8 @@ type t = { loser_mode : Loser_mode.t; } -let get_operator_keys node_ctxt purpose = - let open Lwt_result_syntax in - match Configuration.Operator_purpose_map.find purpose node_ctxt.operators with - | None -> return_none - | Some operator -> - let+ _, pk, sk = Client_keys.get_key node_ctxt.cctxt operator in - Some (operator, pk, sk) +let get_operator node_ctxt purpose = + Configuration.Operator_purpose_map.find purpose node_ctxt.operators (* TODO: https://gitlab.com/tezos/tezos/-/issues/2901 The constants are retrieved from the latest tezos block. These constants can 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 3591bb45e474..9dd96cfb344d 100644 --- a/src/proto_alpha/bin_sc_rollup_node/node_context.mli +++ b/src/proto_alpha/bin_sc_rollup_node/node_context.mli @@ -51,16 +51,11 @@ type t = { issues wrong commitments (for tests). *) } -(** [get_operator_keys cctxt] returns a triple [(pkh, pk, sk)] corresponding - to the address, public key, and secret key URI of the rollup node operator. +(** [get_operator cctxt purpose] returns the public key hash for the operator + who has purpose [purpose], if any. *) -val get_operator_keys : - t -> - Configuration.purpose -> - (Signature.Public_key_hash.t * Signature.Public_key.t * Client_keys.sk_uri) - option - tzresult - Lwt.t +val get_operator : + t -> Configuration.purpose -> Signature.Public_key_hash.t option (** [init cctxt l1_ctxt sc_rollup operators_pkh] initialises the rollup representation. The rollup origination level and kind are fetched via an 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 c033f99ce139..8e01e19e1037 100644 --- a/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml +++ b/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml @@ -74,11 +74,11 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct | Alice, Bob -> Their_turn | Bob, Alice -> Their_turn - (** [inject_next_move node_ctxt signer ~refuation ~opponent] submits an L1 - operation (signed by [signer]) to issue the next move in the refutation + (** [inject_next_move node_ctxt source ~refuation ~opponent] submits an L1 + operation (signed by [source]) to issue the next move in the refutation game. *) - let inject_next_move (node_ctxt : Node_context.t) (source, _src_pk, _src_sk) - ~refutation ~opponent = + let inject_next_move (node_ctxt : Node_context.t) source ~refutation ~opponent + = let refute_operation = Sc_rollup_refute {rollup = node_ctxt.rollup_address; refutation; opponent} in @@ -212,16 +212,19 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct if Z.(equal chosen_section_len one) then final_move choice else return {choice; step = Dissection dissection} - let play_next_move node_ctxt store game signer opponent = + let play_next_move node_ctxt store game self opponent = let open Lwt_result_syntax in let* refutation = next_move node_ctxt store game in - inject_next_move node_ctxt signer ~refutation:(Some refutation) ~opponent + inject_next_move node_ctxt self ~refutation:(Some refutation) ~opponent - let play_timeout (node_ctxt : Node_context.t) (source, _src_pk, _src_sk) - stakers = + let play_timeout (node_ctxt : Node_context.t) self stakers = let timeout_operation = Sc_rollup_timeout {rollup = node_ctxt.rollup_address; stakers} in + let source = + Node_context.get_operator node_ctxt Timeout |> Option.value ~default:self + (* We fallback on the [Refute] operator if none is provided for [Timeout] *) + in Injector.add_pending_operation ~source timeout_operation let timeout_reached ~self head_block node_ctxt players = @@ -243,18 +246,17 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct | None -> return_false | Some _myself -> return_false - let play head_block node_ctxt store ((self, _, _) as signer) game staker1 - staker2 = + let play head_block node_ctxt store self game staker1 staker2 = let open Lwt_result_syntax in let players = (staker1, staker2) in let index = Sc_rollup.Game.Index.make staker1 staker2 in match turn ~self game index with - | Our_turn {opponent} -> play_next_move node_ctxt store game signer opponent + | Our_turn {opponent} -> play_next_move node_ctxt store game self opponent | Their_turn -> let* timeout_reached = timeout_reached ~self head_block node_ctxt players in - unless timeout_reached @@ fun () -> play_timeout node_ctxt signer index + unless timeout_reached @@ fun () -> play_timeout node_ctxt self index let ongoing_game head_block node_ctxt self = let Node_context.{rollup_address; cctxt; _} = node_ctxt in @@ -265,13 +267,13 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct self () - let play_opening_move node_ctxt signer conflict = + let play_opening_move node_ctxt self conflict = let open Lwt_syntax in let open Sc_rollup.Refutation_storage in let* () = Refutation_game_event.conflict_detected conflict in - inject_next_move node_ctxt signer ~refutation:None ~opponent:conflict.other + inject_next_move node_ctxt self ~refutation:None ~opponent:conflict.other - let start_game_if_conflict head_block node_ctxt ((self, _, _) as signer) = + let start_game_if_conflict head_block node_ctxt self = let open Lwt_result_syntax in let Node_context.{rollup_address; cctxt; _} = node_ctxt in let* conflicts = @@ -283,7 +285,7 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct () in let*! res = - Option.iter_es (play_opening_move node_ctxt signer) (List.hd conflicts) + Option.iter_es (play_opening_move node_ctxt self) (List.hd conflicts) in match res with | Ok r -> return r @@ -300,15 +302,15 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct let process (Layer1.Head {hash; _}) node_ctxt store = let head_block = `Hash (hash, 0) in let open Lwt_result_syntax in - let* signer = Node_context.get_operator_keys node_ctxt Refute in - match signer with + let refute_signer = Node_context.get_operator node_ctxt Refute in + match refute_signer with | None -> (* Not injecting refutations, don't play refutation games *) return_unit - | Some ((self, _, _) as signer) -> ( + | Some self -> ( let* res = ongoing_game head_block node_ctxt self in match res with | Some (game, staker1, staker2) -> - play head_block node_ctxt store signer game staker1 staker2 - | None -> start_game_if_conflict head_block node_ctxt signer) + play head_block node_ctxt store self game staker1 staker2 + | None -> start_game_if_conflict head_block node_ctxt self) end -- GitLab From d051242c5b2334394b871e44eec11b825c8c21a2 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 26 Jul 2022 15:47:58 +0200 Subject: [PATCH 11/11] SCORU,Node: fallback Timeout -> Refute when operator missing --- .../bin_sc_rollup_node/configuration.ml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/proto_alpha/bin_sc_rollup_node/configuration.ml b/src/proto_alpha/bin_sc_rollup_node/configuration.ml index 3dd34b696899..0d6607bc7047 100644 --- a/src/proto_alpha/bin_sc_rollup_node/configuration.ml +++ b/src/proto_alpha/bin_sc_rollup_node/configuration.ml @@ -120,8 +120,24 @@ let purpose_of_string_exn s = | Some p -> p | None -> invalid_arg ("purpose_of_string " ^ s) +let add_fallbacks map fallbacks = + List.fold_left + (fun map (missing_purpose, fallback_purpose) -> + if Operator_purpose_map.mem missing_purpose map then + (* No missing purpose, don't fallback *) + map + else + match Operator_purpose_map.find fallback_purpose map with + | None -> + (* Nothing to fallback on *) + map + | Some operator -> Operator_purpose_map.add missing_purpose operator map) + map + fallbacks + let make_purpose_map ~default bindings = let map = Operator_purpose_map.of_seq @@ List.to_seq bindings in + let map = add_fallbacks map [(Timeout, Refute)] in match default with | None -> map | Some default -> -- GitLab