(**************************************************************************) (* *) (* Copyright (c) 2014 - 2016. *) (* Dynamic Ledger Solutions, Inc. *) (* *) (* All rights reserved. No warranty, explicit or implicit, provided. *) (* *) (**************************************************************************) type error += | Consume_roll_change | No_roll_in_contract | Deleted_contract_owning_rolls let get_contract_delegate c contract = match Contract_repr.is_default contract with | Some manager -> return (Some manager) | None -> Storage.Contract.Delegate.get_option c contract let clear_cycle c cycle = Storage.Roll.Last_for_cycle.get c cycle >>=? fun last -> Storage.Roll.Last_for_cycle.delete c cycle >>=? fun c -> let rec loop c roll = if Roll_repr.(roll = last) then return c else Storage.Roll.Owner_for_cycle.delete c (cycle, roll) >>=? fun c -> loop c (Roll_repr.succ roll) in loop c Roll_repr.first let fold ctxt ~f init = Storage.Roll.Next.get ctxt >>=? fun last -> let rec loop ctxt roll acc = acc >>=? fun acc -> if Roll_repr.(roll = last) then return acc else Storage.Roll.Owner.get_option ctxt roll >>=? function | None -> loop ctxt (Roll_repr.succ roll) (return acc) | Some contract -> loop ctxt (Roll_repr.succ roll) (f roll contract acc) in loop ctxt Roll_repr.first (return init) let freeze_rolls_for_cycle ctxt cycle = fold ctxt (ctxt, Roll_repr.first) ~f:(fun roll contract (ctxt, promoted_roll as acc) -> get_contract_delegate ctxt contract >>=? function | None -> return acc | Some delegate -> Storage.Roll.Owner_for_cycle.init ctxt (cycle, roll) delegate >>=? fun ctxt -> return (ctxt, Roll_repr.succ promoted_roll)) >>=? fun (ctxt, last_promoted_roll) -> Storage.Roll.Last_for_cycle.init ctxt cycle last_promoted_roll (* Roll selection *) module Random = struct let int32_to_bytes i = let b = MBytes.create 4 in MBytes.set_int32 b 0 i; b let level_random seed use level = let position = level.Level_repr.cycle_position in Seed_repr.initialize_new seed [MBytes.of_string ("level "^use^":"); int32_to_bytes position] let owner c kind level offset = let cycle = level.Level_repr.cycle in Seed_storage.for_cycle c cycle >>=? fun random_seed -> let rd = level_random random_seed kind level in let sequence = Seed_repr.sequence rd offset in Storage.Roll.Last_for_cycle.get c cycle >>=? fun bound -> let roll, _ = Roll_repr.random sequence bound in Storage.Roll.Owner_for_cycle.get c (cycle, roll) end let mining_rights_owner c level ~priority = Random.owner c "mining" level priority let endorsement_rights_owner c level ~slot = Random.owner c "endorsement" level (Int32.of_int slot) module Contract = struct let fresh_roll c = Storage.Roll.Next.get c >>=? fun roll -> Storage.Roll.Next.set c (Roll_repr.succ roll) >>=? fun c -> return (roll, c) let get_limbo_roll c = Storage.Roll.Limbo.get c >>=? function | None -> fresh_roll c >>=? fun (roll, c) -> Storage.Roll.Limbo.set c (Some roll) >>=? fun c -> return (roll, c) | Some roll -> return (roll, c) let consume_roll_change c contract = Storage.Roll.Contract_change.get c contract >>=? fun change -> match Tez_repr.(change - Constants_repr.roll_value) with | None -> fail Consume_roll_change | Some new_change -> Storage.Roll.Contract_change.set c contract new_change let recover_roll_change c contract = Storage.Roll.Contract_change.get c contract >>=? fun change -> Lwt.return Tez_repr.(change +? Constants_repr.roll_value) >>=? fun new_change -> Storage.Roll.Contract_change.set c contract new_change let pop_roll_from_contract c contract = recover_roll_change c contract >>=? fun c -> (* beginning: contract : roll -> successor_roll -> ... limbo : limbo_head -> ... *) Storage.Roll.Limbo.get c >>=? fun limbo_head -> Storage.Roll.Contract_roll_list.get c contract >>=? function | None -> fail No_roll_in_contract | Some roll -> Storage.Roll.Owner.delete c roll >>=? fun c -> Storage.Roll.Successor.get c roll >>=? fun successor_roll -> Storage.Roll.Contract_roll_list.set c contract successor_roll >>=? fun c -> (* contract : successor_roll -> ... roll ------^ limbo : limbo_head -> ... *) Storage.Roll.Successor.set c roll limbo_head >>=? fun c -> (* contract : successor_roll -> ... roll ------v limbo : limbo_head -> ... *) Storage.Roll.Limbo.set c (Some roll) >>=? fun c -> (* contract : successor_roll -> ... limbo : roll -> limbo_head -> ... *) Lwt.return (Ok (roll, c)) let create_roll_in_contract c contract = consume_roll_change c contract >>=? fun c -> (* beginning: contract : contract_head -> ... limbo : roll -> limbo_successor -> ... *) Storage.Roll.Contract_roll_list.get c contract >>=? fun contract_head -> get_limbo_roll c >>=? fun (roll, c) -> Storage.Roll.Owner.init c roll contract >>=? fun c -> Storage.Roll.Successor.get c roll >>=? fun limbo_successor -> Storage.Roll.Limbo.set c limbo_successor >>=? fun c -> (* contract : contract_head -> ... roll ------v limbo : limbo_successor -> ... *) Storage.Roll.Successor.set c roll contract_head >>=? fun c -> (* contract : contract_head -> ... roll ------^ limbo : limbo_successor -> ... *) Storage.Roll.Contract_roll_list.set c contract (Some roll) (* contract : roll -> contract_head -> ... limbo : limbo_successor -> ... *) let init c contract = Storage.Roll.Contract_change.init c contract Tez_repr.zero let add_amount c contract amount = Storage.Roll.Contract_change.get c contract >>=? fun change -> Lwt.return Tez_repr.(amount +? change) >>=? fun change -> Storage.Roll.Contract_change.set c contract change >>=? fun c -> let rec loop c change = match Tez_repr.(change - Constants_repr.roll_value) with | None -> Lwt.return (Ok c) | Some change -> create_roll_in_contract c contract >>=? fun c -> loop c change in loop c change let remove_amount c contract amount = let rec loop c change = if Tez_repr.(amount <= change) then Lwt.return (Ok (c, change)) else pop_roll_from_contract c contract >>=? fun (_, c) -> Lwt.return Tez_repr.(change +? Constants_repr.roll_value) >>=? fun change -> loop c change in Storage.Roll.Contract_change.get c contract >>=? fun change -> loop c change >>=? fun (c, change) -> match Tez_repr.(change - amount) with | None -> assert false | Some change -> Storage.Roll.Contract_change.set c contract change let assert_empty c contract = Storage.Roll.Contract_change.get c contract >>=? fun change -> Storage.Roll.Contract_roll_list.get c contract >>=? fun roll_list -> fail_unless (Tez_repr.(change = zero) && match roll_list with None -> true | Some _ -> false) Deleted_contract_owning_rolls end let init c = Storage.Roll.Next.init c Roll_repr.first