|
|
|
@ -1,29 +1,35 @@ |
|
|
|
|
package quorum |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"encoding/json" |
|
|
|
|
"math/big" |
|
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common" |
|
|
|
|
"github.com/harmony-one/bls/ffi/go/bls" |
|
|
|
|
"github.com/harmony-one/harmony/internal/utils" |
|
|
|
|
"github.com/harmony-one/harmony/numeric" |
|
|
|
|
"github.com/harmony-one/harmony/shard" |
|
|
|
|
"github.com/harmony-one/harmony/staking/slash" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
twoThirds = numeric.NewDec(2).QuoInt64(3).Int |
|
|
|
|
twoThirds = numeric.NewDec(2).QuoInt64(3) |
|
|
|
|
hSentinel = numeric.ZeroDec() |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
type stakedVoter struct { |
|
|
|
|
isActive, isHarmonyNode bool |
|
|
|
|
earningAccount common.Address |
|
|
|
|
effective numeric.Dec |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type stakedVoteWeight struct { |
|
|
|
|
SignatureReader |
|
|
|
|
DependencyInjectionWriter |
|
|
|
|
// EPOS based staking
|
|
|
|
|
validatorStakes map[[shard.PublicKeySizeInBytes]byte]stakedVoter |
|
|
|
|
totalEffectiveStakedAmount *big.Int |
|
|
|
|
DependencyInjectionReader |
|
|
|
|
slash.ThresholdDecider |
|
|
|
|
validatorStakes map[shard.BlsPublicKey]stakedVoter |
|
|
|
|
total numeric.Dec |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Policy ..
|
|
|
|
@ -31,45 +37,141 @@ func (v *stakedVoteWeight) Policy() Policy { |
|
|
|
|
return SuperMajorityStake |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// We must maintain 2/3 quoroum, so whatever is 2/3 staked amount,
|
|
|
|
|
// we divide that out & you
|
|
|
|
|
// IsQuorumAchieved ..
|
|
|
|
|
func (v *stakedVoteWeight) IsQuorumAchieved(p Phase) bool { |
|
|
|
|
// TODO Implement this logic
|
|
|
|
|
// TODO Implement this logic w/Chao
|
|
|
|
|
// soFar := numeric.ZeroDec()
|
|
|
|
|
w := shard.BlsPublicKey{} |
|
|
|
|
members := v.Participants() |
|
|
|
|
|
|
|
|
|
for i := range members { |
|
|
|
|
w.FromLibBLSPublicKey(members[i]) |
|
|
|
|
// isHMY := v.validatorStakes[w].isHarmonyNode
|
|
|
|
|
if v.ReadSignature(p, members[i]) == nil { |
|
|
|
|
// TODO TODO finish this logic
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// QuorumThreshold ..
|
|
|
|
|
func (v *stakedVoteWeight) QuorumThreshold() *big.Int { |
|
|
|
|
return new(big.Int).Mul(v.totalEffectiveStakedAmount, twoThirds) |
|
|
|
|
return v.total.Mul(twoThirds).Ceil().RoundInt() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// RewardThreshold ..
|
|
|
|
|
func (v *stakedVoteWeight) IsRewardThresholdAchieved() bool { |
|
|
|
|
// TODO Implement
|
|
|
|
|
return false |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// HACK
|
|
|
|
|
var ( |
|
|
|
|
hSentinel = big.NewInt(0) |
|
|
|
|
hEffectiveSentinel = numeric.ZeroDec() |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// Award ..
|
|
|
|
|
func (v *stakedVoteWeight) Award( |
|
|
|
|
Pie *big.Int, earners []common.Address, hook func(earner common.Address, due *big.Int), |
|
|
|
|
) *big.Int { |
|
|
|
|
// TODO Implement
|
|
|
|
|
return nil |
|
|
|
|
payout := big.NewInt(0) |
|
|
|
|
last := big.NewInt(0) |
|
|
|
|
count := big.NewInt(int64(len(earners))) |
|
|
|
|
proportional := map[common.Address]numeric.Dec{} |
|
|
|
|
|
|
|
|
|
for _, details := range v.validatorStakes { |
|
|
|
|
if details.isHarmonyNode == false { |
|
|
|
|
proportional[details.earningAccount] = details.effective.QuoTruncate( |
|
|
|
|
v.total, |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// TODO Finish implementing this logic w/Chao
|
|
|
|
|
|
|
|
|
|
for i := range earners { |
|
|
|
|
cur := big.NewInt(0) |
|
|
|
|
|
|
|
|
|
cur.Mul(Pie, big.NewInt(int64(i+1))).Div(cur, count) |
|
|
|
|
|
|
|
|
|
diff := big.NewInt(0).Sub(cur, last) |
|
|
|
|
|
|
|
|
|
// hook(common.Address(account), diff)
|
|
|
|
|
|
|
|
|
|
payout = big.NewInt(0).Add(payout, diff) |
|
|
|
|
|
|
|
|
|
last = cur |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return payout |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// UpdateVotingPower called only at epoch change, prob need to move to CalculateShardState
|
|
|
|
|
// func (v *stakedVoteWeight) UpdateVotingPower(keeper effective.StakeKeeper) {
|
|
|
|
|
// TODO Implement
|
|
|
|
|
// }
|
|
|
|
|
func (v *stakedVoteWeight) UpdateVotingPower(staked shard.SlotList) { |
|
|
|
|
s, _ := v.ShardIDProvider()() |
|
|
|
|
|
|
|
|
|
func (v *stakedVoteWeight) ToggleActive(*bls.PublicKey) bool { |
|
|
|
|
// TODO Implement
|
|
|
|
|
return true |
|
|
|
|
v.validatorStakes = map[shard.BlsPublicKey]stakedVoter{} |
|
|
|
|
v.Reset([]Phase{Prepare, Commit, ViewChange}) |
|
|
|
|
|
|
|
|
|
for i := range staked { |
|
|
|
|
if staked[i].StakeWithDelegationApplied != nil { |
|
|
|
|
v.validatorStakes[staked[i].BlsPublicKey] = stakedVoter{ |
|
|
|
|
true, false, staked[i].EcdsaAddress, *staked[i].StakeWithDelegationApplied, |
|
|
|
|
} |
|
|
|
|
v.total = v.total.Add(*staked[i].StakeWithDelegationApplied) |
|
|
|
|
} else { |
|
|
|
|
v.validatorStakes[staked[i].BlsPublicKey] = stakedVoter{ |
|
|
|
|
true, true, staked[i].EcdsaAddress, hSentinel, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
utils.Logger().Info(). |
|
|
|
|
Uint32("on-shard", s). |
|
|
|
|
Str("Staked", v.total.String()). |
|
|
|
|
Msg("Total staked") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (v *stakedVoteWeight) ToggleActive(k *bls.PublicKey) bool { |
|
|
|
|
w := shard.BlsPublicKey{} |
|
|
|
|
w.FromLibBLSPublicKey(k) |
|
|
|
|
g := v.validatorStakes[w] |
|
|
|
|
g.isActive = !g.isActive |
|
|
|
|
v.validatorStakes[w] = g |
|
|
|
|
return v.validatorStakes[w].isActive |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (v *stakedVoteWeight) ShouldSlash(key shard.BlsPublicKey) bool { |
|
|
|
|
s, _ := v.ShardIDProvider()() |
|
|
|
|
switch s { |
|
|
|
|
case shard.BeaconChainShardID: |
|
|
|
|
return v.SlashThresholdMet(key) |
|
|
|
|
default: |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (v *stakedVoteWeight) JSON() string { |
|
|
|
|
s, _ := v.ShardIDProvider()() |
|
|
|
|
|
|
|
|
|
type t struct { |
|
|
|
|
Policy string `json"policy"` |
|
|
|
|
ShardID uint32 `json:"shard-id"` |
|
|
|
|
Count int `json:"count"` |
|
|
|
|
Participants []string `json:"committee-members"` |
|
|
|
|
TotalStaked string `json:"total-staked"` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
members := v.DumpParticipants() |
|
|
|
|
parts := []string{} |
|
|
|
|
for i := range members { |
|
|
|
|
k := bls.PublicKey{} |
|
|
|
|
k.DeserializeHexStr(members[i]) |
|
|
|
|
w := shard.BlsPublicKey{} |
|
|
|
|
w.FromLibBLSPublicKey(&k) |
|
|
|
|
staker := v.validatorStakes[w] |
|
|
|
|
if staker.isHarmonyNode { |
|
|
|
|
parts = append(parts, members[i]) |
|
|
|
|
} else { |
|
|
|
|
parts = append(parts, members[i]+"-"+staker.effective.String()) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
b1, _ := json.Marshal(t{ |
|
|
|
|
v.Policy().String(), s, len(members), parts, v.total.String(), |
|
|
|
|
}) |
|
|
|
|
return string(b1) |
|
|
|
|
} |
|
|
|
|