/
abci.go
131 lines (104 loc) · 3.84 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
122
123
124
125
126
127
128
129
130
131
package oracle
import (
"time"
merlion "github.com/merlion-zone/merlion/types"
"github.com/merlion-zone/merlion/x/oracle/keeper"
"github.com/merlion-zone/merlion/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 merlion.IsPeriodLastBlock(ctx, params.VotePeriod) {
stakingKeeper := k.StakingKeeper()
// Build claim map over all validators in active set
validatorClaimMap := make(map[string]types.Claim)
maxValidators := stakingKeeper.MaxValidators(ctx)
iterator := stakingKeeper.ValidatorsPowerStoreIterator(ctx)
defer iterator.Close()
powerReduction := stakingKeeper.PowerReduction(ctx)
i := 0
for ; iterator.Valid() && i < int(maxValidators); iterator.Next() {
validator := 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 map
voteTargets := make(map[string]struct{})
k.IterateVoteTargets(ctx, func(denom string) bool {
voteTargets[denom] = struct{}{}
return false
})
// Clear all exchange rates
k.IterateExchangeRates(ctx, func(denom string, _ sdk.Dec) (stop bool) {
k.DeleteExchangeRate(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)
ctx.Logger().Debug("organized ballot by denom", "voteMap", voteMap)
if referenceMer := PickReferenceMer(ctx, k, voteTargets, voteMap); referenceMer != "" {
// make voteMap of Reference Mer to calculate cross exchange rates
ballotRM := voteMap[referenceMer]
voteMapRM := ballotRM.ToMap()
var exchangeRateRM sdk.Dec
exchangeRateRM = ballotRM.WeightedMedianWithAssertion()
// 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 != referenceMer {
ballot = ballot.ToCrossRateWithSort(voteMapRM)
}
// Get weighted median of cross exchange rates
exchangeRate := Tally(ctx, ballot, params.RewardBand, validatorClaimMap)
// Transform into the original form {denom}/uUSD
if denom != referenceMer {
if exchangeRate.IsZero() {
k.Logger(ctx).Error("invalid tallied cross exchange rate", "denom", denom, "exchangeRate", exchangeRate)
// Do not set exchange rate
continue
}
exchangeRate = exchangeRateRM.Quo(exchangeRate)
}
// Set the exchange rate, emit ABCI event
k.SetExchangeRate(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)
}
// Do slash who did miss voting over threshold and
// reset miss counters of all validators
// at the last block of slash window
if merlion.IsPeriodLastBlock(ctx, params.SlashWindow) {
k.SlashAndResetMissCounters(ctx)
}
return
}