Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file raw_context.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622(*****************************************************************************)(* *)(* 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. *)(* *)(*****************************************************************************)moduleInt_set=Set.Make(Compare.Int)typet={context:Context.t;constants:Constants_repr.parametric;first_level:Raw_level_repr.t;level:Level_repr.t;timestamp:Time.t;fitness:Int64.t;deposits:Tez_repr.tSignature.Public_key_hash.Map.t;allowed_endorsements:(Signature.Public_key.t*intlist*bool)Signature.Public_key_hash.Map.t;fees:Tez_repr.t;rewards:Tez_repr.t;block_gas:Z.t;operation_gas:Gas_limit_repr.t;storage_space_to_pay:Z.toption;origination_nonce:Contract_repr.origination_nonceoption;internal_nonce:int;internal_nonces_used:Int_set.t;}typecontext=ttyperoot_context=tletcurrent_levelctxt=ctxt.levelletcurrent_timestampctxt=ctxt.timestampletcurrent_fitnessctxt=ctxt.fitnessletfirst_levelctxt=ctxt.first_levelletconstantsctxt=ctxt.constantsletrecoverctxt=ctxt.contextletrecord_endorsementctxtk=matchSignature.Public_key_hash.Map.find_optkctxt.allowed_endorsementswith|None->assertfalse|Some(_,_,true)->assertfalse(* right already used *)|Some(d,s,false)->{ctxtwithallowed_endorsements=Signature.Public_key_hash.Map.addk(d,s,true)ctxt.allowed_endorsements}letinit_endorsementsctxtallowed_endorsements=ifSignature.Public_key_hash.Map.is_emptyallowed_endorsementsthenassertfalse(* can't initialize to empty *)elsebeginifSignature.Public_key_hash.Map.is_emptyctxt.allowed_endorsementsthen{ctxtwithallowed_endorsements}elseassertfalse(* can't initialize twice *)endletallowed_endorsementsctxt=ctxt.allowed_endorsementstypeerror+=Too_many_internal_operations(* `Permanent *)let()=letopenData_encodinginregister_error_kind`Permanent~id:"too_many_internal_operations"~title:"Too many internal operations"~description:"A transaction exceeded the hard limit \
of internal operations it can emit"empty(functionToo_many_internal_operations->Some()|_->None)(fun()->Too_many_internal_operations)letfresh_internal_noncectxt=ifCompare.Int.(ctxt.internal_nonce>=65_535)thenerrorToo_many_internal_operationselseok({ctxtwithinternal_nonce=ctxt.internal_nonce+1},ctxt.internal_nonce)letreset_internal_noncectxt={ctxtwithinternal_nonces_used=Int_set.empty;internal_nonce=0}letrecord_internal_noncectxtk={ctxtwithinternal_nonces_used=Int_set.addkctxt.internal_nonces_used}letinternal_nonce_already_recordedctxtk=Int_set.memkctxt.internal_nonces_usedletset_current_fitnessctxtfitness={ctxtwithfitness}letadd_feesctxtfees=Lwt.returnTez_repr.(ctxt.fees+?fees)>>=?funfees->return{ctxtwithfees}letadd_rewardsctxtrewards=Lwt.returnTez_repr.(ctxt.rewards+?rewards)>>=?funrewards->return{ctxtwithrewards}letadd_depositctxtdelegatedeposit=letprevious=matchSignature.Public_key_hash.Map.find_optdelegatectxt.depositswith|Sometz->tz|None->Tez_repr.zeroinLwt.returnTez_repr.(previous+?deposit)>>=?fundeposit->letdeposits=Signature.Public_key_hash.Map.adddelegatedepositctxt.depositsinreturn{ctxtwithdeposits}letget_depositsctxt=ctxt.depositsletget_rewardsctxt=ctxt.rewardsletget_feesctxt=ctxt.feestypeerror+=Undefined_operation_nonce(* `Permanent *)let()=letopenData_encodinginregister_error_kind`Permanent~id:"undefined_operation_nonce"~title:"Ill timed access to the origination nonce"~description:"An origination was attemped out of the scope of a manager operation"empty(functionUndefined_operation_nonce->Some()|_->None)(fun()->Undefined_operation_nonce)letinit_origination_noncectxtoperation_hash=letorigination_nonce=Some(Contract_repr.initial_origination_nonceoperation_hash)in{ctxtwithorigination_nonce}letorigination_noncectxt=matchctxt.origination_noncewith|None->errorUndefined_operation_nonce|Someorigination_nonce->okorigination_nonceletincrement_origination_noncectxt=matchctxt.origination_noncewith|None->errorUndefined_operation_nonce|Somecur_origination_nonce->letorigination_nonce=Some(Contract_repr.incr_origination_noncecur_origination_nonce)inok({ctxtwithorigination_nonce},cur_origination_nonce)letunset_origination_noncectxt={ctxtwithorigination_nonce=None}typeerror+=Gas_limit_too_high(* `Permanent *)let()=letopenData_encodinginregister_error_kind`Permanent~id:"gas_limit_too_high"~title:"Gas limit out of protocol hard bounds"~description:"A transaction tried to exceed the hard limit on gas"empty(functionGas_limit_too_high->Some()|_->None)(fun()->Gas_limit_too_high)letcheck_gas_limitctxtremaining=ifCompare.Z.(remaining>ctxt.constants.hard_gas_limit_per_operation)||Compare.Z.(remaining<Z.zero)thenerrorGas_limit_too_highelseok()letset_gas_limitctxtremaining={ctxtwithoperation_gas=Limited{remaining}}letset_gas_unlimitedctxt={ctxtwithoperation_gas=Unaccounted}letconsume_gasctxtcost=Gas_limit_repr.consumectxt.block_gasctxt.operation_gascost>>?fun(block_gas,operation_gas)->ok{ctxtwithblock_gas;operation_gas}letcheck_enough_gasctxtcost=Gas_limit_repr.check_enoughctxt.block_gasctxt.operation_gascostletgas_levelctxt=ctxt.operation_gasletblock_gas_levelctxt=ctxt.block_gasletgas_consumed~since~until=matchgas_levelsince,gas_leveluntilwith|Limited{remaining=before},Limited{remaining=after}->Z.subbeforeafter|_,_->Z.zeroletinit_storage_space_to_payctxt=matchctxt.storage_space_to_paywith|Some_->assertfalse|None->{ctxtwithstorage_space_to_pay=SomeZ.zero}letupdate_storage_space_to_payctxtn=matchctxt.storage_space_to_paywith|None->assertfalse|Somestorage_space_to_pay->{ctxtwithstorage_space_to_pay=Some(Z.addnstorage_space_to_pay)}letclear_storage_space_to_payctxt=matchctxt.storage_space_to_paywith|None->assertfalse|Somestorage_space_to_pay->{ctxtwithstorage_space_to_pay=None},storage_space_to_paytypestorage_error=|Incompatible_protocol_versionofstring|Missing_keyofstringlist*[`Get|`Set|`Del|`Copy]|Existing_keyofstringlist|Corrupted_dataofstringlistletstorage_error_encoding=letopenData_encodinginunion[case(Tag0)~title:"Incompatible_protocol_version"(obj1(req"incompatible_protocol_version"string))(functionIncompatible_protocol_versionarg->Somearg|_->None)(funarg->Incompatible_protocol_versionarg);case(Tag1)~title:"Missing_key"(obj2(req"missing_key"(liststring))(req"function"(string_enum["get",`Get;"set",`Set;"del",`Del;"copy",`Copy])))(functionMissing_key(key,f)->Some(key,f)|_->None)(fun(key,f)->Missing_key(key,f));case(Tag2)~title:"Existing_key"(obj1(req"existing_key"(liststring)))(functionExisting_keykey->Somekey|_->None)(funkey->Existing_keykey);case(Tag3)~title:"Corrupted_data"(obj1(req"corrupted_data"(liststring)))(functionCorrupted_datakey->Somekey|_->None)(funkey->Corrupted_datakey);]letpp_storage_errorppf=function|Incompatible_protocol_versionversion->Format.fprintfppf"Found a context with an unexpected version '%s'."version|Missing_key(key,`Get)->Format.fprintfppf"Missing key '%s'."(String.concat"/"key)|Missing_key(key,`Set)->Format.fprintfppf"Cannot set undefined key '%s'."(String.concat"/"key)|Missing_key(key,`Del)->Format.fprintfppf"Cannot delete undefined key '%s'."(String.concat"/"key)|Missing_key(key,`Copy)->Format.fprintfppf"Cannot copy undefined key '%s'."(String.concat"/"key)|Existing_keykey->Format.fprintfppf"Cannot initialize defined key '%s'."(String.concat"/"key)|Corrupted_datakey->Format.fprintfppf"Failed to parse the data at '%s'."(String.concat"/"key)typeerror+=Storage_errorofstorage_errorlet()=register_error_kind`Permanent~id:"context.storage_error"~title:"Storage error (fatal internal error)"~description:"An error that should never happen unless something \
has been deleted or corrupted in the database."~pp:(funppferr->Format.fprintfppf"@[<v 2>Storage error:@ %a@]"pp_storage_errorerr)storage_error_encoding(functionStorage_errorerr->Someerr|_->None)(funerr->Storage_errorerr)letstorage_errorerr=fail(Storage_errorerr)(* Initialization *********************************************************)(* This key should always be populated for every version of the
protocol. It's absence meaning that the context is empty. *)letversion_key=["version"]letversion_value="alpha"letversion="v1"letfirst_level_key=[version;"first_level"]letconstants_key=[version;"constants"]letprotocol_param_key=["protocol_parameters"]letget_first_levelctxt=Context.getctxtfirst_level_key>>=function|None->storage_error(Missing_key(first_level_key,`Get))|Somebytes->matchData_encoding.Binary.of_bytesRaw_level_repr.encodingbyteswith|None->storage_error(Corrupted_datafirst_level_key)|Somelevel->returnlevelletset_first_levelctxtlevel=letbytes=Data_encoding.Binary.to_bytes_exnRaw_level_repr.encodinglevelinContext.setctxtfirst_level_keybytes>>=functxt->returnctxttypeerror+=Failed_to_parse_parameterofMBytes.ttypeerror+=Failed_to_decode_parameterofData_encoding.json*stringlet()=register_error_kind`Temporary~id:"context.failed_to_parse_parameter"~title:"Failed to parse parameter"~description:"The protocol parameters are not valid JSON."~pp:beginfunppfbytes->Format.fprintfppf"@[<v 2>Cannot parse the protocol parameter:@ %s@]"(MBytes.to_stringbytes)endData_encoding.(obj1(req"contents"bytes))(functionFailed_to_parse_parameterdata->Somedata|_->None)(fundata->Failed_to_parse_parameterdata);register_error_kind`Temporary~id:"context.failed_to_decode_parameter"~title:"Failed to decode parameter"~description:"Unexpected JSON object."~pp:beginfunppf(json,msg)->Format.fprintfppf"@[<v 2>Cannot decode the protocol parameter:@ %s@ %a@]"msgData_encoding.Json.ppjsonendData_encoding.(obj2(req"contents"json)(req"error"string))(function|Failed_to_decode_parameter(json,msg)->Some(json,msg)|_->None)(fun(json,msg)->Failed_to_decode_parameter(json,msg))letget_proto_paramctxt=Context.getctxtprotocol_param_key>>=function|None->failwith"Missing protocol parameters."|Somebytes->matchData_encoding.Binary.of_bytesData_encoding.jsonbyteswith|None->fail(Failed_to_parse_parameterbytes)|Somejson->beginContext.delctxtprotocol_param_key>>=functxt->matchData_encoding.Json.destructParameters_repr.encodingjsonwith|exception(Data_encoding.Json.Cannot_destruct_asexn)->Format.kasprintffailwith"Invalid protocol_parameters: %a %a"(funppf->Data_encoding.Json.print_errorppf)exnData_encoding.Json.ppjson|param->return(param,ctxt)endletset_constantsctxtconstants=letbytes=Data_encoding.Binary.to_bytes_exnParameters_repr.constants_encodingconstantsinContext.setctxtconstants_keybytesletget_constantsctxt=Context.getctxtconstants_key>>=function|None->failwith"Internal error: cannot read constants in context."|Somebytes->matchData_encoding.Binary.of_bytesParameters_repr.constants_encodingbyteswith|None->failwith"Internal error: cannot parse constants in context."|Someconstants->returnconstantsletpatch_constantsctxtf=letconstants=fctxt.constantsinset_constantsctxt.contextconstants>>=funcontext->Lwt.return{ctxtwithcontext;constants}letcheck_initedctxt=Context.getctxtversion_key>>=function|None->failwith"Internal error: un-initialized context."|Somebytes->lets=MBytes.to_stringbytesinifCompare.String.(s=version_value)thenreturn_unitelsestorage_error(Incompatible_protocol_versions)letprepare~level~timestamp~fitnessctxt=Lwt.return(Raw_level_repr.of_int32level)>>=?funlevel->Lwt.return(Fitness_repr.to_int64fitness)>>=?funfitness->check_initedctxt>>=?fun()->get_constantsctxt>>=?funconstants->get_first_levelctxt>>=?funfirst_level->letlevel=Level_repr.from_raw~first_level~blocks_per_cycle:constants.Constants_repr.blocks_per_cycle~blocks_per_voting_period:constants.Constants_repr.blocks_per_voting_period~blocks_per_commitment:constants.Constants_repr.blocks_per_commitmentlevelinreturn{context=ctxt;constants;level;timestamp;fitness;first_level;allowed_endorsements=Signature.Public_key_hash.Map.empty;fees=Tez_repr.zero;rewards=Tez_repr.zero;deposits=Signature.Public_key_hash.Map.empty;operation_gas=Unaccounted;storage_space_to_pay=None;block_gas=constants.Constants_repr.hard_gas_limit_per_block;origination_nonce=None;internal_nonce=0;internal_nonces_used=Int_set.empty;}letcheck_first_blockctxt=Context.getctxtversion_key>>=function|None->return_unit|Somebytes->lets=MBytes.to_stringbytesinifCompare.String.(s=version_value)thenfailwith"Internal error: previously initialized context."elseifCompare.String.(s="genesis")thenreturn_unitelsestorage_error(Incompatible_protocol_versions)letprepare_first_block~level~timestamp~fitnessctxt=check_first_blockctxt>>=?fun()->Lwt.return(Raw_level_repr.of_int32level)>>=?funfirst_level->get_proto_paramctxt>>=?fun(param,ctxt)->Context.setctxtversion_key(MBytes.of_stringversion_value)>>=functxt->set_first_levelctxtfirst_level>>=?functxt->set_constantsctxtparam.constants>>=functxt->preparectxt~level~timestamp~fitness>>=?functxt->return(param,ctxt)letactivate({context=c;_}ass)h=Updater.activatech>>=func->Lwt.return{swithcontext=c}letfork_test_chain({context=c;_}ass)protocolexpiration=Updater.fork_test_chainc~protocol~expiration>>=func->Lwt.return{swithcontext=c}letregister_resolversencresolve=letresolvecontextstr=letfaked_context={context;constants=Constants_repr.default;first_level=Raw_level_repr.root;level=Level_repr.rootRaw_level_repr.root;timestamp=Time.of_seconds0L;fitness=0L;allowed_endorsements=Signature.Public_key_hash.Map.empty;storage_space_to_pay=None;fees=Tez_repr.zero;rewards=Tez_repr.zero;deposits=Signature.Public_key_hash.Map.empty;block_gas=Constants_repr.default.hard_gas_limit_per_block;operation_gas=Unaccounted;origination_nonce=None;internal_nonce=0;internal_nonces_used=Int_set.empty;}inresolvefaked_contextstrinContext.register_resolverencresolve(* Generic context ********************************************************)typekey=stringlisttypevalue=MBytes.tmoduletypeT=sigtypettypecontext=tvalmem:context->key->boolLwt.tvaldir_mem:context->key->boolLwt.tvalget:context->key->valuetzresultLwt.tvalget_option:context->key->valueoptionLwt.tvalinit:context->key->value->contexttzresultLwt.tvalset:context->key->value->contexttzresultLwt.tvalinit_set:context->key->value->contextLwt.tvalset_option:context->key->valueoption->contextLwt.tvaldelete:context->key->contexttzresultLwt.tvalremove:context->key->contextLwt.tvalremove_rec:context->key->contextLwt.tvalcopy:context->from:key->to_:key->contexttzresultLwt.tvalfold:context->key->init:'a->f:([`Keyofkey|`Dirofkey]->'a->'aLwt.t)->'aLwt.tvalkeys:context->key->keylistLwt.tvalfold_keys:context->key->init:'a->f:(key->'a->'aLwt.t)->'aLwt.tvalproject:context->root_contextvalabsolute_key:context->key->keyvalconsume_gas:context->Gas_limit_repr.cost->contexttzresultvalcheck_enough_gas:context->Gas_limit_repr.cost->unittzresultvaldescription:contextStorage_description.tendletmemctxtk=Context.memctxt.contextkletdir_memctxtk=Context.dir_memctxt.contextkletgetctxtk=Context.getctxt.contextk>>=function|None->storage_error(Missing_key(k,`Get))|Somev->returnvletget_optionctxtk=Context.getctxt.contextk(* Verify that the k is present before modifying *)letsetctxtkv=Context.memctxt.contextk>>=function|false->storage_error(Missing_key(k,`Set))|true->Context.setctxt.contextkv>>=funcontext->return{ctxtwithcontext}(* Verify that the k is not present before inserting *)letinitctxtkv=Context.memctxt.contextk>>=function|true->storage_error(Existing_keyk)|false->Context.setctxt.contextkv>>=funcontext->return{ctxtwithcontext}(* Does not verify that the key is present or not *)letinit_setctxtkv=Context.setctxt.contextkv>>=funcontext->Lwt.return{ctxtwithcontext}(* Verify that the key is present before deleting *)letdeletectxtk=Context.memctxt.contextk>>=function|false->storage_error(Missing_key(k,`Del))|true->Context.delctxt.contextk>>=funcontext->return{ctxtwithcontext}(* Do not verify before deleting *)letremovectxtk=Context.delctxt.contextk>>=funcontext->Lwt.return{ctxtwithcontext}letset_optionctxtk=function|None->removectxtk|Somev->init_setctxtkvletremove_recctxtk=Context.remove_recctxt.contextk>>=funcontext->Lwt.return{ctxtwithcontext}letcopyctxt~from~to_=Context.copyctxt.context~from~to_>>=function|None->storage_error(Missing_key(from,`Copy))|Somecontext->return{ctxtwithcontext}letfoldctxtk~init~f=Context.foldctxt.contextk~init~fletkeysctxtk=Context.keysctxt.contextkletfold_keysctxtk~init~f=Context.fold_keysctxt.contextk~init~fletprojectx=xletabsolute_key_k=kletdescription=Storage_description.create()