-
Notifications
You must be signed in to change notification settings - Fork 87
BSIP-84: Token-based voting #242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
e874bd0
Initial version
pmconrad 84d7df2
Typo
pmconrad f3f2274
Add discussion + risk + clarification about deletion
pmconrad 9f2cbd5
Added rationale about fee lockup
pmconrad 9e98081
Added notes about account_create + assumptions
pmconrad ec3111a
Renamed operations
pmconrad c4fe634
Renamed candidate_holders and added minimum amount
pmconrad 390949b
Allow MPAs and PMs
pmconrad 2a10396
Add threshold percentage
pmconrad File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,215 @@ | ||
| 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 | ||
|
|
||
| # Abstract | ||
|
|
||
| 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. | ||
|
|
||
|
|
||
| # Motivation | ||
|
|
||
| The feature has been requested from independent businesses as well as from within the community. In addition, it paves the way for a to-be-proposed change to BitAsset governance, i. e. the decoupling of BitAsset management from blockchain governance. | ||
|
|
||
|
|
||
| # Rationale | ||
|
|
||
| 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). | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the other hand, the simplification that only counts liquid balances does limit the potential of the feature. There could be use cases that require tokens in other forms to be counted in voting as well. I do agree to implement the simplified version first though. |
||
|
|
||
| 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. | ||
|
|
||
|
|
||
| # Specifications | ||
|
|
||
| ## 1. New asset flag "voting_allowed" | ||
|
|
||
| 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. | ||
|
|
||
|
|
||
| ## 2. New operation "elected_authority_create" | ||
|
|
||
| **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. | ||
abitmore marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| **Fields:** | ||
|
|
||
| * `account_id_type creator` - the account to pay the fee, also the only one who can delete the authority | ||
| * `asset_id_type voting_asset` - the asset on which to base the voting | ||
| * `unsigned_int num_members` - the number of authority members to vote on if fixed, or 0 otherwise | ||
| * `unsigned_int min_members` - the minimum number of authority members to elect, or 0 if fixed | ||
| * `unsigned_int max_members` - the maximum number of authority members that can be elected, or 0 if fixed | ||
| * `uint16_t threshold` - the threshold scaled percentage of weighter member approvals required for authority approval | ||
| * `flat_set<account_id_type> candidates` - a list of candidates eligible for voting, or empty | ||
| * `optional<asset> candidates_hold_min` - an asset and minimum amount of it that candidates must hold to be eligible for voting | ||
| * `bool proxy_allowed` - indicates if proxy voting is allowed | ||
| * `optional<time_point_sec> vote_until` - an optional ending date after which voting slates are frozen | ||
|
|
||
| **Validation:** | ||
|
|
||
| The operation must not be used before the time of the hardfork. | ||
|
|
||
| * `creator` must exist, must have lifetime membership, and must have sufficient balance to pay the fee. | ||
| * `voting_asset` must exist and must have the `voting_allowed` flag set. | ||
| * `threshold` must be in the range `1..GRAPHENE_100_PERCENT` | ||
| * If `num_members` is 0 then `min_members` and `max_members` must both be positive. | ||
| * If `num_members` is positive then both `min_members` and `max_members` must equal 0. | ||
| * If `candidates` is not empty then | ||
| * Its size must be greater or equal to `max(num_members,min_members)`. | ||
| * `candidates_hold_min` must not be present. | ||
| * If `candidates_hold_min` is present the `candidates` must be empty. | ||
| * `vote_until`, if present, must be in the future | ||
|
|
||
| **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`. | ||
abitmore marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| ## 3. New operation "elected_authority_delete" | ||
|
|
||
| **Fields:** | ||
|
|
||
| * `account_id_type owner` - the account to pay the fee, must have created the authority | ||
| * `elected_authority_id_type authority` - the authority to delete | ||
|
|
||
| **Validation:** | ||
|
|
||
| The operation must not be used before the time of the hardfork. | ||
|
|
||
| * `authority` must exist. | ||
| * `owner == authority.creator` | ||
|
|
||
| **Evaluation:** | ||
|
|
||
| * The fee stored in `authority` is returned to `owner`. | ||
| * The `elected_authority_object` is deleted. | ||
| * All related objects, including the `authority` as well as all user votes, are also deleted. | ||
abitmore marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| **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. | ||
|
|
||
|
|
||
| ## 4. New operation "elected_authority_vote" | ||
|
|
||
| **Fields:** | ||
|
|
||
| * `account_id_type voter` - the voting account, also pays fee | ||
| * `elected_authority_id_type authority` - the authority on which to vote | ||
| * `unsigned_int number` - the number of members the authority should have, or 0 if it is fixed | ||
| * `flat_set<account_id_type> votes_to_add` - a list of accounts to add to the current voting slate | ||
| * `flat_set<account_id_type> votes_to_remove` - a list of accounts to remove from the current voting slate | ||
| * `optional<account_id_type> proxy` - an optional voting proxy | ||
|
|
||
| **Validation:** | ||
|
|
||
| The operation must not be used before the time of the hardfork. | ||
|
|
||
| * `authority` must exist. | ||
| * `voter` must exist and have sufficient balance to pay the fee. | ||
| * If `authority.vote_until` is present, then it must be in the future. | ||
| * If `authority.num_members > 0` then `number` must equal 0. | ||
| * If `authority.num_members == 0` then `authority.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.candidates` is not empty then it must be contained therein | ||
| * if `authority.candidates_hold_min` is 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` | ||
| * If both `votes_to_add` and `votes_to_remove` are empty then `number` must be different than the `voter`'s previous choice for `number`, or the `voter`'s proxy setting must change. | ||
| * If `proxy` is present then | ||
| * `authority.proxy_allowed` must be `true`. | ||
| * `proxy` account must exist and must have a voting slate for the `authority`. | ||
| * `number` must equal 0 and both `votes_to_add` and `votes_to_remove` must be empty. | ||
|
|
||
| **Evaluation:** | ||
|
|
||
| * If `proxy` is not present but `voter` had set a proxy on this `authority` before | ||
| * Subtract the `voter`'s token balance from the old proxy's proxy token count and adjust vote tally accordingly. | ||
| * Apply `votes_to_add` as described below. | ||
| * If `proxy` is present and `voter` had 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 to `proxy`'s proxy token count and adjust vote tally accordingly. | ||
| * If `proxy` is present and `voter` had 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 `proxy` is not set | ||
| * `votes_to_add`, `votes_to_remove` and `number` are applied to the user's voting slate. | ||
| * Let `voting_balance` be the sum of the `voter`'s token balance of the asset plus his proxy token balance. | ||
| * The voting delta is the `voting_balance` for each vote to be added and for the new `number`, the negative `voting_balance` for each vote to be removed and the previous `number`. | ||
| * The voting delta in votes is applied to the vote tally of `authority`. | ||
| * The resulting differences in the election outcome (if any) are reflected in the respective `authority` object. | ||
|
|
||
| **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. | ||
|
|
||
|
|
||
| ## 5. `adjust_balance` | ||
abitmore marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| 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 `authority` object. | ||
|
|
||
|
|
||
| ## 6. `account_update_operation` | ||
abitmore marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| 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. | ||
|
|
||
| # Discussion | ||
|
|
||
| ## Deletion | ||
|
|
||
| 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). | ||
|
|
||
| ## "Locked" balances | ||
|
|
||
| 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. | ||
|
|
||
| # Risks | ||
|
|
||
| * 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. | ||
|
|
||
| # Summary for Shareholders | ||
|
|
||
| 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. | ||
|
|
||
| # Copyright | ||
|
|
||
| This document is placed in the public domain. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I won't assume this, but the opposite.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, interesting. Anything specific you have in mind?
IMO in order to be used as collateral, a token would need to have some intrinsic value, which I don't see in a voting token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A voting token would not have value if it tracks the voting weight of another token well (which is hard), in that case it is a simple utility token carries one role for another token. When we have this BSIP (token-based voting), I'd expect that people would directly vote with the tokens they already have but not create new tokens only for voting, because it would be economically much cheaper.
This is also the reason that I don't agree with the MANAGER token idea proposed in BSIP83, because the new token can't track the distribution of BTS well in the long run. That idea means to privatize committee-owned smartcoins, which is something similar to STEALTH, and would divide the community.
On the other hand, there would also be use cases that a voting token is needed, e.g. if the voting weights are time-based or derived from another token.