Substrate中session模块分析

2019-12-02  本文已影响0人  建怀

Substrate中session模块分析

Session模块能够让验证者去管理它们的session key,提供一个方法去改变session长度,和处理session轮流。

Session模块在Substrate中被设计用来做如下的事情:

/// Period是session的固定区块时间,第一个session会有`Offset`的长度,接下来的session会有`period`的长度。随着session不断增长,Offset是不断增加的。
pub struct PeriodicSessions<Period,Offset,>(PhantomData<(Period, Offset)>);

Store

/// 现在的出块验证者集合
Validators get(fn validators): Vec<T::ValidatorId>;

/// 现在session的索引
CurrentIndex get(fn current_index): SessionIndex;

/// 如果底层经济特征或者出块验证者权重友改变,在这个出块认证者队列中,返回True
QueuedChanged: bool;

/// 下一个session的队列keys,当下一个session开启,这些keys会被用来决定队列中出块认证者的session keys
QueuedKeys get(fn queued_keys): Vec<(T::ValidatorId, T::Keys)>;

/// 失效出块认证者的目录
/// 这个集合会被清理掉,当`on_session_ending`返回一个新的身份集合
DisabledValidators get(fn disabled_validators): Vec<u32>;

/// 下一个session,某个出块验证者的session keys
NextKeys: double_map hasher(twox_64_concat) Vec<u8>, blake2_256(T::ValidatorId) => Option<T::Keys>;

/// 一个session key的所有者
KeyOwner: double_map hasher(twox_64_concat) Vec<u8>, blake2_256((KeyTypeId, Vec<u8>)) => Option<T::ValidatorId>;

Event

decl_event!(
    pub enum Event {
        /// 新的session发生了
        NewSession(SessionIndex),
    }
);

Module

decl_module! {
    fn set_keys(origin,keys:T::Keys,proof: vec<u8>) ->Result
    fn on_initialize(n: T::BlockNumber){
        if T::ShouldEndSession::should_end_session(n) {
            Self::rotate_session();
        }
    }
}

session模块有一个辅助性模块historical模块。用来追踪历史性session记录的,在实现区块链的时候,需要在之前若干个session中,出块认证者都能够被保留可被惩罚的状态,这是需要记录历史session记录的。

相比于记录所有session数据,historical采用了只记录默克尔tries的roots数据,这些roots保留了session数据。

这些roots和所包含的证明能够在任何时候被生成,在现在session的过程中,然后,在报告不诚实行为的时候,这些证明能够反哺共识模块。

/// 历史session目录,key是session的索引,value是session-data,主要是root hash和validator数量
HistoricalSessions get(fn historical_root): map SessionIndex => Option<(T::Hash, ValidatorCount)>;
/// value是session的索引,value是废弃掉的validator及其FullIdentification
CachedObsolete get(fn cached_obsolete): map SessionIndex => Option<Vec<(T::ValidatorId, T::FullIdentification)>>;
/// 存储的session索引,[first,last)
StoredRange: Option<(SessionIndex, SessionIndex)>;

staking模块中:

impl<T: Trait> session::OnSessionEnding<T::AccountId> for Module<T> {
    fn on_session_ending(_ending: SessionIndex, start_session: SessionIndex) -> Option<Vec<T::AccountId>> {
        Self::new_session(start_session - 1).map(|(new, _old)| new)
    }
}

impl<T: Trait> OnSessionEnding<T::AccountId, Exposure<T::AccountId, BalanceOf<T>>> for Module<T> {
    fn on_session_ending(_ending: SessionIndex, start_session: SessionIndex)
        -> Option<(Vec<T::AccountId>, Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)>)>
    {
        Self::new_session(start_session - 1)
    }
}

重点调用Self::new_session():

/// 上一个session刚刚结束,为下一个session提供validator集合,如果是一个era的结束,还提供前一个session的validator集合的exposure
fn new_session(session_index: SessionIndex)
    -> Option<(Vec<T::AccountId>, Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)>)>
{
    let era_length = session_index.checked_sub(Self::current_era_start_session_index()).unwrap_or(0);
    match ForceEra::get() {
        Forcing::ForceNew => ForceEra::kill(),
        Forcing::ForceAlways => (),
        Forcing::NotForcing if era_length >= T::SessionsPerEra::get() => (),
        _ => return None,
    }
    let validators = T::SessionInterface::validators();
    let prior = validators.into_iter()
        .map(|v| { let e = Self::stakers(&v); (v, e) })
        .collect();

    Self::new_era(session_index).map(move |new| (new, prior))
}

Substrate几个核心问题

上一篇 下一篇

猜你喜欢

热点阅读