Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file sc_rollup_services.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2021 Nomadic Labs, <contact@nomadic-labs.com> *)(* Copyright (c) 2023 TriliTech <contact@trili.tech> *)(* *)(* 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. *)(* *)(*****************************************************************************)openProtocolopenAlpha_context(* We distinguish RPC endpoints served by the rollup node into `global` and
`local`. The difference between the two lies in whether the responses
given by different rollup nodes in the same state (see below for an
exact definition) must be the same (in the case of global endpoints)
or can differ (in the case of local endpoints).
More formally, two rollup nodes are in the same quiescent state if they are
subscribed to the same rollup address, and have processed the same set of
heads from the layer1. We only consider quiescent states, that is those
where rollup nodes are not actively processing a head received from layer1.
Examples of global endpoints are `current_inbox` and
`last_stored_commitment`, as the responses returned by these endpoints
is expected to be consistent across rollup nodes in the same state.
An example of local endpoint is `last_published_commitments`, as two rollup
nodes in the same state may either publish or not publish a commitment,
according to whether its inbox level is below the inbox level of the
last cemented commitment at the time they tried to publish the commitment.
See below for a more detailed explanation.
*)typeeval_result={state_hash:Sc_rollup.State_hash.t;status:string;output:Sc_rollup.outputlist;inbox_level:Raw_level.t;num_ticks:Z.t;}typesimulate_input={messages:stringlist;reveal_pages:stringlistoption;}typeinbox_info={finalized:bool;cemented:bool}typecommitment_info={commitment:Sc_rollup.Commitment.t;commitment_hash:Sc_rollup.Commitment.Hash.t;first_published_at_level:Raw_level.t;published_at_level:Raw_level.t;}typemessage_status=|Unknown|Pending_batch|Pending_injectionofL1_operation.t|InjectedofInjector_sigs.injected_info|IncludedofInjector_sigs.included_info*inbox_info|CommittedofInjector_sigs.included_info*inbox_info*commitment_infomoduleEncodings=structopenData_encodingletcommitment_with_hash=obj2(req"commitment"Sc_rollup.Commitment.encoding)(req"hash"Sc_rollup.Commitment.Hash.encoding)letcommitment_with_hash_and_level_infos=obj4(req"commitment"Sc_rollup.Commitment.encoding)(req"hash"Sc_rollup.Commitment.Hash.encoding)(opt"first_published_at_level"Raw_level.encoding)(opt"published_at_level"Raw_level.encoding)lethex_string=convBytes.of_stringBytes.to_stringbytesleteval_result=conv(fun{state_hash;status;output;inbox_level;num_ticks}->(state_hash,status,output,inbox_level,num_ticks))(fun(state_hash,status,output,inbox_level,num_ticks)->{state_hash;status;output;inbox_level;num_ticks})@@obj5(req"state_hash"Sc_rollup.State_hash.encoding~description:"Hash of the state after execution of the PVM on the input \
messages")(req"status"string~description:"Status of the PVM after evaluation")(req"output"(listSc_rollup.output_encoding)~description:"Output produced by evaluation of the messages")(req"inbox_level"Raw_level.encoding~description:"Level of the inbox that would contain these messages")(req"num_ticks"z~description:"Ticks taken by the PVM for evaluating the messages")letsimulate_input=conv(fun{messages;reveal_pages}->(messages,reveal_pages))(fun(messages,reveal_pages)->{messages;reveal_pages})@@obj2(req"messages"(listhex_string)~description:"Input messages for simulation")(opt"reveal_pages"(listhex_string)~description:"Pages (at most 4kB) to be used for revelation ticks")letqueued_message=obj2(req"hash"L2_message.Hash.encoding)(req"message"L2_message.encoding)letbatcher_queue=listqueued_messageletinbox_info=conv(fun{finalized;cemented}->(finalized,cemented))(fun(finalized,cemented)->{finalized;cemented})@@obj2(req"finalized"bool)(req"cemented"bool)letcommitment_info=conv(fun{commitment;commitment_hash;first_published_at_level;published_at_level;}->(commitment,commitment_hash,first_published_at_level,published_at_level))(fun(commitment,commitment_hash,first_published_at_level,published_at_level)->{commitment;commitment_hash;first_published_at_level;published_at_level;})@@obj4(req"commitment"Sc_rollup.Commitment.encoding)(req"hash"Sc_rollup.Commitment.Hash.encoding)(req"first_published_at_level"Raw_level.encoding)(req"published_at_level"Raw_level.encoding)letmessage_status=union[case(Tag0)~title:"unknown"~description:"The message is not known by the batcher."(obj1(req"status"(constant"unknown")))(functionUnknown->Some()|_->None)(fun()->Unknown);case(Tag1)~title:"pending_batch"~description:"The message is in the batcher queue."(obj1(req"status"(constant"pending_batch")))(functionPending_batch->Some()|_->None)(fun()->Pending_batch);case(Tag2)~title:"pending_injection"~description:"The message is batched but not injected yet."(obj2(req"status"(constant"pending_injection"))(req"operation"L1_operation.encoding))(functionPending_injectionop->Some((),op)|_->None)(fun((),op)->Pending_injectionop);case(Tag3)~title:"injected"~description:"The message is injected as part of an L1 operation but it is not \
included in a block."(merge_objs(obj1(req"status"(constant"injected")))Injector_sigs.injected_info_encoding)(functionInjectedinfo->Some((),info)|_->None)(fun((),info)->Injectedinfo);case(Tag4)~title:"included"~description:"The message is included in an inbox in an L1 block."(merge_objs(obj1(req"status"(constant"included")))(merge_objsInjector_sigs.included_info_encodinginbox_info))(function|Included(info,inbox_info)->Some((),(info,inbox_info))|_->None)(fun((),(info,inbox_info))->Included(info,inbox_info));case(Tag5)~title:"committed"~description:"The message is included in a committed inbox on L1."(merge_objs(obj1(req"status"(constant"committed")))@@merge_objsInjector_sigs.included_info_encoding@@merge_objsinbox_info(obj1(req"commitment"commitment_info)))(function|Committed(info,inbox_info,commitment)->Some((),(info,(inbox_info,commitment)))|_->None)(fun((),(info,(inbox_info,commitment)))->Committed(info,inbox_info,commitment));]letmessage_status_output=merge_objs(obj1(opt"content"hex_string))message_statusendmoduleArg=structtypeblock_id=[`Head|`HashofBlock_hash.t|`LevelofInt32.t|`Finalized|`Cemented]letconstruct_block_id=function|`Head->"head"|`Hashh->Block_hash.to_b58checkh|`Levell->Int32.to_stringl|`Finalized->"finalized"|`Cemented->"cemented"letdestruct_block_idh=matchhwith|"head"->Ok`Head|"finalized"->Ok`Finalized|"cemented"->Ok`Cemented|_->(matchInt32.of_string_opthwith|Somel->Ok(`Levell)|None->(matchBlock_hash.of_b58check_opthwith|Someb->Ok(`Hashb)|None->Error"Cannot parse block id"))letblock_id:block_idTezos_rpc.Arg.t=Tezos_rpc.Arg.make~descr:"An L1 block identifier."~name:"block_id"~construct:construct_block_id~destruct:destruct_block_id()letl2_message_hash:L2_message.hashTezos_rpc.Arg.t=Tezos_rpc.Arg.make~descr:"A L2 message hash."~name:"l2_message_hash"~construct:L2_message.Hash.to_b58check~destruct:(funs->L2_message.Hash.of_b58check_opts|>Option.to_result~none:"Invalid L2 message hash")()endmoduletypePREFIX=sigtypeprefixvalprefix:(unit,prefix)Tezos_rpc.Path.tendmoduleMake_services(P:PREFIX)=structincludePletpath:prefixTezos_rpc.Path.context=Tezos_rpc.Path.open_rootletmake_calls=Tezos_rpc.Context.make_call(Tezos_rpc.Service.prefixprefixs)letmake_call1s=Tezos_rpc.Context.make_call1(Tezos_rpc.Service.prefixprefixs)letmake_call2s=Tezos_rpc.Context.make_call2(Tezos_rpc.Service.prefixprefixs)endtypesimulate_query={fuel:int64option}letsimulate_query:simulate_queryTezos_rpc.Query.t=letopenTezos_rpc.Queryinquery(funfuel->{fuel})|+opt_field"fuel"Tezos_rpc.Arg.int64(funt->t.fuel)|>sealmoduleGlobal=structopenTezos_rpc.PathincludeMake_services(structtypeprefix=unitletprefix=open_root/"global"end)letsc_rollup_address=Tezos_rpc.Service.get_service~description:"Smart rollup address"~query:Tezos_rpc.Query.empty~output:Sc_rollup.Address.encoding(path/"smart_rollup_address")letcurrent_tezos_head=Tezos_rpc.Service.get_service~description:"Tezos head known to the smart rollup node"~query:Tezos_rpc.Query.empty~output:(Data_encoding.optionBlock_hash.encoding)(path/"tezos_head")letcurrent_tezos_level=Tezos_rpc.Service.get_service~description:"Tezos level known to the smart rollup node"~query:Tezos_rpc.Query.empty~output:(Data_encoding.optionData_encoding.int32)(path/"tezos_level")letlast_stored_commitment=Tezos_rpc.Service.get_service~description:"Last commitment computed by the node"~query:Tezos_rpc.Query.empty~output:(Data_encoding.optionEncodings.commitment_with_hash)(path/"last_stored_commitment")moduleHelpers=structincludeMake_services(structtypeprefix=unitletprefix=open_root/"helpers"end)letoutbox_proof_query=letopenTezos_rpc.QueryinletopenSc_rollupinletinvalid_messagee=raise(Invalid(Format.asprintf"Invalid message (%a)"Environment.Error_monad.pp_tracee))inquery(funoutbox_levelmessage_indexserialized_outbox_message->letreqnamef=function|None->raise(Invalid(Format.sprintf"Query parameter %s is required"name))|Somearg->farginletoutbox_level=req"outbox_level"Raw_level.of_int32_exnoutbox_levelinletmessage_index=req"message_index"Z.of_int64message_indexinletmessage=req"serialized_outbox_message"(funs->Outbox.Message.(unsafe_of_strings|>deserialize))serialized_outbox_messageinmatchmessagewith|Errore->invalid_messagee|Okmessage->{outbox_level;message_index;message})|+opt_field"outbox_level"Tezos_rpc.Arg.int32(funo->Some(Raw_level.to_int32o.outbox_level))|+opt_field"message_index"Tezos_rpc.Arg.int64(funo->Some(Z.to_int64o.message_index))|+opt_field"serialized_outbox_message"Tezos_rpc.Arg.string(funo->matchOutbox.Message.serializeo.messagewith|Okmessage->Some(Outbox.Message.unsafe_to_stringmessage)|Errore->invalid_messagee)|>sealletoutbox_proof=Tezos_rpc.Service.get_service~description:"Generate serialized output proof for some outbox message"~query:outbox_proof_query~output:Data_encoding.(obj2(req"commitment"Sc_rollup.Commitment.Hash.encoding)(req"proof"Encodings.hex_string))(path/"proofs"/"outbox")endmoduleBlock=structincludeMake_services(structtypeprefix=unit*Arg.block_idletprefix=prefix/"block"/:Arg.block_idend)letblock=Tezos_rpc.Service.get_service~description:"Layer-2 block of the layer-2 chain with respect to a Layer 1 block \
identifier"~query:Tezos_rpc.Query.empty~output:Sc_rollup_block.full_encodingpathlethash=Tezos_rpc.Service.get_service~description:"Tezos block hash of block known to the smart rollup node"~query:Tezos_rpc.Query.empty~output:Block_hash.encoding(path/"hash")letlevel=Tezos_rpc.Service.get_service~description:"Level of Tezos block known to the smart rollup node"~query:Tezos_rpc.Query.empty~output:Data_encoding.int32(path/"level")letinbox=Tezos_rpc.Service.get_service~description:"Rollup inbox for block"~query:Tezos_rpc.Query.empty~output:Sc_rollup.Inbox.encoding(path/"inbox")letticks=Tezos_rpc.Service.get_service~description:"Number of ticks for specified level"~query:Tezos_rpc.Query.empty~output:Data_encoding.z(path/"ticks")lettotal_ticks=Tezos_rpc.Service.get_service~description:"Total number of ticks at specified block"~query:Tezos_rpc.Query.empty~output:Sc_rollup.Tick.encoding(path/"total_ticks")letnum_messages=Tezos_rpc.Service.get_service~description:"Number of messages for specified block"~query:Tezos_rpc.Query.empty~output:Data_encoding.z(path/"num_messages")letstate_hash=Tezos_rpc.Service.get_service~description:"State hash for this block"~query:Tezos_rpc.Query.empty~output:Sc_rollup.State_hash.encoding(path/"state_hash")letstate_current_level=Tezos_rpc.Service.get_service~description:"Retrieve the current level of a PVM"~query:Tezos_rpc.Query.empty~output:(Data_encoding.optionRaw_level.encoding)(path/"state_current_level")typestate_value_query={key:string}letstate_value_query:state_value_queryTezos_rpc.Query.t=letopenTezos_rpc.Queryinquery(funkey->{key})|+field"key"Tezos_rpc.Arg.string""(funt->t.key)|>sealletstate_value=Tezos_rpc.Service.get_service~description:"Retrieve value from key is PVM state of specified block"~query:state_value_query~output:Data_encoding.bytes(path/"state")letdurable_state_value(pvm_kind:Protocol.Alpha_context.Sc_rollup.Kind.t)=Tezos_rpc.Service.get_service~description:"Retrieve value by key from PVM durable storage. PVM state is taken \
with respect to the specified block level. Value returned in hex \
format."~query:state_value_query~output:Data_encoding.(optionbytes)(path/"durable"/Protocol.Alpha_context.Sc_rollup.Kind.to_stringpvm_kind/"value")letdurable_state_length(pvm_kind:Protocol.Alpha_context.Sc_rollup.Kind.t)=Tezos_rpc.Service.get_service~description:"Retrieve number of bytes in raw representation of value by key from \
PVM durable storage. PVM state is taken with respect to the \
specified block level."~query:state_value_query~output:Data_encoding.(optionint64)(path/"durable"/Protocol.Alpha_context.Sc_rollup.Kind.to_stringpvm_kind/"length")letdurable_state_subkeys(pvm_kind:Protocol.Alpha_context.Sc_rollup.Kind.t)=Tezos_rpc.Service.get_service~description:"Retrieve subkeys of the specified key from PVM durable storage. PVM \
state is taken with respect to the specified block level."~query:state_value_query~output:Data_encoding.(liststring)(path/"durable"/Protocol.Alpha_context.Sc_rollup.Kind.to_stringpvm_kind/"subkeys")letstatus=Tezos_rpc.Service.get_service~description:"PVM status at block"~query:Tezos_rpc.Query.empty~output:Data_encoding.string(path/"status")letoutbox_level_query=letopenTezos_rpc.Queryinquery(funoutbox_level->letreqnamef=function|None->raise(Invalid(Format.sprintf"Query parameter %s is required"name))|Somearg->farginreq"outbox_level"Raw_level.of_int32_exnoutbox_level)|+opt_field"outbox_level"Tezos_rpc.Arg.int32(funo->Some(Raw_level.to_int32o))|>sealletoutbox=Tezos_rpc.Service.get_service~description:"Outbox at block for a given outbox level"~query:outbox_level_query~output:Data_encoding.(listSc_rollup.output_encoding)(path/"outbox")letsimulate=Tezos_rpc.Service.post_service~description:"Simulate messages evaluation by the PVM"~query:Tezos_rpc.Query.empty~input:Encodings.simulate_input~output:Encodings.eval_result(path/"simulate")letdal_slots=Tezos_rpc.Service.get_service~description:"Availability slots for a given block"~query:Tezos_rpc.Query.empty~output:(Data_encoding.listDal.Slot.Header.encoding)(path/"dal"/"slot_headers")letdal_confirmed_slot_pages=Tezos_rpc.Service.get_service~description:"Data availability confirmed & downloaded slot pages for a given \
block hash"~query:Tezos_rpc.Query.empty~output:(* DAL/FIXME: https://gitlab.com/tezos/tezos/-/issues/3873
Estimate size of binary encoding and add a check_size to the
encoding. *)Data_encoding.(list@@obj2(req"index"Dal.Slot_index.encoding)(req"contents"(listDal.Page.content_encoding)))(path/"dal"/"confirmed_slot_pages")typedal_slot_page_query={index:Dal.Slot_index.t;page:int}letdal_slot_page_query=letopenTezos_rpc.Queryinletreqnamef=function|None->raise(Invalid(Format.sprintf"Query parameter %s is required"name))|Somearg->farginletinvalid_parameteri=raise(Invalid(Format.asprintf"Invalid parameter (%d)"i))inquery(funraw_indexraw_page->letindex=req"index"Dal.Slot_index.of_intraw_indexinletpage=req"page"(funp->p)raw_pageinmatchindexwith|None->invalid_parameter@@Option.value~default:0raw_index|Someindex->ifpage<0theninvalid_parameterpageelse{index;page})|+opt_field"index"Tezos_rpc.Arg.int(funq->Some(Dal.Slot_index.to_intq.index))|+opt_field"slot_page"Tezos_rpc.Arg.int(funq->Someq.page)|>sealletdal_slot_page=Tezos_rpc.Service.get_service~description:"Data availability downloaded slot pages for a given block hash"~query:dal_slot_page_query~output:Data_encoding.(obj2(req"result"string)(opt"contents"Dal.Page.content_encoding))(path/"dal"/"slot_page")moduleOutbox=structletlevel_param=letdestructs=matchInt32.of_string_optswith|None->Error"Invalid level"|Somel->(matchRaw_level.of_int32lwith|Error_->Error"Invalid level"|Okl->Okl)inletconstruct=Format.asprintf"%a"Raw_level.ppinTezos_rpc.Arg.make~name:"level"~construct~destruct()includeMake_services(structtypenonrecprefix=prefix*Raw_level.tletprefix=prefix/"outbox"/:level_paramend)letmessages=Tezos_rpc.Service.get_service~description:"Outbox at block for a given outbox level"~query:Tezos_rpc.Query.empty~output:Data_encoding.(listSc_rollup.output_encoding)(path/"messages")endendendmoduleLocal=structopenTezos_rpc.PathincludeMake_services(structtypeprefix=unitletprefix=open_root/"local"end)(* commitments are published only if their inbox level is above the last
cemented commitment level inbox level. Because this information is
fetched from the head of the tezos node to which the rollup node is
connected, it is possible that two rollup nodes that have processed
the same set of heads, but whose corresponding layer1 node has
different information about the last cemented commitment, will
decide to publish and not to publish a commitment, respectively.
As a consequence, the results returned by the endpoint below
in the rollup node will be different.
*)letlast_published_commitment=Tezos_rpc.Service.get_service~description:"Last commitment published by the node"~query:Tezos_rpc.Query.empty~output:(Data_encoding.optionEncodings.commitment_with_hash_and_level_infos)(path/"last_published_commitment")letinjection=Tezos_rpc.Service.post_service~description:"Inject messages in the batcher's queue"~query:Tezos_rpc.Query.empty~input:Data_encoding.(def"messages"~description:"Messages to inject"(listL2_message.content_encoding))~output:Data_encoding.(def"message_hashes"~description:"Hashes of injected L2 messages"(listL2_message.Hash.encoding))(path/"batcher"/"injection")letbatcher_queue=Tezos_rpc.Service.get_service~description:"List messages present in the batcher's queue"~query:Tezos_rpc.Query.empty~output:Encodings.batcher_queue(path/"batcher"/"queue")letbatcher_message=Tezos_rpc.Service.get_service~description:"Retrieve an L2 message and its status"~query:Tezos_rpc.Query.empty~output:Encodings.message_status_output(path/"batcher"/"queue"/:Arg.l2_message_hash)end