123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2021 Nomadic Labs, <contact@nomadic-labs.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. *)(* *)(*****************************************************************************)openAlpha_contexttypeidentifier=stringletidentifier_of_contractaddr=Contract.to_b58checkaddrletcontract_of_identifieridentifier=Contract.of_b58checkidentifiertypecached_contract=Script.t*Script_ir_translator.ex_scriptletload_and_elaboratectxtaddr=Contract.get_scriptctxtaddr>>=?fun(ctxt,script)->matchscriptwith|None->return(ctxt,None)|Somescript->Script_ir_translator.(parse_scriptctxtscript~legacy:true~allow_forged_in_storage:true>>=?fun(ex_script,ctxt)->(* We consume gas after the fact in order to not have to instrument
[script_size] (for efficiency).
This is safe, as we already pay gas proportional to storage size
in [parse_script] beforehand. *)let(size,cost)=script_sizeex_scriptinGas.consumectxtcost>>?=functxt->return(ctxt,Some(script,ex_script,size)))moduleClient=structtypecached_value=cached_contractletnamespace="contract"letcache_index=0letvalue_of_identifierctxtidentifier=(*
I/O, deserialization, and elaboration of contracts scripts
are cached.
*)contract_of_identifieridentifier>>?=funaddr->load_and_elaboratectxtaddr>>=?function|(_,None)->(* [value_of_identifier ctxt k] is applied to identifiers stored
in the cache. Only script-based contracts that have been
executed are in the cache. Hence, [get_script] always
succeeds for these identifiers if [ctxt] and the [cache] are
properly synchronized by the shell. *)failwith"Script_cache: Inconsistent script cache."|(_,Some(unparsed_script,ir_script,_))->return(unparsed_script,ir_script)endmoduleCache=(valCache.register_exn(moduleClient))letfindctxtaddr=letidentifier=identifier_of_contractaddrinCache.findctxtidentifier>>=?function|Some(unparsed_script,ex_script)->return(ctxt,identifier,Some(unparsed_script,ex_script))|None->(load_and_elaboratectxtaddr>>=?function|(ctxt,None)->return(ctxt,identifier,None)|(ctxt,Some(unparsed_script,script_ir,size))->letcached_value=(unparsed_script,script_ir)inLwt.return(Cache.updatectxtidentifier(Some(cached_value,size))>>?functxt->ok(ctxt,identifier,Some(unparsed_script,script_ir))))letupdatectxtidentifierupdated_scriptapprox_size=Cache.updatectxtidentifier(Some(updated_script,approx_size))letentriesctxt=Cache.list_identifiersctxt|>List.map_e@@fun(identifier,age)->contract_of_identifieridentifier>|?funcontract->(contract,age)letcontract_rankctxtaddr=Cache.identifier_rankctxt(identifier_of_contractaddr)letsize=Cache.sizeletsize_limit=Cache.size_limit