Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file tx_rollup_l2_context.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2022 Marigold <contact@marigold.dev> *)(* Copyright (c) 2022 Nomadic Labs <contact@nomadic-labs.com> *)(* Copyright (c) 2022 Oxhead Alpha <info@oxheadalpha.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. *)(* *)(*****************************************************************************)openTx_rollup_l2_storage_sigopenTx_rollup_l2_context_sigletpk_encoding:Bls_signature.pkData_encoding.t=Data_encoding.(conv_with_guardBls_signature.pk_to_bytes(funx->Option.to_result~none:"not a valid bls public key"(Bls_signature.pk_of_bytes_optx))bytes)letmetadata_encoding=Data_encoding.(conv(fun{counter;public_key}->(counter,public_key))(fun(counter,public_key)->{counter;public_key})(obj2(req"counter"int64)(req"public_key"pk_encoding)))(** {1 Type-Safe Storage Access and Gas Accounting} *)(** A value of type ['a key] identifies a value of type ['a] in an
underlying, untyped storage.
This GADT is used to enforce type-safety of the abstraction of
the transactions rollup context. For this abstraction to work,
it is necessary to ensure that the serialization of values ['a
key] and ['b key] cannot collide. To that end, we use
[Data_encoding] (see {!packed_key_encoding}). *)type_key=|Address_metadata:address_index->metadatakey|Address_count:int32key|Address_index:Tx_rollup_l2_address.t->address_indexkey|Ticket_count:int32key|Ticket_index:Alpha_context.Ticket_hash.t->ticket_indexkey|Ticket_ledger:ticket_index*address_index->Tx_rollup_l2_qty.tkey(** A monomorphic version of {!Key}, used for serialization purposes. *)typepacked_key=Key:'akey->packed_key(** The encoding used to serialize keys to be used with an untyped storage. *)letpacked_key_encoding:packed_keyData_encoding.t=Data_encoding.(union~tag_size:`Uint8[case(Tag0)~title:"Address_metadata"Tx_rollup_l2_address.Indexable.index_encoding(functionKey(Address_metadataidx)->Someidx|_->None)(funidx->Key(Address_metadataidx));case(Tag1)~title:"Address_count"empty(functionKeyAddress_count->Some()|_->None)(fun()->KeyAddress_count);case(Tag2)~title:"Address_index"Tx_rollup_l2_address.encoding(functionKey(Address_indexaddr)->Someaddr|_->None)(funaddr->Key(Address_indexaddr));case(Tag3)~title:"Ticket_count"empty(functionKeyTicket_count->Some()|_->None)(fun()->KeyTicket_count);case(Tag4)~title:"Ticket_index"Alpha_context.Ticket_hash.encoding(functionKey(Ticket_indexticket)->Someticket|_->None)(funticket->Key(Ticket_indexticket));case(Tag5)~title:"Ticket_ledger"(tup2Ticket_indexable.index_encodingTx_rollup_l2_address.Indexable.index_encoding)(function|Key(Ticket_ledger(ticket,address))->Some(ticket,address)|_->None)(fun(ticket,address)->Key(Ticket_ledger(ticket,address)));])(** [value_encoding key] returns the encoding to be used to serialize
and deserialize values associated to a [key] from and to the
underlying storage. *)letvalue_encoding:typea.akey->aData_encoding.t=letopenData_encodinginfunction|Address_metadata_->metadata_encoding|Address_count->int32|Address_index_->Tx_rollup_l2_address.Indexable.index_encoding|Ticket_count->int32|Ticket_index_->Ticket_indexable.index_encoding|Ticket_ledger_->Tx_rollup_l2_qty.encoding(** {1 Errors} *)typeerror+=Key_cannot_be_serializedtypeerror+=Value_cannot_be_serializedtypeerror+=Value_cannot_be_deserializedlet()=letopenData_encodingin(* Key cannot be serialized *)register_error_kind`Permanent~id:"tx_rollup_key_cannot_be_serialized"~title:"Key cannot be serialized"~description:"Tried to serialize an invalid key."empty(functionKey_cannot_be_serialized->Some()|_->None)(fun()->Key_cannot_be_serialized);(* Value cannot be serialized *)register_error_kind`Permanent~id:"tx_rollup_value_cannot_be_serialized"~title:"Value cannot be serialized"~description:"Tried to serialize an invalid value."empty(functionValue_cannot_be_serialized->Some()|_->None)(fun()->Value_cannot_be_serialized);(* Value cannot be deserialized *)register_error_kind`Permanent~id:"tx_rollup_value_cannot_be_deserialized"~title:"Value cannot be deserialized"~description:"A value has been serialized in the Tx_rollup store, but cannot be \
deserialized."empty(functionValue_cannot_be_deserialized->Some()|_->None)(fun()->Value_cannot_be_deserialized)(** {1 The Context Functor} *)moduleMake(S:STORAGE):CONTEXTwithtypet=S.tandtype'am='aS.m=structtypet=S.ttype'am='aS.mmoduleSyntax=structincludeS.Syntaxlet(let*?)resf=matchreswithResult.Okv->fv|Result.Errorerror->failerrorletfail_unlessconderror=letopenS.Syntaxinifcondthenreturn()elsefailerrorletfail_whenconderror=letopenS.Syntaxinifcondthenfailerrorelsereturn()endletbls_verify:(Bls_signature.pk*bytes)list->signature->boolm=funaccountsaggregated_signature->letopenSyntaxinreturn(Bls_signature.aggregate_verifyaccountsaggregated_signature)letunwrap_or:typea.aoption->error->aS.m=funopterr->matchoptwithSomex->S.Syntax.returnx|None->S.Syntax.failerrletserialize_key:typea.akey->bytesm=funkey->unwrap_or(Data_encoding.Binary.to_bytes_optpacked_key_encoding(Keykey))Key_cannot_be_serializedletserialize_value:typea.aData_encoding.t->a->bytesm=funencodingvalue->unwrap_or(Data_encoding.Binary.to_bytes_optencodingvalue)Value_cannot_be_serializedletdeserialize_value:typea.aData_encoding.t->bytes->am=funencodingvalue->unwrap_or(Data_encoding.Binary.of_bytes_optencodingvalue)Value_cannot_be_deserialized(** [get ctxt key] is a type-safe [get] function. *)letget:typea.t->akey->aoptionm=functxtkey->letopenSyntaxinletvalue_encoding=value_encodingkeyinlet*key=serialize_keykeyinlet*value=S.getctxtkeyinmatchvaluewith|Somevalue->let*value=deserialize_valuevalue_encodingvalueinreturn(Somevalue)|None->returnNone(** [set ctxt key value] is a type-safe [set] function. *)letset:typea.t->akey->a->tm=functxtkeyvalue->letopenSyntaxinletvalue_encoding=value_encodingkeyinlet*key=serialize_keykeyinlet*value=serialize_valuevalue_encodingvalueinS.setctxtkeyvalueletremove:typea.t->akey->tm=functxtkey->letopenSyntaxinlet*key=serialize_keykeyinS.removectxtkeymoduleAddress_metadata=structletgetctxtidx=getctxt(Address_metadataidx)letincr_counterctxtidx=letopenSyntaxinlet*metadata=getctxtidxinmatchmetadatawith|Somemeta->letnew_counter=Int64.succmeta.counterinlet*()=fail_unlessCompare.Int64.(new_counter>=meta.counter)Counter_overflowinsetctxt(Address_metadataidx){metawithcounter=new_counter}|None->fail(Unknown_address_indexidx)letinit_with_public_keyctxtidxpublic_key=letopenSyntaxinlet*metadata=getctxtidxinmatchmetadatawith|None->setctxt(Address_metadataidx){counter=0L;public_key}|Some_->fail(Metadata_already_initializedidx)moduleInternal_for_tests=structletsetctxtidxmetadata=setctxt(Address_metadataidx)metadataendendmoduleAddress_index=structletcountctxt=letopenSyntaxinlet+count=getctxtAddress_countinOption.value~default:0lcountletinit_counterctxt=setctxtAddress_count0lletassociate_indexctxtaddr=letopenSyntaxinlet*i=countctxtinletnew_count=Int32.succiinlet*()=fail_unlessCompare.Int32.(new_count>=i)Too_many_l2_addressesin(* This can not fail as by construction [count ctxt] is always positive. *)letidx=Indexable.index_exniinlet*ctxt=setctxt(Address_indexaddr)idxinlet+ctxt=setctxtAddress_countnew_countin(ctxt,idx)letgetctxtaddr=getctxt(Address_indexaddr)letget_or_associate_indexctxtaddr=letopenSyntaxinlet*index_opt=getctxtaddrinmatchindex_optwith|Someidx->return(ctxt,`Existed,idx)|None->let+(ctxt,idx)=associate_indexctxtaddrin(ctxt,`Created,idx)moduleInternal_for_tests=structletset_countctxtcount=setctxtAddress_countcountendendmoduleTicket_index=structletcountctxt=letopenSyntaxinlet+count=getctxtTicket_countinOption.value~default:0lcountletinit_counterctxt=setctxtTicket_count0lletassociate_indexctxtticket=letopenSyntaxinlet*i=countctxtinletnew_count=Int32.succiinlet*()=fail_unlessCompare.Int32.(new_count>=i)Too_many_l2_ticketsin(* This can not fail as by construction [count ctxt] is always positive. *)letidx=Indexable.index_exniinlet*ctxt=setctxt(Ticket_indexticket)idxinlet+ctxt=setctxtTicket_countnew_countin(ctxt,idx)letgetctxtticket=getctxt(Ticket_indexticket)letget_or_associate_indexctxtticket=letopenSyntaxinlet*index_opt=getctxtticketinmatchindex_optwith|Someidx->return(ctxt,`Existed,idx)|None->let+(ctxt,idx)=associate_indexctxtticketin(ctxt,`Created,idx)moduleInternal_for_tests=structletset_countctxtcount=setctxtTicket_countcountendendmoduleTicket_ledger=structletget_optctxttidxaidx=getctxt(Ticket_ledger(tidx,aidx))letgetctxttidxaidx=letopenSyntaxinlet+res=get_optctxttidxaidxinOption.value~default:Tx_rollup_l2_qty.zeroresletsetctxttidxaidx=setctxt(Ticket_ledger(tidx,aidx))letremovectxttidxaidx=removectxt(Ticket_ledger(tidx,aidx))letspendctxttidxaidxqty=letopenSyntaxinlet*src_balance=getctxttidxaidxinmatchTx_rollup_l2_qty.subsrc_balanceqtywith|None->failBalance_too_low|SomeremainderwhenTx_rollup_l2_qty.(remainder>zero)->setctxttidxaidxremainder|Some_->removectxttidxaidxletcreditctxttidxaidxqty=letopenSyntaxinlet*balance=getctxttidxaidxinmatchTx_rollup_l2_qty.addbalanceqtywith|None->failBalance_overflow|Somenew_balance->setctxttidxaidxnew_balancemoduleInternal_for_tests=structletget_opt=get_optendendend