Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file script_repr.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)(* *)(* 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. *)(* *)(*****************************************************************************)typelocation=Micheline.canonical_locationletlocation_encoding=Micheline.canonical_location_encodingtypeannot=Micheline.annottypeexpr=Michelson_v1_primitives.primMicheline.canonicaltypelazy_expr=exprData_encoding.lazy_ttype'locationmichelson_node=('location,Michelson_v1_primitives.prim)Micheline.nodetypeunlocated_michelson_node=unitmichelson_nodetypenode=locationmichelson_nodeletexpr_encoding=Micheline.canonical_encoding~variant:"michelson_v1"Michelson_v1_primitives.prim_encodingtypeerror+=Lazy_script_decode(* `Permanent *)let()=register_error_kind`Permanent~id:"invalid_binary_format"~title:"Invalid binary format"~description:"Could not deserialize some piece of data from its binary representation"Data_encoding.empty(functionLazy_script_decode->Some()|_->None)(fun()->Lazy_script_decode)letlazy_expr_encoding=Data_encoding.lazy_encodingexpr_encodingletlazy_exprexpr=Data_encoding.make_lazyexpr_encodingexprtypet={code:lazy_expr;storage:lazy_expr}letencoding=letopenData_encodingindef"scripted.contracts"@@conv(fun{code;storage}->(code,storage))(fun(code,storage)->{code;storage})(obj2(req"code"lazy_expr_encoding)(req"storage"lazy_expr_encoding))moduleS=Saturation_reprmoduleMicheline_size=structtypet={nodes:S.may_saturateS.t;string_bytes:S.may_saturateS.t;z_bytes:S.may_saturateS.t;}letmake~nodes~string_bytes~z_bytes={nodes;string_bytes;z_bytes}letzero={nodes=S.zero;string_bytes=S.zero;z_bytes=S.zero}letadd_intaccn=letnumbits=Z.numbitsninletz_bytes=S.safe_int((numbits+7)/8)(* Compute the number of bytes in a Z.t *)in{nodes=S.succacc.nodes;string_bytes=acc.string_bytes;z_bytes=S.addacc.z_bytesz_bytes;}letadd_stringaccn=letstring_bytes=S.safe_int(String.lengthn)in{nodes=S.succacc.nodes;string_bytes=S.addacc.string_bytesstring_bytes;z_bytes=acc.z_bytes;}letadd_bytesaccn=letstring_bytes=S.safe_int(Bytes.lengthn)in{nodes=S.succacc.nodes;string_bytes=S.addacc.string_bytesstring_bytes;z_bytes=acc.z_bytes;}letadd_nodes={swithnodes=S.succs.nodes}(* We model annotations as Seqs of Strings *)letof_annotsaccannots=List.fold_left(funaccs->add_stringaccs)accannotslet[@coq_struct"nodes"]recof_nodesaccnodesmore_nodes=letopenMichelineinmatchnodeswith|[]->(matchmore_nodeswith|[]->acc|nodes::more_nodes->(of_nodes[@ocaml.tailcall])accnodesmore_nodes)|Int(_,n)::nodes->letacc=add_intaccnin(of_nodes[@ocaml.tailcall])accnodesmore_nodes|String(_,s)::nodes->letacc=add_stringaccsin(of_nodes[@ocaml.tailcall])accnodesmore_nodes|Bytes(_,s)::nodes->letacc=add_bytesaccsin(of_nodes[@ocaml.tailcall])accnodesmore_nodes|Prim(_,_,args,annots)::nodes->letacc=add_nodeaccinletacc=of_annotsaccannotsin(of_nodes[@ocaml.tailcall])accargs(nodes::more_nodes)|Seq(_,args)::nodes->letacc=add_nodeaccin(of_nodes[@ocaml.tailcall])accargs(nodes::more_nodes)letof_nodenode=of_nodeszero[node][]letdot_products1s2=S.add(S.muls1.nodess2.nodes)(S.add(S.muls1.string_bytess2.string_bytes)(S.muls1.z_bytess2.z_bytes))end(* Costs pertaining to deserialization of Micheline values (bytes to Micheline).
The costs are given in atomic steps (see [Gas_limit_repr]). *)moduleMicheline_decoding=struct(* Cost vector allowing to compute decoding costs as a function of the
size of the Micheline term *)letmicheline_size_dependent_cost=lettraversal_cost=S.safe_int60inletstring_per_byte_cost=S.safe_int10inletz_per_byte_cost=S.safe_int10inMicheline_size.make~nodes:traversal_cost~string_bytes:string_per_byte_cost~z_bytes:z_per_byte_costletbytes_dependent_cost=S.safe_int20end(* Costs pertaining to serialization of Micheline values (Micheline to bytes)
The costs are given in atomic steps (see [Gas_limit_repr]). *)moduleMicheline_encoding=struct(* Cost vector allowing to compute encoding cost as a function of the
size of the Micheline term *)letmicheline_size_dependent_cost=lettraversal_cost=S.safe_int100inletstring_per_byte_cost=S.safe_int10inletz_per_byte_cost=S.safe_int25inMicheline_size.make~nodes:traversal_cost~string_bytes:string_per_byte_cost~z_bytes:z_per_byte_costletbytes_dependent_cost=S.safe_int33endletexpr_sizeexpr=Micheline_size.of_node(Micheline.rootexpr)(* Compute the cost of serializing a term of given [size]. *)letserialization_costsize=Gas_limit_repr.atomic_step_cost@@Micheline_size.dot_productsizeMicheline_encoding.micheline_size_dependent_cost(* Compute the cost of deserializing a term of given [size]. *)letdeserialization_costsize=Gas_limit_repr.atomic_step_cost@@Micheline_size.dot_productsizeMicheline_decoding.micheline_size_dependent_cost(* Estimate the cost of deserializing a term encoded in [bytes_len] bytes. *)letdeserialization_cost_estimated_from_bytesbytes_len=Gas_limit_repr.atomic_step_cost@@S.mulMicheline_decoding.bytes_dependent_cost(S.safe_intbytes_len)(* Estimate the cost of serializing a term from its encoded form,
having [bytes_len] bytes. *)letserialization_cost_estimated_from_bytesbytes_len=Gas_limit_repr.atomic_step_cost@@S.mulMicheline_encoding.bytes_dependent_cost(S.safe_intbytes_len)(* Cost of running [strip_locations] on a term with [size] nodes.
Note that [strip_locations] will reallocate a fresh Micheline tree.
This only depends on the total number of nodes (not the size of
the leaves). *)letcost_micheline_strip_locationssize=Gas_limit_repr.atomic_step_cost@@S.mul(S.safe_intsize)(S.safe_int51)(* TODO: https://gitlab.com/tezos/tezos/-/issues/2049
Plugin benchmarked gas.
Replace this definition, copied from [cost_michelines_strip_locations].
*)(* Cost of running [strip_annotations] on a term with [size] nodes.
Note that [strip_annotations] will reallocate a fresh Micheline tree.
This only depends on the total number of nodes (not the size of
the leaves). *)letcost_micheline_strip_annotationssize=Gas_limit_repr.atomic_step_cost@@S.mul(S.safe_intsize)(S.safe_int51)(* This is currently used to estimate the cost of serializing an operation. *)letbytes_node_costs=serialization_cost_estimated_from_bytes(Bytes.lengths)letdeserialized_costexpr=Gas_limit_repr.atomic_step_cost@@deserialization_cost(expr_sizeexpr)letserialized_costbytes=letcost=letsize=Bytes.lengthbytesinS.add(serialization_cost_estimated_from_bytessize)@@(* N_IConcat_bytes_pair inlined here *)S.add(S.safe_int65)(S.shift_right(S.safe_intsize)4)inGas_limit_repr.atomic_step_costcostletforce_decode_costlexpr=Data_encoding.apply_lazy~fun_value:(fun_->Gas_limit_repr.free)~fun_bytes:(funb->deserialization_cost_estimated_from_bytes(Bytes.lengthb))~fun_combine:(fun__->Gas_limit_repr.free)lexprletstable_force_decode_costlexpr=lethas_bytes=Data_encoding.apply_lazy~fun_value:(funv->`Only_valuev)~fun_bytes:(funb->`Has_bytesb)~fun_combine:(fun_vb->(* When the lazy_expr contains both a deserialized version
and a serialized one, we compute the cost from the
serialized version because its is cheaper to do. *)b)lexprinmatchhas_byteswith|`Has_bytesb->deserialization_cost_estimated_from_bytes(Bytes.lengthb)|`Only_valuev->(* This code path should not be reached in theory because values that are
decoded should have been encoded before.
Here we use Data_encoding.Binary.length, which yields the same results
as serializing the value and taking the size, without the need to
encode (in particular, less allocations).
*)deserialization_cost_estimated_from_bytes(Data_encoding.Binary.lengthexpr_encodingv)letforce_decodelexpr=matchData_encoding.force_decodelexprwith|Somev->okv|None->errorLazy_script_decodeletforce_bytes_costexpr=(* Estimating the cost directly from the bytes would be cheaper, but
using [serialized_cost] is more accurate. *)Data_encoding.apply_lazy~fun_value:(funv->serialization_cost(expr_sizev))~fun_bytes:(fun_->Gas_limit_repr.free)~fun_combine:(fun__->Gas_limit_repr.free)exprletforce_bytesexpr=Error_monad.catch_f(fun()->Data_encoding.force_bytesexpr)(fun_->Lazy_script_decode)letunit=Micheline.strip_locations(Prim(0,Michelson_v1_primitives.D_Unit,[],[]))letunit_parameter=lazy_exprunitletis_unit_parameter=letunit_bytes=Data_encoding.force_bytesunit_parameterinData_encoding.apply_lazy~fun_value:(funv->matchMicheline.rootvwith|Prim(_,Michelson_v1_primitives.D_Unit,[],[])->true|_->false)~fun_bytes:(funb->Compare.Bytes.equalbunit_bytes)~fun_combine:(funres_->res)let[@coq_struct"node"]recstrip_annotationsnode=letopenMichelineinmatchnodewith|(Int(_,_)|String(_,_)|Bytes(_,_))asleaf->leaf|Prim(loc,name,args,_)->Prim(loc,name,List.mapstrip_annotationsargs,[])|Seq(loc,args)->Seq(loc,List.mapstrip_annotationsargs)letrecmicheline_fold_auxnodefacck=matchnodewith|Micheline.Int(_,_)->k(faccnode)|Micheline.String(_,_)->k(faccnode)|Micheline.Bytes(_,_)->k(faccnode)|Micheline.Prim(_,_,subterms,_)->micheline_fold_nodessubtermsf(faccnode)k|Micheline.Seq(_,subterms)->micheline_fold_nodessubtermsf(faccnode)kand[@coq_mutual_as_notation][@coq_struct"subterms"]micheline_fold_nodessubtermsfacck=matchsubtermswith|[]->kacc|node::nodes->micheline_fold_nodesnodesfacc@@funacc->micheline_fold_auxnodefacckletfoldnodeinitf=micheline_fold_auxnodefinit(funx->x)letmicheline_nodesnode=foldnode0@@funn_->n+1letstrip_locations_costnode=letnodes=micheline_nodesnodeincost_micheline_strip_locationsnodesletstrip_annotations_costnode=letnodes=micheline_nodesnodeincost_micheline_strip_annotationsnodes