mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-11-15 04:25:27 +00:00
117 lines
3.3 KiB
Go
117 lines
3.3 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
|
|
accAddr, err := sdk.AccAddressFromHexUnsafe(registration.account)
|
|
if err != nil {
|
|
k.Logger(ctx).Error("[BeginBlock] invalid account")
|
|
continue
|
|
}
|
|
bonded := k.GetDelegatorBonded(ctx, accAddr)
|
|
num := bonded.Quo(sdk.NewInt(1_000_000_000_000_000_000)).Quo(tokensPerVote).Abs().BigInt()
|
|
if num.Cmp(big.NewInt(int64(params.MaxVotesPerSigner))) > 0 {
|
|
num = big.NewInt(int64(params.MaxVotesPerSigner))
|
|
}
|
|
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
|
|
})
|
|
|
|
quorums := types.Quorums{
|
|
Quorums: make([]*types.Quorum, 0),
|
|
}
|
|
if len(ballots) >= int(params.EncodedSlices) {
|
|
for i := 0; i+int(params.EncodedSlices) <= len(ballots); i += int(params.EncodedSlices) {
|
|
if int(params.MaxQuorums) < len(quorums.Quorums) {
|
|
break
|
|
}
|
|
quorum := types.Quorum{
|
|
Signers: make([]string, params.EncodedSlices),
|
|
}
|
|
for j := 0; j < int(params.EncodedSlices); j += 1 {
|
|
quorum.Signers[j] = ballots[i+j].account
|
|
}
|
|
quorums.Quorums = append(quorums.Quorums, &quorum)
|
|
}
|
|
if len(ballots)%int(params.EncodedSlices) != 0 && int(params.MaxQuorums) > len(quorums.Quorums) {
|
|
quorum := types.Quorum{
|
|
Signers: make([]string, 0),
|
|
}
|
|
for j := len(ballots) - int(params.EncodedSlices); j < len(ballots); j += 1 {
|
|
quorum.Signers = append(quorum.Signers, ballots[j].account)
|
|
}
|
|
quorums.Quorums = append(quorums.Quorums, &quorum)
|
|
}
|
|
} else if len(ballots) > 0 {
|
|
quorum := types.Quorum{
|
|
Signers: make([]string, params.EncodedSlices),
|
|
}
|
|
n := len(ballots)
|
|
for i := 0; i < int(params.EncodedSlices); i += 1 {
|
|
quorum.Signers[i] = ballots[i%n].account
|
|
}
|
|
quorums.Quorums = append(quorums.Quorums, &quorum)
|
|
} else {
|
|
quorums.Quorums = append(quorums.Quorums, &types.Quorum{
|
|
Signers: make([]string, 0),
|
|
})
|
|
}
|
|
|
|
// save to store
|
|
k.SetEpochQuorums(ctx, expectedEpoch, quorums)
|
|
k.SetEpochNumber(ctx, expectedEpoch)
|
|
}
|