create account

Introduction to 'Voting Process' for Programmers by eosiosg

View this thread on: hive.blogpeakd.comecency.com
· @eosiosg · (edited)
$4.92
Introduction to 'Voting Process' for Programmers
System Contract Part #2 - Voting Process 
--

In eos network, [**eosio.system**](https://github.com/EOSIO/eos/tree/slim/contracts/eosio.system) contract enable users to 1) stake tokens, and then vote on producers (or worker proposals), 2) proxy their voting influence to other users, 3) register producers, 4) claim producer rewards, 5) delegate resources (net, cpu & ram) and push other necessary actions to keep blockchain system running.

In this series, we will go through What is the contract, What are included in the contract and How the contract can be used.

Our last post discussed the  [**'Block Producer Rewards'**](https://steemit.com/blockchain/@eosiosg/system-contract-part-1-block-producer-rewards), in this article we will talk about voting process.

In this article, we will be discussing detailed flows/steps on **Producer Registration**, **Token Staking**, **Voting on BP** , and **Changing/Withdrawing Vote** successively. 

*All codes present are based on commit of [44e7d3e](https://github.com/EOSIO/eos/commit/44e7d3ef2503d7bc45afc18f04f0289ed26cfdd7)*

TL;DR:
--
* **Token holders have to stake with their tokens on net and cpu for voting**
* **On voting, all staked assets will convert to `x` amount of weighted votes, which can be used to vote up to 30 producers and each selected producer will get `x` amount of votes repectively**
* **Refunding process takes up to 3 days to reflect the unstaked tokens in available token balance**
* **Newer votes possess higher voting weights**

![voting.png](https://steemitimages.com/DQmSUwAR8m8Bcqsqox7n2z5cd8iyY3Z1rDDLNeBgqiH7RLo/voting.png)

Producer Registration
--
**Accounts should register themselves as producer first before they can be voted.  This process is done by pushing a `system_contract::regproducer` action.**


* The core logic code below is to insert or replace producers' configurations (i.e. public key & parameters) into `producerinfo` table.

```cpp
void system_contract::regproducer( const account_name producer, 
                    const eosio::public_key& producer_key, const std::string& url ) { 
                    //, const eosio_parameters& prefs ) {
    ...

    if ( prod != _producers.end() ) {
        if( producer_key != prod->producer_key ) {
             _producers.modify( prod, producer, [&]( producer_info& info ){
                info.producer_key = producer_key;
            });
        }
    } else {
        _producers.emplace( producer, [&]( producer_info& info ){
            info.owner       = producer;
            info.total_votes = 0;
            info.producer_key =  producer_key;
        });
    }
}
```
**This part of code is under rapid development, we will keep updating it if significant changes are found.* 



    
Token Staking
--
**Token holders can only vote after they have staked their tokens on net and cpu. Staking process is done by pushing a `system_contract::delegatebw` action. Inside `delegatebw` action, voter's tokens are staked and cannot be transferred until refunded.**

1. If a user has not staked before, insert a record for this account in the table `deltable`. If a user has staked, add newly amount to the existing amount.
2. Set resource limits for stake receiver. Transfer corresponding amount as stake to a public account `eosio`.

   ```cpp
    void system_contract::delegatebw( account_name from, account_name receiver,
                                     asset stake_net_quantity, 
                                     asset stake_cpu_quantity )                  
           {
              require_auth( from );
              ...

              set_resource_limits( tot_itr->owner, tot_itr->ram_bytes, 
                                tot_itr->net_weight.amount, tot_itr->cpu_weight.amount );

              if( N(eosio) != from) {
                 INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {from,N(active)}, 
                { 
                    from, N(eosio), asset(total_stake), std::string("stake bandwidth") 
                } );
          }  
    ```
   <br/>
3. Update voter's staked amount.
    * Find the voter from `voters` table, if not exist, insert a new record of this voter.
    * Add newly delegated stake into the voter's `staked` attribute.
    * Call `voteproducer` action to update vote results. This means if the push sender has voted before, on new `delegatebw` action, votes will be updated for last voting producers (or lasting voting proxy).
    ```cpp
    ...
          print( "voters \n" );
          auto from_voter = _voters.find(from);
          if( from_voter == _voters.end() ) {
            print( " create voter \n" );
             from_voter = _voters.emplace( from, [&]( auto& v ) {
                v.owner  = from;
                v.staked = uint64_t(total_stake);
            print( "    vote weight: ", v.last_vote_weight, "\n" );
            });
          } else {
            _voters.modify( from_voter, 0, [&]( auto& v ) {
                v.staked += uint64_t(total_stake);
                print( "    vote weight: ", v.last_vote_weight, "\n" );
             });
          }

          print( "voteproducer\n" );
          if( from_voter->producers.size() || from_voter->proxy ) {
            voteproducer( from, from_voter->proxy, from_voter->producers );
          }
       } // delegatebw
    ```

****Note that user can also delegate net & cpu to other accounts, making resource transfer to be possible. We will talk about user resources in depth in the upcoming blog.***



Vote On Producer / Proxy
--
**Stake holders (token holders who have their tokens staked) can vote for producers (or proxy, who will vote on behalf of push sender), all stakes will convert to weighted x votes and then add up to 30 producers by x votes.**

#### Vote producer
**Leaving `proxy` arguments to be empty*

1. Validation: 
    * Producers to be vote must be given in order;
    * Producers to be vote must be registered;
    * Producers to be vote must be active. 

2. Calculate current vote weight based on the following formula:
      
      ![equation](https://latex.codecogs.com/png.latex?%5CLARGE%20%24%24votes%20%3D%20stakes%5Ctimes%7B2%5E%7B%7Bcurrent%5C_timestamp%5C_in%5C_second%5Cover%20604800%20%28seconds%5C_per%5C_week%29%5Ctimes%2052%20%7D%7D%20%5Csimeq%20ax%5Ctimes%20stakes%7D%24%24) 
      
**The weight increasing could be treated as a linear growing with time within a short period.*

If the voter is a proxy, `proxied_vote_weight` of the voter will also be updated. 

3. Reduce `last_vote_weight` (if ever), and then add current vote weight. 
    * Create a relation between voting producer and vote weight.
    * Deduct last voting weight from voting producers.
    * Add each voting producer's vote weight by the new weight.

    ```cpp
    void system_contract::voteproducer( const account_name voter_name, 
                    const account_name proxy, const std::vector<account_name>& producers ) {
        require_auth( voter_name );

        ...

        boost::container::flat_map<account_name, double> producer_deltas;
        for( const auto& p : voter->producers ) {
            producer_deltas[p] -= voter->last_vote_weight;
        }

        if( new_vote_weight >= 0 ) {
            for( const auto& p : producers ) {
                producer_deltas[p] += new_vote_weight;
            }
        }
        ...
    }    
    ```
    <br/>
4. Record voting results.
    * Modify `voters` table, update vote weight & voting producers (or proxy) respectively.
    * Modify `producerinfo` table, update producer's votes.

    ```cpp
        ...
        _voters.modify( voter, 0, [&]( auto& av ) {
            print( "new_vote_weight: ", new_vote_weight, "\n" );
            av.last_vote_weight = new_vote_weight;
            av.producers = producers;
            av.proxy     = proxy;
            print( "    vote weight: ", av.last_vote_weight, "\n" );
          });

        for( const auto& pd : producer_deltas ) {
            auto pitr = _producers.find( pd.first );
            if( pitr != _producers.end() ) {
                _producers.modify( pitr, 0, [&]( auto& p ) {
                p.total_votes += pd.second;
                eosio_assert( p.total_votes >= 0, "something bad happened" );
                eosio_assert( p.active(), "producer is not active" );
                });
            }
        }
    }
    ```

#### Vote proxy
**Leaving `producers` arguments to be empty*

>An account marked as a proxy can vote with the weight of other accounts which have selected it as a proxy. Other accounts must refresh their voteproducer to update the proxy's weight.

1. Validation: 
    * Proxy to be vote must have registered to be a proxy by pushing action `system_contract::regproxy`.
    * Proxy and producers cannot be voted at the same time.
2. Calculate current vote weight, same as above.
3. Update proxy's vote weight
    * Deduct last voting weight from the voting proxy.
    * Add each voting proxy's vote weight by the new amount.
    ```cpp
        ...
        if( voter->proxy != account_name() ) {
            auto old_proxy = _voters.find( voter->proxy );
            _voters.modify( old_proxy, 0, [&]( auto& vp ) {
                vp.proxied_vote_weight -= voter->last_vote_weight;
                print( "    vote weight: ", vp.last_vote_weight, "\n" );
            });
          }

          if( proxy != account_name() && new_vote_weight > 0 ) {
            auto new_proxy = _voters.find( voter->proxy );
             eosio_assert( new_proxy != _voters.end() && new_proxy->is_proxy, "invalid proxy specified" );
             _voters.modify( new_proxy, 0, [&]( auto& vp ) {
                vp.proxied_vote_weight += new_vote_weight;
                print( "    vote weight: ", vp.last_vote_weight, "\n" );
             });
          }
     ```



Changing/Withdrawing Vote
--

![undelegating.png](https://steemitimages.com/DQmdHpd6UohD1CtiQR5iLudxjmBVcBZdDRp6UYx9k9m5r54/undelegating.png)

#### Votes Change

Voters are able to change voted producers (or proxy) by **pushing `voteproducer` actions again**, details have been discussed in the previous section. 

#### Votes Withdraw (Unstake)

**Voters can withdraw their votes by pushing by pushing `system_contract::undelegatebw` actions with any amount that is no bigger than the net & cpu been staked & delegated. Undelegated stakes will be available for `system_contract::refund` after 3 days.**

1. Decrease refunding amount from voter's `staked` column of `voter` table.
2. Update `totals_tbl` table and update resource limits for the account.
3. Create refund request.
    * Update `refunds` table with unstaked amount
    * If user undelegate many times within a short period of time, the last undelegating time will be recorded (this time will be used for calculating the available refunding time).
    ```cpp
       void system_contract::undelegatebw( account_name from, account_name receiver,
                                       asset unstake_net_quantity, asset unstake_cpu_quantity )
   {
        ...
        auto req = refunds_tbl.find( from );
          if ( req != refunds_tbl.end() ) {
            refunds_tbl.modify( req, 0, [&]( refund_request& r ) {
                r.amount += unstake_net_quantity + unstake_cpu_quantity;
                r.request_time = now();
            });
          } else {
            refunds_tbl.emplace( from, [&]( refund_request& r ) {
                r.owner = from;
                   r.amount = unstake_net_quantity + unstake_cpu_quantity;
                   r.request_time = now();
               });
         }
        ...
    ```
4. Create (or replace) a deferred `system_contract::refund` transaction & update voting results. 
    * Push a deferred transaction.
    * `refund_delay = 3*24*3600`, i.e. 3 days.
    * Call `voteproducer` to deduct corresponding votes from voted producers.
    ```cpp
        ...
        eosio::transaction out;
          out.actions.emplace_back( permission_level{ from, N(active) }, _self, N(refund), from );
          out.delay_sec = refund_delay;
          out.send( from, receiver );

          const auto& fromv = _voters.get( from );

          if( fromv.producers.size() || fromv.proxy ) {
            voteproducer( from, fromv.proxy, fromv.producers );
          }
       } // undelegatebw
    ```

Conclusion
--
1. Token owner can only vote after they **staked** their tokens on net & cpu.
2. During voting action, all stakes of the voter will convert into x weighted votes, and every voted producer (up to 30) is going to get **equivalent x weighted votes**.
3. **Newer votes count more than older votes**, the weight grows approximately linearly.
4. Users can undelegate their stakes and have to wait up to **3 days** before they can re-allocate this amount of tokens.

*In the next article, we are going to talk about some detailed implementation about **user resources**, including delegate cpu & net, buy & sell ram, new account, producer voting and proxy related stuff.*

**Stay tuned with [eosio.sg](http://eosio.sg/): [Telegram](https://t.me/eosiosg), [Medium](https://medium.com/@eosiosg).**
👍  , , , , , , , , , , , , , ,
properties (23)
authoreosiosg
permlinkintroduction-to-voting-process-for-programmers
categoryblockchain
json_metadata{"tags":["blockchain","eos","voting","eosio","vote"],"image":["https://steemitimages.com/DQmSUwAR8m8Bcqsqox7n2z5cd8iyY3Z1rDDLNeBgqiH7RLo/voting.png","https://latex.codecogs.com/png.latex?%5CLARGE%20%24%24votes%20%3D%20stakes%5Ctimes%7B2%5E%7B%7Bcurrent%5C_timestamp%5C_in%5C_second%5Cover%20604800%20%28seconds%5C_per%5C_week%29%5Ctimes%2052%20%7D%7D%20%5Csimeq%20ax%5Ctimes%20stakes%7D%24%24","https://steemitimages.com/DQmdHpd6UohD1CtiQR5iLudxjmBVcBZdDRp6UYx9k9m5r54/undelegating.png"],"links":["https://github.com/EOSIO/eos/tree/slim/contracts/eosio.system","https://steemit.com/blockchain/@eosiosg/system-contract-part-1-block-producer-rewards","https://github.com/EOSIO/eos/commit/44e7d3ef2503d7bc45afc18f04f0289ed26cfdd7","http://eosio.sg/","https://t.me/eosiosg","https://medium.com/@eosiosg"],"app":"steemit/0.1","format":"markdown"}
created2018-05-08 13:29:00
last_update2018-05-08 15:17:33
depth0
children7
last_payout2018-05-15 13:29:00
cashout_time1969-12-31 23:59:59
total_payout_value3.736 HBD
curator_payout_value1.184 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length13,115
author_reputation101,225,031,689
root_title"Introduction to 'Voting Process' for Programmers"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id54,569,055
net_rshares1,016,437,874,317
author_curate_reward""
vote details (15)
@csx-eos · (edited)
Thank you for this information.
👍  
properties (23)
authorcsx-eos
permlinkre-eosiosg-introduction-to-voting-process-for-programmers-20180510t165636526z
categoryblockchain
json_metadata{"tags":["blockchain"],"app":"steemit/0.1"}
created2018-05-10 16:56:39
last_update2018-05-10 16:57:00
depth1
children0
last_payout2018-05-17 16:56:39
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length31
author_reputation539,320,185,055
root_title"Introduction to 'Voting Process' for Programmers"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id54,989,404
net_rshares244,320,282
author_curate_reward""
vote details (1)
@dan ·
$0.17
Great article except we’ve updated behavior in slim branch.
👍  ,
properties (23)
authordan
permlinkre-eosiosg-introduction-to-voting-process-for-programmers-20180508t162210765z
categoryblockchain
json_metadata{"tags":["blockchain"],"app":"steemit/0.1"}
created2018-05-08 16:22:12
last_update2018-05-08 16:22:12
depth1
children3
last_payout2018-05-15 16:22:12
cashout_time1969-12-31 23:59:59
total_payout_value0.132 HBD
curator_payout_value0.039 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length59
author_reputation155,470,101,136,708
root_title"Introduction to 'Voting Process' for Programmers"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id54,597,027
net_rshares35,526,167,661
author_curate_reward""
vote details (2)
@eosiosg ·
Thanks a lot Dan! We will update that shortly.
👍  
properties (23)
authoreosiosg
permlinkre-dan-re-eosiosg-introduction-to-voting-process-for-programmers-20180509t125947696z
categoryblockchain
json_metadata{"tags":["blockchain"],"app":"steemit/0.1"}
created2018-05-09 12:59:51
last_update2018-05-09 12:59:51
depth2
children0
last_payout2018-05-16 12:59:51
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length46
author_reputation101,225,031,689
root_title"Introduction to 'Voting Process' for Programmers"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id54,749,220
net_rshares594,809,830
author_curate_reward""
vote details (1)
@shuke0327 ·
I think eosio.sg will update this article soon.
properties (22)
authorshuke0327
permlinkre-dan-re-eosiosg-introduction-to-voting-process-for-programmers-20180509t023126665z
categoryblockchain
json_metadata{"tags":["blockchain"],"app":"steemit/0.1"}
created2018-05-09 02:31:27
last_update2018-05-09 02:31:27
depth2
children0
last_payout2018-05-16 02:31:27
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length47
author_reputation48,788,608,014
root_title"Introduction to 'Voting Process' for Programmers"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id54,671,460
net_rshares0
@stuardo ·
I understand there is no time constrain for a holder to vote. A voter can re-vote every second. This could affect the BP elected. Also, if newer votes weigh more, and I can re-vote every second, I can make my votes to be always the latest ones, giving more weight to them.

Am I understanding it right?

I'll wait for the latest branch to be released to see the new logic fixes this kind of issues.
properties (22)
authorstuardo
permlinkre-dan-re-eosiosg-introduction-to-voting-process-for-programmers-20180517t132338073z
categoryblockchain
json_metadata{"tags":["blockchain"],"app":"steemit/0.1"}
created2018-05-17 13:23:39
last_update2018-05-17 13:23:39
depth2
children0
last_payout2018-05-24 13:23:39
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length398
author_reputation89,120,750,363
root_title"Introduction to 'Voting Process' for Programmers"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id56,184,278
net_rshares0
@shuke0327 ·
great post. I really appreciate your job for introducing the details .
I am Kevin JIng, an Chinease Developer and also volunteer in EOS Go forums as the mod of Chinese sub-forum, 
And I wonder if I will be allowed to translate your articles to Chinese and post it to EOS Go Chinese sub-forum, and also an  steemit like website: bihu? I will add the authors and introduction to your link here.  Thanks .
properties (22)
authorshuke0327
permlinkre-eosiosg-introduction-to-voting-process-for-programmers-20180509t023435637z
categoryblockchain
json_metadata{"tags":["blockchain"],"app":"steemit/0.1"}
created2018-05-09 02:34:36
last_update2018-05-09 02:34:36
depth1
children1
last_payout2018-05-16 02:34:36
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length402
author_reputation48,788,608,014
root_title"Introduction to 'Voting Process' for Programmers"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id54,671,837
net_rshares0
@eosiosg ·
Hi Shuke, many thanks for your comments. In fact we are in the process of translating our post into Chinese version and you will see them shortly :)
👍  
properties (23)
authoreosiosg
permlinkre-shuke0327-re-eosiosg-introduction-to-voting-process-for-programmers-20180509t130446345z
categoryblockchain
json_metadata{"tags":["blockchain"],"app":"steemit/0.1"}
created2018-05-09 13:04:48
last_update2018-05-09 13:04:48
depth2
children0
last_payout2018-05-16 13:04:48
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length148
author_reputation101,225,031,689
root_title"Introduction to 'Voting Process' for Programmers"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id54,750,054
net_rshares582,913,634
author_curate_reward""
vote details (1)