diff --git a/src/lib_smart_rollup_node/configuration.ml b/src/lib_smart_rollup_node/configuration.ml index ec486a62eead73877dc896060c9b0ce56d916726..c20d7e9c654e3bd9679f80e03e24f656175444b9 100644 --- a/src/lib_smart_rollup_node/configuration.ml +++ b/src/lib_smart_rollup_node/configuration.ml @@ -25,7 +25,14 @@ (* *) (*****************************************************************************) -type mode = Observer | Accuser | Batcher | Maintenance | Operator | Custom +type mode = + | Observer + | Accuser + | Bailout + | Batcher + | Maintenance + | Operator + | Custom type operation_kind = Publish | Add_messages | Cement | Timeout | Refute @@ -467,11 +474,12 @@ let fee_parameter_encoding operation_kind = let fee_parameters_encoding = operation_kind_map_encoding fee_parameter_encoding -let modes = [Observer; Batcher; Maintenance; Operator; Custom] +let modes = [Observer; Batcher; Maintenance; Operator; Custom; Bailout] let string_of_mode = function | Observer -> "observer" | Accuser -> "accuser" + | Bailout -> "bailout" | Batcher -> "batcher" | Maintenance -> "maintenance" | Operator -> "operator" @@ -480,6 +488,7 @@ let string_of_mode = function let mode_of_string = function | "observer" -> Ok Observer | "accuser" -> Ok Accuser + | "bailout" -> Ok Bailout | "batcher" -> Ok Batcher | "maintenance" -> Ok Maintenance | "operator" -> Ok Operator @@ -490,6 +499,7 @@ let description_of_mode = function | Observer -> "Only follows the chain, reconstructs and interprets inboxes" | Accuser -> "Only publishes commitments for conflicts and play refutation games" + | Bailout -> "Only defends and cements, does not publish any new commitments" | Batcher -> "Accepts transactions in its queue and batches them on the L1" | Maintenance -> "Follows the chain and publishes commitments, cement and refute" @@ -503,6 +513,7 @@ let mode_encoding = [ ("observer", Observer); ("accuser", Accuser); + ("bailout", Bailout); ("batcher", Batcher); ("maintenance", Maintenance); ("operator", Operator); @@ -742,6 +753,7 @@ let check_mode config = | Observer -> narrow_purposes [] | Batcher -> narrow_purposes [Batching] | Accuser -> narrow_purposes [Operating] + | Bailout -> narrow_purposes [Operating; Cementing] | Maintenance -> narrow_purposes [Operating; Cementing] | Operator -> narrow_purposes [Operating; Cementing; Batching] | Custom -> return config diff --git a/src/lib_smart_rollup_node/configuration.mli b/src/lib_smart_rollup_node/configuration.mli index 119d2efba2f9483fd341635f8d7557948c39ab51..2814dd6f6a862f9e36b21ecdc00b0628228d398a 100644 --- a/src/lib_smart_rollup_node/configuration.mli +++ b/src/lib_smart_rollup_node/configuration.mli @@ -29,6 +29,7 @@ type mode = | Observer (** Only follows the chain and reconstructs inboxes *) | Accuser (** Only publishes commitments for conflicts and play refutation games *) + | Bailout (* Only defends and cements, does not publish any new commitment *) | Batcher (** Accept transactions in its queue and batches them on the L1 *) | Maintenance (** Follows the chain and publishes commitments *) | Operator (** Equivalent to maintenance + batcher *) diff --git a/src/lib_smart_rollup_node/daemon_event.ml b/src/lib_smart_rollup_node/daemon_event.ml index 66fbe0e2489e8c8fb44586d5eb552390d7dace12..0c5da136c4894298da2c3c8e9807ee27b7fcd63c 100644 --- a/src/lib_smart_rollup_node/daemon_event.ml +++ b/src/lib_smart_rollup_node/daemon_event.ml @@ -4,6 +4,7 @@ (* Copyright (c) 2023 TriliTech *) (* Copyright (c) 2023 Nomadic Labs, *) (* Copyright (c) 2023 Functori, *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -141,6 +142,16 @@ module Simple = struct commitments." ~level:Error () + + let bailout_mode = + declare_0 + ~section + ~name:"sc_rollup_daemon_bailout_mode" + ~msg: + "Entering bailout mode: only defends and cements, does not publish any \ + commitment." + ~level:Error + () end let head_processing hash level = Simple.(emit head_processing (hash, level)) @@ -183,3 +194,5 @@ let migration ~catching_up (old_protocol, old_protocol_level) let error e = Simple.(emit error) e let degraded_mode () = Simple.(emit degraded_mode) () + +let bailout_mode () = Simple.(emit bailout_mode) () diff --git a/src/lib_smart_rollup_node/daemon_event.mli b/src/lib_smart_rollup_node/daemon_event.mli index a5beb5c9feb2cc2066eee69af2f3e483daffa497..c5db7a677a4b5bba3a8517111e395ee798ba0e9e 100644 --- a/src/lib_smart_rollup_node/daemon_event.mli +++ b/src/lib_smart_rollup_node/daemon_event.mli @@ -4,6 +4,7 @@ (* Copyright (c) 2023 TriliTech *) (* Copyright (c) 2023 Nomadic Labs, *) (* Copyright (c) 2023 Functori, *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -68,3 +69,7 @@ val error : tztrace -> unit Lwt.t (** Emit an event for when the node enters the degraded mode to only play refutations. *) val degraded_mode : unit -> unit Lwt.t + +(** Emit an event for when the node enters the bailout mode to only defends and + cements, does not publish any new commitment. *) +val bailout_mode : unit -> unit Lwt.t diff --git a/src/lib_smart_rollup_node/node_context.ml b/src/lib_smart_rollup_node/node_context.ml index 957e6696d459fa64c765b256ce8be7fe1d805f20..145525ae737f173a46d70e16e5b2242c349852af 100644 --- a/src/lib_smart_rollup_node/node_context.ml +++ b/src/lib_smart_rollup_node/node_context.ml @@ -3,6 +3,7 @@ (* Open Source License *) (* Copyright (c) 2023 TriliTech *) (* Copyright (c) 2023 Functori, *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -78,6 +79,8 @@ let is_operator node_ctxt pkh = let is_accuser {mode; _} = mode = Accuser +let is_bailout {mode; _} = mode = Bailout + let is_loser {loser_mode; _} = loser_mode <> Loser_mode.no_failures let get_fee_parameter node_ctxt operation_kind = diff --git a/src/lib_smart_rollup_node/node_context.mli b/src/lib_smart_rollup_node/node_context.mli index d7f9934d4f6d4b53444aa68f6545eb3f3e90d277..1d6809ac0605a47fa7485b23715b43d1f516a9b5 100644 --- a/src/lib_smart_rollup_node/node_context.mli +++ b/src/lib_smart_rollup_node/node_context.mli @@ -3,6 +3,7 @@ (* Open Source License *) (* Copyright (c) 2023 TriliTech *) (* Copyright (c) 2023 Functori, *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -113,6 +114,10 @@ val is_operator : _ t -> Signature.Public_key_hash.t -> bool mode. *) val is_accuser : _ t -> bool +(** [is_bailout node_ctxt] returns [true] if the rollup node runs in bailout + mode. *) +val is_bailout : _ t -> bool + (** [is_loser node_ctxt] returns [true] if the rollup node runs has some failures planned. *) val is_loser : _ t -> bool diff --git a/src/lib_smart_rollup_node/publisher.ml b/src/lib_smart_rollup_node/publisher.ml index 2e49f7f73c4aafc0e74235dc76c4701a0cd1885d..eb39ab47ead3185e643f2f408ad6c6296dd8ddda 100644 --- a/src/lib_smart_rollup_node/publisher.ml +++ b/src/lib_smart_rollup_node/publisher.ml @@ -3,6 +3,7 @@ (* Open Source License *) (* Copyright (c) 2022 TriliTech *) (* Copyright (c) 2022 Nomadic Labs, *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -287,8 +288,8 @@ let publish_commitment (node_ctxt : _ Node_context.t) ~source let on_publish_commitments (node_ctxt : state) = let open Lwt_result_syntax in let operator = Node_context.get_operator node_ctxt Operating in - if Node_context.is_accuser node_ctxt then - (* Accuser does not publish all commitments *) + if Node_context.is_accuser node_ctxt || Node_context.is_bailout node_ctxt then + (* Accuser and Bailout do not publish all commitments *) return_unit else match operator with diff --git a/tezt/lib_tezos/sc_rollup_node.ml b/tezt/lib_tezos/sc_rollup_node.ml index 9a8c16017cb29ab8ed3988b97b24400c041a6d68..f499e0d03bc24c30d0acb533cd3897e20ea317c1 100644 --- a/tezt/lib_tezos/sc_rollup_node.ml +++ b/tezt/lib_tezos/sc_rollup_node.ml @@ -2,6 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2021 Nomadic Labs *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -25,7 +26,14 @@ type 'a known = Unknown | Known of 'a -type mode = Batcher | Custom | Maintenance | Observer | Operator | Accuser +type mode = + | Batcher + | Custom + | Maintenance + | Observer + | Operator + | Accuser + | Bailout module Parameters = struct type persistent_state = { @@ -60,6 +68,7 @@ let string_of_mode = function | Operator -> "operator" | Custom -> "custom" | Accuser -> "accuser" + | Bailout -> "bailout" let mode_of_string s = match String.lowercase_ascii s with @@ -69,6 +78,7 @@ let mode_of_string s = | "operator" -> Operator | "custom" -> Custom | "accuser" -> Accuser + | "bailout" -> Bailout | _ -> invalid_arg (Format.sprintf "%S is not an existing mode" s) let check_error ?exit_code ?msg sc_node = @@ -367,23 +377,34 @@ let do_runlike_command ?event_level ?event_sections_levels node arguments = arguments ~on_terminate -let run ?(legacy = false) ?event_level ?event_sections_levels ?loser_mode node - rollup_address extra_arguments = +let run ?(legacy = false) ?(restart = false) ?mode ?event_level + ?event_sections_levels ?loser_mode node rollup_address extra_arguments = + let* () = + if restart then + let* () = terminate node in + return () + else return () + in let cmd = if legacy then let args = legacy_node_args ?loser_mode node rollup_address in ["run"] @ args @ extra_arguments else - let mode, args = node_args ?loser_mode node rollup_address in - ["run"; mode] @ args @ extra_arguments + let default_mode, args = node_args ?loser_mode node rollup_address in + let final_mode = + match mode with Some m -> string_of_mode m | None -> default_mode + in + ["run"; final_mode] @ args @ extra_arguments in do_runlike_command ?event_level ?event_sections_levels node cmd -let run ?legacy ?event_level ?event_sections_levels ?loser_mode +let run ?legacy ?restart ?mode ?event_level ?event_sections_levels ?loser_mode ?(wait_ready = true) node rollup_address arguments = let* () = run ?legacy + ?restart + ?mode ?event_level ?event_sections_levels ?loser_mode diff --git a/tezt/lib_tezos/sc_rollup_node.mli b/tezt/lib_tezos/sc_rollup_node.mli index 50a2c57bb72769e07ce3df00cbb1de84fafa0f8e..e33c027dbb56d759369c483e7846a0ab213e8caa 100644 --- a/tezt/lib_tezos/sc_rollup_node.mli +++ b/tezt/lib_tezos/sc_rollup_node.mli @@ -2,6 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2021 Nomadic Labs *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -31,7 +32,14 @@ (** Smart contract rollup node states. *) type t -type mode = Batcher | Custom | Maintenance | Observer | Operator | Accuser +type mode = + | Batcher + | Custom + | Maintenance + | Observer + | Operator + | Accuser + | Bailout (** Returns the associated {!mode}, fails if the mode is not valid. *) val mode_of_string : string -> mode @@ -135,9 +143,12 @@ val check_error : ?exit_code:int -> ?msg:Base.rex -> t -> unit Lwt.t emit (see {!Daemon}). [legacy] (by default [false]) must be set if we want to use the legacy [run] command of the node (which requires a config file to exist). If [wait_ready] is [false], tezt does not wait for the node to be - ready. *) + ready. If [restart] is [true], it will stop and restart the node if it is already + running. *) val run : ?legacy:bool -> + ?restart:bool -> + ?mode:mode -> ?event_level:Daemon.Level.default_level -> ?event_sections_levels:(string * Daemon.Level.level) list -> ?loser_mode:string -> diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index 2eadee62360b9f6bbb387ad2bbd387e7deb652bd..90583cec2acb91b25752abb3575d2129e132cc5e 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -4,6 +4,7 @@ (* Copyright (c) 2021-2023 Nomadic Labs *) (* Copyright (c) 2022-2023 TriliTech *) (* Copyright (c) 2023 Functori *) +(* Copyright (c) 2023 Marigold *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -5931,6 +5932,110 @@ let test_rollup_whitelist_outdated_update ~kind = ~msg:(rex ".*Outdated whitelist update: got outbox level") process +(** This test uses the rollup node, first it is running in an + Operator mode, it bakes some blocks, then terminate. Then we + restart the node in a Bailout mode, and make sure that there are + no new commitments have been published *) +let bailout_mode_not_publish ~kind = + let operator = Constant.bootstrap1.public_key_hash in + let commitment_period = 5 in + let challenge_window = 5 in + test_full_scenario + { + tags = ["node"; "mode"; "bailout"]; + variant = None; + description = "rollup node - bailout mode does not publish"; + } + ~kind + ~operator + ~mode:Operator + ~challenge_window + ~commitment_period + @@ fun _protocol + sc_rollup_node + sc_rollup_client + sc_rollup + _tezos_node + tezos_client -> + (* Run the rollup node in Operator mode, bake some blocks until + a commitment is published *) + let* () = + Sc_rollup_node.run ~event_level:`Debug sc_rollup_node sc_rollup [] + in + let* _level = + bake_until_lpc_updated + ~at_least:commitment_period + tezos_client + sc_rollup_node + in + let* published_commitment_before = + get_last_published_commitment ~__LOC__ ~hooks sc_rollup_client + in + let* staked_on_commitment = + get_staked_on_commitment ~sc_rollup ~staker:operator tezos_client + in + Log.info "Check that the LPC is equal to the staked commitment onchain." ; + let () = + Check.( + published_commitment_before.commitment_and_hash.hash + = staked_on_commitment) + Check.string + ~error_msg:"Last published commitment is not latest commitment staked on." + in + (* Terminate the rollup of Operator mode and restart it with the Bailout mode *) + let* () = + Sc_rollup_node.run + ~restart:true + ~event_level:`Debug + sc_rollup_node + sc_rollup + [] + ~mode:Bailout + in + let* () = Sc_rollup_node.wait_for_ready sc_rollup_node in + (* The challenge window is neded to compute the correct number of block before + cementation, we also add 2 times of commitment period to make sure + no commit are published. *) + let* () = + repeat + ((2 * commitment_period) + challenge_window) + (fun () -> Client.bake_for_and_wait tezos_client) + in + let* _ = Sc_rollup_node.wait_sync sc_rollup_node ~timeout:100. in + let* published_commitment_after = + get_last_published_commitment ~__LOC__ ~hooks sc_rollup_client + in + let* lcc_hash, _level = + Sc_rollup_helpers.last_cemented_commitment_hash_with_level + ~sc_rollup + tezos_client + in + Log.info "Check the LCC is the same." ; + let () = + Check.(lcc_hash = published_commitment_before.commitment_and_hash.hash) + Check.string + ~error_msg: + "Published commitment is not the same as the cemented commitment hash." + in + Log.info "Check the last published commitment is the same as before." ; + let () = + Check.( + published_commitment_after.commitment_and_hash.hash + = published_commitment_before.commitment_and_hash.hash) + Check.string + ~error_msg:"Last published commitment have been updated." + in + let* () = Sc_rollup_node.terminate sc_rollup_node in + Log.info "Client submits the recover_bond operation." ; + let*! () = + Client.Sc_rollup.submit_recover_bond + ~rollup:sc_rollup + ~src:operator + ~staker:operator + tezos_client + in + unit + let register ~kind ~protocols = test_origination ~kind protocols ; test_rollup_node_running ~kind protocols ; @@ -5999,6 +6104,12 @@ let register ~kind ~protocols = (mode_publish Operator true) protocols ~kind ; + test_commitment_scenario + ~extra_tags:["modes"; "bailout"] + ~variant:"bailout_does_not_publish" + (mode_publish Bailout false) + protocols + ~kind ; test_commitment_scenario ~commitment_period:15 ~challenge_window:10080 @@ -6047,6 +6158,8 @@ let register ~kind ~protocols = protocols ~kind ; test_cement_ignore_commitment ~kind [Nairobi; Alpha] ; + bailout_mode_not_publish ~kind protocols ; + (* TODO: https://gitlab.com/tezos/tezos/-/issues/4373 Uncomment this test as soon as the issue done. test_reinject_failed_commitment protocols ~kind ; *) @@ -6109,6 +6222,7 @@ let register ~protocols = register ~kind:"arith" ~protocols ; (* Both Arith and Wasm PVM tezts *) test_bootstrap_smart_rollup_originated protocols ; + (* Private rollup node *) test_private_rollup_whitelisted_staker protocols ; test_private_rollup_non_whitelisted_staker protocols ; test_private_rollup_node_publish_in_whitelist protocols ;