231 lines
8.0 KiB
OCaml
231 lines
8.0 KiB
OCaml
(*****************************************************************************)
|
|
(* *)
|
|
(* Open Source License *)
|
|
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.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. *)
|
|
(* *)
|
|
(*****************************************************************************)
|
|
|
|
type t =
|
|
| Implicit of Signature.Public_key_hash.t
|
|
| Originated of Contract_hash.t
|
|
|
|
include Compare.Make (struct
|
|
type nonrec t = t
|
|
|
|
let compare l1 l2 =
|
|
match (l1, l2) with
|
|
| (Implicit pkh1, Implicit pkh2) ->
|
|
Signature.Public_key_hash.compare pkh1 pkh2
|
|
| (Originated h1, Originated h2) ->
|
|
Contract_hash.compare h1 h2
|
|
| (Implicit _, Originated _) ->
|
|
-1
|
|
| (Originated _, Implicit _) ->
|
|
1
|
|
end)
|
|
|
|
type contract = t
|
|
|
|
type error += Invalid_contract_notation of string (* `Permanent *)
|
|
|
|
let to_b58check = function
|
|
| Implicit pbk ->
|
|
Signature.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.Data h) ->
|
|
ok (Implicit (Signature.Ed25519 h))
|
|
| Some (Secp256k1.Public_key_hash.Data h) ->
|
|
ok (Implicit (Signature.Secp256k1 h))
|
|
| Some (P256.Public_key_hash.Data h) ->
|
|
ok (Implicit (Signature.P256 h))
|
|
| Some (Contract_hash.Data h) ->
|
|
ok (Originated h)
|
|
| _ ->
|
|
error (Invalid_contract_notation s)
|
|
|
|
let pp ppf = function
|
|
| Implicit pbk ->
|
|
Signature.Public_key_hash.pp ppf pbk
|
|
| Originated h ->
|
|
Contract_hash.pp ppf h
|
|
|
|
let pp_short ppf = function
|
|
| Implicit pbk ->
|
|
Signature.Public_key_hash.pp_short ppf pbk
|
|
| Originated h ->
|
|
Contract_hash.pp_short ppf h
|
|
|
|
let encoding =
|
|
let open Data_encoding in
|
|
def
|
|
"contract_id"
|
|
~title:"A contract handle"
|
|
~description:
|
|
"A contract notation as given to an RPC or inside scripts. Can be a \
|
|
base58 implicit contract hash or a base58 originated contract hash."
|
|
@@ splitted
|
|
~binary:
|
|
(union
|
|
~tag_size:`Uint8
|
|
[ case
|
|
(Tag 0)
|
|
~title:"Implicit"
|
|
Signature.Public_key_hash.encoding
|
|
(function Implicit k -> Some k | _ -> None)
|
|
(fun k -> Implicit k);
|
|
case
|
|
(Tag 1)
|
|
(Fixed.add_padding Contract_hash.encoding 1)
|
|
~title:"Originated"
|
|
(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 implicit_contract id = Implicit id
|
|
|
|
let is_implicit = function Implicit m -> Some m | Originated _ -> None
|
|
|
|
let is_originated = function Implicit _ -> None | Originated h -> Some h
|
|
|
|
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_exn origination_nonce_encoding nonce
|
|
in
|
|
Originated (Contract_hash.hash_bytes [data])
|
|
|
|
let originated_contracts
|
|
~since:{origination_index = first; operation_hash = first_hash}
|
|
~until:( {origination_index = last; operation_hash = last_hash} as
|
|
origination_nonce ) =
|
|
assert (Operation_hash.equal first_hash last_hash) ;
|
|
let rec contracts acc origination_index =
|
|
if Compare.Int32.(origination_index < first) 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 last)
|
|
|
|
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 rpc_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
|
|
()
|
|
|
|
module Index = struct
|
|
type t = contract
|
|
|
|
let path_length = 7
|
|
|
|
let to_path c l =
|
|
let raw_key = Data_encoding.Binary.to_bytes_exn encoding c in
|
|
let (`Hex key) = MBytes.to_hex raw_key in
|
|
let (`Hex index_key) = MBytes.to_hex (Raw_hashes.blake2b raw_key) in
|
|
String.sub index_key 0 2 :: String.sub index_key 2 2
|
|
:: String.sub index_key 4 2 :: String.sub index_key 6 2
|
|
:: String.sub index_key 8 2 :: String.sub index_key 10 2 :: key :: l
|
|
|
|
let of_path = function
|
|
| []
|
|
| [_]
|
|
| [_; _]
|
|
| [_; _; _]
|
|
| [_; _; _; _]
|
|
| [_; _; _; _; _]
|
|
| [_; _; _; _; _; _]
|
|
| _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ :: _ ->
|
|
None
|
|
| [index1; index2; index3; index4; index5; index6; key] ->
|
|
let raw_key = MBytes.of_hex (`Hex key) in
|
|
let (`Hex index_key) = MBytes.to_hex (Raw_hashes.blake2b raw_key) in
|
|
assert (Compare.String.(String.sub index_key 0 2 = index1)) ;
|
|
assert (Compare.String.(String.sub index_key 2 2 = index2)) ;
|
|
assert (Compare.String.(String.sub index_key 4 2 = index3)) ;
|
|
assert (Compare.String.(String.sub index_key 6 2 = index4)) ;
|
|
assert (Compare.String.(String.sub index_key 8 2 = index5)) ;
|
|
assert (Compare.String.(String.sub index_key 10 2 = index6)) ;
|
|
Data_encoding.Binary.of_bytes encoding raw_key
|
|
|
|
let rpc_arg = rpc_arg
|
|
|
|
let encoding = encoding
|
|
|
|
let compare = compare
|
|
end
|