Substrate中democracy模块分析

Substrate中democracy模块分析

民主模块,用来处理常规抵押投票的决议实施。

Conviction

pub enum Conviction {
    /// 不对币上锁,只等额0.1倍
    None,
    /// 对币锁一个实施周期(默认30天),等额1倍
    Locked1x,
    /// 对币锁两个实施周期(默认60天),等额2倍
    Locked2x,
    /// 对币锁四个实施周期(默认120天),等额3倍
    Locked3x,
    /// 对币锁八个实施周期(默认240天),等额4倍
    Locked4x,
    /// 对币锁十六个实施周期(默认480天),等额5倍
    Locked5x,
    /// 对币锁三十二个实施周期(默认960天),等额6倍
    Locked6x,
}

Trait

type Proposal: Parameter + Dispatchable;
type Event: From> + Into<::Event>;

/// Currency type for this module.
type Currency: ReservableCurrency
    + LockableCurrency;

/// 投票如果要锁定,最少的锁定周期,是一个提案被通过后到被执行中间的周期,默认30天
type EnactmentPeriod: Get;

/// 一个公共投票发起的周期,默认28天
type LaunchPeriod: Get;

/// 对一个提案投票统计的周期,默认28天
type VotingPeriod: Get;

/// 发起一个公共投票的最低存款,需要100个Token
type MinimumDeposit: Get>;

/// 直接大多数议会成员(大于1/2)同意能决定其下一个动议,下一个将摆上桌面的全民公投
type ExternalOrigin: EnsureOrigin;

/// 一个绝大多数议会成员(大于3/4)同意能直接调度一个全民公投
type ExternalMajorityOrigin: EnsureOrigin;

/// 一致通过的议会能调度一个全民公投,赞成>反对 即可通过
type ExternalDefaultOrigin: EnsureOrigin;

/// 2/3的技术委员会成员同意能发起一个 ExternalMajority/ExternalDefault投票,且能够立即摆上桌面进行公投,而且有一个更短的投票/实施周期
type FastTrackOrigin: EnsureOrigin;

/// 在快速通道和紧急全民公投情况下,最小投票周期
type EmergencyVotingPeriod: Get;

/// 在紧急情况下,任何全民公投都能够被取消,条件是2/3的议会成员同意
type CancellationOrigin: EnsureOrigin;

/// 任何技术委员会成员能够否决一个将要来临的议会提案,但是他们只能使用一次,在每个冷却周期过后
type VetoOrigin: EnsureOrigin;

/// 技术委员会成员的否决权使用一次后,需要的冷却时间
type CooloffPeriod: Get;

ReferedumInfo

/// 正在进行的全民公投相关信息
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct ReferendumInfo {
    /// 结束时间
    end: BlockNumber,
    /// 投票的提案
    proposal: Proposal,
    /// 全民公投通过的投票比例 
    threshold: VoteThreshold,
    /// 一个通过的全民公投执行需要等待的时间
    delay: BlockNumber,
}

Store

/// 公共提案数量
pub PublicPropCount get(fn public_prop_count) build(|_| 0 as PropIndex) : PropIndex;
/// 公共提案,未排序
pub PublicProps get(fn public_props): Vec<(PropIndex, T::Proposal, T::AccountId)>;
/// 公共提案锁仓的余额和所有账号
pub DepositOf get(fn deposit_of): map PropIndex => Option<(BalanceOf, Vec)>;

/// 全民公投的总数
pub ReferendumCount get(fn referendum_count) build(|_| 0 as ReferendumIndex): ReferendumIndex;
/// 下一个将被统计到的全民公投索引
pub NextTally get(fn next_tally) build(|_| 0 as ReferendumIndex): ReferendumIndex;
/// 全民公投的信息
pub ReferendumInfoOf get(fn referendum_info):
    map ReferendumIndex => Option<(ReferendumInfo)>;
/// 将被调遣的全民公投的队列
pub DispatchQueue get(fn dispatch_queue):
    map T::BlockNumber => Vec>;

/// 现在提案的所有投票账号
pub VotersFor get(fn voters_for): map ReferendumIndex => Vec;

/// 指定全民公投索引和账号,mapping的value是vote
pub VoteOf get(fn vote_of): map (ReferendumIndex, T::AccountId) => Vote;

/// 代理投票,value是资金持有账号,key是投票账号
pub Proxy get(fn proxy): map T::AccountId => Option;

/// 获取另一个正在委托投票的帐户(和锁定期)
pub Delegations get(fn delegations): linked_map T::AccountId => (T::AccountId, Conviction);

/// 如果上次提交的公投是外部提交的,那返回True。如果是公开提案,就返回False
pub LastTabledWasExternal: bool;

/// 公民投票将在任何可能提出外部建议的情况下进行。这种情况发生在需要举行公投,并且满足以下两个条件之一时:
/// - `LastTabledWasExternal` is `false`; or
/// - `PublicProps` is empty.
pub NextExternal: Option<(T::Proposal, VoteThreshold)>;

/// 投票的记录,Maps,value是Proposal的Hash,value是区块高度和该提案所有的投票
pub Blacklist get(fn blacklist): map T::Hash => Option<(T::BlockNumber, Vec)>;

/// 所有被紧急取消的提案
pub Cancellations: map T::Hash => bool;

Event

Proposed(PropIndex, Balance),       // 提案发起 
Tabled(PropIndex, Balance, Vec), // 提案被摆上桌面
ExternalTabled,                         // 外部提交提案上桌面
Started(ReferendumIndex, VoteThreshold), // 全民公投开始
Passed(ReferendumIndex),                // 全民公投通过
NotPassed(ReferendumIndex),         // 全民公投没通过
Cancelled(ReferendumIndex),         // 全民公投取消
Executed(ReferendumIndex, bool),        // 全民公投被执行
Delegated(AccountId, AccountId),        // 某账号被代理了
Undelegated(AccountId),                 // 某账号取消代理
Vetoed(AccountId, Hash, BlockNumber), // 某个账号某个公投被投票

Module

  • fn propose(origin,proposal: Box,#[compact] value: BalanceOf)
    • 发起一个提案,提案人需要保留一定资金,这部分资金涉及惩罚?如何不再保留?
      • >::append_or_put(&[Ref::from(&new_prop)][..]);
        • append_or_put()方法,插入数据到Vec
  • fn second(origin, #[compact] proposal: PropIndex)
    • 对某个提案复议,同样增加自己的保留
  • fn vote(origin,#[compact] ref_index: ReferendumIndex,vote: Vote)
    • 对全民公投进行投票
  • fn proxy_vote(origin,#[compact] ref_index: ReferendumIndex,vote: Vote)
    • 代理人投票
  • fn emergency_cancel(origin, ref_index: ReferendumIndex)
    • 紧急取消全民公投
  • fn external_propose(origin, proposal: Box)
    • 将一个提案摆上桌面进入全民公投阶段,提案需要过了blacklisting的时间
  • fn external_propose_majority(origin, proposal: Box)
    • 将一个提案摆上桌面,进入全民公投阶段,需要大多数同意才能通过,不受blacklisting影响
  • fn external_propose_default(origin, proposal: Box)
    • 将一个提案摆上桌面,进入全民公投阶段,反对通过需要绝大多数,不受blacklisting影响
  • fn fast_track(origin,proposal_hash: T::Hash,voting_period: T::BlockNumber,delay: T::BlockNumber)
    • 快速通道将一个提案直接全民公投
  • fn veto_external(origin, proposal_hash: T::Hash)
    • 反对和黑名单某个外部提案
  • fn cancel_referendum(origin, #[compact] ref_index: ReferendumIndex)
    • Root取消某个公投
  • fn cancel_queued(origin,#[compact] when: T::BlockNumber,#[compact] which: u32,#[compact] what: ReferendumIndex)
    • Root取消某个在队列中的将要执行到提案
  • fn on_initialize(n: T::BlockNumber)
    • Self::end_block(n)
  • fn set_proxy(origin, proxy: T::AccountId)
    • 指定某个代理,stash账号调用
  • fn resign_proxy(origin)
    • 清除代理,代理账号调用
  • fn remove_proxy(origin, proxy: T::AccountId)
    • 移除代理,stash账号调用
  • pub fn delegate(origin, to: T::AccountId, conviction: Conviction)
    • 指定代理,并且最大幅度锁定资产
  • fn undelegate(origin)
    • 取消代理,资产锁定时间确定为EnactmentPeriod + conviction.lock_periods()
  • pub fn locked_for(proposal: PropIndex) -> Option>
    • 锁定资产投票给某个提案
  • pub fn is_active_referendum(ref_index: ReferendumIndex) -> bool
    • 判断某个公投是否正在进行中
  • pub fn active_referenda() -> Vec<(ReferendumIndex, ReferendumInfo)>
    • 现在活跃的所有普通投票
  • pub fn maturing_referenda_at(n: T::BlockNumber) -> Vec<(ReferendumIndex, ReferendumInfo)>
    • 在某个区块高度,准备进行计票统计的公投
  • pub fn tally(ref_index: ReferendumIndex) -> (BalanceOf, BalanceOf, BalanceOf)
    • 公投计票统计
  • fn tally_delegation(ref_index: ReferendumIndex) -> (BalanceOf, BalanceOf, BalanceOf)
    • 代理投票计票统计
  • fn delegated_votes(ref_index: ReferendumIndex,to: T::AccountId,parent_conviction: Conviction,recursion_limit: u32,) -> (BalanceOf, BalanceOf)
    • 代理投票计票统计
  • pub fn force_proxy(stash: T::AccountId, proxy: T::AccountId)
    • 代理人设置
  • pub fn internal_start_referendum(proposal: T::Proposal,threshold: VoteThreshold,delay: T::BlockNumber) -> result::Result
    • 开启一个公投
  • pub fn internal_cancel_referendum(ref_index: ReferendumIndex)
    • 取消一个公投
  • fn do_vote(who: T::AccountId, ref_index: ReferendumIndex, vote: Vote) -> Result
    • 给一个公投投票
  • fn inject_referendum(end: T::BlockNumber,proposal: T::Proposal,threshold: VoteThreshold,delay: T::BlockNumber,) -> result::Result
    • 开启一个公投
  • fn clear_referendum(ref_index: ReferendumIndex)
    • 移除一个公投的所有信息
  • fn enact_proposal(proposal: T::Proposal, index: ReferendumIndex)
    • 执行一个公投的提案,在end_block()方法中,如果到执行,就执行提案
  • fn launch_next(now: T::BlockNumber) -> Result
    • 将正在等待的下一个提案摆上桌面进行公投
  • fn launch_external(now: T::BlockNumber) -> Result
    • 将正在等待的下一个外部提案摆上桌面进行公投
  • fn launch_public(now: T::BlockNumber) -> Result
    • 将正在等待的下一个公共提案,下一个就是最高支持率的公共提案,将其摆上桌面进行公投
  • fn bake_referendum(now: T::BlockNumber,index: ReferendumIndex,info: ReferendumInfo) -> Result
    • 点票统计,通过公投的进入执行队列,该锁定的执行周期进行锁定
  • fn end_block(now: T::BlockNumber) -> Result
    • 现在的era结束了,应该完成任何提案

下一个公投是external需要满足下面两个中任何一个:

  1. LastTabledWasExternal 是 false;
  2. PublicProps 是空。

也就是说下一个公投要是external proposal,要么是上一个公投不是external proposal,要么没有public proposal。

群众发起的提案是public proposal,技术委员会成员快速通道发起的是external proposal,但是快速通道不能连续,除非没有公共提案。

提案执行逻辑

collective模块中,执行调用的必须是议会成员:

#[weight = SimpleDispatchInfo::FixedOperational(100_000)]
fn execute(origin, proposal: Box<>::Proposal>) {
    let who = ensure_signed(origin)?;
    ensure!(Self::is_member(&who), "proposer not a member");

    let proposal_hash = T::Hashing::hash_of(&proposal);
    let ok = proposal.dispatch(RawOrigin::Member(who).into()).is_ok();
    Self::deposit_event(RawEvent::MemberExecuted(proposal_hash, ok));
}

在support模块的dispatch.rs中,定义了dispatch这个方法:

fn dispatch(self, _origin: Self::Origin) -> $crate::dispatch::DispatchResult {
        match self {
            $(
                $call_type::$fn_name( $( $param_name ),* ) => {
                    $crate::decl_module!(
                        @call
                        $from
                        $mod_type<$trait_instance $(, $fn_instance)?> $fn_name _origin $system [ $( $param_name ),* ]
                    )
                },
            )*
            $call_type::__PhantomItem(_, _) => { unreachable!("__PhantomItem should never be used.") },
        }
    }

你可能感兴趣的:(Substrate中democracy模块分析)