Principles and Steps

In election, a certain number of candidates (referred as seats) are elected to be proposer according to their RPT value. We have the following principles to design the election:

  1. An RNode with higher RPT has higher chance to be elected;
  2. Each term of proposers has a certain number of representatives from RNodes with low RPT.

Thus, the basic steps of election process are:

  1. Candidates are divided into two partitions, high-RPT RNodes and low-RPT RNodes;
  2. Either partition has a number of available seats;
  3. The probability mass for each node being elected is proportional to its RPT in its corresponding partition;
  4. Random select nodes in two partitions, which together constitute proposers committee.

Pseudocode of Election

Let \(TotalRnode\) be the number of all RNode candidates, \(TotalSeats\) be the number of seats for each term, \(LowRptPercentage\) be the percentage of low-RPT RNdoes in all RNode candidates, and \(LowRptSeats\) be available seats for low-RPT RNodes. The equation \(0\leq LowRptPercentage\leq 1\) and \(0\leq LowRptSeats\leq LowRptPercentage \times TotalSeats \leq TotalSeats\) always hold.

In current implementation, \(LowRptPercentage\) is \(50\%\), and \(LowRptSeats\) occupies one fourth of \(TotalSeats\).

// rptList is the list of all candidates as well as their RPT value
// seed is the seed for generating random numbers
// tha value of seed is the hash value of the parent block
func elect(rptList, seed, TotalRnode, TotalSeats, LowRptPercentage, LowRptSeats) []address {
    // sort rptList

    var partition uint64
    partition = LowRptPercentage * TotalRnode
    // partition rptList into lowRpts and highRpts
    lowRpts := rptList[:partition]
    highRpts := rptList[partition:]

    // generate a series of random numbers given the seed
    randSource := rand.NewSource(seed)
    myRand := rand.rand.New(randSource)

    lowElected := randomSelectByRpt(lowRpts, myRand, partition, LowRptSeats)
    highElected := randomSelectByRpt(highRpts, myRand, TotalRnode - partition, TotalSeats - LowRptSeats)
    return append(lowElected, highElected)

// uniform random selection from rptPartition
// the mass probability for each node being elected is proportional to its RPT
// the function select l random addresses
// and return them as result
func randomSelectByRpt(rptPartition, myRand, k, l) []address {
    if (k < l) {
        return all k addresses
    // each element in rptPartition is referred as rpt
    // then we sum all rpt values, as sumRpt
    // using myRand to random select l addresses according to its rpt/sumRpt
    // return these l addresses

The Structure of Term

Each term consists of 12 proposers and 36 blocks sealed by these proposers. The order of proposals is scheduled in the form of Round Robin, which is shown in the following figure. Each term consists of three identical views, in which 12 proposers seal blocks one by one.