123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133(*****************************************************************************)(* *)(* 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=letopenLwt_result_syntaxinlet+ctxt,res=Storage.Ticket_balance.Table.findctxtkeyin(res,ctxt)letset_balancectxtkeybalance=letcost_of_key=Z.of_int65inletopenLwt_result_syntaxinlet*()=fail_whenCompare.Z.(balance<Z.zero)(Negative_ticket_balance{key;balance})inifCompare.Z.(balance=Z.zero)thenlet+ctxt,freed,existed=Storage.Ticket_balance.Table.removectxtkeyin(* 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)elselet+ctxt,size_diff,existed=Storage.Ticket_balance.Table.addctxtkeybalanceinletsize_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=letopenLwt_result_syntaxinlet*res,ctxt=get_balancectxtkeyinletold_balance=Option.value~default:Z.zeroresinset_balancectxtkey(Z.addold_balancedelta)letadjust_storage_spacectxt~storage_diff=letopenLwt_result_syntaxinifCompare.Z.(storage_diff=Z.zero)thenreturn(Z.zero,ctxt)elselet*used_storage=Storage.Ticket_balance.Used_storage_space.findctxtinletused_storage=Option.value~default:Z.zeroused_storageinlet*paid_storage=Storage.Ticket_balance.Paid_storage_space.findctxtinletpaid_storage=Option.value~default:Z.zeropaid_storageinletnew_used_storage=Z.addused_storagestorage_diffinlet*?()=error_whenCompare.Z.(new_used_storage<Z.zero)Used_storage_space_underflowinlet*!ctxt=Storage.Ticket_balance.Used_storage_space.addctxtnew_used_storageinletdiff=Z.subnew_used_storagepaid_storageinifCompare.Z.(Z.zero<diff)thenlet*!ctxt=Storage.Ticket_balance.Paid_storage_space.addctxtnew_used_storageinreturn(diff,ctxt)elsereturn(Z.zero,ctxt)moduleInternal_for_tests=structletused_storage_spacec=letopenLwt_result_syntaxinlet+value=Storage.Ticket_balance.Used_storage_space.findcinOption.value~default:Z.zerovalueletpaid_storage_spacec=letopenLwt_result_syntaxinlet+value=Storage.Ticket_balance.Paid_storage_space.findcinOption.value~default:Z.zerovalueend