-
Notifications
You must be signed in to change notification settings - Fork 39
/
abci.go
121 lines (96 loc) · 3.64 KB
/
abci.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
package oracle
import (
"time"
core "github.com/classic-terra/core/v2/types"
"github.com/classic-terra/core/v2/x/oracle/keeper"
"github.com/classic-terra/core/v2/x/oracle/types"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// EndBlocker is called at the end of every block
func EndBlocker(ctx sdk.Context, k keeper.Keeper) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker)
params := k.GetParams(ctx)
if core.IsPeriodLastBlock(ctx, params.VotePeriod) {
// Build claim map over all validators in active set
validatorClaimMap := make(map[string]types.Claim)
maxValidators := k.StakingKeeper.MaxValidators(ctx)
iterator := k.StakingKeeper.ValidatorsPowerStoreIterator(ctx)
defer iterator.Close()
powerReduction := k.StakingKeeper.PowerReduction(ctx)
i := 0
for ; iterator.Valid() && i < int(maxValidators); iterator.Next() {
validator := k.StakingKeeper.Validator(ctx, iterator.Value())
// Exclude not bonded validator
if validator.IsBonded() {
valAddr := validator.GetOperator()
validatorClaimMap[valAddr.String()] = types.NewClaim(validator.GetConsensusPower(powerReduction), 0, 0, valAddr)
i++
}
}
// Denom-TobinTax map
voteTargets := make(map[string]sdk.Dec)
k.IterateTobinTaxes(ctx, func(denom string, tobinTax sdk.Dec) bool {
voteTargets[denom] = tobinTax
return false
})
// Clear all exchange rates
k.IterateLunaExchangeRates(ctx, func(denom string, _ sdk.Dec) (stop bool) {
k.DeleteLunaExchangeRate(ctx, denom)
return false
})
// Organize votes to ballot by denom
// NOTE: **Filter out inactive or jailed validators**
// NOTE: **Make abstain votes to have zero vote power**
voteMap := k.OrganizeBallotByDenom(ctx, validatorClaimMap)
if referenceTerra := PickReferenceTerra(ctx, k, voteTargets, voteMap); referenceTerra != "" {
// make voteMap of Reference Terra to calculate cross exchange rates
ballotRT := voteMap[referenceTerra]
voteMapRT := ballotRT.ToMap()
exchangeRateRT := ballotRT.WeightedMedian()
// Iterate through ballots and update exchange rates; drop if not enough votes have been achieved.
for denom, ballot := range voteMap {
// Convert ballot to cross exchange rates
if denom != referenceTerra {
ballot = ballot.ToCrossRateWithSort(voteMapRT)
}
// Get weighted median of cross exchange rates
exchangeRate := Tally(ballot, params.RewardBand, validatorClaimMap)
// Transform into the original form uluna/stablecoin
if denom != referenceTerra {
exchangeRate = exchangeRateRT.Quo(exchangeRate)
}
// Set the exchange rate, emit ABCI event
k.SetLunaExchangeRateWithEvent(ctx, denom, exchangeRate)
}
}
//---------------------------
// Do miss counting & slashing
voteTargetsLen := len(voteTargets)
for _, claim := range validatorClaimMap {
// Skip abstain & valid voters
if int(claim.WinCount) == voteTargetsLen {
continue
}
// Increase miss counter
k.SetMissCounter(ctx, claim.Recipient, k.GetMissCounter(ctx, claim.Recipient)+1)
}
// Distribute rewards to ballot winners
k.RewardBallotWinners(
ctx,
(int64)(params.VotePeriod),
(int64)(params.RewardDistributionWindow),
voteTargets,
validatorClaimMap,
)
// Clear the ballot
k.ClearBallots(ctx, params.VotePeriod)
// Update vote targets and tobin tax
k.ApplyWhitelist(ctx, params.Whitelist, voteTargets)
}
// Do slash who did miss voting over threshold and
// reset miss counters of all validators at the last block of slash window
if core.IsPeriodLastBlock(ctx, params.SlashWindow) {
k.SlashAndResetMissCounters(ctx)
}
}