Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file context.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018-2021 Tarides <contact@tarides.com> *)(* 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. *)(* *)(*****************************************************************************)moduleProof=Tezos_context_sigs.Context.Proof_typesmoduletypeTEZOS_CONTEXT_MEMORY=sigtypetreeincludeTezos_context_sigs.Context.TEZOS_CONTEXTwithtypememory_context_tree:=treeandtypetree:=treeandtypevalue_key=Context_hash.tandtypenode_key=Context_hash.t(** Exception raised by [find_tree] and [add_tree] when applied to shallow
trees. It is exposed so that it can be catched by the proxy where such
operations on shallow trees are expected. *)exceptionContext_dangling_hashofstringvalencoding:tData_encoding.tendmoduleMake(Encoding:moduletypeofTezos_context_encoding.Context)=structopenEncodingmoduleStore=structmoduleMaker=Irmin_pack_mem.Maker(Conf)includeMaker.Make(Schema)moduleSchema=Tezos_context_encoding.Context.SchemaendmoduleInfo=Store.InfomoduleP=Store.Backendtypenode_key=Context_hash.ttypevalue_key=Context_hash.ttypekinded_key=[`Valueofvalue_key|`Nodeofnode_key]moduleTree=structincludeTezos_context_helpers.Context.Make_tree(Conf)(Store)letkinded_keytree=matchStore.Tree.keytreewith|None->None|Someh->Some(matchhwith|`Nodehash->`Node(Hash.to_context_hashhash)|`Contents(hash,())->`Value(Hash.to_context_hashhash))endtypeindex={path:string;(** [path] corresponds to the directory that Irmin considers to be
the root of the context. Specifying a root is mandatory, even
for in-memory contexts. Irmin might use this value to deduplicate
contexts sharing the same root. If several in-memory contexts
are to coexist in the same process, it might be wise to assign them
distinct roots. *)repo:Store.repo;patch_context:(t->ttzresultLwt.t)option;}andcontext={index:index;parents:Store.Commit.tlist;tree:Store.tree;}andt=contexttypetree=Store.treetypekey=stringlisttypevalue=bytesletindex{index;_}=index(*-- Version Access and Update -----------------------------------------------*)letcurrent_protocol_key=["protocol"]letcurrent_test_chain_key=["test_chain"]letcurrent_predecessor_block_metadata_hash_key=["predecessor_block_metadata_hash"]letcurrent_predecessor_ops_metadata_hash_key=["predecessor_ops_metadata_hash"]letexists(index:index)key=letopenLwt_syntaxinlet+o=Store.Commit.of_hashindex.repo(Hash.of_context_hashkey)inOption.is_someoletcheckout(index:index)key=letopenLwt_syntaxinlet*o=Store.Commit.of_hashindex.repo(Hash.of_context_hashkey)inmatchowith|None->Lwt.return_none|Somecommit->lettree=Store.Commit.treecommitinletctxt={index;tree;parents=[commit]}inLwt.return_somectxtletcheckout_exnindexkey=letopenLwt_syntaxinlet*o=checkoutindexkeyinmatchowithNone->Lwt.failNot_found|Somep->Lwt.returnp(* unshallow possible 1-st level objects from previous partial
checkouts ; might be better to pass directly the list of shallow
objects. *)letunshallowcontext=letopenLwt_syntaxinlet*children=Store.Tree.listcontext.tree[]inStore.Backend.Repo.batchcontext.index.repo(funxy_->List.iter_s(fun(s,k)->matchStore.Tree.destructkwith|`Contents_->Lwt.return()|`Node_->let*tree=Store.Tree.get_treecontext.tree[s]inlet+_=Store.save_tree~clear:truecontext.index.repoxytreein())children)letget_hash_version_c=Context_hash.Version.of_int0letset_hash_versioncv=letopenLwt_result_syntaxinifContext_hash.Version.(of_int0=v)thenreturncelsetzfail(Tezos_context_helpers.Context.Unsupported_context_hash_versionv)letraw_commit~time?(message="")context=letopenLwt_syntaxinletinfo=Store.Info.v(Time.Protocol.to_secondstime)~author:"Tezos"~messageinletparents=List.mapStore.Commit.keycontext.parentsinlet*()=unshallowcontextinlet+h=Store.Commit.vcontext.index.repo~info~parentscontext.treeinStore.Tree.clearcontext.tree;hmoduleCommit_hash=Irmin.Hash.Typed(Hash)(Store.Backend.Commit_portable)lethash~time?(message="")context=letinfo=Store.Info.v(Time.Protocol.to_secondstime)~author:"Tezos"~messageinletparents=List.map(func->Store.Commit.keyc)context.parentsinletnode=Store.Tree.hashcontext.treeinletcommit=Store.Backend.Commit_portable.v~parents~node~infoinletx=Commit_hash.hashcommitinHash.to_context_hashxletcommit~time?messagecontext=letopenLwt_syntaxinlet+commit=raw_commit~time?messagecontextinHash.to_context_hash(Store.Commit.hashcommit)letgc__=(* not implemented for in-memory context *)Lwt.return_unitletwait_gc_completion_=(* not implemented for in-memory context *)Lwt.return_unitletis_gc_allowed_=(* not implemented for in-memory context *)falseletsplit_=(* not implemented for in-memory context *)Lwt.return_unitletexport_snapshot__~path:_=(* not implemented for in-memory context *)Lwt.return_unitletsync_=(* not implemented for in-memory context *)Lwt.return_unit(*-- Generic Store Primitives ------------------------------------------------*)letdata_key=Tezos_context_sigs.Context.data_keyletmem:t->key->boolLwt.t=functxtkey->Tree.memctxt.tree(data_keykey)letmem_treectxtkey=Tree.mem_treectxt.tree(data_keykey)letlistctxt?offset?lengthkey=Tree.listctxt.tree?offset?length(data_keykey)letlengthctxtkey=Tree.lengthctxt.tree(data_keykey)letfindctxtkey=Tree.findctxt.tree(data_keykey)letraw_addctxtkeydata=letopenLwt_syntaxinlet+tree=Tree.addctxt.treekeydatain{ctxtwithtree}letaddctxtkeydata=raw_addctxt(data_keykey)dataletraw_removectxtk=letopenLwt_syntaxinlet+tree=Tree.removectxt.treekin{ctxtwithtree}letremovectxtkey=raw_removectxt(data_keykey)letfind_treectxtkey=Tree.find_treectxt.tree(data_keykey)letadd_treectxtkeytree=letopenLwt_syntaxinlet+tree=Tree.add_treectxt.tree(data_keykey)treein{ctxtwithtree}letfold?depthctxtkey~order~init~f=Tree.fold?depthctxt.tree(data_keykey)~order~init~f(** The light mode relies on the implementation of this
function, because it uses Irmin.Type.of_string to rebuild values
of type Irmin.Hash.t. This is a temporary workaround until we
do that in a type safe manner when there are less moving pieces. *)letmerkle_hash_to_string=Irmin.Type.to_stringStore.Hash.tletrectree_to_raw_contexttree=letopenLwt_syntaxinmatchStore.Tree.destructtreewith|`Contents(v,_)->let+v=Store.Tree.Contents.force_exnvinProof.Keyv|`Node_->let*kvs=Store.Tree.listtree[]inletfacc(key,_)=(* get_tree is safe, because we iterate over keys *)let*tree=Store.Tree.get_treetree[key]inlet+sub_raw_context=tree_to_raw_contexttreeinString.Map.addkeysub_raw_contextaccinlet+res=List.fold_left_sfString.Map.emptykvsinProof.Dirresletto_memory_treetkey=find_treetkeyletmerkle_hashtree=letmerkle_hash_kind=matchStore.Tree.destructtreewith|`Contents_->Proof.Contents|`Node_->Proof.Nodeinlethash_str=Store.Tree.hashtree|>merkle_hash_to_stringinProof.Hash(merkle_hash_kind,hash_str)letmerkle_treetleaf_kindkey=letopenLwt_syntaxinlet*subtree_opt=Store.Tree.find_treet.tree(data_key[])inmatchsubtree_optwith|None->Lwt.returnString.Map.empty|Somesubtree->letkey_to_stringk=String.concat";"kinletreckey_to_merkle_treettarget=match(Store.Tree.destructt,target)with|_,[]->(* We cannot use this case as the base case, because a merkle_node
is a map from string to something. In this case, we have
no key to put in the map's domain. *)raise(Invalid_argument(Printf.sprintf"Reached end of key (top-level key was: %s)"@@key_to_stringkey))|_,[hd]->letfinallykey=(* get_tree is safe because we iterate on keys *)let*tree=Store.Tree.get_treet[key]inifkey=hdthen(* on the target path: the final leaf *)matchleaf_kindwith|Proof.Hole->Lwt.return@@merkle_hashtree|Proof.Raw_context->let+raw_context=tree_to_raw_contexttreeinProof.Dataraw_contextelse(* a sibling of the target path: return a hash *)Lwt.return@@merkle_hashtreeinlet*l=Store.Tree.listt[]inList.fold_left_s(funacc(key,_)->let+v=finallykeyinString.Map.addkeyvacc)String.Map.emptyl|`Node_,target_hd::target_tl->letcontinuekey=(* get_tree is safe because we iterate on keys *)let*tree=Store.Tree.get_treet[key]inifkey=target_hdthen(* on the target path: recurse *)let+sub=key_to_merkle_treetreetarget_tlinProof.Continuesubelse(* a sibling of the target path: return a hash *)Lwt.return@@merkle_hashtreeinlet*l=Store.Tree.listt[]inList.fold_left_s(funacc(key,_)->let+atom=continuekeyinString.Map.addkeyatomacc)String.Map.emptyl|`Contents_,_->raise(Invalid_argument(Printf.sprintf"(`Contents _, l) when l <> [_] (in other words: found a \
leaf node whereas key %s (top-level key: %s) wasn't \
fully consumed)"(key_to_stringtarget)(key_to_stringkey)))inkey_to_merkle_treesubtreekeyexceptionContext_dangling_hash=Tree.Context_dangling_hashincludeTezos_context_helpers.Context.Make_proof(Store)(Conf)includeTezos_context_helpers.Context.Make_config(Conf)letproduce_tree_proof(t:index)key=produce_tree_prooft.repo(matchkeywith|`Nodehash->`Node(Hash.of_context_hashhash)|`Valuehash->`Value(Hash.of_context_hashhash))letproduce_stream_proof(t:index)key=produce_stream_prooft.repo(matchkeywith|`Nodehash->`Node(Hash.of_context_hashhash)|`Valuehash->`Value(Hash.of_context_hashhash))moduleStorelike=structtypekey=stringlisttypetree=Store.treetypevalue=bytesletfind=Tree.findletfind_tree=Tree.find_treeletunshallow=Tree.unshallowendmoduleGet_data=Tezos_context_sigs.Context.With_get_data((Storelike:Tezos_context_sigs.Context.Storelike))letmerkle_tree_v2ctxleaf_kindkey=letopenLwt_syntaxinmatchTree.kinded_keyctx.treewith|None->raise(Invalid_argument"In-memory context.tree has no kinded_key")|Somekinded_key->let*proof,_=produce_tree_proofctx.indexkinded_key(Get_data.get_dataleaf_kind[key])inreturnproof(*-- Predefined Fields -------------------------------------------------------*)moduleRoot_tree=structletget_protocolt=letopenLwt_syntaxinlet+o=Tree.findtcurrent_protocol_keyinletdata=WithExceptions.Option.to_exn_f~none:(fun()->assertfalse)oinProtocol_hash.of_bytes_exndataletadd_protocoltv=letv=Protocol_hash.to_bytesvinTree.addtcurrent_protocol_keyvletget_test_chaint=letopenLwt_syntaxinlet*o=Tree.findtcurrent_test_chain_keyinletdata=WithExceptions.Option.to_exn~none:(Failure"Unexpected error (Context.get_test_chain)")oinmatchData_encoding.Binary.of_bytesTest_chain_status.encodingdatawith|Errorre->Format.kasprintf(funs->Lwt.fail(Failures))"Error in Context.get_test_chain: %a"Data_encoding.Binary.pp_read_errorre|Okr->Lwt.returnrletadd_test_chaintid=letid=Data_encoding.Binary.to_bytes_exnTest_chain_status.encodingidinTree.addtcurrent_test_chain_keyidletfind_predecessor_block_metadata_hasht=letopenLwt_syntaxinlet*o=Tree.findtcurrent_predecessor_block_metadata_hash_keyinmatchowith|None->return_none|Somedata->(matchData_encoding.Binary.of_bytes_optBlock_metadata_hash.encodingdatawith|None->raise(Failure"Unexpected error \
(Context.get_predecessor_block_metadata_hash)")|Somer->return_somer)letadd_predecessor_block_metadata_hashthash=letdata=Data_encoding.Binary.to_bytes_exnBlock_metadata_hash.encodinghashinTree.addtcurrent_predecessor_block_metadata_hash_keydataletfind_predecessor_ops_metadata_hasht=letopenLwt_syntaxinlet*o=Tree.findtcurrent_predecessor_ops_metadata_hash_keyinmatchowith|None->return_none|Somedata->(matchData_encoding.Binary.of_bytes_optOperation_metadata_list_list_hash.encodingdatawith|None->raise(Failure"Unexpected error \
(Context.get_predecessor_ops_metadata_hash)")|Somer->return_somer)letadd_predecessor_ops_metadata_hashthash=letdata=Data_encoding.Binary.to_bytes_exnOperation_metadata_list_list_hash.encodinghashinTree.addtcurrent_predecessor_ops_metadata_hash_keydataendletget_protocolctxt=Root_tree.get_protocolctxt.treeletget_test_chainctxt=Root_tree.get_test_chainctxt.treeletfind_predecessor_block_metadata_hashctxt=Root_tree.find_predecessor_block_metadata_hashctxt.treeletfind_predecessor_ops_metadata_hashctxt=Root_tree.find_predecessor_ops_metadata_hashctxt.treeletlift_tree_add_to_ctxttree_addctxtv=letopenLwt_syntaxinlet+tree=tree_addctxt.treevin{ctxtwithtree}letadd_protocol=lift_tree_add_to_ctxtRoot_tree.add_protocolletadd_test_chain=lift_tree_add_to_ctxtRoot_tree.add_test_chainletadd_predecessor_block_metadata_hash=lift_tree_add_to_ctxtRoot_tree.add_predecessor_block_metadata_hashletadd_predecessor_ops_metadata_hash=lift_tree_add_to_ctxtRoot_tree.add_predecessor_ops_metadata_hashletremove_test_chainv=raw_removevcurrent_test_chain_keyletfork_test_chainv~protocol~expiration=add_test_chainv(Forking{protocol;expiration})letinit?patch_context?(readonly=false)?index_log_sizepath=letopenLwt_syntaxinignoreindex_log_size;letcfg=Irmin_pack.config~readonlypathinlet*repo=Store.Repo.vcfginLwt.return{path;repo;patch_context}letcloseindex=Store.Repo.closeindex.repoletemptyindex={index;parents=[];tree=Store.Tree.empty()}letis_emptyt=Tree.is_emptyt.treeletget_branchchain_id=Format.asprintf"%a"Chain_id.ppchain_idletcommit_genesisindex~chain_id~time~protocol=letopenLwt_result_syntaxinletctxt=emptyindexinlet*ctxt=matchindex.patch_contextwith|None->returnctxt|Somepatch_context->patch_contextctxtinlet*!ctxt=add_protocolctxtprotocolinlet*!ctxt=add_test_chainctxtNot_runninginlet*!commit=raw_commit~time~message:"Genesis"ctxtinlet*!()=Store.Branch.setindex.repo(get_branchchain_id)commitinreturn(Hash.to_context_hash(Store.Commit.hashcommit))letconcrete_encoding:Store.Tree.concreteData_encoding.t=letopenData_encodinginmu"memory_context"(funencoding->letmap_encoding=list(tup2stringencoding)inunion[case~title:"tree"(Tag0)map_encoding(function`Treemap->Somemap|`Contents_->None)(funmap->`Treemap);case~title:"value"(Tag1)bytes(function`Contents(v,_)->Somev|`Tree_->None)(funv->`Contents(v,()));])letencoding:tData_encoding.t=Data_encoding.conv(funt->lettree=Store.Tree.to_concretet.treeinlettree=(* This is safe as store.Tree will never call any blocking
functions. *)matchLwt.statetreewithReturnt->t|_->assertfalseintree)(funt->lettree=Store.Tree.of_concretetinletindex=matchLwt.state(init"/tmp")with|Lwt.Returnresult->result|Lwt.Failexn->raiseexn|Lwt.Sleep->(* The in-memory context should never block *)assertfalseinletctxt=emptyindexin{ctxtwithtree})concrete_encodingletcompute_testchain_chain_idgenesis=letgenesis_hash=Block_hash.hash_bytes[Block_hash.to_bytesgenesis]inChain_id.of_block_hashgenesis_hashletcompute_testchain_genesisforked_block=letgenesis=Block_hash.hash_bytes[Block_hash.to_bytesforked_block]ingenesisletcommit_test_chain_genesisctxt(forked_header:Block_header.t)=letopenLwt_syntaxinletmessage=Format.asprintf"Forking testchain at level %ld."forked_header.shell.levelinlet*commit=raw_commit~time:forked_header.shell.timestamp~messagectxtinletfaked_shell_header:Block_header.shell_header={forked_header.shellwithproto_level=succforked_header.shell.proto_level;predecessor=Block_hash.zero;validation_passes=0;operations_hash=Operation_list_list_hash.empty;context=Hash.to_context_hash(Store.Commit.hashcommit);}inletforked_block=Block_header.hashforked_headerinletgenesis_hash=compute_testchain_genesisforked_blockinletchain_id=compute_testchain_chain_idgenesis_hashinletgenesis_header:Block_header.t={shell={faked_shell_headerwithpredecessor=genesis_hash};protocol_data=Bytes.create0;}inletbranch=get_branchchain_idinlet+()=Store.Branch.setctxt.index.repobranchcommitingenesis_headerletclear_test_chainindexchain_id=(* TODO remove commits... ??? *)(* TODO inherited from [lib_context/disk/context.ml] *)letbranch=get_branchchain_idinStore.Branch.removeindex.repobranchletset_headindexchain_idcommit=letopenLwt_syntaxinletbranch=get_branchchain_idinlet*o=Store.Commit.of_hashindex.repo(Hash.of_context_hashcommit)inmatchowith|None->assertfalse|Somecommit->Store.Branch.setindex.repobranchcommitletset_masterindexcommit=letopenLwt_syntaxinlet*o=Store.Commit.of_hashindex.repo(Hash.of_context_hashcommit)inmatchowith|None->assertfalse|Somecommit->Store.Branch.setindex.repoStore.Branch.maincommitend