Alpha: better error for invalid key revelation

This commit is contained in:
Grégoire Henry 2018-03-22 15:23:23 +01:00 committed by Grégoire Henry
parent 4caf7cf679
commit d0a9fb678c
5 changed files with 121 additions and 38 deletions

View File

@ -438,6 +438,9 @@ module Contract : sig
val exists: context -> contract -> bool tzresult Lwt.t val exists: context -> contract -> bool tzresult Lwt.t
val must_exist: context -> contract -> unit tzresult Lwt.t val must_exist: context -> contract -> unit tzresult Lwt.t
val allocated: context -> contract -> bool tzresult Lwt.t
val must_be_allocated: context -> contract -> unit tzresult Lwt.t
val list: context -> contract list Lwt.t val list: context -> contract list Lwt.t
type origination_nonce type origination_nonce
@ -450,8 +453,12 @@ module Contract : sig
val get_manager: val get_manager:
context -> contract -> public_key_hash tzresult Lwt.t 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_manager_key:
context -> contract -> public_key tzresult Lwt.t
val reveal_manager_key:
context -> contract -> public_key -> context tzresult Lwt.t
val is_delegatable: val is_delegatable:
context -> contract -> bool tzresult Lwt.t context -> contract -> bool tzresult Lwt.t

View File

@ -38,6 +38,7 @@ type error += Outdated_double_baking_evidence
of { level: Raw_level.t ; last: Raw_level.t } (* `Permanent *) of { level: Raw_level.t ; last: Raw_level.t } (* `Permanent *)
type error += Invalid_activation of { pkh : Ed25519.Public_key_hash.t } type error += Invalid_activation of { pkh : Ed25519.Public_key_hash.t }
type error += Wrong_activation_secret type error += Wrong_activation_secret
type error += Multiple_revelation
let () = let () =
register_error_kind register_error_kind
@ -313,7 +314,18 @@ let () =
Format.fprintf ppf "Wrong activation secret.") Format.fprintf ppf "Wrong activation secret.")
Data_encoding.unit Data_encoding.unit
(function Wrong_activation_secret -> Some () | _ -> None) (function Wrong_activation_secret -> Some () | _ -> None)
(fun () -> Wrong_activation_secret) (fun () -> Wrong_activation_secret) ;
register_error_kind
`Permanent
~id:"block.multiple_revelation"
~title:"Multiple revelations were included in a manager operation"
~description:"A manager operation should not contain more than one revelation"
~pp:(fun ppf () ->
Format.fprintf ppf
"Multiple revelations were included in a manager operation")
Data_encoding.empty
(function Multiple_revelation -> Some () | _ -> None)
(fun () -> Multiple_revelation)
let apply_consensus_operation_content ctxt let apply_consensus_operation_content ctxt
pred_block block_priority operation = function pred_block block_priority operation = function
@ -446,15 +458,23 @@ let apply_sourced_operation
operation origination_nonce ops = operation origination_nonce ops =
match ops with match ops with
| Manager_operations { source ; fee ; counter ; operations = contents } -> | Manager_operations { source ; fee ; counter ; operations = contents } ->
let public_key = let revealed_public_keys =
List.fold_left (fun acc op -> List.fold_left (fun acc op ->
match op with match op with
| Reveal pk -> Some pk | Reveal pk -> pk :: acc
| _ -> acc) None contents in | _ -> acc) [] contents in
Contract.must_exist ctxt source >>=? fun () -> Contract.must_be_allocated ctxt source >>=? 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.check_counter_increment ctxt source counter >>=? fun () ->
begin
match revealed_public_keys with
| [] -> return ctxt
| [pk] ->
Contract.reveal_manager_key ctxt source pk
| _ :: _ :: _ ->
fail Multiple_revelation
end >>=? fun ctxt ->
Contract.get_manager_key ctxt source >>=? fun public_key ->
Operation.check_signature public_key operation >>=? fun () ->
Contract.increment_counter ctxt source >>=? fun ctxt -> Contract.increment_counter ctxt source >>=? fun ctxt ->
Contract.spend ctxt source fee >>=? fun ctxt -> Contract.spend ctxt source fee >>=? fun ctxt ->
add_fees ctxt fee >>=? fun ctxt -> add_fees ctxt fee >>=? fun ctxt ->

View File

@ -11,8 +11,7 @@ let init ctxt (account: Parameters_repr.bootstrap_account) =
let public_key_hash = Signature.Public_key.hash account.public_key in let public_key_hash = Signature.Public_key.hash account.public_key in
let contract = Contract_repr.implicit_contract public_key_hash in let contract = Contract_repr.implicit_contract public_key_hash in
Contract_storage.credit ctxt contract account.amount >>=? fun ctxt -> Contract_storage.credit ctxt contract account.amount >>=? fun ctxt ->
Contract_storage.update_manager_key ctxt contract Contract_storage.reveal_manager_key ctxt contract account.public_key >>=? fun ctxt ->
(Some account.public_key) >>=? fun (ctxt, _) ->
Delegate_storage.set ctxt contract (Some public_key_hash) >>=? fun ctxt -> Delegate_storage.set ctxt contract (Some public_key_hash) >>=? fun ctxt ->
return ctxt return ctxt

View File

@ -13,10 +13,13 @@ type error +=
| Counter_in_the_future of Contract_repr.contract * int32 * int32 (* `Temporary *) | Counter_in_the_future of Contract_repr.contract * int32 * int32 (* `Temporary *)
| Unspendable_contract of Contract_repr.contract (* `Permanent *) | Unspendable_contract of Contract_repr.contract (* `Permanent *)
| Non_existing_contract of Contract_repr.contract (* `Temporary *) | Non_existing_contract of Contract_repr.contract (* `Temporary *)
| Empty_implicit_contract of Signature.Public_key_hash.t (* `Temporary *)
| Inconsistent_hash of Signature.Public_key.t * Signature.Public_key_hash.t * Signature.Public_key_hash.t (* `Permanent *) | Inconsistent_hash of Signature.Public_key.t * Signature.Public_key_hash.t * Signature.Public_key_hash.t (* `Permanent *)
| Inconsistent_public_key of Signature.Public_key.t * Signature.Public_key.t (* `Permanent *) | Inconsistent_public_key of Signature.Public_key.t * Signature.Public_key.t (* `Permanent *)
| Missing_public_key of Signature.Public_key_hash.t (* `Permanent *) | Missing_public_key of Signature.Public_key_hash.t (* `Permanent *)
| Failure of string (* `Permanent *) | Failure of string (* `Permanent *)
| Previously_revealed_key of Contract_repr.t (* `Permanent *)
| Unrevealed_manager_key of Contract_repr.t (* `Permanent *)
let () = let () =
register_error_kind register_error_kind
@ -137,7 +140,44 @@ let () =
~pp:(fun ppf s -> Format.fprintf ppf "Contract_storage.Failure %S" s) ~pp:(fun ppf s -> Format.fprintf ppf "Contract_storage.Failure %S" s)
Data_encoding.(obj1 (req "message" string)) Data_encoding.(obj1 (req "message" string))
(function Failure s -> Some s | _ -> None) (function Failure s -> Some s | _ -> None)
(fun s -> Failure s) (fun s -> Failure s) ;
register_error_kind
`Branch
~id:"contract.unrevealed_key"
~title:"Manager operation precedes key revelation"
~description:
"One tried to apply a manager operation \
without revealing the manager public key"
~pp:(fun ppf s ->
Format.fprintf ppf "Unrevealed manager key for contract %a."
Contract_repr.pp s)
Data_encoding.(obj1 (req "contract" Contract_repr.encoding))
(function Unrevealed_manager_key s -> Some s | _ -> None)
(fun s -> Unrevealed_manager_key s) ;
register_error_kind
`Branch
~id:"contract.previously_revealed_key"
~title:"Manager operation already revealed"
~description:
"One tried to revealed twice a manager public key"
~pp:(fun ppf s ->
Format.fprintf ppf "Previously revealed manager key for contract %a."
Contract_repr.pp s)
Data_encoding.(obj1 (req "contract" Contract_repr.encoding))
(function Previously_revealed_key s -> Some s | _ -> None)
(fun s -> Previously_revealed_key s) ;
register_error_kind
`Branch
~id:"implicit.empty_implicit_contract"
~title:"Empty implicit contract"
~description:"No manager operations are allowed on an empty implicit contract."
~pp:(fun ppf implicit ->
Format.fprintf ppf
"Empty implicit contract (%a)"
Signature.Public_key_hash.pp implicit)
Data_encoding.(obj1 (req "implicit" Signature.Public_key_hash.encoding))
(function Empty_implicit_contract c -> Some c | _ -> None)
(fun c -> Empty_implicit_contract c)
let failwith msg = fail (Failure msg) let failwith msg = fail (Failure msg)
@ -191,19 +231,29 @@ let delete c contract =
Storage.Contract.Big_map.clear (c, contract) >>= fun c -> Storage.Contract.Big_map.clear (c, contract) >>= fun c ->
return c return c
let exists c contract = let allocated c contract =
match Contract_repr.is_implicit contract with
| Some _ -> return true
| None ->
Storage.Contract.Counter.get_option c contract >>=? function Storage.Contract.Counter.get_option c contract >>=? function
| None -> return false | None -> return false
| Some _ -> return true | Some _ -> return true
let exists c contract =
match Contract_repr.is_implicit contract with
| Some _ -> return true
| None -> allocated c contract
let must_exist c contract = let must_exist c contract =
exists c contract >>=? function exists c contract >>=? function
| true -> return () | true -> return ()
| false -> fail (Non_existing_contract contract) | false -> fail (Non_existing_contract contract)
let must_be_allocated c contract =
allocated c contract >>=? function
| true -> return ()
| false ->
match Contract_repr.is_implicit contract with
| Some pkh -> fail (Empty_implicit_contract pkh)
| None -> fail (Non_existing_contract contract)
let list c = Storage.Contract.list c let list c = Storage.Contract.list c
let check_counter_increment c contract counter = let check_counter_increment c contract counter =
@ -251,25 +301,22 @@ let get_manager c contract =
| Some (Manager_repr.Hash v) -> return v | Some (Manager_repr.Hash v) -> return v
| Some (Manager_repr.Public_key v) -> return (Signature.Public_key.hash v) | Some (Manager_repr.Public_key v) -> return (Signature.Public_key.hash v)
let update_manager_key c contract = function let get_manager_key c contract =
| Some public_key -> Storage.Contract.Manager.get_option c contract >>=? function
begin Storage.Contract.Manager.get c contract >>=? function | None -> failwith "get_manager_key"
| Public_key v -> (* key revealed for the second time *) | Some (Manager_repr.Hash _) -> fail (Unrevealed_manager_key contract)
if Signature.Public_key.(v = public_key) then return (c,v) | Some (Manager_repr.Public_key v) -> return v
else fail (Inconsistent_public_key (v,public_key))
let reveal_manager_key c contract public_key =
Storage.Contract.Manager.get c contract >>=? function
| Public_key _ -> fail (Previously_revealed_key contract)
| Hash v -> | Hash v ->
let actual_hash = Signature.Public_key.hash public_key in let actual_hash = Signature.Public_key.hash public_key in
if (Signature.Public_key_hash.equal actual_hash v) then if (Signature.Public_key_hash.equal actual_hash v) then
let v = (Manager_repr.Public_key public_key) in let v = (Manager_repr.Public_key public_key) in
Storage.Contract.Manager.set c contract v >>=? fun c -> Storage.Contract.Manager.set c contract v >>=? fun c ->
return (c,public_key) (* reveal and update key *) return c
else fail (Inconsistent_hash (public_key,v,actual_hash)) else fail (Inconsistent_hash (public_key,v,actual_hash))
end
| None ->
begin Storage.Contract.Manager.get c contract >>=? function
| Public_key v -> return (c,v) (* already revealed *)
| Hash v -> fail (Missing_public_key (v))
end
let get_balance c contract = let get_balance c contract =
Storage.Contract.Balance.get_option c contract >>=? function Storage.Contract.Balance.get_option c contract >>=? function

View File

@ -13,14 +13,21 @@ type error +=
| Counter_in_the_future of Contract_repr.contract * int32 * int32 (* `Temporary *) | Counter_in_the_future of Contract_repr.contract * int32 * int32 (* `Temporary *)
| Unspendable_contract of Contract_repr.contract (* `Permanent *) | Unspendable_contract of Contract_repr.contract (* `Permanent *)
| Non_existing_contract of Contract_repr.contract (* `Temporary *) | Non_existing_contract of Contract_repr.contract (* `Temporary *)
| Empty_implicit_contract of Signature.Public_key_hash.t (* `Temporary *)
| Inconsistent_hash of Signature.Public_key.t * Signature.Public_key_hash.t * Signature.Public_key_hash.t (* `Permanent *) | Inconsistent_hash of Signature.Public_key.t * Signature.Public_key_hash.t * Signature.Public_key_hash.t (* `Permanent *)
| Inconsistent_public_key of Signature.Public_key.t * Signature.Public_key.t (* `Permanent *) | Inconsistent_public_key of Signature.Public_key.t * Signature.Public_key.t (* `Permanent *)
| Missing_public_key of Signature.Public_key_hash.t (* `Permanent *) | Missing_public_key of Signature.Public_key_hash.t (* `Permanent *)
| Failure of string (* `Permanent *) | Failure of string (* `Permanent *)
| Previously_revealed_key of Contract_repr.t (* `Permanent *)
| Unrevealed_manager_key of Contract_repr.t (* `Permanent *)
val exists: Raw_context.t -> Contract_repr.t -> bool tzresult Lwt.t val exists: Raw_context.t -> Contract_repr.t -> bool tzresult Lwt.t
val must_exist: Raw_context.t -> Contract_repr.t -> unit tzresult Lwt.t val must_exist: Raw_context.t -> Contract_repr.t -> unit tzresult Lwt.t
val allocated: Raw_context.t -> Contract_repr.t -> bool tzresult Lwt.t
val must_be_allocated: Raw_context.t -> Contract_repr.t -> unit tzresult Lwt.t
val list: Raw_context.t -> Contract_repr.t list Lwt.t val list: Raw_context.t -> Contract_repr.t list Lwt.t
val check_counter_increment: val check_counter_increment:
@ -37,9 +44,12 @@ val is_spendable: Raw_context.t -> Contract_repr.t -> bool tzresult Lwt.t
val get_manager: val get_manager:
Raw_context.t -> Contract_repr.t -> Signature.Public_key_hash.t tzresult Lwt.t Raw_context.t -> Contract_repr.t -> Signature.Public_key_hash.t tzresult Lwt.t
val update_manager_key: val get_manager_key:
Raw_context.t -> Contract_repr.t -> Signature.Public_key.t option -> Raw_context.t -> Contract_repr.t -> Signature.Public_key.t tzresult Lwt.t
(Raw_context.t * Signature.Public_key.t) tzresult Lwt.t
val reveal_manager_key:
Raw_context.t -> Contract_repr.t -> Signature.Public_key.t ->
Raw_context.t tzresult Lwt.t
val get_balance: Raw_context.t -> Contract_repr.t -> Tez_repr.t tzresult Lwt.t val get_balance: Raw_context.t -> Contract_repr.t -> Tez_repr.t tzresult Lwt.t
val get_counter: Raw_context.t -> Contract_repr.t -> int32 tzresult Lwt.t val get_counter: Raw_context.t -> Contract_repr.t -> int32 tzresult Lwt.t