diff --git a/src/proto_alpha/bin_sc_rollup_node/inbox.ml b/src/proto_alpha/bin_sc_rollup_node/inbox.ml index 0d5a5f2fd3ab0d842a6c8deec05c0eb5e2482ec5..a51e99ba6f721d78c27500ada5370279a150fce6 100644 --- a/src/proto_alpha/bin_sc_rollup_node/inbox.ml +++ b/src/proto_alpha/bin_sc_rollup_node/inbox.ml @@ -116,7 +116,12 @@ let process_head Node_context.({cctxt; rollup_address; _} as node_ctxt) store let*! messages_tree = State.get_message_tree store predecessor in let*? level = Raw_level.of_int32 level in let* messages_tree, history, inbox = - Store.Inbox.add_messages history inbox level messages messages_tree + Store.Inbox.add_external_messages + history + inbox + level + messages + messages_tree in let*! () = State.set_message_tree store head_hash messages_tree in let*! () = State.add_inbox store head_hash inbox in diff --git a/src/proto_alpha/lib_benchmarks_proto/sc_rollup_benchmarks.ml b/src/proto_alpha/lib_benchmarks_proto/sc_rollup_benchmarks.ml index 50dcf071e28fb15a23c82bd7e178fd468bc66457..b1e7a8b0995026cd2fa8b4e3ebfa3244ab1e1cf7 100644 --- a/src/proto_alpha/lib_benchmarks_proto/sc_rollup_benchmarks.ml +++ b/src/proto_alpha/lib_benchmarks_proto/sc_rollup_benchmarks.ml @@ -28,8 +28,8 @@ open Protocol (** A benchmark for estimating the gas cost of {!Sc_rollup_costs.Constants.cost_update_num_and_size_of_messages}. This value is used to consume the gas cost internally in - [Sc_rollup_storage.add_messages], when computing the number of messages - and their totla size in bytes to be added to an inbox. + [Sc_rollup_storage.add_external_messages], when computing the number of + messages and their total size in bytes to be added to an inbox. *) module Sc_rollup_update_num_and_size_of_messages_benchmark = struct @@ -122,18 +122,20 @@ module Sc_rollup_update_num_and_size_of_messages_benchmark = struct (Model.For_codegen cost_update_num_and_size_ofmessages_model) end -(** A benchmark for estimating the gas cost of {!Sc_rollup.Inbox.add_messages}. +(** A benchmark for estimating the gas cost of + {!Sc_rollup.Inbox.add_external_messages}. + We assume that the cost (in gas) [cost(n, l)] of adding a message of size [n] bytes, at level [l] since the origination of the rollup, satisfies the equation [cost(n) = c_0 + c_1 * n + c_2 * log(l)], where [c_0], [c_1] and [c_2] are the values to be benchmarked. We also assume that the cost of adding messages [m_0, ..., m_k] to a rollup inbox is - [\sum_{i=0}^{k} cost(|m_i|, l)]. Thus, it suffices to estimate the cost of + [\sum_{i=0}^{k} cost(|m_i|, l)]. Thus, it suffices to estimate the cost of adding a single message to the inbox. *) -module Sc_rollup_add_messages_benchmark = struct - let name = "Sc_rollup_inbox_add_message" +module Sc_rollup_add_external_messages_benchmark = struct + let name = "Sc_rollup_inbox_add_external_message" let info = "Estimating the costs of adding a single message to a rollup inbox" @@ -226,7 +228,10 @@ module Sc_rollup_add_messages_benchmark = struct let open Lwt_result_syntax in let+ inbox, _, ctxt = Lwt.map Environment.wrap_tzresult - @@ Sc_rollup_inbox_storage.add_messages ctxt rollup ["CAFEBABE"] + @@ Sc_rollup_inbox_storage.add_external_messages + ctxt + rollup + ["CAFEBABE"] in let ctxt = Raw_context.Internal_for_tests.add_level ctxt 1 in (inbox, ctxt) @@ -262,7 +267,7 @@ module Sc_rollup_add_messages_benchmark = struct let workload = {message_length; level = last_level_int} in let closure () = ignore - (Sc_rollup_inbox_repr.add_messages_no_history + (Sc_rollup_inbox_repr.add_external_messages_no_history inbox last_level [message] @@ -277,7 +282,9 @@ module Sc_rollup_add_messages_benchmark = struct Registration.register_for_codegen name (Model.For_codegen add_message_model) end -let () = Registration_helpers.register (module Sc_rollup_add_messages_benchmark) +let () = + Registration_helpers.register + (module Sc_rollup_add_external_messages_benchmark) let () = Registration_helpers.register diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index dc7ae1075e91f5508fa031149fd555309cacd6d5..f6a0dd2487ba3c2aa6de573ba53152a347a64202 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -37,8 +37,17 @@ "Level_repr", "Script_repr", "Cache_memory_helpers", + "Seed_repr", + "Sampler", + "Voting_period_repr", + "Ticket_hash_repr", + "Contract_repr", + "Indexable", + "Entrypoint_repr", "Sc_rollup_repr", "Sc_rollup_tick_repr", + "Sc_rollup_inbox_message_repr", + "Sc_rollup_outbox_message_repr", "Sc_rollup_PVM_sem", "Sc_rollup_arith", "Sc_rollups", @@ -47,13 +56,6 @@ "Sc_rollup_commitment_repr", "Sc_rollup_proof_repr", "Sc_rollup_game_repr", - "Seed_repr", - "Sampler", - "Voting_period_repr", - "Ticket_hash_repr", - "Contract_repr", - "Indexable", - "Entrypoint_repr", "Tx_rollup_level_repr", "Tx_rollup_l2_proof", "Tx_rollup_l2_address", diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 8c4eba3f826810342ff1997781cd74f13dda906a..e3e86ad2e665d2791648f956b7292a4b26414bf0 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -62,6 +62,7 @@ module Sc_rollup = struct module Inbox = struct include Sc_rollup_inbox_repr include Sc_rollup_inbox_storage + module Message = Sc_rollup_inbox_message_repr end module Proof = Sc_rollup_proof_repr @@ -76,6 +77,11 @@ module Sc_rollup = struct module Refutation_storage = Sc_rollup_refutation_storage include Sc_rollup_storage include Sc_rollups + + module Outbox = struct + include Sc_rollup_storage.Outbox + module Message = Sc_rollup_outbox_message_repr + end end module Dal = struct diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index cf1bdb92daccf0b5640269b1c7ebad2f142f2c58..f2916423eb7063b2da3e4e66a43b0824c38932eb 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2664,6 +2664,23 @@ module Sc_rollup : sig module Inbox : sig type t + (** See {!Sc_rollup_inbox_message_repr}. *) + module Message : sig + type t = + | Internal of { + payload : Script.expr; + sender : Contract.t; + source : Signature.public_key_hash; + } + | External of string + + val to_bytes : t -> string tzresult + + module Internal_for_tests : sig + val of_bytes : string -> t tzresult + end + end + val pp : Format.formatter -> t -> unit val encoding : t Data_encoding.t @@ -2693,7 +2710,7 @@ module Sc_rollup : sig val history_at_genesis : bound:int64 -> history - val add_messages : + val add_external_messages : history -> t -> Raw_level.t -> @@ -2701,7 +2718,7 @@ module Sc_rollup : sig messages -> (messages * history * t) tzresult Lwt.t - val add_messages_no_history : + val add_external_messages_no_history : t -> Raw_level.t -> string list -> @@ -2750,7 +2767,7 @@ module Sc_rollup : sig module MakeHashingScheme (Tree : TREE) : MerkelizedOperations with type tree = Tree.tree - val add_messages : + val add_external_messages : context -> rollup -> string list -> (t * Z.t * context) tzresult Lwt.t val inbox : context -> rollup -> (t * context) tzresult Lwt.t @@ -2897,6 +2914,23 @@ module Sc_rollup : sig val get_boot_sector : context -> t -> string tzresult Lwt.t module Outbox : sig + (** See {!Sc_rollup_outbox_message_repr}. *) + module Message : sig + type transaction = { + unparsed_parameters : Script.expr; + destination : Contract_hash.t; + entrypoint : Entrypoint.t; + } + + type t = Atomic_transaction_batch of {transactions : transaction list} + + val of_bytes : string -> t tzresult + + module Internal_for_tests : sig + val to_bytes : t -> string tzresult + end + end + val record_applied_message : context -> t -> diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 7d7351d04ab4d1cd8c7474467ffa829904ea73b0..9bfb36220003988bf64002a562e52d86656e02ca 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1785,7 +1785,7 @@ let apply_external_manager_operation_content : in return (ctxt, result, []) | Sc_rollup_add_messages {rollup; messages} -> - Sc_rollup.Inbox.add_messages ctxt rollup messages + Sc_rollup.Inbox.add_external_messages ctxt rollup messages >>=? fun (inbox_after, _size, ctxt) -> let consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt in let result = Sc_rollup_add_messages_result {consumed_gas; inbox_after} in diff --git a/src/proto_alpha/lib_protocol/dune b/src/proto_alpha/lib_protocol/dune index 76288263427d62a8f7348246df5b0e8f4b5da1a6..a4f03327ebc982ee50fb25b349d869e42ca43cd7 100644 --- a/src/proto_alpha/lib_protocol/dune +++ b/src/proto_alpha/lib_protocol/dune @@ -68,8 +68,17 @@ Level_repr Script_repr Cache_memory_helpers + Seed_repr + Sampler + Voting_period_repr + Ticket_hash_repr + Contract_repr + Indexable + Entrypoint_repr Sc_rollup_repr Sc_rollup_tick_repr + Sc_rollup_inbox_message_repr + Sc_rollup_outbox_message_repr Sc_rollup_PVM_sem Sc_rollup_arith Sc_rollups @@ -78,13 +87,6 @@ Sc_rollup_commitment_repr Sc_rollup_proof_repr Sc_rollup_game_repr - Seed_repr - Sampler - Voting_period_repr - Ticket_hash_repr - Contract_repr - Indexable - Entrypoint_repr Tx_rollup_level_repr Tx_rollup_l2_proof Tx_rollup_l2_address @@ -285,8 +287,17 @@ level_repr.ml level_repr.mli script_repr.ml script_repr.mli cache_memory_helpers.ml + seed_repr.ml seed_repr.mli + sampler.ml sampler.mli + voting_period_repr.ml voting_period_repr.mli + ticket_hash_repr.ml ticket_hash_repr.mli + contract_repr.ml contract_repr.mli + indexable.ml indexable.mli + entrypoint_repr.ml entrypoint_repr.mli sc_rollup_repr.ml sc_rollup_repr.mli sc_rollup_tick_repr.ml sc_rollup_tick_repr.mli + sc_rollup_inbox_message_repr.ml sc_rollup_inbox_message_repr.mli + sc_rollup_outbox_message_repr.ml sc_rollup_outbox_message_repr.mli sc_rollup_PVM_sem.ml sc_rollup_arith.ml sc_rollup_arith.mli sc_rollups.ml sc_rollups.mli @@ -295,13 +306,6 @@ sc_rollup_commitment_repr.ml sc_rollup_commitment_repr.mli sc_rollup_proof_repr.ml sc_rollup_proof_repr.mli sc_rollup_game_repr.ml sc_rollup_game_repr.mli - seed_repr.ml seed_repr.mli - sampler.ml sampler.mli - voting_period_repr.ml voting_period_repr.mli - ticket_hash_repr.ml ticket_hash_repr.mli - contract_repr.ml contract_repr.mli - indexable.ml indexable.mli - entrypoint_repr.ml entrypoint_repr.mli tx_rollup_level_repr.ml tx_rollup_level_repr.mli tx_rollup_l2_proof.ml tx_rollup_l2_proof.mli tx_rollup_l2_address.ml tx_rollup_l2_address.mli @@ -489,8 +493,17 @@ level_repr.ml level_repr.mli script_repr.ml script_repr.mli cache_memory_helpers.ml + seed_repr.ml seed_repr.mli + sampler.ml sampler.mli + voting_period_repr.ml voting_period_repr.mli + ticket_hash_repr.ml ticket_hash_repr.mli + contract_repr.ml contract_repr.mli + indexable.ml indexable.mli + entrypoint_repr.ml entrypoint_repr.mli sc_rollup_repr.ml sc_rollup_repr.mli sc_rollup_tick_repr.ml sc_rollup_tick_repr.mli + sc_rollup_inbox_message_repr.ml sc_rollup_inbox_message_repr.mli + sc_rollup_outbox_message_repr.ml sc_rollup_outbox_message_repr.mli sc_rollup_PVM_sem.ml sc_rollup_arith.ml sc_rollup_arith.mli sc_rollups.ml sc_rollups.mli @@ -499,13 +512,6 @@ sc_rollup_commitment_repr.ml sc_rollup_commitment_repr.mli sc_rollup_proof_repr.ml sc_rollup_proof_repr.mli sc_rollup_game_repr.ml sc_rollup_game_repr.mli - seed_repr.ml seed_repr.mli - sampler.ml sampler.mli - voting_period_repr.ml voting_period_repr.mli - ticket_hash_repr.ml ticket_hash_repr.mli - contract_repr.ml contract_repr.mli - indexable.ml indexable.mli - entrypoint_repr.ml entrypoint_repr.mli tx_rollup_level_repr.ml tx_rollup_level_repr.mli tx_rollup_l2_proof.ml tx_rollup_l2_proof.mli tx_rollup_l2_address.ml tx_rollup_l2_address.mli @@ -713,8 +719,17 @@ level_repr.ml level_repr.mli script_repr.ml script_repr.mli cache_memory_helpers.ml + seed_repr.ml seed_repr.mli + sampler.ml sampler.mli + voting_period_repr.ml voting_period_repr.mli + ticket_hash_repr.ml ticket_hash_repr.mli + contract_repr.ml contract_repr.mli + indexable.ml indexable.mli + entrypoint_repr.ml entrypoint_repr.mli sc_rollup_repr.ml sc_rollup_repr.mli sc_rollup_tick_repr.ml sc_rollup_tick_repr.mli + sc_rollup_inbox_message_repr.ml sc_rollup_inbox_message_repr.mli + sc_rollup_outbox_message_repr.ml sc_rollup_outbox_message_repr.mli sc_rollup_PVM_sem.ml sc_rollup_arith.ml sc_rollup_arith.mli sc_rollups.ml sc_rollups.mli @@ -723,13 +738,6 @@ sc_rollup_commitment_repr.ml sc_rollup_commitment_repr.mli sc_rollup_proof_repr.ml sc_rollup_proof_repr.mli sc_rollup_game_repr.ml sc_rollup_game_repr.mli - seed_repr.ml seed_repr.mli - sampler.ml sampler.mli - voting_period_repr.ml voting_period_repr.mli - ticket_hash_repr.ml ticket_hash_repr.mli - contract_repr.ml contract_repr.mli - indexable.ml indexable.mli - entrypoint_repr.ml entrypoint_repr.mli tx_rollup_level_repr.ml tx_rollup_level_repr.mli tx_rollup_l2_proof.ml tx_rollup_l2_proof.mli tx_rollup_l2_address.ml tx_rollup_l2_address.mli @@ -933,8 +941,17 @@ level_repr.ml level_repr.mli script_repr.ml script_repr.mli cache_memory_helpers.ml + seed_repr.ml seed_repr.mli + sampler.ml sampler.mli + voting_period_repr.ml voting_period_repr.mli + ticket_hash_repr.ml ticket_hash_repr.mli + contract_repr.ml contract_repr.mli + indexable.ml indexable.mli + entrypoint_repr.ml entrypoint_repr.mli sc_rollup_repr.ml sc_rollup_repr.mli sc_rollup_tick_repr.ml sc_rollup_tick_repr.mli + sc_rollup_inbox_message_repr.ml sc_rollup_inbox_message_repr.mli + sc_rollup_outbox_message_repr.ml sc_rollup_outbox_message_repr.mli sc_rollup_PVM_sem.ml sc_rollup_arith.ml sc_rollup_arith.mli sc_rollups.ml sc_rollups.mli @@ -943,13 +960,6 @@ sc_rollup_commitment_repr.ml sc_rollup_commitment_repr.mli sc_rollup_proof_repr.ml sc_rollup_proof_repr.mli sc_rollup_game_repr.ml sc_rollup_game_repr.mli - seed_repr.ml seed_repr.mli - sampler.ml sampler.mli - voting_period_repr.ml voting_period_repr.mli - ticket_hash_repr.ml ticket_hash_repr.mli - contract_repr.ml contract_repr.mli - indexable.ml indexable.mli - entrypoint_repr.ml entrypoint_repr.mli tx_rollup_level_repr.ml tx_rollup_level_repr.mli tx_rollup_l2_proof.ml tx_rollup_l2_proof.mli tx_rollup_l2_address.ml tx_rollup_l2_address.mli diff --git a/src/proto_alpha/lib_protocol/sc_rollup_costs.ml b/src/proto_alpha/lib_protocol/sc_rollup_costs.ml index a870d9f0009386c6b8d3efaa4be0a609b6ea09e6..a4212a0842211f13fd547330f5c75dbdcbf06cf5 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_costs.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_costs.ml @@ -49,12 +49,12 @@ end (* We assume that the gas cost of adding messages [[ m_1; ... ; m_n]] at level [l] is linear in the sum of lengths of the messages, and it is logarithmic - in [l]. That is, [cost_add_messages([m_1; .. ; m_n], l)] = + in [l]. That is, [cost_add_external_messages([m_1; .. ; m_n], l)] = `n * cost_add_message_base + cost_add_message_per_bytes * \sum_{i=1}^n length(m_i) + cost_add_inbox_per_level * l`. *) -let cost_add_messages ~num_messages ~total_messages_size l = +let cost_add_external_messages ~num_messages ~total_messages_size l = let open S_syntax in let log_level = if Int32.equal l Int32.zero then Saturation_repr.safe_int 0 diff --git a/src/proto_alpha/lib_protocol/sc_rollup_costs.mli b/src/proto_alpha/lib_protocol/sc_rollup_costs.mli index 979441eaac2f6e2a61a3fa70f2cfffe553dda42d..2c33496f10788a9de5067795f54aca78e27f9758 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_costs.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_costs.mli @@ -41,9 +41,9 @@ end val is_valid_parameters_ty_cost : ty_size:'a Saturation_repr.t -> Saturation_repr.may_saturate Saturation_repr.t -(** [cost_add_messages ~num_messages ~total_messages_length level] +(** [cost_add_external_messages ~num_messages ~total_messages_length level] returns the cost of adding [num_messages] with total messages size - [total_messages_size] to a sc-rollup inbox at level [level]. This + [total_messages_size] to a sc-rollup inbox at level [level]. This function is used internally in the [Sc_rollup_storage] module. *) -val cost_add_messages : +val cost_add_external_messages : num_messages:int -> total_messages_size:int -> int32 -> Gas_limit_repr.cost diff --git a/src/proto_alpha/lib_protocol/sc_rollup_inbox_message_repr.ml b/src/proto_alpha/lib_protocol/sc_rollup_inbox_message_repr.ml new file mode 100644 index 0000000000000000000000000000000000000000..d13fa6c9a6fa7f14b2624b19b5af3838f648c151 --- /dev/null +++ b/src/proto_alpha/lib_protocol/sc_rollup_inbox_message_repr.ml @@ -0,0 +1,106 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 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. *) +(* *) +(*****************************************************************************) + +type error += + | (* `Permanent *) Error_encode_inbox_message + | (* `Permanent *) Error_decode_inbox_message + +let () = + let open Data_encoding in + let msg = + "Failed to encode a rollup management protocol inbox message value" + in + register_error_kind + `Permanent + ~id:"sc_rollup_inbox_message_repr.error_encoding_inbox_message" + ~title:msg + ~pp:(fun fmt () -> Format.fprintf fmt "%s" msg) + ~description:msg + unit + (function Error_encode_inbox_message -> Some () | _ -> None) + (fun () -> Error_encode_inbox_message) ; + let msg = + "Failed to decode a rollup management protocol inbox message value" + in + register_error_kind + `Permanent + ~id:"sc_rollup_inbox_message_repr.error_decoding_inbox_message" + ~title:msg + ~pp:(fun fmt () -> Format.fprintf fmt "%s" msg) + ~description:msg + unit + (function Error_decode_inbox_message -> Some () | _ -> None) + (fun () -> Error_decode_inbox_message) + +type t = + | Internal of { + payload : Script_repr.expr; + (** A Micheline value containing the parameters passed to the rollup. *) + sender : Contract_repr.t; (** The L1 caller contract. *) + source : Signature.public_key_hash; + (** The implicit account that originated the transaction. *) + } + | External of string + +let encoding = + let open Data_encoding in + Data_encoding.union + [ + case + (Tag 0) + ~title:"Internal" + (obj3 + (req "payload" Script_repr.expr_encoding) + (req "sender" Contract_repr.encoding) + (req "source" Signature.Public_key_hash.encoding)) + (function + | Internal {payload; sender; source} -> Some (payload, sender, source) + | External _ -> None) + (fun (payload, sender, source) -> Internal {payload; sender; source}); + case + (Tag 1) + ~title:"External" + (* TODO: #3116 + Add size limit to constrain the maximum size of the string. + The exact limit is yet to be decided. Could be added as a constant. + *) + string + (function External msg -> Some msg | Internal _ -> None) + (fun msg -> External msg); + ] + +let to_bytes msg = + let open Tzresult_syntax in + match Data_encoding.Binary.to_string_opt encoding msg with + | None -> fail Error_encode_inbox_message + | Some str -> return str + +module Internal_for_tests = struct + let of_bytes bytes = + let open Tzresult_syntax in + match Data_encoding.Binary.of_string_opt encoding bytes with + | None -> fail Error_decode_inbox_message + | Some msg -> return msg +end diff --git a/src/proto_alpha/lib_protocol/sc_rollup_inbox_message_repr.mli b/src/proto_alpha/lib_protocol/sc_rollup_inbox_message_repr.mli new file mode 100644 index 0000000000000000000000000000000000000000..18f2993695f5eefb51bd979646bfcbdc699ee2e8 --- /dev/null +++ b/src/proto_alpha/lib_protocol/sc_rollup_inbox_message_repr.mli @@ -0,0 +1,66 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 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. *) +(* *) +(*****************************************************************************) + +(** This module exposes a type {!t} that represents inbox messages. Inbox + messages are produced by the Layer 1 protocol and are encoded using the + {!to_bytes} function, before being added to a smart-contract rollup's inbox. + + They are part of the [Rollup Management Protocol] that defines the + communication protocol for exchanging messages between Layer 1 and Layer 2 + for a smart-contract rollup. + + There are two types of inbox messages: external and internal. + + Internal messages originate from Layer 1 smart-contract and consist of: + - [payload] the parameters passed to the smart-contract rollup. + - [sender] the Layer 1 contract caller. + - [source] the public key hash used for originating the transaction. + + External messages originate from the [Sc_rollup_add_messages] + manager-operation and consists of strings. The Layer 2 node is responsible + for decoding and interpreting these messages. + *) + +(** A type representing messages from Layer 1 to Layer 2. Internal ones are + originated from Layer 1 smart-contracts and external ones are messages from + an external manager operation. *) +type t = + | Internal of { + payload : Script_repr.expr; + (** A Micheline value containing the parameters passed to the rollup. *) + sender : Contract_repr.t; (** The L1 caller contract. *) + source : Signature.public_key_hash; + (** The implicit account that originated the transaction. *) + } + | External of string + +(** [bytes_of_inbox_message msg] encodes the inbox message [msg] in binary + format. *) +val to_bytes : t -> string tzresult + +module Internal_for_tests : sig + (** [of_bytes bs] decodes [bs] as an [inbox_message]. *) + val of_bytes : string -> t tzresult +end diff --git a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml index a45fa3559e432c8c78ede79ebc5580993b092f6b..b32a6d94fd5fad8478cffa44db0e89676a86ee76 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.ml @@ -194,7 +194,7 @@ type t = { nb_messages_in_commitment_period : int64; starting_level_of_current_commitment_period : Raw_level_repr.t; message_counter : Z.t; - (* Lazy to avoid hashing O(n^2) time in [add_messages] *) + (* Lazy to avoid hashing O(n^2) time in [add_external_messages] *) current_messages_hash : unit -> Hash.t; old_levels_messages : history_proof; } @@ -377,7 +377,7 @@ module type MerkelizedOperations = sig val history_at_genesis : bound:int64 -> history - val add_messages : + val add_external_messages : history -> t -> Raw_level_repr.t -> @@ -385,7 +385,7 @@ module type MerkelizedOperations = sig messages -> (messages * history * t) tzresult Lwt.t - val add_messages_no_history : + val add_external_messages_no_history : t -> Raw_level_repr.t -> string list -> @@ -439,13 +439,19 @@ module MakeHashingScheme (Tree : TREE) : type message = tree - let add_message inbox payload messages = - let open Lwt_syntax in + let add_external_message inbox payload messages = + let open Lwt_tzresult_syntax in let message_index = inbox.message_counter in let message_counter = Z.succ message_index in let key = key_of_message message_index in let nb_available_messages = Int64.succ inbox.nb_available_messages in - let* messages = + let*? payload = + Sc_rollup_inbox_message_repr.(to_bytes @@ External payload) + in + (* TODO: 3151 + Consider making tagging type safe by restricting what to add to the tree. + *) + let*! messages = Tree.(add messages [key; "payload"] (Bytes.of_string payload)) in let nb_messages_in_commitment_period = @@ -459,7 +465,7 @@ module MakeHashingScheme (Tree : TREE) : nb_messages_in_commitment_period; } in - Lwt.return (messages, inbox) + return (messages, inbox) let get_message messages message_index = let key = key_of_message message_index in @@ -611,7 +617,7 @@ module MakeHashingScheme (Tree : TREE) : if Tree.is_empty messages then no_messages_hash else Hash.of_context_hash @@ Tree.hash messages - let add_messages_aux history inbox level payloads messages = + let add_external_messages_aux history inbox level payloads messages = let open Lwt_tzresult_syntax in if Raw_level_repr.(level < inbox.level) then fail (Invalid_level_add_messages level) @@ -620,24 +626,29 @@ module MakeHashingScheme (Tree : TREE) : let* messages, inbox = List.fold_left_es (fun (messages, inbox) payload -> - add_message inbox payload messages >>= return) + add_external_message inbox payload messages) (messages, inbox) payloads in let current_messages_hash () = hash_messages messages in return (messages, history, {inbox with current_messages_hash}) - let add_messages history inbox level payloads messages = + let add_external_messages history inbox level payloads messages = let open Lwt_tzresult_syntax in let* messages, With_history history, inbox = - add_messages_aux (With_history history) inbox level payloads messages + add_external_messages_aux + (With_history history) + inbox + level + payloads + messages in return (messages, history, inbox) - let add_messages_no_history inbox level payloads messages = + let add_external_messages_no_history inbox level payloads messages = let open Lwt_tzresult_syntax in let* messages, No_history, inbox = - add_messages_aux No_history inbox level payloads messages + add_external_messages_aux No_history inbox level payloads messages in return (messages, inbox) diff --git a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli index 0d2ca882cb2d0b943ef3d8d3d003f066995d8453..61b542571f4098ff883555bdd4c2dad572167516 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_inbox_repr.mli @@ -191,8 +191,8 @@ module type MerkelizedOperations = sig positive. *) val history_at_genesis : bound:int64 -> history - (** [add_messages history inbox level payloads messages] inserts a list of - [payloads] as new messages in the [messages] of the current + (** [add_external_messages history inbox level payloads messages] inserts a + list of [payloads] as new messages in the [messages] of the current [level] of the [inbox]. This function returns the new sequence of messages as well as updated [inbox] and [history]. @@ -210,7 +210,7 @@ module type MerkelizedOperations = sig if the inbox is full. *) - val add_messages : + val add_external_messages : history -> t -> Raw_level_repr.t -> @@ -218,10 +218,10 @@ module type MerkelizedOperations = sig messages -> (messages * history * t) tzresult Lwt.t - (** [add_messages_no_history inbox level payloads messages] behaves - a [add_messages] except that it does not remember the inbox + (** [add_external_messages_no_history inbox level payloads messages] behaves + a [add_external_messages] except that it does not remember the inbox history. *) - val add_messages_no_history : + val add_external_messages_no_history : t -> Raw_level_repr.t -> string list -> diff --git a/src/proto_alpha/lib_protocol/sc_rollup_inbox_storage.ml b/src/proto_alpha/lib_protocol/sc_rollup_inbox_storage.ml index 9649492b9f139233609f9aaf047dd5effe485878..4a84d104d4dfd9fdb7e955ba383b60dbf36d3b50 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_inbox_storage.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_inbox_storage.ml @@ -59,7 +59,7 @@ let assert_inbox_nb_messages_in_commitment_period inbox extra_messages = Compare.Int64.(nb_messages_in_commitment_period > limit) Sc_rollup_max_number_of_messages_reached_for_commitment_period -let add_messages ctxt rollup messages = +let add_external_messages ctxt rollup messages = let {Level_repr.level; _} = Raw_context.current_level ctxt in let open Lwt_tzresult_syntax in let open Raw_context in @@ -116,10 +116,13 @@ let add_messages ctxt rollup messages = let*? current_messages, ctxt = Sc_rollup_in_memory_inbox.current_messages ctxt rollup in - let gas_cost_add_messages = - Sc_rollup_costs.cost_add_messages ~num_messages ~total_messages_size levels + let gas_cost_add_external_messages = + Sc_rollup_costs.cost_add_external_messages + ~num_messages + ~total_messages_size + levels in - let*? ctxt = Raw_context.consume_gas ctxt gas_cost_add_messages in + let*? ctxt = Raw_context.consume_gas ctxt gas_cost_add_external_messages in (* Notice that the protocol is forgetful: it throws away the inbox history. On the contrary, the history is stored by the rollup @@ -127,7 +130,7 @@ let add_messages ctxt rollup messages = *) let* current_messages, inbox = Sc_rollup_inbox_repr.( - add_messages_no_history inbox level messages current_messages) + add_external_messages_no_history inbox level messages current_messages) in let*? ctxt = Sc_rollup_in_memory_inbox.set_current_messages ctxt rollup current_messages diff --git a/src/proto_alpha/lib_protocol/sc_rollup_inbox_storage.mli b/src/proto_alpha/lib_protocol/sc_rollup_inbox_storage.mli index 607bf8540626122cf6c5af6f74d8aa48ee06302f..6d05184bb4d969bf79a0c23d361ff91afc1ed22c 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_inbox_storage.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_inbox_storage.mli @@ -30,7 +30,7 @@ val inbox : Sc_rollup_repr.t -> (Sc_rollup_inbox_repr.t * Raw_context.t) tzresult Lwt.t -(** [add_messages context rollup msg] adds [msg] to [rollup]'s inbox. +(** [add_external_messages context rollup msg] adds [msg] to [rollup]'s inbox. This function returns the updated context as well as the size diff. @@ -41,7 +41,7 @@ val inbox : the number of messages pushed during commitment period is too high} } *) -val add_messages : +val add_external_messages : Raw_context.t -> Sc_rollup_repr.t -> string list -> diff --git a/src/proto_alpha/lib_protocol/sc_rollup_management_protocol.ml b/src/proto_alpha/lib_protocol/sc_rollup_management_protocol.ml index e7b00869e92f1f991ff2927883bfecfb8aef8a67..98856c39a1eb4e6f2f6326a5bef8d286a74ca40e 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_management_protocol.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_management_protocol.ml @@ -25,94 +25,27 @@ open Alpha_context -type error += - | (* `Permanent *) Error_encode_inbox_message - | (* `Permanent *) Error_decode_inbox_message - | (* `Permanent *) Error_encode_outbox_message - | (* `Permanent *) Error_decode_outbox_message +type error += (* Permanent *) Sc_rollup_invalid_destination let () = let open Data_encoding in - let msg = - "Failed to encode a rollup management protocol inbox message value" - in + let msg = "Invalid destination" in register_error_kind `Permanent - ~id:"rollup_management_protocol.error_encoding_inbox_message" + ~id:"sc_rollup_management_protocol.sc_rollup_invalid_destination" ~title:msg ~pp:(fun fmt () -> Format.fprintf fmt "%s" msg) ~description:msg unit - (function Error_encode_inbox_message -> Some () | _ -> None) - (fun () -> Error_encode_inbox_message) ; - let msg = - "Failed to decode a rollup management protocol inbox message value" - in - register_error_kind - `Permanent - ~id:"rollup_management_protocol.error_decoding_inbox_message" - ~title:msg - ~pp:(fun fmt () -> Format.fprintf fmt "%s" msg) - ~description:msg - unit - (function Error_decode_inbox_message -> Some () | _ -> None) - (fun () -> Error_decode_inbox_message) ; - let msg = - "Failed to encode a rollup management protocol outbox message value" - in - register_error_kind - `Permanent - ~id:"rollup_management_protocol.error_encoding_outbox_message" - ~title:msg - ~pp:(fun fmt () -> Format.fprintf fmt "%s" msg) - ~description:msg - unit - (function Error_encode_outbox_message -> Some () | _ -> None) - (fun () -> Error_encode_outbox_message) ; - let msg = - "Failed to decode a rollup management protocol outbox message value" - in - register_error_kind - `Permanent - ~id:"rollup_management_protocol.error_decoding_outbox_message" - ~title:msg - ~pp:(fun fmt () -> Format.fprintf fmt "%s" msg) - ~description:msg - unit - (function Error_decode_outbox_message -> Some () | _ -> None) - (fun () -> Error_decode_outbox_message) - -type sc_message = { - payload : Script_repr.expr; - (** A Micheline value containing the parameters passed to the rollup. *) - sender : Alpha_context.Contract.t; (** The L1 caller contract. *) - source : Signature.public_key_hash; - (** The implicit account that originated the transaction. *) -} - -type inbox_message = Sc_message of sc_message - -type transaction_internal = { - unparsed_parameters_ty : Script_repr.expr; (** The type of the parameters. *) - unparsed_parameters : Script_repr.expr; (** The payload. *) - destination : Destination.t; (** The recipient contract or rollup. *) - entrypoint : Entrypoint.t; (** Entrypoint of the destination. *) -} - -type atomic_message_batch_internal = { - transactions_internal : transaction_internal list; -} - -type outbox_message_internal = - | Atomic_transaction_batch_internal of atomic_message_batch_internal + (function Sc_rollup_invalid_destination -> Some () | _ -> None) + (fun () -> Sc_rollup_invalid_destination) type transaction = | Transaction : { - destination : Destination.t; + destination : Contract_hash.t; entrypoint : Entrypoint.t; parameters_ty : ('a, _) Script_typed_ir.ty; parameters : 'a; - unparsed_parameters_ty : Script.expr; unparsed_parameters : Script.expr; } -> transaction @@ -121,7 +54,7 @@ type atomic_transaction_batch = {transactions : transaction list} type outbox_message = Atomic_transaction_batch of atomic_transaction_batch -let make_inbox_message ctxt ty ~payload ~sender ~source = +let make_internal_inbox_message ctxt ty ~payload ~sender ~source = let open Lwt_tzresult_syntax in let+ payload, ctxt = Script_ir_translator.unparse_data @@ -131,80 +64,33 @@ let make_inbox_message ctxt ty ~payload ~sender ~source = payload in let payload = Micheline.strip_locations payload in - (Sc_message {payload; sender; source}, ctxt) - -let sc_message_encoding = - let open Data_encoding in - conv - (fun {payload; sender; source} -> (payload, sender, source)) - (fun (payload, sender, source) -> {payload; sender; source}) - @@ obj3 - (req "payload" Script_repr.expr_encoding) - (req "sender" Contract.encoding) - (req "source" Signature.Public_key_hash.encoding) - -let transaction_internal_encoding = - let open Data_encoding in - conv - (fun {unparsed_parameters_ty; unparsed_parameters; destination; entrypoint} -> - (unparsed_parameters_ty, unparsed_parameters, destination, entrypoint)) - (fun (unparsed_parameters_ty, unparsed_parameters, destination, entrypoint) -> - {unparsed_parameters_ty; unparsed_parameters; destination; entrypoint}) - @@ obj4 - (req "parameters_ty" Script_repr.expr_encoding) - (req "parameters" Script_repr.expr_encoding) - (req "destination" Destination.encoding) - (req "entrypoint" Entrypoint.simple_encoding) - -let atomic_message_batch_encoding = - let open Data_encoding in - obj1 - (req - "transactions" - (conv - (fun {transactions_internal} -> transactions_internal) - (fun transactions_internal -> {transactions_internal}) - (list transaction_internal_encoding))) - -let internal_outbox_message_encoding = - let open Data_encoding in - conv - (fun (Atomic_transaction_batch_internal m) -> m) - (fun m -> Atomic_transaction_batch_internal m) - atomic_message_batch_encoding - -let inbox_message_encoding = - let open Data_encoding in - conv (fun (Sc_message m) -> m) (fun m -> Sc_message m) sc_message_encoding + (Sc_rollup.Inbox.Message.Internal {payload; sender; source}, ctxt) -(** TODO: #2951 - Carbonate [to_bytes] step. - Gas for encoding the value in binary format should be accounted for. - *) -let bytes_of_inbox_message msg = - let open Tzresult_syntax in - match Data_encoding.Binary.to_bytes_opt inbox_message_encoding msg with - | None -> fail Error_encode_inbox_message - | Some bs -> return bs - -let transactions_batch_of_internal ctxt {transactions_internal} = +let transactions_batch_of_internal ctxt transactions = let open Lwt_tzresult_syntax in let or_internal_transaction ctxt - {unparsed_parameters_ty; unparsed_parameters; destination; entrypoint} = - let*? Ex_ty parameters_ty, ctxt = - Script_ir_translator.parse_ty - ~legacy:false - ~allow_lazy_storage:false - ~allow_contract:false - ~allow_ticket:true - ~allow_operation:false + {Sc_rollup.Outbox.Message.unparsed_parameters; destination; entrypoint} = + (* Lookup the contract-hash. *) + (* Load the type and entrypoints of the script. *) + let* ( Script_ir_translator.Ex_script (Script {arg_type; entrypoints; _}), + ctxt ) = + let* ctxt, _cache_key, cached = Script_cache.find ctxt destination in + match cached with + | Some (_script, ex_script) -> return (ex_script, ctxt) + | None -> fail Sc_rollup_invalid_destination + in + (* Find the entrypoint type for the given entrypoint. *) + let*? res, ctxt = + Gas_monad.run ctxt - (Micheline.root unparsed_parameters_ty) + (Script_ir_translator.find_entrypoint + ~error_details:(Informative ()) + arg_type + entrypoints + entrypoint) in - (* TODO: #2964 - We should rule out big-maps. - [allow_forged] controls both tickets and big-maps. Here we only want to - allow tickets. *) + let*? (Ex_ty_cstr {ty = parameters_ty; _}) = res in + (* Parse the parameters according to the entrypoint type. *) let* parameters, ctxt = Script_ir_translator.parse_data ctxt @@ -220,7 +106,6 @@ let transactions_batch_of_internal ctxt {transactions_internal} = entrypoint; parameters_ty; parameters; - unparsed_parameters_ty; unparsed_parameters; }, ctxt ) @@ -231,7 +116,7 @@ let transactions_batch_of_internal ctxt {transactions_internal} = let+ t, ctxt = or_internal_transaction ctxt msg in (ctxt, t)) ctxt - transactions_internal + transactions in ({transactions}, ctxt) @@ -241,14 +126,10 @@ let transactions_batch_of_internal ctxt {transactions_internal} = *) let outbox_message_of_bytes ctxt bytes = let open Lwt_tzresult_syntax in - let*? (Atomic_transaction_batch_internal msg) = - match - Data_encoding.Binary.of_bytes_opt internal_outbox_message_encoding bytes - with - | Some x -> ok x - | None -> error Error_decode_inbox_message + let*? (Sc_rollup.Outbox.Message.Atomic_transaction_batch {transactions}) = + Sc_rollup.Outbox.Message.of_bytes bytes in - let+ ts, ctxt = transactions_batch_of_internal ctxt msg in + let+ ts, ctxt = transactions_batch_of_internal ctxt transactions in (Atomic_transaction_batch ts, ctxt) module Internal_for_tests = struct @@ -257,22 +138,7 @@ module Internal_for_tests = struct let* unparsed_parameters, ctxt = Script_ir_translator.unparse_data ctxt Optimized parameters_ty parameters in - let*? unparsed_parameters_ty, ctxt = - Script_ir_translator.unparse_ty - ctxt - ~loc:Micheline.dummy_location - parameters_ty - in - let*? ctxt = - Gas.consume ctxt (Script.strip_locations_cost unparsed_parameters) - in let unparsed_parameters = Micheline.strip_locations unparsed_parameters in - let*? ctxt = - Gas.consume ctxt (Script.strip_locations_cost unparsed_parameters_ty) - in - let unparsed_parameters_ty = - Micheline.strip_locations unparsed_parameters_ty - in return ( Transaction { @@ -280,7 +146,6 @@ module Internal_for_tests = struct entrypoint; parameters_ty; parameters; - unparsed_parameters_ty; unparsed_parameters; }, ctxt ) @@ -296,26 +161,17 @@ module Internal_for_tests = struct entrypoint; parameters_ty = _; parameters = _; - unparsed_parameters_ty; unparsed_parameters; }) = - {unparsed_parameters; unparsed_parameters_ty; destination; entrypoint} + return + {Sc_rollup.Outbox.Message.unparsed_parameters; destination; entrypoint} in + let* transactions = List.map_e to_internal_transaction transactions in let output_message_internal = - Atomic_transaction_batch_internal - {transactions_internal = List.map to_internal_transaction transactions} + Sc_rollup.Outbox.Message.Atomic_transaction_batch {transactions} in - match - Data_encoding.Binary.to_bytes_opt - internal_outbox_message_encoding - output_message_internal - with - | Some x -> return x - | None -> fail Error_encode_inbox_message + Sc_rollup.Outbox.Message.Internal_for_tests.to_bytes output_message_internal - let inbox_message_of_bytes bytes = - let open Tzresult_syntax in - match Data_encoding.Binary.of_bytes_opt inbox_message_encoding bytes with - | None -> fail Error_decode_inbox_message - | Some deposit -> return deposit + let inbox_message_of_bytes = + Sc_rollup.Inbox.Message.Internal_for_tests.of_bytes end diff --git a/src/proto_alpha/lib_protocol/sc_rollup_management_protocol.mli b/src/proto_alpha/lib_protocol/sc_rollup_management_protocol.mli index d664602166fbd6332e8d9d5695957e504200fb50..f762731e98df77aebfca02c165b1bae514d1ffa0 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_management_protocol.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_management_protocol.mli @@ -23,38 +23,32 @@ (* *) (*****************************************************************************) -(** The Rollup Management Protocol defines the communication protocol for - exchanging messages between Layer 1 and Layer 2 for a SCORU. +(** This module provides a typed API for the Rollup Management Protocol that + defines the communication protocol for exchanging messages between Layer 1 + and Layer 2 for smart-contract rollups. - This module exposes a type {!inbox_message}. Inbox messages produced by the - Layer 1 protocol are encoded using the {!bytes_of_inbox} function, before - added to a SCORU's inbox. - - An {!inbox_message} consists of: - - [payload] the parameters passed to the SCORU. - - [sender] the Layer 1 contract caller. - - [source] the public key hash used for originating the transaction. + The API exposes functions for constructing inbox messages. These are + messages produced by the Layer 1 protocol and added to a smart-contract + rollups inbox. The Layer 2 node is responsible for decoding and interpreting the messages. - Another type {!outbox_message} representing messages from Layer 2 to Layer 1 + A type {!outbox_message} representing messages from Layer 2 to Layer 1 is also provided. An {!outbox_message} consists of a set of transactions to L1 accounts. *) open Alpha_context -(** A type representing messages from Layer 1 to Layer 2. *) -type inbox_message +type error += (* Permanent *) Sc_rollup_invalid_destination (** A type representing a Layer 2 to Layer 1 transaction. *) type transaction = private | Transaction : { - destination : Destination.t; + destination : Contract_hash.t; entrypoint : Entrypoint.t; parameters_ty : ('a, _) Script_typed_ir.ty; parameters : 'a; - unparsed_parameters_ty : Script.expr; unparsed_parameters : Script.expr; } -> transaction @@ -66,26 +60,22 @@ type atomic_transaction_batch = private {transactions : transaction list} type outbox_message = private | Atomic_transaction_batch of atomic_transaction_batch -(** [make_inbox_message ctxt ty ~payload ~sender ~source] constructs a SCORU - [inbox message] (an L1 to L2 message) with the given [payload], [sender], - and [source]. *) -val make_inbox_message : +(** [make_internal_inbox_message ctxt ty ~payload ~sender ~source] constructs a + smart-contract rollup's [inbox message] (an L1 to L2 message) with the given + [payload], [sender], and [source]. *) +val make_internal_inbox_message : context -> ('a, _) Script_typed_ir.ty -> payload:'a -> sender:Contract.t -> source:public_key_hash -> - (inbox_message * context) tzresult Lwt.t - -(** [bytes_of_inbox_message msg] encodes the inbox message [msg] in binary - format. *) -val bytes_of_inbox_message : inbox_message -> bytes tzresult + (Sc_rollup.Inbox.Message.t * context) tzresult Lwt.t (** [outbox_message_of_bytes ctxt bs] decodes an outbox message value from the given bytes [bs]. The function involves parsing Micheline expressions to typed values. *) val outbox_message_of_bytes : - context -> bytes -> (outbox_message * context) tzresult Lwt.t + context -> string -> (outbox_message * context) tzresult Lwt.t (** Function for constructing and encoding {!inbox_message} and {!outbox_message} values. Since Layer 1 only ever consumes {!outbox_message} @@ -98,7 +88,7 @@ module Internal_for_tests : sig context -> ('a, _) Script_typed_ir.ty -> parameters:'a -> - destination:Destination.t -> + destination:Contract_hash.t -> entrypoint:Entrypoint.t -> (transaction * context) tzresult Lwt.t @@ -108,9 +98,9 @@ module Internal_for_tests : sig (** [bytes_of_output_message msg] encodes the outbox message [msg] in binary format. *) - val bytes_of_outbox_message : outbox_message -> bytes tzresult + val bytes_of_outbox_message : outbox_message -> string tzresult (** [inbox_message_of_bytes bs] decodes an inbox message from the given bytes [bs]. *) - val inbox_message_of_bytes : bytes -> inbox_message tzresult + val inbox_message_of_bytes : string -> Sc_rollup.Inbox.Message.t tzresult end diff --git a/src/proto_alpha/lib_protocol/sc_rollup_outbox_message_repr.ml b/src/proto_alpha/lib_protocol/sc_rollup_outbox_message_repr.ml new file mode 100644 index 0000000000000000000000000000000000000000..4d51e8bc4f56f15cbaec4d6df14013d6e3bded91 --- /dev/null +++ b/src/proto_alpha/lib_protocol/sc_rollup_outbox_message_repr.ml @@ -0,0 +1,100 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 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. *) +(* *) +(*****************************************************************************) + +type error += + | (* `Permanent *) Error_encode_outbox_message + | (* `Permanent *) Error_decode_outbox_message + +let () = + let open Data_encoding in + let msg = + "Failed to encode a rollup management protocol outbox message value" + in + register_error_kind + `Permanent + ~id:"sc_rollup_outbox_message_repr.error_encoding_outbox_message" + ~title:msg + ~pp:(fun fmt () -> Format.fprintf fmt "%s" msg) + ~description:msg + unit + (function Error_encode_outbox_message -> Some () | _ -> None) + (fun () -> Error_encode_outbox_message) ; + let msg = + "Failed to decode a rollup management protocol outbox message value" + in + register_error_kind + `Permanent + ~id:"sc_rollup_outbox_message_repr.error_decoding_outbox_message" + ~title:msg + ~pp:(fun fmt () -> Format.fprintf fmt "%s" msg) + ~description:msg + unit + (function Error_decode_outbox_message -> Some () | _ -> None) + (fun () -> Error_decode_outbox_message) + +type transaction = { + unparsed_parameters : Script_repr.expr; (** The payload. *) + destination : Contract_hash.t; (** The recipient contract. *) + entrypoint : Entrypoint_repr.t; (** Entrypoint of the destination. *) +} + +type t = Atomic_transaction_batch of {transactions : transaction list} + +let transaction_encoding = + let open Data_encoding in + (* TODO: #3116 + Add size limit to constrain the maximum size of the encoded message. + The exact limit is yet to be decided. Could be added as a constant. + *) + conv + (fun {unparsed_parameters; destination; entrypoint} -> + (unparsed_parameters, destination, entrypoint)) + (fun (unparsed_parameters, destination, entrypoint) -> + {unparsed_parameters; destination; entrypoint}) + @@ obj3 + (req "parameters" Script_repr.expr_encoding) + (req "destination" Contract_repr.originated_encoding) + (req "entrypoint" Entrypoint_repr.simple_encoding) + +let encoding = + let open Data_encoding in + conv + (fun (Atomic_transaction_batch {transactions}) -> transactions) + (fun transactions -> Atomic_transaction_batch {transactions}) + (obj1 (req "transactions" (list transaction_encoding))) + +let of_bytes bytes = + let open Tzresult_syntax in + match Data_encoding.Binary.of_string_opt encoding bytes with + | Some x -> return x + | None -> fail Error_decode_outbox_message + +module Internal_for_tests = struct + let to_bytes outbox_message = + let open Tzresult_syntax in + match Data_encoding.Binary.to_string_opt encoding outbox_message with + | Some str -> return str + | None -> fail Error_encode_outbox_message +end diff --git a/src/proto_alpha/lib_protocol/sc_rollup_outbox_message_repr.mli b/src/proto_alpha/lib_protocol/sc_rollup_outbox_message_repr.mli new file mode 100644 index 0000000000000000000000000000000000000000..2fe02e040a17995c62d51877d68d316c633a5c5a --- /dev/null +++ b/src/proto_alpha/lib_protocol/sc_rollup_outbox_message_repr.mli @@ -0,0 +1,57 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 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. *) +(* *) +(*****************************************************************************) + +(** This module defines a data type {!t} that represents messages from Layer 2 + to Layer 1. + + They are part of the [Rollup Management Protocol] that defines the + communication protocol for exchanging messages between Layer 1 and Layer 2 + for smart-contract rollups. + + An outbox-message consists of a sequence of transactions to L1 + smart-contract accounts. All transactions contained in a message are + intended to be executed as a batch. + *) + +(** A transaction from L2 to L1. *) +type transaction = { + unparsed_parameters : Script_repr.expr; (** The payload. *) + destination : Contract_hash.t; (** The recipient contract. *) + entrypoint : Entrypoint_repr.t; (** Entrypoint of the destination. *) +} + +(** A type representing messages from Layer 2 to Layer 1. *) +type t = Atomic_transaction_batch of {transactions : transaction list} + +(** [of_bytes ctxt bs] decodes an outbox message value from the + given bytes [bs]. The function involves parsing Micheline expressions to + typed values. *) +val of_bytes : string -> t tzresult + +module Internal_for_tests : sig + (** [to_bytes msg] returns the bytes of the given outbox + message [msg]. *) + val to_bytes : t -> string tzresult +end diff --git a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_inbox.ml b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_inbox.ml index 59b777f9fce940205b329c1f3dcaa30d974e66ee..d2f4cd14550d3ad46997f8a9cdb88a0bc26e8548 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_inbox.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_inbox.ml @@ -61,7 +61,7 @@ let setup_inbox_with_messages list_of_payloads f = let rec aux level history inbox inboxes messages = function | [] -> return (messages, history, inbox, inboxes) | payloads :: ps -> - add_messages history inbox level payloads messages + add_external_messages history inbox level payloads messages >>=? fun (messages, history, inbox') -> let level = Raw_level_repr.succ level in aux level history inbox' (inbox :: inboxes) messages ps @@ -98,14 +98,40 @@ let test_consume_messages (payloads, nb_consumed_messages) = "Message consumption fails only when trying to consume more than \ the number of available messages.") -let check_payload message payload = - Environment.Context.Tree.find message ["payload"] >>= function - | None -> fail (err "No payload in message") - | Some payload' -> - let payload' = Bytes.to_string payload' in +(* A message is tagged with a prefix. It consists of 5 bytes: + - Byte 0 is the tag (1 for external and 0 for internal). + - Bytes 1-4 is the length of the message encoded as: + [ prefix[1] * 256^3 + prefix[2] * 256^2 prefix[3] * 256^1 prefix[4]] +*) +let encode_external_message message = + let length = String.length message in + let pow m n = Z.to_int @@ Z.(of_int m ** n) in + let prefix = + [ + (* This is the tag of external messages. *) + 1; + (* The length of the message encoded in base 256. *) + length / pow 256 3 mod 256; + length / pow 256 2 mod 256; + length / 256 mod 256; + length mod 256; + ] + |> List.map Char.chr |> List.to_seq |> String.of_seq + in + Bytes.of_string (Printf.sprintf "%s%s" prefix message) + +let check_payload messages external_message = + Environment.Context.Tree.find messages ["payload"] >>= function + | None -> fail (err "No payload in messages") + | Some payload -> + let expected_payload = encode_external_message external_message in fail_unless - (payload = payload') - (err (Printf.sprintf "Expected payload %s, got %s" payload payload')) + (expected_payload = payload) + (err + (Printf.sprintf + "Expected payload %s, got %s" + (Bytes.to_string expected_payload) + (Bytes.to_string payload))) let test_get_message payloads = setup_inbox_with_messages [payloads] @@ -121,12 +147,13 @@ let test_get_message_payload payloads = setup_inbox_with_messages [payloads] @@ fun messages _history _inbox _inboxes -> List.iteri_es - (fun i payload -> + (fun i message -> + let expected_payload = encode_external_message message in get_message_payload messages (Z.of_int i) >>= function - | Some payload' -> + | Some payload -> fail_unless - (String.equal payload' payload) - (err (Printf.sprintf "Expected %s, got %s" payload payload')) + (String.equal payload (Bytes.to_string expected_payload)) + (err (Printf.sprintf "Expected %s, got %s" message payload)) | None -> fail (err (Printf.sprintf "No message payload number %d in messages" i))) diff --git a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_management_protocol.ml b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_management_protocol.ml index cf900a3f16f336b7d6d017daed9642a58102f6f2..5d570d6cfc114e4449419611f4fcc8c3babc21cf 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_management_protocol.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_management_protocol.ml @@ -39,15 +39,16 @@ let wrap m = m >|= Environment.wrap_tzresult let check_encode_decode_inbox_message message = let open Lwt_result_syntax in let open Sc_rollup_management_protocol in - let*? bytes = Environment.wrap_tzresult @@ bytes_of_inbox_message message in + let*? bytes = + Environment.wrap_tzresult @@ Sc_rollup.Inbox.Message.to_bytes message + in let*? message' = Environment.wrap_tzresult @@ Internal_for_tests.inbox_message_of_bytes bytes in - let*? bytes' = Environment.wrap_tzresult @@ bytes_of_inbox_message message' in - Assert.equal_string - ~loc:__LOC__ - (Bytes.to_string bytes) - (Bytes.to_string bytes') + let*? bytes' = + Environment.wrap_tzresult @@ Sc_rollup.Inbox.Message.to_bytes message' + in + Assert.equal_string ~loc:__LOC__ bytes bytes' let check_encode_decode_outbox_message ctxt message = let open Lwt_result_syntax in @@ -61,10 +62,7 @@ let check_encode_decode_outbox_message ctxt message = Environment.wrap_tzresult @@ Internal_for_tests.bytes_of_outbox_message message' in - Assert.equal_string - ~loc:__LOC__ - (Bytes.to_string bytes) - (Bytes.to_string bytes') + Assert.equal_string ~loc:__LOC__ bytes bytes' let string_ticket ticketer contents amount = let open WithExceptions in @@ -81,7 +79,7 @@ let init_ctxt () = let+ incr = Incremental.begin_construction block in Incremental.alpha_ctxt incr -let test_encode_decode_inbox_message () = +let test_encode_decode_internal_inbox_message () = let open WithExceptions in let open Lwt_result_syntax in let* ctxt = init_ctxt () in @@ -108,7 +106,7 @@ let test_encode_decode_inbox_message () = in let* deposit, _ctxt = wrap - @@ Sc_rollup_management_protocol.make_inbox_message + @@ Sc_rollup_management_protocol.make_internal_inbox_message ctxt pair_nat_ticket_string_ty ~payload @@ -117,60 +115,188 @@ let test_encode_decode_inbox_message () = in check_encode_decode_inbox_message deposit +let test_encode_decode_external_inbox_message () = + let open Lwt_result_syntax in + let assert_prefix message ~prefix = + let inbox_message = Sc_rollup.Inbox.Message.External message in + let*? real_encoding = + Environment.wrap_tzresult + @@ Sc_rollup.Inbox.Message.to_bytes inbox_message + in + (* The prefix consists of 5 bytes: + - Byte 0 is the tag (0 for internal, 1 for external). + - Bytes 1-4 is the length of the message encoded as: + [ prefix[1] * 256^3 + prefix[2] * 256^2 prefix[3] * 256^1 prefix[4]] + *) + let real_prefix = + String.sub real_encoding 0 5 + |> String.to_seq |> List.of_seq |> List.map Char.code + in + let expected_encoding = + Printf.sprintf + "%s%s" + (List.map Char.chr prefix |> List.to_seq |> String.of_seq) + message + in + (* Check that the encode/decode matches. *) + let* () = check_encode_decode_inbox_message inbox_message in + (* Check that the prefix match. *) + let* () = + Assert.assert_equal_list + ~loc:__LOC__ + Int.equal + "Compare encoded prefix" + Format.pp_print_int + real_prefix + prefix + in + (* Check that the encoded string consists of the prefix followed by the + original message. *) + Assert.equal_string ~loc:__LOC__ real_encoding expected_encoding + in + let* () = assert_prefix "" ~prefix:[1; 0; 0; 0; 0] in + let* () = assert_prefix "A" ~prefix:[1; 0; 0; 0; 1] in + let* () = assert_prefix "0123456789" ~prefix:[1; 0; 0; 0; 10] in + let* () = + assert_prefix (String.init 256 (Fun.const 'A')) ~prefix:[1; 0; 0; 1; 0] + in + (* Length 1234567 = 18*256^2 + 214*256 + 135 *) + let* () = + assert_prefix + (String.init 1234567 (Fun.const 'A')) + ~prefix:[1; 0; 18; 214; 135] + in + (* The content of the string should not impact the prefix.*) + let* () = + assert_prefix + (String.init 1234567 (Fun.const 'b')) + ~prefix:[1; 0; 18; 214; 135] + in + return_unit + +let init_env () = + let open Lwt_result_syntax in + let* block, baker, contract, _src2 = Contract_helpers.init () in + return (block, baker, contract) + +let ticket_receiver = + {| + { parameter (pair nat (ticket string)); + storage (list (ticket string)); + code { UNPAIR; # [(nat, ticket) ; list] + CDR; # [ticket ; list] + CONS; # [ticket :: list] + NIL operation ; # [[] ; ticket :: list] + PAIR; # [([], ticket :: list)] + } + } + |} + +let add_or_clear = + {| + { parameter (or (pair %add nat string) (unit %clear)) ; + storage (list (ticket string)) ; + code { UNPAIR ; + IF_LEFT + { UNPAIR ; DIG 2 ; SWAP ; DIG 2 ; TICKET ; CONS ; NIL operation ; PAIR } + { DROP 2 ; NIL (ticket string) ; NIL operation ; PAIR } } } + |} + let test_encode_decode_outbox_message () = let open Lwt_result_syntax in - let* ctxt = init_ctxt () in - let*? (Script_typed_ir.Ty_ex_c pair_nat_ticket_string_ty) = - Environment.wrap_tzresult - (let open Result_syntax in - let open Script_typed_ir in - let* ticket_t = ticket_t (-1) string_t in - pair_t (-1) nat_t ticket_t) + let* block, baker, source_contract = init_env () in + let* ticket_receiver, _, block = + Contract_helpers.originate_contract_from_string + ~script:ticket_receiver + ~storage:"{}" + ~source_contract + ~baker + block in - let parameters = - ( Script_int.(abs @@ of_int 42), - string_ticket "KT1ThEdxfUcWUwqsdergy3QnbCWGHSUHeHJq" "red" 1 ) + let* add_or_clear, _, block = + Contract_helpers.originate_contract_from_string + ~script:add_or_clear + ~storage:"{}" + ~source_contract + ~baker + block + in + let* incr = Incremental.begin_construction block in + let ctxt = Incremental.alpha_ctxt incr in + let ticket_receiver_destination = + match ticket_receiver with + | Contract.Originated ch -> ch + | Implicit _ -> assert false + in + let add_or_clear_destination = + match add_or_clear with + | Contract.Originated ch -> ch + | Implicit _ -> assert false in + (* Transaction to ticket receiver. *) let* transaction1, ctxt = - let*? destination_contract = + let*? (Script_typed_ir.Ty_ex_c pair_nat_ticket_string_ty) = Environment.wrap_tzresult - (Contract.of_b58check "KT1BuEZtb68c1Q4yjtckcNjGELqWt56Xyesc") + (let open Result_syntax in + let open Script_typed_ir in + let* ticket_t = ticket_t (-1) string_t in + pair_t (-1) nat_t ticket_t) + in + let parameters = + ( Script_int.(abs @@ of_int 42), + string_ticket "KT1ThEdxfUcWUwqsdergy3QnbCWGHSUHeHJq" "red" 1 ) in - let destination = Destination.Contract destination_contract in wrap @@ Sc_rollup_management_protocol.Internal_for_tests.make_transaction ctxt pair_nat_ticket_string_ty ~parameters - ~destination + ~destination:ticket_receiver_destination ~entrypoint:Entrypoint.default in + (* Transaction to the `add` endpoint of add-or-clear contract. *) let* transaction2, ctxt = - let*? destination_contract = - Environment.wrap_tzresult - (Contract.of_b58check "KT1BuEZtb68c1Q4yjtckcNjGELqWt56Xyesc") + let*? (Script_typed_ir.Ty_ex_c pair_nat_ticket_string_ty) = + Environment.wrap_tzresult Script_typed_ir.(pair_t (-1) nat_t string_t) in - let destination = Destination.Contract destination_contract in + let*? content = + Environment.wrap_tzresult @@ Script_string.of_string "Hello" + in + let parameters = (Script_int.(abs @@ of_int 11), content) in wrap @@ Sc_rollup_management_protocol.Internal_for_tests.make_transaction ctxt - Script_typed_ir.nat_t - ~parameters:Script_int.(abs @@ of_int 10) - ~destination - ~entrypoint:Entrypoint.default + pair_nat_ticket_string_ty + ~parameters + ~destination:add_or_clear_destination + ~entrypoint:(Entrypoint.of_string_strict_exn "add") + in + (* Transaction to the `clear` endpoint of add-or-clear contract. *) + let* transaction3, ctxt = + wrap + @@ Sc_rollup_management_protocol.Internal_for_tests.make_transaction + ctxt + Script_typed_ir.unit_t + ~parameters:() + ~destination:add_or_clear_destination + ~entrypoint:(Entrypoint.of_string_strict_exn "clear") in let outbox_message = Sc_rollup_management_protocol.Internal_for_tests.make_atomic_batch - [transaction1; transaction2] + [transaction1; transaction2; transaction3] in check_encode_decode_outbox_message ctxt outbox_message let tests = [ Tztest.tztest - "Encode/decode inbox message" + "Encode/decode internal inbox message" + `Quick + test_encode_decode_internal_inbox_message; + Tztest.tztest + "Encode/decode external inbox message" `Quick - test_encode_decode_inbox_message; + test_encode_decode_external_inbox_message; Tztest.tztest "Encode/decode outbox message" `Quick diff --git a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_storage.ml b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_storage.ml index 25a8b1dd5ae473f0d9482b599d219c3e5bb65c02..ea4308be7f6376f0fd8631e3d27308ad157829a2 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_storage.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_storage.ml @@ -825,7 +825,10 @@ let test_cement_consumes_available_messages () = let* ctxt = deposit_stake_and_check_balances ctxt rollup staker in let* inbox, _n, ctxt = lift - @@ Sc_rollup_inbox_storage.add_messages ctxt rollup ["one"; "two"; "three"] + @@ Sc_rollup_inbox_storage.add_external_messages + ctxt + rollup + ["one"; "two"; "three"] in let available_messages = Sc_rollup_inbox_repr.number_of_available_messages inbox @@ -2064,7 +2067,10 @@ let test_kind_of_missing_rollup () = let test_add_messages_from_missing_rollup () = assert_fails_with_missing_rollup ~loc:__LOC__ (fun ctxt rollup -> - Sc_rollup_inbox_storage.add_messages ctxt rollup ["Dummy message"]) + Sc_rollup_inbox_storage.add_external_messages + ctxt + rollup + ["Dummy message"]) let test_inbox_of_missing_rollup () = assert_fails_with_missing_rollup ~loc:__LOC__ Sc_rollup_inbox_storage.inbox @@ -2321,7 +2327,7 @@ let test_carbonated_memory_inbox_set_messages () = let* current_messages, _ = lift @@ Sc_rollup_inbox_repr.( - add_messages_no_history + add_external_messages_no_history inbox level ["CAFEBABE"; "CAFEBABE"; "CAFEBABE"] @@ -2359,7 +2365,8 @@ let test_limit_on_number_of_messages_during_commitment_period with_gap () = else ctxt in let* _inbox, _size_diff, ctxt = - lift @@ Sc_rollup_inbox_storage.add_messages ctxt rollup payload + lift + @@ Sc_rollup_inbox_storage.add_external_messages ctxt rollup payload in return ctxt) ctxt diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index f20eef0005db0b7a4ed92a1d33fe5340b58ce490..3eecb4c1a8ce5600bad817cf54ed171aa369165a 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -502,6 +502,28 @@ module Sc_rollup_inbox = struct include Tezos_context_helpers.Context.Make_tree (Conf) (Store) + (* A message is tagged with a prefix. It consists of 5 bytes: + - Byte 0 is the tag (1 for external and 0 for internal). + - Bytes 1-4 is the length of the message encoded as: + [ prefix[1] * 256^3 + prefix[2] * 256^2 prefix[3] * 256^1 prefix[4]] + *) + let encode_external_message message = + let length = String.length message in + let pow m n = Z.to_int @@ Z.(of_int m ** n) in + let prefix = + [ + (* This is the tag of external messages. *) + 1; + (* The length of the message encoded in base 256. *) + length / pow 256 3 mod 256; + length / pow 256 2 mod 256; + length / 256 mod 256; + length mod 256; + ] + |> List.map Char.chr |> List.to_seq |> String.of_seq + in + Bytes.of_string (Printf.sprintf "%s%s" prefix message) + (* The hash for empty messages is the hash of empty bytes, and not of an empty tree. @@ -518,7 +540,7 @@ module Sc_rollup_inbox = struct | [] -> return tree | message :: rest -> let key = Data_encoding.Binary.to_string_exn Data_encoding.z counter in - let payload = Bytes.of_string message in + let payload = encode_external_message message in let* tree = add tree [key; "payload"] payload in build_current_messages_tree (Z.succ counter) tree rest