Substrate Validator Node
ノード起動時のフラグに --validator フラグをつけるだけではブロック生成は行われない。
Chain state >> session.validators に --key で設定したアドレスが含まれていなければならない
知りたいこと
コードのどこで ブロック生成するかしないかの判定をしているのか
どういうロジックで判定されているのか
validator になる方法は2つ
session.validators にアドレスが含まれていればブロックの生成を行います。(後述)
session.validators にアドレスが含まれるようにする方法は2つ
- chain spec(json, chain_spec.rs) で定義する
- staking.validate() で立候補する
1 はネットワーク、ノードを一番最初に起動するときに使用される初期値です。ブロックが生成されたあとから chain spec を変更することはできません。
2 は既存のネットワークに参加する際に validator になるための正常な手段です。
ブロックを生成する判定をしているコード
探すためのヒント
validator node のログを見ていると
Pre-sealed block for proposal at
これが出力されている。ブロック生成者をみると、Node のアドレスになっていることから、このログを出力しているところがブロックを生成している場所だと思われる。
検索
substrate/lib.rs at master · bdevux/substrate
core/consensus/aura/src/lib.rs
info!("Pre-sealed block for proposal at {}. Hash now {:?}, previously {:?}.",
header_num,
import_block.post_header().hash(),
pre_hash
);
判定している場所
substrate/lib.rs at master · bdevux/substrate
core/consensus/aura/src/lib.rs
let maybe_author = slot_author::<P>(slot_num, &authorities);
let proposal_work = match maybe_author {
None => return Box::new(future::ok(())),
Some(author) => if author == &public_key {
判定している場所はここでしょう。maybe_author と node の アドレス(public_key) が一致したらブロック生成
maybe_author がわかれば、判定のロジックがわかることになる
maybe_author は authorities から抽出された1つ
let maybe_author = slot_author::<P>(slot_num, &authorities);
fn slot_author<P: Pair>(slot_num: u64, authorities: &[AuthorityId<P>]) -> Option<&AuthorityId<P>> {
if authorities.is_empty() { return None }
let idx = slot_num % (authorities.len() as u64);
assert!(idx <= usize::max_value() as u64,
"It is impossible to have a vector with length beyond the address space; qed");
let current_author = authorities.get(idx as usize)
.expect("authorities not empty; index constrained to list length;\
this is a valid index; qed");
Some(current_author)
}
authorities 配列から1つ抽出してます。
substrate/lib.rs at master · bdevux/substrate
let (timestamp, slot_num, slot_duration) =
(slot_info.timestamp, slot_info.number, slot_info.duration);
let authorities = match authorities(client.as_ref(), &BlockId::Hash(chain_head.hash())) {
Ok(authorities) => authorities,
substrate/lib.rs at master · bdevux/substrate
fn authorities<B, C>(client: &C, at: &BlockId<B>) -> Result<Vec<AuthorityIdFor<B>>, ConsensusError> where
B: Block,
C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
{
client
.cache()
.and_then(|cache| cache.get_at(&well_known_cache_keys::AUTHORITIES, at)
.and_then(|v| Decode::decode(&mut &v[..])))
.or_else(|| {
if client.runtime_api().has_api::<AuthoritiesApi<B>>(at).unwrap_or(false) {
AuthoritiesApi::authorities(&*client.runtime_api(), at).ok()
} else {
CoreApi::authorities(&*client.runtime_api(), at).ok()
}
}).ok_or_else(|| consensus_common::ErrorKind::InvalidAuthoritiesSet.into())
}
AuthoritiesApi::authorities(&*client.runtime_api(), at).ok()
substrate/lib.rs at master · bdevux/substrate
impl consensus_authorities::AuthoritiesApi<Block> for Runtime {
fn authorities() -> Vec<AuthorityIdFor<Block>> {
Consensus::authorities()
}
}
Cargo.toml をみると、Consensus は srml-consensus ある
substrate/lib.rs at master · bdevux/substrate
pub fn authorities() -> Vec<T::SessionKey> {
AuthorityStorageVec::<T::SessionKey>::items()
}
(おいかけていくうちに、何をさがしてたのか忘れそうになります)
この authorities 配列 の中に自分のノードのアドレスがあればブロックを生成する
authorities ってどうやってセットされてるの? だっけ?
maybe_author は staking で validator に選出された session アドレス
記憶がただしければ、validator 選出のロジックから set_validators() が呼び出されていた
substrate/lib.rs at master · bdevux/substrate
fn select_validators() -> BalanceOf<T> {
.
.
.
<session::Module<T>>::set_validators(
&elected_stashes.into_iter().map(|s| Self::bonded(s).unwrap_or_default()).collect::<Vec<_>>()
);
.
.
.
}
参考(コードに触れていませんが。。。)
Substrate Validator に立候補、、、がうまくいかない - Qiita
まとめ
ブロックを生成している場所
core/consensus/aura/src/lib.rs
substrate/lib.rs at master · bdevux/substrate
staking で選出された validators に自node が含まれていて、自分の順番になったときにブロックを生成する
所感
そりゃそうだよねという結果
わざわざソースコードをおいかけているのは rust に慣れるためだったりもします。