You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cosmos SDK governance模块定制指导:自定义投票权重计算逻辑

定制Cosmos SDK Governance模块:混合投票权重实现指南

一、前置准备

  • 确保本地安装Go 1.20+(对应Cosmos SDK v0.47.x版本,可根据你使用的SDK版本调整)
  • 基于Starport或Cosmos SDK模板初始化链项目,示例:
    starport init mychain --cosmos-sdk-version v0.47.5
    
  • 熟悉x/gov和x/staking模块的核心逻辑,尤其是默认投票权重的计算流程

二、原有投票权重逻辑梳理

Cosmos SDK默认治理投票权重直接绑定用户的质押金额,核心入口在x/gov/keeper/vote.go的AddVote方法中,通过调用stakingKeeper.GetDelegatorTotalVotePower获取用户总质押权重。我们需要在这个基础上,注入质押时长的权重占比逻辑。

三、核心实现步骤

1. 添加可配置权重比例参数(推荐)

为了让权重比例支持链上治理调整,在x/gov模块中新增参数配置:

  • 修改x/gov/types/params.proto,添加字段:
    message Params {
      // ... 原有字段保留
      string deposit_weight_ratio = 10;    // 存款权重占比,默认"0.8"
      string staking_duration_weight_ratio = 11; // 质押时长权重占比,默认"0.2"
    }
    
  • 运行代码生成命令更新Go代码:
    make proto-gen
    
  • 在x/gov/types/params.go中设置默认值:
    func DefaultParams() Params {
      return Params{
        // ... 原有默认值保留
        DepositWeightRatio:          sdk.MustNewDecFromStr("0.8"),
        StakingDurationWeightRatio:  sdk.MustNewDecFromStr("0.2"),
      }
    }
    

2. 实现质押时长权重计算

从x/staking模块获取用户委托信息,计算加权平均质押时长并转换为权重:

  • 在x/gov/keeper/keeper.go中,确保Keeper持有staking.Keeper引用(项目默认已包含)
  • 添加加权平均时长计算方法:
    // CalculateWeightedStakingDuration 计算用户有效委托的加权平均质押时长(秒)
    func (k Keeper) CalculateWeightedStakingDuration(ctx sdk.Context, delegator sdk.AccAddress) (sdk.Dec, error) {
      totalDuration := sdk.ZeroDec()
      totalStaked := sdk.ZeroInt()
    
      // 遍历用户所有有效委托
      delegations := k.stakingKeeper.GetDelegatorDelegations(ctx, delegator, math.MaxUint16)
      for _, del := range delegations {
        // 跳过解绑中的委托
        if k.stakingKeeper.HasUnbondingDelegation(ctx, delegator, del.GetValidatorAddr()) {
          continue
        }
    
        // 计算单份委托的时长(当前区块时间 - 委托创建时间)
        creationTime := del.GetCreationTime()
        duration := ctx.BlockTime().Sub(creationTime).Seconds()
        
        // 加权累加:委托金额 * 时长
        delAmount := sdk.NewDecFromInt(del.GetShares().TruncateInt())
        totalDuration = totalDuration.Add(delAmount.Mul(sdk.NewDec(duration)))
        totalStaked = totalStaked.Add(del.GetShares().TruncateInt())
      }
    
      if totalStaked.IsZero() {
        return sdk.ZeroDec(), nil
      }
    
      // 返回加权平均时长
      return totalDuration.Quo(sdk.NewDecFromInt(totalStaked)), nil
    }
    
  • 将时长转换为可与质押金额匹配的权重(示例:按年归一化):
    // CalculateStakingDurationWeight 将加权平均时长转换为权重值
    func (k Keeper) CalculateStakingDurationWeight(ctx sdk.Context, delegator sdk.AccAddress) (sdk.Dec, error) {
      avgDuration, err := k.CalculateWeightedStakingDuration(ctx, delegator)
      if err != nil {
        return sdk.ZeroDec(), err
      }
    
      // 归一化:时长转年,最大权重倍数限制为1(质押满1年以上按1倍计算)
      years := avgDuration.Quo(sdk.NewDec(365 * 24 * 3600))
      if years.GT(sdk.OneDec()) {
        years = sdk.OneDec()
      }
    
      // 时长权重 = 总质押金额 * 归一化倍数
      totalStaked := sdk.NewDecFromInt(k.stakingKeeper.GetDelegatorTotalVotePower(ctx, delegator))
      return totalStaked.Mul(years), nil
    }
    

3. 实现混合投票权重计算

修改x/gov/keeper/vote.go中的权重获取逻辑:

func (k Keeper) AddVote(ctx sdk.Context, proposalID uint64, vote types.Vote) error {
  // ... 原有校验逻辑保留

  // 计算混合投票权重
  params := k.GetParams(ctx)
  depositWeight := sdk.NewDecFromInt(k.stakingKeeper.GetDelegatorTotalVotePower(ctx, vote.Voter))
  durationWeight, err := k.CalculateStakingDurationWeight(ctx, vote.Voter)
  if err != nil {
    return err
  }

  mixedVotePower := depositWeight.Mul(params.DepositWeightRatio).Add(durationWeight.Mul(params.StakingDurationWeightRatio))
  votePower := mixedVotePower.TruncateInt() // 转换为整数权重(根据链精度调整)

  // ... 后续投票存储逻辑,使用votePower替代原有默认权重
}

4. 同步修改计票逻辑

在x/gov/keeper/tally.go的Tally方法中,确保遍历投票时使用新的混合权重统计结果,替换原有的质押权重统计逻辑。

四、测试验证

1. 单元测试

编写测试用例覆盖核心场景:

  • 单用户质押100Token,质押30天,验证混合权重是否符合100*0.8 + (100*(30/365))*0.2
  • 多委托、不同时长场景,验证加权平均时长计算正确性
  • 修改权重比例参数,验证权重计算同步变化

2. 本地链测试

  • 编译链:make install
  • 启动节点:mychaind start
  • 创建测试账户并质押:
    mychaind tx staking delegate <validator-addr> 1000000mycoin --from alice
    
  • 创建治理提案并投票:
    mychaind tx gov submit-proposal text-proposal --title "Test Mixed Vote" --description "Verify mixed vote power" --deposit 1000000mycoin --from alice
    mychaind tx gov vote 1 yes --from alice
    
  • 查询提案结果:mychaind query gov proposal 1,验证投票权重是否符合预期

五、注意事项

  • 质押时长逻辑可按需调整(如非线性权重、阶梯式权重)
  • 需处理 redelegation、解绑中委托的情况,确保仅统计有效质押时长
  • 注意委托遍历的性能,避免大量委托场景下的节点卡顿
  • 使用Cosmos SDK的Dec类型处理浮点运算,避免精度误差

内容的提问来源于stack exchange,提问作者Eric0123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 17:52:34