package octez-protocol-017-PtNairob-libs
Octez protocol 017-PtNairob libraries
Install
Dune Dependency
Authors
Maintainers
Sources
octez-19.0.tar.gz
sha256=c6df840ebbf115e454db949028c595bec558a59a66cade73b52a6d099d6fa4d4
sha512=d8aee903b9fe130d73176bc8ec38b78c9ff65317da3cb4f3415f09af0c625b4384e7498201fdb61aa39086a7d5d409d0ab3423f9bc3ab989a680cf444a79bc13
doc/src/octez-protocol-017-PtNairob-libs.test-helpers/liquidity_baking_generator.ml.html
Source file liquidity_baking_generator.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
(*****************************************************************************) (* *) (* Open Source License *) (* Copyright (c) 2021 Nomadic Labs <contact@nomadic-labs.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. *) (* *) (*****************************************************************************) open Liquidity_baking_machine open QCheck2.Gen let total_xtz = 32_000_000_000_000L let ten_subsidies = 25_000_000L let rec remove_last_element = function | [_] -> [] | x :: rst -> x :: remove_last_element rst | [] -> raise (Invalid_argument "remove_last_element") (** Try to shrink a list by removing elements from the tail of said list. The elements themselves are not shrinked. *) let rec shrink_list l = if l == [] then Seq.empty else let l = remove_last_element l in Seq.cons l (shrink_list l) let gen_balances : int64 -> int -> int -> balances QCheck2.Gen.t = fun max_xtz max_tzbtc max_liquidity -> let open Tezos_test_helpers.Qcheck2_helpers in let+ xtz = int64_strictly_positive_gen max_xtz and+ tzbtc = int_strictly_positive_gen max_tzbtc and+ liquidity = int_strictly_positive_gen max_liquidity in {xtz; tzbtc; liquidity} let gen_specs : int -> int -> specs QCheck2.Gen.t = fun total_tzbtc total_liquidity -> (* 1. We pick a random number to decide how many implicit account we will set-up in the specs. Note that there will be one more implicit accounts, the [Holder], that we will use to reach the expected balances for the CPMM and the implicit accounts. *) let* accounts_numbers = int_range 10 20 in (* 2. To keep the generator simpler, we do not try to strictly reach the [total_tzbtc] and [total_liquidity] value, but rather we compute maxima for the implicit accounts balances from them. *) (* 2.1. We divide a fraction of the [total_xtz] that we need to share to the implicit accounts. The rationale is to provide a large amount to xtz to [Holder], so that we do not have to worry about it being “rich enough.” *) let max_xtz = Int64.(div total_xtz (of_int (50 * accounts_numbers))) in (* 2.2. We divide [total_tzbtc] between the implicit accounts *and* the CPMM contract. *) let max_tzbtc = total_tzbtc / (accounts_numbers + 1) in (* 2.2. We divide [total_liquidity] between the implicit accounts only. *) let max_liquidity = total_liquidity / accounts_numbers in let+ cpmm_balance = gen_balances max_xtz max_tzbtc 1 and+ accounts_balances = list_repeat accounts_numbers (gen_balances max_xtz max_tzbtc max_liquidity) in { cpmm_min_xtz_balance = cpmm_balance.xtz; cpmm_min_tzbtc_balance = cpmm_balance.tzbtc; accounts_balances; } type 'a optgen = 'a option QCheck2.Gen.t let ( let*? ) (m : 'a optgen) (f : 'a -> 'b optgen) = let* x = m in match x with None -> return None | Some x -> f x (** [genopt_oneof l] tries to generate a value using the generators of [l], one at a time. First, the list [l] is randomized, then each generator is tried. The first one to return a result (not [None]) is picked. If all generators returns [None], the generators tries again with the whole list (at most 100 times). If no generator of [l] is able to return a result, then [genopt_oneof l] returns [None]. *) let genopt_oneof (l : 'a optgen list) : 'a optgen = let* l = QCheck2.Gen.shuffle_l l in let rec aux n = function | [] -> if n = 0 then pure None else aux (n - 1) l | g :: l -> ( let* x = g in match x with None -> aux n l | Some x -> pure @@ Some x) in aux 100 l let genopt_account ?choice ?(filter = Fun.const true) env : contract_id optgen = let l = List.filter filter (Option.fold ~none:env.implicit_accounts ~some:(fun x -> [x]) choice) in if l = [] then return None else map Option.some (oneofl l) let genopt_account_with_tzbtc ?choice ?(min = 1) env state = genopt_account ?choice ~filter:(fun a -> SymbolicMachine.get_tzbtc_balance a env state >= min) env let genopt_account_with_xtz ?choice ?(min = 1L) env state = genopt_account ?choice ~filter:(fun a -> SymbolicMachine.get_xtz_balance a state >= min) env let genopt_account_with_liquidity ?choice ?(min = 1) env state = genopt_account ?choice ~filter:(fun a -> SymbolicMachine.get_liquidity_balance a env state >= min) env let genopt_step_tzbtc_to_xtz : ?source:contract_id -> ?destination:contract_id -> contract_id env -> SymbolicMachine.t -> contract_id step optgen = fun ?source ?destination env state -> let*? source = genopt_account_with_tzbtc ?choice:source env state in let*? destination = genopt_account ?choice:destination env in let+ tzbtc_deposit = Tezos_test_helpers.Qcheck2_helpers.int_strictly_positive_gen (SymbolicMachine.get_tzbtc_balance source env state) in (* See note (2) *) if SymbolicMachine.get_tzbtc_balance env.cpmm_contract env state < Int.max_int - tzbtc_deposit then Some (SellTzBTC {source; destination; tzbtc_deposit}) else None let genopt_step_xtz_to_tzbtc : ?source:contract_id -> ?destination:contract_id -> contract_id env -> SymbolicMachine.t -> contract_id step optgen = fun ?source ?destination env state -> let*? source = genopt_account_with_xtz ?choice:source env state in let*? destination = genopt_account ?choice:destination env in let+ xtz_deposit = map Int64.of_int (int_range 1 (Int64.to_int @@ SymbolicMachine.get_xtz_balance source state)) in (* See note (2) *) if SymbolicMachine.get_xtz_balance env.cpmm_contract state < Int64.(sub max_int (add ten_subsidies xtz_deposit)) then Some (BuyTzBTC {source; destination; xtz_deposit}) else None let genopt_step_add_liquidity : ?source:contract_id -> ?destination:contract_id -> contract_id env -> SymbolicMachine.t -> contract_id step optgen = fun ?source ?destination env state -> let rec find_xtz_deposit candidate max_tzbtc_deposit = let tzbtc_deposit = SymbolicMachine.predict_required_tzbtc_deposit candidate env state in if tzbtc_deposit <= max_tzbtc_deposit then candidate else find_xtz_deposit (Int64.div candidate 2L) max_tzbtc_deposit in let*? source = genopt_account_with_xtz ?choice:source env state in let*? destination = genopt_account ?choice:destination env in let source_xtz_pool = SymbolicMachine.get_xtz_balance source state in (* the source needs at least one xtz *) if 1L < source_xtz_pool then let+ candidate = Tezos_test_helpers.Qcheck2_helpers.int64_strictly_positive_gen source_xtz_pool in let xtz_deposit = find_xtz_deposit candidate (SymbolicMachine.get_tzbtc_balance source env state) in (* See note (2) *) if SymbolicMachine.get_xtz_balance env.cpmm_contract state < Int64.(sub max_int (add ten_subsidies xtz_deposit)) then Some (AddLiquidity {source; destination; xtz_deposit}) else None else pure None let genopt_step_remove_liquidity : ?source:contract_id -> ?destination:contract_id -> contract_id env -> SymbolicMachine.t -> contract_id step optgen = fun ?source ?destination env state -> let*? source = genopt_account_with_liquidity ?choice:source env state in let*? destination = genopt_account ?choice:destination env in let lqt_available = SymbolicMachine.get_liquidity_balance source env state in if 1 < lqt_available then let+ lqt_burned = int_range 1 (SymbolicMachine.get_liquidity_balance source env state) in Some (RemoveLiquidity {source; destination; lqt_burned}) else return None let genopt_step : ?source:contract_id -> ?destination:contract_id -> contract_id env -> SymbolicMachine.t -> contract_id step optgen = fun ?source ?destination env state -> genopt_oneof [ genopt_step_tzbtc_to_xtz env state ?source ?destination; genopt_step_xtz_to_tzbtc env state ?source ?destination; genopt_step_add_liquidity env state ?source ?destination; genopt_step_remove_liquidity env state ?source ?destination; ] let gen_steps : ?source:contract_id -> ?destination:contract_id -> contract_id env -> SymbolicMachine.t -> int -> contract_id step list QCheck2.Gen.t = fun ?source ?destination env state size -> let rec inner env state size random_state = if size <= 0 then [] else let h = QCheck2.Gen.generate1 ~rand:random_state (genopt_step ?source ?destination env state) in match h with | None -> [] | Some h -> let state = SymbolicMachine.step h env state in let rst = inner env state (size - 1) random_state in h :: rst in QCheck2.Gen.make_primitive ~gen:(inner env state size) ~shrink:(fun l -> shrink_list l) let gen_scenario : tzbtc -> liquidity -> int -> (specs * contract_id step list) QCheck2.Gen.t = fun total_tzbtc total_liquidity size -> let* specs = gen_specs total_tzbtc total_liquidity in let state, env = SymbolicMachine.build specs in let+ scenario = gen_steps env state size in (specs, scenario) let pp_scenario fmt (specs, steps) = Format.( fprintf fmt "@[<v>{@ @[<v 2> @[<v 2>specs@ = %a;@]@ @[<v 2>steps@ = @[<v>[ \ %a]@]@]@]}@]" pp_specs specs (pp_print_list ~pp_sep:(fun fmt _ -> fprintf fmt "@ ; ") (pp_step pp_contract_id)) steps) let print_scenario = Format.asprintf "%a" pp_scenario let gen_adversary_scenario : tzbtc -> liquidity -> int -> (specs * contract_id * contract_id step list) QCheck2.Gen.t = fun total_tzbtc total_liquidity size -> let* specs = gen_specs total_tzbtc total_liquidity in let state, env = SymbolicMachine.build ~subsidy:0L specs in let* c = oneofl env.implicit_accounts in let+ scenario = gen_steps ~source:c ~destination:c env state size in (specs, c, scenario) let print_adversary_scenario (specs, _, steps) = Format.asprintf "%a" pp_scenario (specs, steps) (* -------------------------------------------------------------------------- *) (* Note (1) We shrink a valid scenario by removing steps from its tails, because a prefix of a valid scenario remains a valid scenario. Removing a random element of a scenario could lead to an invalid scenario. We have to use QCheck2.Gen.make_primitive to specify the shrinking method of the generator, and avoid defaulting on the shrinking implied by QCheck2.Gen.bind *) (* Note (2) If we are not being careful, it is possible to provoke an overflow in the xtzPool and tzbtcPool. We try to avoid that as much as possible by being very careful with the steps that are likely to add xtz to the contract. *)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>