diff --git a/CHANGES.rst b/CHANGES.rst index 41a3f2f65d61a25cd30a80d231402d0653155b98..43cf0f7224820d6dde5abba6ea0d61971351929b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -75,6 +75,35 @@ Client ``GET /chains//blocks//context/contracts//storage/used_space`` and ``GET /chains//blocks//context/contracts//storage/paid_space``. +- Added commands related to the "consensus key" feature: + + Update the consensus key of a baker: + +```shell +tezos-client set consensus key for to +``` + + It is also possible to register as a delegate and immediately set the consensus key: + +```shell +tezos-client register key as delegate with consensus key +``` + + (The current registration command still works.) + + + Drain a baker's account: + +```shell +tezos-client drain delegate to +``` + + or, if the destination account is different from the consensus key + +```shell +tezos-client drain delegate to with +``` + Baker ----- @@ -82,6 +111,8 @@ Baker guaranteed to be included in the order they are received from the operations source. +- The logs now display both the delegate and its consensus key. + Accuser ------- diff --git a/devtools/yes_wallet/get_delegates_alpha.ml b/devtools/yes_wallet/get_delegates_alpha.ml index 95f78ea6b5fdcccd2bdd44aa6c353811602d93a3..230d17da0cd86d92a2a9af6515c6ef8549d8e29c 100644 --- a/devtools/yes_wallet/get_delegates_alpha.ml +++ b/devtools/yes_wallet/get_delegates_alpha.ml @@ -42,7 +42,9 @@ module Get_delegates = struct let fold ctxt ~order ~init ~f = fold ctxt ~order ~init ~f - let pubkey ctxt pkh = pubkey ctxt pkh |> Lwt.map Environment.wrap_tzresult + let pubkey ctxt pkh = + Alpha_context.Contract.get_manager_key ctxt pkh + |> Lwt.map Environment.wrap_tzresult let staking_balance ctxt pkh = staking_balance ctxt pkh |> Lwt.map Environment.wrap_tzresult diff --git a/docs/protocols/alpha.rst b/docs/protocols/alpha.rst index a5d3140961319408fb432e461ce4ddd88c1806d1..b2980ef2b516f23634fe5fddfc26ab0c274ff5bf 100644 --- a/docs/protocols/alpha.rst +++ b/docs/protocols/alpha.rst @@ -33,7 +33,136 @@ It requires protocol environment V7, compared to V6 for Kathmandu. - Introduce an Q module, making a subset of Zarith.Q available to the protocol (MR :gl:`!6042`) +Consensus key +------------- +The "consensus key" feature allows bakers to use a different key, +called the *consensus key* for consensus, that is, for baking and for +signing consensus operations (i.e. preendorsements and +endorsements). It also allows them to update this key. The update +becomes active after ``PRESERVED_CYCLES + 1`` cycles. We therefore +distinguish the *active* consensus key and the *pending* consensus +keys. (There can be multiple pending updates.) The active consensus +key is by default the baker's regular key, called its *manager key*, +which cannot change. + +Two new operations have been added: + + ``Update_consensus_key ()`` + This is a manager operation that must be signed by the manager + key of a baker. This operation updates the consensus key of the + baker to ``public_key`` starting from the current cycle plus + ``PRESERVED_CYCLES + 1``. A consensus key can only be used by a + single baker, the operation fails otherwise. + + ``Drain_delegate ()`` + This is an operation that must be signed by the active consensus + key ``consensus_pkh`` of the baker ``baker_pkh``. This operation + immediately transfers all the spendable balance of the + ``baker_pkh``'s implicit account into the ``destination_pkh`` + implicit account. It has no effect on the frozen balance. This + operation is included in pass 2 (anonymous operations). So drain + operations don't compete with regular manager operations for gas + and block size quota; the :doc:`1M restriction<014_kathmandu>` + (one-operation-per-manager-per-block) applies to drain operations + as well, meaning that a drain for a baker and a transfer + operation from the same baker are in conflict. As an incentive + for bakers to include drain operations, a fixed fraction of the + drained baker's spendable balance is transferred as fees to the + baker that includes the operation, i.e. the maximum between 1tz + or 1% of the spendable balance. + +(Breaking changes) Some existing RPCs have been updated: + +- ``/chains/main/blocks/head/metadata`` + + The block metadata is extended with the active consensus key of the + baker and the proposer. The fields ``proposer`` and ``baker`` still + hold the respective public key hashes of the manager keys of the + proposer and the baker. + +:: + + "proposer_consensus_key": "[PUBLIC_KEY_HASH]", + "baker_consensus_key": "[PUBLIC_KEY_HASH]", + +- ``/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]`` + + The delegate data is extended with the active and pending consensus keys. + +:: + + {"full_balance": "4000000000000", + "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", + "staking_balance": "4000000000000", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", + "deactivated": false, + "grace_period": 5, + "voting_power": "4000000000000", + "active_consensus_key": "[PUBLIC_KEY_HASH]", + "pending_consensus_keys": [ + { "cycle": 7, "pkh": "[PUBLIC_KEY_HASH]}, + { "cycle": 9, "pkh": "[PUBLIC_KEY_HASH]} + ]}} + + +- ``/chains/main/blocks/head/helpers/baking_rights`` + + The baking rights RPC now returns both the manager key, required to + identify the rewarded delegate, and the active consensus key + required to sign a block. The RPC also accepts a new parameter + ``consensus_key=`` to filter the result by the active consensus + key. + +:: + + [{ "level": 2, "delegate": "[PUBLIC_KEY_HASH]", + "round": 0, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, + { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", + "round": 1, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, + { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", + "round": 2, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, + { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", + "round": 3, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, + { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", + "round": 10, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }] + +- ``/chains/main/blocks/head/helpers/endorsing_rights`` + + The endorsing rights RPC now returns both the manager key, required + to identify the rewarded delegate, and the active consensus key + required to sign a block. The RPC also accepts a new parameter + ``consensus_key=`` to filter the result by the active consensus + key. + +:: + + [ { "level": 1, + "delegates": + [ { "delegate": "[PUBLIC_KEY_HASH]", + "first_slot": 11, "endorsing_power": 50, + "consensus_key": "[PUBLIC_KEY_HASH]" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "first_slot": 4, "endorsing_power": 47, + "consensus_key": "[PUBLIC_KEY_HASH]" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "first_slot": 2, "endorsing_power": 46, + "consensus_key": "[PUBLIC_KEY_HASH]" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "first_slot": 1, "endorsing_power": 55, + "consensus_key": "[PUBLIC_KEY_HASH]" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "first_slot": 0, "endorsing_power": 58, + "consensus_key": "[PUBLIC_KEY_HASH]" } ] } ] + +MRs: :gl:`!5936`, :gl:`!5961`, :gl:`!5970` Smart Contract Optimistic Rollups (ongoing) ------------------------------------------- diff --git a/src/lib_store/unix/test/alpha_utils.ml b/src/lib_store/unix/test/alpha_utils.ml index f9870f080a556857a7dd0db99b80fbe7f27c1e1e..954a7b85cb0dfe5b51329158e08f29b699d578f4 100644 --- a/src/lib_store/unix/test/alpha_utils.ml +++ b/src/lib_store/unix/test/alpha_utils.ml @@ -111,7 +111,13 @@ module Account = struct let account_to_bootstrap ({pkh; pk; _}, amount, delegate_to) = let open Parameters in - ({public_key_hash = pkh; public_key = Some pk; amount; delegate_to} + ({ + public_key_hash = pkh; + public_key = Some pk; + amount; + delegate_to; + consensus_key = None; + } : bootstrap_account) let commitment_secret = diff --git a/src/proto_alpha/bin_sc_rollup_node/daemon.ml b/src/proto_alpha/bin_sc_rollup_node/daemon.ml index 75f67a7b04a2da95d57090c3b4267dabf661258e..5f1070c6ed4cb9c600ed6417eb0f79e77584ac93 100644 --- a/src/proto_alpha/bin_sc_rollup_node/daemon.ml +++ b/src/proto_alpha/bin_sc_rollup_node/daemon.ml @@ -131,8 +131,8 @@ module Make (PVM : Pvm.S) = struct Sc_rollup.Address.(rollup = node_ctxt.Node_context.rollup_address) | Dal_publish_slot_header _ -> true | Reveal _ | Transaction _ | Origination _ | Delegation _ - | Register_global_constant _ | Set_deposits_limit _ - | Increase_paid_storage _ | Tx_rollup_origination + | Update_consensus_key _ | Register_global_constant _ + | Set_deposits_limit _ | Increase_paid_storage _ | Tx_rollup_origination | Tx_rollup_submit_batch _ | Tx_rollup_commit _ | Tx_rollup_return_bond _ | Tx_rollup_finalize_commitment _ | Tx_rollup_remove_commitment _ | Tx_rollup_rejection _ | Tx_rollup_dispatch_tickets _ | Transfer_ticket _ diff --git a/src/proto_alpha/bin_sc_rollup_node/injector.ml b/src/proto_alpha/bin_sc_rollup_node/injector.ml index 346a86762d10ce349a2d16f7844f015c98accc2c..5b90225165ec25ea68236e1d70d596d4764aa485 100644 --- a/src/proto_alpha/bin_sc_rollup_node/injector.ml +++ b/src/proto_alpha/bin_sc_rollup_node/injector.ml @@ -143,7 +143,7 @@ module Parameters : *) return_true | Reveal _ | Transaction _ | Origination _ | Delegation _ - | Register_global_constant _ | Set_deposits_limit _ + | Update_consensus_key _ | Register_global_constant _ | Set_deposits_limit _ | Increase_paid_storage _ | Tx_rollup_origination | Tx_rollup_submit_batch _ | Tx_rollup_commit _ | Tx_rollup_return_bond _ | Tx_rollup_finalize_commitment _ | Tx_rollup_remove_commitment _ diff --git a/src/proto_alpha/lib_benchmarks_proto/storage_benchmarks.ml b/src/proto_alpha/lib_benchmarks_proto/storage_benchmarks.ml index ff55ca43fac7fb363348a34647b8f4e83f0de276..0a6478171a287c4481afd01fb1a4f72004b50892 100644 --- a/src/proto_alpha/lib_benchmarks_proto/storage_benchmarks.ml +++ b/src/proto_alpha/lib_benchmarks_proto/storage_benchmarks.ml @@ -42,7 +42,8 @@ let default_raw_context () = let bootstrap_accounts = List.map (fun (Account.{pk; pkh; _}, amount, delegate_to) -> - Default_parameters.make_bootstrap_account (pkh, pk, amount, delegate_to)) + Default_parameters.make_bootstrap_account + (pkh, pk, amount, delegate_to, None)) initial_accounts in Block.prepare_initial_context_params initial_accounts diff --git a/src/proto_alpha/lib_client/client_proto_context.ml b/src/proto_alpha/lib_client/client_proto_context.ml index af74d7a2e421cbc66e30f782ebafc4e870da64d2..a8d3947fd10d6da5ac8cbc4c3fb0826ccee470f1 100644 --- a/src/proto_alpha/lib_client/client_proto_context.ml +++ b/src/proto_alpha/lib_client/client_proto_context.ml @@ -304,22 +304,123 @@ let set_delegate cctxt ~chain ~block ?confirmations ?dry_run ?verbose_signing ~fee_parameter opt_delegate +let build_update_consensus_key ?fee ?gas_limit ?storage_limit consensus_pk = + let operation = Update_consensus_key consensus_pk in + Injection.prepare_manager_operation + ~fee:(Limit.of_option fee) + ~gas_limit:(Limit.of_option gas_limit) + ~storage_limit:(Limit.of_option storage_limit) + operation + let register_as_delegate cctxt ~chain ~block ?confirmations ?dry_run - ?verbose_signing ?fee ~manager_sk ~fee_parameter src_pk = + ?verbose_signing ?fee ~manager_sk ~fee_parameter ?consensus_pk src_pk = let source = Signature.Public_key.hash src_pk in - delegate_contract + let delegate_op = build_delegate_operation ?fee (Some source) in + match consensus_pk with + | None -> ( + let operation = Annotated_manager_operation.Single_manager delegate_op in + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ~source + ~fee:(Limit.of_option fee) + ~gas_limit:Limit.unknown + ~storage_limit:Limit.unknown + ~src_pk + ~src_sk:manager_sk + ~fee_parameter + operation + >>=? fun (oph, _, op, result) -> + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> + return ((oph, op, result), None)) + | Some consensus_pk -> ( + let operation = + Annotated_manager_operation.Cons_manager + ( delegate_op, + Annotated_manager_operation.Single_manager + (build_update_consensus_key ?fee consensus_pk) ) + in + Injection.inject_manager_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ~successor_level:true + ~source + ~fee:(Limit.of_option fee) + ~gas_limit:Limit.unknown + ~storage_limit:Limit.unknown + ~src_pk + ~src_sk:manager_sk + ~fee_parameter + operation + >>=? fun (oph, _, op, result) -> + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result + (Manager_operation _, Manager_operation_result _) -> + . + | Apply_results.Cons_and_result + ( (Manager_operation _ as op1), + res1, + Single_and_result ((Manager_operation _ as op2), res2) ) -> + return ((oph, op1, res1), Some (op2, res2))) + +let update_consensus_key cctxt ~chain ~block ?confirmations ?dry_run + ?verbose_signing ?simulation ?fee ~consensus_pk ~manager_sk ~fee_parameter + src_pk = + let source = Signature.Public_key.hash src_pk in + let operation = build_update_consensus_key ?fee consensus_pk in + let operation = Annotated_manager_operation.Single_manager operation in + Injection.inject_manager_operation cctxt ~chain ~block ?confirmations ?dry_run ?verbose_signing + ?simulation + ~successor_level:true ~source + ~fee:(Limit.of_option fee) + ~gas_limit:Limit.unknown + ~storage_limit:Limit.unknown ~src_pk ~src_sk:manager_sk - ?fee ~fee_parameter - (Some source) + operation + >>=? fun (oph, _, op, result) -> + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Manager_operation _ as op), result) -> + return (oph, op, result) + +let drain_delegate cctxt ~chain ~block ?confirmations ?dry_run ?verbose_signing + ?simulation ~consensus_sk ~consensus_pkh ?(destination = consensus_pkh) + ~delegate () = + let operation = + Single + (Drain_delegate {consensus_key = consensus_pkh; delegate; destination}) + in + Injection.inject_operation + cctxt + ~chain + ~block + ?confirmations + ?dry_run + ?verbose_signing + ?simulation + ~src_sk:consensus_sk + operation + >>=? fun (oph, op, result) -> + match Apply_results.pack_contents_list op result with + | Apply_results.Single_and_result ((Drain_delegate _ as op), result) -> + return (oph, op, result) let set_deposits_limit cctxt ~chain ~block ?confirmations ?dry_run ?verbose_signing ?simulation ?fee contract ~src_pk ~manager_sk diff --git a/src/proto_alpha/lib_client/client_proto_context.mli b/src/proto_alpha/lib_client/client_proto_context.mli index 8176311498d741d72b019120b1f7fab732faa991..7830269d141ff1606e0e79b197ffc4267e7d9cc5 100644 --- a/src/proto_alpha/lib_client/client_proto_context.mli +++ b/src/proto_alpha/lib_client/client_proto_context.mli @@ -162,6 +162,36 @@ val set_delegate : public_key_hash option -> Kind.delegation Kind.manager Injection.result tzresult Lwt.t +val update_consensus_key : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?simulation:bool -> + ?fee:Tez.tez -> + consensus_pk:Signature.public_key -> + manager_sk:Client_keys.sk_uri -> + fee_parameter:Injection.fee_parameter -> + Signature.public_key -> + Kind.update_consensus_key Kind.manager Injection.result tzresult Lwt.t + +val drain_delegate : + #Protocol_client_context.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ?confirmations:int -> + ?dry_run:bool -> + ?verbose_signing:bool -> + ?simulation:bool -> + consensus_sk:Client_keys.sk_uri -> + consensus_pkh:Signature.public_key_hash -> + ?destination:Signature.public_key_hash -> + delegate:Signature.public_key_hash -> + unit -> + Kind.drain_delegate Injection.result tzresult Lwt.t + (** Calls {!Injection.inject_manager_operation} with {!Annotated_manager_operation.Single_manager} {!Alpha_context.Set_deposits_limit} [limit_opt] as operation. *) @@ -215,8 +245,14 @@ val register_as_delegate : ?fee:Tez.tez -> manager_sk:Client_keys.sk_uri -> fee_parameter:Injection.fee_parameter -> + ?consensus_pk:public_key -> public_key -> - Kind.delegation Kind.manager Injection.result tzresult Lwt.t + (Kind.delegation Kind.manager Injection.result + * (Kind.update_consensus_key Kind.manager contents + * Kind.update_consensus_key Kind.manager Apply_results.contents_result) + option) + tzresult + Lwt.t (** Calls {!RawContractAlias.add}. *) val save_contract : diff --git a/src/proto_alpha/lib_client/injection.ml b/src/proto_alpha/lib_client/injection.ml index 5006cd403a278676098f3b2fce2ced65b0885a10..6e982c8c9a4aa711407722a3a436ac000e3c6523 100644 --- a/src/proto_alpha/lib_client/injection.ml +++ b/src/proto_alpha/lib_client/injection.ml @@ -316,6 +316,7 @@ let estimated_gas_single (type kind) | Delegation_result {consumed_gas} | Register_global_constant_result {consumed_gas; _} | Set_deposits_limit_result {consumed_gas} + | Update_consensus_key_result {consumed_gas; _} | Increase_paid_storage_result {consumed_gas; _} | Tx_rollup_origination_result {consumed_gas; _} | Tx_rollup_submit_batch_result {consumed_gas; _} @@ -386,6 +387,7 @@ let estimated_storage_single (type kind) ~tx_rollup_origination_size Ok (Z.add paid_storage_size_diff origination_size) | Register_global_constant_result {size_of_constant; _} -> Ok size_of_constant + | Update_consensus_key_result _ -> Ok Z.zero | Tx_rollup_origination_result _ -> Ok tx_rollup_origination_size | Tx_rollup_submit_batch_result {paid_storage_size_diff; _} | Sc_rollup_execute_outbox_message_result {paid_storage_size_diff; _} @@ -493,9 +495,9 @@ let originated_contracts_single (type kind) | Transaction_to_sc_rollup_result _ ) | Register_global_constant_result _ | Reveal_result _ | Delegation_result _ | Set_deposits_limit_result _ - | Increase_paid_storage_result _ | Tx_rollup_origination_result _ - | Tx_rollup_submit_batch_result _ | Tx_rollup_commit_result _ - | Tx_rollup_return_bond_result _ + | Update_consensus_key_result _ | Increase_paid_storage_result _ + | Tx_rollup_origination_result _ | Tx_rollup_submit_batch_result _ + | Tx_rollup_commit_result _ | Tx_rollup_return_bond_result _ | Tx_rollup_finalize_commitment_result _ | Tx_rollup_remove_commitment_result _ | Tx_rollup_rejection_result _ | Tx_rollup_dispatch_tickets_result _ | Transfer_ticket_result _ diff --git a/src/proto_alpha/lib_client/mockup.ml b/src/proto_alpha/lib_client/mockup.ml index 3210b341300794893f6a8b3cf873ee4579689ae0..62ed51f5907664396af9dfcb818e6c1acd4d3b0c 100644 --- a/src/proto_alpha/lib_client/mockup.ml +++ b/src/proto_alpha/lib_client/mockup.ml @@ -107,6 +107,7 @@ module Parsed_account = struct public_key = Some public_key; amount = repr.amount; delegate_to = None; + consensus_key = None; } let default_to_json (cctxt : Tezos_client_base.Client_context.full) : @@ -158,37 +159,17 @@ module Bootstrap_account = struct let encoding : Parameters.bootstrap_account Data_encoding.t = let open Data_encoding in let open Parameters in - union - [ - case - ~title:"No delegate" - (Tag 0) - (obj3 - (req "public_key_hash" Signature.Public_key_hash.encoding) - (opt "public_key" Signature.Public_key.encoding) - (req "amount" Tez.encoding)) - (function - | {public_key_hash; public_key; amount; delegate_to = None} -> - Some (public_key_hash, public_key, amount) - | _ -> None) - (fun (public_key_hash, public_key, amount) -> - {public_key_hash; public_key; amount; delegate_to = None}); - case - ~title:"With delegate" - (Tag 1) - (obj4 - (req "public_key_hash" Signature.Public_key_hash.encoding) - (opt "public_key" Signature.Public_key.encoding) - (req "amount" Tez.encoding) - (req "delegate_to" Signature.Public_key_hash.encoding)) - (function - | {public_key_hash; public_key; amount; delegate_to = Some delegate} - -> - Some (public_key_hash, public_key, amount, delegate) - | _ -> None) - (fun (public_key_hash, public_key, amount, delegate) -> - {public_key_hash; public_key; amount; delegate_to = Some delegate}); - ] + conv + (fun {public_key_hash; public_key; amount; delegate_to; consensus_key} -> + (public_key_hash, public_key, amount, delegate_to, consensus_key)) + (fun (public_key_hash, public_key, amount, delegate_to, consensus_key) -> + {public_key_hash; public_key; amount; delegate_to; consensus_key}) + (obj5 + (req "public_key_hash" Signature.Public_key_hash.encoding) + (opt "public_key" Signature.Public_key.encoding) + (req "amount" Tez.encoding) + (opt "delegate_to" Signature.Public_key_hash.encoding) + (opt "consensus_key" Signature.Public_key.encoding)) end module Bootstrap_contract = struct @@ -245,31 +226,12 @@ module Protocol_parameters = struct end (* This encoding extends [Protocol_constants_overrides.encoding] to allow - reading json files as produced by lib_parameters. Sadly, this require - copying partially [bootstrap_account_encoding], which is not exposed - in parameters_repr.ml. *) + reading json files as produced by lib_parameters. *) let lib_parameters_json_encoding = - let bootstrap_account_encoding = - let open Data_encoding in - conv - (function - | {Parameters.public_key; amount; _} -> ( - match public_key with - | None -> assert false - | Some pk -> (pk, amount))) - (fun (pk, amount) -> - { - Parameters.public_key = Some pk; - public_key_hash = Signature.Public_key.hash pk; - amount; - delegate_to = None; - }) - (tup2 Signature.Public_key.encoding Tez.encoding) - in Data_encoding.( merge_objs (obj2 - (opt "bootstrap_accounts" (list bootstrap_account_encoding)) + (opt "bootstrap_accounts" (list Parameters.bootstrap_account_encoding)) (opt "commitments" (list Commitment.encoding))) Protocol_constants_overrides.encoding) diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index b2d2c3fcf8997572c35c30f589a0648cae9d887c..772e99f5aea791a9f54f3a46e11e54ffac8859d6 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -209,6 +209,12 @@ let pp_manager_operation_content (type kind) source ppf source Contract_hash.pp destination + | Update_consensus_key pk -> + Format.fprintf + ppf + "Update_consensus_key:@,Public key hash: %a" + Signature.Public_key_hash.pp + (Signature.Public_key.hash pk) | Tx_rollup_origination -> Format.fprintf ppf @@ -807,6 +813,7 @@ let pp_manager_operation_contents_result ppf op_result = | Delegation_result _ -> "delegation" | Register_global_constant_result _ -> "global constant registration" | Set_deposits_limit_result _ -> "deposits limit modification" + | Update_consensus_key_result _ -> "consensus key update" | Increase_paid_storage_result _ -> "paid storage increase" | Tx_rollup_origination_result _ -> "transaction rollup origination" | Tx_rollup_submit_batch_result _ -> "transaction rollup batch submission" @@ -844,6 +851,8 @@ let pp_manager_operation_contents_result ppf op_result = | Delegation_result {consumed_gas} -> pp_consumed_gas ppf consumed_gas | Set_deposits_limit_result {consumed_gas} -> pp_consumed_gas ppf consumed_gas + | Update_consensus_key_result {consumed_gas} -> + pp_consumed_gas ppf consumed_gas | Transaction_result tx -> pp_transaction_result ppf tx | Origination_result op_res -> pp_origination_result ppf op_res | Register_global_constant_result _ as op -> @@ -984,8 +993,8 @@ let pp_contents_and_result : pp_balance_updates bus | ( Preendorsement {level; _}, - Preendorsement_result {balance_updates; delegate; preendorsement_power} ) - -> + Preendorsement_result + {balance_updates; delegate; consensus_key; preendorsement_power} ) -> Format.fprintf ppf "@[Preendorsement:@,\ @@ -997,11 +1006,12 @@ let pp_contents_and_result : level pp_balance_updates balance_updates - Signature.Public_key_hash.pp - delegate + Consensus_key.pp + {delegate; consensus_pkh = consensus_key} preendorsement_power | ( Endorsement {level; _}, - Endorsement_result {balance_updates; delegate; endorsement_power} ) -> + Endorsement_result + {balance_updates; delegate; consensus_key; endorsement_power} ) -> Format.fprintf ppf "@[Endorsement:@,\ @@ -1013,8 +1023,8 @@ let pp_contents_and_result : level pp_balance_updates balance_updates - Signature.Public_key_hash.pp - delegate + Consensus_key.pp + {delegate; consensus_pkh = consensus_key} endorsement_power | Dal_slot_availability _, Dal_slot_availability_result {delegate} -> Format.fprintf @@ -1083,6 +1093,24 @@ let pp_contents_and_result : proposal Data_encoding.Json.pp (Data_encoding.Json.construct Vote.ballot_encoding ballot) + | ( Drain_delegate {consensus_key; delegate; destination}, + Drain_delegate_result {balance_updates; allocated_destination_contract} ) + -> + Format.fprintf + ppf + "@[Drain delegate:@,\ + Consensus key hash: %a@,\ + Delegate: %a@,\ + Destination: %a%s%a@]" + Signature.Public_key_hash.pp + consensus_key + Signature.Public_key_hash.pp + delegate + Signature.Public_key_hash.pp + destination + (if allocated_destination_contract then " (allocated)" else "") + pp_balance_updates + balance_updates | Failing_noop _arbitrary, _ -> (* the Failing_noop operation always fails and can't have result *) . diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index 6b01041224a57492813956dcfc8e12b78a48a86e..39b34b34cc9b9e1c596bed061f79d92c8405ba9a 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -1630,6 +1630,150 @@ let commands_rw () = let*! () = cctxt#message "Delegate already activated." in return_unit | Error el -> Lwt.return_error el); + command + ~group + ~desc:"Register the public key hash as a delegate." + (args4 fee_arg dry_run_switch verbose_signing_switch fee_parameter_args) + (prefixes ["register"; "key"] + @@ Public_key_hash.source_param ~name:"mgr" ~desc:"the delegate key" + @@ prefixes ["as"; "delegate"; "with"; "consensus"; "key"] + @@ Public_key.source_param ~name:"key" ~desc:"the consensus key" + @@ stop) + (fun (fee, dry_run, verbose_signing, fee_parameter) + src_pkh + (name_pk, consensus_pk) + cctxt -> + let open Lwt_result_syntax in + let* _, src_pk, src_sk = Client_keys.get_key cctxt src_pkh in + let* consensus_pk = + match consensus_pk with + | Some pk -> return pk + | None -> Client_keys.public_key name_pk + in + let*! r = + register_as_delegate + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~fee_parameter + ~verbose_signing + ?fee + ~manager_sk:src_sk + ~consensus_pk + src_pk + in + match r with + | Ok _ -> return_unit + | Error + [ + Environment.Ecoproto_error + Delegate_storage.Contract.Active_delegate; + ] -> + let*! () = cctxt#message "Delegate already activated." in + return_unit + | Error el -> Lwt.return_error el); + command + ~group + ~desc:"Update the consensus key of a delegate." + (args4 fee_arg dry_run_switch verbose_signing_switch fee_parameter_args) + (prefixes ["set"; "consensus"; "key"; "for"] + @@ Public_key_hash.source_param ~name:"mgr" ~desc:"the delegate key" + @@ prefixes ["to"] + @@ Public_key.source_param ~name:"key" ~desc:"the consensus key" + @@ stop) + (fun (fee, dry_run, verbose_signing, fee_parameter) + delegate_pkh + (name_pk, consensus_pk) + cctxt -> + let open Lwt_result_syntax in + let* _, delegate_pk, delegate_sk = + Client_keys.get_key cctxt delegate_pkh + in + let* consensus_pk = + match consensus_pk with + | Some pk -> return pk + | None -> Client_keys.public_key name_pk + in + let*! r = + update_consensus_key + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~fee_parameter + ~verbose_signing + ?fee + ~consensus_pk + ~manager_sk:delegate_sk + delegate_pk + in + match r with Ok _ -> return_unit | Error el -> Lwt.return_error el); + command + ~group + ~desc:"Drain all funds from a delegate." + (args2 dry_run_switch verbose_signing_switch) + (prefixes ["drain"; "delegate"] + @@ Public_key_hash.source_param ~name:"mgr" ~desc:"the delegate key" + @@ prefixes ["to"] + @@ Public_key_hash.source_param ~name:"key" ~desc:"the consensus key" + @@ stop) + (fun (dry_run, verbose_signing) delegate_pkh consensus_pkh cctxt -> + let open Lwt_result_syntax in + let* _, _consensus_pk, consensus_sk = + Client_keys.get_key cctxt consensus_pkh + in + let*! r = + drain_delegate + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~consensus_pkh + ~consensus_sk + ~delegate:delegate_pkh + () + in + match r with Ok _ -> return_unit | Error el -> Lwt.return_error el); + command + ~group + ~desc:"Drain all funds from a delegate." + (args2 dry_run_switch verbose_signing_switch) + (prefixes ["drain"; "delegate"] + @@ Public_key_hash.source_param ~name:"mgr" ~desc:"the delegate key" + @@ prefixes ["to"] + @@ Public_key_hash.source_param ~name:"key" ~desc:"the destination key" + @@ prefixes ["with"] + @@ Public_key_hash.source_param ~name:"key" ~desc:"the consensus key" + @@ stop) + (fun (dry_run, verbose_signing) + delegate_pkh + destination_pkh + consensus_pkh + cctxt -> + let open Lwt_result_syntax in + let* _, _consensus_pk, consensus_sk = + Client_keys.get_key cctxt consensus_pkh + in + let*! r = + drain_delegate + cctxt + ~chain:cctxt#chain + ~block:cctxt#block + ?confirmations:cctxt#confirmations + ~dry_run + ~verbose_signing + ~consensus_pkh + ~consensus_sk + ~destination:destination_pkh + ~delegate:delegate_pkh + () + in + match r with Ok _ -> return_unit | Error el -> Lwt.return_error el); command ~desc:"Wait until an operation is included in a block" (args3 diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index 58d91acbc7bac687eb2832c160806e5e52d6b5c5..b8a6e51d07a30f1b4a23d343fad7600903d4fd8a 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -117,7 +117,7 @@ type block_kind = type block_to_bake = { predecessor : block_info; round : Round.t; - delegate : Baking_state.delegate; + delegate : Baking_state.consensus_key_and_delegate; kind : block_kind; } @@ -125,11 +125,11 @@ type action = | Do_nothing | Inject_block of {block_to_bake : block_to_bake; updated_state : state} | Inject_preendorsements of { - preendorsements : (delegate * consensus_content) list; + preendorsements : (consensus_key_and_delegate * consensus_content) list; updated_state : state; } | Inject_endorsements of { - endorsements : (delegate * consensus_content) list; + endorsements : (consensus_key_and_delegate * consensus_content) list; updated_state : state; } | Update_to_level of level_update @@ -214,7 +214,9 @@ let sign_block_header state proposer unsigned_block_header = return {Block_header.shell; protocol_data = {contents; signature}} let inject_block ~state_recorder state block_to_bake ~updated_state = - let {predecessor; round; delegate; kind} = block_to_bake in + let {predecessor; round; delegate = (consensus_key, _) as delegate; kind} = + block_to_bake + in let cctxt = state.global_state.cctxt in let chain_id = state.global_state.chain_id in let simulation_mode = state.global_state.validation_mode in @@ -260,7 +262,7 @@ let inject_block ~state_recorder state block_to_bake ~updated_state = >>=? fun injection_level -> generate_seed_nonce_hash state.global_state.config.Baking_configuration.nonce - delegate + consensus_key injection_level >>=? fun seed_nonce_opt -> let seed_nonce_hash = Option.map fst seed_nonce_opt in @@ -308,7 +310,7 @@ let inject_block ~state_recorder state block_to_bake ~updated_state = simulation_kind state.global_state.constants.parametric >>=? fun {unsigned_block_header; operations} -> - sign_block_header state delegate unsigned_block_header + sign_block_header state consensus_key unsigned_block_header >>=? fun signed_block_header -> (match seed_nonce_opt with | None -> @@ -344,7 +346,7 @@ let inject_preendorsements ~state_recorder state ~preendorsements ~updated_state Baking_files.resolve_location ~chain_id `Highwatermarks in List.filter_map_es - (fun (delegate, consensus_content) -> + (fun (((consensus_key, _) as delegate), consensus_content) -> Events.(emit signing_preendorsement delegate) >>= fun () -> let shell = { @@ -355,13 +357,12 @@ let inject_preendorsements ~state_recorder state ~preendorsements ~updated_state let contents = Single (Preendorsement consensus_content) in let level = Raw_level.to_int32 consensus_content.level in let round = consensus_content.round in - let sk_uri = delegate.secret_key_uri in + let sk_uri = consensus_key.secret_key_uri in cctxt#with_lock (fun () -> - let delegate = delegate.public_key_hash in Baking_highwatermarks.may_sign_preendorsement cctxt block_location - ~delegate + ~delegate:consensus_key.public_key_hash ~level ~round >>=? function @@ -369,7 +370,7 @@ let inject_preendorsements ~state_recorder state ~preendorsements ~updated_state Baking_highwatermarks.record_preendorsement cctxt block_location - ~delegate + ~delegate:consensus_key.public_key_hash ~level ~round >>=? fun () -> return_true @@ -430,7 +431,7 @@ let sign_endorsements state endorsements = Baking_files.resolve_location ~chain_id `Highwatermarks in List.filter_map_es - (fun (delegate, consensus_content) -> + (fun (((consensus_key, _) as delegate), consensus_content) -> Events.(emit signing_endorsement delegate) >>= fun () -> let shell = { @@ -444,13 +445,12 @@ let sign_endorsements state endorsements = in let level = Raw_level.to_int32 consensus_content.level in let round = consensus_content.round in - let sk_uri = delegate.secret_key_uri in + let sk_uri = consensus_key.secret_key_uri in cctxt#with_lock (fun () -> - let delegate = delegate.public_key_hash in Baking_highwatermarks.may_sign_endorsement cctxt block_location - ~delegate + ~delegate:consensus_key.public_key_hash ~level ~round >>=? function @@ -458,7 +458,7 @@ let sign_endorsements state endorsements = Baking_highwatermarks.record_endorsement cctxt block_location - ~delegate + ~delegate:consensus_key.public_key_hash ~level ~round >>=? fun () -> return_true diff --git a/src/proto_alpha/lib_delegate/baking_actions.mli b/src/proto_alpha/lib_delegate/baking_actions.mli index 83789e84892f8ec3b83f6af4b7c45d9c02c77b65..da181cda8c3202b695a1e671d5239b9d262c7ee6 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.mli +++ b/src/proto_alpha/lib_delegate/baking_actions.mli @@ -39,7 +39,7 @@ type block_kind = type block_to_bake = { predecessor : block_info; round : Round.t; - delegate : delegate; + delegate : consensus_key_and_delegate; kind : block_kind; } @@ -47,11 +47,11 @@ type action = | Do_nothing | Inject_block of {block_to_bake : block_to_bake; updated_state : state} | Inject_preendorsements of { - preendorsements : (delegate * consensus_content) list; + preendorsements : (consensus_key_and_delegate * consensus_content) list; updated_state : state; } | Inject_endorsements of { - endorsements : (delegate * consensus_content) list; + endorsements : (consensus_key_and_delegate * consensus_content) list; updated_state : state; } | Update_to_level of level_update @@ -75,7 +75,7 @@ type t = action val generate_seed_nonce_hash : Baking_configuration.nonce_config -> - delegate -> + consensus_key -> Level.t -> (Nonce_hash.t * Nonce.t) option tzresult Lwt.t @@ -89,19 +89,19 @@ val inject_block : val inject_preendorsements : state_recorder:(new_state:state -> unit tzresult Lwt.t) -> state -> - preendorsements:(delegate * consensus_content) list -> + preendorsements:(consensus_key_and_delegate * consensus_content) list -> updated_state:state -> state tzresult Lwt.t val sign_endorsements : state -> - (delegate * consensus_content) list -> - (delegate * packed_operation) list tzresult Lwt.t + (consensus_key_and_delegate * consensus_content) list -> + (consensus_key_and_delegate * packed_operation) list tzresult Lwt.t val inject_endorsements : state_recorder:(new_state:state -> unit tzresult Lwt.t) -> state -> - endorsements:(delegate * consensus_content) list -> + endorsements:(consensus_key_and_delegate * consensus_content) list -> updated_state:state -> state tzresult Lwt.t diff --git a/src/proto_alpha/lib_delegate/baking_commands.ml b/src/proto_alpha/lib_delegate/baking_commands.ml index d3c7114872d05ea8682eef653eada03986b1412c..53ac17757e4abe0cfca863b91e0141ebe9ce504a 100644 --- a/src/proto_alpha/lib_delegate/baking_commands.ml +++ b/src/proto_alpha/lib_delegate/baking_commands.ml @@ -202,7 +202,9 @@ let sources_param = Clic.seq_of_param (Client_keys.Public_key_hash.source_param ~name:"baker" - ~desc:"name of the delegate owning the endorsement right") + ~desc: + "name of the delegate owning the endorsement/baking right or name of \ + the consensus key signing on the delegate's behalf") let delegate_commands () : Protocol_client_context.full Clic.command list = let open Clic in diff --git a/src/proto_alpha/lib_delegate/baking_events.ml b/src/proto_alpha/lib_delegate/baking_events.ml index 979c85e0811577a0899842bfc20f4351e83667c4..9bdf35a9fefdce9d720952c45f2cecd08bcbb34a 100644 --- a/src/proto_alpha/lib_delegate/baking_events.ml +++ b/src/proto_alpha/lib_delegate/baking_events.ml @@ -87,8 +87,8 @@ module State_transitions = struct ("level", Data_encoding.int32) ~pp3:Round.pp ("next_round", Round.encoding) - ~pp4:Baking_state.pp_delegate - ("delegate", Baking_state.delegate_encoding) + ~pp4:Baking_state.pp_consensus_key_and_delegate + ("delegate", Baking_state.consensus_key_and_delegate_encoding) let new_head_while_waiting_for_qc = declare_0 @@ -241,8 +241,8 @@ module State_transitions = struct ~name:"proposing_fresh_block" ~level:Info ~msg:"proposing fresh block for {delegate} at round {round}" - ~pp1:Baking_state.pp_delegate - ("delegate", Baking_state.delegate_encoding) + ~pp1:Baking_state.pp_consensus_key_and_delegate + ("delegate", Baking_state.consensus_key_and_delegate_encoding) ~pp2:Round.pp ("round", Round.encoding) @@ -384,8 +384,8 @@ module Scheduling = struct ("round", Round.encoding) ~pp3:Timestamp.pp ("timestamp", Timestamp.encoding) - ~pp4:Baking_state.pp_delegate - ("delegate", Baking_state.delegate_encoding) + ~pp4:Baking_state.pp_consensus_key_and_delegate + ("delegate", Baking_state.consensus_key_and_delegate_encoding) let waiting_end_of_round = declare_3 @@ -499,8 +499,8 @@ module Actions = struct ~name:"skipping_preendorsement" ~level:Error ~msg:"skipping preendorsement for {delegate} -- {trace}" - ~pp1:Baking_state.pp_delegate - ("delegate", Baking_state.delegate_encoding) + ~pp1:Baking_state.pp_consensus_key_and_delegate + ("delegate", Baking_state.consensus_key_and_delegate_encoding) ~pp2:Error_monad.pp_print_trace ("trace", Error_monad.trace_encoding) @@ -510,8 +510,8 @@ module Actions = struct ~name:"skipping_endorsement" ~level:Error ~msg:"skipping endorsement for {delegate} -- {trace}" - ~pp1:Baking_state.pp_delegate - ("delegate", Baking_state.delegate_encoding) + ~pp1:Baking_state.pp_consensus_key_and_delegate + ("delegate", Baking_state.consensus_key_and_delegate_encoding) ~pp2:Error_monad.pp_print_trace ("trace", Error_monad.trace_encoding) @@ -521,8 +521,8 @@ module Actions = struct ~name:"failed_to_inject_preendorsement" ~level:Error ~msg:"failed to inject preendorsement for {delegate} -- {trace}" - ~pp1:Baking_state.pp_delegate - ("delegate", Baking_state.delegate_encoding) + ~pp1:Baking_state.pp_consensus_key_and_delegate + ("delegate", Baking_state.consensus_key_and_delegate_encoding) ~pp2:Error_monad.pp_print_trace ("trace", Error_monad.trace_encoding) @@ -545,8 +545,8 @@ module Actions = struct ~msg:"injected preendorsement {ophash} for {delegate}" ~pp1:Operation_hash.pp ("ophash", Operation_hash.encoding) - ~pp2:Baking_state.pp_delegate - ("delegate", Baking_state.delegate_encoding) + ~pp2:Baking_state.pp_consensus_key_and_delegate + ("delegate", Baking_state.consensus_key_and_delegate_encoding) let endorsement_injected = declare_2 @@ -556,8 +556,8 @@ module Actions = struct ~msg:"injected endorsement {ophash} for {delegate}" ~pp1:Operation_hash.pp ("ophash", Operation_hash.encoding) - ~pp2:Baking_state.pp_delegate - ("delegate", Baking_state.delegate_encoding) + ~pp2:Baking_state.pp_consensus_key_and_delegate + ("delegate", Baking_state.consensus_key_and_delegate_encoding) let synchronizing_round = declare_1 @@ -573,29 +573,26 @@ module Actions = struct ~section ~name:"forging_block" ~level:Info - ~msg: - "forging block at level {level}, round {round} for delegate {delegate}" + ~msg:"forging block at level {level}, round {round} for {delegate}" ~pp1:pp_int32 ~pp2:Round.pp - ~pp3:Baking_state.pp_delegate + ~pp3:Baking_state.pp_consensus_key_and_delegate ("level", Data_encoding.int32) ("round", Round.encoding) - ("delegate", Baking_state.delegate_encoding) + ("delegate", Baking_state.consensus_key_and_delegate_encoding) let injecting_block = declare_3 ~section ~name:"injecting_block" ~level:Debug - ~msg: - "injecting block at level {level}, round {round} for delegate \ - {delegate}" + ~msg:"injecting block at level {level}, round {round} for {delegate}" ~pp1:pp_int32 ~pp2:Round.pp - ~pp3:Baking_state.pp_delegate + ~pp3:Baking_state.pp_consensus_key_and_delegate ("level", Data_encoding.int32) ("round", Round.encoding) - ("delegate", Baking_state.delegate_encoding) + ("delegate", Baking_state.consensus_key_and_delegate_encoding) let block_injected = declare_4 @@ -603,16 +600,15 @@ module Actions = struct ~name:"block_injected" ~level:Notice ~msg: - "block {block} at level {level}, round {round} injected for delegate \ - {delegate}" + "block {block} at level {level}, round {round} injected for {delegate}" ~pp1:Block_hash.pp ~pp2:pp_int32 ~pp3:Round.pp - ~pp4:Baking_state.pp_delegate + ~pp4:Baking_state.pp_consensus_key_and_delegate ("block", Block_hash.encoding) ("level", Data_encoding.int32) ("round", Round.encoding) - ("delegate", Baking_state.delegate_encoding) + ("delegate", Baking_state.consensus_key_and_delegate_encoding) let signing_preendorsement = declare_1 @@ -620,8 +616,8 @@ module Actions = struct ~name:"signing_preendorsement" ~level:Info ~msg:"signing preendorsement for {delegate}" - ~pp1:Baking_state.pp_delegate - ("delegate", Baking_state.delegate_encoding) + ~pp1:Baking_state.pp_consensus_key_and_delegate + ("delegate", Baking_state.consensus_key_and_delegate_encoding) let signing_endorsement = declare_1 @@ -629,8 +625,8 @@ module Actions = struct ~name:"signing_endorsement" ~level:Info ~msg:"signing endorsement for {delegate}" - ~pp1:Baking_state.pp_delegate - ("delegate", Baking_state.delegate_encoding) + ~pp1:Baking_state.pp_consensus_key_and_delegate + ("delegate", Baking_state.consensus_key_and_delegate_encoding) let invalid_json_file = declare_1 diff --git a/src/proto_alpha/lib_delegate/baking_lib.ml b/src/proto_alpha/lib_delegate/baking_lib.ml index 7ef044310a5fcdecef62b38675193170a21d0c21..7ec3ae000cd5f97e8fc8281126379232137dee2a 100644 --- a/src/proto_alpha/lib_delegate/baking_lib.ml +++ b/src/proto_alpha/lib_delegate/baking_lib.ml @@ -80,7 +80,10 @@ let preendorse (cctxt : Protocol_client_context.full) ?(force = false) delegates let*! () = cctxt#message "@[Preendorsing for:@ %a@]" - Format.(pp_print_list ~pp_sep:pp_print_space Baking_state.pp_delegate) + Format.( + pp_print_list + ~pp_sep:pp_print_space + Baking_state.pp_consensus_key_and_delegate) (List.map fst consensus_list) in let state_recorder ~new_state = @@ -117,7 +120,10 @@ let endorse (cctxt : Protocol_client_context.full) ?(force = false) delegates = let*! () = cctxt#message "@[Endorsing for:@ %a@]" - Format.(pp_print_list ~pp_sep:pp_print_space Baking_state.pp_delegate) + Format.( + pp_print_list + ~pp_sep:pp_print_space + Baking_state.pp_consensus_key_and_delegate) (List.map fst consensus_list) in let state_recorder ~new_state = diff --git a/src/proto_alpha/lib_delegate/baking_lib.mli b/src/proto_alpha/lib_delegate/baking_lib.mli index 547822f25d1a878ea38f1216f02d18923b8e31f7..e37f01ac7bb52d7b8d899274fcdb629b5f886674 100644 --- a/src/proto_alpha/lib_delegate/baking_lib.mli +++ b/src/proto_alpha/lib_delegate/baking_lib.mli @@ -37,19 +37,19 @@ val bake : ?extra_operations:Baking_configuration.Operations_source.t -> ?monitor_node_mempool:bool -> ?context_path:string -> - Baking_state.delegate list -> + Baking_state.consensus_key list -> unit tzresult Lwt.t val preendorse : Protocol_client_context.full -> ?force:bool -> - Baking_state.delegate list -> + Baking_state.consensus_key list -> unit tzresult Lwt.t val endorse : Protocol_client_context.full -> ?force:bool -> - Baking_state.delegate list -> + Baking_state.consensus_key list -> unit tzresult Lwt.t val propose : @@ -61,5 +61,5 @@ val propose : ?minimal_timestamp:bool -> ?extra_operations:Baking_configuration.Operations_source.t -> ?context_path:string -> - Baking_state.delegate list -> + Baking_state.consensus_key list -> unit tzresult Lwt.t diff --git a/src/proto_alpha/lib_delegate/baking_nonces.ml b/src/proto_alpha/lib_delegate/baking_nonces.ml index 036226728ef21f69ec29042c674fc85694c1eaa3..76a8bc3dbcfc14e45ff3939bba2f8fe5bfb79852 100644 --- a/src/proto_alpha/lib_delegate/baking_nonces.ml +++ b/src/proto_alpha/lib_delegate/baking_nonces.ml @@ -199,7 +199,7 @@ let get_unrevealed_nonces ({cctxt; chain; _} as state) nonces = (* Nonce creation *) let generate_seed_nonce (nonce_config : Baking_configuration.nonce_config) - (delegate : Baking_state.delegate) level = + (delegate : Baking_state.consensus_key) level = (match nonce_config with | Deterministic -> let data = Data_encoding.Binary.to_bytes_exn Raw_level.encoding level in diff --git a/src/proto_alpha/lib_delegate/baking_nonces.mli b/src/proto_alpha/lib_delegate/baking_nonces.mli index baa6ebf23f188e5ac2e7d04f132af1628a85b626..5151c8909f2479774bbcfa6bce93411fbf8465aa 100644 --- a/src/proto_alpha/lib_delegate/baking_nonces.mli +++ b/src/proto_alpha/lib_delegate/baking_nonces.mli @@ -84,7 +84,7 @@ val get_unrevealed_nonces : val generate_seed_nonce : Baking_configuration.nonce_config -> - Baking_state.delegate -> + Baking_state.consensus_key -> Raw_level.t -> (Nonce_hash.t * Nonce.t) tzresult Lwt.t diff --git a/src/proto_alpha/lib_delegate/baking_scheduling.mli b/src/proto_alpha/lib_delegate/baking_scheduling.mli index a641b7f892fcfbb6af00d462831cc0d65b8d1f88..83e167cfcf3482d062279f06e399b48024204194 100644 --- a/src/proto_alpha/lib_delegate/baking_scheduling.mli +++ b/src/proto_alpha/lib_delegate/baking_scheduling.mli @@ -44,7 +44,9 @@ val wait_next_event : val compute_next_round_time : state -> (Time.Protocol.t * Round.t) option val first_potential_round_at_next_level : - state -> earliest_round:Round.t -> (Round.t * delegate) option + state -> + earliest_round:Round.t -> + (Round.t * consensus_key_and_delegate) option val compute_next_potential_baking_time_at_next_level : state -> (Time.Protocol.t * Round.t) option Lwt.t @@ -58,7 +60,7 @@ val create_initial_state : Baking_configuration.t -> Operation_worker.t -> current_proposal:proposal -> - delegate trace -> + consensus_key list -> state tzresult Lwt.t val compute_bootstrap_event : state -> event tzresult @@ -79,5 +81,5 @@ val run : ?on_error:(tztrace -> unit tzresult Lwt.t) -> chain:Chain_services.chain -> Baking_configuration.t -> - delegate trace -> + consensus_key list -> unit tzresult Lwt.t diff --git a/src/proto_alpha/lib_delegate/baking_state.ml b/src/proto_alpha/lib_delegate/baking_state.ml index bde813946509e0bf9795bf760948440c29aa1125..5e87c78b4efd56d9f36c513090bbe87ca065f3b2 100644 --- a/src/proto_alpha/lib_delegate/baking_state.ml +++ b/src/proto_alpha/lib_delegate/baking_state.ml @@ -27,16 +27,16 @@ open Protocol open Alpha_context open Protocol_client_context -(** A delegate (aka, a validator) is identified by its alias name, its +(** A consensus key (aka, a validator) is identified by its alias name, its public key, its public key hash, and its secret key. *) -type delegate = { +type consensus_key = { alias : string option; public_key : Signature.Public_key.t; public_key_hash : Signature.Public_key_hash.t; secret_key_uri : Client_keys.sk_uri; } -let delegate_encoding = +let consensus_key_encoding = let open Data_encoding in conv (fun {alias; public_key; public_key_hash; secret_key_uri} -> @@ -60,7 +60,7 @@ let delegate_encoding = (req "public_key_hash" Signature.Public_key_hash.encoding) (req "secret_key_uri" string)) -let pp_delegate fmt {alias; public_key_hash; _} = +let pp_consensus_key fmt {alias; public_key_hash; _} = match alias with | None -> Format.fprintf fmt "%a" Signature.Public_key_hash.pp public_key_hash | Some alias -> @@ -71,6 +71,26 @@ let pp_delegate fmt {alias; public_key_hash; _} = Signature.Public_key_hash.pp public_key_hash +type consensus_key_and_delegate = consensus_key * Signature.Public_key_hash.t + +let consensus_key_and_delegate_encoding = + let open Data_encoding in + merge_objs + consensus_key_encoding + (obj1 (req "delegate" Signature.Public_key_hash.encoding)) + +let pp_consensus_key_and_delegate fmt (consensus_key, delegate) = + if Signature.Public_key_hash.equal consensus_key.public_key_hash delegate then + pp_consensus_key fmt consensus_key + else + Format.fprintf + fmt + "%a@,on behalf of %a" + pp_consensus_key + consensus_key + Signature.Public_key_hash.pp + delegate + type validation_mode = Node | Local of Abstract_context_index.t type prequorum = { @@ -97,7 +117,7 @@ type block_info = { type cache = { known_timestamps : Timestamp.time Baking_cache.Timestamp_of_round_cache.t; round_timestamps : - (Timestamp.time * Round.t * delegate) + (Timestamp.time * Round.t * consensus_key_and_delegate) Baking_cache.Round_timestamp_interval_cache.t; } @@ -117,7 +137,7 @@ type global_state = { (* the validation mode used by the baker*) validation_mode : validation_mode; (* the delegates on behalf of which the baker is running *) - delegates : delegate list; + delegates : consensus_key list; cache : cache; } @@ -216,11 +236,7 @@ module SlotMap : Map.S with type key = Slot.t = Map.Make (Slot) list of slots (i.e., a list of position indexes in the slot map, in other words the list of rounds when it will be the proposer), and its endorsing power. *) -type endorsing_slot = { - delegate : Signature.Public_key_hash.t; - slots : Slot.t list; - endorsing_power : int; -} +type endorsing_slot = {slots : Slot.t list; endorsing_power : int} (* FIXME: determine if the slot map should contain all slots or just the first one *) @@ -229,7 +245,7 @@ type endorsing_slot = { type delegate_slots = { (* be careful not to duplicate endorsing slots with different slots keys: always use the first slot in the slots list *) - own_delegate_slots : (delegate * endorsing_slot) SlotMap.t; + own_delegate_slots : (consensus_key_and_delegate * endorsing_slot) SlotMap.t; all_delegate_slots : endorsing_slot SlotMap.t; all_slots_by_round : Slot.t array; } @@ -576,7 +592,7 @@ let may_load_endorsable_data state = module DelegateSet = struct include Set.Make (struct - type t = delegate + type t = consensus_key let compare {public_key_hash = pkh; _} {public_key_hash = pkh'; _} = Signature.Public_key_hash.compare pkh pkh' @@ -606,10 +622,8 @@ let compute_delegate_slots (cctxt : Protocol_client_context.full) let own_delegate_slots, all_delegate_slots = List.fold_left (fun (own_map, all_map) slot -> - let {Plugin.RPC.Validators.delegate; slots; _} = slot in - let endorsing_slot = - {endorsing_power = List.length slots; delegate; slots} - in + let {Plugin.RPC.Validators.consensus_key; delegate; slots; _} = slot in + let endorsing_slot = {endorsing_power = List.length slots; slots} in let all_map = List.fold_left (fun all_map slot -> SlotMap.add slot endorsing_slot all_map) @@ -617,11 +631,14 @@ let compute_delegate_slots (cctxt : Protocol_client_context.full) slots in let own_map = - match DelegateSet.find_pkh delegate own_delegates with - | Some delegate -> + match DelegateSet.find_pkh consensus_key own_delegates with + | Some consensus_key -> List.fold_left (fun own_map slot -> - SlotMap.add slot (delegate, endorsing_slot) own_map) + SlotMap.add + slot + ((consensus_key, delegate), endorsing_slot) + own_map) own_map slots | None -> own_map @@ -659,7 +676,7 @@ let pp_global_state fmt {chain_id; config; validation_mode; delegates; _} = config pp_validation_mode validation_mode - Format.(pp_print_list pp_delegate) + Format.(pp_print_list pp_consensus_key) delegates let pp_option pp fmt = function @@ -740,14 +757,15 @@ let pp_elected_block fmt {proposal; endorsement_qc} = proposal.block (List.length endorsement_qc) -let pp_endorsing_slot fmt (delegate, {delegate = _; slots; endorsing_power}) = +let pp_endorsing_slot fmt (consensus_key_and_delegate, {slots; endorsing_power}) + = Format.fprintf fmt "slots: @[[%a]@],@ delegate: %a,@ endorsing_power: %d" Format.(pp_print_list ~pp_sep:pp_print_space Slot.pp) slots - pp_delegate - delegate + pp_consensus_key_and_delegate + consensus_key_and_delegate endorsing_power let pp_delegate_slots fmt {own_delegate_slots; _} = diff --git a/src/proto_alpha/lib_delegate/baking_state.mli b/src/proto_alpha/lib_delegate/baking_state.mli index 45f325e509d1f639f2deba659e1cca266cefe0fe..3650fc322708918338caddcaf197b0a4c7eaf048 100644 --- a/src/proto_alpha/lib_delegate/baking_state.mli +++ b/src/proto_alpha/lib_delegate/baking_state.mli @@ -26,16 +26,24 @@ open Protocol open Alpha_context -type delegate = { +type consensus_key = { alias : string option; public_key : Signature.public_key; public_key_hash : Signature.public_key_hash; secret_key_uri : Client_keys.sk_uri; } -val delegate_encoding : delegate Data_encoding.t +val consensus_key_encoding : consensus_key Data_encoding.t -val pp_delegate : Format.formatter -> delegate -> unit +val pp_consensus_key : Format.formatter -> consensus_key -> unit + +type consensus_key_and_delegate = consensus_key * Signature.Public_key_hash.t + +val consensus_key_and_delegate_encoding : + consensus_key_and_delegate Data_encoding.t + +val pp_consensus_key_and_delegate : + Format.formatter -> consensus_key_and_delegate -> unit type validation_mode = Node | Local of Abstract_context_index.t @@ -65,7 +73,7 @@ type block_info = { type cache = { known_timestamps : Timestamp.time Baking_cache.Timestamp_of_round_cache.t; round_timestamps : - (Timestamp.time * Round.t * delegate) + (Timestamp.time * Round.t * consensus_key_and_delegate) Baking_cache.Round_timestamp_interval_cache.t; } @@ -77,7 +85,7 @@ type global_state = { round_durations : Round.round_durations; operation_worker : Operation_worker.t; validation_mode : validation_mode; - delegates : delegate list; + delegates : consensus_key list; cache : cache; } @@ -87,14 +95,10 @@ val round_of_shell_header : Block_header.shell_header -> Round.t tzresult module SlotMap : Map.S with type key = Slot.t -type endorsing_slot = { - delegate : Signature.public_key_hash; - slots : Slot.t trace; - endorsing_power : int; -} +type endorsing_slot = {slots : Slot.t list; endorsing_power : int} type delegate_slots = { - own_delegate_slots : (delegate * endorsing_slot) SlotMap.t; + own_delegate_slots : (consensus_key_and_delegate * endorsing_slot) SlotMap.t; all_delegate_slots : endorsing_slot SlotMap.t; all_slots_by_round : Slot.t array; } @@ -189,7 +193,7 @@ val compute_delegate_slots : ?block:Block_services.block -> level:int32 -> chain:Shell_services.chain -> - delegate list -> + consensus_key list -> delegate_slots tzresult Lwt.t val create_cache : unit -> cache @@ -211,7 +215,8 @@ val pp_endorsable_payload : Format.formatter -> endorsable_payload -> unit val pp_elected_block : Format.formatter -> elected_block -> unit -val pp_endorsing_slot : Format.formatter -> delegate * endorsing_slot -> unit +val pp_endorsing_slot : + Format.formatter -> consensus_key_and_delegate * endorsing_slot -> unit val pp_delegate_slots : Format.formatter -> delegate_slots -> unit diff --git a/src/proto_alpha/lib_delegate/client_baking_denunciation.ml b/src/proto_alpha/lib_delegate/client_baking_denunciation.ml index 4f36381313075b1a4ffa8331938dccb2d3cecc10..2ebc4af5961ebbaaaca22a8a95d8ebd310d291f0 100644 --- a/src/proto_alpha/lib_delegate/client_baking_denunciation.ml +++ b/src/proto_alpha/lib_delegate/client_baking_denunciation.ml @@ -264,13 +264,13 @@ let process_block (cctxt : #Protocol_client_context.full) state Option.value ~default:Delegate_Map.empty @@ HLevel.find state.blocks_table (chain_id, level, round) in - match Delegate_Map.find baker map with + match Delegate_Map.find baker.delegate map with | None -> return @@ HLevel.add state.blocks_table (chain_id, level, round) - (Delegate_Map.add baker new_hash map) + (Delegate_Map.add baker.delegate new_hash map) | Some existing_hash when Block_hash.(existing_hash = new_hash) -> (* This case should never happen *) Events.(emit double_baking_but_not) () >>= fun () -> @@ -278,7 +278,7 @@ let process_block (cctxt : #Protocol_client_context.full) state @@ HLevel.replace state.blocks_table (chain_id, level, round) - (Delegate_Map.add baker new_hash map) + (Delegate_Map.add baker.delegate new_hash map) | Some existing_hash -> (* If a previous block made by this pkh is found for the same (level, round) we inject a double_baking_evidence *) @@ -310,7 +310,7 @@ let process_block (cctxt : #Protocol_client_context.full) state @@ HLevel.replace state.blocks_table (chain_id, level, round) - (Delegate_Map.add baker new_hash map)) + (Delegate_Map.add baker.delegate new_hash map)) (* Remove levels that are lower than the [highest_level_encountered] minus [preserved_levels] *) diff --git a/src/proto_alpha/lib_delegate/client_daemon.mli b/src/proto_alpha/lib_delegate/client_daemon.mli index 7402d94880ee29377aff4c38b690667a7b9d3c1a..751db505885762e8ed46ee7c1d52947b4ca4c96a 100644 --- a/src/proto_alpha/lib_delegate/client_daemon.mli +++ b/src/proto_alpha/lib_delegate/client_daemon.mli @@ -39,7 +39,7 @@ module Baker : sig chain:Shell_services.chain -> context_path:string -> keep_alive:bool -> - Baking_state.delegate list -> + Baking_state.consensus_key list -> unit tzresult Lwt.t end diff --git a/src/proto_alpha/lib_delegate/state_transitions.ml b/src/proto_alpha/lib_delegate/state_transitions.ml index dd978072e535c5c9e5f04c1944b05bda45151b7d..6e8dd27e628468da9c64a5493c1d137d5a965e28 100644 --- a/src/proto_alpha/lib_delegate/state_transitions.ml +++ b/src/proto_alpha/lib_delegate/state_transitions.ml @@ -79,8 +79,8 @@ let make_consensus_list state proposal = let round = proposal.block.round in let block_payload_hash = proposal.block.payload_hash in SlotMap.fold - (fun _slot (delegate, slots) acc -> - ( delegate, + (fun _slot (consensus_key_and_delegate, slots) acc -> + ( consensus_key_and_delegate, {slot = Stdlib.List.hd slots.slots; level; round; block_payload_hash} ) :: acc) state.level_state.delegate_slots.own_delegate_slots @@ -96,7 +96,7 @@ let make_preendorse_action state proposal = in {state with round_state} in - let preendorsements : (delegate * consensus_content) list = + let preendorsements : (consensus_key_and_delegate * consensus_content) list = make_consensus_list state proposal in Inject_preendorsements {preendorsements; updated_state} @@ -598,7 +598,7 @@ let make_endorse_action state proposal = proposal.block.round proposal.block.payload_hash in - let endorsements : (delegate * consensus_content) list = + let endorsements : (consensus_key_and_delegate * consensus_content) list = make_consensus_list state proposal in Inject_endorsements {endorsements; updated_state} diff --git a/src/proto_alpha/lib_delegate/state_transitions.mli b/src/proto_alpha/lib_delegate/state_transitions.mli index 4b14864cb1de36a6cc8f3d828ace4cbc8fb735cd..9dde0efaf02bba9e9c9ca327a709020e226757e3 100644 --- a/src/proto_alpha/lib_delegate/state_transitions.mli +++ b/src/proto_alpha/lib_delegate/state_transitions.mli @@ -36,7 +36,7 @@ val is_acceptable_proposal_for_current_level : state -> proposal -> proposal_acceptance Lwt.t val make_consensus_list : - state -> proposal -> (delegate * consensus_content) list + state -> proposal -> (consensus_key_and_delegate * consensus_content) list val make_preendorse_action : state -> proposal -> action @@ -51,21 +51,21 @@ val handle_new_proposal : state -> proposal -> (state * action) Lwt.t val round_proposer : state -> - (delegate * endorsing_slot) SlotMap.t -> + (consensus_key_and_delegate * endorsing_slot) SlotMap.t -> Round.t -> - (delegate * endorsing_slot) option + (consensus_key_and_delegate * endorsing_slot) option val propose_fresh_block_action : endorsements:Kind.endorsement Operation.t list -> ?last_proposal:block_info -> predecessor:block_info -> state -> - delegate -> + consensus_key_and_delegate -> Round.t -> action Lwt.t val propose_block_action : - state -> delegate -> Round.t -> proposal -> action Lwt.t + state -> consensus_key_and_delegate -> Round.t -> proposal -> action Lwt.t (** Increase the current round and propose at the new round (same level), if the baker has a proposer slot. *) diff --git a/src/proto_alpha/lib_delegate/test/mockup_simulator/mockup_simulator.ml b/src/proto_alpha/lib_delegate/test/mockup_simulator/mockup_simulator.ml index 0af160aed4a363d0e7e9a5bffce657126e89accc..48ba5170d77f5208a054d2c7f43c23182f6bc1cf 100644 --- a/src/proto_alpha/lib_delegate/test/mockup_simulator/mockup_simulator.ml +++ b/src/proto_alpha/lib_delegate/test/mockup_simulator/mockup_simulator.ml @@ -135,7 +135,7 @@ module type Hooks = sig val on_start_baker : baker_position:int -> - delegates:Baking_state.delegate list -> + delegates:Baking_state.consensus_key list -> cctxt:Protocol_client_context.full -> unit Lwt.t @@ -738,7 +738,7 @@ let create_fake_node_state ~i ~live_depth } (** Start baker process. *) -let baker_process ~(delegates : Baking_state.delegate list) ~base_dir +let baker_process ~(delegates : Baking_state.consensus_key list) ~base_dir ~(genesis_block : Block_header.t * Tezos_protocol_environment.rpc_context) ~i ~global_chain_table ~broadcast_pipes ~(user_hooks : (module Hooks)) = let broadcast_pipe = @@ -766,7 +766,7 @@ let baker_process ~(delegates : Baking_state.delegate list) ~base_dir User_hooks.on_start_baker ~baker_position:i ~delegates ~cctxt >>= fun () -> List.iter_es (fun ({alias; public_key; public_key_hash; secret_key_uri} : - Baking_state.delegate) -> + Baking_state.consensus_key) -> let open Tezos_client_base in let name = alias |> WithExceptions.Option.get ~loc:__LOC__ in Client_keys.neuterize secret_key_uri >>=? fun public_key_uri -> @@ -1064,7 +1064,7 @@ let default_config = let make_baking_delegate ( (account : Alpha_context.Parameters.bootstrap_account), (secret : Tezos_mockup_commands.Mockup_wallet.bootstrap_secret) ) : - Baking_state.delegate = + Baking_state.consensus_key = Baking_state. { alias = Some secret.name; diff --git a/src/proto_alpha/lib_delegate/test/mockup_simulator/mockup_simulator.mli b/src/proto_alpha/lib_delegate/test/mockup_simulator/mockup_simulator.mli index b2119bf6d1771d7db9446247d7ae4366af408d15..57d24764bc7cf408f310ab6ddf26669a67699ec6 100644 --- a/src/proto_alpha/lib_delegate/test/mockup_simulator/mockup_simulator.mli +++ b/src/proto_alpha/lib_delegate/test/mockup_simulator/mockup_simulator.mli @@ -116,7 +116,7 @@ module type Hooks = sig bakers that were started for this run. *) val on_start_baker : baker_position:int -> - delegates:Baking_state.delegate list -> + delegates:Baking_state.consensus_key list -> cctxt:Protocol_client_context.full -> unit Lwt.t diff --git a/src/proto_alpha/lib_delegate/test/tenderbrute/lib/tenderbrute.ml b/src/proto_alpha/lib_delegate/test/tenderbrute/lib/tenderbrute.ml index fa99d708a0a1bd7ed9ffc107f7efbcf63c12d552..ce3f8bba638032e0e0d5ca935d40cf774956ea05 100644 --- a/src/proto_alpha/lib_delegate/test/tenderbrute/lib/tenderbrute.ml +++ b/src/proto_alpha/lib_delegate/test/tenderbrute/lib/tenderbrute.ml @@ -102,8 +102,9 @@ let check ctxt ~selection = (fun (level, round) delegate ctxt -> Delegate_sampler.baking_rights_owner ctxt level ~round >|= Environment.wrap_tzresult - >>=? fun (ctxt, _, (_, pkh)) -> - if not (Signature.Public_key_hash.equal delegate pkh) then raise Exit + >>=? fun (ctxt, _, pk) -> + if not (Signature.Public_key_hash.equal delegate pk.delegate) then + raise Exit else return ctxt) selection ctxt diff --git a/src/proto_alpha/lib_injector/l1_operation.ml b/src/proto_alpha/lib_injector/l1_operation.ml index b2630b179ca22c3eb5f62c3f52fc473f9db39aff..e9cdbaa5e87d37d3ddb310630b3f6c5165043ce4 100644 --- a/src/proto_alpha/lib_injector/l1_operation.ml +++ b/src/proto_alpha/lib_injector/l1_operation.ml @@ -85,6 +85,7 @@ module Manager_operation = struct | Register_global_constant _ -> register_global_constant_case | Set_deposits_limit _ -> set_deposits_limit_case | Increase_paid_storage _ -> increase_paid_storage_case + | Update_consensus_key _ -> update_consensus_key_case | Tx_rollup_origination -> tx_rollup_origination_case | Tx_rollup_submit_batch _ -> tx_rollup_submit_batch_case | Tx_rollup_commit _ -> tx_rollup_commit_case diff --git a/src/proto_alpha/lib_parameters/default_parameters.ml b/src/proto_alpha/lib_parameters/default_parameters.ml index ad36f967164fd44f7a048790065d885aca401264..1e71aca49e0b516e2030a9857de97db9336da6f4 100644 --- a/src/proto_alpha/lib_parameters/default_parameters.ml +++ b/src/proto_alpha/lib_parameters/default_parameters.ml @@ -376,12 +376,20 @@ let compute_accounts = public_key = Some public_key; amount = bootstrap_balance; delegate_to = None; + consensus_key = None; }) let bootstrap_accounts = compute_accounts bootstrap_accounts_strings -let make_bootstrap_account (pkh, pk, amount, delegate_to) = - Parameters.{public_key_hash = pkh; public_key = Some pk; amount; delegate_to} +let make_bootstrap_account (pkh, pk, amount, delegate_to, consensus_key) = + Parameters. + { + public_key_hash = pkh; + public_key = Some pk; + amount; + delegate_to; + consensus_key; + } let parameters_of_constants ?(bootstrap_accounts = bootstrap_accounts) ?(bootstrap_contracts = []) ?(commitments = []) constants = diff --git a/src/proto_alpha/lib_parameters/default_parameters.mli b/src/proto_alpha/lib_parameters/default_parameters.mli index 8aeb40866526a57d5e4230bd9879609a7c8f61d4..eff7da67497223993fdcca88bfbf31ac7066a7a4 100644 --- a/src/proto_alpha/lib_parameters/default_parameters.mli +++ b/src/proto_alpha/lib_parameters/default_parameters.mli @@ -38,7 +38,8 @@ val make_bootstrap_account : Signature.public_key_hash * Signature.public_key * Tez.t - * Signature.public_key_hash option -> + * Signature.public_key_hash option + * Signature.public_key option -> Parameters.bootstrap_account val parameters_of_constants : diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index 976aab814a247b1877e7040486d8897d1eba01d2..94b2c9a6d001df7e6c498710f0c5b5d6876f5655 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -2777,7 +2777,8 @@ let requested_levels ~default_level ctxt cycles levels = module Baking_rights = struct type t = { level : Raw_level.t; - delegate : Signature.Public_key_hash.t; + delegate : public_key_hash; + consensus_key : public_key_hash; round : int; timestamp : Timestamp.t option; } @@ -2785,15 +2786,16 @@ module Baking_rights = struct let encoding = let open Data_encoding in conv - (fun {level; delegate; round; timestamp} -> - (level, delegate, round, timestamp)) - (fun (level, delegate, round, timestamp) -> - {level; delegate; round; timestamp}) - (obj4 + (fun {level; delegate; consensus_key; round; timestamp} -> + (level, delegate, round, timestamp, consensus_key)) + (fun (level, delegate, round, timestamp, consensus_key) -> + {level; delegate; consensus_key; round; timestamp}) + (obj5 (req "level" Raw_level.encoding) (req "delegate" Signature.Public_key_hash.encoding) (req "round" uint16) - (opt "estimated_time" Timestamp.encoding)) + (opt "estimated_time" Timestamp.encoding) + (req "consensus_key" Signature.Public_key_hash.encoding)) let default_max_round = 64 @@ -2806,18 +2808,21 @@ module Baking_rights = struct levels : Raw_level.t list; cycle : Cycle.t option; delegates : Signature.Public_key_hash.t list; + consensus_keys : Signature.Public_key_hash.t list; max_round : int option; all : bool; } let baking_rights_query = let open RPC_query in - query (fun levels cycle delegates max_round all -> - {levels; cycle; delegates; max_round; all}) + query (fun levels cycle delegates consensus_keys max_round all -> + {levels; cycle; delegates; consensus_keys; max_round; all}) |+ multi_field "level" Raw_level.rpc_arg (fun t -> t.levels) |+ opt_field "cycle" Cycle.rpc_arg (fun t -> t.cycle) |+ multi_field "delegate" Signature.Public_key_hash.rpc_arg (fun t -> t.delegates) + |+ multi_field "consensus_key" Signature.Public_key_hash.rpc_arg (fun t -> + t.consensus_keys) |+ opt_field "max_round" RPC_arg.uint (fun t -> t.max_round) |+ flag "all" (fun t -> t.all) |> seal @@ -2834,9 +2839,10 @@ module Baking_rights = struct (valid) level(s) in the past or future at which the baking \ rights have to be returned.\n\ Parameter `delegate` can be used to restrict the results to the \ - given delegates. If parameter `all` is set, all the baking \ - opportunities for each baker at each level are returned, instead \ - of just the first one.\n\ + given delegates. Parameter `consensus_key` can be used to \ + restrict the results to the given consensus_keys. If parameter \ + `all` is set, all the baking opportunities for each baker at \ + each level are returned, instead of just the first one.\n\ Returns the list of baking opportunities up to round %d. Also \ returns the minimal timestamps that correspond to these \ opportunities. The timestamps are omitted for levels in the \ @@ -2859,8 +2865,7 @@ module Baking_rights = struct let rec loop l acc round = if Compare.Int.(round > max_round) then return (List.rev acc) else - let (Misc.LCons (pk, next)) = l in - let delegate = Signature.Public_key.hash pk in + let (Misc.LCons ({Consensus_key.consensus_pkh; delegate}, next)) = l in estimated_time round_durations ~current_level @@ -2869,7 +2874,16 @@ module Baking_rights = struct ~level ~round >>?= fun timestamp -> - let acc = {level = level.level; delegate; round; timestamp} :: acc in + let acc = + { + level = level.level; + delegate; + consensus_key = consensus_pkh; + round; + timestamp; + } + :: acc + in next () >>=? fun l -> loop l acc (round + 1) in loop delegates [] 0 @@ -2911,27 +2925,44 @@ module Baking_rights = struct if q.all then List.concat rights else List.concat_map remove_duplicated_delegates rights in - match q.delegates with - | [] -> rights - | _ :: _ as delegates -> - let is_requested p = - List.exists (Signature.Public_key_hash.equal p.delegate) delegates - in - List.filter is_requested rights) + let rights = + match q.delegates with + | [] -> rights + | _ :: _ as delegates -> + let is_requested p = + List.exists + (Signature.Public_key_hash.equal p.delegate) + delegates + in + List.filter is_requested rights + in + let rights = + match q.consensus_keys with + | [] -> rights + | _ :: _ as delegates -> + let is_requested p = + List.exists + (Signature.Public_key_hash.equal p.consensus_key) + delegates + in + List.filter is_requested rights + in + rights) - let get ctxt ?(levels = []) ?cycle ?(delegates = []) ?(all = false) ?max_round - block = + let get ctxt ?(levels = []) ?cycle ?(delegates = []) ?(consensus_keys = []) + ?(all = false) ?max_round block = RPC_context.make_call0 S.baking_rights ctxt block - {levels; cycle; delegates; max_round; all} + {levels; cycle; delegates; consensus_keys; max_round; all} () end module Endorsing_rights = struct type delegate_rights = { delegate : Signature.Public_key_hash.t; + consensus_key : Signature.Public_key_hash.t; first_slot : Slot.t; endorsing_power : int; } @@ -2945,14 +2976,15 @@ module Endorsing_rights = struct let delegate_rights_encoding = let open Data_encoding in conv - (fun {delegate; first_slot; endorsing_power} -> - (delegate, first_slot, endorsing_power)) - (fun (delegate, first_slot, endorsing_power) -> - {delegate; first_slot; endorsing_power}) - (obj3 + (fun {delegate; consensus_key; first_slot; endorsing_power} -> + (delegate, first_slot, endorsing_power, consensus_key)) + (fun (delegate, first_slot, endorsing_power, consensus_key) -> + {delegate; first_slot; endorsing_power; consensus_key}) + (obj4 (req "delegate" Signature.Public_key_hash.encoding) (req "first_slot" Slot.encoding) - (req "endorsing_power" uint16)) + (req "endorsing_power" uint16) + (req "consensus_key" Signature.Public_key_hash.encoding)) let encoding = let open Data_encoding in @@ -2975,15 +3007,19 @@ module Endorsing_rights = struct levels : Raw_level.t list; cycle : Cycle.t option; delegates : Signature.Public_key_hash.t list; + consensus_keys : Signature.Public_key_hash.t list; } let endorsing_rights_query = let open RPC_query in - query (fun levels cycle delegates -> {levels; cycle; delegates}) + query (fun levels cycle delegates consensus_keys -> + {levels; cycle; delegates; consensus_keys}) |+ multi_field "level" Raw_level.rpc_arg (fun t -> t.levels) |+ opt_field "cycle" Cycle.rpc_arg (fun t -> t.cycle) |+ multi_field "delegate" Signature.Public_key_hash.rpc_arg (fun t -> t.delegates) + |+ multi_field "consensus_key" Signature.Public_key_hash.rpc_arg (fun t -> + t.consensus_keys) |> seal let endorsing_rights = @@ -2996,6 +3032,8 @@ module Endorsing_rights = struct level(s) in the past or future at which the endorsing rights have \ to be returned. Parameter `delegate` can be used to restrict the \ results to the given delegates.\n\ + Parameter `consensus_key` can be used to restrict the results to \ + the given consensus_keys. \n\ Returns the smallest endorsing slots and the endorsing power. Also \ returns the minimal timestamp that corresponds to endorsing at the \ given level. The timestamps are omitted for levels in the past, and \ @@ -3023,8 +3061,15 @@ module Endorsing_rights = struct >>?= fun estimated_time -> let rights = Slot.Map.fold - (fun first_slot (_pk, delegate, endorsing_power) acc -> - {delegate; first_slot; endorsing_power} :: acc) + (fun first_slot + ( { + Consensus_key.delegate; + consensus_pk = _; + consensus_pkh = consensus_key; + }, + endorsing_power ) + acc -> + {delegate; consensus_key; first_slot; endorsing_power} :: acc) rights [] in @@ -3042,30 +3087,34 @@ module Endorsing_rights = struct in List.map_es (endorsing_rights_at_level ctxt) levels >|=? fun rights_per_level -> - match q.delegates with - | [] -> rights_per_level - | _ :: _ as delegates -> - List.filter_map - (fun rights_at_level -> - let is_requested p = - List.exists - (Signature.Public_key_hash.equal p.delegate) - delegates - in - match - List.filter is_requested rights_at_level.delegates_rights - with - | [] -> None - | delegates_rights -> - Some {rights_at_level with delegates_rights}) - rights_per_level) - - let get ctxt ?(levels = []) ?cycle ?(delegates = []) block = + let rights_per_level = + match q.consensus_keys with + | [] -> rights_per_level + | _ :: _ as consensus_keys -> + List.filter_map + (fun rights_at_level -> + let is_requested p = + List.exists + (Signature.Public_key_hash.equal p.consensus_key) + consensus_keys + in + match + List.filter is_requested rights_at_level.delegates_rights + with + | [] -> None + | delegates_rights -> + Some {rights_at_level with delegates_rights}) + rights_per_level + in + rights_per_level) + + let get ctxt ?(levels = []) ?cycle ?(delegates = []) ?(consensus_keys = []) + block = RPC_context.make_call0 S.endorsing_rights ctxt block - {levels; cycle; delegates} + {levels; cycle; delegates; consensus_keys} () end @@ -3073,18 +3122,22 @@ module Validators = struct type t = { level : Raw_level.t; delegate : Signature.Public_key_hash.t; + consensus_key : Signature.public_key_hash; slots : Slot.t list; } let encoding = let open Data_encoding in conv - (fun {level; delegate; slots} -> (level, delegate, slots)) - (fun (level, delegate, slots) -> {level; delegate; slots}) - (obj3 + (fun {level; delegate; consensus_key; slots} -> + (level, delegate, slots, consensus_key)) + (fun (level, delegate, slots, consensus_key) -> + {level; delegate; consensus_key; slots}) + (obj4 (req "level" Raw_level.encoding) (req "delegate" Signature.Public_key_hash.encoding) - (req "slots" (list Slot.encoding))) + (req "slots" (list Slot.encoding)) + (req "consensus_key" Signature.Public_key_hash.encoding)) module S = struct open Data_encoding @@ -3094,14 +3147,18 @@ module Validators = struct type validators_query = { levels : Raw_level.t list; delegates : Signature.Public_key_hash.t list; + consensus_keys : Signature.Public_key_hash.t list; } let validators_query = let open RPC_query in - query (fun levels delegates -> {levels; delegates}) + query (fun levels delegates consensus_keys -> + {levels; delegates; consensus_keys}) |+ multi_field "level" Raw_level.rpc_arg (fun t -> t.levels) |+ multi_field "delegate" Signature.Public_key_hash.rpc_arg (fun t -> t.delegates) + |+ multi_field "consensus_key" Signature.Public_key_hash.rpc_arg (fun t -> + t.consensus_keys) |> seal let validators = @@ -3113,7 +3170,8 @@ module Validators = struct Parameter `level` can be used to specify the (valid) level(s) in \ the past or future at which the endorsement rights have to be \ returned. Parameter `delegate` can be used to restrict the results \ - to the given delegates.\n" + results to the given delegates. Parameter `consensus_key` can be \ + used to restrict the results to the given consensus_keys.\n" ~query:validators_query ~output:(list encoding) path @@ -3122,8 +3180,9 @@ module Validators = struct let endorsing_slots_at_level ctxt level = Baking.endorsing_rights ctxt level >|=? fun (_, rights) -> Signature.Public_key_hash.Map.fold - (fun delegate slots acc -> {level = level.level; delegate; slots} :: acc) - (rights :> Slot.t list Signature.Public_key_hash.Map.t) + (fun _pkh {Baking.delegate; consensus_key; slots} acc -> + {level = level.level; delegate; consensus_key; slots} :: acc) + rights [] let register () = @@ -3133,16 +3192,37 @@ module Validators = struct in List.concat_map_es (endorsing_slots_at_level ctxt) levels >|=? fun rights -> - match q.delegates with - | [] -> rights - | _ :: _ as delegates -> - let is_requested p = - List.exists (Signature.Public_key_hash.equal p.delegate) delegates - in - List.filter is_requested rights) + let rights = + match q.delegates with + | [] -> rights + | _ :: _ as delegates -> + let is_requested p = + List.exists + (Signature.Public_key_hash.equal p.delegate) + delegates + in + List.filter is_requested rights + in + let rights = + match q.consensus_keys with + | [] -> rights + | _ :: _ as delegates -> + let is_requested p = + List.exists + (Signature.Public_key_hash.equal p.consensus_key) + delegates + in + List.filter is_requested rights + in + rights) - let get ctxt ?(levels = []) ?(delegates = []) block = - RPC_context.make_call0 S.validators ctxt block {levels; delegates} () + let get ctxt ?(levels = []) ?(delegates = []) ?(consensus_keys = []) block = + RPC_context.make_call0 + S.validators + ctxt + block + {levels; delegates; consensus_keys} + () end module S = struct diff --git a/src/proto_alpha/lib_plugin/mempool.ml b/src/proto_alpha/lib_plugin/mempool.ml index dc2a8978d8f515953274c91b70615904c9fc0594..10fba5fb7e6d94e9ae4d873badb9e5bdf6e27d83 100644 --- a/src/proto_alpha/lib_plugin/mempool.ml +++ b/src/proto_alpha/lib_plugin/mempool.ml @@ -854,6 +854,7 @@ let pre_filter config ~(filter_state : state) ?validation_state_before | Single (Activate_account _) | Single (Proposals _) | Single (Vdf_revelation _) + | Single (Drain_delegate _) | Single (Ballot _) -> Lwt.return @@ `Passed_prefilter other_prio | Single (Manager_operation _) as op -> prefilter_manager_op op @@ -993,84 +994,91 @@ let validate_manager_operation_and_handle_conflicts config filter_state | `Weight_ok (`No_replace, _weight) -> (* The mempool is not full: no need to replace any operation. *) return (validation_state, `No_replace) - | `Weight_ok (`Replace min_weight_oph, _weight) -> + | `Weight_ok (`Replace min_weight_oph, _weight) -> ( (* The mempool is full yet the new operation has enough weight to be included: the old operation with the lowest weight is reclassified as [Branch_delayed]. *) (* TODO: https://gitlab.com/tezos/tezos/-/issues/2347 The branch_delayed ring is bounded to 1000, so we may loose operations. We can probably do better. *) - let validation_state = - match - Operation_hash.Map.find - min_weight_oph - filter_state.prechecked_manager_ops - with - | None -> assert false - | Some {manager_op; _} -> + match + Operation_hash.Map.find + min_weight_oph + filter_state.prechecked_manager_ops + with + | None -> + (* This only occurs for a [Drain_delegate] + operation: it has a higher priority than a manager + therefore we keep the drain delegate *) + return (validation_state, `No_replace) + | Some {manager_op; _} -> + let validation_state = remove_from_validation_state validation_state manager_op - in - let replace_err = - Environment.wrap_tzerror Removed_fees_too_low_for_mempool - in - let replacement = - `Replace (min_weight_oph, `Branch_delayed [replace_err]) - in - return (validation_state, replacement) + in + let replace_err = + Environment.wrap_tzerror Removed_fees_too_low_for_mempool + in + let replacement = + `Replace (min_weight_oph, `Branch_delayed [replace_err]) + in + return (validation_state, replacement)) | `Fail err -> (* The mempool is full and the weight of the new operation is too low: raise the error returned by {!check_minimal_weight}. *) fail err) - | `Conflict (old_oph, _proto_error) -> + | `Conflict (old_oph, _proto_error) -> ( (* The protocol [validation_state] already contains an operation from the same manager. We look at the fees and gas limits of both operations to decide whether to replace the old one. *) - let old_info = - match - Operation_hash.Map.find old_oph filter_state.prechecked_manager_ops - with - | None -> assert false - | Some info -> info - in - if - better_fees_and_ratio - config - old_info.gas_limit - old_info.fee - gas_limit - fee - then - (* The new operation is better and replaces the old one from - the same manager. Note that there is no need to check the - number of prechecked operations in the mempool - here. Indeed, the removal of the old operation frees up a - spot in the mempool anyway. *) - let validation_state = - remove_from_validation_state validation_state old_info.manager_op - in - let* proto_validation_outcome2 = - proto_validate_manager_operation - validation_state - oph - ~nb_successful_prechecks - operation - in - match proto_validation_outcome2 with - | `Success validation_state -> - let replace_err = - Environment.wrap_tzerror - (Manager_operation_replaced {old_hash = old_oph; new_hash = oph}) + match + Operation_hash.Map.find old_oph filter_state.prechecked_manager_ops + with + | None -> + (* This only occurs for a [Drain_delegate] operation: it has + a higher priority than a manager therefore we keep the + drain delegate *) + return (validation_state, `No_replace) + | Some old_info -> + if + better_fees_and_ratio + config + old_info.gas_limit + old_info.fee + gas_limit + fee + then + (* The new operation is better and replaces the old one from + the same manager. Note that there is no need to check the + number of prechecked operations in the mempool + here. Indeed, the removal of the old operation frees up a + spot in the mempool anyway. *) + let validation_state = + remove_from_validation_state validation_state old_info.manager_op in - let replacement = `Replace (old_oph, `Outdated [replace_err]) in - return (validation_state, replacement) - | `Conflict (_oph, conflict_proto_error) -> - (* This should not happen: a manager operation should not - conflict with multiple operations. *) - fail conflict_proto_error - else - (* The new operation is not interesting enough so it is rejected. *) - let err = Manager_restriction {oph = old_oph; fee = old_info.fee} in - fail (`Branch_delayed [Environment.wrap_tzerror err]) + let* proto_validation_outcome2 = + proto_validate_manager_operation + validation_state + oph + ~nb_successful_prechecks + operation + in + match proto_validation_outcome2 with + | `Success validation_state -> + let replace_err = + Environment.wrap_tzerror + (Manager_operation_replaced + {old_hash = old_oph; new_hash = oph}) + in + let replacement = `Replace (old_oph, `Outdated [replace_err]) in + return (validation_state, replacement) + | `Conflict (_oph, conflict_proto_error) -> + (* This should not happen: a manager operation should not + conflict with multiple operations. *) + fail conflict_proto_error + else + (* The new operation is not interesting enough so it is rejected. *) + let err = Manager_restriction {oph = old_oph; fee = old_info.fee} in + fail (`Branch_delayed [Environment.wrap_tzerror err])) (** Remove a manager operation hash from the filter state. Do nothing if the operation was not in the state. *) @@ -1374,6 +1382,7 @@ let post_filter config ~(filter_state : state) ~validation_state_before:_ | Single_result (Activate_account_result _) | Single_result Proposals_result | Single_result (Vdf_revelation_result _) + | Single_result (Drain_delegate_result _) | Single_result Ballot_result -> Lwt.return (`Passed_postfilter filter_state) | Single_result (Manager_operation_result _) as result -> diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index dc04c08f8dd2341ad85f2bf6562ac1a3a54821db..19ec69c459c749e690324b06217903805a2f1e38 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -133,6 +133,8 @@ "Stake_storage", "Contract_storage", "Token", + "Fees_storage", + "Delegate_consensus_key", "Delegate_storage", "Delegate_sampler", "Delegate_missed_endorsements_storage", @@ -141,7 +143,6 @@ "Bootstrap_storage", "Vote_storage", - "Fees_storage", "Ticket_storage", "Liquidity_baking_storage", "Liquidity_baking_cpmm", diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 63ee7e4e2037ac316679932e66d21bd9900fbdd2..b35c7c7e6b0a1efaf985c78f7bf1e70d0e05b93e 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -469,6 +469,7 @@ module Bond_id = struct end module Receipt = Receipt_repr +module Consensus_key = Delegate_consensus_key module Delegate = struct include Delegate_storage @@ -489,6 +490,8 @@ module Delegate = struct let delegated_contracts = Contract_delegate_storage.delegated_contracts let deactivated = Delegate_activation_storage.is_inactive + + module Consensus_key = Delegate_consensus_key end module Stake_distribution = struct diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 498b96eb94a36f0a1b65b7529599269d23de3e13..49237ff8ca155de669d38eacca4bcb2de8749953 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2440,6 +2440,25 @@ module Receipt : sig val group_balance_updates : balance_updates -> balance_updates tzresult end +module Consensus_key : sig + type pk = { + delegate : Signature.Public_key_hash.t; + consensus_pk : Signature.Public_key.t; + consensus_pkh : Signature.Public_key_hash.t; + } + + type t = { + delegate : Signature.Public_key_hash.t; + consensus_pkh : Signature.Public_key_hash.t; + } + + val zero : t + + val pp : Format.formatter -> t -> unit + + val pkh : pk -> t +end + (** This module re-exports definitions from {!Delegate_storage}, {!Delegate_missed_endorsements_storage}, {!Delegate_slashed_deposits_storage}, {!Delegate_cycles}. *) @@ -2459,6 +2478,12 @@ module Delegate : sig val list : context -> public_key_hash list Lwt.t + val drain : + context -> + delegate:public_key_hash -> + destination:public_key_hash -> + (context * bool * Tez.t * Receipt.balance_updates) tzresult Lwt.t + type participation_info = { expected_cycle_activity : int; minimal_cycle_activity : int; @@ -2532,7 +2557,18 @@ module Delegate : sig val last_cycle_before_deactivation : context -> public_key_hash -> Cycle.t tzresult Lwt.t - val pubkey : context -> public_key_hash -> public_key tzresult Lwt.t + module Consensus_key : sig + val active_pubkey : + context -> public_key_hash -> Consensus_key.pk tzresult Lwt.t + + val pending_updates : + context -> + public_key_hash -> + (Cycle.t * public_key_hash) list tzresult Lwt.t + + val register_update : + context -> public_key_hash -> public_key -> context tzresult Lwt.t + end (** See {!Stake_storage.prepare_stake_distribution}. *) val prepare_stake_distribution : context -> context tzresult Lwt.t @@ -3862,6 +3898,10 @@ module Kind : sig type increase_paid_storage = Increase_paid_storage_kind + type update_consensus_key = Update_consensus_key_kind + + type drain_delegate = Drain_delegate_kind + type failing_noop = Failing_noop_kind type register_global_constant = Register_global_constant_kind @@ -3916,6 +3956,7 @@ module Kind : sig | Register_global_constant_manager_kind : register_global_constant manager | Set_deposits_limit_manager_kind : set_deposits_limit manager | Increase_paid_storage_manager_kind : increase_paid_storage manager + | Update_consensus_key_manager_kind : update_consensus_key manager | Tx_rollup_origination_manager_kind : tx_rollup_origination manager | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager | Tx_rollup_commit_manager_kind : tx_rollup_commit manager @@ -4030,6 +4071,12 @@ and _ contents = ballot : Vote.ballot; } -> Kind.ballot contents + | Drain_delegate : { + consensus_key : Signature.Public_key_hash.t; + delegate : Signature.Public_key_hash.t; + destination : Signature.Public_key_hash.t; + } + -> Kind.drain_delegate contents | Failing_noop : string -> Kind.failing_noop contents | Manager_operation : { source : public_key_hash; @@ -4069,6 +4116,9 @@ and _ manager_operation = destination : Contract_hash.t; } -> Kind.increase_paid_storage manager_operation + | Update_consensus_key : + Signature.Public_key.t + -> Kind.update_consensus_key manager_operation | Tx_rollup_origination : Kind.tx_rollup_origination manager_operation | Tx_rollup_submit_batch : { tx_rollup : Tx_rollup.t; @@ -4309,6 +4359,8 @@ module Operation : sig val ballot_case : Kind.ballot case + val drain_delegate_case : Kind.drain_delegate case + val failing_noop_case : Kind.failing_noop case val reveal_case : Kind.reveal Kind.manager case @@ -4319,6 +4371,8 @@ module Operation : sig val delegation_case : Kind.delegation Kind.manager case + val update_consensus_key_case : Kind.update_consensus_key Kind.manager case + val tx_rollup_origination_case : Kind.tx_rollup_origination Kind.manager case @@ -4399,6 +4453,10 @@ module Operation : sig val delegation_case : Kind.delegation case + val update_consensus_key_tag : int + + val update_consensus_key_case : Kind.update_consensus_key case + val register_global_constant_case : Kind.register_global_constant case val set_deposits_limit_case : Kind.set_deposits_limit case @@ -4468,13 +4526,10 @@ module Stake_distribution : sig context -> Level.t -> round:Round.t -> - (context * Slot.t * (public_key * public_key_hash)) tzresult Lwt.t + (context * Slot.t * Consensus_key.pk) tzresult Lwt.t val slot_owner : - context -> - Level.t -> - Slot.t -> - (context * (public_key * public_key_hash)) tzresult Lwt.t + context -> Level.t -> Slot.t -> (context * Consensus_key.pk) tzresult Lwt.t end (** This module re-exports definitions from {!Commitment_repr} and, @@ -4561,6 +4616,7 @@ module Parameters : sig public_key : public_key option; amount : Tez.t; delegate_to : public_key_hash option; + consensus_key : public_key option; } type bootstrap_contract = { @@ -4578,6 +4634,8 @@ module Parameters : sig no_reward_cycles : int option; } + val bootstrap_account_encoding : bootstrap_account Data_encoding.t + val encoding : t Data_encoding.t end @@ -4650,6 +4708,7 @@ module Consensus : sig and type 'a slot_map := 'a Slot.Map.t and type slot_set := Slot.Set.t and type round := Round.t + and type consensus_pk := Consensus_key.pk (** [store_endorsement_branch context branch] sets the "endorsement branch" (see {!Storage.Tenderbake.Endorsement_branch} to [branch] in both the disk diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 3a6d1f93f1e97a7f3add842b1bf9c6b4e6d63b43..44b611db0d48c40f6c9c0de289e163448ee6e075 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -35,6 +35,7 @@ type error += | Set_deposits_limit_on_unregistered_delegate of Signature.Public_key_hash.t | Set_deposits_limit_too_high of {limit : Tez.t; max_limit : Tez.t} | Error_while_taking_fees + | Update_consensus_key_on_unregistered_delegate of Signature.Public_key_hash.t | Empty_transaction of Contract.t | Tx_rollup_feature_disabled | Tx_rollup_invalid_transaction_ticket_amount @@ -130,6 +131,21 @@ let () = (function Error_while_taking_fees -> Some () | _ -> None) (fun () -> Error_while_taking_fees) ; + register_error_kind + `Temporary + ~id:"operation.update_consensus_key_on_unregistered_delegate" + ~title:"Update consensus key on an unregistered delegate" + ~description:"Cannot update consensus key an unregistered delegate." + ~pp:(fun ppf c -> + Format.fprintf + ppf + "Cannot update the consensus key on the unregistered delegate %a." + Signature.Public_key_hash.pp + c) + Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding)) + (function + | Update_consensus_key_on_unregistered_delegate c -> Some c | _ -> None) + (fun c -> Update_consensus_key_on_unregistered_delegate c) ; register_error_kind `Branch ~id:"contract.empty_transaction" @@ -1037,6 +1053,18 @@ let apply_manager_operation : } in (ctxt, result, []) + | Update_consensus_key pk -> + Delegate.registered ctxt source >>= fun is_registered -> + error_unless + is_registered + (Update_consensus_key_on_unregistered_delegate source) + >>?= fun () -> + Delegate.Consensus_key.register_update ctxt source pk >>=? fun ctxt -> + return + ( ctxt, + Update_consensus_key_result + {consumed_gas = Gas.consumed ~since:ctxt_before_op ~until:ctxt}, + [] ) | Tx_rollup_origination -> Tx_rollup.originate ctxt >>=? fun (ctxt, originated_tx_rollup) -> let result = @@ -1542,7 +1570,8 @@ let burn_manager_storage_fees : size_of_constant = payload.size_of_constant; global_address = payload.global_address; } ) - | Set_deposits_limit_result _ -> return (ctxt, storage_limit, smopr) + | Set_deposits_limit_result _ | Update_consensus_key_result _ -> + return (ctxt, storage_limit, smopr) | Increase_paid_storage_result _ -> return (ctxt, storage_limit, smopr) | Tx_rollup_origination_result payload -> Fees.burn_tx_rollup_origination_fees ctxt ~storage_limit ~payer @@ -1733,7 +1762,7 @@ type _ fees_updated_contents_list = let rec mark_skipped : type kind. - payload_producer:Signature.Public_key_hash.t -> + payload_producer:Consensus_key.t -> Level.t -> kind Kind.manager fees_updated_contents_list -> kind Kind.manager contents_result_list = @@ -1809,7 +1838,7 @@ let take_fees ctxt contents_list = let rec apply_manager_contents_list_rec : type kind. context -> - payload_producer:public_key_hash -> + payload_producer:Consensus_key.t -> Chain_id.t -> kind Kind.manager fees_updated_contents_list -> (success_or_failure * kind Kind.manager contents_result_list) Lwt.t = @@ -1893,23 +1922,23 @@ type mode = | Application of { block_header : Block_header.t; fitness : Fitness.t; - payload_producer : public_key_hash; - block_producer : public_key_hash; + payload_producer : Consensus_key.t; + block_producer : Consensus_key.t; predecessor_level : Level.t; predecessor_round : Round.t; } | Partial_application of { block_header : Block_header.t; fitness : Fitness.t; - payload_producer : public_key_hash; - block_producer : public_key_hash; + payload_producer : Consensus_key.t; + block_producer : Consensus_key.t; predecessor_level : Level.t; predecessor_round : Round.t; } | Full_construction of { predecessor : Block_hash.t; - payload_producer : public_key_hash; - block_producer : public_key_hash; + payload_producer : Consensus_key.t; + block_producer : Consensus_key.t; block_data_contents : Block_header.contents; round : Round.t; predecessor_level : Level.t; @@ -1942,7 +1971,7 @@ let record_operation (type kind) ctxt hash (operation : kind operation) : ( Failing_noop _ | Proposals _ | Ballot _ | Seed_nonce_revelation _ | Vdf_revelation _ | Double_endorsement_evidence _ | Double_preendorsement_evidence _ | Double_baking_evidence _ - | Activate_account _ | Manager_operation _ ) + | Activate_account _ | Drain_delegate _ | Manager_operation _ ) | Cons (Manager_operation _, _) -> record_non_consensus_operation_hash ctxt hash @@ -1961,7 +1990,7 @@ let record_preendorsement ctxt (mode : mode) (content : consensus_content) : | None -> (* This should not happen: operation validation should have failed. *) error Faulty_validation_wrong_slot - | Some (_delegate_pk, delegate, preendorsement_power) -> + | Some ({delegate; consensus_pkh; _}, preendorsement_power) -> let* ctxt = Consensus.record_preendorsement ctxt @@ -1973,7 +2002,12 @@ let record_preendorsement ctxt (mode : mode) (content : consensus_content) : ( ctxt, Single_result (Preendorsement_result - {balance_updates = []; delegate; preendorsement_power}) ) + { + balance_updates = []; + delegate; + consensus_key = consensus_pkh; + preendorsement_power; + }) ) let is_grandparent_endorsement mode content = match mode with @@ -1984,27 +2018,35 @@ let is_grandparent_endorsement mode content = let record_endorsement ctxt (mode : mode) (content : consensus_content) : (context * Kind.endorsement contents_result_list) tzresult Lwt.t = let open Lwt_tzresult_syntax in - let mk_endorsement_result delegate endorsement_power = + let mk_endorsement_result {Consensus_key.delegate; consensus_pkh} + endorsement_power = Single_result - (Endorsement_result {balance_updates = []; delegate; endorsement_power}) + (Endorsement_result + { + balance_updates = []; + delegate; + consensus_key = consensus_pkh; + endorsement_power; + }) in if is_grandparent_endorsement mode content then let level = Level.from_raw ctxt content.level in - let* ctxt, (_delegate_pk, delegate) = + let* ctxt, ({delegate; _} as consensus_key) = Stake_distribution.slot_owner ctxt level content.slot in let*? ctxt = Consensus.record_grand_parent_endorsement ctxt delegate in - return (ctxt, mk_endorsement_result delegate 0) + return (ctxt, mk_endorsement_result (Consensus_key.pkh consensus_key) 0) else match Slot.Map.find content.slot (Consensus.allowed_endorsements ctxt) with | None -> (* This should not happen: operation validation should have failed. *) fail Faulty_validation_wrong_slot - | Some (_delegate_pk, delegate, power) -> + | Some (consensus_key, power) -> let*? ctxt = Consensus.record_endorsement ctxt ~initial_slot:content.slot ~power in - return (ctxt, mk_endorsement_result delegate power) + return + (ctxt, mk_endorsement_result (Consensus_key.pkh consensus_key) power) let apply_manager_contents_list ctxt ~payload_producer chain_id fees_updated_contents_list = @@ -2045,7 +2087,7 @@ let punish_delegate ctxt delegate level mistake mk_result ~payload_producer = Token.transfer ctxt `Double_signing_evidence_rewards - (`Contract (Contract.Implicit payload_producer)) + (`Contract (Contract.Implicit payload_producer.Consensus_key.delegate)) reward | Error _ -> (* reward is Tez.zero *) return (ctxt, [])) >|=? fun (ctxt, reward_balance_updates) -> @@ -2070,10 +2112,10 @@ let punish_double_endorsement_or_preendorsement (type kind) ctxt | Single (Preendorsement e1) | Single (Endorsement e1) -> let level = Level.from_raw ctxt e1.level in Stake_distribution.slot_owner ctxt level e1.slot - >>=? fun (ctxt, (_delegate_pk, delegate)) -> + >>=? fun (ctxt, consensus_pk1) -> punish_delegate ctxt - delegate + consensus_pk1.delegate level `Double_endorsing mk_result @@ -2087,10 +2129,10 @@ let punish_double_baking ctxt (bh1 : Block_header.t) ~payload_producer = let committee_size = Constants.consensus_committee_size ctxt in Round.to_slot round1 ~committee_size >>?= fun slot1 -> Stake_distribution.slot_owner ctxt level slot1 - >>=? fun (ctxt, (_delegate_pk, delegate)) -> + >>=? fun (ctxt, consensus_pk1) -> punish_delegate ctxt - delegate + consensus_pk1.delegate level `Double_baking ~payload_producer @@ -2129,14 +2171,18 @@ let apply_contents_list (type kind) ctxt chain_id (mode : mode) let level = Level.from_raw ctxt level in Nonce.reveal ctxt level nonce >>=? fun ctxt -> let tip = Constants.seed_nonce_revelation_tip ctxt in - let contract = Contract.Implicit payload_producer in + let contract = + Contract.Implicit payload_producer.Consensus_key.delegate + in Token.transfer ctxt `Revelation_rewards (`Contract contract) tip >|=? fun (ctxt, balance_updates) -> (ctxt, Single_result (Seed_nonce_revelation_result balance_updates)) | Single (Vdf_revelation {solution}) -> Seed.update_seed ctxt solution >>=? fun ctxt -> let tip = Constants.seed_nonce_revelation_tip ctxt in - let contract = Contract.Implicit payload_producer in + let contract = + Contract.Implicit payload_producer.Consensus_key.delegate + in Token.transfer ctxt `Revelation_rewards (`Contract contract) tip >|=? fun (ctxt, balance_updates) -> (ctxt, Single_result (Vdf_revelation_result balance_updates)) @@ -2159,6 +2205,24 @@ let apply_contents_list (type kind) ctxt chain_id (mode : mode) | Single (Proposals _ as contents) -> Amendment.apply_proposals ctxt chain_id contents | Single (Ballot _ as contents) -> Amendment.apply_ballot ctxt contents + | Single (Drain_delegate {delegate; destination; consensus_key = _}) -> + Delegate.drain ctxt ~delegate ~destination + >>=? fun ( ctxt, + allocated_destination_contract, + fees, + drain_balance_updates ) -> + Token.transfer + ctxt + (`Contract (Contract.Implicit delegate)) + (`Contract (Contract.Implicit payload_producer.Consensus_key.delegate)) + fees + >>=? fun (ctxt, fees_balance_updates) -> + let balance_updates = drain_balance_updates @ fees_balance_updates in + return + ( ctxt, + Single_result + (Drain_delegate_result + {balance_updates; allocated_destination_contract}) ) | Single (Failing_noop _) -> (* This operation always fails. It should already have been rejected by {!Validate_operation.validate_operation}. *) @@ -2227,7 +2291,7 @@ let apply_operation application_state operation_hash operation = apply_operation application_state operation - ~payload_producer:Signature.Public_key_hash.zero + ~payload_producer:Consensus_key.zero let may_start_new_cycle ctxt = match Level.dawn_of_a_new_cycle ctxt with @@ -2409,7 +2473,7 @@ let are_endorsements_required ctxt ~level = let record_endorsing_participation ctxt = let validators = Consensus.allowed_endorsements ctxt in Slot.Map.fold_es - (fun initial_slot (_delegate_pk, delegate, power) ctxt -> + (fun initial_slot ((consensus_pk : Consensus_key.pk), power) ctxt -> let participation = if Slot.Set.mem initial_slot (Consensus.endorsements_seen ctxt) then Delegate.Participated @@ -2417,7 +2481,7 @@ let record_endorsing_participation ctxt = in Delegate.record_endorsing_participation ctxt - ~delegate + ~delegate:consensus_pk.delegate ~participation ~endorsing_power:power) validators @@ -2434,10 +2498,10 @@ let begin_application ctxt chain_id ~migration_balance_updates let predecessor_level = Level.from_raw ctxt predecessor_level in let round = Fitness.round fitness in let current_level = Level.current ctxt in - let* ctxt, _slot, (_block_producer_pk, block_producer) = + let* ctxt, _slot, block_producer = Stake_distribution.baking_rights_owner ctxt current_level ~round in - let* ctxt, _slot, (payload_producer, _payload_producer) = + let* ctxt, _slot, payload_producer = Stake_distribution.baking_rights_owner ctxt current_level @@ -2457,8 +2521,8 @@ let begin_application ctxt chain_id ~migration_balance_updates fitness; predecessor_round; predecessor_level; - payload_producer = Signature.Public_key.hash payload_producer; - block_producer; + payload_producer = Consensus_key.pkh payload_producer; + block_producer = Consensus_key.pkh block_producer; } in return @@ -2487,10 +2551,10 @@ let begin_partial_application ~ancestor_context chain_id (* Note: we don't have access to the predecessor context. *) let round = Fitness.round fitness in let current_level = Level.current ancestor_context in - let* ctxt, _slot, (_block_producer_pk, block_producer) = + let* ctxt, _slot, block_producer = Stake_distribution.baking_rights_owner ancestor_context current_level ~round in - let* ctxt, _slot, (payload_producer_pk, _payload_producer) = + let* ctxt, _slot, payload_producer = Stake_distribution.baking_rights_owner ctxt current_level @@ -2510,8 +2574,8 @@ let begin_partial_application ~ancestor_context chain_id fitness; predecessor_level; predecessor_round; - payload_producer = Signature.Public_key.hash payload_producer_pk; - block_producer; + payload_producer = Consensus_key.pkh payload_producer; + block_producer = Consensus_key.pkh block_producer; } in return @@ -2544,10 +2608,10 @@ let begin_full_construction ctxt chain_id ~migration_balance_updates (* The endorsement/preendorsement validation rules for construction are the same as for application. *) let current_level = Level.current ctxt in - let* ctxt, _slot, (_block_producer_pk, block_producer) = + let* ctxt, _slot, block_producer = Stake_distribution.baking_rights_owner ctxt current_level ~round in - let* ctxt, _slot, (_payload_producer_pk, payload_producer) = + let* ctxt, _slot, payload_producer = Stake_distribution.baking_rights_owner ctxt current_level @@ -2561,8 +2625,8 @@ let begin_full_construction ctxt chain_id ~migration_balance_updates Full_construction { predecessor; - payload_producer; - block_producer; + payload_producer = Consensus_key.pkh payload_producer; + block_producer = Consensus_key.pkh block_producer; round; block_data_contents; predecessor_round; @@ -2612,7 +2676,8 @@ let begin_partial_construction ctxt chain_id ~migration_balance_updates let finalize_application ctxt block_data_contents ~round ~predecessor ~liquidity_baking_toggle_ema ~implicit_operations_results - ~migration_balance_updates ~block_producer ~payload_producer = + ~migration_balance_updates ~(block_producer : Consensus_key.t) + ~(payload_producer : Consensus_key.t) = let open Lwt_result_syntax in let level = Level.current ctxt in let endorsing_power = Consensus.current_endorsement_power ctxt in @@ -2647,7 +2712,7 @@ let finalize_application ctxt block_data_contents ~round ~predecessor match block_data_contents.Block_header.seed_nonce_hash with | None -> return ctxt | Some nonce_hash -> - Nonce.record_hash ctxt {nonce_hash; delegate = block_producer} + Nonce.record_hash ctxt {nonce_hash; delegate = block_producer.delegate} in let* ctxt, reward_bonus = if required_endorsements then @@ -2660,8 +2725,8 @@ let finalize_application ctxt block_data_contents ~round ~predecessor let* ctxt, baking_receipts = Delegate.record_baking_activity_and_pay_rewards_and_fees ctxt - ~payload_producer - ~block_producer + ~payload_producer:payload_producer.delegate + ~block_producer:block_producer.delegate ~baking_reward ~reward_bonus in @@ -2815,8 +2880,8 @@ let finalize_block (application_state : application_state) shell_header_opt = ( result, Apply_results. { - proposer = Signature.Public_key_hash.zero; - baker = Signature.Public_key_hash.zero; + proposer = Consensus_key.zero; + baker = Consensus_key.zero; level_info; voting_period_info; nonce_hash = None; @@ -2855,7 +2920,7 @@ let finalize_block (application_state : application_state) shell_header_opt = finalize_with_commit_message ctxt ~cache_nonce fitness round op_count in return (result, receipt) - | Partial_application {block_producer; fitness; _} -> + | Partial_application {payload_producer; block_producer; fitness; _} -> let* voting_period_info = Voting_period.get_rpc_current_info ctxt in let level_info = Level.current ctxt in let ctxt = finalize ctxt (Fitness.to_raw fitness) in @@ -2863,10 +2928,7 @@ let finalize_block (application_state : application_state) shell_header_opt = ( ctxt, Apply_results. { - proposer = Signature.Public_key_hash.zero; - (* We cannot retrieve the proposer as it requires the - frozen deposit that might not be available depending on - the context given to the partial application. *) + proposer = payload_producer; baker = block_producer; level_info; voting_period_info; diff --git a/src/proto_alpha/lib_protocol/apply.mli b/src/proto_alpha/lib_protocol/apply.mli index c497016baf8dbe2bb8d06d52bd4379755271e451..56433919ddd32626354bf7c6086a2cfd1c9fa621 100644 --- a/src/proto_alpha/lib_protocol/apply.mli +++ b/src/proto_alpha/lib_protocol/apply.mli @@ -47,23 +47,23 @@ type mode = | Application of { block_header : Block_header.t; fitness : Fitness.t; - payload_producer : public_key_hash; - block_producer : public_key_hash; + payload_producer : Consensus_key.t; + block_producer : Consensus_key.t; predecessor_level : Level.t; predecessor_round : Round.t; } | Partial_application of { block_header : Block_header.t; fitness : Fitness.t; - payload_producer : public_key_hash; - block_producer : public_key_hash; + payload_producer : Consensus_key.t; + block_producer : Consensus_key.t; predecessor_level : Level.t; predecessor_round : Round.t; } | Full_construction of { predecessor : Block_hash.t; - payload_producer : public_key_hash; - block_producer : public_key_hash; + payload_producer : Consensus_key.t; + block_producer : Consensus_key.t; block_data_contents : Block_header.contents; round : Round.t; predecessor_level : Level.t; diff --git a/src/proto_alpha/lib_protocol/apply_results.ml b/src/proto_alpha/lib_protocol/apply_results.ml index 91e72b60892985baecf5c90608baa350bacc6e83..658828725e9208186b27165b73e89b64fee367c4 100644 --- a/src/proto_alpha/lib_protocol/apply_results.ml +++ b/src/proto_alpha/lib_protocol/apply_results.ml @@ -66,6 +66,10 @@ type _ successful_manager_operation_result = consumed_gas : Gas.Arith.fp; } -> Kind.increase_paid_storage successful_manager_operation_result + | Update_consensus_key_result : { + consumed_gas : Gas.Arith.fp; + } + -> Kind.update_consensus_key successful_manager_operation_result | Tx_rollup_origination_result : { balance_updates : Receipt.balance_updates; consumed_gas : Gas.Arith.fp; @@ -506,6 +510,26 @@ module Manager_result = struct ~proj:(function Delegation_result {consumed_gas} -> consumed_gas) ~inj:(fun consumed_gas -> Delegation_result {consumed_gas}) + let update_consensus_key_case = + make + ~op_case:Operation.Encoding.Manager_operations.update_consensus_key_case + ~encoding: + Data_encoding.( + obj2 + (dft "consumed_gas" Gas.Arith.n_integral_encoding Gas.Arith.zero) + (dft "consumed_milligas" Gas.Arith.n_fp_encoding Gas.Arith.zero)) + ~select:(function + | Successful_manager_result (Update_consensus_key_result _ as op) -> + Some op + | _ -> None) + ~kind:Kind.Update_consensus_key_manager_kind + ~proj:(function + | Update_consensus_key_result {consumed_gas} -> + (Gas.Arith.ceil consumed_gas, consumed_gas)) + ~inj:(fun (consumed_gas, consumed_milligas) -> + assert (Gas.Arith.(equal (ceil consumed_milligas) consumed_gas)) ; + Update_consensus_key_result {consumed_gas = consumed_milligas}) + let set_deposits_limit_case = make ~op_case:Operation.Encoding.Manager_operations.set_deposits_limit_case @@ -1006,6 +1030,7 @@ let successful_manager_operation_result_encoding : make Manager_result.transaction_case; make Manager_result.origination_case; make Manager_result.delegation_case; + make Manager_result.update_consensus_key_case; make Manager_result.set_deposits_limit_case; make Manager_result.increase_paid_storage_case; make Manager_result.sc_rollup_originate_case; @@ -1014,13 +1039,15 @@ let successful_manager_operation_result_encoding : type 'kind contents_result = | Preendorsement_result : { balance_updates : Receipt.balance_updates; - delegate : Signature.Public_key_hash.t; + delegate : Signature.public_key_hash; + consensus_key : Signature.public_key_hash; preendorsement_power : int; } -> Kind.preendorsement contents_result | Endorsement_result : { balance_updates : Receipt.balance_updates; - delegate : Signature.Public_key_hash.t; + delegate : Signature.public_key_hash; + consensus_key : Signature.public_key_hash; endorsement_power : int; } -> Kind.endorsement contents_result @@ -1048,6 +1075,11 @@ type 'kind contents_result = -> Kind.activate_account contents_result | Proposals_result : Kind.proposals contents_result | Ballot_result : Kind.ballot contents_result + | Drain_delegate_result : { + balance_updates : Receipt.balance_updates; + allocated_destination_contract : bool; + } + -> Kind.drain_delegate contents_result | Manager_operation_result : { balance_updates : Receipt.balance_updates; operation_result : 'kind manager_operation_result; @@ -1077,6 +1109,10 @@ let equal_manager_kind : | Kind.Origination_manager_kind, _ -> None | Kind.Delegation_manager_kind, Kind.Delegation_manager_kind -> Some Eq | Kind.Delegation_manager_kind, _ -> None + | ( Kind.Update_consensus_key_manager_kind, + Kind.Update_consensus_key_manager_kind ) -> + Some Eq + | Kind.Update_consensus_key_manager_kind, _ -> None | ( Kind.Register_global_constant_manager_kind, Kind.Register_global_constant_manager_kind ) -> Some Eq @@ -1194,10 +1230,11 @@ module Encoding = struct { op_case = Operation.Encoding.preendorsement_case; encoding = - obj3 + obj4 (dft "balance_updates" Receipt.balance_updates_encoding []) (req "delegate" Signature.Public_key_hash.encoding) - (req "preendorsement_power" int31); + (req "preendorsement_power" int31) + (req "consensus_key" Signature.Public_key_hash.encoding); select = (function | Contents_result (Preendorsement_result _ as op) -> Some op @@ -1209,12 +1246,13 @@ module Encoding = struct proj = (function | Preendorsement_result - {balance_updates; delegate; preendorsement_power} -> - (balance_updates, delegate, preendorsement_power)); + {balance_updates; delegate; consensus_key; preendorsement_power} + -> + (balance_updates, delegate, preendorsement_power, consensus_key)); inj = - (fun (balance_updates, delegate, preendorsement_power) -> + (fun (balance_updates, delegate, preendorsement_power, consensus_key) -> Preendorsement_result - {balance_updates; delegate; preendorsement_power}); + {balance_updates; delegate; consensus_key; preendorsement_power}); } let endorsement_case = @@ -1222,10 +1260,11 @@ module Encoding = struct { op_case = Operation.Encoding.endorsement_case; encoding = - obj3 + obj4 (dft "balance_updates" Receipt.balance_updates_encoding []) (req "delegate" Signature.Public_key_hash.encoding) - (req "endorsement_power" int31); + (req "endorsement_power" int31) + (req "consensus_key" Signature.Public_key_hash.encoding); select = (function | Contents_result (Endorsement_result _ as op) -> Some op | _ -> None); @@ -1235,11 +1274,13 @@ module Encoding = struct | _ -> None); proj = (function - | Endorsement_result {balance_updates; delegate; endorsement_power} -> - (balance_updates, delegate, endorsement_power)); + | Endorsement_result + {balance_updates; delegate; consensus_key; endorsement_power} -> + (balance_updates, delegate, endorsement_power, consensus_key)); inj = - (fun (balance_updates, delegate, endorsement_power) -> - Endorsement_result {balance_updates; delegate; endorsement_power}); + (fun (balance_updates, delegate, endorsement_power, consensus_key) -> + Endorsement_result + {balance_updates; delegate; consensus_key; endorsement_power}); } let dal_slot_availability_case = @@ -1408,6 +1449,34 @@ module Encoding = struct inj = (fun () -> Ballot_result); } + let drain_delegate_case = + Case + { + op_case = Operation.Encoding.drain_delegate_case; + encoding = + Data_encoding.( + obj2 + (dft "balance_updates" Receipt.balance_updates_encoding []) + (dft "allocated_destination_contract" bool false)); + select = + (function + | Contents_result (Drain_delegate_result _ as op) -> Some op + | _ -> None); + mselect = + (function + | Contents_and_result ((Drain_delegate _ as op), res) -> Some (op, res) + | _ -> None); + proj = + (function + | Drain_delegate_result + {balance_updates; allocated_destination_contract} -> + (balance_updates, allocated_destination_contract)); + inj = + (fun (balance_updates, allocated_destination_contract) -> + Drain_delegate_result + {balance_updates; allocated_destination_contract}); + } + let make_manager_case (type kind) (Operation.Encoding.Case op_case : kind Kind.manager Operation.Encoding.case) @@ -1471,6 +1540,7 @@ module Encoding = struct | Contents_result (Double_preendorsement_evidence_result _) -> None | Contents_result (Double_baking_evidence_result _) -> None | Contents_result (Activate_account_result _) -> None + | Contents_result (Drain_delegate_result _) -> None | Contents_result Proposals_result -> None); mselect; proj = @@ -1531,6 +1601,17 @@ module Encoding = struct Some (op, res) | _ -> None) + let update_consensus_key_case = + make_manager_case + Operation.Encoding.update_consensus_key_case + Manager_result.update_consensus_key_case + (function + | Contents_and_result + ( (Manager_operation {operation = Update_consensus_key _; _} as op), + res ) -> + Some (op, res) + | _ -> None) + let register_global_constant_case = make_manager_case Operation.Encoding.register_global_constant_case @@ -1822,6 +1903,7 @@ let contents_result_encoding = make activate_account_case; make proposals_case; make ballot_case; + make drain_delegate_case; make reveal_case; make transaction_case; make origination_case; @@ -1829,6 +1911,7 @@ let contents_result_encoding = make register_global_constant_case; make set_deposits_limit_case; make increase_paid_storage_case; + make update_consensus_key_case; make tx_rollup_origination_case; make tx_rollup_submit_batch_case; make tx_rollup_commit_case; @@ -1893,6 +1976,8 @@ let contents_and_result_encoding = make register_global_constant_case; make set_deposits_limit_case; make increase_paid_storage_case; + make update_consensus_key_case; + make drain_delegate_case; make tx_rollup_origination_case; make tx_rollup_submit_batch_case; make tx_rollup_commit_case; @@ -2043,6 +2128,8 @@ let kind_equal : | Proposals _, _ -> None | Ballot _, Ballot_result -> Some Eq | Ballot _, _ -> None + | Drain_delegate _, Drain_delegate_result _ -> Some Eq + | Drain_delegate _, _ -> None | Failing_noop _, _ -> (* the Failing_noop operation always fails and can't have result *) None @@ -2139,6 +2226,32 @@ let kind_equal : } ) -> Some Eq | Manager_operation {operation = Delegation _; _}, _ -> None + | ( Manager_operation {operation = Update_consensus_key _; _}, + Manager_operation_result + {operation_result = Applied (Update_consensus_key_result _); _} ) -> + Some Eq + | ( Manager_operation {operation = Update_consensus_key _; _}, + Manager_operation_result + {operation_result = Backtracked (Update_consensus_key_result _, _); _} ) + -> + Some Eq + | ( Manager_operation {operation = Update_consensus_key _; _}, + Manager_operation_result + { + operation_result = + Failed (Alpha_context.Kind.Update_consensus_key_manager_kind, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Update_consensus_key _; _}, + Manager_operation_result + { + operation_result = + Skipped Alpha_context.Kind.Update_consensus_key_manager_kind; + _; + } ) -> + Some Eq + | Manager_operation {operation = Update_consensus_key _; _}, _ -> None | ( Manager_operation {operation = Register_global_constant _; _}, Manager_operation_result {operation_result = Applied (Register_global_constant_result _); _} ) -> @@ -2870,8 +2983,8 @@ let operation_data_and_metadata_encoding = ] type block_metadata = { - proposer : Signature.Public_key_hash.t; - baker : Signature.Public_key_hash.t; + proposer : Consensus_key.t; + baker : Consensus_key.t; level_info : Level.t; voting_period_info : Voting_period.info; nonce_hash : Nonce_hash.t option; @@ -2888,8 +3001,9 @@ let block_metadata_encoding = def "block_header.alpha.metadata" @@ conv (fun { - proposer; - baker; + proposer = + {delegate = proposer; consensus_pkh = proposer_active_key}; + baker = {delegate = baker; consensus_pkh = baker_active_key}; level_info; voting_period_info; nonce_hash; @@ -2909,7 +3023,10 @@ let block_metadata_encoding = balance_updates, liquidity_baking_toggle_ema, implicit_operations_results ), - (consumed_gas, dal_slot_availability) )) + ( proposer_active_key, + baker_active_key, + consumed_gas, + dal_slot_availability ) )) (fun ( ( proposer, baker, level_info, @@ -2919,10 +3036,13 @@ let block_metadata_encoding = balance_updates, liquidity_baking_toggle_ema, implicit_operations_results ), - (consumed_gas, dal_slot_availability) ) -> + ( proposer_active_key, + baker_active_key, + consumed_gas, + dal_slot_availability ) ) -> { - proposer; - baker; + proposer = {delegate = proposer; consensus_pkh = proposer_active_key}; + baker = {delegate = baker; consensus_pkh = baker_active_key}; level_info; voting_period_info; nonce_hash; @@ -2948,10 +3068,11 @@ let block_metadata_encoding = (req "implicit_operations_results" (list successful_manager_operation_result_encoding))) - (obj2 + (obj4 + (req "proposer_consensus_key" Signature.Public_key_hash.encoding) + (req "baker_consensus_key" Signature.Public_key_hash.encoding) (req "consumed_milligas" Gas.Arith.n_fp_encoding) (* DAL/FIXME https://gitlab.com/tezos/tezos/-/issues/3119 - This varopt is here while the DAL is behind a feature flag. This should be replaced by a required field once the feature flag will be activated. *) diff --git a/src/proto_alpha/lib_protocol/apply_results.mli b/src/proto_alpha/lib_protocol/apply_results.mli index 6b3903dd929f2bed265f76c57f9a524fadf5460e..f60d87231dc69389580b114e2ae612c200ba6f4f 100644 --- a/src/proto_alpha/lib_protocol/apply_results.mli +++ b/src/proto_alpha/lib_protocol/apply_results.mli @@ -60,13 +60,15 @@ and packed_contents_result_list = and 'kind contents_result = | Preendorsement_result : { balance_updates : Receipt.balance_updates; - delegate : Signature.Public_key_hash.t; + delegate : Signature.public_key_hash; + consensus_key : Signature.public_key_hash; preendorsement_power : int; } -> Kind.preendorsement contents_result | Endorsement_result : { balance_updates : Receipt.balance_updates; - delegate : Signature.Public_key_hash.t; + delegate : Signature.public_key_hash; + consensus_key : Signature.public_key_hash; endorsement_power : int; } -> Kind.endorsement contents_result @@ -94,6 +96,11 @@ and 'kind contents_result = -> Kind.activate_account contents_result | Proposals_result : Kind.proposals contents_result | Ballot_result : Kind.ballot contents_result + | Drain_delegate_result : { + balance_updates : Receipt.balance_updates; + allocated_destination_contract : bool; + } + -> Kind.drain_delegate contents_result | Manager_operation_result : { balance_updates : Receipt.balance_updates; operation_result : 'kind manager_operation_result; @@ -162,6 +169,10 @@ and _ successful_manager_operation_result = consumed_gas : Gas.Arith.fp; } -> Kind.increase_paid_storage successful_manager_operation_result + | Update_consensus_key_result : { + consumed_gas : Gas.Arith.fp; + } + -> Kind.update_consensus_key successful_manager_operation_result | Tx_rollup_origination_result : { balance_updates : Receipt.balance_updates; consumed_gas : Gas.Arith.fp; @@ -334,8 +345,8 @@ val kind_equal_list : ('kind, 'kind2) eq option type block_metadata = { - proposer : Signature.Public_key_hash.t; - baker : Signature.Public_key_hash.t; + proposer : Consensus_key.t; + baker : Consensus_key.t; level_info : Level.t; voting_period_info : Voting_period.info; nonce_hash : Nonce_hash.t option; diff --git a/src/proto_alpha/lib_protocol/baking.ml b/src/proto_alpha/lib_protocol/baking.ml index 00bc864d91028aaa0517cd4f0246cf39b2c7a37f..4cf700d66586ea345403af34ff41d27cfde4b23e 100644 --- a/src/proto_alpha/lib_protocol/baking.ml +++ b/src/proto_alpha/lib_protocol/baking.ml @@ -72,12 +72,17 @@ let bonus_baking_reward ctxt ~endorsing_power = let baking_rights c level = let rec f c round = Stake_distribution.baking_rights_owner c level ~round - >>=? fun (c, _slot, (delegate, _)) -> - return (LCons (delegate, fun () -> f c (Round.succ round))) + >>=? fun (c, _slot, consensus_pk) -> + return + (LCons (Consensus_key.pkh consensus_pk, fun () -> f c (Round.succ round))) in f c Round.zero -type ordered_slots = Slot.t list +type ordered_slots = { + delegate : Signature.public_key_hash; + consensus_key : Signature.public_key_hash; + slots : Slot.t list; +} (* Slots returned by this function are assumed by consumers to be in increasing order, hence the use of [Slot.Range.rev_fold_es]. *) @@ -86,11 +91,20 @@ let endorsing_rights (ctxt : t) level = Slot.Range.create ~min:0 ~count:consensus_committee_size >>?= fun slots -> Slot.Range.rev_fold_es (fun (ctxt, map) slot -> - Stake_distribution.slot_owner ctxt level slot >>=? fun (ctxt, (_, pkh)) -> + Stake_distribution.slot_owner ctxt level slot + >>=? fun (ctxt, consensus_pk) -> let map = Signature.Public_key_hash.Map.update - pkh - (function None -> Some [slot] | Some slots -> Some (slot :: slots)) + consensus_pk.delegate + (function + | None -> + Some + { + delegate = consensus_pk.delegate; + consensus_key = consensus_pk.consensus_pkh; + slots = [slot]; + } + | Some slots -> Some {slots with slots = slot :: slots.slots}) map in return (ctxt, map)) @@ -103,11 +117,17 @@ let endorsing_rights_by_first_slot ctxt level = Slot.Range.fold_es (fun (ctxt, (delegates_map, slots_map)) slot -> Stake_distribution.slot_owner ctxt level slot - >|=? fun (ctxt, (pk, pkh)) -> + >|=? fun (ctxt, consensus_pk) -> let initial_slot, delegates_map = - match Signature.Public_key_hash.Map.find pkh delegates_map with + match + Signature.Public_key_hash.Map.find consensus_pk.delegate delegates_map + with | None -> - (slot, Signature.Public_key_hash.Map.add pkh slot delegates_map) + ( slot, + Signature.Public_key_hash.Map.add + consensus_pk.delegate + slot + delegates_map ) | Some initial_slot -> (initial_slot, delegates_map) in (* [slots_map]'keys are the minimal slots of delegates because @@ -116,8 +136,8 @@ let endorsing_rights_by_first_slot ctxt level = Slot.Map.update initial_slot (function - | None -> Some (pk, pkh, 1) - | Some (pk, pkh, count) -> Some (pk, pkh, count + 1)) + | None -> Some (consensus_pk, 1) + | Some (consensus_pk, count) -> Some (consensus_pk, count + 1)) slots_map in (ctxt, (delegates_map, slots_map))) diff --git a/src/proto_alpha/lib_protocol/baking.mli b/src/proto_alpha/lib_protocol/baking.mli index 9d9281b735a3922496eb29ebff754b683cd13595..9e90eb4ea479969793121d7c08db0d831422e973 100644 --- a/src/proto_alpha/lib_protocol/baking.mli +++ b/src/proto_alpha/lib_protocol/baking.mli @@ -34,7 +34,11 @@ type error += consensus_threshold : int; } -type ordered_slots = private Slot.t list +type ordered_slots = private { + delegate : Signature.public_key_hash; + consensus_key : Signature.public_key_hash; + slots : Slot.t list; +} (** For a given level computes who has the right to include an endorsement in the next block. @@ -48,14 +52,14 @@ val endorsing_rights : Level.t -> (context * ordered_slots Signature.Public_key_hash.Map.t) tzresult Lwt.t -(** Computes endorsing rights for a given level. +(** Computes endorsing rights for a given level. @return map from allocated first slots to their owner's public key, public key hash, and endorsing power. *) val endorsing_rights_by_first_slot : context -> Level.t -> - (context * (public_key * public_key_hash * int) Slot.Map.t) tzresult Lwt.t + (context * (Consensus_key.pk * int) Slot.Map.t) tzresult Lwt.t (** Computes the bonus baking reward depending on the endorsing power. *) val bonus_baking_reward : context -> endorsing_power:int -> Tez.t tzresult @@ -63,4 +67,4 @@ val bonus_baking_reward : context -> endorsing_power:int -> Tez.t tzresult (** [baking_rights ctxt level] is the lazy list of contract's public key hashes that are allowed to propose for [level] at each round. *) -val baking_rights : context -> Level.t -> public_key lazy_list +val baking_rights : context -> Level.t -> Consensus_key.t lazy_list diff --git a/src/proto_alpha/lib_protocol/bootstrap_storage.ml b/src/proto_alpha/lib_protocol/bootstrap_storage.ml index 592bdebbec46a3168cd6f2d1e6bf2f66c0ca07e7..02f7a938c93e83f9a140270cc2c0513ea4f79217 100644 --- a/src/proto_alpha/lib_protocol/bootstrap_storage.ml +++ b/src/proto_alpha/lib_protocol/bootstrap_storage.ml @@ -42,7 +42,7 @@ let () = (fun pkh -> Unrevealed_public_key pkh) let init_account (ctxt, balance_updates) - ({public_key_hash; public_key; amount; delegate_to} : + ({public_key_hash; public_key; amount; delegate_to; consensus_key} : Parameters_repr.bootstrap_account) = let contract = Contract_repr.Implicit public_key_hash in Token.transfer @@ -63,6 +63,12 @@ let init_account (ctxt, balance_updates) ctxt contract (Some (Option.value ~default:public_key_hash delegate_to)) + >>=? fun ctxt -> + (match consensus_key with + | None -> return ctxt + | Some consensus_key -> + Delegate_consensus_key.init ctxt public_key_hash consensus_key) + >>=? fun ctxt -> return ctxt | None -> fail_when (Option.is_some delegate_to) diff --git a/src/proto_alpha/lib_protocol/delegate_consensus_key.ml b/src/proto_alpha/lib_protocol/delegate_consensus_key.ml new file mode 100644 index 0000000000000000000000000000000000000000..023247a68263803a0758d32ef3fd03d9be6c8fdb --- /dev/null +++ b/src/proto_alpha/lib_protocol/delegate_consensus_key.ml @@ -0,0 +1,208 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 G.B. Fefe, *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +type error += + | Invalid_consensus_key_update_noop of Cycle_repr.t + | Invalid_consensus_key_update_active + +let () = + register_error_kind + `Permanent + ~id:"delegate.consensus_key.invalid_noop" + ~title:"Invalid key for consensus key update" + ~description:"Tried to update the consensus key with the active key" + ~pp:(fun ppf cycle -> + Format.fprintf + ppf + "Invalid key while updating a consensus key (already active since %a)." + Cycle_repr.pp + cycle) + Data_encoding.(obj1 (req "cycle" Cycle_repr.encoding)) + (function Invalid_consensus_key_update_noop c -> Some c | _ -> None) + (fun c -> Invalid_consensus_key_update_noop c) ; + register_error_kind + `Permanent + ~id:"delegate.consensus_key.active" + ~title:"Active consensus key" + ~description: + "The delegate consensus key is already used by another delegate" + ~pp:(fun ppf () -> + Format.fprintf + ppf + "The delegate consensus key is already used by another delegate") + Data_encoding.empty + (function Invalid_consensus_key_update_active -> Some () | _ -> None) + (fun () -> Invalid_consensus_key_update_active) + +type pk = Raw_context.consensus_pk = { + delegate : Signature.Public_key_hash.t; + consensus_pk : Signature.Public_key.t; + consensus_pkh : Signature.Public_key_hash.t; +} + +type t = { + delegate : Signature.Public_key_hash.t; + consensus_pkh : Signature.Public_key_hash.t; +} + +let pkh {delegate; consensus_pkh; consensus_pk = _} = {delegate; consensus_pkh} + +let zero = + { + consensus_pkh = Signature.Public_key_hash.zero; + delegate = Signature.Public_key_hash.zero; + } + +let pp ppf {delegate; consensus_pkh} = + Format.fprintf ppf "@[%a" Signature.Public_key_hash.pp delegate ; + if not (Signature.Public_key_hash.equal delegate consensus_pkh) then + Format.fprintf + ppf + "@,Active key: %a" + Signature.Public_key_hash.pp + consensus_pkh ; + Format.fprintf ppf "@]" + +let check_inactive ctxt pkh = + let open Lwt_tzresult_syntax in + let*! is_active = Storage.Consensus_keys.mem ctxt pkh in + fail_when is_active Invalid_consensus_key_update_active + +let set_inactive = Storage.Consensus_keys.remove + +let set_active = Storage.Consensus_keys.add + +let init ctxt delegate pk = + let open Lwt_tzresult_syntax in + let pkh = Signature.Public_key.hash pk in + let* () = check_inactive ctxt pkh in + let*! ctxt = set_active ctxt pkh in + Storage.Contract.Consensus_key.init ctxt (Contract_repr.Implicit delegate) pk + +let active_pubkey ctxt delegate = + let open Lwt_tzresult_syntax in + let* pk = + Storage.Contract.Consensus_key.get ctxt (Contract_repr.Implicit delegate) + in + let pkh = Signature.Public_key.hash pk in + return {consensus_pk = pk; consensus_pkh = pkh; delegate} + +let active_key ctxt delegate = + let open Lwt_tzresult_syntax in + let* pk = active_pubkey ctxt delegate in + return (pkh pk) + +let raw_pending_updates ctxt delegate = + let open Lwt_tzresult_syntax in + let*! pendings = + Storage.Contract.Pending_consensus_keys.bindings + (ctxt, Contract_repr.Implicit delegate) + in + return pendings + +let pending_updates ctxt delegate = + let open Lwt_tzresult_syntax in + let* updates = raw_pending_updates ctxt delegate in + let updates = + List.sort (fun (c1, _) (c2, _) -> Cycle_repr.compare c1 c2) updates + in + return (List.map (fun (c, pk) -> (c, Signature.Public_key.hash pk)) updates) + +let raw_active_pubkey_for_cycle ctxt delegate cycle = + let open Lwt_tzresult_syntax in + let* pendings = raw_pending_updates ctxt delegate in + let* active = active_pubkey ctxt delegate in + let current_level = Raw_context.current_level ctxt in + let active_for_cycle = + List.fold_left + (fun (c1, active) (c2, pk) -> + if Cycle_repr.(c1 < c2 && c2 <= cycle) then (c2, pk) else (c1, active)) + (current_level.cycle, active.consensus_pk) + pendings + in + return active_for_cycle + +let active_pubkey_for_cycle ctxt delegate cycle = + let open Lwt_tzresult_syntax in + let* _, consensus_pk = raw_active_pubkey_for_cycle ctxt delegate cycle in + return + { + consensus_pk; + consensus_pkh = Signature.Public_key.hash consensus_pk; + delegate; + } + +let register_update ctxt delegate pk = + let open Lwt_tzresult_syntax in + let update_cycle = + let current_level = Raw_context.current_level ctxt in + let preserved_cycles = Constants_storage.preserved_cycles ctxt in + Cycle_repr.add current_level.cycle (preserved_cycles + 1) + in + let* () = + let* first_active_cycle, active_pubkey = + raw_active_pubkey_for_cycle ctxt delegate update_cycle + in + fail_when + Signature.Public_key.(pk = active_pubkey) + (Invalid_consensus_key_update_noop first_active_cycle) + in + let pkh = Signature.Public_key.hash pk in + let* () = check_inactive ctxt pkh in + let*! ctxt = set_active ctxt pkh in + let* {consensus_pkh = old_pkh; _} = + active_pubkey_for_cycle ctxt delegate update_cycle + in + let*! ctxt = set_inactive ctxt old_pkh in + let*! ctxt = + Storage.Contract.Pending_consensus_keys.add + (ctxt, Contract_repr.Implicit delegate) + update_cycle + pk + in + return ctxt + +let activate ctxt ~new_cycle = + let open Lwt_tzresult_syntax in + Storage.Delegates.fold + ctxt + ~order:`Undefined + ~init:(ok ctxt) + ~f:(fun delegate ctxt -> + let*? ctxt = ctxt in + let delegate = Contract_repr.Implicit delegate in + let* update = + Storage.Contract.Pending_consensus_keys.find (ctxt, delegate) new_cycle + in + match update with + | None -> return ctxt + | Some pk -> + let*! ctxt = Storage.Contract.Consensus_key.add ctxt delegate pk in + let*! ctxt = + Storage.Contract.Pending_consensus_keys.remove + (ctxt, delegate) + new_cycle + in + return ctxt) diff --git a/src/proto_alpha/lib_protocol/delegate_consensus_key.mli b/src/proto_alpha/lib_protocol/delegate_consensus_key.mli new file mode 100644 index 0000000000000000000000000000000000000000..babfeb0349e1dd0157a86c71fb3dd1c54c0db2ab --- /dev/null +++ b/src/proto_alpha/lib_protocol/delegate_consensus_key.mli @@ -0,0 +1,87 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 G.B. Fefe, *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +type error += + | Invalid_consensus_key_update_noop of Cycle_repr.t + | Invalid_consensus_key_update_active + +(** The public key of a consensus key and the associated delegate. *) +type pk = Raw_context.consensus_pk = { + delegate : Signature.Public_key_hash.t; + consensus_pk : Signature.Public_key.t; + consensus_pkh : Signature.Public_key_hash.t; +} + +(** The public key hash of a consensus key and the associated delegate. *) +type t = { + delegate : Signature.Public_key_hash.t; + consensus_pkh : Signature.Public_key_hash.t; +} + +val zero : t + +val pp : Format.formatter -> t -> unit + +val pkh : pk -> t + +(** Initialize the consensus key when registering a delegate. *) +val init : + Raw_context.t -> + Signature.Public_key_hash.t -> + Signature.Public_key.t -> + Raw_context.t tzresult Lwt.t + +(** Returns the active consensus key for the current cycle. *) +val active_pubkey : + Raw_context.t -> Signature.Public_key_hash.t -> pk tzresult Lwt.t + +(** Returns the active consensus key for the current cycle. *) +val active_key : + Raw_context.t -> Signature.Public_key_hash.t -> t tzresult Lwt.t + +(** Returns the active consensus key for the given cycle. *) +val active_pubkey_for_cycle : + Raw_context.t -> + Signature.Public_key_hash.t -> + Cycle_repr.t -> + pk tzresult Lwt.t + +(** Returns the list of pending consensus-key updates in upcoming cycles. *) +val pending_updates : + Raw_context.t -> + Signature.Public_key_hash.t -> + (Cycle_repr.t * Signature.Public_key_hash.t) list tzresult Lwt.t + +(** Register a consensus-key update. *) +val register_update : + Raw_context.t -> + Signature.Public_key_hash.t -> + Signature.Public_key.t -> + Raw_context.t tzresult Lwt.t + +(** Activate consensus keys at the beginning of cycle [new_cycle]. + This function iterates on all registered delegates. *) +val activate : + Raw_context.t -> new_cycle:Cycle_repr.t -> Raw_context.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/delegate_cycles.ml b/src/proto_alpha/lib_protocol/delegate_cycles.ml index 27c1fa572ed7d4b6b5d99576309a64ad5eaf47e0..d64d8628a160bb70b62eaa3361228ad8df4a3bdf 100644 --- a/src/proto_alpha/lib_protocol/delegate_cycles.ml +++ b/src/proto_alpha/lib_protocol/delegate_cycles.ml @@ -252,6 +252,7 @@ let cycle_end ctxt last_cycle = let new_cycle = Cycle_repr.add last_cycle 1 in Delegate_sampler.select_new_distribution_at_cycle_end ctxt ~new_cycle >>=? fun ctxt -> + Delegate_consensus_key.activate ctxt ~new_cycle >>=? fun ctxt -> Delegate_slashed_deposits_storage.clear_outdated_slashed_deposits ctxt ~new_cycle @@ -279,3 +280,35 @@ let init_first_cycles ctxt ~origin = >>=? fun ctxt -> let cycle = (Raw_context.current_level ctxt).cycle in freeze_deposits ~origin ~new_cycle:cycle ~balance_updates:[] ctxt + +module Migration_from_Kathmandu = struct + let update_delegate pkh ctxt = + let open Lwt_tzresult_syntax in + let*? ctxt = ctxt in + let* pk = Contract_manager_storage.get_manager_key ctxt pkh in + Delegate_consensus_key.init ctxt pkh pk + + let update ctxt = + let open Lwt_tzresult_syntax in + let* ctxt = + Delegate_storage.fold + ctxt + ~order:`Undefined + ~f:update_delegate + ~init:(ok ctxt) + in + let*! cycles = + Storage.Migration_from_Kathmandu.Delegate_sampler_state.keys ctxt + in + let*! ctxt = + Storage.Migration_from_Kathmandu.Delegate_sampler_state.clear ctxt + in + let*? ctxt = Raw_context.Migration_from_Kathmandu.reset_samplers ctxt in + let* ctxt = + List.fold_left_es + Delegate_sampler.Migration_from_Kathmandu.update_sampler + ctxt + cycles + in + return ctxt +end diff --git a/src/proto_alpha/lib_protocol/delegate_cycles.mli b/src/proto_alpha/lib_protocol/delegate_cycles.mli index 1b7f8a87bad6cc85ca7982ef207c33d5e6fb0ae0..679b87f5a7458f27cda328fb3bcdc38a3e326652 100644 --- a/src/proto_alpha/lib_protocol/delegate_cycles.mli +++ b/src/proto_alpha/lib_protocol/delegate_cycles.mli @@ -49,3 +49,7 @@ val init_first_cycles : Raw_context.t -> origin:Receipt_repr.update_origin -> (Raw_context.t * Receipt_repr.balance_updates) tzresult Lwt.t + +module Migration_from_Kathmandu : sig + val update : Raw_context.t -> Raw_context.t tzresult Lwt.t +end diff --git a/src/proto_alpha/lib_protocol/delegate_sampler.ml b/src/proto_alpha/lib_protocol/delegate_sampler.ml index 104bdd6312d1d49d8af0235a9e4fc05c464a71b2..827c81a7a9f0cbd171457fa73b19727ff952a384 100644 --- a/src/proto_alpha/lib_protocol/delegate_sampler.ml +++ b/src/proto_alpha/lib_protocol/delegate_sampler.ml @@ -27,8 +27,7 @@ module Delegate_sampler_state = struct module Cache_client = struct - type cached_value = - (Signature.Public_key.t * Signature.Public_key_hash.t) Sampler.t + type cached_value = Delegate_consensus_key.pk Sampler.t let namespace = Cache_repr.create_namespace "sampler_state" @@ -133,8 +132,8 @@ module Random = struct let elt, _ = take_int64 mass_bound state in (Int64.to_int i, elt) in - let pk, pkh = Sampler.sample state sample in - return (c, (pk, pkh)) + let pk = Sampler.sample state sample in + return (c, pk) end let slot_owner c level slot = Random.owner c level (Slot_repr.to_int slot) @@ -216,8 +215,8 @@ let select_distribution_for_cycle ctxt cycle = >>=? fun ctxt -> List.fold_left_es (fun acc (pkh, stake) -> - Delegate_storage.pubkey ctxt pkh >|=? fun pk -> - ((pk, pkh), Tez_repr.to_mutez stake) :: acc) + Delegate_consensus_key.active_pubkey_for_cycle ctxt pkh cycle + >|=? fun pk -> (pk, Tez_repr.to_mutez stake) :: acc) [] stakes >>=? fun stakes_pk -> @@ -238,3 +237,21 @@ let clear_outdated_sampling_data ctxt ~new_cycle = | Some outdated_cycle -> Delegate_sampler_state.remove_existing ctxt outdated_cycle >>=? fun ctxt -> Seed_storage.remove_for_cycle ctxt outdated_cycle + +module Migration_from_Kathmandu = struct + let update_sampler ctxt cycle = + let open Lwt_tzresult_syntax in + let* stakes = Stake_storage.get_selected_distribution ctxt cycle in + let* stakes_pk = + List.fold_left_es + (fun acc (delegate, stake) -> + Delegate_consensus_key.active_pubkey ctxt delegate >>=? fun pk -> + return ((pk, Tez_repr.to_mutez stake) :: acc)) + [] + stakes + in + let state = Sampler.create stakes_pk in + Delegate_sampler_state.init ctxt cycle state >>=? fun ctxt -> + Storage.Seed.For_cycle.get ctxt cycle >>=? fun seed -> + Lwt.return (Raw_context.init_sampler_for_cycle ctxt cycle seed state) +end diff --git a/src/proto_alpha/lib_protocol/delegate_sampler.mli b/src/proto_alpha/lib_protocol/delegate_sampler.mli index b011b056c2b64aa5b71b05251b7e16b3e975cdf6..53a8386f1ec5cd858b42b50c0cab6406bbb89242 100644 --- a/src/proto_alpha/lib_protocol/delegate_sampler.mli +++ b/src/proto_alpha/lib_protocol/delegate_sampler.mli @@ -45,18 +45,13 @@ val slot_owner : Raw_context.t -> Level_repr.t -> Slot_repr.t -> - (Raw_context.t * (Signature.public_key * Signature.public_key_hash)) tzresult - Lwt.t + (Raw_context.t * Delegate_consensus_key.pk) tzresult Lwt.t val baking_rights_owner : Raw_context.t -> Level_repr.t -> round:Round_repr.round -> - (Raw_context.t - * Slot_repr.t - * (Signature.public_key * Signature.public_key_hash)) - tzresult - Lwt.t + (Raw_context.t * Slot_repr.t * Delegate_consensus_key.pk) tzresult Lwt.t (** [compute_snapshot_index ctxt cycle max_snapshot_index] Returns the index of the selected snapshot for the [cycle] passed as argument, and for the max @@ -73,3 +68,8 @@ val clear_outdated_sampling_data : val select_distribution_for_cycle : Raw_context.t -> Cycle_repr.t -> Raw_context.t tzresult Lwt.t + +module Migration_from_Kathmandu : sig + val update_sampler : + Raw_context.t -> Cycle_repr.t -> Raw_context.t tzresult Lwt.t +end diff --git a/src/proto_alpha/lib_protocol/delegate_services.ml b/src/proto_alpha/lib_protocol/delegate_services.ml index 5efd3ecbe425df52ee6d5afeabc2a87dbe0aa507..3388da4761e40c6e3d5c332605db282b6cb6b949 100644 --- a/src/proto_alpha/lib_protocol/delegate_services.ml +++ b/src/proto_alpha/lib_protocol/delegate_services.ml @@ -83,6 +83,8 @@ type info = { deactivated : bool; grace_period : Cycle.t; voting_info : Vote.delegate_info; + active_consensus_key : Signature.Public_key_hash.t; + pending_consensus_keys : (Cycle.t * Signature.Public_key_hash.t) list; } let info_encoding = @@ -99,6 +101,8 @@ let info_encoding = deactivated; grace_period; voting_info; + active_consensus_key; + pending_consensus_keys; } -> ( ( full_balance, current_frozen_deposits, @@ -109,7 +113,7 @@ let info_encoding = delegated_balance, deactivated, grace_period ), - voting_info )) + (voting_info, (active_consensus_key, pending_consensus_keys)) )) (fun ( ( full_balance, current_frozen_deposits, frozen_deposits, @@ -119,7 +123,7 @@ let info_encoding = delegated_balance, deactivated, grace_period ), - voting_info ) -> + (voting_info, (active_consensus_key, pending_consensus_keys)) ) -> { full_balance; current_frozen_deposits; @@ -131,6 +135,8 @@ let info_encoding = deactivated; grace_period; voting_info; + active_consensus_key; + pending_consensus_keys; }) (merge_objs (obj9 @@ -143,7 +149,17 @@ let info_encoding = (req "delegated_balance" Tez.encoding) (req "deactivated" bool) (req "grace_period" Cycle.encoding)) - Vote.delegate_info_encoding) + (merge_objs + Vote.delegate_info_encoding + (obj2 + (req "active_consensus_key" Signature.Public_key_hash.encoding) + (dft + "pending_consensus_keys" + (list + (obj2 + (req "cycle" Cycle.encoding) + (req "pkh" Signature.Public_key_hash.encoding))) + [])))) let participation_info_encoding = let open Data_encoding in @@ -331,6 +347,25 @@ module S = struct ~output:Vote.delegate_info_encoding RPC_path.(path / "voting_info") + let consensus_key = + RPC_service.get_service + ~description: + "The active consensus key for a given delegate and the pending \ + consensus keys." + ~query:RPC_query.empty + ~output: + Data_encoding.( + obj2 + (req "active" Signature.Public_key_hash.encoding) + (dft + "pendings" + (list + (obj2 + (req "cycle" Cycle.encoding) + (req "pkh" Signature.Public_key_hash.encoding))) + [])) + RPC_path.(path / "consensus_key") + let participation = RPC_service.get_service ~description: @@ -403,7 +438,9 @@ let register () = Delegate.delegated_balance ctxt pkh >>=? fun delegated_balance -> Delegate.deactivated ctxt pkh >>=? fun deactivated -> Delegate.last_cycle_before_deactivation ctxt pkh >>=? fun grace_period -> - Vote.get_delegate_info ctxt pkh >|=? fun voting_info -> + Vote.get_delegate_info ctxt pkh >>=? fun voting_info -> + Delegate.Consensus_key.active_pubkey ctxt pkh >>=? fun consensus_key -> + Delegate.Consensus_key.pending_updates ctxt pkh >|=? fun pendings -> { full_balance; current_frozen_deposits = frozen_deposits.current_amount; @@ -415,6 +452,8 @@ let register () = deactivated; grace_period; voting_info; + active_consensus_key = consensus_key.consensus_pkh; + pending_consensus_keys = pendings; }) ; register1 ~chunked:false S.full_balance (fun ctxt pkh () () -> trace (Balance_rpc_non_delegate pkh) (check_delegate_registered ctxt pkh) @@ -451,6 +490,10 @@ let register () = register1 ~chunked:false S.voting_info (fun ctxt pkh () () -> check_delegate_registered ctxt pkh >>=? fun () -> Vote.get_delegate_info ctxt pkh) ; + register1 ~chunked:false S.consensus_key (fun ctxt pkh () () -> + Delegate.Consensus_key.active_pubkey ctxt pkh >>=? fun pk -> + Delegate.Consensus_key.pending_updates ctxt pkh >>=? fun pendings -> + return (pk.consensus_pkh, pendings)) ; register1 ~chunked:false S.participation (fun ctxt pkh () () -> check_delegate_registered ctxt pkh >>=? fun () -> Delegate.participation_info ctxt pkh) @@ -499,5 +542,8 @@ let voting_power ctxt block pkh = let voting_info ctxt block pkh = RPC_context.make_call1 S.voting_info ctxt block pkh () () +let consensus_key ctxt block pkh = + RPC_context.make_call1 S.consensus_key ctxt block pkh () () + let participation ctxt block pkh = RPC_context.make_call1 S.participation ctxt block pkh () () diff --git a/src/proto_alpha/lib_protocol/delegate_services.mli b/src/proto_alpha/lib_protocol/delegate_services.mli index a5eda671e57decec2ab53a7638f5acbf1439dacc..d1d235e47f575ce0281177d9f462168f2956c3f3 100644 --- a/src/proto_alpha/lib_protocol/delegate_services.mli +++ b/src/proto_alpha/lib_protocol/delegate_services.mli @@ -54,6 +54,8 @@ type info = { deactivated : bool; grace_period : Cycle.t; voting_info : Vote.delegate_info; + active_consensus_key : Signature.Public_key_hash.t; + pending_consensus_keys : (Cycle.t * Signature.Public_key_hash.t) list; } val info_encoding : info Data_encoding.t @@ -127,6 +129,14 @@ val voting_info : public_key_hash -> Vote.delegate_info shell_tzresult Lwt.t +val consensus_key : + 'a #RPC_context.simple -> + 'a -> + Signature.Public_key_hash.t -> + (Signature.Public_key_hash.t * (Cycle.t * Signature.Public_key_hash.t) list) + shell_tzresult + Lwt.t + val participation : 'a #RPC_context.simple -> 'a -> diff --git a/src/proto_alpha/lib_protocol/delegate_storage.ml b/src/proto_alpha/lib_protocol/delegate_storage.ml index 28e96c3f2ff1a888a84eb251005c4f946425c4fa..373f18be208bea5e7c9062796f7bf34daeac52ac 100644 --- a/src/proto_alpha/lib_protocol/delegate_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_storage.ml @@ -103,11 +103,11 @@ module Contract = struct Stake_storage.set_active c delegate else let contract = Contract_repr.Implicit delegate in - let* () = - let* is_pk_revealed = - Contract_manager_storage.is_manager_key_revealed c delegate - in - fail_unless is_pk_revealed (Unregistered_delegate delegate) + let* pk = + Contract_manager_storage.get_manager_key + c + ~error:(Unregistered_delegate delegate) + delegate in let* () = let*! is_allocated = Contract_storage.allocated c contract in @@ -122,6 +122,7 @@ module Contract = struct let* c = Contract_delegate_storage.set c contract delegate in let* c = Stake_storage.add_stake c delegate balance_and_frozen_bonds in let*! c = Storage.Delegates.add c delegate in + let* c = Delegate_consensus_key.init c delegate pk in let* c = Stake_storage.set_active c delegate in return c @@ -247,8 +248,33 @@ let delegated_balance ctxt delegate = full_balance ctxt delegate >>=? fun self_staking_balance -> Lwt.return Tez_repr.(staking_balance -? self_staking_balance) -let pubkey ctxt delegate = - Contract_manager_storage.get_manager_key - ctxt - delegate - ~error:(Unregistered_delegate delegate) +let drain ctxt ~delegate ~destination = + let open Lwt_tzresult_syntax in + let*! is_destination_allocated = + Contract_storage.allocated ctxt (Contract_repr.Implicit destination) + in + let delegate_contract = Contract_repr.Implicit delegate in + let* ctxt, _, balance_updates1 = + if not is_destination_allocated then + Fees_storage.burn_origination_fees + ctxt + ~storage_limit:(Z.of_int (Constants_storage.origination_size ctxt)) + ~payer:(`Contract delegate_contract) + else return (ctxt, Z.zero, []) + in + let* manager_balance = spendable_balance ctxt delegate in + let*? one_percent = Tez_repr.(manager_balance /? 100L) in + let fees = Tez_repr.(max one one_percent) in + let*? transfered = Tez_repr.(manager_balance -? fees) in + let* ctxt, balance_updates2 = + Token.transfer + ctxt + (`Contract delegate_contract) + (`Contract (Contract_repr.Implicit destination)) + transfered + in + return + ( ctxt, + not is_destination_allocated, + fees, + balance_updates1 @ balance_updates2 ) diff --git a/src/proto_alpha/lib_protocol/delegate_storage.mli b/src/proto_alpha/lib_protocol/delegate_storage.mli index 784d7732f492b8c411fe88145fcf5c2f5a3836cf..9d809e26660571cb67c417fdae7b82f3a3068982 100644 --- a/src/proto_alpha/lib_protocol/delegate_storage.mli +++ b/src/proto_alpha/lib_protocol/delegate_storage.mli @@ -144,9 +144,9 @@ val full_balance : val delegated_balance : Raw_context.t -> Signature.Public_key_hash.t -> Tez_repr.t tzresult Lwt.t -(** Returns the public key of a registered delegate. Returns the error - {!Contract.Unregistered_delegate} if the delegate is not registered. *) -val pubkey : +val drain : Raw_context.t -> - Signature.Public_key_hash.t -> - Signature.Public_key.t tzresult Lwt.t + delegate:Signature.Public_key_hash.t -> + destination:Signature.Public_key_hash.t -> + (Raw_context.t * bool * Tez_repr.t * Receipt_repr.balance_updates) tzresult + Lwt.t diff --git a/src/proto_alpha/lib_protocol/dune b/src/proto_alpha/lib_protocol/dune index c9b2bfe301fa24fe8741363a311d6e15edd6fd3a..06601b32c5d3d79478d2c47b37d42b4df203ea75 100644 --- a/src/proto_alpha/lib_protocol/dune +++ b/src/proto_alpha/lib_protocol/dune @@ -154,6 +154,8 @@ Stake_storage Contract_storage Token + Fees_storage + Delegate_consensus_key Delegate_storage Delegate_sampler Delegate_missed_endorsements_storage @@ -161,7 +163,6 @@ Delegate_cycles Bootstrap_storage Vote_storage - Fees_storage Ticket_storage Liquidity_baking_storage Liquidity_baking_cpmm @@ -412,6 +413,8 @@ stake_storage.ml stake_storage.mli contract_storage.ml contract_storage.mli token.ml token.mli + fees_storage.ml fees_storage.mli + delegate_consensus_key.ml delegate_consensus_key.mli delegate_storage.ml delegate_storage.mli delegate_sampler.ml delegate_sampler.mli delegate_missed_endorsements_storage.ml @@ -420,7 +423,6 @@ delegate_cycles.ml delegate_cycles.mli bootstrap_storage.ml bootstrap_storage.mli vote_storage.ml vote_storage.mli - fees_storage.ml fees_storage.mli ticket_storage.ml ticket_storage.mli liquidity_baking_storage.ml liquidity_baking_storage.mli liquidity_baking_cpmm.ml @@ -651,6 +653,8 @@ stake_storage.ml stake_storage.mli contract_storage.ml contract_storage.mli token.ml token.mli + fees_storage.ml fees_storage.mli + delegate_consensus_key.ml delegate_consensus_key.mli delegate_storage.ml delegate_storage.mli delegate_sampler.ml delegate_sampler.mli delegate_missed_endorsements_storage.ml @@ -659,7 +663,6 @@ delegate_cycles.ml delegate_cycles.mli bootstrap_storage.ml bootstrap_storage.mli vote_storage.ml vote_storage.mli - fees_storage.ml fees_storage.mli ticket_storage.ml ticket_storage.mli liquidity_baking_storage.ml liquidity_baking_storage.mli liquidity_baking_cpmm.ml @@ -895,6 +898,8 @@ stake_storage.ml stake_storage.mli contract_storage.ml contract_storage.mli token.ml token.mli + fees_storage.ml fees_storage.mli + delegate_consensus_key.ml delegate_consensus_key.mli delegate_storage.ml delegate_storage.mli delegate_sampler.ml delegate_sampler.mli delegate_missed_endorsements_storage.ml @@ -903,7 +908,6 @@ delegate_cycles.ml delegate_cycles.mli bootstrap_storage.ml bootstrap_storage.mli vote_storage.ml vote_storage.mli - fees_storage.ml fees_storage.mli ticket_storage.ml ticket_storage.mli liquidity_baking_storage.ml liquidity_baking_storage.mli liquidity_baking_cpmm.ml diff --git a/src/proto_alpha/lib_protocol/init_storage.ml b/src/proto_alpha/lib_protocol/init_storage.ml index 39e62b88310bda134abee7529793746a9092449d..e2e048a37e6200b355448582ff551cc25c609167 100644 --- a/src/proto_alpha/lib_protocol/init_storage.ml +++ b/src/proto_alpha/lib_protocol/init_storage.ml @@ -164,7 +164,9 @@ let prepare_first_block _chain_id ctxt ~typecheck ~level ~timestamp = if that is done, do not set Storage.Tenderbake.First_level_of_protocol. *) Raw_level_repr.of_int32 level >>?= fun level -> Storage.Tenderbake.First_level_of_protocol.update ctxt level - >>=? fun ctxt -> return (ctxt, [])) + >>=? fun ctxt -> + Delegate_cycles.Migration_from_Kathmandu.update ctxt >>=? fun ctxt -> + return (ctxt, [])) >>=? fun (ctxt, balance_updates) -> List.fold_right_es patch_script Legacy_script_patches.addresses_to_patch ctxt >>=? fun ctxt -> diff --git a/src/proto_alpha/lib_protocol/level_repr.ml b/src/proto_alpha/lib_protocol/level_repr.ml index 3e69c5dfd1341b4329060de5b214580e27070996..f4cb006b83177b6e8107f31e027f50cbe711b51c 100644 --- a/src/proto_alpha/lib_protocol/level_repr.ml +++ b/src/proto_alpha/lib_protocol/level_repr.ml @@ -342,4 +342,13 @@ module Internal_for_tests = struct let raw_level = level.level in let new_raw_level = Raw_level_repr.add raw_level n in {level with level = new_raw_level} + + let add_cycles ~blocks_per_cycle level n = + { + level with + cycle = Cycle_repr.add level.cycle n; + level = Raw_level_repr.add level.level (n * blocks_per_cycle); + level_position = + Int32.add level.level_position (Int32.of_int (n * blocks_per_cycle)); + } end diff --git a/src/proto_alpha/lib_protocol/level_repr.mli b/src/proto_alpha/lib_protocol/level_repr.mli index 7e98b9653037f2d4cdf46636040e7707721ec346..0c2800556dc296a572ae84f080a6e0f93a58e060 100644 --- a/src/proto_alpha/lib_protocol/level_repr.mli +++ b/src/proto_alpha/lib_protocol/level_repr.mli @@ -114,6 +114,8 @@ val last_of_cycle : cycle_eras:cycle_eras -> level -> bool module Internal_for_tests : sig val add_level : t -> int -> t + + val add_cycles : blocks_per_cycle:int -> t -> int -> t end (**/**) diff --git a/src/proto_alpha/lib_protocol/operation_repr.ml b/src/proto_alpha/lib_protocol/operation_repr.ml index 47f146024877f244f86de862530ef0beb4bfe2e4..386003470779d231c25b865e42f3d8eceedfd799 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.ml +++ b/src/proto_alpha/lib_protocol/operation_repr.ml @@ -76,6 +76,10 @@ module Kind = struct type increase_paid_storage = Increase_paid_storage_kind + type update_consensus_key = Update_consensus_key_kind + + type drain_delegate = Drain_delegate_kind + type failing_noop = Failing_noop_kind type register_global_constant = Register_global_constant_kind @@ -130,6 +134,7 @@ module Kind = struct | Register_global_constant_manager_kind : register_global_constant manager | Set_deposits_limit_manager_kind : set_deposits_limit manager | Increase_paid_storage_manager_kind : increase_paid_storage manager + | Update_consensus_key_manager_kind : update_consensus_key manager | Tx_rollup_origination_manager_kind : tx_rollup_origination manager | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager | Tx_rollup_commit_manager_kind : tx_rollup_commit manager @@ -312,6 +317,12 @@ and _ contents = ballot : Vote_repr.ballot; } -> Kind.ballot contents + | Drain_delegate : { + consensus_key : Signature.Public_key_hash.t; + delegate : Signature.Public_key_hash.t; + destination : Signature.Public_key_hash.t; + } + -> Kind.drain_delegate contents | Failing_noop : string -> Kind.failing_noop contents | Manager_operation : { source : Signature.public_key_hash; @@ -353,6 +364,9 @@ and _ manager_operation = destination : Contract_hash.t; } -> Kind.increase_paid_storage manager_operation + | Update_consensus_key : + Signature.Public_key.t + -> Kind.update_consensus_key manager_operation | Tx_rollup_origination : Kind.tx_rollup_origination manager_operation | Tx_rollup_submit_batch : { tx_rollup : Tx_rollup_repr.t; @@ -479,6 +493,7 @@ let manager_kind : type kind. kind manager_operation -> kind Kind.manager = | Register_global_constant _ -> Kind.Register_global_constant_manager_kind | Set_deposits_limit _ -> Kind.Set_deposits_limit_manager_kind | Increase_paid_storage _ -> Kind.Increase_paid_storage_manager_kind + | Update_consensus_key _ -> Kind.Update_consensus_key_manager_kind | Tx_rollup_origination -> Kind.Tx_rollup_origination_manager_kind | Tx_rollup_submit_batch _ -> Kind.Tx_rollup_submit_batch_manager_kind | Tx_rollup_commit _ -> Kind.Tx_rollup_commit_manager_kind @@ -756,6 +771,21 @@ module Encoding = struct Increase_paid_storage {amount_in_bytes; destination}); } + let update_consensus_key_tag = 6 + + let update_consensus_key_case = + MCase + { + tag = update_consensus_key_tag; + name = "update_consensus_key"; + encoding = obj1 (req "pk" Signature.Public_key.encoding); + select = + (function + | Manager (Update_consensus_key _ as op) -> Some op | _ -> None); + proj = (function Update_consensus_key consensus_pk -> consensus_pk); + inj = (fun consensus_pk -> Update_consensus_key consensus_pk); + } + let tx_rollup_origination_case = MCase { @@ -1511,6 +1541,27 @@ module Encoding = struct Ballot {source; period; proposal; ballot}); } + let drain_delegate_case = + Case + { + tag = 9; + name = "drain_delegate"; + encoding = + obj3 + (req "consensus_key" Signature.Public_key_hash.encoding) + (req "delegate" Signature.Public_key_hash.encoding) + (req "destination" Signature.Public_key_hash.encoding); + select = + (function Contents (Drain_delegate _ as op) -> Some op | _ -> None); + proj = + (function + | Drain_delegate {consensus_key; delegate; destination} -> + (consensus_key, delegate, destination)); + inj = + (fun (consensus_key, delegate, destination) -> + Drain_delegate {consensus_key; delegate; destination}); + } + let failing_noop_case = Case { @@ -1580,6 +1631,9 @@ module Encoding = struct let increase_paid_storage_case = make_manager_case 113 Manager_operations.increase_paid_storage_case + let update_consensus_key_case = + make_manager_case 114 Manager_operations.update_consensus_key_case + let tx_rollup_origination_case = make_manager_case tx_rollup_operation_tag_offset @@ -1709,6 +1763,8 @@ module Encoding = struct make delegation_case; make set_deposits_limit_case; make increase_paid_storage_case; + make update_consensus_key_case; + make drain_delegate_case; make failing_noop_case; make register_global_constant_case; make tx_rollup_origination_case; @@ -1812,6 +1868,7 @@ let acceptable_pass (op : packed_operation) = | Single (Double_preendorsement_evidence _) -> Some anonymous_pass | Single (Double_baking_evidence _) -> Some anonymous_pass | Single (Activate_account _) -> Some anonymous_pass + | Single (Drain_delegate _) -> Some anonymous_pass | Single (Manager_operation _) -> Some manager_pass | Cons (Manager_operation _, _ops) -> Some manager_pass @@ -1901,7 +1958,7 @@ let check_signature (type kind) key chain_id ( Failing_noop _ | Proposals _ | Ballot _ | Seed_nonce_revelation _ | Vdf_revelation _ | Double_endorsement_evidence _ | Double_preendorsement_evidence _ | Double_baking_evidence _ - | Activate_account _ | Manager_operation _ ) -> + | Activate_account _ | Drain_delegate _ | Manager_operation _ ) -> check ~watermark:Generic_operation (Contents_list protocol_data.contents) @@ -1948,6 +2005,8 @@ let equal_manager_operation_kind : | Set_deposits_limit _, _ -> None | Increase_paid_storage _, Increase_paid_storage _ -> Some Eq | Increase_paid_storage _, _ -> None + | Update_consensus_key _, Update_consensus_key _ -> Some Eq + | Update_consensus_key _, _ -> None | Tx_rollup_origination, Tx_rollup_origination -> Some Eq | Tx_rollup_origination, _ -> None | Tx_rollup_submit_batch _, Tx_rollup_submit_batch _ -> Some Eq @@ -2017,6 +2076,8 @@ let equal_contents_kind : type a b. a contents -> b contents -> (a, b) eq option | Proposals _, _ -> None | Ballot _, Ballot _ -> Some Eq | Ballot _, _ -> None + | Drain_delegate _, Drain_delegate _ -> Some Eq + | Drain_delegate _, _ -> None | Failing_noop _, Failing_noop _ -> Some Eq | Failing_noop _, _ -> None | Manager_operation op1, Manager_operation op2 -> ( @@ -2190,6 +2251,9 @@ let consensus_infos_and_hash_from_block_header (bh : Block_header_repr.t) = The [weight] of an {!Activate_account} depends on its public key hash. + The [weight] of an {!Drain_delegate} depends on the public key + hash of the delegate. + The [weight] of {!Manager_operation} depends on its [fee] and [gas_limit] ratio expressed in {!Q.t}. *) type _ weight = @@ -2212,6 +2276,9 @@ type _ weight = | Weight_activate_account : Ed25519.Public_key_hash.t -> anonymous_pass_type weight + | Weight_drain_delegate : + Signature.Public_key_hash.t + -> anonymous_pass_type weight | Weight_manager : Q.t * Signature.public_key_hash -> manager_pass_type weight | Weight_noop : noop_pass_type weight @@ -2328,6 +2395,8 @@ let weight_of : packed_operation -> operation_weight = W (Anonymous, Weight_double_baking double_baking_infos) | Single (Activate_account {id; _}) -> W (Anonymous, Weight_activate_account id) + | Single (Drain_delegate {delegate; _}) -> + W (Anonymous, Weight_drain_delegate delegate) | Single (Manager_operation _) as ops -> let manweight, src = weight_manager ops in W (Manager, Weight_manager (manweight, src)) @@ -2525,37 +2594,49 @@ let compare_anonymous_weight w1 w2 = | Weight_double_endorsement infos1, Weight_double_endorsement infos2 -> compare_round_infos infos1 infos2 | ( ( Weight_double_baking _ | Weight_seed_nonce_revelation _ - | Weight_vdf_revelation _ | Weight_activate_account _ ), + | Weight_vdf_revelation _ | Weight_activate_account _ + | Weight_drain_delegate _ ), (Weight_double_preendorsement _ | Weight_double_endorsement _) ) -> -1 | ( (Weight_double_preendorsement _ | Weight_double_endorsement _), ( Weight_double_baking _ | Weight_seed_nonce_revelation _ - | Weight_vdf_revelation _ | Weight_activate_account _ ) ) -> + | Weight_vdf_revelation _ | Weight_activate_account _ + | Weight_drain_delegate _ ) ) -> 1 | Weight_double_baking infos1, Weight_double_baking infos2 -> compare_baking_infos infos1 infos2 | ( ( Weight_seed_nonce_revelation _ | Weight_vdf_revelation _ - | Weight_activate_account _ ), + | Weight_activate_account _ | Weight_drain_delegate _ ), Weight_double_baking _ ) -> -1 | ( Weight_double_baking _, ( Weight_seed_nonce_revelation _ | Weight_vdf_revelation _ - | Weight_activate_account _ ) ) -> + | Weight_activate_account _ | Weight_drain_delegate _ ) ) -> 1 | Weight_vdf_revelation solution1, Weight_vdf_revelation solution2 -> Seed_repr.compare_vdf_solution solution1 solution2 - | ( (Weight_seed_nonce_revelation _ | Weight_activate_account _), + | ( ( Weight_seed_nonce_revelation _ | Weight_activate_account _ + | Weight_drain_delegate _ ), Weight_vdf_revelation _ ) -> -1 | ( Weight_vdf_revelation _, - (Weight_seed_nonce_revelation _ | Weight_activate_account _) ) -> + ( Weight_seed_nonce_revelation _ | Weight_activate_account _ + | Weight_drain_delegate _ ) ) -> 1 | Weight_seed_nonce_revelation l1, Weight_seed_nonce_revelation l2 -> Compare.Int32.compare l1 l2 - | Weight_activate_account _, Weight_seed_nonce_revelation _ -> -1 - | Weight_seed_nonce_revelation _, Weight_activate_account _ -> 1 + | ( (Weight_activate_account _ | Weight_drain_delegate _), + Weight_seed_nonce_revelation _ ) -> + -1 + | ( Weight_seed_nonce_revelation _, + (Weight_activate_account _ | Weight_drain_delegate _) ) -> + 1 | Weight_activate_account pkh1, Weight_activate_account pkh2 -> Ed25519.Public_key_hash.compare pkh1 pkh2 + | Weight_drain_delegate _, Weight_activate_account _ -> -1 + | Weight_activate_account _, Weight_drain_delegate _ -> 1 + | Weight_drain_delegate pkh1, Weight_drain_delegate pkh2 -> + Signature.Public_key_hash.compare pkh1 pkh2 (** {5 Comparison of valid {!Manager_operation}} *) diff --git a/src/proto_alpha/lib_protocol/operation_repr.mli b/src/proto_alpha/lib_protocol/operation_repr.mli index 1e20a748b11e94283811be7c03bc9d16fbb0adf5..ce9e4cf2089e0a2e74db148ed6a2bfdf7fcedf1b 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.mli +++ b/src/proto_alpha/lib_protocol/operation_repr.mli @@ -106,6 +106,10 @@ module Kind : sig type increase_paid_storage = Increase_paid_storage_kind + type update_consensus_key = Update_consensus_key_kind + + type drain_delegate = Drain_delegate_kind + type failing_noop = Failing_noop_kind type register_global_constant = Register_global_constant_kind @@ -160,6 +164,7 @@ module Kind : sig | Register_global_constant_manager_kind : register_global_constant manager | Set_deposits_limit_manager_kind : set_deposits_limit manager | Increase_paid_storage_manager_kind : increase_paid_storage manager + | Update_consensus_key_manager_kind : update_consensus_key manager | Tx_rollup_origination_manager_kind : tx_rollup_origination manager | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager | Tx_rollup_commit_manager_kind : tx_rollup_commit manager @@ -325,6 +330,15 @@ and _ contents = ballot : Vote_repr.ballot; } -> Kind.ballot contents + (* [Drain_delegate { consensus_key ; delegate ; destination }] + transfers the spendable balance of the [delegate] to [destination] + when [consensus_key] is the active consensus key of [delegate].. *) + | Drain_delegate : { + consensus_key : Signature.Public_key_hash.t; + delegate : Signature.Public_key_hash.t; + destination : Signature.Public_key_hash.t; + } + -> Kind.drain_delegate contents (* Failing_noop: An operation never considered by the state machine and which will always fail at [apply]. This allows end-users to sign arbitrary messages which have no computational semantics. *) @@ -393,6 +407,11 @@ and _ manager_operation = destination : Contract_hash.t; } -> Kind.increase_paid_storage manager_operation + (* [Update_consensus_key pk] updates the consensus key of + the signing delegate to [pk]. *) + | Update_consensus_key : + Signature.Public_key.t + -> Kind.update_consensus_key manager_operation (* [Tx_rollup_origination] allows an implicit contract to originate a new transactional rollup. *) | Tx_rollup_origination : Kind.tx_rollup_origination manager_operation @@ -652,19 +671,19 @@ val compare_by_passes : packed_operation -> packed_operation -> int {!Proposals} > {!Ballot} > {!Double_preendorsement_evidence} > {!Double_endorsement_evidence} > {!Double_baking_evidence} > {!Vdf_revelation} > {!Seed_nonce_revelation} > {!Activate_account} - > {!Manager_operation}. + > {!Drain_delegate} > {!Manager_operation}. {!Endorsement} and {!Preendorsement} are compared by the pair of their [level] and [round] such as the farther to the current state - [level] and [round] is greater;e.g. the greater pair in + [level] and [round] is greater; e.g. the greater pair in lexicographic order being the better. When equal and both operations being of the same kind, we compare their [slot]: the - The smaller begin the better; assuming that the more an endorser has - slots, the smaller is its smaller [slot]. When the pair is equal + The smaller being the better, assuming that the more slots an endorser + has, the smaller is its smallest [slot]. When the pair is equal and comparing an {!Endorsement] to a {!Preendorsement}, the {!Endorsement} is better. - Two {!Dal_slot_availability} are compared in the lexicographic + Two {!Dal_slot_availability} ops are compared in the lexicographic order of the pair of their number of endorsed slots as available and their endorsers. @@ -677,13 +696,15 @@ val compare_by_passes : packed_operation -> packed_operation -> int in the case of equality, they are compared by the hashes of their first denounced block_header. - Two {!Vdf_revelation} are compared as their [solution]. + Two {!Vdf_revelation} ops are compared by their [solution]. - Two {!Seed_nonce_relevation} are compared as their [level]. + Two {!Seed_nonce_relevation} ops are compared by their [level]. - Two {!Activate_account} are compared as their [id]. + Two {!Activate_account} ops are compared by their [id]. - Two {!Manager_operation} are compared in the lexicographic order of + Two {!Drain_delegate} ops are compared by their [delegate]. + + Two {!Manager_operation}s are compared in the lexicographic order of the pair of their [fee]/[gas_limit] ratios and [source]. *) val compare : Operation_hash.t * packed_operation -> @@ -736,6 +757,8 @@ module Encoding : sig val ballot_case : Kind.ballot case + val drain_delegate_case : Kind.drain_delegate case + val failing_noop_case : Kind.failing_noop case val reveal_case : Kind.reveal Kind.manager case @@ -746,6 +769,8 @@ module Encoding : sig val delegation_case : Kind.delegation Kind.manager case + val update_consensus_key_case : Kind.update_consensus_key Kind.manager case + val register_global_constant_case : Kind.register_global_constant Kind.manager case @@ -822,6 +847,10 @@ module Encoding : sig val delegation_case : Kind.delegation case + val update_consensus_key_tag : int + + val update_consensus_key_case : Kind.update_consensus_key case + val register_global_constant_case : Kind.register_global_constant case val set_deposits_limit_case : Kind.set_deposits_limit case diff --git a/src/proto_alpha/lib_protocol/parameters_repr.ml b/src/proto_alpha/lib_protocol/parameters_repr.ml index 3ab238b23d485cbbd3fde4d61e912c767ac80157..13604ffdc600a09776d0be837ec410587da145e2 100644 --- a/src/proto_alpha/lib_protocol/parameters_repr.ml +++ b/src/proto_alpha/lib_protocol/parameters_repr.ml @@ -29,6 +29,7 @@ type bootstrap_account = { public_key : Signature.Public_key.t option; amount : Tez_repr.t; delegate_to : Signature.Public_key_hash.t option; + consensus_key : Signature.Public_key.t option; } type bootstrap_contract = { @@ -60,30 +61,50 @@ let bootstrap_account_encoding = public_key = Some public_key; amount; delegate_to = None; + consensus_key = None; } -> assert ( Signature.Public_key_hash.equal (Signature.Public_key.hash public_key) public_key_hash) ; Some (public_key, amount) - | {public_key = None; _} | {delegate_to = Some _; _} -> None) + | {public_key = None; _} + | {delegate_to = Some _; _} + | {consensus_key = Some _; _} -> + None) (fun (public_key, amount) -> { public_key = Some public_key; public_key_hash = Signature.Public_key.hash public_key; amount; delegate_to = None; + consensus_key = None; }); case (Tag 1) ~title:"Public_key_unknown" (tup2 Signature.Public_key_hash.encoding Tez_repr.encoding) (function - | {public_key_hash; public_key = None; amount; delegate_to = None} -> + | { + public_key_hash; + public_key = None; + amount; + delegate_to = None; + consensus_key = None; + } -> Some (public_key_hash, amount) - | {public_key = Some _; _} | {delegate_to = Some _; _} -> None) + | {public_key = Some _; _} + | {delegate_to = Some _; _} + | {consensus_key = Some _; _} -> + None) (fun (public_key_hash, amount) -> - {public_key = None; public_key_hash; amount; delegate_to = None}); + { + public_key = None; + public_key_hash; + amount; + delegate_to = None; + consensus_key = None; + }); case (Tag 2) ~title:"Public_key_known_with_delegate" @@ -97,19 +118,24 @@ let bootstrap_account_encoding = public_key = Some public_key; amount; delegate_to = Some delegate; + consensus_key = None; } -> assert ( Signature.Public_key_hash.equal (Signature.Public_key.hash public_key) public_key_hash) ; Some (public_key, amount, delegate) - | {public_key = None; _} | {delegate_to = None; _} -> None) + | {public_key = None; _} + | {delegate_to = None; _} + | {consensus_key = Some _; _} -> + None) (fun (public_key, amount, delegate) -> { public_key = Some public_key; public_key_hash = Signature.Public_key.hash public_key; amount; delegate_to = Some delegate; + consensus_key = None; }); case (Tag 3) @@ -124,15 +150,52 @@ let bootstrap_account_encoding = public_key = None; amount; delegate_to = Some delegate; + consensus_key = None; } -> Some (public_key_hash, amount, delegate) - | {public_key = Some _; _} | {delegate_to = None; _} -> None) + | {public_key = Some _; _} + | {delegate_to = None; _} + | {consensus_key = Some _; _} -> + None) (fun (public_key_hash, amount, delegate) -> { public_key = None; public_key_hash; amount; delegate_to = Some delegate; + consensus_key = None; + }); + case + (Tag 4) + ~title:"Public_key_known_with_consensus_key" + (tup3 + Signature.Public_key.encoding + Tez_repr.encoding + Signature.Public_key.encoding) + (function + | { + public_key_hash; + public_key = Some public_key; + amount; + delegate_to = None; + consensus_key = Some consensus_key; + } -> + assert ( + Signature.Public_key_hash.equal + (Signature.Public_key.hash public_key) + public_key_hash) ; + Some (public_key, amount, consensus_key) + | {public_key = None; _} + | {delegate_to = Some _; _} + | {consensus_key = None; _} -> + None) + (fun (public_key, amount, consensus_key) -> + { + public_key = Some public_key; + public_key_hash = Signature.Public_key.hash public_key; + amount; + delegate_to = None; + consensus_key = Some consensus_key; }); ] diff --git a/src/proto_alpha/lib_protocol/parameters_repr.mli b/src/proto_alpha/lib_protocol/parameters_repr.mli index 844e54ba3753ff58c7275b8488c08c881042d703..97bad09f1ccbd3704b1a49070eb9add1674c6576 100644 --- a/src/proto_alpha/lib_protocol/parameters_repr.mli +++ b/src/proto_alpha/lib_protocol/parameters_repr.mli @@ -33,6 +33,7 @@ type bootstrap_account = { public_key : Signature.Public_key.t option; amount : Tez_repr.t; delegate_to : Signature.Public_key_hash.t option; + consensus_key : Signature.Public_key.t option; } (** An originated contract initially existing on a chain since genesis. *) @@ -53,6 +54,8 @@ type t = { no_reward_cycles : int option; } +val bootstrap_account_encoding : bootstrap_account Data_encoding.t + val encoding : t Data_encoding.t val check_params : t -> unit tzresult diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index ce877fef08c7cd828cb3ceb733ac9d04cd8a199d..dc5a33e10d10ed05e1da8df0c14f2e22d6b1ae84 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -73,6 +73,29 @@ module Sc_rollup_address_map_builder = *) +type consensus_pk = { + delegate : Signature.Public_key_hash.t; + consensus_pk : Signature.Public_key.t; + consensus_pkh : Signature.Public_key_hash.t; +} + +let consensus_pk_encoding = + let open Data_encoding in + conv + (fun {delegate; consensus_pk; consensus_pkh} -> + if Signature.Public_key_hash.equal consensus_pkh delegate then + (consensus_pk, None) + else (consensus_pk, Some delegate)) + (fun (consensus_pk, delegate) -> + let consensus_pkh = Signature.Public_key.hash consensus_pk in + let delegate = + match delegate with None -> consensus_pkh | Some del -> del + in + {delegate; consensus_pk; consensus_pkh}) + (obj2 + (req "consensus_pk" Signature.Public_key.encoding) + (opt "delegate" Signature.Public_key_hash.encoding)) + module Raw_consensus = struct (** Consensus operations are indexed by their [initial slots]. Given a delegate, the [initial slot] is the lowest slot assigned to @@ -81,16 +104,12 @@ module Raw_consensus = struct type t = { current_endorsement_power : int; (** Number of endorsement slots recorded for the current block. *) - allowed_endorsements : - (Signature.Public_key.t * Signature.Public_key_hash.t * int) - Slot_repr.Map.t; + allowed_endorsements : (consensus_pk * int) Slot_repr.Map.t; (** Endorsements rights for the current block. Only an endorsement for the lowest slot in the block can be recorded. The map associates to each initial slot the [pkh] associated to this slot with its power. *) - allowed_preendorsements : - (Signature.Public_key.t * Signature.Public_key_hash.t * int) - Slot_repr.Map.t; + allowed_preendorsements : (consensus_pk * int) Slot_repr.Map.t; (** Preendorsements rights for the current block. Only a preendorsement for the lowest slot in the block can be recorded. The map associates to each initial slot the [pkh] associated to this @@ -238,10 +257,7 @@ type back = { unlimited_operation_gas : bool; consensus : Raw_consensus.t; non_consensus_operations_rev : Operation_hash.t list; - sampler_state : - (Seed_repr.seed - * (Signature.Public_key.t * Signature.Public_key_hash.t) Sampler.t) - Cycle_repr.Map.t; + sampler_state : (Seed_repr.seed * consensus_pk Sampler.t) Cycle_repr.Map.t; stake_distribution_for_current_cycle : Tez_repr.t Signature.Public_key_hash.Map.t option; tx_rollup_current_messages : @@ -1286,6 +1302,12 @@ let record_non_consensus_operation_hash ctxt operation_hash = let non_consensus_operations ctxt = List.rev (non_consensus_operations_rev ctxt) +module Migration_from_Kathmandu = struct + let reset_samplers ctxt = + let ctxt = update_sampler_state ctxt Cycle_repr.Map.empty in + ok ctxt +end + let init_sampler_for_cycle ctxt cycle seed state = let map = sampler_state ctxt in if Cycle_repr.Map.mem cycle map then error (Sampler_already_set cycle) @@ -1324,6 +1346,17 @@ module Internal_for_tests = struct let new_level = Level_repr.Internal_for_tests.add_level ctxt.back.level l in let new_back = {ctxt.back with level = new_level} in {ctxt with back = new_back} + + let add_cycles ctxt l = + let blocks_per_cycle = Int32.to_int (constants ctxt).blocks_per_cycle in + let new_level = + Level_repr.Internal_for_tests.add_cycles + ~blocks_per_cycle + ctxt.back.level + l + in + let new_back = {ctxt.back with level = new_level} in + {ctxt with back = new_back} end module type CONSENSUS = sig @@ -1337,20 +1370,18 @@ module type CONSENSUS = sig type round - val allowed_endorsements : - t -> (Signature.Public_key.t * Signature.Public_key_hash.t * int) slot_map + type consensus_pk + + val allowed_endorsements : t -> (consensus_pk * int) slot_map - val allowed_preendorsements : - t -> (Signature.Public_key.t * Signature.Public_key_hash.t * int) slot_map + val allowed_preendorsements : t -> (consensus_pk * int) slot_map val current_endorsement_power : t -> int val initialize_consensus_operation : t -> - allowed_endorsements: - (Signature.Public_key.t * Signature.Public_key_hash.t * int) slot_map -> - allowed_preendorsements: - (Signature.Public_key.t * Signature.Public_key_hash.t * int) slot_map -> + allowed_endorsements:(consensus_pk * int) slot_map -> + allowed_preendorsements:(consensus_pk * int) slot_map -> t val record_grand_parent_endorsement : @@ -1384,7 +1415,8 @@ module Consensus : and type slot := Slot_repr.t and type 'a slot_map := 'a Slot_repr.Map.t and type slot_set := Slot_repr.Set.t - and type round := Round_repr.t = struct + and type round := Round_repr.t + and type consensus_pk := consensus_pk = struct let[@inline] allowed_endorsements ctxt = ctxt.back.consensus.allowed_endorsements @@ -1573,11 +1605,13 @@ module Dal = struct let rec compute_shards ?(index = 0) ctxt ~endorser = let max_shards = ctxt.back.constants.dal.number_of_shards in Slot_repr.Map.fold_e - (fun _ (_, public_key_hash, power) (index, shards) -> + (fun _ (consensus_key, power) (index, shards) -> let limit = Compare.Int.min (index + power) max_shards in (* Early fail when we have reached the desired number of shards *) if Compare.Int.(index >= max_shards) then Error shards - else if Signature.Public_key_hash.(public_key_hash = endorser) then + else if + Signature.Public_key_hash.(consensus_key.consensus_pkh = endorser) + then let shards = Misc.(index --> (limit - 1)) in Ok (index + power, shards) else Ok (index + power, shards)) diff --git a/src/proto_alpha/lib_protocol/raw_context.mli b/src/proto_alpha/lib_protocol/raw_context.mli index f5d85c760b6aaf96db46d4e15972554f0de1063e..b656afe0c09aba4644071c5abf7e532cac0c0070 100644 --- a/src/proto_alpha/lib_protocol/raw_context.mli +++ b/src/proto_alpha/lib_protocol/raw_context.mli @@ -234,14 +234,18 @@ val record_non_consensus_operation_hash : t -> Operation_hash.t -> t val non_consensus_operations : t -> Operation_hash.t list +type consensus_pk = { + delegate : Signature.Public_key_hash.t; + consensus_pk : Signature.Public_key.t; + consensus_pkh : Signature.Public_key_hash.t; +} + +val consensus_pk_encoding : consensus_pk Data_encoding.t + (** [init_sampler_for_cycle ctxt cycle seed state] caches the seeded stake sampler (a.k.a. [seed, state]) for [cycle] in memory for quick access. *) val init_sampler_for_cycle : - t -> - Cycle_repr.t -> - Seed_repr.seed -> - (Signature.public_key * Signature.public_key_hash) Sampler.t -> - t tzresult + t -> Cycle_repr.t -> Seed_repr.seed -> consensus_pk Sampler.t -> t tzresult (** [sampler_for_cycle ~read ctxt cycle] returns the seeded stake sampler for [cycle]. The sampler is read in memory if @@ -250,19 +254,10 @@ val init_sampler_for_cycle : the [read] function and then cached in [ctxt] like [init_sampler_for_cycle]. *) val sampler_for_cycle : - read: - (t -> - (Seed_repr.seed - * (Signature.public_key * Signature.public_key_hash) Sampler.t) - tzresult - Lwt.t) -> + read:(t -> (Seed_repr.seed * consensus_pk Sampler.t) tzresult Lwt.t) -> t -> Cycle_repr.t -> - (t - * Seed_repr.seed - * (Signature.public_key * Signature.public_key_hash) Sampler.t) - tzresult - Lwt.t + (t * Seed_repr.seed * consensus_pk Sampler.t) tzresult Lwt.t (* The stake distribution is stored both in [t] and in the cache. It may be sufficient to only store it in the cache. *) @@ -274,6 +269,8 @@ val init_stake_distribution_for_current_cycle : module Internal_for_tests : sig val add_level : t -> int -> t + + val add_cycles : t -> int -> t end module type CONSENSUS = sig @@ -287,17 +284,17 @@ module type CONSENSUS = sig type round + type consensus_pk + (** Returns a map where each endorser's pkh is associated to the list of its endorsing slots (in decreasing order) for a given level. *) - val allowed_endorsements : - t -> (Signature.Public_key.t * Signature.Public_key_hash.t * int) slot_map + val allowed_endorsements : t -> (consensus_pk * int) slot_map (** Returns a map where each endorser's pkh is associated to the list of its endorsing slots (in decreasing order) for a given level. *) - val allowed_preendorsements : - t -> (Signature.Public_key.t * Signature.Public_key_hash.t * int) slot_map + val allowed_preendorsements : t -> (consensus_pk * int) slot_map (** [endorsement power ctx] returns the endorsement power of the current block. *) @@ -308,10 +305,8 @@ module type CONSENSUS = sig any consensus operation. *) val initialize_consensus_operation : t -> - allowed_endorsements: - (Signature.Public_key.t * Signature.Public_key_hash.t * int) slot_map -> - allowed_preendorsements: - (Signature.Public_key.t * Signature.Public_key_hash.t * int) slot_map -> + allowed_endorsements:(consensus_pk * int) slot_map -> + allowed_preendorsements:(consensus_pk * int) slot_map -> t (** [record_grand_parent_endorsement ctx pkh] records an @@ -373,6 +368,7 @@ module Consensus : and type 'a slot_map := 'a Slot_repr.Map.t and type slot_set := Slot_repr.Set.t and type round := Round_repr.t + and type consensus_pk := consensus_pk module Tx_rollup : sig val add_message : @@ -419,3 +415,7 @@ module Dal : sig [endorser] for the current level. *) val shards : t -> endorser:Signature.Public_key_hash.t -> int list end + +module Migration_from_Kathmandu : sig + val reset_samplers : t -> t tzresult +end diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index 486b9561a512a0e6297df40d3746d5a37f1fc030..97151f463c957bb68192173fe807fbd9fa459579 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -190,6 +190,7 @@ module Contract = struct module Spendable_balance = Indexed_context.Make_map + (Registered) (struct let name = ["balance"] end) @@ -197,6 +198,7 @@ module Contract = struct module Missed_endorsements = Indexed_context.Make_map + (Registered) (struct let name = ["missed_endorsements"] end) @@ -204,13 +206,32 @@ module Contract = struct module Manager = Indexed_context.Make_map + (Registered) (struct let name = ["manager"] end) (Manager_repr) + module Consensus_key = + Indexed_context.Make_map + (Registered) + (struct + let name = ["consensus_key"; "active"] + end) + (Signature.Public_key) + + module Pending_consensus_keys = + Make_indexed_data_storage + (Make_subcontext (Registered) (Indexed_context.Raw_context) + (struct + let name = ["consensus_key"; "pendings"] + end)) + (Make_index (Cycle_repr.Index)) + (Signature.Public_key) + module Delegate = Indexed_context.Make_map + (Registered) (struct let name = ["delegate"] end) @@ -225,6 +246,7 @@ module Contract = struct module Delegate_last_cycle_before_deactivation = Indexed_context.Make_map + (Registered) (struct (* FIXME? Change the key name to reflect the functor's name *) let name = ["delegate_desactivation"] @@ -241,6 +263,7 @@ module Contract = struct module Counter = Indexed_context.Make_map + (Registered) (struct let name = ["counter"] end) @@ -254,8 +277,7 @@ module Contract = struct and type value = Script_repr.lazy_expr and type t := Raw_context.t = struct module I = - Indexed_context.Make_carbonated_map - (N) + Indexed_context.Make_carbonated_map (Registered) (N) (struct type t = Script_repr.lazy_expr @@ -326,6 +348,7 @@ module Contract = struct module Paid_storage_space = Indexed_context.Make_map + (Registered) (struct let name = ["paid_bytes"] end) @@ -333,6 +356,7 @@ module Contract = struct module Used_storage_space = Indexed_context.Make_map + (Registered) (struct let name = ["used_bytes"] end) @@ -340,6 +364,7 @@ module Contract = struct module Frozen_deposits = Indexed_context.Make_map + (Registered) (struct let name = ["frozen_deposits"] end) @@ -347,6 +372,7 @@ module Contract = struct module Frozen_deposits_limit = Indexed_context.Make_map + (Registered) (struct let name = ["frozen_deposits_limit"] end) @@ -362,6 +388,7 @@ module Contract = struct module Frozen_bonds = Bond_id_index.Make_carbonated_map + (Registered) (struct let name = ["frozen_bonds"] end) @@ -371,6 +398,7 @@ module Contract = struct module Total_frozen_bonds = Indexed_context.Make_map + (Registered) (struct let name = ["total_frozen_bonds"] end) @@ -455,6 +483,7 @@ module Big_map = struct module Total_bytes = Indexed_context.Make_map + (Registered) (struct let name = ["total_bytes"] end) @@ -462,6 +491,7 @@ module Big_map = struct module Key_type = Indexed_context.Make_map + (Registered) (struct let name = ["key_type"] end) @@ -473,6 +503,7 @@ module Big_map = struct module Value_type = Indexed_context.Make_map + (Registered) (struct let name = ["value_type"] end) @@ -582,6 +613,7 @@ module Sapling = struct module Total_bytes = Indexed_context.Make_map + (Registered) (struct let name = ["total_bytes"] end) @@ -905,6 +937,14 @@ module Delegates = end)) (Public_key_hash_index) +module Consensus_keys = + Make_data_set_storage + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["consensus_keys"] + end)) + (Public_key_hash_index) + (** Per cycle storage *) type slashed_level = {for_double_endorsing : bool; for_double_baking : bool} @@ -942,6 +982,7 @@ module Cycle = struct module Selected_stake_distribution = Indexed_context.Make_map + (Registered) (struct let name = ["selected_stake_distribution"] end) @@ -958,27 +999,43 @@ module Cycle = struct module Total_active_stake = Indexed_context.Make_map + (Registered) (struct let name = ["total_active_stake"] end) (Tez_repr) - let public_key_with_ghost_hash_encoding = - Data_encoding.conv - fst - (fun x -> (x, Signature.Public_key.hash x)) - Signature.Public_key.encoding + module Migration_from_Kathmandu = struct + let public_key_with_ghost_hash_encoding = + Data_encoding.conv + fst + (fun x -> (x, Signature.Public_key.hash x)) + Signature.Public_key.encoding + + module Delegate_sampler_state = + Indexed_context.Make_map + (Ghost) + (struct + let name = ["delegate_sampler_state"] + end) + (struct + type t = + (Signature.Public_key.t * Signature.Public_key_hash.t) Sampler.t + + let encoding = Sampler.encoding public_key_with_ghost_hash_encoding + end) + end module Delegate_sampler_state = Indexed_context.Make_map + (Registered) (struct let name = ["delegate_sampler_state"] end) (struct - type t = - (Signature.Public_key.t * Signature.Public_key_hash.t) Sampler.t + type t = Raw_context.consensus_pk Sampler.t - let encoding = Sampler.encoding public_key_with_ghost_hash_encoding + let encoding = Sampler.encoding Raw_context.consensus_pk_encoding end) type unrevealed_nonce = { @@ -1025,6 +1082,7 @@ module Cycle = struct module Seed = Indexed_context.Make_map + (Registered) (struct let name = ["random_seed"] end) @@ -1468,6 +1526,7 @@ module Tx_rollup = struct module State = Indexed_context.Make_carbonated_map + (Registered) (struct let name = ["state"] end) @@ -1483,6 +1542,7 @@ module Tx_rollup = struct module Inbox = Level_context.Make_carbonated_map + (Registered) (struct let name = ["inbox"] end) @@ -1494,6 +1554,7 @@ module Tx_rollup = struct module Revealed_withdrawals = Level_context.Make_carbonated_map + (Registered) (struct let name = ["withdrawals"] end) @@ -1501,6 +1562,7 @@ module Tx_rollup = struct module Commitment = Level_context.Make_carbonated_map + (Registered) (struct let name = ["commitment"] end) @@ -1516,6 +1578,7 @@ module Tx_rollup = struct module Commitment_bond = Bond_indexed_context.Make_carbonated_map + (Registered) (struct let name = ["commitment"] end) @@ -1597,6 +1660,7 @@ module Sc_rollup = struct module PVM_kind = Indexed_context.Make_carbonated_map + (Registered) (struct let name = ["kind"] end) @@ -1608,6 +1672,7 @@ module Sc_rollup = struct module Boot_sector = Indexed_context.Make_carbonated_map + (Registered) (struct let name = ["boot_sector"] end) @@ -1619,6 +1684,7 @@ module Sc_rollup = struct module Parameters_type = Indexed_context.Make_carbonated_map + (Registered) (struct let name = ["parameters_type"] end) @@ -1630,6 +1696,7 @@ module Sc_rollup = struct module Genesis_info = Indexed_context.Make_carbonated_map + (Registered) (struct let name = ["genesis_info"] end) @@ -1641,6 +1708,7 @@ module Sc_rollup = struct module Inbox_versioned = Indexed_context.Make_carbonated_map + (Registered) (struct let name = ["inbox"] end) @@ -1657,6 +1725,7 @@ module Sc_rollup = struct module Last_cemented_commitment = Indexed_context.Make_carbonated_map + (Registered) (struct let name = ["last_cemented_commitment"] end) @@ -1684,6 +1753,7 @@ module Sc_rollup = struct module Staker_count = Indexed_context.Make_carbonated_map + (Registered) (struct let name = ["staker_count"] end) @@ -1837,6 +1907,7 @@ module Sc_rollup = struct module Applied_outbox_messages = Level_index_context.Make_carbonated_map + (Registered) (struct let name = ["applied_outbox_messages"] end) @@ -1857,6 +1928,7 @@ module Sc_rollup = struct module Slot_subscriptions = Dal_level_index.Make_map + (Registered) (struct let name = ["slot_subscriptions"] end) @@ -1888,6 +1960,7 @@ module Dal = struct to index each header directly. *) module Slot_headers = Level_context.Make_map + (Registered) (struct let name = ["slots"] end) @@ -1913,6 +1986,7 @@ module Zk_rollup = struct and type key = Zk_rollup_repr.t and type value = Zk_rollup_account_repr.t = Indexed_context.Make_carbonated_map + (Registered) (struct let name = ["account"] end) @@ -1920,6 +1994,7 @@ module Zk_rollup = struct module Pending_list = Indexed_context.Make_carbonated_map + (Registered) (struct let name = ["pending_list"] end) @@ -1983,3 +2058,8 @@ module Zk_rollup = struct (option Ticket_hash_repr.encoding)) end) end + +module Migration_from_Kathmandu = struct + module Delegate_sampler_state = + Cycle.Migration_from_Kathmandu.Delegate_sampler_state +end diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index 8f3757547638fdc644710c80eb497aad9cf3689b..f8362f85abc1930f19fe7eedff4ada300f87f43f 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -104,6 +104,20 @@ module Contract : sig and type value = Manager_repr.t and type t := Raw_context.t + (** The active consensus key of a delegate *) + module Consensus_key : + Indexed_data_storage + with type key = Contract_repr.t + and type value = Signature.Public_key.t + and type t := Raw_context.t + + (** The pending consensus key of a delegate *) + module Pending_consensus_keys : + Indexed_data_storage + with type key = Cycle_repr.t + and type value = Signature.Public_key.t + and type t := Raw_context.t * Contract_repr.t + (** The delegate of a contract, if any. *) module Delegate : Indexed_data_storage @@ -345,6 +359,12 @@ module Delegates : with type t := Raw_context.t and type elt = Signature.Public_key_hash.t +(** Set of all active consensus keys in cycle `current + preserved_cycles + 1` *) +module Consensus_keys : + Data_set_storage + with type t := Raw_context.t + and type elt = Signature.Public_key_hash.t + type slashed_level = {for_double_endorsing : bool; for_double_baking : bool} (** Set used to avoid slashing multiple times the same event *) @@ -399,8 +419,7 @@ end module Delegate_sampler_state : Indexed_data_storage with type key = Cycle_repr.t - and type value = - (Signature.Public_key.t * Signature.Public_key_hash.t) Sampler.t + and type value = Raw_context.consensus_pk Sampler.t and type t := Raw_context.t (** Votes *) @@ -905,3 +924,12 @@ module Zk_rollup : sig and type key = int64 and type value = Zk_rollup_operation_repr.t * Ticket_hash_repr.t option end + +module Migration_from_Kathmandu : sig + module Delegate_sampler_state : + Indexed_data_storage + with type key = Cycle_repr.t + and type value = + (Signature.Public_key.t * Signature.Public_key_hash.t) Sampler.t + and type t := Raw_context.t +end diff --git a/src/proto_alpha/lib_protocol/storage_functors.ml b/src/proto_alpha/lib_protocol/storage_functors.ml index c16ef987af57838d3ca9e2873633b98bac835b5d..5b85863bee77b0d06d7b9ee22a95a3c222c99e22 100644 --- a/src/proto_alpha/lib_protocol/storage_functors.ml +++ b/src/proto_alpha/lib_protocol/storage_functors.ml @@ -885,7 +885,7 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX) : Data_encoding.bool end - module Make_map (N : NAME) (V : VALUE) : + module Make_map (R : REGISTER) (N : NAME) (V : VALUE) : Indexed_data_storage with type t = t and type key = key and type value = V.t = struct type t = C.t @@ -969,15 +969,19 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX) : let () = let open Storage_description in let unpack = unpack I.args in + let description = + if R.ghost then Storage_description.create () + else Raw_context.description + in register_value ~get:(fun c -> let c, k = unpack c in find c k) - (register_named_subcontext Raw_context.description N.name) + (register_named_subcontext description N.name) V.encoding end - module Make_carbonated_map (N : NAME) (V : VALUE) : + module Make_carbonated_map (R : REGISTER) (N : NAME) (V : VALUE) : Non_iterable_indexed_carbonated_data_storage with type t = t and type key = key @@ -1096,11 +1100,15 @@ module Make_indexed_subcontext (C : Raw_context.T) (I : INDEX) : let () = let open Storage_description in let unpack = unpack I.args in + let description = + if R.ghost then Storage_description.create () + else Raw_context.description + in register_value ~get:(fun c -> let c, k = unpack c in find c k >|=? fun (_, v) -> v) - (register_named_subcontext Raw_context.description N.name) + (register_named_subcontext description N.name) V.encoding end end diff --git a/src/proto_alpha/lib_protocol/storage_sigs.ml b/src/proto_alpha/lib_protocol/storage_sigs.ml index 206b7f7dc86e53ef3145fc5b623829cc6d7c1f27..e85da6645fc92773a27066e576be6a4be91143b2 100644 --- a/src/proto_alpha/lib_protocol/storage_sigs.ml +++ b/src/proto_alpha/lib_protocol/storage_sigs.ml @@ -418,10 +418,10 @@ module type Indexed_raw_context = sig module Make_set (_ : REGISTER) (_ : NAME) : Data_set_storage with type t = t and type elt = key - module Make_map (_ : NAME) (V : VALUE) : + module Make_map (_ : REGISTER) (_ : NAME) (V : VALUE) : Indexed_data_storage with type t = t and type key = key and type value = V.t - module Make_carbonated_map (_ : NAME) (V : VALUE) : + module Make_carbonated_map (_ : REGISTER) (_ : NAME) (V : VALUE) : Non_iterable_indexed_carbonated_data_storage with type t = t and type key = key diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.ml b/src/proto_alpha/lib_protocol/test/helpers/block.ml index b0cbcd5e536b3b889abf656f5e96c2fd61040696..f5de31e4900b501ee9754ac987dd31d0ff1ffe43 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/block.ml @@ -76,13 +76,16 @@ type baking_mode = Application | Baking let get_next_baker_by_round round block = Plugin.RPC.Baking_rights.get rpc_ctxt ~all:true ~max_round:(round + 1) block >|=? fun bakers -> - let {Plugin.RPC.Baking_rights.delegate = pkh; timestamp; _} = + let {Plugin.RPC.Baking_rights.delegate = pkh; consensus_key; timestamp; _} = WithExceptions.Option.get ~loc:__LOC__ @@ List.find (fun {Plugin.RPC.Baking_rights.round = r; _} -> r = round) bakers in - (pkh, round, WithExceptions.Option.to_exn ~none:(Failure "") timestamp) + ( pkh, + consensus_key, + round, + WithExceptions.Option.to_exn ~none:(Failure "") timestamp ) let get_next_baker_by_account pkh block = Plugin.RPC.Baking_rights.get rpc_ctxt ~delegates:[pkh] block @@ -90,21 +93,42 @@ let get_next_baker_by_account pkh block = (match List.hd bakers with | Some b -> return b | None -> failwith "No slots found for %a" Signature.Public_key_hash.pp pkh) - >>=? fun {Plugin.RPC.Baking_rights.delegate = pkh; timestamp; round; _} -> + >>=? fun { + Plugin.RPC.Baking_rights.delegate = pkh; + consensus_key; + timestamp; + round; + _; + } -> return - (pkh, round, WithExceptions.Option.to_exn ~none:(Failure __LOC__) timestamp) + ( pkh, + consensus_key, + round, + WithExceptions.Option.to_exn ~none:(Failure __LOC__) timestamp ) let get_next_baker_excluding excludes block = Plugin.RPC.Baking_rights.get rpc_ctxt block >|=? fun bakers -> - let {Plugin.RPC.Baking_rights.delegate = pkh; timestamp; round; _} = + let { + Plugin.RPC.Baking_rights.delegate = pkh; + consensus_key; + timestamp; + round; + _; + } = WithExceptions.Option.get ~loc:__LOC__ @@ List.find - (fun {Plugin.RPC.Baking_rights.delegate; _} -> + (fun {Plugin.RPC.Baking_rights.consensus_key; _} -> not - (List.mem ~equal:Signature.Public_key_hash.equal delegate excludes)) + (List.mem + ~equal:Signature.Public_key_hash.equal + consensus_key + excludes)) bakers in - (pkh, round, WithExceptions.Option.to_exn ~none:(Failure "") timestamp) + ( pkh, + consensus_key, + round, + WithExceptions.Option.to_exn ~none:(Failure "") timestamp ) let dispatch_policy = function | By_round r -> get_next_baker_by_round r @@ -120,6 +144,7 @@ let get_round (b : t) = module Forge = struct type header = { baker : public_key_hash; + consensus_key : public_key_hash; (* the signer of the block *) shell : Block_header.shell_header; contents : Block_header.contents; @@ -155,13 +180,15 @@ module Forge = struct context = Context_hash.zero; } - let set_seed_nonce_hash seed_nonce_hash {baker; shell; contents} = - {baker; shell; contents = {contents with seed_nonce_hash}} + let set_seed_nonce_hash seed_nonce_hash + {baker; consensus_key; shell; contents} = + {baker; consensus_key; shell; contents = {contents with seed_nonce_hash}} - let set_baker baker header = {header with baker} + let set_baker baker ?(consensus_key = baker) header = + {header with baker; consensus_key} - let sign_header {baker; shell; contents} = - Account.find baker >|=? fun delegate -> + let sign_header {consensus_key; shell; contents; _} = + Account.find consensus_key >|=? fun signer_account -> let unsigned_bytes = Data_encoding.Binary.to_bytes_exn Block_header.unsigned_encoding @@ -170,7 +197,7 @@ module Forge = struct let signature = Signature.sign ~watermark:Block_header.(to_watermark (Block_header Chain_id.zero)) - delegate.sk + signer_account.sk unsigned_bytes in Block_header.{shell; protocol_data = {contents; signature}} @@ -196,7 +223,8 @@ module Forge = struct | _ -> assert false in let predecessor_round = Fitness.round pred_fitness in - dispatch_policy policy pred >>=? fun (pkh, round, expected_timestamp) -> + dispatch_policy policy pred + >>=? fun (delegate, consensus_key, round, expected_timestamp) -> let timestamp = Option.value ~default:expected_timestamp timestamp in let level = Int32.succ pred.header.shell.level in Raw_level.of_int32 level |> Environment.wrap_tzresult >>?= fun raw_level -> @@ -243,7 +271,7 @@ module Forge = struct ~payload_round () in - {baker = pkh; shell; contents} + {baker = delegate; consensus_key; shell; contents} (* compatibility only, needed by incremental *) let contents ?(proof_of_work_nonce = default_proof_of_work_nonce) @@ -296,7 +324,8 @@ let prepare_main_init_params ?bootstrap_contracts commitments constants let bootstrap_accounts = List.map (fun (Account.{pk; pkh; _}, amount, delegate_to) -> - Default_parameters.make_bootstrap_account (pkh, pk, amount, delegate_to)) + Default_parameters.make_bootstrap_account + (pkh, pk, amount, delegate_to, None)) initial_accounts in let parameters = @@ -684,7 +713,8 @@ let get_application_vstate (pred : t) (operations : Protocol.operation trace) = let get_construction_vstate ?(policy = By_round 0) ?timestamp ?(protocol_data = None) (pred : t) = let open Protocol in - dispatch_policy policy pred >>=? fun (_pkh, _round, expected_timestamp) -> + dispatch_policy policy pred + >>=? fun (_pkh, _ck, _round, expected_timestamp) -> let timestamp = Option.value ~default:expected_timestamp timestamp in Main.begin_construction ~chain_id:Chain_id.zero @@ -811,9 +841,9 @@ let bake_n_with_all_balance_updates ?(baking_mode = Application) ?policy match r with | Transaction_result (Transaction_to_sc_rollup_result _) | Reveal_result _ | Delegation_result _ - | Set_deposits_limit_result _ | Tx_rollup_origination_result _ - | Tx_rollup_submit_batch_result _ | Tx_rollup_commit_result _ - | Tx_rollup_return_bond_result _ + | Update_consensus_key_result _ | Set_deposits_limit_result _ + | Tx_rollup_origination_result _ | Tx_rollup_submit_batch_result _ + | Tx_rollup_commit_result _ | Tx_rollup_return_bond_result _ | Tx_rollup_finalize_commitment_result _ | Tx_rollup_remove_commitment_result _ | Tx_rollup_rejection_result _ | Transfer_ticket_result _ @@ -853,6 +883,7 @@ let bake_n_with_origination_results ?(baking_mode = Application) ?policy n b = function | Successful_manager_result (Reveal_result _) | Successful_manager_result (Delegation_result _) + | Successful_manager_result (Update_consensus_key_result _) | Successful_manager_result (Transaction_result _) | Successful_manager_result (Register_global_constant_result _) | Successful_manager_result (Set_deposits_limit_result _) diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.mli b/src/proto_alpha/lib_protocol/test/helpers/block.mli index 286b91ff5f2d3c39fb650a27997224d0e37d8638..7a381919f32cbf18e3f93cd3517256d6e957bc94 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/block.mli @@ -46,7 +46,11 @@ val to_alpha_ctxt : t -> Alpha_context.t tzresult Lwt.t - [By_round r] selects the baker at round [r] - [By_account pkh] selects the first slot for baker [pkh] - [Excluding pkhs] selects the first baker that doesn't belong to [pkhs] -*) + + Note that bakers can have active consensus keys different from + their regular delegate keys. For the [By_account pkh] policy, [pkh] + refers to the baker's delegate key. However, for the [Excluding pkhs] + policy, [pkhs] refer to the baker's active consensus key. *) type baker_policy = | By_round of int | By_account of public_key_hash @@ -63,7 +67,7 @@ type baking_mode = Application | Baking val get_next_baker : ?policy:baker_policy -> t -> - (public_key_hash * int * Time.Protocol.t) tzresult Lwt.t + (public_key_hash * public_key_hash * int * Time.Protocol.t) tzresult Lwt.t val get_round : block -> Round.t tzresult @@ -97,7 +101,11 @@ module Forge : sig val set_seed_nonce_hash : Nonce_hash.t option -> header -> header (** Sets the baker that will sign the header to an arbitrary pkh *) - val set_baker : public_key_hash -> header -> header + val set_baker : + public_key_hash -> + ?consensus_key:Signature.public_key_hash -> + header -> + header (** Signs the header with the key of the baker configured in the header. The header can no longer be modified, only applied. *) diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.ml b/src/proto_alpha/lib_protocol/test/helpers/context.ml index aecb15ac3237a4b2c9a36199e6801632819ad44e..7f141b3731387bb6be80d9fe745f78bf8d10ae04 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/context.ml @@ -340,6 +340,8 @@ module Delegate = struct deactivated : bool; grace_period : Cycle.t; voting_info : Alpha_context.Vote.delegate_info; + active_consensus_key : Signature.Public_key_hash.t; + pending_consensus_keys : (Cycle.t * Signature.Public_key_hash.t) list; } let info ctxt pkh = Delegate_services.info rpc_ctxt ctxt pkh @@ -362,6 +364,8 @@ module Delegate = struct let voting_info ctxt d = Alpha_services.Delegate.voting_info rpc_ctxt ctxt d + let consensus_key ctxt pkh = Delegate_services.consensus_key rpc_ctxt ctxt pkh + let participation ctxt pkh = Delegate_services.participation rpc_ctxt ctxt pkh end @@ -521,7 +525,7 @@ let init_with_constants_gen tup constants = List.map (fun (acc, tez, delegate_to) -> Default_parameters.make_bootstrap_account - (acc.Account.pkh, acc.Account.pk, tez, delegate_to)) + (acc.Account.pkh, acc.Account.pk, tez, delegate_to, None)) accounts in let parameters = @@ -544,7 +548,8 @@ let default_raw_context () = let bootstrap_accounts = List.map (fun (Account.{pk; pkh; _}, amount, delegate_to) -> - Default_parameters.make_bootstrap_account (pkh, pk, amount, delegate_to)) + Default_parameters.make_bootstrap_account + (pkh, pk, amount, delegate_to, None)) initial_accounts in Block.prepare_initial_context_params initial_accounts diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.mli b/src/proto_alpha/lib_protocol/test/helpers/context.mli index 68506b9f04efb6aa2a65f8f5fcaeeb841d97dbc5..31b691bc5ff6417ca4b68e33fdb027edf7dea414 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/context.mli @@ -177,6 +177,8 @@ module Delegate : sig deactivated : bool; grace_period : Cycle.t; voting_info : Vote.delegate_info; + active_consensus_key : Signature.Public_key_hash.t; + pending_consensus_keys : (Cycle.t * Signature.Public_key_hash.t) list; } val info : t -> public_key_hash -> Delegate_services.info tzresult Lwt.t @@ -198,6 +200,11 @@ module Delegate : sig val voting_info : t -> public_key_hash -> Vote.delegate_info tzresult Lwt.t + val consensus_key : + t -> + public_key_hash -> + (public_key_hash * (Cycle.t * public_key_hash) list) tzresult Lwt.t + val participation : t -> public_key_hash -> Delegate.participation_info tzresult Lwt.t end diff --git a/src/proto_alpha/lib_protocol/test/helpers/incremental.ml b/src/proto_alpha/lib_protocol/test/helpers/incremental.ml index 3d7ca909ee79924cc528606b0f7f931d1ad9c68b..f3ebdd9db24a3f478977f4800be62f361772c3bd 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/incremental.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/incremental.ml @@ -74,7 +74,7 @@ let set_alpha_ctxt st ctxt = let begin_construction ?timestamp ?seed_nonce_hash ?(mempool_mode = false) ?(policy = Block.By_round 0) (predecessor : Block.t) = Block.get_next_baker ~policy predecessor - >>=? fun (delegate, round, real_timestamp) -> + >>=? fun (delegate, _consensus_key, round, real_timestamp) -> Account.find delegate >>=? fun delegate -> Round.of_int round |> Environment.wrap_tzresult >>?= fun payload_round -> let timestamp = Option.value ~default:real_timestamp timestamp in diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 25609b41682f5a7e33ddb50e95eb01c9e929a9e5..7eab0f71f8d2937a86b62089b08b154edd71fc9b 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -983,3 +983,25 @@ let zk_rollup_origination ?force_reveal ?counter ?fee ?gas_limit ?storage_limit Context.Contract.manager ctxt src >|=? fun account -> let op = sign account.sk ctxt to_sign_op in originated_zk_rollup op |> fun addr -> (op, addr) + +let update_consensus_key ?force_reveal ?counter ?fee ?gas_limit ?storage_limit + ctxt (src : Contract.t) pkh = + manager_operation + ?force_reveal + ?counter + ?fee + ?gas_limit + ?storage_limit + ~source:src + ctxt + (Update_consensus_key pkh) + >>=? fun to_sign_op -> + Context.Contract.manager ctxt src >|=? fun account -> + sign account.sk ctxt to_sign_op + +let drain_delegate ctxt ~consensus_key ~delegate ~destination = + let contents = + Single (Drain_delegate {consensus_key; delegate; destination}) + in + Context.Contract.manager ctxt (Contract.Implicit consensus_key) + >|=? fun account -> sign account.sk ctxt (Contents_list contents) diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 07c47a75307e06e774784a00ff0f0ec7a32b1257..43be79111161e513d17d9765868016d8f3ef3353 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -716,3 +716,21 @@ val zk_rollup_origination : init_state:Zk_rollup.State.t -> nb_ops:int -> (Operation.packed * Zk_rollup.t) tzresult Lwt.t + +val update_consensus_key : + ?force_reveal:bool -> + ?counter:counter -> + ?fee:Tez.t -> + ?gas_limit:gas_limit -> + ?storage_limit:counter -> + Context.t -> + Contract.t -> + public_key -> + (packed_operation, tztrace) result Lwt.t + +val drain_delegate : + Context.t -> + consensus_key:Signature.Public_key_hash.t -> + delegate:Signature.Public_key_hash.t -> + destination:Signature.Public_key_hash.t -> + packed_operation tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/main.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/main.ml index 5218657ab34ef792709b63805b8e9d13fd42ff23..04f2209b8b9d807905d67972ab831d3219e7ad09 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/main.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/main.ml @@ -46,5 +46,6 @@ let () = ("helpers rpcs", Test_helpers_rpcs.tests); ("participation monitoring", Test_participation.tests); ("frozen deposits", Test_frozen_deposits.tests); + ("consensus key", Test_consensus_key.tests); ] |> Lwt_main.run diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_baking.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_baking.ml index 88e2267d7f9d135af56fe1bda7215c229b5acfc6..d029b34d9335f94c22330270cf2ef37dda642b9f 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_baking.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_baking.ml @@ -344,7 +344,7 @@ let test_committee_sampling () = List.map (fun (acc, tez, delegate_to) -> Default_parameters.make_bootstrap_account - (acc.Account.pkh, acc.Account.pk, tez, delegate_to)) + (acc.Account.pkh, acc.Account.pk, tez, delegate_to, None)) accounts in let consensus_committee_size = max_round in diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_consensus_key.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_consensus_key.ml new file mode 100644 index 0000000000000000000000000000000000000000..0afd74a2d327e8980f449f67034967ff21e39f0f --- /dev/null +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_consensus_key.ml @@ -0,0 +1,240 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (delegate_storage) + Invocation: dune exec \ + src/proto_alpha/lib_protocol/test/integration/consensus/main.exe \ + -- test "^consensus key$" + Subject: consistency of the [Drain_delegate] operation + *) + +open Protocol +open Alpha_context + +let constants = + { + Default_parameters.constants_test with + endorsing_reward_per_slot = Tez.zero; + baking_reward_bonus_per_slot = Tez.zero; + baking_reward_fixed_portion = Tez.zero; + consensus_threshold = 0; + origination_size = 0; + } + +(** Checks that staking balance is sum of delegators' stake. *) +let check_delegate_staking_invariant blk delegate_pkh = + Context.Delegate.staking_balance (B blk) delegate_pkh + >>=? fun delegate_staking_balance -> + Context.Delegate.full_balance (B blk) delegate_pkh + >>=? fun self_staking_balance -> + Context.Delegate.info (B blk) delegate_pkh >>=? fun delegate_info -> + let delegate_contract = Contract.Implicit delegate_pkh in + let delegated_contracts = + List.filter + (fun c -> Contract.(c <> delegate_contract)) + delegate_info.delegated_contracts + in + List.fold_left_es + (fun total pkh -> + Context.Contract.balance_and_frozen_bonds (B blk) pkh + >>=? fun staking_balance -> + Lwt.return Tez.(total +? staking_balance) >|= Environment.wrap_tzresult) + self_staking_balance + delegated_contracts + >>=? fun delegators_stake -> + Assert.equal_tez ~loc:__LOC__ delegate_staking_balance delegators_stake + +let update_consensus_key blk delegate public_key = + let nb_delay_cycles = constants.preserved_cycles + 1 in + Op.update_consensus_key (B blk) (Contract.Implicit delegate) public_key + >>=? fun update_ck -> + Block.bake ~operation:update_ck blk >>=? fun blk' -> + Block.bake_until_n_cycle_end nb_delay_cycles blk' + +let delegate_stake blk source delegate = + Op.delegation (B blk) (Contract.Implicit source) (Some delegate) + >>=? fun delegation -> Block.bake ~operation:delegation blk + +let transfer_tokens blk source destination amount = + Op.transaction + (B blk) + (Contract.Implicit source) + (Contract.Implicit destination) + amount + >>=? fun transfer_op -> Block.bake ~operation:transfer_op blk + +let reveal_manager_key blk pk = + Op.revelation (B blk) pk >>=? fun reveal_op -> + Block.bake ~operation:reveal_op blk + +let drain_delegate ~policy blk consensus_key delegate destination + expected_final_balance = + Op.drain_delegate (B blk) ~consensus_key ~delegate ~destination + >>=? fun drain_del -> + Block.bake ~policy ~operation:drain_del blk >>=? fun blk' -> + check_delegate_staking_invariant blk' delegate >>=? fun () -> + Context.Contract.balance (B blk') (Contract.Implicit delegate) + >>=? fun final_balance -> + Assert.equal_tez ~loc:__LOC__ final_balance expected_final_balance + +let get_first_2_accounts_contracts (a1, a2) = + ((a1, Context.Contract.pkh a1), (a2, Context.Contract.pkh a2)) + +let test_drain_delegate_scenario f = + Context.init_with_constants2 constants >>=? fun (genesis, contracts) -> + let (_contract1, account1_pkh), (_contract2, account2_pkh) = + get_first_2_accounts_contracts contracts + in + let consensus_account = Account.new_account () in + let delegate = account1_pkh in + let consensus_pk = consensus_account.pk in + let consensus_pkh = consensus_account.pkh in + transfer_tokens genesis account2_pkh consensus_pkh Tez.one_mutez + >>=? fun blk' -> + update_consensus_key blk' delegate consensus_pk >>=? fun blk' -> + f blk' consensus_pkh consensus_pk delegate + +let test_drain_delegate ~low_balance ~exclude_ck ~ck_delegates () = + test_drain_delegate_scenario (fun blk consensus_pkh consensus_pk delegate -> + let policy = + if exclude_ck then Block.Excluding [consensus_pkh] + else Block.By_account delegate + in + (if ck_delegates then + reveal_manager_key blk consensus_pk >>=? fun blk -> + delegate_stake blk consensus_pkh delegate + else return blk) + >>=? fun blk -> + Context.Contract.balance (B blk) (Contract.Implicit delegate) + >>=? fun delegate_balance -> + (if low_balance then + transfer_tokens blk delegate consensus_pkh delegate_balance + >>=? fun blk -> + reveal_manager_key blk consensus_pk >>=? fun blk -> + transfer_tokens blk consensus_pkh delegate Tez.(of_mutez_exn 1_000_000L) + else return blk) + >>=? fun blk -> + Context.Contract.balance (B blk) (Contract.Implicit delegate) + >>=? fun delegate_balance -> + let expected_final_balance = + if exclude_ck then Tez.zero + else Tez.(max one (div_exn delegate_balance 100)) + in + drain_delegate + ~policy + blk + consensus_pkh + delegate + consensus_pkh + expected_final_balance) + +let test_drain_empty_delegate ~exclude_ck () = + test_drain_delegate_scenario (fun blk consensus_pkh _consensus_pk delegate -> + let policy = + if exclude_ck then Block.Excluding [consensus_pkh] + else Block.By_account delegate + in + Context.Contract.balance (B blk) (Contract.Implicit delegate) + >>=? fun delegate_balance -> + transfer_tokens blk delegate consensus_pkh delegate_balance + >>=? fun blk -> + drain_delegate ~policy blk consensus_pkh delegate consensus_pkh Tez.zero + >>= fun res -> + Assert.proto_error_with_info + ~loc:__LOC__ + res + "Drain delegate without enough balance for allocation burn or drain \ + fees") + +let tests = + Tztest. + [ + tztest + "test drain delegate high balance, excluding ck, ck delegates" + `Quick + (test_drain_delegate + ~low_balance:false + ~exclude_ck:true + ~ck_delegates:true); + tztest + "test drain delegate high balance, excluding ck, ck does not delegate" + `Quick + (test_drain_delegate + ~low_balance:false + ~exclude_ck:true + ~ck_delegates:false); + tztest + "test drain delegate high balance, with ck, ck delegates" + `Quick + (test_drain_delegate + ~low_balance:false + ~exclude_ck:false + ~ck_delegates:true); + tztest + "test drain delegate high balance, with ck, ck does not delegate" + `Quick + (test_drain_delegate + ~low_balance:false + ~exclude_ck:false + ~ck_delegates:false); + tztest + "test drain delegate low balance, excluding ck, ck delegates" + `Quick + (test_drain_delegate + ~low_balance:true + ~exclude_ck:true + ~ck_delegates:true); + tztest + "test drain delegate low balance, excluding ck, ck does not delegate" + `Quick + (test_drain_delegate + ~low_balance:true + ~exclude_ck:true + ~ck_delegates:false); + tztest + "test drain delegate low balance, with ck, ck delegates" + `Quick + (test_drain_delegate + ~low_balance:true + ~exclude_ck:false + ~ck_delegates:true); + tztest + "test drain delegate low balance, with ck, ck does not delegate" + `Quick + (test_drain_delegate + ~low_balance:true + ~exclude_ck:false + ~ck_delegates:false); + tztest + "test empty drain delegate excluding ck" + `Quick + (test_drain_empty_delegate ~exclude_ck:true); + tztest + "test empty drain delegate with ck" + `Quick + (test_drain_empty_delegate ~exclude_ck:false); + ] diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_seed.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_seed.ml index a463afc6be59d49a7138b4a78cff6d6532722fa5..4025164abc26b788c55dd191c3f9ef33799414f7 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_seed.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_seed.ml @@ -134,7 +134,7 @@ let test_revelation_early_wrong_right_twice () = csts.parametric.baking_reward_fixed_portion in (* get the pkh of a baker *) - let* pkh, _, _ = Block.get_next_baker b in + let* pkh, _, _, _ = Block.get_next_baker b in let id = Alpha_context.Contract.Implicit pkh in let policy = Block.Excluding [pkh] in (* bake until commitment - 2, excluding id *) @@ -190,7 +190,7 @@ let test_revelation_early_wrong_right_twice () = level_commitment (WithExceptions.Option.to_exn ~none:Not_found @@ Nonce.get committed_hash) in - let* baker_pkh, _, _ = Block.get_next_baker ~policy b in + let* baker_pkh, _, _, _ = Block.get_next_baker ~policy b in let baker = Alpha_context.Contract.Implicit baker_pkh in let* baker_bal = Context.Contract.balance (B b) baker in (* test that revealing twice in a block produces an error *) @@ -243,7 +243,7 @@ let test_revelation_missing_and_late () = (* bake until commitment *) let* b = Block.bake_n (blocks_per_commitment - 2) b in (* the next baker [id] will include a seed_nonce commitment *) - let* pkh, _, _ = Block.get_next_baker b in + let* pkh, _, _, _ = Block.get_next_baker b in let* b = Block.bake b in let*? level_commitment = Context.get_level (B b) in let* committed_hash = Context.get_seed_nonce_hash (B b) in @@ -381,7 +381,7 @@ let test_early_incorrect_unverified_correct_already_vdf () = let seed_nonce_revelation_tip = csts.parametric.seed_nonce_revelation_tip in let vdf_nonce_revelation_tip = csts.parametric.seed_nonce_revelation_tip in (* get the pkh of a baker *) - let* pkh, _, _ = Block.get_next_baker b in + let* pkh, _, _, _ = Block.get_next_baker b in let id = Alpha_context.Contract.Implicit pkh in let policy = Block.Excluding [pkh] in (* bake until commitment - 2, excluding id *) @@ -409,7 +409,7 @@ let test_early_incorrect_unverified_correct_already_vdf () = level_commitment (WithExceptions.Option.to_exn ~none:Not_found @@ Nonce.get committed_hash) in - let* baker_pkh, _, _ = Block.get_next_baker ~policy b in + let* baker_pkh, _, _, _ = Block.get_next_baker ~policy b in let baker = Alpha_context.Contract.Implicit baker_pkh in let* baker_bal = Context.Contract.balance (B b) baker in let* b = Block.bake ~policy:(Block.By_account baker_pkh) ~operation b in diff --git a/src/proto_alpha/lib_protocol/test/integration/validate/manager_operation_helpers.ml b/src/proto_alpha/lib_protocol/test/integration/validate/manager_operation_helpers.ml index 7c59b71b92facefc74e477db86fe14286b1a756b..92f448bbdcbeb1769e45457edc0bf36081f6d182 100644 --- a/src/proto_alpha/lib_protocol/test/integration/validate/manager_operation_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/integration/validate/manager_operation_helpers.ml @@ -77,6 +77,7 @@ type manager_operation_kind = | K_Undelegation | K_Self_delegation | K_Set_deposits_limit + | K_Update_consensus_key | K_Increase_paid_storage | K_Reveal | K_Tx_rollup_origination @@ -176,6 +177,7 @@ let kind_to_string = function | K_Undelegation -> "Undelegation" | K_Self_delegation -> "Self-delegation" | K_Set_deposits_limit -> "Set deposits limit" + | K_Update_consensus_key -> "Update consensus key" | K_Origination -> "Origination" | K_Register_global_constant -> "Register global constant" | K_Increase_paid_storage -> "Increase paid storage" @@ -643,6 +645,19 @@ let mk_set_deposits_limit (oinfos : operation_req) (infos : infos) = (contract_of infos.accounts.source) None +let mk_update_consensus_key (oinfos : operation_req) (infos : infos) = + Op.update_consensus_key + ?force_reveal:oinfos.force_reveal + ?fee:oinfos.fee + ?gas_limit:oinfos.gas_limit + ?storage_limit:oinfos.storage_limit + ?counter:oinfos.counter + (B infos.ctxt.block) + (contract_of infos.accounts.source) + (match infos.accounts.dest with + | None -> infos.accounts.source.pk + | Some dest -> dest.pk) + let mk_increase_paid_storage (oinfos : operation_req) (infos : infos) = Op.increase_paid_storage ?force_reveal:oinfos.force_reveal @@ -1059,6 +1074,7 @@ let select_op (op_req : operation_req) (infos : infos) = | K_Undelegation -> mk_undelegation | K_Self_delegation -> mk_self_delegation | K_Set_deposits_limit -> mk_set_deposits_limit + | K_Update_consensus_key -> mk_update_consensus_key | K_Increase_paid_storage -> mk_increase_paid_storage | K_Reveal -> mk_reveal | K_Tx_rollup_origination -> mk_tx_rollup_origination @@ -1393,6 +1409,7 @@ let subjects = K_Undelegation; K_Self_delegation; K_Set_deposits_limit; + K_Update_consensus_key; K_Increase_paid_storage; K_Reveal; K_Tx_rollup_origination; @@ -1417,14 +1434,15 @@ let subjects = ] let is_consumer = function - | K_Set_deposits_limit | K_Increase_paid_storage | K_Reveal - | K_Self_delegation | K_Delegation | K_Undelegation | K_Tx_rollup_origination - | K_Tx_rollup_submit_batch | K_Tx_rollup_finalize | K_Tx_rollup_commit - | K_Tx_rollup_return_bond | K_Tx_rollup_remove_commitment | K_Tx_rollup_reject - | K_Sc_rollup_add_messages | K_Sc_rollup_origination | K_Sc_rollup_refute - | K_Sc_rollup_timeout | K_Sc_rollup_cement | K_Sc_rollup_publish - | K_Sc_rollup_execute_outbox_message | K_Sc_rollup_recover_bond - | K_Dal_publish_slot_header | K_Zk_rollup_origination -> + | K_Set_deposits_limit | K_Update_consensus_key | K_Increase_paid_storage + | K_Reveal | K_Self_delegation | K_Delegation | K_Undelegation + | K_Tx_rollup_origination | K_Tx_rollup_submit_batch | K_Tx_rollup_finalize + | K_Tx_rollup_commit | K_Tx_rollup_return_bond | K_Tx_rollup_remove_commitment + | K_Tx_rollup_reject | K_Sc_rollup_add_messages | K_Sc_rollup_origination + | K_Sc_rollup_refute | K_Sc_rollup_timeout | K_Sc_rollup_cement + | K_Sc_rollup_publish | K_Sc_rollup_execute_outbox_message + | K_Sc_rollup_recover_bond | K_Dal_publish_slot_header + | K_Zk_rollup_origination -> false | K_Transaction | K_Origination | K_Register_global_constant | K_Tx_rollup_dispatch_tickets | K_Transfer_ticket -> @@ -1439,7 +1457,7 @@ let revealed_subjects = let is_disabled flags = function | K_Transaction | K_Origination | K_Register_global_constant | K_Delegation | K_Undelegation | K_Self_delegation | K_Set_deposits_limit - | K_Increase_paid_storage | K_Reveal -> + | K_Update_consensus_key | K_Increase_paid_storage | K_Reveal -> false | K_Tx_rollup_origination | K_Tx_rollup_submit_batch | K_Tx_rollup_commit | K_Tx_rollup_return_bond | K_Tx_rollup_finalize diff --git a/src/proto_alpha/lib_protocol/test/integration/validate/test_manager_operation_validation.ml b/src/proto_alpha/lib_protocol/test/integration/validate/test_manager_operation_validation.ml index ae497adffc3f3b7f7d861bdda1279ab61a6a469b..26b86c64a4672aa78b5f7bc57df03151fde2f2b4 100644 --- a/src/proto_alpha/lib_protocol/test/integration/validate/test_manager_operation_validation.ml +++ b/src/proto_alpha/lib_protocol/test/integration/validate/test_manager_operation_validation.ml @@ -65,6 +65,7 @@ let ensure_kind infos kind = | Delegation _, K_Self_delegation | Register_global_constant _, K_Register_global_constant | Set_deposits_limit _, K_Set_deposits_limit + | Update_consensus_key _, K_Update_consensus_key | Increase_paid_storage _, K_Increase_paid_storage | Tx_rollup_origination, K_Tx_rollup_origination | Tx_rollup_submit_batch _, K_Tx_rollup_submit_batch @@ -87,16 +88,17 @@ let ensure_kind infos kind = | Zk_rollup_origination _, K_Zk_rollup_origination -> return_unit | ( ( Transaction _ | Origination _ | Register_global_constant _ - | Delegation _ | Set_deposits_limit _ | Increase_paid_storage _ - | Reveal _ | Tx_rollup_origination | Tx_rollup_submit_batch _ - | Tx_rollup_commit _ | Tx_rollup_return_bond _ - | Tx_rollup_finalize_commitment _ | Tx_rollup_remove_commitment _ - | Tx_rollup_dispatch_tickets _ | Transfer_ticket _ - | Tx_rollup_rejection _ | Sc_rollup_originate _ | Sc_rollup_publish _ - | Sc_rollup_cement _ | Sc_rollup_add_messages _ | Sc_rollup_refute _ - | Sc_rollup_timeout _ | Sc_rollup_execute_outbox_message _ - | Sc_rollup_recover_bond _ | Dal_publish_slot_header _ - | Sc_rollup_dal_slot_subscribe _ | Zk_rollup_origination _ ), + | Delegation _ | Set_deposits_limit _ | Update_consensus_key _ + | Increase_paid_storage _ | Reveal _ | Tx_rollup_origination + | Tx_rollup_submit_batch _ | Tx_rollup_commit _ + | Tx_rollup_return_bond _ | Tx_rollup_finalize_commitment _ + | Tx_rollup_remove_commitment _ | Tx_rollup_dispatch_tickets _ + | Transfer_ticket _ | Tx_rollup_rejection _ | Sc_rollup_originate _ + | Sc_rollup_publish _ | Sc_rollup_cement _ | Sc_rollup_add_messages _ + | Sc_rollup_refute _ | Sc_rollup_timeout _ + | Sc_rollup_execute_outbox_message _ | Sc_rollup_recover_bond _ + | Dal_publish_slot_header _ | Sc_rollup_dal_slot_subscribe _ + | Zk_rollup_origination _ ), _ ) -> assert false) | Single _ -> assert false diff --git a/src/proto_alpha/lib_protocol/test/unit/main.ml b/src/proto_alpha/lib_protocol/test/unit/main.ml index 767372e1d70cdf9ca4663d029088defa72f6d88c..b79bb923951867daae09e8026737d8e46d301503 100644 --- a/src/proto_alpha/lib_protocol/test/unit/main.ml +++ b/src/proto_alpha/lib_protocol/test/unit/main.ml @@ -84,5 +84,6 @@ let () = Unit_test.spec "Bond_id_repr.ml" Test_bond_id_repr.tests; Unit_test.spec "zk rollup storage" Test_zk_rollup_storage.tests; Unit_test.spec "compare operations" Test_compare_operations.tests; + Unit_test.spec "Delegate_consensus_key.ml" Test_consensus_key.tests; ] |> Lwt_main.run diff --git a/src/proto_alpha/lib_protocol/test/unit/test_consensus_key.ml b/src/proto_alpha/lib_protocol/test/unit/test_consensus_key.ml new file mode 100644 index 0000000000000000000000000000000000000000..a6769ed0648b555e615c23e54ccd03c99e51316f --- /dev/null +++ b/src/proto_alpha/lib_protocol/test/unit/test_consensus_key.ml @@ -0,0 +1,244 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 G.B. Fefe, *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (delegate_consensus_key) + Invocation: dune exec src/proto_alpha/lib_protocol/test/unit/main.exe \ + -- test "^\[Unit\] Delegate_consensus_key.ml" + Subject: Functions from the module `Delegate_consensus_key` +*) + +open Protocol + +let create () = + let open Lwt_result_syntax in + let accounts = Account.generate_accounts 2 in + let a1, a2 = + match accounts with + | [(a1, _, _); (a2, _, _)] -> (a1, a2) + | _ -> assert false + in + let* ctxt = Block.alpha_context accounts in + return (Alpha_context.Internal_for_tests.to_raw ctxt, a1, a2) + +module Consensus_key = struct + let active_key ctxt pkh = + Delegate_consensus_key.active_key ctxt pkh >|= Environment.wrap_tzresult + + let active_pubkey ctxt pkh = + Delegate_consensus_key.active_pubkey ctxt pkh >|= Environment.wrap_tzresult + + let active_pubkey_for_cycle ctxt pkh cycle = + Delegate_consensus_key.active_pubkey_for_cycle + ctxt + pkh + (Cycle_repr.of_int32_exn (Int32.of_int cycle)) + >|= Environment.wrap_tzresult + + let pending_updates ctxt pkh = + Delegate_consensus_key.pending_updates ctxt pkh + >|= Environment.wrap_tzresult + + let register_update ctxt pkh pk = + Delegate_consensus_key.register_update ctxt pkh pk + >|= Environment.wrap_tzresult + + let activate ctxt ~new_cycle = + Delegate_consensus_key.activate ctxt ~new_cycle + >|= Environment.wrap_tzresult +end + +module Assert = struct + include Assert + + let equal_pkh ~__LOC__ a b = + Assert.equal + ~loc:__LOC__ + Signature.Public_key_hash.equal + "pkh" + Signature.Public_key_hash.pp + a + b + + let equal_pk ~__LOC__ a b = + Assert.equal + ~loc:__LOC__ + Signature.Public_key.equal + "pk" + Signature.Public_key.pp + a + b + + let active_keys ~__LOC__ ctxt delegate l = + List.iter_es + (fun (c, pk) -> + let open Lwt_result_syntax in + let* active_pk = + Consensus_key.active_pubkey_for_cycle ctxt delegate c + in + equal_pk ~__LOC__ active_pk.consensus_pk pk) + l +end + +let rec add_cycles ctxt n = + if n <= 0 then return ctxt + else + let open Lwt_result_syntax in + let current_level = Raw_context.current_level ctxt in + let new_cycle = Cycle_repr.succ current_level.cycle in + let* ctxt = Consensus_key.activate ctxt ~new_cycle in + let ctxt = Raw_context.Internal_for_tests.add_cycles ctxt 1 in + add_cycles ctxt (n - 1) + +let test_consensus_key_storage () = + let open Lwt_result_syntax in + let* ctxt, del1, del2 = create () in + let a1 = Account.new_account () in + let a2 = Account.new_account () in + let preserved_cycles = Constants_storage.preserved_cycles ctxt in + let* () = Assert.equal_int ~loc:__LOC__ preserved_cycles 3 in + let* () = + let* active_pkh = Consensus_key.active_key ctxt del1.pkh in + Assert.equal_pkh ~__LOC__ active_pkh.consensus_pkh del1.pkh + in + let* () = + let* active_pk = Consensus_key.active_pubkey ctxt del1.pkh in + Assert.equal_pk ~__LOC__ active_pk.consensus_pk del1.pk + in + let* () = + let* active_pk = Consensus_key.active_pubkey_for_cycle ctxt del1.pkh 3 in + Assert.equal_pk ~__LOC__ active_pk.consensus_pk del1.pk + in + let* () = + let*! err = Consensus_key.register_update ctxt del1.pkh del2.pk in + Assert.proto_error ~loc:__LOC__ err (function + | Delegate_consensus_key.Invalid_consensus_key_update_active -> true + | _ -> false) + in + let* ctxt = Consensus_key.register_update ctxt del1.pkh a1.pk in + let* () = + let*! err = Consensus_key.register_update ctxt del1.pkh a1.pk in + Assert.proto_error ~loc:__LOC__ err (function + | Delegate_consensus_key.Invalid_consensus_key_update_noop c -> + c = Cycle_repr.of_int32_exn 4l + | _ -> false) + in + let* () = + let*! err = Consensus_key.register_update ctxt del2.pkh a1.pk in + Assert.proto_error ~loc:__LOC__ err (function + | Delegate_consensus_key.Invalid_consensus_key_update_active -> true + | _ -> false) + in + let* ctxt = Consensus_key.register_update ctxt del2.pkh del1.pk in + let* () = + Assert.active_keys + ~__LOC__ + ctxt + del1.pkh + [ + (0, del1.pk); + (1, del1.pk); + (2, del1.pk); + (2, del1.pk); + (3, del1.pk); + (4, a1.pk); + (5, a1.pk); + ] + in + let* ctxt = add_cycles ctxt 1 in + let* () = + let* active_pkh = Consensus_key.active_key ctxt del1.pkh in + Assert.equal_pkh ~__LOC__ active_pkh.consensus_pkh del1.pkh + in + let* () = + let*! err = Consensus_key.register_update ctxt del1.pkh a1.pk in + Assert.proto_error ~loc:__LOC__ err (function + | Delegate_consensus_key.Invalid_consensus_key_update_noop c -> + c = Cycle_repr.of_int32_exn 4l + | _ -> false) + in + let* ctxt = Consensus_key.register_update ctxt del1.pkh a2.pk in + let* ctxt = Consensus_key.register_update ctxt del2.pkh a1.pk in + let* ctxt = Consensus_key.register_update ctxt del2.pkh del2.pk in + let* () = + Assert.active_keys + ~__LOC__ + ctxt + del1.pkh + [ + (1, del1.pk); + (2, del1.pk); + (2, del1.pk); + (3, del1.pk); + (4, a1.pk); + (5, a2.pk); + (6, a2.pk); + ] + in + let* ctxt = add_cycles ctxt 2 in + let* () = + let* active_pkh = Consensus_key.active_key ctxt del1.pkh in + Assert.equal_pkh ~__LOC__ active_pkh.consensus_pkh del1.pkh + in + let* () = + let*! err = Consensus_key.register_update ctxt del1.pkh a2.pk in + Assert.proto_error ~loc:__LOC__ err (function + | Delegate_consensus_key.Invalid_consensus_key_update_noop c -> + c = Cycle_repr.of_int32_exn 5l + | _ -> false) + in + let* ctxt = Consensus_key.register_update ctxt del1.pkh a1.pk in + let* () = + Assert.active_keys + ~__LOC__ + ctxt + del1.pkh + [(3, del1.pk); (4, a1.pk); (5, a2.pk); (6, a2.pk); (7, a1.pk); (8, a1.pk)] + in + let* ctxt = add_cycles ctxt 1 in + let* () = + let* active_pkh = Consensus_key.active_key ctxt del1.pkh in + Assert.equal_pkh ~__LOC__ active_pkh.consensus_pkh a1.pkh + in + let* ctxt = add_cycles ctxt 1 in + let* () = + let* active_pkh = Consensus_key.active_key ctxt del1.pkh in + Assert.equal_pkh ~__LOC__ active_pkh.consensus_pkh a2.pkh + in + let* ctxt = add_cycles ctxt 1 in + let* () = + let* active_pkh = Consensus_key.active_key ctxt del1.pkh in + Assert.equal_pkh ~__LOC__ active_pkh.consensus_pkh a2.pkh + in + let* ctxt = add_cycles ctxt 1 in + let* () = + let* active_pkh = Consensus_key.active_key ctxt del1.pkh in + Assert.equal_pkh ~__LOC__ active_pkh.consensus_pkh a1.pkh + in + return () + +let tests = + [Tztest.tztest "consensus_key_storage" `Quick test_consensus_key_storage] diff --git a/src/proto_alpha/lib_protocol/validate.ml b/src/proto_alpha/lib_protocol/validate.ml index 67b498846abfec6b26e842d4311fdbbb8150fd4c..49ac6f8a5264bef134fdd31fd4abb38f8a854b41 100644 --- a/src/proto_alpha/lib_protocol/validate.ml +++ b/src/proto_alpha/lib_protocol/validate.ml @@ -95,10 +95,8 @@ type all_expected_consensus_features = { type consensus_info = { all_expected_features : all_expected_consensus_features; - preendorsement_slot_map : - (Signature.public_key * Signature.public_key_hash * int) Slot.Map.t; - endorsement_slot_map : - (Signature.public_key * Signature.public_key_hash * int) Slot.Map.t; + preendorsement_slot_map : (Consensus_key.pk * int) Slot.Map.t; + endorsement_slot_map : (Consensus_key.pk * int) Slot.Map.t; } let init_consensus_info ctxt all_expected_features = @@ -246,8 +244,8 @@ let init_manager_state ctxt = (** Mode-dependent information needed in final checks. *) type application_info = { fitness : Fitness.t; - block_producer : public_key_hash; - payload_producer : public_key_hash; + block_producer : Consensus_key.pk; + payload_producer : Consensus_key.pk; predecessor_hash : Block_hash.t; block_data_contents : Block_header.contents; } @@ -278,8 +276,8 @@ type mode = predecessor_hash : Block_hash.t; round : Round.t; block_data_contents : Block_header.contents; - block_producer : public_key_hash; - payload_producer : public_key_hash; + block_producer : Consensus_key.pk; + payload_producer : Consensus_key.pk; } | Mempool @@ -599,16 +597,21 @@ module Consensus = struct consensus_content operation in - let*? delegate_pk, delegate_pkh, voting_power = + let*? consensus_key, voting_power = get_delegate_details vi.consensus_info.preendorsement_slot_map kind consensus_content in - let* () = check_frozen_deposits_are_positive vi.ctxt delegate_pkh in + let* () = + check_frozen_deposits_are_positive vi.ctxt consensus_key.delegate + in let*? () = if should_check_signature then - Operation.check_signature delegate_pk vi.chain_id operation + Operation.check_signature + consensus_key.consensus_pk + vi.chain_id + operation else ok () in return @@ -646,19 +649,25 @@ module Consensus = struct let open Lwt_result_syntax in let kind = Grandparent_endorsement in let level = Level.from_raw vi.ctxt consensus_content.level in - let* _ctxt, (delegate_pk, delegate_pkh) = + let* _ctxt, consensus_key = Stake_distribution.slot_owner vi.ctxt level consensus_content.slot in - let*? () = ensure_conflict_free_grandparent_endorsement vs delegate_pkh in + let*? () = + ensure_conflict_free_grandparent_endorsement vs consensus_key.delegate + in let*? () = check_consensus_features vs kind expected consensus_content operation in let*? () = if should_check_signature then - Operation.check_signature delegate_pk vi.chain_id operation + Operation.check_signature + consensus_key.consensus_pk + vi.chain_id + operation else ok () in - return (update_validity_state_grandparent_endorsement vs delegate_pkh) + return + (update_validity_state_grandparent_endorsement vs consensus_key.delegate) let ensure_conflict_free_endorsement vs slot = error_unless @@ -713,16 +722,21 @@ module Consensus = struct consensus_content operation in - let*? delegate_pk, delegate_pkh, voting_power = + let*? consensus_key, voting_power = get_delegate_details vi.consensus_info.endorsement_slot_map kind consensus_content in - let* () = check_frozen_deposits_are_positive vi.ctxt delegate_pkh in + let* () = + check_frozen_deposits_are_positive vi.ctxt consensus_key.delegate + in let*? () = if should_check_signature then - Operation.check_signature delegate_pk vi.chain_id operation + Operation.check_signature + consensus_key.consensus_pk + vi.chain_id + operation else ok () in return @@ -1307,19 +1321,22 @@ module Anonymous = struct (* Disambiguate: levels are equal *) let level = Level.from_raw vi.ctxt e1.level in let*? () = check_denunciation_age vi denunciation_kind level.level in - let* ctxt, (delegate1_pk, delegate1) = + let* ctxt, consensus_key1 = Stake_distribution.slot_owner vi.ctxt level e1.slot in - let* ctxt, (_delegate2_pk, delegate2) = + let* ctxt, consensus_key2 = Stake_distribution.slot_owner ctxt level e2.slot in + let delegate1, delegate2 = + (consensus_key1.delegate, consensus_key2.delegate) + in let*? () = error_unless (Signature.Public_key_hash.equal delegate1 delegate2) (Inconsistent_denunciation {kind = denunciation_kind; delegate1; delegate2}) in - let delegate_pk, delegate = (delegate1_pk, delegate1) in + let delegate_pk, delegate = (consensus_key1.consensus_pk, delegate1) in let*? () = match Double_evidence.find @@ -1394,19 +1411,22 @@ module Anonymous = struct let level = Level.from_raw vi.ctxt level1 in let committee_size = Constants.consensus_committee_size vi.ctxt in let*? slot1 = Round.to_slot round1 ~committee_size in - let* ctxt, (delegate1_pk, delegate1) = + let* ctxt, consensus_key1 = Stake_distribution.slot_owner vi.ctxt level slot1 in let*? slot2 = Round.to_slot round2 ~committee_size in - let* ctxt, (_delegate2_pk, delegate2) = + let* ctxt, consensus_key2 = Stake_distribution.slot_owner ctxt level slot2 in + let delegate1, delegate2 = + (consensus_key1.delegate, consensus_key2.delegate) + in let*? () = error_unless Signature.Public_key_hash.(delegate1 = delegate2) (Inconsistent_denunciation {kind = Block; delegate1; delegate2}) in - let delegate_pk, delegate = (delegate1_pk, delegate1) in + let delegate_pk, delegate = (consensus_key1.consensus_pk, delegate1) in let*? () = match Double_evidence.find @@ -1441,6 +1461,83 @@ module Anonymous = struct anonymous_state = {vs.anonymous_state with double_baking_evidences_seen}; } + let validate_drain_delegate vi vs ~should_check_signature oph + (operation : Kind.drain_delegate Operation.t) = + let open Lwt_tzresult_syntax in + let (Single (Drain_delegate {delegate; destination; consensus_key})) = + operation.protocol_data.contents + in + let*! is_registered = Delegate.registered vi.ctxt delegate in + let* () = + fail_unless + is_registered + (Drain_delegate_on_unregistered_delegate delegate) + in + let* active_pk = Delegate.Consensus_key.active_pubkey vi.ctxt delegate in + let* () = + if + not + (Signature.Public_key_hash.equal + active_pk.consensus_pkh + consensus_key) + then + fail + (Invalid_drain_delegate_inactive_key + { + delegate; + consensus_key; + active_consensus_key = active_pk.consensus_pkh; + }) + else if Signature.Public_key_hash.equal active_pk.consensus_pkh delegate + then fail (Invalid_drain_delegate_no_consensus_key delegate) + else if Signature.Public_key_hash.equal destination delegate then + fail (Invalid_drain_delegate_noop delegate) + else return_unit + in + let*! is_destination_allocated = + Contract.allocated vi.ctxt (Contract.Implicit destination) + in + let* balance = Contract.get_balance vi.ctxt (Contract.Implicit delegate) in + let*? origination_burn = + if is_destination_allocated then ok Tez.zero + else + let cost_per_byte = Constants.cost_per_byte vi.ctxt in + let origination_size = Constants.origination_size vi.ctxt in + Tez.(cost_per_byte *? Int64.of_int origination_size) + in + let* drain_fees = + let*? one_percent = Tez.(balance /? 100L) in + return Tez.(max one one_percent) + in + let*? min_amount = Tez.(origination_burn +? drain_fees) in + let* () = + fail_when + Tez.(balance < min_amount) + (Invalid_drain_delegate_insufficient_funds_for_burn_or_fees + {delegate; destination; min_amount}) + in + let*? () = + if should_check_signature then + Operation.check_signature active_pk.consensus_pk vi.chain_id operation + else ok () + in + let*? () = + match + Signature.Public_key_hash.Map.find + delegate + vs.manager_state.managers_seen + with + | None -> ok () + | Some _ -> error (Conflicting_drain {delegate}) + in + let managers_seen = + Signature.Public_key_hash.Map.add + delegate + oph + vs.manager_state.managers_seen + in + return {vs with manager_state = {vs.manager_state with managers_seen}} + let validate_seed_nonce_revelation vi vs (Seed_nonce_revelation {level = commitment_raw_level; nonce}) = let open Lwt_result_syntax in @@ -1810,7 +1907,8 @@ module Manager = struct consume_decoding_gas remaining_gas script.storage | Register_global_constant {value} -> consume_decoding_gas remaining_gas value - | Delegation _ | Set_deposits_limit _ | Increase_paid_storage _ -> + | Delegation _ | Set_deposits_limit _ | Increase_paid_storage _ + | Update_consensus_key _ -> return remaining_gas | Tx_rollup_origination -> let* () = assert_tx_rollup_feature_enabled vi in @@ -2010,7 +2108,7 @@ let begin_application ctxt chain_id ~predecessor_level ~predecessor_timestamp let predecessor_round = Fitness.predecessor_round fitness in let round = Fitness.round fitness in let current_level = Level.current ctxt in - let* ctxt, _slot, (block_producer_pk, block_producer) = + let* ctxt, _slot, block_producer = Stake_distribution.baking_rights_owner ctxt current_level ~round in let*? () = @@ -2021,13 +2119,15 @@ let begin_application ctxt chain_id ~predecessor_level ~predecessor_timestamp ~predecessor_round ~fitness ~timestamp:block_header.shell.timestamp - ~delegate_pk:block_producer_pk + ~delegate_pk:block_producer.consensus_pk ~round_durations:(Constants.round_durations ctxt) ~proof_of_work_threshold:(Constants.proof_of_work_threshold ctxt) ~expected_commitment:current_level.expected_commitment in - let* () = Consensus.check_frozen_deposits_are_positive ctxt block_producer in - let* ctxt, _slot, (_payload_producer_pk, payload_producer) = + let* () = + Consensus.check_frozen_deposits_are_positive ctxt block_producer.delegate + in + let* ctxt, _slot, payload_producer = Stake_distribution.baking_rights_owner ctxt current_level @@ -2097,11 +2197,13 @@ let begin_full_construction ctxt chain_id ~predecessor_level ~predecessor_round ~predecessor_round in let current_level = Level.current ctxt in - let* ctxt, _slot, (_block_producer_pk, block_producer) = + let* ctxt, _slot, block_producer = Stake_distribution.baking_rights_owner ctxt current_level ~round in - let* () = Consensus.check_frozen_deposits_are_positive ctxt block_producer in - let* ctxt, _slot, (_payload_producer_pk, payload_producer) = + let* () = + Consensus.check_frozen_deposits_are_positive ctxt block_producer.delegate + in + let* ctxt, _slot, payload_producer = Stake_distribution.baking_rights_owner ctxt current_level @@ -2264,6 +2366,13 @@ let validate_operation {info; state} ?(should_check_signature = true) oph contents | Single (Double_baking_evidence _ as contents) -> Anonymous.validate_double_baking_evidence info state oph contents + | Single (Drain_delegate _) -> + Anonymous.validate_drain_delegate + info + state + ~should_check_signature + oph + operation | Single (Seed_nonce_revelation _ as contents) -> Anonymous.validate_seed_nonce_revelation info state contents | Single (Vdf_revelation _ as contents) -> diff --git a/src/proto_alpha/lib_protocol/validate_errors.ml b/src/proto_alpha/lib_protocol/validate_errors.ml index fba200ec512967003ed6539dcf2a3c225887a9e2..12269b8ba96cec0e78e424c52a348873b0b164e6 100644 --- a/src/proto_alpha/lib_protocol/validate_errors.ml +++ b/src/proto_alpha/lib_protocol/validate_errors.ml @@ -1063,6 +1063,145 @@ module Anonymous = struct Data_encoding.unit (function Conflicting_nonce_revelation -> Some () | _ -> None) (fun () -> Conflicting_nonce_revelation) + + type error += + | Drain_delegate_on_unregistered_delegate of Signature.Public_key_hash.t + | Invalid_drain_delegate_inactive_key of { + delegate : Signature.Public_key_hash.t; + consensus_key : Signature.Public_key_hash.t; + active_consensus_key : Signature.Public_key_hash.t; + } + | Invalid_drain_delegate_no_consensus_key of Signature.Public_key_hash.t + | Invalid_drain_delegate_noop of Signature.Public_key_hash.t + | Invalid_drain_delegate_insufficient_funds_for_burn_or_fees of { + delegate : Signature.Public_key_hash.t; + destination : Signature.Public_key_hash.t; + min_amount : Tez.t; + } + | Conflicting_drain of {delegate : Signature.Public_key_hash.t} + + let () = + register_error_kind + `Temporary + ~id:"operation.drain_delegate_key_on_unregistered_delegate" + ~title:"Drain delegate key on an unregistered delegate" + ~description:"Cannot drain an unregistered delegate." + ~pp:(fun ppf c -> + Format.fprintf + ppf + "Cannot drain an unregistered delegate %a." + Signature.Public_key_hash.pp + c) + Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding)) + (function + | Drain_delegate_on_unregistered_delegate c -> Some c | _ -> None) + (fun c -> Drain_delegate_on_unregistered_delegate c) ; + register_error_kind + `Temporary + ~id:"operation.invalid_drain.inactive_key" + ~title:"Drain delegate with an inactive consensus key" + ~description:"Cannot drain with an inactive consensus key." + ~pp:(fun ppf (delegate, consensus_key, active_consensus_key) -> + Format.fprintf + ppf + "Consensus key %a is not the active consensus key for delegate %a. \ + The active consensus key is %a." + Signature.Public_key_hash.pp + consensus_key + Signature.Public_key_hash.pp + delegate + Signature.Public_key_hash.pp + active_consensus_key) + Data_encoding.( + obj3 + (req "delegate" Signature.Public_key_hash.encoding) + (req "consensus_key" Signature.Public_key_hash.encoding) + (req "active_consensus_key" Signature.Public_key_hash.encoding)) + (function + | Invalid_drain_delegate_inactive_key + {delegate; consensus_key; active_consensus_key} -> + Some (delegate, consensus_key, active_consensus_key) + | _ -> None) + (fun (delegate, consensus_key, active_consensus_key) -> + Invalid_drain_delegate_inactive_key + {delegate; consensus_key; active_consensus_key}) ; + register_error_kind + `Temporary + ~id:"operation.invalid_drain.no_consensus_key" + ~title:"Drain a delegate without consensus key" + ~description:"Cannot drain a delegate without consensus key." + ~pp:(fun ppf delegate -> + Format.fprintf + ppf + "There is no active consensus key for delegate %a." + Signature.Public_key_hash.pp + delegate) + Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding)) + (function + | Invalid_drain_delegate_no_consensus_key c -> Some c | _ -> None) + (fun c -> Invalid_drain_delegate_no_consensus_key c) ; + register_error_kind + `Temporary + ~id:"operation.invalid_drain.noop" + ~title:"Invalid drain delegate: noop" + ~description:"Cannot drain a delegate to itself." + ~pp:(fun ppf delegate -> + Format.fprintf + ppf + "The destination of a drain operation cannot be the delegate itself \ + (%a)." + Signature.Public_key_hash.pp + delegate) + Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding)) + (function Invalid_drain_delegate_noop c -> Some c | _ -> None) + (fun c -> Invalid_drain_delegate_noop c) ; + register_error_kind + `Temporary + ~id:"operation.invalid_drain.insufficient_funds_for_burn_or_fees" + ~title: + "Drain delegate without enough balance for allocation burn or drain \ + fees" + ~description:"Cannot drain without enough allocation burn and drain fees." + ~pp:(fun ppf (delegate, destination, min_amount) -> + Format.fprintf + ppf + "Cannot drain delegate from %a to %a: not enough funds for the drain \ + fees in the delegate account (minimum balance required: %a)." + Signature.Public_key_hash.pp + delegate + Signature.Public_key_hash.pp + destination + Tez.pp + min_amount) + Data_encoding.( + obj3 + (req "delegate" Signature.Public_key_hash.encoding) + (req "destination" Signature.Public_key_hash.encoding) + (req "min_amount" Tez.encoding)) + (function + | Invalid_drain_delegate_insufficient_funds_for_burn_or_fees + {delegate; destination; min_amount} -> + Some (delegate, destination, min_amount) + | _ -> None) + (fun (delegate, destination, min_amount) -> + Invalid_drain_delegate_insufficient_funds_for_burn_or_fees + {delegate; destination; min_amount}) ; + register_error_kind + `Branch + ~id:"validate_operation.conflicting_drain" + ~title:"Conflicting drain in the current validation state)." + ~description: + "A manager operation or another drain operation is in conflict." + ~pp:(fun ppf delegate -> + Format.fprintf + ppf + "This drain operation is conflicting with another drain operation or \ + a manager operation for delegate %a" + Signature.Public_key_hash.pp + delegate) + Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding)) + (function Conflicting_drain {delegate} -> Some delegate | _ -> None) + (fun delegate -> Conflicting_drain {delegate}) end module Manager = struct diff --git a/src/proto_alpha/lib_protocol/validate_errors.mli b/src/proto_alpha/lib_protocol/validate_errors.mli index f642f618e0354fece609e3381192301170b82d14..2bd2b0be1f6ca5f1773c813b9c272f75cf2ed65f 100644 --- a/src/proto_alpha/lib_protocol/validate_errors.mli +++ b/src/proto_alpha/lib_protocol/validate_errors.mli @@ -167,6 +167,20 @@ module Anonymous : sig last_cycle : Cycle.t; } | Conflicting_nonce_revelation + | Drain_delegate_on_unregistered_delegate of Signature.Public_key_hash.t + | Invalid_drain_delegate_inactive_key of { + delegate : Signature.Public_key_hash.t; + consensus_key : Signature.Public_key_hash.t; + active_consensus_key : Signature.Public_key_hash.t; + } + | Invalid_drain_delegate_no_consensus_key of Signature.Public_key_hash.t + | Invalid_drain_delegate_noop of Signature.Public_key_hash.t + | Invalid_drain_delegate_insufficient_funds_for_burn_or_fees of { + delegate : Signature.Public_key_hash.t; + destination : Signature.Public_key_hash.t; + min_amount : Tez.t; + } + | Conflicting_drain of {delegate : Signature.Public_key_hash.t} end (** Errors that may arise while validating a manager operation. *) diff --git a/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_send_tickets_in_big_map.out b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_send_tickets_in_big_map.out index 3ef62cb72b65333298cc8ceadfaf4fcc523b1cec..cfa26de12043db8740231d314ff9623fc2a6aaf2 100644 --- a/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_send_tickets_in_big_map.out +++ b/tests_python/tests_alpha/_regtest_outputs/test_contract.TestSendTicketsInBigMap::test_send_tickets_in_big_map.out @@ -1,7 +1,7 @@ tests_alpha/test_contract.py::TestSendTicketsInBigMap::test_send_tickets_in_big_map Node is bootstrapped. -Estimated gas: 100143.052 units (will add 100 for safety) +Estimated gas: 100143.520 units (will add 100 for safety) Estimated storage: 10767 bytes added (will add 20 for safety) Operation successfully injected in the node. Operation hash is '[BLOCK_HASH]' @@ -130,7 +130,7 @@ This sequence of operations was run: Set temp(1)[40] to (Pair 0x013fdf9fa7cb678c9c1da3bbfdd83a77ca36efa00300 (Pair "BLUE" 1)) Storage size: 294 bytes Paid storage size diff: 67 bytes - Consumed gas: 50522.233 + Consumed gas: 50522.350 Balance updates: [CONTRACT_HASH] ... -ꜩ0.01675 storage fees ........................... +ꜩ0.01675 @@ -147,7 +147,7 @@ This sequence of operations was run: Copy temp(1) to map(5) Storage size: 10783 bytes Paid storage size diff: 10700 bytes - Consumed gas: 49620.819 + Consumed gas: 49621.170 Balance updates: [CONTRACT_HASH] ... -ꜩ2.675 storage fees ........................... +ꜩ2.675 diff --git a/tezt/lib_tezos/client.ml b/tezt/lib_tezos/client.ml index ae05470ba4e9830102f6dee47cb4c6f32a88887f..b83176c37b991faf4ba27071ef4a4be8c1f5f83e 100644 --- a/tezt/lib_tezos/client.ml +++ b/tezt/lib_tezos/client.ml @@ -541,7 +541,7 @@ let spawn_bake_for ?endpoint ?protocol ?(keys = [Constant.bootstrap1.alias]) let bake_for ?endpoint ?protocol ?keys ?minimal_fees ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?minimal_timestamp - ?mempool ?ignore_node_mempool ?force ?context_path client = + ?mempool ?ignore_node_mempool ?force ?context_path ?expect_failure client = spawn_bake_for ?endpoint ?keys @@ -555,7 +555,7 @@ let bake_for ?endpoint ?protocol ?keys ?minimal_fees ?context_path ?protocol client - |> Process.check + |> Process.check ?expect_failure let bake_for_and_wait ?endpoint ?protocol ?keys ?minimal_fees ?minimal_nanotez_per_gas_unit ?minimal_nanotez_per_byte ?minimal_timestamp @@ -825,7 +825,7 @@ let get_delegate ?endpoint ~src client = Lwt.return (output =~* rex "(tz[a-zA-Z0-9]+) \\(.*\\)") let set_delegate ?endpoint ?(wait = "none") ?fee ?fee_cap - ?(force_low_fee = false) ~src ~delegate client = + ?(force_low_fee = false) ?expect_failure ~src ~delegate client = let value = spawn_command ?endpoint @@ -836,7 +836,7 @@ let set_delegate ?endpoint ?(wait = "none") ?fee ?fee_cap @ optional_arg "fee-cap" Tez.to_string fee_cap @ if force_low_fee then ["--force-low-fee"] else []) in - {value; run = Process.check} + {value; run = Process.check ?expect_failure} let reveal ?endpoint ?(wait = "none") ?fee ?fee_cap ?(force_low_fee = false) ~src client = @@ -856,10 +856,11 @@ let spawn_withdraw_delegate ?endpoint ?(wait = "none") ~src client = spawn_command ?endpoint client - (["--wait"; wait] @ ["withdraw"; "delegate"; "for"; src]) + (["--wait"; wait] @ ["withdraw"; "delegate"; "from"; src]) -let withdraw_delegate ?endpoint ?wait ~src client = - spawn_withdraw_delegate ?endpoint ?wait ~src client |> Process.check +let withdraw_delegate ?endpoint ?wait ?expect_failure ~src client = + spawn_withdraw_delegate ?endpoint ?wait ~src client + |> Process.check ?expect_failure let spawn_get_balance_for ?endpoint ~account client = spawn_command ?endpoint client ["get"; "balance"; "for"; account] @@ -955,6 +956,33 @@ let increase_paid_storage ?hooks ?endpoint ?(wait = "none") ~contract ~amount ]) |> Process.check_and_read_stdout +let update_consensus_key ?hooks ?endpoint ?(wait = "none") ?burn_cap + ?expect_failure ~src ~pk client = + spawn_command + ?hooks + ?endpoint + client + (["--wait"; wait] + @ ["set"; "consensus"; "key"; "for"; src; "to"; pk] + @ optional_arg "burn-cap" Tez.to_string burn_cap) + |> Process.check ?expect_failure + +let drain_delegate ?hooks ?endpoint ?(wait = "none") ?expect_failure ~delegate + ~consensus_key ?destination client = + let destination = + match destination with + | None -> [] + | Some destination -> [destination; "with"] + in + spawn_command + ?hooks + ?endpoint + client + (["--wait"; wait] + @ ["drain"; "delegate"; delegate; "to"] + @ destination @ [consensus_key]) + |> Process.check ?expect_failure + let spawn_originate_contract ?hooks ?log_output ?endpoint ?(wait = "none") ?init ?burn_cap ?gas_limit ?(dry_run = false) ~alias ~amount ~src ~prg client = spawn_command @@ -1980,12 +2008,19 @@ let init_with_protocol ?path ?admin_path ?name ?color ?base_dir ?event_level let* _ = Node.wait_for_level node 1 in return (node, client) -let spawn_register_key owner client = +let spawn_register_key ?hooks ?consensus owner client = spawn_command + ?hooks client - ["--wait"; "none"; "register"; "key"; owner; "as"; "delegate"] + (["--wait"; "none"; "register"; "key"; owner; "as"; "delegate"] + @ + match consensus with + | None -> [] + | Some pk -> ["with"; "consensus"; "key"; pk]) -let register_key owner client = spawn_register_key owner client |> Process.check +let register_key ?hooks ?expect_failure ?consensus owner client = + spawn_register_key ?hooks ?consensus owner client + |> Process.check ?expect_failure let contract_storage ?unparsing_mode address client = spawn_command diff --git a/tezt/lib_tezos/client.mli b/tezt/lib_tezos/client.mli index ad96df82ccc1d7b2c879227babbd9b4d21111428..d5b32c372cfe83da1d68cf479e350ced6b7ea3d1 100644 --- a/tezt/lib_tezos/client.mli +++ b/tezt/lib_tezos/client.mli @@ -394,6 +394,7 @@ val bake_for : ?ignore_node_mempool:bool -> ?force:bool -> ?context_path:string -> + ?expect_failure:bool -> t -> unit Lwt.t @@ -650,6 +651,7 @@ val set_delegate : ?fee:Tez.t -> ?fee_cap:Tez.t -> ?force_low_fee:bool -> + ?expect_failure:bool -> src:string -> delegate:string -> t -> @@ -668,7 +670,12 @@ val reveal : (** Run [tezos-client withdraw delegate from ]. *) val withdraw_delegate : - ?endpoint:endpoint -> ?wait:string -> src:string -> t -> unit Lwt.t + ?endpoint:endpoint -> + ?wait:string -> + ?expect_failure:bool -> + src:string -> + t -> + unit Lwt.t (** Same as [withdraw_delegate], but do not wait for the process to exit. *) val spawn_withdraw_delegate : @@ -765,6 +772,30 @@ val increase_paid_storage : t -> string Lwt.t +(** Run [tezos-client use as consensus key for delegate ] *) +val update_consensus_key : + ?hooks:Process.hooks -> + ?endpoint:endpoint -> + ?wait:string -> + ?burn_cap:Tez.t -> + ?expect_failure:bool -> + src:string -> + pk:string -> + t -> + unit Lwt.t + +(** Run [tezos-client drain delegate with consensus key ] *) +val drain_delegate : + ?hooks:Process.hooks -> + ?endpoint:endpoint -> + ?wait:string -> + ?expect_failure:bool -> + delegate:string -> + consensus_key:string -> + ?destination:string -> + t -> + unit Lwt.t + (* TODO: https://gitlab.com/tezos/tezos/-/issues/2336 [amount] should be named [transferring] *) (* TODO: https://gitlab.com/tezos/tezos/-/issues/2336 @@ -1450,10 +1481,17 @@ val spawn_command : Process.t (** Register public key for given account with given client. *) -val spawn_register_key : string -> t -> Process.t +val spawn_register_key : + ?hooks:Process.hooks -> ?consensus:string -> string -> t -> Process.t (** Register public key for given account with given client. *) -val register_key : string -> t -> unit Lwt.t +val register_key : + ?hooks:Process.hooks -> + ?expect_failure:bool -> + ?consensus:string -> + string -> + t -> + unit Lwt.t (** Get contract storage for a contract. Returns a Micheline expression representing the storage as a string. *) diff --git a/tezt/tests/consensus_key.ml b/tezt/tests/consensus_key.ml new file mode 100644 index 0000000000000000000000000000000000000000..0c1da3b1f538016abaef89e3ec39730e1a048bd0 --- /dev/null +++ b/tezt/tests/consensus_key.ml @@ -0,0 +1,785 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 G.B. Fefe *) +(* Copyright (c) 2022 Nomadic Labs *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +(* Testing + ------- + Component: Baker + Invocation: dune exec tezt/tests/main.exe -- --file consensus_key.ml + Subject: Test the operation `Update_consensus_key` and its effects + on the baker. +*) + +let hooks = Tezos_regression.hooks + +module Helpers = struct + type level = { + level : int; + level_position : int; + cycle : int; + cycle_position : int; + expected_commitment : bool; + } + + let level_type : level Check.typ = + Check.convert + (fun {level; level_position; cycle; cycle_position; expected_commitment} -> + (level, level_position, cycle, cycle_position, expected_commitment)) + Check.(tuple5 int int int int bool) + + let decode_level json = + let level = JSON.(json |-> "level" |> as_int) in + let level_position = JSON.(json |-> "level_position" |> as_int) in + let cycle = JSON.(json |-> "cycle" |> as_int) in + let cycle_position = JSON.(json |-> "cycle_position" |> as_int) in + let expected_commitment = + JSON.(json |-> "expected_commitment" |> as_bool) + in + {level; level_position; cycle; cycle_position; expected_commitment} + + let get_current_level client = + let* json = RPC.get_current_level client in + return (decode_level json) + + let check_current_level client expected_level = + let* level = get_current_level client in + Check.((level = expected_level) level_type) + ~error_msg:"expected current_period = %R, got %L" ; + unit + + let bake_and_wait_block node client = + let* level_json = RPC.get_current_level client in + let level = JSON.(level_json |-> "level" |> as_int) in + let* () = + Client.bake_for ~context_path:(Node.data_dir node // "context") client + in + let* _i = Node.wait_for_level node (level + 1) in + Lwt.return_unit +end + +open Helpers + +let blocks_per_cycle = 4 + +let preserved_cycles = 1 + +let test_update_consensus_key = + Protocol.register_test + ~__FILE__ + ~title:"update consensus key" + ~tags:["consensus_key"] + @@ fun protocol -> + let parameters = + (* we update paramaters for faster testing: no need to wait + 5 cycles for the consensus key to activate. *) + [ + (["blocks_per_cycle"], Some (Int.to_string blocks_per_cycle)); + (["nonce_revelation_threshold"], Some "2"); + (["preserved_cycles"], Some (Int.to_string preserved_cycles)); + ] + in + let* parameter_file = + Protocol.write_parameter_file ~base:(Right (protocol, None)) parameters + in + let* _, client = + Client.init_with_protocol ~parameter_file ~protocol `Client () + in + let* key_a = Client.gen_and_show_keys client in + let* key_b = Client.gen_and_show_keys client in + let* key_c = Client.gen_and_show_keys client in + let* destination = Client.gen_and_show_keys client in + + let* () = + Client.transfer + ~burn_cap:Tez.one + ~amount:(Tez.of_int 1_000_000) + ~giver:Constant.bootstrap1.alias + ~receiver:key_b.alias + client + in + let* () = + Client.transfer + ~burn_cap:Tez.one + ~amount:(Tez.of_int 1_000_000) + ~giver:Constant.bootstrap2.alias + ~receiver:key_c.alias + client + in + let* () = + Client.transfer + ~burn_cap:Tez.one + ~amount:(Tez.of_int 1) + ~giver:Constant.bootstrap4.alias + ~receiver:destination.alias + client + in + let* () = Client.bake_for_and_wait client in + + Log.info + "Invalid update: changing the consensus key of an unregistered delegate" ; + let* () = + Client.update_consensus_key + ~expect_failure:true + ~src:key_b.alias + ~pk:Constant.bootstrap1.alias + client + in + Log.info "Invalid update: changing the consensus key to its actual value" ; + let* () = + Client.update_consensus_key + ~expect_failure:true + ~src:Constant.bootstrap1.alias + ~pk:Constant.bootstrap1.alias + client + in + Log.info + "Invalid update: changing the consensus key to an active consensus key \ + (bootstrap)" ; + let* () = + Client.update_consensus_key + ~expect_failure:true + ~src:Constant.bootstrap2.alias + ~pk:Constant.bootstrap1.alias + client + in + + Log.info "Trying a valid consensus key update." ; + let* () = + Client.update_consensus_key + ~src:Constant.bootstrap1.alias + ~pk:key_a.alias + client + in + let* () = Client.bake_for_and_wait client in + + Log.info + "Invalid update: changing the consensus key to an active consensus key \ + (set)" ; + let* () = + Client.update_consensus_key + ~expect_failure:true + ~src:Constant.bootstrap2.alias + ~pk:key_a.alias + client + in + + Log.info "Register a delegate with a consensus key." ; + let* () = Client.register_key ~consensus:key_c.alias key_b.alias client in + + Log.info "Bake until the end of the next cycle..." ; + let* () = repeat 5 (fun () -> Client.bake_for_and_wait client) in + let* () = + check_current_level + client + { + level = 8; + level_position = 7; + cycle = 1; + cycle_position = 3; + expected_commitment = true; + } + in + + Log.info "Bootstrap1 should not be able to bake anymore..." ; + let* () = + Client.bake_for + ~expect_failure:true + ~keys:[Constant.bootstrap1.alias] + client + in + + Log.info "... while `key_a` and `key_c` are able to bake." ; + let* () = Client.bake_for_and_wait ~keys:[key_a.alias] client in + let* () = Client.bake_for_and_wait ~keys:[key_c.alias] client in + + Log.info "Switch back to the initial consensus key." ; + let* () = + Client.update_consensus_key + ~src:Constant.bootstrap1.alias + ~pk:Constant.bootstrap1.alias + client + in + let* () = + Client.update_consensus_key ~src:key_b.alias ~pk:key_b.alias client + in + + Log.info "Bake until the end of the next cycle..." ; + let* () = + repeat 6 (fun () -> Client.bake_for_and_wait ~keys:[key_a.alias] client) + in + let* () = + check_current_level + client + { + level = 16; + level_position = 15; + cycle = 3; + cycle_position = 3; + expected_commitment = true; + } + in + + Log.info "We are not able to bake with `key_a` nor `key_c` anymore..." ; + let* () = Client.bake_for ~expect_failure:true ~keys:[key_a.alias] client in + let* () = Client.bake_for ~expect_failure:true ~keys:[key_c.alias] client in + + Log.info "... but are able to bake again with `bootstrap1` and `key_b`..." ; + let* () = Client.bake_for_and_wait ~keys:[Constant.bootstrap1.alias] client in + let* () = Client.bake_for_and_wait ~keys:[key_b.alias] client in + + Log.info + "Update the consensus key of bootstrap3 and bootstrap4 to `key_a` and \ + `key_c`, respectively..." ; + let* () = + Client.update_consensus_key + ~src:Constant.bootstrap3.alias + ~pk:key_a.alias + client + in + let* () = + Client.update_consensus_key + ~src:Constant.bootstrap4.alias + ~pk:key_c.alias + client + in + + Log.info "Bake until the end of the next cycle..." ; + let* () = + repeat 6 (fun () -> + Client.bake_for_and_wait ~keys:[Constant.bootstrap1.alias] client) + in + let* () = + check_current_level + client + { + level = 24; + level_position = 23; + cycle = 5; + cycle_position = 3; + expected_commitment = true; + } + in + + Log.info "Invalid drain: unregistered delegate." ; + let* () = + Client.drain_delegate + ~expect_failure:true + ~delegate:destination.alias + ~consensus_key:destination.alias + ~destination:destination.alias + client + in + + Log.info "Invalid drain: bootstrap2 is has no custom consensus key." ; + let* () = + Client.drain_delegate + ~expect_failure:true + ~delegate:Constant.bootstrap2.alias + ~consensus_key:Constant.bootstrap2.alias + ~destination:destination.alias + client + in + + Log.info "Invalid drain: bootstrap2 is not the consensus key for bootstrap1." ; + let* () = + Client.drain_delegate + ~expect_failure:true + ~delegate:Constant.bootstrap1.alias + ~consensus_key:Constant.bootstrap2.alias + ~destination:destination.alias + client + in + + Log.info "Invalid drain: cannot drain to itself." ; + let* () = + Client.drain_delegate + ~expect_failure:true + ~delegate:Constant.bootstrap4.alias + ~consensus_key:key_c.alias + ~destination:Constant.bootstrap4.alias + client + in + + Log.info "Invalid drain: there is nothing drain to itself." ; + let* () = + let delegate = Constant.bootstrap4.alias in + let* balance = Client.get_balance_for ~account:delegate client in + let* () = + Client.transfer + ~fee:Tez.zero + ~amount:balance + ~giver:delegate + ~receiver:key_c.alias + client + in + let* () = Client.bake_for_and_wait client in + Client.drain_delegate + ~expect_failure:true + ~delegate:Constant.bootstrap4.alias + ~consensus_key:key_c.alias + ~destination:Constant.bootstrap4.alias + client + in + + let* old_balance = Client.get_balance_for ~account:destination.alias client in + let* old_balance5 = + Client.get_balance_for ~account:Constant.bootstrap5.alias client + in + let* () = + Client.drain_delegate + ~delegate:Constant.bootstrap4.alias + ~consensus_key:key_c.alias + ~destination:destination.alias + client + in + let* () = + Client.transfer + ~burn_cap:Tez.one + ~amount:(Tez.of_int 1) + ~giver:Constant.bootstrap4.alias + ~receiver:Constant.bootstrap5.alias + client + in + let* () = Client.bake_for_and_wait ~keys:[Constant.bootstrap1.alias] client in + Log.info + "Check that other manager operations are not included after a drain..." ; + let* () = + let* json = + RPC.get_chain_mempool_pending_operations () |> RPC.Client.call client + in + let delayed_op_kind = + JSON.( + json |-> "branch_delayed" |> geti 0 |> geti 1 |-> "contents" |> geti 0 + |-> "kind" |> encode) + in + Check.((delayed_op_kind = "\"transaction\"") string) + ~error_msg: + "The transaction is not in the branch_delayed pool (expected %R, got \ + %L)" ; + Lwt.return_unit + in + Log.info "The manager account has been drained..." ; + let* b = Client.get_balance_for ~account:Constant.bootstrap4.alias client in + Check.((Tez.to_mutez b = 0) int) ~error_msg:"Manager balance is not empty" ; + let* new_balance = Client.get_balance_for ~account:destination.alias client in + Check.((Tez.to_mutez old_balance < Tez.to_mutez new_balance) int) + ~error_msg:"Destination account has not been credited" ; + let* new_balance5 = + Client.get_balance_for ~account:Constant.bootstrap5.alias client + in + Check.((Tez.to_mutez new_balance5 = Tez.to_mutez old_balance5) int) + ~error_msg:"Manager operation was included" ; + + Log.info + "Check that a drain conflicts with (ie is not included after) a manager \ + operation of the same delegate..." ; + let* () = + Client.transfer + ~burn_cap:Tez.one + ~amount:(Tez.of_int 1) + ~giver:Constant.bootstrap3.alias + ~receiver:Constant.bootstrap5.alias + client + in + let* () = + Client.drain_delegate + ~expect_failure:true + ~delegate:Constant.bootstrap3.alias + ~consensus_key:key_a.alias + ~destination:destination.alias + client + in + let* old_balance3 = + Client.get_balance_for ~account:Constant.bootstrap3.alias client + in + let* old_balance5 = + Client.get_balance_for ~account:Constant.bootstrap5.alias client + in + let* old_balance = Client.get_balance_for ~account:destination.alias client in + + let* () = Client.bake_for_and_wait ~keys:[Constant.bootstrap1.alias] client in + + let* new_balance5 = + Client.get_balance_for ~account:Constant.bootstrap5.alias client + in + let* new_balance = Client.get_balance_for ~account:destination.alias client in + Check.((Tez.to_mutez old_balance = Tez.to_mutez new_balance) int) + ~error_msg:"Drain operation was included (destination balance changed)" ; + Check.((Tez.to_mutez old_balance3 > 0) int) + ~error_msg: + "Drain operation was included (delegate balance changed: old %L versus \ + new %R)" ; + Check.((Tez.to_mutez old_balance5 < Tez.to_mutez new_balance5) int) + ~error_msg:"Destination account has not been credited" ; + + unit + +let bake_n_cycles n client = + let rec loop n = + if n = 0 then unit + else + let* () = Client.bake_for_and_wait client in + loop (n - 1) + in + let* current_level = Helpers.get_current_level client in + let nb_remaining_blocks = current_level.level mod blocks_per_cycle in + let nb_baked_blocks_in_cycle = blocks_per_cycle - nb_remaining_blocks in + let nb_blocks_to_bake = (n * blocks_per_cycle) - nb_baked_blocks_in_cycle in + loop nb_blocks_to_bake + +let update_consensus_key ?(expect_failure = false) + ?(baker = Constant.bootstrap1.alias) ~(src : Account.key) + ~(consensus_key : Account.key) client = + let* () = + Client.update_consensus_key + ~hooks + ~expect_failure + ~src:src.alias + ~pk:consensus_key.alias + client + in + let* _ = RPC.Delegates.get ~hooks ~pkh:src.public_key_hash client in + let* () = Client.bake_for_and_wait ~keys:[baker] client in + let* _ = RPC.Delegates.get ~hooks ~pkh:src.public_key_hash client in + let* () = bake_n_cycles (preserved_cycles + 1) client in + let* _ = RPC.Delegates.get ~hooks ~pkh:src.public_key_hash client in + unit + +let test_consensus_key_update ?(expect_failure = false) + ?(baker = Constant.bootstrap1.alias) ~(src : Account.key) + ~(consensus_key : Account.key) client = + (* Update the consensus key and go past [preserved_cycles + 1] *) + let* () = + update_consensus_key ~expect_failure ~baker ~src ~consensus_key client + in + (* Check that one can bake with the updated consensus key *) + let* () = Client.bake_for_and_wait ~keys:[consensus_key.alias] client in + unit + +let drain_delegate ~delegate ~consensus_key ~destination + ?(expect_failure = false) ?(baker = Constant.bootstrap1.alias) client = + let* () = + Client.drain_delegate + ~hooks + ~expect_failure + ~delegate + ~consensus_key + ~destination + client + in + Client.bake_for_and_wait ~keys:[baker] client + +let register_key_as_delegate ?(expect_failure = false) + ?(baker = Constant.bootstrap1.alias) ~(owner : Account.key) + ~(consensus_key : Account.key) client = + let*! _ = + RPC.Contracts.get ~hooks ~contract_id:consensus_key.public_key_hash client + in + let* () = + Client.register_key + ~hooks + ~expect_failure + ~consensus:consensus_key.alias + owner.alias + client + in + let* () = Client.bake_for_and_wait ~keys:[baker] client in + let* _ = RPC.Delegates.get ~hooks ~pkh:owner.public_key_hash client in + let*! _ = + RPC.Contracts.get ~hooks ~contract_id:consensus_key.public_key_hash client + in + (* Wait for consensus key to be active *) + let* () = bake_n_cycles (preserved_cycles + 1) client in + let* _ = RPC.Delegates.get ~hooks ~pkh:owner.public_key_hash client in + unit + +let transfer ?hooks ?(expect_failure = false) + ?(baker = Constant.bootstrap1.alias) ~source ~destination ~amount client = + let* () = + Client.transfer + ?hooks + ~expect_failure + ~burn_cap:Tez.one + ~giver:source + ~receiver:destination + ~amount + client + in + Client.bake_for_and_wait ~keys:[baker] client + +let register title test = + Protocol.register_regression_test ~__FILE__ ~title ~tags:["consensus_key"] + @@ fun protocol -> + let parameters = + (* we update paramaters for faster testing: no need to wait + 5 cycles for the consensus key to activate. *) + [ + (["blocks_per_cycle"], Some (Int.to_string blocks_per_cycle)); + (["nonce_revelation_threshold"], Some "2"); + (["preserved_cycles"], Some (Int.to_string preserved_cycles)); + ] + in + let* parameter_file = + Protocol.write_parameter_file ~base:(Right (protocol, None)) parameters + in + let* _, client = + Client.init_with_protocol ~parameter_file ~protocol `Client () + in + let baker_0 = Constant.bootstrap1 in + let baker_1 = Constant.bootstrap2 in + let* account_0 = Client.gen_and_show_keys ~alias:"dummy_account_0" client in + let* account_1 = Client.gen_and_show_keys ~alias:"dummy_account_1" client in + test client baker_0 baker_1 account_0 account_1 + +let test_register_delegate_with_consensus_key ?(expect_failure = false) + ?(baker = Constant.bootstrap1.alias) ~(new_delegate : Account.key) + ~(new_consensus_key : Account.key) client = + let* () = + transfer + ~source:baker + ~destination:new_delegate.alias + ~amount:(Tez.of_int 1_000_000) + ~baker + client + in + let* () = + register_key_as_delegate + ~expect_failure + ~owner:new_delegate + ~consensus_key:new_consensus_key + ~baker + client + in + (* Check that one can bake with the consensus key *) + let* () = Client.bake_for_and_wait ~keys:[new_consensus_key.alias] client in + unit + +let test_revert_to_unique_consensus_key ?(baker = Constant.bootstrap1.alias) + ~(new_delegate : Account.key) ~(new_consensus_key : Account.key) client = + (* Set a new consensus key *) + let* () = + transfer + ~source:baker + ~destination:new_delegate.alias + ~amount:(Tez.of_int 1_000_000) + ~baker + client + in + let* () = + register_key_as_delegate + ~owner:new_delegate + ~consensus_key:new_consensus_key + ~baker + client + in + (* Check that new_consensus_key can bake *) + let* () = Client.bake_for_and_wait ~keys:[new_consensus_key.alias] client in + (* Revert the consensus key *) + let* () = + update_consensus_key + ~baker + ~src:new_delegate + ~consensus_key:new_delegate + client + in + (* Check that new_delegate can bake *) + let* () = Client.bake_for_and_wait ~keys:[new_delegate.alias] client in + unit + +let test_drain_delegate_1 ?(baker = Constant.bootstrap1.alias) + ~(delegate : Account.key) ~(consensus : Account.key) + ~(destination : Account.key) client = + let* () = + update_consensus_key ~baker ~src:delegate ~consensus_key:consensus client + in + let* _ = RPC.Delegates.get ~hooks ~pkh:delegate.public_key_hash client in + let*! _ = + RPC.Contracts.get_balance + ~hooks + ~contract_id:delegate.public_key_hash + client + in + let*! _ = + RPC.Contracts.get_balance + ~hooks + ~contract_id:consensus.public_key_hash + client + in + let*! _ = + RPC.Contracts.get_balance + ~hooks + ~contract_id:destination.public_key_hash + client + in + (* Goto beginning of cycle to ensure a baking slot is available *) + let* () = + drain_delegate + ~delegate:delegate.alias + ~consensus_key:consensus.alias + ~destination:destination.alias + ~baker:consensus.alias + (* In case delegate = baker, use the consensus key updated above *) + client + in + let* _ = RPC.Delegates.get ~hooks ~pkh:delegate.public_key_hash client in + let*! _ = + RPC.Contracts.get_balance + ~hooks + ~contract_id:delegate.public_key_hash + client + in + let*! _ = + RPC.Contracts.get_balance + ~hooks + ~contract_id:consensus.public_key_hash + client + in + let*! _ = + RPC.Contracts.get_balance + ~hooks + ~contract_id:destination.public_key_hash + client + in + unit + +let register ~protocols = + let () = test_update_consensus_key protocols in + let () = + register + "Test set consensus key - baker is not delegate" + (fun client baker_0 baker_1 account_0 _account_1 -> + let baker_0_consensus_key = account_0 in + let* () = + test_consensus_key_update + ~src:baker_0 + ~consensus_key:baker_0_consensus_key + ~baker:baker_1.alias + client + in + unit) + protocols + in + let () = + register + "Test set consensus key - baker is delegate" + (fun client baker_0 _baker_1 account_0 _account_1 -> + let baker_0_consensus_key = account_0 in + let* () = + test_consensus_key_update + ~src:baker_0 + ~consensus_key:baker_0_consensus_key + ~baker:baker_0.alias + client + in + unit) + protocols + in + let () = + register + "Test register with consensus key" + (fun client baker_0 _baker_1 account_0 account_1 -> + let new_delegate = account_0 in + let new_consensus_key = account_1 in + test_register_delegate_with_consensus_key + ~baker:baker_0.alias + ~new_delegate + ~new_consensus_key + client) + protocols + in + let () = + register + "Test revert to unique consensus key" + (fun client baker_0 _baker_1 account_0 account_1 -> + let new_delegate = account_0 in + let new_consensus_key = account_1 in + test_revert_to_unique_consensus_key + ~baker:baker_0.alias + ~new_delegate + ~new_consensus_key + client) + protocols + in + let () = + register + "Test drain delegate with (baker = delegate & consensus = destination)" + (fun client baker_0 _baker_1 account_0 _account_1 -> + let delegate = baker_0 in + let consensus = account_0 in + let destination = account_0 in + test_drain_delegate_1 + ~baker:baker_0.alias + ~delegate + ~consensus + ~destination + client) + protocols + in + let () = + register + "Test drain delegate with (baker = delegate & consensus <> destination)" + (fun client baker_0 _baker_1 account_0 account_1 -> + let delegate = baker_0 in + let consensus = account_0 in + let destination = account_1 in + test_drain_delegate_1 + ~baker:baker_0.alias + ~delegate + ~consensus + ~destination + client) + protocols + in + let () = + register + "Test drain delegate with (baker <> delegate & consensus = destination)" + (fun client baker_0 baker_1 account_0 _account_1 -> + let delegate = baker_0 in + let consensus = account_0 in + let destination = account_0 in + test_drain_delegate_1 + ~baker:baker_1.alias + ~delegate + ~consensus + ~destination + client) + protocols + in + let () = + register + "Test drain delegate with (baker <> delegate & consensus <> destination)" + (fun client baker_0 baker_1 account_0 account_1 -> + let delegate = baker_0 in + let consensus = account_0 in + let destination = account_1 in + test_drain_delegate_1 + ~baker:baker_1.alias + ~delegate + ~consensus + ~destination + client) + protocols + in + () diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- delegates.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- delegates.out index c5963596007d4a5764cabb65c9f5e01892138a0a..7e05acf2dbfbcbfbd366e1663e0b64b1ab987828 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- delegates.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- delegates.out @@ -21,7 +21,8 @@ "frozen_deposits": "200000000000", "staking_balance": "4000000000000", "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], "delegated_balance": "0", "deactivated": false, "grace_period": 5, - "voting_power": "4000000000000", "remaining_proposals": 20 } + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } ./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]/full_balance' "4000000000000" diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out index 5b74758fa4ea2815f6ac6387ae22e0ed9b1815a0..6525d5b7078b74f7ca9098fbc38a4d94a0c8a268 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out @@ -63,15 +63,20 @@ ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights [ { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 0, "estimated_time": "[TIMESTAMP]" }, + "round": 0, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 1, "estimated_time": "[TIMESTAMP]" }, + "round": 1, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 2, "estimated_time": "[TIMESTAMP]" }, + "round": 2, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 3, "estimated_time": "[TIMESTAMP]" }, + "round": 3, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 10, "estimated_time": "[TIMESTAMP]" } ] + "round": 10, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" } ] ./tezos-client rpc get '/chains/main/blocks/head/helpers/current_level?offset=0' { "level": 1, "level_position": 0, "cycle": 0, "cycle_position": 0, @@ -81,15 +86,20 @@ [ { "level": 1, "delegates": [ { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 11, "endorsing_power": 50 }, + "first_slot": 11, "endorsing_power": 50, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 4, "endorsing_power": 47 }, + "first_slot": 4, "endorsing_power": 47, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 2, "endorsing_power": 46 }, + "first_slot": 2, "endorsing_power": 46, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 1, "endorsing_power": 55 }, + "first_slot": 1, "endorsing_power": 55, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 0, "endorsing_power": 58 } ] } ] + "first_slot": 0, "endorsing_power": 58, + "consensus_key": "[PUBLIC_KEY_HASH]" } ] } ] ./tezos-client rpc get /chains/main/blocks/head/helpers/levels_in_current_cycle { "first": 1, "last": 8 } diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- delegates.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- delegates.out index 874166ce630ee0b53637d3ebf2376ab61da02764..839186e69dcc60d0fed175b25800c2519a9c280f 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- delegates.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- delegates.out @@ -23,7 +23,8 @@ protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenes "frozen_deposits": "200000000000", "staking_balance": "4000000000000", "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], "delegated_balance": "0", "deactivated": false, "grace_period": 5, - "voting_power": "4000000000000", "remaining_proposals": 20 } + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im ./tezos-client --mode light rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]/full_balance' diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- misc_protocol.out index e6cf8ebf86271f958c193a63082ab7da8a85a97f..e68a8fa77f191c5a441c119d70a6690c15f852f7 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode light) RPC regression tests- misc_protocol.out @@ -64,15 +64,20 @@ protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenes ./tezos-client --mode light rpc get /chains/main/blocks/head/helpers/baking_rights [ { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 0, "estimated_time": "[TIMESTAMP]" }, + "round": 0, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 1, "estimated_time": "[TIMESTAMP]" }, + "round": 1, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 2, "estimated_time": "[TIMESTAMP]" }, + "round": 2, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 3, "estimated_time": "[TIMESTAMP]" }, + "round": 3, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 10, "estimated_time": "[TIMESTAMP]" } ] + "round": 10, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" } ] protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im ./tezos-client --mode light rpc get '/chains/main/blocks/head/helpers/current_level?offset=0' @@ -84,15 +89,20 @@ protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenes [ { "level": 1, "delegates": [ { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 11, "endorsing_power": 50 }, + "first_slot": 11, "endorsing_power": 50, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 4, "endorsing_power": 47 }, + "first_slot": 4, "endorsing_power": 47, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 2, "endorsing_power": 46 }, + "first_slot": 2, "endorsing_power": 46, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 1, "endorsing_power": 55 }, + "first_slot": 1, "endorsing_power": 55, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 0, "endorsing_power": 58 } ] } ] + "first_slot": 0, "endorsing_power": 58, + "consensus_key": "[PUBLIC_KEY_HASH]" } ] } ] protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im ./tezos-client --mode light rpc get /chains/main/blocks/head/helpers/levels_in_current_cycle diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- delegates.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- delegates.out index 8cc972f14b266f0423ef834c6af45e307ca2854e..faaa3dc4e853512aa87bf5c95d17806503103da4 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- delegates.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- delegates.out @@ -23,7 +23,8 @@ protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGen "frozen_deposits": "200000000000", "staking_balance": "4000000000000", "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], "delegated_balance": "0", "deactivated": false, "grace_period": 5, - "voting_power": "4000000000000", "remaining_proposals": 20 } + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im ./tezos-client --mode proxy rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]/full_balance' diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- misc_protocol.out index 664cafae0909b7c4e480e9ade7bb5ba594f50e3f..a25d314cd6c128ac6eacd3080cfdd3bcff1eaf1a 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy) RPC regression tests- misc_protocol.out @@ -64,15 +64,20 @@ protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGen ./tezos-client --mode proxy rpc get /chains/main/blocks/head/helpers/baking_rights [ { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 0, "estimated_time": "[TIMESTAMP]" }, + "round": 0, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 1, "estimated_time": "[TIMESTAMP]" }, + "round": 1, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 2, "estimated_time": "[TIMESTAMP]" }, + "round": 2, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 3, "estimated_time": "[TIMESTAMP]" }, + "round": 3, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 10, "estimated_time": "[TIMESTAMP]" } ] + "round": 10, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" } ] protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im ./tezos-client --mode proxy rpc get '/chains/main/blocks/head/helpers/current_level?offset=0' @@ -84,15 +89,20 @@ protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGen [ { "level": 1, "delegates": [ { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 11, "endorsing_power": 50 }, + "first_slot": 11, "endorsing_power": 50, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 4, "endorsing_power": 47 }, + "first_slot": 4, "endorsing_power": 47, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 2, "endorsing_power": 46 }, + "first_slot": 2, "endorsing_power": 46, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 1, "endorsing_power": 55 }, + "first_slot": 1, "endorsing_power": 55, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 0, "endorsing_power": 58 } ] } ] + "first_slot": 0, "endorsing_power": 58, + "consensus_key": "[PUBLIC_KEY_HASH]" } ] } ] protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im ./tezos-client --mode proxy rpc get /chains/main/blocks/head/helpers/levels_in_current_cycle diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- delegates.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- delegates.out index c5963596007d4a5764cabb65c9f5e01892138a0a..7e05acf2dbfbcbfbd366e1663e0b64b1ab987828 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- delegates.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- delegates.out @@ -21,7 +21,8 @@ "frozen_deposits": "200000000000", "staking_balance": "4000000000000", "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], "delegated_balance": "0", "deactivated": false, "grace_period": 5, - "voting_power": "4000000000000", "remaining_proposals": 20 } + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } ./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]/full_balance' "4000000000000" diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- misc_protocol.out index c5b98962d41281e95a80f6ce3e4499fe367bc30a..8778a17acf544346e7f8b772a48098337011c3cb 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_data_dir) RPC regression tests- misc_protocol.out @@ -63,15 +63,20 @@ ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights [ { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", - "round": 0, "estimated_time": "[TIMESTAMP]" }, + "round": 0, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", - "round": 1, "estimated_time": "[TIMESTAMP]" }, + "round": 1, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", - "round": 2, "estimated_time": "[TIMESTAMP]" }, + "round": 2, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", - "round": 3, "estimated_time": "[TIMESTAMP]" }, + "round": 3, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", - "round": 4, "estimated_time": "[TIMESTAMP]" } ] + "round": 4, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" } ] ./tezos-client rpc get '/chains/main/blocks/head/helpers/current_level?offset=0' { "level": 2, "level_position": 1, "cycle": 0, "cycle_position": 1, @@ -81,15 +86,20 @@ [ { "level": 2, "delegates": [ { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 10, "endorsing_power": 50 }, + "first_slot": 10, "endorsing_power": 50, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 3, "endorsing_power": 50 }, + "first_slot": 3, "endorsing_power": 50, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 2, "endorsing_power": 65 }, + "first_slot": 2, "endorsing_power": 65, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 1, "endorsing_power": 50 }, + "first_slot": 1, "endorsing_power": 50, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 0, "endorsing_power": 41 } ] } ] + "first_slot": 0, "endorsing_power": 41, + "consensus_key": "[PUBLIC_KEY_HASH]" } ] } ] ./tezos-client rpc get /chains/main/blocks/head/helpers/levels_in_current_cycle { "first": 1, "last": 8 } diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- delegates.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- delegates.out index c5963596007d4a5764cabb65c9f5e01892138a0a..7e05acf2dbfbcbfbd366e1663e0b64b1ab987828 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- delegates.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- delegates.out @@ -21,7 +21,8 @@ "frozen_deposits": "200000000000", "staking_balance": "4000000000000", "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], "delegated_balance": "0", "deactivated": false, "grace_period": 5, - "voting_power": "4000000000000", "remaining_proposals": 20 } + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } ./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]/full_balance' "4000000000000" diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- misc_protocol.out index c5b98962d41281e95a80f6ce3e4499fe367bc30a..8778a17acf544346e7f8b772a48098337011c3cb 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode proxy_server_rpc) RPC regression tests- misc_protocol.out @@ -63,15 +63,20 @@ ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights [ { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", - "round": 0, "estimated_time": "[TIMESTAMP]" }, + "round": 0, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", - "round": 1, "estimated_time": "[TIMESTAMP]" }, + "round": 1, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", - "round": 2, "estimated_time": "[TIMESTAMP]" }, + "round": 2, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", - "round": 3, "estimated_time": "[TIMESTAMP]" }, + "round": 3, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", - "round": 4, "estimated_time": "[TIMESTAMP]" } ] + "round": 4, "estimated_time": "[TIMESTAMP]", + "consensus_key": "[PUBLIC_KEY_HASH]" } ] ./tezos-client rpc get '/chains/main/blocks/head/helpers/current_level?offset=0' { "level": 2, "level_position": 1, "cycle": 0, "cycle_position": 1, @@ -81,15 +86,20 @@ [ { "level": 2, "delegates": [ { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 10, "endorsing_power": 50 }, + "first_slot": 10, "endorsing_power": 50, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 3, "endorsing_power": 50 }, + "first_slot": 3, "endorsing_power": 50, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 2, "endorsing_power": 65 }, + "first_slot": 2, "endorsing_power": 65, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 1, "endorsing_power": 50 }, + "first_slot": 1, "endorsing_power": 50, + "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 0, "endorsing_power": 41 } ] } ] + "first_slot": 0, "endorsing_power": 41, + "consensus_key": "[PUBLIC_KEY_HASH]" } ] } ] ./tezos-client rpc get /chains/main/blocks/head/helpers/levels_in_current_cycle { "first": 1, "last": 8 } diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus - destination).out b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus - destination).out new file mode 100644 index 0000000000000000000000000000000000000000..41e62c49ef1439d62b9888ebec829e3ef43e23f4 --- /dev/null +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus - destination).out @@ -0,0 +1,108 @@ + +./tezos-client --wait none set consensus key for bootstrap1 to dummy_account_0 +Node is bootstrapped. +Estimated gas: 1000 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000367 + Expected counter: 1 + Gas limit: 1100 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000367 + payload fees(the block proposer) ....... +ꜩ0.000367 + Update_consensus_key: + Public key hash: [PUBLIC_KEY_HASH] + This consensus key update was successfully applied + Consumed gas: 1000 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000000000000", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "4000000000000", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000000333333", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "4000000333333", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]", + "pending_consensus_keys": + [ { "cycle": 2, "pkh": "[PUBLIC_KEY_HASH]" } ] } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000004170240", "current_frozen_deposits": "200000208512", + "frozen_deposits": "200000208512", "staking_balance": "4000004170240", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000004170240", "current_frozen_deposits": "200000208512", + "frozen_deposits": "200000208512", "staking_balance": "4000004170240", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"3800003961728" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"0" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"0" + +./tezos-client --wait none drain delegate bootstrap1 to dummy_account_0 with dummy_account_0 +Node is bootstrapped. +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Drain delegate: + Consensus key hash: [PUBLIC_KEY_HASH] + Delegate: [PUBLIC_KEY_HASH] + Destination: [PUBLIC_KEY_HASH] (allocated) + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.06425 + storage fees ........................... +ꜩ0.06425 + [PUBLIC_KEY_HASH] ... -ꜩ3762003.858504 + [PUBLIC_KEY_HASH] ... +ꜩ3762003.858504 + [PUBLIC_KEY_HASH] ... -ꜩ38000.038974 + [PUBLIC_KEY_HASH] ... +ꜩ38000.038974 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "238000580819", "current_frozen_deposits": "200000208512", + "frozen_deposits": "200000208512", "staking_balance": "238000580819", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 4, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"38000372307" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"3762003858504" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"3762003858504" diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus -- destination).out b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus -- destination).out new file mode 100644 index 0000000000000000000000000000000000000000..7f9c6b3912d829ff68dd34030e4ed685abbaf950 --- /dev/null +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus -- destination).out @@ -0,0 +1,108 @@ + +./tezos-client --wait none set consensus key for bootstrap1 to dummy_account_0 +Node is bootstrapped. +Estimated gas: 1000 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000367 + Expected counter: 1 + Gas limit: 1100 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000367 + payload fees(the block proposer) ....... +ꜩ0.000367 + Update_consensus_key: + Public key hash: [PUBLIC_KEY_HASH] + This consensus key update was successfully applied + Consumed gas: 1000 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000000000000", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "4000000000000", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000000333333", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "4000000333333", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]", + "pending_consensus_keys": + [ { "cycle": 2, "pkh": "[PUBLIC_KEY_HASH]" } ] } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000004170240", "current_frozen_deposits": "200000208512", + "frozen_deposits": "200000208512", "staking_balance": "4000004170240", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000004170240", "current_frozen_deposits": "200000208512", + "frozen_deposits": "200000208512", "staking_balance": "4000004170240", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"3800003961728" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"0" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"0" + +./tezos-client --wait none drain delegate bootstrap1 to dummy_account_1 with dummy_account_0 +Node is bootstrapped. +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Drain delegate: + Consensus key hash: [PUBLIC_KEY_HASH] + Delegate: [PUBLIC_KEY_HASH] + Destination: [PUBLIC_KEY_HASH] (allocated) + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.06425 + storage fees ........................... +ꜩ0.06425 + [PUBLIC_KEY_HASH] ... -ꜩ3762003.858504 + [PUBLIC_KEY_HASH] ... +ꜩ3762003.858504 + [PUBLIC_KEY_HASH] ... -ꜩ38000.038974 + [PUBLIC_KEY_HASH] ... +ꜩ38000.038974 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "238000580819", "current_frozen_deposits": "200000208512", + "frozen_deposits": "200000208512", "staking_balance": "238000580819", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 4, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"38000372307" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"0" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"3762003858504" diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus - destination).out b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus - destination).out new file mode 100644 index 0000000000000000000000000000000000000000..ab11adc6f5925ad9f92868a32219267387211038 --- /dev/null +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus - destination).out @@ -0,0 +1,108 @@ + +./tezos-client --wait none set consensus key for bootstrap1 to dummy_account_0 +Node is bootstrapped. +Estimated gas: 1000 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000367 + Expected counter: 1 + Gas limit: 1100 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000367 + payload fees(the block proposer) ....... +ꜩ0.000367 + Update_consensus_key: + Public key hash: [PUBLIC_KEY_HASH] + This consensus key update was successfully applied + Consumed gas: 1000 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000000000000", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "4000000000000", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "3999999999633", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "3999999999633", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]", + "pending_consensus_keys": + [ { "cycle": 2, "pkh": "[PUBLIC_KEY_HASH]" } ] } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000003836540", "current_frozen_deposits": "200000191827", + "frozen_deposits": "200000191827", "staking_balance": "4000003836540", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000003836540", "current_frozen_deposits": "200000191827", + "frozen_deposits": "200000191827", "staking_balance": "4000003836540", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"3800003644713" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"0" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"0" + +./tezos-client --wait none drain delegate bootstrap1 to dummy_account_0 with dummy_account_0 +Node is bootstrapped. +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Drain delegate: + Consensus key hash: [PUBLIC_KEY_HASH] + Delegate: [PUBLIC_KEY_HASH] + Destination: [PUBLIC_KEY_HASH] (allocated) + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.06425 + storage fees ........................... +ꜩ0.06425 + [PUBLIC_KEY_HASH] ... -ꜩ3762003.544659 + [PUBLIC_KEY_HASH] ... +ꜩ3762003.544659 + [PUBLIC_KEY_HASH] ... -ꜩ38000.035804 + [PUBLIC_KEY_HASH] ... +ꜩ38000.035804 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "238000560964", "current_frozen_deposits": "200000191827", + "frozen_deposits": "200000191827", "staking_balance": "238000560964", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 4, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"38000369137" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"3762003544659" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"3762003544659" diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus -- destination).out b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus -- destination).out new file mode 100644 index 0000000000000000000000000000000000000000..e2221c4218b71ea18cacf6e42f20d3aa2c837478 --- /dev/null +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus -- destination).out @@ -0,0 +1,108 @@ + +./tezos-client --wait none set consensus key for bootstrap1 to dummy_account_0 +Node is bootstrapped. +Estimated gas: 1000 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000367 + Expected counter: 1 + Gas limit: 1100 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000367 + payload fees(the block proposer) ....... +ꜩ0.000367 + Update_consensus_key: + Public key hash: [PUBLIC_KEY_HASH] + This consensus key update was successfully applied + Consumed gas: 1000 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000000000000", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "4000000000000", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "3999999999633", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "3999999999633", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]", + "pending_consensus_keys": + [ { "cycle": 2, "pkh": "[PUBLIC_KEY_HASH]" } ] } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000003836540", "current_frozen_deposits": "200000191827", + "frozen_deposits": "200000191827", "staking_balance": "4000003836540", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000003836540", "current_frozen_deposits": "200000191827", + "frozen_deposits": "200000191827", "staking_balance": "4000003836540", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"3800003644713" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"0" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"0" + +./tezos-client --wait none drain delegate bootstrap1 to dummy_account_1 with dummy_account_0 +Node is bootstrapped. +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Drain delegate: + Consensus key hash: [PUBLIC_KEY_HASH] + Delegate: [PUBLIC_KEY_HASH] + Destination: [PUBLIC_KEY_HASH] (allocated) + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.06425 + storage fees ........................... +ꜩ0.06425 + [PUBLIC_KEY_HASH] ... -ꜩ3762003.544659 + [PUBLIC_KEY_HASH] ... +ꜩ3762003.544659 + [PUBLIC_KEY_HASH] ... -ꜩ38000.035804 + [PUBLIC_KEY_HASH] ... +ꜩ38000.035804 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "238000560964", "current_frozen_deposits": "200000191827", + "frozen_deposits": "200000191827", "staking_balance": "238000560964", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 4, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"38000369137" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"0" + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]/balance' +"3762003544659" diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test register with consensus key.out b/tezt/tests/expected/consensus_key.ml/Alpha- Test register with consensus key.out new file mode 100644 index 0000000000000000000000000000000000000000..21d96971409d0a8252509c2a0879b424e30152df --- /dev/null +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test register with consensus key.out @@ -0,0 +1,79 @@ + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]' +{ "balance": "0", "counter": "1" } + +./tezos-client --wait none register key dummy_account_0 as delegate with consensus key dummy_account_1 +Node is bootstrapped. +Estimated storage: no bytes added +Estimated gas: 1000 units (will add 0 for safety) +Estimated storage: no bytes added +Estimated gas: 1000 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000357 + Expected counter: 2 + Gas limit: 1000 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000357 + payload fees(the block proposer) ....... +ꜩ0.000357 + Revelation of manager public key: + Contract: [PUBLIC_KEY_HASH] + Key: [PUBLIC_KEY] + This revelation was successfully applied + Consumed gas: 1000 + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.00025 + Expected counter: 3 + Gas limit: 1000 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.00025 + payload fees(the block proposer) ....... +ꜩ0.00025 + Delegation: + Contract: [PUBLIC_KEY_HASH] + To: [PUBLIC_KEY_HASH] + This delegation was successfully applied + Consumed gas: 1000 + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000271 + Expected counter: 4 + Gas limit: 1100 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000271 + payload fees(the block proposer) ....... +ꜩ0.000271 + Update_consensus_key: + Public key hash: [PUBLIC_KEY_HASH] + This consensus key update was successfully applied + Consumed gas: 1000 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "999999999122", "current_frozen_deposits": "0", + "frozen_deposits": "0", "staking_balance": "999999999122", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "active_consensus_key": "[PUBLIC_KEY_HASH]", + "pending_consensus_keys": + [ { "cycle": 2, "pkh": "[PUBLIC_KEY_HASH]" } ] } + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]' +{ "balance": "0", "counter": "4" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "999999999122", "current_frozen_deposits": "49999999956", + "frozen_deposits": "49999999956", "staking_balance": "999999999122", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test revert to unique consensus key.out b/tezt/tests/expected/consensus_key.ml/Alpha- Test revert to unique consensus key.out new file mode 100644 index 0000000000000000000000000000000000000000..bf19a73ac22be389f87dcf186ae0450d3388e082 --- /dev/null +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test revert to unique consensus key.out @@ -0,0 +1,128 @@ + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]' +{ "balance": "0", "counter": "1" } + +./tezos-client --wait none register key dummy_account_0 as delegate with consensus key dummy_account_1 +Node is bootstrapped. +Estimated storage: no bytes added +Estimated gas: 1000 units (will add 0 for safety) +Estimated storage: no bytes added +Estimated gas: 1000 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000357 + Expected counter: 2 + Gas limit: 1000 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000357 + payload fees(the block proposer) ....... +ꜩ0.000357 + Revelation of manager public key: + Contract: [PUBLIC_KEY_HASH] + Key: [PUBLIC_KEY] + This revelation was successfully applied + Consumed gas: 1000 + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.00025 + Expected counter: 3 + Gas limit: 1000 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.00025 + payload fees(the block proposer) ....... +ꜩ0.00025 + Delegation: + Contract: [PUBLIC_KEY_HASH] + To: [PUBLIC_KEY_HASH] + This delegation was successfully applied + Consumed gas: 1000 + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000271 + Expected counter: 4 + Gas limit: 1100 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000271 + payload fees(the block proposer) ....... +ꜩ0.000271 + Update_consensus_key: + Public key hash: [PUBLIC_KEY_HASH] + This consensus key update was successfully applied + Consumed gas: 1000 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "999999999122", "current_frozen_deposits": "0", + "frozen_deposits": "0", "staking_balance": "999999999122", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "active_consensus_key": "[PUBLIC_KEY_HASH]", + "pending_consensus_keys": + [ { "cycle": 2, "pkh": "[PUBLIC_KEY_HASH]" } ] } + +./tezos-client rpc get '/chains/main/blocks/head/context/contracts/[PUBLIC_KEY_HASH]' +{ "balance": "0", "counter": "4" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "999999999122", "current_frozen_deposits": "49999999956", + "frozen_deposits": "49999999956", "staking_balance": "999999999122", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client --wait none set consensus key for dummy_account_0 to dummy_account_0 +Node is bootstrapped. +Estimated gas: 1000 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000367 + Expected counter: 5 + Gas limit: 1100 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000367 + payload fees(the block proposer) ....... +ꜩ0.000367 + Update_consensus_key: + Public key hash: [PUBLIC_KEY_HASH] + This consensus key update was successfully applied + Consumed gas: 1000 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "1000000383428", "current_frozen_deposits": "49999999956", + "frozen_deposits": "49999999956", "staking_balance": "1000000383428", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 4, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "1000000383061", "current_frozen_deposits": "50000019153", + "frozen_deposits": "50000019153", "staking_balance": "1000000383061", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 4, + "active_consensus_key": "[PUBLIC_KEY_HASH]", + "pending_consensus_keys": + [ { "cycle": 4, "pkh": "[PUBLIC_KEY_HASH]" } ] } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "1000000383061", "current_frozen_deposits": "50000019153", + "frozen_deposits": "50000019153", "staking_balance": "1000000383061", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 4, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test set consensus key - baker is delegate.out b/tezt/tests/expected/consensus_key.ml/Alpha- Test set consensus key - baker is delegate.out new file mode 100644 index 0000000000000000000000000000000000000000..cef7e650c7b2b98eb9ed0dcd8a71452d19666d63 --- /dev/null +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test set consensus key - baker is delegate.out @@ -0,0 +1,52 @@ + +./tezos-client --wait none set consensus key for bootstrap1 to dummy_account_0 +Node is bootstrapped. +Estimated gas: 1000 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000367 + Expected counter: 1 + Gas limit: 1100 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000367 + payload fees(the block proposer) ....... +ꜩ0.000367 + Update_consensus_key: + Public key hash: [PUBLIC_KEY_HASH] + This consensus key update was successfully applied + Consumed gas: 1000 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000000000000", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "4000000000000", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000000333333", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "4000000333333", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]", + "pending_consensus_keys": + [ { "cycle": 2, "pkh": "[PUBLIC_KEY_HASH]" } ] } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000004170240", "current_frozen_deposits": "200000208512", + "frozen_deposits": "200000208512", "staking_balance": "4000004170240", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test set consensus key - baker is not delegate.out b/tezt/tests/expected/consensus_key.ml/Alpha- Test set consensus key - baker is not delegate.out new file mode 100644 index 0000000000000000000000000000000000000000..8c003d1dc2ff9f6b7e6fb21a983983c904db9a75 --- /dev/null +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test set consensus key - baker is not delegate.out @@ -0,0 +1,52 @@ + +./tezos-client --wait none set consensus key for bootstrap1 to dummy_account_0 +Node is bootstrapped. +Estimated gas: 1000 units (will add 100 for safety) +Estimated storage: no bytes added +Operation successfully injected in the node. +Operation hash is '[OPERATION_HASH]' +NOT waiting for the operation to be included. +Use command + tezos-client wait for [OPERATION_HASH] to be included --confirmations 1 --branch [BLOCK_HASH] +and/or an external block explorer to make sure that it has been included. +This sequence of operations was run: + Manager signed operations: + From: [PUBLIC_KEY_HASH] + Fee to the baker: ꜩ0.000367 + Expected counter: 1 + Gas limit: 1100 + Storage limit: 0 bytes + Balance updates: + [PUBLIC_KEY_HASH] ... -ꜩ0.000367 + payload fees(the block proposer) ....... +ꜩ0.000367 + Update_consensus_key: + Public key hash: [PUBLIC_KEY_HASH] + This consensus key update was successfully applied + Consumed gas: 1000 + + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000000000000", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "4000000000000", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "3999999999633", "current_frozen_deposits": "200000000000", + "frozen_deposits": "200000000000", "staking_balance": "3999999999633", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]", + "pending_consensus_keys": + [ { "cycle": 2, "pkh": "[PUBLIC_KEY_HASH]" } ] } + +./tezos-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' +{ "full_balance": "4000003836540", "current_frozen_deposits": "200000191827", + "frozen_deposits": "200000191827", "staking_balance": "4000003836540", + "delegated_contracts": [ "[PUBLIC_KEY_HASH]" ], + "delegated_balance": "0", "deactivated": false, "grace_period": 3, + "voting_power": "4000000000000", "remaining_proposals": 20, + "active_consensus_key": "[PUBLIC_KEY_HASH]" } diff --git a/tezt/tests/main.ml b/tezt/tests/main.ml index f2134e7ae4e1d1588c683eb34a674fac85bc8a7d..0f91aefe265bb2fa226881db4d2649a4e0c62ce7 100644 --- a/tezt/tests/main.ml +++ b/tezt/tests/main.ml @@ -108,6 +108,7 @@ let register_protocol_agnostic_tests () = Mockup.register_global_constants ~protocols:[Alpha] ; Monitor_operations.register ~protocols:[Alpha] ; Multinode_snapshot.register ~protocols:[Alpha] ; + Consensus_key.register ~protocols:[Alpha] ; Node_event_level.register ~protocols:[Alpha] ; Normalize.register ~protocols:[Alpha] ; Precheck.register ~protocols ;