2024-05-09 18:54:47 +00:00
|
|
|
package keeper
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/hex"
|
2024-09-24 01:39:16 +00:00
|
|
|
"fmt"
|
2024-06-07 07:47:56 +00:00
|
|
|
"math/big"
|
2024-05-09 18:54:47 +00:00
|
|
|
|
2024-06-07 07:47:56 +00:00
|
|
|
"cosmossdk.io/math"
|
2024-08-02 10:34:24 +00:00
|
|
|
"github.com/cometbft/cometbft/libs/log"
|
2024-05-09 18:54:47 +00:00
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
|
|
"github.com/cosmos/cosmos-sdk/store/prefix"
|
2024-09-24 01:39:16 +00:00
|
|
|
|
2024-05-09 18:54:47 +00:00
|
|
|
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
2024-09-24 01:39:16 +00:00
|
|
|
|
2024-05-09 18:54:47 +00:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
|
2024-06-11 07:20:30 +00:00
|
|
|
"github.com/0glabs/0g-chain/chaincfg"
|
2024-05-09 18:54:47 +00:00
|
|
|
"github.com/0glabs/0g-chain/x/dasigners/v1/types"
|
2024-09-24 01:39:16 +00:00
|
|
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
2024-05-09 18:54:47 +00:00
|
|
|
)
|
|
|
|
|
2024-06-11 07:20:30 +00:00
|
|
|
var BondedConversionRate = math.NewIntFromBigInt(big.NewInt(0).Exp(big.NewInt(10), big.NewInt(chaincfg.GasDenomUnit), nil))
|
|
|
|
|
2024-05-09 18:54:47 +00:00
|
|
|
type Keeper struct {
|
|
|
|
storeKey storetypes.StoreKey
|
|
|
|
cdc codec.BinaryCodec
|
|
|
|
stakingKeeper types.StakingKeeper
|
2024-09-24 01:39:16 +00:00
|
|
|
authority string // the address capable of changing signers params. Should be the gov module account
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewKeeper creates a new das Keeper instance
|
|
|
|
func NewKeeper(
|
|
|
|
storeKey storetypes.StoreKey,
|
|
|
|
cdc codec.BinaryCodec,
|
|
|
|
stakingKeeper types.StakingKeeper,
|
2024-09-24 01:39:16 +00:00
|
|
|
authority string,
|
2024-05-09 18:54:47 +00:00
|
|
|
) Keeper {
|
|
|
|
return Keeper{
|
|
|
|
storeKey: storeKey,
|
|
|
|
cdc: cdc,
|
|
|
|
stakingKeeper: stakingKeeper,
|
2024-09-24 01:39:16 +00:00
|
|
|
authority: authority,
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
2024-09-24 01:39:16 +00:00
|
|
|
|
|
|
|
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)),
|
|
|
|
),
|
|
|
|
)
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2024-05-16 14:49:29 +00:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2024-05-09 18:54:47 +00:00
|
|
|
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)
|
|
|
|
|
2024-05-10 18:41:14 +00:00
|
|
|
prefix := types.SignerKeyPrefix
|
|
|
|
iterator := sdk.KVStorePrefixIterator(store, prefix)
|
2024-05-09 18:54:47 +00:00
|
|
|
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++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-14 10:29:01 +00:00
|
|
|
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
|
|
|
|
}
|
2024-05-16 14:49:29 +00:00
|
|
|
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.EpochQuorumsKeyPrefix)
|
2024-06-14 10:29:01 +00:00
|
|
|
bz := store.Get(types.GetEpochQuorumKey(epoch, quorumId))
|
2024-05-09 18:54:47 +00:00
|
|
|
if bz == nil {
|
2024-06-14 10:29:01 +00:00
|
|
|
return types.Quorum{}, types.ErrQuorumNotFound
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
2024-06-14 10:29:01 +00:00
|
|
|
var quorum types.Quorum
|
|
|
|
k.cdc.MustUnmarshal(bz, &quorum)
|
|
|
|
return quorum, nil
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
|
|
|
|
2024-05-16 14:49:29 +00:00
|
|
|
func (k Keeper) SetEpochQuorums(ctx sdk.Context, epoch uint64, quorums types.Quorums) {
|
|
|
|
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.EpochQuorumsKeyPrefix)
|
2024-06-14 10:29:01 +00:00
|
|
|
for quorumId, quorum := range quorums.Quorums {
|
|
|
|
bz := k.cdc.MustMarshal(quorum)
|
|
|
|
store.Set(types.GetEpochQuorumKey(epoch, uint64(quorumId)), bz)
|
|
|
|
}
|
2024-05-16 14:49:29 +00:00
|
|
|
k.SetQuorumCount(ctx, epoch, uint64(len(quorums.Quorums)))
|
2024-05-09 18:54:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
2024-05-10 18:41:14 +00:00
|
|
|
prefix := types.GetEpochRegistrationKeyPrefix(epoch)
|
|
|
|
iterator := sdk.KVStorePrefixIterator(store, prefix)
|
2024-05-09 18:54:47 +00:00
|
|
|
defer iterator.Close()
|
|
|
|
|
|
|
|
i := int64(0)
|
|
|
|
|
|
|
|
for ; iterator.Valid(); iterator.Next() {
|
2024-05-10 18:41:14 +00:00
|
|
|
stop := fn(hex.EncodeToString((iterator.Key())[len(prefix):]), iterator.Value())
|
2024-05-09 18:54:47 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2024-06-07 07:47:56 +00:00
|
|
|
|
|
|
|
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)
|
2024-06-11 07:20:30 +00:00
|
|
|
tokensPerVote := sdk.NewIntFromUint64(params.TokensPerVote)
|
|
|
|
if bonded.Quo(BondedConversionRate).Quo(tokensPerVote).Abs().BigInt().Cmp(big.NewInt(0)) <= 0 {
|
2024-06-07 07:47:56 +00:00
|
|
|
return types.ErrInsufficientBonded
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|