diff --git a/CHANGES.rst b/CHANGES.rst index efef9c327cf4f7e8404c8048e64f78864f60d894..f2d25dc63d3ba20d8d7ef9473b02ea52c2ce158c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -105,6 +105,9 @@ Client support legacy ``endorsement`` kind instead of ``attestation``. (MR :gl:`!11871`) +- For the protocol that support it, added + ``increment counter by AMOUNT from SOURCE`` and ``get counter`` + - **Breaking change** Removed read-write commands specific to Nairobi (MR :gl:`!12058`) Baker diff --git a/docs/protocols/alpha.rst b/docs/protocols/alpha.rst index 4d5aa336b512b6263b9a5415a9951411e50d95a0..68407a1df02037182df2297b1c32d52bee73a016 100644 --- a/docs/protocols/alpha.rst +++ b/docs/protocols/alpha.rst @@ -35,6 +35,8 @@ Breaking Changes RPC Changes ----------- +- Client can increment and get the global counter. + Operation receipts ------------------ @@ -47,6 +49,8 @@ Operation receipts Protocol parameters ------------------- +- Added a global counter that can be incremented using a manager operation. + Bug Fixes --------- diff --git a/src/proto_alpha/lib_client/client_proto_context.ml b/src/proto_alpha/lib_client/client_proto_context.ml index 9a071294f15257dc72e26b60bdaa0f0936a18f14..5ca5182b1e1791ac57ed14bf049ab9da0f3d4b23 100644 --- a/src/proto_alpha/lib_client/client_proto_context.ml +++ b/src/proto_alpha/lib_client/client_proto_context.ml @@ -1503,3 +1503,48 @@ let dal_publish (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 counter_update (cctxt : #full) ?amount ?fee ?confirmations ~source ~src_pk ~src_sk + ~fee_parameter () = + let open Lwt_result_syntax in + let*! () = + cctxt#message "==> client_proto_context.ml: about to inject...\n" + in + let amount = + match amount with + | Some value -> value + | None -> Z.zero + in + let operation = Counter_update { amount } in + let operation = + Annotated_manager_operation.Single_manager + (Injection.prepare_manager_operation + ~fee:(Limit.of_option fee) + ~gas_limit:Limit.unknown + ~storage_limit:Limit.unknown + operation) + in + let* oph, _, op, result = + Injection.inject_manager_operation + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations + ~source + ~fee:(Limit.of_option fee) + ~storage_limit:Limit.unknown + ~gas_limit:Limit.unknown + ~src_pk + ~src_sk + ~fee_parameter + operation + in + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> + return (oph, op, result) + +let counter_get (rpc : #rpc_context) ~chain ~block = + let open Lwt_result_syntax in + let block = (chain, block) in + let* counter = Alpha_services.Counter.get rpc block in + return counter \ No newline at end of file diff --git a/src/proto_alpha/lib_client/client_proto_context.mli b/src/proto_alpha/lib_client/client_proto_context.mli index cf4b7046e68f6d4f83d961f7d052b3b622ce954d..3eacdba7d924419e63c319c00c67200157d6e100 100644 --- a/src/proto_alpha/lib_client/client_proto_context.mli +++ b/src/proto_alpha/lib_client/client_proto_context.mli @@ -1016,3 +1016,21 @@ val dal_publish : * Kind.dal_publish_commitment Kind.manager Apply_results.contents_result) tzresult Lwt.t + +val counter_update : + #Protocol_client_context.full -> + ?amount:Z.t -> + ?fee:Tez.t -> + ?confirmations:int -> + source:Signature.public_key_hash -> + src_pk:Signature.public_key -> + src_sk:Client_keys.sk_uri -> + fee_parameter:Injection.fee_parameter -> + unit -> + (Kind.counter_update Kind.manager Injection.result, tztrace) result Lwt.t + +val counter_get : + #Protocol_client_context.full -> + chain:Chain_services.chain -> + block:Block_services.block -> + (Z.t, Error_monad.tztrace) result Lwt.t \ No newline at end of file diff --git a/src/proto_alpha/lib_client/injection.ml b/src/proto_alpha/lib_client/injection.ml index 2fa804d9bea3c7874b4a0ca73c83cd107ae96315..f11a749b7a133a8b0bdbd3157a71a12a8737d33c 100644 --- a/src/proto_alpha/lib_client/injection.ml +++ b/src/proto_alpha/lib_client/injection.ml @@ -357,7 +357,8 @@ let estimated_gas_single (type kind) Ok consumed_gas | Zk_rollup_origination_result {consumed_gas; _} -> Ok consumed_gas | Zk_rollup_publish_result {consumed_gas; _} -> Ok consumed_gas - | Zk_rollup_update_result {consumed_gas; _} -> Ok consumed_gas) + | Zk_rollup_update_result {consumed_gas; _} -> Ok consumed_gas + | Counter_update_result {consumed_gas;} -> Ok consumed_gas) | Skipped _ -> error_with "Cannot estimate gas of skipped operation" (* There must be another error for this to happen, and it should not @@ -430,6 +431,8 @@ let estimated_storage_single (type kind) ~origination_size | Sc_rollup_cement_result _ | Sc_rollup_publish_result _ | Sc_rollup_refute_result _ | Sc_rollup_timeout_result _ | Sc_rollup_recover_bond_result _ -> + Ok Z.zero + | Counter_update_result _ -> Ok Z.zero) | Skipped _ -> error_with "Cannot estimate storage of skipped operation" @@ -508,7 +511,8 @@ let originated_contracts_single (type kind) | Sc_rollup_refute_result _ | Sc_rollup_timeout_result _ | Sc_rollup_execute_outbox_message_result _ | Sc_rollup_recover_bond_result _ | Zk_rollup_origination_result _ - | Zk_rollup_publish_result _ | Zk_rollup_update_result _ -> + | Zk_rollup_publish_result _ | Zk_rollup_update_result _ + | Counter_update_result _ -> return_nil) | Skipped _ -> error_with "Cannot know originated contracts of skipped operation" diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index 811bdc1fc4f4766a0beab8535c53f71d5d397c9e..2c72636d2ebbc130adaa3ef89927ee8a6dc15bdf 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -355,6 +355,8 @@ let pp_manager_operation_content (type kind) source ppf Format.fprintf ppf "Epoxy publish:@,From: %a" Contract.pp source | Zk_rollup_update _ -> Format.fprintf ppf "Epoxy update:@,From: %a" Contract.pp source + | Counter_update _ -> + Format.fprintf ppf "Counter update:@,Contract: %a" Contract.pp source let pp_balance_updates ppf balance_updates = let open Receipt in @@ -808,6 +810,10 @@ let pp_manager_operation_contents_result ppf op_result = pp_paid_storage_size_diff ppf paid_storage_size_diff ; pp_balance_updates ppf balance_updates in + let pp_counter_update_result + (Counter_update_result {consumed_gas}) = + pp_consumed_gas ppf consumed_gas ; + in let manager_operation_name (type kind) (result : kind successful_manager_operation_result) = @@ -835,6 +841,7 @@ let pp_manager_operation_contents_result ppf op_result = | Zk_rollup_origination_result _ -> "epoxy originate" | Zk_rollup_publish_result _ -> "epoxy publish" | Zk_rollup_update_result _ -> "epoxy update" + | Counter_update_result _ -> "counter update" in let pp_manager_operation_contents_result (type kind) ppf (result : kind successful_manager_operation_result) = @@ -869,6 +876,7 @@ let pp_manager_operation_contents_result ppf op_result = | Zk_rollup_origination_result _ as op -> pp_zk_rollup_origination_result op | Zk_rollup_publish_result _ as op -> pp_zk_rollup_publish_result op | Zk_rollup_update_result _ as op -> pp_zk_rollup_update_result op + | Counter_update_result _ as op -> pp_counter_update_result op in pp_operation_result ~operation_name:manager_operation_name 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 2d710acb6c6268827bf92b49bf17cbaed5187832..ffd68a06ce39d0372347c17955a6e4bcac3fc9d0 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 @@ -1756,6 +1756,57 @@ let commands_rw () = () in return_unit); + command + ~group + ~desc:"Increment counter: inject the manager operation" + (args2 fee_arg fee_parameter_args) + (prefixes ["increment"; "counter"; "by"] + @@ non_negative_z_param + ~name:"amount" + ~desc:"amount to increment counter" + @@ prefix "from" + @@ Client_keys.Public_key_hash.source_param + ~name:"src" + ~desc:"source account" + @@ stop) + (fun (fee, fee_parameter) amount source cctxt -> + let open Lwt_result_syntax in + let* _, src_pk, src_sk = Client_keys.get_key cctxt source in + let*! () = cctxt#message "==> Incrementing counter...\n" in + let fee = + match fee with + | None -> Tez.zero + | Some fee -> fee + in + let* _res = + counter_update + cctxt + ~amount + ~fee + ~source + ~src_pk + ~src_sk + ~fee_parameter + () + in + let* counter_val = counter_get cctxt ~chain:cctxt#chain ~block:cctxt#block in + let*! () = cctxt#answer "==> Counter incremented.\n ==> Counter = %d\n" (Z.to_int counter_val) in + return_unit); + command + ~group + ~desc:"Get the counter" + no_options + (prefixes ["get"; "counter"] + @@ stop) + (fun () cctxt -> + let open Lwt_result_syntax in + let* counter = counter_get + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + in + let*! () = cctxt#answer "==> Counter: %d\n" (Z.to_int counter) in + return_unit); command ~group ~desc:"Transfer tokens / call a smart contract." diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index 355f5509e016f53c66a4f5b3dd320e324ae7812b..0f5cb6b2b7699c3ea45491e7abc4eeaf5d0a4ab8 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -139,6 +139,8 @@ "Storage_sigs", "Storage_functors", "Storage", + + "Counter_storage", "Global_constants_costs_generated", "Global_constants_costs", diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 6e5b48cc2a7e0f5c9ea01458f0ab470007cd5b0c..a2b58d01fffd6ff1d7c8571867d687c49137ef03 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -183,6 +183,8 @@ module Zk_rollup = struct include Zk_rollup_storage end +module Counter = Counter_storage + module Entrypoint = Entrypoint_repr module Manager_counter = Manager_counter_repr include Operation_repr diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index e6ecfa1eec42368269e5e0f417dc09f8c33cecc7..0a37e82c1a35412fd29bbf2224ee432d623dd65b 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -4452,6 +4452,8 @@ module Kind : sig type zk_rollup_update = Zk_rollup_update_kind + type counter_update = Counter_update_kind + type 'a manager = | Reveal_manager_kind : reveal manager | Transaction_manager_kind : transaction manager @@ -4476,6 +4478,7 @@ module Kind : sig | Zk_rollup_origination_manager_kind : zk_rollup_origination manager | Zk_rollup_publish_manager_kind : zk_rollup_publish manager | Zk_rollup_update_manager_kind : zk_rollup_update manager + | Counter_update_manager_kind : counter_update manager end (** All the definitions below are re-exported from {!Operation_repr}. *) @@ -4684,6 +4687,10 @@ and _ manager_operation = update : Zk_rollup.Update.t; } -> Kind.zk_rollup_update manager_operation + | Counter_update : { + amount : Z.t; + } + -> Kind.counter_update manager_operation type packed_manager_operation = | Manager : 'kind manager_operation -> packed_manager_operation @@ -4887,6 +4894,8 @@ module Operation : sig val zk_rollup_update_case : Kind.zk_rollup_update Kind.manager case + val counter_update_case : Kind.counter_update Kind.manager case + module Manager_operations : sig type 'b case = | MCase : { @@ -5409,3 +5418,11 @@ module Fees : sig val check_storage_limit : context -> storage_limit:Z.t -> unit tzresult end + +(** This module re-exports definitions from {!Counter_storage}. *) +module Counter : sig + val incr_or_init : + context -> Z.t -> (Z.t * context) Lwt.t + val get_or_init : + context -> (Z.t * context) Lwt.t +end diff --git a/src/proto_alpha/lib_protocol/alpha_services.ml b/src/proto_alpha/lib_protocol/alpha_services.ml index 000d36a5f3fb44215e398c13770d7d358ce55547..df65948746ac13a5c0eefad3b84a2ebadbd54e60 100644 --- a/src/proto_alpha/lib_protocol/alpha_services.ml +++ b/src/proto_alpha/lib_protocol/alpha_services.ml @@ -269,6 +269,27 @@ module Denunciations = struct RPC_context.make_call0 S.denunciations ctxt block () () end +module Counter = struct + module S = struct + let counter = + RPC_service.get_service + ~description:"Return the current context counter." + ~query:RPC_query.empty + ~output:Data_encoding.z + RPC_path.(custom_root / "context" / "counter") + end + + let register () = + let open Services_registration in + let open Lwt_result_syntax in + register0 ~chunked:false S.counter (fun ctxt () () -> + let*! (counter, _) = Counter.get_or_init ctxt in + return counter) + + let get ctxt block = + RPC_context.make_call0 S.counter ctxt block () () +end + let register () = Contract.register () ; Constants.register () ; @@ -279,4 +300,5 @@ let register () = Liquidity_baking.register () ; Cache.register () ; Adaptive_issuance.register () ; - Denunciations.register () + Denunciations.register (); + Counter.register () diff --git a/src/proto_alpha/lib_protocol/alpha_services.mli b/src/proto_alpha/lib_protocol/alpha_services.mli index 049064397e294bbf9b9e26946d24df922a21d7ae..e16fbe52964b4f99a41b74e803c1ce3adfe27296 100644 --- a/src/proto_alpha/lib_protocol/alpha_services.mli +++ b/src/proto_alpha/lib_protocol/alpha_services.mli @@ -91,3 +91,9 @@ module Denunciations : sig end val register : unit -> unit + +module Counter : sig + val get : + 'a #RPC_context.simple -> 'a -> Z.t shell_tzresult Lwt.t + (* t -> (Z.t * t) Lwt.t *) +end diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 461cc5673b60936d18b0aaa3c3f79d07e8025719..be846742a0bb5b70556769dcfc4629615b08319b 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1623,6 +1623,13 @@ let apply_manager_operation : Zk_rollup_apply.publish ~ctxt_before_op ~ctxt ~zk_rollup ~l2_ops:ops | Zk_rollup_update {zk_rollup; update} -> Zk_rollup_apply.update ~ctxt_before_op ~ctxt ~zk_rollup ~update + | Counter_update {amount} -> + let*! _, ctxt = Counter.incr_or_init ctxt amount in + let consumed_gas = Gas.consumed ~since:ctxt_before_op ~until:ctxt in + let result = + Counter_update_result {consumed_gas} + in + return (ctxt, result, []) type success_or_failure = Success of context | Failure @@ -1868,6 +1875,7 @@ let burn_manager_storage_fees : ( ctxt, storage_limit, Zk_rollup_update_result {payload with balance_updates} ) + | Counter_update_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 9d7a3ec6fe7b7b444a3639791355c8f1344eb4e3..867903e4113956ea5240bd1c5ac4e19bcfecf06b 100644 --- a/src/proto_alpha/lib_protocol/apply_results.ml +++ b/src/proto_alpha/lib_protocol/apply_results.ml @@ -153,6 +153,10 @@ type _ successful_manager_operation_result = paid_storage_size_diff : Z.t; } -> Kind.zk_rollup_update successful_manager_operation_result + | Counter_update_result : { + consumed_gas : Gas.Arith.fp; + } + -> Kind.counter_update successful_manager_operation_result let migration_origination_result_to_successful_manager_operation_result ({ @@ -636,6 +640,20 @@ module Manager_result = struct Zk_rollup_update_result {balance_updates; consumed_gas; paid_storage_size_diff}) + let counter_update_case = + make + ~op_case:Operation.Encoding.Manager_operations.counter_update_case + ~encoding: + Data_encoding.( + obj1 (dft "consumed_milligas" Gas.Arith.n_fp_encoding Gas.Arith.zero)) + ~select:(function + | Successful_manager_result (Counter_update_result _ as op) -> Some op + | _ -> None) + ~kind:Kind.Counter_update_manager_kind + ~proj:(function + | Counter_update_result {consumed_gas} -> consumed_gas) + ~inj:(fun consumed_gas -> Counter_update_result {consumed_gas}) + let sc_rollup_originate_case = make ~op_case:Operation.Encoding.Manager_operations.sc_rollup_originate_case @@ -1012,6 +1030,9 @@ let equal_manager_kind : | Kind.Zk_rollup_update_manager_kind, Kind.Zk_rollup_update_manager_kind -> Some Eq | Kind.Zk_rollup_update_manager_kind, _ -> None + | Kind.Counter_update_manager_kind, Kind.Counter_update_manager_kind -> + Some Eq + | Kind.Counter_update_manager_kind, _ -> None module Encoding = struct let consensus_result_encoding power_name = @@ -1764,6 +1785,17 @@ module Encoding = struct -> Some (op, res) | _ -> None) + + let counter_update_case = + make_manager_case + Operation.Encoding.counter_update_case + Manager_result.counter_update_case + (function + | Contents_and_result + ((Manager_operation {operation = Counter_update _; _} as op), res) + -> + Some (op, res) + | _ -> None) end let common_cases = @@ -1797,6 +1829,7 @@ let common_cases = zk_rollup_origination_case; zk_rollup_publish_case; zk_rollup_update_case; + counter_update_case; ] let contents_cases = @@ -2578,6 +2611,11 @@ let kind_equal : } ) -> Some Eq | Manager_operation {operation = Zk_rollup_update _; _}, _ -> None + | ( Manager_operation {operation = Counter_update _; _}, + Manager_operation_result {operation_result = Applied (Counter_update_result _); _} + ) -> + Some Eq + | Manager_operation {operation = Counter_update _; _}, _ -> None let rec kind_equal_list : type kind kind2. diff --git a/src/proto_alpha/lib_protocol/apply_results.mli b/src/proto_alpha/lib_protocol/apply_results.mli index 8c60ad0d6c201111699ce1cb21aa84a76ab2650f..073659bc4a575503f7cb4ee6dbd7265915bc3a4d 100644 --- a/src/proto_alpha/lib_protocol/apply_results.mli +++ b/src/proto_alpha/lib_protocol/apply_results.mli @@ -260,6 +260,10 @@ and _ successful_manager_operation_result = paid_storage_size_diff : Z.t; } -> Kind.zk_rollup_update successful_manager_operation_result + | Counter_update_result: { + consumed_gas: Gas.Arith.fp; + } + -> Kind.counter_update successful_manager_operation_result and packed_successful_manager_operation_result = | Successful_manager_result : diff --git a/src/proto_alpha/lib_protocol/counter_storage.ml b/src/proto_alpha/lib_protocol/counter_storage.ml new file mode 100644 index 0000000000000000000000000000000000000000..6465bc335a1541d7c619bbdccf1d5064132e641e --- /dev/null +++ b/src/proto_alpha/lib_protocol/counter_storage.ml @@ -0,0 +1,46 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2024 Trili Tech, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +let get_or_init ctxt = + let open Lwt_syntax in + let* res = Storage.Counter_storage.get ctxt in + match res with + | Ok value -> Lwt.return (value, ctxt) + | Error _ -> + let* init = Storage.Counter_storage.add ctxt Z.zero in + Lwt.return (Z.zero, init) + +let incr_or_init ctxt value = + let open Lwt_syntax in + let* res = Storage.Counter_storage.get ctxt in + match res with + | Ok v -> + let new_v = Z.add v value in + let* update_res = Storage.Counter_storage.add ctxt new_v in + Lwt.return (new_v, update_res) + | Error _ -> + let* update_res = Storage.Counter_storage.add ctxt value in + Lwt.return (value, update_res) + diff --git a/src/proto_alpha/lib_protocol/counter_storage.mli b/src/proto_alpha/lib_protocol/counter_storage.mli new file mode 100644 index 0000000000000000000000000000000000000000..25776307c7a02d632ee484199bd5f7f9a2ec60a3 --- /dev/null +++ b/src/proto_alpha/lib_protocol/counter_storage.mli @@ -0,0 +1,32 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2024 Trili Tech, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Gets the value stored in the counter, or initializes it to zero *) +val get_or_init : Raw_context.t -> (Z.t * Raw_context.t) Lwt.t + +(* Increments the counter by a given value, starting from the current value or + initializes it to zero if it does not exist *) +val incr_or_init : Raw_context.t -> Z.t -> (Z.t * Raw_context.t) Lwt.t + diff --git a/src/proto_alpha/lib_protocol/operation_repr.ml b/src/proto_alpha/lib_protocol/operation_repr.ml index 531efa05714af2aadef91568d7e0707bec472452..d753eb0800b6a8c17187a152d6f652c8ed77b175 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.ml +++ b/src/proto_alpha/lib_protocol/operation_repr.ml @@ -109,6 +109,8 @@ module Kind = struct type zk_rollup_update = Zk_rollup_update_kind + type counter_update = Counter_update_kind + type 'a manager = | Reveal_manager_kind : reveal manager | Transaction_manager_kind : transaction manager @@ -133,6 +135,7 @@ module Kind = struct | Zk_rollup_origination_manager_kind : zk_rollup_origination manager | Zk_rollup_publish_manager_kind : zk_rollup_publish manager | Zk_rollup_update_manager_kind : zk_rollup_update manager + | Counter_update_manager_kind : counter_update manager end type 'a consensus_operation_type = @@ -398,6 +401,10 @@ and _ manager_operation = update : Zk_rollup_update_repr.t; } -> Kind.zk_rollup_update manager_operation + | Counter_update : { + amount : Z.t + } + -> Kind.counter_update manager_operation let manager_kind : type kind. kind manager_operation -> kind Kind.manager = function @@ -423,6 +430,7 @@ let manager_kind : type kind. kind manager_operation -> kind Kind.manager = | Zk_rollup_origination _ -> Kind.Zk_rollup_origination_manager_kind | Zk_rollup_publish _ -> Kind.Zk_rollup_publish_manager_kind | Zk_rollup_update _ -> Kind.Zk_rollup_update_manager_kind + | Counter_update _ -> Kind.Counter_update_manager_kind type packed_manager_operation = | Manager : 'kind manager_operation -> packed_manager_operation @@ -535,6 +543,8 @@ let sc_rollup_operation_recover_bond_tag = sc_rollup_operation_tag_offset + 7 let dal_offset = 230 +let counter_operation_update_tag = 231 + let dal_publish_commitment_tag = dal_offset + 0 let zk_rollup_operation_tag_offset = 250 @@ -820,6 +830,24 @@ module Encoding = struct (fun (zk_rollup, update) -> Zk_rollup_update {zk_rollup; update}); } + let counter_update_case = + MCase + { + tag = counter_operation_update_tag; + name = "counter_update"; + encoding = + obj1 + (req "amount" Data_encoding.z); + select = + ( function + | Manager (Counter_update _ as op) -> Some op | _ -> None); + proj = + ( function + | Counter_update {amount} -> (amount)); + inj = + (fun (amount) -> Counter_update {amount}); + } + let sc_rollup_originate_case = MCase { @@ -1644,6 +1672,11 @@ module Encoding = struct zk_rollup_operation_update_tag Manager_operations.zk_rollup_update_case + let counter_update_case = + make_manager_case + counter_operation_update_tag + Manager_operations.counter_update_case + type packed_case = PCase : 'b case -> packed_case let common_cases = @@ -1677,6 +1710,7 @@ module Encoding = struct PCase zk_rollup_origination_case; PCase zk_rollup_publish_case; PCase zk_rollup_update_case; + PCase counter_update_case; ] let contents_cases = @@ -2154,6 +2188,8 @@ let equal_manager_operation_kind : | Zk_rollup_publish _, _ -> None | Zk_rollup_update _, Zk_rollup_update _ -> Some Eq | Zk_rollup_update _, _ -> None + | Counter_update _, Counter_update _ -> Some Eq + | Counter_update _, _ -> 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 b98884088c81849e4fc2055602a3b30c612cdddd..aaf65b2db8d0fb8d964648674ef14b9b49fad98f 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.mli +++ b/src/proto_alpha/lib_protocol/operation_repr.mli @@ -143,6 +143,9 @@ module Kind : sig type zk_rollup_update = Zk_rollup_update_kind + type counter_update = Counter_update_kind + + type 'a manager = | Reveal_manager_kind : reveal manager | Transaction_manager_kind : transaction manager @@ -167,6 +170,7 @@ module Kind : sig | Zk_rollup_origination_manager_kind : zk_rollup_origination manager | Zk_rollup_publish_manager_kind : zk_rollup_publish manager | Zk_rollup_update_manager_kind : zk_rollup_update manager + | Counter_update_manager_kind : counter_update manager end type 'a consensus_operation_type = @@ -498,6 +502,10 @@ and _ manager_operation = update : Zk_rollup_update_repr.t; } -> Kind.zk_rollup_update manager_operation + | Counter_update : { + amount : Z.t + } + -> Kind.counter_update manager_operation type packed_manager_operation = | Manager : 'kind manager_operation -> packed_manager_operation @@ -763,6 +771,8 @@ module Encoding : sig val zk_rollup_update_case : Kind.zk_rollup_update Kind.manager case + val counter_update_case : Kind.counter_update Kind.manager case + module Manager_operations : sig type 'b case = | MCase : { @@ -819,6 +829,8 @@ module Encoding : sig val zk_rollup_publish_case : Kind.zk_rollup_publish case val zk_rollup_update_case : Kind.zk_rollup_update case + + val counter_update_case : Kind.counter_update case end end diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index ad2b76ee94cb3fa5c32e6721c914a5921e72d6da..d62b7532ce6277691fa276fe089d73f0220664cd 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -2306,3 +2306,17 @@ module Legacy = struct end) (Tenderbake.Branch) end + +(* Counter storage for the dummy task *) +(* Stores one value, type Z (int), and has a name. *) +(* Makes use of Single_data_storage and encoding Z *) +module Counter_storage : + Single_data_storage + with type t = Raw_context.t + and type value = Z.t = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["Dummy_counter"] + end) + (Encoding.Z) + diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index 2b905fcce5e4546a4b1fe72fba0f986c9d756ffc..bdbb115d4069b76318fcdd25a7e112dc10bc8f89 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -1070,3 +1070,9 @@ module Legacy : sig with type value = Block_hash.t * Block_payload_hash.t and type t := Raw_context.t end + +(* Counter storage for the dummy task *) +module Counter_storage : + Single_data_storage + with type value = Z.t + and type t = Raw_context.t \ No newline at end of file diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.ml b/src/proto_alpha/lib_protocol/test/helpers/block.ml index e46e0f5183561a0960d0bc32d5e4fcb4cefe1fc3..332a1fba765542835e1520fea9cb9ded352ec7bc 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/block.ml @@ -1088,7 +1088,8 @@ let balance_update_of_operation_result : | Sc_rollup_publish_result _ | Sc_rollup_refute_result _ | Sc_rollup_timeout_result _ | Sc_rollup_execute_outbox_message_result _ | Sc_rollup_recover_bond_result _ | Zk_rollup_origination_result _ - | Zk_rollup_publish_result _ | Zk_rollup_update_result _ -> + | Zk_rollup_publish_result _ | Zk_rollup_update_result _ + | Counter_update_result _-> [] | Delegation_result {balance_updates; _} | Transaction_result @@ -1099,6 +1100,7 @@ let balance_update_of_operation_result : | Increase_paid_storage_result {balance_updates; _} -> balance_updates) + let balance_updates_of_single_content : type a. a Protocol.Apply_results.contents_result -> @@ -1209,7 +1211,8 @@ let bake_n_with_origination_results ?baking_mode ?policy n b = | Successful_manager_result (Sc_rollup_recover_bond_result _) | Successful_manager_result (Zk_rollup_origination_result _) | Successful_manager_result (Zk_rollup_publish_result _) - | Successful_manager_result (Zk_rollup_update_result _) -> + | Successful_manager_result (Zk_rollup_update_result _) + | Successful_manager_result (Counter_update_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 7a625f8c4bc8cea30a545be9c7fc5d3ac36e0692..f7e2ff5f17f7a3a1047fcb46d754edbbb8795642 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -1063,3 +1063,20 @@ let zk_rollup_update ?force_reveal ?counter ?fee ?gas_limit ?storage_limit ctxt in let+ account = Context.Contract.manager ctxt src in sign account.sk (Context.branch ctxt) to_sign_op + +let counter_update ?force_reveal ?counter ?fee ?gas_limit ?storage_limit ctxt + (src : Contract.t) ~amount = + let open Lwt_result_syntax in + let* to_sign_op = + manager_operation + ?force_reveal + ?counter + ?fee + ?gas_limit + ?storage_limit + ~source:src + ctxt + (Counter_update {amount}) + in + let+ account = Context.Contract.manager ctxt src in + sign account.sk (Context.branch ctxt) to_sign_op \ No newline at end of file diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 5f39291b0461370485350ada47e81f18f6461e94..bc9e7899f044837318d6e643f54bba9ba4aa6239 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -631,3 +631,14 @@ val zk_rollup_update : zk_rollup:Zk_rollup.t -> update:Zk_rollup.Update.t -> Operation.packed tzresult Lwt.t + +val counter_update : + ?force_reveal:bool -> + ?counter:Manager_counter.t -> + ?fee:Tez.t -> + ?gas_limit:gas_limit -> + ?storage_limit:Z.t -> + Context.t -> + Contract.t -> + amount:Z.t -> + Operation.packed tzresult Lwt.t \ No newline at end of file diff --git a/src/proto_alpha/lib_protocol/test/integration/validate/manager_operation_helpers.ml b/src/proto_alpha/lib_protocol/test/integration/validate/manager_operation_helpers.ml index 88a42a38e5df457705903bdac9609922ab3fab29..909476d31ce0d9e72a20c11e0daa3c51c36834b3 100644 --- a/src/proto_alpha/lib_protocol/test/integration/validate/manager_operation_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/integration/validate/manager_operation_helpers.ml @@ -79,6 +79,7 @@ type manager_operation_kind = | K_Zk_rollup_origination | K_Zk_rollup_publish | K_Zk_rollup_update + | K_Counter_update (** The requirements for a tested manager operation. *) type operation_req = { @@ -170,6 +171,7 @@ let kind_to_string = function | K_Zk_rollup_origination -> "Zk_rollup_origination" | K_Zk_rollup_publish -> "Zk_rollup_publish" | K_Zk_rollup_update -> "Zk_rollup_update" + | K_Counter_update -> "Counter_update" (** {2 Pretty-printers} *) let pp_opt pp v = @@ -958,6 +960,21 @@ let mk_zk_rollup_update (oinfos : operation_req) (infos : infos) = in return op +let mk_counter_update (oinfos : operation_req) (infos : infos) = + let open Lwt_result_syntax in + let* op = + Op.counter_update + ?fee:oinfos.fee + ?gas_limit:oinfos.gas_limit + ?counter:oinfos.counter + ?storage_limit:oinfos.storage_limit + ?force_reveal:oinfos.force_reveal + (B infos.ctxt.block) + (contract_of (get_source infos)) + ~amount:(Z.one) + in + return op + (** {2 Helpers for generation of generic check tests by manager operation} *) (** Generic forge for any kind of manager operation according to @@ -988,6 +1005,7 @@ let select_op (op_req : operation_req) (infos : infos) = | K_Zk_rollup_origination -> mk_zk_rollup_origination | K_Zk_rollup_publish -> mk_zk_rollup_publish | K_Zk_rollup_update -> mk_zk_rollup_update + | K_Counter_update -> mk_counter_update in mk_op op_req infos @@ -1354,6 +1372,7 @@ let subjects = K_Zk_rollup_origination; K_Zk_rollup_publish; K_Zk_rollup_update; + K_Counter_update; ] let is_consumer = function @@ -1363,7 +1382,7 @@ let is_consumer = function | K_Sc_rollup_timeout | K_Sc_rollup_cement | K_Sc_rollup_publish | K_Sc_rollup_execute_outbox_message | K_Sc_rollup_recover_bond | K_Dal_publish_commitment | K_Zk_rollup_origination | K_Zk_rollup_publish - | K_Zk_rollup_update -> + | K_Zk_rollup_update | K_Counter_update -> false | K_Transaction | K_Origination | K_Register_global_constant | K_Transfer_ticket -> @@ -1379,7 +1398,7 @@ let is_disabled flags = function | K_Transaction | K_Origination | K_Register_global_constant | K_Delegation | K_Undelegation | K_Self_delegation | K_Set_deposits_limit | K_Update_consensus_key | K_Increase_paid_storage | K_Reveal - | K_Transfer_ticket -> + | K_Transfer_ticket | K_Counter_update -> false | K_Sc_rollup_origination | K_Sc_rollup_publish | K_Sc_rollup_cement | K_Sc_rollup_add_messages | K_Sc_rollup_refute | K_Sc_rollup_timeout diff --git a/src/proto_alpha/lib_protocol/test/integration/validate/test_sanity.ml b/src/proto_alpha/lib_protocol/test/integration/validate/test_sanity.ml index 760e6d9e33ea98f64ec5859b45d3ff7114de88f1..fdba9a64195204226ef57cadbe7c9dab10dce256 100644 --- a/src/proto_alpha/lib_protocol/test/integration/validate/test_sanity.ml +++ b/src/proto_alpha/lib_protocol/test/integration/validate/test_sanity.ml @@ -60,7 +60,8 @@ let ensure_kind infos kind = | Dal_publish_commitment _, K_Dal_publish_commitment | Zk_rollup_origination _, K_Zk_rollup_origination | Zk_rollup_publish _, K_Zk_rollup_publish - | Zk_rollup_update _, K_Zk_rollup_update -> + | Zk_rollup_update _, K_Zk_rollup_update + | Counter_update _, K_Counter_update -> return_unit | ( ( Transaction _ | Origination _ | Register_global_constant _ | Delegation _ | Set_deposits_limit _ | Update_consensus_key _ @@ -69,7 +70,7 @@ let ensure_kind infos kind = | Sc_rollup_add_messages _ | Sc_rollup_refute _ | Sc_rollup_timeout _ | Sc_rollup_execute_outbox_message _ | Sc_rollup_recover_bond _ | Dal_publish_commitment _ | Zk_rollup_origination _ - | Zk_rollup_publish _ | Zk_rollup_update _ ), + | Zk_rollup_publish _ | Zk_rollup_update _ | Counter_update _), _ ) -> assert false) | Single _ -> assert false diff --git a/src/proto_alpha/lib_protocol/test/unit/test_counter_storage.ml b/src/proto_alpha/lib_protocol/test/unit/test_counter_storage.ml new file mode 100644 index 0000000000000000000000000000000000000000..3feed87923af7cd6498c73676a817f1f48daf7a9 --- /dev/null +++ b/src/proto_alpha/lib_protocol/test/unit/test_counter_storage.ml @@ -0,0 +1,106 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2024 Trili Tech, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Counter_storage + Invocation: dune exec src/proto_alpha/lib_protocol/test/unit/main.exe \ + -- --file test_counter_storage.ml + Subject: Tests for counter storage module +*) + +open Protocol + +let assert_equal_Z ~loc = + Assert.equal ~loc Z.equal "Z.t's aren't equal" Z.pp_print + +module Counter_storage_test = struct + let test_initialise () = + let open Lwt_result_syntax in + let* ctxt = Context.default_raw_context () in + let*! v, _ = Counter_storage.get_or_init ctxt in + assert_equal_Z v Z.zero ~loc:__LOC__ + + let test_incr n = + let open Lwt_result_syntax in + let* ctxt = Context.default_raw_context () in + let*! _, new_ctxt = Counter_storage.incr_or_init ctxt n in + let*! v, _ = Counter_storage.get_or_init new_ctxt in + assert_equal_Z v n ~loc:__LOC__ + + let test_incr_res n = + let open Lwt_result_syntax in + let* ctxt = Context.default_raw_context () in + let*! n, new_ctxt = Counter_storage.incr_or_init ctxt n in + let*! v, _ = Counter_storage.get_or_init new_ctxt in + assert_equal_Z v n ~loc:__LOC__ + + let test_incrs ns = + let open Lwt_result_syntax in + let rec incr_cons ns ctxt = + match ns with + | n :: tail -> + let*! _, new_ctxt = Counter_storage.incr_or_init ctxt n in + incr_cons tail new_ctxt + | [] -> Counter_storage.get_or_init ctxt + in + let rec sum_cons ns cum = + match ns with h :: t -> sum_cons t (Z.add cum h) | [] -> cum + in + let* ctxt = Context.default_raw_context () in + let*! n, _ = incr_cons ns ctxt in + assert_equal_Z (sum_cons ns Z.zero) n ~loc:__LOC__ +end + +let tests = + [ + Tztest.tztest + "initialise global counter with get_or_init to zero" + `Quick + Counter_storage_test.test_initialise; + Tztest.tztest + "initialise global counter with incr_or_init to one" + `Quick + (fun () -> Counter_storage_test.test_incr Z.one); + Tztest.tztest + "initialise global counter with incr_or_init to ten" + `Quick + (fun () -> Counter_storage_test.test_incr (Z.of_int 10)); + Tztest.tztest + "increment global counter: compare result of incr with get" + `Quick + (fun () -> Counter_storage_test.test_incr_res (Z.of_int 6)); + + Tztest.tztest + "increment global counter multiple times" + `Quick + (fun () -> + Counter_storage_test.test_incrs + [Z.of_int 1; Z.of_int 9; Z.of_int 3]); + ] + +let () = + Alcotest_lwt.run ~__FILE__ Protocol.name [("Counter_storage.ml", tests)] + |> Lwt_main.run \ No newline at end of file diff --git a/src/proto_alpha/lib_protocol/validate.ml b/src/proto_alpha/lib_protocol/validate.ml index e3b776374838c1eb4bc4c2620adaae2e6c3b2015..27cfcf53b89ee30027029de0db7678d864e33d69 100644 --- a/src/proto_alpha/lib_protocol/validate.ml +++ b/src/proto_alpha/lib_protocol/validate.ml @@ -2026,7 +2026,8 @@ module Manager = struct return_unit | Delegation (Some pkh) -> Delegate.check_not_tz4 pkh | Update_consensus_key pk -> Delegate.Consensus_key.check_not_tz4 pk - | Delegation None | Set_deposits_limit _ | Increase_paid_storage _ -> + | Delegation None | Set_deposits_limit _ | Increase_paid_storage _ + | Counter_update _ -> return_unit | Transfer_ticket {contents; ty; _} -> let* remaining_gas = consume_decoding_gas remaining_gas contents in 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 50208c2472e8f5a72f9ef09d0380b0b850338a71..9328d5384720ac601aff34194f4f383d1d1afcfe 100644 --- a/src/proto_alpha/lib_sc_rollup_node/daemon_helpers.ml +++ b/src/proto_alpha/lib_sc_rollup_node/daemon_helpers.ml @@ -299,7 +299,8 @@ let process_l1_operation (type kind) ~catching_up node_ctxt | Reveal _ | Transaction _ | Origination _ | Delegation _ | Update_consensus_key _ | Register_global_constant _ | Set_deposits_limit _ | Increase_paid_storage _ | Transfer_ticket _ | Sc_rollup_originate _ - | Zk_rollup_origination _ | Zk_rollup_publish _ | Zk_rollup_update _ -> + | Zk_rollup_origination _ | Zk_rollup_publish _ | Zk_rollup_update _ + | Counter_update _ -> false in (* Only look at operations that are for the node's rollup *)