diff --git a/src/proto_alpha/lib_client/client_proto_args.ml b/src/proto_alpha/lib_client/client_proto_args.ml index 5d44f1f3f02ca25daf64bbc7049a508ae5f44059..0a6667700c4b488db02160229b2994d023624ac8 100644 --- a/src/proto_alpha/lib_client/client_proto_args.ml +++ b/src/proto_alpha/lib_client/client_proto_args.ml @@ -882,6 +882,30 @@ module Tx_rollup = struct next end +module Sc_rollup_params = struct + let sc_rollup_address_parameter = + Clic.parameter (fun _ s -> + match Alpha_context.Sc_rollup.Address.of_b58check_opt s with + | Some c -> return c + | None -> + failwith + "Parameter '%s' is an invalid smart contract rollup address \ + encoded in a base58 string." + s) + + let sc_rollup_address_param ?(name = "smart contract rollup address") ~usage + next = + Clic.param + ~name + ~desc: + (Format.sprintf + "@[@[%s@]@.@[Smart contract rollup address encoded in a base58 \ + string.@]@]" + usage) + sc_rollup_address_parameter + next +end + let fee_parameter_args = let open Clic in let force_low_fee_arg = diff --git a/src/proto_alpha/lib_client/client_proto_args.mli b/src/proto_alpha/lib_client/client_proto_args.mli index 4efa1d3837dc9eedab6aa3d784b2920488e88964..1a3df5f6f3df791c1fdb2a26be098a3f3ef15440 100644 --- a/src/proto_alpha/lib_client/client_proto_args.mli +++ b/src/proto_alpha/lib_client/client_proto_args.mli @@ -239,5 +239,13 @@ module Tx_rollup : sig (Tx_rollup_inbox.Merkle.root -> 'a, full) Clic.params end +module Sc_rollup_params : sig + val sc_rollup_address_param : + ?name:string -> + usage:string -> + ('a, full) Clic.params -> + (Alpha_context.Sc_rollup.t -> 'a, full) Clic.params +end + val fee_parameter_args : (Injection.fee_parameter, Protocol_client_context.full) Clic.arg diff --git a/src/proto_alpha/lib_client/client_proto_context.ml b/src/proto_alpha/lib_client/client_proto_context.ml index 38b3d4e38c8fccbd595039a5c9ca6101c6c7e493..789965ed87d8ca3a9d443e9b794bcb145ac05651 100644 --- a/src/proto_alpha/lib_client/client_proto_context.ml +++ b/src/proto_alpha/lib_client/client_proto_context.ml @@ -1310,3 +1310,40 @@ let sc_rollup_atomic_batch (cctxt : #full) ~chain ~block ?confirmations ?dry_run match Apply_results.pack_contents_list op result with | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> return (oph, op, result) + +let sc_rollup_return_bond (cctxt : #full) ~chain ~block ?confirmations ?dry_run + ?verbose_signing ?simulation ?fee ?gas_limit ?storage_limit ?counter ~source + ~src_pk ~src_sk ~fee_parameter ~sc_rollup () = + let contents : + Kind.sc_rollup_return_bond Annotated_manager_operation.annotated_list = + Annotated_manager_operation.Single_manager + (Injection.prepare_manager_operation + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + (Sc_rollup_return_bond {sc_rollup})) + in + (* TODO/Fixme: https://gitlab.com/tezos/tezos/-/issues/2609 + Decide if we should enforce ~successor_level:true for simulation. + See https://gitlab.com/tezos/tezos/-/merge_requests/5395#note_958326685 *) + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?simulation + ?counter + ~source + ~fee:(Limit.of_option fee) + ~storage_limit:(Limit.of_option storage_limit) + ~gas_limit:(Limit.of_option gas_limit) + ~src_pk + ~src_sk + ~fee_parameter + contents + >>=? fun (oph, _, op, result) -> + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> + return (oph, op, result) diff --git a/src/proto_alpha/lib_client/client_proto_context.mli b/src/proto_alpha/lib_client/client_proto_context.mli index 97951466bf00e31650fa65b8a93be0070843951b..89a40d5cc456d91434571722835ec5a98a601515 100644 --- a/src/proto_alpha/lib_client/client_proto_context.mli +++ b/src/proto_alpha/lib_client/client_proto_context.mli @@ -795,3 +795,27 @@ val sc_rollup_atomic_batch : tztrace ) result Lwt.t + +val sc_rollup_return_bond : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?simulation:bool -> + ?fee:Tez.tez -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + ?counter:Z.t -> + source:Signature.public_key_hash -> + src_pk:Signature.public_key -> + src_sk:Client_keys.sk_uri -> + fee_parameter:Injection.fee_parameter -> + sc_rollup:Sc_rollup.t -> + unit -> + (Operation_hash.t + * Kind.sc_rollup_return_bond Kind.manager contents + * Kind.sc_rollup_return_bond Kind.manager Apply_results.contents_result) + tzresult + Lwt.t diff --git a/src/proto_alpha/lib_client/injection.ml b/src/proto_alpha/lib_client/injection.ml index 61706e1e4d1a1fb4e9441686b1d292cfb4cde9b4..6ad982bb5a27a552d351a05b53d172a07788498a 100644 --- a/src/proto_alpha/lib_client/injection.ml +++ b/src/proto_alpha/lib_client/injection.ml @@ -332,7 +332,8 @@ let estimated_gas_single (type kind) | Sc_rollup_publish_result {consumed_gas; _} -> Ok consumed_gas | Sc_rollup_refute_result {consumed_gas; _} -> Ok consumed_gas | Sc_rollup_timeout_result {consumed_gas; _} -> Ok consumed_gas - | Sc_rollup_atomic_batch_result {consumed_gas; _} -> Ok consumed_gas) + | Sc_rollup_atomic_batch_result {consumed_gas; _} -> Ok consumed_gas + | Sc_rollup_return_bond_result {consumed_gas; _} -> Ok consumed_gas) | Skipped _ -> Ok Gas.Arith.zero (* there must be another error for this to happen *) | Failed (_, errs) -> Error (Environment.wrap_tztrace errs) @@ -411,7 +412,8 @@ let estimated_storage_single (type kind) ~tx_rollup_origination_size | Sc_rollup_cement_result _ -> Ok Z.zero | Sc_rollup_publish_result _ -> Ok Z.zero | Sc_rollup_refute_result _ -> Ok Z.zero - | Sc_rollup_timeout_result _ -> Ok Z.zero) + | Sc_rollup_timeout_result _ -> Ok Z.zero + | Sc_rollup_return_bond_result _ -> Ok Z.zero) | Skipped _ -> Ok Z.zero (* there must be another error for this to happen *) | Failed (_, errs) -> Error (Environment.wrap_tztrace errs) @@ -500,7 +502,8 @@ let originated_contracts_single (type kind) | Sc_rollup_publish_result _ -> Ok [] | Sc_rollup_refute_result _ -> Ok [] | Sc_rollup_timeout_result _ -> Ok [] - | Sc_rollup_atomic_batch_result _ -> Ok []) + | Sc_rollup_atomic_batch_result _ -> Ok [] + | Sc_rollup_return_bond_result _ -> Ok []) | Skipped _ -> Ok [] (* there must be another error for this to happen *) | Failed (_, errs) -> Error (Environment.wrap_tztrace errs) in diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index fec54f0f6169cc3e80ce4779ffe011c0dd151a12..565636a05f2d6f1a7e996e9f3735cadf61b69a75 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -358,8 +358,15 @@ let pp_manager_operation_content (type kind) source pp_result ppf outbox_level message_index inclusion_proof - atomic_transaction_batch) ; - + atomic_transaction_batch + | Sc_rollup_return_bond {sc_rollup} -> + Format.fprintf + ppf + "Sc rollup return commitment bond:%a @,From: %a" + Sc_rollup.Address.pp + sc_rollup + Contract.pp + source) ; Format.fprintf ppf "%a@]@]" pp_result result let pp_balance_updates ppf = function @@ -756,6 +763,15 @@ let pp_manager_operation_contents_and_result ppf Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas ; pp_balance_updates_opt ppf balance_updates in + let pp_sc_rollup_return_bond_result + (Sc_rollup_return_bond_result {balance_updates; consumed_gas}) = + Format.fprintf + ppf + "@,Balance updates:@, %a" + pp_balance_updates + balance_updates ; + Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas + in let pp_result (type kind) ppf (result : kind manager_operation_result) = Format.fprintf ppf "@," ; match result with @@ -1006,12 +1022,24 @@ let pp_manager_operation_contents_and_result ppf ppf "This sc rollup atomic batch operation was successfully applied." ; pp_sc_rollup_atomic_batch_result op + | Applied (Sc_rollup_return_bond_result _ as op) -> + Format.fprintf + ppf + "This sc rollup return commitment bond operation was successfully \ + applied" ; + pp_sc_rollup_return_bond_result op | Backtracked ((Sc_rollup_atomic_batch_result _ as op), _err) -> Format.fprintf ppf "@[This sc rollup atomic batch operation was BACKTRACKED, its \ expected effects (as follow) were NOT applied.@]" ; pp_sc_rollup_atomic_batch_result op + | Backtracked ((Sc_rollup_return_bond_result _ as op), _err) -> + Format.fprintf + ppf + "@[This sc rollup return commitment bond operation was \ + BACKTRACKED, its expected effects (as follow) were NOT applied.@]" ; + pp_sc_rollup_return_bond_result op in let pp_internal_result (type kind) ppf (result : kind internal_manager_operation_result) = diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index cf9ac2638b16ffabf735bd6484f5b15943cf2e67..b5a914174bb8e5cccd39f773980ad21546c03743 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -117,6 +117,9 @@ let messages_param = | ["file"; path] -> from_path path | _ -> if Sys.file_exists p then from_path p else from_text p +(* TODO: https://gitlab.com/tezos/tezos/-/issues/3064 + Move scoru related params to Client_proto_args.Sc_rollup(_params) +*) let commitment_hash_param = Clic.parameter (fun _ commitment_hash -> match Sc_rollup.Commitment.Hash.of_b58check_opt commitment_hash with @@ -2871,6 +2874,58 @@ let commands_rw () = ~fee_parameter () >>=? fun _res -> return_unit); + command + ~group + ~desc:"Recover commitment bond from a smart contract rollup." + (args7 + fee_arg + dry_run_switch + verbose_signing_switch + simulate_switch + fee_parameter_args + storage_limit_arg + counter_arg) + (prefixes ["recover"; "bond"; "of"] + @@ ContractAlias.destination_param + ~name:"src" + ~desc:"Account that owns the bond." + @@ prefixes ["for"; "sc"; "rollup"] + @@ Sc_rollup_params.sc_rollup_address_param + ~usage:"Smart-contract rollup of the bond." + @@ stop) + (fun ( fee, + dry_run, + verbose_signing, + simulation, + fee_parameter, + storage_limit, + counter ) + source + sc_rollup + cctxt -> + match source with + | Originated _ -> + failwith "Only implicit accounts can deposit/recover bonds" + | Implicit source -> + Client_keys.get_key cctxt source >>=? fun (_, src_pk, src_sk) -> + sc_rollup_return_bond + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ~dry_run + ~verbose_signing + ?fee + ?storage_limit + ?counter + ?confirmations:cctxt#confirmations + ~simulation + ~source + ~src_pk + ~src_sk + ~fee_parameter + ~sc_rollup + () + >>=? fun _res -> return_unit); ] let commands network () = diff --git a/src/proto_alpha/lib_injector/l1_operation.ml b/src/proto_alpha/lib_injector/l1_operation.ml index ca94bfaed2b84300d3178dac7a0ed32c839bd5f8..769dc6f007c2fbfc447222b86582120d9c72eb17 100644 --- a/src/proto_alpha/lib_injector/l1_operation.ml +++ b/src/proto_alpha/lib_injector/l1_operation.ml @@ -98,6 +98,7 @@ module Manager_operation = struct | Sc_rollup_refute _ -> sc_rollup_refute_case | Sc_rollup_timeout _ -> sc_rollup_timeout_case | Sc_rollup_atomic_batch _ -> sc_rollup_atomic_batch_case + | Sc_rollup_return_bond _ -> sc_rollup_return_bond_case let pp_kind ppf op = let open Operation.Encoding.Manager_operations in diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 712e27b6aa05f8f0a1ddf1015192b31dcaa3566f..96f390c51cfb1fc8ca6fae9d4d64adb057a57052 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2920,6 +2920,12 @@ module Sc_rollup : sig val cement_commitment : context -> t -> Commitment.Hash.t -> context tzresult Lwt.t + + val withdraw_stake : + context -> + t -> + Staker.t -> + (context * Receipt.balance_updates) tzresult Lwt.t end module Refutation_storage : sig @@ -3247,6 +3253,8 @@ module Kind : sig type sc_rollup_atomic_batch = Sc_rollup_atomic_batch_kind + type sc_rollup_return_bond = Sc_rollup_return_bond_kind + type 'a manager = | Reveal_manager_kind : reveal manager | Transaction_manager_kind : transaction manager @@ -3274,6 +3282,7 @@ module Kind : sig | Sc_rollup_refute_manager_kind : sc_rollup_refute manager | Sc_rollup_timeout_manager_kind : sc_rollup_timeout manager | Sc_rollup_atomic_batch_manager_kind : sc_rollup_atomic_batch manager + | Sc_rollup_return_bond_manager_kind : sc_rollup_return_bond manager end type 'a consensus_operation_type = @@ -3495,6 +3504,10 @@ and _ manager_operation = atomic_transaction_batch : string; } -> Kind.sc_rollup_atomic_batch manager_operation + | Sc_rollup_return_bond : { + sc_rollup : Sc_rollup.t; + } + -> Kind.sc_rollup_return_bond manager_operation and counter = Z.t @@ -3669,6 +3682,9 @@ module Operation : sig val sc_rollup_atomic_batch_case : Kind.sc_rollup_atomic_batch Kind.manager case + val sc_rollup_return_bond_case : + Kind.sc_rollup_return_bond Kind.manager case + module Manager_operations : sig type 'b case = | MCase : { @@ -3728,6 +3744,8 @@ module Operation : sig val sc_rollup_timeout_case : Kind.sc_rollup_timeout case val sc_rollup_atomic_batch_case : Kind.sc_rollup_atomic_batch case + + val sc_rollup_return_bond_case : Kind.sc_rollup_return_bond case end end diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 8aaa58486a0b484b1bf8ccb93820886de0f913e2..c24991c1f402b71a16dd3020207906d29a507570 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1857,6 +1857,17 @@ let apply_external_manager_operation_content : ~atomic_transaction_batch >>=? fun _ctxt -> failwith "Sc_rolup_atomic_batch operation is not yet supported." + | Sc_rollup_return_bond {sc_rollup} -> + Sc_rollup.Stake_storage.withdraw_stake ctxt sc_rollup source + >>=? fun (ctxt, balance_updates) -> + let result = + Sc_rollup_return_bond_result + { + consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt; + balance_updates; + } + in + return (ctxt, result, []) type success_or_failure = Success of context | Failure @@ -2054,6 +2065,13 @@ let precheck_manager_contents (type kind) ctxt (op : kind Kind.manager contents) | Sc_rollup_publish _ | Sc_rollup_refute _ | Sc_rollup_timeout _ | Sc_rollup_atomic_batch _ -> assert_sc_rollup_feature_enabled ctxt >|=? fun () -> ctxt + | Sc_rollup_return_bond _ -> + (* TODO: https://gitlab.com/tezos/tezos/-/issues/3063 + should we successfully precheck Sc_rollup_return_bond and any + (simple) Sc rollup operation, or should we add some some checks to make + the operations Branch_delayed if they cannot be successfully + prechecked. *) + assert_sc_rollup_feature_enabled ctxt >|=? fun () -> ctxt | Dal_publish_slot_header {slot} -> Dal_apply.validate_publish_slot_header ctxt slot >>?= fun () -> return ctxt) @@ -2235,6 +2253,7 @@ let burn_manager_storage_fees : ( ctxt, storage_limit, Sc_rollup_atomic_batch_result {payload with balance_updates} ) + | Sc_rollup_return_bond_result _ -> return (ctxt, storage_limit, smopr) (** [burn_internal_storage_fees ctxt smopr storage_limit payer] burns the storage fees associated to an internal operation result [smopr]. diff --git a/src/proto_alpha/lib_protocol/apply_results.ml b/src/proto_alpha/lib_protocol/apply_results.ml index b83e0e45deaa55bb0dddba728db175a38d3e6802..2b07e65765e0c042ea7209ce90347f1a90f9a4af 100644 --- a/src/proto_alpha/lib_protocol/apply_results.ml +++ b/src/proto_alpha/lib_protocol/apply_results.ml @@ -258,6 +258,11 @@ type _ successful_manager_operation_result = paid_storage_size_diff : Z.t; } -> Kind.sc_rollup_atomic_batch successful_manager_operation_result + | Sc_rollup_return_bond_result : { + balance_updates : Receipt.balance_updates; + consumed_gas : Gas.Arith.fp; + } + -> Kind.sc_rollup_return_bond successful_manager_operation_result type _ successful_internal_manager_operation_result = | ITransaction_result : @@ -1141,6 +1146,28 @@ module Manager_result = struct consumed_gas = consumed_milligas; paid_storage_size_diff; }) + + let[@coq_axiom_with_reason "gadt"] sc_rollup_return_bond_case = + make + ~op_case:Operation.Encoding.Manager_operations.sc_rollup_return_bond_case + ~encoding: + Data_encoding.( + obj3 + (req "balance_updates" Receipt.balance_updates_encoding) + (dft "consumed_gas" Gas.Arith.n_integral_encoding Gas.Arith.zero) + (dft "consumed_milligas" Gas.Arith.n_fp_encoding Gas.Arith.zero)) + ~select:(function + | Successful_manager_result (Sc_rollup_return_bond_result _ as op) -> + Some op + | _ -> None) + ~kind:Kind.Sc_rollup_return_bond_manager_kind + ~proj:(function + | Sc_rollup_return_bond_result {balance_updates; consumed_gas} -> + (balance_updates, Gas.Arith.ceil consumed_gas, consumed_gas)) + ~inj:(fun (balance_updates, consumed_gas, consumed_milligas) -> + assert (Gas.Arith.(equal (ceil consumed_milligas) consumed_gas)) ; + Sc_rollup_return_bond_result + {balance_updates; consumed_gas = consumed_milligas}) end type 'kind iselect = @@ -1650,6 +1677,10 @@ let equal_manager_kind : Kind.Sc_rollup_atomic_batch_manager_kind ) -> Some Eq | Kind.Sc_rollup_atomic_batch_manager_kind, _ -> None + | ( Kind.Sc_rollup_return_bond_manager_kind, + Kind.Sc_rollup_return_bond_manager_kind ) -> + Some Eq + | Kind.Sc_rollup_return_bond_manager_kind, _ -> None module Encoding = struct type 'kind case = @@ -2210,6 +2241,17 @@ module Encoding = struct res ) -> Some (op, res) | _ -> None) + + let[@coq_axiom_with_reason "gadt"] sc_rollup_return_bond_case = + make_manager_case + Operation.Encoding.sc_rollup_return_bond_case + Manager_result.sc_rollup_return_bond_case + (function + | Contents_and_result + ( (Manager_operation {operation = Sc_rollup_return_bond _; _} as op), + res ) -> + Some (op, res) + | _ -> None) end let contents_result_encoding = @@ -2264,6 +2306,7 @@ let contents_result_encoding = make sc_rollup_refute_case; make sc_rollup_timeout_case; make sc_rollup_atomic_batch_case; + make sc_rollup_return_bond_case; ] let contents_and_result_encoding = @@ -2320,6 +2363,7 @@ let contents_and_result_encoding = make sc_rollup_publish_case; make sc_rollup_refute_case; make sc_rollup_timeout_case; + make sc_rollup_return_bond_case; ] type 'kind contents_result_list = @@ -2701,6 +2745,32 @@ let kind_equal : } ) -> Some Eq | Manager_operation {operation = Tx_rollup_return_bond _; _}, _ -> None + | ( Manager_operation {operation = Sc_rollup_return_bond _; _}, + Manager_operation_result + {operation_result = Applied (Sc_rollup_return_bond_result _); _} ) -> + Some Eq + | ( Manager_operation {operation = Sc_rollup_return_bond _; _}, + Manager_operation_result + {operation_result = Backtracked (Sc_rollup_return_bond_result _, _); _} + ) -> + Some Eq + | ( Manager_operation {operation = Sc_rollup_return_bond _; _}, + Manager_operation_result + { + operation_result = + Failed (Alpha_context.Kind.Sc_rollup_return_bond_manager_kind, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Sc_rollup_return_bond _; _}, + Manager_operation_result + { + operation_result = + Skipped Alpha_context.Kind.Sc_rollup_return_bond_manager_kind; + _; + } ) -> + Some Eq + | Manager_operation {operation = Sc_rollup_return_bond _; _}, _ -> None | ( Manager_operation {operation = Tx_rollup_finalize_commitment _; _}, Manager_operation_result {operation_result = Applied (Tx_rollup_finalize_commitment_result _); _} diff --git a/src/proto_alpha/lib_protocol/apply_results.mli b/src/proto_alpha/lib_protocol/apply_results.mli index b73211b91b74285b9c34352159fab4850b70abdb..4e9db1f35de21f1315b2cedef2d193af2bf3da23 100644 --- a/src/proto_alpha/lib_protocol/apply_results.mli +++ b/src/proto_alpha/lib_protocol/apply_results.mli @@ -324,6 +324,11 @@ and _ successful_manager_operation_result = paid_storage_size_diff : Z.t; } -> Kind.sc_rollup_atomic_batch successful_manager_operation_result + | Sc_rollup_return_bond_result : { + balance_updates : Receipt.balance_updates; + consumed_gas : Gas.Arith.fp; + } + -> Kind.sc_rollup_return_bond successful_manager_operation_result (** Result of applying a {!Script_typed_ir.internal_operation}. *) and _ successful_internal_manager_operation_result = diff --git a/src/proto_alpha/lib_protocol/operation_repr.ml b/src/proto_alpha/lib_protocol/operation_repr.ml index 52bbeda71d5f20382f63f909291d931e2feee7d4..774a5cf8f30c5a3c19e8d230b4ba4b55a0ed2cdc 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.ml +++ b/src/proto_alpha/lib_protocol/operation_repr.ml @@ -108,6 +108,8 @@ module Kind = struct type sc_rollup_atomic_batch = Sc_rollup_atomic_batch_kind + type sc_rollup_return_bond = Sc_rollup_return_bond_kind + type 'a manager = | Reveal_manager_kind : reveal manager | Transaction_manager_kind : transaction manager @@ -135,6 +137,7 @@ module Kind = struct | Sc_rollup_refute_manager_kind : sc_rollup_refute manager | Sc_rollup_timeout_manager_kind : sc_rollup_timeout manager | Sc_rollup_atomic_batch_manager_kind : sc_rollup_atomic_batch manager + | Sc_rollup_return_bond_manager_kind : sc_rollup_return_bond manager end type 'a consensus_operation_type = @@ -423,6 +426,10 @@ and _ manager_operation = atomic_transaction_batch : string; } -> Kind.sc_rollup_atomic_batch manager_operation + | Sc_rollup_return_bond : { + sc_rollup : Sc_rollup_repr.t; + } + -> Kind.sc_rollup_return_bond manager_operation and counter = Z.t @@ -453,6 +460,7 @@ let manager_kind : type kind. kind manager_operation -> kind Kind.manager = | Sc_rollup_refute _ -> Kind.Sc_rollup_refute_manager_kind | Sc_rollup_timeout _ -> Kind.Sc_rollup_timeout_manager_kind | Sc_rollup_atomic_batch _ -> Kind.Sc_rollup_atomic_batch_manager_kind + | Sc_rollup_return_bond _ -> Kind.Sc_rollup_return_bond_manager_kind type packed_manager_operation = | Manager : 'kind manager_operation -> packed_manager_operation @@ -542,6 +550,8 @@ let sc_rollup_operation_timeout_tag = sc_rollup_operation_tag_offset + 5 let sc_rollup_operation_atomic_batch_tag = sc_rollup_operation_tag_offset + 6 +let sc_rollup_operation_return_bond_tag = sc_rollup_operation_tag_offset + 7 + let dal_offset = 230 let dal_publish_slot_header_tag = dal_offset + 0 @@ -1134,6 +1144,19 @@ module Encoding = struct atomic_transaction_batch; }); } + + let[@coq_axiom_with_reason "gadt"] sc_rollup_return_bond_case = + MCase + { + tag = sc_rollup_operation_return_bond_tag; + name = "sc_rollup_return_bond"; + encoding = obj1 (req "rollup" Sc_rollup_repr.Address.encoding); + select = + (function + | Manager (Sc_rollup_return_bond _ as op) -> Some op | _ -> None); + proj = (function Sc_rollup_return_bond {sc_rollup} -> sc_rollup); + inj = (fun sc_rollup -> Sc_rollup_return_bond {sc_rollup}); + } end type 'b case = @@ -1537,6 +1560,11 @@ module Encoding = struct sc_rollup_operation_atomic_batch_tag Manager_operations.sc_rollup_atomic_batch_case + let sc_rollup_return_bond_case = + make_manager_case + sc_rollup_operation_return_bond_tag + Manager_operations.sc_rollup_return_bond_case + let contents_encoding = let make (Case {tag; name; encoding; select; proj; inj}) = case @@ -1583,6 +1611,7 @@ module Encoding = struct make sc_rollup_refute_case; make sc_rollup_timeout_case; make sc_rollup_atomic_batch_case; + make sc_rollup_return_bond_case; ] let contents_list_encoding = @@ -1809,6 +1838,8 @@ let equal_manager_operation_kind : | Sc_rollup_timeout _, _ -> None | Sc_rollup_atomic_batch _, Sc_rollup_atomic_batch _ -> Some Eq | Sc_rollup_atomic_batch _, _ -> None + | Sc_rollup_return_bond _, Sc_rollup_return_bond _ -> Some Eq + | Sc_rollup_return_bond _, _ -> None let equal_contents_kind : type a b. a contents -> b contents -> (a, b) eq option = diff --git a/src/proto_alpha/lib_protocol/operation_repr.mli b/src/proto_alpha/lib_protocol/operation_repr.mli index d17d5d3d5b6ab17c77d54d11e7fdf23c441df4f5..c9f25012ed2ee95d635817695b2f5ae36b307bbe 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.mli +++ b/src/proto_alpha/lib_protocol/operation_repr.mli @@ -137,6 +137,8 @@ module Kind : sig type sc_rollup_atomic_batch = Sc_rollup_atomic_batch_kind + type sc_rollup_return_bond = Sc_rollup_return_bond_kind + type 'a manager = | Reveal_manager_kind : reveal manager | Transaction_manager_kind : transaction manager @@ -164,6 +166,7 @@ module Kind : sig | Sc_rollup_refute_manager_kind : sc_rollup_refute manager | Sc_rollup_timeout_manager_kind : sc_rollup_timeout manager | Sc_rollup_atomic_batch_manager_kind : sc_rollup_atomic_batch manager + | Sc_rollup_return_bond_manager_kind : sc_rollup_return_bond manager end type 'a consensus_operation_type = @@ -498,6 +501,10 @@ and _ manager_operation = (** The bytes corresponding to a serialized batch of transactions. *) } -> Kind.sc_rollup_atomic_batch manager_operation + | Sc_rollup_return_bond : { + sc_rollup : Sc_rollup_repr.t; + } + -> Kind.sc_rollup_return_bond manager_operation (** Counters are used as anti-replay protection mechanism in manager operations: each manager account stores a counter and @@ -651,6 +658,8 @@ module Encoding : sig val sc_rollup_atomic_batch_case : Kind.sc_rollup_atomic_batch Kind.manager case + val sc_rollup_return_bond_case : Kind.sc_rollup_return_bond Kind.manager case + module Manager_operations : sig type 'b case = | MCase : { @@ -709,5 +718,7 @@ module Encoding : sig val sc_rollup_timeout_case : Kind.sc_rollup_timeout case val sc_rollup_atomic_batch_case : Kind.sc_rollup_atomic_batch case + + val sc_rollup_return_bond_case : Kind.sc_rollup_return_bond case end end diff --git a/src/proto_alpha/lib_protocol/sc_rollup_stake_storage.ml b/src/proto_alpha/lib_protocol/sc_rollup_stake_storage.ml index d8d05c4c033100d35732d0d486f0d624e1fc00f4..1cb5ce8ea5bd77199bc0fafacf575856f39f846c 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_stake_storage.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_stake_storage.ml @@ -414,7 +414,5 @@ let remove_staker ctxt rollup staker = module Internal_for_tests = struct let deposit_stake = deposit_stake - let withdraw_stake = withdraw_stake - let refine_stake = refine_stake end diff --git a/src/proto_alpha/lib_protocol/sc_rollup_stake_storage.mli b/src/proto_alpha/lib_protocol/sc_rollup_stake_storage.mli index c2c5b2a337fd319188977b10b09502debc895d36..3f37fdeb968afb0317fc7aa1a973bdd924bf0f17 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_stake_storage.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_stake_storage.mli @@ -126,6 +126,30 @@ val find_staker : (** The storage size requirement (in bytes) of a commitment *) val commitment_storage_size_in_bytes : int +(** [withdraw_stake context rollup staker] removes [staker] and returns + any deposit previously frozen by [deposit_stake]. + + May fail with: + {ul + {li [Sc_rollup_does_not_exist] if [rollup] does not exist} + {li [Sc_rollup_not_staked_on_lcc] if [staker] is not staked on the last + cemented commitment} + } + + Note that it is not possible to be staked on a Cemented commitment other + than the Last, because of Cementation Rule #4. See [cement_commitment] + for details. + + By design, the operation wrapping this might {i not} be authenticated, + as it may be necessary for nodes on the honest branch to refund stakers on + the LCC. They must do so by using [withdraw_stake] as they are implicitly + staked on the LCC and can not dispute it. *) +val withdraw_stake : + Raw_context.t -> + Sc_rollup_repr.t -> + Sc_rollup_repr.Staker.t -> + (Raw_context.t * Receipt_repr.balance_updates) tzresult Lwt.t + (**/**) module Internal_for_tests : sig @@ -152,30 +176,6 @@ module Internal_for_tests : sig Sc_rollup_repr.Staker.t -> (Raw_context.t * Receipt_repr.balance_updates) tzresult Lwt.t - (** [withdraw_stake context rollup staker] removes [staker] and returns - any deposit previously frozen by [deposit_stake]. - - May fail with: - {ul - {li [Sc_rollup_does_not_exist] if [rollup] does not exist} - {li [Sc_rollup_not_staked_on_lcc] if [staker] is not staked on the last - cemented commitment} - } - - Note that it is not possible to be staked on a Cemented commitment other - than the Last, because of Cementation Rule #4. See [cement_commitment] - for details. - - By design, the operation wrapping this should {i not} be authenticated, - as it may be necessary for nodes on the honest branch to refund stakers on - the LCC. They must do so by using [withdraw_stake] as they are implicitly - staked on the LCC and can not dispute it. *) - val withdraw_stake : - Raw_context.t -> - Sc_rollup_repr.t -> - Sc_rollup_repr.Staker.t -> - (Raw_context.t * Receipt_repr.balance_updates) tzresult Lwt.t - (** [refine_stake context rollup staker commitment] moves the stake of [staker] to [commitment]. Because we do not assume any form of coordination between validators, we do not distinguish between {i adding new} diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.ml b/src/proto_alpha/lib_protocol/test/helpers/block.ml index d9eb23de47996f3fd1ff608785eb1555abf92b4b..a764db602b0f4d0f300a8680aa4c113f33c681ca 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/block.ml @@ -756,7 +756,8 @@ let bake_n_with_all_balance_updates ?(baking_mode = Application) ?policy | Dal_publish_slot_header_result _ | Sc_rollup_originate_result _ | Sc_rollup_add_messages_result _ | Sc_rollup_cement_result _ | Sc_rollup_publish_result _ | Sc_rollup_refute_result _ - | Sc_rollup_timeout_result _ | Sc_rollup_atomic_batch_result _ -> + | Sc_rollup_timeout_result _ | Sc_rollup_atomic_batch_result _ + | Sc_rollup_return_bond_result _ -> balance_updates_rev | Transaction_result (Transaction_to_contract_result {balance_updates; _}) @@ -803,7 +804,8 @@ let bake_n_with_origination_results ?(baking_mode = Application) ?policy n b = | Successful_manager_result (Sc_rollup_publish_result _) | Successful_manager_result (Sc_rollup_refute_result _) | Successful_manager_result (Sc_rollup_timeout_result _) - | Successful_manager_result (Sc_rollup_atomic_batch_result _) -> + | Successful_manager_result (Sc_rollup_atomic_batch_result _) + | Successful_manager_result (Sc_rollup_return_bond_result _) -> origination_results_rev | Successful_manager_result (Origination_result x) -> Origination_result x :: origination_results_rev) diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 2f6da236b847385e1dacc184db28bc6ac657ee38..f97a761475f9129c8a85979eb2ff5a6da8a5c419 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -803,3 +803,17 @@ let sc_rollup_atomic_batch ?counter ?fee ?gas_limit ?storage_limit ctxt >>=? fun to_sign_op -> Context.Contract.manager ctxt src >|=? fun account -> sign account.sk ctxt to_sign_op + +let sc_rollup_return_bond ?counter ?fee ?gas_limit ?storage_limit ctxt + (source : Contract.t) (sc_rollup : Sc_rollup.t) = + manager_operation + ?counter + ?fee + ?gas_limit + ?storage_limit + ~source + ctxt + (Sc_rollup_return_bond {sc_rollup}) + >>=? fun to_sign_op -> + Context.Contract.manager ctxt source >|=? fun account -> + sign account.sk ctxt to_sign_op diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 6d2bdec7248b11cf17e5e758c664266790a440e6..df044f633a6ed9d63819319e4fc063931d834456 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -543,3 +543,14 @@ val sc_rollup_atomic_batch : inclusion_proof:string -> atomic_transaction_batch:string -> (packed_operation, tztrace) result Lwt.t + +(** [sc_rollup_return_bond ctxt source sc_rollup] returns a commitment bond. *) +val sc_rollup_return_bond : + ?counter:Z.t -> + ?fee:Tez.tez -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + Context.t -> + Contract.t -> + Sc_rollup.t -> + Operation.packed tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml index 62eae97382e604d981a8fd317518e33cdac4e1cc..7eca03403fbe14da6f4c1bd66569792f18b2ab77 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml @@ -175,12 +175,78 @@ let dummy_commitment ctxt rollup = compressed_state = Sc_rollup.State_hash.zero; } -(** [test_publish_and_cement] creates a rollup, publishes a - commitment and then [commitment_freq] blocks later cements that commitment *) -let test_publish_and_cement () = +(** Assert that the computation fails with the given message. *) +let assert_fails_with ~__LOC__ k expected_err = + let*! res = k in + Assert.proto_error ~loc:__LOC__ res (( = ) expected_err) + +type balances = {liquid : Tez.t; frozen : Tez.t} + +let balances ctxt contract = + let* liquid = Context.Contract.balance ctxt contract in + let* frozen = Context.Contract.frozen_bonds ctxt contract in + return {liquid; frozen} + +let check_balances_evolution bal_before {liquid; frozen} ~action = + let open Lwt_result_syntax in + let wret x = wrap @@ Lwt.return x in + let* {liquid = expected_liquid; frozen = expected_frozen} = + match action with + | `Freeze amount -> + let* liquid = wret @@ Tez.( -? ) bal_before.liquid amount in + let* frozen = wret @@ Tez.( +? ) bal_before.frozen amount in + return {liquid; frozen} + | `Unfreeze amount -> + let* liquid = wret @@ Tez.( +? ) bal_before.liquid amount in + let* frozen = wret @@ Tez.( -? ) bal_before.frozen amount in + return {liquid; frozen} + in + let* () = Assert.equal_tez ~loc:__LOC__ expected_liquid liquid in + let* () = Assert.equal_tez ~loc:__LOC__ expected_frozen frozen in + return () + +let attempt_to_return_bond i contract rollup = + let* return_bond_op = Op.sc_rollup_return_bond (I i) contract rollup in + let* i = Incremental.add_operation i return_bond_op in + let* b = Incremental.finalize_block i in + return b + +let return_bond_not_lcc i contract rollup = + assert_fails_with + ~__LOC__ + (attempt_to_return_bond i contract rollup) + Sc_rollup_errors.Sc_rollup_not_staked_on_lcc + +let return_bond_not_staked i contract rollup = + assert_fails_with + ~__LOC__ + (attempt_to_return_bond i contract rollup) + Sc_rollup_errors.Sc_rollup_not_staked + +let return_bond_with_success i contract rollup = + let* bal_before = balances (I i) contract in + let* b = attempt_to_return_bond i contract rollup in + let* bal_after = balances (B b) contract in + let* constants = Context.get_constants (I i) in + let* () = + check_balances_evolution + bal_before + bal_after + ~action:(`Unfreeze constants.parametric.sc_rollup.stake_amount) + in + return b + +(** [test_publish_cement_and_return_bond] creates a rollup, publishes a + commitment and then [challenge_window_in_blocks] blocks later cements + that commitment. + The comitter tries to withdraw stake before and after cementing. Only the + second attempt is expected to succeed. *) +let test_publish_cement_and_return_bond () = let* ctxt, contracts, rollup = init_and_originate Context.T2 "unit" in let _, contract = contracts in let* i = Incremental.begin_construction ctxt in + (* not staked yet *) + let* () = return_bond_not_staked i contract rollup in let* c = dummy_commitment i rollup in let* operation = Op.sc_rollup_publish (B ctxt) contract rollup c in let* i = Incremental.add_operation i operation in @@ -191,8 +257,24 @@ let test_publish_and_cement () = in let* i = Incremental.begin_construction b in let hash = Sc_rollup.Commitment.hash c in + (* stake not on LCC *) + let* () = return_bond_not_lcc i contract rollup in let* cement_op = Op.sc_rollup_cement (I i) contract rollup hash in - let* _ = Incremental.add_operation i cement_op in + let* i = Incremental.add_operation i cement_op in + let* b = Incremental.finalize_block i in + let* i = + let pkh = + (* We forbid the stake owner from baker to correctly check the unfrozen + amount below. *) + match contract with Implicit pkh -> pkh | Originated _ -> assert false + in + Incremental.begin_construction b ~policy:(Excluding [pkh]) + in + (* return bond should succeed *) + let* b = return_bond_with_success i contract rollup in + let* i = Incremental.begin_construction b in + (* not staked anymore *) + let* () = return_bond_not_staked i contract rollup in return_unit (** [test_publish_fails_on_backtrack] creates a rollup and then @@ -435,9 +517,9 @@ let tests = `Quick test_sc_rollups_all_well_defined; Tztest.tztest - "can publish a commit and then cement it" + "can publish a commit, cement it and withdraw stake" `Quick - test_publish_and_cement; + test_publish_cement_and_return_bond; Tztest.tztest "publish will fail if staker is backtracking" `Quick diff --git a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_storage.ml b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_storage.ml index dae2d174aea37455c27b51aaf56b6ade98ac308b..48603b80d477bdd5d3fde6cf55d212e779e4dff0 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_storage.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_storage.ml @@ -293,11 +293,7 @@ let withdraw_stake_and_check_balances ctxt rollup staker = staker (fun ctxt rollup staker_contract stake -> let* ctxt', _ = - lift - @@ Sc_rollup_stake_storage.Internal_for_tests.withdraw_stake - ctxt - rollup - staker + lift @@ Sc_rollup_stake_storage.withdraw_stake ctxt rollup staker in let* () = assert_balance_increased ctxt ctxt' (`Contract staker_contract) stake @@ -320,7 +316,7 @@ let test_deposit_then_withdraw () = let test_withdrawal_from_missing_rollup () = assert_fails_with_missing_rollup ~loc:__LOC__ (fun ctxt rollup -> - Sc_rollup_stake_storage.Internal_for_tests.withdraw_stake + Sc_rollup_stake_storage.withdraw_stake ctxt rollup Sc_rollup_repr.Staker.zero) @@ -334,10 +330,7 @@ let test_withdraw_when_not_staked () = in assert_fails_with ~loc:__LOC__ - (Sc_rollup_stake_storage.Internal_for_tests.withdraw_stake - ctxt - rollup - staker) + (Sc_rollup_stake_storage.withdraw_stake ctxt rollup staker) Sc_rollup_errors.Sc_rollup_not_staked let test_withdrawing_twice () = @@ -351,10 +344,7 @@ let test_withdrawing_twice () = let* ctxt = withdraw_stake_and_check_balances ctxt rollup staker in assert_fails_with ~loc:__LOC__ - (Sc_rollup_stake_storage.Internal_for_tests.withdraw_stake - ctxt - rollup - staker) + (Sc_rollup_stake_storage.withdraw_stake ctxt rollup staker) Sc_rollup_errors.Sc_rollup_not_staked let number_of_messages_exn n = @@ -1083,10 +1073,7 @@ let test_withdrawal_fails_when_not_staked_on_lcc () = in assert_fails_with ~loc:__LOC__ - (Sc_rollup_stake_storage.Internal_for_tests.withdraw_stake - ctxt - rollup - staker) + (Sc_rollup_stake_storage.withdraw_stake ctxt rollup staker) Sc_rollup_errors.Sc_rollup_not_staked_on_lcc let test_initial_level_of_rollup () = @@ -1329,10 +1316,7 @@ let test_removed_staker_can_not_withdraw () = in assert_fails_with ~loc:__LOC__ - (Sc_rollup_stake_storage.Internal_for_tests.withdraw_stake - ctxt - rollup - staker2) + (Sc_rollup_stake_storage.withdraw_stake ctxt rollup staker2) Sc_rollup_errors.Sc_rollup_not_staked let test_no_cement_on_conflict () = diff --git a/tezt/lib_tezos/client.ml b/tezt/lib_tezos/client.ml index 2d3a8a43fb309dbada61d7ce78a623cadd2f48d4..b00f43ac69d3f8dda5ae744dc6f3df4aed596873 100644 --- a/tezt/lib_tezos/client.ml +++ b/tezt/lib_tezos/client.ml @@ -1637,6 +1637,30 @@ module Sc_rollup = struct spawn_cement_commitment ?hooks ?wait ?burn_cap ~hash ~src ~dst client in Process.check process + + let submit_return_bond ?(wait = "none") ?burn_cap ?storage_limit ?fee ?hooks + ~rollup ~src client = + let process = + spawn_command + ?hooks + client + (["--wait"; wait] + @ ["recover"; "bond"; "of"; src; "for"; "sc"; "rollup"; rollup] + @ Option.fold + ~none:[] + ~some:(fun burn_cap -> ["--burn-cap"; Tez.to_string burn_cap]) + burn_cap + @ Option.fold + ~none:[] + ~some:(fun fee -> ["--fee"; Tez.to_string fee]) + fee + @ Option.fold + ~none:[] + ~some:(fun s -> ["--storage-limit"; string_of_int s]) + storage_limit) + in + let parse process = Process.check process in + {value = process; run = parse} end let init ?path ?admin_path ?name ?color ?base_dir ?endpoint ?media_type () = diff --git a/tezt/lib_tezos/client.mli b/tezt/lib_tezos/client.mli index 236d049fed5f57d1c53b1bb1f7f5a2ed80f16edf..da51d20344ba4760044b8569debbacb175662a95 100644 --- a/tezt/lib_tezos/client.mli +++ b/tezt/lib_tezos/client.mli @@ -1251,6 +1251,18 @@ module Sc_rollup : sig dst:string -> t -> Process.t + + (** Run [tezos-client submit sc rollup return bond to from ]. *) + val submit_return_bond : + ?wait:string -> + ?burn_cap:Tez.t -> + ?storage_limit:int -> + ?fee:Tez.t -> + ?hooks:Process.hooks -> + rollup:string -> + src:string -> + t -> + unit Runnable.process end (** {2 High-Level Functions} *) diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- mempool.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- mempool.out index 57487190d745f23ad04da3a1bfa97e049a67b394..699a66517216fe5424d88f5c3b97d052a3b25b94 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- mempool.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- mempool.out @@ -674,6 +674,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "title": "A Tezos protocol ID (Base58Check-encoded)", "$ref": "#/definitions/unistring" }, + "Sc_rollup_hash": { + "title": "A smart contract rollup address (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "Signature": { "title": "A Ed25519, Secp256k1 or P256 signature (Base58Check-encoded)", "$ref": "#/definitions/unistring" @@ -6139,6 +6143,46 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "kind" ], "additionalProperties": false + }, + { + "title": "Sc_rollup_return_bond", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "sc_rollup_return_bond" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/Sc_rollup_hash" + } + }, + "required": [ + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false } ] }, @@ -10405,6 +10449,91 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "name": "Sc_rollup_atomic_batch" }, + { + "tag": 207, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "source", + "layout": { + "name": "public_key_hash", + "kind": "Ref" + }, + "data_kind": { + "size": 21, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "fee", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "counter", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "gas_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "storage_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "rollup", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 20, + "kind": "Float" + }, + "kind": "named" + } + ], + "name": "Sc_rollup_return_bond" + }, { "tag": 230, "fields": [ @@ -16011,6 +16140,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "title": "A Tezos protocol ID (Base58Check-encoded)", "$ref": "#/definitions/unistring" }, + "Sc_rollup_hash": { + "title": "A smart contract rollup address (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "Signature": { "title": "A Ed25519, Secp256k1 or P256 signature (Base58Check-encoded)", "$ref": "#/definitions/unistring" @@ -21476,6 +21609,46 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "kind" ], "additionalProperties": false + }, + { + "title": "Sc_rollup_return_bond", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "sc_rollup_return_bond" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/Sc_rollup_hash" + } + }, + "required": [ + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false } ] }, diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- mempool.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- mempool.out index c4e83ef3183a30ea72ede22a554c74dc03100126..e8b0b3ae68148efe76fe5afa60ed3ae4f6fa0301 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- mempool.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- mempool.out @@ -695,6 +695,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "title": "A Tezos protocol ID (Base58Check-encoded)", "$ref": "#/definitions/unistring" }, + "Sc_rollup_hash": { + "title": "A smart contract rollup address (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "Signature": { "title": "A Ed25519, Secp256k1 or P256 signature (Base58Check-encoded)", "$ref": "#/definitions/unistring" @@ -6160,6 +6164,46 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "kind" ], "additionalProperties": false + }, + { + "title": "Sc_rollup_return_bond", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "sc_rollup_return_bond" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/Sc_rollup_hash" + } + }, + "required": [ + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false } ] }, @@ -10426,6 +10470,91 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "name": "Sc_rollup_atomic_batch" }, + { + "tag": 207, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "source", + "layout": { + "name": "public_key_hash", + "kind": "Ref" + }, + "data_kind": { + "size": 21, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "fee", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "counter", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "gas_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "storage_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "rollup", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 20, + "kind": "Float" + }, + "kind": "named" + } + ], + "name": "Sc_rollup_return_bond" + }, { "tag": 230, "fields": [ @@ -16032,6 +16161,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "title": "A Tezos protocol ID (Base58Check-encoded)", "$ref": "#/definitions/unistring" }, + "Sc_rollup_hash": { + "title": "A smart contract rollup address (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "Signature": { "title": "A Ed25519, Secp256k1 or P256 signature (Base58Check-encoded)", "$ref": "#/definitions/unistring" @@ -21497,6 +21630,46 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "kind" ], "additionalProperties": false + }, + { + "title": "Sc_rollup_return_bond", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "sc_rollup_return_bond" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/Sc_rollup_hash" + } + }, + "required": [ + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false } ] }, diff --git a/tezt/tests/expected/sc_rollup.ml/Alpha- observing the correct handling of commitments in the rollup node (no_comm.out b/tezt/tests/expected/sc_rollup.ml/Alpha- observing the correct handling of commitments in the rollup node (no_comm.out index 6b9b065f03b67f6c956fdff4b4dd43f9c7826739..8e084d4161fe504b5a37c7cbecb58f0b0dc9b843 100644 --- a/tezt/tests/expected/sc_rollup.ml/Alpha- observing the correct handling of commitments in the rollup node (no_comm.out +++ b/tezt/tests/expected/sc_rollup.ml/Alpha- observing the correct handling of commitments in the rollup node (no_comm.out @@ -51,6 +51,80 @@ This sequence of operations was run: "hash": "[SC_ROLLUP_COMMITMENT_HASH]", "published_at_level": 35 } +./tezos-client rpc get /chains/main/blocks/head/context/constants +{ "proof_of_work_nonce_size": 8, "nonce_length": 32, + "max_anon_ops_per_block": 132, "max_operation_data_length": 32768, + "max_proposals_per_delegate": 20, "max_micheline_node_count": 50000, + "max_micheline_bytes_limit": 50000, + "max_allowed_global_constants_depth": 10000, "cache_layout_size": 3, + "michelson_maximum_type_size": 2001, "preserved_cycles": 2, + "blocks_per_cycle": 8, "blocks_per_commitment": 4, + "blocks_per_stake_snapshot": 4, "cycles_per_voting_period": 8, + "hard_gas_limit_per_operation": "1040000", + "hard_gas_limit_per_block": "5200000", "proof_of_work_threshold": "-1", + "tokens_per_roll": "6000000000", "seed_nonce_revelation_tip": "125000", + "origination_size": 257, "baking_reward_fixed_portion": "333333", + "baking_reward_bonus_per_slot": "3921", + "endorsing_reward_per_slot": "2604", "cost_per_byte": "250", + "hard_storage_limit_per_operation": "60000", "quorum_min": 2000, + "quorum_max": 7000, "min_proposal_quorum": 500, + "liquidity_baking_subsidy": "2500000", + "liquidity_baking_sunset_level": 128, + "liquidity_baking_toggle_ema_threshold": 1000000000, + "max_operations_time_to_live": 120, "minimal_block_delay": "1", + "delay_increment_per_round": "1", "consensus_committee_size": 256, + "consensus_threshold": 0, + "minimal_participation_ratio": { "numerator": 2, "denominator": 3 }, + "max_slashing_period": 2, "frozen_deposits_percentage": 5, + "double_baking_punishment": "640000000", + "ratio_of_frozen_deposits_slashed_per_double_endorsement": + { "numerator": 1, "denominator": 2 }, "cache_script_size": 100000000, + "cache_stake_distribution_cycles": 8, "cache_sampler_state_cycles": 8, + "tx_rollup_enable": true, "tx_rollup_origination_size": 4000, + "tx_rollup_hard_size_limit_per_inbox": 500000, + "tx_rollup_hard_size_limit_per_message": 5000, + "tx_rollup_max_withdrawals_per_batch": 15, + "tx_rollup_commitment_bond": "10000000000", + "tx_rollup_finality_period": 40000, "tx_rollup_withdraw_period": 40000, + "tx_rollup_max_inboxes_count": 40100, + "tx_rollup_max_messages_per_inbox": 1010, + "tx_rollup_max_commitments_count": 80100, + "tx_rollup_cost_per_byte_ema_factor": 120, + "tx_rollup_max_ticket_payload_size": 2048, + "tx_rollup_rejection_max_proof_size": 30000, + "tx_rollup_sunset_level": 3473409, + "dal_parametric": + { "feature_enable": false, "number_of_slots": 256, + "number_of_shards": 2048, "endorsement_lag": 2, + "availability_threshold": 50 }, "sc_rollup_enable": true, + "sc_rollup_origination_size": 6314, + "sc_rollup_challenge_window_in_blocks": 1, + "sc_rollup_max_available_messages": 1000000, + "sc_rollup_stake_amount": "32000000", + "sc_rollup_commitment_period_in_blocks": 30, + "sc_rollup_max_lookahead_in_blocks": 30000, + "sc_rollup_max_active_outbox_levels": 20160, + "sc_rollup_max_outbox_messages_per_level": 100 } + +./tezos-client --wait none recover bond of '[PUBLIC_KEY_HASH]' for sc rollup '[SC_ROLLUP_HASH]' --fee 1 +Node is bootstrapped. +This simulation failed: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ1 + Expected counter: 3 + Gas limit: 1040000 + Storage limit: 60000 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ1 + payload fees(the block proposer) ....... +ꜩ1 + Sc rollup return commitment bond:[SC_ROLLUP_HASH] + From: [PUBLIC_KEY_HASH] + This operation FAILED. + +Error: + Attempted to withdraw while not staked on the last cemented commitment. + ./tezos-client --wait none cement commitment '[SC_ROLLUP_COMMITMENT_HASH]' from bootstrap1 for sc rollup '[SC_ROLLUP_HASH]' Node is bootstrapped. Estimated gas: 3451.196 units (will add 100 for safety) @@ -76,6 +150,90 @@ This sequence of operations was run: Consumed gas: 3451.196 +./tezos-client rpc get /chains/main/blocks/head/context/constants +{ "proof_of_work_nonce_size": 8, "nonce_length": 32, + "max_anon_ops_per_block": 132, "max_operation_data_length": 32768, + "max_proposals_per_delegate": 20, "max_micheline_node_count": 50000, + "max_micheline_bytes_limit": 50000, + "max_allowed_global_constants_depth": 10000, "cache_layout_size": 3, + "michelson_maximum_type_size": 2001, "preserved_cycles": 2, + "blocks_per_cycle": 8, "blocks_per_commitment": 4, + "blocks_per_stake_snapshot": 4, "cycles_per_voting_period": 8, + "hard_gas_limit_per_operation": "1040000", + "hard_gas_limit_per_block": "5200000", "proof_of_work_threshold": "-1", + "tokens_per_roll": "6000000000", "seed_nonce_revelation_tip": "125000", + "origination_size": 257, "baking_reward_fixed_portion": "333333", + "baking_reward_bonus_per_slot": "3921", + "endorsing_reward_per_slot": "2604", "cost_per_byte": "250", + "hard_storage_limit_per_operation": "60000", "quorum_min": 2000, + "quorum_max": 7000, "min_proposal_quorum": 500, + "liquidity_baking_subsidy": "2500000", + "liquidity_baking_sunset_level": 128, + "liquidity_baking_toggle_ema_threshold": 1000000000, + "max_operations_time_to_live": 120, "minimal_block_delay": "1", + "delay_increment_per_round": "1", "consensus_committee_size": 256, + "consensus_threshold": 0, + "minimal_participation_ratio": { "numerator": 2, "denominator": 3 }, + "max_slashing_period": 2, "frozen_deposits_percentage": 5, + "double_baking_punishment": "640000000", + "ratio_of_frozen_deposits_slashed_per_double_endorsement": + { "numerator": 1, "denominator": 2 }, "cache_script_size": 100000000, + "cache_stake_distribution_cycles": 8, "cache_sampler_state_cycles": 8, + "tx_rollup_enable": true, "tx_rollup_origination_size": 4000, + "tx_rollup_hard_size_limit_per_inbox": 500000, + "tx_rollup_hard_size_limit_per_message": 5000, + "tx_rollup_max_withdrawals_per_batch": 15, + "tx_rollup_commitment_bond": "10000000000", + "tx_rollup_finality_period": 40000, "tx_rollup_withdraw_period": 40000, + "tx_rollup_max_inboxes_count": 40100, + "tx_rollup_max_messages_per_inbox": 1010, + "tx_rollup_max_commitments_count": 80100, + "tx_rollup_cost_per_byte_ema_factor": 120, + "tx_rollup_max_ticket_payload_size": 2048, + "tx_rollup_rejection_max_proof_size": 30000, + "tx_rollup_sunset_level": 3473409, + "dal_parametric": + { "feature_enable": false, "number_of_slots": 256, + "number_of_shards": 2048, "endorsement_lag": 2, + "availability_threshold": 50 }, "sc_rollup_enable": true, + "sc_rollup_origination_size": 6314, + "sc_rollup_challenge_window_in_blocks": 1, + "sc_rollup_max_available_messages": 1000000, + "sc_rollup_stake_amount": "32000000", + "sc_rollup_commitment_period_in_blocks": 30, + "sc_rollup_max_lookahead_in_blocks": 30000, + "sc_rollup_max_active_outbox_levels": 20160, + "sc_rollup_max_outbox_messages_per_level": 100 } + +./tezos-client --wait none recover bond of '[PUBLIC_KEY_HASH]' for sc rollup '[SC_ROLLUP_HASH]' --fee 1 +Node is bootstrapped. +Estimated gas: 3205.160 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ1 + Expected counter: 4 + Gas limit: 3306 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ1 + payload fees(the block proposer) ....... +ꜩ1 + Sc rollup return commitment bond:[SC_ROLLUP_HASH] + From: [PUBLIC_KEY_HASH] + This sc rollup return commitment bond operation was successfully applied + Balance updates: + Frozen_bonds([PUBLIC_KEY_HASH],[SC_ROLLUP_HASH]) ... -ꜩ32 + [PUBLIC_KEY_HASH] ....................................................... +ꜩ32 + Consumed gas: 3205.160 + + ./tezos-sc-rollup-client-alpha rpc get /last_published_commitment null diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index 3eecb4c1a8ce5600bad817cf54ed171aa369165a..13a813b9c96570d859782544d7156b0a77c21478 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -1378,6 +1378,56 @@ let commitments_reorgs protocol sc_rollup_node sc_rollup_address node client = Option.map (fun (_hash, c2, _level) -> (c1, c2)) stored_commitment) ; check_published_commitment_in_l1 sc_rollup_address client published_commitment +type balances = {liquid : int; frozen : int} + +let contract_balances ~pkh client = + let*! liquid = RPC.Contracts.get_balance ~contract_id:pkh client in + let*! frozen = RPC.Contracts.get_frozen_bonds ~contract_id:pkh client in + return {liquid = JSON.as_int liquid; frozen = JSON.as_int frozen} + +(** This helper allow to attempt recovering bond for SCORU rollup operator. + if [expect_failure] is set to some string then, we expect the command to fail + with an error that contains that string. *) +let attempt_withdraw_stake = + let check_eq_int a b = + Check.((a = b) int ~error_msg:"expected value %L, got %R") + in + fun ?expect_failure ~sc_rollup_address client -> + (* placehoders *) + (* TODO/Fixme: + - Shoud provide the rollup operator key (bootstrap1_key) as an + argument to scenarios. + *) + let bootstrap1_key = Constant.bootstrap1.public_key_hash in + let* constants = RPC.get_constants ~hooks client in + let return_bond_unfreeze = + JSON.(constants |-> "sc_rollup_stake_amount" |> as_int) + in + let return_bond_fee = 1_000_000 in + let inject_op () = + Client.Sc_rollup.submit_return_bond + ~hooks + ~rollup:sc_rollup_address + ~src:bootstrap1_key + ~fee:(Tez.of_mutez_int return_bond_fee) + client + in + match expect_failure with + | None -> + let*! () = inject_op () in + let* old_bal = contract_balances ~pkh:bootstrap1_key client in + let* () = Client.bake_for_and_wait ~keys:["bootstrap2"] client in + let* new_bal = contract_balances ~pkh:bootstrap1_key client in + let expected_liq_new_bal = + old_bal.liquid - return_bond_fee + return_bond_unfreeze + in + check_eq_int new_bal.liquid expected_liq_new_bal ; + check_eq_int new_bal.frozen (old_bal.frozen - return_bond_unfreeze) ; + unit + | Some failure_string -> + let*? p = inject_op () in + Process.check_error ~msg:(rex failure_string) p + (* FIXME: https://gitlab.com/tezos/tezos/-/issues/2942 Do not pass an explicit value for `?commitment_period until https://gitlab.com/tezos/tezos/-/merge_requests/5212 has been merged. *) @@ -1442,12 +1492,27 @@ let commitment_before_lcc_not_stored ?(commitment_period = 30) sc_rollup_node (commitment_finalized_level + levels_to_cementation) in + + (* Withdraw stake before cementing should fail *) + let* () = + attempt_withdraw_stake + ~sc_rollup_address + client + ~expect_failure: + "Attempted to withdraw while not staked on the last cemented \ + commitment." + in + let* () = cement_commitment client ~sc_rollup_address ~hash:cemented_commitment_hash in let* level_after_cementation = Sc_rollup_node.wait_for_level sc_rollup_node (cemented_commitment_level + 1) in + + (* Withdraw stake after cementing should succeed *) + let* () = attempt_withdraw_stake ~sc_rollup_address client in + let* () = Sc_rollup_node.terminate sc_rollup_node in (* Rollup node 2 starts and processes enough levels to publish a commitment.*) let bootstrap2_key = Constant.bootstrap2.public_key_hash in