Skip to content

Commit

Permalink
Merge pull request #242 from bitshares/token_based_voting
Browse files Browse the repository at this point in the history
BSIP-84: Token-based voting
  • Loading branch information
pmconrad authored Oct 25, 2019
2 parents 967bcda + 2a10396 commit bcc4628
Showing 1 changed file with 215 additions and 0 deletions.
215 changes: 215 additions & 0 deletions bsip-0084.md
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).

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.

**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`.


## 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.

**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`

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`

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.

0 comments on commit bcc4628

Please sign in to comment.