diff --git a/src/proto_016_PtMumbai/lib_injector/injector_errors.ml b/src/proto_016_PtMumbai/lib_injector/injector_errors.ml index b2e5b98bebc3859edeace13a3be59f6a56bed10c..c1ba94461b902745572446cdd53139c1f9232d48 100644 --- a/src/proto_016_PtMumbai/lib_injector/injector_errors.ml +++ b/src/proto_016_PtMumbai/lib_injector/injector_errors.ml @@ -27,7 +27,7 @@ type error += No_worker_for_source of Tezos_crypto.Signature.Public_key_hash.t let () = register_error_kind - ~id:"rollups.injector.no_worker_for_source" + ~id:"injector.no_worker_for_source" ~title:"No injecting queue for source" ~description: "An L1 operation could not be queued because its source has no worker." @@ -47,7 +47,7 @@ type error += No_worker_for_tag of string let () = register_error_kind - ~id:"rollups.injector.no_worker_for_tag" + ~id:"injector.no_worker_for_tag" ~title:"No injecting queue for tag" ~description: "An L1 operation could not be queued because its tag has no worker." @@ -57,27 +57,11 @@ let () = (function No_worker_for_tag t -> Some t | _ -> None) (fun t -> No_worker_for_tag t) -type error += No_worker_for_operation of L1_operation.t - -let () = - register_error_kind - ~id:"rollups.injector.no_worker_for_operation" - ~title:"This operation is not supported by injector" - ~description: - "An L1 operation could not be queued because the injector does not \ - handle it." - ~pp:(fun ppf op -> - Format.fprintf ppf "No worker for operation %a" L1_operation.pp op) - `Permanent - Data_encoding.(obj1 (req "operation" L1_operation.encoding)) - (function No_worker_for_operation op -> Some op | _ -> None) - (fun op -> No_worker_for_operation op) - type error += Step_failed of string let () = register_error_kind - ~id:"rollups.injector.step_failed" + ~id:"injector.step_failed" ~title:"A step failed in the injector" ~description:"A step failed in the injector." ~pp:(fun ppf step -> diff --git a/src/proto_016_PtMumbai/lib_injector/injector_errors.mli b/src/proto_016_PtMumbai/lib_injector/injector_errors.mli index 1c39b4ffc53ab88fe47b98ba7347bb3b48a16fbe..3925237d599dafa53e9b0ce6133a10fd1497d62c 100644 --- a/src/proto_016_PtMumbai/lib_injector/injector_errors.mli +++ b/src/proto_016_PtMumbai/lib_injector/injector_errors.mli @@ -31,8 +31,5 @@ type error += No_worker_for_source of Tezos_crypto.Signature.Public_key_hash.t injected. *) type error += No_worker_for_tag of string -(** Error when the injector does not handle the operation. *) -type error += No_worker_for_operation of L1_operation.t - (** Error when a step of the injector failed. *) type error += Step_failed of string diff --git a/src/proto_016_PtMumbai/lib_injector/injector_events.ml b/src/proto_016_PtMumbai/lib_injector/injector_events.ml index b1a4cedb3371658db03f34f74e799076a5cf56fe..d5cdbecd1b3c75c286e869b176bcdc8cae89cc08 100644 --- a/src/proto_016_PtMumbai/lib_injector/injector_events.ml +++ b/src/proto_016_PtMumbai/lib_injector/injector_events.ml @@ -24,225 +24,243 @@ (*****************************************************************************) open Injector_worker_types +open Injector_sigs -module Make (Rollup : Injector_sigs.PARAMETERS) = struct - module Tags = Injector_tags.Make (Rollup.Tag) - include Internal_event.Simple - - let section = Rollup.events_section - - let declare_1 ~name ~msg ~level ?pp1 enc1 = - declare_3 - ~section - ~name - ~msg:("[{signer}: {tags}] " ^ msg) - ~level - ("signer", Tezos_crypto.Signature.Public_key_hash.encoding) - ("tags", Tags.encoding) - enc1 - ~pp1:Tezos_crypto.Signature.Public_key_hash.pp_short - ~pp2:Tags.pp - ?pp3:pp1 - - let declare_2 ~name ~msg ~level ?pp1 ?pp2 enc1 enc2 = - declare_4 - ~section - ~name - ~msg:("[{signer}: {tags}] " ^ msg) - ~level - ("signer", Tezos_crypto.Signature.Public_key_hash.encoding) - ("tags", Tags.encoding) - enc1 - enc2 - ~pp1:Tezos_crypto.Signature.Public_key_hash.pp_short - ~pp2:Tags.pp - ?pp3:pp1 - ?pp4:pp2 - - let declare_3 ~name ~msg ~level ?pp1 ?pp2 ?pp3 enc1 enc2 enc3 = - declare_5 - ~section - ~name - ~msg:("[{signer}: {tags}] " ^ msg) - ~level - ("signer", Tezos_crypto.Signature.Public_key_hash.encoding) - ("tags", Tags.encoding) - enc1 - enc2 - enc3 - ~pp1:Tezos_crypto.Signature.Public_key_hash.pp_short - ~pp2:Tags.pp - ?pp3:pp1 - ?pp4:pp2 - ?pp5:pp3 - - let request_failed = - declare_3 - ~name:"request_failed" - ~msg:"request {view} failed ({worker_status}): {errors}" - ~level:Warning - ("view", Request.encoding) - ~pp1:Request.pp - ("worker_status", Worker_types.request_status_encoding) - ~pp2:Worker_types.pp_status - ("errors", Error_monad.trace_encoding) - ~pp3:Error_monad.pp_print_trace - - let request_completed_notice = - declare_2 - ~name:"request_completed_notice" - ~msg:"{view} {worker_status}" - ~level:Notice - ("view", Request.encoding) - ("worker_status", Worker_types.request_status_encoding) - ~pp1:Request.pp - ~pp2:Worker_types.pp_status - - let request_completed_debug = - declare_2 - ~name:"request_completed_debug" - ~msg:"{view} {worker_status}" - ~level:Debug - ("view", Request.encoding) - ("worker_status", Worker_types.request_status_encoding) - ~pp1:Request.pp - ~pp2:Worker_types.pp_status - - let new_tezos_head = - declare_1 - ~name:"new_tezos_head" - ~msg:"processing new Tezos head {head}" - ~level:Debug - ("head", Block_hash.encoding) - - let injecting_pending = - declare_1 - ~name:"injecting_pending" - ~msg:"Injecting {count} pending operations" - ~level:Notice - ("count", Data_encoding.int31) - - let pp_operations_list ppf operations = - Format.fprintf - ppf - "@[%a@]" - (Format.pp_print_list L1_operation.pp) - operations - - let pp_operations_hash_list ppf operations = - Format.fprintf - ppf - "@[%a@]" - (Format.pp_print_list L1_operation.Hash.pp) - operations - - let injecting_operations = - declare_1 - ~name:"injecting_operations" - ~msg:"Injecting operations: {operations}" - ~level:Notice - ("operations", Data_encoding.list L1_operation.encoding) - ~pp1:pp_operations_list - - let simulating_operations = - declare_2 - ~name:"simulating_operations" - ~msg:"Simulating operations (force = {force}): {operations}" - ~level:Debug - ("operations", Data_encoding.list L1_operation.encoding) - ("force", Data_encoding.bool) - ~pp1:pp_operations_list - - let dropping_operation = - declare_2 - ~name:"dropping_operation" - ~msg:"Dropping operation {operation} failing with {error}" - ~level:Notice - ("operation", L1_operation.encoding) - ~pp1:L1_operation.pp - ("error", Environment.Error_monad.trace_encoding) - ~pp2:Environment.Error_monad.pp_trace - - let injected = - declare_2 - ~name:"injected" - ~msg:"Injected {nb} operations in {oph}" - ~level:Notice - ("nb", Data_encoding.int31) - ("oph", Operation_hash.encoding) - - let add_pending = - declare_1 - ~name:"add_pending" - ~msg:"Add {operation} to pending" - ~level:Notice - ("operation", L1_operation.encoding) - ~pp1:L1_operation.pp - - let retry_operation = - declare_1 - ~name:"retry_operation" - ~msg:"Retry {operation}" - ~level:Notice - ("operation", L1_operation.encoding) - ~pp1:L1_operation.pp - - let included = - declare_3 - ~name:"included" - ~msg:"Included operations of {block} at level {level}: {operations}" - ~level:Notice - ("block", Block_hash.encoding) - ("level", Data_encoding.int32) - ("operations", Data_encoding.list L1_operation.Hash.encoding) - ~pp3:pp_operations_hash_list - - let revert_operations = - declare_1 - ~name:"revert_operations" - ~msg:"Reverting operations: {operations}" - ~level:Notice - ("operations", Data_encoding.list L1_operation.Hash.encoding) - ~pp1:pp_operations_hash_list - - let confirmed_level = - declare_1 - ~name:"confirmed_level" - ~msg:"Confirmed Tezos level {level}" - ~level:Notice - ("level", Data_encoding.int32) - - let confirmed_operations = - declare_2 - ~name:"confirmed_operations" - ~msg:"Confirmed operations of level {level}: {operations}" - ~level:Notice - ("level", Data_encoding.int32) - ("operations", Data_encoding.list L1_operation.Hash.encoding) - ~pp2:pp_operations_hash_list - - let loaded_from_disk = - declare_2 - ~name:"loaded_from_disk" - ~msg:"Loaded {nb} elements in {kind} from disk" - ~level:Notice - ("nb", Data_encoding.int31) - ("kind", Data_encoding.string) - - let corrupted_operation_on_disk = - declare_2 - ~name:"corrupted_operation_on_disk" - ~msg:"Ignoring unreadable file {file} on disk: {error}" - ~level:Warning - ("file", Data_encoding.string) - ("error", Error_monad.trace_encoding) - ~pp1:Format.pp_print_string - ~pp2:Error_monad.pp_print_trace - - let inject_wait = - declare_1 - ~name:"inject_wait" - ~msg:"Waiting {delay} seconds to trigger injection" - ~level:Notice - ("delay", Data_encoding.float) -end +module Make + (Parameters : PARAMETERS) + (Tags : module type of Injector_tags.Make (Parameters.Tag)) + (Operation : PARAM_OPERATION) + (Inj_operation : INJECTOR_OPERATION with type operation = Operation.t) + (Request : module type of Request (Inj_operation)) = + struct + include Internal_event.Simple + + let section = Parameters.events_section + + let declare_1 ~name ~msg ~level ?pp1 enc1 = + declare_3 + ~section + ~name + ~msg:("[{signer}: {tags}] " ^ msg) + ~level + ("signer", Signature.Public_key_hash.encoding) + ("tags", Tags.encoding) + enc1 + ~pp1:Signature.Public_key_hash.pp_short + ~pp2:Tags.pp + ?pp3:pp1 + + let declare_2 ~name ~msg ~level ?pp1 ?pp2 enc1 enc2 = + declare_4 + ~section + ~name + ~msg:("[{signer}: {tags}] " ^ msg) + ~level + ("signer", Signature.Public_key_hash.encoding) + ("tags", Tags.encoding) + enc1 + enc2 + ~pp1:Signature.Public_key_hash.pp_short + ~pp2:Tags.pp + ?pp3:pp1 + ?pp4:pp2 + + let declare_3 ~name ~msg ~level ?pp1 ?pp2 ?pp3 enc1 enc2 enc3 = + declare_5 + ~section + ~name + ~msg:("[{signer}: {tags}] " ^ msg) + ~level + ("signer", Signature.Public_key_hash.encoding) + ("tags", Tags.encoding) + enc1 + enc2 + enc3 + ~pp1:Signature.Public_key_hash.pp_short + ~pp2:Tags.pp + ?pp3:pp1 + ?pp4:pp2 + ?pp5:pp3 + + let request_failed = + declare_3 + ~name:"request_failed" + ~msg:"request {view} failed ({worker_status}): {errors}" + ~level:Warning + ("view", Request.encoding) + ~pp1:Request.pp + ("worker_status", Worker_types.request_status_encoding) + ~pp2:Worker_types.pp_status + ("errors", Error_monad.trace_encoding) + ~pp3:Error_monad.pp_print_trace + + let request_completed_notice = + declare_2 + ~name:"request_completed_notice" + ~msg:"{view} {worker_status}" + ~level:Notice + ("view", Request.encoding) + ("worker_status", Worker_types.request_status_encoding) + ~pp1:Request.pp + ~pp2:Worker_types.pp_status + + let request_completed_debug = + declare_2 + ~name:"request_completed_debug" + ~msg:"{view} {worker_status}" + ~level:Debug + ("view", Request.encoding) + ("worker_status", Worker_types.request_status_encoding) + ~pp1:Request.pp + ~pp2:Worker_types.pp_status + + let new_tezos_head = + declare_1 + ~name:"new_tezos_head" + ~msg:"processing new Tezos head {head}" + ~level:Debug + ("head", Block_hash.encoding) + + let injecting_pending = + declare_1 + ~name:"injecting_pending" + ~msg:"injecting {count} pending operations" + ~level:Notice + ("count", Data_encoding.int31) + + let pp_operations_list ppf operations = + Format.fprintf + ppf + "@[%a@]" + (Format.pp_print_list Operation.pp) + operations + + let pp_operations_hash_list ppf operations = + Format.fprintf + ppf + "@[%a@]" + (Format.pp_print_list Inj_operation.Hash.pp) + operations + + let number_of_operations_in_queue = + declare_1 + ~name:"number_of_operations_in_queue" + ~msg: + "injector's queue: there is currently {number_of_operations} \ + operations waiting to be injected" + ~level:Info + ("number_of_operations", Data_encoding.int31) + + let considered_operations_info = + declare_1 + ~name:"considered_operations_info" + ~msg: + "injector's queue: the following operations are being considered \ + for injection {operations}" + ~level:Debug + ("operations", Data_encoding.list Operation.encoding) + ~pp1:pp_operations_list + + let dropped_operations = + declare_1 + ~name:"dropped_operations" + ~msg: + "dropping operations: the following operations are dropped \ + {operations}" + ~level:Debug + ("operations", Data_encoding.list Operation.encoding) + ~pp1:pp_operations_list + + let simulating_operations = + declare_2 + ~name:"simulating_operations" + ~msg:"simulating operations (force = {force}): {operations}" + ~level:Debug + ("operations", Data_encoding.list Operation.encoding) + ("force", Data_encoding.bool) + ~pp1:pp_operations_list + + let dropping_operation = + declare_2 + ~name:"dropping_operation" + ~msg:"dropping operation {operation} failing with {error}" + ~level:Notice + ("operation", Operation.encoding) + ~pp1:Operation.pp + ("error", Error_monad.trace_encoding) + ~pp2:Error_monad.pp_print_trace + + let injected = + declare_2 + ~name:"injected" + ~msg:"injected {nb} operations in {oph}" + ~level:Notice + ("nb", Data_encoding.int31) + ("oph", Operation_hash.encoding) + + let add_pending = + declare_1 + ~name:"add_pending" + ~msg:"add {operation} to pending" + ~level:Notice + ("operation", Operation.encoding) + ~pp1:Operation.pp + + let retry_operation = + declare_1 + ~name:"retry_operation" + ~msg:"retry {operation}" + ~level:Notice + ("operation", Operation.encoding) + ~pp1:Operation.pp + + let included = + declare_3 + ~name:"included" + ~msg:"included operations of {block} at level {level}: {operations}" + ~level:Notice + ("block", Block_hash.encoding) + ("level", Data_encoding.int32) + ("operations", Data_encoding.list Inj_operation.Hash.encoding) + ~pp3:pp_operations_hash_list + + let revert_operations = + declare_1 + ~name:"revert_operations" + ~msg:"reverting operations: {operations}" + ~level:Notice + ("operations", Data_encoding.list Inj_operation.Hash.encoding) + ~pp1:pp_operations_hash_list + + let confirmed_level = + declare_1 + ~name:"confirmed_level" + ~msg:"confirmed Tezos level {level}" + ~level:Notice + ("level", Data_encoding.int32) + + let loaded_from_disk = + declare_2 + ~name:"loaded_from_disk" + ~msg:"loaded {nb} elements in {kind} from disk" + ~level:Notice + ("nb", Data_encoding.int31) + ("kind", Data_encoding.string) + + let corrupted_operation_on_disk = + declare_2 + ~name:"corrupted_operation_on_disk" + ~msg:"ignoring unreadable file {file} on disk: {error}" + ~level:Warning + ("file", Data_encoding.string) + ("error", Error_monad.trace_encoding) + ~pp1:Format.pp_print_string + ~pp2:Error_monad.pp_print_trace + + let inject_wait = + declare_1 + ~name:"inject_wait" + ~msg:"waiting {delay} seconds to trigger injection" + ~level:Notice + ("delay", Data_encoding.float) + end diff --git a/src/proto_016_PtMumbai/lib_injector/injector_functor.ml b/src/proto_016_PtMumbai/lib_injector/injector_functor.ml index 524e09df9dc3782992e10b306e2d8b8514645112..16143a52f13733030d20cc91bca15275316747ba 100644 --- a/src/proto_016_PtMumbai/lib_injector/injector_functor.ml +++ b/src/proto_016_PtMumbai/lib_injector/injector_functor.ml @@ -54,28 +54,134 @@ let injector_context (cctxt : #Protocol_client_context.full) = Format.ksprintf Stdlib.failwith "Injector client wants to exit %d" code end -module Make (Rollup : PARAMETERS) = struct - module Tags = Injector_tags.Make (Rollup.Tag) - module Tags_table = Hashtbl.Make (Rollup.Tag) +let manager_operation_result_status (type kind) + (op_result : kind Apply_results.manager_operation_result) : operation_status + = + match op_result with + | Applied _ -> Successful + | Backtracked (_, None) -> Unsuccessful Backtracked + | Skipped _ -> Unsuccessful Skipped + | Backtracked (_, Some err) + (* Backtracked because internal operation failed *) + | Failed (_, err) -> + Unsuccessful (Failed (Environment.wrap_tztrace err)) + +let operation_result_status (type kind) + (op_result : kind Apply_results.contents_result) : operation_status = + match op_result with + | Preendorsement_result _ -> Successful + | Endorsement_result _ -> Successful + | Dal_attestation_result _ -> Successful + | Seed_nonce_revelation_result _ -> Successful + | Vdf_revelation_result _ -> Successful + | Double_endorsement_evidence_result _ -> Successful + | Double_preendorsement_evidence_result _ -> Successful + | Double_baking_evidence_result _ -> Successful + | Activate_account_result _ -> Successful + | Proposals_result -> Successful + | Ballot_result -> Successful + | Drain_delegate_result _ -> Successful + | Manager_operation_result {operation_result; _} -> + manager_operation_result_status operation_result + +let operation_contents_status (type kind) + (contents : kind Apply_results.contents_result_list) ~index : + operation_status tzresult = + let rec rec_status : + type kind. int -> kind Apply_results.contents_result_list -> _ = + fun n -> function + | Apply_results.Single_result _ when n <> 0 -> + error_with "No operation with index %d" index + | Single_result result -> Ok (operation_result_status result) + | Cons_result (result, _rest) when n = 0 -> + Ok (operation_result_status result) + | Cons_result (_result, rest) -> rec_status (n - 1) rest + in + rec_status index contents + +let operation_status (operation : Protocol.operation_receipt) ~index : + operation_status tzresult = + match (operation : _) with + | No_operation_metadata -> + error_with "Cannot find operation status because metadata is missing" + | Operation_metadata {contents} -> operation_contents_status contents ~index + +module Make (Parameters : PARAMETERS) = struct + module Tags = Injector_tags.Make (Parameters.Tag) + module Tags_table = Hashtbl.Make (Parameters.Tag) + module POperation = Parameters.Operation + module Inj_operation = Injector_operation.Make (POperation) + module Request = Request (Inj_operation) + + type injected_info = { + op : Inj_operation.t; + oph : Operation_hash.t; + op_index : int; + } + + type included_info = { + op : Inj_operation.t; + oph : Operation_hash.t; + op_index : int; + l1_block : Block_hash.t; + l1_level : int32; + } + + type status = + | Pending of POperation.t + | Injected of injected_info + | Included of included_info + + let injected_info_encoding = + let open Data_encoding in + conv + (fun ({op; oph; op_index} : injected_info) -> (op, (oph, op_index))) + (fun (op, (oph, op_index)) -> {op; oph; op_index}) + @@ merge_objs + Inj_operation.encoding + (obj1 + (req + "layer1" + (obj2 + (req "operation_hash" Operation_hash.encoding) + (req "operation_index" int31)))) + + let included_info_encoding = + let open Data_encoding in + conv + (fun {op; oph; op_index; l1_block; l1_level} -> + (op, (oph, op_index, l1_block, l1_level))) + (fun (op, (oph, op_index, l1_block, l1_level)) -> + {op; oph; op_index; l1_block; l1_level}) + @@ merge_objs + Inj_operation.encoding + (obj1 + (req + "layer1" + (obj4 + (req "operation_hash" Operation_hash.encoding) + (req "operation_index" int31) + (req "block_hash" Block_hash.encoding) + (req "level" int32)))) module Op_queue = Disk_persistence.Make_queue (struct let name = "operations_queue" end) - (L1_operation.Hash) - (L1_operation) + (Inj_operation.Hash) + (Inj_operation) module Injected_operations = Disk_persistence.Make_table (struct - include L1_operation.Hash.Table + include Inj_operation.Hash.Table type value = injected_info let name = "injected_operations" - let string_of_key = L1_operation.Hash.to_b58check + let string_of_key = Inj_operation.Hash.to_b58check - let key_of_string = L1_operation.Hash.of_b58check_opt + let key_of_string = Inj_operation.Hash.of_b58check_opt let value_encoding = injected_info_encoding end) @@ -83,7 +189,7 @@ module Make (Rollup : PARAMETERS) = struct module Injected_ophs = Disk_persistence.Make_table (struct include Operation_hash.Table - type value = L1_operation.Hash.t list + type value = Inj_operation.Hash.t list let name = "injected_ophs" @@ -91,7 +197,7 @@ module Make (Rollup : PARAMETERS) = struct let key_of_string = Operation_hash.of_b58check_opt - let value_encoding = Data_encoding.list L1_operation.Hash.encoding + let value_encoding = Data_encoding.list Inj_operation.Hash.encoding end) (** The part of the state which gathers information about injected @@ -106,15 +212,15 @@ module Make (Rollup : PARAMETERS) = struct } module Included_operations = Disk_persistence.Make_table (struct - include L1_operation.Hash.Table + include Inj_operation.Hash.Table type value = included_info let name = "included_operations" - let string_of_key = L1_operation.Hash.to_b58check + let string_of_key = Inj_operation.Hash.to_b58check - let key_of_string = L1_operation.Hash.of_b58check_opt + let key_of_string = Inj_operation.Hash.of_b58check_opt let value_encoding = included_info_encoding end) @@ -122,7 +228,7 @@ module Make (Rollup : PARAMETERS) = struct module Included_in_blocks = Disk_persistence.Make_table (struct include Block_hash.Table - type value = int32 * L1_operation.Hash.t list + type value = int32 * Inj_operation.Hash.t list let name = "included_in_blocks" @@ -132,7 +238,7 @@ module Make (Rollup : PARAMETERS) = struct let value_encoding = let open Data_encoding in - obj2 (req "level" int32) (req "l1_ops" (list L1_operation.Hash.encoding)) + obj2 (req "level" int32) (req "l1_ops" (list Inj_operation.Hash.encoding)) end) (** The part of the state which gathers information about @@ -162,15 +268,16 @@ module Make (Rollup : PARAMETERS) = struct (** The information about included operations. {b Note}: Operations which are confirmed are simply removed from the state and do not appear anymore. *) - rollup_node_state : Rollup.rollup_node_state; - (** The state of the rollup node. *) + state : Parameters.state; retention_period : int; (** Number of blocks for which the injector keeps the included information. *) } module Event = struct - include Injector_events.Make (Rollup) + include + Injector_events.Make (Parameters) (Tags) (POperation) (Inj_operation) + (Request) let emit1 e state x = emit e (state.signer.pkh, state.tags, x) @@ -179,17 +286,14 @@ module Make (Rollup : PARAMETERS) = struct let emit3 e state x y z = emit e (state.signer.pkh, state.tags, x, y, z) end - let init_injector cctxt constants ~data_dir rollup_node_state - ~retention_period ~signer strategy tags = + let init_injector cctxt constants ~data_dir state ~retention_period ~signer + strategy tags = let open Lwt_result_syntax in let* signer = get_signer cctxt signer in let data_dir = Filename.concat data_dir "injector" in let*! () = Lwt_utils_unix.create_dir data_dir in let filter op_proj op = - let {L1_operation.manager_operation = Manager op; _} = op_proj op in - match Rollup.operation_tag op with - | None -> false - | Some t -> Tags.mem t tags + Tags.mem (Parameters.operation_tag (op_proj op)) tags in let warn_unreadable = (* Warn of corrupted files but don't fail *) @@ -206,20 +310,20 @@ module Make (Rollup : PARAMETERS) = struct ~warn_unreadable ~capacity:50_000 ~data_dir - ~filter:(filter (fun op -> op)) + ~filter:(filter (fun op -> op.Inj_operation.operation)) in let*! () = emit_event_loaded "operations_queue" @@ Op_queue.length queue in (* Very coarse approximation for the number of operation we expect for each block *) let n = - Tags.fold (fun t acc -> acc + Rollup.table_estimated_size t) tags 0 + Tags.fold (fun t acc -> acc + Parameters.table_estimated_size t) tags 0 in let* injected_operations = Injected_operations.load_from_disk ~warn_unreadable ~initial_size:n ~data_dir - ~filter:(filter (fun (i : injected_info) -> i.op)) + ~filter:(filter (fun (i : injected_info) -> i.op.operation)) in let*! () = emit_event_loaded "injected_operations" @@ -231,7 +335,7 @@ module Make (Rollup : PARAMETERS) = struct ~warn_unreadable ~initial_size:((confirmations + retention_period) * n) ~data_dir - ~filter:(filter (fun (i : included_info) -> i.op)) + ~filter:(filter (fun (i : included_info) -> i.op.operation)) in let*! () = emit_event_loaded "included_operations" @@ -271,7 +375,7 @@ module Make (Rollup : PARAMETERS) = struct queue; injected = {injected_operations; injected_ophs}; included = {included_operations; included_in_blocks}; - rollup_node_state; + state; retention_period; } @@ -280,15 +384,25 @@ module Make (Rollup : PARAMETERS) = struct let add_pending_operation ?(retry = false) state op = let open Lwt_result_syntax in let*! () = - Event.(emit1 (if retry then retry_operation else add_pending)) state op + Event.(emit1 (if retry then retry_operation else add_pending)) + state + op.Inj_operation.operation + in + let* () = Op_queue.replace state.queue op.hash op in + let*! () = + Event.(emit1 number_of_operations_in_queue) + state + (Op_queue.length state.queue) in - Op_queue.replace state.queue op.L1_operation.hash op + return_unit (** Mark operations as injected (in [oph]). *) let add_injected_operations state oph operations = let open Lwt_result_syntax in let infos = - List.map (fun op -> (op.L1_operation.hash, {op; oph})) operations + List.map + (fun (op_index, op) -> (op.Inj_operation.hash, {op; oph; op_index})) + operations in let* () = Injected_operations.replace_seq @@ -300,18 +414,22 @@ module Make (Rollup : PARAMETERS) = struct (** [add_included_operations state oph l1_block l1_level operations] marks the [operations] as included (in the L1 batch [oph]) in the Tezos block [l1_block] of level [l1_level]. *) - let add_included_operations state oph l1_block l1_level operations = + let add_included_operations state l1_block l1_level + (operations : injected_info list) = let open Lwt_result_syntax in let*! () = Event.(emit3 included) state l1_block l1_level - (List.map (fun o -> o.L1_operation.hash) operations) + (List.map + (fun (o : injected_info) -> o.op.Inj_operation.hash) + operations) in let infos = List.map - (fun op -> (op.L1_operation.hash, {op; oph; l1_block; l1_level})) + (fun ({op; oph; op_index} : injected_info) -> + (op.Inj_operation.hash, {op; oph; op_index; l1_block; l1_level})) operations in let* () = @@ -386,8 +504,8 @@ module Make (Rollup : PARAMETERS) = struct let fee_parameter_of_operations state ops = List.fold_left - (fun acc {L1_operation.manager_operation = Manager op; _} -> - let param = Rollup.fee_parameter state op in + (fun acc {Inj_operation.operation; _} -> + let param = Parameters.fee_parameter state operation in Injection. { minimal_fees = Tez.max acc.minimal_fees param.minimal_fees; @@ -431,7 +549,7 @@ module Make (Rollup : PARAMETERS) = struct quotas) and [results] are the results of the simulation. See {!inject_operations} for the specification of [must_succeed]. *) let rec simulate_operations ~must_succeed state - (operations : L1_operation.t list) = + (operations : Inj_operation.t list) = let open Lwt_result_syntax in let open Annotated_manager_operation in let force = @@ -445,13 +563,17 @@ module Make (Rollup : PARAMETERS) = struct succeed *) match must_succeed with `All -> false | `At_least_one -> true) in - let*! () = Event.(emit2 simulating_operations) state operations force in - let fee_parameter = - fee_parameter_of_operations state.rollup_node_state operations + let*! () = + Event.(emit2 simulating_operations) + state + (List.map (fun o -> o.Inj_operation.operation) operations) + force in + let fee_parameter = fee_parameter_of_operations state.state operations in let annotated_operations = List.map - (fun {L1_operation.manager_operation = Manager operation; _} -> + (fun {Inj_operation.operation; _} -> + let (Manager operation) = POperation.to_manager_operation operation in Annotated_manager_operation (Injection.prepare_manager_operation ~fee:Limit.unknown @@ -484,6 +606,11 @@ module Make (Rollup : PARAMETERS) = struct in match simulation_result with | Error trace -> + let*! () = + Event.(emit1 number_of_operations_in_queue) + state + (Op_queue.length state.queue) + in let exceeds_quota = TzTrace.fold (fun exceeds -> function @@ -506,6 +633,18 @@ module Make (Rollup : PARAMETERS) = struct simulate_operations ~must_succeed state operations else fail trace | Ok (_, op, _, result) -> + let nb_ops = List.length operations in + let nb_packed_ops = + let {protocol_data = Operation_data {contents; _}; _} = op in + Alpha_context.Operation.to_list (Contents_list contents) + |> List.length + in + (* packed_op can have reveal operations added automatically. *) + let start_index = nb_packed_ops - nb_ops in + (* Add indexes of operations in the packed, i.e. batched, operation. *) + let operations = + List.mapi (fun i op -> (i + start_index, op)) operations + in return (op, operations, Apply_results.Contents_result_list result) let inject_on_node state ~nb @@ -545,51 +684,39 @@ module Make (Rollup : PARAMETERS) = struct "or-batches" by iteratively removing operations that fail from the desired batch. *) let rec inject_operations ~must_succeed state - (operations : L1_operation.t list) = + (operations : Inj_operation.t list) = let open Lwt_result_syntax in let* packed_op, operations, result = trace (Step_failed "simulation") @@ simulate_operations ~must_succeed state operations in - let results = Apply_results.to_list result in + let (Contents_result_list contents_result) = result in let failure = ref false in let* rev_non_failing_operations = - List.fold_left2_s - ~when_different_lengths: - [ - Exn - (Failure - "Unexpected error: length of operations and result differ in \ - simulation"); - ] - (fun acc op (Apply_results.Contents_result result) -> - match result with - | Apply_results.Manager_operation_result - { - operation_result = - Failed (_, error) | Backtracked (_, Some error); - _; - } -> - let*! () = Event.(emit2 dropping_operation) state op error in + List.fold_left_es + (fun acc (index, op) -> + let open Lwt_result_syntax in + let*? status = operation_contents_status contents_result ~index in + match status with + | Unsuccessful (Failed error) -> + let*! () = + Event.(emit2 dropping_operation) + state + op.Inj_operation.operation + error + in failure := true ; - Lwt.return acc - | Apply_results.Manager_operation_result - { - operation_result = Applied _ | Backtracked (_, None) | Skipped _; - _; - } -> + return acc + | Successful | Unsuccessful (Backtracked | Skipped | Other_branch) -> (* Not known to be failing *) - Lwt.return (op :: acc) - | _ -> - (* Only manager operations *) - assert false) + return (op :: acc)) [] operations - results in if !failure then - (* Invariant: must_succeed = `At_least_one, otherwise the simulation would have - returned an error. We try to inject without the failing operation. *) + (* Invariant: must_succeed = `At_least_one, otherwise the simulation would + have returned an error. We try to inject without the failing + operation. *) let operations = List.rev rev_non_failing_operations in inject_operations ~must_succeed state operations else @@ -605,10 +732,12 @@ module Make (Rollup : PARAMETERS) = struct let size_l1_batch state rev_ops = let contents_list = List.map - (fun (op : L1_operation.t) -> - let (Manager operation) = op.manager_operation in + (fun (op : Inj_operation.t) -> let {fee; counter; gas_limit; storage_limit} = - Rollup.approximate_fee_bound state.rollup_node_state operation + Parameters.approximate_fee_bound state.state op.operation + in + let (Manager operation) = + POperation.to_manager_operation op.operation in let contents = Manager_operation @@ -645,7 +774,7 @@ module Make (Rollup : PARAMETERS) = struct (** Retrieve as many operations from the queue while remaining below the size limit. *) let get_operations_from_queue ~size_limit state = - let exception Reached_limit of L1_operation.t list in + let exception Reached_limit of Inj_operation.t list in let rev_ops = try Op_queue.fold @@ -668,11 +797,10 @@ module Make (Rollup : PARAMETERS) = struct let+ operations_to_drop = List.fold_left_es (fun to_drop op -> - let (Manager operation) = op.L1_operation.manager_operation in let*! retry = - Rollup.retry_unsuccessful_operation - state.rollup_node_state - operation + Parameters.retry_unsuccessful_operation + state.state + op.Inj_operation.operation (Failed err) in match retry with @@ -693,6 +821,11 @@ module Make (Rollup : PARAMETERS) = struct let open Lwt_result_syntax in (* Retrieve and remove operations from pending *) let operations_to_inject = get_operations_from_queue ~size_limit state in + let*! () = + Event.(emit1 considered_operations_info) + state + (List.map (fun o -> o.Inj_operation.operation) operations_to_inject) + in match operations_to_inject with | [] -> return_unit | _ -> ( @@ -702,9 +835,9 @@ module Make (Rollup : PARAMETERS) = struct (List.length operations_to_inject) in let must_succeed = - Rollup.batch_must_succeed + Parameters.batch_must_succeed @@ List.map - (fun op -> op.L1_operation.manager_operation) + (fun op -> op.Inj_operation.operation) operations_to_inject in let*! res = @@ -718,15 +851,23 @@ module Make (Rollup : PARAMETERS) = struct (* Injection succeeded, remove from pending and add to injected *) let* () = List.iter_es - (fun op -> Op_queue.remove state.queue op.L1_operation.hash) + (fun (_index, op) -> + Op_queue.remove state.queue op.Inj_operation.hash) injected_operations in add_injected_operations state oph injected_operations | `Ignored operations_to_drop -> (* Injection failed but we ignore the failure. *) + let*! () = + Event.(emit1 dropped_operations) + state + (List.map + (fun o -> o.Inj_operation.operation) + operations_to_drop) + in let* () = List.iter_es - (fun op -> Op_queue.remove state.queue op.L1_operation.hash) + (fun op -> Op_queue.remove state.queue op.Inj_operation.hash) operations_to_drop in return_unit) @@ -745,60 +886,42 @@ module Make (Rollup : PARAMETERS) = struct (* No operations injected by us *) return_unit | _ -> - let apply (type kind) acc ~source:_ (op : kind manager_operation) - (result : kind Apply_results.manager_operation_result) = - match op with - | Reveal _ -> - (* Ignore public key revelations because, when present, they are - added by the injection function automatically. If we don't - ignore them, we may have more operations than we think we - injected (and end up in the assert false below). *) - acc - | _ -> ( - let* (injected : injected_info list), included, to_retry = acc in - let info, injected = - match injected with - | [] -> assert false - (* We should have the same number of injected operations and - included operations. *) - | i :: rest -> (i, rest) + let* included, to_retry = + List.fold_left_es + (fun (included, to_retry) (info : injected_info) -> + let*? receipt = + match operation.receipt with + | Empty -> + error_with + "Empty receipt for %a" + Operation_hash.pp + operation.hash + | Too_large -> + error_with + "Receipt too large for %a" + Operation_hash.pp + operation.hash + | Receipt r -> Ok r in - match result with - | Applied _ -> return (injected, info.op :: included, to_retry) - | _ -> ( - let status = - match result with - | Applied _ -> assert false - | Backtracked (_, _) -> Backtracked - | Skipped _ -> Skipped - | Failed (_, err) -> Failed (Environment.wrap_tztrace err) - in + let*? status = operation_status receipt ~index:info.op_index in + match status with + | Successful -> return (info :: included, to_retry) + | Unsuccessful status -> ( let*! retry = - Rollup.retry_unsuccessful_operation - state.rollup_node_state - op + Parameters.retry_unsuccessful_operation + state.state + info.op.operation status in match retry with - | Retry -> return (injected, included, info.op :: to_retry) - | Forget -> return (injected, included, to_retry) + | Retry -> return (included, info.op :: to_retry) + | Forget -> return (included, to_retry) | Abort err -> fail err)) + ([], []) + injected_infos in - let apply_internal acc ~source:_ _op _result = acc in - let* unhandled_injected, included, to_retry = - Layer1_services.process_manager_operations - (return (injected_infos, [], [])) - [[operation]] - {apply; apply_internal} - in - assert (unhandled_injected = []) ; let* () = - add_included_operations - state - operation.hash - block - level - (List.rev included) + add_included_operations state block level (List.rev included) in List.iter_es (add_pending_operation ~retry:true state) @@ -833,11 +956,10 @@ module Make (Rollup : PARAMETERS) = struct maybe put at the front of the queue for re-injection. *) List.iter_es (fun {op; _} -> - let {L1_operation.manager_operation = Manager mop; _} = op in let*! requeue = - Rollup.retry_unsuccessful_operation - state.rollup_node_state - mop + Parameters.retry_unsuccessful_operation + state.state + op.operation Other_branch in match requeue with @@ -910,7 +1032,7 @@ module Make (Rollup : PARAMETERS) = struct cctxt : Protocol_client_context.full; constants : Constants.t; data_dir : string; - rollup_node_state : Rollup.rollup_node_state; + state : Parameters.state; retention_period : int; strategy : injection_strategy; tags : Tags.t; @@ -950,21 +1072,14 @@ module Make (Rollup : PARAMETERS) = struct let on_launch _w signer Types. - { - cctxt; - constants; - data_dir; - rollup_node_state; - retention_period; - strategy; - tags; - } = + {cctxt; constants; data_dir; state; retention_period; strategy; tags} + = trace (Step_failed "initialization") @@ init_injector cctxt constants ~data_dir - rollup_node_state + state ~retention_period ~signer strategy @@ -1004,7 +1119,7 @@ module Make (Rollup : PARAMETERS) = struct (* TODO: https://gitlab.com/tezos/tezos/-/issues/2754 Injector worker in a separate process *) let init (cctxt : #Protocol_client_context.full) ~data_dir - ?(retention_period = 0) rollup_node_state ~signers = + ?(retention_period = 0) state ~signers = let open Lwt_result_syntax in assert (retention_period >= 0) ; let signers_map = @@ -1048,7 +1163,7 @@ module Make (Rollup : PARAMETERS) = struct cctxt = (cctxt :> Protocol_client_context.full); constants; data_dir; - rollup_node_state; + state; retention_period; strategy; tags; @@ -1072,25 +1187,22 @@ module Make (Rollup : PARAMETERS) = struct Format.kasprintf (fun s -> error (No_worker_for_tag s)) "%a" - Rollup.Tag.pp + Parameters.Tag.pp tag | Some worker -> ok worker let add_pending_operation ?source op = let open Lwt_result_syntax in - let l1_operation = L1_operation.make op in + let operation = Inj_operation.make op in let*? w = match source with | Some source -> worker_of_signer source - | None -> ( - match Rollup.operation_tag op with - | None -> error (No_worker_for_operation l1_operation) - | Some tag -> worker_of_tag tag) + | None -> worker_of_tag (Parameters.operation_tag op) in let*! (_pushed : bool) = - Worker.Queue.push_request w (Request.Add_pending l1_operation) + Worker.Queue.push_request w (Request.Add_pending operation) in - return l1_operation.hash + return operation.hash let new_tezos_head h reorg = let open Lwt_syntax in @@ -1186,7 +1298,7 @@ module Make (Rollup : PARAMETERS) = struct let op_status_in_worker state l1_hash = match Op_queue.find_opt state.queue l1_hash with - | Some op -> Some (Pending op) + | Some op -> Some (Pending op.operation) | None -> ( match Injected_operations.find state.injected.injected_operations l1_hash diff --git a/src/proto_016_PtMumbai/lib_injector/injector_functor.mli b/src/proto_016_PtMumbai/lib_injector/injector_functor.mli index 183066b02a9a379d9a7e3dac3a57762ee18ae091..1c7d4f7c8f8c2791072b541bf3c122ec1058796c 100644 --- a/src/proto_016_PtMumbai/lib_injector/injector_functor.mli +++ b/src/proto_016_PtMumbai/lib_injector/injector_functor.mli @@ -26,4 +26,7 @@ open Injector_sigs module Make (P : PARAMETERS) : - S with type rollup_node_state := P.rollup_node_state and type tag := P.Tag.t + S + with type state := P.state + and type tag := P.Tag.t + and type operation := P.Operation.t diff --git a/src/proto_016_PtMumbai/lib_injector/injector_operation.ml b/src/proto_016_PtMumbai/lib_injector/injector_operation.ml new file mode 100644 index 0000000000000000000000000000000000000000..b3738be6ba84293cad0aa2b46d169c7d753905b8 --- /dev/null +++ b/src/proto_016_PtMumbai/lib_injector/injector_operation.ml @@ -0,0 +1,68 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Injector_sigs + +module Make (O : PARAM_OPERATION) : + INJECTOR_OPERATION with type operation = O.t = struct + module Hash = + Tezos_crypto.Blake2B.Make + (Tezos_crypto.Base58) + (struct + let name = "injector_operation_hash" + + let title = "An identifier (hash) for an operation in the injector" + + let b58check_prefix = "\064\007\206" (* iop(53) *) + + let size = None + end) + + let () = + Tezos_crypto.Base58.check_encoded_prefix Hash.b58check_encoding "iop" 53 + + type operation = O.t + + type hash = Hash.t + + type t = {hash : hash; operation : O.t} + + let hash_inner_operation op = + Hash.hash_bytes [Data_encoding.Binary.to_bytes_exn O.encoding op] + + let make operation = + let hash = hash_inner_operation operation in + {hash; operation} + + let encoding = + let open Data_encoding in + conv + (fun {hash; operation} -> (hash, operation)) + (fun (hash, operation) -> {hash; operation}) + @@ obj2 (req "hash" Hash.encoding) (req "operation" O.encoding) + + let pp ppf {hash; operation} = + Format.fprintf ppf "%a (%a)" O.pp operation Hash.pp hash +end diff --git a/src/proto_016_PtMumbai/lib_injector/l1_operation.mli b/src/proto_016_PtMumbai/lib_injector/injector_operation.mli similarity index 71% rename from src/proto_016_PtMumbai/lib_injector/l1_operation.mli rename to src/proto_016_PtMumbai/lib_injector/injector_operation.mli index 6dc5bdeb9cd85f191a23eafe80a7fc403ee888a1..97f9eadd65a570d8cc360f4b7e9a1db89a22f189 100644 --- a/src/proto_016_PtMumbai/lib_injector/l1_operation.mli +++ b/src/proto_016_PtMumbai/lib_injector/injector_operation.mli @@ -23,26 +23,6 @@ (* *) (*****************************************************************************) -open Protocol.Alpha_context +open Injector_sigs -(** Hash with b58check encoding mop(53), for hashes of L1 manager operations *) -module Hash : Tezos_crypto.Intfs.HASH - -(** Alias for L1 operations hashes *) -type hash = Hash.t - -(** The type of L1 operations that are injected on Tezos by the rollup node *) -type t = private { - hash : hash; (** The hash of the L1 manager operation (without the source) *) - manager_operation : packed_manager_operation; (** The manager operation *) -} - -(** [make op] returns an L1 operation with the corresponding hash. *) -val make : 'a manager_operation -> t - -(** Encoding for L1 operations *) -val encoding : t Data_encoding.t - -(** Pretty printer for L1 operations. Only the relevant part for the rollup node - is printed. *) -val pp : Format.formatter -> t -> unit +module Make (O : PARAM_OPERATION) : INJECTOR_OPERATION with type operation = O.t diff --git a/src/proto_016_PtMumbai/lib_injector/injector_sigs.ml b/src/proto_016_PtMumbai/lib_injector/injector_sigs.ml index 4326e1f4e6d820006ae038295a36b5c1486e4dc6..f763dee30a820fca6a359d7bad1a689b10276fe5 100644 --- a/src/proto_016_PtMumbai/lib_injector/injector_sigs.ml +++ b/src/proto_016_PtMumbai/lib_injector/injector_sigs.ml @@ -56,6 +56,8 @@ type unsuccessful_status = the same batch. *) | Failed of error trace (** The operation failed with the provided error. *) +type operation_status = Successful | Unsuccessful of unsuccessful_status + (** Action to be taken for unsuccessful operation. *) type retry_action = | Retry (** The operation is retried by being re-queued for injection. *) @@ -64,60 +66,6 @@ type retry_action = (** The error for the failing operation should be propagated at a higher level. *) -(** Information stored about an L1 operation that was injected on a Tezos - node. *) -type injected_info = { - op : L1_operation.t; (** The L1 manager operation. *) - oph : Operation_hash.t; - (** The hash of the operation which contains [op] (this can be an L1 batch - of several manager operations). *) -} - -(** Information stored about an L1 operation that was included in a Tezos - block. *) -type included_info = { - op : L1_operation.t; (** The L1 manager operation. *) - oph : Operation_hash.t; - (** The hash of the operation which contains [op] (this can be an L1 batch - of several manager operations). *) - l1_block : Block_hash.t; - (** The hash of the L1 block in which the operation was included. *) - l1_level : int32; (** The level of [l1_block]. *) -} - -(** Status of an operation in the injector. *) -type status = - | Pending of L1_operation.t (** The operation is pending injection. *) - | Injected of injected_info - (** The operation has been injected successfully in the node. *) - | Included of included_info - (** The operation has been included in a L1 block. *) - -let injected_info_encoding = - let open Data_encoding in - conv - (fun ({op; oph} : injected_info) -> (op, oph)) - (fun (op, oph) -> {op; oph}) - @@ merge_objs - L1_operation.encoding - (obj1 - (req "layer1" (obj1 (req "operation_hash" Operation_hash.encoding)))) - -let included_info_encoding = - let open Data_encoding in - conv - (fun {op; oph; l1_block; l1_level} -> (op, (oph, l1_block, l1_level))) - (fun (op, (oph, l1_block, l1_level)) -> {op; oph; l1_block; l1_level}) - @@ merge_objs - L1_operation.encoding - (obj1 - (req - "layer1" - (obj3 - (req "operation_hash" Operation_hash.encoding) - (req "block_hash" Block_hash.encoding) - (req "level" int32)))) - (** Signature for tags used in injector *) module type TAG = sig include Stdlib.Set.OrderedType @@ -129,14 +77,56 @@ module type TAG = sig val encoding : t Data_encoding.t end +module type PARAM_OPERATION = sig + (** The abstract type of operations to inject *) + type t + + (** An encoding for injector's operations *) + val encoding : t Data_encoding.t + + (** Convert an injector operation to a manager_operation of the protocol *) + val to_manager_operation : t -> packed_manager_operation + + (** Pretty-printing injector's operations *) + val pp : Format.formatter -> t -> unit +end + +(** Internal representation of injector operations. *) +module type INJECTOR_OPERATION = sig + type operation + + (** Hash with b58check encoding iop(53), for hashes of injector operations *) + module Hash : Tezos_crypto.Intfs.HASH + + (** Alias for L1 operations hashes *) + type hash = Hash.t + + (** The type of L1 operations that are injected on Tezos. These have a hash + attached to them that allows tracking and retrieving their status. *) + type t = private {hash : hash; operation : operation} + + (** [make op] returns an L1 operation with the corresponding hash. *) + val make : operation -> t + + (** Encoding for L1 operations *) + val encoding : t Data_encoding.t + + (** Pretty printer for L1 operations. Only the relevant part for the rollup node + is printed. *) + val pp : Format.formatter -> t -> unit +end + (** Module type for parameter of functor {!Injector_functor.Make}. *) module type PARAMETERS = sig - (** The type of the state for the rollup node that the injector can access *) - type rollup_node_state + (** The type of the state that the injector can access *) + type state (** A module which contains the different tags for the injector *) module Tag : TAG + (** A module for the injector operations *) + module Operation : PARAM_OPERATION + (** Where to put the events for this injector *) val events_section : string list @@ -147,26 +137,21 @@ module type PARAMETERS = sig (** Action (see {!retry_action}) to be taken on unsuccessful operation (see {!unsuccessful_status}). *) val retry_unsuccessful_operation : - rollup_node_state -> - 'a manager_operation -> - unsuccessful_status -> - retry_action Lwt.t + state -> Operation.t -> unsuccessful_status -> retry_action Lwt.t (** The tag of a manager operation. This is used to send operations to the correct queue automatically (when signer is not provided) and to recover persistent information. *) - val operation_tag : 'a manager_operation -> Tag.t option + val operation_tag : Operation.t -> Tag.t (** Returns the {e approximate upper-bounds} for the fee and limits of an operation, used to compute an upper bound on the size (in bytes) for this operation. *) - val approximate_fee_bound : - rollup_node_state -> 'a manager_operation -> approximate_fee_bound + val approximate_fee_bound : state -> Operation.t -> approximate_fee_bound (** Returns the fee_parameter (to compute fee w.r.t. gas, size, etc.) and the caps of fee and burn for each operation. *) - val fee_parameter : - rollup_node_state -> 'a manager_operation -> Injection.fee_parameter + val fee_parameter : state -> Operation.t -> Injection.fee_parameter (** When injecting the given [operations] in an L1 batch, if [batch_must_succeed operations] returns [`All] then all the operations must @@ -176,16 +161,56 @@ module type PARAMETERS = sig be included in the injected L1 batch. {b Note}: Returning [`At_least_one] allows to incrementally build "or-batches" by iteratively removing operations that fail from the desired batch. *) - val batch_must_succeed : - packed_manager_operation list -> [`All | `At_least_one] + val batch_must_succeed : Operation.t list -> [`All | `At_least_one] end (** Output signature for functor {!Injector_functor.Make}. *) module type S = sig - type rollup_node_state + type state type tag + type operation + + module Inj_operation : INJECTOR_OPERATION with type operation = operation + + (** Information stored about an L1 operation that was injected on a Tezos + node. *) + type injected_info = { + op : Inj_operation.t; (** The injector operation. *) + oph : Operation_hash.t; + (** The hash of the operation which contains [op] (this can be an L1 batch + of several manager operations). *) + op_index : int; + (** The index of the operation [op] in the L1 batch corresponding to [oph]. *) + } + + (** Information stored about an L1 operation that was included in a Tezos + block. *) + type included_info = { + op : Inj_operation.t; (** The injector operation. *) + oph : Operation_hash.t; + (** The hash of the operation which contains [op] (this can be an L1 batch + of several manager operations). *) + op_index : int; + (** The index of the operation [op] in the L1 batch corresponding to [oph]. *) + l1_block : Block_hash.t; + (** The hash of the L1 block in which the operation was included. *) + l1_level : int32; (** The level of [l1_block]. *) + } + + (** Status of an operation in the injector. *) + type status = + | Pending of operation (** The operation is pending injection. *) + | Injected of injected_info + (** The operation has been injected successfully in the node. *) + | Included of included_info + (** The operation has been included in a L1 block. *) + + val injected_info_encoding : injected_info Data_encoding.t + + val included_info_encoding : included_info Data_encoding.t + (** Initializes the injector with the rollup node state, for a list of signers, and start the workers. Each signer has its own worker with a queue of operations to inject. @@ -199,7 +224,7 @@ module type S = sig #Protocol_client_context.full -> data_dir:string -> ?retention_period:int -> - rollup_node_state -> + state -> signers:(public_key_hash * injection_strategy * tag list) list -> unit tzresult Lwt.t @@ -208,9 +233,7 @@ module type S = sig corresponding tag. It returns the hash of the operation in the injector queue. *) val add_pending_operation : - ?source:public_key_hash -> - 'a manager_operation -> - L1_operation.hash tzresult Lwt.t + ?source:public_key_hash -> operation -> Inj_operation.Hash.t tzresult Lwt.t (** Notify the injector of a new Tezos head. The injector marks the operations appropriately (for instance reverted operations that are part of a @@ -233,5 +256,5 @@ module type S = sig val shutdown : unit -> unit Lwt.t (** The status of an operation in the injector. *) - val operation_status : L1_operation.hash -> status option + val operation_status : Inj_operation.Hash.t -> status option end diff --git a/src/proto_016_PtMumbai/lib_injector/injector_worker_types.ml b/src/proto_016_PtMumbai/lib_injector/injector_worker_types.ml index 8ea98a4b4871dc8134a1c50e9dd3820d9ab9c0f9..2d39e9243c787ea7c9101baafa52ecdcfe20b644 100644 --- a/src/proto_016_PtMumbai/lib_injector/injector_worker_types.ml +++ b/src/proto_016_PtMumbai/lib_injector/injector_worker_types.ml @@ -27,8 +27,9 @@ open Protocol_client_context open Protocol open Alpha_context open Injector_common +open Injector_sigs -module Request = struct +module Request (L1_operation : INJECTOR_OPERATION) = struct type ('a, 'b) t = | Add_pending : L1_operation.t -> (unit, error trace) t | New_tezos_head : @@ -75,11 +76,7 @@ module Request = struct let pp ppf (View r) = match r with | Add_pending op -> - Format.fprintf - ppf - "request add %a to pending queue" - L1_operation.Hash.pp - op.hash + Format.fprintf ppf "request add %a to pending queue" L1_operation.pp op | New_tezos_head (b, r) -> Format.fprintf ppf @@ -100,7 +97,7 @@ module Name = struct let encoding = Tezos_crypto.Signature.Public_key_hash.encoding - let base = ["tx_rollup_injector"] + let base = ["injector"] let pp = Tezos_crypto.Signature.Public_key_hash.pp_short diff --git a/src/proto_016_PtMumbai/lib_injector/injector_worker_types.mli b/src/proto_016_PtMumbai/lib_injector/injector_worker_types.mli index 28c23d0a517d6ba5e2697a623615b1fde2b14144..15ce6419727542da607403b7174422d238b82fa2 100644 --- a/src/proto_016_PtMumbai/lib_injector/injector_worker_types.mli +++ b/src/proto_016_PtMumbai/lib_injector/injector_worker_types.mli @@ -27,10 +27,11 @@ open Protocol_client_context open Protocol open Alpha_context open Injector_common +open Injector_sigs -module Request : sig +module Request (Inj_operation : INJECTOR_OPERATION) : sig type ('a, 'b) t = - | Add_pending : L1_operation.t -> (unit, error trace) t + | Add_pending : Inj_operation.t -> (unit, error trace) t | New_tezos_head : Alpha_block_services.block_info * Alpha_block_services.block_info reorg -> (unit, error trace) t diff --git a/src/proto_016_PtMumbai/lib_injector/l1_operation.ml b/src/proto_016_PtMumbai/lib_injector/l1_operation.ml deleted file mode 100644 index c140f9901087be938a6ecbed636c7145bda2c14a..0000000000000000000000000000000000000000 --- a/src/proto_016_PtMumbai/lib_injector/l1_operation.ml +++ /dev/null @@ -1,232 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -open Protocol -open Alpha_context - -module Manager_operation = struct - type t = packed_manager_operation - - let encoding : t Data_encoding.t = - let open Data_encoding in - let open Operation.Encoding.Manager_operations in - let make (MCase {tag; name; encoding; select; proj; inj}) = - case - (Tag tag) - ~title:name - (merge_objs (obj1 (req "kind" (constant name))) encoding) - (fun o -> - match select o with None -> None | Some o -> Some ((), proj o)) - (fun ((), x) -> Manager (inj x)) - in - def "manager_operation" - @@ union - [ - make reveal_case; - make transaction_case; - make origination_case; - make delegation_case; - make set_deposits_limit_case; - make increase_paid_storage_case; - make register_global_constant_case; - make tx_rollup_origination_case; - make tx_rollup_submit_batch_case; - make tx_rollup_commit_case; - make tx_rollup_return_bond_case; - make tx_rollup_finalize_commitment_case; - make tx_rollup_remove_commitment_case; - make tx_rollup_rejection_case; - make tx_rollup_dispatch_tickets_case; - make transfer_ticket_case; - make dal_publish_slot_header_case; - make sc_rollup_originate_case; - make sc_rollup_add_messages_case; - make sc_rollup_cement_case; - make sc_rollup_publish_case; - make sc_rollup_refute_case; - make sc_rollup_timeout_case; - make sc_rollup_execute_outbox_message_case; - make sc_rollup_recover_bond_case; - ] - - let get_case : - type kind. - kind manager_operation -> kind Operation.Encoding.Manager_operations.case - = - let open Operation.Encoding.Manager_operations in - function - | Reveal _ -> reveal_case - | Transaction _ -> transaction_case - | Origination _ -> origination_case - | Delegation _ -> delegation_case - | Register_global_constant _ -> register_global_constant_case - | Set_deposits_limit _ -> set_deposits_limit_case - | Increase_paid_storage _ -> increase_paid_storage_case - | Update_consensus_key _ -> update_consensus_key_case - | Tx_rollup_origination -> tx_rollup_origination_case - | Tx_rollup_submit_batch _ -> tx_rollup_submit_batch_case - | Tx_rollup_commit _ -> tx_rollup_commit_case - | Tx_rollup_return_bond _ -> tx_rollup_return_bond_case - | Tx_rollup_finalize_commitment _ -> tx_rollup_finalize_commitment_case - | Tx_rollup_remove_commitment _ -> tx_rollup_remove_commitment_case - | Tx_rollup_rejection _ -> tx_rollup_rejection_case - | Tx_rollup_dispatch_tickets _ -> tx_rollup_dispatch_tickets_case - | Transfer_ticket _ -> transfer_ticket_case - | Dal_publish_slot_header _ -> dal_publish_slot_header_case - | Sc_rollup_originate _ -> sc_rollup_originate_case - | Sc_rollup_add_messages _ -> sc_rollup_add_messages_case - | Sc_rollup_cement _ -> sc_rollup_cement_case - | Sc_rollup_publish _ -> sc_rollup_publish_case - | Sc_rollup_refute _ -> sc_rollup_refute_case - | Sc_rollup_timeout _ -> sc_rollup_timeout_case - | Sc_rollup_execute_outbox_message _ -> - sc_rollup_execute_outbox_message_case - | Sc_rollup_recover_bond _ -> sc_rollup_recover_bond_case - | Zk_rollup_origination _ -> zk_rollup_origination_case - | Zk_rollup_publish _ -> zk_rollup_publish_case - | Zk_rollup_update _ -> zk_rollup_update_case - - let pp_kind ppf op = - let open Operation.Encoding.Manager_operations in - let (MCase {name; _}) = get_case op in - Format.pp_print_string ppf name - - let pp ppf (Manager op) = - match op with - | Tx_rollup_commit {commitment = {level; _}; _} -> - Format.fprintf - ppf - "commitment for rollup level %a" - Tx_rollup_level.pp - level - | Tx_rollup_rejection {level; message_position; _} -> - Format.fprintf - ppf - "rejection for commitment at level %a for message %d" - Tx_rollup_level.pp - level - message_position - | Tx_rollup_dispatch_tickets {level; tickets_info; _} -> - let pp_rollup_reveal ppf - Tx_rollup_reveal.{contents; ty; amount; ticketer; claimer; _} = - let pp_lazy_expr ppf e = - Michelson_v1_printer.print_expr_unwrapped - ppf - (Result.value - (Script_repr.force_decode e) - ~default:(Micheline.strip_locations (Micheline.Seq ((), [])))) - in - Format.fprintf - ppf - "%a tickets (%a, %a, %a) to %a" - Tx_rollup_l2_qty.pp - amount - Contract.pp - ticketer - pp_lazy_expr - ty - pp_lazy_expr - contents - Tezos_crypto.Signature.Public_key_hash.pp - claimer - in - Format.fprintf - ppf - "@[dispatch withdrawals at rollup level %a: %a@]" - Tx_rollup_level.pp - level - (Format.pp_print_list pp_rollup_reveal) - tickets_info - | Sc_rollup_add_messages {messages} -> - Format.fprintf - ppf - "publishing %d messages to smart rollups' inbox" - (List.length messages) - | Sc_rollup_cement {rollup; commitment} -> - Format.fprintf - ppf - "cementing commitment %a of rollup %a" - Sc_rollup.Commitment.Hash.pp - commitment - Sc_rollup.Address.pp - rollup - | Sc_rollup_publish - {rollup; commitment = Sc_rollup.Commitment.{inbox_level; _}} -> - Format.fprintf - ppf - "publish commitment for level %a of rollup %a" - Raw_level.pp - inbox_level - Sc_rollup.Address.pp - rollup - | _ -> pp_kind ppf op -end - -module Hash = - Tezos_crypto.Blake2B.Make - (Tezos_crypto.Base58) - (struct - let name = "manager_operation_hash" - - let title = "A manager operation hash" - - let b58check_prefix = "\068\160\013" (* mop(53) *) - - let size = None - end) - -let () = - Tezos_crypto.Base58.check_encoded_prefix Hash.b58check_encoding "mop" 53 - -type hash = Hash.t - -type t = {hash : hash; manager_operation : packed_manager_operation} - -let hash_manager_operation op = - Hash.hash_bytes - [Data_encoding.Binary.to_bytes_exn Manager_operation.encoding op] - -let make manager_operation = - let manager_operation = Manager manager_operation in - let hash = hash_manager_operation manager_operation in - {hash; manager_operation} - -let encoding = - let open Data_encoding in - conv - (fun {hash; manager_operation} -> (hash, manager_operation)) - (fun (hash, manager_operation) -> {hash; manager_operation}) - @@ obj2 - (req "hash" Hash.encoding) - (req "manager_operation" Manager_operation.encoding) - -let pp ppf {hash; manager_operation} = - Format.fprintf - ppf - "%a (%a)" - Manager_operation.pp - manager_operation - Hash.pp - hash diff --git a/src/proto_016_PtMumbai/lib_sc_rollup/l1_operation.ml b/src/proto_016_PtMumbai/lib_sc_rollup/l1_operation.ml new file mode 100644 index 0000000000000000000000000000000000000000..1b3e165b794ff98f676d154ef7162e9703531525 --- /dev/null +++ b/src/proto_016_PtMumbai/lib_sc_rollup/l1_operation.ml @@ -0,0 +1,178 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol.Alpha_context + +type t = + | Add_messages of {messages : string list} + | Cement of {rollup : Sc_rollup.t; commitment : Sc_rollup.Commitment.Hash.t} + | Publish of {rollup : Sc_rollup.t; commitment : Sc_rollup.Commitment.t} + | Refute of { + rollup : Sc_rollup.t; + opponent : Sc_rollup.Staker.t; + refutation : Sc_rollup.Game.refutation; + } + | Timeout of {rollup : Sc_rollup.t; stakers : Sc_rollup.Game.Index.t} + +let encoding : t Data_encoding.t = + let open Data_encoding in + let case tag kind encoding proj inj = + case + ~title:kind + (Tag tag) + (merge_objs (obj1 (req "kind" (constant kind))) encoding) + (fun o -> Option.map (fun p -> ((), p)) (proj o)) + (fun ((), p) -> inj p) + in + def "sc_rollup_node_l1_operation" + @@ union + [ + case + 0 + "add_messages" + (obj1 (req "message" (list (string' Hex)))) + (function Add_messages {messages} -> Some messages | _ -> None) + (fun messages -> Add_messages {messages}); + case + 1 + "cement" + (obj2 + (req "rollup" Sc_rollup.Address.encoding) + (req "commitment" Sc_rollup.Commitment.Hash.encoding)) + (function + | Cement {rollup; commitment} -> Some (rollup, commitment) + | _ -> None) + (fun (rollup, commitment) -> Cement {rollup; commitment}); + case + 2 + "publish" + (obj2 + (req "rollup" Sc_rollup.Address.encoding) + (req "commitment" Sc_rollup.Commitment.encoding)) + (function + | Publish {rollup; commitment} -> Some (rollup, commitment) + | _ -> None) + (fun (rollup, commitment) -> Publish {rollup; commitment}); + case + 3 + "refute" + (obj3 + (req "rollup" Sc_rollup.Address.encoding) + (req "opponent" Sc_rollup.Staker.encoding) + (req "refutation" Sc_rollup.Game.refutation_encoding)) + (function + | Refute {rollup; opponent; refutation} -> + Some (rollup, opponent, refutation) + | _ -> None) + (fun (rollup, opponent, refutation) -> + Refute {rollup; opponent; refutation}); + case + 4 + "timeout" + (obj2 + (req "rollup" Sc_rollup.Address.encoding) + (req "stakers" Sc_rollup.Game.Index.encoding)) + (function + | Timeout {rollup; stakers} -> Some (rollup, stakers) | _ -> None) + (fun (rollup, stakers) -> Timeout {rollup; stakers}); + ] + +let pp ppf = function + | Add_messages {messages} -> + Format.fprintf + ppf + "publishing %d messages to smart rollups' inbox" + (List.length messages) + | Cement {rollup = _; commitment} -> + Format.fprintf + ppf + "cementing commitment %a" + Sc_rollup.Commitment.Hash.pp + commitment + | Publish {rollup = _; commitment = Sc_rollup.Commitment.{inbox_level; _}} -> + Format.fprintf + ppf + "publish commitment for level %a" + Raw_level.pp + inbox_level + | Refute {rollup = _; opponent; refutation = Start _} -> + Format.fprintf + ppf + "start refutation game against %a" + Signature.Public_key_hash.pp + opponent + | Refute + { + rollup = _; + opponent; + refutation = Move {step = Dissection (first :: _ as d); _}; + } -> + let last = List.last first d in + Format.fprintf + ppf + "dissection between ticks %a and %a (against %a)" + Sc_rollup.Tick.pp + first.tick + Sc_rollup.Tick.pp + last.tick + Signature.Public_key_hash.pp + opponent + | Refute {rollup = _; opponent; refutation = Move {step = Dissection []; _}} + -> + Format.fprintf + ppf + "dissection (against %a)" + Signature.Public_key_hash.pp + opponent + | Refute {rollup = _; opponent; refutation = Move {choice; step = Proof _}} -> + Format.fprintf + ppf + "proof for tick %a (against %a)" + Sc_rollup.Tick.pp + choice + Signature.Public_key_hash.pp + opponent + | Timeout {rollup = _; stakers = _} -> Format.fprintf ppf "timeout" + +let to_manager_operation : t -> packed_manager_operation = function + | Add_messages {messages} -> Manager (Sc_rollup_add_messages {messages}) + | Cement {rollup; commitment} -> + Manager (Sc_rollup_cement {rollup; commitment}) + | Publish {rollup; commitment} -> + Manager (Sc_rollup_publish {rollup; commitment}) + | Refute {rollup; opponent; refutation} -> + Manager (Sc_rollup_refute {rollup; opponent; refutation}) + | Timeout {rollup; stakers} -> Manager (Sc_rollup_timeout {rollup; stakers}) + +let of_manager_operation : type kind. kind manager_operation -> t option = + function + | Sc_rollup_add_messages {messages} -> Some (Add_messages {messages}) + | Sc_rollup_cement {rollup; commitment} -> Some (Cement {rollup; commitment}) + | Sc_rollup_publish {rollup; commitment} -> + Some (Publish {rollup; commitment}) + | Sc_rollup_refute {rollup; opponent; refutation} -> + Some (Refute {rollup; opponent; refutation}) + | Sc_rollup_timeout {rollup; stakers} -> Some (Timeout {rollup; stakers}) + | _ -> None diff --git a/src/proto_016_PtMumbai/lib_sc_rollup/l1_operation.mli b/src/proto_016_PtMumbai/lib_sc_rollup/l1_operation.mli new file mode 100644 index 0000000000000000000000000000000000000000..d6bd71285e0f47e35d01ce3f0f11fcbbb32dbfcb --- /dev/null +++ b/src/proto_016_PtMumbai/lib_sc_rollup/l1_operation.mli @@ -0,0 +1,50 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol.Alpha_context + +(** L1 operations produced (and injected) by the rollup node. *) +type t = + | Add_messages of {messages : string list} + | Cement of {rollup : Sc_rollup.t; commitment : Sc_rollup.Commitment.Hash.t} + | Publish of {rollup : Sc_rollup.t; commitment : Sc_rollup.Commitment.t} + | Refute of { + rollup : Sc_rollup.t; + opponent : Sc_rollup.Staker.t; + refutation : Sc_rollup.Game.refutation; + } + | Timeout of {rollup : Sc_rollup.t; stakers : Sc_rollup.Game.Index.t} + +(** Encoding for L1 operations (used by injector for on-disk persistence). *) +val encoding : t Data_encoding.t + +(** Manager operation for a given L1 operation. *) +val to_manager_operation : t -> packed_manager_operation + +(** L1 operation corresponding to a manager operation if any. *) +val of_manager_operation : 'a manager_operation -> t option + +(** Pretty printer (human readable) for L1 operations. *) +val pp : Format.formatter -> t -> unit diff --git a/src/proto_016_PtMumbai/lib_sc_rollup/sc_rollup_services.ml b/src/proto_016_PtMumbai/lib_sc_rollup/sc_rollup_services.ml index 9bcbfa7c4eb3c2aba2c718ac24add20b39a4a88d..4a918a5575250ef809e9f603a884ee20d44ec178 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup/sc_rollup_services.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup/sc_rollup_services.ml @@ -62,8 +62,6 @@ type simulate_input = { reveal_pages : string list option; } -type inbox_info = {finalized : bool; cemented : bool} - type commitment_info = { commitment : Sc_rollup.Commitment.t; commitment_hash : Sc_rollup.Commitment.Hash.t; @@ -75,9 +73,29 @@ type message_status = | Unknown | Pending_batch | Pending_injection of L1_operation.t - | Injected of Injector_sigs.injected_info - | Included of Injector_sigs.included_info * inbox_info - | Committed of Injector_sigs.included_info * inbox_info * commitment_info + | Injected of {op : L1_operation.t; oph : Operation_hash.t; op_index : int} + | Included of { + op : L1_operation.t; + oph : Operation_hash.t; + op_index : int; + l1_block : Block_hash.t; + l1_level : int32; + finalized : bool; + cemented : bool; + } + | Committed of { + op : L1_operation.t; + oph : Operation_hash.t; + op_index : int; + l1_block : Block_hash.t; + l1_level : int32; + finalized : bool; + cemented : bool; + commitment : Sc_rollup.Commitment.t; + commitment_hash : Sc_rollup.Commitment.Hash.t; + first_published_at_level : Raw_level.t; + published_at_level : Raw_level.t; + } module Encodings = struct open Data_encoding @@ -144,12 +162,6 @@ module Encodings = struct let batcher_queue = list queued_message - let inbox_info = - conv - (fun {finalized; cemented} -> (finalized, cemented)) - (fun (finalized, cemented) -> {finalized; cemented}) - @@ obj2 (req "finalized" bool) (req "cemented" bool) - let commitment_info = conv (fun { @@ -210,35 +222,117 @@ module Encodings = struct ~description: "The message is injected as part of an L1 operation but it is not \ included in a block." - (merge_objs - (obj1 (req "status" (constant "injected"))) - Injector_sigs.injected_info_encoding) - (function Injected info -> Some ((), info) | _ -> None) - (fun ((), info) -> Injected info); + (obj3 + (req "status" (constant "injected")) + (req "operation" L1_operation.encoding) + (req + "layer1" + (obj2 + (req "operation_hash" Operation_hash.encoding) + (req "operation_index" int31)))) + (function + | Injected {op; oph; op_index} -> Some ((), op, (oph, op_index)) + | _ -> None) + (fun ((), op, (oph, op_index)) -> Injected {op; oph; op_index}); case (Tag 4) ~title:"included" ~description:"The message is included in an inbox in an L1 block." - (merge_objs - (obj1 (req "status" (constant "included"))) - (merge_objs Injector_sigs.included_info_encoding inbox_info)) + (obj5 + (req "status" (constant "included")) + (req "operation" L1_operation.encoding) + (req + "layer1" + (obj4 + (req "operation_hash" Operation_hash.encoding) + (req "operation_index" int31) + (req "block_hash" Block_hash.encoding) + (req "level" int32))) + (req "finalized" bool) + (req "cemented" bool)) (function - | Included (info, inbox_info) -> Some ((), (info, inbox_info)) + | Included + {op; oph; op_index; l1_block; l1_level; finalized; cemented} -> + Some + ( (), + op, + (oph, op_index, l1_block, l1_level), + finalized, + cemented ) | _ -> None) - (fun ((), (info, inbox_info)) -> Included (info, inbox_info)); + (fun ((), op, (oph, op_index, l1_block, l1_level), finalized, cemented) + -> + Included + {op; oph; op_index; l1_block; l1_level; finalized; cemented}); case (Tag 5) ~title:"committed" ~description:"The message is included in a committed inbox on L1." - (merge_objs (obj1 (req "status" (constant "committed"))) - @@ merge_objs Injector_sigs.included_info_encoding - @@ merge_objs inbox_info (obj1 (req "commitment" commitment_info))) + (obj9 + (req "status" (constant "committed")) + (req "operation" L1_operation.encoding) + (req + "layer1" + (obj4 + (req "operation_hash" Operation_hash.encoding) + (req "operation_index" int31) + (req "block_hash" Block_hash.encoding) + (req "level" int32))) + (req "finalized" bool) + (req "cemented" bool) + (req "commitment" Sc_rollup.Commitment.encoding) + (req "hash" Sc_rollup.Commitment.Hash.encoding) + (req "first_published_at_level" Raw_level.encoding) + (req "published_at_level" Raw_level.encoding)) (function - | Committed (info, inbox_info, commitment) -> - Some ((), (info, (inbox_info, commitment))) + | Committed + { + op; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + commitment; + commitment_hash; + first_published_at_level; + published_at_level; + } -> + Some + ( (), + op, + (oph, op_index, l1_block, l1_level), + finalized, + cemented, + commitment, + commitment_hash, + first_published_at_level, + published_at_level ) | _ -> None) - (fun ((), (info, (inbox_info, commitment))) -> - Committed (info, inbox_info, commitment)); + (fun ( (), + op, + (oph, op_index, l1_block, l1_level), + finalized, + cemented, + commitment, + commitment_hash, + first_published_at_level, + published_at_level ) -> + Committed + { + op; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + commitment; + commitment_hash; + first_published_at_level; + published_at_level; + }); ] let message_status_output = diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/RPC_server.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/RPC_server.ml index b54b65fe433077c4c80fdc5e2015ba8eaac2913e..7663077fd8a0c9eee4d54d06c95e84c27f436433 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/RPC_server.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/RPC_server.ml @@ -431,7 +431,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct let cemented = Compare.Int32.(inbox_level <= Raw_level.to_int32 node_ctxt.lcc.level) in - Sc_rollup_services.{finalized; cemented} + (finalized, cemented) let () = Local_directory.register1 Sc_rollup_services.Local.batcher_message @@ -450,18 +450,30 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct | None -> return Sc_rollup_services.Unknown | Some (Pending op) -> return (Sc_rollup_services.Pending_injection op) - | Some (Injected info) -> - return (Sc_rollup_services.Injected info) - | Some (Included info) -> ( - let* inbox_info = - inbox_info_of_level node_ctxt info.l1_level + | Some (Injected {op; oph; op_index}) -> + return + (Sc_rollup_services.Injected + {op = op.operation; oph; op_index}) + | Some (Included {op; oph; op_index; l1_block; l1_level}) -> ( + let* finalized, cemented = + inbox_info_of_level node_ctxt l1_level in let commitment_level = - commitment_level_of_inbox_level node_ctxt info.l1_level + commitment_level_of_inbox_level node_ctxt l1_level in match commitment_level with | None -> - return (Sc_rollup_services.Included (info, inbox_info)) + return + (Sc_rollup_services.Included + { + op = op.operation; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + }) | Some commitment_level -> ( let* block = Node_context.find_l2_block_by_level @@ -472,7 +484,16 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct | None -> (* Commitment not computed yet for inbox *) return - (Sc_rollup_services.Included (info, inbox_info)) + (Sc_rollup_services.Included + { + op = op.operation; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + }) | Some block -> ( let commitment_hash = WithExceptions.Option.get @@ -489,7 +510,16 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct | None | Some {published_at_level = None; _} -> (* Commitment not published yet *) return - (Sc_rollup_services.Included (info, inbox_info)) + (Sc_rollup_services.Included + { + op = op.operation; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + }) | Some { first_published_at_level; @@ -501,18 +531,21 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct node_ctxt commitment_hash in - let commitment_info = - Sc_rollup_services. - { - commitment; - commitment_hash; - first_published_at_level; - published_at_level; - } - in return (Sc_rollup_services.Committed - (info, inbox_info, commitment_info))))))) + { + op = op.operation; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + commitment; + commitment_hash; + first_published_at_level; + published_at_level; + })))))) in return status diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.ml index 357a86dbf91f15caac68da6c9b07b7354bf41056..84be3b4fa94e1fcfe18f22841737814ec79471ba 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.ml @@ -29,13 +29,13 @@ open Batcher_worker_types module Message_queue = Hash_queue.Make (L2_message.Hash) (L2_message) module L2_batched_message = struct - type t = {content : string; l1_hash : L1_operation.hash} + type t = {content : string; l1_hash : Injector.Inj_operation.hash} end module Batched_messages = Hash_queue.Make (L2_message.Hash) (L2_batched_message) module type S = sig - type status = Pending_batch | Batched of L1_operation.hash + type status = Pending_batch | Batched of Injector.Inj_operation.hash val init : Configuration.batcher -> @@ -63,7 +63,7 @@ end module Make (Simulation : Simulation.S) : S = struct module PVM = Simulation.PVM - type status = Pending_batch | Batched of L1_operation.hash + type status = Pending_batch | Batched of Injector.Inj_operation.hash type state = { node_ctxt : Node_context.ro; @@ -81,7 +81,7 @@ module Make (Simulation : Simulation.S) : S = struct let inject_batch state (l2_messages : L2_message.t list) = let open Lwt_result_syntax in let messages = List.map L2_message.content l2_messages in - let operation = Sc_rollup_add_messages {messages} in + let operation = L1_operation.Add_messages {messages} in let+ l1_hash = Injector.add_pending_operation ~source:state.signer operation in diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.mli index 3855c96e9fc18d6c407c96fd335c6e85c68d087d..a6618f27bdc9a7bc0068d15841d3b4ceaca193b4 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.mli +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/batcher.mli @@ -30,7 +30,7 @@ module type S = sig (** The type for the status of messages in the batcher. *) type status = | Pending_batch (** The message is in the queue of the batcher. *) - | Batched of L1_operation.hash + | Batched of Injector.Inj_operation.hash (** The message has already been batched and sent to the injector in an L1 operation whose hash is given. *) diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment.ml index cf661f32afa606e4602793845b8f7fcbeab64702..4b67e37a569b499be63ecfd0ffa9e276079fbee2 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/commitment.ml @@ -242,7 +242,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct (commitment : Sc_rollup.Commitment.t) = let open Lwt_result_syntax in let publish_operation = - Sc_rollup_publish {rollup = node_ctxt.rollup_address; commitment} + L1_operation.Publish {rollup = node_ctxt.rollup_address; commitment} in let*! () = Commitment_event.publish_commitment @@ -376,7 +376,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct let cement_commitment (node_ctxt : _ Node_context.t) ~source commitment_hash = let open Lwt_result_syntax in let cement_operation = - Sc_rollup_cement + L1_operation.Cement {rollup = node_ctxt.rollup_address; commitment = commitment_hash} in let* _hash = Injector.add_pending_operation ~source cement_operation in diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon_event.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon_event.ml index 61958297e722bb7d4de13475ad244361e43683ed..bfac41676c492caeed854b4456bcff3b182bd9bb 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon_event.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/daemon_event.ml @@ -153,23 +153,25 @@ let new_heads_processed = new_heads_iteration Simple.new_heads_processed let included_operation (type kind) ~finalized (operation : kind Protocol.Alpha_context.manager_operation) (result : kind Protocol.Apply_results.manager_operation_result) = - let operation = L1_operation.make operation in - match result with - | Applied _ when finalized -> - Simple.(emit finalized_successful_operation) operation - | _ when finalized -> - (* No events for finalized non successful operations *) - Lwt.return_unit - | Applied _ -> Simple.(emit included_successful_operation) operation - | result -> - let status, errors = - match result with - | Applied _ -> assert false - | Failed (_, e) -> (`Failed, Some e) - | Backtracked (_, e) -> (`Backtracked, e) - | Skipped _ -> (`Skipped, None) - in - Simple.(emit included_failed_operation) (operation, status, errors) + match L1_operation.of_manager_operation operation with + | None -> Lwt.return_unit + | Some operation -> ( + match result with + | Applied _ when finalized -> + Simple.(emit finalized_successful_operation) operation + | _ when finalized -> + (* No events for finalized non successful operations *) + Lwt.return_unit + | Applied _ -> Simple.(emit included_successful_operation) operation + | result -> + let status, errors = + match result with + | Applied _ -> assert false + | Failed (_, e) -> (`Failed, Some e) + | Backtracked (_, e) -> (`Backtracked, e) + | Skipped _ -> (`Skipped, None) + in + Simple.(emit included_failed_operation) (operation, status, errors)) let wrong_initial_pvm_state_hash actual_hash expected_hash = Simple.(emit wrong_initial_pvm_state_hash (actual_hash, expected_hash)) diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.ml index 9864f35192ca34147fd41d31b72b145f16100c4d..8bcb5fbd162244a2361fe9d324b24e31ad98f11f 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.ml @@ -28,9 +28,10 @@ open Injector_sigs module Parameters : PARAMETERS - with type rollup_node_state = Node_context.ro - and type Tag.t = Configuration.purpose = struct - type rollup_node_state = Node_context.ro + with type state = Node_context.ro + and type Tag.t = Configuration.purpose + and type Operation.t = L1_operation.t = struct + type state = Node_context.ro let events_section = ["sc_rollup.injector"] @@ -53,6 +54,8 @@ module Parameters : (List.map (fun t -> (string_of_tag t, t)) Configuration.purposes) end + module Operation = L1_operation + (* TODO: https://gitlab.com/tezos/tezos/-/issues/3459 Very coarse approximation for the number of operation we expect for each block *) @@ -63,20 +66,15 @@ module Parameters : | Timeout -> 1 | Refute -> 1 - let operation_tag (type kind) (operation : kind manager_operation) : - Tag.t option = - match operation with - | Sc_rollup_add_messages _ -> Some Add_messages - | Sc_rollup_cement _ -> Some Cement - | Sc_rollup_publish _ -> Some Publish - | Sc_rollup_timeout _ -> Some Timeout - | Sc_rollup_refute _ -> Some Refute - | _ -> None + let operation_tag : Operation.t -> Tag.t = function + | Add_messages _ -> Add_messages + | Cement _ -> Cement + | Publish _ -> Publish + | Timeout _ -> Timeout + | Refute _ -> Refute let fee_parameter node_ctxt operation = - match operation_tag operation with - | None -> Configuration.default_fee_parameter () - | Some tag -> Node_context.get_fee_parameter node_ctxt tag + Node_context.get_fee_parameter node_ctxt (operation_tag operation) (* Below are dummy values that are only used to approximate the size. It is thus important that they remain above the real @@ -98,8 +96,7 @@ module Parameters : {!Injector_sigs.Parameter.batch_must_succeed}. *) let batch_must_succeed _ = `At_least_one - let retry_unsuccessful_operation (type kind) _node_ctxt - (op : kind manager_operation) status = + let retry_unsuccessful_operation _node_ctxt (op : Operation.t) status = let open Lwt_syntax in match status with | Backtracked | Skipped | Other_branch -> @@ -140,34 +137,10 @@ module Parameters : return Retry else match op with - | Sc_rollup_timeout _ | Sc_rollup_refute _ | Sc_rollup_cement _ - | Sc_rollup_add_messages _ -> + | Timeout _ | Refute _ | Cement _ | Add_messages _ -> (* Failing timeout and refutation operations can be ignored. *) return Forget - | Sc_rollup_publish _ -> return (Abort error) - | Reveal _ | Transaction _ | Origination _ | Delegation _ - | Update_consensus_key _ | Register_global_constant _ - | Set_deposits_limit _ | Increase_paid_storage _ - | Tx_rollup_origination | Tx_rollup_submit_batch _ - | Tx_rollup_commit _ | Tx_rollup_return_bond _ - | Tx_rollup_finalize_commitment _ | Tx_rollup_remove_commitment _ - | Tx_rollup_rejection _ | Tx_rollup_dispatch_tickets _ - | Transfer_ticket _ | Dal_publish_slot_header _ - | Sc_rollup_originate _ | Sc_rollup_execute_outbox_message _ - | Sc_rollup_recover_bond _ | Zk_rollup_origination _ - | Zk_rollup_publish _ | Zk_rollup_update _ -> - (* These operations should never be handled by this injector *) - assert false) - - let operation_tag (type kind) (operation : kind manager_operation) : - Tag.t option = - match operation with - | Sc_rollup_add_messages _ -> Some Add_messages - | Sc_rollup_cement _ -> Some Cement - | Sc_rollup_publish _ -> Some Publish - | Sc_rollup_timeout _ -> Some Timeout - | Sc_rollup_refute _ -> Some Refute - | _ -> None + | Publish _ -> return (Abort error)) end include Injector_functor.Make (Parameters) diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.mli index d4b38f8ec62f5838eb9ee4fbb94ed7b1cfe92b06..0f3db24e434eeded77d995b2d9125bb5dfab40b5 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.mli +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/injector.mli @@ -25,5 +25,6 @@ include Injector_sigs.S - with type rollup_node_state := Node_context.ro + with type state := Node_context.ro and type tag := Configuration.purpose + and type operation := L1_operation.t diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game.ml index d18ee79baa2648dccb8c050cd5eff7811f87a003..2f958d8d1cdc020b2303d1b9f6d9bf6f0b2b1521 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game.ml @@ -79,7 +79,7 @@ module Make (Interpreter : Interpreter.S) : let inject_next_move node_ctxt source ~refutation ~opponent = let open Lwt_result_syntax in let refute_operation = - Sc_rollup_refute + L1_operation.Refute {rollup = node_ctxt.Node_context.rollup_address; refutation; opponent} in let* _hash = Injector.add_pending_operation ~source refute_operation in @@ -424,7 +424,7 @@ module Make (Interpreter : Interpreter.S) : let play_timeout (node_ctxt : _ Node_context.t) self stakers = let open Lwt_result_syntax in let timeout_operation = - Sc_rollup_timeout {rollup = node_ctxt.rollup_address; stakers} + L1_operation.Timeout {rollup = node_ctxt.rollup_address; stakers} in let source = Node_context.get_operator node_ctxt Timeout |> Option.value ~default:self diff --git a/src/proto_alpha/lib_injector/injector_errors.ml b/src/proto_alpha/lib_injector/injector_errors.ml index 2a278f1d5e53bd9b96cc1e850ec66aac11216386..34fe0d4d0173383942e75cbb990690e03945aab6 100644 --- a/src/proto_alpha/lib_injector/injector_errors.ml +++ b/src/proto_alpha/lib_injector/injector_errors.ml @@ -56,22 +56,6 @@ let () = (function No_worker_for_tag t -> Some t | _ -> None) (fun t -> No_worker_for_tag t) -type error += No_worker_for_operation of L1_operation.t - -let () = - register_error_kind - ~id:"injector.no_worker_for_operation" - ~title:"This operation is not supported by injector" - ~description: - "An L1 operation could not be queued because the injector does not \ - handle it." - ~pp:(fun ppf op -> - Format.fprintf ppf "No worker for operation %a" L1_operation.pp op) - `Permanent - Data_encoding.(obj1 (req "operation" L1_operation.encoding)) - (function No_worker_for_operation op -> Some op | _ -> None) - (fun op -> No_worker_for_operation op) - type error += Step_failed of string let () = diff --git a/src/proto_alpha/lib_injector/injector_errors.mli b/src/proto_alpha/lib_injector/injector_errors.mli index e3e0f56666c9ed0c52f85f0500177d371086d9b4..51aa99df60488a828f63f4fd235b5de533d5e00b 100644 --- a/src/proto_alpha/lib_injector/injector_errors.mli +++ b/src/proto_alpha/lib_injector/injector_errors.mli @@ -31,8 +31,5 @@ type error += No_worker_for_source of Signature.Public_key_hash.t injected. *) type error += No_worker_for_tag of string -(** Error when the injector does not handle the operation. *) -type error += No_worker_for_operation of L1_operation.t - (** Error when a step of the injector failed. *) type error += Step_failed of string diff --git a/src/proto_alpha/lib_injector/injector_events.ml b/src/proto_alpha/lib_injector/injector_events.ml index 563eacf7f3606e730141f82d28a4b90f93ef085f..d5cdbecd1b3c75c286e869b176bcdc8cae89cc08 100644 --- a/src/proto_alpha/lib_injector/injector_events.ml +++ b/src/proto_alpha/lib_injector/injector_events.ml @@ -24,236 +24,243 @@ (*****************************************************************************) open Injector_worker_types +open Injector_sigs -module Make (Parameters : Injector_sigs.PARAMETERS) = struct - module Tags = Injector_tags.Make (Parameters.Tag) - include Internal_event.Simple +module Make + (Parameters : PARAMETERS) + (Tags : module type of Injector_tags.Make (Parameters.Tag)) + (Operation : PARAM_OPERATION) + (Inj_operation : INJECTOR_OPERATION with type operation = Operation.t) + (Request : module type of Request (Inj_operation)) = + struct + include Internal_event.Simple - let section = Parameters.events_section + let section = Parameters.events_section - let declare_1 ~name ~msg ~level ?pp1 enc1 = - declare_3 - ~section - ~name - ~msg:("[{signer}: {tags}] " ^ msg) - ~level - ("signer", Signature.Public_key_hash.encoding) - ("tags", Tags.encoding) - enc1 - ~pp1:Signature.Public_key_hash.pp_short - ~pp2:Tags.pp - ?pp3:pp1 + let declare_1 ~name ~msg ~level ?pp1 enc1 = + declare_3 + ~section + ~name + ~msg:("[{signer}: {tags}] " ^ msg) + ~level + ("signer", Signature.Public_key_hash.encoding) + ("tags", Tags.encoding) + enc1 + ~pp1:Signature.Public_key_hash.pp_short + ~pp2:Tags.pp + ?pp3:pp1 - let declare_2 ~name ~msg ~level ?pp1 ?pp2 enc1 enc2 = - declare_4 - ~section - ~name - ~msg:("[{signer}: {tags}] " ^ msg) - ~level - ("signer", Signature.Public_key_hash.encoding) - ("tags", Tags.encoding) - enc1 - enc2 - ~pp1:Signature.Public_key_hash.pp_short - ~pp2:Tags.pp - ?pp3:pp1 - ?pp4:pp2 + let declare_2 ~name ~msg ~level ?pp1 ?pp2 enc1 enc2 = + declare_4 + ~section + ~name + ~msg:("[{signer}: {tags}] " ^ msg) + ~level + ("signer", Signature.Public_key_hash.encoding) + ("tags", Tags.encoding) + enc1 + enc2 + ~pp1:Signature.Public_key_hash.pp_short + ~pp2:Tags.pp + ?pp3:pp1 + ?pp4:pp2 - let declare_3 ~name ~msg ~level ?pp1 ?pp2 ?pp3 enc1 enc2 enc3 = - declare_5 - ~section - ~name - ~msg:("[{signer}: {tags}] " ^ msg) - ~level - ("signer", Signature.Public_key_hash.encoding) - ("tags", Tags.encoding) - enc1 - enc2 - enc3 - ~pp1:Signature.Public_key_hash.pp_short - ~pp2:Tags.pp - ?pp3:pp1 - ?pp4:pp2 - ?pp5:pp3 + let declare_3 ~name ~msg ~level ?pp1 ?pp2 ?pp3 enc1 enc2 enc3 = + declare_5 + ~section + ~name + ~msg:("[{signer}: {tags}] " ^ msg) + ~level + ("signer", Signature.Public_key_hash.encoding) + ("tags", Tags.encoding) + enc1 + enc2 + enc3 + ~pp1:Signature.Public_key_hash.pp_short + ~pp2:Tags.pp + ?pp3:pp1 + ?pp4:pp2 + ?pp5:pp3 - let request_failed = - declare_3 - ~name:"request_failed" - ~msg:"request {view} failed ({worker_status}): {errors}" - ~level:Warning - ("view", Request.encoding) - ~pp1:Request.pp - ("worker_status", Worker_types.request_status_encoding) - ~pp2:Worker_types.pp_status - ("errors", Error_monad.trace_encoding) - ~pp3:Error_monad.pp_print_trace + let request_failed = + declare_3 + ~name:"request_failed" + ~msg:"request {view} failed ({worker_status}): {errors}" + ~level:Warning + ("view", Request.encoding) + ~pp1:Request.pp + ("worker_status", Worker_types.request_status_encoding) + ~pp2:Worker_types.pp_status + ("errors", Error_monad.trace_encoding) + ~pp3:Error_monad.pp_print_trace - let request_completed_notice = - declare_2 - ~name:"request_completed_notice" - ~msg:"{view} {worker_status}" - ~level:Notice - ("view", Request.encoding) - ("worker_status", Worker_types.request_status_encoding) - ~pp1:Request.pp - ~pp2:Worker_types.pp_status + let request_completed_notice = + declare_2 + ~name:"request_completed_notice" + ~msg:"{view} {worker_status}" + ~level:Notice + ("view", Request.encoding) + ("worker_status", Worker_types.request_status_encoding) + ~pp1:Request.pp + ~pp2:Worker_types.pp_status - let request_completed_debug = - declare_2 - ~name:"request_completed_debug" - ~msg:"{view} {worker_status}" - ~level:Debug - ("view", Request.encoding) - ("worker_status", Worker_types.request_status_encoding) - ~pp1:Request.pp - ~pp2:Worker_types.pp_status + let request_completed_debug = + declare_2 + ~name:"request_completed_debug" + ~msg:"{view} {worker_status}" + ~level:Debug + ("view", Request.encoding) + ("worker_status", Worker_types.request_status_encoding) + ~pp1:Request.pp + ~pp2:Worker_types.pp_status - let new_tezos_head = - declare_1 - ~name:"new_tezos_head" - ~msg:"processing new Tezos head {head}" - ~level:Debug - ("head", Block_hash.encoding) + let new_tezos_head = + declare_1 + ~name:"new_tezos_head" + ~msg:"processing new Tezos head {head}" + ~level:Debug + ("head", Block_hash.encoding) - let injecting_pending = - declare_1 - ~name:"injecting_pending" - ~msg:"injecting {count} pending operations" - ~level:Notice - ("count", Data_encoding.int31) + let injecting_pending = + declare_1 + ~name:"injecting_pending" + ~msg:"injecting {count} pending operations" + ~level:Notice + ("count", Data_encoding.int31) - let pp_operations_list ppf operations = - Format.fprintf - ppf - "@[%a@]" - (Format.pp_print_list L1_operation.pp) - operations + let pp_operations_list ppf operations = + Format.fprintf + ppf + "@[%a@]" + (Format.pp_print_list Operation.pp) + operations - let pp_operations_hash_list ppf operations = - Format.fprintf - ppf - "@[%a@]" - (Format.pp_print_list L1_operation.Hash.pp) - operations + let pp_operations_hash_list ppf operations = + Format.fprintf + ppf + "@[%a@]" + (Format.pp_print_list Inj_operation.Hash.pp) + operations - let number_of_operations_in_queue = - declare_1 - ~name:"number_of_operations_in_queue" - ~msg: - "injector's queue: there is currently {number_of_operations} \ - operations waiting to be injected" - ~level:Info - ("number_of_operations", Data_encoding.int31) + let number_of_operations_in_queue = + declare_1 + ~name:"number_of_operations_in_queue" + ~msg: + "injector's queue: there is currently {number_of_operations} \ + operations waiting to be injected" + ~level:Info + ("number_of_operations", Data_encoding.int31) - let considered_operations_info = - declare_1 - ~name:"considered_operations_info" - ~msg: - "injector's queue: the following operations are being considered for \ - injection {operations}" - ~level:Debug - ("operations", Data_encoding.list L1_operation.encoding) - ~pp1:pp_operations_list + let considered_operations_info = + declare_1 + ~name:"considered_operations_info" + ~msg: + "injector's queue: the following operations are being considered \ + for injection {operations}" + ~level:Debug + ("operations", Data_encoding.list Operation.encoding) + ~pp1:pp_operations_list - let dropped_operations = - declare_1 - ~name:"dropped_operations" - ~msg: - "dropping operations: the following operations are dropped {operations}" - ~level:Debug - ("operations", Data_encoding.list L1_operation.encoding) - ~pp1:pp_operations_list + let dropped_operations = + declare_1 + ~name:"dropped_operations" + ~msg: + "dropping operations: the following operations are dropped \ + {operations}" + ~level:Debug + ("operations", Data_encoding.list Operation.encoding) + ~pp1:pp_operations_list - let simulating_operations = - declare_2 - ~name:"simulating_operations" - ~msg:"simulating operations (force = {force}): {operations}" - ~level:Debug - ("operations", Data_encoding.list L1_operation.encoding) - ("force", Data_encoding.bool) - ~pp1:pp_operations_list + let simulating_operations = + declare_2 + ~name:"simulating_operations" + ~msg:"simulating operations (force = {force}): {operations}" + ~level:Debug + ("operations", Data_encoding.list Operation.encoding) + ("force", Data_encoding.bool) + ~pp1:pp_operations_list - let dropping_operation = - declare_2 - ~name:"dropping_operation" - ~msg:"dropping operation {operation} failing with {error}" - ~level:Notice - ("operation", L1_operation.encoding) - ~pp1:L1_operation.pp - ("error", Environment.Error_monad.trace_encoding) - ~pp2:Environment.Error_monad.pp_trace + let dropping_operation = + declare_2 + ~name:"dropping_operation" + ~msg:"dropping operation {operation} failing with {error}" + ~level:Notice + ("operation", Operation.encoding) + ~pp1:Operation.pp + ("error", Error_monad.trace_encoding) + ~pp2:Error_monad.pp_print_trace - let injected = - declare_2 - ~name:"injected" - ~msg:"injected {nb} operations in {oph}" - ~level:Notice - ("nb", Data_encoding.int31) - ("oph", Operation_hash.encoding) + let injected = + declare_2 + ~name:"injected" + ~msg:"injected {nb} operations in {oph}" + ~level:Notice + ("nb", Data_encoding.int31) + ("oph", Operation_hash.encoding) - let add_pending = - declare_1 - ~name:"add_pending" - ~msg:"add {operation} to pending" - ~level:Notice - ("operation", L1_operation.encoding) - ~pp1:L1_operation.pp + let add_pending = + declare_1 + ~name:"add_pending" + ~msg:"add {operation} to pending" + ~level:Notice + ("operation", Operation.encoding) + ~pp1:Operation.pp - let retry_operation = - declare_1 - ~name:"retry_operation" - ~msg:"retry {operation}" - ~level:Notice - ("operation", L1_operation.encoding) - ~pp1:L1_operation.pp + let retry_operation = + declare_1 + ~name:"retry_operation" + ~msg:"retry {operation}" + ~level:Notice + ("operation", Operation.encoding) + ~pp1:Operation.pp - let included = - declare_3 - ~name:"included" - ~msg:"included operations of {block} at level {level}: {operations}" - ~level:Notice - ("block", Block_hash.encoding) - ("level", Data_encoding.int32) - ("operations", Data_encoding.list L1_operation.Hash.encoding) - ~pp3:pp_operations_hash_list + let included = + declare_3 + ~name:"included" + ~msg:"included operations of {block} at level {level}: {operations}" + ~level:Notice + ("block", Block_hash.encoding) + ("level", Data_encoding.int32) + ("operations", Data_encoding.list Inj_operation.Hash.encoding) + ~pp3:pp_operations_hash_list - let revert_operations = - declare_1 - ~name:"revert_operations" - ~msg:"reverting operations: {operations}" - ~level:Notice - ("operations", Data_encoding.list L1_operation.Hash.encoding) - ~pp1:pp_operations_hash_list + let revert_operations = + declare_1 + ~name:"revert_operations" + ~msg:"reverting operations: {operations}" + ~level:Notice + ("operations", Data_encoding.list Inj_operation.Hash.encoding) + ~pp1:pp_operations_hash_list - let confirmed_level = - declare_1 - ~name:"confirmed_level" - ~msg:"confirmed Tezos level {level}" - ~level:Notice - ("level", Data_encoding.int32) + let confirmed_level = + declare_1 + ~name:"confirmed_level" + ~msg:"confirmed Tezos level {level}" + ~level:Notice + ("level", Data_encoding.int32) - let loaded_from_disk = - declare_2 - ~name:"loaded_from_disk" - ~msg:"loaded {nb} elements in {kind} from disk" - ~level:Notice - ("nb", Data_encoding.int31) - ("kind", Data_encoding.string) + let loaded_from_disk = + declare_2 + ~name:"loaded_from_disk" + ~msg:"loaded {nb} elements in {kind} from disk" + ~level:Notice + ("nb", Data_encoding.int31) + ("kind", Data_encoding.string) - let corrupted_operation_on_disk = - declare_2 - ~name:"corrupted_operation_on_disk" - ~msg:"ignoring unreadable file {file} on disk: {error}" - ~level:Warning - ("file", Data_encoding.string) - ("error", Error_monad.trace_encoding) - ~pp1:Format.pp_print_string - ~pp2:Error_monad.pp_print_trace + let corrupted_operation_on_disk = + declare_2 + ~name:"corrupted_operation_on_disk" + ~msg:"ignoring unreadable file {file} on disk: {error}" + ~level:Warning + ("file", Data_encoding.string) + ("error", Error_monad.trace_encoding) + ~pp1:Format.pp_print_string + ~pp2:Error_monad.pp_print_trace - let inject_wait = - declare_1 - ~name:"inject_wait" - ~msg:"waiting {delay} seconds to trigger injection" - ~level:Notice - ("delay", Data_encoding.float) -end + let inject_wait = + declare_1 + ~name:"inject_wait" + ~msg:"waiting {delay} seconds to trigger injection" + ~level:Notice + ("delay", Data_encoding.float) + end diff --git a/src/proto_alpha/lib_injector/injector_functor.ml b/src/proto_alpha/lib_injector/injector_functor.ml index 559f8d3744fae0538e114915dd7b2ee48afabd4c..6c5f2c1cffd13de89804ac0f771def291369eee8 100644 --- a/src/proto_alpha/lib_injector/injector_functor.ml +++ b/src/proto_alpha/lib_injector/injector_functor.ml @@ -54,28 +54,134 @@ let injector_context (cctxt : #Protocol_client_context.full) = Format.ksprintf Stdlib.failwith "Injector client wants to exit %d" code end +let manager_operation_result_status (type kind) + (op_result : kind Apply_results.manager_operation_result) : operation_status + = + match op_result with + | Applied _ -> Successful + | Backtracked (_, None) -> Unsuccessful Backtracked + | Skipped _ -> Unsuccessful Skipped + | Backtracked (_, Some err) + (* Backtracked because internal operation failed *) + | Failed (_, err) -> + Unsuccessful (Failed (Environment.wrap_tztrace err)) + +let operation_result_status (type kind) + (op_result : kind Apply_results.contents_result) : operation_status = + match op_result with + | Preendorsement_result _ -> Successful + | Endorsement_result _ -> Successful + | Dal_attestation_result _ -> Successful + | Seed_nonce_revelation_result _ -> Successful + | Vdf_revelation_result _ -> Successful + | Double_endorsement_evidence_result _ -> Successful + | Double_preendorsement_evidence_result _ -> Successful + | Double_baking_evidence_result _ -> Successful + | Activate_account_result _ -> Successful + | Proposals_result -> Successful + | Ballot_result -> Successful + | Drain_delegate_result _ -> Successful + | Manager_operation_result {operation_result; _} -> + manager_operation_result_status operation_result + +let operation_contents_status (type kind) + (contents : kind Apply_results.contents_result_list) ~index : + operation_status tzresult = + let rec rec_status : + type kind. int -> kind Apply_results.contents_result_list -> _ = + fun n -> function + | Apply_results.Single_result _ when n <> 0 -> + error_with "No operation with index %d" index + | Single_result result -> Ok (operation_result_status result) + | Cons_result (result, _rest) when n = 0 -> + Ok (operation_result_status result) + | Cons_result (_result, rest) -> rec_status (n - 1) rest + in + rec_status index contents + +let operation_status (operation : Protocol.operation_receipt) ~index : + operation_status tzresult = + match (operation : _) with + | No_operation_metadata -> + error_with "Cannot find operation status because metadata is missing" + | Operation_metadata {contents} -> operation_contents_status contents ~index + module Make (Parameters : PARAMETERS) = struct module Tags = Injector_tags.Make (Parameters.Tag) module Tags_table = Hashtbl.Make (Parameters.Tag) + module POperation = Parameters.Operation + module Inj_operation = Injector_operation.Make (POperation) + module Request = Request (Inj_operation) + + type injected_info = { + op : Inj_operation.t; + oph : Operation_hash.t; + op_index : int; + } + + type included_info = { + op : Inj_operation.t; + oph : Operation_hash.t; + op_index : int; + l1_block : Block_hash.t; + l1_level : int32; + } + + type status = + | Pending of POperation.t + | Injected of injected_info + | Included of included_info + + let injected_info_encoding = + let open Data_encoding in + conv + (fun ({op; oph; op_index} : injected_info) -> (op, (oph, op_index))) + (fun (op, (oph, op_index)) -> {op; oph; op_index}) + @@ merge_objs + Inj_operation.encoding + (obj1 + (req + "layer1" + (obj2 + (req "operation_hash" Operation_hash.encoding) + (req "operation_index" int31)))) + + let included_info_encoding = + let open Data_encoding in + conv + (fun {op; oph; op_index; l1_block; l1_level} -> + (op, (oph, op_index, l1_block, l1_level))) + (fun (op, (oph, op_index, l1_block, l1_level)) -> + {op; oph; op_index; l1_block; l1_level}) + @@ merge_objs + Inj_operation.encoding + (obj1 + (req + "layer1" + (obj4 + (req "operation_hash" Operation_hash.encoding) + (req "operation_index" int31) + (req "block_hash" Block_hash.encoding) + (req "level" int32)))) module Op_queue = Disk_persistence.Make_queue (struct let name = "operations_queue" end) - (L1_operation.Hash) - (L1_operation) + (Inj_operation.Hash) + (Inj_operation) module Injected_operations = Disk_persistence.Make_table (struct - include L1_operation.Hash.Table + include Inj_operation.Hash.Table type value = injected_info let name = "injected_operations" - let string_of_key = L1_operation.Hash.to_b58check + let string_of_key = Inj_operation.Hash.to_b58check - let key_of_string = L1_operation.Hash.of_b58check_opt + let key_of_string = Inj_operation.Hash.of_b58check_opt let value_encoding = injected_info_encoding end) @@ -83,7 +189,7 @@ module Make (Parameters : PARAMETERS) = struct module Injected_ophs = Disk_persistence.Make_table (struct include Operation_hash.Table - type value = L1_operation.Hash.t list + type value = Inj_operation.Hash.t list let name = "injected_ophs" @@ -91,7 +197,7 @@ module Make (Parameters : PARAMETERS) = struct let key_of_string = Operation_hash.of_b58check_opt - let value_encoding = Data_encoding.list L1_operation.Hash.encoding + let value_encoding = Data_encoding.list Inj_operation.Hash.encoding end) (** The part of the state which gathers information about injected @@ -106,15 +212,15 @@ module Make (Parameters : PARAMETERS) = struct } module Included_operations = Disk_persistence.Make_table (struct - include L1_operation.Hash.Table + include Inj_operation.Hash.Table type value = included_info let name = "included_operations" - let string_of_key = L1_operation.Hash.to_b58check + let string_of_key = Inj_operation.Hash.to_b58check - let key_of_string = L1_operation.Hash.of_b58check_opt + let key_of_string = Inj_operation.Hash.of_b58check_opt let value_encoding = included_info_encoding end) @@ -122,7 +228,7 @@ module Make (Parameters : PARAMETERS) = struct module Included_in_blocks = Disk_persistence.Make_table (struct include Block_hash.Table - type value = int32 * L1_operation.Hash.t list + type value = int32 * Inj_operation.Hash.t list let name = "included_in_blocks" @@ -132,7 +238,7 @@ module Make (Parameters : PARAMETERS) = struct let value_encoding = let open Data_encoding in - obj2 (req "level" int32) (req "l1_ops" (list L1_operation.Hash.encoding)) + obj2 (req "level" int32) (req "l1_ops" (list Inj_operation.Hash.encoding)) end) (** The part of the state which gathers information about @@ -169,7 +275,9 @@ module Make (Parameters : PARAMETERS) = struct } module Event = struct - include Injector_events.Make (Parameters) + include + Injector_events.Make (Parameters) (Tags) (POperation) (Inj_operation) + (Request) let emit1 e state x = emit e (state.signer.pkh, state.tags, x) @@ -185,10 +293,7 @@ module Make (Parameters : PARAMETERS) = struct let data_dir = Filename.concat data_dir "injector" in let*! () = Lwt_utils_unix.create_dir data_dir in let filter op_proj op = - let {L1_operation.manager_operation = Manager op; _} = op_proj op in - match Parameters.operation_tag op with - | None -> false - | Some t -> Tags.mem t tags + Tags.mem (Parameters.operation_tag (op_proj op)) tags in let warn_unreadable = (* Warn of corrupted files but don't fail *) @@ -205,7 +310,7 @@ module Make (Parameters : PARAMETERS) = struct ~warn_unreadable ~capacity:50_000 ~data_dir - ~filter:(filter (fun op -> op)) + ~filter:(filter (fun op -> op.Inj_operation.operation)) in let*! () = emit_event_loaded "operations_queue" @@ Op_queue.length queue in (* Very coarse approximation for the number of operation we expect for each @@ -218,7 +323,7 @@ module Make (Parameters : PARAMETERS) = struct ~warn_unreadable ~initial_size:n ~data_dir - ~filter:(filter (fun (i : injected_info) -> i.op)) + ~filter:(filter (fun (i : injected_info) -> i.op.operation)) in let*! () = emit_event_loaded "injected_operations" @@ -230,7 +335,7 @@ module Make (Parameters : PARAMETERS) = struct ~warn_unreadable ~initial_size:((confirmations + retention_period) * n) ~data_dir - ~filter:(filter (fun (i : included_info) -> i.op)) + ~filter:(filter (fun (i : included_info) -> i.op.operation)) in let*! () = emit_event_loaded "included_operations" @@ -279,9 +384,11 @@ module Make (Parameters : PARAMETERS) = struct let add_pending_operation ?(retry = false) state op = let open Lwt_result_syntax in let*! () = - Event.(emit1 (if retry then retry_operation else add_pending)) state op + Event.(emit1 (if retry then retry_operation else add_pending)) + state + op.Inj_operation.operation in - let* () = Op_queue.replace state.queue op.L1_operation.hash op in + let* () = Op_queue.replace state.queue op.hash op in let*! () = Event.(emit1 number_of_operations_in_queue) state @@ -293,7 +400,9 @@ module Make (Parameters : PARAMETERS) = struct let add_injected_operations state oph operations = let open Lwt_result_syntax in let infos = - List.map (fun op -> (op.L1_operation.hash, {op; oph})) operations + List.map + (fun (op_index, op) -> (op.Inj_operation.hash, {op; oph; op_index})) + operations in let* () = Injected_operations.replace_seq @@ -305,18 +414,22 @@ module Make (Parameters : PARAMETERS) = struct (** [add_included_operations state oph l1_block l1_level operations] marks the [operations] as included (in the L1 batch [oph]) in the Tezos block [l1_block] of level [l1_level]. *) - let add_included_operations state oph l1_block l1_level operations = + let add_included_operations state l1_block l1_level + (operations : injected_info list) = let open Lwt_result_syntax in let*! () = Event.(emit3 included) state l1_block l1_level - (List.map (fun o -> o.L1_operation.hash) operations) + (List.map + (fun (o : injected_info) -> o.op.Inj_operation.hash) + operations) in let infos = List.map - (fun op -> (op.L1_operation.hash, {op; oph; l1_block; l1_level})) + (fun ({op; oph; op_index} : injected_info) -> + (op.Inj_operation.hash, {op; oph; op_index; l1_block; l1_level})) operations in let* () = @@ -391,8 +504,8 @@ module Make (Parameters : PARAMETERS) = struct let fee_parameter_of_operations state ops = List.fold_left - (fun acc {L1_operation.manager_operation = Manager op; _} -> - let param = Parameters.fee_parameter state op in + (fun acc {Inj_operation.operation; _} -> + let param = Parameters.fee_parameter state operation in Injection. { minimal_fees = Tez.max acc.minimal_fees param.minimal_fees; @@ -436,7 +549,7 @@ module Make (Parameters : PARAMETERS) = struct quotas) and [results] are the results of the simulation. See {!inject_operations} for the specification of [must_succeed]. *) let rec simulate_operations ~must_succeed state - (operations : L1_operation.t list) = + (operations : Inj_operation.t list) = let open Lwt_result_syntax in let open Annotated_manager_operation in let force = @@ -450,11 +563,17 @@ module Make (Parameters : PARAMETERS) = struct succeed *) match must_succeed with `All -> false | `At_least_one -> true) in - let*! () = Event.(emit2 simulating_operations) state operations force in + let*! () = + Event.(emit2 simulating_operations) + state + (List.map (fun o -> o.Inj_operation.operation) operations) + force + in let fee_parameter = fee_parameter_of_operations state.state operations in let annotated_operations = List.map - (fun {L1_operation.manager_operation = Manager operation; _} -> + (fun {Inj_operation.operation; _} -> + let (Manager operation) = POperation.to_manager_operation operation in Annotated_manager_operation (Injection.prepare_manager_operation ~fee:Limit.unknown @@ -514,6 +633,18 @@ module Make (Parameters : PARAMETERS) = struct simulate_operations ~must_succeed state operations else fail trace | Ok (_, op, _, result) -> + let nb_ops = List.length operations in + let nb_packed_ops = + let {protocol_data = Operation_data {contents; _}; _} = op in + Alpha_context.Operation.to_list (Contents_list contents) + |> List.length + in + (* packed_op can have reveal operations added automatically. *) + let start_index = nb_packed_ops - nb_ops in + (* Add indexes of operations in the packed, i.e. batched, operation. *) + let operations = + List.mapi (fun i op -> (i + start_index, op)) operations + in return (op, operations, Apply_results.Contents_result_list result) let inject_on_node state ~nb @@ -553,51 +684,39 @@ module Make (Parameters : PARAMETERS) = struct "or-batches" by iteratively removing operations that fail from the desired batch. *) let rec inject_operations ~must_succeed state - (operations : L1_operation.t list) = + (operations : Inj_operation.t list) = let open Lwt_result_syntax in let* packed_op, operations, result = trace (Step_failed "simulation") @@ simulate_operations ~must_succeed state operations in - let results = Apply_results.to_list result in + let (Contents_result_list contents_result) = result in let failure = ref false in let* rev_non_failing_operations = - List.fold_left2_s - ~when_different_lengths: - [ - Exn - (Failure - "Unexpected error: length of operations and result differ in \ - simulation"); - ] - (fun acc op (Apply_results.Contents_result result) -> - match result with - | Apply_results.Manager_operation_result - { - operation_result = - Failed (_, error) | Backtracked (_, Some error); - _; - } -> - let*! () = Event.(emit2 dropping_operation) state op error in + List.fold_left_es + (fun acc (index, op) -> + let open Lwt_result_syntax in + let*? status = operation_contents_status contents_result ~index in + match status with + | Unsuccessful (Failed error) -> + let*! () = + Event.(emit2 dropping_operation) + state + op.Inj_operation.operation + error + in failure := true ; - Lwt.return acc - | Apply_results.Manager_operation_result - { - operation_result = Applied _ | Backtracked (_, None) | Skipped _; - _; - } -> + return acc + | Successful | Unsuccessful (Backtracked | Skipped | Other_branch) -> (* Not known to be failing *) - Lwt.return (op :: acc) - | _ -> - (* Only manager operations *) - assert false) + return (op :: acc)) [] operations - results in if !failure then - (* Invariant: must_succeed = `At_least_one, otherwise the simulation would have - returned an error. We try to inject without the failing operation. *) + (* Invariant: must_succeed = `At_least_one, otherwise the simulation would + have returned an error. We try to inject without the failing + operation. *) let operations = List.rev rev_non_failing_operations in inject_operations ~must_succeed state operations else @@ -613,10 +732,12 @@ module Make (Parameters : PARAMETERS) = struct let size_l1_batch state rev_ops = let contents_list = List.map - (fun (op : L1_operation.t) -> - let (Manager operation) = op.manager_operation in + (fun (op : Inj_operation.t) -> let {fee; counter; gas_limit; storage_limit} = - Parameters.approximate_fee_bound state.state operation + Parameters.approximate_fee_bound state.state op.operation + in + let (Manager operation) = + POperation.to_manager_operation op.operation in let contents = Manager_operation @@ -653,7 +774,7 @@ module Make (Parameters : PARAMETERS) = struct (** Retrieve as many operations from the queue while remaining below the size limit. *) let get_operations_from_queue ~size_limit state = - let exception Reached_limit of L1_operation.t list in + let exception Reached_limit of Inj_operation.t list in let rev_ops = try Op_queue.fold @@ -676,11 +797,10 @@ module Make (Parameters : PARAMETERS) = struct let+ operations_to_drop = List.fold_left_es (fun to_drop op -> - let (Manager operation) = op.L1_operation.manager_operation in let*! retry = Parameters.retry_unsuccessful_operation state.state - operation + op.Inj_operation.operation (Failed err) in match retry with @@ -702,7 +822,9 @@ module Make (Parameters : PARAMETERS) = struct (* Retrieve and remove operations from pending *) let operations_to_inject = get_operations_from_queue ~size_limit state in let*! () = - Event.(emit1 considered_operations_info) state operations_to_inject + Event.(emit1 considered_operations_info) + state + (List.map (fun o -> o.Inj_operation.operation) operations_to_inject) in match operations_to_inject with | [] -> return_unit @@ -715,7 +837,7 @@ module Make (Parameters : PARAMETERS) = struct let must_succeed = Parameters.batch_must_succeed @@ List.map - (fun op -> op.L1_operation.manager_operation) + (fun op -> op.Inj_operation.operation) operations_to_inject in let*! res = @@ -729,18 +851,23 @@ module Make (Parameters : PARAMETERS) = struct (* Injection succeeded, remove from pending and add to injected *) let* () = List.iter_es - (fun op -> Op_queue.remove state.queue op.L1_operation.hash) + (fun (_index, op) -> + Op_queue.remove state.queue op.Inj_operation.hash) injected_operations in add_injected_operations state oph injected_operations | `Ignored operations_to_drop -> (* Injection failed but we ignore the failure. *) let*! () = - Event.(emit1 dropped_operations) state operations_to_drop + Event.(emit1 dropped_operations) + state + (List.map + (fun o -> o.Inj_operation.operation) + operations_to_drop) in let* () = List.iter_es - (fun op -> Op_queue.remove state.queue op.L1_operation.hash) + (fun op -> Op_queue.remove state.queue op.Inj_operation.hash) operations_to_drop in return_unit) @@ -759,60 +886,42 @@ module Make (Parameters : PARAMETERS) = struct (* No operations injected by us *) return_unit | _ -> - let apply (type kind) acc ~source:_ (op : kind manager_operation) - (result : kind Apply_results.manager_operation_result) = - match op with - | Reveal _ -> - (* Ignore public key revelations because, when present, they are - added by the injection function automatically. If we don't - ignore them, we may have more operations than we think we - injected (and end up in the assert false below). *) - acc - | _ -> ( - let* (injected : injected_info list), included, to_retry = acc in - let info, injected = - match injected with - | [] -> assert false - (* We should have the same number of injected operations and - included operations. *) - | i :: rest -> (i, rest) + let* included, to_retry = + List.fold_left_es + (fun (included, to_retry) (info : injected_info) -> + let*? receipt = + match operation.receipt with + | Empty -> + error_with + "Empty receipt for %a" + Operation_hash.pp + operation.hash + | Too_large -> + error_with + "Receipt too large for %a" + Operation_hash.pp + operation.hash + | Receipt r -> Ok r in - match result with - | Applied _ -> return (injected, info.op :: included, to_retry) - | _ -> ( - let status = - match result with - | Applied _ -> assert false - | Backtracked (_, _) -> Backtracked - | Skipped _ -> Skipped - | Failed (_, err) -> Failed (Environment.wrap_tztrace err) - in + let*? status = operation_status receipt ~index:info.op_index in + match status with + | Successful -> return (info :: included, to_retry) + | Unsuccessful status -> ( let*! retry = Parameters.retry_unsuccessful_operation state.state - op + info.op.operation status in match retry with - | Retry -> return (injected, included, info.op :: to_retry) - | Forget -> return (injected, included, to_retry) + | Retry -> return (included, info.op :: to_retry) + | Forget -> return (included, to_retry) | Abort err -> fail err)) + ([], []) + injected_infos in - let apply_internal acc ~source:_ _op _result = acc in - let* unhandled_injected, included, to_retry = - Layer1_services.process_manager_operations - (return (injected_infos, [], [])) - [[operation]] - {apply; apply_internal} - in - assert (unhandled_injected = []) ; let* () = - add_included_operations - state - operation.hash - block - level - (List.rev included) + add_included_operations state block level (List.rev included) in List.iter_es (add_pending_operation ~retry:true state) @@ -847,9 +956,11 @@ module Make (Parameters : PARAMETERS) = struct maybe put at the front of the queue for re-injection. *) List.iter_es (fun {op; _} -> - let {L1_operation.manager_operation = Manager mop; _} = op in let*! requeue = - Parameters.retry_unsuccessful_operation state.state mop Other_branch + Parameters.retry_unsuccessful_operation + state.state + op.operation + Other_branch in match requeue with | Retry -> add_pending_operation ~retry:true state op @@ -1077,19 +1188,16 @@ module Make (Parameters : PARAMETERS) = struct let add_pending_operation ?source op = let open Lwt_result_syntax in - let l1_operation = L1_operation.make op in + let operation = Inj_operation.make op in let*? w = match source with | Some source -> worker_of_signer source - | None -> ( - match Parameters.operation_tag op with - | None -> error (No_worker_for_operation l1_operation) - | Some tag -> worker_of_tag tag) + | None -> worker_of_tag (Parameters.operation_tag op) in let*! (_pushed : bool) = - Worker.Queue.push_request w (Request.Add_pending l1_operation) + Worker.Queue.push_request w (Request.Add_pending operation) in - return l1_operation.hash + return operation.hash let new_tezos_head h reorg = let open Lwt_syntax in @@ -1185,7 +1293,7 @@ module Make (Parameters : PARAMETERS) = struct let op_status_in_worker state l1_hash = match Op_queue.find_opt state.queue l1_hash with - | Some op -> Some (Pending op) + | Some op -> Some (Pending op.operation) | None -> ( match Injected_operations.find state.injected.injected_operations l1_hash diff --git a/src/proto_alpha/lib_injector/injector_functor.mli b/src/proto_alpha/lib_injector/injector_functor.mli index 6f4d83fa6e9a2ab89e10a5118bde71630c22c40f..1c7d4f7c8f8c2791072b541bf3c122ec1058796c 100644 --- a/src/proto_alpha/lib_injector/injector_functor.mli +++ b/src/proto_alpha/lib_injector/injector_functor.mli @@ -26,4 +26,7 @@ open Injector_sigs module Make (P : PARAMETERS) : - S with type state := P.state and type tag := P.Tag.t + S + with type state := P.state + and type tag := P.Tag.t + and type operation := P.Operation.t diff --git a/src/proto_alpha/lib_injector/injector_operation.ml b/src/proto_alpha/lib_injector/injector_operation.ml new file mode 100644 index 0000000000000000000000000000000000000000..b3738be6ba84293cad0aa2b46d169c7d753905b8 --- /dev/null +++ b/src/proto_alpha/lib_injector/injector_operation.ml @@ -0,0 +1,68 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Injector_sigs + +module Make (O : PARAM_OPERATION) : + INJECTOR_OPERATION with type operation = O.t = struct + module Hash = + Tezos_crypto.Blake2B.Make + (Tezos_crypto.Base58) + (struct + let name = "injector_operation_hash" + + let title = "An identifier (hash) for an operation in the injector" + + let b58check_prefix = "\064\007\206" (* iop(53) *) + + let size = None + end) + + let () = + Tezos_crypto.Base58.check_encoded_prefix Hash.b58check_encoding "iop" 53 + + type operation = O.t + + type hash = Hash.t + + type t = {hash : hash; operation : O.t} + + let hash_inner_operation op = + Hash.hash_bytes [Data_encoding.Binary.to_bytes_exn O.encoding op] + + let make operation = + let hash = hash_inner_operation operation in + {hash; operation} + + let encoding = + let open Data_encoding in + conv + (fun {hash; operation} -> (hash, operation)) + (fun (hash, operation) -> {hash; operation}) + @@ obj2 (req "hash" Hash.encoding) (req "operation" O.encoding) + + let pp ppf {hash; operation} = + Format.fprintf ppf "%a (%a)" O.pp operation Hash.pp hash +end diff --git a/src/proto_alpha/lib_injector/l1_operation.mli b/src/proto_alpha/lib_injector/injector_operation.mli similarity index 71% rename from src/proto_alpha/lib_injector/l1_operation.mli rename to src/proto_alpha/lib_injector/injector_operation.mli index 6dc5bdeb9cd85f191a23eafe80a7fc403ee888a1..97f9eadd65a570d8cc360f4b7e9a1db89a22f189 100644 --- a/src/proto_alpha/lib_injector/l1_operation.mli +++ b/src/proto_alpha/lib_injector/injector_operation.mli @@ -23,26 +23,6 @@ (* *) (*****************************************************************************) -open Protocol.Alpha_context +open Injector_sigs -(** Hash with b58check encoding mop(53), for hashes of L1 manager operations *) -module Hash : Tezos_crypto.Intfs.HASH - -(** Alias for L1 operations hashes *) -type hash = Hash.t - -(** The type of L1 operations that are injected on Tezos by the rollup node *) -type t = private { - hash : hash; (** The hash of the L1 manager operation (without the source) *) - manager_operation : packed_manager_operation; (** The manager operation *) -} - -(** [make op] returns an L1 operation with the corresponding hash. *) -val make : 'a manager_operation -> t - -(** Encoding for L1 operations *) -val encoding : t Data_encoding.t - -(** Pretty printer for L1 operations. Only the relevant part for the rollup node - is printed. *) -val pp : Format.formatter -> t -> unit +module Make (O : PARAM_OPERATION) : INJECTOR_OPERATION with type operation = O.t diff --git a/src/proto_alpha/lib_injector/injector_sigs.ml b/src/proto_alpha/lib_injector/injector_sigs.ml index 01adc7ef578b5d3592d841bac99caedf449d149c..f763dee30a820fca6a359d7bad1a689b10276fe5 100644 --- a/src/proto_alpha/lib_injector/injector_sigs.ml +++ b/src/proto_alpha/lib_injector/injector_sigs.ml @@ -56,6 +56,8 @@ type unsuccessful_status = the same batch. *) | Failed of error trace (** The operation failed with the provided error. *) +type operation_status = Successful | Unsuccessful of unsuccessful_status + (** Action to be taken for unsuccessful operation. *) type retry_action = | Retry (** The operation is retried by being re-queued for injection. *) @@ -64,60 +66,6 @@ type retry_action = (** The error for the failing operation should be propagated at a higher level. *) -(** Information stored about an L1 operation that was injected on a Tezos - node. *) -type injected_info = { - op : L1_operation.t; (** The L1 manager operation. *) - oph : Operation_hash.t; - (** The hash of the operation which contains [op] (this can be an L1 batch - of several manager operations). *) -} - -(** Information stored about an L1 operation that was included in a Tezos - block. *) -type included_info = { - op : L1_operation.t; (** The L1 manager operation. *) - oph : Operation_hash.t; - (** The hash of the operation which contains [op] (this can be an L1 batch - of several manager operations). *) - l1_block : Block_hash.t; - (** The hash of the L1 block in which the operation was included. *) - l1_level : int32; (** The level of [l1_block]. *) -} - -(** Status of an operation in the injector. *) -type status = - | Pending of L1_operation.t (** The operation is pending injection. *) - | Injected of injected_info - (** The operation has been injected successfully in the node. *) - | Included of included_info - (** The operation has been included in a L1 block. *) - -let injected_info_encoding = - let open Data_encoding in - conv - (fun ({op; oph} : injected_info) -> (op, oph)) - (fun (op, oph) -> {op; oph}) - @@ merge_objs - L1_operation.encoding - (obj1 - (req "layer1" (obj1 (req "operation_hash" Operation_hash.encoding)))) - -let included_info_encoding = - let open Data_encoding in - conv - (fun {op; oph; l1_block; l1_level} -> (op, (oph, l1_block, l1_level))) - (fun (op, (oph, l1_block, l1_level)) -> {op; oph; l1_block; l1_level}) - @@ merge_objs - L1_operation.encoding - (obj1 - (req - "layer1" - (obj3 - (req "operation_hash" Operation_hash.encoding) - (req "block_hash" Block_hash.encoding) - (req "level" int32)))) - (** Signature for tags used in injector *) module type TAG = sig include Stdlib.Set.OrderedType @@ -129,6 +77,45 @@ module type TAG = sig val encoding : t Data_encoding.t end +module type PARAM_OPERATION = sig + (** The abstract type of operations to inject *) + type t + + (** An encoding for injector's operations *) + val encoding : t Data_encoding.t + + (** Convert an injector operation to a manager_operation of the protocol *) + val to_manager_operation : t -> packed_manager_operation + + (** Pretty-printing injector's operations *) + val pp : Format.formatter -> t -> unit +end + +(** Internal representation of injector operations. *) +module type INJECTOR_OPERATION = sig + type operation + + (** Hash with b58check encoding iop(53), for hashes of injector operations *) + module Hash : Tezos_crypto.Intfs.HASH + + (** Alias for L1 operations hashes *) + type hash = Hash.t + + (** The type of L1 operations that are injected on Tezos. These have a hash + attached to them that allows tracking and retrieving their status. *) + type t = private {hash : hash; operation : operation} + + (** [make op] returns an L1 operation with the corresponding hash. *) + val make : operation -> t + + (** Encoding for L1 operations *) + val encoding : t Data_encoding.t + + (** Pretty printer for L1 operations. Only the relevant part for the rollup node + is printed. *) + val pp : Format.formatter -> t -> unit +end + (** Module type for parameter of functor {!Injector_functor.Make}. *) module type PARAMETERS = sig (** The type of the state that the injector can access *) @@ -137,6 +124,9 @@ module type PARAMETERS = sig (** A module which contains the different tags for the injector *) module Tag : TAG + (** A module for the injector operations *) + module Operation : PARAM_OPERATION + (** Where to put the events for this injector *) val events_section : string list @@ -147,22 +137,21 @@ module type PARAMETERS = sig (** Action (see {!retry_action}) to be taken on unsuccessful operation (see {!unsuccessful_status}). *) val retry_unsuccessful_operation : - state -> 'a manager_operation -> unsuccessful_status -> retry_action Lwt.t + state -> Operation.t -> unsuccessful_status -> retry_action Lwt.t (** The tag of a manager operation. This is used to send operations to the correct queue automatically (when signer is not provided) and to recover persistent information. *) - val operation_tag : 'a manager_operation -> Tag.t option + val operation_tag : Operation.t -> Tag.t (** Returns the {e approximate upper-bounds} for the fee and limits of an operation, used to compute an upper bound on the size (in bytes) for this operation. *) - val approximate_fee_bound : - state -> 'a manager_operation -> approximate_fee_bound + val approximate_fee_bound : state -> Operation.t -> approximate_fee_bound (** Returns the fee_parameter (to compute fee w.r.t. gas, size, etc.) and the caps of fee and burn for each operation. *) - val fee_parameter : state -> 'a manager_operation -> Injection.fee_parameter + val fee_parameter : state -> Operation.t -> Injection.fee_parameter (** When injecting the given [operations] in an L1 batch, if [batch_must_succeed operations] returns [`All] then all the operations must @@ -172,8 +161,7 @@ module type PARAMETERS = sig be included in the injected L1 batch. {b Note}: Returning [`At_least_one] allows to incrementally build "or-batches" by iteratively removing operations that fail from the desired batch. *) - val batch_must_succeed : - packed_manager_operation list -> [`All | `At_least_one] + val batch_must_succeed : Operation.t list -> [`All | `At_least_one] end (** Output signature for functor {!Injector_functor.Make}. *) @@ -182,6 +170,47 @@ module type S = sig type tag + type operation + + module Inj_operation : INJECTOR_OPERATION with type operation = operation + + (** Information stored about an L1 operation that was injected on a Tezos + node. *) + type injected_info = { + op : Inj_operation.t; (** The injector operation. *) + oph : Operation_hash.t; + (** The hash of the operation which contains [op] (this can be an L1 batch + of several manager operations). *) + op_index : int; + (** The index of the operation [op] in the L1 batch corresponding to [oph]. *) + } + + (** Information stored about an L1 operation that was included in a Tezos + block. *) + type included_info = { + op : Inj_operation.t; (** The injector operation. *) + oph : Operation_hash.t; + (** The hash of the operation which contains [op] (this can be an L1 batch + of several manager operations). *) + op_index : int; + (** The index of the operation [op] in the L1 batch corresponding to [oph]. *) + l1_block : Block_hash.t; + (** The hash of the L1 block in which the operation was included. *) + l1_level : int32; (** The level of [l1_block]. *) + } + + (** Status of an operation in the injector. *) + type status = + | Pending of operation (** The operation is pending injection. *) + | Injected of injected_info + (** The operation has been injected successfully in the node. *) + | Included of included_info + (** The operation has been included in a L1 block. *) + + val injected_info_encoding : injected_info Data_encoding.t + + val included_info_encoding : included_info Data_encoding.t + (** Initializes the injector with the rollup node state, for a list of signers, and start the workers. Each signer has its own worker with a queue of operations to inject. @@ -204,9 +233,7 @@ module type S = sig corresponding tag. It returns the hash of the operation in the injector queue. *) val add_pending_operation : - ?source:public_key_hash -> - 'a manager_operation -> - L1_operation.hash tzresult Lwt.t + ?source:public_key_hash -> operation -> Inj_operation.Hash.t tzresult Lwt.t (** Notify the injector of a new Tezos head. The injector marks the operations appropriately (for instance reverted operations that are part of a @@ -229,5 +256,5 @@ module type S = sig val shutdown : unit -> unit Lwt.t (** The status of an operation in the injector. *) - val operation_status : L1_operation.hash -> status option + val operation_status : Inj_operation.Hash.t -> status option end diff --git a/src/proto_alpha/lib_injector/injector_worker_types.ml b/src/proto_alpha/lib_injector/injector_worker_types.ml index 62e6a76ce37470bf31dc9392c466a87c9de94a8c..0702581588eef3486e409f3eaed5c27bea4e08a2 100644 --- a/src/proto_alpha/lib_injector/injector_worker_types.ml +++ b/src/proto_alpha/lib_injector/injector_worker_types.ml @@ -27,8 +27,9 @@ open Protocol_client_context open Protocol open Alpha_context open Injector_common +open Injector_sigs -module Request = struct +module Request (L1_operation : INJECTOR_OPERATION) = struct type ('a, 'b) t = | Add_pending : L1_operation.t -> (unit, error trace) t | New_tezos_head : @@ -75,11 +76,7 @@ module Request = struct let pp ppf (View r) = match r with | Add_pending op -> - Format.fprintf - ppf - "request add %a to pending queue" - L1_operation.Hash.pp - op.hash + Format.fprintf ppf "request add %a to pending queue" L1_operation.pp op | New_tezos_head (b, r) -> Format.fprintf ppf diff --git a/src/proto_alpha/lib_injector/injector_worker_types.mli b/src/proto_alpha/lib_injector/injector_worker_types.mli index 28c23d0a517d6ba5e2697a623615b1fde2b14144..15ce6419727542da607403b7174422d238b82fa2 100644 --- a/src/proto_alpha/lib_injector/injector_worker_types.mli +++ b/src/proto_alpha/lib_injector/injector_worker_types.mli @@ -27,10 +27,11 @@ open Protocol_client_context open Protocol open Alpha_context open Injector_common +open Injector_sigs -module Request : sig +module Request (Inj_operation : INJECTOR_OPERATION) : sig type ('a, 'b) t = - | Add_pending : L1_operation.t -> (unit, error trace) t + | Add_pending : Inj_operation.t -> (unit, error trace) t | New_tezos_head : Alpha_block_services.block_info * Alpha_block_services.block_info reorg -> (unit, error trace) t diff --git a/src/proto_alpha/lib_injector/l1_operation.ml b/src/proto_alpha/lib_injector/l1_operation.ml deleted file mode 100644 index 59438c487992297e449eda58f6e469a338a4e9af..0000000000000000000000000000000000000000 --- a/src/proto_alpha/lib_injector/l1_operation.ml +++ /dev/null @@ -1,232 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -open Protocol -open Alpha_context - -module Manager_operation = struct - type t = packed_manager_operation - - let encoding : t Data_encoding.t = - let open Data_encoding in - let open Operation.Encoding.Manager_operations in - let make (MCase {tag; name; encoding; select; proj; inj}) = - case - (Tag tag) - ~title:name - (merge_objs (obj1 (req "kind" (constant name))) encoding) - (fun o -> - match select o with None -> None | Some o -> Some ((), proj o)) - (fun ((), x) -> Manager (inj x)) - in - def "manager_operation" - @@ union - [ - make reveal_case; - make transaction_case; - make origination_case; - make delegation_case; - make set_deposits_limit_case; - make increase_paid_storage_case; - make register_global_constant_case; - make tx_rollup_origination_case; - make tx_rollup_submit_batch_case; - make tx_rollup_commit_case; - make tx_rollup_return_bond_case; - make tx_rollup_finalize_commitment_case; - make tx_rollup_remove_commitment_case; - make tx_rollup_rejection_case; - make tx_rollup_dispatch_tickets_case; - make transfer_ticket_case; - make dal_publish_slot_header_case; - make sc_rollup_originate_case; - make sc_rollup_add_messages_case; - make sc_rollup_cement_case; - make sc_rollup_publish_case; - make sc_rollup_refute_case; - make sc_rollup_timeout_case; - make sc_rollup_execute_outbox_message_case; - make sc_rollup_recover_bond_case; - ] - - let get_case : - type kind. - kind manager_operation -> kind Operation.Encoding.Manager_operations.case - = - let open Operation.Encoding.Manager_operations in - function - | Reveal _ -> reveal_case - | Transaction _ -> transaction_case - | Origination _ -> origination_case - | Delegation _ -> delegation_case - | Register_global_constant _ -> register_global_constant_case - | Set_deposits_limit _ -> set_deposits_limit_case - | Increase_paid_storage _ -> increase_paid_storage_case - | Update_consensus_key _ -> update_consensus_key_case - | Tx_rollup_origination -> tx_rollup_origination_case - | Tx_rollup_submit_batch _ -> tx_rollup_submit_batch_case - | Tx_rollup_commit _ -> tx_rollup_commit_case - | Tx_rollup_return_bond _ -> tx_rollup_return_bond_case - | Tx_rollup_finalize_commitment _ -> tx_rollup_finalize_commitment_case - | Tx_rollup_remove_commitment _ -> tx_rollup_remove_commitment_case - | Tx_rollup_rejection _ -> tx_rollup_rejection_case - | Tx_rollup_dispatch_tickets _ -> tx_rollup_dispatch_tickets_case - | Transfer_ticket _ -> transfer_ticket_case - | Dal_publish_slot_header _ -> dal_publish_slot_header_case - | Sc_rollup_originate _ -> sc_rollup_originate_case - | Sc_rollup_add_messages _ -> sc_rollup_add_messages_case - | Sc_rollup_cement _ -> sc_rollup_cement_case - | Sc_rollup_publish _ -> sc_rollup_publish_case - | Sc_rollup_refute _ -> sc_rollup_refute_case - | Sc_rollup_timeout _ -> sc_rollup_timeout_case - | Sc_rollup_execute_outbox_message _ -> - sc_rollup_execute_outbox_message_case - | Sc_rollup_recover_bond _ -> sc_rollup_recover_bond_case - | Zk_rollup_origination _ -> zk_rollup_origination_case - | Zk_rollup_publish _ -> zk_rollup_publish_case - | Zk_rollup_update _ -> zk_rollup_update_case - - let pp_kind ppf op = - let open Operation.Encoding.Manager_operations in - let (MCase {name; _}) = get_case op in - Format.pp_print_string ppf name - - let pp ppf (Manager op) = - match op with - | Tx_rollup_commit {commitment = {level; _}; _} -> - Format.fprintf - ppf - "commitment for rollup level %a" - Tx_rollup_level.pp - level - | Tx_rollup_rejection {level; message_position; _} -> - Format.fprintf - ppf - "rejection for commitment at level %a for message %d" - Tx_rollup_level.pp - level - message_position - | Tx_rollup_dispatch_tickets {level; tickets_info; _} -> - let pp_rollup_reveal ppf - Tx_rollup_reveal.{contents; ty; amount; ticketer; claimer; _} = - let pp_lazy_expr ppf e = - Michelson_v1_printer.print_expr_unwrapped - ppf - (Result.value - (Script_repr.force_decode e) - ~default:(Micheline.strip_locations (Micheline.Seq ((), [])))) - in - Format.fprintf - ppf - "%a tickets (%a, %a, %a) to %a" - Tx_rollup_l2_qty.pp - amount - Contract.pp - ticketer - pp_lazy_expr - ty - pp_lazy_expr - contents - Signature.Public_key_hash.pp - claimer - in - Format.fprintf - ppf - "@[dispatch withdrawals at rollup level %a: %a@]" - Tx_rollup_level.pp - level - (Format.pp_print_list pp_rollup_reveal) - tickets_info - | Sc_rollup_add_messages {messages} -> - Format.fprintf - ppf - "publishing %d messages to smart rollups' inbox" - (List.length messages) - | Sc_rollup_cement {rollup; commitment} -> - Format.fprintf - ppf - "cementing commitment %a of rollup %a" - Sc_rollup.Commitment.Hash.pp - commitment - Sc_rollup.Address.pp - rollup - | Sc_rollup_publish - {rollup; commitment = Sc_rollup.Commitment.{inbox_level; _}} -> - Format.fprintf - ppf - "publish commitment for level %a of rollup %a" - Raw_level.pp - inbox_level - Sc_rollup.Address.pp - rollup - | _ -> pp_kind ppf op -end - -module Hash = - Tezos_crypto.Blake2B.Make - (Tezos_crypto.Base58) - (struct - let name = "manager_operation_hash" - - let title = "A manager operation hash" - - let b58check_prefix = "\068\160\013" (* mop(53) *) - - let size = None - end) - -let () = - Tezos_crypto.Base58.check_encoded_prefix Hash.b58check_encoding "mop" 53 - -type hash = Hash.t - -type t = {hash : hash; manager_operation : packed_manager_operation} - -let hash_manager_operation op = - Hash.hash_bytes - [Data_encoding.Binary.to_bytes_exn Manager_operation.encoding op] - -let make manager_operation = - let manager_operation = Manager manager_operation in - let hash = hash_manager_operation manager_operation in - {hash; manager_operation} - -let encoding = - let open Data_encoding in - conv - (fun {hash; manager_operation} -> (hash, manager_operation)) - (fun (hash, manager_operation) -> {hash; manager_operation}) - @@ obj2 - (req "hash" Hash.encoding) - (req "manager_operation" Manager_operation.encoding) - -let pp ppf {hash; manager_operation} = - Format.fprintf - ppf - "%a (%a)" - Manager_operation.pp - manager_operation - Hash.pp - hash diff --git a/src/proto_alpha/lib_sc_rollup/l1_operation.ml b/src/proto_alpha/lib_sc_rollup/l1_operation.ml new file mode 100644 index 0000000000000000000000000000000000000000..1b3e165b794ff98f676d154ef7162e9703531525 --- /dev/null +++ b/src/proto_alpha/lib_sc_rollup/l1_operation.ml @@ -0,0 +1,178 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol.Alpha_context + +type t = + | Add_messages of {messages : string list} + | Cement of {rollup : Sc_rollup.t; commitment : Sc_rollup.Commitment.Hash.t} + | Publish of {rollup : Sc_rollup.t; commitment : Sc_rollup.Commitment.t} + | Refute of { + rollup : Sc_rollup.t; + opponent : Sc_rollup.Staker.t; + refutation : Sc_rollup.Game.refutation; + } + | Timeout of {rollup : Sc_rollup.t; stakers : Sc_rollup.Game.Index.t} + +let encoding : t Data_encoding.t = + let open Data_encoding in + let case tag kind encoding proj inj = + case + ~title:kind + (Tag tag) + (merge_objs (obj1 (req "kind" (constant kind))) encoding) + (fun o -> Option.map (fun p -> ((), p)) (proj o)) + (fun ((), p) -> inj p) + in + def "sc_rollup_node_l1_operation" + @@ union + [ + case + 0 + "add_messages" + (obj1 (req "message" (list (string' Hex)))) + (function Add_messages {messages} -> Some messages | _ -> None) + (fun messages -> Add_messages {messages}); + case + 1 + "cement" + (obj2 + (req "rollup" Sc_rollup.Address.encoding) + (req "commitment" Sc_rollup.Commitment.Hash.encoding)) + (function + | Cement {rollup; commitment} -> Some (rollup, commitment) + | _ -> None) + (fun (rollup, commitment) -> Cement {rollup; commitment}); + case + 2 + "publish" + (obj2 + (req "rollup" Sc_rollup.Address.encoding) + (req "commitment" Sc_rollup.Commitment.encoding)) + (function + | Publish {rollup; commitment} -> Some (rollup, commitment) + | _ -> None) + (fun (rollup, commitment) -> Publish {rollup; commitment}); + case + 3 + "refute" + (obj3 + (req "rollup" Sc_rollup.Address.encoding) + (req "opponent" Sc_rollup.Staker.encoding) + (req "refutation" Sc_rollup.Game.refutation_encoding)) + (function + | Refute {rollup; opponent; refutation} -> + Some (rollup, opponent, refutation) + | _ -> None) + (fun (rollup, opponent, refutation) -> + Refute {rollup; opponent; refutation}); + case + 4 + "timeout" + (obj2 + (req "rollup" Sc_rollup.Address.encoding) + (req "stakers" Sc_rollup.Game.Index.encoding)) + (function + | Timeout {rollup; stakers} -> Some (rollup, stakers) | _ -> None) + (fun (rollup, stakers) -> Timeout {rollup; stakers}); + ] + +let pp ppf = function + | Add_messages {messages} -> + Format.fprintf + ppf + "publishing %d messages to smart rollups' inbox" + (List.length messages) + | Cement {rollup = _; commitment} -> + Format.fprintf + ppf + "cementing commitment %a" + Sc_rollup.Commitment.Hash.pp + commitment + | Publish {rollup = _; commitment = Sc_rollup.Commitment.{inbox_level; _}} -> + Format.fprintf + ppf + "publish commitment for level %a" + Raw_level.pp + inbox_level + | Refute {rollup = _; opponent; refutation = Start _} -> + Format.fprintf + ppf + "start refutation game against %a" + Signature.Public_key_hash.pp + opponent + | Refute + { + rollup = _; + opponent; + refutation = Move {step = Dissection (first :: _ as d); _}; + } -> + let last = List.last first d in + Format.fprintf + ppf + "dissection between ticks %a and %a (against %a)" + Sc_rollup.Tick.pp + first.tick + Sc_rollup.Tick.pp + last.tick + Signature.Public_key_hash.pp + opponent + | Refute {rollup = _; opponent; refutation = Move {step = Dissection []; _}} + -> + Format.fprintf + ppf + "dissection (against %a)" + Signature.Public_key_hash.pp + opponent + | Refute {rollup = _; opponent; refutation = Move {choice; step = Proof _}} -> + Format.fprintf + ppf + "proof for tick %a (against %a)" + Sc_rollup.Tick.pp + choice + Signature.Public_key_hash.pp + opponent + | Timeout {rollup = _; stakers = _} -> Format.fprintf ppf "timeout" + +let to_manager_operation : t -> packed_manager_operation = function + | Add_messages {messages} -> Manager (Sc_rollup_add_messages {messages}) + | Cement {rollup; commitment} -> + Manager (Sc_rollup_cement {rollup; commitment}) + | Publish {rollup; commitment} -> + Manager (Sc_rollup_publish {rollup; commitment}) + | Refute {rollup; opponent; refutation} -> + Manager (Sc_rollup_refute {rollup; opponent; refutation}) + | Timeout {rollup; stakers} -> Manager (Sc_rollup_timeout {rollup; stakers}) + +let of_manager_operation : type kind. kind manager_operation -> t option = + function + | Sc_rollup_add_messages {messages} -> Some (Add_messages {messages}) + | Sc_rollup_cement {rollup; commitment} -> Some (Cement {rollup; commitment}) + | Sc_rollup_publish {rollup; commitment} -> + Some (Publish {rollup; commitment}) + | Sc_rollup_refute {rollup; opponent; refutation} -> + Some (Refute {rollup; opponent; refutation}) + | Sc_rollup_timeout {rollup; stakers} -> Some (Timeout {rollup; stakers}) + | _ -> None diff --git a/src/proto_alpha/lib_sc_rollup/l1_operation.mli b/src/proto_alpha/lib_sc_rollup/l1_operation.mli new file mode 100644 index 0000000000000000000000000000000000000000..d6bd71285e0f47e35d01ce3f0f11fcbbb32dbfcb --- /dev/null +++ b/src/proto_alpha/lib_sc_rollup/l1_operation.mli @@ -0,0 +1,50 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol.Alpha_context + +(** L1 operations produced (and injected) by the rollup node. *) +type t = + | Add_messages of {messages : string list} + | Cement of {rollup : Sc_rollup.t; commitment : Sc_rollup.Commitment.Hash.t} + | Publish of {rollup : Sc_rollup.t; commitment : Sc_rollup.Commitment.t} + | Refute of { + rollup : Sc_rollup.t; + opponent : Sc_rollup.Staker.t; + refutation : Sc_rollup.Game.refutation; + } + | Timeout of {rollup : Sc_rollup.t; stakers : Sc_rollup.Game.Index.t} + +(** Encoding for L1 operations (used by injector for on-disk persistence). *) +val encoding : t Data_encoding.t + +(** Manager operation for a given L1 operation. *) +val to_manager_operation : t -> packed_manager_operation + +(** L1 operation corresponding to a manager operation if any. *) +val of_manager_operation : 'a manager_operation -> t option + +(** Pretty printer (human readable) for L1 operations. *) +val pp : Format.formatter -> t -> unit diff --git a/src/proto_alpha/lib_sc_rollup/sc_rollup_services.ml b/src/proto_alpha/lib_sc_rollup/sc_rollup_services.ml index 4feffad8d8e814f1ecf6cb2d4746dfe5b52bc7ff..32bc76841bed1e9551f4b489514f01c4d9b81842 100644 --- a/src/proto_alpha/lib_sc_rollup/sc_rollup_services.ml +++ b/src/proto_alpha/lib_sc_rollup/sc_rollup_services.ml @@ -62,8 +62,6 @@ type simulate_input = { reveal_pages : string list option; } -type inbox_info = {finalized : bool; cemented : bool} - type commitment_info = { commitment : Sc_rollup.Commitment.t; commitment_hash : Sc_rollup.Commitment.Hash.t; @@ -75,9 +73,29 @@ type message_status = | Unknown | Pending_batch | Pending_injection of L1_operation.t - | Injected of Injector_sigs.injected_info - | Included of Injector_sigs.included_info * inbox_info - | Committed of Injector_sigs.included_info * inbox_info * commitment_info + | Injected of {op : L1_operation.t; oph : Operation_hash.t; op_index : int} + | Included of { + op : L1_operation.t; + oph : Operation_hash.t; + op_index : int; + l1_block : Block_hash.t; + l1_level : int32; + finalized : bool; + cemented : bool; + } + | Committed of { + op : L1_operation.t; + oph : Operation_hash.t; + op_index : int; + l1_block : Block_hash.t; + l1_level : int32; + finalized : bool; + cemented : bool; + commitment : Sc_rollup.Commitment.t; + commitment_hash : Sc_rollup.Commitment.Hash.t; + first_published_at_level : Raw_level.t; + published_at_level : Raw_level.t; + } module Encodings = struct open Data_encoding @@ -144,12 +162,6 @@ module Encodings = struct let batcher_queue = list queued_message - let inbox_info = - conv - (fun {finalized; cemented} -> (finalized, cemented)) - (fun (finalized, cemented) -> {finalized; cemented}) - @@ obj2 (req "finalized" bool) (req "cemented" bool) - let commitment_info = conv (fun { @@ -210,35 +222,117 @@ module Encodings = struct ~description: "The message is injected as part of an L1 operation but it is not \ included in a block." - (merge_objs - (obj1 (req "status" (constant "injected"))) - Injector_sigs.injected_info_encoding) - (function Injected info -> Some ((), info) | _ -> None) - (fun ((), info) -> Injected info); + (obj3 + (req "status" (constant "injected")) + (req "operation" L1_operation.encoding) + (req + "layer1" + (obj2 + (req "operation_hash" Operation_hash.encoding) + (req "operation_index" int31)))) + (function + | Injected {op; oph; op_index} -> Some ((), op, (oph, op_index)) + | _ -> None) + (fun ((), op, (oph, op_index)) -> Injected {op; oph; op_index}); case (Tag 4) ~title:"included" ~description:"The message is included in an inbox in an L1 block." - (merge_objs - (obj1 (req "status" (constant "included"))) - (merge_objs Injector_sigs.included_info_encoding inbox_info)) + (obj5 + (req "status" (constant "included")) + (req "operation" L1_operation.encoding) + (req + "layer1" + (obj4 + (req "operation_hash" Operation_hash.encoding) + (req "operation_index" int31) + (req "block_hash" Block_hash.encoding) + (req "level" int32))) + (req "finalized" bool) + (req "cemented" bool)) (function - | Included (info, inbox_info) -> Some ((), (info, inbox_info)) + | Included + {op; oph; op_index; l1_block; l1_level; finalized; cemented} -> + Some + ( (), + op, + (oph, op_index, l1_block, l1_level), + finalized, + cemented ) | _ -> None) - (fun ((), (info, inbox_info)) -> Included (info, inbox_info)); + (fun ((), op, (oph, op_index, l1_block, l1_level), finalized, cemented) + -> + Included + {op; oph; op_index; l1_block; l1_level; finalized; cemented}); case (Tag 5) ~title:"committed" ~description:"The message is included in a committed inbox on L1." - (merge_objs (obj1 (req "status" (constant "committed"))) - @@ merge_objs Injector_sigs.included_info_encoding - @@ merge_objs inbox_info (obj1 (req "commitment" commitment_info))) + (obj9 + (req "status" (constant "committed")) + (req "operation" L1_operation.encoding) + (req + "layer1" + (obj4 + (req "operation_hash" Operation_hash.encoding) + (req "operation_index" int31) + (req "block_hash" Block_hash.encoding) + (req "level" int32))) + (req "finalized" bool) + (req "cemented" bool) + (req "commitment" Sc_rollup.Commitment.encoding) + (req "hash" Sc_rollup.Commitment.Hash.encoding) + (req "first_published_at_level" Raw_level.encoding) + (req "published_at_level" Raw_level.encoding)) (function - | Committed (info, inbox_info, commitment) -> - Some ((), (info, (inbox_info, commitment))) + | Committed + { + op; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + commitment; + commitment_hash; + first_published_at_level; + published_at_level; + } -> + Some + ( (), + op, + (oph, op_index, l1_block, l1_level), + finalized, + cemented, + commitment, + commitment_hash, + first_published_at_level, + published_at_level ) | _ -> None) - (fun ((), (info, (inbox_info, commitment))) -> - Committed (info, inbox_info, commitment)); + (fun ( (), + op, + (oph, op_index, l1_block, l1_level), + finalized, + cemented, + commitment, + commitment_hash, + first_published_at_level, + published_at_level ) -> + Committed + { + op; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + commitment; + commitment_hash; + first_published_at_level; + published_at_level; + }); ] let message_status_output = diff --git a/src/proto_alpha/lib_sc_rollup_node/RPC_server.ml b/src/proto_alpha/lib_sc_rollup_node/RPC_server.ml index 75c9717b4cf0c8f6d306496c0271c0083793488c..ea3457213c2a7c8807046f9bf4fbd6d722359dcc 100644 --- a/src/proto_alpha/lib_sc_rollup_node/RPC_server.ml +++ b/src/proto_alpha/lib_sc_rollup_node/RPC_server.ml @@ -384,7 +384,7 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct let cemented = Compare.Int32.(inbox_level <= Raw_level.to_int32 lcc.level) in - Sc_rollup_services.{finalized; cemented} + (finalized, cemented) let () = Local_directory.register1 Sc_rollup_services.Local.batcher_message @@ -403,18 +403,30 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct | None -> return Sc_rollup_services.Unknown | Some (Pending op) -> return (Sc_rollup_services.Pending_injection op) - | Some (Injected info) -> - return (Sc_rollup_services.Injected info) - | Some (Included info) -> ( - let* inbox_info = - inbox_info_of_level node_ctxt info.l1_level + | Some (Injected {op; oph; op_index}) -> + return + (Sc_rollup_services.Injected + {op = op.operation; oph; op_index}) + | Some (Included {op; oph; op_index; l1_block; l1_level}) -> ( + let* finalized, cemented = + inbox_info_of_level node_ctxt l1_level in let commitment_level = - commitment_level_of_inbox_level node_ctxt info.l1_level + commitment_level_of_inbox_level node_ctxt l1_level in match commitment_level with | None -> - return (Sc_rollup_services.Included (info, inbox_info)) + return + (Sc_rollup_services.Included + { + op = op.operation; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + }) | Some commitment_level -> ( let* block = Node_context.find_l2_block_by_level @@ -425,7 +437,16 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct | None -> (* Commitment not computed yet for inbox *) return - (Sc_rollup_services.Included (info, inbox_info)) + (Sc_rollup_services.Included + { + op = op.operation; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + }) | Some block -> ( let commitment_hash = WithExceptions.Option.get @@ -442,7 +463,16 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct | None | Some {published_at_level = None; _} -> (* Commitment not published yet *) return - (Sc_rollup_services.Included (info, inbox_info)) + (Sc_rollup_services.Included + { + op = op.operation; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + }) | Some { first_published_at_level; @@ -454,18 +484,21 @@ module Make (Simulation : Simulation.S) (Batcher : Batcher.S) = struct node_ctxt commitment_hash in - let commitment_info = - Sc_rollup_services. - { - commitment; - commitment_hash; - first_published_at_level; - published_at_level; - } - in return (Sc_rollup_services.Committed - (info, inbox_info, commitment_info))))))) + { + op = op.operation; + oph; + op_index; + l1_block; + l1_level; + finalized; + cemented; + commitment; + commitment_hash; + first_published_at_level; + published_at_level; + })))))) in return status diff --git a/src/proto_alpha/lib_sc_rollup_node/batcher.ml b/src/proto_alpha/lib_sc_rollup_node/batcher.ml index b1782893b7a06e09c96b864e2ec2bf52bac77310..27aa3059d536afc37b006a0ed46dd7810f504ccb 100644 --- a/src/proto_alpha/lib_sc_rollup_node/batcher.ml +++ b/src/proto_alpha/lib_sc_rollup_node/batcher.ml @@ -29,13 +29,13 @@ open Batcher_worker_types module Message_queue = Hash_queue.Make (L2_message.Hash) (L2_message) module L2_batched_message = struct - type t = {content : string; l1_hash : L1_operation.hash} + type t = {content : string; l1_hash : Injector.Inj_operation.hash} end module Batched_messages = Hash_queue.Make (L2_message.Hash) (L2_batched_message) module type S = sig - type status = Pending_batch | Batched of L1_operation.hash + type status = Pending_batch | Batched of Injector.Inj_operation.hash val init : Configuration.batcher -> @@ -63,7 +63,7 @@ end module Make (Simulation : Simulation.S) : S = struct module PVM = Simulation.PVM - type status = Pending_batch | Batched of L1_operation.hash + type status = Pending_batch | Batched of Injector.Inj_operation.hash type state = { node_ctxt : Node_context.ro; @@ -81,7 +81,7 @@ module Make (Simulation : Simulation.S) : S = struct let inject_batch state (l2_messages : L2_message.t list) = let open Lwt_result_syntax in let messages = List.map L2_message.content l2_messages in - let operation = Sc_rollup_add_messages {messages} in + let operation = L1_operation.Add_messages {messages} in let+ l1_hash = Injector.add_pending_operation ~source:state.signer operation in diff --git a/src/proto_alpha/lib_sc_rollup_node/batcher.mli b/src/proto_alpha/lib_sc_rollup_node/batcher.mli index 3855c96e9fc18d6c407c96fd335c6e85c68d087d..a6618f27bdc9a7bc0068d15841d3b4ceaca193b4 100644 --- a/src/proto_alpha/lib_sc_rollup_node/batcher.mli +++ b/src/proto_alpha/lib_sc_rollup_node/batcher.mli @@ -30,7 +30,7 @@ module type S = sig (** The type for the status of messages in the batcher. *) type status = | Pending_batch (** The message is in the queue of the batcher. *) - | Batched of L1_operation.hash + | Batched of Injector.Inj_operation.hash (** The message has already been batched and sent to the injector in an L1 operation whose hash is given. *) diff --git a/src/proto_alpha/lib_sc_rollup_node/commitment.ml b/src/proto_alpha/lib_sc_rollup_node/commitment.ml index 465348acaa0fcc71c0561f093c9d42e905a0586f..499207755a3b8c799fb1937392afd8ba8aaf6ccb 100644 --- a/src/proto_alpha/lib_sc_rollup_node/commitment.ml +++ b/src/proto_alpha/lib_sc_rollup_node/commitment.ml @@ -242,7 +242,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct (commitment : Sc_rollup.Commitment.t) = let open Lwt_result_syntax in let publish_operation = - Sc_rollup_publish {rollup = node_ctxt.rollup_address; commitment} + L1_operation.Publish {rollup = node_ctxt.rollup_address; commitment} in let*! () = Commitment_event.publish_commitment @@ -377,7 +377,7 @@ module Make (PVM : Pvm.S) : Commitment_sig.S with module PVM = PVM = struct let cement_commitment (node_ctxt : _ Node_context.t) ~source commitment_hash = let open Lwt_result_syntax in let cement_operation = - Sc_rollup_cement + L1_operation.Cement {rollup = node_ctxt.rollup_address; commitment = commitment_hash} in let* _hash = Injector.add_pending_operation ~source cement_operation in diff --git a/src/proto_alpha/lib_sc_rollup_node/daemon_event.ml b/src/proto_alpha/lib_sc_rollup_node/daemon_event.ml index 61958297e722bb7d4de13475ad244361e43683ed..bfac41676c492caeed854b4456bcff3b182bd9bb 100644 --- a/src/proto_alpha/lib_sc_rollup_node/daemon_event.ml +++ b/src/proto_alpha/lib_sc_rollup_node/daemon_event.ml @@ -153,23 +153,25 @@ let new_heads_processed = new_heads_iteration Simple.new_heads_processed let included_operation (type kind) ~finalized (operation : kind Protocol.Alpha_context.manager_operation) (result : kind Protocol.Apply_results.manager_operation_result) = - let operation = L1_operation.make operation in - match result with - | Applied _ when finalized -> - Simple.(emit finalized_successful_operation) operation - | _ when finalized -> - (* No events for finalized non successful operations *) - Lwt.return_unit - | Applied _ -> Simple.(emit included_successful_operation) operation - | result -> - let status, errors = - match result with - | Applied _ -> assert false - | Failed (_, e) -> (`Failed, Some e) - | Backtracked (_, e) -> (`Backtracked, e) - | Skipped _ -> (`Skipped, None) - in - Simple.(emit included_failed_operation) (operation, status, errors) + match L1_operation.of_manager_operation operation with + | None -> Lwt.return_unit + | Some operation -> ( + match result with + | Applied _ when finalized -> + Simple.(emit finalized_successful_operation) operation + | _ when finalized -> + (* No events for finalized non successful operations *) + Lwt.return_unit + | Applied _ -> Simple.(emit included_successful_operation) operation + | result -> + let status, errors = + match result with + | Applied _ -> assert false + | Failed (_, e) -> (`Failed, Some e) + | Backtracked (_, e) -> (`Backtracked, e) + | Skipped _ -> (`Skipped, None) + in + Simple.(emit included_failed_operation) (operation, status, errors)) let wrong_initial_pvm_state_hash actual_hash expected_hash = Simple.(emit wrong_initial_pvm_state_hash (actual_hash, expected_hash)) diff --git a/src/proto_alpha/lib_sc_rollup_node/injector.ml b/src/proto_alpha/lib_sc_rollup_node/injector.ml index 0259a88434465c6567068a47865f235db81c840d..8bcb5fbd162244a2361fe9d324b24e31ad98f11f 100644 --- a/src/proto_alpha/lib_sc_rollup_node/injector.ml +++ b/src/proto_alpha/lib_sc_rollup_node/injector.ml @@ -29,7 +29,8 @@ open Injector_sigs module Parameters : PARAMETERS with type state = Node_context.ro - and type Tag.t = Configuration.purpose = struct + and type Tag.t = Configuration.purpose + and type Operation.t = L1_operation.t = struct type state = Node_context.ro let events_section = ["sc_rollup.injector"] @@ -53,6 +54,8 @@ module Parameters : (List.map (fun t -> (string_of_tag t, t)) Configuration.purposes) end + module Operation = L1_operation + (* TODO: https://gitlab.com/tezos/tezos/-/issues/3459 Very coarse approximation for the number of operation we expect for each block *) @@ -63,20 +66,15 @@ module Parameters : | Timeout -> 1 | Refute -> 1 - let operation_tag (type kind) (operation : kind manager_operation) : - Tag.t option = - match operation with - | Sc_rollup_add_messages _ -> Some Add_messages - | Sc_rollup_cement _ -> Some Cement - | Sc_rollup_publish _ -> Some Publish - | Sc_rollup_timeout _ -> Some Timeout - | Sc_rollup_refute _ -> Some Refute - | _ -> None + let operation_tag : Operation.t -> Tag.t = function + | Add_messages _ -> Add_messages + | Cement _ -> Cement + | Publish _ -> Publish + | Timeout _ -> Timeout + | Refute _ -> Refute let fee_parameter node_ctxt operation = - match operation_tag operation with - | None -> Configuration.default_fee_parameter () - | Some tag -> Node_context.get_fee_parameter node_ctxt tag + Node_context.get_fee_parameter node_ctxt (operation_tag operation) (* Below are dummy values that are only used to approximate the size. It is thus important that they remain above the real @@ -98,8 +96,7 @@ module Parameters : {!Injector_sigs.Parameter.batch_must_succeed}. *) let batch_must_succeed _ = `At_least_one - let retry_unsuccessful_operation (type kind) _node_ctxt - (op : kind manager_operation) status = + let retry_unsuccessful_operation _node_ctxt (op : Operation.t) status = let open Lwt_syntax in match status with | Backtracked | Skipped | Other_branch -> @@ -140,34 +137,10 @@ module Parameters : return Retry else match op with - | Sc_rollup_timeout _ | Sc_rollup_refute _ | Sc_rollup_cement _ - | Sc_rollup_add_messages _ -> + | Timeout _ | Refute _ | Cement _ | Add_messages _ -> (* Failing timeout and refutation operations can be ignored. *) return Forget - | Sc_rollup_publish _ -> return (Abort error) - | Reveal _ | Transaction _ | Origination _ | Delegation _ - | Update_consensus_key _ | Register_global_constant _ - | Set_deposits_limit _ | Increase_paid_storage _ - | Tx_rollup_origination | Tx_rollup_submit_batch _ - | Tx_rollup_commit _ | Tx_rollup_return_bond _ - | Tx_rollup_finalize_commitment _ | Tx_rollup_remove_commitment _ - | Tx_rollup_rejection _ | Tx_rollup_dispatch_tickets _ - | Transfer_ticket _ | Dal_publish_slot_header _ - | Sc_rollup_originate _ | Sc_rollup_execute_outbox_message _ - | Sc_rollup_recover_bond _ | Zk_rollup_origination _ - | Zk_rollup_publish _ | Zk_rollup_update _ -> - (* These operations should never be handled by this injector *) - assert false) - - let operation_tag (type kind) (operation : kind manager_operation) : - Tag.t option = - match operation with - | Sc_rollup_add_messages _ -> Some Add_messages - | Sc_rollup_cement _ -> Some Cement - | Sc_rollup_publish _ -> Some Publish - | Sc_rollup_timeout _ -> Some Timeout - | Sc_rollup_refute _ -> Some Refute - | _ -> None + | Publish _ -> return (Abort error)) end include Injector_functor.Make (Parameters) diff --git a/src/proto_alpha/lib_sc_rollup_node/injector.mli b/src/proto_alpha/lib_sc_rollup_node/injector.mli index 8d936a76fdbbcbe2a3e6515ec773de5c30ed780e..0f3db24e434eeded77d995b2d9125bb5dfab40b5 100644 --- a/src/proto_alpha/lib_sc_rollup_node/injector.mli +++ b/src/proto_alpha/lib_sc_rollup_node/injector.mli @@ -27,3 +27,4 @@ include Injector_sigs.S with type state := Node_context.ro and type tag := Configuration.purpose + and type operation := L1_operation.t diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_game.ml b/src/proto_alpha/lib_sc_rollup_node/refutation_game.ml index 966e1200429a1ccd8135856a21dc11397fb9ba45..03d1c60622d7a610845546ddd0cffea2d3e2eb94 100644 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_game.ml +++ b/src/proto_alpha/lib_sc_rollup_node/refutation_game.ml @@ -79,7 +79,7 @@ module Make (Interpreter : Interpreter.S) : let inject_next_move node_ctxt source ~refutation ~opponent = let open Lwt_result_syntax in let refute_operation = - Sc_rollup_refute + L1_operation.Refute {rollup = node_ctxt.Node_context.rollup_address; refutation; opponent} in let* _hash = Injector.add_pending_operation ~source refute_operation in @@ -423,7 +423,7 @@ module Make (Interpreter : Interpreter.S) : let play_timeout (node_ctxt : _ Node_context.t) self stakers = let open Lwt_result_syntax in let timeout_operation = - Sc_rollup_timeout {rollup = node_ctxt.rollup_address; stakers} + L1_operation.Timeout {rollup = node_ctxt.rollup_address; stakers} in let source = Node_context.get_operator node_ctxt Timeout |> Option.value ~default:self