Michelson: add SET_DELEGATE opcode
This commit is contained in:
parent
b669632075
commit
a11e0000e7
@ -1438,6 +1438,12 @@ contract.
|
|||||||
The parameter must be consistent with the one expected by the
|
The parameter must be consistent with the one expected by the
|
||||||
contract, unit for an account.
|
contract, unit for an account.
|
||||||
|
|
||||||
|
- ``SET_DELEGATE``: Forge a delegation.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
:: option key_hash : 'S -> operation : S
|
||||||
|
|
||||||
- ``BALANCE``: Push the current amount of tez of the current contract.
|
- ``BALANCE``: Push the current amount of tez of the current contract.
|
||||||
|
|
||||||
::
|
::
|
||||||
@ -2469,6 +2475,7 @@ XII - Full grammar
|
|||||||
| MANAGER
|
| MANAGER
|
||||||
| SELF
|
| SELF
|
||||||
| TRANSFER_TOKENS
|
| TRANSFER_TOKENS
|
||||||
|
| SET_DELEGATE
|
||||||
| CREATE_ACCOUNT
|
| CREATE_ACCOUNT
|
||||||
| CREATE_CONTRACT
|
| CREATE_CONTRACT
|
||||||
| IMPLICIT_ACCOUNT
|
| IMPLICIT_ACCOUNT
|
||||||
|
30
src/bin_client/test/contracts/vote_for_delegate.tz
Normal file
30
src/bin_client/test/contracts/vote_for_delegate.tz
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
parameter (option key_hash) ;
|
||||||
|
storage (pair
|
||||||
|
(pair (address @mgr1) (option key_hash))
|
||||||
|
(pair (address @mgr2) (option key_hash))) ;
|
||||||
|
code { # Update the storage
|
||||||
|
DUP ; CDAAR ; SOURCE ;
|
||||||
|
IFCMPEQ
|
||||||
|
{ UNPAIR ; SWAP ; SET_CADR }
|
||||||
|
{ DUP ; CDDAR ; SOURCE ;
|
||||||
|
IFCMPEQ
|
||||||
|
{ UNPAIR ; SWAP ; SET_CDDR }
|
||||||
|
{ FAIL } } ;
|
||||||
|
# Now compare the proposals
|
||||||
|
DUP ; CADR ;
|
||||||
|
DIP { DUP ; CDDR } ;
|
||||||
|
IF_NONE
|
||||||
|
{ IF_NONE
|
||||||
|
{ NONE key_hash ;
|
||||||
|
SET_DELEGATE ; NIL operation ; SWAP ; CONS }
|
||||||
|
{ DROP ; NIL operation } }
|
||||||
|
{ SWAP ;
|
||||||
|
IF_SOME
|
||||||
|
{ DIP { DUP } ;
|
||||||
|
IFCMPEQ
|
||||||
|
{ SOME ;
|
||||||
|
SET_DELEGATE ; NIL operation ; SWAP ; CONS }
|
||||||
|
{ DROP ;
|
||||||
|
NIL operation }}
|
||||||
|
{ DROP ; NIL operation }} ;
|
||||||
|
PAIR }
|
@ -414,6 +414,26 @@ init_with_transfer $contract_dir/self.tz $key1 \
|
|||||||
bake_after $client transfer 0 from bootstrap1 to self
|
bake_after $client transfer 0 from bootstrap1 to self
|
||||||
assert_storage_contains self "\"$(get_contract_addr self)\""
|
assert_storage_contains self "\"$(get_contract_addr self)\""
|
||||||
|
|
||||||
|
# Test SET_DELEGATE
|
||||||
|
b2='tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN'
|
||||||
|
b3='tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU'
|
||||||
|
b4='tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv'
|
||||||
|
b5='tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv'
|
||||||
|
init_with_transfer $contract_dir/vote_for_delegate.tz bootstrap1 \
|
||||||
|
"(Pair (Pair \"$b3\" None) (Pair \"$b4\" None))" 1,000 bootstrap1
|
||||||
|
$client get delegate for vote_for_delegate | assert_in_output none
|
||||||
|
|
||||||
|
assert_fails $client transfer 0 from bootstrap1 to vote_for_delegate -arg None
|
||||||
|
assert_fails $client transfer 0 from bootstrap2 to vote_for_delegate -arg None
|
||||||
|
bake_after $client transfer 0 from bootstrap3 to vote_for_delegate -arg "(Some \"$b5\")"
|
||||||
|
assert_storage_contains vote_for_delegate "\"$b5\""
|
||||||
|
$client get delegate for vote_for_delegate | assert_in_output none
|
||||||
|
bake_after $client transfer 0 from bootstrap4 to vote_for_delegate -arg "(Some \"$b2\")"
|
||||||
|
assert_storage_contains vote_for_delegate "\"$b2\""
|
||||||
|
$client get delegate for vote_for_delegate | assert_in_output none
|
||||||
|
bake_after $client transfer 0 from bootstrap4 to vote_for_delegate -arg "(Some \"$b5\")"
|
||||||
|
$client get delegate for vote_for_delegate | assert_in_output "$b5"
|
||||||
|
|
||||||
# Test sets and map literals
|
# Test sets and map literals
|
||||||
assert_fails $client typecheck data '{ Elt 0 1 ; Elt 0 1 }' against type '(map nat nat)'
|
assert_fails $client typecheck data '{ Elt 0 1 ; Elt 0 1 }' against type '(map nat nat)'
|
||||||
assert_fails $client typecheck data '{ Elt 0 1 ; Elt 10 1 ; Elt 5 1 }' against type '(map nat nat)'
|
assert_fails $client typecheck data '{ Elt 0 1 ; Elt 10 1 ; Elt 5 1 }' against type '(map nat nat)'
|
||||||
|
@ -80,11 +80,11 @@ let pp_manager_operation_content ppf source operation internal pp_result result
|
|||||||
Michelson_v1_printer.print_expr storage
|
Michelson_v1_printer.print_expr storage
|
||||||
end ;
|
end ;
|
||||||
begin match delegate with
|
begin match delegate with
|
||||||
| None -> Format.fprintf ppf "@,Delegate is the manager"
|
| None -> Format.fprintf ppf "@,No delegate for this contract"
|
||||||
| Some delegate -> Format.fprintf ppf "@,Delegate: %a" Signature.Public_key_hash.pp delegate
|
| Some delegate -> Format.fprintf ppf "@,Delegate: %a" Signature.Public_key_hash.pp delegate
|
||||||
end ;
|
end ;
|
||||||
if spendable then Format.fprintf ppf "@,Spendable by its manager" ;
|
if spendable then Format.fprintf ppf "@,Spendable by the manager" ;
|
||||||
if delegatable then Format.fprintf ppf "@,Delegate can be changed later" ;
|
if delegatable then Format.fprintf ppf "@,Delegate can be changed by the manager" ;
|
||||||
pp_result ppf result ;
|
pp_result ppf result ;
|
||||||
Format.fprintf ppf "@]" ;
|
Format.fprintf ppf "@]" ;
|
||||||
| Reveal key ->
|
| Reveal key ->
|
||||||
|
@ -145,6 +145,17 @@ let commands () =
|
|||||||
operation_submitted_message cctxt oph
|
operation_submitted_message cctxt oph
|
||||||
end ;
|
end ;
|
||||||
|
|
||||||
|
command ~group ~desc: "Withdraw the delegate from a contract."
|
||||||
|
(args1 fee_arg)
|
||||||
|
(prefixes [ "withdraw" ; "delegate" ; "from" ]
|
||||||
|
@@ ContractAlias.destination_param ~name:"src" ~desc:"source contract"
|
||||||
|
@@ stop)
|
||||||
|
begin fun fee (_, contract) (cctxt : Proto_alpha.full) ->
|
||||||
|
source_to_keys cctxt cctxt#block contract >>=? fun (src_pk, manager_sk) ->
|
||||||
|
set_delegate ~fee cctxt cctxt#block contract None ~src_pk ~manager_sk >>=? fun oph ->
|
||||||
|
operation_submitted_message cctxt oph
|
||||||
|
end ;
|
||||||
|
|
||||||
command ~group ~desc:"Open a new account."
|
command ~group ~desc:"Open a new account."
|
||||||
(args4 fee_arg delegate_arg delegatable_switch (Client_keys.force_switch ()))
|
(args4 fee_arg delegate_arg delegatable_switch (Client_keys.force_switch ()))
|
||||||
(prefixes [ "originate" ; "account" ]
|
(prefixes [ "originate" ; "account" ]
|
||||||
|
@ -236,6 +236,7 @@ module Script : sig
|
|||||||
| I_SUB
|
| I_SUB
|
||||||
| I_SWAP
|
| I_SWAP
|
||||||
| I_TRANSFER_TOKENS
|
| I_TRANSFER_TOKENS
|
||||||
|
| I_SET_DELEGATE
|
||||||
| I_UNIT
|
| I_UNIT
|
||||||
| I_UPDATE
|
| I_UPDATE
|
||||||
| I_XOR
|
| I_XOR
|
||||||
@ -566,6 +567,9 @@ module Delegate : sig
|
|||||||
val set:
|
val set:
|
||||||
context -> Contract.t -> public_key_hash option -> context tzresult Lwt.t
|
context -> Contract.t -> public_key_hash option -> context tzresult Lwt.t
|
||||||
|
|
||||||
|
val set_from_script:
|
||||||
|
context -> Contract.t -> public_key_hash option -> context tzresult Lwt.t
|
||||||
|
|
||||||
val fold:
|
val fold:
|
||||||
context ->
|
context ->
|
||||||
init:'a -> f:(public_key_hash -> 'a -> 'a Lwt.t) -> 'a Lwt.t
|
init:'a -> f:(public_key_hash -> 'a -> 'a Lwt.t) -> 'a Lwt.t
|
||||||
|
@ -391,6 +391,8 @@ let apply_manager_operation_content ctxt ~payer ~source ~internal operation =
|
|||||||
Contract.must_exist ctxt source >>=? fun () ->
|
Contract.must_exist ctxt source >>=? fun () ->
|
||||||
let spend =
|
let spend =
|
||||||
if internal then Contract.spend_from_script else Contract.spend in
|
if internal then Contract.spend_from_script else Contract.spend in
|
||||||
|
let set_delegate =
|
||||||
|
if internal then Delegate.set_from_script else Delegate.set in
|
||||||
match operation with
|
match operation with
|
||||||
| Reveal _ -> return (ctxt, Reveal_result)
|
| Reveal _ -> return (ctxt, Reveal_result)
|
||||||
| Transaction { amount ; parameters ; destination } -> begin
|
| Transaction { amount ; parameters ; destination } -> begin
|
||||||
@ -486,7 +488,7 @@ let apply_manager_operation_content ctxt ~payer ~source ~internal operation =
|
|||||||
storage_fees_increment = fees } in
|
storage_fees_increment = fees } in
|
||||||
return (ctxt, result)
|
return (ctxt, result)
|
||||||
| Delegation delegate ->
|
| Delegation delegate ->
|
||||||
Delegate.set ctxt source delegate >>=? fun ctxt ->
|
set_delegate ctxt source delegate >>=? fun ctxt ->
|
||||||
return (ctxt, Delegation_result)
|
return (ctxt, Delegation_result)
|
||||||
|
|
||||||
let apply_internal_manager_operations ctxt ~payer ops =
|
let apply_internal_manager_operations ctxt ~payer ops =
|
||||||
|
@ -121,7 +121,7 @@ let init ctxt contract delegate =
|
|||||||
|
|
||||||
let get = Roll_storage.get_contract_delegate
|
let get = Roll_storage.get_contract_delegate
|
||||||
|
|
||||||
let set c contract delegate =
|
let set_base c is_delegatable contract delegate =
|
||||||
match delegate with
|
match delegate with
|
||||||
| None -> begin
|
| None -> begin
|
||||||
match Contract_repr.is_implicit contract with
|
match Contract_repr.is_implicit contract with
|
||||||
@ -180,6 +180,12 @@ let set c contract delegate =
|
|||||||
end >>=? fun c ->
|
end >>=? fun c ->
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
let set c contract delegate =
|
||||||
|
set_base c is_delegatable contract delegate
|
||||||
|
|
||||||
|
let set_from_script c contract delegate =
|
||||||
|
set_base c (fun _ _ -> return true) contract delegate
|
||||||
|
|
||||||
let remove ctxt contract =
|
let remove ctxt contract =
|
||||||
Storage.Contract.Balance.get ctxt contract >>=? fun balance ->
|
Storage.Contract.Balance.get ctxt contract >>=? fun balance ->
|
||||||
unlink ctxt contract balance
|
unlink ctxt contract balance
|
||||||
|
@ -38,6 +38,11 @@ val set:
|
|||||||
Raw_context.t -> Contract_repr.t -> Signature.Public_key_hash.t option ->
|
Raw_context.t -> Contract_repr.t -> Signature.Public_key_hash.t option ->
|
||||||
Raw_context.t tzresult Lwt.t
|
Raw_context.t tzresult Lwt.t
|
||||||
|
|
||||||
|
(** Same as {!set} ignoring the [delegatable] flag. *)
|
||||||
|
val set_from_script:
|
||||||
|
Raw_context.t -> Contract_repr.t -> Signature.Public_key_hash.t option ->
|
||||||
|
Raw_context.t tzresult Lwt.t
|
||||||
|
|
||||||
type error +=
|
type error +=
|
||||||
| Non_delegatable_contract of Contract_repr.contract (* `Permanent *)
|
| Non_delegatable_contract of Contract_repr.contract (* `Permanent *)
|
||||||
| No_deletion of Signature.Public_key_hash.t (* `Permanent *)
|
| No_deletion of Signature.Public_key_hash.t (* `Permanent *)
|
||||||
|
@ -176,6 +176,7 @@ module Cost_of = struct
|
|||||||
let create_account = step_cost 20
|
let create_account = step_cost 20
|
||||||
let create_contract = step_cost 70
|
let create_contract = step_cost 70
|
||||||
let implicit_account = step_cost 10
|
let implicit_account = step_cost 10
|
||||||
|
let set_delegate = step_cost 10
|
||||||
let balance = step_cost 5
|
let balance = step_cost 5
|
||||||
let now = step_cost 3
|
let now = step_cost 3
|
||||||
let check_signature = step_cost 3
|
let check_signature = step_cost 3
|
||||||
|
@ -71,6 +71,7 @@ module Cost_of : sig
|
|||||||
val create_account : Gas.cost
|
val create_account : Gas.cost
|
||||||
val create_contract : Gas.cost
|
val create_contract : Gas.cost
|
||||||
val implicit_account : Gas.cost
|
val implicit_account : Gas.cost
|
||||||
|
val set_delegate : Gas.cost
|
||||||
val balance : Gas.cost
|
val balance : Gas.cost
|
||||||
val now : Gas.cost
|
val now : Gas.cost
|
||||||
val check_signature : Gas.cost
|
val check_signature : Gas.cost
|
||||||
|
@ -89,6 +89,7 @@ type prim =
|
|||||||
| I_SUB
|
| I_SUB
|
||||||
| I_SWAP
|
| I_SWAP
|
||||||
| I_TRANSFER_TOKENS
|
| I_TRANSFER_TOKENS
|
||||||
|
| I_SET_DELEGATE
|
||||||
| I_UNIT
|
| I_UNIT
|
||||||
| I_UPDATE
|
| I_UPDATE
|
||||||
| I_XOR
|
| I_XOR
|
||||||
@ -214,6 +215,7 @@ let string_of_prim = function
|
|||||||
| I_SUB -> "SUB"
|
| I_SUB -> "SUB"
|
||||||
| I_SWAP -> "SWAP"
|
| I_SWAP -> "SWAP"
|
||||||
| I_TRANSFER_TOKENS -> "TRANSFER_TOKENS"
|
| I_TRANSFER_TOKENS -> "TRANSFER_TOKENS"
|
||||||
|
| I_SET_DELEGATE -> "SET_DELEGATE"
|
||||||
| I_UNIT -> "UNIT"
|
| I_UNIT -> "UNIT"
|
||||||
| I_UPDATE -> "UPDATE"
|
| I_UPDATE -> "UPDATE"
|
||||||
| I_XOR -> "XOR"
|
| I_XOR -> "XOR"
|
||||||
@ -320,6 +322,7 @@ let prim_of_string = function
|
|||||||
| "SUB" -> ok I_SUB
|
| "SUB" -> ok I_SUB
|
||||||
| "SWAP" -> ok I_SWAP
|
| "SWAP" -> ok I_SWAP
|
||||||
| "TRANSFER_TOKENS" -> ok I_TRANSFER_TOKENS
|
| "TRANSFER_TOKENS" -> ok I_TRANSFER_TOKENS
|
||||||
|
| "SET_DELEGATE" -> ok I_SET_DELEGATE
|
||||||
| "UNIT" -> ok I_UNIT
|
| "UNIT" -> ok I_UNIT
|
||||||
| "UPDATE" -> ok I_UPDATE
|
| "UPDATE" -> ok I_UPDATE
|
||||||
| "XOR" -> ok I_XOR
|
| "XOR" -> ok I_XOR
|
||||||
@ -470,6 +473,7 @@ let prim_encoding =
|
|||||||
("SUB", I_SUB) ;
|
("SUB", I_SUB) ;
|
||||||
("SWAP", I_SWAP) ;
|
("SWAP", I_SWAP) ;
|
||||||
("TRANSFER_TOKENS", I_TRANSFER_TOKENS) ;
|
("TRANSFER_TOKENS", I_TRANSFER_TOKENS) ;
|
||||||
|
("SET_DELEGATE", I_SET_DELEGATE) ;
|
||||||
("UNIT", I_UNIT) ;
|
("UNIT", I_UNIT) ;
|
||||||
("UPDATE", I_UPDATE) ;
|
("UPDATE", I_UPDATE) ;
|
||||||
("XOR", I_XOR) ;
|
("XOR", I_XOR) ;
|
||||||
|
@ -87,6 +87,7 @@ type prim =
|
|||||||
| I_SUB
|
| I_SUB
|
||||||
| I_SWAP
|
| I_SWAP
|
||||||
| I_TRANSFER_TOKENS
|
| I_TRANSFER_TOKENS
|
||||||
|
| I_SET_DELEGATE
|
||||||
| I_UNIT
|
| I_UNIT
|
||||||
| I_UPDATE
|
| I_UPDATE
|
||||||
| I_XOR
|
| I_XOR
|
||||||
|
@ -701,6 +701,11 @@ let rec interp
|
|||||||
(init, rest)))))) ->
|
(init, rest)))))) ->
|
||||||
create_contract descr ~manager ~delegate ~spendable ~delegatable ~credit ~code ~init
|
create_contract descr ~manager ~delegate ~spendable ~delegatable ~credit ~code ~init
|
||||||
~param_type ~storage_type ~rest
|
~param_type ~storage_type ~rest
|
||||||
|
| Set_delegate,
|
||||||
|
Item (delegate, rest) ->
|
||||||
|
Lwt.return (Gas.consume ctxt Interp_costs.create_account) >>=? fun ctxt ->
|
||||||
|
let operation = Delegation delegate in
|
||||||
|
logged_return (Item ({ source = self ; operation ; signature = None }, rest), ctxt)
|
||||||
| Balance, rest ->
|
| Balance, rest ->
|
||||||
Lwt.return (Gas.consume ctxt Interp_costs.balance) >>=? fun ctxt ->
|
Lwt.return (Gas.consume ctxt Interp_costs.balance) >>=? fun ctxt ->
|
||||||
Contract.get_balance ctxt self >>=? fun balance ->
|
Contract.get_balance ctxt self >>=? fun balance ->
|
||||||
|
@ -211,6 +211,7 @@ let number_of_generated_growing_types : type b a. (b, a) instr -> int = function
|
|||||||
| Source -> 0
|
| Source -> 0
|
||||||
| Self _ -> 1
|
| Self _ -> 1
|
||||||
| Amount -> 0
|
| Amount -> 0
|
||||||
|
| Set_delegate -> 0
|
||||||
|
|
||||||
(* ---- Error helpers -------------------------------------------------------*)
|
(* ---- Error helpers -------------------------------------------------------*)
|
||||||
|
|
||||||
@ -302,6 +303,7 @@ let namespace = function
|
|||||||
| I_SUB
|
| I_SUB
|
||||||
| I_SWAP
|
| I_SWAP
|
||||||
| I_TRANSFER_TOKENS
|
| I_TRANSFER_TOKENS
|
||||||
|
| I_SET_DELEGATE
|
||||||
| I_UNIT
|
| I_UNIT
|
||||||
| I_UPDATE
|
| I_UPDATE
|
||||||
| I_XOR
|
| I_XOR
|
||||||
@ -2055,6 +2057,9 @@ and parse_instr
|
|||||||
(Contract_t cp, rest, _), _), _) ->
|
(Contract_t cp, rest, _), _), _) ->
|
||||||
check_item_ty p cp loc I_TRANSFER_TOKENS 1 4 >>=? fun Eq ->
|
check_item_ty p cp loc I_TRANSFER_TOKENS 1 4 >>=? fun Eq ->
|
||||||
typed ctxt loc Transfer_tokens (Item_t (Operation_t, rest, instr_annot))
|
typed ctxt loc Transfer_tokens (Item_t (Operation_t, rest, instr_annot))
|
||||||
|
| Prim (loc, I_SET_DELEGATE, [], instr_annot),
|
||||||
|
Item_t (Option_t Key_hash_t, rest, _) ->
|
||||||
|
typed ctxt loc Set_delegate (Item_t (Operation_t, rest, instr_annot))
|
||||||
| Prim (loc, I_CREATE_ACCOUNT, [], instr_annot),
|
| Prim (loc, I_CREATE_ACCOUNT, [], instr_annot),
|
||||||
Item_t
|
Item_t
|
||||||
(Key_hash_t, Item_t
|
(Key_hash_t, Item_t
|
||||||
@ -2165,7 +2170,7 @@ and parse_instr
|
|||||||
| I_COMPARE | I_EQ | I_NEQ
|
| I_COMPARE | I_EQ | I_NEQ
|
||||||
| I_LT | I_GT | I_LE | I_GE
|
| I_LT | I_GT | I_LE | I_GE
|
||||||
| I_MANAGER | I_TRANSFER_TOKENS | I_CREATE_ACCOUNT
|
| I_MANAGER | I_TRANSFER_TOKENS | I_CREATE_ACCOUNT
|
||||||
| I_CREATE_CONTRACT | I_NOW
|
| I_CREATE_CONTRACT | I_SET_DELEGATE | I_NOW
|
||||||
| I_IMPLICIT_ACCOUNT | I_AMOUNT | I_BALANCE
|
| I_IMPLICIT_ACCOUNT | I_AMOUNT | I_BALANCE
|
||||||
| I_CHECK_SIGNATURE | I_HASH_KEY | I_SOURCE
|
| I_CHECK_SIGNATURE | I_HASH_KEY | I_SOURCE
|
||||||
| I_H | I_STEPS_TO_QUOTA | I_ADDRESS
|
| I_H | I_STEPS_TO_QUOTA | I_ADDRESS
|
||||||
|
@ -344,6 +344,8 @@ and ('bef, 'aft) instr =
|
|||||||
| Create_contract_literal : 'g ty * 'p ty * ('p * 'g, internal_operation list * 'g) lambda ->
|
| Create_contract_literal : 'g ty * 'p ty * ('p * 'g, internal_operation list * 'g) lambda ->
|
||||||
(public_key_hash * (public_key_hash option * (bool * (bool * (Tez.t * ('g * 'rest))))),
|
(public_key_hash * (public_key_hash option * (bool * (bool * (Tez.t * ('g * 'rest))))),
|
||||||
internal_operation * (Contract.t * 'rest)) instr
|
internal_operation * (Contract.t * 'rest)) instr
|
||||||
|
| Set_delegate :
|
||||||
|
(public_key_hash option * 'rest, internal_operation * 'rest) instr
|
||||||
| Now :
|
| Now :
|
||||||
('rest, Script_timestamp.t * 'rest) instr
|
('rest, Script_timestamp.t * 'rest) instr
|
||||||
| Balance :
|
| Balance :
|
||||||
|
Loading…
Reference in New Issue
Block a user