123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2021 Trili Tech, <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. *)(* *)(*****************************************************************************)typekey_hash=Script_expr_hash.ttypeerror+=|Negative_ticket_balanceof{key:Script_expr_hash.t;balance:Z.t}|Failed_to_hash_nodeletscript_expr_hash_of_key_hashkey_hash=key_hashlethash_bytes_costbytes=letmoduleS=Saturation_reprinlet(+)=S.addinletv0=S.safe_int@@Bytes.lengthbytesinlet(lsr)=S.shift_rightinS.safe_int200+(v0+(v0lsr2))|>Gas_limit_repr.atomic_step_costlethash_of_nodectxtnode=Raw_context.consume_gasctxt(Script_repr.strip_locations_costnode)>>?functxt->letnode=Micheline.strip_locationsnodeinmatchData_encoding.Binary.to_bytes_optScript_repr.expr_encodingnodewith|Somebytes->Raw_context.consume_gasctxt(hash_bytes_costbytes)>|?functxt->(Script_expr_hash.hash_bytes[bytes],ctxt)|None->errorFailed_to_hash_nodeletmake_key_hashctxt~ticketer~typ~contents~owner=hash_of_nodectxt@@Micheline.Seq(Micheline.dummy_location,[ticketer;typ;contents;owner])let()=letopenData_encodinginregister_error_kind`Permanent~id:"Negative_ticket_balance"~title:"Negative ticket balance"~description:"Attempted to set a negative ticket balance value"~pp:(funppf(key,balance)->Format.fprintfppf"Attempted to set negative ticket balance value '%a' for key %a."Z.pp_printbalanceScript_expr_hash.ppkey)(obj2(req"key"Script_expr_hash.encoding)(req"balance"Data_encoding.z))(function|Negative_ticket_balance{key;balance}->Some(key,balance)|_->None)(fun(key,balance)->Negative_ticket_balance{key;balance});register_error_kind`Branch~id:"Failed_to_hash_node"~title:"Failed to hash node"~description:"Failed to hash node for a key in the ticket-balance table"~pp:(funppf()->Format.fprintfppf"Failed to hash node for a key in the ticket-balance table")Data_encoding.empty(functionFailed_to_hash_node->Some()|_->None)(fun()->Failed_to_hash_node)letget_balancectxtkey=Storage.Ticket_balance.Table.findctxtkey>|=?fun(ctxt,res)->(res,ctxt)letset_balancectxtkeybalance=letcost_of_key=Z.of_int65infail_whenCompare.Z.(balance<Z.zero)(Negative_ticket_balance{key;balance})>>=?fun()->ifCompare.Z.(balance=Z.zero)thenStorage.Ticket_balance.Table.removectxtkey>|=?fun(ctxt,freed,existed)->(* If we remove an existing entry, then we return the freed size for
both the key and the value. *)letfreed=ifexistedthenZ.neg@@Z.addcost_of_key(Z.of_intfreed)elseZ.zeroin(freed,ctxt)elseStorage.Ticket_balance.Table.addctxtkeybalance>|=?fun(ctxt,size_diff,existed)->letsize_diff=letz_diff=Z.of_intsize_diffin(* For a new entry we also charge the space for storing the key *)ifexistedthenz_diffelseZ.addcost_of_keyz_diffin(size_diff,ctxt)letadjust_balancectxtkey~delta=get_balancectxtkey>>=?fun(res,ctxt)->letold_balance=Option.value~default:Z.zeroresinset_balancectxtkey(Z.addold_balancedelta)