Specification

Authors: BlockScience and SDF, July 2023

Intro

A notebook containing an example implementation for this document can be found on the BlockScience/scf-voting-mechanism GitHub repository.

General Definitions

The admissible user actions for the SDF-Voting Mechansim in each round (mutually exclusive):

  • Vote (yes/no) / Refrain from Voting (abstain) on any number of project submissions

    • A "no" vote will cancel a "yes" vote with the same voting power. In other words, if someone has a Voting Power of 5, then Yes would add +5 to the Project Votes, No would add -5 and Abstain would add 0.

  • Delegate full Voting Power to an ordered list of at least 5 other users - called a Quorum. Quorums are only valid for the current round and should be re-initialized / re-activated for each new round.

    • The Actual Quorum will consist of the first 5 users that opted for Voting rather than Delegating. If there are less than 5 users voting any missing slot will be replaced by Abstain votes.

    • Quorum Members do not know of each other, or that they have been "delegated" to.

Voting is going to take place based on Discrete Rounds, and tallying only occurs by the end of the round.

The SDF-VM PoC can be described in terms of Inputs and Outputs as:

  • Input:

    • Structural (once per round): set of Users and set of Projects

      • Assumption: the set of Users and set of Projects are validated before (i.e. "whitelisted" by SDF).

    • Active (user discretionary): set of User Actions

  • Output: a map from Projects to Project Voting Power.

    • Project Voting Power = Real Number

The generic structures that make up the Voting Mechanism are:

  • User: a UUID

  • Project: a UUID

  • Project Votes: a map from project-UUID to a Real Number.

  • User Action: Either User Quorum or (exclusive) User Vote.

    • A User Quorum: a map from a single user-UUID (key) to multiple user-UUIDs (value)

      • Constraint: The map value should contain five distinct user-UUIDs. Cannot include the own user-UUID.

    • A User Round Vote: a map from a single user-UUID to a set of User Project Votes. Project UUIDs on the set of User Project Votes must be distinct.

    • A User Project Vote is a 2-tuple consisting of project-UUID and Vote Decision

      • Vote Decision: Yes, No and Abstain

Lastly, the procedure on which User Actions are converted into Project Votes is as follows:

  1. The Voting Power associated with each User Project Vote object is computed.

    • If Voting Power is agnostic to the project voted on, then this is equivalent to computing the Voting Power for each User.

    • Note that Quorum Votes arise from the Quorum Voting Module

  2. All User Project Votes are summed per project and assigned to the Project Votes map.

Vote tallying example

ℹ️ Note: this pseudo-code is decoupled from the Vote Neurons that were defined for the PoC. Different ones are used here for pedagogical purposes.

⚠️ Warning: This code is not assured to be valid, and the output is potentially incorrect. This is not a substitute for unit tests.

Below we have a demo work-flow for the PoC Voting Mechanism. A key simplification is the usage of a single-layer layer for Neural Governance rather than multiple layers.

Given a set of users, projects and user actions, the end output is a map from projects to votes. This is computed by aggregating (by taking the product) over the outputs originating from the Neural Governance Neurons, which in turn can be either simple functions (like the one user, one vote neuron), or complex functions implemented elsewhere (like the Quorum Delegation Neuron, or the Reputation Score Neuron).

print(project_vote_power)
> {'voting-mech-for-scf': 6.5, 'quorum-voting': 4.3}

Logic

Neural Governance is a label for a general architecture that attributes Voting Power by using parallellely and sequentially linked Neurons, where the input is derived from Oracle Functions, which is then weighted and the subsequent output aggregated across layers through custom rules (eg. take the product or sum between all Neurons in a given layer).

Key primitives associated with Neural Governance are the Oracle Function (a raw input provider), a Weighting Function (which transforms the raw input into a comparable measurement for voting power), and a Layer Aggregator (which combines all the Vote Neuron outputs into a single number). A Neuron is a pair consisting of a single Oracle Function and a single Weighting Function. A Layer is a list of Neurons and a single Layer Aggregator.

An Oracle Function must take 2 or 3 arguments as an input: Voter ID (string), Project ID (string) and Previous Layer Vote (float, optional). The output is the Raw Neuron Vote (float).

The Weighting Function takes a single argument as an input - Raw Neuron Votes (float) and their output is a single number - the Neuron Vote (float).

A Layer Aggregator function takes an ordered list of numbers (Neuron Votes, list[float]) and its output should be a single number - the Layer Vote (float).

The Final Voting Power that is directed from a Voter ID towards a Project ID is determined by feedforwarding the sequential network made by the pre-defined Layers.

Example Implementation in Python

Resources

Last updated