diff --git a/CHANGES.rst b/CHANGES.rst index ec17def83608f3cdc5168d86f19a3ae5a662801a..19f9042fe7b0df62f97705179133b6b2f83b737e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -79,6 +79,11 @@ Docker Images Smart Rollup node ----------------- +- A new bailout mode that solely cements and defends existing + commitments without publishing new ones. Recovers bonds when + possible, after which the node exits gracefully. (MR :gl:`!9721`, MR + :gl:`!9817`, MR :gl:`!9835`) + Smart Rollup client ------------------- diff --git a/src/lib_smart_rollup_node/daemon_event.ml b/src/lib_smart_rollup_node/daemon_event.ml index c737ca5f594977b966187571efe197956d212e68..fdca440c8d8a12bfe1d57284cddda0e27605d565 100644 --- a/src/lib_smart_rollup_node/daemon_event.ml +++ b/src/lib_smart_rollup_node/daemon_event.ml @@ -142,6 +142,14 @@ module Simple = struct commitments." ~level:Error () + + let exit_bailout_mode = + declare_0 + ~section + ~name:"sc_rollup_daemon_exit_bailout_mode" + ~msg:"Stakes have been recovered, and the node is exiting safely now." + ~level:Error + () end let head_processing hash level = Simple.(emit head_processing (hash, level)) @@ -184,3 +192,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 exit_bailout_mode () = Simple.(emit exit_bailout_mode) () diff --git a/src/lib_smart_rollup_node/daemon_event.mli b/src/lib_smart_rollup_node/daemon_event.mli index cebe62989b774a7211c928aac2e2ea9eb5a0a99a..96ae022ccc455dda511fe2d0812d921e02e02eb2 100644 --- a/src/lib_smart_rollup_node/daemon_event.mli +++ b/src/lib_smart_rollup_node/daemon_event.mli @@ -69,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 when the node exits after recovering the operator's + stakes. *) +val exit_bailout_mode : unit -> unit Lwt.t diff --git a/src/lib_smart_rollup_node/rollup_node_daemon.ml b/src/lib_smart_rollup_node/rollup_node_daemon.ml index 3d9d7bf5b781cdaab5b7a2628ca65cda5b2cf531..3523e3468df6a37c55583401768ecc6f3ecbbf7f 100644 --- a/src/lib_smart_rollup_node/rollup_node_daemon.ml +++ b/src/lib_smart_rollup_node/rollup_node_daemon.ml @@ -431,6 +431,10 @@ let run ({node_ctxt; configuration; plugin; _} as state) = fatal_error_exit e | Rollup_node_errors.Could_not_open_preimage_file _ :: _ as e -> handle_preimage_not_found e + | Rollup_node_errors.Exit_bond_recovered_bailout_mode :: [] -> + let*! () = Daemon_event.exit_bailout_mode () in + let*! _ = Lwt_exit.exit_and_wait 0 in + return_unit | e -> error_to_degraded_mode e) module Internal_for_tests = struct diff --git a/src/lib_smart_rollup_node/rollup_node_errors.ml b/src/lib_smart_rollup_node/rollup_node_errors.ml index 37f4f8c0f8478c89d79bf2d8ea81ed4f201e081d..43c4a573bb38100b3edd3b2f3e87230e61b29415 100644 --- a/src/lib_smart_rollup_node/rollup_node_errors.ml +++ b/src/lib_smart_rollup_node/rollup_node_errors.ml @@ -76,6 +76,8 @@ type error += type error += Operator_not_in_whitelist +type error += Exit_bond_recovered_bailout_mode + let () = register_error_kind `Permanent @@ -399,4 +401,18 @@ let () = `Permanent Data_encoding.unit (function Operator_not_in_whitelist -> Some () | _ -> None) - (fun () -> Operator_not_in_whitelist) + (fun () -> Operator_not_in_whitelist) ; + + register_error_kind + ~id:"sc_rollup.node.exiting_bailout_mode" + ~title:"The rollup node is exiting." + ~description: + "The rollup node is exiting after recovering the bond of the operator." + ~pp:(fun ppf () -> + Format.pp_print_string + ppf + "The rollup node is exiting after bailout mode.") + `Permanent + Data_encoding.unit + (function Exit_bond_recovered_bailout_mode -> Some () | _ -> None) + (fun () -> Exit_bond_recovered_bailout_mode) diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/daemon_helpers.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/daemon_helpers.ml index 1aa60be37de5ed592c43958f5db3211570741ff3..8602b64367f14632320984817b297a6b524b9916 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/daemon_helpers.ml +++ b/src/proto_017_PtNairob/lib_sc_rollup_node/daemon_helpers.ml @@ -273,6 +273,18 @@ let process_included_l1_operation (type kind) (node_ctxt : Node_context.rw) (Sc_rollup_proto_types.Dal.Slot_header.to_octez slot_header) in return_unit + (* If the node is in bailout mode and the bond of the operator has + been recovered then initiate an exit from bailout mode and + gracefully shut down the process. Otherwise, no action is + taken. *) + | Sc_rollup_recover_bond {staker; _}, Sc_rollup_recover_bond_result _ + when Node_context.is_bailout node_ctxt -> ( + match Node_context.get_operator node_ctxt Operating with + | Some operating_pkh -> + fail_when + Signature.Public_key_hash.(operating_pkh = staker) + Sc_rollup_node_errors.Exit_bond_recovered_bailout_mode + | _ -> return_unit) | _, _ -> (* Other manager operations *) return_unit diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/daemon_helpers.ml b/src/proto_018_Proxford/lib_sc_rollup_node/daemon_helpers.ml index 4c072573b6a4c95cf7151715270bd01502f3bf35..8093066ca481f8c7145311408f956cc4bafb4915 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_node/daemon_helpers.ml +++ b/src/proto_018_Proxford/lib_sc_rollup_node/daemon_helpers.ml @@ -270,6 +270,18 @@ let process_included_l1_operation (type kind) (node_ctxt : Node_context.rw) (Sc_rollup_proto_types.Dal.Slot_header.to_octez slot_header) in return_unit + (* If the node is in bailout mode and the bond of the operator has + been recovered then initiate an exit from bailout mode and + gracefully shut down the process. Otherwise, no action is + taken. *) + | Sc_rollup_recover_bond {staker; _}, Sc_rollup_recover_bond_result _ + when Node_context.is_bailout node_ctxt -> ( + match Node_context.get_operator node_ctxt Operating with + | Some operating_pkh -> + fail_when + Signature.Public_key_hash.(operating_pkh = staker) + Sc_rollup_node_errors.Exit_bond_recovered_bailout_mode + | _ -> return_unit) | _, _ -> (* Other manager operations *) return_unit diff --git a/src/proto_alpha/lib_sc_rollup_node/daemon_helpers.ml b/src/proto_alpha/lib_sc_rollup_node/daemon_helpers.ml index 4c072573b6a4c95cf7151715270bd01502f3bf35..8093066ca481f8c7145311408f956cc4bafb4915 100644 --- a/src/proto_alpha/lib_sc_rollup_node/daemon_helpers.ml +++ b/src/proto_alpha/lib_sc_rollup_node/daemon_helpers.ml @@ -270,6 +270,18 @@ let process_included_l1_operation (type kind) (node_ctxt : Node_context.rw) (Sc_rollup_proto_types.Dal.Slot_header.to_octez slot_header) in return_unit + (* If the node is in bailout mode and the bond of the operator has + been recovered then initiate an exit from bailout mode and + gracefully shut down the process. Otherwise, no action is + taken. *) + | Sc_rollup_recover_bond {staker; _}, Sc_rollup_recover_bond_result _ + when Node_context.is_bailout node_ctxt -> ( + match Node_context.get_operator node_ctxt Operating with + | Some operating_pkh -> + fail_when + Signature.Public_key_hash.(operating_pkh = staker) + Sc_rollup_node_errors.Exit_bond_recovered_bailout_mode + | _ -> return_unit) | _, _ -> (* Other manager operations *) return_unit diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index 566add4e346e0649554f236d4b0e011e0d4cfbea..6e5a03c19ae0dd84c9dc82a03f6507989d3cc771 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -6023,11 +6023,12 @@ let bailout_mode_not_publish ~kind = sc_rollup_node "sc_rollup_node_recover_bond.v0" (Fun.const (Some ())) - 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 + and* () = + Sc_rollup_node.wait_for + sc_rollup_node + "sc_rollup_daemon_exit_bailout_mode.v0" + (Fun.const (Some ())) + and* exit_error = Sc_rollup_node.wait sc_rollup_node in let* lcc_hash, _level = Sc_rollup_helpers.last_cemented_commitment_hash_with_level ~sc_rollup @@ -6040,26 +6041,23 @@ let bailout_mode_not_publish ~kind = ~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 Log.info "The node has submitted the recover_bond operation, and the operator is no \ longer staked." ; - let* operator_balance = contract_balances ~pkh:operator tezos_client in + let* frozen_balance = + RPC.Client.call tezos_client + @@ RPC.get_chain_block_context_contract_frozen_bonds ~id:operator () + in let () = Check.( - (operator_balance.frozen = 0) + (Tez.to_mutez frozen_balance = 0) int ~error_msg: "The operator should not have a stake nor holds a frozen balance.") in - unit + match exit_error with + | WEXITED 0 -> unit + | _ -> failwith "rollup node did not stop gracefully" let custom_mode_empty_operation_kinds ~kind = test_l1_scenario