Proto: Completion of Base48-encoded public keys and contracts

This required some modifications in the Base48 module, in order not to
share the 'resolver' between distinct version of the economical protocol.
This commit is contained in:
Grégoire Henry 2016-11-14 16:26:34 +01:00
parent 1805a1d816
commit b16a644e55
39 changed files with 677 additions and 257 deletions

View File

@ -12,7 +12,8 @@ all: ${TZCOMPILER} ${TZNODE} ${TZCLIENT}
## Protocol environment ## Protocol environment
############################################################################ ############################################################################
PROTOCOL_ENV_INTFS := $(addprefix proto/environment/, \ PROTOCOL_ENV_INTFS := \
$(addprefix proto/environment/, \
pervasives.mli \ pervasives.mli \
compare.mli \ compare.mli \
\ \
@ -30,7 +31,7 @@ PROTOCOL_ENV_INTFS := $(addprefix proto/environment/, \
uri.mli \ uri.mli \
data_encoding.mli \ data_encoding.mli \
time.mli \ time.mli \
base48.mli \ ../../utils/base48.mli \
hash.mli \ hash.mli \
ed25519.mli \ ed25519.mli \
persist.mli \ persist.mli \
@ -42,7 +43,8 @@ PROTOCOL_ENV_INTFS := $(addprefix proto/environment/, \
) \ ) \
utils/logging.mli \ utils/logging.mli \
utils/error_monad_sig.ml \ utils/error_monad_sig.ml \
utils/error_monad.mli utils/error_monad.mli \
.INTERMEDIATE: node/updater/environment_gen .INTERMEDIATE: node/updater/environment_gen
.SECONDARY: node/updater/proto_environment.mli .SECONDARY: node/updater/proto_environment.mli
@ -75,6 +77,7 @@ EMBEDDED_PROTOCOL_LIB_CMIS := \
tmp/camlinternalFormatBasics.cmi \ tmp/camlinternalFormatBasics.cmi \
utils/error_monad.cmi \ utils/error_monad.cmi \
proto/environment/error_monad.mli \ proto/environment/error_monad.mli \
proto/environment/base48.mli \
proto/environment/logging.mli \ proto/environment/logging.mli \
node/updater/proto_environment.cmi \ node/updater/proto_environment.cmi \
node/updater/register.cmi node/updater/register.cmi

View File

@ -11,5 +11,6 @@ val camlinternalFormatBasics_cmi: string
val error_monad_cmi: string val error_monad_cmi: string
val error_monad_mli: string val error_monad_mli: string
val logging_mli: string val logging_mli: string
val base48_mli: string
val proto_environment_cmi: string val proto_environment_cmi: string
val register_cmi: string val register_cmi: string

View File

@ -258,7 +258,8 @@ let link_shared ?(static=false) output objects =
let create_register_file client file hash packname modules = let create_register_file client file hash packname modules =
let unit = List.hd (List.rev modules) in let unit = List.hd (List.rev modules) in
let error_monad = packname ^ ".Local_error_monad.Error_monad" in let error_monad = packname ^ ".Local_modules.Error_monad" in
let base48 = packname ^ ".Local_modules.Base48" in
create_file file create_file file
(Printf.sprintf (Printf.sprintf
"module Packed_protocol = struct\n\ "module Packed_protocol = struct\n\
@ -269,6 +270,7 @@ let create_register_file client file hash packname modules =
\ let error_encoding = %s.error_encoding ()\n\ \ let error_encoding = %s.error_encoding ()\n\
\ let classify_errors = %s.classify_errors\n\ \ let classify_errors = %s.classify_errors\n\
\ let pp = %s.pp\n\ \ let pp = %s.pp\n\
\ let complete_b48prefix = %s.complete
\ end\n\ \ end\n\
\ %s\n\ \ %s\n\
" "
@ -279,6 +281,7 @@ let create_register_file client file hash packname modules =
error_monad error_monad
error_monad error_monad
error_monad error_monad
base48
(if client then (if client then
"include Register.Make(Packed_protocol)" "include Register.Make(Packed_protocol)"
else else
@ -397,38 +400,44 @@ let main () =
(* Compile the /ad-hoc/ Error_monad. *) (* Compile the /ad-hoc/ Error_monad. *)
List.iter (dump_cmi sigs_dir) tezos_protocol_env ; List.iter (dump_cmi sigs_dir) tezos_protocol_env ;
at_exit (fun () -> List.iter (unlink_cmi sigs_dir) tezos_protocol_env ) ; at_exit (fun () -> List.iter (unlink_cmi sigs_dir) tezos_protocol_env ) ;
let error_monad_unit = "local_error_monad" in let local_modules_unit = "local_modules" in
let error_monad_ml = build_dir // error_monad_unit ^ ".ml" in let local_modules_ml = build_dir // local_modules_unit ^ ".ml" in
create_file error_monad_ml @@ Printf.sprintf {| create_file local_modules_ml @@ Printf.sprintf {|
module Error_monad = struct module Error_monad = struct
type error_category = [ `Branch | `Temporary | `Permanent ] type error_category = [ `Branch | `Temporary | `Permanent ]
include Error_monad.Make() include Error_monad.Make()
end end
module Logging = Logging.Make(struct let name = %S end) module Logging = Logging.Make(struct let name = %S end)
module Base48 = struct
include Base48
include Make(struct type context = Context.t end)
end
|} |}
logname ; logname ;
let error_monad_mli = build_dir // error_monad_unit ^ ".mli" in let local_modules_mli = build_dir // local_modules_unit ^ ".mli" in
create_file error_monad_mli @@ Printf.sprintf {| create_file local_modules_mli @@ Printf.sprintf {|
module Error_monad : sig %s end module Error_monad : sig %s end
module Logging : sig %s end module Logging : sig %s end
module Base48 : sig %s end
|} |}
Embedded_cmis.error_monad_mli Embedded_cmis.error_monad_mli
Embedded_cmis.logging_mli ; Embedded_cmis.logging_mli
Embedded_cmis.base48_mli ;
if not keep_object then if not keep_object then
at_exit (fun () -> at_exit (fun () ->
safe_unlink error_monad_mli ; safe_unlink local_modules_mli ;
safe_unlink error_monad_ml) ; safe_unlink local_modules_ml) ;
let error_monad_object = let local_modules_object =
compile_units compile_units
~ctxt ~ctxt
~for_pack:packname ~for_pack:packname
~keep_object ~keep_object
~build_dir ~source_dir:build_dir [error_monad_unit] ~build_dir ~source_dir:build_dir [local_modules_unit]
in in
Compenv.implicit_modules := Compenv.implicit_modules :=
!Compenv.implicit_modules @ !Compenv.implicit_modules @
[ "Local_error_monad"; "Error_monad" ; "Hash" ; "Logging" ]; [ "Local_modules"; "Error_monad" ; "Hash" ; "Logging" ];
(* Compile the protocol *) (* Compile the protocol *)
let objects = let objects =
@ -437,7 +446,7 @@ let main () =
~update_needed ~update_needed
~keep_object ~for_pack:packname ~build_dir ~source_dir units in ~keep_object ~for_pack:packname ~build_dir ~source_dir units in
pack_objects ~ctxt ~keep_object pack_objects ~ctxt ~keep_object
packed_objects (error_monad_object @ objects) ; packed_objects (local_modules_object @ objects) ;
(* Compiler the 'registering module' *) (* Compiler the 'registering module' *)
List.iter (dump_cmi sigs_dir) register_env; List.iter (dump_cmi sigs_dir) register_env;

View File

@ -30,6 +30,7 @@ module rec S : sig
val update_path: t -> IrminPath.t -> v -> unit Lwt.t val update_path: t -> IrminPath.t -> v -> unit Lwt.t
val mem: v -> IrminPath.t -> bool Lwt.t val mem: v -> IrminPath.t -> bool Lwt.t
val dir_mem: v -> IrminPath.t -> bool Lwt.t
val get: v -> IrminPath.t -> MBytes.t option Lwt.t val get: v -> IrminPath.t -> MBytes.t option Lwt.t
val set: v -> IrminPath.t -> MBytes.t-> v Lwt.t val set: v -> IrminPath.t -> MBytes.t-> v Lwt.t
val del: v -> IrminPath.t -> v Lwt.t val del: v -> IrminPath.t -> v Lwt.t
@ -187,6 +188,11 @@ let mem (module View : VIEW) key =
GitStore.FunView.mem View.v (data_key key) >>= fun v -> GitStore.FunView.mem View.v (data_key key) >>= fun v ->
Lwt.return v Lwt.return v
let dir_mem (module View : VIEW) key =
let module GitStore = View.Store in
GitStore.FunView.dir_mem View.v (data_key key) >>= fun v ->
Lwt.return v
let raw_get (module View : VIEW) key = let raw_get (module View : VIEW) key =
let module GitStore = View.Store in let module GitStore = View.Store in
GitStore.FunView.get View.v key >>= function GitStore.FunView.get View.v key >>= function

View File

@ -466,6 +466,11 @@ module Make (S: Irmin.S) = struct
| None -> Lwt.return false | None -> Lwt.return false
| _ -> Lwt.return true | _ -> Lwt.return true
let dir_mem t k =
sub t k >>= function
| Some _ -> Lwt.return true
| None -> Lwt.return false
let list_aux t path = let list_aux t path =
sub t path >>= function sub t path >>= function
| None -> Lwt.return [] | None -> Lwt.return []
@ -662,6 +667,7 @@ end
module type S = sig module type S = sig
include Irmin.RO include Irmin.RO
val dir_mem: t -> key -> bool Lwt.t
val update: t -> key -> value -> t Lwt.t val update: t -> key -> value -> t Lwt.t
val remove: t -> key -> t Lwt.t val remove: t -> key -> t Lwt.t
val list: t -> key -> key list Lwt.t val list: t -> key -> key list Lwt.t

View File

@ -9,6 +9,7 @@
module type S = sig module type S = sig
include Irmin.RO include Irmin.RO
val dir_mem: t -> key -> bool Lwt.t
val update: t -> key -> value -> t Lwt.t val update: t -> key -> value -> t Lwt.t
val remove: t -> key -> t Lwt.t val remove: t -> key -> t Lwt.t
val list: t -> key -> key list Lwt.t val list: t -> key -> key list Lwt.t

View File

@ -19,12 +19,12 @@ type value = MBytes.t
module type STORE = sig module type STORE = sig
type t type t
val mem: t -> key -> bool Lwt.t val mem: t -> key -> bool Lwt.t
val dir_mem: t -> key -> bool Lwt.t
val get: t -> key -> value option Lwt.t val get: t -> key -> value option Lwt.t
val set: t -> key -> value -> t Lwt.t val set: t -> key -> value -> t Lwt.t
val del: t -> key -> t Lwt.t val del: t -> key -> t Lwt.t
val list: t -> key list -> key list Lwt.t val list: t -> key list -> key list Lwt.t
val remove_rec: t -> key -> t Lwt.t val remove_rec: t -> key -> t Lwt.t
val keys: t -> key list Lwt.t val keys: t -> key list Lwt.t
end end
@ -37,7 +37,6 @@ module type BYTES_STORE = sig
val del: t -> key -> t Lwt.t val del: t -> key -> t Lwt.t
val list: t -> key list -> key list Lwt.t val list: t -> key list -> key list Lwt.t
val remove_rec: t -> key -> t Lwt.t val remove_rec: t -> key -> t Lwt.t
val keys: t -> key list Lwt.t val keys: t -> key list Lwt.t
end end
@ -49,7 +48,6 @@ module type TYPED_STORE = sig
val get: t -> key -> value option Lwt.t val get: t -> key -> value option Lwt.t
val set: t -> key -> value -> t Lwt.t val set: t -> key -> value -> t Lwt.t
val del: t -> key -> t Lwt.t val del: t -> key -> t Lwt.t
val keys: t -> key list Lwt.t val keys: t -> key list Lwt.t
end end
@ -583,3 +581,37 @@ module MakeBufferedPersistentTypedMap
(Map : Map.S with type key = K.t) (Map : Map.S with type key = K.t)
= =
MakeBufferedPersistentMap(S)(K)(TypedValue(T))(Map) MakeBufferedPersistentMap(S)(K)(TypedValue(T))(Map)
module MakeHashResolver
(Store : sig
type t
val dir_mem: t -> string list -> bool Lwt.t
val list: t -> string list list -> string list list Lwt.t
val prefix: string list
end)
(H: HASH) = struct
let plen = List.length Store.prefix
let build path =
H.of_path @@
Utils.remove_elem_from_list plen path
let resolve t p =
let rec loop prefix = function
| [] ->
Lwt.return [build prefix]
| "" :: ds ->
Store.list t [ prefix] >>= fun prefixes ->
Lwt_list.map_p (fun prefix -> loop prefix ds) prefixes
>|= List.flatten
| [d] ->
Store.list t [prefix] >>= fun prefixes ->
Lwt_list.filter_map_p (fun prefix ->
match remove_prefix d (List.hd (List.rev prefix)) with
| None -> Lwt.return_none
| Some _ -> Lwt.return (Some (build prefix))
) prefixes
| d :: ds ->
Store.dir_mem t (prefix @ [d]) >>= function
| true -> loop (prefix @ [d]) ds
| false -> Lwt.return_nil in
loop Store.prefix (H.prefix_path p)
end

View File

@ -22,12 +22,12 @@ type value = MBytes.t
module type STORE = sig module type STORE = sig
type t type t
val mem: t -> key -> bool Lwt.t val mem: t -> key -> bool Lwt.t
val dir_mem: t -> key -> bool Lwt.t
val get: t -> key -> value option Lwt.t val get: t -> key -> value option Lwt.t
val set: t -> key -> value -> t Lwt.t val set: t -> key -> value -> t Lwt.t
val del: t -> key -> t Lwt.t val del: t -> key -> t Lwt.t
val list: t -> key list -> key list Lwt.t val list: t -> key list -> key list Lwt.t
val remove_rec: t -> key -> t Lwt.t val remove_rec: t -> key -> t Lwt.t
val keys: t -> key list Lwt.t val keys: t -> key list Lwt.t
end end
@ -258,3 +258,14 @@ module MakeBufferedPersistentTypedMap
and type key := K.t and type key := K.t
and type value := T.value and type value := T.value
and module Map := Map and module Map := Map
module MakeHashResolver
(Store : sig
type t
val dir_mem: t -> string list -> bool Lwt.t
val list: t -> string list list -> string list list Lwt.t
val prefix: string list
end)
(H: HASH) : sig
val resolve : Store.t -> string -> H.t list Lwt.t
end

View File

@ -50,6 +50,10 @@ module FS = struct
let file = file_of_key root key in let file = file_of_key root key in
Lwt.return (Sys.file_exists file && not (Sys.is_directory file)) Lwt.return (Sys.file_exists file && not (Sys.is_directory file))
let dir_mem root key =
let file = file_of_key root key in
Lwt.return (Sys.file_exists file && Sys.is_directory file)
let exists root key = let exists root key =
let file = file_of_key root key in let file = file_of_key root key in
Sys.file_exists file Sys.file_exists file
@ -139,6 +143,7 @@ end
module type IMPERATIVE_STORE = sig module type IMPERATIVE_STORE = sig
type t type t
val mem: t -> key -> bool Lwt.t val mem: t -> key -> bool Lwt.t
val dir_mem: t -> key -> bool Lwt.t
val get: t -> key -> value option Lwt.t val get: t -> key -> value option Lwt.t
val get_exn: t -> key -> value Lwt.t val get_exn: t -> key -> value Lwt.t
val set: t -> key -> value -> unit Lwt.t val set: t -> key -> value -> unit Lwt.t
@ -210,6 +215,7 @@ module Make (K : KEY) (V : Persist.VALUE) = struct
type key = K.t type key = K.t
type value = V.t type value = V.t
let mem t k = FS.mem t (K.to_path k) let mem t k = FS.mem t (K.to_path k)
let dir_mem t k = FS.dir_mem t (K.to_path k)
let get t k = let get t k =
FS.get t (K.to_path k) >|= function FS.get t (K.to_path k) >|= function
| None -> None | None -> None
@ -226,37 +232,6 @@ module Make (K : KEY) (V : Persist.VALUE) = struct
let keys _t = undefined_key_fn let keys _t = undefined_key_fn
end end
module MakeResolver (P: sig val prefix: string list end) (H: HASH) = struct
let plen = List.length P.prefix
let build path =
H.to_raw @@ H.of_path @@
Utils.remove_elem_from_list plen path
let resolve t p =
let rec loop prefix = function
| [] -> Lwt.return [build prefix]
| "" :: ds ->
FS.list t [ prefix] >>= fun prefixes ->
Lwt_list.map_p (fun prefix -> loop prefix ds) prefixes
>|= List.flatten
| [d] ->
FS.list t [prefix] >>= fun prefixes ->
Lwt_list.filter_map_p (fun prefix ->
match remove_prefix d (List.hd (List.rev prefix)) with
| None -> Lwt.return_none
| Some _ -> Lwt.return (Some (build prefix))
) prefixes
| d :: ds ->
if FS.exists t prefix then
loop (prefix @ [d]) ds
else
Lwt.return_nil in
loop P.prefix (H.prefix_path p)
let register t =
match H.kind with
| None -> ()
| Some kind -> Base48.register_resolver kind (resolve t)
end
module Data_store : IMPERATIVE_STORE with type t = FS.t = module Data_store : IMPERATIVE_STORE with type t = FS.t =
Make (Raw_key) (Raw_value) Make (Raw_key) (Raw_value)
@ -343,7 +318,12 @@ end
module Block_errors = Make (Block_errors_key) (Errors_value) module Block_errors = Make (Block_errors_key) (Errors_value)
module Block_resolver = module Block_resolver =
MakeResolver(struct let prefix = ["blocks"] end)(Block_hash) Persist.MakeHashResolver
(struct
include FS
let prefix = ["blocks"]
end)
(Block_hash)
module Block = struct module Block = struct
type t = FS.t type t = FS.t
@ -497,7 +477,13 @@ end
module Operation_errors = Make (Operation_errors_key) (Errors_value) module Operation_errors = Make (Operation_errors_key) (Errors_value)
module Operation_resolver = module Operation_resolver =
MakeResolver(struct let prefix = ["operations"] end)(Operation_hash) Persist.MakeHashResolver
(struct
include FS
let mem t k = Lwt.return (exists t k)
let prefix = ["operations"]
end)
(Operation_hash)
module Operation = struct module Operation = struct
type t = FS.t type t = FS.t
@ -756,8 +742,12 @@ let net_destroy ~root { net_genesis } =
let init root = let init root =
raw_init ~root:(Filename.concat root "global") () >>= fun t -> raw_init ~root:(Filename.concat root "global") () >>= fun t ->
Block_resolver.register t ; Base48.register_resolver
Operation_resolver.register t ; Block_hash.b48check_encoding
(fun s -> Block_resolver.resolve t s);
Base48.register_resolver
Operation_hash.b48check_encoding
(fun s -> Operation_resolver.resolve t s);
Lwt.return Lwt.return
{ block = Persist.share t ; { block = Persist.share t ;
blockchain = Persist.share t ; blockchain = Persist.share t ;

View File

@ -27,6 +27,7 @@ end
module type IMPERATIVE_STORE = sig module type IMPERATIVE_STORE = sig
type t type t
val mem: t -> key -> bool Lwt.t val mem: t -> key -> bool Lwt.t
val dir_mem: t -> key -> bool Lwt.t
val get: t -> key -> value option Lwt.t val get: t -> key -> value option Lwt.t
val get_exn: t -> key -> value Lwt.t val get_exn: t -> key -> value Lwt.t
val set: t -> key -> value -> unit Lwt.t val set: t -> key -> value -> unit Lwt.t

View File

@ -498,6 +498,20 @@ module RPC = struct
Proto.fitness ctxt >>= fun fitness -> Proto.fitness ctxt >>= fun fitness ->
return (fitness, r) return (fitness, r)
let complete node ?block str =
match block with
| None ->
Base48.complete str
| Some block ->
get_context node block >>= function
| None -> Lwt.fail Not_found
| Some ctxt ->
Context.get_protocol ctxt >>= fun protocol_hash ->
let (module Proto) = Updater.get_exn protocol_hash in
Base48.complete str >>= fun l1 ->
Proto.complete_b48prefix ctxt str >>= fun l2 ->
Lwt.return (l1 @ l2)
let context_dir node block = let context_dir node block =
get_context node block >>= function get_context node block >>= function
| None -> Lwt.return None | None -> Lwt.return None

View File

@ -72,6 +72,12 @@ module RPC : sig
val validate: t -> State.net_id -> Block_hash.t -> unit tzresult Lwt.t val validate: t -> State.net_id -> Block_hash.t -> unit tzresult Lwt.t
val context_dir:
t -> block -> 'a RPC.directory option Lwt.t
val complete:
t -> ?block:block -> string -> string list Lwt.t
end end
val shutdown: t -> unit Lwt.t val shutdown: t -> unit Lwt.t

View File

@ -437,8 +437,11 @@ let build_rpc_directory node =
let dir = let dir =
RPC.register1 dir Services.complete RPC.register1 dir Services.complete
(fun s () -> (fun s () ->
Base48.decode_partial s >>= fun l -> Node.RPC.complete node s >>= RPC.Answer.return) in
RPC.Answer.return (List.map Base48.encode l)) in let dir =
RPC.register2 dir Services.Blocks.complete
(fun block s () ->
Node.RPC.complete node ~block s >>= RPC.Answer.return) in
let dir = let dir =
RPC.register_describe_directory_service dir Services.describe in RPC.register_describe_directory_service dir Services.describe in
dir dir

View File

@ -255,6 +255,19 @@ module Blocks = struct
~output: (RPC.Error.wrap preapply_result_encoding) ~output: (RPC.Error.wrap preapply_result_encoding)
RPC.Path.(block_path / "preapply") RPC.Path.(block_path / "preapply")
let complete =
let prefix_arg =
let destruct s = Ok s
and construct s = s in
RPC.Arg.make ~name:"prefix" ~destruct ~construct () in
RPC.service
~description: "Try to complete a prefix of a Base48Check-encoded data. \
This RPC is actually able to complete hashes of \
block, operations, public_keys and contracts."
~input: empty
~output: (list string)
RPC.Path.(block_path / "complete" /: prefix_arg )
type list_param = { type list_param = {
operations: bool option ; operations: bool option ;
length: int option ; length: int option ;
@ -329,6 +342,8 @@ module Blocks = struct
~output: (obj1 (req "blocks" (list (list block_info_encoding)))) ~output: (obj1 (req "blocks" (list (list block_info_encoding))))
RPC.Path.(root / "blocks") RPC.Path.(root / "blocks")
end end
module Operations = struct module Operations = struct
@ -591,7 +606,7 @@ let complete =
RPC.service RPC.service
~description: "Try to complete a prefix of a Base48Check-encoded data. \ ~description: "Try to complete a prefix of a Base48Check-encoded data. \
This RPC is actually able to complete hashes of \ This RPC is actually able to complete hashes of \
black and hashes of operations." block and hashes of operations."
~input: empty ~input: empty
~output: (list string) ~output: (list string)
RPC.Path.(root / "complete" /: prefix_arg ) RPC.Path.(root / "complete" /: prefix_arg )

View File

@ -80,6 +80,8 @@ module Blocks : sig
val preapply: val preapply:
(unit, unit * block, preapply_param, preapply_result tzresult) RPC.service (unit, unit * block, preapply_param, preapply_result tzresult) RPC.service
val complete: (unit, (unit * block) * string, unit, string list) RPC.service
val proto_path: (unit, unit * block) RPC.Path.path val proto_path: (unit, unit * block) RPC.Path.path
end end

View File

@ -72,21 +72,25 @@ module Ed25519 = struct
Base48.register_encoding Base48.register_encoding
~prefix: Base48.Prefix.ed25519_public_key ~prefix: Base48.Prefix.ed25519_public_key
~to_raw:(fun x -> Bytes.to_string (Sodium.Sign.Bytes.of_public_key x)) ~to_raw:(fun x -> Bytes.to_string (Sodium.Sign.Bytes.of_public_key x))
~of_raw:(fun x -> Sodium.Sign.Bytes.to_public_key (Bytes.of_string x)) ~of_raw:(fun x ->
try Some (Sodium.Sign.Bytes.to_public_key (Bytes.of_string x))
with _ -> None)
~wrap:(fun x -> Public_key x) ~wrap:(fun x -> Public_key x)
let b48check_secret_key_encoding = let b48check_secret_key_encoding =
Base48.register_encoding Base48.register_encoding
~prefix: Base48.Prefix.ed25519_secret_key ~prefix: Base48.Prefix.ed25519_secret_key
~to_raw:(fun x -> Bytes.to_string (Sodium.Sign.Bytes.of_secret_key x)) ~to_raw:(fun x -> Bytes.to_string (Sodium.Sign.Bytes.of_secret_key x))
~of_raw:(fun x -> Sodium.Sign.Bytes.to_secret_key (Bytes.of_string x)) ~of_raw:(fun x ->
try Some (Sodium.Sign.Bytes.to_secret_key (Bytes.of_string x))
with _ -> None)
~wrap:(fun x -> Secret_key x) ~wrap:(fun x -> Secret_key x)
let b48check_signature_encoding = let b48check_signature_encoding =
Base48.register_encoding Base48.register_encoding
~prefix: Base48.Prefix.ed25519_signature ~prefix: Base48.Prefix.ed25519_signature
~to_raw:MBytes.to_string ~to_raw:MBytes.to_string
~of_raw:MBytes.of_string ~of_raw:(fun s -> Some (MBytes.of_string s))
~wrap:(fun x -> Signature x) ~wrap:(fun x -> Signature x)
let public_key_encoding = let public_key_encoding =
@ -164,4 +168,6 @@ module type PACKED_PROTOCOL = sig
val error_encoding : error Data_encoding.t val error_encoding : error Data_encoding.t
val classify_errors : error list -> [ `Branch | `Temporary | `Permanent ] val classify_errors : error list -> [ `Branch | `Temporary | `Permanent ]
val pp : Format.formatter -> error -> unit val pp : Format.formatter -> error -> unit
val complete_b48prefix :
?alphabet:string -> Context.t -> string -> string list Lwt.t
end end

View File

@ -48,6 +48,8 @@ module type PACKED_PROTOCOL = sig
val error_encoding : error Data_encoding.t val error_encoding : error Data_encoding.t
val classify_errors : error list -> [ `Branch | `Temporary | `Permanent ] val classify_errors : error list -> [ `Branch | `Temporary | `Permanent ]
val pp : Format.formatter -> error -> unit val pp : Format.formatter -> error -> unit
val complete_b48prefix :
?alphabet:string -> Context.t -> string -> string list Lwt.t
end end
val __cast: (module PACKED_PROTOCOL) -> (module Protocol.PACKED_PROTOCOL) val __cast: (module PACKED_PROTOCOL) -> (module Protocol.PACKED_PROTOCOL)
|} |}

View File

@ -135,4 +135,6 @@ module type PACKED_PROTOCOL = sig
val error_encoding : error Data_encoding.t val error_encoding : error Data_encoding.t
val classify_errors : error list -> [ `Branch | `Temporary | `Permanent ] val classify_errors : error list -> [ `Branch | `Temporary | `Permanent ]
val pp : Format.formatter -> error -> unit val pp : Format.formatter -> error -> unit
val complete_b48prefix :
?alphabet:string -> Context.t -> string -> string list Lwt.t
end end

View File

@ -16,6 +16,8 @@ module type REGISTRED_PROTOCOL = sig
val hash: Protocol_hash.t val hash: Protocol_hash.t
include Protocol.PROTOCOL with type error := error include Protocol.PROTOCOL with type error := error
and type 'a tzresult := 'a tzresult and type 'a tzresult := 'a tzresult
val complete_b48prefix :
?alphabet:string -> Context.t -> string -> string list Lwt.t
end end
type net_id = Store.net_id = Net of Block_hash.t type net_id = Store.net_id = Net of Block_hash.t

View File

@ -68,6 +68,8 @@ module type REGISTRED_PROTOCOL = sig
(* exception Ecoproto_error of error list *) (* exception Ecoproto_error of error list *)
include Protocol.PROTOCOL with type error := error include Protocol.PROTOCOL with type error := error
and type 'a tzresult := 'a tzresult and type 'a tzresult := 'a tzresult
val complete_b48prefix :
?alphabet:string -> Context.t -> string -> string list Lwt.t
end end
type component = Tezos_compiler.Protocol.component = { type component = Tezos_compiler.Protocol.component = {

View File

@ -3,7 +3,7 @@ B _tzbuild
FLG -nopervasives FLG -nopervasives
FLG -open Proto_environment FLG -open Proto_environment
FLG -open Hash FLG -open Hash
FLG -open Local_error_monad FLG -open Local_modules
FLG -open Error_monad FLG -open Error_monad
FLG -open Logging FLG -open Logging
FLG -w -40 FLG -w -40

View File

@ -88,6 +88,7 @@ module Key = struct
end end
module Contract = struct module Contract = struct
let store_root l = store_root ("contracts" :: l) let store_root l = store_root ("contracts" :: l)
let set = store_root ["set"] let set = store_root ["set"]
let pubkey_contract l = store_root ("pubkey" :: l) let pubkey_contract l = store_root ("pubkey" :: l)
@ -238,6 +239,7 @@ module Contract = struct
let encoding = Data_encoding.int32 let encoding = Data_encoding.int32
end) end)
(** FIXME REMOVE : use 'list' *)
module Set = module Set =
Make_data_set_storage(struct Make_data_set_storage(struct
type value = Contract_repr.t type value = Contract_repr.t
@ -518,3 +520,15 @@ let fork_test_network (c, constants) =
Updater.fork_test_network c >>= fun c -> Lwt.return (c, constants) Updater.fork_test_network c >>= fun c -> Lwt.return (c, constants)
let set_test_protocol (c, constants) h = let set_test_protocol (c, constants) h =
Updater.set_test_protocol c h >>= fun c -> Lwt.return (c, constants) Updater.set_test_protocol c h >>= fun c -> Lwt.return (c, constants)
(** Resolver *)
let () =
Storage_functors.register_resolvers
(module Contract_hash)
[ Key.Contract.generic_contract [] ] ;
Storage_functors.register_resolvers
(module Ed25519.Public_key_hash)
[ Key.Contract.pubkey_contract [] ;
Key.public_keys ]

View File

@ -202,10 +202,9 @@ end
module Make_data_set_storage (P : Single_data_description) = struct module Make_data_set_storage (P : Single_data_description) = struct
module Key = struct module Key = struct
include Hash.Make_SHA256(struct include Hash.Make_minimal_SHA256(struct
let name = P.name let name = P.name
let title = ("A " ^ P.name ^ "key") let title = ("A " ^ P.name ^ "key")
let prefix = None
end) end)
let prefix = P.key let prefix = P.key
let length = path_len let length = path_len
@ -352,3 +351,31 @@ module Make_iterable_data_storage (H: HASH) (P: Single_data_description) =
let prefix = P.key let prefix = P.key
let length = path_len let length = path_len
end)(P) end)(P)
let register_resolvers (module H : Hash.HASH) prefixes =
let module Set = Hash_set(H) in
let resolvers =
List.map
(fun prefix ->
let module R = Persist.MakeHashResolver(struct
include Context
let prefix = prefix
end)(H) in
R.resolve)
prefixes in
let resolve c m =
match resolvers with
| [resolve] -> resolve c m
| resolvers ->
Lwt_list.map_p (fun resolve -> resolve c m) resolvers >|= fun hs ->
List.fold_left
(fun acc hs -> List.fold_left (fun acc h -> Set.add h acc) acc hs)
Set.empty hs |>
Set.elements in
Base48.register_resolver H.b48check_encoding resolve

View File

@ -98,3 +98,5 @@ module Raw_make_iterable_data_storage (K: Persist.KEY) (P: Data_description) :
and type value = P.value and type value = P.value
and type context := context and type context := context
val register_resolvers: (module Hash.HASH) -> string list list -> unit

View File

@ -227,3 +227,10 @@ module Make_data_set_storage (P : Single_data_description) :
module Make_iterable_data_storage (H : HASH) (P: Single_data_description) : module Make_iterable_data_storage (H : HASH) (P: Single_data_description) :
Iterable_data_storage with type key = H.t and type value = P.value Iterable_data_storage with type key = H.t and type value = P.value
module Make_hash_resolver
(K: sig val prefix: string list end)
(H: Hash.HASH) : sig
val register : Store.t -> unit
end

View File

@ -8,42 +8,44 @@
(**************************************************************************) (**************************************************************************)
module Prefix = struct module Prefix = struct
let random_state_hash = Base48.Prefix.protocol_prefix ^ "\001" let make x =
let nonce_hash = Base48.Prefix.protocol_prefix ^ "\002" assert (Compare.String.(Base48.Prefix.protocol_prefix = "\015")) ;
let script_expr_hash = Base48.Prefix.protocol_prefix ^ "\003" String.make 1 (char_of_int ((x lsl 4) lor 15))
let proposition_hash = Base48.Prefix.protocol_prefix ^ "\004" let public_key_hash = make 0
let contract_hash = Base48.Prefix.protocol_prefix ^ "\005" let contract_hash = make 1
let nonce_hash = make 2
let script_expr_hash = make 3
let random_state_hash = make 15 (* never used... *)
end end
module State_hash = Hash.Make_SHA256(struct module State_hash = Hash.Make_SHA256(Base48)(struct
let name = "random" let name = "random"
let title = "A random generation state" let title = "A random generation state"
let prefix = Some Prefix.random_state_hash let b48check_prefix = Prefix.random_state_hash
end) end)
module State_hash_set = Hash_set(State_hash) module State_hash_set = Hash_set(State_hash)
module State_hash_map = Hash_map(State_hash) module State_hash_map = Hash_map(State_hash)
module Nonce_hash = Hash.Make_SHA256(struct module Nonce_hash = Hash.Make_SHA256(Base48)(struct
let name = "cycle_nonce" let name = "cycle_nonce"
let title = "A nonce hash" let title = "A nonce hash"
let prefix = Some Prefix.nonce_hash let b48check_prefix = Prefix.nonce_hash
end) end)
module Nonce_hash_set = Hash_set(Nonce_hash) module Nonce_hash_set = Hash_set(Nonce_hash)
module Nonce_hash_map = Hash_map(Nonce_hash) module Nonce_hash_map = Hash_map(Nonce_hash)
module Script_expr_hash = Hash.Make_SHA256(struct module Script_expr_hash = Hash.Make_SHA256(Base48)(struct
let name = "script_expr" let name = "script_expr"
let title = "A script expression ID" let title = "A script expression ID"
let prefix = Some Prefix.script_expr_hash let b48check_prefix = Prefix.script_expr_hash
end) end)
module Script_expr_hash_set = Hash_set(Script_expr_hash) module Script_expr_hash_set = Hash_set(Script_expr_hash)
module Script_expr_hash_map = Hash_map(Script_expr_hash) module Script_expr_hash_map = Hash_map(Script_expr_hash)
module Contract_hash = Hash.Make_SHA256(struct module Contract_hash = Hash.Make_SHA256(Base48)(struct
let name = "Contract_hash" let name = "Contract_hash"
let title = "A contract ID" let title = "A contract ID"
let prefix = Some Prefix.contract_hash let b48check_prefix = Prefix.contract_hash
end) end)
module Contract_hash_set = Hash_set(Contract_hash) module Contract_hash_set = Hash_set(Contract_hash)
module Contract_hash_map = Hash_map(Contract_hash) module Contract_hash_map = Hash_map(Contract_hash)

View File

@ -3,6 +3,7 @@ B _tzbuild
FLG -nopervasives FLG -nopervasives
FLG -open Proto_environment FLG -open Proto_environment
FLG -open Hash FLG -open Hash
FLG -open Local_error_monad FLG -open Local_modules
FLG -open Error_monad FLG -open Error_monad
FLG -open Logging
FLG -w -40 FLG -w -40

View File

@ -1,20 +1,26 @@
type data = ..
val decode: ?alphabet:string -> string -> data
val encode: ?alphabet:string -> data -> string
type kind
val register:
prefix:string ->
read:(data -> string option) ->
build:(string -> data) ->
kind
val register_resolver:
kind -> (string -> string list Lwt.t) -> unit
module Prefix : sig module Prefix : sig
val protocol_prefix: string val protocol_prefix: string
end end
type 'a encoding = 'a Base48.encoding
val simple_decode: ?alphabet:string -> 'a encoding -> string -> 'a option
val simple_encode: ?alphabet:string -> 'a encoding -> 'a -> string
type data = Base48.data = ..
val register_encoding:
prefix: string ->
to_raw: ('a -> string) ->
of_raw: (string -> 'a option) ->
wrap: ('a -> data) ->
'a encoding
val decode: ?alphabet:string -> string -> data option
val register_resolver:
'a encoding -> (Context.t -> string -> 'a list Lwt.t) -> unit
val complete:
?alphabet:string -> Context.t -> string -> string list Lwt.t

View File

@ -1,5 +1,5 @@
(** Tezos - Manipulation and creation of hashes *)
(** Tezos - Manipulation and creation of hashes *)
(** {2 Hash Types} ************************************************************) (** {2 Hash Types} ************************************************************)
@ -8,9 +8,14 @@
various kinds of hashes in the system at typing time. Each type is various kinds of hashes in the system at typing time. Each type is
equipped with functions to use it as is of as keys in the database equipped with functions to use it as is of as keys in the database
or in memory sets and maps. *) or in memory sets and maps. *)
module type HASH = sig
module type MINIMAL_HASH = sig
type t type t
val name: string
val title: string
val hash_bytes: MBytes.t list -> t val hash_bytes: MBytes.t list -> t
val hash_string: string list -> t val hash_string: string list -> t
val size: int (* in bytes *) val size: int (* in bytes *)
@ -20,9 +25,6 @@ module type HASH = sig
val to_raw: t -> string val to_raw: t -> string
val of_hex: string -> t val of_hex: string -> t
val to_hex: t -> string val to_hex: t -> string
val of_b48check: string -> t
val to_b48check: t -> string
val to_short_b48check: t -> string
val to_bytes: t -> MBytes.t val to_bytes: t -> MBytes.t
val of_bytes: MBytes.t -> t val of_bytes: MBytes.t -> t
val read: MBytes.t -> int -> t val read: MBytes.t -> int -> t
@ -31,11 +33,22 @@ module type HASH = sig
val of_path: string list -> t val of_path: string list -> t
val prefix_path: string -> string list val prefix_path: string -> string list
val path_len: int val path_len: int
end
module type HASH = sig
include MINIMAL_HASH
val of_b48check: string -> t
val to_b48check: t -> string
val to_short_b48check: t -> string
val encoding: t Data_encoding.t val encoding: t Data_encoding.t
val pp: Format.formatter -> t -> unit val pp: Format.formatter -> t -> unit
val pp_short: Format.formatter -> t -> unit val pp_short: Format.formatter -> t -> unit
type Base48.data += Hash of t type Base48.data += Hash of t
val kind: Base48.kind option val b48check_encoding: t Base48.encoding
end end
(** {2 Building Hashes} *******************************************************) (** {2 Building Hashes} *******************************************************)
@ -43,14 +56,30 @@ end
(** The parameters for creating a new Hash type using (** The parameters for creating a new Hash type using
{!Make_SHA256}. Both {!name} and {!title} are only informative, {!Make_SHA256}. Both {!name} and {!title} are only informative,
used in error messages and serializers. *) used in error messages and serializers. *)
module type Name = sig module type Name = sig
val name : string val name : string
val title : string val title : string
val prefix : string option end
module type PrefixedName = sig
include Name
val b48check_prefix : string
end end
(** Builds a new Hash type using Sha256. *) (** Builds a new Hash type using Sha256. *)
module Make_SHA256 (Name:Name) : HASH
module Make_minimal_SHA256 (Name : Name) : MINIMAL_HASH
module Make_SHA256
(Register : sig
val register_encoding:
prefix: string ->
to_raw: ('a -> string) ->
of_raw: (string -> 'a option) ->
wrap: ('a -> Base48.data) ->
'a Base48.encoding
end)
(Name : PrefixedName) : HASH
(** Builds a Set of values of some Hash type. *) (** Builds a Set of values of some Hash type. *)
module Hash_set (Hash : HASH) : sig module Hash_set (Hash : HASH) : sig
@ -80,3 +109,4 @@ module Operation_hash_map : module type of Hash_map (Operation_hash)
module Protocol_hash : HASH module Protocol_hash : HASH
module Protocol_hash_set : Set.S with type elt = Protocol_hash.t module Protocol_hash_set : Set.S with type elt = Protocol_hash.t
module Protocol_hash_map : module type of Hash_map (Protocol_hash) module Protocol_hash_map : module type of Hash_map (Protocol_hash)

View File

@ -13,12 +13,12 @@ type value = MBytes.t
module type STORE = sig module type STORE = sig
type t type t
val mem: t -> key -> bool Lwt.t val mem: t -> key -> bool Lwt.t
val dir_mem: t -> key -> bool Lwt.t
val get: t -> key -> value option Lwt.t val get: t -> key -> value option Lwt.t
val set: t -> key -> value -> t Lwt.t val set: t -> key -> value -> t Lwt.t
val del: t -> key -> t Lwt.t val del: t -> key -> t Lwt.t
val list: t -> key list -> key list Lwt.t val list: t -> key list -> key list Lwt.t
val remove_rec: t -> key -> t Lwt.t val remove_rec: t -> key -> t Lwt.t
val keys: t -> key list Lwt.t val keys: t -> key list Lwt.t
end end
@ -196,3 +196,14 @@ module MakeBufferedPersistentTypedMap
and type key := K.t and type key := K.t
and type value := T.value and type value := T.value
and module Map := Map and module Map := Map
module MakeHashResolver
(Store : sig
type t
val dir_mem: t -> key -> bool Lwt.t
val list: t -> key list -> key list Lwt.t
val prefix: string list
end)
(H: Hash.HASH) : sig
val resolve : Store.t -> string -> H.t list Lwt.t
end

View File

@ -10,6 +10,7 @@
open Utils open Utils
let (>>=) = Lwt.bind let (>>=) = Lwt.bind
let (>|=) = Lwt.(>|=)
let decode_alphabet alphabet = let decode_alphabet alphabet =
let str = Bytes.make 256 '\255' in let str = Bytes.make 256 '\255' in
@ -102,83 +103,131 @@ let safe_decode ?alphabet s =
type data = .. type data = ..
type kind = type 'a encoding = {
Kind : { prefix: string; prefix: string;
read: data -> string option ; to_raw: 'a -> string ;
build: string -> data ; of_raw: string -> 'a option ;
mutable resolver: string -> string list Lwt.t ; wrap: 'a -> data ;
} -> kind }
let kinds = ref ([] : kind list) let simple_decode ?alphabet { prefix ; of_raw } s =
safe_decode ?alphabet s |>
remove_prefix ~prefix |>
Utils.apply_option ~f:of_raw
exception Unknown_prefix let simple_encode ?alphabet { prefix ; to_raw } d =
safe_encode ?alphabet (prefix ^ to_raw d)
type registred_encoding = Encoding : 'a encoding -> registred_encoding
module MakeEncodings(E: sig
val encodings: registred_encoding list
end) = struct
let encodings = ref E.encodings
let ambiguous_prefix prefix encodings =
List.exists (fun (Encoding { prefix = s }) ->
remove_prefix s prefix <> None ||
remove_prefix prefix s <> None)
encodings
let register_encoding ~prefix ~to_raw ~of_raw ~wrap =
if ambiguous_prefix prefix !encodings then
Format.ksprintf invalid_arg
"Base48.register_encoding: duplicate prefix: %S" prefix ;
let encoding = { prefix ; to_raw ; of_raw ; wrap } in
encodings := Encoding encoding :: !encodings ;
encoding
let decode ?alphabet s = let decode ?alphabet s =
let rec find s = function let rec find s = function
| [] -> raise Unknown_prefix | [] -> None
| Kind { prefix ; build } :: kinds -> | Encoding { prefix ; of_raw ; wrap } :: encodings ->
match remove_prefix ~prefix s with match remove_prefix ~prefix s with
| None -> find s kinds | None -> find s encodings
| Some msg -> build msg in | Some msg -> of_raw msg |> Utils.map_option ~f:wrap in
let s = safe_decode ?alphabet s in let s = safe_decode ?alphabet s in
find s !kinds find s !encodings
exception Unregistred_kind
let encode ?alphabet s =
let rec find s = function
| [] -> raise Unregistred_kind
| Kind { prefix ; read } :: kinds ->
match read s with
| None -> find s kinds
| Some msg -> safe_encode ?alphabet (prefix ^ msg) in
try find s !kinds
with Not_found -> raise Unknown_prefix
let default_resolver _ = Lwt.return_nil
let register ~prefix ~read ~build =
match List.find (fun (Kind {prefix=s}) -> remove_prefix s prefix <> None || remove_prefix prefix s <> None) !kinds with
| exception Not_found ->
let kind =
Kind { prefix ; read ; build ; resolver = default_resolver } in
kinds := kind :: !kinds ;
kind
| Kind { prefix = s } ->
Format.kasprintf
Pervasives.failwith
"Base48.register: Conflicting prefixes: %S and %S." prefix s
let register_resolver (Kind k) resolver = k.resolver <- resolver
module Prefix = struct
let block_hash = "\000"
let operation_hash = "\001"
let protocol_hash = "\002"
let public_key_hash = "\003"
let public_key = "\004"
let secret_key = "\005"
let signature = "\006"
let protocol_prefix = "\015"
end end
let decode_partial ?alphabet request = type 'a resolver =
Resolver : {
encoding: 'h encoding ;
resolver: 'a -> string -> 'h list Lwt.t ;
} -> 'a resolver
module MakeResolvers(R: sig
type context
val encodings: registred_encoding list ref
end) = struct
let resolvers = ref []
let register_resolver
(type a)
(encoding : a encoding)
(resolver : R.context -> string -> a list Lwt.t) =
try
resolvers := Resolver { encoding ; resolver } :: !resolvers
with Not_found ->
invalid_arg "Base48.register_resolver: unregistred encodings"
type context = R.context
let complete ?alphabet context request =
(* One may extract from the prefix of a Base48-encoded value, a
prefix of the original encoded value. Given that `48 = 3 * 2^4`,
every "digits" in the Base48-prefix (i.e. a "bytes" in its ascii
representation), provides for sure 4 bits of the original data.
Hence, when we decode a prefix of a Base48-encoded value of
length `n`, the `n/2` first bytes of the decoded value are (for
sure) a prefix of the original value. *)
let n = String.length request in let n = String.length request in
let s = raw_decode request ?alphabet in let s = raw_decode request ?alphabet in
let partial = String.sub s 0 (n / 2) in let partial = String.sub s 0 (n / 2) in
let rec find s = function let rec find s = function
| [] -> Lwt.return_nil | [] -> Lwt.return_nil
| Kind { prefix ; build ; resolver } :: kinds -> | Resolver { encoding ; resolver } :: resolvers ->
match remove_prefix ~prefix s with match remove_prefix ~prefix:encoding.prefix s with
| None -> find s kinds | None -> find s resolvers
| Some msg -> | Some msg ->
resolver msg >>= fun msgs -> resolver context msg >|= fun msgs ->
let candidates = List.map build msgs in filter_map
Lwt.return @@ (fun msg ->
List.filter let res = simple_encode encoding ?alphabet msg in
(fun data -> Utils.remove_prefix ~prefix:request res |>
match Utils.remove_prefix ~prefix:request (encode data) with Utils.map_option ~f:(fun _ -> res))
| None -> false msgs in
| Some _ -> true) find partial !resolvers
candidates in
find partial !kinds end
include MakeEncodings(struct let encodings = [] end)
include MakeResolvers(struct
type context = unit
let encodings = encodings
end)
let register_resolver enc f = register_resolver enc (fun () s -> f s)
let complete ?alphabet s = complete ?alphabet () s
module Make(C: sig type context end) = struct
include MakeEncodings(struct let encodings = !encodings end)
include MakeResolvers(struct
type context = C.context
let encodings = encodings
end)
end
module Prefix = struct
let block_hash = "\000"
let operation_hash = "\001"
let protocol_hash = "\002"
let ed25519_public_key_hash = "\003"
let ed25519_public_key = "\012"
let ed25519_secret_key = "\013"
let ed25519_signature = "\014"
let protocol_prefix = "\015"
end

View File

@ -1,4 +1,3 @@
(**************************************************************************) (**************************************************************************)
(* *) (* *)
(* Copyright (c) 2014 - 2016. *) (* Copyright (c) 2014 - 2016. *)
@ -8,34 +7,131 @@
(* *) (* *)
(**************************************************************************) (**************************************************************************)
(** {1 Prefixed Base48Check encodings} *)
(** Like Bitcoin's Base58Check, all the data encoded in Tezos are
prefixed with a constant which depends on the kind of encoded
data.
The [Prefix] exports all the prefix used by the Tezos Shell. Each
version of the economical protocol might complete this list.
Unlike Bitcoin's Base58Check, the prefix in the unencoded-data
is visible in the encoded data.
*)
module Prefix : sig
val block_hash: string
(** Prefix for block hashes: "\000".
(in Base48: "e" "f" or "g") *)
val operation_hash: string
(** Prefix for operation hashes: "\001".
(in Base48: "E" "F" or "G") *)
val protocol_hash: string
(** Prefix for protocol-version hashes: "\002".
(in Base48: "2" "3" or "4") *)
val ed25519_public_key_hash: string
(** Prefix for Ed25519 public key hashes: "\003". *)
val ed25519_public_key: string
(** Prefix for Ed25519 public key: "\012". *)
val ed25519_secret_key: string
(** Prefix for Ed25519 secret key: "\013". *)
val ed25519_signature: string
(** Prefix for Ed25519 signature key: "\014". *)
val protocol_prefix: string
(** Prefix for all the encodings defined by economical protocol:
"\015". *)
end
(** An extensible sum-type for decoded data: one case per known
"prefix". See for instance [Hash.Block_hash.Hash] or
[Environment.Ed25519.Public_key_hash]. *)
type data = ..
(** Abstract representation of registred encodings. The type paramater
is the type of the encoded data, for instance [Hash.Block_hash.t]. *)
type 'a encoding = private {
prefix: string;
to_raw: 'a -> string ;
of_raw: string -> 'a option ;
wrap: 'a -> data ;
}
(** Register a new encoding. The function might raise `Invalid_arg` if
the provided [prefix] overlap with a previously registred
prefix. The [to_raw] and [of_raw] are the ad-hoc
serialisation/deserialisation for the data. The [wrap] should wrap
the deserialised value into the extensible sum-type [data] (see
the generic function [decode]). *)
val register_encoding:
prefix: string ->
to_raw: ('a -> string) ->
of_raw: (string -> 'a option) ->
wrap: ('a -> data) ->
'a encoding
(** Encoder for a given kind of data. *)
val simple_encode: ?alphabet:string -> 'a encoding -> 'a -> string
(** Decoder for a given kind of data. It returns [None] when
the decoded data does not start with the expected prefix. *)
val simple_decode: ?alphabet:string -> 'a encoding -> string -> 'a option
(** Generic decoder. It returns [None] when the decoded data does
not start with a registred prefix. *)
val decode: ?alphabet:string -> string -> data option
(** {2 Completion of partial Base48Check value} *)
(** Register a (global) resolver for a previsously
registred kind af data. *)
val register_resolver: 'a encoding -> (string -> 'a list Lwt.t) -> unit
(** Try to complete a prefix of a Base48Check encoded data, by using
the previously registered resolver associated to this kind of
data. Note that a prefix of [n] characters of a Base48-encoded
value provides at least [n/2] bytes of a prefix of the original value. *)
val complete: ?alphabet:string -> string -> string list Lwt.t
(** {1 Low-level: distinct registering function for economical protocol} *)
(** See [src/proto/environment/base48.mli]} for an inlined
documentation. *)
module Make(C: sig type context end) : sig
val register_encoding:
prefix: string ->
to_raw: ('a -> string) ->
of_raw: (string -> 'a option) ->
wrap: ('a -> data) ->
'a encoding
val decode: ?alphabet:string -> string -> data option
val register_resolver:
'a encoding -> (C.context -> string -> 'a list Lwt.t) -> unit
val complete:
?alphabet:string -> C.context -> string -> string list Lwt.t
end
(** {2 Low-level Base48Check encodings} *)
(** Base48Check-encoding/decoding functions (with error detections). *)
val safe_encode: ?alphabet:string -> string -> string val safe_encode: ?alphabet:string -> string -> string
val safe_decode: ?alphabet:string -> string -> string val safe_decode: ?alphabet:string -> string -> string
type data = .. (** Base48-encoding/decoding functions (without error detections). *)
val raw_encode: ?alphabet:string -> string -> string
val raw_decode: ?alphabet:string -> string -> string
val decode: ?alphabet:string -> string -> data
val encode: ?alphabet:string -> data -> string
val decode_partial: ?alphabet:string -> string -> data list Lwt.t
type kind
val register:
prefix:string ->
read:(data -> string option) ->
build:(string -> data) ->
kind
val register_resolver:
kind -> (string -> string list Lwt.t) -> unit
module Prefix : sig
val block_hash: string
val operation_hash: string
val protocol_hash: string
val public_key_hash: string
val public_key: string
val secret_key: string
val signature: string
val protocol_prefix: string
end

View File

@ -15,9 +15,13 @@ open Utils
(*-- Signatures -------------------------------------------------------------*) (*-- Signatures -------------------------------------------------------------*)
module type HASH = sig module type MINIMAL_HASH = sig
type t type t
val name: string
val title: string
val hash_bytes: MBytes.t list -> t val hash_bytes: MBytes.t list -> t
val hash_string: string list -> t val hash_string: string list -> t
val size: int (* in bytes *) val size: int (* in bytes *)
@ -27,9 +31,6 @@ module type HASH = sig
val to_raw: t -> string val to_raw: t -> string
val of_hex: string -> t val of_hex: string -> t
val to_hex: t -> string val to_hex: t -> string
val of_b48check: string -> t
val to_b48check: t -> string
val to_short_b48check: t -> string
val to_bytes: t -> MBytes.t val to_bytes: t -> MBytes.t
val of_bytes: MBytes.t -> t val of_bytes: MBytes.t -> t
val read: MBytes.t -> int -> t val read: MBytes.t -> int -> t
@ -38,25 +39,42 @@ module type HASH = sig
val of_path: string list -> t val of_path: string list -> t
val prefix_path: string -> string list val prefix_path: string -> string list
val path_len: int val path_len: int
end
module type HASH = sig
include MINIMAL_HASH
val of_b48check: string -> t
val to_b48check: t -> string
val to_short_b48check: t -> string
val encoding: t Data_encoding.t val encoding: t Data_encoding.t
val pp: Format.formatter -> t -> unit val pp: Format.formatter -> t -> unit
val pp_short: Format.formatter -> t -> unit val pp_short: Format.formatter -> t -> unit
type Base48.data += Hash of t type Base48.data += Hash of t
val kind: Base48.kind option val b48check_encoding: t Base48.encoding
end end
module type Name = sig module type Name = sig
val name: string val name: string
val title: string val title: string
val prefix : string option end
module type PrefixedName = sig
include Name
val b48check_prefix: string
end end
(*-- Type specific Hash builder ---------------------------------------------*) (*-- Type specific Hash builder ---------------------------------------------*)
module Make_SHA256 (K : Name) = struct module Make_minimal_SHA256 (K : Name) = struct
type t = string type t = string
include K
let size = 32 (* SHA256 *) let size = 32 (* SHA256 *)
let of_raw s = let of_raw s =
@ -72,25 +90,6 @@ module Make_SHA256 (K : Name) = struct
let of_hex s = of_raw (Hex_encode.hex_decode s) let of_hex s = of_raw (Hex_encode.hex_decode s)
let to_hex s = Hex_encode.hex_encode s let to_hex s = Hex_encode.hex_encode s
type Base48.data += Hash of t
let kind =
Utils.map_option
K.prefix
~f:(fun prefix ->
Base48.register
~prefix
~read:(function Hash x -> Some x | _ -> None)
~build:(fun x -> Hash x))
let of_b48check s =
match Base48.decode s with
| Hash x -> x
| _ -> Format.kasprintf failwith "Unexpected hash (%s)" K.name
let to_b48check s = Base48.encode (Hash s)
let to_short_b48check s = String.sub (to_b48check s) 0 12
let compare = String.compare let compare = String.compare
let equal : t -> t -> bool = (=) let equal : t -> t -> bool = (=)
@ -143,12 +142,12 @@ module Make_SHA256 (K : Name) = struct
let equal = equal let equal = equal
end) end)
let path_len = 5 let path_len = 6
let to_path key = let to_path key =
let key = to_hex key in let key = to_hex key in
[ String.sub key 0 2 ; String.sub key 2 2 ; [ String.sub key 0 2 ; String.sub key 2 2 ;
String.sub key 4 2 ; String.sub key 6 2 ; String.sub key 4 2 ; String.sub key 6 2 ;
String.sub key 8 (size * 2 - 8) ] String.sub key 8 2 ; String.sub key 10 (size * 2 - 10) ]
let of_path path = let of_path path =
let path = String.concat "" path in let path = String.concat "" path in
of_hex path of_hex path
@ -160,11 +159,41 @@ module Make_SHA256 (K : Name) = struct
and p2 = if len >= 4 then String.sub p 2 2 else "" and p2 = if len >= 4 then String.sub p 2 2 else ""
and p3 = if len >= 6 then String.sub p 4 2 else "" and p3 = if len >= 6 then String.sub p 4 2 else ""
and p4 = if len >= 8 then String.sub p 6 2 else "" and p4 = if len >= 8 then String.sub p 6 2 else ""
and p5 = if len > 8 then String.sub p 8 (len - 8) else "" in and p5 = if len >= 10 then String.sub p 8 2 else ""
[ p1 ; p2 ; p3 ; p4 ; p5 ] and p6 = if len > 10 then String.sub p 10 (len - 10) else "" in
[ p1 ; p2 ; p3 ; p4 ; p5 ; p6 ]
end
module Make_SHA256 (R : sig
val register_encoding:
prefix: string ->
to_raw: ('a -> string) ->
of_raw: (string -> 'a option) ->
wrap: ('a -> Base48.data) ->
'a Base48.encoding
end) (K : PrefixedName) = struct
include Make_minimal_SHA256(K)
(* Serializers *) (* Serializers *)
type Base48.data += Hash of t
let b48check_encoding =
R.register_encoding
~prefix: K.b48check_prefix
~wrap: (fun x -> Hash x)
~of_raw:(fun s -> Some s) ~to_raw
let of_b48check s =
match Base48.simple_decode b48check_encoding s with
| Some x -> x
| None -> Format.kasprintf failwith "Unexpected hash (%s)" K.name
let to_b48check s = Base48.simple_encode b48check_encoding s
let to_short_b48check s = String.sub (to_b48check s) 0 12
let encoding = let encoding =
let open Data_encoding in let open Data_encoding in
splitted splitted
@ -219,10 +248,10 @@ module Hash_table (Hash : HASH)
(*-- Pre-instanciated hashes ------------------------------------------------*) (*-- Pre-instanciated hashes ------------------------------------------------*)
module Block_hash = module Block_hash =
Make_SHA256 (struct Make_SHA256 (Base48) (struct
let name = "Block_hash" let name = "Block_hash"
let title = "A Tezos block ID" let title = "A Tezos block ID"
let prefix = Some Base48.Prefix.block_hash let b48check_prefix = Base48.Prefix.block_hash
end) end)
module Block_hash_set = Hash_set (Block_hash) module Block_hash_set = Hash_set (Block_hash)
@ -230,10 +259,10 @@ module Block_hash_map = Hash_map (Block_hash)
module Block_hash_table = Hash_table (Block_hash) module Block_hash_table = Hash_table (Block_hash)
module Operation_hash = module Operation_hash =
Make_SHA256 (struct Make_SHA256 (Base48) (struct
let name = "Operation_hash" let name = "Operation_hash"
let title = "A Tezos operation ID" let title = "A Tezos operation ID"
let prefix = Some Base48.Prefix.operation_hash let b48check_prefix = Base48.Prefix.operation_hash
end) end)
module Operation_hash_set = Hash_set (Operation_hash) module Operation_hash_set = Hash_set (Operation_hash)
@ -241,10 +270,10 @@ module Operation_hash_map = Hash_map (Operation_hash)
module Operation_hash_table = Hash_table (Operation_hash) module Operation_hash_table = Hash_table (Operation_hash)
module Protocol_hash = module Protocol_hash =
Make_SHA256 (struct Make_SHA256 (Base48) (struct
let name = "Protocol_hash" let name = "Protocol_hash"
let title = "A Tezos protocol ID" let title = "A Tezos protocol ID"
let prefix = Some Base48.Prefix.protocol_hash let b48check_prefix = Base48.Prefix.protocol_hash
end) end)
module Protocol_hash_set = Hash_set (Protocol_hash) module Protocol_hash_set = Hash_set (Protocol_hash)

View File

@ -17,9 +17,14 @@
various kinds of hashes in the system at typing time. Each type is various kinds of hashes in the system at typing time. Each type is
equipped with functions to use it as is of as keys in the database equipped with functions to use it as is of as keys in the database
or in memory sets and maps. *) or in memory sets and maps. *)
module type HASH = sig
module type MINIMAL_HASH = sig
type t type t
val name: string
val title: string
val hash_bytes: MBytes.t list -> t val hash_bytes: MBytes.t list -> t
val hash_string: string list -> t val hash_string: string list -> t
val size: int (* in bytes *) val size: int (* in bytes *)
@ -29,9 +34,6 @@ module type HASH = sig
val to_raw: t -> string val to_raw: t -> string
val of_hex: string -> t val of_hex: string -> t
val to_hex: t -> string val to_hex: t -> string
val of_b48check: string -> t
val to_b48check: t -> string
val to_short_b48check: t -> string
val to_bytes: t -> MBytes.t val to_bytes: t -> MBytes.t
val of_bytes: MBytes.t -> t val of_bytes: MBytes.t -> t
val read: MBytes.t -> int -> t val read: MBytes.t -> int -> t
@ -40,11 +42,22 @@ module type HASH = sig
val of_path: string list -> t val of_path: string list -> t
val prefix_path: string -> string list val prefix_path: string -> string list
val path_len: int val path_len: int
end
module type HASH = sig
include MINIMAL_HASH
val of_b48check: string -> t
val to_b48check: t -> string
val to_short_b48check: t -> string
val encoding: t Data_encoding.t val encoding: t Data_encoding.t
val pp: Format.formatter -> t -> unit val pp: Format.formatter -> t -> unit
val pp_short: Format.formatter -> t -> unit val pp_short: Format.formatter -> t -> unit
type Base48.data += Hash of t type Base48.data += Hash of t
val kind: Base48.kind option val b48check_encoding: t Base48.encoding
end end
(** {2 Building Hashes} *******************************************************) (** {2 Building Hashes} *******************************************************)
@ -52,14 +65,29 @@ end
(** The parameters for creating a new Hash type using (** The parameters for creating a new Hash type using
{!Make_SHA256}. Both {!name} and {!title} are only informative, {!Make_SHA256}. Both {!name} and {!title} are only informative,
used in error messages and serializers. *) used in error messages and serializers. *)
module type Name = sig module type Name = sig
val name : string val name : string
val title : string val title : string
val prefix : string option end
module type PrefixedName = sig
include Name
val b48check_prefix : string
end end
(** Builds a new Hash type using Sha256. *) (** Builds a new Hash type using Sha256. *)
module Make_SHA256 (Name:Name) : HASH module Make_minimal_SHA256 (Name : Name) : MINIMAL_HASH
module Make_SHA256
(Register : sig
val register_encoding:
prefix: string ->
to_raw: ('a -> string) ->
of_raw: (string -> 'a option) ->
wrap: ('a -> Base48.data) ->
'a Base48.encoding
end)
(Name : PrefixedName) : HASH
(** Builds a Set of values of some Hash type. *) (** Builds a Set of values of some Hash type. *)
module Hash_set (Hash : HASH) : sig module Hash_set (Hash : HASH) : sig
@ -103,3 +131,4 @@ module Protocol_hash : HASH
module Protocol_hash_set : module type of Hash_set (Protocol_hash) module Protocol_hash_set : module type of Hash_set (Protocol_hash)
module Protocol_hash_map : module type of Hash_map (Protocol_hash) module Protocol_hash_map : module type of Hash_map (Protocol_hash)
module Protocol_hash_table : module type of Hash_table (Protocol_hash) module Protocol_hash_table : module type of Hash_table (Protocol_hash)

View File

@ -96,6 +96,10 @@ let map_option ~f = function
| None -> None | None -> None
| Some x -> Some (f x) | Some x -> Some (f x)
let apply_option ~f = function
| None -> None
| Some x -> f x
let iter_option ~f = function let iter_option ~f = function
| None -> () | None -> ()
| Some x -> f x | Some x -> f x

View File

@ -27,6 +27,7 @@ val split_path: string -> string list
val split: char -> ?limit: int -> string -> string list val split: char -> ?limit: int -> string -> string list
val map_option: f:('a -> 'b) -> 'a option -> 'b option val map_option: f:('a -> 'b) -> 'a option -> 'b option
val apply_option: f:('a -> 'b option) -> 'a option -> 'b option
val iter_option: f:('a -> unit) -> 'a option -> unit val iter_option: f:('a -> unit) -> 'a option -> unit
val unopt: 'a -> 'a option -> 'a val unopt: 'a -> 'a option -> 'a
val unopt_list: 'a option list -> 'a list val unopt_list: 'a option list -> 'a list

View File

@ -27,11 +27,9 @@ let equal_block_hash_list ?msg l1 l2 =
let pr_block_hash = Block_hash.to_short_b48check in let pr_block_hash = Block_hash.to_short_b48check in
Assert.make_equal_list ?msg Block_hash.equal pr_block_hash l1 l2 Assert.make_equal_list ?msg Block_hash.equal pr_block_hash l1 l2
let equal_base48_list ?msg l1 l2 = let equal_string_list ?msg l1 l2 =
let msg = format_msg msg in let msg = format_msg msg in
let pr_base48 = Base48.encode in Assert.make_equal_list ?msg (=) (fun x -> x) l1 l2
(* TODO do not use polymorphic equality ! *)
Assert.make_equal_list ?msg (=) pr_base48 l1 l2
let equal_string_option ?msg o1 o2 = let equal_string_option ?msg o1 o2 =
let msg = format_msg msg in let msg = format_msg msg in

View File

@ -20,8 +20,8 @@ val equal_persist_list :
val equal_block_hash_list : val equal_block_hash_list :
?msg:string -> Block_hash.t list -> Block_hash.t list -> unit ?msg:string -> Block_hash.t list -> Block_hash.t list -> unit
val equal_base48_list : val equal_string_list :
?msg:string -> Base48.data list -> Base48.data list -> unit ?msg:string -> string list -> string list -> unit
val equal_string_option : ?msg:string -> string option -> string option -> unit val equal_string_option : ?msg:string -> string option -> string option -> unit

View File

@ -121,12 +121,12 @@ let test_expand (s: Store.store) =
Block.full_set s bh2 b2 >>= fun () -> Block.full_set s bh2 b2 >>= fun () ->
Block.full_set s bh3 b3 >>= fun () -> Block.full_set s bh3 b3 >>= fun () ->
Block.full_set s bh3' b3 >>= fun () -> Block.full_set s bh3' b3 >>= fun () ->
Base48.decode_partial (Block_hash.to_short_b48check bh1) >>= fun res -> Base48.complete (Block_hash.to_short_b48check bh1) >>= fun res ->
Assert.equal_base48_list ~msg:__LOC__ res [Block_hash.Hash bh1] ; Assert.equal_string_list ~msg:__LOC__ res [Block_hash.to_b48check bh1] ;
Base48.decode_partial (Block_hash.to_short_b48check bh2) >>= fun res -> Base48.complete (Block_hash.to_short_b48check bh2) >>= fun res ->
Assert.equal_base48_list ~msg:__LOC__ res [Block_hash.Hash bh2] ; Assert.equal_string_list ~msg:__LOC__ res [Block_hash.to_b48check bh2] ;
Base48.decode_partial (Block_hash.to_short_b48check bh3) >>= fun res -> Base48.complete (Block_hash.to_short_b48check bh3) >>= fun res ->
Assert.equal_base48_list ~msg:__LOC__ res [Block_hash.Hash bh3] ; Assert.equal_string_list ~msg:__LOC__ res [Block_hash.to_b48check bh3] ;
Lwt.return_unit) Lwt.return_unit)