123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2020 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. *)(* *)(*****************************************************************************)moduleLocal=Tezos_context_memory.ContextmoduleM=structtypekey=Local.keytypevalue=Local.valuetypetree=Local.tree(* When the [proxy] option is [None], this instance of [M] should
behave like [Memory_context]. *)typet={proxy:Proxy_delegate.toption;local:Local.t}letempty=Tezos_context_memory.Context.make_empty_tree()endmoduleC=structtypekey=M.keytypevalue=M.valuetypet=M.t(* [tree] is the tree available under [/data/<path>]. *)typetree={proxy:Proxy_delegate.toption;path:key;tree:Local.tree}(** Generic pretty printing functions *)letpp_keyppfkey=Format.pp_print_list~pp_sep:(funppf_->Format.fprintfppf"; ")Format.pp_print_stringppfkeymoduleL=structmoduleS=Internal_event.Simpleletsection=["proxy";"context"]letproxy_context_missing=S.declare_1~section~name:"proxy_context_missing"~msg:"delegating to proxy cache, because data misses for: {key}"~pp1:pp_key("key",Data_encoding.(Variable.liststring))letdelegation_error=S.declare_2~section~name:"delegation_error"~msg:"{function} returned an error, ignoring it but this is bad: {trace}"~pp2:pp_print_trace("function",Data_encoding.string)("trace",Error_monad.trace_encoding)endtypeelt=Keyofvalue|DirofLocal.treeleteltt=letopenLwt_syntaxinlet+o=Local.Tree.to_valuetinmatchowithSomev->Keyv|None->Dirtletraw_find(t:tree)k=letopenLwt_syntaxinlet*o=Local.Tree.find_treet.treekinmatchowith|Some_->Lwt.returno|None->(let*()=L.(S.emitproxy_context_missing)kinmatcht.proxywith|None->Lwt.return_none|Some(moduleProxyDelegation)->(let*r=ProxyDelegation.proxy_get(t.path@k)inmatchrwith|Errorerr->let*()=L.(S.emitdelegation_error("get",err))inLwt.return_none|Okx->Lwt.returnx))letraw_mem_auxkind(t:tree)k=letopenLwt_syntaxinlet*o=Local.Tree.find_treet.treekinleto=Option.mapLocal.Tree.kindoinmatchowith|Some`Value->Lwt.return(kind=`Value)|Some`Tree->Lwt.return(kind=`Tree)|None->(matcht.proxywith|None->Lwt.return_false|Some(moduleProxyDelegation)->(letmem=matchkindwith|`Value->ProxyDelegation.proxy_mem|`Tree->ProxyDelegation.proxy_dir_meminlet*r=mem(t.path@k)inmatchrwith|Errorerr->letmsg=matchkindwith`Value->"mem"|`Tree->"dir_mem"inlet*()=L.(S.emitdelegation_error(msg,err))inLwt.return_false|Okx->Lwt.returnx))letraw_mem=raw_mem_aux`Valueletraw_mem_tree=raw_mem_aux`Tree(* The tree under /data *)letdata_tree(t:t)=letopenLwt_syntaxinlet+o=Local.find_treet.local[]inmatchowith|None->{proxy=t.proxy;path=[];tree=Local.Tree.emptyt.local}|Sometree->{proxy=t.proxy;path=[];tree}letmemtk=letopenLwt_syntaxinlet*tree=data_treetinraw_memtreekletmem_treetk=letopenLwt_syntaxinlet*tree=data_treetinraw_mem_treetreekletfindtk=letopenLwt_syntaxinlet*tree=data_treetinlet*o=raw_findtreekinmatchowith|None->Lwt.return_none|Somev->(let+k=eltvinmatchkwithKeyv->Somev|_->None)letfind_treetk=letopenLwt_syntaxinlet*tree=data_treetinlet+o=raw_findtreekinOption.map(funtree->{proxy=t.proxy;path=k;tree})oletadd_tree(t:t)k(v:tree)=letopenLwt_syntaxinlet+local=Local.add_treet.localkv.treeinift.local==localthentelse{twithlocal}letadd(t:t)kv=letopenLwt_syntaxinlet+local=Local.addt.localkvinift.local==localthentelse{twithlocal}letremove(t:t)k=letopenLwt_syntaxinlet+local=Local.removet.localkinift.local==localthentelse{twithlocal}letraw_list(t:tree)?offset?lengthk=letopenLwt_syntaxinlet+ls=Local.Tree.listt.tree?offset?lengthkinList.fold_left(funacc(k,tree)->letv={proxy=t.proxy;path=t.path@[k];tree}in(k,v)::acc)[](List.revls)letlistt?offset?lengthk=letopenLwt_syntaxinletlocal_raw_list()=let*tree=data_treetinraw_listtree?offset?lengthkinmatcht.proxywith|None->local_raw_list()|Some(moduleProxyDelegation)->(let*tree=ProxyDelegation.proxy_getkinmatchtreewith|Okv->(matchvwith|Sometree->(* [tree] is the value at [k], so we need to pass [] as the key
in the call to [raw_list]: *)raw_list{proxy=None;path=k;tree}?offset?length[]|None->return[])|Errorerr->(* We are in trouble here. The delegate failed; but we can't
forward the error to the caller, because this function is
[Lwt.t], but not in [tzresult Lwt.t]. To keep track of the error,
we log it and are left with deciding what to return. We could
list on the local tree ([local_raw_list]) but it doesn't make
much sense, because in production this tree is almost
completely empty. That is why we return the default value, i.e. the
empty list. It's not a perfect choice, but we prefer that than failing. *)let+()=L.(S.emitdelegation_error("get",err))in[])letlengthtk=letopenLwt_syntaxinletlocal_raw_length()=let*t=data_treetinLocal.Tree.lengtht.treekinmatcht.proxywith|None->local_raw_length()|Some(moduleProxyDelegation)->(let*tree=ProxyDelegation.proxy_getkinmatchtreewith|Okv->(matchvwith|Sometree->(* [tree] is the value at [k], so we need to pass [] as the key
in the call to [length]: *)Local.Tree.lengthtree[]|None->local_raw_length())|Errorerr->(* We are in trouble here. The delegate failed; but we can't
forward the error to the caller, because this function is
[Lwt.t], but not in [tzresult Lwt.t]. To keep track of the error,
we log it and are left with deciding what to return. We could call
[length] on the local tree ([local_raw_length]) but it doesn't make
much sense, because in production this tree is almost
completely empty. That is why we return the default value, i.e. zero.
It's not a perfect choice, but we prefer that than failing. *)let+()=L.(S.emitdelegation_error("get",err))in0)letfold?depth(t:t)root~order~init~f=letopenLwt_syntaxin(* Fold over the tree mapped by [root] *)letfold_root_tree(tree:M.tree)=Local.Tree.fold?depthtree[]~order~init~f:(funktreeacc->lettree={proxy=t.proxy;path=root@k;tree}infktreeacc)inletlocal_raw_fold()=let*tr=find_treetrootinmatchtrwith|None->Lwt.returninit|Sometr->fold_root_treetr.treeinmatcht.proxywith|None->local_raw_fold()|Some(moduleProxyDelegation)->(let*tree=ProxyDelegation.proxy_getrootinmatchtreewith|OkNone->Lwt.returninit|Ok(Somev)->fold_root_treev|Errorerr->(* We are in trouble here. The delegate failed; but we can't
forward the error to the caller, because this function is
[Lwt.t], but not in [tzresult Lwt.t]. To keep track of the error,
we log it and are left with deciding what to return. We could
fold on the local tree ([local_raw_fold]) but it doesn't make
much sense, because in production this tree is almost
completely empty. That is why we return the default value.
It's not a perfect choice, but we prefer that than failing. *)let+()=L.(S.emitdelegation_error("get",err))ininit)letset_protocol(t:t)p=letopenLwt_syntaxinlet+local=Local.add_protocolt.localpin{twithlocal}letget_protocol(t:t)=Local.get_protocolt.localletfork_test_chainc~protocol:_~expiration:_=Lwt.returncletset_hash_version(t:t)v=letopenLwt_result_syntaxinlet+local=Local.set_hash_versiont.localvin{twithlocal}letget_hash_version(t:t)=Local.get_hash_versiont.localmoduleTree=structletppppft=Local.Tree.ppppft.treeletemptyt={proxy=None;path=[];tree=Local.Tree.emptyt.M.local}letequalxy=Local.Tree.equalx.treey.treelethashx=Local.Tree.hashx.treeletis_emptyt=Local.Tree.is_emptyt.treeletaddtkv=letopenLwt_syntaxinlet+tree=Local.Tree.addt.treekviniftree==t.treethentelse{twithtree}letadd_treetkv=letopenLwt_syntaxinlet+tree=Local.Tree.add_treet.treekv.treeiniftree==t.treethentelse{twithtree}letmem=raw_memletmem_tree=raw_mem_treeletfindtk=letopenLwt_syntaxinlet*o=raw_findtkinmatchowith|None->Lwt.return_none|Sometree->Local.Tree.to_valuetreeletfind_treetk=letopenLwt_syntaxinlet+o=raw_findtkinmatchowith|None->None|Sometree->ifk=[]thenSometelseSome{proxy=t.proxy;path=t.path@k;tree}letremovetk=letopenLwt_syntaxinlet+tree=Local.Tree.removet.treekiniftree==t.treethentelse{twithtree}letlengthtk=Local.Tree.lengtht.treekletfold?depth(t:tree)k~order~init~f=Local.Tree.fold?deptht.treek~order~init~f:(funktreeacc->lettree={proxy=t.proxy;path=t.path@k;tree}infktreeacc)letkindt=Local.Tree.kindt.treeletto_valuet=Local.Tree.to_valuet.treeletof_valuetv=letopenLwt_syntaxinlet+tree=Local.Tree.of_valuet.M.localvin{proxy=t.proxy;path=[];tree}letlist=raw_listletclear?deptht=Local.Tree.clear?deptht.treeletconfigt=Local.Tree.configt.treeendmoduleProof=Local.Proofletof_localtree={proxy=None;path=[];tree}letmap_fftree=letopenLwt_syntaxinlet+t,r=f(of_localtree)in(t.tree,r)letverifyverifierprooff=letopenLwt_syntaxinlet+r=verifierproof(map_ff)inmatchrwithOk(t,r)->Ok(of_localt,r)|Error_ase->eletverify_tree_proofpf=verifyLocal.verify_tree_proofpfletverify_stream_proofpf=verifyLocal.verify_stream_proofpfletconfigt=Local.configt.M.localletequal_config=Local.equal_configendopenEnvironment_contextincludeEnvironment_context.Register(C)letproxy_impl_name="proxy"letemptyproxy=letlocal=Tezos_context_memory.Context.make_empty_context()inletctxt=M.{proxy;local}inContext.make~ops~ctxt~kind:Context~equality_witness~impl_name:proxy_impl_name