Alpha/RPC: add a low-level but typed RPC for context introspection

Example:

```
> tezos-client rpc get /chains/main/blocks/head/context/raw/json/\?depth\=1 | jq
{
  "commitments": [],
  "contracts": {
    "global_counter": 0,
    "index": []
  },
  "cycle": [
    4,
    3,
    2,
    1,
    0
  ],
  "delegates": [
    "tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN",
    "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU",
    "tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv",
    "tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv",
    "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"
  ],
  "last_block_priority": 0,
  "rolls": {
    "index": [],
    "next": 2000,
    "owner": {}
  },
  "votes": {
    "ballots": [],
    "current_period_kind": "proposal",
    "current_quorum": 8000,
    "listings": [],
    "proposals": []
  }
}
> tezos-client rpc get /chains/main/blocks/head/context/raw/json/cycle/4\?depth\=2 | jq
{
  "last_roll": [
    [
      0,
      2000
    ]
  ],
  "nonces": [],
  "random_seed": "97d50852c159ada8e9f107e98f693b059ba28336c723e6cd0f6353eb3c0cb415",
  "roll_snapshot": 0
}
> tezos-client rpc get /chains/main/blocks/head/context/raw/json/cycle/5\?depth\=2 | jq
{
  "last_roll": [
    [
      1,
      2000
    ],
    [
      0,
      2000
    ]
  ],
  "nonces": [],
  "roll_snapshot": 2
}
```
This commit is contained in:
Grégoire Henry 2018-04-24 02:17:25 +02:00 committed by Benjamin Canou
parent 74acad1472
commit 33c3d1fcbd
29 changed files with 740 additions and 191 deletions

View File

@ -13,13 +13,13 @@ $client -w none config update
sleep 2 sleep 2
#tests for the rpc service raw_context #tests for the rpc service raw_context
$client rpc get '/chains/main/blocks/head/context/raw/version' | assert '"616c706861"' $client rpc get '/chains/main/blocks/head/context/raw/bytes/version' | assert '"616c706861"'
$client rpc get '/chains/main/blocks/head/context/raw/non-existent' | assert 'No service found at this URL' $client rpc get '/chains/main/blocks/head/context/raw/bytes/non-existent' | assert 'No service found at this URL'
$client rpc get '/chains/main/blocks/head/context/raw/delegates/?depth=3' | assert '{ "ed25519": $client rpc get '/chains/main/blocks/head/context/raw/bytes/delegates/?depth=3' | assert '{ "ed25519":
{ "02": { "29": null }, "a9": { "ce": null }, "c5": { "5c": null }, { "02": { "29": null }, "a9": { "ce": null }, "c5": { "5c": null },
"da": { "c9": null }, "e7": { "67": null } } }' "da": { "c9": null }, "e7": { "67": null } } }'
$client rpc get '/chains/main/blocks/head/context/raw/non-existent?depth=-1' | assert 'Unexpected server answer' $client rpc get '/chains/main/blocks/head/context/raw/bytes/non-existent?depth=-1' | assert 'Unexpected server answer'
$client rpc get '/chains/main/blocks/head/context/raw/non-existent?depth=0' | assert 'No service found at this URL' $client rpc get '/chains/main/blocks/head/context/raw/bytes/non-existent?depth=0' | assert 'No service found at this URL'
bake bake

View File

@ -202,3 +202,10 @@ val lwt_register5:
('m, 'prefix, ((((unit * 'a) * 'b) * 'c) * 'd) * 'e, 'q , 'i, 'o) RPC_service.t -> ('m, 'prefix, ((((unit * 'a) * 'b) * 'c) * 'd) * 'e, 'q , 'i, 'o) RPC_service.t ->
('a -> 'b -> 'c -> 'd -> 'e -> 'q -> 'i -> 'o Lwt.t) -> ('a -> 'b -> 'c -> 'd -> 'e -> 'q -> 'i -> 'o Lwt.t) ->
'prefix directory 'prefix directory
(** Registring dynamic subtree. *)
val register_dynamic_directory:
?descr:string ->
'prefix directory ->
('prefix, 'a) RPC_path.t -> ('a -> 'a directory Lwt.t) ->
'prefix directory

View File

@ -218,7 +218,7 @@ let build_raw_rpc_directory
(* context *) (* context *)
register1 S.Context.Raw.read begin fun block path q () -> register1 S.Context.read begin fun block path q () ->
let depth = Option.unopt ~default:max_int q#depth in let depth = Option.unopt ~default:max_int q#depth in
fail_unless (depth >= 0) fail_unless (depth >= 0)
(Tezos_shell_services.Block_services.Invalid_depth_arg (path, depth)) >>=? fun () -> (Tezos_shell_services.Block_services.Invalid_depth_arg (path, depth)) >>=? fun () ->

View File

@ -648,11 +648,7 @@ module Make(Proto : PROTO)(Next_proto : PROTO) = struct
module Context = struct module Context = struct
let path = RPC_path.(path / "context") let path = RPC_path.(path / "context" / "raw" / "bytes")
module Raw = struct
let path = RPC_path.(path / "raw")
let context_path_arg : string RPC_arg.t = let context_path_arg : string RPC_arg.t =
let name = "context_path" in let name = "context_path" in
@ -678,8 +674,6 @@ module Make(Proto : PROTO)(Next_proto : PROTO) = struct
end end
end
let info = let info =
RPC_service.get_service RPC_service.get_service
~description:"All the information about a block." ~description:"All the information about a block."
@ -872,10 +866,6 @@ module Make(Proto : PROTO)(Next_proto : PROTO) = struct
module S = S.Context module S = S.Context
module Raw = struct
module S = S.Raw
let read ctxt = let read ctxt =
let f = make_call1 S.read ctxt in let f = make_call1 S.read ctxt in
fun ?(chain = `Main) ?(block = `Head 0) ?depth path -> fun ?(chain = `Main) ?(block = `Head 0) ?depth path ->
@ -884,8 +874,6 @@ module Make(Proto : PROTO)(Next_proto : PROTO) = struct
end end
end
module Helpers = struct module Helpers = struct
module S = S.Helpers module S = S.Helpers

View File

@ -222,8 +222,6 @@ module Make(Proto : PROTO)(Next_proto : PROTO) : sig
module Context : sig module Context : sig
module Raw : sig
val read: val read:
#simple -> ?chain:chain -> ?block:block -> #simple -> ?chain:chain -> ?block:block ->
?depth: int -> ?depth: int ->
@ -231,8 +229,6 @@ module Make(Proto : PROTO)(Next_proto : PROTO) : sig
end end
end
module Helpers : sig module Helpers : sig
module Forge : sig module Forge : sig
@ -433,8 +429,6 @@ module Make(Proto : PROTO)(Next_proto : PROTO) : sig
module Context : sig module Context : sig
module Raw : sig
val read: val read:
([ `GET ], prefix, ([ `GET ], prefix,
prefix * string list, < depth : int option >, unit, prefix * string list, < depth : int option >, unit,
@ -442,8 +436,6 @@ module Make(Proto : PROTO)(Next_proto : PROTO) : sig
end end
end
module Helpers : sig module Helpers : sig
module Forge : sig module Forge : sig

View File

@ -152,7 +152,7 @@ let level (chain, block) =
return level return level
let rpc_raw_context block path depth = let rpc_raw_context block path depth =
Shell_services.Blocks.Context.Raw.read !rpc_ctxt ~block ~depth path Shell_services.Blocks.Context.read !rpc_ctxt ~block ~depth path
module Account = struct module Account = struct

View File

@ -2,6 +2,7 @@
"hash": "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK", "hash": "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK",
"modules": [ "modules": [
"Misc", "Misc",
"Storage_description",
"State_hash", "State_hash",
"Nonce_hash", "Nonce_hash",
"Script_expr_hash", "Script_expr_hash",

View File

@ -150,3 +150,5 @@ let add_rewards = Raw_context.add_rewards
let get_fees = Raw_context.get_fees let get_fees = Raw_context.get_fees
let get_rewards = Raw_context.get_rewards let get_rewards = Raw_context.get_rewards
let description = Raw_context.description

View File

@ -975,3 +975,5 @@ val add_rewards: context -> Tez.t -> context tzresult Lwt.t
val get_fees: context -> Tez.t val get_fees: context -> Tez.t
val get_rewards: context -> Tez.t val get_rewards: context -> Tez.t
val description: context Storage_description.t

View File

@ -43,4 +43,8 @@ module Index = struct
| [ h1 ; h2 ] -> of_bytes_opt (MBytes.of_hex (`Hex (h1 ^ h2))) | [ h1 ; h2 ] -> of_bytes_opt (MBytes.of_hex (`Hex (h1 ^ h2)))
| _ -> None | _ -> None
let compare = compare
let encoding = encoding
let rpc_arg = rpc_arg
end end

View File

@ -19,9 +19,4 @@ val of_ed25519_pkh : activation_code -> Ed25519.Public_key_hash.t -> t
val activation_code_of_hex : string -> activation_code val activation_code_of_hex : string -> activation_code
module Index : sig module Index : Storage_description.INDEX with type t = t
type nonrec t = t
val path_length : int
val to_path : t -> string list -> string list
val of_path : string list -> t option
end

View File

@ -178,4 +178,7 @@ module Index = struct
Ed25519.Public_key_hash.prefix_path s Ed25519.Public_key_hash.prefix_path s
let pkh_prefix_secp256k1 s = let pkh_prefix_secp256k1 s =
Secp256k1.Public_key_hash.prefix_path s Secp256k1.Public_key_hash.prefix_path s
let rpc_arg = rpc_arg
let encoding = encoding
let compare = compare
end end

View File

@ -61,10 +61,7 @@ val origination_nonce_encoding : origination_nonce Data_encoding.t
val rpc_arg : contract RPC_arg.arg val rpc_arg : contract RPC_arg.arg
module Index : sig module Index : sig
type t = contract include Storage_description.INDEX with type t = t
val path_length: int
val to_path: t -> string list -> string list
val of_path: string list -> t option
val contract_prefix: string -> string list val contract_prefix: string -> string list
val pkh_prefix_ed25519: string -> string list val pkh_prefix_ed25519: string -> string list
val pkh_prefix_secp256k1: string -> string list val pkh_prefix_secp256k1: string -> string list

View File

@ -63,4 +63,7 @@ module Index = struct
with _ -> None with _ -> None
end end
| _ -> None | _ -> None
let rpc_arg = rpc_arg
let encoding = encoding
let compare = compare
end end

View File

@ -25,10 +25,4 @@ val of_int32_exn: int32 -> cycle
module Map : S.MAP with type key = cycle module Map : S.MAP with type key = cycle
module Index : sig module Index : Storage_description.INDEX with type t = cycle
(* Storage_functors.INDEX with type t = cycle *)
type t = cycle
val path_length: int
val to_path: t -> string list -> string list
val of_path: string list -> t option
end

View File

@ -490,6 +490,8 @@ module type T = sig
val record_bytes_stored: context -> Int64.t -> context tzresult val record_bytes_stored: context -> Int64.t -> context tzresult
val description: context Storage_description.t
end end
let mem ctxt k = Context.mem ctxt.context k let mem ctxt k = Context.mem ctxt.context k
@ -563,3 +565,5 @@ let fold_keys ctxt k ~init ~f =
let project x = x let project x = x
let absolute_key _ k = k let absolute_key _ k = k
let description = Storage_description.create ()

View File

@ -182,6 +182,8 @@ module type T = sig
within a view. *) within a view. *)
val record_bytes_stored: context -> Int64.t -> context tzresult val record_bytes_stored: context -> Int64.t -> context tzresult
val description: context Storage_description.t
end end
include T with type t := t and type context := context include T with type t := t and type context := context

View File

@ -56,4 +56,7 @@ module Index = struct
with _ -> None with _ -> None
end end
| _ -> None | _ -> None
let rpc_arg = rpc_arg
let encoding = encoding
let compare = compare
end end

View File

@ -28,9 +28,4 @@ val root: raw_level
val succ: raw_level -> raw_level val succ: raw_level -> raw_level
val pred: raw_level -> raw_level option val pred: raw_level -> raw_level option
module Index : sig module Index : Storage_description.INDEX with type t = raw_level
type t = raw_level
val path_length: int
val to_path: t -> string list -> string list
val of_path: string list -> t option
end

View File

@ -7,7 +7,7 @@
(* *) (* *)
(**************************************************************************) (**************************************************************************)
type t = int32 include Compare.Int32
type roll = t type roll = t
let encoding = Data_encoding.int32 let encoding = Data_encoding.int32
@ -25,7 +25,6 @@ let rpc_arg =
let to_int32 v = v let to_int32 v = v
let (=) = Compare.Int32.(=)
module Index = struct module Index = struct
type t = roll type t = roll
@ -40,4 +39,7 @@ module Index = struct
with _ -> None with _ -> None
end end
| _ -> None | _ -> None
let rpc_arg = rpc_arg
let encoding = encoding
let compare = compare
end end

View File

@ -23,9 +23,4 @@ val to_int32: roll -> Int32.t
val (=): roll -> roll -> bool val (=): roll -> roll -> bool
module Index : sig module Index : Storage_description.INDEX with type t = roll
type t = roll
val path_length: int
val to_path: t -> string list -> string list
val of_path: string list -> t option
end

View File

@ -64,4 +64,15 @@ let register2_fullctxt s f =
let register2 s f = let register2 s f =
register2_fullctxt s (fun { context ; _ } a1 a2 q i -> f context a1 a2 q i) register2_fullctxt s (fun { context ; _ } a1 a2 q i -> f context a1 a2 q i)
let get_rpc_services () = !rpc_services let get_rpc_services () =
let p =
RPC_directory.map
(fun c ->
rpc_init c >>= function
| Error _ -> assert false
| Ok c -> Lwt.return c.context)
(Storage_description.build_directory Alpha_context.description) in
RPC_directory.register_dynamic_directory
!rpc_services
RPC_path.(open_root / "context" / "raw" / "json")
(fun _ -> Lwt.return p)

View File

@ -33,6 +33,12 @@ module Int_index = struct
| [ c ] -> | [ c ] ->
try Some (int_of_string c) try Some (int_of_string c)
with _ -> None with _ -> None
type 'a ipath = 'a * t
let args = Storage_description.One {
rpc_arg = RPC_arg.int ;
encoding = Data_encoding.int31 ;
compare = Compare.Int.compare ;
}
end end
module String_index = struct module String_index = struct
@ -42,6 +48,23 @@ module String_index = struct
let of_path = function let of_path = function
| [ c ] -> Some c | [ c ] -> Some c
| [] | _ :: _ :: _ -> None | [] | _ :: _ :: _ -> None
type 'a ipath = 'a * t
let args = Storage_description.One {
rpc_arg = RPC_arg.string ;
encoding = Data_encoding.string ;
compare = Compare.String.compare ;
}
end
module Make_index(H : Storage_description.INDEX)
: INDEX with type t = H.t and type 'a ipath = 'a * H.t = struct
include H
type 'a ipath = 'a * t
let args = Storage_description.One {
rpc_arg ;
encoding ;
compare ;
}
end end
module Last_block_priority = module Last_block_priority =
@ -66,7 +89,7 @@ module Contract = struct
module Indexed_context = module Indexed_context =
Make_indexed_subcontext Make_indexed_subcontext
(Make_subcontext(Raw_context)(struct let name = ["index"] end)) (Make_subcontext(Raw_context)(struct let name = ["index"] end))
(Contract_repr.Index) (Make_index(Contract_repr.Index))
let fold = Indexed_context.fold_keys let fold = Indexed_context.fold_keys
let list = Indexed_context.keys let list = Indexed_context.keys
@ -81,7 +104,7 @@ module Contract = struct
(Make_subcontext (Make_subcontext
(Indexed_context.Raw_context) (Indexed_context.Raw_context)
(struct let name = ["frozen_balance"] end)) (struct let name = ["frozen_balance"] end))
(Cycle_repr.Index) (Make_index(Cycle_repr.Index))
module Frozen_deposits = module Frozen_deposits =
Frozen_balance_index.Make_map Frozen_balance_index.Make_map
@ -130,7 +153,7 @@ module Contract = struct
(Make_subcontext (Make_subcontext
(Indexed_context.Raw_context) (Indexed_context.Raw_context)
(struct let name = ["delegated"] end)) (struct let name = ["delegated"] end))
(Contract_hash) (Make_index(Contract_hash))
module Counter = module Counter =
Indexed_context.Make_map Indexed_context.Make_map
@ -191,7 +214,7 @@ end
module Delegates = module Delegates =
Make_data_set_storage Make_data_set_storage
(Make_subcontext(Raw_context)(struct let name = ["delegates"] end)) (Make_subcontext(Raw_context)(struct let name = ["delegates"] end))
(Signature.Public_key_hash) (Make_index(Signature.Public_key_hash))
(** Rolls *) (** Rolls *)
@ -200,7 +223,7 @@ module Cycle = struct
module Indexed_context = module Indexed_context =
Make_indexed_subcontext Make_indexed_subcontext
(Make_subcontext(Raw_context)(struct let name = ["cycle"] end)) (Make_subcontext(Raw_context)(struct let name = ["cycle"] end))
(Cycle_repr.Index) (Make_index(Cycle_repr.Index))
module Last_roll = module Last_roll =
Make_indexed_data_storage Make_indexed_data_storage
@ -254,7 +277,7 @@ module Cycle = struct
(Make_subcontext (Make_subcontext
(Indexed_context.Raw_context) (Indexed_context.Raw_context)
(struct let name = ["nonces"] end)) (struct let name = ["nonces"] end))
(Raw_level_repr.Index) (Make_index(Raw_level_repr.Index))
(struct (struct
type t = nonce_status type t = nonce_status
let encoding = nonce_status_encoding let encoding = nonce_status_encoding
@ -278,7 +301,7 @@ module Roll = struct
module Indexed_context = module Indexed_context =
Make_indexed_subcontext Make_indexed_subcontext
(Make_subcontext(Raw_context)(struct let name = ["index"] end)) (Make_subcontext(Raw_context)(struct let name = ["index"] end))
(Roll_repr.Index) (Make_index(Roll_repr.Index))
module Next = module Next =
Make_single_data_storage Make_single_data_storage
@ -326,13 +349,28 @@ module Roll = struct
try Some (c, int_of_string l2) try Some (c, int_of_string l2)
with _ -> None with _ -> None
end end
type 'a ipath = ('a * Cycle_repr.t) * int
let left_args =
Storage_description.One {
rpc_arg = Cycle_repr.rpc_arg ;
encoding = Cycle_repr.encoding ;
compare = Cycle_repr.compare
}
let right_args =
Storage_description.One {
rpc_arg = RPC_arg.int ;
encoding = Data_encoding.int31 ;
compare = Compare.Int.compare ;
}
let args =
Storage_description.(Pair (left_args, right_args))
end end
module Owner = module Owner =
Make_indexed_data_snapshotable_storage Make_indexed_data_snapshotable_storage
(Make_subcontext(Raw_context)(struct let name = ["owner"] end)) (Make_subcontext(Raw_context)(struct let name = ["owner"] end))
(Snapshoted_owner_index) (Snapshoted_owner_index)
(Roll_repr.Index) (Make_index(Roll_repr.Index))
(Signature.Public_key) (Signature.Public_key)
module Snapshot_for_cycle = Cycle.Roll_snapshot module Snapshot_for_cycle = Cycle.Roll_snapshot
@ -379,18 +417,18 @@ module Vote = struct
module Listings = module Listings =
Make_indexed_data_storage Make_indexed_data_storage
(Make_subcontext(Raw_context)(struct let name = ["listings"] end)) (Make_subcontext(Raw_context)(struct let name = ["listings"] end))
(Signature.Public_key_hash) (Make_index(Signature.Public_key_hash))
(Int32) (Int32)
module Proposals = module Proposals =
Make_data_set_storage Make_data_set_storage
(Make_subcontext(Raw_context)(struct let name = ["proposals"] end)) (Make_subcontext(Raw_context)(struct let name = ["proposals"] end))
(Pair(Protocol_hash)(Signature.Public_key_hash)) (Pair(Make_index(Protocol_hash))(Make_index(Signature.Public_key_hash)))
module Ballots = module Ballots =
Make_indexed_data_storage Make_indexed_data_storage
(Make_subcontext(Raw_context)(struct let name = ["ballots"] end)) (Make_subcontext(Raw_context)(struct let name = ["ballots"] end))
(Signature.Public_key_hash) (Make_index(Signature.Public_key_hash))
(struct (struct
type t = Vote_repr.ballot type t = Vote_repr.ballot
let encoding = Vote_repr.ballot_encoding let encoding = Vote_repr.ballot_encoding
@ -435,7 +473,7 @@ end
module Commitments = module Commitments =
Make_indexed_data_storage Make_indexed_data_storage
(Make_subcontext(Raw_context)(struct let name = ["commitments"] end)) (Make_subcontext(Raw_context)(struct let name = ["commitments"] end))
(Blinded_public_key_hash.Index) (Make_index(Blinded_public_key_hash.Index))
(Tez_repr) (Tez_repr)
(** Ramp up security deposits... *) (** Ramp up security deposits... *)
@ -445,7 +483,7 @@ module Ramp_up = struct
module Rewards = module Rewards =
Make_indexed_data_storage Make_indexed_data_storage
(Make_subcontext(Raw_context)(struct let name = ["ramp_up"; "rewards"] end)) (Make_subcontext(Raw_context)(struct let name = ["ramp_up"; "rewards"] end))
(Cycle_repr.Index) (Make_index(Cycle_repr.Index))
(struct (struct
type t = Tez_repr.t * Tez_repr.t type t = Tez_repr.t * Tez_repr.t
let encoding = Data_encoding.tup2 Tez_repr.encoding Tez_repr.encoding let encoding = Data_encoding.tup2 Tez_repr.encoding Tez_repr.encoding
@ -454,7 +492,7 @@ module Ramp_up = struct
module Security_deposits = module Security_deposits =
Make_indexed_data_storage Make_indexed_data_storage
(Make_subcontext(Raw_context)(struct let name = ["ramp_up"; "deposits"] end)) (Make_subcontext(Raw_context)(struct let name = ["ramp_up"; "deposits"] end))
(Cycle_repr.Index) (Make_index(Cycle_repr.Index))
(struct (struct
type t = Tez_repr.t * Tez_repr.t type t = Tez_repr.t * Tez_repr.t
let encoding = Data_encoding.tup2 Tez_repr.encoding Tez_repr.encoding let encoding = Data_encoding.tup2 Tez_repr.encoding Tez_repr.encoding

View File

@ -0,0 +1,291 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
module StringMap = Map.Make(String)
type 'key t = 'key description ref
and 'key description =
| Empty : 'key description
| Value : { get: 'key -> 'a option tzresult Lwt.t ;
encoding: 'a Data_encoding.t } -> 'key description
| NamedDir: 'key t StringMap.t -> 'key description
| IndexedDir: { arg: 'a RPC_arg.t ;
arg_encoding: 'a Data_encoding.t ;
list: 'key -> 'a list tzresult Lwt.t ;
subdir: ('key * 'a) t }-> 'key description
let rec register_named_subcontext : type r. r t -> string list -> r t =
fun dir names ->
match !dir, names with
| _, [] -> dir
| Value _, _ -> invalid_arg ""
| IndexedDir _, _ -> invalid_arg ""
| Empty, name :: names ->
let subdir = ref Empty in
dir := NamedDir (StringMap.singleton name subdir) ;
register_named_subcontext subdir names
| NamedDir map, name :: names ->
let subdir =
match StringMap.find_opt name map with
| Some subdir -> subdir
| None ->
let subdir = ref Empty in
dir := NamedDir (StringMap.add name subdir map) ;
subdir in
register_named_subcontext subdir names
type (_, _, _) args =
| One : { rpc_arg: 'a RPC_arg.t ;
encoding: 'a Data_encoding.t ;
compare: 'a -> 'a -> int } -> ('key, 'a, 'key * 'a) args
| Pair : ('key, 'a, 'inter_key) args *
('inter_key, 'b, 'sub_key) args -> ('key, 'a * 'b, 'sub_key) args
let rec unpack : type a b c. (a, b, c) args -> c -> a * b = function
| One _ -> (fun x -> x)
| Pair (l, r) ->
let unpack_l = unpack l in
let unpack_r = unpack r in
fun x ->
let c, d = unpack_r x in
let b, a = unpack_l c in
(b, (a, d))
let rec pack : type a b c. (a, b, c) args -> a -> b -> c = function
| One _ -> (fun b a -> (b, a))
| Pair (l, r) ->
let pack_l = pack l in
let pack_r = pack r in
fun b (a, d) ->
let c = pack_l b a in
pack_r c d
let rec compare : type a b c. (a, b, c) args -> b -> b -> int = function
| One { compare ; _ } -> compare
| Pair (l, r) ->
let compare_l = compare l in
let compare_r = compare r in
fun (a1, b1) (a2, b2) ->
match compare_l a1 a2 with
| 0 -> compare_r b1 b2
| x -> x
let destutter equal l =
match l with
| [] -> []
| (i, _) :: l ->
let rec loop acc i = function
| [] -> acc
| (j, _) :: l ->
if equal i j then loop acc i l
else loop (j :: acc) j l in
loop [i] i l
let rec register_indexed_subcontext
: type r a b. r t -> list:(r -> a list tzresult Lwt.t) ->
(r, a, b) args -> b t =
fun dir ~list path ->
match path with
| Pair (left, right) ->
let compare_left = compare left in
let equal_left x y = Compare.Int.(compare_left x y = 0) in
let list_left r =
list r >>=? fun l ->
return (destutter equal_left l) in
let list_right r =
let a, k = unpack left r in
list a >>=? fun l ->
return
(List.map snd
(List.filter (fun (x, _) -> equal_left x k) l)) in
register_indexed_subcontext
(register_indexed_subcontext dir ~list:list_left left)
~list:list_right right
| One { rpc_arg = arg ; encoding = arg_encoding ; _ } ->
match !dir with
| Value _ -> invalid_arg ""
| NamedDir _ -> invalid_arg ""
| Empty ->
let subdir = ref Empty in
dir := IndexedDir { arg ; arg_encoding ; list ; subdir };
subdir
| IndexedDir { arg = inner_arg ; subdir ; _ } ->
match RPC_arg.eq arg inner_arg with
| None -> invalid_arg ""
| Some RPC_arg.Eq -> subdir
let register_value :
type a b. a t -> get:(a -> b option tzresult Lwt.t) -> b Data_encoding.t -> unit =
fun dir ~get encoding ->
match !dir with
| Empty -> dir := Value { get ; encoding }
| _ -> invalid_arg ""
let create () = ref Empty
let rec pp : type a. Format.formatter -> a t -> unit = fun ppf dir ->
match !dir with
| Empty ->
Format.fprintf ppf "EMPTY"
| Value _e ->
Format.fprintf ppf "Value"
| NamedDir map ->
Format.fprintf ppf "@[<v>%a@]"
(Format.pp_print_list pp_item)
(StringMap.bindings map)
| IndexedDir { arg ; subdir ; _ } ->
let name = Format.asprintf "<%s>" (RPC_arg.descr arg).name in
pp_item ppf (name, subdir)
and pp_item : type a. Format.formatter -> (string * a t) -> unit =
fun ppf (name, dir) ->
Format.fprintf ppf "@[<v 2>%s@ %a@]"
name
pp dir
module type INDEX = sig
type t
val path_length: int
val to_path: t -> string list -> string list
val of_path: string list -> t option
val rpc_arg: t RPC_arg.t
val encoding: t Data_encoding.t
val compare: t -> t -> int
end
type _ handler =
Handler :
{ encoding: 'a Data_encoding.t ;
get: 'key -> int -> 'a tzresult Lwt.t } -> 'key handler
type _ opt_handler =
Opt_handler :
{ encoding: 'a Data_encoding.t ;
get: 'key -> int -> 'a option tzresult Lwt.t } -> 'key opt_handler
let rec combine_object = function
| [] -> Handler { encoding = Data_encoding.unit ;
get = fun _ _ -> return () }
| (name, Opt_handler handler) :: fields ->
let Handler handlers = combine_object fields in
Handler { encoding =
Data_encoding.merge_objs
Data_encoding.(obj1 (opt name (dynamic_size handler.encoding)))
handlers.encoding ;
get = fun k i ->
handler.get k i >>=? fun v1 ->
handlers.get k i >>=? fun v2 ->
return (v1, v2) }
type query = {
depth: int ;
}
let depth_query =
let open RPC_query in
query (fun depth -> { depth })
|+ field "depth" RPC_arg.int 0 (fun t -> t.depth)
|> seal
let build_directory : type key. key t -> key RPC_directory.t =
fun dir ->
let rpc_dir = ref (RPC_directory.empty : key RPC_directory.t) in
let register : type ikey. (key, ikey) RPC_path.t -> ikey opt_handler -> unit =
fun path (Opt_handler { encoding ; get }) ->
let service =
RPC_service.get_service
~query: depth_query
~output: encoding
path in
rpc_dir :=
RPC_directory.register !rpc_dir service begin
fun k q () ->
get k (q.depth + 1) >>=? function
| None -> raise Not_found
| Some x -> return x
end in
let rec build_handler : type ikey. ikey t -> (key, ikey) RPC_path.t -> ikey opt_handler =
fun dir path ->
match !dir with
| Empty -> Opt_handler { encoding = Data_encoding.unit ;
get = fun _ _ -> return None }
| Value { get ; encoding } ->
let handler =
Opt_handler {
encoding ;
get =
fun k i -> if Compare.Int.(i < 0) then return None else get k
} in
register path handler ;
handler
| NamedDir map ->
let fields = StringMap.bindings map in
let fields =
List.map
(fun (name, dir) ->
(name, build_handler dir RPC_path.(path / name)))
fields in
let Handler handler = combine_object fields in
let handler =
Opt_handler
{ encoding = handler.encoding ;
get = fun k i ->
if Compare.Int.(i < 0) then
return None
else
handler.get k (i-1) >>=? fun v ->
return (Some v) } in
register path handler ;
handler
| IndexedDir { arg ; arg_encoding ; list ; subdir } ->
let Opt_handler handler =
build_handler subdir RPC_path.(path /: arg) in
let encoding =
let open Data_encoding in
union [
case (Tag 0)
(dynamic_size arg_encoding)
(function (key, None) -> Some key | _ -> None)
(fun key -> (key, None)) ;
case (Tag 1)
(tup2
(dynamic_size arg_encoding)
(dynamic_size handler.encoding))
(* (obj2 *)
(* (req "key" (dynamic_size arg_encoding)) *)
(* (req "value" (dynamic_size handler.encoding))) *)
(function (key, Some value) -> Some (key, value) | _ -> None)
(fun (key, value) -> (key, Some value)) ;
] in
let get k i =
if Compare.Int.(i < 0) then return None
else if Compare.Int.(i = 0) then return (Some [])
else
list k >>=? fun keys ->
map_p
(fun key ->
if Compare.Int.(i = 1) then
return (key, None)
else
handler.get (k, key) (i-1) >>=? fun value ->
return (key, value))
keys >>=? fun values ->
return (Some values) in
let handler =
Opt_handler {
encoding = Data_encoding.(list (dynamic_size encoding)) ;
get ;
} in
register path handler ;
handler in
ignore (build_handler dir RPC_path.open_root : key opt_handler) ;
!rpc_dir

View File

@ -0,0 +1,66 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
(** Typed description of the key-value context. *)
type 'key t
(** Trivial display of the key-value context layout. *)
val pp: Format.formatter -> 'key t -> unit
(** Export an RPC hierarchy for querying the context. There is one service
by possible path in the context. Services for "directory" are able to
aggregate in one JSON object the whole subtree. *)
val build_directory: 'key t -> 'key RPC_directory.t
(** Create a empty context description,
keys will be registred by side effects. *)
val create: unit -> 'key t
(** Register a single key accessor at a given path. *)
val register_value:
'key t ->
get:('key -> 'a option tzresult Lwt.t) ->
'a Data_encoding.t -> unit
(** Return a description for a prefixed fragment of the given context.
All keys registred in the subcontext will be shared by the external
context *)
val register_named_subcontext: 'key t -> string list -> 'key t
(** Description of an index as a sequence of `RPC_arg.t`. *)
type (_, _, _) args =
| One : { rpc_arg: 'a RPC_arg.t ;
encoding: 'a Data_encoding.t ;
compare: 'a -> 'a -> int } -> ('key, 'a, 'key * 'a) args
| Pair : ('key, 'a, 'inter_key) args *
('inter_key, 'b, 'sub_key) args -> ('key, 'a * 'b, 'sub_key) args
(** Return a description for a indexed sub-context.
All keys registred in the subcontext will be shared by the external
context. One should provide a function to list all the registred
index in the context. *)
val register_indexed_subcontext:
'key t ->
list:('key -> 'arg list tzresult Lwt.t) ->
('key, 'arg, 'sub_key) args -> 'sub_key t
(** Helpers for manipulating and defining indexes. *)
val pack: ('key, 'a, 'sub_key) args -> 'key -> 'a -> 'sub_key
val unpack: ('key, 'a, 'sub_key) args -> 'sub_key -> 'key * 'a
module type INDEX = sig
type t
val path_length: int
val to_path: t -> string list -> string list
val of_path: string list -> t option
val rpc_arg: t RPC_arg.t
val encoding: t Data_encoding.t
val compare: t -> t -> int
end

View File

@ -77,6 +77,8 @@ module Make_subcontext (C : Raw_context.T) (N : NAME)
let absolute_key c k = C.absolute_key c (to_key k) let absolute_key c k = C.absolute_key c (to_key k)
let consume_gas = C.consume_gas let consume_gas = C.consume_gas
let record_bytes_stored = C.record_bytes_stored let record_bytes_stored = C.record_bytes_stored
let description =
Storage_description.register_named_subcontext C.description N.name
end end
module Make_single_data_storage (C : Raw_context.T) (N : NAME) (V : VALUE) module Make_single_data_storage (C : Raw_context.T) (N : NAME) (V : VALUE)
@ -118,6 +120,14 @@ module Make_single_data_storage (C : Raw_context.T) (N : NAME) (V : VALUE)
let delete t = let delete t =
C.delete t N.name >>=? fun t -> C.delete t N.name >>=? fun t ->
return (C.project t) return (C.project t)
let () =
let open Storage_description in
register_value
~get:get_option
(register_named_subcontext C.description N.name)
V.encoding
end end
module Make_single_carbonated_data_storage module Make_single_carbonated_data_storage
@ -219,6 +229,14 @@ module Make_single_carbonated_data_storage
match v with match v with
| None -> remove c | None -> remove c
| Some v -> init_set c v | Some v -> init_set c v
let () =
let open Storage_description in
register_value
~get:(fun c -> get_option c >>=? fun (_, v) -> return v)
(register_named_subcontext C.description N.name)
V.encoding
end end
module type INDEX = sig module type INDEX = sig
@ -226,6 +244,8 @@ module type INDEX = sig
val path_length: int val path_length: int
val to_path: t -> string list -> string list val to_path: t -> string list -> string list
val of_path: string list -> t option val of_path: string list -> t option
type 'a ipath
val args: ('a, t, 'a ipath) Storage_description.args
end end
module Pair(I1 : INDEX)(I2 : INDEX) module Pair(I1 : INDEX)(I2 : INDEX)
@ -240,6 +260,8 @@ module Pair(I1 : INDEX)(I2 : INDEX)
match I1.of_path l1, I2.of_path l2 with match I1.of_path l1, I2.of_path l2 with
| Some x, Some y -> Some (x, y) | Some x, Some y -> Some (x, y)
| _ -> None | _ -> None
type 'a ipath = 'a I1.ipath I2.ipath
let args = Storage_description.Pair (I1.args, I2.args)
end end
module Make_data_set_storage (C : Raw_context.T) (I : INDEX) module Make_data_set_storage (C : Raw_context.T) (I : INDEX)
@ -290,6 +312,21 @@ module Make_data_set_storage (C : Raw_context.T) (I : INDEX)
let elements s = let elements s =
fold s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) fold s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc))
let () =
let open Storage_description in
let unpack = unpack I.args in
register_value
(* TODO fixme 'elements...' *)
~get:(fun c ->
let (c, k) = unpack c in
mem c k >>= function
| true -> return (Some true)
| false -> return None)
(register_indexed_subcontext
~list:(fun c -> elements c >>= return)
C.description I.args)
Data_encoding.bool
end end
module Make_indexed_data_storage module Make_indexed_data_storage
@ -371,6 +408,18 @@ module Make_indexed_data_storage
let keys s = let keys s =
fold_keys s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) fold_keys s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc))
let () =
let open Storage_description in
let unpack = unpack I.args in
register_value
~get:(fun c ->
let (c, k) = unpack c in
get_option c k)
(register_indexed_subcontext
~list:(fun c -> keys c >>= return)
C.description I.args)
V.encoding
end end
module Make_indexed_carbonated_data_storage module Make_indexed_carbonated_data_storage
@ -536,6 +585,20 @@ module Make_indexed_carbonated_data_storage
let keys s = let keys s =
fold_keys s ~init:[] ~f:(fun p (s, acc) -> return (s, p :: acc)) fold_keys s ~init:[] ~f:(fun p (s, acc) -> return (s, p :: acc))
let () =
let open Storage_description in
let unpack = unpack I.args in
register_value
(* TODO export consumed gas ?? *)
~get:(fun c ->
let (c, k) = unpack c in
get_option c k >>=? fun (_, v) ->
return v)
(register_indexed_subcontext
~list:(fun c -> keys c >>=? fun (_, l) -> return l)
C.description I.args)
V.encoding
end end
@ -574,54 +637,18 @@ end
module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX) module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
: Indexed_raw_context with type t = C.t : Indexed_raw_context with type t = C.t
and type key = I.t = struct and type key = I.t
and type 'a ipath = 'a I.ipath = struct
type t = C.t type t = C.t
type context = t type context = t
type key = I.t type key = I.t
type 'a ipath = 'a I.ipath
let clear t = let clear t =
C.remove_rec t [] >>= fun t -> C.remove_rec t [] >>= fun t ->
Lwt.return (C.project t) Lwt.return (C.project t)
module Raw_context = struct
type t = C.t * I.t
type context = t
let to_key i k = I.to_path i k
let of_key k = Misc.remove_elem_from_list I.path_length k
let mem (t, i) k = C.mem t (to_key i k)
let dir_mem (t, i) k = C.dir_mem t (to_key i k)
let get (t, i) k = C.get t (to_key i k)
let get_option (t, i) k = C.get_option t (to_key i k)
let init (t, i) k v =
C.init t (to_key i k) v >>=? fun t -> return (t, i)
let set (t, i) k v =
C.set t (to_key i k) v >>=? fun t -> return (t, i)
let init_set (t, i) k v =
C.init_set t (to_key i k) v >>= fun t -> Lwt.return (t, i)
let set_option (t, i) k v =
C.set_option t (to_key i k) v >>= fun t -> Lwt.return (t, i)
let delete (t, i) k =
C.delete t (to_key i k) >>=? fun t -> return (t, i)
let remove (t, i) k =
C.remove t (to_key i k) >>= fun t -> Lwt.return (t, i)
let remove_rec (t, i) k =
C.remove_rec t (to_key i k) >>= fun t -> Lwt.return (t, i)
let copy (t, i) ~from ~to_ =
C.copy t ~from:(to_key i from) ~to_:(to_key i to_) >>=? fun t ->
return (t, i)
let fold (t, i) k ~init ~f =
C.fold t (to_key i k) ~init
~f:(fun k acc -> f (map_key of_key k) acc)
let keys (t, i) k = C.keys t (to_key i k) >|= fun keys -> List.map of_key keys
let fold_keys (t, i) k ~init ~f =
C.fold_keys t (to_key i k) ~init ~f:(fun k acc -> f (of_key k) acc)
let project (t, _) = C.project t
let absolute_key (t, i) k = C.absolute_key t (to_key i k)
let consume_gas (t, k) c = C.consume_gas t c >>? fun t -> ok (t, k)
let record_bytes_stored (t, k) c = C.record_bytes_stored t c >>? fun t -> ok (t, k)
end
let fold_keys t ~init ~f = let fold_keys t ~init ~f =
let rec dig i path acc = let rec dig i path acc =
if Compare.Int.(i <= 0) then if Compare.Int.(i <= 0) then
@ -640,6 +667,76 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
fold_keys t ~init:[] ~f:(fun i acc -> Lwt.return (i :: acc)) fold_keys t ~init:[] ~f:(fun i acc -> Lwt.return (i :: acc))
let list t k = C.fold t k ~init:[] ~f:(fun k acc -> Lwt.return (k :: acc)) let list t k = C.fold t k ~init:[] ~f:(fun k acc -> Lwt.return (k :: acc))
let description =
Storage_description.register_indexed_subcontext
~list:(fun c -> keys c >>= return)
C.description
I.args
let unpack = Storage_description.unpack I.args
let pack = Storage_description.pack I.args
module Raw_context = struct
type t = C.t I.ipath
type context = t
let to_key i k = I.to_path i k
let of_key k = Misc.remove_elem_from_list I.path_length k
let mem c k = let (t, i) = unpack c in C.mem t (to_key i k)
let dir_mem c k = let (t, i) = unpack c in C.dir_mem t (to_key i k)
let get c k = let (t, i) = unpack c in C.get t (to_key i k)
let get_option c k = let (t, i) = unpack c in C.get_option t (to_key i k)
let init c k v =
let (t, i) = unpack c in
C.init t (to_key i k) v >>=? fun t -> return (pack t i)
let set c k v =
let (t, i) = unpack c in
C.set t (to_key i k) v >>=? fun t -> return (pack t i)
let init_set c k v =
let (t, i) = unpack c in
C.init_set t (to_key i k) v >>= fun t -> Lwt.return (pack t i)
let set_option c k v =
let (t, i) = unpack c in
C.set_option t (to_key i k) v >>= fun t -> Lwt.return (pack t i)
let delete c k =
let (t, i) = unpack c in
C.delete t (to_key i k) >>=? fun t -> return (pack t i)
let remove c k =
let (t, i) = unpack c in
C.remove t (to_key i k) >>= fun t -> Lwt.return (pack t i)
let remove_rec c k =
let (t, i) = unpack c in
C.remove_rec t (to_key i k) >>= fun t -> Lwt.return (pack t i)
let copy c ~from ~to_ =
let (t, i) = unpack c in
C.copy t ~from:(to_key i from) ~to_:(to_key i to_) >>=? fun t ->
return (pack t i)
let fold c k ~init ~f =
let (t, i) = unpack c in
C.fold t (to_key i k) ~init
~f:(fun k acc -> f (map_key of_key k) acc)
let keys c k =
let (t, i) = unpack c in
C.keys t (to_key i k) >|= fun keys -> List.map of_key keys
let fold_keys c k ~init ~f =
let (t, i) = unpack c in
C.fold_keys t (to_key i k) ~init ~f:(fun k acc -> f (of_key k) acc)
let project c =
let (t, _) = unpack c in
C.project t
let absolute_key c k =
let (t, i) = unpack c in
C.absolute_key t (to_key i k)
let consume_gas c g =
let (t, i) = unpack c in
C.consume_gas t g >>? fun t -> ok (pack t i)
let record_bytes_stored c v =
let (t, i) = unpack c in
C.record_bytes_stored t v >>? fun t ->
ok (pack t i)
let description = description
end
let resolve t prefix = let resolve t prefix =
let rec loop i prefix = function let rec loop i prefix = function
| [] when Compare.Int.(i = I.path_length) -> begin | [] when Compare.Int.(i = I.path_length) -> begin
@ -679,12 +776,14 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
type context = t type context = t
type elt = I.t type elt = I.t
let inited = MBytes.of_string "inited" let inited = MBytes.of_string "inited"
let mem s i = Raw_context.mem (s, i) N.name let mem s i = Raw_context.mem (pack s i) N.name
let add s i = let add s i =
Raw_context.init_set (s, i) N.name inited >>= fun (s, _) -> Raw_context.init_set (pack s i) N.name inited >>= fun c ->
let (s, _) = unpack c in
Lwt.return (C.project s) Lwt.return (C.project s)
let del s i = let del s i =
Raw_context.remove (s, i) N.name >>= fun (s, _) -> Raw_context.remove (pack s i) N.name >>= fun c ->
let (s, _) = unpack c in
Lwt.return (C.project s) Lwt.return (C.project s)
let set s i = function let set s i = function
| true -> add s i | true -> add s i
@ -693,7 +792,8 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
fold_keys s fold_keys s
~init:s ~init:s
~f:begin fun i s -> ~f:begin fun i s ->
Raw_context.remove (s, i) N.name >>= fun (s, _) -> Raw_context.remove (pack s i) N.name >>= fun c ->
let (s, _) = unpack c in
Lwt.return s Lwt.return s
end >>= fun t -> end >>= fun t ->
Lwt.return (C.project t) Lwt.return (C.project t)
@ -705,6 +805,19 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
| false -> Lwt.return acc) | false -> Lwt.return acc)
let elements s = let elements s =
fold s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) fold s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc))
let () =
let open Storage_description in
let unpack = unpack I.args in
register_value
~get:(fun c ->
let (c, k) = unpack c in
mem c k >>= function
| true -> return (Some true)
| false -> return None)
(register_named_subcontext Raw_context.description N.name)
Data_encoding.bool
end end
module Make_map (N : NAME) (V : VALUE) = struct module Make_map (N : NAME) (V : VALUE) = struct
@ -714,42 +827,49 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
type value = V.t type value = V.t
include Make_encoder(V) include Make_encoder(V)
let mem s i = let mem s i =
Raw_context.mem (s,i) N.name Raw_context.mem (pack s i) N.name
let get s i = let get s i =
Raw_context.get (s,i) N.name >>=? fun b -> Raw_context.get (pack s i) N.name >>=? fun b ->
let key = Raw_context.absolute_key (s,i) N.name in let key = Raw_context.absolute_key (pack s i) N.name in
Lwt.return (of_bytes ~key b) Lwt.return (of_bytes ~key b)
let get_option s i = let get_option s i =
Raw_context.get_option (s,i) N.name >>= function Raw_context.get_option (pack s i) N.name >>= function
| None -> return None | None -> return None
| Some b -> | Some b ->
let key = Raw_context.absolute_key (s,i) N.name in let key = Raw_context.absolute_key (pack s i) N.name in
match of_bytes ~key b with match of_bytes ~key b with
| Ok v -> return (Some v) | Ok v -> return (Some v)
| Error _ as err -> Lwt.return err | Error _ as err -> Lwt.return err
let set s i v = let set s i v =
Raw_context.set (s,i) N.name (to_bytes v) >>=? fun (s, _) -> Raw_context.set (pack s i) N.name (to_bytes v) >>=? fun c ->
let (s, _) = unpack c in
return (C.project s) return (C.project s)
let init s i v = let init s i v =
Raw_context.init (s,i) N.name (to_bytes v) >>=? fun (s, _) -> Raw_context.init (pack s i) N.name (to_bytes v) >>=? fun c ->
let (s, _) = unpack c in
return (C.project s) return (C.project s)
let init_set s i v = let init_set s i v =
Raw_context.init_set (s,i) N.name (to_bytes v) >>= fun (s, _) -> Raw_context.init_set (pack s i) N.name (to_bytes v) >>= fun c ->
let (s, _) = unpack c in
Lwt.return (C.project s) Lwt.return (C.project s)
let set_option s i v = let set_option s i v =
Raw_context.set_option (s,i) Raw_context.set_option (pack s i)
N.name (Option.map ~f:to_bytes v) >>= fun (s, _) -> N.name (Option.map ~f:to_bytes v) >>= fun c ->
let (s, _) = unpack c in
Lwt.return (C.project s) Lwt.return (C.project s)
let remove s i = let remove s i =
Raw_context.remove (s,i) N.name >>= fun (s, _) -> Raw_context.remove (pack s i) N.name >>= fun c ->
let (s, _) = unpack c in
Lwt.return (C.project s) Lwt.return (C.project s)
let delete s i = let delete s i =
Raw_context.delete (s,i) N.name >>=? fun (s, _) -> Raw_context.delete (pack s i) N.name >>=? fun c ->
let (s, _) = unpack c in
return (C.project s) return (C.project s)
let clear s = let clear s =
fold_keys s ~init:s fold_keys s ~init:s
~f:begin fun i s -> ~f:begin fun i s ->
Raw_context.remove (s,i) N.name >>= fun (s, _) -> Raw_context.remove (pack s i) N.name >>= fun c ->
let (s, _) = unpack c in
Lwt.return s Lwt.return s
end >>= fun t -> end >>= fun t ->
Lwt.return (C.project t) Lwt.return (C.project t)
@ -769,6 +889,17 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
| true -> f i acc) | true -> f i acc)
let keys s = let keys s =
fold_keys s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) fold_keys s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc))
let () =
let open Storage_description in
let unpack = unpack I.args in
register_value
~get:(fun c ->
let (c, k) = unpack c in
get_option c k)
(register_named_subcontext Raw_context.description N.name)
V.encoding
end end
module Make_carbonated_map (N : NAME) (V : CARBONATED_VALUE) = struct module Make_carbonated_map (N : NAME) (V : CARBONATED_VALUE) = struct
@ -813,39 +944,40 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
Lwt.return (Raw_context.consume_gas c (Gas_limit_repr.write_bytes_cost Z.zero)) >>=? fun c -> Lwt.return (Raw_context.consume_gas c (Gas_limit_repr.write_bytes_cost Z.zero)) >>=? fun c ->
del c (len_name N.name) del c (len_name N.name)
let mem s i = let mem s i =
consume_mem_gas (s, i) >>=? fun c -> consume_mem_gas (pack s i) >>=? fun c ->
Raw_context.mem c N.name >>= fun res -> Raw_context.mem c N.name >>= fun res ->
return (Raw_context.project c, res) return (Raw_context.project c, res)
let get s i = let get s i =
consume_read_gas Raw_context.get (s, i) >>=? fun c -> consume_read_gas Raw_context.get (pack s i) >>=? fun c ->
Raw_context.get c N.name >>=? fun b -> Raw_context.get c N.name >>=? fun b ->
let key = Raw_context.absolute_key c N.name in let key = Raw_context.absolute_key c N.name in
Lwt.return (of_bytes ~key b) >>=? fun v -> Lwt.return (of_bytes ~key b) >>=? fun v ->
return (Raw_context.project c, v) return (Raw_context.project c, v)
let get_option s i = let get_option s i =
consume_mem_gas (s, i) >>=? fun (s, _) -> consume_mem_gas (pack s i) >>=? fun c ->
Raw_context.mem (s, i) N.name >>= fun exists -> let (s, _) = unpack c in
Raw_context.mem (pack s i) N.name >>= fun exists ->
if exists then if exists then
get s i >>=? fun (s, v) -> get s i >>=? fun (s, v) ->
return (s, Some v) return (s, Some v)
else else
return (C.project s, None) return (C.project s, None)
let set s i v = let set s i v =
consume_write_gas Raw_context.set (s, i) v >>=? fun (c, bytes) -> consume_write_gas Raw_context.set (pack s i) v >>=? fun (c, bytes) ->
existing_size (s, i) >>=? fun prev_size -> existing_size (pack s i) >>=? fun prev_size ->
Raw_context.set c N.name bytes >>=? fun c -> Raw_context.set c N.name bytes >>=? fun c ->
let size_diff = MBytes.length bytes - prev_size in let size_diff = MBytes.length bytes - prev_size in
Lwt.return (Raw_context.record_bytes_stored c (Int64.of_int size_diff)) >>=? fun c -> Lwt.return (Raw_context.record_bytes_stored c (Int64.of_int size_diff)) >>=? fun c ->
return (Raw_context.project c, size_diff) return (Raw_context.project c, size_diff)
let init s i v = let init s i v =
consume_write_gas Raw_context.init (s, i) v >>=? fun (c, bytes) -> consume_write_gas Raw_context.init (pack s i) v >>=? fun (c, bytes) ->
Raw_context.init c N.name bytes >>=? fun c -> Raw_context.init c N.name bytes >>=? fun c ->
let size = MBytes.length bytes in let size = MBytes.length bytes in
Lwt.return (Raw_context.record_bytes_stored c (Int64.of_int size)) >>=? fun c -> Lwt.return (Raw_context.record_bytes_stored c (Int64.of_int size)) >>=? fun c ->
return (Raw_context.project c, size) return (Raw_context.project c, size)
let init_set s i v = let init_set s i v =
let init_set c k v = Raw_context.init_set c k v >>= return in let init_set c k v = Raw_context.init_set c k v >>= return in
consume_write_gas init_set (s, i) v >>=? fun (c, bytes) -> consume_write_gas init_set (pack s i) v >>=? fun (c, bytes) ->
existing_size c >>=? fun prev_size -> existing_size c >>=? fun prev_size ->
init_set c N.name bytes >>=? fun c -> init_set c N.name bytes >>=? fun c ->
let size_diff = MBytes.length bytes - prev_size in let size_diff = MBytes.length bytes - prev_size in
@ -853,14 +985,14 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
return (Raw_context.project c, size_diff) return (Raw_context.project c, size_diff)
let remove s i = let remove s i =
let remove c k = Raw_context.remove c k >>= return in let remove c k = Raw_context.remove c k >>= return in
consume_remove_gas remove (s, i) >>=? fun c -> consume_remove_gas remove (pack s i) >>=? fun c ->
existing_size (s, i) >>=? fun prev_size -> existing_size (pack s i) >>=? fun prev_size ->
remove c N.name >>=? fun c -> remove c N.name >>=? fun c ->
Lwt.return (Raw_context.record_bytes_stored c (Int64.of_int ~-prev_size)) >>=? fun c -> Lwt.return (Raw_context.record_bytes_stored c (Int64.of_int ~-prev_size)) >>=? fun c ->
return (Raw_context.project c, prev_size) return (Raw_context.project c, prev_size)
let delete s i = let delete s i =
consume_remove_gas Raw_context.delete (s, i) >>=? fun c -> consume_remove_gas Raw_context.delete (pack s i) >>=? fun c ->
existing_size (s, i) >>=? fun prev_size -> existing_size (pack s i) >>=? fun prev_size ->
Raw_context.delete c N.name >>=? fun c -> Raw_context.delete c N.name >>=? fun c ->
Lwt.return (Raw_context.record_bytes_stored c (Int64.of_int ~-prev_size)) >>=? fun c -> Lwt.return (Raw_context.record_bytes_stored c (Int64.of_int ~-prev_size)) >>=? fun c ->
return (Raw_context.project c, prev_size) return (Raw_context.project c, prev_size)
@ -873,10 +1005,13 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
~f:begin fun i s -> ~f:begin fun i s ->
Lwt.return s >>=? fun (s, total) -> Lwt.return s >>=? fun (s, total) ->
let remove c k = Raw_context.remove c k >>= return in let remove c k = Raw_context.remove c k >>= return in
consume_remove_gas remove (s, i) >>=? fun (s, _) -> consume_remove_gas remove (pack s i) >>=? fun c ->
existing_size (s, i) >>=? fun prev_size -> let (s, _) = unpack c in
remove (s,i) N.name >>=? fun (s, _) -> existing_size (pack s i) >>=? fun prev_size ->
Lwt.return (Raw_context.record_bytes_stored (s, i) (Int64.of_int ~-prev_size)) >>=? fun (s, _) -> remove (pack s i) N.name >>=? fun c ->
let (s, _) = unpack c in
Lwt.return (Raw_context.record_bytes_stored (pack s i) (Int64.of_int ~-prev_size)) >>=? fun c ->
let (s, _) = unpack c in
return (s, Z.add total (Z.of_int prev_size)) return (s, Z.add total (Z.of_int prev_size))
end >>=? fun (s, total) -> end >>=? fun (s, total) ->
return (C.project s, total) return (C.project s, total)
@ -884,9 +1019,10 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
fold_keys s ~init:(ok (s, init)) fold_keys s ~init:(ok (s, init))
~f:(fun i acc -> ~f:(fun i acc ->
Lwt.return acc >>=? fun (s, acc) -> Lwt.return acc >>=? fun (s, acc) ->
consume_read_gas Raw_context.get (s, i) >>=? fun (s, _) -> consume_read_gas Raw_context.get (pack s i) >>=? fun c ->
Raw_context.get (s, i) N.name >>=? fun b -> let (s, _) = unpack c in
let key = Raw_context.absolute_key (s, i) N.name in Raw_context.get (pack s i) N.name >>=? fun b ->
let key = Raw_context.absolute_key (pack s i) N.name in
Lwt.return (of_bytes ~key b) >>=? fun v -> Lwt.return (of_bytes ~key b) >>=? fun v ->
f i v (s, acc)) >>=? fun (s, v) -> f i v (s, acc)) >>=? fun (s, v) ->
return (C.project s, v) return (C.project s, v)
@ -896,14 +1032,28 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
fold_keys s ~init:(ok (s, init)) fold_keys s ~init:(ok (s, init))
~f:(fun i acc -> ~f:(fun i acc ->
Lwt.return acc >>=? fun (s, acc) -> Lwt.return acc >>=? fun (s, acc) ->
consume_mem_gas (s, i) >>=? fun (s, _) -> consume_mem_gas (pack s i) >>=? fun c ->
Raw_context.mem (s, i) N.name >>= function let (s, _) = unpack c in
Raw_context.mem (pack s i) N.name >>= function
| false -> return (s, acc) | false -> return (s, acc)
| true -> f i (s, acc)) >>=? fun (s, v) -> | true -> f i (s, acc)) >>=? fun (s, v) ->
return (C.project s, v) return (C.project s, v)
let keys s = let keys s =
fold_keys s ~init:[] ~f:(fun p (s, acc) -> return (s, p :: acc)) fold_keys s ~init:[] ~f:(fun p (s, acc) -> return (s, p :: acc))
let () =
let open Storage_description in
let unpack = unpack I.args in
register_value
~get:(fun c ->
let (c, k) = unpack c in
get_option c k >>=? fun (_, v) ->
return v)
(register_named_subcontext Raw_context.description N.name)
V.encoding
end end
end end
module Wrap_indexed_data_storage module Wrap_indexed_data_storage

View File

@ -31,6 +31,8 @@ module type INDEX = sig
val path_length: int val path_length: int
val to_path: t -> string list -> string list val to_path: t -> string list -> string list
val of_path: string list -> t option val of_path: string list -> t option
type 'a ipath
val args: ('a, t, 'a ipath) Storage_description.args
end end
module Pair(I1 : INDEX)(I2 : INDEX) : INDEX with type t = I1.t * I2.t module Pair(I1 : INDEX)(I2 : INDEX) : INDEX with type t = I1.t * I2.t
@ -60,6 +62,7 @@ module Make_indexed_data_snapshotable_storage (C : Raw_context.T)
module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX) module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
: Indexed_raw_context with type t = C.t : Indexed_raw_context with type t = C.t
and type key = I.t and type key = I.t
and type 'a ipath = 'a I.ipath
module Wrap_indexed_data_storage module Wrap_indexed_data_storage
(C : Indexed_data_storage) (C : Indexed_data_storage)

View File

@ -389,6 +389,7 @@ module type Indexed_raw_context = sig
type t type t
type context = t type context = t
type key type key
type 'a ipath
val clear: context -> Raw_context.t Lwt.t val clear: context -> Raw_context.t Lwt.t
@ -412,6 +413,6 @@ module type Indexed_raw_context = sig
and type key = key and type key = key
and type value = V.t and type value = V.t
module Raw_context : Raw_context.T with type t = t * key module Raw_context : Raw_context.T with type t = t ipath
end end

View File

@ -273,21 +273,21 @@ module Make (Encoding : ENCODING) = struct
end end
| DynamicTail ( _, dir) -> describe_directory ~recurse dir | DynamicTail ( _, dir) -> describe_directory ~recurse dir
| Static dir -> | Static dir ->
describe_static_directory recurse arg dir >>= fun dir -> describe_static_directory recurse dir >>= fun dir ->
Lwt.return (Static dir : Encoding.schema Description.directory) Lwt.return (Static dir : Encoding.schema Description.directory)
and describe_static_directory and describe_static_directory
: type a. : type a.
bool -> a option -> a static_directory -> bool -> a static_directory ->
Encoding.schema Description.static_directory Lwt.t Encoding.schema Description.static_directory Lwt.t
= fun recurse arg dir -> = fun recurse dir ->
let services = MethMap.map describe_service dir.services in let services = MethMap.map describe_service dir.services in
begin begin
if recurse then if recurse then
match dir.subdirs with match dir.subdirs with
| None -> Lwt.return_none | None -> Lwt.return_none
| Some subdirs -> | Some subdirs ->
describe_static_subdirectories arg subdirs >>= fun dirs -> describe_static_subdirectories subdirs >>= fun dirs ->
Lwt.return (Some dirs) Lwt.return (Some dirs)
else else
Lwt.return_none Lwt.return_none
@ -296,14 +296,14 @@ module Make (Encoding : ENCODING) = struct
and describe_static_subdirectories and describe_static_subdirectories
: type a. : type a.
a option -> a static_subdirectories -> a static_subdirectories ->
Encoding.schema Description.static_subdirectories Lwt.t Encoding.schema Description.static_subdirectories Lwt.t
= fun arg dir -> = fun dir ->
match dir with match dir with
| Suffixes map -> | Suffixes map ->
StringMap.fold (fun key dir map -> StringMap.fold (fun key dir map ->
map >>= fun map -> map >>= fun map ->
describe_directory ~recurse:true ?arg dir >>= fun dir -> describe_directory ~recurse:true dir >>= fun dir ->
Lwt.return (StringMap.add key dir map)) Lwt.return (StringMap.add key dir map))
map (Lwt.return StringMap.empty) >>= fun map -> map (Lwt.return StringMap.empty) >>= fun map ->
Lwt.return (Suffixes map : Encoding.schema Description.static_subdirectories) Lwt.return (Suffixes map : Encoding.schema Description.static_subdirectories)