From c9c37700a2093fba972ef6dd77101081b1582fdb Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Fri, 4 Aug 2023 15:47:05 +0200 Subject: [PATCH 1/2] Mempool: Project [syntactic_check] in Lwt.t --- src/lib_shell/prevalidation.ml | 4 +- src/lib_validation/block_validation.ml | 6 ++- src/lib_validation/protocol_plugin.ml | 4 +- src/lib_validation/protocol_plugin.mli | 2 +- src/proto_017_PtNairob/lib_plugin/mempool.ml | 38 +++++++++++-------- src/proto_017_PtNairob/lib_plugin/mempool.mli | 2 +- src/proto_018_Proxford/lib_plugin/mempool.ml | 2 +- src/proto_018_Proxford/lib_plugin/mempool.mli | 2 +- src/proto_alpha/lib_plugin/mempool.ml | 2 +- src/proto_alpha/lib_plugin/mempool.mli | 2 +- 10 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/lib_shell/prevalidation.ml b/src/lib_shell/prevalidation.ml index 661deb70bd62..8081b3aef73c 100644 --- a/src/lib_shell/prevalidation.ml +++ b/src/lib_shell/prevalidation.ml @@ -176,7 +176,9 @@ module MakeAbstract create_aux ~old_state chain_store head timestamp let pre_filter state (filter_config, (_ : Prevalidator_bounding.config)) op = - match Proto.Plugin.syntactic_check op.protocol with + let open Lwt_syntax in + let* status = Proto.Plugin.syntactic_check op.protocol in + match status with | `Ill_formed -> Lwt.return (`Refused diff --git a/src/lib_validation/block_validation.ml b/src/lib_validation/block_validation.ml index 9e582d916ccf..c1c1fa1e7ade 100644 --- a/src/lib_validation/block_validation.ml +++ b/src/lib_validation/block_validation.ml @@ -896,8 +896,9 @@ module Make (Proto : Protocol_plugin.T) = struct {shell = op.raw.shell; protocol_data = op.protocol_data} in let open Lwt_result_syntax in + let*! status = Proto.Plugin.syntactic_check operation in let* validation_state = - match Proto.Plugin.syntactic_check operation with + match status with | `Ill_formed -> failwith "Ill-formed operation filtered" | `Well_formed -> Proto.validate_operation @@ -1285,7 +1286,8 @@ module Make (Proto : Protocol_plugin.T) = struct (fun state ops -> List.fold_left_es (fun state (oph, op, check_signature) -> - match Proto.Plugin.syntactic_check op with + let*! status = Proto.Plugin.syntactic_check op in + match status with | `Ill_formed -> failwith "Ill-formed operation filtered" | `Well_formed -> Proto.validate_operation ~check_signature state oph op) diff --git a/src/lib_validation/protocol_plugin.ml b/src/lib_validation/protocol_plugin.ml index acfd9960af07..28d763c6d7c1 100644 --- a/src/lib_validation/protocol_plugin.ml +++ b/src/lib_validation/protocol_plugin.ml @@ -44,7 +44,7 @@ module type T = sig val flush : info -> head:Tezos_base.Block_header.shell_header -> info tzresult Lwt.t - val syntactic_check : operation -> [`Well_formed | `Ill_formed] + val syntactic_check : operation -> [`Well_formed | `Ill_formed] Lwt.t val pre_filter : info -> @@ -104,7 +104,7 @@ module No_plugin (Proto : Registered_protocol.T) : let flush _ ~head:_ = Lwt_result_syntax.return_unit - let syntactic_check _ = `Well_formed + let syntactic_check _ = Lwt.return `Well_formed let pre_filter _ _ _ = Lwt.return @@ `Passed_prefilter (`Low []) diff --git a/src/lib_validation/protocol_plugin.mli b/src/lib_validation/protocol_plugin.mli index 6d47a4614a9e..73177d9b3d82 100644 --- a/src/lib_validation/protocol_plugin.mli +++ b/src/lib_validation/protocol_plugin.mli @@ -69,7 +69,7 @@ module type T = sig ill-formed operations to block block application. Should be called before the {!pre_filter}, does not need a context. *) - val syntactic_check : operation -> [`Well_formed | `Ill_formed] + val syntactic_check : operation -> [`Well_formed | `Ill_formed] Lwt.t (** Perform some light preliminary checks on the operation. diff --git a/src/proto_017_PtNairob/lib_plugin/mempool.ml b/src/proto_017_PtNairob/lib_plugin/mempool.ml index 631a8dfb610a..e82f81be7c08 100644 --- a/src/proto_017_PtNairob/lib_plugin/mempool.ml +++ b/src/proto_017_PtNairob/lib_plugin/mempool.ml @@ -279,30 +279,36 @@ let kinded_hash_to_state_hash = function | `Value hash | `Node hash -> Sc_rollup.State_hash.context_hash_to_state_hash hash -let is_invalid_op : type t. t manager_operation -> bool = function +let is_invalid_op : type t. t manager_operation -> bool Lwt.t = + let open Lwt_syntax in + function | Sc_rollup_execute_outbox_message {rollup = _; cemented_commitment = _; output_proof} -> ( match Data_encoding.Binary.of_string_opt output_proof_encoding output_proof with - | None -> true + | None -> return_true | Some (output_proof, output_proof_state, _) -> - not - (Sc_rollup.State_hash.equal - output_proof_state - (kinded_hash_to_state_hash - output_proof.Environment.Context.Proof.before))) - | _ -> false - -let rec contains_invalid_op : type t. t Kind.manager contents_list -> bool = - function + Lwt.return + @@ not + (Sc_rollup.State_hash.equal + output_proof_state + (kinded_hash_to_state_hash + output_proof.Environment.Context.Proof.before))) + | _ -> return_false + +let rec contains_invalid_op : type t. t Kind.manager contents_list -> bool Lwt.t + = function | Single (Manager_operation {operation; _}) -> is_invalid_op operation | Cons (Manager_operation {operation; _}, rest) -> - is_invalid_op operation || contains_invalid_op rest + let open Lwt_syntax in + let* is_invalid = is_invalid_op operation in + if not is_invalid then contains_invalid_op rest else return_true let syntactic_check ({shell = _; protocol_data = Operation_data {contents; _}} : Main.operation) = + let open Lwt_syntax in match contents with | Single (Failing_noop _) | Single (Preendorsement _) @@ -317,11 +323,13 @@ let syntactic_check | Single (Vdf_revelation _) | Single (Drain_delegate _) | Single (Ballot _) -> - `Well_formed + Lwt.return `Well_formed | Single (Manager_operation _) as op -> - if contains_invalid_op op then `Ill_formed else `Well_formed + let* is_invalid = contains_invalid_op op in + if is_invalid then return `Ill_formed else return `Well_formed | Cons (Manager_operation _, _) as op -> - if contains_invalid_op op then `Ill_formed else `Well_formed + let* is_invalid = contains_invalid_op op in + if is_invalid then return `Ill_formed else return `Well_formed let pre_filter_manager : type t. diff --git a/src/proto_017_PtNairob/lib_plugin/mempool.mli b/src/proto_017_PtNairob/lib_plugin/mempool.mli index 954cb5190b51..8157d174f705 100644 --- a/src/proto_017_PtNairob/lib_plugin/mempool.mli +++ b/src/proto_017_PtNairob/lib_plugin/mempool.mli @@ -72,7 +72,7 @@ val flush : info -> head:Block_header.shell_header -> info tzresult Lwt.t Should be called before the {!pre_filter}, does not need a context. *) val syntactic_check : - Protocol.Alpha_context.packed_operation -> [`Well_formed | `Ill_formed] + Protocol.Alpha_context.packed_operation -> [`Well_formed | `Ill_formed] Lwt.t (** Perform some preliminary checks on an operation. diff --git a/src/proto_018_Proxford/lib_plugin/mempool.ml b/src/proto_018_Proxford/lib_plugin/mempool.ml index e107df24db3f..5b9cf6f28efd 100644 --- a/src/proto_018_Proxford/lib_plugin/mempool.ml +++ b/src/proto_018_Proxford/lib_plugin/mempool.ml @@ -554,7 +554,7 @@ let pre_filter info config | Single (Manager_operation _) as op -> prefilter_manager_op op | Cons (Manager_operation _, _) as op -> prefilter_manager_op op -let syntactic_check _ = `Well_formed +let syntactic_check _ = Lwt.return `Well_formed let is_manager_operation op = match Operation.acceptable_pass op with diff --git a/src/proto_018_Proxford/lib_plugin/mempool.mli b/src/proto_018_Proxford/lib_plugin/mempool.mli index 954cb5190b51..8157d174f705 100644 --- a/src/proto_018_Proxford/lib_plugin/mempool.mli +++ b/src/proto_018_Proxford/lib_plugin/mempool.mli @@ -72,7 +72,7 @@ val flush : info -> head:Block_header.shell_header -> info tzresult Lwt.t Should be called before the {!pre_filter}, does not need a context. *) val syntactic_check : - Protocol.Alpha_context.packed_operation -> [`Well_formed | `Ill_formed] + Protocol.Alpha_context.packed_operation -> [`Well_formed | `Ill_formed] Lwt.t (** Perform some preliminary checks on an operation. diff --git a/src/proto_alpha/lib_plugin/mempool.ml b/src/proto_alpha/lib_plugin/mempool.ml index edef73395f85..b672a841d4b7 100644 --- a/src/proto_alpha/lib_plugin/mempool.ml +++ b/src/proto_alpha/lib_plugin/mempool.ml @@ -561,7 +561,7 @@ let pre_filter info config | Single (Manager_operation _) as op -> prefilter_manager_op op | Cons (Manager_operation _, _) as op -> prefilter_manager_op op -let syntactic_check _ = `Well_formed +let syntactic_check _ = Lwt.return `Well_formed let is_manager_operation op = match Operation.acceptable_pass op with diff --git a/src/proto_alpha/lib_plugin/mempool.mli b/src/proto_alpha/lib_plugin/mempool.mli index 954cb5190b51..8157d174f705 100644 --- a/src/proto_alpha/lib_plugin/mempool.mli +++ b/src/proto_alpha/lib_plugin/mempool.mli @@ -72,7 +72,7 @@ val flush : info -> head:Block_header.shell_header -> info tzresult Lwt.t Should be called before the {!pre_filter}, does not need a context. *) val syntactic_check : - Protocol.Alpha_context.packed_operation -> [`Well_formed | `Ill_formed] + Protocol.Alpha_context.packed_operation -> [`Well_formed | `Ill_formed] Lwt.t (** Perform some preliminary checks on an operation. -- GitLab From 0e6af334b20736bb29fb8b46ae7734cfc792176a Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Wed, 9 Aug 2023 18:22:23 +0200 Subject: [PATCH 2/2] Nairobi: Discard operations containing invalid proof earlier --- CHANGES.rst | 3 + src/proto_017_PtNairob/lib_plugin/mempool.ml | 68 +++++++++++++++++--- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 4b1106edd3de..e84b9dd15d7c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -231,6 +231,9 @@ Node - Removed Mumbai mempool plugin. (MR :gl:`!9696`) +- Operations posting invalid WASM proofs are now discarded earlier by the + Nairobi mempool plugin. (MR :gl:`!`) + Client ------ - Adding client commands to generate, open and verify a time-lock. diff --git a/src/proto_017_PtNairob/lib_plugin/mempool.ml b/src/proto_017_PtNairob/lib_plugin/mempool.ml index e82f81be7c08..f7737b7bcbd0 100644 --- a/src/proto_017_PtNairob/lib_plugin/mempool.ml +++ b/src/proto_017_PtNairob/lib_plugin/mempool.ml @@ -266,14 +266,52 @@ let weight_and_resources_manager_operation ~hard_gas_limit_per_block ?size ~fee let resources = Q.max size_ratio gas_ratio in (Q.(fee_f / resources), resources) +let output_encoding = + let open Data_encoding in + obj3 + (req "outbox_level" Environment.Bounded.Non_negative_int32.encoding) + (req "message_index" n) + (req "message" Variable.string) + let output_proof_encoding = let open Data_encoding in obj3 (req "output_proof" - Sc_rollup_wasm.V2_0_0.Protocol_implementation.proof_encoding) + Tezos_context_helpers.Context.Proof_encoding.Merkle_proof_encoding.V2 + .Tree2 + .tree_proof_encoding) (req "output_proof_state" Sc_rollup.State_hash.encoding) - (req "output_proof_output" Variable.bytes) + (req "output_proof_output" output_encoding) + +module Tree = struct + open Environment + include Context.Tree + + type tree = Context.tree + + type t = Context.t + + type key = string list + + type value = bytes +end + +module Wasm_machine = Environment.Wasm_2_0_0.Make (Tree) + +let discard_wasm_output_proof_early output_proof outbox_level message_index + output = + let open Lwt_syntax in + let+ result = + Environment.Context.verify_tree_proof output_proof (fun tree -> + let* output = + Wasm_machine.get_output {outbox_level; message_index} tree + in + return (tree, output)) + in + match result with + | Ok (_, Some expected_output) -> not (expected_output = output) + | _ -> false let kinded_hash_to_state_hash = function | `Value hash | `Node hash -> @@ -288,13 +326,25 @@ let is_invalid_op : type t. t manager_operation -> bool Lwt.t = Data_encoding.Binary.of_string_opt output_proof_encoding output_proof with | None -> return_true - | Some (output_proof, output_proof_state, _) -> - Lwt.return - @@ not - (Sc_rollup.State_hash.equal - output_proof_state - (kinded_hash_to_state_hash - output_proof.Environment.Context.Proof.before))) + | Some + ( output_proof, + output_proof_state, + (outbox_level, message_index, output) ) -> + let* discard_wasm_proof = + discard_wasm_output_proof_early + output_proof + outbox_level + message_index + output + in + let state_is_correct = + Sc_rollup.State_hash.equal + output_proof_state + (kinded_hash_to_state_hash + output_proof.Environment.Context.Proof.before) + in + let is_invalid = (not state_is_correct) || discard_wasm_proof in + return is_invalid) | _ -> return_false let rec contains_invalid_op : type t. t Kind.manager contents_list -> bool Lwt.t -- GitLab