12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787(*****************************************************************************)(* *)(* 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)moduletypeS=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_revealofSc_rollup_PVM_sig.reveal|Parsing|Evaluatingvalget_status:is_reveal_enabled:Sc_rollup_PVM_sig.is_reveal_enabled->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:Sc_rollup_PVM_sig.Generic_pvm_context_sig):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_revealofSc_rollup_PVM_sig.reveal|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.encodingletpp=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=letopenData_encodinginletkindname=req"status"(constantname)inletcase_halted=case~title:"Halted"(Tag0)(obj1(kind"halted"))(functionHalted->Some()|_->None)(fun()->Halted)inletcase_waiting_for_input_message=case~title:"Waiting_for_input_message"(Tag1)(obj1(kind"waiting_for_input_message"))(functionWaiting_for_input_message->Some()|_->None)(fun()->Waiting_for_input_message)inletcase_waiting_for_reveal=case~title:"Waiting_for_reveal"(Tag2)(obj2(kind"waiting_for_reveal")(req"reveal"Sc_rollup_PVM_sig.reveal_encoding))(functionWaiting_for_revealr->Some((),r)|_->None)(fun((),r)->Waiting_for_revealr)inletcase_parsing=case~title:"Parsing"(Tag3)(obj1(kind"parsing"))(functionParsing->Some()|_->None)(fun()->Parsing)inletcase_evaluating=case~title:"Evaluating"(Tag4)(obj1(kind"evaluating"))(functionEvaluating->Some()|_->None)(fun()->Evaluating)inunion[case_halted;case_waiting_for_input_message;case_waiting_for_reveal;case_parsing;case_evaluating;]letname="status"letstring_of_status=function|Halted->"Halted"|Waiting_for_input_message->"Waiting for input message"|Waiting_for_revealreveal->Format.asprintf"Waiting for reveal %a"Sc_rollup_PVM_sig.pp_revealreveal|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)typedal_slots_list=Dal_slot_index_repr.tlistletdal_slots_list_encoding=Data_encoding.listDal_slot_index_repr.encodingletpp_dal_slots_list=Format.pp_print_list~pp_sep:(funfmt()->Format.pp_print_stringfmt":")Dal_slot_index_repr.pptypedal_parameters={attestation_lag:int32;number_of_pages:int32;tracked_slots:dal_slots_list;}moduleDal_parameters=Make_var(structtypet=dal_parametersletinitial=(* This initial value is, from a semantic point of vue, equivalent to
have [None], as no slot is tracked.
For the initial values of the fields, only [tracked_slots]'s content
matters. Setting it the empty set means that the rollup is not
subscribed to the DAL. *){attestation_lag=1l;number_of_pages=0l;tracked_slots=[]}letencoding=letopenData_encodinginconv(fun{attestation_lag;number_of_pages;tracked_slots}->(attestation_lag,number_of_pages,tracked_slots))(fun(attestation_lag,number_of_pages,tracked_slots)->{attestation_lag;number_of_pages;tracked_slots})(obj3(req"attestation_lag"int32)(req"number_of_pages"int32)(req"tracked_slots"dal_slots_list_encoding))letname="dal_parameters"letppfmt{attestation_lag;number_of_pages;tracked_slots}=Format.fprintffmt"dal:%ld:%ld:%a"attestation_lagnumber_of_pagespp_dal_slots_listtracked_slotsend)moduleDal_remaining_slots=Make_var(structtypet=dal_slots_listletinitial=[]letencoding=dal_slots_list_encodingletname="dal_remaining_slots"letpp=pp_dal_slots_listend)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.set(Waiting_for_revealReveal_metadata)inreturn()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.getletget_status~is_reveal_enabled:statusMonad.t=letopenMonad.Syntaxinlet*status=Status.getinlet*current_block_level=Current_level.getin(* We do not put the machine in a stuck condition if a kind of reveal
happens to not be supported. This is a sensible thing to do, as if
there is an off-by-one error in the WASM kernel one can do an
incorrect reveal, which can put the PVM in a stuck state with no way
to upgrade the kernel to fix the off-by-one. *)lettry_return_revealcandidate:status=match(current_block_level,candidate)with|_,Waiting_for_revealcandidate->letis_enabled=is_reveal_enabled~current_block_levelcandidateinifis_enabledthenWaiting_for_revealcandidateelseWaiting_for_reveal(Reveal_raw_dataSc_rollup_reveal_hash.well_known_reveal_hash)|_,_->candidateinreturn@@matchstatuswith|Waiting_for_reveal_->try_return_revealstatus|s->sletis_input_state_monadic~is_reveal_enabled=letopenMonad.Syntaxinlet*status=get_status~is_reveal_enabledinmatchstatuswith|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(Reveal_raw_data_)->(let*r=Required_reveal.getinmatchrwith|None->internal_error"Internal error: Reveal invariant broken"|Somereveal->return(PS.Needs_revealreveal))|Waiting_for_revealReveal_metadata->returnPS.(Needs_revealReveal_metadata)|Waiting_for_reveal(Request_dal_pagepage)->returnPS.(Needs_reveal(Request_dal_pagepage))|Halted|Parsing|Evaluating->returnPS.No_input_requiredletis_input_state~is_reveal_enabled=result_of~default:PS.No_input_required@@is_input_state_monadic~is_reveal_enabledletget_current_levelstate=letopenLwt_syntaxinlet*_state_,current_level=Monad.runCurrent_level.getstateinreturncurrent_levelletget_status~is_reveal_enabled:state->statusLwt.t=result_of~default:Waiting_for_input_message(get_status~is_reveal_enabled)letget_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()(** Compute and set the next Dal page to request if any. Otherwise, request
the next inbox message.
The value of [target] allows to compute the next page to request: either
the first one the PVM is subscribed to, or the one after the given
(slot_index, page_index) page. *)letnext_dal_pagedal_params~target=letopenMonad.SyntaxinletopenDal_slot_reprinletmoduleIndex=Dal_slot_index_reprinlet*case=match(dal_params,target)with|{tracked_slots=[];_},`First_page_published_level->(* PVM subscribed to no slot. *)return`Inbox_message|{tracked_slots=index::rest;_},`First_pagepublished_level->(* Initiate the DAL data fetching process with the first page of the
first slot. *)let*()=Dal_remaining_slots.setrestinreturn(`Dal(published_level,index,0))|({number_of_pages;_},`Page_after{Page.slot_id={published_level;index};page_index})->((* We already read some DAL pages for the published level. Try one of
the following in this order:
- Attempt to move to the next page of the current slot;
- In case all pages have been read; attempt to move to the next slot;
- In case all slots have been read; request the next inbox message. *)letpage_index=page_index+1inifCompare.Int.(page_index<Int32.to_intnumber_of_pages)thenreturn(`Dal(published_level,index,page_index))elselet*remaining_slots=Dal_remaining_slots.getinmatchremaining_slotswith|index::rest->let*()=Dal_remaining_slots.setrestinreturn(`Dal(published_level,index,0))|[]->return`Inbox_message)inmatchcasewith|`Dal(published_level,index,page_index)->letpage_id={Page.slot_id={published_level;index};page_index}inlet*()=Required_reveal.set@@Some(Request_dal_pagepage_id)inStatus.set(Waiting_for_reveal(Request_dal_pagepage_id))|`Inbox_message->let*()=Required_reveal.setNoneinStatus.setWaiting_for_input_message(** Request a Dal page or an input message depending on the value of the given
[published_level] argument and on the content of the {Required_reveal.get}.
*)letupdate_waiting_for_data_status=letopenDal_slot_reprinletmoduleIndex=Dal_slot_index_reprinfun?published_level()->letopenMonad.Syntaxinlet*dal_params=Dal_parameters.getinifList.is_emptydal_params.tracked_slotsthen(* This rollup doesn't track any DAL slot. *)Status.setWaiting_for_input_messageelselet*required_reveal=Required_reveal.getin(* Depending on whether [?published_level] is set, and on the value stored
in [required_reveal], the next data to request may either be a DAL page
or an inbox message. *)match(published_level,required_reveal)with|None,None->(* The default case is to request an inbox message. *)Status.setWaiting_for_input_message|Somepublished_level,None->(* We are explictely asked to start fetching DAL pages. *)next_dal_pagedal_params~target:(`First_pagepublished_level)|Somepublished_level,Some(Request_dal_pagepage_id)->(* We are moving to the next level, and there are no explicit inbox
messages in the previous level. *)let*remaining_slots=Dal_remaining_slots.getinassert(letslot_id=page_id.Page.slot_idinletpage_index=page_id.Page.page_indexinCompare.Int.(Int32.to_int@@Raw_level_repr.diffpublished_levelslot_id.published_level=1&&List.is_emptyremaining_slots&&page_index=Int32.to_intdal_params.number_of_pages-1));next_dal_pagedal_params~target:(`First_pagepublished_level)|None,Some(Request_dal_pagepage_id)->(* We are in the same level, fetch the next page. *)next_dal_pagedal_params~target:(`Page_afterpage_id)|_,SomeReveal_metadata->(* Should not happen. *)assertfalse|_,Some(Reveal_raw_data_)->(* Note that, providing a DAC input via a DAL page will interrupt
the interpretation of the next DAL pages of the same level, as the
content of [Required_reveal] is lost. We should use two
distinct states if we don't want this to happen. *)let*()=Required_reveal.setNoneinStatus.setWaiting_for_input_messageletset_inbox_message_monadic{PS.inbox_level;message_counter;payload}=letopenMonad.Syntaxinletdeserialized=Sc_rollup_inbox_message_repr.deserializepayloadinlet*payload=matchdeserializedwith|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(Internal(Protocol_migration_))->let*()=incr_internal_message_counterinreturnNone|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)inmatchdeserializedwith|Ok(InternalStart_of_level)->(let*dal_params=Dal_parameters.getinletinbox_level=Raw_level_repr.to_int32inbox_levelin(* the [published_level]'s pages to request is [inbox_level -
attestation_lag - 1]. *)letlvl=Int32.sub(Int32.subinbox_leveldal_params.attestation_lag)1linmatchRaw_level_repr.of_int32lvlwith|Error_->(* Too early. We cannot request DAL data yet. *)return()|Okpublished_level->(let*metadata=Metadata.getinmatchmetadatawith|None->assertfalse(* Setting Metadata should be the first input provided to the
PVM. *)|Some{origination_level;_}->ifRaw_level_repr.(origination_level>=published_level)then(* We can only fetch DAL data that are published after
the rollup's origination level. *)Status.setWaiting_for_input_messageelse(* Start fetching DAL data for this [published_level]. *)update_waiting_for_data_status~published_level()))|_->Status.setWaiting_for_input_message)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->(* We may either move to the next DAL page or to the next inbox
message. *)update_waiting_for_data_status()|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)in(* Once the evaluation of the current input is done, we either request the
next DAL page or the next inbox message. *)update_waiting_for_data_status()letparse: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_hexhashwith|None->stop_evaluatingfalse|Somehash->letreveal:Sc_rollup_PVM_sig.reveal=Reveal_raw_datahashinlet*()=Required_reveal.set(Somereveal)inlet*()=Status.set(Waiting_for_revealreveal)inreturn()letevaluate_dal_parametersdal_directive=letdal_params=(* Dal pages import directive is [dal:<num_slots>:<e>:<num_p>:<s1>:<s2>:...:<sn>]. See
mli file.*)letopenOption_syntaxinmatchString.split_on_char':'dal_directivewith|number_of_slots::attestation_lag::number_of_pages::tracked_slots->let*number_of_slots=Int32.of_string_optnumber_of_slotsinlet*attestation_lag=Int32.of_string_optattestation_laginlet*number_of_pages=Int32.of_string_optnumber_of_pagesinlet*tracked_slots=letrecauxaccsl=matchslwith|[]->return(List.revacc)|s::rest->let*dal_slot_int=int_of_string_optsinlet*dal_slot=Dal_slot_index_repr.of_int_opt~number_of_slots:(Int32.to_intnumber_of_slots)dal_slot_intin(aux[@tailcall])(dal_slot::acc)restinaux[]tracked_slotsinSome{attestation_lag;number_of_pages;tracked_slots}|_->NoneinletopenMonad.Syntaxinmatchdal_paramswith|None->stop_evaluatingfalse|Somedal_params->let*()=Dal_parameters.setdal_paramsinStatus.setWaiting_for_input_messageletremove_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 reveal 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|Somedal_directive->evaluate_dal_parametersdal_directive|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_->(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_transition~is_reveal_enabledinput_givenstate=letopenLwt_syntaxinlet*request=is_input_state~is_reveal_enabledstateinleterrormsg=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_proof~is_reveal_enabledinput_givenproof=letopenLwt_result_syntaxinlet*!result=Context.verify_proofproof(step_transition~is_reveal_enabledinput_given)inmatchresultwith|None->tzfailArith_proof_verification_failed|Some(_state,request)->returnrequestletproduce_proofcontext~is_reveal_enabledinput_givenstate=letopenLwt_result_syntaxinlet*!result=Context.produce_proofcontextstate(step_transition~is_reveal_enabledinput_given)inmatchresultwith|Some(tree_proof,_requested)->returntree_proof|None->tzfailArith_proof_production_failedtypeoutput_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_keymessage_index=Z.to_stringmessage_indexletget_output~outbox_level~message_index~messagestate=letopenLwt_syntaxinlet*_state,output=run(Output.get(output_keymessage_index))stateinletoutput=letoutput=Option.joinoutputinOption.bindoutput(fun{outbox_level=found_outbox_level;message=found_message;message_index=_;}->(* We can safely ignore the [message_index] since it is the key
used to fetch the messag from the storage. *)letfound_message_encoded=Data_encoding.Binary.to_string_exnSc_rollup_outbox_message_repr.encodingfound_messageinletgiven_message_encoded=Data_encoding.Binary.to_string_exnSc_rollup_outbox_message_repr.encodingmessageinifRaw_level_repr.equaloutbox_levelfound_outbox_level&&Compare.String.equalfound_message_encodedgiven_message_encodedthenSomemessageelseNone)inreturn(state,output)letverify_output_proofp=letopenLwt_result_syntaxinletoutbox_level=p.output_proof_output.outbox_levelinletmessage_index=p.output_proof_output.message_indexinletmessage=p.output_proof_output.messageinlettransition=get_output~outbox_level~message_index~messageinlet*!result=Context.verify_proofp.output_prooftransitioninmatchresultwith|Some(_state,Somemessage)->returnSc_rollup_PVM_sig.{outbox_level;message_index;message}|_->tzfailArith_output_proof_production_failedletproduce_output_proofcontextstateoutput_proof_output=letopenLwt_result_syntaxinletoutbox_level=output_proof_output.Sc_rollup_PVM_sig.outbox_levelinletmessage_index=output_proof_output.message_indexinletmessage=output_proof_output.messageinlet*!result=Context.produce_proofcontextstate@@get_output~outbox_level~message_index~messageinmatchresultwith|Some(output_proof,Somemessage)->let*!output_proof_state=state_hashstateinreturn{output_proof;output_proof_state;output_proof_output={outbox_level;message_index;message};}|_->failArith_output_proof_production_failedmoduleInternal_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.treetypeproof=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)