Implementation of EPoS (#1826)
* [staking] Stumble out test case for validator information * [shard] Provide JSON dump of shard state * [EPoS] Checkpoint w/RJ * [EPoS] Implement EPoS at slot level * [shard] Remove two-value loop * [epos] Remove test code generation - use commit for testing later * [epos] Remove debug code, address lint * [epos] Remove staking epoch comment * [epos] Use max(320, len(stakers)) for median calculation * [epos] Remove search for empty spot for staked validator, only use top 320 for median * [epos] Address PR comments * [epos] Raise pull count as function parameter * [epos] Add initial testing for calculatepull/1833/head
parent
b9479fb835
commit
867fdb1f8d
@ -0,0 +1,105 @@ |
||||
package effective |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"math/big" |
||||
"sort" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/harmony-one/harmony/numeric" |
||||
"github.com/harmony-one/harmony/shard" |
||||
) |
||||
|
||||
// medium.com/harmony-one/introducing-harmonys-effective-proof-of-stake-epos-2d39b4b8d58
|
||||
var ( |
||||
two = numeric.NewDecFromBigInt(big.NewInt(2)) |
||||
c, _ = numeric.NewDecFromStr("0.15") |
||||
onePlusC = numeric.OneDec().Add(c) |
||||
oneMinusC = numeric.OneDec().Sub(c) |
||||
) |
||||
|
||||
func effectiveStake(median, actual numeric.Dec) numeric.Dec { |
||||
left := numeric.MinDec(onePlusC.Mul(median), actual) |
||||
right := oneMinusC.Mul(median) |
||||
return numeric.MaxDec(left, right) |
||||
} |
||||
|
||||
// SlotPurchase ..
|
||||
type SlotPurchase struct { |
||||
common.Address `json:"slot-owner"` |
||||
shard.BlsPublicKey `json:"bls-public-key"` |
||||
numeric.Dec `json:"eposed-stake"` |
||||
} |
||||
|
||||
// SlotOrder ..
|
||||
type SlotOrder struct { |
||||
Stake *big.Int |
||||
SpreadAmong []shard.BlsPublicKey |
||||
} |
||||
|
||||
// Slots ..
|
||||
type Slots []SlotPurchase |
||||
|
||||
// JSON is a plain JSON dump
|
||||
func (s Slots) JSON() string { |
||||
type t struct { |
||||
Slots []SlotPurchase `json:"slots"` |
||||
} |
||||
b, _ := json.Marshal(t{s}) |
||||
return string(b) |
||||
} |
||||
|
||||
func median(stakes []SlotPurchase) numeric.Dec { |
||||
sort.SliceStable( |
||||
stakes, |
||||
func(i, j int) bool { return stakes[i].Dec.LTE(stakes[j].Dec) }, |
||||
) |
||||
const isEven = 0 |
||||
switch l := len(stakes); l % 2 { |
||||
case isEven: |
||||
return stakes[(l/2)-1].Dec.Add(stakes[(l/2)+1].Dec).Quo(two) |
||||
default: |
||||
return stakes[l/2].Dec |
||||
} |
||||
} |
||||
|
||||
// Apply ..
|
||||
func Apply(shortHand map[common.Address]SlotOrder, pull int) Slots { |
||||
eposedSlots := Slots{} |
||||
if len(shortHand) == 0 { |
||||
return eposedSlots |
||||
} |
||||
// Expand
|
||||
for staker := range shortHand { |
||||
slotsCount := len(shortHand[staker].SpreadAmong) |
||||
spread := numeric.NewDecFromBigInt(shortHand[staker].Stake). |
||||
QuoInt64(int64(slotsCount)) |
||||
for i := 0; i < slotsCount; i++ { |
||||
eposedSlots = append(eposedSlots, SlotPurchase{ |
||||
staker, |
||||
shortHand[staker].SpreadAmong[i], |
||||
spread, |
||||
}) |
||||
} |
||||
} |
||||
if len(eposedSlots) < len(shortHand) { |
||||
// WARN Should never happen
|
||||
} |
||||
|
||||
sort.SliceStable( |
||||
eposedSlots, |
||||
func(i, j int) bool { return eposedSlots[i].Dec.GT(eposedSlots[j].Dec) }, |
||||
) |
||||
|
||||
if l := len(eposedSlots); l < pull { |
||||
pull = l |
||||
} |
||||
picks := eposedSlots[:pull] |
||||
median := median(picks) |
||||
|
||||
for i := range picks { |
||||
picks[i].Dec = effectiveStake(median, picks[i].Dec) |
||||
} |
||||
|
||||
return picks |
||||
} |
@ -0,0 +1,47 @@ |
||||
package effective |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
"io/ioutil" |
||||
"testing" |
||||
) |
||||
|
||||
const eposTestingFile = "epos.json" |
||||
|
||||
var ( |
||||
testingSlots slotsData |
||||
) |
||||
|
||||
type slotsData struct { |
||||
EPOSedSlot []string `json:"slots"` |
||||
} |
||||
|
||||
func init() { |
||||
input, err := ioutil.ReadFile(eposTestingFile) |
||||
if err != nil { |
||||
panic( |
||||
fmt.Sprintf("cannot open genesisblock config file %v, err %v\n", |
||||
eposTestingFile, |
||||
err, |
||||
)) |
||||
} |
||||
|
||||
t := slotsData{} |
||||
oops := json.Unmarshal(input, &t) |
||||
if oops != nil { |
||||
fmt.Println(oops.Error()) |
||||
panic("Could not unmarshal slots data into memory") |
||||
} |
||||
} |
||||
|
||||
func TestMedian(t *testing.T) { |
||||
//
|
||||
} |
||||
|
||||
func TestEffectiveStake(t *testing.T) { |
||||
//
|
||||
} |
||||
func TestApply(t *testing.T) { |
||||
//
|
||||
} |
@ -0,0 +1,324 @@ |
||||
{ |
||||
"slots": [ |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.690000000000000000", |
||||
"23.666666666666666666", |
||||
"23.666666666666666666", |
||||
"23.666666666666666666", |
||||
"23.500000000000000000", |
||||
"23.500000000000000000", |
||||
"23.500000000000000000", |
||||
"23.500000000000000000", |
||||
"23.500000000000000000", |
||||
"23.500000000000000000", |
||||
"23.500000000000000000", |
||||
"23.500000000000000000", |
||||
"22.500000000000000000", |
||||
"22.500000000000000000", |
||||
"22.500000000000000000", |
||||
"22.500000000000000000", |
||||
"22.250000000000000000", |
||||
"22.250000000000000000", |
||||
"22.250000000000000000", |
||||
"22.250000000000000000", |
||||
"22.000000000000000000", |
||||
"22.000000000000000000", |
||||
"22.000000000000000000", |
||||
"22.000000000000000000", |
||||
"22.000000000000000000", |
||||
"21.000000000000000000", |
||||
"21.000000000000000000", |
||||
"21.000000000000000000", |
||||
"21.000000000000000000", |
||||
"20.666666666666666666", |
||||
"20.666666666666666666", |
||||
"20.666666666666666666", |
||||
"20.666666666666666666", |
||||
"20.666666666666666666", |
||||
"20.666666666666666666", |
||||
"20.600000000000000000", |
||||
"20.600000000000000000", |
||||
"20.600000000000000000", |
||||
"20.600000000000000000", |
||||
"20.600000000000000000", |
||||
"20.000000000000000000", |
||||
"20.000000000000000000", |
||||
"20.000000000000000000", |
||||
"20.000000000000000000", |
||||
"20.000000000000000000", |
||||
"19.600000000000000000", |
||||
"19.600000000000000000", |
||||
"19.600000000000000000", |
||||
"19.600000000000000000", |
||||
"19.600000000000000000", |
||||
"19.500000000000000000", |
||||
"19.500000000000000000", |
||||
"19.333333333333333333", |
||||
"19.333333333333333333", |
||||
"19.333333333333333333", |
||||
"19.000000000000000000", |
||||
"19.000000000000000000", |
||||
"19.000000000000000000", |
||||
"19.000000000000000000", |
||||
"18.750000000000000000", |
||||
"18.750000000000000000", |
||||
"18.750000000000000000", |
||||
"18.750000000000000000", |
||||
"18.500000000000000000", |
||||
"18.500000000000000000", |
||||
"18.500000000000000000", |
||||
"18.500000000000000000", |
||||
"18.500000000000000000", |
||||
"18.500000000000000000", |
||||
"18.500000000000000000", |
||||
"18.500000000000000000", |
||||
"18.000000000000000000", |
||||
"18.000000000000000000", |
||||
"18.000000000000000000", |
||||
"18.000000000000000000", |
||||
"18.000000000000000000", |
||||
"18.000000000000000000", |
||||
"18.000000000000000000", |
||||
"17.714285714285714285", |
||||
"17.714285714285714285", |
||||
"17.714285714285714285", |
||||
"17.714285714285714285", |
||||
"17.714285714285714285", |
||||
"17.714285714285714285", |
||||
"17.714285714285714285", |
||||
"17.600000000000000000", |
||||
"17.600000000000000000", |
||||
"17.600000000000000000", |
||||
"17.600000000000000000", |
||||
"17.600000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000", |
||||
"17.510000000000000000" |
||||
] |
||||
} |
Loading…
Reference in new issue