Alpha: add variants of storage functors with size accounting

This commit is contained in:
Benjamin Canou 2018-03-30 20:56:30 +02:00 committed by Grégoire Henry
parent ba09cdf883
commit 4a0b30d968
5 changed files with 606 additions and 8 deletions

View File

@ -380,6 +380,9 @@ module type T = sig
context -> key -> init:'a -> f:(key -> 'a -> 'a Lwt.t) -> 'a Lwt.t context -> key -> init:'a -> f:(key -> 'a -> 'a Lwt.t) -> 'a Lwt.t
val project: context -> root_context val project: context -> root_context
val consume_gas: context -> Gas_repr.cost -> context tzresult
end end
let mem ctxt k = Context.mem ctxt.context k let mem ctxt k = Context.mem ctxt.context k

View File

@ -153,6 +153,8 @@ module type T = sig
val project: context -> root_context val project: context -> root_context
val consume_gas: context -> Gas_repr.cost -> context tzresult
end end
include T with type t := t and type context := context include T with type t := t and type context := context

View File

@ -26,12 +26,37 @@ module Make_value (V : ENCODED_VALUE) = struct
| None -> MBytes.create 0 | None -> MBytes.create 0
end end
module Raw_value = struct module Make_carbonated_value (V : ENCODED_VALUE) = struct
type t = MBytes.t type t = V.t
let of_bytes b = ok b let of_bytes b =
let to_bytes b = b match Data_encoding.Binary.of_bytes V.encoding b with
| None -> Error [Raw_context.Storage_error (Corrupted_data [(* FIXME??*)])]
| Some v -> Ok v
let to_bytes v =
try Data_encoding.Binary.to_bytes_exn V.encoding v
with _ -> MBytes.create 0
let size =
match Data_encoding.classify V.encoding with
| `Fixed size -> Fixed size
| `Variable | `Dynamic -> Variable
end end
let rec len_name = function
| [] -> assert false
| [ last ] -> [ last ^ "$" ]
| first :: rest -> first :: len_name rest
let encode_len_value bytes =
let length = MBytes.length bytes in
Data_encoding.(Binary.to_bytes int31) length
let decode_len_value key len =
match Data_encoding.(Binary.of_bytes int31) len with
| None ->
fail (Raw_context.Storage_error (Corrupted_data (len_name key)))
| Some len ->
return len
let map_key f = function let map_key f = function
| `Key k -> `Key (f k) | `Key k -> `Key (f k)
| `Dir k -> `Dir (f k) | `Dir k -> `Dir (f k)
@ -62,6 +87,7 @@ module Make_subcontext (C : Raw_context.T) (N : NAME)
let fold_keys t k ~init ~f = let fold_keys t k ~init ~f =
C.fold_keys t (to_key k) ~init ~f:(fun k acc -> f (of_key k) acc) C.fold_keys t (to_key k) ~init ~f:(fun k acc -> f (of_key k) acc)
let project = C.project let project = C.project
let consume_gas = C.consume_gas
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)
@ -102,6 +128,97 @@ module Make_single_data_storage (C : Raw_context.T) (N : NAME) (V : VALUE)
return (C.project t) return (C.project t)
end end
module Make_single_carbonated_data_storage
(C : Raw_context.T) (N : NAME) (V : CARBONATED_VALUE)
: Single_carbonated_data_storage with type t = C.t
and type value = V.t = struct
type t = C.t
type context = t
type value = V.t
let consume_mem_gas c =
Lwt.return (C.consume_gas c (Gas_repr.read_bytes_cost Z.zero))
let existing_size c =
match V.size with
| Fixed len ->
C.mem c N.name >>= fun exists ->
if exists then return len else return 0
| Variable ->
C.get_option c (len_name N.name) >>= function
| None -> return 0
| Some len -> decode_len_value N.name len
let consume_read_gas get c =
match V.size with
| Fixed len ->
Lwt.return (C.consume_gas c (Gas_repr.read_bytes_cost (Z.of_int len)))
| Variable ->
get c (len_name N.name) >>=? fun len ->
decode_len_value N.name len >>=? fun len ->
Lwt.return (C.consume_gas c (Gas_repr.read_bytes_cost (Z.of_int len)))
let consume_write_gas set c v =
match V.size with
| Fixed s ->
Lwt.return (C.consume_gas c (Gas_repr.write_bytes_cost (Z.of_int s))) >>=? fun c ->
return (c, V.to_bytes v)
| Variable ->
let bytes = V.to_bytes v in
let len = MBytes.length bytes in
Lwt.return (C.consume_gas c (Gas_repr.write_bytes_cost (Z.of_int len))) >>=? fun c ->
set c (len_name N.name) (encode_len_value bytes) >>=? fun c ->
return (c, bytes)
let consume_remove_gas del c =
match V.size with
| Fixed _ | Variable ->
Lwt.return (C.consume_gas c (Gas_repr.write_bytes_cost Z.zero)) >>=? fun c ->
del c (len_name N.name)
let mem c =
consume_mem_gas c >>=? fun c ->
C.mem c N.name >>= fun res ->
return (C.project c, res)
let get c =
consume_read_gas C.get c >>=? fun c ->
C.get c N.name >>=? fun bytes ->
Lwt.return (V.of_bytes bytes) >>=? fun res ->
return (C.project c, res)
let get_option c =
consume_mem_gas c >>=? fun c ->
C.mem c N.name >>= fun exists ->
if exists then
get c >>=? fun (c, r) ->
return (c, Some r)
else
return (C.project c, None)
let init c v =
consume_write_gas C.init c v >>=? fun (c, bytes) ->
existing_size c >>=? fun prev_size ->
C.init c N.name bytes >>=? fun c ->
return (C.project c, MBytes.length bytes - prev_size)
let set c v =
consume_write_gas C.set c v >>=? fun (c, bytes) ->
C.set c N.name bytes >>=? fun c ->
return (C.project c, MBytes.length bytes)
let init_set c v =
let init_set c k v = C.init_set c k v >>= return in
consume_write_gas init_set c v >>=? fun (c, bytes) ->
existing_size c >>=? fun prev_size ->
init_set c N.name bytes >>=? fun c ->
return (C.project c, MBytes.length bytes - prev_size)
let remove c =
let remove c k = C.remove c k >>= return in
consume_remove_gas remove c >>=? fun c ->
existing_size c >>=? fun prev_size ->
remove c N.name >>=? fun c ->
return (C.project c, prev_size)
let delete c =
consume_remove_gas C.delete c >>=? fun c ->
existing_size c >>=? fun prev_size ->
C.delete c N.name >>=? fun c ->
return (C.project c, prev_size)
let set_option c v =
match v with
| None -> remove c
| Some v -> init_set c v
end
module type INDEX = sig module type INDEX = sig
type t type t
val path_length: int val path_length: int
@ -251,6 +368,160 @@ module Make_indexed_data_storage
end end
module Make_indexed_carbonated_data_storage
(C : Raw_context.T) (I : INDEX) (V : CARBONATED_VALUE)
: Indexed_carbonated_data_storage with type t = C.t
and type key = I.t
and type value = V.t = struct
type t = C.t
type context = t
type key = I.t
type value = V.t
let name i =
I.to_path i []
let len_name i =
len_name (I.to_path i [])
let rec is_len_name = function
| [] | [ "" ] -> false
| [ last ] -> Compare.Char.(=) (String.get last (String.length last - 1)) '$'
| _ :: rest -> is_len_name rest
let consume_mem_gas c =
Lwt.return (C.consume_gas c (Gas_repr.read_bytes_cost Z.zero))
let existing_size c i =
match V.size with
| Fixed len ->
C.mem c (name i) >>= fun exists ->
if exists then return len else return 0
| Variable ->
C.get_option c (len_name i) >>= function
| None -> return 0
| Some len -> decode_len_value (name i) len
let consume_read_gas get c i =
match V.size with
| Fixed len ->
Lwt.return (C.consume_gas c (Gas_repr.read_bytes_cost (Z.of_int len)))
| Variable ->
get c (len_name i) >>=? fun len ->
decode_len_value (name i) len >>=? fun len ->
Lwt.return (C.consume_gas c (Gas_repr.read_bytes_cost (Z.of_int len)))
let consume_write_gas set c i v =
match V.size with
| Fixed s ->
Lwt.return (C.consume_gas c (Gas_repr.write_bytes_cost (Z.of_int s))) >>=? fun c ->
return (c, V.to_bytes v)
| Variable ->
let bytes = V.to_bytes v in
let len = MBytes.length bytes in
Lwt.return (C.consume_gas c (Gas_repr.write_bytes_cost (Z.of_int len))) >>=? fun c ->
set c (len_name i) (encode_len_value bytes) >>=? fun c ->
return (c, bytes)
let consume_remove_gas del c i =
match V.size with
| Fixed _ | Variable ->
Lwt.return (C.consume_gas c (Gas_repr.write_bytes_cost Z.zero)) >>=? fun c ->
del c (len_name i)
let mem s i =
consume_mem_gas s >>=? fun s ->
C.mem s (name i) >>= fun exists ->
return (C.project s, exists)
let get s i =
consume_read_gas C.get s i >>=? fun s ->
C.get s (name i) >>=? fun b ->
Lwt.return (V.of_bytes b) >>=? fun v ->
return (C.project s, v)
let get_option s i =
consume_mem_gas s >>=? fun s ->
C.mem s (name i) >>= fun exists ->
if exists then
get s i >>=? fun (s, v) ->
return (s, Some v)
else
return (C.project s, None)
let set s i v =
consume_write_gas C.set s i v >>=? fun (s, bytes) ->
existing_size s i >>=? fun prev_size ->
C.set s (name i) bytes >>=? fun t ->
return (C.project t, MBytes.length bytes - prev_size)
let init s i v =
consume_write_gas C.init s i v >>=? fun (s, bytes) ->
C.init s (name i) bytes >>=? fun t ->
return (C.project t, MBytes.length bytes)
let init_set s i v =
let init_set s i v = C.init_set s i v >>= return in
consume_write_gas init_set s i v >>=? fun (s, bytes) ->
existing_size s i >>=? fun prev_size ->
init_set s (name i) bytes >>=? fun t ->
return (C.project t, MBytes.length bytes - prev_size)
let remove s i =
let remove s i = C.remove s i >>= return in
consume_remove_gas remove s i >>=? fun s ->
existing_size s i >>=? fun prev_size ->
remove s (name i) >>=? fun t ->
return (C.project t, prev_size)
let delete s i =
consume_remove_gas C.delete s i >>=? fun s ->
existing_size s i >>=? fun prev_size ->
C.delete s (name i) >>=? fun t ->
return (C.project t, prev_size)
let set_option s i v =
match v with
| None -> remove s i
| Some v -> init_set s i v
let fold_keys_unaccounted s ~init ~f =
let rec dig s i path acc =
if Compare.Int.(i <= 1) then
C.fold s path ~init:(ok (s, acc)) ~f:begin fun k acc ->
Lwt.return acc >>=? fun (s, acc) ->
match k with
| `Dir _ -> return (s, acc)
| `Key file ->
if is_len_name file then
return (s, acc)
else
match I.of_path file with
| None ->
fail (Raw_context.Storage_error (Corrupted_data file))
| Some path ->
f path (s, acc)
end
else
C.fold s path ~init:(ok (s, acc)) ~f:begin fun k acc ->
Lwt.return acc >>=? fun (s, acc) ->
match k with
| `Dir k -> dig s (i-1) k acc
| `Key _ -> return (s, acc)
end in
dig s I.path_length [] init >>=? fun (s, acc) ->
return (C.project s, acc)
let fold_keys s ~init ~f =
let f path (s, acc) =
consume_mem_gas s >>=? fun s ->
f path (s, acc) in
fold_keys_unaccounted s ~init ~f
let clear s =
let f path (s, total) =
consume_remove_gas C.delete s path >>=? fun s ->
existing_size s path >>=? fun prev_size ->
C.delete s (name path) >>=? fun s ->
return (s, Z.add (Z.of_int prev_size) total) in
fold_keys_unaccounted s ~init:Z.zero ~f
let fold s ~init ~f =
let f path (s, acc) =
consume_read_gas C.get s path >>=? fun s ->
C.get s (name path) >>=? fun b ->
Lwt.return (V.of_bytes b) >>=? fun v ->
f path v (s, acc) in
fold_keys_unaccounted s ~init ~f
let bindings s =
fold s ~init:[] ~f:(fun p v (s, acc) -> return (s, (p, v) :: acc))
let keys s =
fold_keys s ~init:[] ~f:(fun p (s, acc) -> return (s, p :: acc))
end
module Make_indexed_data_snapshotable_storage (C : Raw_context.T) module Make_indexed_data_snapshotable_storage (C : Raw_context.T)
(Snapshot_index : INDEX) (I : INDEX) (V : VALUE) (Snapshot_index : INDEX) (I : INDEX) (V : VALUE)
: Indexed_data_snapshotable_storage with type t = C.t : Indexed_data_snapshotable_storage with type t = C.t
@ -329,6 +600,7 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
let fold_keys (t, i) k ~init ~f = 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) 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 project (t, _) = C.project t
let consume_gas (t, k) c = C.consume_gas t c >>? fun t -> ok (t, k)
end end
let fold_keys t ~init ~f = let fold_keys t ~init ~f =
@ -477,6 +749,127 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX)
fold_keys s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc)) fold_keys s ~init:[] ~f:(fun p acc -> Lwt.return (p :: acc))
end end
module Make_carbonated_map (N : NAME) (V : CARBONATED_VALUE) = struct
type t = C.t
type context = t
type key = I.t
type value = V.t
let consume_mem_gas c =
Lwt.return (Raw_context.consume_gas c (Gas_repr.read_bytes_cost Z.zero))
let existing_size c =
match V.size with
| Fixed len ->
Raw_context.mem c N.name >>= fun exists ->
if exists then return len else return 0
| Variable ->
Raw_context.get_option c (len_name N.name) >>= function
| None -> return 0
| Some len -> decode_len_value N.name len
let consume_read_gas get c =
match V.size with
| Fixed len ->
Lwt.return (Raw_context.consume_gas c (Gas_repr.read_bytes_cost (Z.of_int len)))
| Variable ->
get c (len_name N.name) >>=? fun len ->
decode_len_value N.name len >>=? fun len ->
Lwt.return (Raw_context.consume_gas c (Gas_repr.read_bytes_cost (Z.of_int len)))
let consume_write_gas set c v =
match V.size with
| Fixed s ->
Lwt.return (Raw_context.consume_gas c (Gas_repr.write_bytes_cost (Z.of_int s))) >>=? fun c ->
return (c, V.to_bytes v)
| Variable ->
let bytes = V.to_bytes v in
let len = MBytes.length bytes in
Lwt.return (Raw_context.consume_gas c (Gas_repr.write_bytes_cost (Z.of_int len))) >>=? fun c ->
set c (len_name N.name) (encode_len_value bytes) >>=? fun c ->
return (c, bytes)
let consume_remove_gas del c =
match V.size with
| Fixed _ | Variable ->
Lwt.return (Raw_context.consume_gas c (Gas_repr.write_bytes_cost Z.zero)) >>=? fun c ->
del c (len_name N.name)
let mem s i =
consume_mem_gas (s, i) >>=? fun c ->
Raw_context.mem c N.name >>= fun res ->
return (Raw_context.project c, res)
let get s i =
consume_read_gas Raw_context.get (s, i) >>=? fun c ->
Raw_context.get c N.name >>=? fun b ->
Lwt.return (V.of_bytes b) >>=? fun v ->
return (Raw_context.project c, v)
let get_option s i =
consume_mem_gas (s, i) >>=? fun (s, _) ->
Raw_context.mem (s, i) N.name >>= fun exists ->
if exists then
get s i >>=? fun (s, v) ->
return (s, Some v)
else
return (C.project s, None)
let set s i v =
consume_write_gas Raw_context.set (s, i) v >>=? fun (c, bytes) ->
existing_size (s, i) >>=? fun prev_size ->
Raw_context.set c N.name bytes >>=? fun c ->
return (Raw_context.project c, MBytes.length bytes - prev_size)
let init s i v =
consume_write_gas Raw_context.init (s, i) v >>=? fun (c, bytes) ->
Raw_context.init c N.name bytes >>=? fun c ->
return (Raw_context.project c, MBytes.length bytes)
let init_set s i v =
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) ->
existing_size c >>=? fun prev_size ->
init_set c N.name bytes >>=? fun c ->
return (Raw_context.project c, MBytes.length bytes - prev_size)
let remove s i =
let remove c k = Raw_context.remove c k >>= return in
consume_remove_gas remove (s, i) >>=? fun c ->
existing_size (s, i) >>=? fun prev_size ->
remove c N.name >>=? fun c ->
return (Raw_context.project c, prev_size)
let delete s i =
consume_remove_gas Raw_context.delete (s, i) >>=? fun c ->
existing_size (s, i) >>=? fun prev_size ->
Raw_context.delete c N.name >>=? fun c ->
return (Raw_context.project c, prev_size)
let set_option s i v =
match v with
| None -> remove s i
| Some v -> init_set s i v
let clear s =
fold_keys s ~init:(ok (s, Z.zero))
~f:begin fun i s ->
Lwt.return s >>=? fun (s, total) ->
let remove c k = Raw_context.remove c k >>= return in
consume_remove_gas remove (s, i) >>=? fun (s, _) ->
existing_size (s, i) >>=? fun prev_size ->
remove (s,i) N.name >>=? fun (s, _) ->
return (s, Z.add total (Z.of_int prev_size))
end >>=? fun (s, total) ->
return (C.project s, total)
let fold s ~init ~f =
fold_keys s ~init:(ok (s, init))
~f:(fun i acc ->
Lwt.return acc >>=? fun (s, acc) ->
consume_read_gas Raw_context.get (s, i) >>=? fun (s, _) ->
Raw_context.get (s, i) N.name >>=? fun b ->
Lwt.return (V.of_bytes b) >>=? fun v ->
f i v (s, acc)) >>=? fun (s, v) ->
return (C.project s, v)
let bindings s =
fold s ~init:[] ~f:(fun p v (c, acc) -> return (c, (p,v) :: acc))
let fold_keys s ~init ~f =
fold_keys s ~init:(ok (s, init))
~f:(fun i acc ->
Lwt.return acc >>=? fun (s, acc) ->
consume_mem_gas (s, i) >>=? fun (s, _) ->
Raw_context.mem (s, i) N.name >>= function
| false -> return (s, acc)
| true -> f i (s, acc)) >>=? fun (s, v) ->
return (C.project s, v)
let keys s =
fold_keys s ~init:[] ~f:(fun p (s, acc) -> return (s, p :: acc))
end
end end
module Wrap_indexed_data_storage module Wrap_indexed_data_storage

View File

@ -18,15 +18,21 @@ end
module Make_value (V : ENCODED_VALUE) : VALUE with type t = V.t module Make_value (V : ENCODED_VALUE) : VALUE with type t = V.t
module Raw_value : VALUE with type t = MBytes.t
module Make_subcontext (C : Raw_context.T) (N : NAME) module Make_subcontext (C : Raw_context.T) (N : NAME)
: Raw_context.T with type t = C.t : Raw_context.T with type t = C.t
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)
: Single_data_storage with type t = C.t : Single_data_storage with type t = C.t
and type value = V.t and type value = V.t
module Make_carbonated_value (V : ENCODED_VALUE) : CARBONATED_VALUE with type t = V.t
module Make_single_carbonated_data_storage
(C : Raw_context.T) (N : NAME) (V : CARBONATED_VALUE)
: Single_carbonated_data_storage with type t = C.t
and type value = V.t
module type INDEX = sig module type INDEX = sig
type t type t
val path_length: int val path_length: int
@ -39,11 +45,18 @@ module Pair(I1 : INDEX)(I2 : INDEX) : INDEX with type t = I1.t * I2.t
module Make_data_set_storage (C : Raw_context.T) (I : INDEX) module Make_data_set_storage (C : Raw_context.T) (I : INDEX)
: Data_set_storage with type t = C.t and type elt = I.t : Data_set_storage with type t = C.t and type elt = I.t
module Make_indexed_data_storage (C : Raw_context.T) (I : INDEX) (V : VALUE) module Make_indexed_data_storage
(C : Raw_context.T) (I : INDEX) (V : VALUE)
: Indexed_data_storage with type t = C.t : Indexed_data_storage with type t = C.t
and type key = I.t and type key = I.t
and type value = V.t and type value = V.t
module Make_indexed_carbonated_data_storage
(C : Raw_context.T) (I : INDEX) (V : CARBONATED_VALUE)
: Indexed_carbonated_data_storage with type t = C.t
and type key = I.t
and type value = V.t
module Make_indexed_data_snapshotable_storage (C : Raw_context.T) module Make_indexed_data_snapshotable_storage (C : Raw_context.T)
(Snapshot : INDEX) (I : INDEX) (V : VALUE) (Snapshot : INDEX) (I : INDEX) (V : VALUE)
: Indexed_data_snapshotable_storage with type t = C.t : Indexed_data_snapshotable_storage with type t = C.t

View File

@ -61,6 +61,72 @@ module type Single_data_storage = sig
end end
(** Variant of {!Single_data_storage} with gas accounting. *)
module type Single_carbonated_data_storage = sig
type t
type context = t
(** The type of the value *)
type value
(** Tells if the data is already defined.
Consumes [Gas_repr.read_bytes_cost Z.zero]. *)
val mem: context -> (Raw_context.t * bool) tzresult Lwt.t
(** Retrieve the value from the storage bucket ; returns a
{!Storage_error} if the key is not set or if the deserialisation
fails.
Consumes [Gas_repr.read_bytes_cost <size of the value>]. *)
val get: context -> (Raw_context.t * value) tzresult Lwt.t
(** Retrieves the value from the storage bucket ; returns [None] if
the data is not initialized, or {!Storage_helpers.Storage_error}
if the deserialisation fails.
Consumes [Gas_repr.read_bytes_cost <size of the value>] if present
or [Gas_repr.read_bytes_cost Z.zero]. *)
val get_option: context -> (Raw_context.t * value option) tzresult Lwt.t
(** Allocates the storage bucket and initializes it ; returns a
{!Storage_error Missing_key} if the bucket exists.
Consumes [Gas_repr.write_bytes_cost <size of the value>].
Returns the size. *)
val init: context -> value -> (Raw_context.t * int) tzresult Lwt.t
(** Updates the content of the bucket ; returns a {!Storage_Error
Existing_key} if the value does not exists.
Consumes [Gas_repr.write_bytes_cost <size of the new value>].
Returns the difference from the old to the new size. *)
val set: context -> value -> (Raw_context.t * int) tzresult Lwt.t
(** Allocates the data and initializes it with a value ; just
updates it if the bucket exists.
Consumes [Gas_repr.write_bytes_cost <size of the new value>].
Returns the difference from the old (maybe 0) to the new size. *)
val init_set: context -> value -> (Raw_context.t * int) tzresult Lwt.t
(** When the value is [Some v], allocates the data and initializes
it with [v] ; just updates it if the bucket exists. When the
valus is [None], delete the storage bucket when the value ; does
nothing if the bucket does not exists.
Consumes the same gas cost as either {!remove} or {!init_set}.
Returns the difference from the old (maybe 0) to the new size. *)
val set_option: context -> value option -> (Raw_context.t * int) tzresult Lwt.t
(** Delete the storage bucket ; returns a {!Storage_error
Missing_key} if the bucket does not exists.
Consumes [Gas_repr.write_bytes_cost Z.zero].
Returns the freed size. *)
val delete: context -> (Raw_context.t * int) tzresult Lwt.t
(** Removes the storage bucket and its contents ; does nothing if
the bucket does not exists.
Consumes [Gas_repr.write_bytes_cost Z.zero].
Returns the freed size. *)
val remove: context -> (Raw_context.t * int) tzresult Lwt.t
end
(** Restricted version of {!Indexed_data_storage} w/o iterators. *) (** Restricted version of {!Indexed_data_storage} w/o iterators. *)
module type Non_iterable_indexed_data_storage = sig module type Non_iterable_indexed_data_storage = sig
@ -115,6 +181,76 @@ module type Non_iterable_indexed_data_storage = sig
end end
(** Variant of {!Non_iterable_indexed_data_storage} with gas accounting. *)
module type Non_iterable_indexed_carbonated_data_storage = sig
type t
type context = t
(** An abstract type for keys *)
type key
(** The type of values *)
type value
(** Tells if a given key is already bound to a storage bucket.
Consumes [Gas_repr.read_bytes_cost Z.zero]. *)
val mem: context -> key -> (Raw_context.t * bool) tzresult Lwt.t
(** Retrieve a value from the storage bucket at a given key ;
returns {!Storage_error Missing_key} if the key is not set ;
returns {!Storage_error Corrupted_data} if the deserialisation
fails.
Consumes [Gas_repr.read_bytes_cost <size of the value>]. *)
val get: context -> key -> (Raw_context.t * value) tzresult Lwt.t
(** Retrieve a value from the storage bucket at a given key ;
returns [None] if the value is not set ; returns {!Storage_error
Corrupted_data} if the deserialisation fails.
Consumes [Gas_repr.read_bytes_cost <size of the value>] if present
or [Gas_repr.read_bytes_cost Z.zero]. *)
val get_option: context -> key -> (Raw_context.t * value option) tzresult Lwt.t
(** Updates the content of a bucket ; returns A {!Storage_Error
Missing_key} if the value does not exists.
Consumes [Gas_repr.write_bytes_cost <size of the new value>].
Returns the difference from the old to the new size. *)
val set: context -> key -> value -> (Raw_context.t * int) tzresult Lwt.t
(** Allocates a storage bucket at the given key and initializes it ;
returns a {!Storage_error Existing_key} if the bucket exists.
Consumes [Gas_repr.write_bytes_cost <size of the value>].
Returns the size. *)
val init: context -> key -> value -> (Raw_context.t * int) tzresult Lwt.t
(** Allocates a storage bucket at the given key and initializes it
with a value ; just updates it if the bucket exists.
Consumes [Gas_repr.write_bytes_cost <size of the new value>].
Returns the difference from the old (maybe 0) to the new size. *)
val init_set: context -> key -> value -> (Raw_context.t * int) tzresult Lwt.t
(** When the value is [Some v], allocates the data and initializes
it with [v] ; just updates it if the bucket exists. When the
valus is [None], delete the storage bucket when the value ; does
nothing if the bucket does not exists.
Consumes the same gas cost as either {!remove} or {!init_set}.
Returns the difference from the old (maybe 0) to the new size. *)
val set_option: context -> key -> value option -> (Raw_context.t * int) tzresult Lwt.t
(** Delete a storage bucket and its contents ; returns a
{!Storage_error Missing_key} if the bucket does not exists.
Consumes [Gas_repr.write_bytes_cost Z.zero].
Returns the freed size. *)
val delete: context -> key -> (Raw_context.t * int) tzresult Lwt.t
(** Removes a storage bucket and its contents ; does nothing if the
bucket does not exists.
Consumes [Gas_repr.write_bytes_cost Z.zero].
Returns the freed size. *)
val remove: context -> key -> (Raw_context.t * int) tzresult Lwt.t
end
(** The generic signature of indexed data accessors (a set of values (** The generic signature of indexed data accessors (a set of values
of the same type indexed by keys of the same form in the of the same type indexed by keys of the same form in the
hierarchical (key x value) database). *) hierarchical (key x value) database). *)
@ -141,6 +277,43 @@ module type Indexed_data_storage = sig
end end
(** Variant of {!Indexed_data_storage} with gas accounting. *)
module type Indexed_carbonated_data_storage = sig
include Non_iterable_indexed_carbonated_data_storage
(** Empties all the keys and associated data.
Consumes [Gas_repr.read_bytes_cost Z.zero] per deleted key.
Returns the total freed size. *)
val clear: context -> (Raw_context.t * Z.t) tzresult Lwt.t
(** Lists all the keys.
Consumes [Gas_repr.read_bytes_cost Z.zero] per returned key. *)
val keys: context -> (Raw_context.t * key list) tzresult Lwt.t
(** Lists all the keys and associated data.
Consumes [Gas_repr.read_bytes_cost <size of the value>] per returned key. *)
val bindings: context -> (Raw_context.t * (key * value) list) tzresult Lwt.t
(** Iterates over all the keys and associated data present in the
initial context (keys added or removed during the iteration are
not taken into account).
Consumes [Gas_repr.read_bytes_cost <size of the value>] per iterated key. *)
val fold:
context -> init:'a ->
f:(key -> value -> (context * 'a) -> (context * 'a) tzresult Lwt.t) ->
(Raw_context.t * 'a) tzresult Lwt.t
(** Iterate over all the keys present in the initial context
(keys added or removed during the iteration are not taken into account).
Consumes [Gas_repr.read_bytes_cost Z.zero] per iterated key. *)
val fold_keys:
context -> init:'a ->
f:(key -> (context * 'a) -> (context * 'a) tzresult Lwt.t) ->
(Raw_context.t * 'a) tzresult Lwt.t
end
module type Indexed_data_snapshotable_storage = sig module type Indexed_data_snapshotable_storage = sig
type snapshot type snapshot
type key type key
@ -203,6 +376,15 @@ module type VALUE = sig
val to_bytes: t -> MBytes.t val to_bytes: t -> MBytes.t
end end
type value_size =
| Fixed of int
| Variable
module type CARBONATED_VALUE = sig
include VALUE
val size: value_size
end
module type Indexed_raw_context = sig module type Indexed_raw_context = sig
type t type t
@ -226,6 +408,11 @@ 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 Make_carbonated_map (N : NAME) (V : CARBONATED_VALUE)
: Indexed_carbonated_data_storage with type t = t
and type key = key
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 * key
end end