-
Notifications
You must be signed in to change notification settings - Fork 30
/
validator_info.go
153 lines (123 loc) · 5.44 KB
/
validator_info.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// common parameters used in withdraws from validators
type WithdrawContext struct {
FeePool FeePool
Height int64 // block height
TotalPower sdk.Dec // total bonded tokens in the network
ValPower sdk.Dec // validator's bonded tokens
CommissionRate sdk.Dec // validator commission rate
}
func NewWithdrawContext(feePool FeePool, height int64, totalPower,
valPower, commissionRate sdk.Dec) WithdrawContext {
return WithdrawContext{
FeePool: feePool,
Height: height,
TotalPower: totalPower,
ValPower: valPower,
CommissionRate: commissionRate,
}
}
//_____________________________________________________________________________
// distribution info for a particular validator
type ValidatorDistInfo struct {
OperatorAddr sdk.ValAddress `json:"operator_addr"`
FeePoolWithdrawalHeight int64 `json:"fee_pool_withdrawal_height"` // last height this validator withdrew from the global pool
DelAccum TotalAccum `json:"del_accum"` // total accumulation factor held by delegators
DelPool DecCoins `json:"del_pool"` // rewards owed to delegators, commission has already been charged (includes proposer reward)
ValCommission DecCoins `json:"val_commission"` // commission collected by this validator (pending withdrawal)
}
func NewValidatorDistInfo(operatorAddr sdk.ValAddress, currentHeight int64) ValidatorDistInfo {
return ValidatorDistInfo{
OperatorAddr: operatorAddr,
FeePoolWithdrawalHeight: currentHeight,
DelPool: DecCoins{},
DelAccum: NewTotalAccum(currentHeight),
ValCommission: DecCoins{},
}
}
// update total delegator accumululation
func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares sdk.Dec) ValidatorDistInfo {
vi.DelAccum = vi.DelAccum.UpdateForNewHeight(height, totalDelShares)
return vi
}
// Get the total delegator accum within this validator at the provided height
func (vi ValidatorDistInfo) GetTotalDelAccum(height int64, totalDelShares sdk.Dec) sdk.Dec {
return vi.DelAccum.GetAccum(height, totalDelShares)
}
// Get the validator accum at the provided height
func (vi ValidatorDistInfo) GetValAccum(height int64, valTokens sdk.Dec) sdk.Dec {
blocks := height - vi.FeePoolWithdrawalHeight
return valTokens.MulInt(sdk.NewInt(blocks))
}
// Move any available accumulated fees in the FeePool to the validator's pool
// - updates validator info's FeePoolWithdrawalHeight, thus setting accum to 0
// - updates fee pool to latest height and total val accum w/ given totalBonded
// This is the only way to update the FeePool's validator TotalAccum.
// NOTE: This algorithm works as long as TakeFeePoolRewards is called after every power change.
// - called in ValidationDistInfo.WithdrawCommission
// - called in DelegationDistInfo.WithdrawRewards
// NOTE: When a delegator unbonds, say, onDelegationSharesModified ->
// WithdrawDelegationReward -> WithdrawRewards
func (vi ValidatorDistInfo) TakeFeePoolRewards(wc WithdrawContext) (
ValidatorDistInfo, FeePool) {
fp := wc.FeePool.UpdateTotalValAccum(wc.Height, wc.TotalPower)
if fp.TotalValAccum.Accum.IsZero() {
vi.FeePoolWithdrawalHeight = wc.Height
return vi, fp
}
// update the validators pool
accum := vi.GetValAccum(wc.Height, wc.ValPower)
vi.FeePoolWithdrawalHeight = wc.Height
if accum.GT(fp.TotalValAccum.Accum) {
panic("individual accum should never be greater than the total")
}
withdrawalTokens := fp.ValPool.MulDec(accum).QuoDec(fp.TotalValAccum.Accum) // XXX ensure this doesn't cause problems
remValPool := fp.ValPool.Minus(withdrawalTokens)
commission := withdrawalTokens.MulDec(wc.CommissionRate)
afterCommission := withdrawalTokens.Minus(commission)
fp.TotalValAccum.Accum = fp.TotalValAccum.Accum.Sub(accum)
fp.ValPool = remValPool
vi.ValCommission = vi.ValCommission.Plus(commission)
vi.DelPool = vi.DelPool.Plus(afterCommission)
return vi, fp
}
// withdraw commission rewards
func (vi ValidatorDistInfo) WithdrawCommission(wc WithdrawContext) (
vio ValidatorDistInfo, fpo FeePool, withdrawn DecCoins) {
vi, fp := vi.TakeFeePoolRewards(wc)
withdrawalTokens := vi.ValCommission
vi.ValCommission = DecCoins{} // zero
return vi, fp, withdrawalTokens
}
// get the validator's pool rewards at this current state,
func (vi ValidatorDistInfo) CurrentPoolRewards(
wc WithdrawContext) DecCoins {
fp := wc.FeePool
totalValAccum := fp.GetTotalValAccum(wc.Height, wc.TotalPower)
valAccum := vi.GetValAccum(wc.Height, wc.ValPower)
if valAccum.GT(totalValAccum) {
panic("individual accum should never be greater than the total")
}
withdrawalTokens := fp.ValPool.MulDec(valAccum).QuoDec(totalValAccum)
commission := withdrawalTokens.MulDec(wc.CommissionRate)
afterCommission := withdrawalTokens.Minus(commission)
pool := vi.DelPool.Plus(afterCommission)
return pool
}
// get the validator's commission pool rewards at this current state,
func (vi ValidatorDistInfo) CurrentCommissionRewards(
wc WithdrawContext) DecCoins {
fp := wc.FeePool
totalValAccum := fp.GetTotalValAccum(wc.Height, wc.TotalPower)
valAccum := vi.GetValAccum(wc.Height, wc.ValPower)
if valAccum.GT(totalValAccum) {
panic("individual accum should never be greater than the total")
}
withdrawalTokens := fp.ValPool.MulDec(valAccum).QuoDec(totalValAccum)
commission := withdrawalTokens.MulDec(wc.CommissionRate)
commissionPool := vi.ValCommission.Plus(commission)
return commissionPool
}