123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2021 Nomadic Labs, <contact@nomadic-labs.com> *)(* Copyright (c) 2023 Marigold <contact@marigold.dev> *)(* *)(* 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. *)(* *)(*****************************************************************************)openStore_sigsopenContext_sigsmoduleContext_encoding=Tezos_context_encoding.Context_binary(* We shadow [Tezos_context_encoding] to prevent accidentally using
[Tezos_context_encoding.Context] instead of
[Tezos_context_encoding.Context_binary] during a future
refactoring.*)moduleTezos_context_encoding=structendmoduleMaker=Irmin_pack_unix.Maker(Context_encoding.Conf)moduleIStore=structincludeMaker.Make(Context_encoding.Schema)moduleSchema=Context_encoding.SchemaendmoduleIStoreTree=Tezos_context_helpers.Context.Make_tree(Context_encoding.Conf)(IStore)typerepo=IStore.Repo.ttypetree=IStore.treetype'araw_index=('a,repo)Context_sigs.raw_indextype'aindex=('a,repo)Context_sigs.indextyperw_index=[`Read|`Write]indextypero_index=[`Read]indextype'at=('a,repo,tree)Context_sigs.ttyperw=[`Read|`Write]ttypero=[`Read]ttypecommit=IStore.committypehash=Context_hash.ttypepath=stringlistmoduleTree:Tezos_context_sigs.Context.TREEwithtypetree=IStore.treeandtypekey=stringlistandtypevalue=bytesandtypet=rw=structincludeIStoreTreetypet=rwtypetree=IStore.treetypekey=stringlisttypevalue=bytesendlet()=assert(Context_hash.size=IStore.Hash.hash_size)letimpl_name="Irmin"letequality_witness:(repo,tree)Context_sigs.equality_witness=(Context_sigs.Equality_witness.make(),Context_sigs.Equality_witness.make())lethash_to_istore_hashh=Context_hash.to_stringh|>IStore.Hash.unsafe_of_raw_stringletistore_hash_to_hashh=IStore.Hash.to_raw_stringh|>Context_hash.of_string_exnletload:typea.cache_size:int->amode->string->araw_indexLwt.t=fun~cache_sizemodepath->letopenLwt_syntaxinletreadonly=matchmodewithRead_only->true|Read_write->falseinlet+repo=IStore.Repo.v(Irmin_pack.config~readonly(* Note that the use of GC in the context requires that
* the [always] indexing strategy not be used. *)~indexing_strategy:Irmin_pack.Indexing_strategy.minimal~lru_size:cache_sizepath)in{path;repo}letclosectxt=let_interrupted_gc=IStore.Gc.cancelctxt.repoinIStore.Repo.closectxt.repoletreadonly(index:[>`Read]index)=(index:>[`Read]index)letraw_commit?(message="")indextree=letinfo=IStore.Info.v~author:"Tezos"0L~messageinIStore.Commit.vindex.repo~info~parents:[]treeletcommit?messagectxt=letopenLwt_syntaxinlet+commit=raw_commit?messagectxt.indexctxt.treeinIStore.Commit.hashcommit|>istore_hash_to_hashletcheckoutindexkey=letopenLwt_syntaxinlet*o=IStore.Commit.of_hashindex.repo(hash_to_istore_hashkey)inmatchowith|None->return_none|Somecommit->lettree=IStore.Commit.treecommitinreturn_some{index;tree}letcheckout_exnindexkey=letopenLwt_syntaxinlet*context=checkoutindexkeyinmatchcontextwith|Somecontext->returncontext|None->Lwt.fail_with"No store found"letemptyindex={index;tree=IStore.Tree.empty()}letis_emptyctxt=IStore.Tree.is_emptyctxt.treeletsplitctxt=IStore.splitctxt.repo(* adapted from lib_context/disk/context.ml *)letgcindex?(callback:unit->unitLwt.t=fun()->Lwt.return())(hash:hash)=letopenLwt_syntaxinletrepo=index.repoinletistore_hash=hash_to_istore_hashhashinlet*commit_opt=IStore.Commit.of_hashindex.repoistore_hashinmatchcommit_optwith|None->Fmt.failwith"%a: unknown context hash"Context_hash.pphash|Somecommit->(letfinished=function|Ok(stats:Irmin_pack_unix.Stats.Latest_gc.stats)->lettotal_duration=Irmin_pack_unix.Stats.Latest_gc.total_durationstatsinletfinalise_duration=Irmin_pack_unix.Stats.Latest_gc.finalise_durationstatsinlet*()=callback()inEvent.ending_context_gc(Time.System.Span.of_seconds_exntotal_duration,Time.System.Span.of_seconds_exnfinalise_duration)|Error(`Msgerr)->Event.context_gc_failureerrinletcommit_key=IStore.Commit.keycommitinlet*launch_result=IStore.Gc.run~finishedrepocommit_keyinmatchlaunch_resultwith|Error(`Msgerr)->Event.context_gc_launch_failureerr|Okfalse->Event.context_gc_already_launched()|Oktrue->Event.starting_context_gchash)letwait_gc_completionindex=letopenLwt_syntaxinlet*r=IStore.Gc.waitindex.repoinmatchrwith|Ok_stats_opt->return_unit|Error(`Msg_msg)->(* Logs will be printed by the [gc] caller. *)return_unitletis_gc_finishedindex=IStore.Gc.is_finishedindex.repoletindexcontext=context.indexletexport_snapshot{path=_;repo}context_hash~path=letopenLwt_result_syntaxinlet*!commit_opt=IStore.Commit.of_hashrepo(hash_to_istore_hashcontext_hash)inmatchcommit_optwith|None->failwith"Cannot export context snapshot: unknown context hash %a"Context_hash.ppcontext_hash|Somecommit->leth=IStore.Commit.keycommitinlet*!()=IStore.create_one_commit_storerepohpathinreturn_unitmoduleProof(Hash:sigtypetvalof_context_hash:Context_hash.t->tend)(Proof_encoding:sigvalproof_encoding:Tezos_context_sigs.Context.Proof_types.treeTezos_context_sigs.Context.Proof_types.tData_encoding.tend)=structmoduleIStoreProof=Tezos_context_helpers.Context.Make_proof(IStore)(Context_encoding.Conf)moduleTree=structincludeIStoreTreetypet=rw_indextypetree=IStore.treetypekey=pathtypevalue=bytesendtypetree=Tree.treetypeproof=IStoreProof.Proof.treeIStoreProof.Proof.tlethash_treetree=Hash.of_context_hash(Tree.hashtree)letproof_encoding=Proof_encoding.proof_encodingletproof_beforeproof=let(`Valuehash|`Nodehash)=proof.IStoreProof.Proof.beforeinHash.of_context_hashhashletproof_afterproof=let(`Valuehash|`Nodehash)=proof.IStoreProof.Proof.afterinHash.of_context_hashhashletproduce_proofindextreestep=letopenLwt_syntaxin(* Committing the context is required by Irmin to produce valid proofs. *)let*_commit_key=raw_commitindextreeinmatchTree.kinded_keytreewith|Somek->let*p=IStoreProof.produce_tree_proofindex.repokstepinreturn_somep|None->return_noneletverify_proofproofstep=(* The rollup node is not supposed to verify proof. We keep
this part in case this changes in the future. *)letopenLwt_syntaxinlet*result=IStoreProof.verify_tree_proofproofstepinmatchresultwith|Okv->return_somev|Error_->(* We skip the error analysis here since proof verification is not a
job for the rollup node. *)return_noneend(** State of the PVM that this rollup node deals with. *)modulePVMState=structtypevalue=treeletkey=["pvm_state"]letempty()=IStore.Tree.empty()letfindctxt=IStore.Tree.find_treectxt.treekeyletgetctxt=letopenLwt_syntaxinlet*pvm_state=findctxtinmatchpvm_statewith|Somestore->returnstore|None->Lwt.fail_with"No pvm_state found"letlookuptreepath=IStore.Tree.findtreepathletsetctxtstate=letopenLwt_syntaxinlet+tree=IStore.Tree.add_treectxt.treekeystatein{ctxtwithtree}endletload~cache_sizemodepath=letopenLwt_result_syntaxinlet*!index=load~cache_sizemodepathinreturnindexmoduleInternal_for_tests=structletget_a_treekey=lettree=IStore.Tree.empty()inIStore.Tree.addtree[key]Bytes.emptyend