123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739(*****************************************************************************)(* *)(* 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. *)(* *)(*****************************************************************************)openMisc.SyntaxmoduleInt_set=Set.Make(Compare.Int)typet={context:Context.t;constants:Constants_repr.parametric;first_level:Raw_level_repr.t;level:Level_repr.t;predecessor_timestamp:Time.t;timestamp:Time.t;fitness:Int64.t;deposits:Tez_repr.tSignature.Public_key_hash.Map.t;included_endorsements:int;allowed_endorsements:(Signature.Public_key.t*intlist*bool)Signature.Public_key_hash.Map.t;fees:Tez_repr.t;rewards:Tez_repr.t;block_gas:Gas_limit_repr.Arith.fp;operation_gas:Gas_limit_repr.t;storage_space_to_pay:Z.toption;allocated_contracts:intoption;origination_nonce:Contract_repr.origination_nonceoption;temporary_big_map:Z.t;internal_nonce:int;internal_nonces_used:Int_set.t;}typecontext=ttyperoot_context=tletcurrent_levelctxt=ctxt.levelletpredecessor_timestampctxt=ctxt.predecessor_timestampletcurrent_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)->{ctxtwithincluded_endorsements=ctxt.included_endorsements+List.lengths;allowed_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 *)elseifSignature.Public_key_hash.Map.is_emptyctxt.allowed_endorsementsthen{ctxtwithallowed_endorsements}elseassertfalse(* can't initialize twice *)letallowed_endorsementsctxt=ctxt.allowed_endorsementsletincluded_endorsementsctxt=ctxt.included_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=Tez_repr.(ctxt.fees+?fees)>|?funfees->{ctxtwithfees}letadd_rewardsctxtrewards=Tez_repr.(ctxt.rewards+?rewards)>|?funrewards->{ctxtwithrewards}letadd_depositctxtdelegatedeposit=letprevious=matchSignature.Public_key_hash.Map.find_optdelegatectxt.depositswith|Sometz->tz|None->Tez_repr.zeroinTez_repr.(previous+?deposit)>|?fundeposit->letdeposits=Signature.Public_key_hash.Map.adddelegatedepositctxt.depositsin{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 attempted 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_limitctxt(remaining:'aGas_limit_repr.Arith.t)=ifGas_limit_repr.Arith.(remaining>ctxt.constants.hard_gas_limit_per_operation||remaining<zero)thenerrorGas_limit_too_highelseok_unitletset_gas_limitctxt(remaining:'aGas_limit_repr.Arith.t)=letremaining=Gas_limit_repr.Arith.fpremainingin{ctxtwithoperation_gas=Limited{remaining}}letset_gas_unlimitedctxt={ctxtwithoperation_gas=Unaccounted}letconsume_gasctxtcost=Gas_limit_repr.raw_consumectxt.block_gasctxt.operation_gascost>>?fun(block_gas,operation_gas)->ok{ctxtwithblock_gas;operation_gas}letcheck_enough_gasctxtcost=Gas_limit_repr.raw_check_enoughctxt.block_gasctxt.operation_gascostletgas_levelctxt=ctxt.operation_gasletblock_gas_levelctxt=ctxt.block_gasletgas_consumed~since~until=match(gas_levelsince,gas_leveluntil)with|(Limited{remaining=before},Limited{remaining=after})->Gas_limit_repr.Arith.subbeforeafter|(_,_)->Gas_limit_repr.Arith.zeroletinit_storage_space_to_payctxt=matchctxt.storage_space_to_paywith|Some_->assertfalse|None->{ctxtwithstorage_space_to_pay=SomeZ.zero;allocated_contracts=Some0;}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)}letupdate_allocated_contracts_countctxt=matchctxt.allocated_contractswith|None->assertfalse|Someallocated_contracts->{ctxtwithallocated_contracts=Some(succallocated_contracts)}letclear_storage_space_to_payctxt=match(ctxt.storage_space_to_pay,ctxt.allocated_contracts)with|(None,_)|(_,None)->assertfalse|(Somestorage_space_to_pay,Someallocated_contracts)->({ctxtwithstorage_space_to_pay=None;allocated_contracts=None},storage_space_to_pay,allocated_contracts)typemissing_key_kind=Get|Set|Del|Copytypestorage_error=|Incompatible_protocol_versionofstring|Missing_keyofstringlist*missing_key_kind|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=error(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="delphi_007"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->oklevel)letset_first_levelctxtlevel=letbytes=Data_encoding.Binary.to_bytes_exnRaw_level_repr.encodinglevelinContext.setctxtfirst_level_keybytes>|=oktypeerror+=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:(funppfbytes->Format.fprintfppf"@[<v 2>Cannot parse the protocol parameter:@ %s@]"(MBytes.to_stringbytes))Data_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:(funppf(json,msg)->Format.fprintfppf"@[<v 2>Cannot decode the protocol parameter:@ %s@ %a@]"msgData_encoding.Json.ppjson)Data_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->(Context.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->ok(param,ctxt)))letset_constantsctxtconstants=letbytes=Data_encoding.Binary.to_bytes_exnConstants_repr.parametric_encodingconstantsinContext.setctxtconstants_keybytesletget_constantsctxt=Context.getctxtconstants_key>|=function|None->failwith"Internal error: cannot read constants in context."|Somebytes->(matchData_encoding.Binary.of_bytesConstants_repr.parametric_encodingbyteswith|None->failwith"Internal error: cannot parse constants in context."|Someconstants->okconstants)letpatch_constantsctxtf=letconstants=fctxt.constantsinset_constantsctxt.contextconstants>|=funcontext->{ctxtwithcontext;constants}letcheck_initedctxt=Context.getctxtversion_key>|=function|None->failwith"Internal error: un-initialized context."|Somebytes->lets=MBytes.to_stringbytesinifCompare.String.(s=version_value)thenok_unitelsestorage_error(Incompatible_protocol_versions)letprepare~level~predecessor_timestamp~timestamp~fitnessctxt=Raw_level_repr.of_int32level>>?=funlevel->Fitness_repr.to_int64fitness>>?=funfitness->check_initedctxt>>=?fun()->get_constantsctxt>>=?funconstants->get_first_levelctxt>|=?funfirst_level->letlevel=Level_repr.level_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_commitmentlevelin{context=ctxt;constants;level;predecessor_timestamp;timestamp;fitness;first_level;allowed_endorsements=Signature.Public_key_hash.Map.empty;included_endorsements=0;fees=Tez_repr.zero;rewards=Tez_repr.zero;deposits=Signature.Public_key_hash.Map.empty;operation_gas=Unaccounted;storage_space_to_pay=None;allocated_contracts=None;block_gas=Gas_limit_repr.Arith.fpconstants.Constants_repr.hard_gas_limit_per_block;origination_nonce=None;temporary_big_map=Z.subZ.zeroZ.one;internal_nonce=0;internal_nonces_used=Int_set.empty;}typeprevious_protocol=GenesisofParameters_repr.t|Carthage_006letcheck_and_update_protocol_versionctxt=Context.getctxtversion_key>>=(function|None->failwith"Internal error: un-initialized context in check_first_block."|Somebytes->lets=MBytes.to_stringbytesinifCompare.String.(s=version_value)thenfailwith"Internal error: previously initialized context."elseifCompare.String.(s="genesis")thenget_proto_paramctxt>|=?fun(param,ctxt)->(Genesisparam,ctxt)elseifCompare.String.(s="carthage_006")thenreturn(Carthage_006,ctxt)elseLwt.return@@storage_error(Incompatible_protocol_versions))>>=?fun(previous_proto,ctxt)->Context.setctxtversion_key(MBytes.of_stringversion_value)>|=functxt->ok(previous_proto,ctxt)letprepare_first_block~level~timestamp~fitnessctxt=check_and_update_protocol_versionctxt>>=?fun(previous_proto,ctxt)->(matchprevious_protowith|Genesisparam->Raw_level_repr.of_int32level>>?=funfirst_level->set_first_levelctxtfirst_level>>=?functxt->set_constantsctxtparam.constants>|=ok|Carthage_006->get_constantsctxt>>=?funconstants->letconstants={constantswithcost_per_byte=Tez_repr.of_mutez_exn250L}inset_constantsctxtconstants>>=functxt->returnctxt)>>=?functxt->preparectxt~level~predecessor_timestamp:timestamp~timestamp~fitness>|=?functxt->(previous_proto,ctxt)letactivate({context=c;_}ass)h=Updater.activatech>|=func->{swithcontext=c}letfork_test_chain({context=c;_}ass)protocolexpiration=Updater.fork_test_chainc~protocol~expiration>|=func->{swithcontext=c}(* 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>|=functionNone->storage_error(Missing_key(k,Get))|Somev->okvletget_optionctxtk=Context.getctxt.contextk(* Verify that the k is present before modifying *)letsetctxtkv=Context.memctxt.contextk>>=function|false->Lwt.return@@storage_error(Missing_key(k,Set))|true->Context.setctxt.contextkv>|=funcontext->ok{ctxtwithcontext}(* Verify that the k is not present before inserting *)letinitctxtkv=Context.memctxt.contextk>>=function|true->Lwt.return@@storage_error(Existing_keyk)|false->Context.setctxt.contextkv>|=funcontext->ok{ctxtwithcontext}(* Does not verify that the key is present or not *)letinit_setctxtkv=Context.setctxt.contextkv>|=funcontext->{ctxtwithcontext}(* Verify that the key is present before deleting *)letdeletectxtk=Context.memctxt.contextk>>=function|false->Lwt.return@@storage_error(Missing_key(k,Del))|true->Context.delctxt.contextk>|=funcontext->ok{ctxtwithcontext}(* Do not verify before deleting *)letremovectxtk=Context.delctxt.contextk>|=funcontext->{ctxtwithcontext}letset_optionctxtk=function|None->removectxtk|Somev->init_setctxtkvletremove_recctxtk=Context.remove_recctxt.contextk>|=funcontext->{ctxtwithcontext}letcopyctxt~from~to_=Context.copyctxt.context~from~to_>|=function|None->storage_error(Missing_key(from,Copy))|Somecontext->ok{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()letfresh_temporary_big_mapctxt=({ctxtwithtemporary_big_map=Z.subctxt.temporary_big_mapZ.one},ctxt.temporary_big_map)letreset_temporary_big_mapctxt={ctxtwithtemporary_big_map=Z.subZ.zeroZ.one}lettemporary_big_mapsctxtfacc=letreciteraccid=ifZ.equalidctxt.temporary_big_mapthenLwt.returnaccelsefaccid>>=funacc->iteracc(Z.subidZ.one)initeracc(Z.subZ.zeroZ.one)