Proto: store the public key of the manager in the contract

This commit is contained in:
Pietro Abate 2017-11-09 11:50:42 +01:00 committed by Benjamin Canou
parent 3d19e3bd59
commit de8967540f
13 changed files with 184 additions and 27 deletions

View File

@ -23,6 +23,7 @@
"Roll_repr",
"Vote_repr",
"Operation_repr",
"Manager_repr",
"Block_header_repr",
"Storage_sigs",

View File

@ -149,28 +149,15 @@ let apply_manager_operation_content
Contract.set_delegate ctxt source delegate >>=? fun ctxt ->
return (ctxt, origination_nonce, None)
let check_signature_and_update_public_key ctxt id public_key op =
begin
match public_key with
| None -> return ctxt
| Some public_key ->
Public_key.reveal ctxt id public_key
end >>=? fun ctxt ->
Public_key.get ctxt id >>=? fun public_key ->
Operation.check_signature public_key op >>=? fun () ->
return ctxt
let apply_sourced_operation
ctxt baker_contract pred_block block_prio
operation origination_nonce ops =
match ops with
| Manager_operations { source ; public_key ; fee ; counter ; operations = contents } ->
Contract.must_exist ctxt source >>=? fun () ->
Contract.get_manager ctxt source >>=? fun manager ->
check_signature_and_update_public_key
ctxt manager public_key operation >>=? fun ctxt ->
Contract.check_counter_increment
ctxt source counter >>=? fun () ->
Contract.update_manager_key ctxt source public_key >>=? fun (ctxt,public_key) ->
Operation.check_signature public_key operation >>=? fun () ->
Contract.check_counter_increment ctxt source counter >>=? fun () ->
Contract.increment_counter ctxt source >>=? fun ctxt ->
Contract.spend ctxt source fee >>=? fun ctxt ->
(match baker_contract with
@ -187,10 +174,10 @@ let apply_sourced_operation
(ctxt, origination_nonce, None) contents
| Delegate_operations { source ; operations = contents } ->
let delegate = Ed25519.Public_key.hash source in
check_signature_and_update_public_key
ctxt delegate (Some source) operation >>=? fun ctxt ->
Public_key.reveal ctxt delegate source >>=? fun ctxt ->
Operation.check_signature source operation >>=? fun () ->
(* TODO, see how to extract the public key hash after this operation to
pass it to apply_delegate_operation_content *)
pass it to apply_delegate_operation_content *)
fold_left_s (fun ctxt content ->
apply_delegate_operation_content
ctxt delegate pred_block block_prio content)

View File

@ -16,6 +16,9 @@ type error +=
| Unspendable_contract of Contract_repr.contract (* `Permanent *)
| Non_existing_contract of Contract_repr.contract (* `Temporary *)
| Non_delegatable_contract of Contract_repr.contract (* `Permanent *)
| Inconsistent_hash of Ed25519.Public_key.t * Ed25519.Public_key_hash.t * Ed25519.Public_key_hash.t (* `Permanent *)
| Inconsistent_public_key of Ed25519.Public_key.t * Ed25519.Public_key.t (* `Permanent *)
| Missing_public_key of Ed25519.Public_key_hash.t (* `Permanent *)
| Failure of string (* `Permanent *)
let () =
@ -129,6 +132,47 @@ let () =
Data_encoding.(obj1 (req "contract" Contract_repr.encoding))
(function Non_delegatable_contract c -> Some c | _ -> None)
(fun c -> Non_delegatable_contract c) ;
register_error_kind
`Permanent
~id:"contract.manager.inconsistent_hash"
~title:"Inconsistent public key hash"
~description:"A revealed manager public key is inconsistent with the announced hash"
~pp:(fun ppf (k, eh, ph) ->
Format.fprintf ppf "The hash of the manager public key %s is not %a as announced but %a"
(Ed25519.Public_key.to_b58check k)
Ed25519.Public_key_hash.pp ph
Ed25519.Public_key_hash.pp eh)
Data_encoding.(obj3
(req "public_key" Ed25519.Public_key.encoding)
(req "expected_hash" Ed25519.Public_key_hash.encoding)
(req "provided_hash" Ed25519.Public_key_hash.encoding))
(function Inconsistent_hash (k, eh, ph) -> Some (k, eh, ph) | _ -> None)
(fun (k, eh, ph) -> Inconsistent_hash (k, eh, ph)) ;
register_error_kind
`Permanent
~id:"contract.manager.inconsistent_public_key"
~title:"Inconsistent public key"
~description:"A provided manager public key is different with the public key stored in the contract"
~pp:(fun ppf (eh, ph) ->
Format.fprintf ppf "Expected manager public key %s but %s was provided"
(Ed25519.Public_key.to_b58check ph)
(Ed25519.Public_key.to_b58check eh))
Data_encoding.(obj2
(req "public_key" Ed25519.Public_key.encoding)
(req "expected_public_key" Ed25519.Public_key.encoding))
(function Inconsistent_public_key (eh, ph) -> Some (eh, ph) | _ -> None)
(fun (eh, ph) -> Inconsistent_public_key (eh, ph)) ;
register_error_kind
`Permanent
~id:"contract.manager.missing_public_key"
~title:"Missing public key"
~description:"The manager public key must be provided to execute the current operation"
~pp:(fun ppf (k) ->
Format.fprintf ppf "The manager public key ( with hash %a ) is missing"
Ed25519.Public_key_hash.pp k)
Data_encoding.(obj1 (req "hash" Ed25519.Public_key_hash.encoding))
(function Missing_public_key (k) -> Some (k) | _ -> None)
(fun (k) -> Missing_public_key (k)) ;
register_error_kind
`Permanent
~id:"contract.failure"
@ -138,7 +182,7 @@ let () =
Data_encoding.(obj1 (req "message" string))
(function Failure s -> Some s | _ -> None)
(fun s -> Failure s)
let failwith msg = fail (Failure msg)
let create_base c contract ~balance ~manager ~delegate ?script ~spendable ~delegatable =
@ -146,7 +190,7 @@ let create_base c contract ~balance ~manager ~delegate ?script ~spendable ~deleg
| None -> return 0l
| Some _ -> Storage.Contract.Global_counter.get c) >>=? fun counter ->
Storage.Contract.Balance.init c contract balance >>=? fun c ->
Storage.Contract.Manager.init c contract manager >>=? fun c ->
Storage.Contract.Manager.init c contract (Manager_repr.hash manager) >>=? fun c ->
begin
match delegate with
| None -> return c
@ -254,7 +298,28 @@ let get_manager c contract =
| Some manager -> return manager
| None -> failwith "get_manager"
end
| Some v -> return v
| Some (Manager_repr.Hash v) -> return v
| Some (Manager_repr.Public_key v) -> return (Ed25519.Public_key.hash v)
let update_manager_key c contract = function
| Some public_key ->
begin Storage.Contract.Manager.get c contract >>=? function
| (Manager_repr.Public_key v) -> (* key revealed for the second time *)
if Ed25519.Public_key.(v = public_key) then return (c,v)
else fail (Inconsistent_public_key (v,public_key))
| (Manager_repr.Hash v) ->
let actual_hash = Ed25519.Public_key.hash public_key in
if (Ed25519.Public_key_hash.equal actual_hash v) then
let v = (Manager_repr.public_key public_key) in
Storage.Contract.Manager.set c contract v >>=? fun c ->
return (c,public_key) (* reveal and update key *)
else fail (Inconsistent_hash (public_key,v,actual_hash))
end
| None ->
begin Storage.Contract.Manager.get c contract >>=? function
| (Manager_repr.Public_key v) -> return (c,v) (* already revealed *)
| (Manager_repr.Hash v) -> fail (Missing_public_key (v))
end
let get_delegate_opt = Roll_storage.get_contract_delegate

View File

@ -16,6 +16,9 @@ type error +=
| Unspendable_contract of Contract_repr.contract (* `Permanent *)
| Non_existing_contract of Contract_repr.contract (* `Temporary *)
| Non_delegatable_contract of Contract_repr.contract (* `Permanent *)
| Inconsistent_hash of Ed25519.Public_key.t * Ed25519.Public_key_hash.t * Ed25519.Public_key_hash.t (* `Permanent *)
| Inconsistent_public_key of Ed25519.Public_key.t * Ed25519.Public_key.t (* `Permanent *)
| Missing_public_key of Ed25519.Public_key_hash.t (* `Permanent *)
| Failure of string (* `Permanent *)
val delete : Storage.t -> Contract_repr.t -> Storage.t tzresult Lwt.t
@ -32,6 +35,10 @@ val is_delegatable : Storage.t -> Contract_repr.t -> bool tzresult Lwt.t
val is_spendable : Storage.t -> Contract_repr.t -> bool tzresult Lwt.t
val get_manager: Storage.t -> Contract_repr.t -> Ed25519.Public_key_hash.t tzresult Lwt.t
val update_manager_key:
Storage.t -> Contract_repr.t -> Ed25519.Public_key.t option ->
(Storage.t * Ed25519.Public_key.t) tzresult Lwt.t
val get_delegate_opt: Storage.t -> Contract_repr.t -> Ed25519.Public_key_hash.t option tzresult Lwt.t
val get_balance: Storage.t -> Contract_repr.t -> Tez_repr.t tzresult Lwt.t
val get_counter: Storage.t -> Contract_repr.t -> int32 tzresult Lwt.t

View File

@ -0,0 +1,53 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2016. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
(* Tezos Protocol Implementation - Low level Repr. of Managers' keys *)
type manager_key =
| Hash of Ed25519.Public_key_hash.t
| Public_key of Ed25519.Public_key.t
type t = manager_key
let hash hash = Hash hash
let public_key hash = Public_key hash
open Data_encoding
let hash_encoding =
(obj1
(req "hash" Ed25519.Public_key_hash.encoding)
)
let pubkey_encoding =
(obj1
(req "public_key" Ed25519.Public_key.encoding)
)
let hash_case tag =
case ~tag hash_encoding
(function
| Hash hash -> Some hash
| _ -> None)
(fun hash -> Hash hash)
let pubkey_case tag =
case ~tag pubkey_encoding
(function
| Public_key hash -> Some hash
| _ -> None)
(fun hash -> Public_key hash)
let encoding =
union [
hash_case 0 ;
pubkey_case 1 ;
]

View File

@ -0,0 +1,22 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2016. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
(* Tezos Protocol Implementation - Low level Repr. of Managers' keys *)
(** The public key of the manager of a contract is reveled only after the
first operation. At Origination time, the manager provides only the hash
of its public key that is stored in the contract. When the public key
is actually reveeld, the public key instead of the hash of the key *)
type manager_key =
| Hash of Ed25519.Public_key_hash.t
| Public_key of Ed25519.Public_key.t
type t = manager_key
val encoding : t Data_encoding.encoding

View File

@ -295,10 +295,10 @@ module Contract = struct
module Manager =
Make_indexed_data_storage(struct
type key = Contract_repr.t
type value = Ed25519.Public_key_hash.t
type value = Manager_repr.t
let name = "contract manager"
let key = Key.Contract.manager
let encoding = Ed25519.Public_key_hash.encoding
let encoding = Manager_repr.encoding
end)
module Spendable =

View File

@ -136,7 +136,7 @@ module Contract : sig
(** The manager of a contract *)
module Manager : Indexed_data_storage
with type key = Contract_repr.t
and type value = Ed25519.Public_key_hash.t
and type value = Manager_repr.t
and type context := t
(** The delegate of a contract, if any. *)

View File

@ -424,6 +424,9 @@ module Contract : sig
val get_manager:
context -> contract -> public_key_hash tzresult Lwt.t
val update_manager_key:
context -> contract -> public_key option -> (context * public_key) tzresult Lwt.t
val get_delegate_opt:
context -> contract -> public_key_hash option tzresult Lwt.t
val is_delegatable:

View File

@ -224,6 +224,7 @@ module Account = struct
let set_delegate
?(block = `Prevalidation)
?(fee = 5L)
?src_pk
~contract
~manager_sk
delegate_opt =
@ -234,6 +235,7 @@ module Account = struct
~source:contract
~manager_sk
~fee
?src_pk
delegate_opt
let balance ?(block = `Prevalidation) (account : t) =
@ -370,7 +372,19 @@ module Assert = struct
let inconsistent_pkh ~msg =
Assert.contain_error ~msg ~f:begin ecoproto_error (function
| Public_key_storage.Inconsistent_hash _ -> true
| Contract_storage.Inconsistent_hash _ -> true
| _ -> false)
end
let inconsistent_public_key ~msg =
Assert.contain_error ~msg ~f:begin ecoproto_error (function
| Contract_storage.Inconsistent_public_key _ -> true
| _ -> false)
end
let missing_public_key ~msg =
Assert.contain_error ~msg ~f:begin ecoproto_error (function
| Contract_storage.Missing_public_key _ -> true
| _ -> false)
end

View File

@ -78,6 +78,7 @@ module Account : sig
val set_delegate :
?block:Client_proto_rpcs.block ->
?fee:int64 ->
?src_pk:public_key ->
contract:Contract.t ->
manager_sk:secret_key ->
public_key_hash option ->
@ -176,6 +177,8 @@ module Assert : sig
val balance_too_low : msg:string -> 'a tzresult -> unit
val non_spendable : msg:string -> 'a tzresult -> unit
val inconsistent_pkh : msg:string -> 'a tzresult -> unit
val inconsistent_public_key : msg:string -> 'a tzresult -> unit
val missing_public_key : msg:string -> 'a tzresult -> unit
(** Origination assertions *)

View File

@ -64,6 +64,7 @@ let run blkid ({ b1 ; b2 ; _ } : Helpers.Account.bootstrap_accounts) =
(* Change delegate of a non-delegatable contract *)
Helpers.Account.set_delegate
~src_pk:b1.pk
~contract:nd_contract
~manager_sk:b1.sk
(Some b2.pkh) >>= fun result ->
@ -71,6 +72,7 @@ let run blkid ({ b1 ; b2 ; _ } : Helpers.Account.bootstrap_accounts) =
(* Change delegate of a delegatable contract *)
Helpers.Account.set_delegate
~src_pk:b1.pk
~contract:d_contract
~manager_sk:b1.sk
(Some b2.pkh) >>= fun _result ->

View File

@ -100,7 +100,7 @@ let run blkid ({ b1 ; b2 ; b3 ; _ } : Helpers.Account.bootstrap_accounts) =
~account
~destination:b2.contract
~amount:10_00L () >>= fun result ->
Assert.inconsistent_pkh ~msg:__LOC__ result ;
Assert.inconsistent_public_key ~msg:__LOC__ result ;
return blkh