BSIP: 47
Title: Vote Proxies for Different Referendum Categories and explicit voting operation
Authors: Fabian Schuh <https://github.com/xeroc>
Dmitrij Vinokour <https://github.com/Dimfred>
Alex Megalokonomos <https://github.com/clockworkgr>
Michel Santos <https://github.com/MichelSantos>
Status: Draft
Type: Protocol
Created: 2018-09-20
Discussion: https://github.com/bitshares/bsips/pull/114
Voting power by core token holders may be assigned to different proxies in each of the BitShares referendum categories: witnesses, committee members, and worker proposals.
Some proxies can be more or less knowledgeable, wise, and trusted by token holders to vote on certain referendum categories than others. It is therefore desirable to empower token holders to select different proxies for each of the referendum categories.
If the ability to select multiple proxies or to directly vote through a single new operation were made possible, this new operation could be used in conjunction with BSIP40 which will allow an account holder to assign a specific key for voting. This combination could simplify voting for many account holders.
Holders of the core token of BitShares (BTS) have always had the ability to directly vote on three referendum categories: witnesses, committee members, and worker proposals. They have also had the option of delegating their voting power to another account (a "proxy") to vote on any of these referendum categories.
Rather than delegating voting power to a single proxy for all three referendum categories, a core token holder might prefer to select different proxies for each of the referendum categories.
This more granular approach empowers core token holders with more options. A BTS token holder may choose to directly vote on any referendum category including the option to abstain. A BTS token holder may choose to select proxies for each of the referendum categories. Each of the referendum categories may have distinct proxies or may have common proxies. Some referendum categories may have assigned proxies while others may be unassigned. Any referendum category that does not have an assigned proxy permits the voter to vote directly on any referendum in that category. But if a confused core token holder votes for a referendum in a category while also delegating that category to a proxy, the token holder's direct vote shall be ignored.
The introduction of a new operation (account_update_votes_operation
) with additional changes to the core shall also enable an account holder to select proxies for different referendum categories, and to vote for referendums without needing to use the existing account_update_operation
. The existing operation requires the account holder to pass all possible account settings to avoid overriding existing settings. This is inconvenient and requires a higher payload to be stored on the blockchain which results in the account holder paying a higher fee. The proposed operation shall only update the portion of the account data
that is related to voting and should also reduce the fee.
The new operation only needs to include
- The voting account
- The desired proxy, if any, for the committee referendum category
- The desired proxy, if any, for the witness referendum category
- The desired proxy, if any, for the worker referendum category
- The quantity of desired witnesses
- The quantity of desired committee members
- The list of referendums that are supported
Whenever a proxy for a category is assigned, any direct votes by a core token holder within that category shall be ignored. Whenever a proxy for a category is unassigned, any direct votes by a core token holder for that category shall be counted during the vote tallying process of the blockchain. This shall require an upgrade to the protocol.
A new special account GRAPHENE_PROXY_PER_CATEGORY_ACCOUNT
with ID 1.2.6
is defined and added to the database at protocol change activation time.
Fields:
The account_options
receives three new extensions:
optional<account_id_type> committee_voting_account
optional<account_id_type> witness_voting_account
optional<account_id_type> worker_voting_account
Validation:
- These extensions must not be present before the protocol change activation date, neither in transactions nor in proposals.
- If any extension is present, it must contain the ID of an existing account.
- If any extension is present,
account_options.voting_account == GRAPHENE_PROXY_PER_CATEGORY_ACCOUNT
Note: this is an implementation detail and meant to be a hint for later development. The actual implementation may differ.
The account object shall receive these new fields:
flat_set<vote_id_type> committee_votes
flat_set<vote_id_type> witness_votes
flat_set<vote_id_type> worker_votes
account_create_operation
and account_update_operation
shall be modified to create these sets by filtering the account_options.votes
field appropriately. account_update_votes_operation
shall also create these sets by filtering the votes_to_add
and votes_to_remove
fields appropriately.
The following is an example implementation.
struct account_update_votes_operation : public base_operation
{
asset fee;
/// The account to update
account_id_type account;
/// New account options
flat_set<vote_id_type> votes_to_add;
flat_set<vote_id_type> votes_to_remove;
// A new voting account to set
optional<account_id_type> committee_voting_account
optional<account_id_type> witness_voting_account
optional<account_id_type> worker_voting_account
// A new number of witness_votes to set
optional<uint16_t> num_witness;
// A new number of committee_votes to set
optional<uint16_t> num_committee;
// For future extensions (see account_update_operation)
extensions_type extensions;
};
Changes to direct votes can be specified by means of a list of vote identifiers to be added or removed. This has multiple advantages:
- Reduces the size of the operation compared to replacing the entire slate
- Allows to easily compare votes before and after the operation
Validation checks:
Many of the validation checks are dependent on the merger of the proposed values in the operation with the account's current voting values on the blockchain.
General validation checks
account
must be a valid account ID, must exist, must authorize the operation, must pay feecommittee_voting_account
, if present, must be a valid account ID, must existwitness_voting_account
, if present, must be a valid account ID, must existworker_voting_account
, if present, must be a valid account ID, must exist- Validate the existence of each vote to add and remove
Committee validation checks
- Let the new committee slate consist of the current commitee slate plus the committee
votes_to_add
minus the committeevotes_to_remove
- If
committee_voting_account
is present- Let
new_committee_account
=committee_voting_account
- Let
- otherwise
- Let
new_committee_account
=account_options.committee_voting_account
- Let
num_committee
, if present, is only allowed when:new_committee_account
=GRAPHENE_PROXY_TO_SELF_ACCOUNT
, and- 0 ≤
num_committee
≤ size of new committee slate ≤chain_params.maximum_committee_count
- If
num_committee
is present- Let
new_num_committee
=num_committee
- Let
- otherwise
- Let
new_num_committee
=account_options.num_committee
- Let
- Non-empty committee
votes_to_add
andvotes_to_remove
are only allowed when:new_committee_account
=GRAPHENE_PROXY_TO_SELF_ACCOUNT
, and- 0 ≤
new_num_committee
≤ size of new committee slate ≤chain_params.maximum_committee_count
Witness Validation Checks
- Let the new witness slate consist of the current witness slate plus the witness
votes_to_add
minus the witnessvotes_to_remove
- If
witness_voting_account
is present- Let
new_witness_account
=witness_voting_account
- Let
- otherwise
- Let
new_witness_account
=account_options.witness_voting_account
- Let
num_witness
, if present, is only allowed when:- if
new_witness_account
=GRAPHENE_PROXY_TO_SELF_ACCOUNT
, and - if 0 ≤
num_witness
≤ size of new witness slate ≤chain_params.maximum_witness_count
- if
- If
num_witness
is present- Let
new_num_witness
=num_witness
- Let
- otherwise
- Let
new_num_witness
=account_options.num_witness
- Let
- Non-empty witness
votes_to_add
andvotes_to_remove
are only allowed when:new_witness_account
=GRAPHENE_PROXY_TO_SELF_ACCOUNT
, and- 0 ≤
new_num_witness
≤ size of new witness slate ≤chain_params.maximum_witness_count
Worker Validation Checks
- If
worker_voting_account
is present- Let
new_worker_account
=worker_voting_account
- Let
- otherwise
- Let
new_worker_account
=account_options.worker_voting_account
- Let
- The worker
votes_to_add
andvotes_to_remove
are valid:- if
new_worker_account
=GRAPHENE_PROXY_TO_SELF_ACCOUNT
- if
Evaluation:
- Update the account's
account_options.committee_votes
,account_options.witness_votes
, andaccount_options.worker_votes
by filtering thevotes_to_add
andvotes_to_remove
field appropriately - If any of
committee_voting_account
,witness_voting_account
orworker_voting_account
is present- Update the corresponding field in the account's
account_options
- Set the account's
account_options.voting_account
toGRAPHENE_PROXY_PER_CATEGORY_ACCOUNT
- Update the corresponding field in the account's
- if
num_witness
is presentaccount_options.witness_votes = num_witness
- if
num_committee
is presentaccount_options.committee_votes = num_committee
- Update the account's last vote time to the head block time
This operation shall also be updated for backwards compatibility. If account_options.voting_account == GRAPHENE_PROXY_PER_CATEGORY_ACCOUNT
, then the account's per-category voting proxies are set to the specified extension if present, or to GRAPHENE_PROXY_TO_SELF_ACCOUNT
if absent.
Otherwise, the voting proxy for all three categories is set to account_options.voting_account
.
This operation shall also be updated for backwards compatibility. If account_options.voting_account == GRAPHENE_PROXY_PER_CATEGORY_ACCOUNT
, then the account's per-category voting proxies are set to the specified extension if present, or remain unchanged if absent.
Otherwise, the voting proxy for all three categories is set to account_options.voting_account
.
The vote tallying algorithm shall be modified to select the opinion_account
per voting category, and use the current account's voting stake only for the opinion account's votes in the respective category.
Other BSIPs that may scale the voting weight of an account, such as by vote decay or by vote staking, can remain compatible with this BSIP by assigning the scaled voting weight to the different voting proxies that may or may not be selected by an account.
There will be a performance impact by account_create_operation
, account_update_operation
, and account_update_votes_operation
due to the filtering if implemented as suggested. This impact should be small overall, because these operations are comparatively rare.
There will also be some overhead for vote tallying. Vote tallying happens only during the maintenance interval so the operational impact should be negligible as well.
Note that the cumulative effect of both may be noticable during chain replay.
This proposal introduces a means for token holders to select different proxies in each of the BitShares referendum categories: witnesses, committee members, and worker proposals. The proposed mechanism in combination with BSIP40 will permit core token holders to simplify automated voting without compromising the account through the use of a new operation that can be used only for voting.
This document is placed in the public domain.