123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121(*****************************************************************************)(* *)(* 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. *)(* *)(*****************************************************************************)typeerror+=|Negative_ticket_balanceof{key:Ticket_hash_repr.t;balance:Z.t}|Used_storage_space_underflowlet()=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_printbalanceTicket_hash_repr.ppkey)(obj2(req"key"Ticket_hash_repr.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`Permanent~id:"Used_storage_underflow"~title:"Ticket balance used storage underflow"~description:"Attempt to free more bytes than allocated for the tickets balance"empty(functionUsed_storage_space_underflow->Some()|_->None)(fun()->Used_storage_space_underflow)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)letadjust_storage_spacectxt~storage_diff=ifCompare.Z.(storage_diff=Z.zero)thenreturn(Z.zero,ctxt)elseStorage.Ticket_balance.Used_storage_space.findctxt>>=?funused_storage->letused_storage=Option.value~default:Z.zeroused_storageinStorage.Ticket_balance.Paid_storage_space.findctxt>>=?funpaid_storage->letpaid_storage=Option.value~default:Z.zeropaid_storageinletnew_used_storage=Z.addused_storagestorage_diffinerror_whenCompare.Z.(new_used_storage<Z.zero)Used_storage_space_underflow>>?=fun()->Storage.Ticket_balance.Used_storage_space.addctxtnew_used_storage>>=functxt->letdiff=Z.subnew_used_storagepaid_storageinifCompare.Z.(Z.zero<diff)thenStorage.Ticket_balance.Paid_storage_space.addctxtnew_used_storage>>=functxt->return(diff,ctxt)elsereturn(Z.zero,ctxt)moduleInternal_for_tests=structletused_storage_spacec=Storage.Ticket_balance.Used_storage_space.findc>|=?Option.value~default:Z.zeroletpaid_storage_spacec=Storage.Ticket_balance.Paid_storage_space.findc>|=?Option.value~default:Z.zeroend