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<Origin=Self::Origin>;
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
/// Currency type for this module.
type Currency: ReservableCurrency<Self::AccountId>
+ LockableCurrency<Self::AccountId, Moment=Self::BlockNumber>;
/// 投票如果要锁定,最少的锁定周期,是一个提案被通过后到被执行中间的周期,默认30天
type EnactmentPeriod: Get<Self::BlockNumber>;
/// 一个公共投票发起的周期,默认28天
type LaunchPeriod: Get<Self::BlockNumber>;
/// 对一个提案投票统计的周期,默认28天
type VotingPeriod: Get<Self::BlockNumber>;
/// 发起一个公共投票的最低存款,需要100个Token
type MinimumDeposit: Get<BalanceOf<Self>>;
/// 直接大多数议会成员(大于1/2)同意能决定其下一个动议,下一个将摆上桌面的全民公投
type ExternalOrigin: EnsureOrigin<Self::Origin>;
/// 一个绝大多数议会成员(大于3/4)同意能直接调度一个全民公投
type ExternalMajorityOrigin: EnsureOrigin<Self::Origin>;
/// 一致通过的议会能调度一个全民公投,赞成>反对 即可通过
type ExternalDefaultOrigin: EnsureOrigin<Self::Origin>;
/// 2/3的技术委员会成员同意能发起一个 ExternalMajority/ExternalDefault投票,且能够立即摆上桌面进行公投,而且有一个更短的投票/实施周期
type FastTrackOrigin: EnsureOrigin<Self::Origin>;
/// 在快速通道和紧急全民公投情况下,最小投票周期
type EmergencyVotingPeriod: Get<Self::BlockNumber>;
/// 在紧急情况下,任何全民公投都能够被取消,条件是2/3的议会成员同意
type CancellationOrigin: EnsureOrigin<Self::Origin>;
/// 任何技术委员会成员能够否决一个将要来临的议会提案,但是他们只能使用一次,在每个冷却周期过后
type VetoOrigin: EnsureOrigin<Self::Origin, Success=Self::AccountId>;
/// 技术委员会成员的否决权使用一次后,需要的冷却时间
type CooloffPeriod: Get<Self::BlockNumber>;
ReferedumInfo
/// 正在进行的全民公投相关信息
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct ReferendumInfo<BlockNumber: Parameter, Proposal: Parameter> {
/// 结束时间
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<T>, Vec<T::AccountId>)>;
/// 全民公投的总数
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<T::BlockNumber, T::Proposal>)>;
/// 将被调遣的全民公投的队列
pub DispatchQueue get(fn dispatch_queue):
map T::BlockNumber => Vec<Option<(T::Proposal, ReferendumIndex)>>;
/// 现在提案的所有投票账号
pub VotersFor get(fn voters_for): map ReferendumIndex => Vec<T::AccountId>;
/// 指定全民公投索引和账号,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<T::AccountId>;
/// 获取另一个正在委托投票的帐户(和锁定期)
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<T::AccountId>)>;
/// 所有被紧急取消的提案
pub Cancellations: map T::Hash => bool;
Event
Proposed(PropIndex, Balance), // 提案发起
Tabled(PropIndex, Balance, Vec<AccountId>), // 提案被摆上桌面
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<T::Proposal>,#[compact] value: BalanceOf<T>)
- 发起一个提案,提案人需要保留一定资金,这部分资金涉及惩罚?如何不再保留?
- <PublicProps<T>>::append_or_put(&[Ref::from(&new_prop)][..]);
- append_or_put()方法,插入数据到Vec
- <PublicProps<T>>::append_or_put(&[Ref::from(&new_prop)][..]);
- 发起一个提案,提案人需要保留一定资金,这部分资金涉及惩罚?如何不再保留?
- 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<T::Proposal>)
- 将一个提案摆上桌面进入全民公投阶段,提案需要过了blacklisting的时间
- fn external_propose_majority(origin, proposal: Box<T::Proposal>)
- 将一个提案摆上桌面,进入全民公投阶段,需要大多数同意才能通过,不受blacklisting影响
- fn external_propose_default(origin, proposal: Box<T::Proposal>)
- 将一个提案摆上桌面,进入全民公投阶段,反对通过需要绝大多数,不受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<BalanceOf<T>>
- 锁定资产投票给某个提案
- pub fn is_active_referendum(ref_index: ReferendumIndex) -> bool
- 判断某个公投是否正在进行中
- pub fn active_referenda() -> Vec<(ReferendumIndex, ReferendumInfo<T::BlockNumber, T::Proposal>)>
- 现在活跃的所有普通投票
- pub fn maturing_referenda_at(n: T::BlockNumber) -> Vec<(ReferendumIndex, ReferendumInfo<T::BlockNumber, T::Proposal>)>
- 在某个区块高度,准备进行计票统计的公投
- pub fn tally(ref_index: ReferendumIndex) -> (BalanceOf<T>, BalanceOf<T>, BalanceOf<T>)
- 公投计票统计
- fn tally_delegation(ref_index: ReferendumIndex) -> (BalanceOf<T>, BalanceOf<T>, BalanceOf<T>)
- 代理投票计票统计
- fn delegated_votes(ref_index: ReferendumIndex,to: T::AccountId,parent_conviction: Conviction,recursion_limit: u32,) -> (BalanceOf<T>, BalanceOf<T>)
- 代理投票计票统计
- 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<ReferendumIndex, &'static str>
- 开启一个公投
- 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<ReferendumIndex, &'static str>
- 开启一个公投
- 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<T::BlockNumber, T::Proposal>) -> Result
- 点票统计,通过公投的进入执行队列,该锁定的执行周期进行锁定
- fn end_block(now: T::BlockNumber) -> Result
- 现在的era结束了,应该完成任何提案
下一个公投是external需要满足下面两个中任何一个:
- LastTabledWasExternal 是 false;
- PublicProps 是空。
也就是说下一个公投要是external proposal,要么是上一个公投不是external proposal,要么没有public proposal。
群众发起的提案是public proposal,技术委员会成员快速通道发起的是external proposal,但是快速通道不能连续,除非没有公共提案。
提案执行逻辑
在collective
模块中,执行调用的必须是议会成员:
#[weight = SimpleDispatchInfo::FixedOperational(100_000)]
fn execute(origin, proposal: Box<<T as Trait<I>>::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<Self::Error> {
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.") },
}
}
网友评论