(**************************************************************************) (* *) (* Copyright (c) 2014 - 2017. *) (* Dynamic Ledger Solutions, Inc. *) (* *) (* All rights reserved. No warranty, explicit or implicit, provided. *) (* *) (**************************************************************************) open Tezos_hash type t = | Default of Ed25519.Public_key_hash.t | Originated of Contract_hash.t type contract = t type error += Invalid_contract_notation of string (* `Permanent *) let to_b58check = function | Default pbk -> Ed25519.Public_key_hash.to_b58check pbk | Originated h -> Contract_hash.to_b58check h let of_b58check s = match Base58.decode s with | Some (Ed25519.Public_key_hash.Hash h) -> ok (Default h) | Some (Contract_hash.Hash h) -> ok (Originated h) | _ -> error (Invalid_contract_notation s) let pp ppf = function | Default pbk -> Ed25519.Public_key_hash.pp ppf pbk | Originated h -> Contract_hash.pp ppf h let pp_short ppf = function | Default pbk -> Ed25519.Public_key_hash.pp_short ppf pbk | Originated h -> Contract_hash.pp_short ppf h let encoding = let open Data_encoding in describe ~title: "A contract handle" ~description: "A contract notation as given to an RPC or inside scripts. \ Can be a base58 public key hash, representing the default contract \ of this identity, or a base58 originated contract hash." @@ splitted ~binary: (union ~tag_size:`Uint8 [ case ~tag:0 Ed25519.Public_key_hash.encoding (function Default k -> Some k | _ -> None) (fun k -> Default k) ; case ~tag:1 Contract_hash.encoding (function Originated k -> Some k | _ -> None) (fun k -> Originated k) ; ]) ~json: (conv to_b58check (fun s -> match of_b58check s with | Ok s -> s | Error _ -> Json.cannot_destruct "Invalid contract notation.") string) let () = let open Data_encoding in register_error_kind `Permanent ~id:"contract.invalid_contract_notation" ~title: "Invalid contract notation" ~pp: (fun ppf x -> Format.fprintf ppf "Invalid contract notation %S" x) ~description: "A malformed contract notation was given to an RPC or in a script." (obj1 (req "notation" string)) (function Invalid_contract_notation loc -> Some loc | _ -> None) (fun loc -> Invalid_contract_notation loc) let default_contract id = Default id let is_default = function | Default m -> Some m | Originated _ -> None type origination_nonce = { operation_hash: Operation_hash.t ; origination_index: int32 } let origination_nonce_encoding = let open Data_encoding in conv (fun { operation_hash ; origination_index } -> (operation_hash, origination_index)) (fun (operation_hash, origination_index) -> { operation_hash ; origination_index }) @@ obj2 (req "operation" Operation_hash.encoding) (dft "index" int32 0l) let originated_contract nonce = let data = Data_encoding.Binary.to_bytes origination_nonce_encoding nonce in Originated (Contract_hash.hash_bytes [data]) let originated_contracts ({ origination_index } as origination_nonce) = let rec contracts acc origination_index = if Compare.Int32.(origination_index < 0l) then acc else let origination_nonce = { origination_nonce with origination_index } in let acc = originated_contract origination_nonce :: acc in contracts acc (Int32.pred origination_index) in contracts [] (Int32.pred origination_index) let initial_origination_nonce operation_hash = { operation_hash ; origination_index = 0l } let incr_origination_nonce nonce = let origination_index = Int32.succ nonce.origination_index in { nonce with origination_index } let arg = let construct = to_b58check in let destruct hash = match of_b58check hash with | Error _ -> Error "Cannot parse contract id" | Ok contract -> Ok contract in RPC.Arg.make ~descr: "A contract identifier encoded in b58check." ~name: "contract_id" ~construct ~destruct () let compare l1 l2 = match l1, l2 with | Default pkh1, Default pkh2 -> Ed25519.Public_key_hash.compare pkh1 pkh2 | Originated h1, Originated h2 -> Contract_hash.compare h1 h2 | Default _, Originated _ -> -1 | Originated _, Default _ -> 1 let (=) l1 l2 = Compare.Int.(=) (compare l1 l2) 0 let (<>) l1 l2 = Compare.Int.(<>) (compare l1 l2) 0 let (>) l1 l2 = Compare.Int.(>) (compare l1 l2) 0 let (>=) l1 l2 = Compare.Int.(>=) (compare l1 l2) 0 let (<=) l1 l2 = Compare.Int.(<=) (compare l1 l2) 0 let (<) l1 l2 = Compare.Int.(<) (compare l1 l2) 0 let min l1 l2 = if l1 <= l2 then l1 else l2 let max l1 l2 = if l1 >= l2 then l1 else l2 module Index = struct type t = contract let path_length = assert Compare.Int.(Ed25519.Public_key_hash.path_length = Contract_hash.path_length) ; Ed25519.Public_key_hash.path_length + 1 let to_path c l = match c with | Default k -> "pubkey" :: Ed25519.Public_key_hash.to_path k l | Originated h -> "originated" :: Contract_hash.to_path h l let of_path = function | "pubkey" :: key -> begin match Ed25519.Public_key_hash.of_path key with | None -> None | Some h -> Some (Default h) end | "originated" :: key -> begin match Contract_hash.of_path key with | None -> None | Some h -> Some (Originated h) end | _ -> None let contract_prefix s = "originated" :: Contract_hash.prefix_path s let pkh_prefix s = "pubkey" :: Ed25519.Public_key_hash.prefix_path s end