Michelson: enforce a maximum stack item type size
This commit is contained in:
parent
b4495568cb
commit
fedeb6c8fd
@ -43,6 +43,7 @@ type constants = {
|
|||||||
max_number_of_operations: int list ;
|
max_number_of_operations: int list ;
|
||||||
max_operation_data_length: int ;
|
max_operation_data_length: int ;
|
||||||
initial_roll_value: Tez_repr.t ;
|
initial_roll_value: Tez_repr.t ;
|
||||||
|
michelson_maximum_type_size: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
let read_public_key s =
|
let read_public_key s =
|
||||||
@ -79,6 +80,7 @@ let default = {
|
|||||||
16 * 1024 ; (* 16kB *)
|
16 * 1024 ; (* 16kB *)
|
||||||
initial_roll_value =
|
initial_roll_value =
|
||||||
Tez_repr.of_cents_exn 10000_00L ;
|
Tez_repr.of_cents_exn 10000_00L ;
|
||||||
|
michelson_maximum_type_size = 1000 ;
|
||||||
}
|
}
|
||||||
|
|
||||||
let opt (=) def v = if def = v then None else Some v
|
let opt (=) def v = if def = v then None else Some v
|
||||||
@ -136,6 +138,9 @@ let constants_encoding =
|
|||||||
and initial_roll_value =
|
and initial_roll_value =
|
||||||
opt Tez_repr.(=)
|
opt Tez_repr.(=)
|
||||||
default.initial_roll_value c.initial_roll_value
|
default.initial_roll_value c.initial_roll_value
|
||||||
|
and michelson_maximum_type_size =
|
||||||
|
opt Compare.Int.(=)
|
||||||
|
default.michelson_maximum_type_size c.michelson_maximum_type_size
|
||||||
in
|
in
|
||||||
((( cycle_length,
|
((( cycle_length,
|
||||||
voting_period_length,
|
voting_period_length,
|
||||||
@ -149,7 +154,8 @@ let constants_encoding =
|
|||||||
dictator_pubkey),
|
dictator_pubkey),
|
||||||
(max_number_of_operations,
|
(max_number_of_operations,
|
||||||
max_operation_data_length,
|
max_operation_data_length,
|
||||||
initial_roll_value)), ()) )
|
initial_roll_value,
|
||||||
|
michelson_maximum_type_size)), ()) )
|
||||||
(fun ((( cycle_length,
|
(fun ((( cycle_length,
|
||||||
voting_period_length,
|
voting_period_length,
|
||||||
time_before_reward,
|
time_before_reward,
|
||||||
@ -162,7 +168,8 @@ let constants_encoding =
|
|||||||
dictator_pubkey),
|
dictator_pubkey),
|
||||||
(max_number_of_operations,
|
(max_number_of_operations,
|
||||||
max_operation_data_length,
|
max_operation_data_length,
|
||||||
initial_roll_value)), ()) ->
|
initial_roll_value,
|
||||||
|
michelson_maximum_type_size)), ()) ->
|
||||||
{ cycle_length =
|
{ cycle_length =
|
||||||
unopt default.cycle_length cycle_length ;
|
unopt default.cycle_length cycle_length ;
|
||||||
voting_period_length =
|
voting_period_length =
|
||||||
@ -191,6 +198,8 @@ let constants_encoding =
|
|||||||
unopt default.max_operation_data_length max_operation_data_length ;
|
unopt default.max_operation_data_length max_operation_data_length ;
|
||||||
initial_roll_value =
|
initial_roll_value =
|
||||||
unopt default.initial_roll_value initial_roll_value ;
|
unopt default.initial_roll_value initial_roll_value ;
|
||||||
|
michelson_maximum_type_size =
|
||||||
|
unopt default.michelson_maximum_type_size michelson_maximum_type_size ;
|
||||||
} )
|
} )
|
||||||
Data_encoding.(
|
Data_encoding.(
|
||||||
merge_objs
|
merge_objs
|
||||||
@ -206,10 +215,11 @@ let constants_encoding =
|
|||||||
(opt "proof_of_work_threshold" int64)
|
(opt "proof_of_work_threshold" int64)
|
||||||
(opt "bootstrap_keys" (list Ed25519.Public_key.encoding))
|
(opt "bootstrap_keys" (list Ed25519.Public_key.encoding))
|
||||||
(opt "dictator_pubkey" Ed25519.Public_key.encoding))
|
(opt "dictator_pubkey" Ed25519.Public_key.encoding))
|
||||||
(obj3
|
(obj4
|
||||||
(opt "max_number_of_operations" (list uint16))
|
(opt "max_number_of_operations" (list uint16))
|
||||||
(opt "max_number_of_operations" int31)
|
(opt "max_number_of_operations" int31)
|
||||||
(opt "initial_roll_value" Tez_repr.encoding)
|
(opt "initial_roll_value" Tez_repr.encoding)
|
||||||
|
(opt "michelson_maximum_type_size" uint16)
|
||||||
))
|
))
|
||||||
unit)
|
unit)
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ type error += Unexpected_annotation of Script.location
|
|||||||
type error += Invalid_map_body : Script.location * _ stack_ty -> error
|
type error += Invalid_map_body : Script.location * _ stack_ty -> error
|
||||||
type error += Invalid_map_block_fail of Script.location
|
type error += Invalid_map_block_fail of Script.location
|
||||||
type error += Invalid_iter_body : Script.location * _ stack_ty * _ stack_ty -> error
|
type error += Invalid_iter_body : Script.location * _ stack_ty * _ stack_ty -> error
|
||||||
|
type error += Type_too_large : Script.location * int * int -> error
|
||||||
|
|
||||||
(* Value typing errors *)
|
(* Value typing errors *)
|
||||||
type error += Invalid_constant : Script.location * Script.expr * _ ty -> error
|
type error += Invalid_constant : Script.location * Script.expr * _ ty -> error
|
||||||
@ -81,6 +82,58 @@ let default_annot ~default = function
|
|||||||
| None -> default
|
| None -> default
|
||||||
| annot -> annot
|
| annot -> annot
|
||||||
|
|
||||||
|
(* ---- Type size accounting ------------------------------------------------*)
|
||||||
|
|
||||||
|
let comparable_type_size : type t. t comparable_ty -> int = function
|
||||||
|
(* No wildcard to force the update when comparable_ty chages. *)
|
||||||
|
| Int_key -> 1
|
||||||
|
| Nat_key -> 1
|
||||||
|
| String_key -> 1
|
||||||
|
| Tez_key -> 1
|
||||||
|
| Bool_key -> 1
|
||||||
|
| Key_hash_key -> 1
|
||||||
|
| Timestamp_key -> 1
|
||||||
|
|
||||||
|
let rec type_size : type t. t ty -> int = function
|
||||||
|
| Unit_t -> 1
|
||||||
|
| Int_t -> 1
|
||||||
|
| Nat_t -> 1
|
||||||
|
| Signature_t -> 1
|
||||||
|
| String_t -> 1
|
||||||
|
| Tez_t -> 1
|
||||||
|
| Key_hash_t -> 1
|
||||||
|
| Key_t -> 1
|
||||||
|
| Timestamp_t -> 1
|
||||||
|
| Bool_t -> 1
|
||||||
|
| Pair_t ((l, _), (r, _)) ->
|
||||||
|
1 + type_size l + type_size r
|
||||||
|
| Union_t ((l, _), (r, _)) ->
|
||||||
|
1 + type_size l + type_size r
|
||||||
|
| Lambda_t (arg, ret) ->
|
||||||
|
1 + type_size arg + type_size ret
|
||||||
|
| Option_t t ->
|
||||||
|
1 + type_size t
|
||||||
|
| List_t t ->
|
||||||
|
1 + type_size t
|
||||||
|
| Set_t k ->
|
||||||
|
1 + comparable_type_size k
|
||||||
|
| Map_t (k, v) ->
|
||||||
|
1 + comparable_type_size k + type_size v
|
||||||
|
| Contract_t (arg, ret) ->
|
||||||
|
1 + type_size arg + type_size ret
|
||||||
|
|
||||||
|
let rec type_size_of_stack_head
|
||||||
|
: type st. st stack_ty -> up_to:int -> int
|
||||||
|
= fun stack ~up_to ->
|
||||||
|
match stack with
|
||||||
|
| Empty_t -> 0
|
||||||
|
| Item_t (head, tail, _annot) ->
|
||||||
|
if Compare.Int.(up_to > 0) then
|
||||||
|
Compare.Int.max (type_size head)
|
||||||
|
(type_size_of_stack_head tail ~up_to:(up_to - 1))
|
||||||
|
else
|
||||||
|
0
|
||||||
|
|
||||||
(* ---- Error helpers -------------------------------------------------------*)
|
(* ---- Error helpers -------------------------------------------------------*)
|
||||||
|
|
||||||
let location = function
|
let location = function
|
||||||
@ -1040,7 +1093,18 @@ and parse_instr
|
|||||||
?type_logger: (int -> Script.expr list -> Script.expr list -> unit) ->
|
?type_logger: (int -> Script.expr list -> Script.expr list -> unit) ->
|
||||||
Script.node -> bef stack_ty -> bef judgement tzresult Lwt.t =
|
Script.node -> bef stack_ty -> bef judgement tzresult Lwt.t =
|
||||||
fun tc_context ctxt ?type_logger script_instr stack_ty ->
|
fun tc_context ctxt ?type_logger script_instr stack_ty ->
|
||||||
let return : bef judgement -> bef judgement tzresult Lwt.t = return in
|
let return (judgement : bef judgement) : bef judgement tzresult Lwt.t =
|
||||||
|
match judgement with
|
||||||
|
| Typed { loc; aft } ->
|
||||||
|
(* No instruction builds more than two new stack slots. *)
|
||||||
|
let maximum_type_size = Constants.michelson_maximum_type_size ctxt in
|
||||||
|
let type_size = type_size_of_stack_head aft ~up_to:2 in
|
||||||
|
if Compare.Int.(type_size > maximum_type_size) then
|
||||||
|
fail (Type_too_large (loc, type_size, maximum_type_size))
|
||||||
|
else
|
||||||
|
return judgement
|
||||||
|
| Failed _ ->
|
||||||
|
return judgement in
|
||||||
let keep_or_rewrite_annot value_annot instr_annot =
|
let keep_or_rewrite_annot value_annot instr_annot =
|
||||||
match value_annot, instr_annot with
|
match value_annot, instr_annot with
|
||||||
| annot, None -> annot
|
| annot, None -> annot
|
||||||
@ -2307,7 +2371,7 @@ let () =
|
|||||||
`Permanent
|
`Permanent
|
||||||
~id:"invalidMapBlockFail"
|
~id:"invalidMapBlockFail"
|
||||||
~title:"FAIL instruction occurred as body of map block"
|
~title:"FAIL instruction occurred as body of map block"
|
||||||
~description:"FAIL cannot be the only instruction in the body.\
|
~description:"FAIL cannot be the only instruction in the body. \
|
||||||
The propper type of the return list cannot be inferred."
|
The propper type of the return list cannot be inferred."
|
||||||
(obj1 (req "loc" Script.location_encoding))
|
(obj1 (req "loc" Script.location_encoding))
|
||||||
(function
|
(function
|
||||||
@ -2318,8 +2382,8 @@ let () =
|
|||||||
`Permanent
|
`Permanent
|
||||||
~id:"invalidIterBody"
|
~id:"invalidIterBody"
|
||||||
~title:"ITER body returned wrong stack type"
|
~title:"ITER body returned wrong stack type"
|
||||||
~description:"The body of an ITER instruction\
|
~description:"The body of an ITER instruction \
|
||||||
must result in the same stack type as before\
|
must result in the same stack type as before \
|
||||||
the ITER."
|
the ITER."
|
||||||
(obj3
|
(obj3
|
||||||
(req "loc" Script.location_encoding)
|
(req "loc" Script.location_encoding)
|
||||||
@ -2329,6 +2393,19 @@ let () =
|
|||||||
| Invalid_iter_body (loc, bef, aft) -> Some (loc, Ex_stack_ty bef, Ex_stack_ty aft)
|
| Invalid_iter_body (loc, bef, aft) -> Some (loc, Ex_stack_ty bef, Ex_stack_ty aft)
|
||||||
| _ -> None)
|
| _ -> None)
|
||||||
(fun (loc, Ex_stack_ty bef, Ex_stack_ty aft) -> Invalid_iter_body (loc, bef, aft)) ;
|
(fun (loc, Ex_stack_ty bef, Ex_stack_ty aft) -> Invalid_iter_body (loc, bef, aft)) ;
|
||||||
|
register_error_kind
|
||||||
|
`Permanent
|
||||||
|
~id:"typeTooLarge"
|
||||||
|
~title:"Stack item type too large"
|
||||||
|
~description:"An instruction generated a type larger than the limit."
|
||||||
|
(obj3
|
||||||
|
(req "loc" Script.location_encoding)
|
||||||
|
(req "typeSize" uint16)
|
||||||
|
(req "maximumTypeSize" uint16))
|
||||||
|
(function
|
||||||
|
| Type_too_large (loc, ts, maxts) -> Some (loc, ts, maxts)
|
||||||
|
| _ -> None)
|
||||||
|
(fun (loc, ts, maxts) -> Type_too_large (loc, ts, maxts)) ;
|
||||||
(* Toplevel errors *)
|
(* Toplevel errors *)
|
||||||
register_error_kind
|
register_error_kind
|
||||||
`Permanent
|
`Permanent
|
||||||
@ -2347,7 +2424,6 @@ let () =
|
|||||||
| _ -> None)
|
| _ -> None)
|
||||||
(fun (name, Ex_ty ty, expr) ->
|
(fun (name, Ex_ty ty, expr) ->
|
||||||
Ill_typed_data (name, expr, ty)) ;
|
Ill_typed_data (name, expr, ty)) ;
|
||||||
(* type error += Ill_formed_type of string option * Script.expr *)
|
|
||||||
register_error_kind
|
register_error_kind
|
||||||
`Permanent
|
`Permanent
|
||||||
~id:"illFormedTypeTypeError"
|
~id:"illFormedTypeTypeError"
|
||||||
|
@ -91,6 +91,9 @@ module Constants = struct
|
|||||||
let max_operation_data_length c =
|
let max_operation_data_length c =
|
||||||
let constants = Raw_context.constants c in
|
let constants = Raw_context.constants c in
|
||||||
constants.max_operation_data_length
|
constants.max_operation_data_length
|
||||||
|
let michelson_maximum_type_size c =
|
||||||
|
let constants = Raw_context.constants c in
|
||||||
|
constants.michelson_maximum_type_size
|
||||||
end
|
end
|
||||||
|
|
||||||
module Delegates_pubkey = Public_key_storage
|
module Delegates_pubkey = Public_key_storage
|
||||||
|
@ -280,7 +280,7 @@ module Constants : sig
|
|||||||
val dictator_pubkey: context -> Ed25519.Public_key.t
|
val dictator_pubkey: context -> Ed25519.Public_key.t
|
||||||
val max_number_of_operations: context -> int list
|
val max_number_of_operations: context -> int list
|
||||||
val max_operation_data_length: context -> int
|
val max_operation_data_length: context -> int
|
||||||
|
val michelson_maximum_type_size: context -> int
|
||||||
end
|
end
|
||||||
|
|
||||||
(** Global storage for all delegates public keys *)
|
(** Global storage for all delegates public keys *)
|
||||||
|
Loading…
Reference in New Issue
Block a user