diff --git a/src/proto_alpha/lib_client/injection.ml b/src/proto_alpha/lib_client/injection.ml index b7386271af6501807a3446e3a636744e7e532f58..73ac1a1ae8c177e7feafdab4e495f9aacf9d6334 100644 --- a/src/proto_alpha/lib_client/injection.ml +++ b/src/proto_alpha/lib_client/injection.ml @@ -325,6 +325,7 @@ let estimated_gas_single (type kind) Ok consumed_gas | Applied (Tx_rollup_submit_batch_result {consumed_gas; _}) -> Ok consumed_gas + | Applied (Tx_rollup_commit_result {consumed_gas; _}) -> Ok consumed_gas | Applied (Sc_rollup_originate_result {consumed_gas; _}) -> Ok consumed_gas | Applied (Sc_rollup_add_messages_result {consumed_gas; _}) -> Ok consumed_gas @@ -367,6 +368,7 @@ let estimated_storage_single (type kind) ~tx_rollup_origination_size We need to charge for newly allocated storage (as we do for Michelson’s big map). *) Ok Z.zero + | Applied (Tx_rollup_commit_result _) -> Ok Z.zero | Applied (Sc_rollup_originate_result {size; _}) -> Ok size | Applied (Sc_rollup_add_messages_result _) -> Ok Z.zero | Skipped _ -> assert false @@ -419,6 +421,7 @@ let originated_contracts_single (type kind) | Applied (Set_deposits_limit_result _) -> Ok [] | Applied (Tx_rollup_origination_result _) -> Ok [] | Applied (Tx_rollup_submit_batch_result _) -> Ok [] + | Applied (Tx_rollup_commit_result _) -> Ok [] | Applied (Sc_rollup_originate_result _) -> Ok [] | Applied (Sc_rollup_add_messages_result _) -> Ok [] | Skipped _ -> assert false diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index 2b73c4aca0f7a84052b45c89bdd0167dd6c1f12e..8450b010855d5428a8a2f077a4e7006f91b585a5 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -187,6 +187,20 @@ let pp_manager_operation_content (type kind) source internal pp_result ppf source pp_result result + | Tx_rollup_commit {tx_rollup; commitment} -> + Format.fprintf + ppf + "@[%s:%a, %a@,From: %a%a@]" + (if internal then "Internal tx rollup commitment" + else "Tx rollup commitment") + Tx_rollup.pp + tx_rollup + Tx_rollup_commitments.Commitment.pp + commitment + Contract.pp + source + pp_result + result | Sc_rollup_originate {kind; boot_sector} -> let (module R : Sc_rollups.PVM.S) = Sc_rollups.of_kind kind in Format.fprintf @@ -451,6 +465,15 @@ let pp_manager_operation_contents_and_result ppf balance_updates ; Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas in + let pp_tx_rollup_commit_result + (Tx_rollup_commit_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_sc_rollup_originate_result (Sc_rollup_originate_result {address; consumed_gas; size; balance_updates}) = @@ -548,6 +571,17 @@ let pp_manager_operation_contents_and_result ppf "@[This rollup submit operation was BACKTRACKED, its expected \ effects (as follow) were NOT applied.@]" ; pp_tx_rollup_submit_batch_result op + | Applied (Tx_rollup_commit_result _ as op) -> + Format.fprintf + ppf + "This tx rollup commit operation was successfully applied" ; + pp_tx_rollup_commit_result op + | Backtracked ((Tx_rollup_commit_result _ as op), _err) -> + Format.fprintf + ppf + "@[This tx rollup commit rollup operation was BACKTRACKED, its \ + expected effects (as follow) were NOT applied.@]" ; + pp_tx_rollup_commit_result op | Applied (Sc_rollup_originate_result _ as op) -> Format.fprintf ppf diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index f5c504d44c929ec26201a90ad0a3380a5b943221..60e38958a865c6fcf83ad4db98ad735c6c6e2d5a 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -47,6 +47,7 @@ "Tx_rollup_state_repr", "Tx_rollup_message_repr", "Tx_rollup_inbox_repr", + "Tx_rollup_commitments_repr", "Roll_repr_legacy", "Vote_repr", "Block_header_repr", @@ -102,6 +103,7 @@ "Global_constants_storage", "Tx_rollup_state_storage", "Tx_rollup_inbox_storage", + "Tx_rollup_commitments_storage", "Tx_rollup_storage", "Sc_rollup_storage", diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 5d7d9d17e59dab60281f7c02cfc70a355d44acb5..1ff3098b30b0b5657ea338a2098eeeb59bc80df1 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -276,6 +276,11 @@ module Tx_rollup_inbox = struct include Tx_rollup_inbox_storage end +module Tx_rollup_commitments = struct + include Tx_rollup_commitments_repr + include Tx_rollup_commitments_storage +end + module Global_constants_storage = Global_constants_storage module Big_map = struct diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index e4e3f22343dc67e47c632a8c7c0fcbea66e0b043..312e0873bb2cc1ae1cc5fd7e547aca5f3d22559f 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2116,6 +2116,68 @@ module Tx_rollup_inbox : sig | Tx_rollup_message_size_exceeds_limit end +(** This simply re-exports [Tx_rollup_commitments_repr] *) +module Tx_rollup_commitments : sig + module Commitment_hash : sig + val commitment_hash : string + + include S.HASH + end + + module Commitment : sig + type batch_commitment = {root : bytes} + + val batch_commitment_equal : batch_commitment -> batch_commitment -> bool + + type t = { + level : Raw_level.t; + batches : batch_commitment list; + predecessor : Commitment_hash.t option; + } + + val ( = ) : t -> t -> bool + + val pp : Format.formatter -> t -> unit + + val encoding : t Data_encoding.t + + val hash : t -> Commitment_hash.t + end + + type pending_commitment = { + commitment : Commitment.t; + hash : Commitment_hash.t; + committer : Signature.Public_key_hash.t; + submitted_at : Raw_level.t; + } + + type t = pending_commitment list + + val encoding : t Data_encoding.t + + type error += Commitment_hash_already_submitted + + type error += Two_commitments_from_one_committer + + type error += Wrong_commitment_predecessor_level + + type error += Missing_commitment_predecessor + + type error += Wrong_batch_count + + type error += Commitment_too_early + + val add_commitment : + context -> + Tx_rollup.t -> + Signature.Public_key_hash.t -> + Commitment.t -> + context tzresult Lwt.t + + val get_commitments : + context -> Tx_rollup.t -> Raw_level.t -> (context * t) tzresult Lwt.t +end + module Kind : sig type preendorsement_consensus_kind = Preendorsement_consensus_kind @@ -2166,6 +2228,8 @@ module Kind : sig type tx_rollup_submit_batch = Tx_rollup_submit_batch_kind + type tx_rollup_commit = Tx_rollup_commit_kind + type sc_rollup_originate = Sc_rollup_originate_kind type sc_rollup_add_messages = Sc_rollup_add_messages_kind @@ -2179,6 +2243,7 @@ module Kind : sig | Set_deposits_limit_manager_kind : set_deposits_limit manager | Tx_rollup_origination_manager_kind : tx_rollup_origination manager | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager + | Tx_rollup_commit_manager_kind : tx_rollup_commit manager | Sc_rollup_originate_manager_kind : sc_rollup_originate manager | Sc_rollup_add_messages_manager_kind : sc_rollup_add_messages manager end @@ -2304,6 +2369,11 @@ and _ manager_operation = content : string; } -> Kind.tx_rollup_submit_batch manager_operation + | Tx_rollup_commit : { + tx_rollup : Tx_rollup.t; + commitment : Tx_rollup_commitments.Commitment.t; + } + -> Kind.tx_rollup_commit manager_operation | Sc_rollup_originate : { kind : Sc_rollup.Kind.t; boot_sector : Sc_rollup.PVM.boot_sector; @@ -2457,6 +2527,8 @@ module Operation : sig val tx_rollup_submit_batch_case : Kind.tx_rollup_submit_batch Kind.manager case + val tx_rollup_commit_case : Kind.tx_rollup_commit Kind.manager case + val register_global_constant_case : Kind.register_global_constant Kind.manager case @@ -2495,6 +2567,8 @@ module Operation : sig val tx_rollup_submit_batch_case : Kind.tx_rollup_submit_batch case + val tx_rollup_commit_case : Kind.tx_rollup_commit case + val sc_rollup_originate_case : Kind.sc_rollup_originate case val sc_rollup_add_messages_case : Kind.sc_rollup_add_messages case diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 87d97c19aeb9aadc940b9d0a3cb6554b0222039b..d13d628423f6ced92f8b9aa4f191688ffa94a082 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1185,6 +1185,21 @@ let apply_manager_operation_content : } in return (ctxt, result, []) + | Tx_rollup_commit {tx_rollup; commitment} -> ( + (* TODO: bonds https://gitlab.com/tezos/tezos/-/issues/2459 *) + match Contract.is_implicit source with + | None -> assert false (* This is only called with implicit contracts *) + | Some key -> + Tx_rollup_commitments.add_commitment ctxt tx_rollup key commitment + >>=? fun ctxt -> + let result = + Tx_rollup_commit_result + { + consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt; + balance_updates = []; + } + in + return (ctxt, result, [])) | Sc_rollup_originate {kind; boot_sector} -> Sc_rollup_operations.originate ctxt ~kind ~boot_sector >>=? fun ({address; size}, ctxt) -> @@ -1315,7 +1330,7 @@ let precheck_manager_contents (type kind) ctxt (op : kind Kind.manager contents) | Tx_rollup_origination -> assert_tx_rollup_feature_enabled ctxt >|=? fun () -> ctxt | Tx_rollup_submit_batch {content; _} -> - (* FIXME: https://gitlab.com/tezos/tezos/-/issues/2408 + (* FIXME/TORU: https://gitlab.com/tezos/tezos/-/issues/2408 Do we need to take into account the carbonation of hasing [content] here? *) assert_tx_rollup_feature_enabled ctxt >>=? fun () -> @@ -1327,6 +1342,17 @@ let precheck_manager_contents (type kind) ctxt (op : kind Kind.manager contents) Compare.Int.(message_size < size_limit) Tx_rollup_inbox.Tx_rollup_message_size_exceeds_limit >|=? fun () -> ctxt + | Tx_rollup_commit {commitment; _} -> + assert_tx_rollup_feature_enabled ctxt >>=? fun () -> + (* FIXME/TORU: https://gitlab.com/tezos/tezos/-/issues/2469 + + We should think harder about the semantics of commitments + application. *) + let current_level = (Level.current ctxt).level in + fail_when + Raw_level.(current_level <= Raw_level.succ commitment.level) + Tx_rollup_commitments.Commitment_too_early + >|=? fun () -> ctxt | Sc_rollup_originate _ | Sc_rollup_add_messages _ -> assert_sc_rollup_feature_enabled ctxt >|=? fun () -> ctxt) >>=? fun ctxt -> @@ -1432,6 +1458,8 @@ let burn_storage_fees : We need to charge for newly allocated storage (as we do for Michelson’s big map). *) return (ctxt, storage_limit, Tx_rollup_submit_batch_result payload) + | Tx_rollup_commit_result payload -> + return (ctxt, storage_limit, Tx_rollup_commit_result payload) | Sc_rollup_originate_result payload -> let payer = `Contract payer in Fees.burn_sc_rollup_origination_fees diff --git a/src/proto_alpha/lib_protocol/apply_results.ml b/src/proto_alpha/lib_protocol/apply_results.ml index 6cf254e2004a7ce1f82b603d4ab49c33603a86f2..5407e01b8ad5bdd0a62e6b82f0f585c0ba7e59de 100644 --- a/src/proto_alpha/lib_protocol/apply_results.ml +++ b/src/proto_alpha/lib_protocol/apply_results.ml @@ -101,6 +101,11 @@ type _ successful_manager_operation_result = consumed_gas : Gas.Arith.fp; } -> Kind.tx_rollup_submit_batch successful_manager_operation_result + | Tx_rollup_commit_result : { + balance_updates : Receipt.balance_updates; + consumed_gas : Gas.Arith.fp; + } + -> Kind.tx_rollup_commit successful_manager_operation_result | Sc_rollup_originate_result : { balance_updates : Receipt.balance_updates; address : Sc_rollup.Address.t; @@ -569,6 +574,32 @@ module Manager_result = struct Tx_rollup_submit_batch_result {balance_updates; consumed_gas = consumed_milligas}) + let[@coq_axiom_with_reason "gadt"] tx_rollup_commit_case = + make + ~op_case:Operation.Encoding.Manager_operations.tx_rollup_commit_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)) + ~iselect:(function + | Internal_operation_result + (({operation = Tx_rollup_commit _; _} as op), res) -> + Some (op, res) + | _ -> None) + ~select:(function + | Successful_manager_result (Tx_rollup_commit_result _ as op) -> Some op + | _ -> None) + ~kind:Kind.Tx_rollup_commit_manager_kind + ~proj:(function + | Tx_rollup_commit_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)) ; + Tx_rollup_commit_result + {balance_updates; consumed_gas = consumed_milligas}) + let[@coq_axiom_with_reason "gadt"] sc_rollup_originate_case = make ~op_case:Operation.Encoding.Manager_operations.sc_rollup_originate_case @@ -773,6 +804,9 @@ let equal_manager_kind : Kind.Tx_rollup_submit_batch_manager_kind ) -> Some Eq | (Kind.Tx_rollup_submit_batch_manager_kind, _) -> None + | (Kind.Tx_rollup_commit_manager_kind, Kind.Tx_rollup_commit_manager_kind) -> + Some Eq + | (Kind.Tx_rollup_commit_manager_kind, _) -> None | ( Kind.Sc_rollup_originate_manager_kind, Kind.Sc_rollup_originate_manager_kind ) -> Some Eq @@ -1154,6 +1188,17 @@ module Encoding = struct Some (op, res) | _ -> None) + let[@coq_axiom_with_reason "gadt"] tx_rollup_commit_case = + make_manager_case + Operation.Encoding.tx_rollup_commit_case + Manager_result.tx_rollup_commit_case + (function + | Contents_and_result + ((Manager_operation {operation = Tx_rollup_commit _; _} as op), res) + -> + Some (op, res) + | _ -> None) + let[@coq_axiom_with_reason "gadt"] sc_rollup_originate_case = make_manager_case Operation.Encoding.sc_rollup_originate_case @@ -1213,6 +1258,7 @@ let contents_result_encoding = make set_deposits_limit_case; make tx_rollup_origination_case; make tx_rollup_submit_batch_case; + make tx_rollup_commit_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -1258,6 +1304,7 @@ let contents_and_result_encoding = make set_deposits_limit_case; make tx_rollup_origination_case; make tx_rollup_submit_batch_case; + make tx_rollup_commit_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -1589,6 +1636,31 @@ let kind_equal : } ) -> Some Eq | (Manager_operation {operation = Tx_rollup_submit_batch _; _}, _) -> None + | ( Manager_operation {operation = Tx_rollup_commit _; _}, + Manager_operation_result + {operation_result = Applied (Tx_rollup_commit_result _); _} ) -> + Some Eq + | ( Manager_operation {operation = Tx_rollup_commit _; _}, + Manager_operation_result + {operation_result = Backtracked (Tx_rollup_commit_result _, _); _} ) -> + Some Eq + | ( Manager_operation {operation = Tx_rollup_commit _; _}, + Manager_operation_result + { + operation_result = + Failed (Alpha_context.Kind.Tx_rollup_commit_manager_kind, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Tx_rollup_commit _; _}, + Manager_operation_result + { + operation_result = + Skipped Alpha_context.Kind.Tx_rollup_commit_manager_kind; + _; + } ) -> + Some Eq + | (Manager_operation {operation = Tx_rollup_commit _; _}, _) -> None | ( Manager_operation {operation = Sc_rollup_originate _; _}, Manager_operation_result {operation_result = Applied (Sc_rollup_originate_result _); _} ) -> diff --git a/src/proto_alpha/lib_protocol/apply_results.mli b/src/proto_alpha/lib_protocol/apply_results.mli index 47a7cafc2952f35e210985d6b64eab4d0bc5e406..7fcdc6979d045abe94cd51d1709fcef7e2e00bf3 100644 --- a/src/proto_alpha/lib_protocol/apply_results.mli +++ b/src/proto_alpha/lib_protocol/apply_results.mli @@ -174,6 +174,11 @@ and _ successful_manager_operation_result = consumed_gas : Gas.Arith.fp; } -> Kind.tx_rollup_submit_batch successful_manager_operation_result + | Tx_rollup_commit_result : { + balance_updates : Receipt.balance_updates; + consumed_gas : Gas.Arith.fp; + } + -> Kind.tx_rollup_commit successful_manager_operation_result | Sc_rollup_originate_result : { balance_updates : Receipt.balance_updates; address : Sc_rollup.Address.t; diff --git a/src/proto_alpha/lib_protocol/dune.inc b/src/proto_alpha/lib_protocol/dune.inc index e093fe6def6677a911b91dd31bc58cbc3816e7ae..986aabbc1ad691520df67d2ed287b433fbb1a49b 100644 --- a/src/proto_alpha/lib_protocol/dune.inc +++ b/src/proto_alpha/lib_protocol/dune.inc @@ -72,6 +72,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end tx_rollup_state_repr.mli tx_rollup_state_repr.ml tx_rollup_message_repr.mli tx_rollup_message_repr.ml tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml + tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml roll_repr_legacy.mli roll_repr_legacy.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml @@ -124,6 +125,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end global_constants_storage.mli global_constants_storage.ml tx_rollup_state_storage.mli tx_rollup_state_storage.ml tx_rollup_inbox_storage.mli tx_rollup_inbox_storage.ml + tx_rollup_commitments_storage.mli tx_rollup_commitments_storage.ml tx_rollup_storage.mli tx_rollup_storage.ml sc_rollup_storage.mli sc_rollup_storage.ml alpha_context.mli alpha_context.ml @@ -226,6 +228,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end tx_rollup_state_repr.mli tx_rollup_state_repr.ml tx_rollup_message_repr.mli tx_rollup_message_repr.ml tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml + tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml roll_repr_legacy.mli roll_repr_legacy.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml @@ -278,6 +281,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end global_constants_storage.mli global_constants_storage.ml tx_rollup_state_storage.mli tx_rollup_state_storage.ml tx_rollup_inbox_storage.mli tx_rollup_inbox_storage.ml + tx_rollup_commitments_storage.mli tx_rollup_commitments_storage.ml tx_rollup_storage.mli tx_rollup_storage.ml sc_rollup_storage.mli sc_rollup_storage.ml alpha_context.mli alpha_context.ml @@ -380,6 +384,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end tx_rollup_state_repr.mli tx_rollup_state_repr.ml tx_rollup_message_repr.mli tx_rollup_message_repr.ml tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml + tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml roll_repr_legacy.mli roll_repr_legacy.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml @@ -432,6 +437,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end global_constants_storage.mli global_constants_storage.ml tx_rollup_state_storage.mli tx_rollup_state_storage.ml tx_rollup_inbox_storage.mli tx_rollup_inbox_storage.ml + tx_rollup_commitments_storage.mli tx_rollup_commitments_storage.ml tx_rollup_storage.mli tx_rollup_storage.ml sc_rollup_storage.mli sc_rollup_storage.ml alpha_context.mli alpha_context.ml @@ -556,6 +562,7 @@ include Tezos_raw_protocol_alpha.Main Tx_rollup_state_repr Tx_rollup_message_repr Tx_rollup_inbox_repr + Tx_rollup_commitments_repr Roll_repr_legacy Vote_repr Block_header_repr @@ -608,6 +615,7 @@ include Tezos_raw_protocol_alpha.Main Global_constants_storage Tx_rollup_state_storage Tx_rollup_inbox_storage + Tx_rollup_commitments_storage Tx_rollup_storage Sc_rollup_storage Alpha_context @@ -751,6 +759,7 @@ include Tezos_raw_protocol_alpha.Main tx_rollup_state_repr.mli tx_rollup_state_repr.ml tx_rollup_message_repr.mli tx_rollup_message_repr.ml tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml + tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml roll_repr_legacy.mli roll_repr_legacy.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml @@ -803,6 +812,7 @@ include Tezos_raw_protocol_alpha.Main global_constants_storage.mli global_constants_storage.ml tx_rollup_state_storage.mli tx_rollup_state_storage.ml tx_rollup_inbox_storage.mli tx_rollup_inbox_storage.ml + tx_rollup_commitments_storage.mli tx_rollup_commitments_storage.ml tx_rollup_storage.mli tx_rollup_storage.ml sc_rollup_storage.mli sc_rollup_storage.ml alpha_context.mli alpha_context.ml diff --git a/src/proto_alpha/lib_protocol/operation_repr.ml b/src/proto_alpha/lib_protocol/operation_repr.ml index 24b882ddbcf6c94324ae920914e38f87f3a1d1db..965ed457cb3d9945a1a14f42f84d2fba5cf9df8f 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.ml +++ b/src/proto_alpha/lib_protocol/operation_repr.ml @@ -75,6 +75,8 @@ module Kind = struct type tx_rollup_submit_batch = Tx_rollup_submit_batch_kind + type tx_rollup_commit = Tx_rollup_commit_kind + type sc_rollup_originate = Sc_rollup_originate_kind type sc_rollup_add_messages = Sc_rollup_add_messages_kind @@ -88,6 +90,7 @@ module Kind = struct | Set_deposits_limit_manager_kind : set_deposits_limit manager | Tx_rollup_origination_manager_kind : tx_rollup_origination manager | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager + | Tx_rollup_commit_manager_kind : tx_rollup_commit manager | Sc_rollup_originate_manager_kind : sc_rollup_originate manager | Sc_rollup_add_messages_manager_kind : sc_rollup_add_messages manager end @@ -273,6 +276,11 @@ and _ manager_operation = content : string; } -> Kind.tx_rollup_submit_batch manager_operation + | Tx_rollup_commit : { + tx_rollup : Tx_rollup_repr.t; + commitment : Tx_rollup_commitments_repr.Commitment.t; + } + -> Kind.tx_rollup_commit manager_operation | Sc_rollup_originate : { kind : Sc_rollup_repr.Kind.t; boot_sector : Sc_rollup_repr.PVM.boot_sector; @@ -296,6 +304,7 @@ let manager_kind : type kind. kind manager_operation -> kind Kind.manager = | Set_deposits_limit _ -> Kind.Set_deposits_limit_manager_kind | Tx_rollup_origination -> Kind.Tx_rollup_origination_manager_kind | Tx_rollup_submit_batch _ -> Kind.Tx_rollup_submit_batch_manager_kind + | Tx_rollup_commit _ -> Kind.Tx_rollup_commit_manager_kind | Sc_rollup_originate _ -> Kind.Sc_rollup_originate_manager_kind | Sc_rollup_add_messages _ -> Kind.Sc_rollup_add_messages_manager_kind @@ -543,6 +552,26 @@ module Encoding = struct Tx_rollup_submit_batch {tx_rollup; content}); } + let[@coq_axiom_with_reason "gadt"] tx_rollup_commit_case = + MCase + { + tag = tx_rollup_operation_tag_offset + 2; + name = "tx_rollup_commit"; + encoding = + obj2 + (req "rollup" Tx_rollup_repr.encoding) + (req "commitment" Tx_rollup_commitments_repr.Commitment.encoding); + select = + (function + | Manager (Tx_rollup_commit _ as op) -> Some op | _ -> None); + proj = + (function + | Tx_rollup_commit {tx_rollup; commitment} -> (tx_rollup, commitment)); + inj = + (fun (tx_rollup, commitment) -> + Tx_rollup_commit {tx_rollup; commitment}); + } + let[@coq_axiom_with_reason "gadt"] sc_rollup_originate_case = MCase { @@ -603,6 +632,7 @@ module Encoding = struct make set_deposits_limit_case; make tx_rollup_origination_case; make tx_rollup_submit_batch_case; + make tx_rollup_commit_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -913,6 +943,11 @@ module Encoding = struct (tx_rollup_operation_tag_offset + 1) Manager_operations.tx_rollup_submit_batch_case + let tx_rollup_commit_case = + make_manager_case + (tx_rollup_operation_tag_offset + 2) + Manager_operations.tx_rollup_commit_case + let sc_rollup_originate_case = make_manager_case sc_rollup_operation_origination_tag @@ -953,6 +988,7 @@ module Encoding = struct make register_global_constant_case; make tx_rollup_origination_case; make tx_rollup_submit_batch_case; + make tx_rollup_commit_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -1158,6 +1194,8 @@ let equal_manager_operation_kind : | (Tx_rollup_origination, _) -> None | (Tx_rollup_submit_batch _, Tx_rollup_submit_batch _) -> Some Eq | (Tx_rollup_submit_batch _, _) -> None + | (Tx_rollup_commit _, Tx_rollup_commit _) -> Some Eq + | (Tx_rollup_commit _, _) -> None | (Sc_rollup_originate _, Sc_rollup_originate _) -> Some Eq | (Sc_rollup_originate _, _) -> None | (Sc_rollup_add_messages _, Sc_rollup_add_messages _) -> Some Eq @@ -1270,6 +1308,9 @@ let internal_manager_operation_size (type a) (op : a manager_operation) = | Tx_rollup_submit_batch _ -> (* Tx_rollup_submit_batch operation can’t occur as internal operations *) assert false + | Tx_rollup_commit _ -> + (* Tx_rollup_commit operation can’t occur as internal operations *) + assert false let packed_internal_operation_in_memory_size : packed_internal_operation -> nodes_and_size = function diff --git a/src/proto_alpha/lib_protocol/operation_repr.mli b/src/proto_alpha/lib_protocol/operation_repr.mli index 022990d2e9774868b9fbd852d1824122a7a3eff2..df21d962d1e03465ec9be25d2b1c287d31dffccf 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.mli +++ b/src/proto_alpha/lib_protocol/operation_repr.mli @@ -101,6 +101,8 @@ module Kind : sig type tx_rollup_submit_batch = Tx_rollup_submit_batch_kind + type tx_rollup_commit = Tx_rollup_commit_kind + type sc_rollup_originate = Sc_rollup_originate_kind type sc_rollup_add_messages = Sc_rollup_add_messages_kind @@ -114,6 +116,7 @@ module Kind : sig | Set_deposits_limit_manager_kind : set_deposits_limit manager | Tx_rollup_origination_manager_kind : tx_rollup_origination manager | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager + | Tx_rollup_commit_manager_kind : tx_rollup_commit manager | Sc_rollup_originate_manager_kind : sc_rollup_originate manager | Sc_rollup_add_messages_manager_kind : sc_rollup_add_messages manager end @@ -252,6 +255,11 @@ and _ manager_operation = content : string; } -> Kind.tx_rollup_submit_batch manager_operation + | Tx_rollup_commit : { + tx_rollup : Tx_rollup_repr.t; + commitment : Tx_rollup_commitments_repr.Commitment.t; + } + -> Kind.tx_rollup_commit manager_operation | Sc_rollup_originate : { kind : Sc_rollup_repr.Kind.t; boot_sector : Sc_rollup_repr.PVM.boot_sector; @@ -386,6 +394,8 @@ module Encoding : sig val tx_rollup_submit_batch_case : Kind.tx_rollup_submit_batch Kind.manager case + val tx_rollup_commit_case : Kind.tx_rollup_commit Kind.manager case + val sc_rollup_originate_case : Kind.sc_rollup_originate Kind.manager case val sc_rollup_add_messages_case : @@ -419,6 +429,8 @@ module Encoding : sig val tx_rollup_submit_batch_case : Kind.tx_rollup_submit_batch case + val tx_rollup_commit_case : Kind.tx_rollup_commit case + val sc_rollup_originate_case : Kind.sc_rollup_originate case val sc_rollup_add_messages_case : Kind.sc_rollup_add_messages case diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index 5422c58667981f50b02353c039b6429b85119723..088fa6dd2befc8a599aab4f36312bd0cfc20a350 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -1695,6 +1695,24 @@ module Tx_rollup = struct let encoding = Data_encoding.list Tx_rollup_message_repr.hash_encoding end) + + module Level_indexed_context = + Make_indexed_subcontext + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["tx_rollup_level"] + end)) + (Pair + (Make_index + (Raw_level_repr.Index)) + (Make_index (Tx_rollup_repr.Index))) + + module Commitment_list = + Level_indexed_context.Make_carbonated_map + (struct + let name = ["commitment_list"] + end) + (Tx_rollup_commitments_repr) end module Sc_rollup = struct diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index 8b64604818ed68e77438400b781b2c9a47592eda..e3f6680aca930ea9d879810a2775b02b9a210e7f 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -736,6 +736,18 @@ module Tx_rollup : sig init:'a -> f:(Tx_rollup_repr.t -> 'a -> 'a Lwt.t) -> 'a Lwt.t + + (* A list of the commitments for each rollup and level. The level, + here, is the level committed to (not the level the commitment was + submitted). Usually this list will be of size zero or one, since + there is only one valid commitment for each level. The list is + ordered by reverse priority -- that is, the first-submitted one is + last. *) + module Commitment_list : + Non_iterable_indexed_carbonated_data_storage + with type key = Raw_level_repr.t * Tx_rollup_repr.t + and type value = Tx_rollup_commitments_repr.t + and type t := Raw_context.t end module Sc_rollup : sig diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.ml b/src/proto_alpha/lib_protocol/test/helpers/block.ml index 8cfc77e35431f24e43610bfa3b1e9bdaab1f1ab3..9361b7c5a5d78f2d811d8a4e27d6266dbdf8963d 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/block.ml @@ -700,8 +700,9 @@ let bake_n_with_all_balance_updates ?(baking_mode = Application) ?policy match r with | Reveal_result _ | Delegation_result _ | Set_deposits_limit_result _ | Tx_rollup_origination_result _ - | Tx_rollup_submit_batch_result _ | Sc_rollup_originate_result _ - | Sc_rollup_add_messages_result _ -> + | Tx_rollup_submit_batch_result _ | Tx_rollup_commit_result _ + | Sc_rollup_originate_result _ | Sc_rollup_add_messages_result _ + -> balance_updates_rev | Transaction_result (Transaction_to_contract_result {balance_updates; _}) @@ -732,6 +733,7 @@ let bake_n_with_origination_results ?(baking_mode = Application) ?policy n b = | Successful_manager_result (Set_deposits_limit_result _) | Successful_manager_result (Tx_rollup_origination_result _) | Successful_manager_result (Tx_rollup_submit_batch_result _) + | Successful_manager_result (Tx_rollup_commit_result _) | Successful_manager_result (Sc_rollup_originate_result _) | Successful_manager_result (Sc_rollup_add_messages_result _) -> 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 3b53df76d0547183cfb9cd33dc0edcb5f9a6bc69..c01cb68c8b852ec1b1d29435b98204894355311a 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -538,3 +538,18 @@ let sc_rollup_origination ?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 tx_rollup_commit ?counter ?fee ?gas_limit ?storage_limit ctxt + (source : Contract.t) (tx_rollup : Tx_rollup.t) + (commitment : Tx_rollup_commitments.Commitment.t) = + manager_operation + ?counter + ?fee + ?gas_limit + ?storage_limit + ~source + ctxt + (Tx_rollup_commit {tx_rollup; commitment}) + >>=? 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 ea51e7812696763df295ea7ed5554dbac50b1d87..6902adbea622977ec51921b42158d9baead15365 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -230,3 +230,16 @@ val sc_rollup_origination : Sc_rollup.Kind.t -> Sc_rollup.PVM.boot_sector -> packed_operation tzresult Lwt.t + +(** [tx_rollup_commit ctxt source tx_rollup commitment] Commits to a tx + rollup state. *) +val tx_rollup_commit : + ?counter:Z.t -> + ?fee:Tez.tez -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + Context.t -> + Contract.t -> + Tx_rollup.t -> + Tx_rollup_commitments.Commitment.t -> + Operation.packed tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index 689139b49ce5114050cedebc9b8f80883c4a1a9d..cd6916e763f9a5979869d9caecbcb0d2edd76e4c 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -136,10 +136,40 @@ let init_originate_and_submit ?(batch = String.make 5 'c') () = Block.bake ~operation b >>=? fun b -> return ((contract, balance), state, tx_rollup, b) +let commitment_hash_testable = + Alcotest.testable + Tx_rollup_commitments.Commitment_hash.pp + Tx_rollup_commitments.Commitment_hash.( = ) + +let public_key_hash_testable = + Alcotest.testable Signature.Public_key_hash.pp Signature.Public_key_hash.( = ) + +let raw_level_testable = Alcotest.testable Raw_level.pp Raw_level.( = ) + +let rng_state = Random.State.make_self_init () + +let gen_l2_account () = + let seed = + Bytes.init 32 (fun _ -> char_of_int @@ Random.State.int rng_state 255) + in + let secret_key = Bls12_381.Signature.generate_sk seed in + let public_key = Bls12_381.Signature.derive_pk secret_key in + (secret_key, public_key, Tx_rollup_l2_address.of_bls_pk public_key) + +let is_implicit_exn x = + match Alpha_context.Contract.is_implicit x with + | Some x -> x + | None -> raise (Invalid_argument "is_implicit_exn") + let assert_ok res = match res with Ok r -> r | Error _ -> assert false let raw_level level = assert_ok @@ Raw_level.of_int32 level +let public_key_hash_exn contract = + match Contract.is_implicit contract with + | None -> assert false + | Some public_key_hash -> public_key_hash + (** ---- TESTS -------------------------------------------------------------- *) (** [test_origination] originates a transaction rollup and checks that @@ -539,6 +569,208 @@ let test_inbox_linked_list () = Assert.is_none ~loc:__LOC__ ~pp:Raw_level.pp before >>=? fun () -> assert_level_equals ~loc:__LOC__ (raw_level 4l) after >>=? fun () -> return () +(** [test_commitment_duplication] originates a rollup, and makes a + commitment. It attempts to have a second contract make the same + ommitment, and ensures that this fails (and the second contract is + not charged). It also tests that the same contract can't submit + a different commitment*) +let test_commitment_duplication () = + context_init 2 >>=? fun (b, contracts) -> + let contract1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + let contract2 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 1 + in + let pkh1 = public_key_hash_exn contract1 in + originate b contract1 >>=? fun (b, tx_rollup) -> + Context.Contract.balance (B b) contract1 >>=? fun balance -> + Context.Contract.balance (B b) contract2 >>=? fun balance2 -> + (* In order to have a permissible commitment, we need a transaction. *) + let contents = "batch" in + Op.tx_rollup_submit_batch (B b) contract1 tx_rollup contents + >>=? fun operation -> + Block.bake ~operation b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + let level_opt = + Raw_level.pred (Level.current (Incremental.alpha_ctxt i)).level + in + (* Need an extra block here to ensure finality *) + Incremental.finalize_block i >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + let level = + match level_opt with None -> assert false | Some level -> level + in + let batches : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '0'}] + in + let commitment : Tx_rollup_commitments.Commitment.t = + {level; batches; predecessor = None} + in + let submitted_level = (Level.current (Incremental.alpha_ctxt i)).level in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + let cost = Tez.of_mutez_exn 10_000_000_000L in + Assert.balance_was_debited ~loc:__LOC__ (I i) contract1 balance cost + >>= fun _ -> + (* Successfully fail to submit a duplicate commitment *) + Op.tx_rollup_commit (I i) contract2 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error + (Tx_rollup_commitments.Commitment_hash_already_submitted as e) + :: _ -> + Assert.test_error_encodings e ; + return_unit + | t -> failwith "Unexpected error: %a" Error_monad.pp_print_trace t) + >>=? fun i -> + let batches2 : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '1'}] + in + let commitment2 : Tx_rollup_commitments.Commitment.t = + {level; batches = batches2; predecessor = None} + in + (* Successfully fail to submit a different commitment from contract1 *) + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment2 >>=? fun op -> + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error + (Tx_rollup_commitments.Two_commitments_from_one_committer as e) + :: _ -> + Assert.test_error_encodings e ; + return_unit + | t -> failwith "Unexpected error: %a" Error_monad.pp_print_trace t) + >>=? fun i -> + let batches3 : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '1'}; {root = Bytes.make 20 '2'}] + in + let commitment3 : Tx_rollup_commitments.Commitment.t = + {level; batches = batches3; predecessor = None} + in + (* Successfully fail to submit a different commitment from contract2 *) + Op.tx_rollup_commit (I i) contract2 tx_rollup commitment3 >>=? fun op -> + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error + (Tx_rollup_commitments.Wrong_batch_count as e) + :: _ -> + Assert.test_error_encodings e ; + return_unit + | t -> failwith "Unexpected error: %a" Error_monad.pp_print_trace t) + >>=? fun i -> + (* No charge. *) + Assert.balance_was_debited ~loc:__LOC__ (I i) contract2 balance2 Tez.zero + >>=? fun () -> + let ctxt = Incremental.alpha_ctxt i in + wrap (Tx_rollup_commitments.get_commitments ctxt tx_rollup level) + >>=? fun (_, commitments) -> + (Alcotest.(check int "Expected one commitment" 1 (List.length commitments)) ; + let expected_hash = Tx_rollup_commitments.Commitment.hash commitment in + match List.nth commitments 0 with + | None -> assert false + | Some {hash; committer; submitted_at; _} -> + Alcotest.( + check commitment_hash_testable "Commitment hash" expected_hash hash) ; + + Alcotest.(check public_key_hash_testable "Committer" pkh1 committer) ; + + Alcotest.( + check raw_level_testable "Submitted" submitted_level submitted_at) ; + return ()) + >>=? fun () -> + ignore i ; + return () + +let make_transactions_in tx_rollup contract blocks b = + let contents = "batch " in + let rec aux cur blocks b = + match blocks with + | [] -> return b + | hd :: rest when hd = cur -> + Op.tx_rollup_submit_batch (B b) contract tx_rollup contents + >>=? fun operation -> + Block.bake ~operation b >>=? fun b -> aux (cur + 1) rest b + | blocks -> + let operations = [] in + Block.bake ~operations b >>=? fun b -> aux (cur + 1) blocks b + in + aux 2 blocks b + +let assert_ok res = match res with Ok r -> r | Error _ -> assert false + +let raw_level level = assert_ok @@ Raw_level.of_int32 level + +(** [test_commitment_predecessor] tests commitment predecessor edge cases *) +let test_commitment_predecessor () = + context_init 1 >>=? fun (b, contracts) -> + let contract1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + originate b contract1 >>=? fun (b, tx_rollup) -> + (* Transactions in blocks 2, 3, 6 *) + make_transactions_in tx_rollup contract1 [2; 3; 6] b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + (* Check error: Commitment with predecessor for first block *) + let batches : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '0'}] + in + let some_hash = + Tx_rollup_commitments.Commitment_hash.of_bytes_exn + (Bytes.of_string "tcu1deadbeefdeadbeefdeadbeefdead") + in + let commitment : Tx_rollup_commitments.Commitment.t = + {level = raw_level 1l; batches; predecessor = Some some_hash} + in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> + let error = + Tx_rollup_inbox.Tx_rollup_inbox_does_not_exist (tx_rollup, raw_level 1l) + in + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error e :: _ when e = error -> + Assert.test_error_encodings error ; + return_unit + | _ -> failwith "Need to check commitment predecessor") + >>=? fun i -> + (* Commitment without predecessor for block with predecessor*) + let commitment : Tx_rollup_commitments.Commitment.t = + {level = raw_level 3l; batches; predecessor = None} + in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error + (Tx_rollup_commitments.Wrong_commitment_predecessor_level as e) + :: _ -> + Assert.test_error_encodings e ; + return_unit + | _ -> failwith "Need to check commitment predecessor") + >>=? fun i -> + (* Commitment refers to a predecessor which does not exist *) + let commitment : Tx_rollup_commitments.Commitment.t = + {level = raw_level 3l; batches; predecessor = Some some_hash} + in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error + (Tx_rollup_commitments.Missing_commitment_predecessor as e) + :: _ -> + Assert.test_error_encodings e ; + return_unit + | _ -> failwith "Need to check commitment predecessor") + >>=? fun i -> + (* Try to commit to an empty level between full ones *) + let commitment : Tx_rollup_commitments.Commitment.t = + {level = raw_level 5l; batches; predecessor = Some some_hash} + in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> + let error = + Tx_rollup_inbox.Tx_rollup_inbox_does_not_exist (tx_rollup, raw_level 5l) + in + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error e :: _ when e = error -> + Assert.test_error_encodings e ; + return_unit + | _ -> failwith "Need to check for skipped levels") + >>=? fun i -> + ignore i ; + return () + let tests = [ Tztest.tztest @@ -567,4 +799,9 @@ let tests = test_inbox_too_big; Tztest.tztest "Test finalization" `Quick test_finalization; Tztest.tztest "Test inbox linked list" `Quick test_inbox_linked_list; + Tztest.tztest "Smoke test commitment" `Quick test_commitment_duplication; + Tztest.tztest + "Test commitment predecessor edge cases" + `Quick + test_commitment_predecessor; ] diff --git a/src/proto_alpha/lib_protocol/ticket_operations_diff.ml b/src/proto_alpha/lib_protocol/ticket_operations_diff.ml index dffafb095a9cd3c5a3ed1e722e951139afa22a12..45d3384efc4b80a56a762b870837b3dd11b97c22 100644 --- a/src/proto_alpha/lib_protocol/ticket_operations_diff.ml +++ b/src/proto_alpha/lib_protocol/ticket_operations_diff.ml @@ -248,6 +248,7 @@ let tickets_of_operation ctxt | Set_deposits_limit _ -> return (None, ctxt) | Tx_rollup_origination -> return (None, ctxt) | Tx_rollup_submit_batch _ -> return (None, ctxt) + | Tx_rollup_commit _ -> return (None, ctxt) | Sc_rollup_originate {kind = _; boot_sector = _} -> return (None, ctxt) | Sc_rollup_add_messages {rollup = _; messages = _} -> return (None, ctxt) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml new file mode 100644 index 0000000000000000000000000000000000000000..a61cfddc8b67373a527648a6f9ca2d5624f07d8f --- /dev/null +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml @@ -0,0 +1,319 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Marigold *) +(* Copyright (c) 2022 Nomadic Labs *) +(* Copyright (c) 2022 Oxhead Alpha *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += (* `Branch *) Commitment_hash_already_submitted + +type error += (* `Branch *) Two_commitments_from_one_committer + +type error += (* `Branch *) Wrong_commitment_predecessor_level + +type error += (* `Temporary *) Missing_commitment_predecessor + +type error += (* `Branch *) Wrong_batch_count + +type error += (* `Temporary *) Commitment_too_early + +let () = + let open Data_encoding in + (* Commitment_hash_already_submitted *) + register_error_kind + `Temporary + ~id:"Commitment_hash_already_submitted" + ~title:"Someone already made this commitment" + ~description:"The requested commitment is a duplicate" + unit + (function Commitment_hash_already_submitted -> Some () | _ -> None) + (fun () -> Commitment_hash_already_submitted) ; + (* Two_commitments_from_one_committer *) + register_error_kind + `Temporary + ~id:"Two_commitments_from_one_committer" + ~title:"This contract already made a different commitment at this level" + ~description: + "This contract already made a different commitment at this level" + unit + (function Two_commitments_from_one_committer -> Some () | _ -> None) + (fun () -> Two_commitments_from_one_committer) ; + (* Wrong_commitment_predecessor_level *) + register_error_kind + `Temporary + ~id:"Wrong_commitment_predecessor_level" + ~title:"This commitment's predecessor is invalid" + ~description: + "This commitment has predecessor but shouldn't, or doesn't but should" + unit + (function Wrong_commitment_predecessor_level -> Some () | _ -> None) + (fun () -> Wrong_commitment_predecessor_level) ; + (* Missing_commitment_predecessor *) + register_error_kind + `Temporary + ~id:"Missing_commitment_predecessor" + ~title:"This commitment refers to a predecessor that doesn't exist" + ~description:"This commitment refers to a predecessor that doesn't exist" + unit + (function Missing_commitment_predecessor -> Some () | _ -> None) + (fun () -> Missing_commitment_predecessor) ; + (* Wrong_batch_count *) + register_error_kind + `Temporary + ~id:"Wrong_batch_count" + ~title:"This commitment has the wrong number of batches" + ~description: + "This commitment has a different number of batches than its inbox" + unit + (function Wrong_batch_count -> Some () | _ -> None) + (fun () -> Wrong_batch_count) ; + (* Commitment_too_early *) + register_error_kind + `Temporary + ~id:"Commitment_too_early" + ~title:"This commitment is for a level that hasn't finished yet" + ~description:"This commitment is for a level that hasn't finished yet" + unit + (function Commitment_too_early -> Some () | _ -> None) + (fun () -> Commitment_too_early) + +let compare_or cmp c1 c2 f = match cmp c1 c2 with 0 -> f () | diff -> diff + +module Commitment_hash = struct + let commitment_hash = "\017\249\195\013" (* toc1(54) *) + + module H = + Blake2B.Make + (Base58) + (struct + let name = "Commitment_hash" + + let title = "A commitment ID" + + let b58check_prefix = commitment_hash + + let size = Some 32 + end) + + include H + + let () = Base58.check_encoded_prefix b58check_encoding "toc1" 54 + + include Path_encoding.Make_hex (H) + + let rpc_arg = + let construct = Data_encoding.Binary.to_string_exn encoding in + let destruct str = + Option.value_e ~error:"Failed to decode commitment" + @@ Data_encoding.Binary.of_string_opt encoding str + in + RPC_arg.make + ~descr:"A tx_rollup commitment." + ~name:"tx_rollup_commitment" + ~construct + ~destruct + () +end + +module Commitment = struct + type batch_commitment = { + (* TODO: add effects and replace bytes with Irmin: + https://gitlab.com/tezos/tezos/-/issues/2444 + *) + root : bytes; + } + + module Batch = struct + type t = batch_commitment + + let encoding = + Data_encoding.( + conv (fun {root} -> root) (fun root -> {root}) (obj1 (req "root" bytes))) + + let pp : Format.formatter -> t -> unit = + fun fmt {root} -> Hex.pp fmt (Hex.of_bytes root) + + include Compare.Make (struct + type nonrec t = t + + let compare {root = root1} {root = root2} = Bytes.compare root1 root2 + end) + end + + let batch_commitment_equal : batch_commitment -> batch_commitment -> bool = + Batch.equal + + type t = { + level : Raw_level_repr.t; + batches : batch_commitment list; + predecessor : Commitment_hash.t option; + } + + include Compare.Make (struct + type nonrec t = t + + module Compare_root_list = Compare.List (Batch) + + let compare r1 r2 = + compare_or Raw_level_repr.compare r1.level r2.level (fun () -> + compare_or Compare_root_list.compare r1.batches r2.batches (fun () -> + Option.compare + Commitment_hash.compare + r1.predecessor + r2.predecessor)) + end) + + let pp : Format.formatter -> t -> unit = + fun fmt t -> + Format.fprintf + fmt + "commitment %a : batches = %a predecessor %a" + Raw_level_repr.pp + t.level + (Format.pp_print_list Batch.pp) + t.batches + (Format.pp_print_option Commitment_hash.pp) + t.predecessor + + (* FIXME/TORU: https://gitlab.com/tezos/tezos/-/issues/2470 + + This encoding is not bounded, and maybe it is an issue. *) + let encoding = + let open Data_encoding in + conv + (fun {level; batches; predecessor} -> (level, batches, predecessor)) + (fun (level, batches, predecessor) -> {level; batches; predecessor}) + (obj3 + (req "level" Raw_level_repr.encoding) + (req "batches" (list Batch.encoding)) + (req "predecessor" (option Commitment_hash.encoding))) + + let hash t = + let to_bytes_exn = Data_encoding.Binary.to_bytes_exn in + let level_bytes = to_bytes_exn Raw_level_repr.encoding t.level in + let predecessor_bytes = + Option.fold + ~none:Bytes.empty + ~some:(fun pred -> Commitment_hash.to_bytes pred) + t.predecessor + in + let batches_bytes = + to_bytes_exn (Data_encoding.list Batch.encoding) t.batches + in + Commitment_hash.hash_bytes [level_bytes; predecessor_bytes; batches_bytes] + + module Index = struct + type t = Commitment_hash.t + + let path_length = 1 + + let to_path c l = + let raw_key = + Data_encoding.Binary.to_bytes_exn Commitment_hash.encoding c + in + let (`Hex key) = Hex.of_bytes raw_key in + key :: l + + let of_path = function + | [key] -> + Option.bind + (Hex.to_bytes (`Hex key)) + (Data_encoding.Binary.of_bytes_opt Commitment_hash.encoding) + | _ -> None + + let rpc_arg = Commitment_hash.rpc_arg + + let encoding = Commitment_hash.encoding + + let compare = Commitment_hash.compare + end +end + +type pending_commitment = { + commitment : Commitment.t; + hash : Commitment_hash.t; + committer : Signature.Public_key_hash.t; + submitted_at : Raw_level_repr.t; +} + +let pp_pending_commitment : Format.formatter -> pending_commitment -> unit = + fun fmt {commitment; hash; committer; submitted_at} -> + Format.fprintf + fmt + "pending_commitment %a; hash = %a; committer = %a; submitted_at = %a" + Commitment.pp + commitment + Commitment_hash.pp + hash + Signature.Public_key_hash.pp_short + committer + Raw_level_repr.pp + submitted_at + +let pending_commitment_encoding = + Data_encoding.( + conv + (fun {commitment; committer; submitted_at; _} -> + (commitment, committer, submitted_at)) + (fun (commitment, committer, submitted_at) -> + let hash = Commitment.hash commitment in + {hash; commitment; committer; submitted_at}) + (obj3 + (req "commitment" Commitment.encoding) + (req "commiter" Signature.Public_key_hash.encoding) + (req "submitted_at" Raw_level_repr.encoding))) + +type t = pending_commitment list + +let encoding = Data_encoding.(list pending_commitment_encoding) + +let empty = [] + +let commitment_exists : t -> Commitment_hash.t -> bool = + fun t hash -> List.exists (fun {hash = h; _} -> Commitment_hash.(h = hash)) t + +let commitment_with_committer_exists : t -> Signature.Public_key_hash.t -> bool + = + fun t contract -> + List.exists + (fun {committer; _} -> Signature.Public_key_hash.(committer = contract)) + t + +let append : + t -> + Signature.Public_key_hash.t -> + Commitment.t -> + Raw_level_repr.t -> + t tzresult = + fun t contract commitment level -> + let hash = Commitment.hash commitment in + (* We fail if this contract already has a commitment at this level, + or if anyone has already made this commitment at this level; a + bond entitles you to at most one commitment per level. *) + error_when (commitment_exists t hash) Commitment_hash_already_submitted + >>? fun () -> + error_when + (commitment_with_committer_exists t contract) + Two_commitments_from_one_committer + >>? fun () -> + Ok ({hash; commitment; committer = contract; submitted_at = level} :: t) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli new file mode 100644 index 0000000000000000000000000000000000000000..876019cd65adfe0c3084c860e8e0a5069413b02e --- /dev/null +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli @@ -0,0 +1,116 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Marigold *) +(* Copyright (c) 2022 Nomadic Labs *) +(* Copyright (c) 2022 Oxhead Alpha *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += (* `Branch *) Commitment_hash_already_submitted + +type error += (* `Branch *) Two_commitments_from_one_committer + +type error += (* `Branch *) Wrong_commitment_predecessor_level + +type error += (* `Temporary *) Missing_commitment_predecessor + +type error += (* `Branch *) Wrong_batch_count + +type error += (* `Temporary *) Commitment_too_early + +(** A specialized Blake2B implementation for hashing commitments with + "toc1" as a base58 prefix *) +module Commitment_hash : sig + val commitment_hash : string + + include S.HASH +end + +module Commitment : sig + type batch_commitment = {root : bytes} + + val batch_commitment_equal : batch_commitment -> batch_commitment -> bool + + (* A commitment describes the interpretation of the messages stored in the + inbox of a particular [level], on top of a particular layer-2 context. + + It includes one Merkle tree root for each of the [batches]. It has + a [predecessor], which is the identifier of the commitment for the + previous inbox. The [predecessor] is used to get the Merkle root of the + layer-2 context before any inboxes are processed. If [predecessor] is + [None], the commitment is for the first inbox with messages in this rollup, + and the initial Merkle root is the empty tree. *) + type t = { + level : Raw_level_repr.t; + batches : batch_commitment list; + predecessor : Commitment_hash.t option; + } + + val ( = ) : t -> t -> bool + + val pp : Format.formatter -> t -> unit + + val encoding : t Data_encoding.t + + val hash : t -> Commitment_hash.t + + module Index : Storage_description.INDEX with type t = Commitment_hash.t +end + +(** A [pending_commitment] is a commitment which has not yet become final. + The [hash] is redundant and is only stored to reduce computation. We + track the level that the commitment was submitted at; after the + finality period, it will become final if it has not been rejected. *) +type pending_commitment = { + commitment : Commitment.t; + hash : Commitment_hash.t; + committer : Signature.Public_key_hash.t; + submitted_at : Raw_level_repr.t; +} + +val pp_pending_commitment : Format.formatter -> pending_commitment -> unit + +(** This is the type that we store, ordered in reverse priority order. *) +type t = pending_commitment list + +val encoding : t Data_encoding.t + +val empty : t + +(** [append commitments contract commitment level] appends a new commitment + to a list of commitments. It fails if the same account has already + made a commitment, or if any account has already made this exact + commitment. *) +val append : + t -> + Signature.Public_key_hash.t -> + Commitment.t -> + Raw_level_repr.t -> + t tzresult + +(** [commitment_exists commitments t hash] returns true if a commitment + with this [hash] already exists in this list. *) +val commitment_exists : t -> Commitment_hash.t -> bool + +(** [commitment_with_committer_exists commitments t contract] returns + true if a commitment by this [contract] already exists in this list. *) +val commitment_with_committer_exists : t -> Signature.Public_key_hash.t -> bool diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml new file mode 100644 index 0000000000000000000000000000000000000000..25eb0118554d29a711456c23f3b5030d76cabcb0 --- /dev/null +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml @@ -0,0 +1,94 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* Copyright (c) 2021 Nomadic Labs *) +(* Copyright (c) 2021 Oxhead Alpha *) +(* *) +(* 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 just_ctxt (ctxt, _, _) = ctxt + +open Tx_rollup_commitments_repr + +(** Return commitments in the order that they werre submitted *) +let get_or_empty_commitments : + Raw_context.t -> + Raw_level_repr.t * Tx_rollup_repr.t -> + (Raw_context.t * Tx_rollup_commitments_repr.t) tzresult Lwt.t = + fun ctxt key -> + Storage.Tx_rollup.Commitment_list.find ctxt key >|=? fun (ctxt, commitment) -> + Option.fold + commitment + ~none:(ctxt, Tx_rollup_commitments_repr.empty) + ~some:(fun l -> (ctxt, List.rev l)) + +let get_prev_level ctxt tx_rollup level = + Tx_rollup_inbox_storage.get_adjacent_levels ctxt level tx_rollup + >|=? fun (ctxt, predecessor_level, _) -> (ctxt, predecessor_level) + +let check_commitment_predecessor_hash ctxt tx_rollup (commitment : Commitment.t) + = + let level = commitment.level in + (* Check that level has the correct predecessor *) + get_prev_level ctxt tx_rollup level >>=? fun (ctxt, predecessor_level) -> + match (predecessor_level, commitment.predecessor) with + | (None, None) -> return ctxt + | (Some _, None) | (None, Some _) -> fail Wrong_commitment_predecessor_level + | (Some predecessor_level, Some hash) -> + (* The predecessor level must include this commitment*) + get_or_empty_commitments ctxt (predecessor_level, tx_rollup) + >>=? fun (ctxt, predecesor_commitments) -> + fail_unless + (Tx_rollup_commitments_repr.commitment_exists + predecesor_commitments + hash) + Missing_commitment_predecessor + >>=? fun () -> return ctxt + +let add_commitment ctxt tx_rollup contract (commitment : Commitment.t) = + let key = (commitment.level, tx_rollup) in + get_or_empty_commitments ctxt key >>=? fun (ctxt, pending) -> + Tx_rollup_inbox_storage.get ctxt ~level:(`Level commitment.level) tx_rollup + >>=? fun (ctxt, inbox) -> + let expected_len = List.length inbox.contents in + let actual_len = List.length commitment.batches in + fail_unless Compare.Int.(expected_len = actual_len) Wrong_batch_count + >>=? fun () -> + check_commitment_predecessor_hash ctxt tx_rollup commitment >>=? fun ctxt -> + Tx_rollup_commitments_repr.append + pending + contract + commitment + (Raw_context.current_level ctxt).level + >>?= fun new_pending -> + Storage.Tx_rollup.Commitment_list.add ctxt key new_pending >|=? just_ctxt + +let get_commitments : + Raw_context.t -> + Tx_rollup_repr.t -> + Raw_level_repr.t -> + (Raw_context.t * Tx_rollup_commitments_repr.t) tzresult Lwt.t = + fun ctxt tx_rollup level -> + Storage.Tx_rollup.State.find ctxt tx_rollup >>=? fun (ctxt, state) -> + match state with + | None -> fail @@ Tx_rollup_state_storage.Tx_rollup_does_not_exist tx_rollup + | Some _ -> get_or_empty_commitments ctxt (level, tx_rollup) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli new file mode 100644 index 0000000000000000000000000000000000000000..7b633f8a23b0c862831c79b08d679092a09246d3 --- /dev/null +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli @@ -0,0 +1,51 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Marigold *) +(* Copyright (c) 2021 Nomadic Labs *) +(* Copyright (c) 2021 Oxhead Alpha *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** This module introduces various functions to manipulate the storage related + to commitments for transaction rollups. *) + +(** [add_commitment context tx_rollup contract commitment] adds a + commitment to a rollup. *) + +(** FIXME/TORU: https://gitlab.com/tezos/tezos/-/issues/2468 + + We should document better the invariants. *) +val add_commitment : + Raw_context.t -> + Tx_rollup_repr.t -> + Signature.Public_key_hash.t -> + Tx_rollup_commitments_repr.Commitment.t -> + Raw_context.t tzresult Lwt.t + +(** [get_commitments context tx_rollup level] returns the list of + non-rejected commitments for a rollup at a level, first-submitted + first. *) +val get_commitments : + Raw_context.t -> + Tx_rollup_repr.t -> + Raw_level_repr.t -> + (Raw_context.t * Tx_rollup_commitments_repr.t) tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml index 2570f9c4938b28e334021936f23e4894b2a451ad..f3d49fc15e0b67c69714c0066272b899db822529 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml @@ -99,7 +99,7 @@ let append_message : >>=? fun () -> Storage.Tx_rollup.Inbox_rev_contents.find (ctxt, level) rollup >>=? fun (ctxt, mcontents) -> - (* FIXME: https://gitlab.com/tezos/tezos/-/issues/2408 + (* FIXME/TORU: https://gitlab.com/tezos/tezos/-/issues/2408 Carbonate hashing the message. *) Storage.Tx_rollup.Inbox_rev_contents.add (ctxt, level) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_services.ml b/src/proto_alpha/lib_protocol/tx_rollup_services.ml index ea51929bbd0b0ab9347c566be73b4f5fc6dc8c2d..dbf1b21d702b0822b21077265aa3e502cd2a0fe8 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_services.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_services.ml @@ -44,6 +44,13 @@ module S = struct ~query:RPC_query.empty ~output:Tx_rollup_inbox.encoding RPC_path.(custom_root /: Tx_rollup.rpc_arg / "inbox") + + let commitments = + RPC_service.get_service + ~description:"." + ~query:RPC_query.empty + ~output:Tx_rollup_commitments.encoding + RPC_path.(custom_root /: Tx_rollup.rpc_arg / "commitments") end let register () = @@ -51,10 +58,16 @@ let register () = opt_register1 ~chunked:false S.state (fun ctxt tx_rollup () () -> Tx_rollup_state.find ctxt tx_rollup >|=? snd) ; opt_register1 ~chunked:false S.inbox (fun ctxt tx_rollup () () -> - Tx_rollup_inbox.find ctxt tx_rollup ~level:`Current >|=? snd) + Tx_rollup_inbox.find ctxt tx_rollup ~level:`Current >|=? snd) ; + register1 ~chunked:false S.commitments (fun ctxt tx_rollup () () -> + let level = (Level.current ctxt).level in + Tx_rollup_commitments.get_commitments ctxt tx_rollup level >|=? snd) let state ctxt block tx_rollup = RPC_context.make_call1 S.state ctxt block tx_rollup () () let inbox ctxt block tx_rollup = RPC_context.make_call1 S.inbox ctxt block tx_rollup () () + +let commitments ctxt block tx_rollup = + RPC_context.make_call1 S.commitments ctxt block tx_rollup () () diff --git a/src/proto_alpha/lib_protocol/tx_rollup_services.mli b/src/proto_alpha/lib_protocol/tx_rollup_services.mli index 3e4f932d703c649bd0a907a374de8c52f182be1e..d881aa5b9689f401a7680c2d244ec1b107e102e3 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_services.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_services.mli @@ -43,4 +43,10 @@ val inbox : Tx_rollup.t -> Tx_rollup_inbox.t shell_tzresult Lwt.t +val commitments : + 'a #RPC_context.simple -> + 'a -> + Tx_rollup.t -> + Tx_rollup_commitments.t shell_tzresult Lwt.t + val register : unit -> unit diff --git a/tezt/_regressions/rpc/alpha.client.mempool.out b/tezt/_regressions/rpc/alpha.client.mempool.out index 9cb3e38877cb5c102be32fe230a028c88df3a564..b40904976ebd1a953fe58befff6fe46f73a45cca 100644 --- a/tezt/_regressions/rpc/alpha.client.mempool.out +++ b/tezt/_regressions/rpc/alpha.client.mempool.out @@ -657,6 +657,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "additionalProperties": false }, "definitions": { + "Commitment_hash": { + "title": "A commitment ID (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "Context_hash": { "title": "A hash of context (Base58Check-encoded)", "$ref": "#/definitions/unistring" @@ -1877,6 +1881,91 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_commit", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_commit" + ] + }, + "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/alpha.tx_rollup_id" + }, + "commitment": { + "type": "object", + "properties": { + "level": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "batches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "root": { + "type": "string", + "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" + } + }, + "required": [ + "root" + ], + "additionalProperties": false + } + }, + "predecessor": { + "oneOf": [ + { + "title": "Some", + "$ref": "#/definitions/Commitment_hash" + }, + { + "title": "None", + "type": "null" + } + ] + } + }, + "required": [ + "predecessor", + "batches", + "level" + ], + "additionalProperties": false + } + }, + "required": [ + "commitment", + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", @@ -2385,6 +2474,127 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ] } }, + { + "description": { + "title": "X_5" + }, + "encoding": { + "tag_size": "Uint8", + "kind": { + "kind": "Dynamic" + }, + "cases": [ + { + "tag": 0, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "layout": { + "kind": "Zero_width" + }, + "kind": "anon", + "data_kind": { + "size": 0, + "kind": "Float" + } + } + ], + "name": "None" + }, + { + "tag": 1, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "Commitment_hash", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 32, + "kind": "Float" + }, + "kind": "named" + } + ], + "name": "Some" + } + ] + } + }, + { + "description": { + "title": "X_3" + }, + "encoding": { + "fields": [ + { + "name": "level", + "layout": { + "size": "Int32", + "kind": "Int" + }, + "data_kind": { + "size": 4, + "kind": "Float" + }, + "kind": "named" + }, + { + "kind": "dyn", + "num_fields": 1, + "size": "Uint30" + }, + { + "name": "batches", + "layout": { + "layout": { + "name": "fitness.elem", + "kind": "Ref" + }, + "kind": "Seq" + }, + "data_kind": { + "kind": "Variable" + }, + "kind": "named" + }, + { + "name": "predecessor", + "layout": { + "name": "X_5", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + } + ] + } + }, { "description": { "title": "alpha.scripted.contracts" @@ -2695,7 +2905,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' }, { "description": { - "title": "X_3" + "title": "X_6" }, "encoding": { "fields": [ @@ -4110,7 +4320,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' { "name": "parameters", "layout": { - "name": "X_3", + "name": "X_6", "kind": "Ref" }, "data_kind": { @@ -4675,6 +4885,102 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "name": "Tx_rollup_submit_batch" }, + { + "tag": 152, + "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": "commitment", + "layout": { + "name": "X_3", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + } + ], + "name": "Tx_rollup_commit" + }, { "tag": 200, "fields": [ @@ -5587,6 +5893,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' } ], "definitions": { + "Commitment_hash": { + "title": "A commitment ID (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "Context_hash": { "title": "A hash of context (Base58Check-encoded)", "$ref": "#/definitions/unistring" @@ -6807,6 +7117,91 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_commit", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_commit" + ] + }, + "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/alpha.tx_rollup_id" + }, + "commitment": { + "type": "object", + "properties": { + "level": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "batches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "root": { + "type": "string", + "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" + } + }, + "required": [ + "root" + ], + "additionalProperties": false + } + }, + "predecessor": { + "oneOf": [ + { + "title": "Some", + "$ref": "#/definitions/Commitment_hash" + }, + { + "title": "None", + "type": "null" + } + ] + } + }, + "required": [ + "predecessor", + "batches", + "level" + ], + "additionalProperties": false + } + }, + "required": [ + "commitment", + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", diff --git a/tezt/_regressions/rpc/alpha.proxy.mempool.out b/tezt/_regressions/rpc/alpha.proxy.mempool.out index 70b727ab130c8a2a9246de110544fd48ffe31a15..4877da35785eb3db14eb1075684f3e82c7563c0e 100644 --- a/tezt/_regressions/rpc/alpha.proxy.mempool.out +++ b/tezt/_regressions/rpc/alpha.proxy.mempool.out @@ -678,6 +678,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "additionalProperties": false }, "definitions": { + "Commitment_hash": { + "title": "A commitment ID (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "Context_hash": { "title": "A hash of context (Base58Check-encoded)", "$ref": "#/definitions/unistring" @@ -1898,6 +1902,91 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_commit", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_commit" + ] + }, + "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/alpha.tx_rollup_id" + }, + "commitment": { + "type": "object", + "properties": { + "level": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "batches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "root": { + "type": "string", + "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" + } + }, + "required": [ + "root" + ], + "additionalProperties": false + } + }, + "predecessor": { + "oneOf": [ + { + "title": "Some", + "$ref": "#/definitions/Commitment_hash" + }, + { + "title": "None", + "type": "null" + } + ] + } + }, + "required": [ + "predecessor", + "batches", + "level" + ], + "additionalProperties": false + } + }, + "required": [ + "commitment", + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", @@ -2406,6 +2495,127 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ] } }, + { + "description": { + "title": "X_5" + }, + "encoding": { + "tag_size": "Uint8", + "kind": { + "kind": "Dynamic" + }, + "cases": [ + { + "tag": 0, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "layout": { + "kind": "Zero_width" + }, + "kind": "anon", + "data_kind": { + "size": 0, + "kind": "Float" + } + } + ], + "name": "None" + }, + { + "tag": 1, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "Commitment_hash", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 32, + "kind": "Float" + }, + "kind": "named" + } + ], + "name": "Some" + } + ] + } + }, + { + "description": { + "title": "X_3" + }, + "encoding": { + "fields": [ + { + "name": "level", + "layout": { + "size": "Int32", + "kind": "Int" + }, + "data_kind": { + "size": 4, + "kind": "Float" + }, + "kind": "named" + }, + { + "kind": "dyn", + "num_fields": 1, + "size": "Uint30" + }, + { + "name": "batches", + "layout": { + "layout": { + "name": "fitness.elem", + "kind": "Ref" + }, + "kind": "Seq" + }, + "data_kind": { + "kind": "Variable" + }, + "kind": "named" + }, + { + "name": "predecessor", + "layout": { + "name": "X_5", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + } + ] + } + }, { "description": { "title": "alpha.scripted.contracts" @@ -2716,7 +2926,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' }, { "description": { - "title": "X_3" + "title": "X_6" }, "encoding": { "fields": [ @@ -4131,7 +4341,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' { "name": "parameters", "layout": { - "name": "X_3", + "name": "X_6", "kind": "Ref" }, "data_kind": { @@ -4696,6 +4906,102 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "name": "Tx_rollup_submit_batch" }, + { + "tag": 152, + "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": "commitment", + "layout": { + "name": "X_3", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + } + ], + "name": "Tx_rollup_commit" + }, { "tag": 200, "fields": [ @@ -5608,6 +5914,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' } ], "definitions": { + "Commitment_hash": { + "title": "A commitment ID (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "Context_hash": { "title": "A hash of context (Base58Check-encoded)", "$ref": "#/definitions/unistring" @@ -6828,6 +7138,91 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_commit", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_commit" + ] + }, + "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/alpha.tx_rollup_id" + }, + "commitment": { + "type": "object", + "properties": { + "level": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "batches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "root": { + "type": "string", + "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" + } + }, + "required": [ + "root" + ], + "additionalProperties": false + } + }, + "predecessor": { + "oneOf": [ + { + "title": "Some", + "$ref": "#/definitions/Commitment_hash" + }, + { + "title": "None", + "type": "null" + } + ] + } + }, + "required": [ + "predecessor", + "batches", + "level" + ], + "additionalProperties": false + } + }, + "required": [ + "commitment", + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index 95f33af6096da894481bf4b9a9876f00c2c4f1eb..46070d9232ca4f2a2431a376c21151cb2c39b3fc 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -640,6 +640,11 @@ module Tx_rollup = struct let spawn_get_inbox ?endpoint ?hooks ?chain ?block ~tx_rollup client = let path = sub_path ?chain ?block ~tx_rollup "inbox" in Client.spawn_rpc ?endpoint ?hooks GET path client + + let get_commitments ?endpoint ?hooks ?(chain = "main") ?(block = "head") + ~tx_rollup client = + let path = sub_path ~chain ~block ~tx_rollup "commitments" in + Client.rpc ?endpoint ?hooks GET path client end module Sc_rollup = struct diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index 7e5709a73eaa37c31181a1e98dcf5a29825f99b7..0ca2f70cc4dfe5d02fb5d649e04fa0b3021cbed2 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -1006,6 +1006,16 @@ module Tx_rollup : sig tx_rollup:string -> Client.t -> Process.t + + (** Call RPC /chain/[chain]/blocks/[block]/context/[rollup_hash]/commitments *) + val get_commitments : + ?endpoint:Client.endpoint -> + ?hooks:Process.hooks -> + ?chain:string -> + ?block:string -> + tx_rollup:string -> + Client.t -> + JSON.t Lwt.t end module Sc_rollup : sig