BSIP: 0084
Title: Elections based on non-core asset
Authors: Peter Conrad
Status: Draft
Type: Protocol
Created: 2019-10-12
Discussion: https://github.com/bitshares/bsips/issues/81
From the beginning, the BitShares blockchain has offered the ability to vote with the core token, and to have elected accounts govern the blockchain.
For specific use-cases it can be desirable to have a similar mechanism for voting and elections where the votes are counted in relation not to BTS but to some other asset. An example might be a community of people who are interested in a specific topic.
This BSIP proposes changes that will enable elections based on dedicated assets.
The feature has been requested from independent businesses as well as from within the community.
It allows the definition of more fine-grained roles in any kind of governance, and offers the possibility to elect people with the specific knowledge required for specific tasks.
There are fundamental differences between the mechanics proposed here and the mechanics already in place for BTS-based voting.
BTS balances are affected by almost every operation, due to transaction fees. The voting tokens will only be affected when they are being used.
BTS is used in a multitude of ways, e. g. as collateral, as the counterpart in most active markets, as payment for workers and witnesses, as cashback for fees and so on. Contrarily, it is assumed that the primary purpose of the voting tokens will be voting. They are unlikely to be used as collateral.
These differences allow for various simplifications and optimizations. In particular, we propose to allow only liquid balances for voting. Because these presumably change rarely in comparison to the number of distinct balances, it is more efficient to recalculate votes on the fly instead of once per maintenance interval (see STEEM for comparison). Nevertheless, the Elected Authority can be configured that the actual accounts that are in control of the Authority only change every given time interval (e.g. only every hour).
Furthermore, we make no distinction between voting and elections. Voting (as in making a yes/no decision) can be emulated with an election where only the votes for two designated candidates are counted and compared to each other. Depending on voting rules (to be defined externally on a case-by-case basis), the one with more votes wins, or perhaps the one with an absolute majority of eligible votes.
Because maintaining elected authorities is expensive (in terms of node resources), they should not stay active any longer than necessary. We propose to incentivize removal of elected authorities by locking up half of the creation fee, and to pay it back to the creator when the object is deleted. It is recommended that the committee set an accordingly high fee for the create operation.
A new asset flag/permission "voting_allowed" will be introduced. At the time of the hardfork, all existing assets except BTS will have the corresponding permission set.
As usual with flags, the flag can be changed only if the permission is set. The permission can be unset any time, but can be set only when supply is zero.
The flag must not be used before the time of the hardfork.
Note 1: Since the overall computational overhead for this voting mechanism is significant, the height of the fee should reflect this.
Note 2: The new asset flag voting_allowed is only checked for this operation. If the flag is removed from an asset, any existing elected authorities are unaffected.
Fields:
account_id_type creator- the account to pay the fee, also the only one who can delete the authorityasset_id_type voting_asset- the asset on which to base the votingunsigned_int num_members- the number of authority members to vote on if fixed, or 0 otherwiseunsigned_int min_members- the minimum number of authority members to elect, or 0 if fixedunsigned_int max_members- the maximum number of authority members that can be elected, or 0 if fixeduint16_t threshold- the threshold scaled percentage of weighter member approvals required for authority approvalflat_set<account_id_type> candidates- a list of candidates eligible for voting, or emptyoptional<asset> candidates_hold_min- an asset and minimum amount of it that candidates must hold to be eligible for votingbool proxy_allowed- indicates if proxy voting is allowedoptional<time_point_sec> vote_until- an optional ending date after which voting slates are frozenoptional<uint32_t> retally_interval- if present, the vote tally result is applied to the authority only everyretally_intervalseconds
Validation:
The operation must not be used before the time of the hardfork.
creatormust exist, must have lifetime membership, and must have sufficient balance to pay the fee.voting_assetmust exist and must have thevoting_allowedflag set.thresholdmust be in the range1..GRAPHENE_100_PERCENT- If
num_membersis 0 thenmin_membersandmax_membersmust both be positive. - If
num_membersis positive then bothmin_membersandmax_membersmust equal 0. - If
candidatesis not empty then- Its size must be greater or equal to
max(num_members,min_members). candidates_hold_minmust not be present.
- Its size must be greater or equal to
- If
candidates_hold_minis present thecandidatesmust be empty. vote_until, if present, must be in the futureretally_interval, if present, must be greater than the block time
Evaluation:
A new object type elected_authority_object is introduced. The operation creates such an object using the fields from the operation.
A new, empty authority is created. The desired number of members for the authority is set to max(num_members,min_members).
Half of the operation fee is set aside and stored in the elected_authority_object.
Fields:
account_id_type owner- the account to pay the fee, must have created the authorityelected_authority_id_type authority- the authority to delete
Validation:
The operation must not be used before the time of the hardfork.
authoritymust exist.owner == authority.creator
Evaluation:
- The fee stored in
authorityis returned toowner. - The
elected_authority_objectis deleted. - All related objects, including the
authorityas well as all user votes, are also deleted.
Note: Afterwards, accounts that have the authority still referenced in its owner authority will be unable to ever change their owner again. Accounts that have the authority referenced in their active authority will be usable only by their owner authority until the active authority has been changed.
Fields:
account_id_type voter- the voting account, also pays feeelected_authority_id_type authority- the authority on which to voteunsigned_int number- the number of members the authority should have, or 0 if it is fixedflat_set<account_id_type> votes_to_add- a list of accounts to add to the current voting slateflat_set<account_id_type> votes_to_remove- a list of accounts to remove from the current voting slateoptional<account_id_type> proxy- an optional voting proxy
Validation:
The operation must not be used before the time of the hardfork.
authoritymust exist.votermust exist and have sufficient balance to pay the fee.- If
authority.vote_untilis present, then it must be in the future. - If
authority.num_members > 0thennumbermust equal 0. - If
authority.num_members == 0thenauthority.min_members <= number <= authority.max_members. - For all entries in
votes_to_add:- must exist
- must not be present in the user's voting slate on
authority - if
authority.candidatesis not empty then it must be contained therein - if
authority.candidates_hold_minis present then it must own at least the given amount of tokens of the given type
- For all entries in
votes_to_remove:- must be present in the user's voting slate on
authority
- must be present in the user's voting slate on
- If both
votes_to_addandvotes_to_removeare empty thennumbermust be different than thevoter's previous choice fornumber, or thevoter's proxy setting must change. - If
proxyis present thenauthority.proxy_allowedmust betrue.proxyaccount must exist and must have a voting slate for theauthority.numbermust equal 0 and bothvotes_to_addandvotes_to_removemust be empty.
Evaluation:
- If
proxyis not present butvoterhad set a proxy on thisauthoritybefore- Subtract the
voter's token balance from the old proxy's proxy token count and adjust vote tally accordingly. - Apply
votes_to_addas described below.
- Subtract the
- If
proxyis present andvoterhad not set a proxy before- Remove all accounts from the user's own voting slate and adjust vote tally accordingly.
- Set proxy in voting slate.
- Add
voter's balance toproxy's proxy token count and adjust vote tally accordingly.
- If
proxyis present andvoterhad set a (different) proxy before- Remove old proxy and adjust vote tally accordingly (see above).
- Set new proxy and adjust vote tally accordingly (see above).
- If
proxyis not setvotes_to_add,votes_to_removeandnumberare applied to the user's voting slate.- Let
voting_balancebe the sum of thevoter's token balance of the asset plus his proxy token balance. - The voting delta is the
voting_balancefor each vote to be added and for the newnumber, the negativevoting_balancefor each vote to be removed and the previousnumber. - The voting delta in votes is applied to the vote tally of
authority. - If
retally_intervalis absent, the resulting differences in the election outcome (if any) are reflected in the respectiveauthorityobject.
Note: the intent is to have vote tallying work in the same way it is currently performed when voting with BTS. The same goes for determining the number of accounts that make up the authority, unless it is fixed.
The chain logic for adjusting account balances is modified as follows:
- For each voting slate of the balance's owner with the same asset type as is being updated:
- If the voting slate points to a proxy, adjust the proxy's proxy token count according to the balance delta.
- Apply the balance delta to the vote tally according to the user's (or proxy's if set) voting slate.
- Reflect the resulting differences to the election outcome in the respective
authorityobject.
After the time of the hardfork, a new type of special_authority is allowed. This new type wraps an elected_authority_object.
If the wrapped elected_authority has been deleted, the special_authority will block, i. e. it cannot authorize anything anymore.
Note: for simplicity, it is left to the implementers to decide if account_create_operation is modified accordingly.
Code is added to database::apply_block to check if any retally_intervals have passed. For each such elected_authority_object,
- the current vote tally result is applied to the authority
- the point in time of the next retally is calculated as the next multiple of the
retally_interval(the intent is to have the retally happen at predictable "natural" times, e. g. at the full hour, just like the maintenance interval)
Deleting an authority that is still being used, e. g. as the active authority of an account, can cause problems.
The problem is, if we disallow deletion if the authority is in use anywhere, then it is easy for someone to block an authority from being deleted.
OTOH someone who uses an elected authority that is not under his control can be expected to coordinate this with the authority owner. Setting an elected authority as owner on an account is strongly discouraged, because authority deletion would block the account. Use as an active authority (or feed producer) can easily be repaired by the account owner (or asset owner).
As explained in the "Rationale" section we have made certain assumptions about the voting tokens that allow many simplifications when compared to the current BTS-based voting system.
Not all of these assumptions may prove to be true in all cases.
- This BSIP has an impact on the performance of balance-changing operations. It is believed that the overall impact will be low, because only few assets will be affected.
- Deleting an authority that is still being used, e. g. as the active authority of an account, can cause problems.
This BSIP introduces new operations to allow voting and elections using other assets than BTS. Authorities based on election outcomes can be assigned to accounts. Proxy voting is not possible in these elections.
This document is placed in the public domain.