治理

概述

PoA 模块与 Cosmos SDK 治理集成,将参与权限限制为仅授权验证者。与使用质押代币作为投票权重的标准治理不同,PoA 治理以验证者权重作为投票基础。

仅限验证者的治理

PoA 模块通过治理钩子将治理参与限制为仅授权验证者。 治理钩子 (x/poa/keeper/hooks.go) 该模块实现了 govtypes.GovHooks:
  1. AfterProposalSubmission:只有授权验证者可以提交提案
  2. AfterProposalDeposit:只有授权验证者可以为提案存入押金
  3. AfterProposalVote:只有授权验证者可以投票
授权验证者定义:
  • 在 PoA 模块中已注册
  • Power > 0
  • 拥有有效的 operator address
被拒绝的操作:
  • 如果非验证者尝试执行治理操作 → 交易失败
  • 如果验证者的 power = 0 → 交易失败
  • 错误:“voter X is not an active PoA validator”
位置:x/poa/keeper/governance.go:92

投票权重

自定义计票 (x/poa/keeper/governance.go:18)。可在 SimApp 中查看接线示例。 标准治理使用质押代币作为投票权重。PoA 治理使用验证者权重:
  1. 收集投票:系统遍历某个提案上的全部投票
  2. 验证者检查:对每一票,验证投票者是否为活跃的 PoA 验证者
  3. 权重计算:使用验证者的 power 作为投票权重
  4. 加权选项:支持拆分投票,与传统 POS 治理中的 x/staking 完全一致(例如 70% Yes,30% Abstain)
  5. 汇总结果:按选项累加加权投票结果

计票算法

投票权重公式: Vi=PiV_i = P_i 其中:
  • ViV_i = 验证者 ii 的投票权重
  • PiP_i = 验证者权重(共识权重)
加权投票计算: 对于一个将投票拆分到多个选项的验证者: Wi,o=Vi×wi,oW_{i,o} = V_i \times w_{i,o} 其中:
  • Wi,oW_{i,o} = 验证者 ii 对选项 oo 的投票权重
  • wi,ow_{i,o} = 验证者 ii 分配给选项 oo 的权重(其中 ∑owi,o=1\sum_{o} w_{i,o} = 1)
各选项总计票: To=∑i∈votersWi,oT_o = \sum_{i \in voters} W_{i,o} 其中:
  • ToT_o = 选项 oo 的总票数
  • 对所有已投票的验证者求和

示例

验证者 A:PA=100P_A = 100,100% 投 Yes
  • WA,Yes=100×1.0=100W_{A,Yes} = 100 \times 1.0 = 100
验证者 B:PB=50P_B = 50,60% 投 Yes,40% 投 No
  • WB,Yes=50×0.6=30W_{B,Yes} = 50 \times 0.6 = 30
  • WB,No=50×0.4=20W_{B,No} = 50 \times 0.4 = 20
总计:
  • TYes=130T_{Yes} = 130
  • TNo=20T_{No} = 20

提案生命周期

1. 提案提交

MsgSubmitProposal(标准 x/gov 模块) 当提案被提交时:
  1. 标准治理先校验提案内容
  2. 调用 AfterProposalSubmission 钩子
  3. PoA 模块检查提案提交者是否为授权验证者:
    • 通过 operator address 查找提案提交者
    • 验证该验证者存在且满足 P>0P > 0
    • 如果不是活跃验证者,则返回错误并拒绝
  4. 如果校验通过,提案进入押金期
限制:只有授权验证者可以提交提案,从而防止非共识参与者发起垃圾提案。

2. 押金期

MsgDeposit(标准 x/gov 模块) 当有押金存入时:
  1. 标准治理处理该押金
  2. 调用 AfterProposalDeposit 钩子
  3. PoA 模块检查存入者是否为授权验证者
  4. 如果达到押金门槛,提案进入投票期
限制:只有授权验证者可以存入押金,确保只有共识参与者能够推动提案进入下一阶段。

3. 投票期

MsgVote 或 MsgVoteWeighted(标准 x/gov 模块) 当投票被提交时:
  1. 标准治理记录该投票
  2. 调用 AfterProposalVote 钩子
  3. PoA 模块校验投票者是否为授权验证者
  4. 如果校验失败,交易失败
投票选项:
  • Yes:支持提案
  • No:反对提案
  • NoWithVeto:反对并否决(若达到阈值可销毁押金)
  • Abstain:参与法定人数统计但不表达立场
加权投票:验证者可以将投票拆分到多个选项,且各权重之和为 1。

4. 计票

在投票期结束时,会调用自定义计票函数: NewPoACalculateVoteResultsAndVotingPowerFn (x/poa/keeper/governance.go:18)
  1. 遍历提案上的全部投票
  2. 对每一票,根据投票者地址查找对应验证者
  3. 如果验证者不是活跃状态(P≤0P \leq 0),则跳过该票
  4. 否则,使用验证者权重作为投票权重
  5. 对于加权投票,将权重分配到各个选项
  6. 按选项汇总所有加权投票
  7. 应用标准治理阈值:
    • Quorum:最低参与比例
    • Threshold:提案通过所需的最低 Yes 比例
    • Veto:触发否决前允许的最高 NoWithVeto 比例
结果:提案将基于按权重计票的结果被判定为通过、失败或被否决。

实现细节

治理钩子

位置:x/poa/keeper/hooks.go 该模块实现了 govtypes.GovHooks 接口:
type GovHooks interface {
    AfterProposalSubmission(ctx, proposalID, depositorAddr)
    AfterProposalDeposit(ctx, proposalID, depositorAddr)
    AfterProposalVote(ctx, proposalID, voterAddr)
    // ... other hooks
}
每个钩子实现都会:
  1. 从上下文中提取 operator address
  2. 通过 operator address 查找验证者
  3. 检查验证者是否存在且 power > 0
  4. 如果校验失败则返回错误

自定义计票函数

位置:x/poa/keeper/governance.go:18 该计票函数替换了标准治理计票逻辑:
func NewPoACalculateVoteResultsAndVotingPowerFn(keeper) TallyFn {
    return func(ctx, proposal) (totalVotingPower, results) {
        // Iterate votes
        for vote in votes(proposal) {
            validator = keeper.GetValidatorByOperator(vote.voter)
            if validator == nil || validator.Power <= 0 {
                continue // Skip non-authorized validators
            }

            // Add validator power to total
            totalVotingPower += validator.Power

            // Apply vote weights
            for option, weight in vote.options {
                results[option] += validator.Power * weight
            }
        }
        return totalVotingPower, results
    }
}

治理参数

标准治理模块的参数仍然适用:
  • MinDeposit:进入投票期所需的最小代币押金
  • MaxDepositPeriod:达到最小押金要求的时间上限
  • VotingPeriod:投票期时长
  • Quorum:最低参与率(占总权重的比例)
  • Threshold:提案通过所需的最低 Yes 比例(占非弃权票的比例)
  • VetoThreshold:触发拒绝前允许的最高 NoWithVeto 比例
关键区别:Quorum 是按验证者总权重的百分比计算,而不是按已绑定质押代币总量计算。

安全性考量

  1. 验证者排他性:
    • 只有授权验证者(power > 0)可以参与
    • 防止未授权验证者通过垃圾注册发起女巫攻击
    • 确保治理真实代表共识参与者
  2. 基于权重的投票:
    • 投票权重与共识权重绑定
    • 管理员控制权重分配,因此也会间接控制治理
  3. 管理员对治理的控制:
    • 管理员可以随时修改验证者权重
    • 管理员可以通过调整权重有效控制治理结果
    • 应考虑使用多签管理员,或由治理来控制管理员变更
  4. 防止提案垃圾信息:
    • 将提案提交限制为授权验证者可减少垃圾提案
    • 押金要求仍然适用
    • 验证者对提案质量承担声誉风险

与标准治理的对比

方面标准 Cosmos 治理PoA 治理
谁可以投票代币持有者(委托人 + 验证者)仅授权验证者
投票权重已绑定质押代币验证者权重
谁可以提案任何满足最小押金要求的人仅授权验证者
谁可以存入押金任何人仅授权验证者
计票方式已绑定质押代币总和验证者权重总和
Quorum 计算已绑定质押代币的百分比验证者总权重的百分比
管理员控制无直接控制管理员控制权重 → 控制投票

治理流程示例

场景:验证者 A 希望提出一个参数变更提案
  1. 提交提案:
    • 验证者 A(power = 40)提交 MsgSubmitProposal
    • 钩子验证 A 是授权验证者
    • 提案进入押金期
  2. 达到押金门槛:
    • 验证者 B(power = 30)存入押金
    • 验证者 C(power = 30)存入押金
    • 达到押金门槛 → 投票期开始
  3. 投票:
    • 验证者 A:100% Yes(40 power → 40 张 Yes 票)
    • 验证者 B:60% Yes,40% No(30 power → 18 张 Yes,12 张 No)
    • 验证者 C:100% Abstain(30 power → 30 张 Abstain)
    • 总权重:100(全部授权验证者)
  4. 计票:
    • 总投票权重:100(全部已投票)
    • Quorum:100/100 = 100% ✓(假设 Quorum 为 33%)
    • 结果:58 Yes,12 No,30 Abstain(非弃权票共 70)
    • Threshold:58/70 = 82.9% Yes ✓(假设 Threshold 为 50%)
    • 提案通过

Governance

Overview

The PoA module integrates with Cosmos SDK governance to restrict participation to authorized validators only. Unlike standard governance that uses bonded tokens for voting weight, PoA governance uses validator power as the basis for voting.

Validator-Only Governance

The PoA module restricts governance participation to authorized validators only through governance hooks. Governance Hooks (x/poa/keeper/hooks.go) The module implements govtypes.GovHooks:
  1. AfterProposalSubmission: Only authorized validators can submit proposals
  2. AfterProposalDeposit: Only authorized validators can deposit on proposals
  3. AfterProposalVote: Only authorized validators can vote
Authorized Validator Definition:
  • Registered in PoA module
  • Power > 0
  • Has valid operator address
Rejected Actions:
  • If non-validator attempts governance action → transaction fails
  • If validator has power = 0 → transaction fails
  • Error: “voter X is not an active PoA validator”
Location: x/poa/keeper/governance.go:92

Voting Power

Custom Vote Tallying (x/poa/keeper/governance.go:18). An example of the wiring can be found in the SimApp. Standard governance uses staked tokens as voting weight. PoA governance uses validator power:
  1. Vote Collection: System iterates all votes on a proposal
  2. Validator Check: For each vote, verify voter is active PoA validator
  3. Weight Calculation: Use validator’s power as voting weight
  4. Weighted Options: Supports split votes, exactly like x/staking in traditional POS governance (e.g., 70% Yes, 30% Abstain)
  5. Tally Results: Sum weighted votes by option

Vote Tallying Algorithm

Voting Power Formula: Vi=PiV_i = P_i Where:
  • ViV_i = voting power of validator ii
  • PiP_i = validator power (consensus weight)
Weighted Vote Calculation: For a validator casting a split vote across multiple options: Wi,o=Vi×wi,oW_{i,o} = V_i \times w_{i,o} Where:
  • Wi,oW_{i,o} = vote weight from validator ii for option oo
  • wi,ow_{i,o} = weight assigned to option oo by validator ii (where ∑owi,o=1\sum_{o} w_{i,o} = 1)
Total Tally per Option: To=∑i∈votersWi,oT_o = \sum_{i \in voters} W_{i,o} Where:
  • ToT_o = total votes for option oo
  • Sum over all validators who voted

Example

Validator A: PA=100P_A = 100, votes 100% Yes
  • WA,Yes=100×1.0=100W_{A,Yes} = 100 \times 1.0 = 100
Validator B: PB=50P_B = 50, votes 60% Yes, 40% No
  • WB,Yes=50×0.6=30W_{B,Yes} = 50 \times 0.6 = 30
  • WB,No=50×0.4=20W_{B,No} = 50 \times 0.4 = 20
Totals:
  • TYes=130T_{Yes} = 130
  • TNo=20T_{No} = 20

Proposal Lifecycle

1. Proposal Submission

MsgSubmitProposal (standard x/gov module) When a proposal is submitted:
  1. Standard governance validates the proposal content
  2. AfterProposalSubmission hook is called
  3. PoA module checks if proposer is authorized validator:
    • Look up proposer by operator address
    • Verify validator exists and has P>0P > 0
    • If not active, reject with error
  4. If valid, proposal enters deposit period
Restriction: Only authorized validators can submit proposals, preventing spam from non-consensus participants.

2. Deposit Period

MsgDeposit (standard x/gov module) When a deposit is made:
  1. Standard governance processes the deposit
  2. AfterProposalDeposit hook is called
  3. PoA module checks if depositor is authorized validator
  4. If deposit threshold reached, proposal moves to voting period
Restriction: Only authorized validators can deposit, ensuring only consensus participants can advance proposals.

3. Voting Period

MsgVote or MsgVoteWeighted (standard x/gov module) When a vote is cast:
  1. Standard governance records the vote
  2. AfterProposalVote hook is called
  3. PoA module validates voter is authorized validator
  4. If invalid, transaction fails
Vote Options:
  • Yes: Support the proposal
  • No: Oppose the proposal
  • NoWithVeto: Oppose and veto (can burn deposits if threshold met)
  • Abstain: Participate in quorum without taking a position
Weighted Voting: Validators can split their vote across multiple options, with weights summing to 1.

4. Vote Tallying

At the end of the voting period, the custom tally function is called: NewPoACalculateVoteResultsAndVotingPowerFn (x/poa/keeper/governance.go:18)
  1. Iterate all votes on the proposal
  2. For each vote, look up the validator by voter address
  3. If validator is not active (P≤0P \leq 0), skip the vote
  4. Otherwise, use validator power as voting weight
  5. For weighted votes, distribute power across options
  6. Sum all weighted votes by option
  7. Apply standard governance thresholds:
    • Quorum: Minimum participation percentage
    • Threshold: Minimum “Yes” percentage to pass
    • Veto: Maximum “NoWithVeto” percentage before rejection
Result: Proposal passes, fails, or is vetoed based on power-weighted votes.

Implementation Details

Governance Hooks

Location: x/poa/keeper/hooks.go The module implements the govtypes.GovHooks interface:
type GovHooks interface {
    AfterProposalSubmission(ctx, proposalID, depositorAddr)
    AfterProposalDeposit(ctx, proposalID, depositorAddr)
    AfterProposalVote(ctx, proposalID, voterAddr)
    // ... other hooks
}
Each hook implementation:
  1. Extracts the operator address from the context
  2. Looks up the validator by operator address
  3. Checks if validator exists and has power > 0
  4. Returns error if validation fails

Custom Tally Function

Location: x/poa/keeper/governance.go:18 The tally function replaces the standard governance tally:
func NewPoACalculateVoteResultsAndVotingPowerFn(keeper) TallyFn {
    return func(ctx, proposal) (totalVotingPower, results) {
        // Iterate votes
        for vote in votes(proposal) {
            validator = keeper.GetValidatorByOperator(vote.voter)
            if validator == nil || validator.Power <= 0 {
                continue // Skip non-authorized validators
            }

            // Add validator power to total
            totalVotingPower += validator.Power

            // Apply vote weights
            for option, weight in vote.options {
                results[option] += validator.Power * weight
            }
        }
        return totalVotingPower, results
    }
}

Governance Parameters

The standard governance module parameters still apply:
  • MinDeposit: Minimum tokens required to enter voting period
  • MaxDepositPeriod: Time limit for reaching minimum deposit
  • VotingPeriod: Duration of the voting period
  • Quorum: Minimum participation rate (fraction of total power)
  • Threshold: Minimum “Yes” rate to pass (fraction of non-abstain votes)
  • VetoThreshold: Maximum “NoWithVeto” rate before rejection
Key Difference: Quorum is calculated as a percentage of total validator power, not total bonded tokens.

Security Considerations

  1. Validator Exclusivity:
    • Only authorized validators (power > 0) can participate
    • Prevents sybil attacks through unauthorized validator spam
    • Ensures governance represents actual consensus participants
  2. Power-Based Voting:
    • Voting weight tied to consensus power
    • Admin controls power distribution, thus controls governance indirectly
  3. Admin Governance Control:
    • Admin can change validator power at any time
    • Admin can effectively control governance by adjusting power
    • Consider multi-sig admin or governance-controlled admin changes
  4. Proposal Spam Prevention:
    • Restricting submissions to authorized validators reduces spam
    • Deposit requirements still apply
    • Validators have reputational stake in proposal quality

Comparison to Standard Governance

AspectStandard Cosmos GovernancePoA Governance
Who can voteToken holders (delegators + validators)Authorized validators only
Voting weightBonded tokensValidator power
Who can proposeAnyone with min depositAuthorized validators only
Who can depositAnyoneAuthorized validators only
Vote tallyingSum of bonded tokensSum of validator power
Quorum calculation% of bonded tokens% of total validator power
Admin controlNo direct controlAdmin controls power → controls votes

Example Governance Flow

Scenario: Validator A wants to propose a parameter change
  1. Submit Proposal:
    • Validator A (power = 40) submits MsgSubmitProposal
    • Hook verifies A is authorized validator
    • Proposal enters deposit period
  2. Reach Deposit:
    • Validator B (power = 30) deposits
    • Validator C (power = 30) deposits
    • Deposit threshold reached → voting period starts
  3. Voting:
    • Validator A: 100% Yes (40 power → 40 Yes votes)
    • Validator B: 60% Yes, 40% No (30 power → 18 Yes, 12 No)
    • Validator C: 100% Abstain (30 power → 30 Abstain)
    • Total power: 100 (all authorized validators)
  4. Tally:
    • Total voting power: 100 (all voted)
    • Quorum: 100/100 = 100% ✓ (assuming 33% quorum)
    • Results: 58 Yes, 12 No, 30 Abstain (out of 70 non-abstain)
    • Threshold: 58/70 = 82.9% Yes ✓ (assuming 50% threshold)
    • Proposal passes