diff --git a/CHANGES.rst b/CHANGES.rst index 18be80f73bef7028b1e72b98b61a67b1cb6a2e7a..9b6d99e2d7d83bc0463d8470364071e905b276bf 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -273,6 +273,9 @@ Smart Rollup node - The command ``generate openapi`` now exports mimified JSON. (MR :gl:`!14908`) +- The rollup node can be configured to execute outbox message automatically with + filters. (MRs :gl:`!14498`, :gl:`!14499`) + Smart Rollup WASM Debugger -------------------------- diff --git a/src/lib_smart_rollup/outbox_message.ml b/src/lib_smart_rollup/outbox_message.ml index de19f1154479b4c281b08c717a32d2e6bbc3e691..0e457165e6b93e1f45dda7b5fb5e26c76db82852 100644 --- a/src/lib_smart_rollup/outbox_message.ml +++ b/src/lib_smart_rollup/outbox_message.ml @@ -59,3 +59,27 @@ let summary_encoding = (function Transaction_batch trs -> Some trs | _ -> None) (fun trs -> Transaction_batch trs); ] + +let pp_summary fmt = function + | Whitelist_update None -> Format.pp_print_string fmt "Remove whitelist" + | Whitelist_update (Some pkhs) -> + Format.fprintf + fmt + "Set whitelist to @[[@,%a]@]" + (Format.pp_print_list + ~pp_sep:(fun fmt () -> Format.fprintf fmt ",@ ") + Signature.Public_key_hash.pp) + pkhs + | Transaction_batch txs -> + Format.fprintf fmt "@[Transactions:@," ; + List.iter + (fun {destination; entrypoint; parameters; parameters_ty = _} -> + Format.fprintf + fmt + "@[%s:@ %s(%a)@]" + destination + entrypoint + Tezos_micheline.Micheline_printer.print_expr_unwrapped + (Tezos_micheline.Micheline_printer.printable Fun.id parameters)) + txs ; + Format.fprintf fmt "@]" diff --git a/src/lib_smart_rollup/outbox_message.mli b/src/lib_smart_rollup/outbox_message.mli index 0029d4fc25807d6c51cd71634db792f4d49d6d99..098dfa3ead94dbd82fe90d9af46aae50d39023f3 100644 --- a/src/lib_smart_rollup/outbox_message.mli +++ b/src/lib_smart_rollup/outbox_message.mli @@ -19,3 +19,5 @@ type summary = | Transaction_batch of transaction_summary list val summary_encoding : summary Data_encoding.t + +val pp_summary : Format.formatter -> summary -> unit diff --git a/src/lib_smart_rollup_node/batcher.ml b/src/lib_smart_rollup_node/batcher.ml index 31c32a52e86c58ffbc4ff9d73ea55985592aac80..00c1c99e3cd5b6d7806337fedb90b3b9256e79e3 100644 --- a/src/lib_smart_rollup_node/batcher.ml +++ b/src/lib_smart_rollup_node/batcher.ml @@ -331,7 +331,7 @@ let start_in_mode mode = match mode with | Batcher | Operator -> true | Observer | Accuser | Bailout | Maintenance -> false - | Custom ops -> purpose_matches_mode (Custom ops) Batching + | Custom ops -> purposes_matches_mode (Custom ops) [Batching] let init plugin (node_ctxt : _ Node_context.t) = let open Lwt_result_syntax in diff --git a/src/lib_smart_rollup_node/commitment_event.ml b/src/lib_smart_rollup_node/commitment_event.ml index 7cb4d777fcfe07029c655160c05d4c954cb1b1ae..16dd6acb112a0fec3335ca9b136bebbd5850ce33 100644 --- a/src/lib_smart_rollup_node/commitment_event.ml +++ b/src/lib_smart_rollup_node/commitment_event.ml @@ -114,6 +114,33 @@ module Simple = struct ("outbox_level", Data_encoding.int32) ("message_index", Data_encoding.int31) + let execute_outbox_message = + declare_3 + ~section + ~name:"smart_rollup_node_execute_outbox_message" + ~msg: + "Executing outbox message {message_index} of level {outbox_level}: \ + {message}" + ~level:Notice + ("outbox_level", Data_encoding.int32) + ("message_index", Data_encoding.int31) + ("message", Outbox_message.summary_encoding) + ~pp3:Outbox_message.pp_summary + + let outbox_message_execution_failed = + declare_4 + ~section + ~name:"smart_rollup_node_outbox_message_execution_failed" + ~msg: + "Execution of outbox message {message_index} of level {outbox_level} \ + ({message}) failed: {error}" + ~level:Warning + ("outbox_level", Data_encoding.int32) + ("message_index", Data_encoding.int31) + ("message", Outbox_message.summary_encoding) + ("error", trace_encoding) + ~pp3:Outbox_message.pp_summary + module Publisher = struct let section = section @ ["publisher"] @@ -167,6 +194,15 @@ let recover_bond staker = Simple.(emit recover_bond staker) let publish_execute_whitelist_update hash level index = Simple.(emit publish_execute_whitelist_update (hash, level, index)) +let execute_outbox_message ~outbox_level ~message_index message = + Simple.(emit execute_outbox_message (outbox_level, message_index, message)) + +let outbox_message_execution_failed ~outbox_level ~message_index message trace = + Simple.( + emit + outbox_message_execution_failed + (outbox_level, message_index, message, trace)) + module Publisher = struct let request_failed view worker_status errors = Simple.(emit Publisher.request_failed (view, worker_status, errors)) diff --git a/src/lib_smart_rollup_node/commitment_event.mli b/src/lib_smart_rollup_node/commitment_event.mli index 402771f2ca9248f4ceac56409f75d62322333b66..0457abc21b8b76e6bcc58e0e38b1a43fb6722ec2 100644 --- a/src/lib_smart_rollup_node/commitment_event.mli +++ b/src/lib_smart_rollup_node/commitment_event.mli @@ -65,6 +65,19 @@ val recover_bond : Signature.Public_key_hash.t -> unit Lwt.t val publish_execute_whitelist_update : Commitment.Hash.t -> int32 -> int -> unit Lwt.t +val execute_outbox_message : + outbox_level:int32 -> + message_index:int -> + Outbox_message.summary -> + unit Lwt.t + +val outbox_message_execution_failed : + outbox_level:int32 -> + message_index:int -> + Outbox_message.summary -> + tztrace -> + unit Lwt.t + (** Events emmitted by the Publisher worker *) module Publisher : sig (** [request_failed view status errors] emits the event that a worker diff --git a/src/lib_smart_rollup_node/configuration.ml b/src/lib_smart_rollup_node/configuration.ml index 8ecfec13c3aeadc515eb08091f8e1e71040e56dc..f4e905d75405568e19029b1ff96795bd3f52658b 100644 --- a/src/lib_smart_rollup_node/configuration.ml +++ b/src/lib_smart_rollup_node/configuration.ml @@ -53,6 +53,20 @@ type gc_parameters = { type history_mode = Archive | Full +type outbox_destination_filter = + | Any_destination + | Destination_among of string list + +type outbox_entrypoint_filter = + | Any_entrypoint + | Entrypoint_among of string list + +type outbox_message_filter = + | Transaction of { + destination : outbox_destination_filter; + entrypoint : outbox_entrypoint_filter; + } + type t = { sc_rollup_address : Tezos_crypto.Hashed.Smart_rollup_address.t; boot_sector_file : string option; @@ -68,6 +82,7 @@ type t = { loser_mode : Loser_mode.t; apply_unsafe_patches : bool; unsafe_pvm_patches : Pvm_patches.unsafe_patch list; + execute_outbox_messages_filter : outbox_message_filter list; dal_node_endpoint : Uri.t option; dac_observer_endpoint : Uri.t option; dac_timeout : Z.t option; @@ -235,6 +250,8 @@ let default_gc_parameters = let default_history_mode = Full +let default_execute_outbox_filter = [] + let string_of_history_mode = function Archive -> "archive" | Full -> "full" let history_mode_of_string = function @@ -411,6 +428,72 @@ let cors_encoding : Resto_cohttp.Cors.t Data_encoding.t = (req "allowed_headers" (list string)) (req "allowed_origins" (list string)) +let outbox_destination_filter_encoding = + let open Data_encoding in + union + [ + case + ~title:"any_destination" + ~description:"Accept any destination." + (Tag 0) + (constant "any") + (function Any_destination -> Some () | _ -> None) + (fun () -> Any_destination); + case + ~title:"destination_among" + ~description: + "Accept destination that matches the given list (in base58-check)." + (Tag 1) + (list string) + (function Destination_among l -> Some l | _ -> None) + (fun l -> Destination_among l); + ] + +let outbox_entrypoint_filter_encoding = + let open Data_encoding in + union + [ + case + ~title:"any_entrypoint" + ~description:"Accept any entrypoint." + (Tag 0) + (constant "any") + (function Any_entrypoint -> Some () | _ -> None) + (fun () -> Any_entrypoint); + case + ~title:"entrypoint_among" + ~description:"Accept entrypoint of the given list." + (Tag 1) + (list string) + (function Entrypoint_among l -> Some l | _ -> None) + (fun l -> Entrypoint_among l); + ] + +let outbox_messages_filter_encoding = + let open Data_encoding in + union + [ + case + ~title:"transaction_filter" + ~description: + "Accept transactions which match the filter on their destination and \ + entrypoint." + (Tag 0) + (obj1 + (req + "transaction" + (obj2 + (req "destination" outbox_destination_filter_encoding) + (req "entrypoint" outbox_entrypoint_filter_encoding)))) + (function + | Transaction {destination; entrypoint} -> + Some (destination, entrypoint)) + (fun (destination, entrypoint) -> Transaction {destination; entrypoint}); + ] + +let execute_outbox_messages_filter_encoding = + Data_encoding.list outbox_messages_filter_encoding + let encoding default_display : t Data_encoding.t = let open Data_encoding in let dft = @@ -435,6 +518,7 @@ let encoding default_display : t Data_encoding.t = mode; loser_mode; apply_unsafe_patches = _; + execute_outbox_messages_filter; unsafe_pvm_patches; dal_node_endpoint; dac_observer_endpoint; @@ -468,7 +552,8 @@ let encoding default_display : t Data_encoding.t = fee_parameters, mode, loser_mode, - unsafe_pvm_patches ) ), + unsafe_pvm_patches, + execute_outbox_messages_filter ) ), ( ( dal_node_endpoint, dac_observer_endpoint, dac_timeout, @@ -500,7 +585,8 @@ let encoding default_display : t Data_encoding.t = fee_parameters, mode, loser_mode, - unsafe_pvm_patches ) ), + unsafe_pvm_patches, + execute_outbox_messages_filter ) ), ( ( dal_node_endpoint, dac_observer_endpoint, dac_timeout, @@ -538,6 +624,7 @@ let encoding default_display : t Data_encoding.t = line. *) false; unsafe_pvm_patches; + execute_outbox_messages_filter; dal_node_endpoint; dac_observer_endpoint; dac_timeout; @@ -580,7 +667,7 @@ let encoding default_display : t Data_encoding.t = ~description:"Access control list" Tezos_rpc_http_server.RPC_server.Acl.policy_encoding default_acl)) - (obj7 + (obj8 (opt "metrics-addr" ~description:"Metrics address" string) (dft "performance-metrics" bool false) (dft @@ -613,7 +700,15 @@ let encoding default_display : t Data_encoding.t = "Unsafe patches to apply to the PVM. For tests only, don't \ set this value in production." (list Pvm_patches.unsafe_patch_encoding) - []))) + []) + (dft + "execute-outbox-messages-filter" + ~description: + "A filter to select which outbox messages the rollup will \ + execute automatically (must be in maintenance or operator \ + mode)." + execute_outbox_messages_filter_encoding + default_execute_outbox_filter))) (merge_objs (obj9 (opt "DAL node endpoint" Tezos_rpc.Encoding.uri_encoding) @@ -678,8 +773,11 @@ let can_inject mode (op_kind : Operation_kind.t) = let allowed_operations = operation_kinds_of_mode mode in List.mem ~equal:Stdlib.( = ) op_kind allowed_operations -let purpose_matches_mode (type k) mode (purpose : k Purpose.t) = - List.mem ~equal:Stdlib.( = ) (Purpose.Purpose purpose) (purposes_of_mode mode) +let purposes_matches_mode (type k) mode (purposes : k Purpose.t list) = + List.exists + (fun p -> + List.mem ~equal:Stdlib.( = ) (Purpose.Purpose p) (purposes_of_mode mode)) + purposes let refutation_player_buffer_levels = 5 @@ -788,6 +886,7 @@ module Cli = struct loser_mode = Option.value ~default:Loser_mode.no_failures loser_mode; apply_unsafe_patches; unsafe_pvm_patches = []; + execute_outbox_messages_filter = default_execute_outbox_filter; batcher = default_batcher; injector = { diff --git a/src/lib_smart_rollup_node/configuration.mli b/src/lib_smart_rollup_node/configuration.mli index db75ec9626f93d1cb0583fd3d3fea078082aab0d..151457e0a89cdcdc8f43d9344fe11d72cd04ccda 100644 --- a/src/lib_smart_rollup_node/configuration.mli +++ b/src/lib_smart_rollup_node/configuration.mli @@ -83,6 +83,26 @@ type history_mode = (** Only the history necessary to play refutation games is kept (i.e. after the LCC only) *) +(** Filter on destination of outbox message transactions. *) +type outbox_destination_filter = + | Any_destination (** Accept any destination. *) + | Destination_among of string list + (** Accept destination which match the given list (in base58-check). *) + +(** Filter on entrypoints of outbox message transactions. *) +type outbox_entrypoint_filter = + | Any_entrypoint (** Accept any entrypoint. *) + | Entrypoint_among of string list (** Accept entrypoints which are listed. *) + +(** Filter on outbox messages executed by the rollup node automatically. *) +type outbox_message_filter = + | Transaction of { + destination : outbox_destination_filter; + entrypoint : outbox_entrypoint_filter; + } + (** Accept transactions which match the filter on their destination and + entrypoint. *) + type t = { sc_rollup_address : Tezos_crypto.Hashed.Smart_rollup_address.t; boot_sector_file : string option; @@ -102,6 +122,7 @@ type t = { Decide whether we want to handle connections to multiple Dal nodes for different slot indexes. *) + execute_outbox_messages_filter : outbox_message_filter list; dal_node_endpoint : Uri.t option; dac_observer_endpoint : Uri.t option; dac_timeout : Z.t option; @@ -194,6 +215,9 @@ val default_gc_parameters : gc_parameters ({!Full}). *) val default_history_mode : history_mode +(** Default filter for executing outbox messages is only whitelist updates. *) +val default_execute_outbox_filter : outbox_message_filter list + val history_mode_encoding : history_mode Data_encoding.t (** [max_injector_retention_period] is the maximum allowed value for @@ -227,9 +251,9 @@ val operation_kinds_of_mode : mode -> Operation_kind.t list be injected based on the configuration settings. *) val can_inject : mode -> Operation_kind.t -> bool -(** [purpose_matches_mode mode purpose] returns true if and only if the given [mode] - supports the given [purpose]. *) -val purpose_matches_mode : mode -> 'kind Purpose.t -> bool +(** [purposes_matches_mode mode purposes] returns true if and only if the given + [mode] supports the given [purposes]. *) +val purposes_matches_mode : mode -> 'kind Purpose.t list -> bool (** Number of levels the refutation player waits until trying to play for a game state it already played before. *) diff --git a/src/lib_smart_rollup_node/dal_injection_queue.ml b/src/lib_smart_rollup_node/dal_injection_queue.ml index b7f175908f223fc4bf61a2d5b963be2d168e8882..40b985a5d430fa9cc05db20b3e591565ae768181 100644 --- a/src/lib_smart_rollup_node/dal_injection_queue.ml +++ b/src/lib_smart_rollup_node/dal_injection_queue.ml @@ -327,7 +327,7 @@ let start_in_mode mode = match mode with | Batcher | Operator -> true | Observer | Accuser | Bailout | Maintenance -> false - | Custom ops -> purpose_matches_mode (Custom ops) Batching + | Custom ops -> purposes_matches_mode (Custom ops) [Batching] let init (node_ctxt : _ Node_context.t) = let open Lwt_result_syntax in diff --git a/src/lib_smart_rollup_node/injector.ml b/src/lib_smart_rollup_node/injector.ml index 8391f3196ce3f030b2c6d5cdd2b73f725ae02a20..8c243d238efc1b22cc1377cdd80195bbb08fc1fc 100644 --- a/src/lib_smart_rollup_node/injector.ml +++ b/src/lib_smart_rollup_node/injector.ml @@ -147,12 +147,12 @@ module Parameters : (* TODO: https://gitlab.com/tezos/tezos/-/issues/4071 Think about which operations should be retried and when. *) match op with - | Cement _ | Publish _ -> - (* Cement and Publish commitments can be forgotten to free up the + | Cement _ | Publish _ | Execute_outbox_message _ -> + (* These operations can be forgotten to free up the injector as they are requeued by the node automatically. *) return Forget | Refute _ | Timeout _ | Add_messages _ | Recover_bond _ - | Execute_outbox_message _ | Publish_dal_commitment _ -> ( + | Publish_dal_commitment _ -> ( match classify_trace error with | Permanent | Outdated -> return Forget | Branch | Temporary -> return Retry)) diff --git a/src/lib_smart_rollup_node/node_context_loader.ml b/src/lib_smart_rollup_node/node_context_loader.ml index 46c1b990dbb17731a6aea2bf36af31181bce9c6e..d1027701c8891c38ce5116206b8c052111705c24 100644 --- a/src/lib_smart_rollup_node/node_context_loader.ml +++ b/src/lib_smart_rollup_node/node_context_loader.ml @@ -257,6 +257,8 @@ module For_snapshots = struct loser_mode; apply_unsafe_patches; unsafe_pvm_patches = []; + execute_outbox_messages_filter = + Configuration.default_execute_outbox_filter; dal_node_endpoint = None; dac_observer_endpoint = None; dac_timeout = None; @@ -369,6 +371,8 @@ module Internal_for_tests = struct loser_mode; apply_unsafe_patches = false; unsafe_pvm_patches = []; + execute_outbox_messages_filter = + Configuration.default_execute_outbox_filter; dal_node_endpoint = None; dac_observer_endpoint = None; dac_timeout = None; diff --git a/src/lib_smart_rollup_node/outbox_execution.ml b/src/lib_smart_rollup_node/outbox_execution.ml index aeff4abfd3f347146dda3e3af21d7e2805077d9e..9f0c13d52d9ba91b746a73ecc8d007e869719b1a 100644 --- a/src/lib_smart_rollup_node/outbox_execution.ml +++ b/src/lib_smart_rollup_node/outbox_execution.ml @@ -159,27 +159,145 @@ let execute_whitelist_update_message_aux (node_ctxt : _ Node_context.t) let publish_execute_whitelist_update_message (node_ctxt : _ Node_context.t) = let open Lwt_result_syntax in let operator = Node_context.get_operator node_ctxt Executing_outbox in - match operator with - | None -> - (* Configured to not execute whitelist update commitments *) - return_unit - | Some _ -> ( - let* cemented_commitment_and_proof = - executable_whitelist_update_message node_ctxt + unless (operator = None) @@ fun () -> + (* Configured to execute whitelist update commitments *) + let* cemented_commitment_and_proof = + executable_whitelist_update_message node_ctxt + in + let () = + Reference.map + (Option.map (fun private_info -> + let ({level; _} : Node_context.lcc) = Reference.get node_ctxt.lcc in + Node_context.{private_info with last_outbox_level_searched = level})) + node_ctxt.private_info + in + match cemented_commitment_and_proof with + | Some cemented_commitment_and_proof -> + execute_whitelist_update_message_aux + node_ctxt + cemented_commitment_and_proof + | None -> return_unit + +let outbox_message_destination_match_filter + (dest_filter : Configuration.outbox_destination_filter) dest = + match dest_filter with + | Any_destination -> true + | Destination_among allowed_dests -> + List.mem ~equal:String.equal dest allowed_dests + +let outbox_message_entrypoint_match_filter + (entrypoint_filter : Configuration.outbox_entrypoint_filter) entrypoint = + match entrypoint_filter with + | Any_entrypoint -> true + | Entrypoint_among allowed_entrypoints -> + List.mem ~equal:String.equal entrypoint allowed_entrypoints + +let outbox_message_transaction_match_filter destination_filter entrypoint_filter + (transaction : Outbox_message.transaction_summary) = + outbox_message_destination_match_filter + destination_filter + transaction.destination + && outbox_message_entrypoint_match_filter + entrypoint_filter + transaction.entrypoint + +let outbox_message_match_filter (message : Outbox_message.summary) + (filter : Configuration.outbox_message_filter) = + match (filter, message) with + | ( Transaction {destination = Any_destination; entrypoint = Any_entrypoint}, + Transaction_batch _ ) -> + true + | Transaction {destination; entrypoint}, Transaction_batch txs -> + List.for_all + (outbox_message_transaction_match_filter destination entrypoint) + txs + | _ -> false + +let publish_executable_messages (node_ctxt : _ Node_context.t) = + let open Lwt_result_syntax in + let operator = Node_context.get_operator node_ctxt Executing_outbox in + unless (operator = None) @@ fun () -> + (* Configured to execute outbox messages *) + let lcc = Reference.get node_ctxt.lcc in + let* lcc_block_hash = Node_context.hash_of_level node_ctxt lcc.level in + let* ctxt = Node_context.checkout_context node_ctxt lcc_block_hash in + let*! state = Context.PVMState.find ctxt in + match state with + | None -> failwith "No PVM state at LCC to execute outbox messages" + | Some state -> + let* executable_messages = + Node_context.get_executable_pending_outbox_messages node_ctxt + in + let*? (module Plugin) = + Protocol_plugins.proto_plugin_for_protocol + (Reference.get node_ctxt.current_protocol).hash in - let () = - Reference.map - (Option.map (fun private_info -> - let ({level; _} : Node_context.lcc) = - Reference.get node_ctxt.lcc - in - Node_context. - {private_info with last_outbox_level_searched = level})) - node_ctxt.private_info + let*! () = + let open Lwt_syntax in + List.iter_s + (fun (outbox_level, message_indexes) -> + let* outbox = + Plugin.Pvm.get_outbox_messages node_ctxt state ~outbox_level + in + List.iter_s + (fun message_index -> + let message = + List.assoc ~equal:Int.equal message_index outbox + in + match message with + | None -> assert false + | Some (Whitelist_update _) -> + (* Don't execute whitelist updates as this is done by + {!publish_execute_whitelist_update_message}. *) + return_unit + | Some message + when not + (List.exists + (outbox_message_match_filter message) + node_ctxt.config.execute_outbox_messages_filter) -> + (* Message does not match filter of config: ignore. *) + return_unit + | Some message -> ( + let*! () = + Commitment_event.execute_outbox_message + ~outbox_level + ~message_index + message + in + let* res = + let open Lwt_result_syntax in + let* output_proof = + Plugin.Pvm.produce_serialized_output_proof + node_ctxt + state + ~outbox_level + ~message_index + in + let outbox_message = + L1_operation.Execute_outbox_message + { + rollup = node_ctxt.config.sc_rollup_address; + cemented_commitment = lcc.commitment; + output_proof; + } + in + let* _hash = + Injector.add_pending_operation outbox_message + in + return_unit + in + match res with + | Error trace -> + let*! () = + Commitment_event.outbox_message_execution_failed + ~outbox_level + ~message_index + message + trace + in + return_unit + | Ok () -> return_unit)) + message_indexes) + executable_messages in - match cemented_commitment_and_proof with - | Some cemented_commitment_and_proof -> - execute_whitelist_update_message_aux - node_ctxt - cemented_commitment_and_proof - | None -> return_unit) + return_unit diff --git a/src/lib_smart_rollup_node/outbox_execution.mli b/src/lib_smart_rollup_node/outbox_execution.mli index ade37ac7c30ca6b971aaa516c425a709424fe608..3c6dcf607bad063fecbd459de0f8145efe4fccad 100644 --- a/src/lib_smart_rollup_node/outbox_execution.mli +++ b/src/lib_smart_rollup_node/outbox_execution.mli @@ -31,3 +31,7 @@ recent/closest one. *) val publish_execute_whitelist_update_message : Node_context.rw -> unit tzresult Lwt.t + +(** [publish_executable_message node_ctxt] publishes on L1 all outbox messages + that can be executed and that have not yet been executed. *) +val publish_executable_messages : Node_context.rw -> unit tzresult Lwt.t diff --git a/src/lib_smart_rollup_node/publisher.ml b/src/lib_smart_rollup_node/publisher.ml index f89e1b898e405e8fd83b38ad0e85c47f29587944..37215b791b5c07fa304e99af17e9d7bfc12c4fe5 100644 --- a/src/lib_smart_rollup_node/publisher.ml +++ b/src/lib_smart_rollup_node/publisher.ml @@ -87,7 +87,7 @@ let sc_rollup_challenge_window node_ctxt = let next_commitment_level node_ctxt last_commitment_level = add_level last_commitment_level (sc_rollup_commitment_period node_ctxt) -type state = Node_context.ro +type state = Node_context.rw let tick_of_level (node_ctxt : _ Node_context.t) inbox_level = let open Lwt_result_syntax in @@ -462,10 +462,13 @@ let on_cement_commitments (node_ctxt : state) = let* cementable_commitments = cementable_commitments node_ctxt in List.iter_es (cement_commitment node_ctxt) cementable_commitments +let on_execute_outbox (node_ctxt : state) = + Outbox_execution.publish_executable_messages node_ctxt + module Types = struct type nonrec state = state - type parameters = {node_ctxt : Node_context.ro} + type parameters = {node_ctxt : Node_context.rw} end module Name = struct @@ -497,6 +500,7 @@ module Handlers = struct match request with | Request.Publish -> protect @@ fun () -> on_publish_commitments state | Request.Cement -> protect @@ fun () -> on_cement_commitments state + | Request.Execute_outbox -> protect @@ fun () -> on_execute_outbox state type launch_error = error trace @@ -515,6 +519,7 @@ module Handlers = struct match r with | Request.Publish -> emit_and_return_errors errs | Request.Cement -> emit_and_return_errors errs + | Request.Execute_outbox -> emit_and_return_errors errs let on_completion _w r _ st = Commitment_event.Publisher.request_completed (Request.view r) st @@ -531,7 +536,6 @@ let worker_promise, worker_waker = Lwt.task () let start node_ctxt = let open Lwt_result_syntax in let*! () = Commitment_event.starting () in - let node_ctxt = Node_context.readonly node_ctxt in let+ worker = Worker.launch table () {node_ctxt} (module Handlers) in Lwt.wakeup worker_waker worker @@ -540,7 +544,10 @@ let start_in_mode mode = match mode with | Maintenance | Operator | Bailout -> true | Observer | Accuser | Batcher -> false - | Custom ops -> purpose_matches_mode (Custom ops) Operating + | Custom ops -> + purposes_matches_mode + (Custom ops) + [Operating; Cementing; Executing_outbox] let init (node_ctxt : _ Node_context.t) = let open Lwt_result_syntax in @@ -565,22 +572,32 @@ let worker = | Lwt.Fail exn -> fail (Error_monad.error_of_exn exn) | Lwt.Sleep -> Error Rollup_node_errors.No_publisher) -let worker_add_request ~request = +let worker_add_request condition ~request = let open Lwt_result_syntax in match Lazy.force worker with | Ok w -> let node_ctxt = Worker.state w in (* Bailout does not publish any commitment it only cement them. *) - unless (Node_context.is_bailout node_ctxt && request = Request.Publish) + unless + ((not (condition node_ctxt)) + || (Node_context.is_bailout node_ctxt && request = Request.Publish)) @@ fun () -> let*! (_pushed : bool) = Worker.Queue.push_request w request in return_unit | Error Rollup_node_errors.No_publisher -> return_unit | Error e -> tzfail e -let publish_commitments () = worker_add_request ~request:Request.Publish +let publish_commitments () = + worker_add_request ~request:Request.Publish (fun node_ctxt -> + Configuration.can_inject node_ctxt.config.mode Publish) + +let cement_commitments () = + worker_add_request ~request:Request.Cement (fun node_ctxt -> + Configuration.can_inject node_ctxt.config.mode Cement) -let cement_commitments () = worker_add_request ~request:Request.Cement +let execute_outbox () = + worker_add_request ~request:Request.Execute_outbox (fun node_ctxt -> + Configuration.can_inject node_ctxt.config.mode Execute_outbox_message) let shutdown () = match Lazy.force worker with diff --git a/src/lib_smart_rollup_node/publisher.mli b/src/lib_smart_rollup_node/publisher.mli index e7745a685385fd779b089fee85ea4a889ab3141f..32ca5080e93d418e5166f9bd356b08102968e83c 100644 --- a/src/lib_smart_rollup_node/publisher.mli +++ b/src/lib_smart_rollup_node/publisher.mli @@ -81,7 +81,7 @@ val recover_bond : _ Node_context.t -> unit tzresult Lwt.t (** Initialize worker for publishing and cementing commitments, if the rollup node mode supports it. *) -val init : _ Node_context.t -> unit tzresult Lwt.t +val init : Node_context.rw -> unit tzresult Lwt.t (** [publish_commitments] publishes the commitments that were not yet published up to the finalized head and which are after the last cemented @@ -96,6 +96,9 @@ val publish_commitments : unit -> unit tzresult Lwt.t appropriate mode. *) val cement_commitments : unit -> unit tzresult Lwt.t +(** [execute_outbox] execute pending outbox messages on L1. *) +val execute_outbox : unit -> unit tzresult Lwt.t + (** Stop worker for publishing and cementing commitments. *) val shutdown : unit -> unit Lwt.t diff --git a/src/lib_smart_rollup_node/publisher_worker_types.ml b/src/lib_smart_rollup_node/publisher_worker_types.ml index c10e697273e3a27772ce298eb43d33c53dde9db5..2084d99e0c1f98e92e4c0d62b1b453fc316f364d 100644 --- a/src/lib_smart_rollup_node/publisher_worker_types.ml +++ b/src/lib_smart_rollup_node/publisher_worker_types.ml @@ -27,6 +27,7 @@ module Request = struct type ('a, 'b) t = | Publish : (unit, error trace) t | Cement : (unit, error trace) t + | Execute_outbox : (unit, error trace) t type view = View : _ t -> view @@ -48,10 +49,17 @@ module Request = struct (obj1 (req "request" (constant "cement"))) (function View Cement -> Some () | _ -> None) (fun () -> View Cement); + case + (Tag 2) + ~title:"Execute_outbox" + (obj1 (req "request" (constant "execute_outbox"))) + (function View Execute_outbox -> Some () | _ -> None) + (fun () -> View Execute_outbox); ] let pp ppf (View r) = match r with | Publish -> Format.pp_print_string ppf "publish" | Cement -> Format.pp_print_string ppf "cement" + | Execute_outbox -> Format.pp_print_string ppf "execute_outbox" end diff --git a/src/lib_smart_rollup_node/publisher_worker_types.mli b/src/lib_smart_rollup_node/publisher_worker_types.mli index eed1fdcad468e10c17c8bb15d651c24ab699ee0c..eb43e0109428517bef228cb5362cb09bcf210708 100644 --- a/src/lib_smart_rollup_node/publisher_worker_types.mli +++ b/src/lib_smart_rollup_node/publisher_worker_types.mli @@ -30,6 +30,8 @@ module Request : sig (** Request to publish new commitments in L1. *) | Cement : (unit, error trace) t (** Request to cement commitments in L1. *) + | Execute_outbox : (unit, error trace) t + (** Request to execute outbox messages on L1. *) type view = View : _ t -> view diff --git a/src/lib_smart_rollup_node/refutation_coordinator.ml b/src/lib_smart_rollup_node/refutation_coordinator.ml index 95516e6ad29d956558525e79e21939b8d1e535f2..19170c91c0905285fc6f5fb8d1f35bd0c6732575 100644 --- a/src/lib_smart_rollup_node/refutation_coordinator.ml +++ b/src/lib_smart_rollup_node/refutation_coordinator.ml @@ -199,7 +199,7 @@ let start_in_mode mode = match mode with | Accuser | Bailout | Operator | Maintenance -> true | Observer | Batcher -> false - | Custom ops -> purpose_matches_mode (Custom ops) Operating + | Custom ops -> purposes_matches_mode (Custom ops) [Operating] let init (node_ctxt : _ Node_context.t) = let open Lwt_result_syntax in diff --git a/src/lib_smart_rollup_node/rollup_node_daemon.ml b/src/lib_smart_rollup_node/rollup_node_daemon.ml index 476f5287d4648505ad28f4f0b9b37a71e06d3029..650a01bacbc5ff35992a08b4845776ff23acb52d 100644 --- a/src/lib_smart_rollup_node/rollup_node_daemon.ml +++ b/src/lib_smart_rollup_node/rollup_node_daemon.ml @@ -368,6 +368,7 @@ let on_layer_1_head ({node_ctxt; _} as state) (head : Layer1.header) = notify_synchronization node_ctxt head.level ; let* () = Publisher.publish_commitments () in let* () = Publisher.cement_commitments () in + let* () = Publisher.execute_outbox () in let*! () = Daemon_event.new_heads_processed reorg.new_chain in let* () = Batcher.produce_batches () in let* () = Dal_injection_queue.produce_dal_slots () in diff --git a/tezt/lib_tezos/sc_rollup_helpers.ml b/tezt/lib_tezos/sc_rollup_helpers.ml index f4fe322dfcd2e37fac5b723b0507395effd4096d..533e54ed3ab7676d77467f03fdafd90bb05b068b 100644 --- a/tezt/lib_tezos/sc_rollup_helpers.ml +++ b/tezt/lib_tezos/sc_rollup_helpers.ml @@ -337,6 +337,7 @@ let setup_rollup ~kind ?hooks ?alias ?(mode = Sc_rollup_node.Operator) let originate_forward_smart_contract ?(src = Constant.bootstrap1.alias) client protocol = (* Originate forwarder contract to send internal messages to rollup *) + Log.info "Originate forward contract" ; let* alias, contract_id = Client.originate_contract_at ~amount:Tez.zero diff --git a/tezt/lib_tezos/sc_rollup_node.ml b/tezt/lib_tezos/sc_rollup_node.ml index 52ba3e0b9798638f8ab43707a774c5fa8d1780b1..be8c95e47488da31f8b4cdb12b1c0999f14dc8d1 100644 --- a/tezt/lib_tezos/sc_rollup_node.ml +++ b/tezt/lib_tezos/sc_rollup_node.ml @@ -26,7 +26,12 @@ type 'a known = Unknown | Known of 'a -type purpose = Operating | Batching | Cementing | Recovering +type purpose = + | Operating + | Batching + | Cementing + | Recovering + | Executing_outbox type operation_kind = | Publish @@ -198,7 +203,7 @@ module Parameters = struct type persistent_state = { data_dir : string; base_dir : string; - operators : (purpose * string) list; + mutable operators : (purpose * string) list; default_operator : string option; metrics_addr : string option; metrics_port : int; @@ -307,6 +312,7 @@ let string_of_purpose = function | Batching -> "batching" | Cementing -> "cementing" | Recovering -> "recovering" + | Executing_outbox -> "executing_outbox" (* Extracts operators from node state, handling custom mode, and formats them as "purpose:operator". Includes default operator if present. *) @@ -411,6 +417,24 @@ let patch_config_unsafe_pvm_patches pvm_patches = pvm_patches); ] ) +let patch_config_execute_outbox = + JSON.put + ( "execute-outbox-messages-filter", + JSON.annotate ~origin:"sc_rollup_node.execute_outbox" + @@ `A + [ + `O + [ + ( "transaction", + `O + [ + ("destination", `String "any"); + ("entrypoint", `String "any"); + ] ); + ] + (* execute all outbox messages transactions *); + ] ) + let trigger_ready sc_node value = let pending = sc_node.persistent_state.pending_ready in sc_node.persistent_state.pending_ready <- [] ; @@ -650,6 +674,9 @@ let change_node_mode sc_rollup_node mode = persistent_state = {sc_rollup_node.persistent_state with mode}; } +let change_operators sc_rollup_node operators = + sc_rollup_node.persistent_state.operators <- operators + let dump_durable_storage ~sc_rollup_node ~dump ?(block = "head") () = let cmd = [ diff --git a/tezt/lib_tezos/sc_rollup_node.mli b/tezt/lib_tezos/sc_rollup_node.mli index 15491fbb63b916c478c9cd243f180e0b347b93ea..879ee41be34f8cf7aca627ecc0c42624f1873f8a 100644 --- a/tezt/lib_tezos/sc_rollup_node.mli +++ b/tezt/lib_tezos/sc_rollup_node.mli @@ -32,7 +32,12 @@ (** Smart contract rollup node states. *) type t -type purpose = Operating | Batching | Cementing | Recovering +type purpose = + | Operating + | Batching + | Cementing + | Recovering + | Executing_outbox type operation_kind = | Publish @@ -284,6 +289,8 @@ type unsafe_pvm_patch = Increase_max_nb_ticks of int val patch_config_unsafe_pvm_patches : unsafe_pvm_patch list -> JSON.t -> JSON.t +val patch_config_execute_outbox : JSON.t -> JSON.t + val patch_durable_storage : t -> key:string -> value:string -> unit Lwt.t (** Wait until the sc node is ready. @@ -339,6 +346,10 @@ val change_node_and_restart : node. Change will take effect when the node is run/restart. *) val change_node_mode : t -> mode -> t +(** Change the rollup node operators. This does not terminate nor restart the + node. Change will take effect when the node is run/restart. *) +val change_operators : t -> (purpose * string) list -> unit + (** [dump_durable_storage ~sc_rollup_node ~dump ?string ()] writes to [dump] the current state of the WASM PVM from [sc_rollup_node]. *) val dump_durable_storage : diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index e1666322345afb3120404f741f8b68dd4cf25629..34574b87c95e5274baee17ed92c28c4fcc3b8493 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -686,20 +686,38 @@ let bake_until_lpc_updated ?hook ?at_least ?timeout client sc_rollup_node = in bake_until_event ?hook ?at_least ?timeout client ~event_name event +let bake_until_lcc_updated ?hook ?at_least ?timeout ~level client sc_rollup_node + = + let event_name = "smart_rollup_node_commitment_lcc_updated.v0" in + let event = + Sc_rollup_node.wait_for sc_rollup_node event_name @@ fun json -> + let lcc_level = JSON.(json |-> "level" |> as_int) in + Log.info "LCC updated to %d" lcc_level ; + if lcc_level >= level then Some lcc_level else None + in + bake_until_event ?hook ?at_least ?timeout client ~event_name event + +let bake_until_execute_outbox_message ?at_least ?timeout client rollup_node = + bake_until_event + ?at_least + ?timeout + client + ~event_name:"included_successful_operation" + @@ wait_for_included_successful_operation + rollup_node + ~operation_kind:"execute_outbox_message" + (** helpers that send a message then bake until the rollup node executes an output message (whitelist_update) *) let send_messages_then_bake_until_rollup_node_execute_output_message ~commitment_period ~challenge_window client rollup_node msg_list = let* () = send_text_messages ~hooks ~format:`Hex client msg_list in let* () = - bake_until_event + bake_until_execute_outbox_message ~timeout:5.0 ~at_least:(commitment_period + challenge_window + 1) client - ~event_name:"included_successful_operation" - @@ wait_for_included_successful_operation - rollup_node - ~operation_kind:"execute_outbox_message" + rollup_node and* res = wait_for_publish_execute_whitelist_update rollup_node in return res @@ -4017,9 +4035,9 @@ let test_refutation_reward_and_punishment ~kind = let test_outbox_message_generic ?supports ?regression ?expected_error ?expected_l1_error ~earliness ?entrypoint ~init_storage ~storage_ty ?outbox_parameters_ty ?boot_sector ~input_message ~expected_storage ~kind - ~message_kind = + ~message_kind ~auto_execute_outbox = let commitment_period = 2 and challenge_window = 5 in - let outbox_level = 5 in + let _outbox_level = 5 in let message_index = 0 in let message_kind_s = match message_kind with `Internal -> "intern" | `External -> "extern" @@ -4028,6 +4046,7 @@ let test_outbox_message_generic ?supports ?regression ?expected_error let outbox_parameters_ty_s = Option.value ~default:"no_parameters_ty" outbox_parameters_ty in + let auto_s = if auto_execute_outbox then ", auto_execute_outbox" else "" in test_full_scenario ?supports ?regression @@ -4042,20 +4061,36 @@ let test_outbox_message_generic ?supports ?regression ?expected_error variant = Some (Format.sprintf - "%s, entrypoint: %%%s, eager: %d, %s, %s" + "%s, entrypoint: %%%s, eager: %d, %s, %s%s" init_storage entrypoint_s earliness message_kind_s - outbox_parameters_ty_s); + outbox_parameters_ty_s + auto_s); description = "output exec"; } ~uses:(fun _protocol -> [Constant.octez_codec]) @@ fun protocol rollup_node sc_rollup node client -> - let* () = Sc_rollup_node.run rollup_node sc_rollup [] in let src = Constant.bootstrap1.public_key_hash in let src2 = Constant.bootstrap2.public_key_hash in + let* () = + if auto_execute_outbox then ( + Sc_rollup_node.change_operators rollup_node [(Executing_outbox, src2)] ; + let* () = + Process.check @@ Sc_rollup_node.spawn_config_init rollup_node sc_rollup + in + Sc_rollup_node.Config_file.update + rollup_node + Sc_rollup_node.patch_config_execute_outbox ; + Log.info "config updated" ; + unit) + else unit + in + let* () = Sc_rollup_node.run ~event_level:`Debug rollup_node sc_rollup [] in + let* _level = Sc_rollup_node.wait_sync ~timeout:30. rollup_node in let originate_target_contract () = + Log.info "Originate target contract" ; let prg = Printf.sprintf {| @@ -4101,6 +4136,7 @@ let test_outbox_message_generic ?supports ?regression ?expected_error return address in let check_contract_execution address expected_storage = + Log.info "Check contract execution" ; let* storage = Client.contract_storage address client in return @@ Check.( @@ -4139,6 +4175,7 @@ let test_outbox_message_generic ?supports ?regression ?expected_error unexecutable in let perform_rollup_execution_and_cement source_address target_address = + Log.info "Perform rollup execution and cement" ; let* payload = input_message protocol target_address in let* () = match payload with @@ -4158,7 +4195,7 @@ let test_outbox_message_generic ?supports ?regression ?expected_error in Client.bake_for_and_wait client in - let* _ = Sc_rollup_node.wait_sync rollup_node ~timeout:10. in + let* outbox_level = Sc_rollup_node.wait_sync rollup_node ~timeout:10. in let* outbox_l2_block = Sc_rollup_node.RPC.call rollup_node @@ Sc_rollup_rpc.get_global_block ~outbox:true () @@ -4171,12 +4208,21 @@ let test_outbox_message_generic ?supports ?regression ?expected_error Check.((nb_outbox_transactions_in_block = [1]) (list int)) ~error_msg:"Block has %L outbox transactions but expected %R" ; let* () = check_outbox_execution outbox_level `Unexecutable in - let blocks_to_wait = - 3 + (2 * commitment_period) + challenge_window - earliness + let* _ = + bake_until_lcc_updated + ~timeout:100. + client + rollup_node + ~level:outbox_level + ~hook:(fun _ -> + let* _level = Sc_rollup_node.wait_sync ~timeout:10. rollup_node in + unit) in - repeat blocks_to_wait @@ fun () -> Client.bake_for_and_wait client + return outbox_level in - let trigger_outbox_message_execution ?expected_l1_error address = + let trigger_outbox_message_execution ?expected_l1_error ~outbox_level address + = + Log.info "Trigger outbox message execution" ; let parameters = "37" in let check_expected_outbox () = let* outbox = @@ -4225,49 +4271,64 @@ let test_outbox_message_generic ?supports ?regression ?expected_error assert (JSON.encode outbox = "[]") ; return None in - let* answer = check_expected_outbox () in - match (answer, expected_error) with - | Some _, Some _ -> assert false - | None, None -> failwith "Unexpected error during proof generation" - | None, Some _ -> unit - | Some {commitment_hash; proof}, None -> ( - match expected_l1_error with - | None -> - let* () = check_outbox_execution outbox_level `Executable in - let*! () = - Client.Sc_rollup.execute_outbox_message - ~hooks - ~burn_cap:(Tez.of_int 10) - ~rollup:sc_rollup - ~src:src2 - ~commitment_hash - ~proof - client - in - Client.bake_for_and_wait client - | Some msg -> - let*? process = - Client.Sc_rollup.execute_outbox_message - ~hooks - ~burn_cap:(Tez.of_int 10) - ~rollup:sc_rollup - ~src:src2 - ~commitment_hash - ~proof - client - in - Process.check_error ~msg process) + if Option.is_some expected_error then unit + else + let* () = check_outbox_execution outbox_level `Executable in + if auto_execute_outbox then + bake_until_execute_outbox_message + ~at_least:1 + ~timeout:30. + client + rollup_node + else + let* answer = check_expected_outbox () in + match answer with + | None -> failwith "Unexpected error during proof generation" + | Some {commitment_hash; proof} -> ( + match expected_l1_error with + | None -> + let* () = check_outbox_execution outbox_level `Executable in + let*! () = + Client.Sc_rollup.execute_outbox_message + ~hooks + ~burn_cap:(Tez.of_int 1) + ~rollup:sc_rollup + ~src:src2 + ~commitment_hash + ~proof + client + in + let* () = Client.bake_for_and_wait client in + let* _ = Sc_rollup_node.wait_sync rollup_node ~timeout:10. in + let* _ = Client.RPC.call client @@ RPC.get_chain_block () in + unit + (* Client.bake_for_and_wait client *) + | Some msg -> + let*? process = + Client.Sc_rollup.execute_outbox_message + ~hooks + ~burn_cap:(Tez.of_int 10) + ~rollup:sc_rollup + ~src:src2 + ~commitment_hash + ~proof + client + in + Process.check_error ~msg process) in let* target_contract_address = originate_target_contract () in + let* _level = Sc_rollup_node.wait_sync ~timeout:30. rollup_node in let* source_contract_address = originate_forward_smart_contract client protocol in - let* () = + let* _level = Sc_rollup_node.wait_sync ~timeout:30. rollup_node in + let* outbox_level = perform_rollup_execution_and_cement source_contract_address target_contract_address in let* () = Client.bake_for_and_wait client in + let* _level = Sc_rollup_node.wait_sync ~timeout:30. rollup_node in let consumed_outputs () = Node.RPC.call node @@ RPC.get_chain_block_context_smart_rollups_smart_rollup_consumed_outputs @@ -4279,7 +4340,10 @@ let test_outbox_message_generic ?supports ?regression ?expected_error Check.((prior_consumed_outputs = []) (list int)) ~error_msg:"Expected empty list found %L for consumed outputs" ; let* () = - trigger_outbox_message_execution ?expected_l1_error target_contract_address + trigger_outbox_message_execution + ?expected_l1_error + ~outbox_level + target_contract_address in match expected_error with | None -> @@ -4299,7 +4363,8 @@ let test_outbox_message_generic ?supports ?regression ?expected_error let test_outbox_message ?supports ?regression ?expected_error ?expected_l1_error ~earliness ?entrypoint ?(init_storage = "0") ?(storage_ty = "int") - ?(outbox_parameters = "37") ?outbox_parameters_ty ~kind ~message_kind = + ?(outbox_parameters = "37") ?outbox_parameters_ty ~kind ~message_kind + ~auto_execute_outbox = let wrap payload = match message_kind with | `Internal -> `Internal payload @@ -4368,16 +4433,20 @@ let test_outbox_message ?supports ?regression ?expected_error ?expected_l1_error ~expected_storage ~message_kind ~kind + ~auto_execute_outbox let test_outbox_message protocols ~kind = - let test (expected_error, earliness, entrypoint, message_kind) = + let test + (expected_error, earliness, entrypoint, message_kind, auto_execute_outbox) + = test_outbox_message ?expected_error ~earliness ?entrypoint ~message_kind protocols - ~kind ; + ~kind + ~auto_execute_outbox ; (* arith does not support, yet, the typed outbox messages *) if kind <> "arith" then test_outbox_message @@ -4389,18 +4458,31 @@ let test_outbox_message protocols ~kind = ~outbox_parameters_ty:"int" protocols ~kind + ~auto_execute_outbox in List.iter test [ - (None, 0, None, `Internal); - (None, 0, Some "aux", `Internal); - (Some (Base.rex ".*Invalid claim about outbox"), 5, None, `Internal); - (Some (Base.rex ".*Invalid claim about outbox"), 5, Some "aux", `Internal); - (None, 0, None, `External); - (None, 0, Some "aux", `External); - (Some (Base.rex ".*Invalid claim about outbox"), 5, None, `External); - (Some (Base.rex ".*Invalid claim about outbox"), 5, Some "aux", `External); + (None, 0, None, `Internal, false); + (None, 0, Some "aux", `Internal, false); + (Some (Base.rex ".*Invalid claim about outbox"), 5, None, `Internal, false); + ( Some (Base.rex ".*Invalid claim about outbox"), + 5, + Some "aux", + `Internal, + false ); + (None, 0, None, `External, false); + (None, 0, Some "aux", `External, false); + (Some (Base.rex ".*Invalid claim about outbox"), 5, None, `External, false); + ( Some (Base.rex ".*Invalid claim about outbox"), + 5, + Some "aux", + `External, + false ); + (None, 0, None, `Internal, true); + (None, 0, Some "aux", `Internal, true); + (None, 0, None, `External, true); + (None, 0, Some "aux", `External, true); ] ; if kind <> "arith" then ( (* wrong type for the parameters *) @@ -4412,7 +4494,8 @@ let test_outbox_message protocols ~kind = ~message_kind:`Internal ~outbox_parameters_ty:"string" protocols - ~kind ; + ~kind + ~auto_execute_outbox:false ; test_outbox_message ~expected_l1_error: (Base.rex ".*or a parameter was supplied of the wrong type") @@ -4423,7 +4506,8 @@ let test_outbox_message protocols ~kind = ~storage_ty:"string" ~outbox_parameters_ty:"int" protocols - ~kind) + ~kind + ~auto_execute_outbox:false) let test_rpcs ~kind ?(boot_sector = Sc_rollup_helpers.default_boot_sector_of ~kind)