###### tags: `LéCøre` # Baking accounts ## Contents [TOC] ## Introduction Currently, there are 2 types of accounts, implicit and originated. Baker accounts are implicit accounts that delegate to themselves. Because a baker identifier is an implicit account, the only way to change their key is to move to a new implicit account and ask all their delegators to re-delegate to their new address. A new first-class baker account type is added. A baker account is represented by a baker hash with the prefix "SG1". This has the advantage of distinguishing between implicit and baker contracts to allow to associate baker-specific state only with baker accounts and for bakers to be able to change the key they use to participate in the consensus, governance and other interactions with the chain without switching to a new address. Furthermore, baker accounts are enhanced with a generic multi-signature Michelson script. While this may sound like a whole lot of breaking changes, the implementation is mostly additive to make this change as non-intrusive as possible. The breaking changes are listed in the [breaking changes](#Breaking-changes) section. ## Compatibility with the predecessor protocol `007-PsDELPH1` Most of the interactions, operations, encodings and RPCs are compatible with the predecessor protocol version. That is, one can still interact with a baker account using their public key hash (`tz[123]`) - bake and endorse, transfer from and to a baker’s public key hash address, propose and vote on protocol upgrades, originate contracts and being delegated to. This is achieved by migrating all the currently registered bakers to the new accounts and using their public key as a consensus key, explained in further detail in the following section. ## Features ### Consensus key A consensus key is a public key. A baker account has exactly one active consensus key and at most one pending consensus key. When an operation to change baker's consensus key is applied, the new key is pending before it becomes active. Consensus keys (both active and pending) must be unique and its forbidden to use a key that is already being used for an allocated implicit account (that is a `tz[123]` account whose balance is greater than 0ꜩ). This means that there is 1-to-1 mapping between a baker account and its consensus key. An active baker consensus key can be used to bake and endorse and as a source and target of operations: - propose and vote on protocol upgrades - being delegated to - transfer from and to - origination - baker registration On operation application, the hashes of consensus keys (i.e. public key hashes) are mapped to their baker contracts. The mapping from consensus keys to baker accounts applied in an operation is attached to the operation metadata (receipts) in the field `"mapped_keys"`, e.g.: ```json "mapped_keys": [ { "consensus_key": "tz1UJbFsTQfdpa1qYrqHG9Ykw834AXi5WqRR", "baker": "SG1fpFaowYY8G7PfkYdKkGmsMziHKUfrHRHW" } ] ``` When an active consensus key is used as the source of an operation, it will be the baker account that uses this consensus key who pays for the operation burns and fees. For balance transfers, the balance will be credited or debited from the baker's account (because the consensus key may not be allocated with balance). Also, the baker account's internal counter is being used for replay protection. A consensus key can be changed at any point. This may be done with commands (on [a single-signature and a multi-signature baker script](#Generic-multisig-script), respectively): ```shell tezos-client set baker <bkr> consensus key to <key> ``` ```shell # forge a signature tezos-client sign baker transaction on <bkr> setting consensus key to <key> with key <owner_key> # submit the operation with given signatures tezos-client set multisig baker <bkr> consensus key to <key> on behalf of <src> with signatures [<signature>...] ``` The given key then becomes a pending consensus key with its activation cycle set to `Constants.preserved_cycles + 2` cycles from the current cycle. On the start of the activation cycle, a pending consensus key becomes the active consensus key and the previous active consensus key is freed up. Should a new consensus key be set before the current pending key becomes active, the previous pending consensus key will be replaced and free up and the activation cycle will reset to `Constants.preserved_cycles + 2` cycles from the current cycle. A pending consensus key may not be used as a source of target of operations until it becomes active. A command to look-up a baker by an active consensus key is provided: ```shell tezos-client find baker with consensus key <src> ``` ### Generic multisig script Baker accounts include a generic multisig script. For now, baker accounts cannot deploy custom scripts. For those familiar with the multisig script integrated into the tezos client: The generic multisig is similar, but instead of having the possible actions hard-coded in the script's parameter, it accepts a generic lambda expression that may be used to submit custom actions as well as perform the same actions as the non-generic multisig. The baker generic multisig script is based on the [generic multisig](https://github.com/murbard/smart-contracts/blob/abdb582d8f1fe7ba7eb15975867d8862cb70acfe/multisig/michelson/generic.tz) that may be used with originated (`KT1`) contracts. The difference is that the generic action allows one to submit baker operations. Baker operations are operations that may only be applied from baker contract scripts and not from originated contracts. The baker operations are given in the [new operations](#New-operations) section. For the generic multisig script the type of the generic action is extended from returning a list of operations: ``` (lambda %operation unit (list operation)) ``` to return a pair of a list of operations and a list of baker operations: ``` (lambda %operation unit pair (list operation) (list baker_operation))) ``` The baker script is authorized with what we call owner keys. These keys are stored in the script's storage together with a threshold, which determines the minimum number of signatures required to successfully call some action. When only one owner key is set, it is said to be single-signature. The script also contains a counter for replay protection. A list of predefined actions and a generic call with a Michelson lambda expression are supported by the [command line interace](#Command-line-interface) for both single-signature and multi-signature variants. ### Toggle delegations A new baker operation to toggle accepting new delegations and a Michelson instruction to submit this operation is added. When a baker accounts toggles delegations off, any new delegations to the baker will fail. Any existing delegations may still be withdrawn. When the toggle is on, any new delegations will be handled as usual. ## Non-breaking changes ### New RPC New RPC for "bakers" is added. This is to replace the "delegates" RPC, which is deprecated, but remains functional and compatible with the previous version: - GET /chains/main/blocks/head/context/bakers Lists all registered bakers. + chains/main/blocks/head/context/bakers/<Baker_hash>/ - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/balance Returns the full balance of a given baker, including the frozen balances. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/consensus_key Get baker's consensus key that is being used for baking and endorsing. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/deactivated Tells whether the baker is currently tagged as deactivated or not. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/delegated_balance Returns the balances of all the contracts that delegate to a given baker. This excludes the baker's own balance and its frozen balances. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/delegated_contracts Returns the list of contracts that delegate to a given baker. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/frozen_balance Returns the total frozen balances of a given baker, this includes the frozen deposits, rewards and fees. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/frozen_balance_by_cycle Returns the frozen balances of a given baker, indexed by the cycle by which it will be unfrozen. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/grace_period Returns the cycle by the end of which the baker might be deactivated if she fails to execute any baker action. A deactivated baker might be reactivated (without loosing any rolls) with a call to baker script. For deactivated bakers, this value contains the cycle by which they were deactivated. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/pending_consensus_key Get baker's pending consensus key and its activation cycle, if any. If the pending consensus key doesn't get changed before its activation cycle, it will become active and it will be used for baking and endorsing. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/proof_levels Returns the list of levels where a proof has been made against a given delegate. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/staking_balance Returns the total amount of tokens delegated to a given baker. This includes the balances of all the contracts that delegate to it, but also the balance of the baker itself and its frozen fees and deposits. The rewards do not count in the delegated balance until they are unfrozen. - GET /chains/main/blocks/head/context/bakers/<Baker_hash>/voting_power The number of rolls in the vote listings for a given baker. A couple of new helpers RPCs are also added: - GET /chains/main/blocks/head/helpers/is_baker_consensus_key/<pkh> Find the baker hash for a baker that uses the given key as consensus key, if any. + scripts/ - POST /chains/main/blocks/head/helpers/scripts/run_baker_code Run the baker code in the current context - GET /chains/main/blocks/head/helpers/scripts/run_baker_code_contract Get the contract on which the baker code is ran, which corresponds to `SELF` or `SELF_ADDRESS` in Michelson - POST /chains/main/blocks/head/helpers/scripts/trace_baker_code Run the baker code in the current context, keeping a trace ### Command line interface Single-signature is a special case of multi-sig (it has a single owner key). Because of this, single-signature actions may be submitted in a single command, which forges the signature and calls the script. For single-signature commands, the baker account is set as the source and will be paying for the transaction fees and burns that may inccur. We add the following single-signature commands: - Transfer: `tezos-client from baker contract <bkr> transfer <qty> to <dst>` - Submit proposals: `tezos-client from baker contract <bkr> submit proposals for protocols [<proposal>...]` - Submit ballot: `tezos-client from baker contract <bkr> submit ballot for protocol <proposal> <yays_per_roll> <nays_per_roll> <passes_per_roll>` - Set baker active: `tezos-client set baker <bkr> <active/inactive>` - Toggle new delegations: `tezos-client set baker <bkr> <accepting/declining> new delegations` - Set consensus key: `tezos-client set baker <bkr> consensus key to <key>` - Set owner keys: `tezos-client set baker <bkr> threshold to <threshold> and owner keys to [<owner_key>...]` - Generic: `tezos-client call generic baker <bkr> with lambda <lambda>` Calling multi-signature contracts is a bit more involved. There are triples of commands: - "prepare" commands to display the threshold, public keys, and byte sequence to sign for a multisigned transfer - "sign" commands to forge a signature with a given key - "transaction" commands that call the script with the given signatures The multi-signature commands are: - Transfer: - `tezos-client prepare baker transaction on <bkr> transferring <qty> to <dst>` - `tezos-client sign baker transaction on <bkr> transferring <qty> to <dst> with key <owner_key>` - `tezos-client from multisig baker <bkr> transfer <qty> to <dst> on behalf of <src> with signatures [<signature>...]` - Submit proposals: - `tezos-client prepare baker transaction on <bkr> submitting proposals [<proposal>...]` - `tezos-client sign baker transaction on <bkr> submitting proposals [<proposal>...] with key <owner_key>` - `tezos-client from multisig baker <bkr> submit proposals on behalf of <src> with signatures [<signature>...] for protocols [<proposal>...]` - Submit ballot: - `tezos-client prepare baker transaction on <bkr> submitting ballot <proposal> <yays_per_roll> <nays_per_roll> <passes_per_roll>` - `tezos-client sign baker transaction on <bkr> submitting ballot <proposal> <yays_per_roll> <nays_per_roll> <passes_per_roll> with key <owner_key>` - `tezos-client from multisig baker <bkr> submit ballot on behalf of <src> with signatures [<signature>...] for protocol <proposal> <yays_per_roll> <nays_per_roll> <passes_per_roll>` - Set baker active: - `tezos-client prepare baker transaction on <bkr> setting it <active/inactive>` - `tezos-client sign baker transaction on <bkr> setting it <active/inactive> with key <owner_key>` -`tezos-client set multisig baker <bkr> <active/inactive> on behalf of <src> with signatures [<signature>...]` - Toggle new delegations: - `tezos-client prepare baker transaction on <bkr> setting it <accepting/declining> new delegations` - `sign baker transaction on <bkr> setting it <accepting/declining> new delegations with key <owner_key>` - `tezos-client set multisig baker <bkr> <accepting/declining> new delegations on behalf of <src> with signatures [<signature>...]` - Set consensus key: - `tezos-client prepare baker transaction on <bkr> setting consensus key to <key>` - `tezos-client sign baker transaction on <bkr> setting consensus key to <key> with key <owner_key>` - `tezos-client set multisig baker <bkr> consensus key to <key> on behalf of <src> with signatures [<signature>...]` - Set owner keys: - `tezos-client prepare baker transaction on <bkr> setting threshold to <threshold> and owner keys to [<owner_key>...]` - `tezos-client sign baker transaction on <bkr> setting threshold to <threshold> and owner keys to [<owner_key>...] with key <owner_key>` - `tezos-client set multisig bakers <bkr> threshold to <threshold> and owner keys to [<owner_key>...] on behalf of <src> with signatures [<signature>...]` - Generic: - `tezos-client prepare baker transaction on <bkr> calling generic lambda <lambda>` - `tezos-client sign baker transaction on <bkr> calling generic lambda <lambda> with key <owner_key>` - `tezos-client call generic multisig baker <bkr> with lambda <lambda> on behalf of <src> with signatures [<signature>...]` Arguments: - `<bkr>`: baker_hash or its alias - `<src>`: a contract that pays for the call's fees - `<owner_key>`: baker owner key that has to match one of the public keys set in baker script's storage to authorize the call by verifying its signature - `<threshold>`: a minimum number of signatures required - `<key>`: public key - ``<proposal>``: the protocol hash proposal to vote for - `<yays_per_roll>`: number of yays per roll (total number of yays/nays/passes must be equal to 100) - `<nays_per_roll>`: number of nays per roll (total number of yays/nays/passes must be equal to 100) - `<passes_per_roll>`: number of passes per roll (yays, nays and passes must add up to 100) The commands works with the counter in the baker's script storage to prevent replay attacks and construct signed payload that verifies ownership if the signing owner key(s) matches the one(s) in script's storage. ### Michelson New types: - `baker_hash` - the b58check hash of the baker account (prefixed "SG1") - `pvss_key` - PVSS public key - `baker_operations` - baker operations are internal, they may only be submitted from a baker script New instructions to submit supported baker operations: - `SUBMIT_PROPOSALS :: list string : 'S -> baker_operation : 'S` - `SUBMIT_BALLOT :: string : nat : nat : nat : 'S -> baker_operation : 'S` - `SET_BAKER_ACTIVE :: bool : 'S -> baker_operation : 'S` - `TOGGLE_BAKER_DELEGATIONS :: bool : 'S -> baker_operation : 'S` - `SET_BAKER_CONSENSUS_KEY :: key : 'S -> baker_operation : 'S` - `SET_BAKER_PVSS_KEY :: pvss_key : 'S -> baker_operation : 'S` While originated `KT1` contracts script are typechecked to be of the type: ``` lambda (pair 'arg 'global) (pair (list operation) 'global) ``` the type of baker script is extended with baker operations, so that only baker script may submit these operations: ``` lambda (pair 'arg 'global) (pair (pair (list operation) (list baker_operation) 'global)) ``` ### New operations Added new types of manager operation `Baker_registration` and new types of baker operations `Baker_proposals`, `Baker_ballot`, `Set_baker_active`, `Toggle_baker_delegations`, `Set_baker_consensus_key` and `Set_baker_pvss_key`. There are new versions of `Delegation` and `Origination`. The type of the `delegate` field is changed from `public_key_hash` to `baker_hash` and `version` field is added to disambiguate from the legacy types with constant value `"1"`. The legacy types are preserved with the original encoding for compatibility. ### Operation metadata (receipts) A new field `mapped_keys` is added which contains a set of active consensus keys that got mapped to baker accounts during operation application. ### Encoding additions #### Binary encoding descriptions ##### Manager operations - Baker_registration (tag 111) | Name | Size | Contents | |--------------------------------|----------------------|---------------------------------------| | Tag | 1 byte | unsigned 8-bit integer | | source | 21 bytes | $public_key_hash | | fee | Determined from data | $N.t | | counter | Determined from data | $N.t | | gas_limit | Determined from data | $N.t | | storage_limit | Determined from data | $N.t | | credit | Determined from data | $N.t | | consensus_key | Determined from data | $public_key | | threshold | 2 bytes | unsigned 16-bit integer | | # bytes in next field | 4 bytes | unsigned 30-bit integer | | owner_keys | Determined from data | sequence of $public_key | - Origination - new version (tag 209) | Name | Size | Contents | |--------------------------------|----------------------|---------------------------------------| | Tag | 1 byte | unsigned 8-bit integer | | source | 21 bytes | $public_key_hash | | fee | Determined from data | $N.t | | counter | Determined from data | $N.t | | gas_limit | Determined from data | $N.t | | storage_limit | Determined from data | $N.t | | balance | Determined from data | $N.t | | ? presence of field “delegate” | 1 byte | boolean (0 for false, 255 for true) | | delegate | 20 bytes | $baker_hash | | script | Determined from data | $scripted.contracts | - Delegation - new version (tag 210) | Name | Size | Contents | |--------------------------------|----------------------|---------------------------------------| | Tag | 1 byte | unsigned 8-bit integer | | source | 21 bytes | $public_key_hash | | fee | Determined from data | $N.t | | counter | Determined from data | $N.t | | gas_limit | Determined from data | $N.t | | storage_limit | Determined from data | $N.t | | balance | Determined from data | $N.t | | ? presence of field “delegate” | 1 byte | boolean (0 for false, 255 for true) | | delegate | 20 bytes | $baker_hash | ##### Operation metadata - Operation_with_metadata (tag 0) | Name | Size | Contents | |---|---|---| | Tag | 1 byte | unsigned 8-bit integer | | # bytes in next field | 4 bytes | unsigned 30-bit integer | | contents | Variable | sequence of $operation.alpha.operation_contents_and_result | | ? presence of field "signature" | 1 byte | boolean (0 for false, 255 for true) | | signature | 64 bytes | bytes | | # bytes in next field | 4 bytes | unsigned 30-bit integer | | mapped_keys | Variable | sequence of $mapped_key - $mapped_key | Name | Size | Contents | |---|---|---| | consensus_key | 21 bytes | $public_key_hash | | baker | 20 bytes | $baker_hash | ##### Baker operations (internal only) - Baker\_proposals (tag 0) | Name | Size | Contents | |------------------------|----------|-------------------------| | Tag | 1 byte | unsigned 8-bit integer | | period | 4 bytes | signed 32-bit integer | | \# bytes in next field | 4 bytes | unsigned 30-bit integer | | proposals | Variable | sequence of $X\_1 | - Baker\_ballot (tag 1) | Name | Size | Contents | |------------------------|----------|-------------------------| | Tag | 1 byte | unsigned 8-bit integer | | period | 4 bytes | signed 32-bit integer | | \# bytes in next field | 4 bytes | unsigned 30-bit integer | | proposal | Variable | bytes | | ballot | 6 bytes | $ballot | - Set\_baker\_active (tag 2) | Name | Size | Contents | |--------|--------|-------------------------------------| | Tag | 1 byte | unsigned 8-bit integer | | active | 1 byte | boolean (0 for false, 255 for true) | - Toggle\_baker\_delegations (tag 3) | Name | Size | Contents | |---------------------|--------|-------------------------------------| | Tag | 1 byte | unsigned 8-bit integer | | accept\_delegations | 1 byte | boolean (0 for false, 255 for true) | - Set\_baker\_consensus\_key (tag 4) | Name | Size | Contents | |------|----------------------|------------------------| | Tag | 1 byte | unsigned 8-bit integer | | key | Determined from data | $public\_key | - Set\_baker\_pvss\_key (tag 5) | Name | Size | Contents | |------|----------------------|------------------------| | Tag | 1 byte | unsigned 8-bit integer | | key | Determined from data | $X\_1 | - $X\_1 | Name | Size | Contents | |------------------------|----------|-------------------------| | \# bytes in next field | 4 bytes | unsigned 30-bit integer | | Unnamed field 0 | Variable | bytes | #### JSON encoding descriptions - $Baker_hash: ```json /* A baker ID (Base58Check-encoded) */ $unistring ``` - $operation.alpha.contents: ```json { /* Origination */ "kind": "origination", "source": $Signature.Public_key_hash, "fee": $mutez, "counter": $positive_bignum, "gas_limit": $positive_bignum, "storage_limit": $positive_bignum, "balance": $mutez, "delegate"?: $Baker_hash, "script": $scripted.contracts, "version": "1" } || { /* Delegation */ "kind": "delegation", "source": $Signature.Public_key_hash, "fee": $mutez, "counter": $positive_bignum, "gas_limit": $positive_bignum, "storage_limit": $positive_bignum, "delegate"?: $Baker_hash, "version": "1" } || { /* Baker_registration */ "kind": "baker_registration", "source": $Signature.Public_key_hash, "fee": $mutez, "counter": $positive_bignum, "gas_limit": $positive_bignum, "storage_limit": $positive_bignum, "credit": $mutez, "consensus_key": $Signature.Public_key, "threshold": integer ∈ [0, 2^16-1], "owner_keys": [ $Signature.Public_key ... ] } ``` - $operation.alpha.internal_operation: ```json /* Internal_manager_operation */ { /* Origination */ "source": $contract_id, "nonce": integer ∈ [0, 2^16-1], "kind": "origination", "balance": $mutez, "delegate"?: $Baker_hash, "script": $scripted.contracts, "version": "1" } || { /* Delegation */ "source": $contract_id, "nonce": integer ∈ [0, 2^16-1], "kind": "delegation", "delegate"?: $Baker_hash, "version": "1" } || { /* Baker_registration */ "source": $contract_id, "nonce": integer ∈ [0, 2^16-1], "kind": "baker_registration", "credit": $mutez, "consensus_key": $Signature.Public_key, "threshold": integer ∈ [0, 2^16-1], "owner_keys": [ $Signature.Public_key ... ] } || /* Internal_baker_operation */ { /* Baker_proposals */ "baker": $Baker_hash, "nonce": integer ∈ [0, 2^16-1], "kind": "baker_proposals", "period": integer ∈ [-2^31-2, 2^31+2], "proposals": [ $unistring ... ] } || { /* Baker_ballot */ "baker": $Baker_hash, "nonce": integer ∈ [0, 2^16-1], "kind": "baker_ballot", "period": integer ∈ [-2^31-2, 2^31+2], "proposal": $unistring, "ballot": { "yays_per_roll": integer ∈ [0, 2^16-1], "nays_per_roll": integer ∈ [0, 2^16-1], "passes_per_roll": integer ∈ [0, 2^16-1] } } || { /* Set_baker_active */ "baker": $Baker_hash, "nonce": integer ∈ [0, 2^16-1], "kind": "set_baker_active", "active": boolean } || { /* Toggle_baker_delegations */ "baker": $Baker_hash, "nonce": integer ∈ [0, 2^16-1], "kind": "toggle_baker_delegations", "accept_delegations": boolean } || { /* Set_baker_consensus_key */ "baker": $Baker_hash, "nonce": integer ∈ [0, 2^16-1], "kind": "set_baker_consensus_key", "key": $Signature.Public_key } || { /* Set_baker_pvss_key */ "baker": $Baker_hash, "nonce": integer ∈ [0, 2^16-1], "kind": "set_baker_pvss_key", "key": $An element of secp256k1 } ``` - $mapped_key: ```json { "consensus_key": $Signature.Public_key_hash, "baker": $Baker_hash } ``` - $operation: ```json { "protocol": "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK", "chain_id": $Chain_id, "hash": $Operation_hash, "branch": $block_hash, "contents": [ $operation.alpha.operation_contents_and_result ... ], "signature"?: $Signature, "mapped_keys": [ $mapped_key ... ] } ``` - $operation.alpha.operation_with_metadata: ```json { /* Operation_with_metadata */ "contents": [ $operation.alpha.operation_contents_and_result ... ], "signature"?: $Signature, "mapped_keys": [ $mapped_key ... ] } || { /* Operation_without_metadata */ "contents": [ $operation.alpha.contents ... ], "signature"?: $Signature } ``` ## Breaking changes ### Overview #### Baker registration In the new protocol, the operation and the client command to register a new baker account has been changed in a way that is not compatible with the predecessor protocol. This is due to the fact that a successful baker registration now originates a new account. Previously, a baker account has been internally represented by an implicit account that delegated to itself. #### Baker reactivation Because baker accounts are no longer internally self-delegated, one can no longer reactivate an inactive baker account with the baker registration or self-delegation command. ### RPC The "delegates" RPC is deprecated, but it remains functional and compatible with the previous protocol version. The [new "bakers" RPC](#New-RPC) should be preferred. The types "delegate" has been changed in "contracts" RPC for endpoints: - GET chains/main/blocks/head/context/contracts/<contract_id> - GET /chains/main/blocks/head/context/contracts/<contract_id>/delegate The "manager_keys" endpoint in "contracts" RPC is being deprecated, but remains functional: - GET /chains/main/blocks/head/context/contracts/<contract_id>/manager_key DEPRECATED: use `public_key` instead. Access the manager of a contract. - GET /chains/main/blocks/head/context/contracts/<contract_id>/public_key Access the public key of a contract, if any. For implicit contracts, this may be their revealed key and for baker contracts it's their consensus key In the "votes" RPC, the "ballot_list" endpoint has replaced field "pkh" with new field "baker", whose type has been changed from public key hash to baker hash: - GET /chains/main/blocks/head/votes/ballot_list Ballots casted so far during a voting period. Also in the "votes" RPC, the "listings" endpoint has replaced field "pkh" with new field "baker", whose type has been changed from public key hash to baker hash: - GET /chains/main/blocks/head/votes/listings List of bakers with their voting weight, in number of rolls. ### Command line interface #### Baker registration The old command that is no longer functional: ``` tezos-client register key <mgr> as delegate ``` Baker registration now requires a consensus key, threshold, owner keys and some initial balance for the new baker account that will be originated on successful execution: ``` tezos-client register baker <alias> transferring <qty> from <src> with consensus key <key> and threshold <threshold> and owner keys [<key>...] ``` #### Baker reactivation The old command that is no longer functional: ``` tezos-client register key <mgr> as delegate ``` And the other command that is still functional, but can no longer be used for this purpose: ``` tezos-client set delegate for <src> to <mgr> ``` Become ([single-signature and multi-signature](#Command-line-interface), respectively) ``` tezos-client set baker <baker> active/inactive on behalf of <src> with key <owner_key> ``` ``` tezos-client prepare baker transaction on <baker> setting it active/inactive tezos-client sign baker transaction on <baker> setting it active/inactive with key <owner_key> tezos-client set bakers <baker> active/inactive on behalf of <src> with signatures [<owner_key>...] ``` ### Michelson There are no breaking changes to Michelson, however two instructions have been deprecated in favour of new versions. The deprecated instructions will continue to work as before for the already deployed contracts and are forbidden to be used when deploying new contracts. In the new versions, the type of delegate is changed from `key_hash` to `baker_hash`: - `SET_DELEGATE` - legacy `:: option key_hash : 'S -> operation : 'S` - new `:: option baker_hash : 'S -> operation : 'S` - `CREATE_CONTRACT { storage 'g ; parameter 'p ; code ... }` - legacy ``` :: key_hash : option key_hash : bool : bool : mutez : 'g : 'S -> operation : address : 'S ``` - new ``` :: key_hash : option baker_hash : bool : bool : mutez : 'g : 'S -> operation : address : 'S ``` ### Operations changes The baker registration operation which was previously represented by a self-delegation can no longer be used for this purpose. There is now a dedicated baker registration operation described in the [New operations](#New-operations) section. The baker reactivation operation which was previously also self-delegation can no longer be used for this purpose. Instead, baker account may be reactivated (and also deactivate) by a call to a the baker script with the `SET_BAKER_ACTIVE` Michelson instruction. ### Encodings changes - balance_updates (receipts) - changed the field `delegate: Signature.Public_key_hash.encoding` to `baker: Baker_hash.encoding` - added a new kind `"migration"` for balance updates applied during migration - listings - changed the field `pkh: Signature.Public_key_hash.encoding` to `baker: Baker_hash.encoding` #### JSON encoding descriptions - $operation_metadata.alpha.balance_updates: ```json [ { "kind": "contract", "contract": $contract_id, "change": $int64 } || { "kind": "freezer", "category": "rewards", "baker": $Baker_hash, "cycle": integer ∈ [-2^31-2, 2^31+2], "change": $int64 } || { "kind": "freezer", "category": "fees", "baker": $Baker_hash, "cycle": integer ∈ [-2^31-2, 2^31+2], "change": $int64 } || { "kind": "freezer", "category": "deposits", "baker": $Baker_hash, "cycle": integer ∈ [-2^31-2, 2^31+2], "change": $int64 } || { "kind": "migration", "contract": $contract_id, "change": $int64 } ... ] ``` - listings: ```json [ { "contract": $contract_id, "votes": integer ∈ [-2^31-2, 2^31+2] } ... ] ``` ### Storage Storage changes (besides type changes also include paths changes): - Roll.Owner - value type from "Signature.Public_key_hash" to "Baker_hash" - Contract.Delegate - value type from "Signature.Public_key_hash" to "Baker_hash" - Vote.Listings - key type from "Signature.Public_key_hash" to "Baker_hash" - Vote.Proposals - value type from "Signature.Public_key_hash" to "Baker_hash" - Vote.Proposals_count - key type from "Signature.Public_key_hash" to "Baker_hash" - Vote.Ballots - key type from "Signature.Public_key_hash" to "Baker_hash" - Seed.unrevealed_nonce record type - field name from "delegate" to "baker" and - type from "Signature.Public_key_hash" to "Baker_hash" - Roll.Delegate_roll_list - moved to Roll.Baker_roll_list - key type from "Signature.Public_key_hash" to "Baker_hash" - Roll.Delegate_change - move to Roll.Baker_change - key type from "Signature.Public_key_hash" to "Baker_hash" - Contract.Delegated - move to Baker.Delegated - value type from "Signature.Public_key_hash" to "Baker_hash" - Delegates - move to Baker.Registered - value type from "Signature.Public_key_hash" to "Baker_hash" - Active_delegates_with_rolls - move to Baker.Active_with_rolls - value type from "Signature.Public_key_hash" to "Baker_hash" - Delegates_with_frozen_balance - move to Baker.With_frozen_balance - value type from "Signature.Public_key_hash" to "Baker_hash" - Contract.Inactive_delegate - move to Baker.Inactive - value type from "Signature.Public_key_hash" to "Baker_hash" - path from "contract/inactive_delegate" to "baker/inactive" - Contract.Delegate_desactivation - move to Baker.Deactivation - key type from "Signature.Public_key_hash" to "Baker_hash" - path from "contract/delegate_desactivation" to "baker/deactivation" - Contract.Frozen_deposits - move to Baker.Frozen_deposits - key type from "Signature.Public_key_hash" to "Baker_hash" - path from "contract/frozen_balance/deposits" to "baker/frozen_balance/deposits" - Contract.Frozen_fees - move to Baker.Frozen_fees - key type from "Signature.Public_key_hash" to "Baker_hash" - path from "contract/frozen_balance/fees" to "baker/frozen_balance/fees" - Contract.Frozen_rewards - move to Baker.Frozen_rewards - key type from "Signature.Public_key_hash" to "Baker_hash" - path from "contract/frozen_balance/rewards" to "baker/frozen_balance/rewards" ### Protocol bootstrap parameters The bootstrap accounts are no longer bakers, instead they are just regular implicit accounts. A new field for bootstrap bakers has been added. ## Protocol migration from predecessor protocol `007-PsDELPH1` All (valid) registered bakers and their associated storages are migrated to their new SG1 baker accounts. We move the balance of the original implicit baker accounts to the new baker accounts. The moved balances are visible in the block's metadata `balance_updates` field of the first block of the new protocol, distinguished from regular balance updates with the [kind set to `"migration"`](#Encodings-changes). For each baker, we set the consensus key and owner keys to the source implicit account's public key and the threshold to 1. This implies that all the [migrated bakers' scripts](#Generic-multisig-script) will be initially setup for [single-signature interactions](#Command-line-interface). The migrated consensus keys are pre-actived to be usable immediatelly and no pending consensus keys are set. ## Appendix ### General multisig baker script (Michelson) ``` parameter %root (or (unit %default) (pair %main (pair :payload (nat %counter) # counter, used to prevent replay attacks (or :action # payload to sign, represents the requested action (lambda %operation unit (pair (list operation) (list baker_operation))) (pair %change_keys # change the keys controlling the multisig (nat %threshold) # new threshold (list %keys key)))) # new list of keys (list %sigs (option signature)))); # signatures storage (pair (nat %stored_counter) (pair (nat %threshold) (list %keys key))) ; code { UNPAIR ; IF_LEFT { # Default entry point: do nothing # This entry point can be used to send tokens to this contract DROP ; NIL baker_operation ; NIL operation ; PAIR ; PAIR } { # Main entry point # Assert no token was sent: # to send tokens, the default entry point should be used PUSH mutez 0 ; AMOUNT ; ASSERT_CMPEQ ; SWAP ; DUP ; DIP { SWAP } ; DIP { UNPAIR ; # pair the payload with the current contract address, to ensure signatures # can't be replayed accross different contracts if a key is reused. DUP ; SELF_ADDRESS ; CHAIN_ID ; PAIR ; PAIR ; PACK ; # form the binary payload that we expect to be signed DIP { UNPAIR @counter ; DIP { SWAP } } ; SWAP } ; # Check that the counters match UNPAIR @stored_counter; DIP { SWAP }; ASSERT_CMPEQ ; # Compute the number of valid signatures DIP { SWAP } ; UNPAIR @threshold @keys; DIP { # Running count of valid signatures PUSH @valid nat 0; SWAP ; ITER { DIP { SWAP } ; SWAP ; IF_CONS { IF_SOME { SWAP ; DIP { SWAP ; DIIP { DUUP } ; # Checks signatures, fails if invalid { DUUUP; DIP {CHECK_SIGNATURE}; SWAP; IF {DROP} {FAILWITH} }; PUSH nat 1 ; ADD @valid } } { SWAP ; DROP } } { # There were fewer signatures in the list # than keys. Not all signatures must be present, but # they should be marked as absent using the option type. FAIL } ; SWAP } } ; # Assert that the threshold is less than or equal to the # number of valid signatures. ASSERT_CMPLE ; # Assert no unchecked signature remains IF_CONS {FAIL} {} ; DROP ; # Increment counter and place in storage DIP { UNPAIR ; PUSH nat 1 ; ADD @new_counter ; PAIR} ; # We have now handled the signature verification part, # produce the operation requested by the signers. IF_LEFT { # Get operation UNIT ; EXEC } { # Change set of signatures DIP { CAR } ; SWAP ; PAIR ; NIL baker_operation ; NIL operation ; PAIR } ; PAIR } } ```