2024-05-09 18:54:47 +00:00
|
|
|
package keeper
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2024-08-10 02:24:11 +00:00
|
|
|
"fmt"
|
2024-06-07 07:47:56 +00:00
|
|
|
"math/big"
|
2024-05-09 18:54:47 +00:00
|
|
|
"sort"
|
|
|
|
|
|
|
|
"github.com/0glabs/0g-chain/x/dasigners/v1/types"
|
2024-08-02 10:34:24 +00:00
|
|
|
abci "github.com/cometbft/cometbft/abci/types"
|
2024-05-09 18:54:47 +00:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Ballot struct {
|
|
|
|
account string
|
|
|
|
content []byte
|
|
|
|
}
|
|
|
|
|
2024-08-10 02:24:11 +00:00
|
|
|
// generateOneEpoch generate one epoch and returns true if there is a new epoch generated
|
|
|
|
func (k Keeper) generateOneEpoch(ctx sdk.Context) bool {
|
2024-05-09 18:54:47 +00:00
|
|
|
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 {
|
2024-08-10 02:24:11 +00:00
|
|
|
return false
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
2024-08-10 02:24:11 +00:00
|
|
|
if expectedEpoch < epochNumber {
|
2024-05-09 18:54:47 +00:00
|
|
|
panic("block height is not continuous")
|
|
|
|
}
|
2024-08-10 02:24:11 +00:00
|
|
|
expectedEpoch = epochNumber + 1
|
2024-05-09 18:54:47 +00:00
|
|
|
// new epoch
|
2024-08-10 02:24:11 +00:00
|
|
|
k.Logger(ctx).Info(fmt.Sprintf("[BeginBlock] generating epoch %v", expectedEpoch))
|
2024-05-09 18:54:47 +00:00
|
|
|
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{}
|
2024-06-11 07:20:30 +00:00
|
|
|
tokensPerVote := sdk.NewIntFromUint64(params.TokensPerVote)
|
2024-05-09 18:54:47 +00:00
|
|
|
for _, registration := range registrations {
|
|
|
|
// get validator
|
2024-06-07 07:47:56 +00:00
|
|
|
accAddr, err := sdk.AccAddressFromHexUnsafe(registration.account)
|
2024-05-09 18:54:47 +00:00
|
|
|
if err != nil {
|
|
|
|
k.Logger(ctx).Error("[BeginBlock] invalid account")
|
|
|
|
continue
|
|
|
|
}
|
2024-06-07 07:47:56 +00:00
|
|
|
bonded := k.GetDelegatorBonded(ctx, accAddr)
|
2024-06-11 07:20:30 +00:00
|
|
|
num := bonded.Quo(BondedConversionRate).Quo(tokensPerVote).Abs().BigInt()
|
2024-06-07 07:47:56 +00:00
|
|
|
if num.Cmp(big.NewInt(int64(params.MaxVotesPerSigner))) > 0 {
|
|
|
|
num = big.NewInt(int64(params.MaxVotesPerSigner))
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
|
})
|
2024-05-16 14:49:29 +00:00
|
|
|
|
|
|
|
quorums := types.Quorums{
|
|
|
|
Quorums: make([]*types.Quorum, 0),
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
2024-05-16 14:49:29 +00:00
|
|
|
if len(ballots) >= int(params.EncodedSlices) {
|
2024-05-16 15:46:12 +00:00
|
|
|
for i := 0; i+int(params.EncodedSlices) <= len(ballots); i += int(params.EncodedSlices) {
|
2024-08-09 05:34:37 +00:00
|
|
|
if int(params.MaxQuorums) <= len(quorums.Quorums) {
|
2024-05-16 15:39:07 +00:00
|
|
|
break
|
|
|
|
}
|
2024-05-16 14:49:29 +00:00
|
|
|
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)
|
|
|
|
}
|
2024-05-16 15:46:12 +00:00
|
|
|
if len(ballots)%int(params.EncodedSlices) != 0 && int(params.MaxQuorums) > len(quorums.Quorums) {
|
2024-05-16 15:39:07 +00:00
|
|
|
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)
|
|
|
|
}
|
2024-05-16 15:25:43 +00:00
|
|
|
} else if len(ballots) > 0 {
|
2024-05-16 14:49:29 +00:00
|
|
|
quorum := types.Quorum{
|
|
|
|
Signers: make([]string, params.EncodedSlices),
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
2024-05-16 14:49:29 +00:00
|
|
|
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)
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
2024-05-16 14:49:29 +00:00
|
|
|
|
2024-05-09 18:54:47 +00:00
|
|
|
// save to store
|
2024-05-16 14:49:29 +00:00
|
|
|
k.SetEpochQuorums(ctx, expectedEpoch, quorums)
|
2024-05-09 18:54:47 +00:00
|
|
|
k.SetEpochNumber(ctx, expectedEpoch)
|
2024-08-10 02:24:11 +00:00
|
|
|
k.Logger(ctx).Info(fmt.Sprintf("[BeginBlock] epoch %v generated, with %v quorums", expectedEpoch, len(quorums.Quorums)))
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k Keeper) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) {
|
|
|
|
for k.generateOneEpoch(ctx) {
|
|
|
|
}
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|