diff --git a/src/proto_alpha/lib_baking/test/test_transaction.ml b/src/proto_alpha/lib_baking/test/test_transaction.ml index ee9173f4b..bc4262eca 100644 --- a/src/proto_alpha/lib_baking/test/test_transaction.ml +++ b/src/proto_alpha/lib_baking/test/test_transaction.ml @@ -85,7 +85,7 @@ let run blkid ({ b1 ; b2 ; b3 ; _ } : Helpers.Account.bootstrap_accounts) = ~account ~destination:b3.contract ~amount:(tez 10L) () >>= fun result -> - Assert.inconsistent_pkh ~msg:__LOC__ result ; + Assert.inconsistent_public_key ~msg:__LOC__ result ; (* Try spending an originated contract without the manager's key. *) let account = { b1 with contract = spendable } in diff --git a/src/proto_alpha/lib_protocol/src/bootstrap_storage.ml b/src/proto_alpha/lib_protocol/src/bootstrap_storage.ml index 45ec8b7c2..703e95bfa 100644 --- a/src/proto_alpha/lib_protocol/src/bootstrap_storage.ml +++ b/src/proto_alpha/lib_protocol/src/bootstrap_storage.ml @@ -14,10 +14,13 @@ type account = { let init_account ctxt account = Storage.Public_key.init ctxt account.public_key_hash account.public_key >>=? fun ctxt -> - Contract_storage.credit - ctxt - (Contract_repr.implicit_contract account.public_key_hash) + let contract = Contract_repr.implicit_contract account.public_key_hash in + Contract_storage.credit ctxt contract Constants_repr.bootstrap_wealth >>=? fun ctxt -> + Contract_storage.update_manager_key ctxt contract + (Some account.public_key) >>=? fun (ctxt, _) -> + Contract_storage.set_delegate ctxt contract + (Some account.public_key_hash) >>=? fun ctxt -> return ctxt diff --git a/src/proto_alpha/lib_protocol/src/contract_storage.ml b/src/proto_alpha/lib_protocol/src/contract_storage.ml index f9a722a5f..a5628ca21 100644 --- a/src/proto_alpha/lib_protocol/src/contract_storage.ml +++ b/src/proto_alpha/lib_protocol/src/contract_storage.ml @@ -18,6 +18,7 @@ type error += | 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 *) + | Unregistred_delegate of Ed25519.Public_key_hash.t (* `Permanent *) let () = register_error_kind @@ -136,12 +137,12 @@ let () = ~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) -> + ~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)) ; + (function Missing_public_key k -> Some k | _ -> None) + (fun k -> Missing_public_key k) ; register_error_kind `Permanent ~id:"contract.failure" @@ -150,7 +151,18 @@ let () = ~pp:(fun ppf s -> Format.fprintf ppf "Contract_storage.Failure %S" s) Data_encoding.(obj1 (req "message" string)) (function Failure s -> Some s | _ -> None) - (fun s -> Failure s) + (fun s -> Failure s) ; + register_error_kind + `Permanent + ~id:"contract.manager.unregistred_delegate" + ~title:"Unregistred delegate" + ~description:"A contract cannot be delegated to an unregistred delegate" + ~pp:(fun ppf (k) -> + Format.fprintf ppf "The delegate public key (with hash %a) is missing" + Ed25519.Public_key_hash.pp k) + Data_encoding.(obj1 (req "hash" Ed25519.Public_key_hash.encoding)) + (function Unregistred_delegate (k) -> Some (k) | _ -> None) + (fun (k) -> Unregistred_delegate (k)) let failwith msg = fail (Failure msg) @@ -168,7 +180,12 @@ let create_base c contract Storage.Contract.Delegate.init c contract delegate end >>=? fun c -> Storage.Contract.Spendable.init c contract spendable >>=? fun c -> - Storage.Contract.Delegatable.init c contract delegatable >>=? fun c -> + begin + if delegatable then + Storage.Contract.Delegatable.add c contract + else + Lwt.return c + end >>= fun c -> Storage.Contract.Counter.init c contract counter >>=? fun c -> (match script with | Some ({ Script_repr.code ; storage }, (code_fees, storage_fees)) -> @@ -189,8 +206,7 @@ let originate c nonce ~balance ~manager ?script ~delegate ~spendable ~delegatabl let create_implicit c manager ~balance = create_base c (Contract_repr.implicit_contract manager) - ~balance ~manager ~delegate:(Some manager) - ?script:None + ~balance ~manager ?script:None ~delegate:None ~spendable:true ~delegatable:false let delete c contract = @@ -201,7 +217,7 @@ let delete c contract = Storage.Contract.Manager.delete c contract >>=? fun c -> Storage.Contract.Delegate.remove c contract >>= fun c -> Storage.Contract.Spendable.delete c contract >>=? fun c -> - Storage.Contract.Delegatable.delete c contract >>=? fun c -> + Storage.Contract.Delegatable.del c contract >>= fun c -> Storage.Contract.Counter.delete c contract >>=? fun c -> Storage.Contract.Code.remove c contract >>= fun c -> Storage.Contract.Storage.remove c contract >>= fun c -> @@ -302,13 +318,11 @@ let get_balance c contract = | Some v -> return v let is_delegatable c contract = - Storage.Contract.Delegatable.get_option c contract >>=? function - | None -> begin - match Contract_repr.is_implicit contract with - | Some _ -> return false - | None -> failwith "is_delegatable" - end - | Some v -> return v + match Contract_repr.is_implicit contract with + | Some _ -> + return false + | None -> + Storage.Contract.Delegatable.mem c contract >>= return let is_spendable c contract = Storage.Contract.Spendable.get_option c contract >>=? function @@ -320,17 +334,33 @@ let is_spendable c contract = | Some v -> return v let set_delegate c contract delegate = - (* A contract delegate can be set only if the contract is delegatable *) - is_delegatable c contract >>=? function - | false -> fail (Non_delegatable_contract contract) - | true -> - match delegate with - | None -> - Storage.Contract.Delegate.remove c contract >>= fun c -> - return c - | Some delegate -> - Storage.Contract.Delegate.init_set c contract delegate >>= fun c -> - return c + match delegate with + | None -> + Storage.Contract.Delegate.remove c contract >>= fun c -> + return c + | Some delegate -> + begin + Storage.Contract.Manager.get_option + c (Contract_repr.implicit_contract delegate) >>=? function + | None | Some (Manager_repr.Hash _) -> return false + | Some (Manager_repr.Public_key _) -> return true + end >>=? fun known_delegate -> + Storage.Contract.Delegate.mem + c (Contract_repr.implicit_contract delegate) + >>= fun registred_delegate -> + is_delegatable c contract >>=? fun delegatable -> + let self_delegation = + match Contract_repr.is_implicit contract with + | Some pkh -> Ed25519.Public_key_hash.equal pkh delegate + | None -> false in + if not known_delegate || not (registred_delegate || self_delegation) then + fail (Unregistred_delegate delegate) + else if not (delegatable || self_delegation) then + fail (Non_delegatable_contract contract) + else + Storage.Contract.Delegate.init_set c contract delegate >>= fun c -> + return c + let code_and_storage_fee c contract = Storage.Contract.Code_fees.get_option c contract >>=? fun code_fees -> @@ -375,8 +405,16 @@ let spend_from_script c contract amount = Roll_storage.Contract.remove_amount c contract amount else match Contract_repr.is_implicit contract with - | Some _ -> delete c contract - | None -> return c + | None -> return c (* don't delete originated contract. *) + | Some pkh -> + Storage.Contract.Delegate.get_option c contract >>=? function + | Some pkh' -> + (* Don't delete "delegate" contract *) + assert (Ed25519.Public_key_hash.equal pkh pkh') ; + return c + | None -> + (* Delete empty implicit contract *) + delete c contract let credit c contract amount = Storage.Contract.Balance.get_option c contract >>=? function diff --git a/src/proto_alpha/lib_protocol/src/roll_storage.ml b/src/proto_alpha/lib_protocol/src/roll_storage.ml index dabf7fc9a..60a6c0375 100644 --- a/src/proto_alpha/lib_protocol/src/roll_storage.ml +++ b/src/proto_alpha/lib_protocol/src/roll_storage.ml @@ -14,9 +14,7 @@ type error += | No_roll_snapshot_for_cycle of Cycle_repr.t let get_contract_delegate c contract = - match Contract_repr.is_implicit contract with - | Some manager -> return (Some manager) - | None -> Storage.Contract.Delegate.get_option c contract + Storage.Contract.Delegate.get_option c contract let get_contract_delegate_at_cycle c cycle contract = match Contract_repr.is_implicit contract with diff --git a/src/proto_alpha/lib_protocol/src/storage.ml b/src/proto_alpha/lib_protocol/src/storage.ml index 8ac7d9049..ae5194b0b 100644 --- a/src/proto_alpha/lib_protocol/src/storage.ml +++ b/src/proto_alpha/lib_protocol/src/storage.ml @@ -65,9 +65,8 @@ module Contract = struct (Make_value(Bool)) module Delegatable = - Indexed_context.Make_map + Indexed_context.Make_set (struct let name = ["delegatable"] end) - (Make_value(Bool)) module Delegate = Make_indexed_data_snapshotable_storage diff --git a/src/proto_alpha/lib_protocol/src/storage.mli b/src/proto_alpha/lib_protocol/src/storage.mli index eb368d714..21bee92d4 100644 --- a/src/proto_alpha/lib_protocol/src/storage.mli +++ b/src/proto_alpha/lib_protocol/src/storage.mli @@ -114,9 +114,8 @@ module Contract : sig and type value = bool and type t := Raw_context.t - module Delegatable : Indexed_data_storage - with type key = Contract_repr.t - and type value = bool + module Delegatable : Data_set_storage + with type elt = Contract_repr.t and type t := Raw_context.t module Counter : Indexed_data_storage