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 := sdk.NewIntFromUint64(params.TokensPerVote) 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(BondedConversionRate).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) }