1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549(*****************************************************************************)(* *)(* Open Source License *)(* 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. *)(* *)(*****************************************************************************)openSc_rollup_reprmodulePS=Sc_rollup_PVM_sig(*
This is the state hash of reference that both the prover of the node
and the verifier of the protocol {!Protocol_implementation} have to
agree on (if they do, it means they are using the same tree
structure).
We have to hard-code this value because the Arith PVM uses Irmin as
its Merkle proof verification backend, and the economic protocol
cannot create an empty Irmin context. Such a context is required to
create an empty tree, itself required to create the initial state of
the Arith PVM.
Utlimately, the value of this constant is decided by the prover of
reference (the only need is for it to be compatible with
{!Protocol_implementation}.)
Its value is the result of the following snippet
{|
let*! state = Prover.initial_state ~empty in
Prover.state_hash state
|}
*)letreference_initial_state_hash=State_hash.of_b58check_exn"srs11Z9V76SGd97kGmDQXV8tEF67C48GMy77RuaHdF1kWLk6UTmMfj"typeerror+=|Arith_proof_production_failed|Arith_output_proof_production_failed|Arith_invalid_claim_about_outboxlet()=letopenData_encodinginletmsg="Invalid claim about outbox"inregister_error_kind`Permanent~id:"smart_rollup_arith_invalid_claim_about_outbox"~title:msg~pp:(funfmt()->Format.pp_print_stringfmtmsg)~description:msgunit(functionArith_invalid_claim_about_outbox->Some()|_->None)(fun()->Arith_invalid_claim_about_outbox);letmsg="Output proof production failed"inregister_error_kind`Permanent~id:"smart_rollup_arith_output_proof_production_failed"~title:msg~pp:(funfmt()->Format.fprintffmt"%s"msg)~description:msgunit(functionArith_output_proof_production_failed->Some()|_->None)(fun()->Arith_output_proof_production_failed);letmsg="Proof production failed"inregister_error_kind`Permanent~id:"smart_rollup_arith_proof_production_failed"~title:msg~pp:(funfmt()->Format.fprintffmt"%s"msg)~description:msgunit(functionArith_proof_production_failed->Some()|_->None)(fun()->Arith_proof_production_failed)moduletypeP=sigmoduleTree:Context.TREEwithtypekey=stringlistandtypevalue=bytestypetree=Tree.treevalhash_tree:tree->State_hash.ttypeproofvalproof_encoding:proofData_encoding.tvalproof_before:proof->State_hash.tvalproof_after:proof->State_hash.tvalverify_proof:proof->(tree->(tree*'a)Lwt.t)->(tree*'a)optionLwt.tvalproduce_proof:Tree.t->tree->(tree->(tree*'a)Lwt.t)->(proof*'a)optionLwt.tendmoduletypeS=sigincludePS.Svalparse_boot_sector:string->stringoptionvalpp_boot_sector:Format.formatter->string->unitvalpp:state->(Format.formatter->unit->unit)Lwt.tvalget_tick:state->Sc_rollup_tick_repr.tLwt.ttypestatus=|Halted|Waiting_for_input_message|Waiting_for_reveal|Waiting_for_metadata|Parsing|Evaluatingvalget_status:state->statusLwt.tvalget_outbox:Raw_level_repr.t->state->Sc_rollup_PVM_sig.outputlistLwt.ttypeinstruction=|IPush:int->instruction|IAdd:instruction|IStore:string->instructionvalequal_instruction:instruction->instruction->boolvalpp_instruction:Format.formatter->instruction->unitvalget_parsing_result:state->booloptionLwt.tvalget_code:state->instructionlistLwt.tvalget_stack:state->intlistLwt.tvalget_var:state->string->intoptionLwt.tvalget_evaluation_result:state->booloptionLwt.tvalget_is_stuck:state->stringoptionLwt.tendmoduleMake(Context:P):Swithtypecontext=Context.Tree.tandtypestate=Context.treeandtypeproof=Context.proof=structmoduleTree=Context.Treetypecontext=Context.Tree.ttypehash=State_hash.ttypeproof=Context.proofletproof_encoding=Context.proof_encodingletproof_start_stateproof=Context.proof_beforeproofletproof_stop_stateproof=Context.proof_afterproofletparse_boot_sectors=Somesletpp_boot_sectorfmts=Format.fprintffmt"%s"stypetree=Tree.treetypestatus=|Halted|Waiting_for_input_message|Waiting_for_reveal|Waiting_for_metadata|Parsing|Evaluatingtypeinstruction=|IPush:int->instruction|IAdd:instruction|IStore:string->instructionletequal_instructioni1i2=match(i1,i2)with|IPushx,IPushy->Compare.Int.(x=y)|IAdd,IAdd->true|IStorex,IStorey->Compare.String.(x=y)|_,_->falseletpp_instructionfmt=function|IPushx->Format.fprintffmt"push(%d)"x|IAdd->Format.fprintffmt"add"|IStorex->Format.fprintffmt"store(%s)"xletcheck_dissection~default_number_of_sections~start_chunk~stop_chunk=letopenSc_rollup_dissection_chunk_reprinletdist=Sc_rollup_tick_repr.distancestart_chunk.tickstop_chunk.tickinletsection_maximum_size=Z.divdist(Z.of_int2)inSc_rollup_dissection_chunk_repr.(default_check~section_maximum_size~check_sections_number:default_check_sections_number~default_number_of_sections~start_chunk~stop_chunk)(*
The machine state is represented using a Merkle tree.
Here is the data model of this state represented in the tree:
- tick : Sc_rollup_tick_repr.t
The current tick counter of the machine.
- status : status
The current status of the machine.
- stack : int deque
The stack of integers.
- next_message : string option
The current input message to be processed.
- code : instruction deque
The instructions parsed from the input message.
- lexer_state : int * int
The internal state of the lexer.
- parsing_state : parsing_state
The internal state of the parser.
- parsing_result : bool option
The outcome of parsing.
- evaluation_result : bool option
The outcome of evaluation.
*)moduleState=structtypestate=treemoduleMonad:sigtype'atvalrun:'at->state->(state*'aoption)Lwt.tvalis_stuck:stringoptiontvalinternal_error:string->'atvalreturn:'a->'atmoduleSyntax:sigval(let*):'at->('a->'bt)->'btendvalremove:Tree.key->unittvalfind_value:Tree.key->'aData_encoding.t->'aoptiontvalchildren:Tree.key->'aData_encoding.t->(string*'a)listtvalget_value:default:'a->Tree.key->'aData_encoding.t->'atvalset_value:Tree.key->'aData_encoding.t->'a->unittend=structtype'at=state->(state*'aoption)Lwt.tletreturnxstate=Lwt.return(state,Somex)letbindmfstate=letopenLwt_syntaxinlet*state,res=mstateinmatchreswithNone->return(state,None)|Someres->fresstatemoduleSyntax=structlet(let*)=bindendletrunmstate=mstateletinternal_error_key=["internal_error"]letinternal_errormsgtree=letopenLwt_syntaxinlet*tree=Tree.addtreeinternal_error_key(Bytes.of_stringmsg)inreturn(tree,None)letis_stucktree=letopenLwt_syntaxinlet*v=Tree.findtreeinternal_error_keyinreturn(tree,Some(Option.mapBytes.to_stringv))letremovekeytree=letopenLwt_syntaxinlet*tree=Tree.removetreekeyinreturn(tree,Some())letdecodeencodingbytesstate=letopenLwt_syntaxinmatchData_encoding.Binary.of_bytes_optencodingbyteswith|None->internal_error"Error during decoding"state|Somev->return(state,Somev)letfind_valuekeyencodingstate=letopenLwt_syntaxinlet*obytes=Tree.findstatekeyinmatchobyteswith|None->return(state,SomeNone)|Somebytes->let*state,value=decodeencodingbytesstateinreturn(state,Somevalue)letchildrenkeyencodingstate=letopenLwt_syntaxinlet*children=Tree.liststatekeyinletrecaux=function|[]->return(state,Some[])|(key,tree)::children->(let*obytes=Tree.to_valuetreeinmatchobyteswith|None->internal_error"Invalid children"state|Somebytes->(let*state,v=decodeencodingbytesstateinmatchvwith|None->return(state,None)|Somev->(let*state,l=auxchildreninmatchlwith|None->return(state,None)|Somel->return(state,Some((key,v)::l)))))inauxchildrenletget_value~defaultkeyencoding=letopenSyntaxinlet*ov=find_valuekeyencodinginmatchovwithNone->returndefault|Somex->returnxletset_valuekeyencodingvaluetree=letopenLwt_syntaxinData_encoding.Binary.to_bytes_optencodingvalue|>function|None->internal_error"Internal_Error during encoding"tree|Somebytes->let*tree=Tree.addtreekeybytesinreturn(tree,Some())endopenMonadmoduleMake_var(P:sigtypetvalname:stringvalinitial:tvalpp:Format.formatter->t->unitvalencoding:tData_encoding.tend)=structletkey=[P.name]letcreate=set_valuekeyP.encodingP.initialletget=letopenMonad.Syntaxinlet*v=find_valuekeyP.encodinginmatchvwith|None->(* This case should not happen if [create] is properly called. *)returnP.initial|Somev->returnvletset=set_valuekeyP.encodingletpp=letopenMonad.Syntaxinlet*v=getinreturn@@funfmt()->Format.fprintffmt"@[%s : %a@]"P.nameP.ppvendmoduleMake_dict(P:sigtypetvalname:stringvalpp:Format.formatter->t->unitvalencoding:tData_encoding.tend)=structletkeyk=[P.name;k]letgetk=find_value(keyk)P.encodingletsetkv=set_value(keyk)P.encodingvletentries=children[P.name]P.encodingletmapped_tokvstate=letopenLwt_syntaxinlet*state',_=Monad.(run(setkv)state)inlet*t=Tree.find_treestate(keyk)and*t'=Tree.find_treestate'(keyk)inLwt.return(Option.equalTree.equaltt')letpp=letopenMonad.Syntaxinlet*l=entriesinletpp_elemfmt(key,value)=Format.fprintffmt"@[%s : %a@]"keyP.ppvalueinreturn@@funfmt()->Format.pp_print_listpp_elemfmtlendmoduleMake_deque(P:sigtypetvalname:stringvalencoding:tData_encoding.tend)=struct(*
A stateful deque.
[[head; end[] is the index range for the elements of the deque.
The length of the deque is therefore [end - head].
*)lethead_key=[P.name;"head"]letend_key=[P.name;"end"]letget_head=get_value~default:Z.zerohead_keyData_encoding.zletset_head=set_valuehead_keyData_encoding.zletget_end=get_value~default:(Z.of_int0)end_keyData_encoding.zletset_end=set_valueend_keyData_encoding.zletidx_keyidx=[P.name;Z.to_stringidx]lettop=letopenMonad.Syntaxinlet*head_idx=get_headinlet*end_idx=get_endinlet*v=find_value(idx_keyhead_idx)P.encodinginifZ.(leqend_idxhead_idx)thenreturnNoneelsematchvwith|None->(* By invariants of the Deque. *)assertfalse|Somex->return(Somex)letpushx=letopenMonad.Syntaxinlet*head_idx=get_headinlethead_idx'=Z.predhead_idxinlet*()=set_headhead_idx'inset_value(idx_keyhead_idx')P.encodingxletpop=letopenMonad.Syntaxinlet*head_idx=get_headinlet*end_idx=get_endinifZ.(leqend_idxhead_idx)thenreturnNoneelselet*v=find_value(idx_keyhead_idx)P.encodinginmatchvwith|None->(* By invariants of the Deque. *)assertfalse|Somex->let*()=remove(idx_keyhead_idx)inlethead_idx=Z.succhead_idxinlet*()=set_headhead_idxinreturn(Somex)letinjectx=letopenMonad.Syntaxinlet*end_idx=get_endinletend_idx'=Z.succend_idxinlet*()=set_endend_idx'inset_value(idx_keyend_idx)P.encodingxletto_list=letopenMonad.Syntaxinlet*head_idx=get_headinlet*end_idx=get_endinletrecauxlidx=ifZ.(ltidxhead_idx)thenreturnlelselet*v=find_value(idx_keyidx)P.encodinginmatchvwith|None->(* By invariants of deque *)assertfalse|Somev->aux(v::l)(Z.predidx)inaux[](Z.predend_idx)letclear=remove[P.name]endmoduleCurrent_tick=Make_var(structincludeSc_rollup_tick_reprletname="tick"end)moduleVars=Make_dict(structtypet=intletname="vars"letencoding=Data_encoding.int31letppfmtx=Format.fprintffmt"%d"xend)moduleStack=Make_deque(structtypet=intletname="stack"letencoding=Data_encoding.int31end)moduleCode=Make_deque(structtypet=instructionletname="code"letencoding=Data_encoding.(union[case~title:"push"(Tag0)Data_encoding.int31(functionIPushx->Somex|_->None)(funx->IPushx);case~title:"add"(Tag1)Data_encoding.unit(functionIAdd->Some()|_->None)(fun()->IAdd);case~title:"store"(Tag2)Data_encoding.(stringPlain)(functionIStorex->Somex|_->None)(funx->IStorex);])end)moduleBoot_sector=Make_var(structtypet=stringletname="boot_sector"letinitial=""letencoding=Data_encoding.(stringPlain)letppfmts=Format.fprintffmt"%s"send)moduleStatus=Make_var(structtypet=statusletinitial=Haltedletencoding=Data_encoding.string_enum[("Halted",Halted);("Waiting_for_input_message",Waiting_for_input_message);("Waiting_for_reveal",Waiting_for_reveal);("Waiting_for_metadata",Waiting_for_metadata);("Parsing",Parsing);("Evaluating",Evaluating);]letname="status"letstring_of_status=function|Halted->"Halted"|Waiting_for_input_message->"Waiting for input message"|Waiting_for_reveal->"Waiting for reveal"|Waiting_for_metadata->"Waiting for metadata"|Parsing->"Parsing"|Evaluating->"Evaluating"letppfmtstatus=Format.fprintffmt"%s"(string_of_statusstatus)end)moduleRequired_reveal=Make_var(structtypet=PS.revealoptionletinitial=Noneletencoding=Data_encoding.optionPS.reveal_encodingletname="required_reveal"letppfmtv=matchvwith|None->Format.fprintffmt"<none>"|Someh->PS.pp_revealfmthend)moduleMetadata=Make_var(structtypet=Sc_rollup_metadata_repr.toptionletinitial=Noneletencoding=Data_encoding.optionSc_rollup_metadata_repr.encodingletname="metadata"letppfmtv=matchvwith|None->Format.fprintffmt"<none>"|Somev->Sc_rollup_metadata_repr.ppfmtvend)moduleCurrent_level=Make_var(structtypet=Raw_level_repr.tletinitial=Raw_level_repr.rootletencoding=Raw_level_repr.encodingletname="current_level"letpp=Raw_level_repr.ppend)moduleMessage_counter=Make_var(structtypet=Z.toptionletinitial=Noneletencoding=Data_encoding.optionData_encoding.nletname="message_counter"letppfmt=function|None->Format.fprintffmt"None"|Somec->Format.fprintffmt"Some %a"Z.pp_printcend)(** Store an internal message counter. This is used to distinguish
an unparsable external message and a internal message, which we both
treat as no-ops. *)moduleInternal_message_counter=Make_var(structtypet=Z.tletinitial=Z.zeroletencoding=Data_encoding.nletname="internal_message_counter"letppfmtc=Z.pp_printfmtcend)letincr_internal_message_counter=letopenMonad.Syntaxinlet*current_counter=Internal_message_counter.getinInternal_message_counter.set(Z.succcurrent_counter)moduleNext_message=Make_var(structtypet=stringoptionletinitial=Noneletencoding=Data_encoding.(option(stringPlain))letname="next_message"letppfmt=function|None->Format.fprintffmt"None"|Somes->Format.fprintffmt"Some %s"send)typeparser_state=ParseInt|ParseVar|SkipLayoutmoduleLexer_state=Make_var(structtypet=int*intletname="lexer_buffer"letinitial=(-1,-1)letencoding=Data_encoding.(tup2int31int31)letppfmt(start,len)=Format.fprintffmt"lexer.(start = %d, len = %d)"startlenend)moduleParser_state=Make_var(structtypet=parser_stateletname="parser_state"letinitial=SkipLayoutletencoding=Data_encoding.string_enum[("ParseInt",ParseInt);("ParseVar",ParseVar);("SkipLayout",SkipLayout);]letppfmt=function|ParseInt->Format.fprintffmt"Parsing int"|ParseVar->Format.fprintffmt"Parsing var"|SkipLayout->Format.fprintffmt"Skipping layout"end)moduleParsing_result=Make_var(structtypet=booloptionletname="parsing_result"letinitial=Noneletencoding=Data_encoding.(optionbool)letppfmt=function|None->Format.fprintffmt"n/a"|Sometrue->Format.fprintffmt"parsing succeeds"|Somefalse->Format.fprintffmt"parsing fails"end)moduleEvaluation_result=Make_var(structtypet=booloptionletname="evaluation_result"letinitial=Noneletencoding=Data_encoding.(optionbool)letppfmt=function|None->Format.fprintffmt"n/a"|Sometrue->Format.fprintffmt"evaluation succeeds"|Somefalse->Format.fprintffmt"evaluation fails"end)moduleOutput_counter=Make_var(structtypet=Z.tletinitial=Z.zeroletname="output_counter"letencoding=Data_encoding.nletpp=Z.pp_printend)moduleOutput=Make_dict(structtypet=Sc_rollup_PVM_sig.outputletname="output"letencoding=Sc_rollup_PVM_sig.output_encodingletpp=Sc_rollup_PVM_sig.pp_outputend)letpp=letopenMonad.Syntaxinlet*status_pp=Status.ppinlet*message_counter_pp=Message_counter.ppinlet*next_message_pp=Next_message.ppinlet*parsing_result_pp=Parsing_result.ppinlet*parser_state_pp=Parser_state.ppinlet*lexer_state_pp=Lexer_state.ppinlet*evaluation_result_pp=Evaluation_result.ppinlet*vars_pp=Vars.ppinlet*output_pp=Output.ppinlet*stack=Stack.to_listinlet*current_tick_pp=Current_tick.ppinreturn@@funfmt()->Format.fprintffmt"@[<v 0 >@;\
%a@;\
%a@;\
%a@;\
%a@;\
%a@;\
%a@;\
%a@;\
tick : %a@;\
vars : %a@;\
output :%a@;\
stack : %a@;\
@]"status_pp()message_counter_pp()next_message_pp()parsing_result_pp()parser_state_pp()lexer_state_pp()evaluation_result_pp()current_tick_pp()vars_pp()output_pp()Format.(pp_print_listpp_print_int)stackendopenStatetypestate=State.stateopenMonadletinitial_state~empty=letm=letopenMonad.Syntaxinlet*()=Status.setHaltedinreturn()inletopenLwt_syntaxinlet*state,_=runmemptyinreturnstateletinstall_boot_sectorstateboot_sector=letm=letopenMonad.Syntaxinlet*()=Boot_sector.setboot_sectorinreturn()inletopenLwt_syntaxinlet*state,_=runmstateinreturnstateletstate_hashstate=letcontext_hash=Tree.hashstateinLwt.return@@State_hash.context_hash_to_state_hashcontext_hashletppstate=letopenLwt_syntaxinlet*_,pp=Monad.runppstateinmatchppwith|None->return@@funfmt_->Format.fprintffmt"<opaque>"|Somepp->let*state_hash=state_hashstateinreturn(funfmt()->Format.fprintffmt"@[%a: %a@]"State_hash.ppstate_hashpp())letboot=letopenMonad.Syntaxinlet*()=Status.createinlet*()=Next_message.createinlet*()=Status.setWaiting_for_metadatainreturn()letresult_of~defaultmstate=letopenLwt_syntaxinlet*_,v=runmstateinmatchvwithNone->returndefault|Somev->returnvletstate_ofmstate=letopenLwt_syntaxinlet*s,_=runmstateinreturnsletget_tick=result_of~default:Sc_rollup_tick_repr.initialCurrent_tick.getletis_input_state_monadic=letopenMonad.Syntaxinlet*status=Status.getinmatchstatuswith|Waiting_for_input_message->(let*level=Current_level.getinlet*counter=Message_counter.getinmatchcounterwith|Somen->return(PS.First_after(level,n))|None->returnPS.Initial)|Waiting_for_reveal->(let*r=Required_reveal.getinmatchrwith|None->internal_error"Internal error: Reveal invariant broken"|Somereveal->return(PS.Needs_revealreveal))|Waiting_for_metadata->returnPS.(Needs_revealReveal_metadata)|Halted|Parsing|Evaluating->returnPS.No_input_requiredletis_input_state=result_of~default:PS.No_input_required@@is_input_state_monadicletget_status=result_of~default:Waiting_for_input_message@@Status.getletget_outboxoutbox_levelstate=letopenLwt_syntaxinlet+entries=result_of~default:[]Output.entriesstateinList.filter_map(fun(_,msg)->ifRaw_level_repr.(msg.PS.outbox_level=outbox_level)thenSomemsgelseNone)entriesletget_code=result_of~default:[]@@Code.to_listletget_parsing_result=result_of~default:None@@Parsing_result.getletget_stack=result_of~default:[]@@Stack.to_listletget_varstatek=(result_of~default:None@@Vars.getk)stateletget_evaluation_result=result_of~default:None@@Evaluation_result.getletget_is_stuck=result_of~default:None@@is_stuckletstart_parsing:unitt=letopenMonad.Syntaxinlet*()=Status.setParsinginlet*()=Parsing_result.setNoneinlet*()=Parser_state.setSkipLayoutinlet*()=Lexer_state.set(0,0)inlet*()=Code.clearinreturn()letset_inbox_message_monadic{PS.inbox_level;message_counter;payload}=letopenMonad.Syntaxinlet*payload=matchSc_rollup_inbox_message_repr.deserializepayloadwith|Error_->returnNone|Ok(Externalpayload)->return(Somepayload)|Ok(Internal(Transfer{payload;destination;_}))->(let*()=incr_internal_message_counterinlet*(metadata:Sc_rollup_metadata_repr.toption)=Metadata.getinmatchmetadatawith|Some{address;_}whenAddress.(destination=address)->(matchMicheline.rootpayloadwith|Bytes(_,payload)->letpayload=Bytes.to_stringpayloadinreturn(Somepayload)|_->returnNone)|_->returnNone)|Ok(InternalStart_of_level)->let*()=incr_internal_message_counterinreturnNone|Ok(InternalEnd_of_level)->let*()=incr_internal_message_counterinreturnNone|Ok(Internal(Info_per_level_))->let*()=incr_internal_message_counterinreturnNoneinmatchpayloadwith|Somepayload->let*boot_sector=Boot_sector.getinletmsg=boot_sector^payloadinlet*()=Current_level.setinbox_levelinlet*()=Message_counter.set(Somemessage_counter)inlet*()=Next_message.set(Somemsg)inlet*()=start_parsinginreturn()|None->let*()=Current_level.setinbox_levelinlet*()=Message_counter.set(Somemessage_counter)inlet*()=Status.setWaiting_for_input_messageinreturn()letreveal_monadicreveal_data=(*
The inbox cursor is unchanged as the message comes from the
outer world.
We don't have to check that the data is the one we
expected as we decided to trust the initial witness.
It is the responsibility of the rollup node to check the validity
of the [reveal_data] if it does not want to publish a wrong commitment.
*)letopenMonad.Syntaxinmatchreveal_datawith|PS.Raw_datadata->(* Notice that a multi-page transmission is possible by embedding
a continuation encoded as an optional hash in [data]. *)let*()=Next_message.set(Somedata)inlet*()=start_parsinginreturn()|PS.Metadatametadata->let*()=Metadata.set(Somemetadata)inlet*()=Status.setWaiting_for_input_messageinreturn()|PS.Dal_pageNone->(* FIXME/DAL: https://gitlab.com/tezos/tezos/-/issues/3995
Below, we set the status to [Waiting_for_input_message] because the
inbox is the only source of automatically fetched data.
Once the issue above is handled (auto-fetch of Dal pages with EOL/SOL),
the implementation should be adapted. *)let*()=Status.setWaiting_for_input_messageinreturn()|PS.Dal_page(Somedata)->let*()=Next_message.set(Some(Bytes.to_stringdata))inlet*()=start_parsinginreturn()lettickedm=letopenMonad.Syntaxinlet*tick=Current_tick.getinlet*()=Current_tick.set(Sc_rollup_tick_repr.nexttick)inmletset_input_monadicinput=matchinputwith|PS.Inbox_messagem->set_inbox_message_monadicm|PS.Reveals->reveal_monadicsletset_inputinput=set_input_monadicinput|>ticked|>state_ofletnext_char=letopenMonad.SyntaxinLexer_state.(let*start,len=getinset(start,len+1))letno_message_to_lex()=internal_error"lexer: There is no input message to lex"letcurrent_char=letopenMonad.Syntaxinlet*start,len=Lexer_state.getinlet*msg=Next_message.getinmatchmsgwith|None->no_message_to_lex()|Somes->ifCompare.Int.(start+len<String.lengths)thenreturn(Somes.[start+len])elsereturnNoneletlexeme=letopenMonad.Syntaxinlet*start,len=Lexer_state.getinlet*msg=Next_message.getinmatchmsgwith|None->no_message_to_lex()|Somes->let*()=Lexer_state.set(start+len,0)inreturn(String.subsstartlen)letpush_int_literal=letopenMonad.Syntaxinlet*s=lexemeinmatchint_of_string_optswith|Somex->Code.inject(IPushx)|None->(* By validity of int parsing. *)assertfalseletpush_var=letopenMonad.Syntaxinlet*s=lexemeinCode.inject(IStores)letstart_evaluating:unitt=letopenMonad.Syntaxinlet*()=Status.setEvaluatinginlet*()=Evaluation_result.setNoneinreturn()letstop_parsingoutcome=letopenMonad.Syntaxinlet*()=Parsing_result.set(Someoutcome)instart_evaluatingletstop_evaluatingoutcome=letopenMonad.Syntaxinlet*()=Evaluation_result.set(Someoutcome)inStatus.setWaiting_for_input_messageletparse:unitt=letopenMonad.Syntaxinletproduce_add=let*(_:string)=lexemeinlet*()=next_charinlet*()=Code.injectIAddinreturn()inletproduce_int=let*()=push_int_literalinlet*()=Parser_state.setSkipLayoutinreturn()inletproduce_var=let*()=push_varinlet*()=Parser_state.setSkipLayoutinreturn()inletis_digitd=Compare.Char.(d>='0'&&d<='9')inletis_letterd=Compare.Char.((d>='a'&&d<='z')||(d>='A'&&d<='Z'))inletis_identifier_chard=is_letterd||is_digitd||Compare.Char.(d=':')||Compare.Char.(d='%')inlet*parser_state=Parser_state.getinmatchparser_statewith|ParseInt->(let*char=current_charinmatchcharwith|Somedwhenis_digitd->next_char|Some'+'->let*()=produce_intinlet*()=produce_addinreturn()|Some(' '|'\n')->let*()=produce_intinlet*()=next_charinreturn()|None->let*()=push_int_literalinstop_parsingtrue|_->stop_parsingfalse)|ParseVar->(let*char=current_charinmatchcharwith|Somedwhenis_identifier_chard->next_char|Some'+'->let*()=produce_varinlet*()=produce_addinreturn()|Some(' '|'\n')->let*()=produce_varinlet*()=next_charinreturn()|None->let*()=push_varinstop_parsingtrue|_->stop_parsingfalse)|SkipLayout->(let*char=current_charinmatchcharwith|Some(' '|'\n')->next_char|Some'+'->produce_add|Somedwhenis_digitd->let*(_:string)=lexemeinlet*()=next_charinlet*()=Parser_state.setParseIntinreturn()|Somedwhenis_letterd->let*(_:string)=lexemeinlet*()=next_charinlet*()=Parser_state.setParseVarinreturn()|None->stop_parsingtrue|_->stop_parsingfalse)letoutput(destination,entrypoint)v=letopenMonad.SyntaxinletopenSc_rollup_outbox_message_reprinlet*counter=Output_counter.getinlet*()=Output_counter.set(Z.succcounter)inletunparsed_parameters=Micheline.(Int((),Z.of_intv)|>strip_locations)inlettransaction={unparsed_parameters;destination;entrypoint}inletmessage=Atomic_transaction_batch{transactions=[transaction]}inlet*outbox_level=Current_level.getinletoutput=Sc_rollup_PVM_sig.{outbox_level;message_index=counter;message}inOutput.set(Z.to_stringcounter)outputletidentifies_target_contractx=letopenOption_syntaxinmatchString.split_on_char'%'xwith|destination::entrypoint->(matchContract_hash.of_b58check_optdestinationwith|None->ifCompare.String.(x="out")thenreturn(Contract_hash.zero,Entrypoint_repr.default)elsefail|Somedestination->let*entrypoint=matchentrypointwith|[]->returnEntrypoint_repr.default|_->let*entrypoint=Non_empty_string.of_string(String.concat""entrypoint)inlet*entrypoint=Entrypoint_repr.of_annot_lax_optentrypointinreturnentrypointinreturn(destination,entrypoint))|[]->failletevaluate_preimage_requesthash=letopenMonad.SyntaxinmatchSc_rollup_reveal_hash.of_b58check_opthashwith|None->stop_evaluatingfalse|Somehash->let*()=Required_reveal.set(Some(Reveal_raw_datahash))inlet*()=Status.setWaiting_for_revealinreturn()letevaluate_dal_page_request=(* FIXME/DAL: https://gitlab.com/tezos/tezos/-/issues/3997
- We should rather provide DAL parameters to PVM via metadata (and handle
the case where parameters are updated on L1).
- It's better to use EOL/SOL to request DAL pages once unique inbox MR
is merged. *)(* The parameters below are those of mainnet in protocol constants, divided
by 16. *)letattestation_lag=1linletpage_size=4096/64inletslot_size=(1lsl20)/64inletnumber_of_slots=256/64inletnumber_of_pages=slot_size/page_sizeinletmk_slot_indexslot_str=letopenOption_syntaxinlet*index=Option.mapInt32.to_int@@Int32.of_string_optslot_strinifCompare.Int.(index<0||index>=number_of_slots)thenNoneelseDal_slot_repr.Index.of_intindexinletmk_page_indexpage_str=letopenOption_syntaxinlet*index=Option.mapInt32.to_int@@Int32.of_string_optpage_strinifCompare.Int.(index<0||index>=number_of_pages)thenNoneelseSomeindexinfunraw_page_id->letmk_page_idcurrent_lvl=(* Dal pages import directive is [dal:<LVL>:<SID>:<PID>]. See mli file.*)letopenOption_syntaxinmatchString.split_on_char':'raw_page_idwith|[lvl;slot;page]->let*lvl=Int32.of_string_optlvlinlet*lvl=Bounded.Non_negative_int32.of_valuelvlinletpublished_level=Raw_level_repr.of_int32_non_negativelvlinletdelta=Raw_level_repr.diffcurrent_lvlpublished_levelin(* FIXME/DAL: https://gitlab.com/tezos/tezos/-/issues/3995
Putting delta > 0l doesn't work here because of the way the node
currently fetches blocks' data and calls the PVM.
This will be changed, in particular once EOL is used to fetch DAL
data.
More generally, the whole condition below will be reworked. *)ifCompare.Int32.(delta>1l&&delta<=Int32.mul2lattestation_lag)thenlet*index=mk_slot_indexslotinlet*page_index=mk_page_indexpageinletslot_id=Dal_slot_repr.Header.{published_level;index}inSomeDal_slot_repr.Page.{slot_id;page_index}elseNone|_->NoneinletopenMonad.Syntaxinlet*current_lvl=Current_level.getinmatchmk_page_idcurrent_lvlwith|Somepage_id->let*()=Required_reveal.set(Some(Request_dal_pagepage_id))inlet*()=Status.setWaiting_for_revealinreturn()|None->stop_evaluatingfalseletremove_prefixprefixinputinput_len=letprefix_len=String.lengthprefixinifCompare.Int.(input_len>prefix_len)&&String.(equal(subinput0prefix_len)prefix)thenSome(String.subinputprefix_len(input_len-prefix_len))elseNoneletevaluate=letopenMonad.Syntaxinlet*i=Code.popinmatchiwith|None->stop_evaluatingtrue|Some(IPushx)->Stack.pushx|Some(IStorex)->((* When evaluating an instruction [IStore x], we start by checking if [x]
is a reserved directive:
- "hash:<HASH>", to import a DAC data;
- "dal:<LVL>:<SID>:<PID>", to request a Dal page;
- "out" or "<DESTINATION>%<ENTRYPOINT>", to add a message in the outbox.
Otherwise, the instruction is interpreted as a directive to store the
top of the PVM's stack into the variable [x].
*)letlen=String.lengthxinmatchremove_prefix"hash:"xlenwith|Somehash->evaluate_preimage_requesthash|None->(matchremove_prefix"dal:"xlenwith|Somepid->evaluate_dal_page_requestpid|None->(let*v=Stack.topinmatchvwith|None->stop_evaluatingfalse|Somev->(matchidentifies_target_contractxwith|Somecontract_entrypoint->outputcontract_entrypointv|None->Vars.setxv))))|SomeIAdd->(let*v=Stack.popinmatchvwith|None->stop_evaluatingfalse|Somex->(let*v=Stack.popinmatchvwith|None->stop_evaluatingfalse|Somey->Stack.push(x+y)))letreboot=letopenMonad.Syntaxinlet*()=Status.setWaiting_for_input_messageinlet*()=Stack.clearinlet*()=Code.clearinreturn()leteval_step=letopenMonad.Syntaxinlet*x=is_stuckinmatchxwith|Some_->reboot|None->(let*status=Status.getinmatchstatuswith|Halted->boot|Waiting_for_input_message|Waiting_for_reveal|Waiting_for_metadata->(let*msg=Next_message.getinmatchmsgwith|None->internal_error"An input state was not provided an input."|Some_->start_parsing)|Parsing->parse|Evaluating->evaluate)letevalstate=state_of(tickedeval_step)stateletstep_transitioninput_givenstate=letopenLwt_syntaxinlet*request=is_input_statestateinleterrormsg=state_of(internal_errormsg)stateinlet*state=match(request,input_given)with|PS.No_input_required,None->evalstate|PS.No_input_required,Some_->error"Invalid set_input: expecting no input message but got one."|(PS.Initial|PS.First_after_),Some(PS.Inbox_message_asinput)|(PS.Needs_reveal(Reveal_raw_data_),Some(PS.Reveal(Raw_data_)asinput))|PS.Needs_revealReveal_metadata,Some(PS.Reveal(Metadata_)asinput)|(PS.Needs_reveal(PS.Request_dal_page_),Some(PS.Reveal(Dal_page_)asinput))->(* For all the cases above, the input request matches the given input, so
we proceed by setting the input. *)set_inputinputstate|(PS.Initial|PS.First_after_),_->error"Invalid set_input: expecting inbox message, got a reveal."|PS.Needs_reveal(Reveal_raw_data_hash),_->error"Invalid set_input: expecting a raw data reveal, got an inbox \
message or a reveal metadata."|PS.Needs_revealReveal_metadata,_->error"Invalid set_input: expecting a metadata reveal, got an inbox \
message or a raw data reveal."|PS.Needs_reveal(PS.Request_dal_page_),_->error"Invalid set_input: expecting a dal page reveal, got an inbox \
message or a raw data reveal."inreturn(state,request)typeerror+=Arith_proof_verification_failedletverify_proofinput_givenproof=letopenLwt_result_syntaxinlet*!result=Context.verify_proofproof(step_transitioninput_given)inmatchresultwith|None->tzfailArith_proof_verification_failed|Some(_state,request)->returnrequestletproduce_proofcontextinput_givenstate=letopenLwt_result_syntaxinlet*!result=Context.produce_proofcontextstate(step_transitioninput_given)inmatchresultwith|Some(tree_proof,_requested)->returntree_proof|None->tzfailArith_proof_production_failedletverify_origination_proofproofboot_sector=letopenLwt_syntaxinletbefore=Context.proof_beforeproofinifState_hash.(before<>reference_initial_state_hash)thenreturnfalseelselet*result=Context.verify_proofproof(funstate->let*state=install_boot_sectorstateboot_sectorinreturn(state,()))inmatchresultwithNone->returnfalse|Some(_,())->returntrueletproduce_origination_proofcontextboot_sector=letopenLwt_result_syntaxinlet*!state=initial_state~empty:(Tree.emptycontext)inlet*!result=Context.produce_proofcontextstate(funstate->letopenLwt_syntaxinlet*state=install_boot_sectorstateboot_sectorinreturn(state,()))inmatchresultwith|Some(proof,())->returnproof|None->tzfailArith_proof_production_failed(* TEMPORARY: The following definitions will be extended in a future commit. *)typeoutput_proof={output_proof:Context.proof;output_proof_state:hash;output_proof_output:PS.output;}letoutput_proof_encoding=letopenData_encodinginconv(fun{output_proof;output_proof_state;output_proof_output}->(output_proof,output_proof_state,output_proof_output))(fun(output_proof,output_proof_state,output_proof_output)->{output_proof;output_proof_state;output_proof_output})(obj3(req"output_proof"Context.proof_encoding)(req"output_proof_state"State_hash.encoding)(req"output_proof_output"PS.output_encoding))letoutput_of_output_proofs=s.output_proof_outputletstate_of_output_proofs=s.output_proof_stateletoutput_key(output:PS.output)=Z.to_stringoutput.message_indexlethas_outputoutputtree=letopenLwt_syntaxinlet*equal=Output.mapped_to(output_keyoutput)outputtreeinreturn(tree,equal)letverify_output_proofp=letopenLwt_syntaxinlettransition=has_outputp.output_proof_outputinlet*result=Context.verify_proofp.output_prooftransitioninmatchresultwithNone->returnfalse|Some_->returntrueletproduce_output_proofcontextstateoutput_proof_output=letopenLwt_result_syntaxinlet*!output_proof_state=state_hashstateinlet*!result=Context.produce_proofcontextstate@@has_outputoutput_proof_outputinmatchresultwith|Some(output_proof,true)->return{output_proof;output_proof_state;output_proof_output}|Some(_,false)->failArith_invalid_claim_about_outbox|None->failArith_output_proof_production_failedletget_current_levelstate=letopenLwt_syntaxinlet*_state_,current_level=Monad.runCurrent_level.getstateinreturncurrent_levelmoduleInternal_for_tests=structletinsert_failurestate=letaddn=Tree.addstate["failures";string_of_intn]Bytes.emptyinletopenLwt_syntaxinlet*n=Tree.lengthstate["failures"]inaddnendendmoduleProtocol_implementation=Make(structmoduleTree=structincludeContext.Treetypetree=Context.treetypet=Context.ttypekey=stringlisttypevalue=bytesendtypetree=Context.treelethash_treet=State_hash.context_hash_to_state_hash(Tree.hasht)typeproof=Context.Proof.treeContext.Proof.tletverify_proofpf=letopenLwt_option_syntaxinlet*?()=Result.to_option(Context_binary_proof.check_is_binaryp)inLwt.mapResult.to_option(Context.verify_tree_proofpf)letproduce_proof_context_state_f=(* Can't produce proof without full context*)Lwt.returnNoneletkinded_hash_to_state_hash=function|`Valuehash|`Nodehash->State_hash.context_hash_to_state_hashhashletproof_beforeproof=kinded_hash_to_state_hashproof.Context.Proof.beforeletproof_afterproof=kinded_hash_to_state_hashproof.Context.Proof.afterletproof_encoding=Context.Proof_encoding.V2.Tree2.tree_proof_encodingend)