赞
踩
在开源框架Substrate中构建核心区块链基础设施的初学者友好教程。
substrate是一个强大的区块链框架,它允许开发者构建自定义的区块链。Substrate提供了大量的模块化组件,使得开发者可以选择和定制这些组件以满足他们的特定需求,从而极大地加快了区块链开发的速度和灵活性。
Substrate的架构主要可以分为几个关键组件:
Substrate的设计哲学是提供灵活性和可扩展性,使其不仅适用于创建新的区块链项目,还可以用来构建整个区块链网络。通过使用Substrate,Parity Technologies希望能够加速Web3技术的发展和采用。
原项目地址
GitHub - substrate-developer-hub/utxo-workshop at 2d7697ccfa4e7a5922db957d8fb1ef5529b600fc
一个简化的服务器端应用程序的一部分,看起来像是为了处理网络连接和执行一些基于TCP的请求/响应模式设计的。整个流程涉及到网络编程的基本概念,如套接字操作、非阻塞I/O、以及一些特定数据结构的使用。下面是对关键部分的详细讲解:
stderr
。stderr
,然后中止程序。clock_gettime
函数和CLOCK_MONOTONIC
时钟。整体而言,这段代码是为了展示如何使用Substrate和Tokio等Rust库来构建和管理一个区块链节点的生命周期,包括服务的启动、运行和停止。这需要对Rust的异步编程、Futures和Tokio运行时有较深的理解,同时也需要熟悉Substrate框架的基本概念和组件。
Conn
实例添加到全局的fd2conn
映射中。Conn
实例,并将其设置为非阻塞。Conn
结构中的状态字段来操作。 - static void msg(const char *msg) {
- fprintf(stderr, "%s\n", msg);
- }
-
- static void die(const char *msg) {
- int err = errno;
- fprintf(stderr, "[%d] %s\n", err, msg);
- abort();
- }
-
- static uint64_t get_monotonic_usec() {
- timespec tv = {0, 0};
- clock_gettime(CLOCK_MONOTONIC, &tv);
- return uint64_t(tv.tv_sec) * 1000000 + tv.tv_nsec / 1000;
- }
-
- static void fd_set_nb(int fd) {
- errno = 0;
- int flags = fcntl(fd, F_GETFL, 0);
- if (errno) {
- die("fcntl error");
- return;
- }
-
- flags |= O_NONBLOCK;
-
- errno = 0;
- (void)fcntl(fd, F_SETFL, flags);
- if (errno) {
- die("fcntl error");
- }
- }
-
- struct Conn;
-
- // global variables
- static struct {
- HMap db;
- // a map of all client connections, keyed by fd
- std::vector<Conn *> fd2conn;
- // timers for idle connections
- DList idle_list;
- // timers for TTLs
- std::vector<HeapItem> heap;
- // the thread pool
- TheadPool tp;
- } g_data;
-
- const size_t k_max_msg = 4096;
-
- enum {
- STATE_REQ = 0,
- STATE_RES = 1,
- STATE_END = 2, // mark the connection for deletion
- };
-
- struct Conn {
- int fd = -1;
- uint32_t state = 0; // either STATE_REQ or STATE_RES
- // buffer for reading
- size_t rbuf_size = 0;
- uint8_t rbuf[4 + k_max_msg];
- // buffer for writing
- size_t wbuf_size = 0;
- size_t wbuf_sent = 0;
- uint8_t wbuf[4 + k_max_msg];
- uint64_t idle_start = 0;
- // timer
- DList idle_list;
- };
-
- static void conn_put(std::vector<Conn *> &fd2conn, struct Conn *conn) {
- if (fd2conn.size() <= (size_t)conn->fd) {
- fd2conn.resize(conn->fd + 1);
- }
- fd2conn[conn->fd] = conn;
- }
-
- static int32_t accept_new_conn(int fd) {
- // accept
- struct sockaddr_in client_addr = {};
- socklen_t socklen = sizeof(client_addr);
- int connfd = accept(fd, (struct sockaddr *)&client_addr, &socklen);
- if (connfd < 0) {
- msg("accept() error");
- return -1; // error
- }
-
- // set the new connection fd to nonblocking mode
- fd_set_nb(connfd);
- // creating the struct Conn
- struct Conn *conn = (struct Conn *)malloc(sizeof(struct Conn));
- if (!conn) {
- close(connfd);
- return -1;
- }
- conn->fd = connfd;
- conn->state = STATE_REQ;
- conn->rbuf_size = 0;
- conn->wbuf_size = 0;
- conn->wbuf_sent = 0;
- conn->idle_start = get_monotonic_usec();
- dlist_insert_before(&g_data.idle_list, &conn->idle_list);
- conn_put(g_data.fd2conn, conn);
- return 0;
- }
-
- static void state_req(Conn *conn);
- static void state_res(Conn *conn);
-
- const size_t k_max_args = 1024;
-
- static int32_t parse_req(
- const uint8_t *data, size_t len, std::vector<std::string> &out)
- {
- if (len < 4) {
- return -1;
- }
- uint32_t n = 0;
- memcpy(&n, &data[0], 4);
- if (n > k_max_args) {
- return -1;
- }
-
- size_t pos = 4;
- while (n--) {
- if (pos + 4 > len) {
- return -1;
- }
- uint32_t sz = 0;
- memcpy(&sz, &data[pos], 4);
- if (pos + 4 + sz > len) {
- return -1;
- }
- out.push_back(std::string((char *)&data[pos + 4], sz));
- pos += 4 + sz;
- }
-
- if (pos != len) {
- return -1; // trailing garbage
- }
- return 0;
- }
-
- enum {
- T_STR = 0,
- T_ZSET = 1,
- };
-
- // the structure for the key
- struct Entry {
- struct HNode node;
- std::string key;
- std::string val;
- uint32_t type = 0;
- ZSet *zset = NULL;
- // for TTLs
- size_t heap_idx = -1;
- };
-
- static bool entry_eq(HNode *lhs, HNode *rhs) {
- struct Entry *le = container_of(lhs, struct Entry, node);
- struct Entry *re = container_of(rhs, struct Entry, node);
- return le->key == re->key;
- }
-
- enum {
- ERR_UNKNOWN = 1,
- ERR_2BIG = 2,
- ERR_TYPE = 3,
- ERR_ARG = 4,
- };
-
- static void out_nil(std::string &out) {
- out.push_back(SER_NIL);
- }
-
- static void out_str(std::string &out, const char *s, size_t size) {
- out.push_back(SER_STR);
- uint32_t len = (uint32_t)size;
- out.append((char *)&len, 4);
- out.append(s, len);
- }
-
- static void out_str(std::string &out, const std::string &val) {
- return out_str(out, val.data(), val.size());
- }
-
- static void out_int(std::string &out, int64_t val) {
- out.push_back(SER_INT);
- out.append((char *)&val, 8);
- }
-
- static void out_dbl(std::string &out, double val) {
- out.push_back(SER_DBL);
- out.append((char *)&val, 8);
- }
-
- static void out_err(std::string &out, int32_t code, const std::string &msg) {
- out.push_back(SER_ERR);
- out.append((char *)&code, 4);
- uint32_t len = (uint32_t)msg.size();
- out.append((char *)&len, 4);
- out.append(msg);
- }
这段Rust代码主要是用于构建和运行一个Substrate区块链节点的命令行接口(CLI)。Substrate是一个区块链框架,允许开发者构建定制的区块链。这段代码展示了如何解析命令行参数,启动一个Substrate服务,并处理不同的命令行指令,例如运行节点、构建规格文件、导出或导入区块、检查区块、清除链数据或回退链上的数据。
代码的主要部分包括:
run
函数:这是入口函数,负责解析命令行参数并根据不同的命令执行相应的操作。它使用parse_and_prepare
函数解析命令行参数,并根据解析结果选择执行相应的动作(如运行节点、导出区块等)。
load_spec
函数:根据给定的标识符加载链规格(ChainSpec)。链规格定义了链的初始状态和配置。
run_until_exit
函数:启动服务并运行直到接收到退出信号。它在一个Tokio运行时上执行并处理退出逻辑,确保服务优雅地关闭。这个函数处理了服务的启动、运行以及退出信号(如Ctrl-C)的处理。
Exit
结构体和IntoExit
trait实现:提供一个处理退出信号的机制。它使用ctrlc
crate来监听Ctrl-C命令,并在收到信号时发送一个退出消息。
- use crate::service;
- use futures::{future::{select, Map}, FutureExt, TryFutureExt, channel::oneshot, compat::Future01CompatExt};
- use std::cell::RefCell;
- use tokio::runtime::Runtime;
- pub use sc_cli::{VersionInfo, IntoExit, error};
- use sc_cli::{display_role, informant, parse_and_prepare, ParseAndPrepare, NoCustom};
- use sc_service::{AbstractService, Roles as ServiceRoles, Configuration};
- use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair};
- use crate::chain_spec;
- use log::info;
-
- /// Parse command line arguments into service configuration.
- pub fn run<I, T, E>(args: I, exit: E, version: VersionInfo) -> error::Result<()> where
- I: IntoIterator<Item = T>,
- T: Into<std::ffi::OsString> + Clone,
- E: IntoExit,
- {
- type Config<T> = Configuration<(), T>;
- match parse_and_prepare::<NoCustom, NoCustom, _>(&version, "substrate-node", args) {
- ParseAndPrepare::Run(cmd) => cmd.run(load_spec, exit,
- |exit, _cli_args, _custom_args, config: Config<_>| {
- info!("{}", version.name);
- info!(" version {}", config.full_version());
- info!(" by {}, 2017, 2018", version.author);
- info!("Chain specification: {}", config.chain_spec.name());
- info!("Node name: {}", config.name);
- info!("Roles: {}", display_role(&config));
- let runtime = Runtime::new().map_err(|e| format!("{:?}", e))?;
- match config.roles {
- ServiceRoles::LIGHT => run_until_exit(
- runtime,
- service::new_light(config)?,
- exit
- ),
- _ => run_until_exit(
- runtime,
- service::new_full(config)?,
- exit
- ),
- }
- }),
- ParseAndPrepare::BuildSpec(cmd) => cmd.run::<NoCustom, _, _, _>(load_spec),
- ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>|
- Ok(new_full_start!(config).0), load_spec, exit),
- ParseAndPrepare::ImportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>|
- Ok(new_full_start!(config).0), load_spec, exit),
- ParseAndPrepare::CheckBlock(cmd) => cmd.run_with_builder(|config: Config<_>|
- Ok(new_full_start!(config).0), load_spec, exit),
- ParseAndPrepare::PurgeChain(cmd) => cmd.run(load_spec),
- ParseAndPrepare::RevertChain(cmd) => cmd.run_with_builder(|config: Config<_>|
- Ok(new_full_start!(config).0), load_spec),
- ParseAndPrepare::CustomCommand(_) => Ok(())
- }?;
-
- Ok(())
- }
-
- fn load_spec(id: &str) -> Result<Option<chain_spec::ChainSpec>, String> {
- Ok(match chain_spec::Alternative::from(id) {
- Some(spec) => Some(spec.load()?),
- None => None,
- })
- }
-
- fn run_until_exit<T, E>(mut runtime: Runtime, service: T, e: E) -> error::Result<()>
- where
- T: AbstractService,
- E: IntoExit,
- {
- let (exit_send, exit) = oneshot::channel();
-
- let informant = informant::build(&service);
-
- let future = select(exit, informant)
- .map(|_| Ok(()))
- .compat();
-
- runtime.executor().spawn(future);
-
- // we eagerly drop the service so that the internal exit future is fired,
- // but we need to keep holding a reference to the global telemetry guard
- let _telemetry = service.telemetry();
-
- let service_res = {
- let exit = e.into_exit();
- let service = service
- .map_err(|err| error::Error::Service(err))
- .compat();
- let select = select(service, exit)
- .map(|_| Ok(()))
- .compat();
- runtime.block_on(select)
- };
-
- let _ = exit_send.send(());
-
- // TODO [andre]: timeout this future #1318
-
- use futures01::Future;
-
- let _ = runtime.shutdown_on_idle().wait();
-
- service_res
- }
-
- // handles ctrl-c
- pub struct Exit;
- impl IntoExit for Exit {
- type Exit = Map<oneshot::Receiver<()>, fn(Result<(), oneshot::Canceled>) -> ()>;
- fn into_exit(self) -> Self::Exit {
- // can't use signal directly here because CtrlC takes only `Fn`.
- let (exit_send, exit) = oneshot::channel();
-
- let exit_send_cell = RefCell::new(Some(exit_send));
- ctrlc::set_handler(move || {
- let exit_send = exit_send_cell.try_borrow_mut().expect("signal handler not reentrant; qed").take();
- if let Some(exit_send) = exit_send {
- exit_send.send(()).expect("Error sending exit notification");
- }
- }).expect("Error setting Ctrl-C handler");
-
- exit.map(drop)
- }
- }详细见即使
这段代码主要涉及构建Substrate区块链服务的过程,其中包括完整节点服务(new_full
)和轻节点服务(new_light
)的建立。Substrate是一个区块链框架,允许你构建定制的区块链。这段代码使用Rust语言编写,展示了如何利用Substrate的服务构建器来配置和启动一个区块链节点。我们将逐步解析代码的关键部分。
new_full_start
宏sc_service::ServiceBuilder
创建一个新的服务构建器实例,这是启动Substrate服务的第一步。sc_client::LongestChain
策略。new_full
函数new_full_start
宏来初始化服务的核心部分,并进一步配置节点以参与共识等。new_light
函数展示了如何使用Substrate框架来构建和配置完整节点和轻节点服务,包括设置交易池、选择链策略、配置共识机制等关键组件。这是构建区块链节点的核心步骤,确保节点能够正常参与区块链网络的运作。
- macro_rules! new_full_start {
- ($config:expr) => {{
- let mut import_setup = None;
- let inherent_data_providers = sp_inherents::InherentDataProviders::new();
-
- let builder = sc_service::ServiceBuilder::new_full::<
- utxo_runtime::opaque::Block, utxo_runtime::RuntimeApi, crate::service::Executor
- >($config)?
- .with_select_chain(|_config, backend| {
- Ok(sc_client::LongestChain::new(backend.clone()))
- })?
- .with_transaction_pool(|config, client, _fetcher| {
- let pool_api = sc_transaction_pool::FullChainApi::new(client.clone());
- let pool = sc_transaction_pool::BasicPool::new(config, pool_api);
- let maintainer = sc_transaction_pool::FullBasicPoolMaintainer::new(pool.pool().clone(), client);
- let maintainable_pool = sp_transaction_pool::MaintainableTransactionPool::new(pool, maintainer);
- Ok(maintainable_pool)
- })?
- .with_import_queue(|_config, client, mut select_chain, transaction_pool| {
- let select_chain = select_chain.take()
- .ok_or_else(|| sc_service::Error::SelectChainRequired)?;
-
- let (grandpa_block_import, grandpa_link) =
- grandpa::block_import::<_, _, _, utxo_runtime::RuntimeApi, _>(
- client.clone(), &*client, select_chain
- )?;
-
- let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(
- grandpa_block_import.clone(), client.clone(),
- );
-
- let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _>(
- sc_consensus_aura::SlotDuration::get_or_compute(&*client)?,
- aura_block_import,
- Some(Box::new(grandpa_block_import.clone())),
- None,
- client,
- inherent_data_providers.clone(),
- Some(transaction_pool),
- )?;
-
- import_setup = Some((grandpa_block_import, grandpa_link));
-
- Ok(import_queue)
- })?;
-
- (builder, import_setup, inherent_data_providers)
- }}
- }
-
- /// Builds a new service for a full client.
- pub fn new_full<C: Send + Default + 'static>(config: Configuration<C, GenesisConfig>)
- -> Result<impl AbstractService, ServiceError>
- {
- let is_authority = config.roles.is_authority();
- let force_authoring = config.force_authoring;
- let name = config.name.clone();
- let disable_grandpa = config.disable_grandpa;
-
- // sentry nodes announce themselves as authorities to the network
- // and should run the same protocols authorities do, but it should
- // never actively participate in any consensus process.
- let participates_in_consensus = is_authority && !config.sentry_mode;
-
- let (builder, mut import_setup, inherent_data_providers) = new_full_start!(config);
-
- let (block_import, grandpa_link) =
- import_setup.take()
- .expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
-
- let service = builder.with_network_protocol(|_| Ok(NodeProtocol::new()))?
- .with_finality_proof_provider(|client, backend|
- Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _)
- )?
- .build()?;
-
- if participates_in_consensus {
- let proposer = sc_basic_authority::ProposerFactory {
- client: service.client(),
- transaction_pool: service.transaction_pool(),
- };
-
- let client = service.client();
- let select_chain = service.select_chain()
- .ok_or(ServiceError::SelectChainRequired)?;
-
- let can_author_with =
- sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
-
- let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _, _>(
- sc_consensus_aura::SlotDuration::get_or_compute(&*client)?,
- client,
- select_chain,
- block_import,
- proposer,
- service.network(),
- inherent_data_providers.clone(),
- force_authoring,
- service.keystore(),
- can_author_with,
- )?;
-
- // the AURA authoring task is considered essential, i.e. if it
- // fails we take down the service with it.
- service.spawn_essential_task(aura);
- }
-
- // if the node isn't actively participating in consensus then it doesn't
- // need a keystore, regardless of which protocol we use below.
- let keystore = if participates_in_consensus {
- Some(service.keystore())
- } else {
- None
- };
-
- let grandpa_config = grandpa::Config {
- // FIXME #1578 make this available through chainspec
- gossip_duration: Duration::from_millis(333),
- justification_period: 512,
- name: Some(name),
- observer_enabled: true,
- keystore,
- is_authority,
- };
-
- match (is_authority, disable_grandpa) {
- (false, false) => {
- // start the lightweight GRANDPA observer
- service.spawn_task(grandpa::run_grandpa_observer(
- grandpa_config,
- grandpa_link,
- service.network(),
- service.on_exit(),
- service.spawn_task_handle(),
- )?);
- },
- (true, false) => {
- // start the full GRANDPA voter
- let voter_config = grandpa::GrandpaParams {
- config: grandpa_config,
- link: grandpa_link,
- network: service.network(),
- inherent_data_providers: inherent_data_providers.clone(),
- on_exit: service.on_exit(),
- telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
- voting_rule: grandpa::VotingRulesBuilder::default().build(),
- executor: service.spawn_task_handle(),
- };
-
- // the GRANDPA voter task is considered infallible, i.e.
- // if it fails we take down the service with it.
- service.spawn_essential_task(grandpa::run_grandpa_voter(voter_config)?);
- },
- (_, true) => {
- grandpa::setup_disabled_grandpa(
- service.client(),
- &inherent_data_providers,
- service.network(),
- )?;
- },
- }
-
- Ok(service)
- }
-
- /// Builds a new service for a light client.
- pub fn new_light<C: Send + Default + 'static>(config: Configuration<C, GenesisConfig>)
- -> Result<impl AbstractService, ServiceError>
- {
- let inherent_data_providers = InherentDataProviders::new();
-
- ServiceBuilder::new_light::<Block, RuntimeApi, Executor>(config)?
- .with_select_chain(|_config, backend| {
- Ok(LongestChain::new(backend.clone()))
- })?
- .with_transaction_pool(|config, client, fetcher| {
- let fetcher = fetcher
- .ok_or_else(|| "Trying to start light transaction pool without active fetcher")?;
- let pool_api = sc_transaction_pool::LightChainApi::new(client.clone(), fetcher.clone());
- let pool = sc_transaction_pool::BasicPool::new(config, pool_api);
- let maintainer = sc_transaction_pool::LightBasicPoolMaintainer::with_defaults(pool.pool().clone(), client, fetcher);
- let maintainable_pool = sp_transaction_pool::MaintainableTransactionPool::new(pool, maintainer);
- Ok(maintainable_pool)
- })?
- .with_import_queue_and_fprb(|_config, client, backend, fetcher, _select_chain, _tx_pool| {
- let fetch_checker = fetcher
- .map(|fetcher| fetcher.checker().clone())
- .ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
- let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>(
- client.clone(), backend, &*client.clone(), Arc::new(fetch_checker),
- )?;
- let finality_proof_import = grandpa_block_import.clone();
- let finality_proof_request_builder =
- finality_proof_import.create_finality_proof_request_builder();
-
- let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, ()>(
- sc_consensus_aura::SlotDuration::get_or_compute(&*client)?,
- grandpa_block_import,
- None,
- Some(Box::new(finality_proof_import)),
- client,
- inherent_data_providers.clone(),
- None,
- )?;
-
- Ok((import_queue, finality_proof_request_builder))
- })?
- .with_network_protocol(|_| Ok(NodeProtocol::new()))?
- .with_finality_proof_provider(|client, backend|
- Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _)
- )?
- .build()
- }
这段代码是基于Rust编程语言和Substrate框架,用于构建区块链的一个例子。Substrate是一个用于创建定制区块链的框架,由Parity Technologies开发。这段代码特别是为了创建和配置一个新的Substrate-based 区块链的链规格(ChainSpec)和创始区块(genesis block)。以下是代码的关键部分的详细解释:
导入语句: 代码开始部分的use
语句导入了在文件中使用的模块和类型。这些导入包括Substrate的核心模块、加密组件、账户识别和验证机制等。
类型别名和枚举:
ChainSpec
是一个特化的类型,用于定义链的规格。Alternative
枚举定义了两种区块链环境:Development
和LocalTestnet
,分别代表开发环境和本地测试网络。帮助函数: 提供了几个函数用于从种子生成公私钥对、账户ID、和权威节点ID(用于Aura和Grandpa共识算法)。
链规格加载: Alternative
枚举的load
方法根据枚举值生成相应的ChainSpec
。这个ChainSpec
定义了链的名称、节点、创世账户和UTXO等配置。
testnet_genesis
函数: 这个函数生成了链的创始区块配置,包括系统配置、Indices配置、初始余额、Sudo权限、Aura和Grandpa共识机制的配置,以及UTXO的初始设置。这个函数也输出了一些用于UI演示的辅助信息。
具体配置:
SystemConfig
包含了链代码和变化跟踪配置。IndicesConfig
定义了具有特定索引的账户。BalancesConfig
配置了初始账户及其余额。SudoConfig
为特定账户提供了超级用户权限。AuraConfig
和GrandpaConfig
分别配置了用于Aura和Grandpa共识算法的验证者。Genesis UTXO配置: 在UTXO模型中,初始的交易输出(UTXOs)被分配给特定的公钥。这为链上的初始状态配置了一系列可以被花费的UTXOs。
总的来说,这段代码是一个基于Substrate的区块链项目的配置片段,它设置了链的初始状态、共识机制、账户余额等。通过调整这些配置,开发者可以定制自己的区块链网络来满足特定的需求。
- macro_rules! new_full_start {
- ($config:expr) => {{
- let mut import_setup = None;
- let inherent_data_providers = sp_inherents::InherentDataProviders::new();
-
- let builder = sc_service::ServiceBuilder::new_full::<
- utxo_runtime::opaque::Block, utxo_runtime::RuntimeApi, crate::service::Executor
- >($config)?
- .with_select_chain(|_config, backend| {
- Ok(sc_client::LongestChain::new(backend.clone()))
- })?
- .with_transaction_pool(|config, client, _fetcher| {
- let pool_api = sc_transaction_pool::FullChainApi::new(client.clone());
- let pool = sc_transaction_pool::BasicPool::new(config, pool_api);
- let maintainer = sc_transaction_pool::FullBasicPoolMaintainer::new(pool.pool().clone(), client);
- let maintainable_pool = sp_transaction_pool::MaintainableTransactionPool::new(pool, maintainer);
- Ok(maintainable_pool)
- })?
- .with_import_queue(|_config, client, mut select_chain, transaction_pool| {
- let select_chain = select_chain.take()
- .ok_or_else(|| sc_service::Error::SelectChainRequired)?;
-
- let (grandpa_block_import, grandpa_link) =
- grandpa::block_import::<_, _, _, utxo_runtime::RuntimeApi, _>(
- client.clone(), &*client, select_chain
- )?;
-
- let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(
- grandpa_block_import.clone(), client.clone(),
- );
-
- let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _>(
- sc_consensus_aura::SlotDuration::get_or_compute(&*client)?,
- aura_block_import,
- Some(Box::new(grandpa_block_import.clone())),
- None,
- client,
- inherent_data_providers.clone(),
- Some(transaction_pool),
- )?;
-
- import_setup = Some((grandpa_block_import, grandpa_link));
-
- Ok(import_queue)
- })?;
-
- (builder, import_setup, inherent_data_providers)
- }}
- }
-
- /// Builds a new service for a full client.
- pub fn new_full<C: Send + Default + 'static>(config: Configuration<C, GenesisConfig>)
- -> Result<impl AbstractService, ServiceError>
- {
- let is_authority = config.roles.is_authority();
- let force_authoring = config.force_authoring;
- let name = config.name.clone();
- let disable_grandpa = config.disable_grandpa;
-
- // sentry nodes announce themselves as authorities to the network
- // and should run the same protocols authorities do, but it should
- // never actively participate in any consensus process.
- let participates_in_consensus = is_authority && !config.sentry_mode;
-
- let (builder, mut import_setup, inherent_data_providers) = new_full_start!(config);
-
- let (block_import, grandpa_link) =
- import_setup.take()
- .expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
-
- let service = builder.with_network_protocol(|_| Ok(NodeProtocol::new()))?
- .with_finality_proof_provider(|client, backend|
- Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _)
- )?
- .build()?;
-
- if participates_in_consensus {
- let proposer = sc_basic_authority::ProposerFactory {
- client: service.client(),
- transaction_pool: service.transaction_pool(),
- };
-
- let client = service.client();
- let select_chain = service.select_chain()
- .ok_or(ServiceError::SelectChainRequired)?;
-
- let can_author_with =
- sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
-
- let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _, _>(
- sc_consensus_aura::SlotDuration::get_or_compute(&*client)?,
- client,
- select_chain,
- block_import,
- proposer,
- service.network(),
- inherent_data_providers.clone(),
- force_authoring,
- service.keystore(),
- can_author_with,
- )?;
-
- // the AURA authoring task is considered essential, i.e. if it
- // fails we take down the service with it.
- service.spawn_essential_task(aura);
- }
-
- // if the node isn't actively participating in consensus then it doesn't
- // need a keystore, regardless of which protocol we use below.
- let keystore = if participates_in_consensus {
- Some(service.keystore())
- } else {
- None
- };
-
- let grandpa_config = grandpa::Config {
- // FIXME #1578 make this available through chainspec
- gossip_duration: Duration::from_millis(333),
- justification_period: 512,
- name: Some(name),
- observer_enabled: true,
- keystore,
- is_authority,
- };
-
- match (is_authority, disable_grandpa) {
- (false, false) => {
- // start the lightweight GRANDPA observer
- service.spawn_task(grandpa::run_grandpa_observer(
- grandpa_config,
- grandpa_link,
- service.network(),
- service.on_exit(),
- service.spawn_task_handle(),
- )?);
- },
- (true, false) => {
- // start the full GRANDPA voter
- let voter_config = grandpa::GrandpaParams {
- config: grandpa_config,
- link: grandpa_link,
- network: service.network(),
- inherent_data_providers: inherent_data_providers.clone(),
- on_exit: service.on_exit(),
- telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
- voting_rule: grandpa::VotingRulesBuilder::default().build(),
- executor: service.spawn_task_handle(),
- };
-
- // the GRANDPA voter task is considered infallible, i.e.
- // if it fails we take down the service with it.
- service.spawn_essential_task(grandpa::run_grandpa_voter(voter_config)?);
- },
- (_, true) => {
- grandpa::setup_disabled_grandpa(
- service.client(),
- &inherent_data_providers,
- service.network(),
- )?;
- },
- }
-
- Ok(service)
- }
-
- /// Builds a new service for a light client.
- pub fn new_light<C: Send + Default + 'static>(config: Configuration<C, GenesisConfig>)
- -> Result<impl AbstractService, ServiceError>
- {
- let inherent_data_providers = InherentDataProviders::new();
-
- ServiceBuilder::new_light::<Block, RuntimeApi, Executor>(config)?
- .with_select_chain(|_config, backend| {
- Ok(LongestChain::new(backend.clone()))
- })?
- .with_transaction_pool(|config, client, fetcher| {
- let fetcher = fetcher
- .ok_or_else(|| "Trying to start light transaction pool without active fetcher")?;
- let pool_api = sc_transaction_pool::LightChainApi::new(client.clone(), fetcher.clone());
- let pool = sc_transaction_pool::BasicPool::new(config, pool_api);
- let maintainer = sc_transaction_pool::LightBasicPoolMaintainer::with_defaults(pool.pool().clone(), client, fetcher);
- let maintainable_pool = sp_transaction_pool::MaintainableTransactionPool::new(pool, maintainer);
- Ok(maintainable_pool)
- })?
- .with_import_queue_and_fprb(|_config, client, backend, fetcher, _select_chain, _tx_pool| {
- let fetch_checker = fetcher
- .map(|fetcher| fetcher.checker().clone())
- .ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
- let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>(
- client.clone(), backend, &*client.clone(), Arc::new(fetch_checker),
- )?;
- let finality_proof_import = grandpa_block_import.clone();
- let finality_proof_request_builder =
- finality_proof_import.create_finality_proof_request_builder();
-
- let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, ()>(
- sc_consensus_aura::SlotDuration::get_or_compute(&*client)?,
- grandpa_block_import,
- None,
- Some(Box::new(finality_proof_import)),
- client,
- inherent_data_providers.clone(),
- None,
- )?;
-
- Ok((import_queue, finality_proof_request_builder))
- })?
- .with_network_protocol(|_| Ok(NodeProtocol::new()))?
- .with_finality_proof_provider(|client, backend|
- Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _)
- )?
- .build()
- }详细解释
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。