diff --git a/src/lib_data_encoding/data_encoding.ml b/src/lib_data_encoding/data_encoding.ml index 00e82eeeb..108077d9e 100644 --- a/src/lib_data_encoding/data_encoding.ml +++ b/src/lib_data_encoding/data_encoding.ml @@ -100,6 +100,11 @@ struct splitted ~json ~binary let make_lazy encoding value = { encoding ; state = Value value } + let fold_lazy fun_value fun_bytes fun_combine le = + match le.state with + | Value value -> fun_value value + | Bytes bytes -> fun_bytes bytes + | Both (bytes, value) -> fun_combine (fun_value value) (fun_bytes bytes) end diff --git a/src/lib_data_encoding/data_encoding.mli b/src/lib_data_encoding/data_encoding.mli index db9a12f79..5d73fbbcc 100644 --- a/src/lib_data_encoding/data_encoding.mli +++ b/src/lib_data_encoding/data_encoding.mli @@ -510,6 +510,11 @@ module Encoding: sig (** Make a lazy value from an immediate one. *) val make_lazy : 'a encoding -> 'a -> 'a lazy_t + (** Fold on structure of lazy value, and combine results *) + val fold_lazy : + ('a -> 'b) -> (MBytes.t -> 'b) -> ('b -> 'b -> 'b) -> + 'a lazy_t -> 'b + end include module type of Encoding with type 'a t = 'a Encoding.t diff --git a/src/lib_protocol_environment/sigs/v1/data_encoding.mli b/src/lib_protocol_environment/sigs/v1/data_encoding.mli index aefcc4f89..28da335b7 100644 --- a/src/lib_protocol_environment/sigs/v1/data_encoding.mli +++ b/src/lib_protocol_environment/sigs/v1/data_encoding.mli @@ -198,6 +198,9 @@ val lazy_encoding : 'a encoding -> 'a lazy_t encoding val force_decode : 'a lazy_t -> 'a option val force_bytes : 'a lazy_t -> MBytes.t val make_lazy : 'a encoding -> 'a -> 'a lazy_t +val fold_lazy : + ('a -> 'b) -> (MBytes.t -> 'b) -> ('b -> 'b -> 'b) -> + 'a lazy_t -> 'b module Json : sig diff --git a/src/proto_alpha/lib_protocol/src/alpha_context.mli b/src/proto_alpha/lib_protocol/src/alpha_context.mli index 89720e205..4707d5988 100644 --- a/src/proto_alpha/lib_protocol/src/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/src/alpha_context.mli @@ -301,6 +301,7 @@ module Script : sig val prim_encoding: prim Data_encoding.t val encoding: t Data_encoding.t val lazy_expr_encoding: lazy_expr Data_encoding.t + val expr_cost : expr -> Gas.cost end module Constants : sig diff --git a/src/proto_alpha/lib_protocol/src/apply.ml b/src/proto_alpha/lib_protocol/src/apply.ml index 0829fcd91..02f80ece5 100644 --- a/src/proto_alpha/lib_protocol/src/apply.ml +++ b/src/proto_alpha/lib_protocol/src/apply.ml @@ -41,6 +41,7 @@ type error += Outdated_double_baking_evidence of { level: Raw_level.t ; last: Raw_level.t } (* `Permanent *) type error += Invalid_activation of { pkh : Ed25519.Public_key_hash.t } type error += Multiple_revelation +type error += Not_enough_gas_minimal_deserialize let () = register_error_kind @@ -318,7 +319,15 @@ let () = "Multiple revelations were included in a manager operation") Data_encoding.empty (function Multiple_revelation -> Some () | _ -> None) - (fun () -> Multiple_revelation) + (fun () -> Multiple_revelation) ; + register_error_kind + `Permanent + ~id:"not_enough_gas.minimal_deserialization" + ~title:"Not enough gas for minimal deserialization of transaction parameters" + ~description:"Gas quota is not enough for deserializing the transaction parameters, even for the cheapest case" + Data_encoding.empty + (function Not_enough_gas_minimal_deserialize -> Some () | _ -> None) + (fun () -> Not_enough_gas_minimal_deserialize) open Apply_results @@ -491,6 +500,14 @@ let precheck_manager_contents match operation with | Reveal pk -> Contract.reveal_manager_key ctxt source pk + | Transaction { parameters = Some arg ; _ } -> + let min_gas = Michelson_v1_gas.Cost_of.Typechecking.minimal_deserialize arg in + (* Fail if not enough gas for minimal deserialization cost *) + begin + match Gas.consume ctxt min_gas with + | Ok _ -> return ctxt + | Error _ -> fail Not_enough_gas_minimal_deserialize + end | _ -> return ctxt end >>=? fun ctxt -> Contract.get_manager_key ctxt source >>=? fun public_key -> diff --git a/src/proto_alpha/lib_protocol/src/michelson_v1_gas.ml b/src/proto_alpha/lib_protocol/src/michelson_v1_gas.ml index 5d4582e90..c77d3d055 100644 --- a/src/proto_alpha/lib_protocol/src/michelson_v1_gas.ml +++ b/src/proto_alpha/lib_protocol/src/michelson_v1_gas.ml @@ -233,6 +233,12 @@ module Cost_of = struct (* TODO: proper handling of (de)serialization costs *) let len = MBytes.length b in alloc_cost len +@ step_cost (len * 10) + let minimal_deserialize expr = + Data_encoding.fold_lazy + Script.expr_cost + (fun b -> alloc_bytes_cost (MBytes.length b)) + (fun c _ -> c) (* keep expr cost if present *) + expr end module Unparse = struct diff --git a/src/proto_alpha/lib_protocol/src/michelson_v1_gas.mli b/src/proto_alpha/lib_protocol/src/michelson_v1_gas.mli index 87498fa7e..a6f4aaaf7 100644 --- a/src/proto_alpha/lib_protocol/src/michelson_v1_gas.mli +++ b/src/proto_alpha/lib_protocol/src/michelson_v1_gas.mli @@ -132,6 +132,8 @@ module Cost_of : sig val two_arg_type : Gas.cost val operation : MBytes.t -> Gas.cost + + val minimal_deserialize : Script.lazy_expr -> Gas.cost end module Unparse : sig