mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-11-10 18:15:19 +00:00
89 lines
2.4 KiB
Go
89 lines
2.4 KiB
Go
|
package keeper
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"math/big"
|
||
|
"sort"
|
||
|
|
||
|
"github.com/0glabs/0g-chain/x/dasigners/v1/types"
|
||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||
|
"github.com/ethereum/go-ethereum/crypto"
|
||
|
abci "github.com/tendermint/tendermint/abci/types"
|
||
|
)
|
||
|
|
||
|
type Ballot struct {
|
||
|
account string
|
||
|
content []byte
|
||
|
}
|
||
|
|
||
|
func (k Keeper) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) {
|
||
|
epochNumber, err := k.GetEpochNumber(ctx)
|
||
|
if err != nil {
|
||
|
k.Logger(ctx).Error("[BeginBlock] cannot get epoch number")
|
||
|
panic(err)
|
||
|
}
|
||
|
params := k.GetParams(ctx)
|
||
|
expectedEpoch := uint64(ctx.BlockHeight()) / params.EpochBlocks
|
||
|
if expectedEpoch == epochNumber {
|
||
|
return
|
||
|
}
|
||
|
if expectedEpoch > epochNumber+1 || expectedEpoch < epochNumber {
|
||
|
panic("block height is not continuous")
|
||
|
}
|
||
|
// new epoch
|
||
|
registrations := []Ballot{}
|
||
|
k.IterateRegistrations(ctx, expectedEpoch, func(account string, signature []byte) (stop bool) {
|
||
|
registrations = append(registrations, Ballot{
|
||
|
account: account,
|
||
|
content: signature,
|
||
|
})
|
||
|
return false
|
||
|
})
|
||
|
ballots := []Ballot{}
|
||
|
tokensPerVote, ok := sdk.NewIntFromString(params.TokensPerVote)
|
||
|
if !ok {
|
||
|
panic("failed to load params tokens_per_vote")
|
||
|
}
|
||
|
for _, registration := range registrations {
|
||
|
// get validator
|
||
|
valAddr, err := sdk.ValAddressFromHex(registration.account)
|
||
|
if err != nil {
|
||
|
k.Logger(ctx).Error("[BeginBlock] invalid account")
|
||
|
continue
|
||
|
}
|
||
|
validator, found := k.stakingKeeper.GetValidator(ctx, valAddr)
|
||
|
if !found {
|
||
|
continue
|
||
|
}
|
||
|
num := validator.Tokens.Quo(sdk.NewInt(1_000_000_000_000_000_000)).Quo(tokensPerVote).Abs().BigInt()
|
||
|
if num.Cmp(big.NewInt(int64(params.MaxVotes))) > 0 {
|
||
|
num = big.NewInt(int64(params.MaxVotes))
|
||
|
}
|
||
|
content := registration.content
|
||
|
ballotNum := num.Int64()
|
||
|
for j := 0; j < int(ballotNum); j += 1 {
|
||
|
ballots = append(ballots, Ballot{
|
||
|
account: registration.account,
|
||
|
content: content,
|
||
|
})
|
||
|
content = crypto.Keccak256(content)
|
||
|
}
|
||
|
}
|
||
|
sort.Slice(ballots, func(i, j int) bool {
|
||
|
return bytes.Compare(ballots[i].content, ballots[j].content) < 0
|
||
|
})
|
||
|
chosen := make(map[string]struct{})
|
||
|
epochSignerSet := types.EpochSignerSet{
|
||
|
Signers: make([]string, 0),
|
||
|
}
|
||
|
for _, ballot := range ballots {
|
||
|
if _, ok := chosen[ballot.account]; !ok {
|
||
|
chosen[ballot.account] = struct{}{}
|
||
|
epochSignerSet.Signers = append(epochSignerSet.Signers, ballot.account)
|
||
|
}
|
||
|
}
|
||
|
// save to store
|
||
|
k.SetEpochSignerSet(ctx, expectedEpoch, epochSignerSet)
|
||
|
k.SetEpochNumber(ctx, expectedEpoch)
|
||
|
}
|