package keeper import ( "encoding/hex" "fmt" "math/big" "cosmossdk.io/math" "github.com/cometbft/cometbft/libs/log" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/0glabs/0g-chain/chaincfg" "github.com/0glabs/0g-chain/x/dasigners/v1/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) var BondedConversionRate = math.NewIntFromBigInt(big.NewInt(0).Exp(big.NewInt(10), big.NewInt(chaincfg.GasDenomUnit), nil)) type Keeper struct { storeKey storetypes.StoreKey cdc codec.BinaryCodec stakingKeeper types.StakingKeeper authority string // the address capable of changing signers params. Should be the gov module account } // NewKeeper creates a new das Keeper instance func NewKeeper( storeKey storetypes.StoreKey, cdc codec.BinaryCodec, stakingKeeper types.StakingKeeper, authority string, ) Keeper { return Keeper{ storeKey: storeKey, cdc: cdc, stakingKeeper: stakingKeeper, authority: authority, } } // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+types.ModuleName) } func (k Keeper) GetParams(ctx sdk.Context) types.Params { store := ctx.KVStore(k.storeKey) bz := store.Get(types.ParamsKey) var params types.Params k.cdc.MustUnmarshal(bz, ¶ms) return params } func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshal(¶ms) store.Set(types.ParamsKey, bz) ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeUpdateParams, sdk.NewAttribute(types.AttributeKeyBlockHeight, fmt.Sprint(ctx.BlockHeader().Height)), sdk.NewAttribute(types.AttributeKeyTokensPerVote, fmt.Sprint(params.TokensPerVote)), sdk.NewAttribute(types.AttributeKeyMaxQuorums, fmt.Sprint(params.MaxQuorums)), sdk.NewAttribute(types.AttributeKeyEpochBlocks, fmt.Sprint(params.EpochBlocks)), sdk.NewAttribute(types.AttributeKeyEncodedSlices, fmt.Sprint(params.EncodedSlices)), ), ) } func (k Keeper) GetEpochNumber(ctx sdk.Context) (uint64, error) { store := ctx.KVStore(k.storeKey) bz := store.Get(types.EpochNumberKey) if bz == nil { return 0, types.ErrEpochNumberNotSet } return sdk.BigEndianToUint64(bz), nil } func (k Keeper) SetEpochNumber(ctx sdk.Context, epoch uint64) { store := ctx.KVStore(k.storeKey) store.Set(types.EpochNumberKey, sdk.Uint64ToBigEndian(epoch)) } func (k Keeper) GetQuorumCount(ctx sdk.Context, epoch uint64) (uint64, error) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.QuorumCountKeyPrefix) bz := store.Get(types.GetQuorumCountKey(epoch)) if bz == nil { return 0, types.ErrQuorumNotFound } return sdk.BigEndianToUint64(bz), nil } func (k Keeper) SetQuorumCount(ctx sdk.Context, epoch uint64, quorums uint64) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.QuorumCountKeyPrefix) store.Set(types.GetQuorumCountKey(epoch), sdk.Uint64ToBigEndian(quorums)) } func (k Keeper) GetSigner(ctx sdk.Context, account string) (types.Signer, bool, error) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.SignerKeyPrefix) key, err := types.GetSignerKeyFromAccount(account) if err != nil { return types.Signer{}, false, err } bz := store.Get(key) if bz == nil { return types.Signer{}, false, nil } var signer types.Signer k.cdc.MustUnmarshal(bz, &signer) return signer, true, nil } func (k Keeper) SetSigner(ctx sdk.Context, signer types.Signer) error { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.SignerKeyPrefix) bz := k.cdc.MustMarshal(&signer) key, err := types.GetSignerKeyFromAccount(signer.Account) if err != nil { return err } store.Set(key, bz) ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeUpdateSigner, sdk.NewAttribute(types.AttributeKeySigner, signer.Account), sdk.NewAttribute(types.AttributeKeySocket, signer.Socket), sdk.NewAttribute(types.AttributeKeyPublicKeyG1, hex.EncodeToString(signer.PubkeyG1)), sdk.NewAttribute(types.AttributeKeyPublicKeyG2, hex.EncodeToString(signer.PubkeyG2)), ), ) return nil } // iterate through the signers set and perform the provided function func (k Keeper) IterateSigners(ctx sdk.Context, fn func(index int64, signer types.Signer) (stop bool)) { store := ctx.KVStore(k.storeKey) prefix := types.SignerKeyPrefix iterator := sdk.KVStorePrefixIterator(store, prefix) defer iterator.Close() i := int64(0) for ; iterator.Valid(); iterator.Next() { var signer types.Signer k.cdc.MustUnmarshal(iterator.Value(), &signer) stop := fn(i, signer) if stop { break } i++ } } func (k Keeper) GetEpochQuorum(ctx sdk.Context, epoch uint64, quorumId uint64) (types.Quorum, error) { quorumCount, err := k.GetQuorumCount(ctx, epoch) if err != nil { return types.Quorum{}, err } if quorumCount <= quorumId { return types.Quorum{}, types.ErrQuorumIdOutOfBound } store := prefix.NewStore(ctx.KVStore(k.storeKey), types.EpochQuorumsKeyPrefix) bz := store.Get(types.GetEpochQuorumKey(epoch, quorumId)) if bz == nil { return types.Quorum{}, types.ErrQuorumNotFound } var quorum types.Quorum k.cdc.MustUnmarshal(bz, &quorum) return quorum, nil } func (k Keeper) SetEpochQuorums(ctx sdk.Context, epoch uint64, quorums types.Quorums) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.EpochQuorumsKeyPrefix) for quorumId, quorum := range quorums.Quorums { bz := k.cdc.MustMarshal(quorum) store.Set(types.GetEpochQuorumKey(epoch, uint64(quorumId)), bz) } k.SetQuorumCount(ctx, epoch, uint64(len(quorums.Quorums))) } func (k Keeper) GetRegistration(ctx sdk.Context, epoch uint64, account string) ([]byte, bool, error) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.GetEpochRegistrationKeyPrefix(epoch)) key, err := types.GetRegistrationKey(account) if err != nil { return nil, false, err } signature := store.Get(key) if signature == nil { return nil, false, nil } return signature, true, nil } // iterate through the registrations set and perform the provided function func (k Keeper) IterateRegistrations(ctx sdk.Context, epoch uint64, fn func(account string, signature []byte) (stop bool)) { store := ctx.KVStore(k.storeKey) prefix := types.GetEpochRegistrationKeyPrefix(epoch) iterator := sdk.KVStorePrefixIterator(store, prefix) defer iterator.Close() i := int64(0) for ; iterator.Valid(); iterator.Next() { stop := fn(hex.EncodeToString((iterator.Key())[len(prefix):]), iterator.Value()) if stop { break } i++ } } func (k Keeper) SetRegistration(ctx sdk.Context, epoch uint64, account string, signature []byte) error { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.GetEpochRegistrationKeyPrefix(epoch)) key, err := types.GetRegistrationKey(account) if err != nil { return err } store.Set(key, signature) return nil } func (k Keeper) GetDelegatorBonded(ctx sdk.Context, delegator sdk.AccAddress) math.Int { bonded := sdk.ZeroDec() cnt := 0 k.stakingKeeper.IterateDelegatorDelegations(ctx, delegator, func(delegation stakingtypes.Delegation) bool { validatorAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress) if err != nil { panic(err) // shouldn't happen } validator, found := k.stakingKeeper.GetValidator(ctx, validatorAddr) if found { shares := delegation.Shares tokens := validator.TokensFromSharesTruncated(shares) bonded = bonded.Add(tokens) } cnt += 1 return cnt > 10 }) return bonded.RoundInt() } func (k Keeper) CheckDelegations(ctx sdk.Context, account string) error { accAddr, err := sdk.AccAddressFromHexUnsafe(account) if err != nil { return err } bonded := k.GetDelegatorBonded(ctx, accAddr) params := k.GetParams(ctx) tokensPerVote := sdk.NewIntFromUint64(params.TokensPerVote) if bonded.Quo(BondedConversionRate).Quo(tokensPerVote).Abs().BigInt().Cmp(big.NewInt(0)) <= 0 { return types.ErrInsufficientBonded } return nil }