Proto, Gas: Fail at precheck if not enough gas to deserialize parameters

This commit is contained in:
Alain Mebsout 2018-06-25 18:00:40 +02:00 committed by Benjamin Canou
parent ecbab4fb77
commit 245b888ccc
7 changed files with 40 additions and 1 deletions

View File

@ -100,6 +100,11 @@ struct
splitted ~json ~binary splitted ~json ~binary
let make_lazy encoding value = let make_lazy encoding value =
{ encoding ; state = Value 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 end

View File

@ -510,6 +510,11 @@ module Encoding: sig
(** Make a lazy value from an immediate one. *) (** Make a lazy value from an immediate one. *)
val make_lazy : 'a encoding -> 'a -> 'a lazy_t 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 end
include module type of Encoding with type 'a t = 'a Encoding.t include module type of Encoding with type 'a t = 'a Encoding.t

View File

@ -198,6 +198,9 @@ val lazy_encoding : 'a encoding -> 'a lazy_t encoding
val force_decode : 'a lazy_t -> 'a option val force_decode : 'a lazy_t -> 'a option
val force_bytes : 'a lazy_t -> MBytes.t val force_bytes : 'a lazy_t -> MBytes.t
val make_lazy : 'a encoding -> 'a -> 'a lazy_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 module Json : sig

View File

@ -301,6 +301,7 @@ module Script : sig
val prim_encoding: prim Data_encoding.t val prim_encoding: prim Data_encoding.t
val encoding: t Data_encoding.t val encoding: t Data_encoding.t
val lazy_expr_encoding: lazy_expr Data_encoding.t val lazy_expr_encoding: lazy_expr Data_encoding.t
val expr_cost : expr -> Gas.cost
end end
module Constants : sig module Constants : sig

View File

@ -41,6 +41,7 @@ type error += Outdated_double_baking_evidence
of { level: Raw_level.t ; last: Raw_level.t } (* `Permanent *) of { level: Raw_level.t ; last: Raw_level.t } (* `Permanent *)
type error += Invalid_activation of { pkh : Ed25519.Public_key_hash.t } type error += Invalid_activation of { pkh : Ed25519.Public_key_hash.t }
type error += Multiple_revelation type error += Multiple_revelation
type error += Not_enough_gas_minimal_deserialize
let () = let () =
register_error_kind register_error_kind
@ -318,7 +319,15 @@ let () =
"Multiple revelations were included in a manager operation") "Multiple revelations were included in a manager operation")
Data_encoding.empty Data_encoding.empty
(function Multiple_revelation -> Some () | _ -> None) (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 open Apply_results
@ -491,6 +500,14 @@ let precheck_manager_contents
match operation with match operation with
| Reveal pk -> | Reveal pk ->
Contract.reveal_manager_key ctxt source 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 | _ -> return ctxt
end >>=? fun ctxt -> end >>=? fun ctxt ->
Contract.get_manager_key ctxt source >>=? fun public_key -> Contract.get_manager_key ctxt source >>=? fun public_key ->

View File

@ -233,6 +233,12 @@ module Cost_of = struct
(* TODO: proper handling of (de)serialization costs *) (* TODO: proper handling of (de)serialization costs *)
let len = MBytes.length b in let len = MBytes.length b in
alloc_cost len +@ step_cost (len * 10) 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 end
module Unparse = struct module Unparse = struct

View File

@ -132,6 +132,8 @@ module Cost_of : sig
val two_arg_type : Gas.cost val two_arg_type : Gas.cost
val operation : MBytes.t -> Gas.cost val operation : MBytes.t -> Gas.cost
val minimal_deserialize : Script.lazy_expr -> Gas.cost
end end
module Unparse : sig module Unparse : sig