Substrate原始碼分析 啟動流程

2021-09-26 13:58:30 字數 4752 閱讀 6275

我們在命令列啟動 substrate 節點,到底發生了什麼呢?本文基於 substrate 原始碼,對其啟動流程進行了簡單的分析。

命令列啟動 substrate,主要是解析命令列引數並配置服務。

主程式在substrate/node/main.rs中,入口是main()函式。其中的關鍵**如下:

fn main() \n\n", e, e);

std::process::exit(1)

}}

這行**呼叫的是node/cli/src/lib.rsrun函式。進入該run函式,有如下**:

pub fn run(args: i, exit: e, version: cli::versioninfo) -> error::result<()> where

i: intoiterator,

t: into + clone,

e: intoexit,

", version.name);

...}

parse_and_prepare函式(位於core/cli/src/lib.rs中),這個函式類似於所有的區塊鏈啟動,主要是對命令列引數進行解析,並啟動相關的操作。

parse_and_prepare函式中,會根據不同的引數,返回不同型別的parseandprepare

pub fn parse_and_prepare<'a, cc, rp, i>(

version: &'a versioninfo,

impl_name: &'static str,

args: i,

) -> parseandprepare<'a, cc, rp>

where

cc: structopt + clone + getlogfilter,

rp: structopt + clone + augmentclap,

i: intoiterator,

::item: into + clone,

),...

}

pub enum coreparams
而對於列舉型別parseandprepare,每一類結構體,均會實現各自的run方法,解析引數生成配置,並根據配置執行服務。

pub enum parseandprepare<'a, cc, rp>
以結構體parseandpreparerun為例,其run函式的實現**如下:

impl<'a, rp> parseandpreparerun<'a, rp> 

}

其實執行服務,具體是在run函式的閉包函式中,**如下:

parseandprepare::run(cmd) => cmd.run(load_spec, exit, |exit, _cli_args, _custom_args, config| ", version.name);

info!(" version {}", config.full_version());

info!(" by parity technologies, 2017-2019");

info!("chain specification: {}", config.chain_spec.name());

info!("node name: {}", config.name);

info!("roles: ", config.roles);

let runtime = runtimebuilder::new().name_prefix("main-tokio-").build()

.map_err(|e| format!("", e))?;

match config.roles ", e))?,

exit

),_ => run_until_exit(

runtime,

service::factory::new_full(config).map_err(|e| format!("", e))?,

exit

),}.map_err(|e| format!("", e))

}),

fn run_until_exit(

mut runtime: runtime,

service: t,

e: e,

) -> error::result<()>

where

t: deref> + future + send + 'static,

c: substrate_service::components,

e: intoexit,

**中呼叫了core/cli/src/informant.rsbuild函式,建立了乙個futrue「線人」informant

基本上到這兒,相關的命令就全啟動了。我們看下生成全節點或輕節點服務的具體細節。

在宣告巨集construct_service_factory的定義中,有如下**:

#[macro_export]

macro_rules! construct_service_factory ,

authoritysetup = ,

lightservice = $light_service:ty ,

...fn new_light(

config: $crate::factoryfullconfiguration

) -> $crate::result

fn new_full(

config: $crate::factoryfullconfiguration

) -> result)}

...}

node/cli/src/service.rs中,包含了service結合service中的對巨集的呼叫,巨集展開後,是執行的::new(config),**如下:

construct_service_factory! ,

...lightservice = lightcomponents

,...

}

core/service/src/components.rs中定義了substrate的服務元件:fullcomponentslightcomponents。它們new函式的實現均呼叫了servicenew函式,**如下:

ok(

self

)

通過該函式建立substrate service,它會啟動客戶端,初始化session keys,構建網路,交易池以及rpc,並管理他們之間的通訊,包括區塊通知,交易通知等。關鍵**如下:

let executor = nativeexecutor::new(config.default_heap_pages);

...components::runtimeservices::generate_intial_session_keys(

client.clone(),

config.dev_key_seed.clone().map(|s| vec![s]).unwrap_or_default(),

)?;...

let network_protocol = ::build_network_protocol(&config)?;

let transaction_pool = arc::new(

components::build_transaction_pool(config.transaction_pool.clone(), client.clone())?

);...

let events = client.import_notification_stream()

.map(|v| ok::<_, ()>(v)).compat()

.for_each(move |notification| )

這個有些類似於以太坊,在啟動節點時把相關的網路服務都建立好。這樣最後ok返回整個service

ps:原始碼分析是基於master分支(substrate 2.0)。

1. 其中對命令列引數的解析,使用了第三方庫structopt,該庫通過結構體來解析引數,並對clap庫進行了補充。

2. 非同步程式設計,使用了第三方庫tokio,該庫使用reactor-executor模式,是基於事件驅動的非阻塞i/o庫。是 rust 中的非同步程式設計框架,它將複雜的非同步程式設計抽象為 futures、tasks 和 executor,並提供了 timers 等基礎設施。

spring原始碼學習 初啟

spring最重要的概念是ioc和aop,其中ioc又是spring的根基。我們來先看看spring的整體架構 spring框架是乙個分層架構,它包含一系列的功能要素,並被分為大約20個模組,如下圖所示 從看出,整個模型就是乙個容器關係,spring通過動態載入不同的模組實現我們想要的功能,而最io...

spring原始碼分析 spring原始碼分析

1.spring 執行原理 spring 啟動時讀取應用程式提供的 bean 配置資訊,並在 spring 容器中生成乙份相應的 bean 配置登錄檔,然後根據這張登錄檔例項化 bean,裝配好 bean 之間的依賴關係,為上 層應用提供準備就緒的執行環境。二 spring 原始碼分析 1.1spr...

思科VPP原始碼分析(dpo機制原始碼分析)

vpp的dpo機制跟路由緊密結合在一起。路由表查詢 ip4 lookup 的最後結果是乙個load balance t結構。該結構可以看做是乙個hash表,裡面包含了很多dpo,指向為下一步處理動作。每個dpo都是新增路由時的乙個path的結果。dpo標準型別有 dpo drop,dpo ip nu...