Libra的测试程序运行和源码解析

1、下载 Libra 及相关软件安装

下载 Libra


git clone https://github.com/libra/libra.git

安装 Rust 等相关

 

curl https://sh.rustup.rs -sSf | sh
rustup toolchain install nightly-2019-05-22-x86_64-unknown-linux-gnu
rustup override set nightly-2019-05-22

安装完成后查看版本信息

 

cy3deMacBook-Pro:libra root# rustc --version

rustc 1.38.0-nightly (6e310f2ab 2019-07-07)

cy3deMacBook-Pro:libra root# rustup --version

rustup 1.18.3 (435397f48 2019-05-22)

2、安装测试 Libra 环境

运行环境依赖安装脚本

cd libra
./scripts/dev_setup.sh

 

显示如下:

 

Installing CMake......
CMake is already installed
Installing Go......
Go is already installed
Installing Protobuf......
Protobuf is already installed

Finished installing all dependencies.

You should now be able to build the project by running:
	source /root/.cargo/env
	cargo build

 

运行测试网络脚本

./scripts/cli/start_cli_testnet.sh

完成后显示如下:

 

3、Libra的准入控制(AC)模块使用

准入控制模块(AC:admission control,本文中简称 AC 模块)是位于验证器(Validator)与普通用户交互的入口。准入控制模块是验证器的唯一外部接口。 客户端向验证器发出的任何请求都会先转到 AC

创建账户及状态查看

先查看 account 内容:

 

创建账户 Alice 和 Bob 账户

libra% account create
>> Creating/retrieving next account from wallet
Created/retrieved account #0 address c94d5411d85442374cc24c0eb0203f1666c9cd681eb4eeedf366905c950c20ee
libra% account create
>> Creating/retrieving next account from wallet
Created/retrieved account #1 address 39c0ff0bdc00b710599e6f4c8c32d2fa873ce360f20b100703eca748e0941f24
libra%

 

通过 account list 查看

 

分配 Libra Coins 到 Alice 和 Bob 的账户。

根据之前的建 account 顺序,那么 0 为 Alice、1 为 Bob,110 和 50 为 Libra coin。

libra% account mint 0 110
>> Minting coins
Mint request submitted
libra% account mint 1 52
>> Minting coins
Mint request submitted
libra%

检查下 account 0、1 的余额

libra% query balance 0
Balance is: 110
libra% query balance 1
Balance is: 52
libra%

查看账户序列

ibra% query sequence 0
>> Getting current sequence number
Sequence number is: 0
libra% query sequence 1
>> Getting current sequence number
Sequence number is: 0
libra%

 

账户转账

转移 10 个 Libra coin 从 Alice 到 Bob:

transfer 0 1 10

  • 0 是 Alice 的帐户的索引。
  • 1 是 Bob 的帐户索引。
  • 10 是从 Alice 的账户转移到 Bob 的账户的 Libra 的数量。

 

transfer 0 1 10

 

下图清晰显示账户转账后的状态:

 

4、Libra 的准入控制 (AC) 模块流程与源码

AC 基本上就干了两件事,提供了两个接口。一个是 SubmitTransaction,另一个是UpdateToLatestLedger

主要代码位于 admission_control_service\admission_control_service.rs这个是对admission_control.proto下的service AdmissionControl实现

SubmitTransaction

这个模块主要是接受来自普通用户的 Tx,如果合理有效则提交给 MemPool 模块,最终会进入到 block 中。

工作流程:

  1. 校验 Tx,包括三个部分一个是签名是否有效,另一个则是 gas 是否有效,第三个则是执行 Tx 中的 code 是否能够通过。
  2. 校验账户余额是否足够,然后通过 grpc 链接发送给 mempool 模块
  3. 将 mempool 结果返回给用户

校验 Tx 在VMValidator1中进行的。

相关代码简单分析

/// Validate transaction signature, then via VM, and add it to Mempool if it passes VM check.
    /// 流程非常简单
    /// 1. 交由本地validator验证Tx执行能否通过,如果不通过报错,否则继续2
    /// 2. 获取账户最新状态,组装`AddTransactionWithValidationRequest`
    /// 3. 调用mempool grpc接口,添加Tx到mempool中
    pub(crate) fn submit_transaction_inner(
        &self,
        req: SubmitTransactionRequest,
    ) -> Result<SubmitTransactionResponse> {
        // 就是校验mempool服务是否正常
        if !self.can_send_txn_to_mempool()? {
            debug!("Mempool is full");
            OP_COUNTERS.inc_by("submit_txn.rejected.mempool_full", 1);
            let mut response = SubmitTransactionResponse::new();
            response.set_mempool_status(MempoolIsFull);
            return Ok(response);
        }

        let signed_txn_proto = req.get_signed_txn();
        //利用`FromProto`这个trait将grpc 类型转换为内部类型.
        let signed_txn = match SignedTransaction::from_proto(signed_txn_proto.clone()) {
            Ok(t) => t,
            Err(e) => {
                security_log(SecurityEvent::InvalidTransactionAC)
                    .error(&e)
                    .data(&signed_txn_proto)
                    .log();
                let mut response = SubmitTransactionResponse::new();
                response.set_ac_status(AdmissionControlStatus::Rejected);
                OP_COUNTERS.inc_by("submit_txn.rejected.invalid_txn", 1);
                return Ok(response);
            }
        };
        //交由vm_validator校验Tx是否合法.实际对应的是`VMValidator`这个struct
        //签名校验是否有效实际上是在vm_validator中.
        let gas_cost = signed_txn.max_gas_amount();
        let validation_status = self
            .vm_validator
            .validate_transaction(signed_txn.clone())
            .wait()
            .map_err(|e| {
                security_log(SecurityEvent::InvalidTransactionAC)
                    .error(&e)
                    .data(&signed_txn)
                    .log();
                e
            })?; //Validator验证Tx是否有效,注意该调用也是一个grpc调用,因此走的是异步,wait模式
        if let Some(validation_status) = validation_status {
            let mut response = SubmitTransactionResponse::new();
            OP_COUNTERS.inc_by("submit_txn.vm_validation.failure", 1);
            debug!(
                "txn failed in vm validation, status: {:?}, txn: {:?}",
                validation_status, signed_txn
            );
            response.set_vm_status(validation_status.into_proto());
            return Ok(response);
        }
        let sender = signed_txn.sender();
        let account_state = block_on(get_account_state(self.storage_read_client.clone(), sender));
        let mut add_transaction_request = AddTransactionWithValidationRequest::new();
        add_transaction_request.signed_txn = req.signed_txn.clone();
        add_transaction_request.set_max_gas_cost(gas_cost);

        if let Ok((sequence_number, balance)) = account_state {
            add_transaction_request.set_account_balance(balance);
            add_transaction_request.set_latest_sequence_number(sequence_number);
        }
        //这个函数非常简单,就是调用mempool的grpc接口`add_transaction_with_validation` 来试图添加一个Tx到mempool中去
        self.add_txn_to_mempool(add_transaction_request)
    }

UpdateToLatestLedger

AC 的另一个功能就是提供查询功能,这个包括账户状态,交易,ContractEvent 等的查询。 这实际上可以看做 libra 所有对外能够提供的服务了。

请求参数

主要有四类请求,深刻理解了这四类请求的所有数据结构。

#[derive(Arbitrary, Clone, Debug, Eq, PartialEq)]
pub enum RequestItem {
    GetAccountTransactionBySequenceNumber {
        account: AccountAddress,
        sequence_number: u64,
        fetch_events: bool,
    },
    // this can't be the first variant, tracked here AltSysrq/proptest#141
    GetAccountState {
        address: AccountAddress,
    },
    GetEventsByEventAccessPath {
        access_path: AccessPath,
        start_event_seq_num: u64,
        ascending: bool,
        limit: u64,
    },
    GetTransactions {
        start_version: Version,
        limit: u64,
        fetch_events: bool,
    },
}

 

从这些请求里面没有看到任何 block 相关字样,这也说明了 libra 有意弱化 block 概念,直接针对的是 transaction。

返回结果

请求和返回都位于 types/src/get_with_proof.rs, types/src 目录下就是系统的核心数据结构所在。

#[allow(clippy::large_enum_variant)]
#[derive(Arbitrary, Clone, Debug, Eq, PartialEq)]

pub enum ResponseItem {
    GetAccountTransactionBySequenceNumber {
        signed_transaction_with_proof: Option<SignedTransactionWithProof>,
        proof_of_current_sequence_number: Option<AccountStateWithProof>,
    },
    // this can't be the first variant, tracked here AltSysrq/proptest#141
    GetAccountState {
        account_state_with_proof: AccountStateWithProof,
    },
    GetEventsByEventAccessPath {
        events_with_proof: Vec<EventWithProof>,
        proof_of_latest_event: Option<AccountStateWithProof>,
    },
    GetTransactions {
        txn_list_with_proof: TransactionListWithProof,
    },
}

具体实现

实现非常简单,实际上就是一个请求转达,是直接调用的 storage 模块的 grpc 服务,所以阅读 storage 模块相关文章即可,参考:打通 Libra CLI 客户端与 libradb 模块 , Libra 中数据存储的 Schema

 

/// Pass the UpdateToLatestLedgerRequest to Storage for read query.
 fn update_to_latest_ledger_inner(
     &self,
     req: UpdateToLatestLedgerRequest,
 ) -> Result<UpdateToLatestLedgerResponse> {
     let rust_req = types::get_with_proof::UpdateToLatestLedgerRequest::from_proto(req)?;
     let (response_items, ledger_info_with_sigs, validator_change_events) = self
         .storage_read_client
         .update_to_latest_ledger(rust_req.client_known_version, rust_req.requested_items)?;
     let rust_resp = types::get_with_proof::UpdateToLatestLedgerResponse::new(
         response_items,
         ledger_info_with_sigs,
         validator_change_events,
     ); //直接读取本地数据库,注意这个接口是查询而不是更新
     Ok(rust_resp.into_proto())
 }

启动流程

AC 模块是一个独立的 grpc 服务,也是一个独立的可执行程序。

入口处位于 main.rs。

这里简单分析一下启动流程

main.rs

 

/// Run a Admission Control service in its own process.
/// It will also setup global logger and initialize config.
fn main() {
    let (config, _logger, _args) = setup_executable(
        "Libra AdmissionControl node".to_string(),
        vec![ARG_PEER_ID, ARG_CONFIG_PATH, ARG_DISABLE_LOGGING],
    );

    let admission_control_node = admission_control_node::AdmissionControlNode::new(config);

    admission_control_node
        .run()
        .expect("Unable to run AdmissionControl node");
}

首先核心是使用setup_executable来解析参数,获取系统配置以及日志。 这个函数做整个 libra 所有的服务中都是这么使用的。

AdmissionControlNode

第二步则是创建AdmissionControlNode

/// Struct to run Admission Control service in a dedicated process. It will be used to spin up
/// extra AC instances to talk to the same validator.
pub struct AdmissionControlNode {
    /// Config used to setup environment for this Admission Control service instance.
    node_config: NodeConfig,
}

 

从定义中无法直接看出依赖,在 run 函数中可以看出启动过程。

/// Setup environment and start a new Admission Control service.
    pub fn run(&self) -> Result<()> {
        logger::set_global_log_collector(
            self.node_config
                .log_collector
                .get_log_collector_type()
                .unwrap(),
            self.node_config.log_collector.is_async,
            self.node_config.log_collector.chan_size,
        );
        info!("Starting AdmissionControl node",);
        // Start receiving requests
        let client_env = Arc::new(EnvBuilder::new().name_prefix("grpc-ac-mem-").build());
        let mempool_connection_str = format!(
            "{}:{}",
            self.node_config.mempool.address, self.node_config.mempool.mempool_service_port
        );
        let mempool_channel =
            ChannelBuilder::new(client_env.clone()).connect(&mempool_connection_str);

        self.run_with_clients(
            client_env.clone(),
            //依赖两个服务,一个是mempool服务
            Arc::new(MempoolClient::new(mempool_channel)),
            //另一个是storage服务,正如我们上面的分析
            Some(Arc::new(StorageReadServiceClient::new(
                Arc::clone(&client_env),
                &self.node_config.storage.address,
                self.node_config.storage.port,
            ))),
        )
    }

 

实际上在run_with_clients中还创建了vm_validator,只不过这个不是独立的服务罢了。

run_with_clients

 

/// This method will start a node using the provided clients to external services.
    /// For now, mempool is a mandatory argument, and storage is Option. If it doesn't exist,
    /// it'll be generated before starting the node.
    pub fn run_with_clients<M: MempoolClientTrait + 'static>(
        /*
        若是有where T:'static 的约束,意思则是,类型T⾥⾯不包含任何指向短⽣命周期的借⽤指针,
        意思是要么完全不包含任何借⽤,要么可以有指向'static的借⽤指针。
        */
        &self,
        env: Arc<Environment>,
        mp_client: Arc<M>,
        storage_client: Option<Arc<StorageReadServiceClient>>, /* storage_client是和后端的storage服务进行通信
                                                               libra实现的各个服务之间都是通过grpc服务交互*/
    ) -> Result<()> {
        // create storage client if doesn't exist
        let storage_client: Arc<dyn StorageRead> = match storage_client {
            Some(c) => c,
            None => Arc::new(StorageReadServiceClient::new(
                env,
                &self.node_config.storage.address,
                self.node_config.storage.port,
            )),
        };

        let vm_validator = Arc::new(VMValidator::new(&self.node_config, storage_client.clone()));

        let handle = AdmissionControlService::new(
            mp_client,
            storage_client,
            vm_validator,
            self.node_config
                .admission_control
                .need_to_check_mempool_before_validation,
        );
        let service = admission_control_grpc::create_admission_control(handle);

        let _ac_service_handle = spawn_service_thread(
            service,
            self.node_config.admission_control.address.clone(),
            self.node_config
                .admission_control
                .admission_control_service_port,
            "admission_control",
        );
        //这个debug服务与我们说的上述内容无关,纯粹是为了调试需要.
        // Start Debug interface
        let debug_service =
            node_debug_interface_grpc::create_node_debug_interface(NodeDebugService::new());
        let _debug_handle = spawn_service_thread(
            debug_service,
            self.node_config.admission_control.address.clone(),
            self.node_config
                .debug_interface
                .admission_control_node_debug_port,
            "debug_service",
        );

        info!(
            "Started AdmissionControl node on port {}",
            self.node_config
                .admission_control
                .admission_control_service_port
        );

        loop {
            thread::park();
        }
    }

5、 LibraBft共识模块架构与源码

基本概念

1. SMR(状态机复制):在计算机领域,SMR是用于在网络的不同副本之间进行状态复制的协议。

2.安全性:简单地被理解为一致性的共识保证,即诚实的节点可以实现一致的状态;

3.活跃度:简单地理解为区块链网络的可用性,类似于分布式系统中的分区可用性;

4.时代,在实际应用中,参与协议的节点的状态随着时间的推移而演变,LibraBFT通过时代支持这种状态变化。 一个。每个时代都基于他之前的时代发展。或者基于系统定义的初始时代; 湾每个纪元都有一个独特的epochid标识符; C。每当提交一个新的epochid时,当前的纪元将结束并且下一个纪元将开始;

5. LibraBFT假设网络是部分同步网络,具有全局建立时间(GST)和最大延迟(ΔT)可控;

6. LibraBFT假定非拜占庭节点将根据协议履行其职责,并保证可用。

7.记录,LibraBFT的状态由一系列记录组成。它主要包括四种类型,块,票,仲裁证书(QC)和超时。

基本架构

Libra Consensus Module代码主要在共识包中,该包定义了Libra Consensus的抽象接口及其具体实现。 Libra团队目前只实施LibraBFT。约定包是一个独立的可编译单元,在编译后生成库。其代码目录结构和每个级别的模块的主要特征如下:

consensus
├── src
│   └── chained_bft                # LibraBFT协议的实现
│       ├── block_storage          # 块和相关数据结构的内存存储
│       ├── consensus_types        # 共识数据类型
│       ├── consensusdb            # 数据库交互以持久一致的数据来保证安全性和活动性
│       ├── liveness               # 跟踪器,提议者,和其他活力相关的代码
│       ├── safety                 # 安全(投票)规则
│       └── test_utils             
└── state_synchronizer             # 验证器之间的同步去跟踪提交的状态

 

在一致性包的每个级别中定义的模块如下所示:

 

//consensus/src/lib.rs 中定义的子模块
mod state_computer;//状态计算模块,与执行模块相互通信.它可以执行区块、提交区块,并且同步状态。
mod state_replication;//状态复制模块,定义了SMR(状态机复制)接口和StateComputer接口
mod state_synchronizer;//状态同步模块,验证节点之间进行状态同步到具体实现
mod txn_manager;//tx管理模块,是一套内存池组件接口,它支持交易的提交和拉取。申请人请求从内存池拉取交易到自己的区块表中。

// consensus/chained_bft中定义的子模块
mod common;//定义了Round,Height和Author、Block Payload的接口
mod consensus_types;//librabft共识模数据结构
mod consensusdb;//共识持久化存储模块
mod liveness;//librabft liveness模块,实现了Pacemaker,负责round的切换
mod safety;//librabft safety模块

mod block_storage;//内存中的区块存储模块。维护了一棵树,这棵树包括个人区块,区块执行信息,投票信息,QC和持久存储信息。它负责维护这个数据结构的一致性,同时可以被其它子组件接收
pub mod chained_bft_consensus_provider;//libra共识算法librabft的具体实现
mod chained_bft_smr;//libra smr的具体实现,实现了StateMachineReplication的接口
mod event_processor;//librabft的smr是基于事件驱动方式实现的,这个模块定义了具体的事件,各个事件的定义和handler
mod network;//librabft中与网络模块交互的主要逻辑

pub mod persistent_storage;//block持久化存储的模块
mod sync_manager;//同步模块,同步的目标状态有highest_ledger_info,highest_quorum_cert和peer,
// consensor/state_synchronizer中定义的子模块
mod coordinator;//协同模块,用于处理共识请求并与远程节点进行同步
mod downloader;//下载模块。用于从远程节点下载事物
mod synchronizer;//用于从其他验证几点同步提交的状态

 

源码分析

Libra代码的入口

Libra代码的入口在 。/libra_node/src/main.rs中,启动服务主流程的代码在 。/libra_node/src/main_node.rs

 

//位于./libra_node/src/main.rs中
fn main() {
    //加载节点配置信息
    let (config, _logger, _args) = setup_executable(
        "Libra single node".to_string(),
        vec![ARG_PEER_ID, ARG_CONFIG_PATH, ARG_DISABLE_LOGGING],
    );
    //启动节点的所有子模块、共识模块也在其中进行初始化并启动
    let (_ac_handle, _node_handle) = libra_node::main_node::setup_environment(&config);

    let term = Arc::new(AtomicBool::new(false));
    register_signals(Arc::clone(&term));

    while !term.load(Ordering::Acquire) {
        std::thread::park();
    }
}

//位于./libra_node/src/main_node.rs文件中
//启动各个子服务
pub fn setup_environment(node_config: &NodeConfig) -> (AdmissionControlClient, LibraHandle) {
    crash_handler::setup_panic_handler();

    let mut instant = Instant::now();
    let storage = start_storage_service(&node_config);
    debug!(
        "Storage service started in {} ms",
        instant.elapsed().as_millis()
    );

    instant = Instant::now();
    let execution = ServerHandle::setup(setup_executor(&node_config));
    debug!(
        "Execution service started in {} ms",
        instant.elapsed().as_millis()
    );

    instant = Instant::now();
    //初始化共识模块与网络交互相关内容
    let (
        (mempool_network_sender, mempool_network_events),
        (consensus_network_sender, consensus_network_events),
        network_runtime,
    ) = setup_network(&node_config);
    debug!("Network started in {} ms", instant.elapsed().as_millis());
    //初始化Admission控制模块
    instant = Instant::now();
    let (ac_server, ac_client) = setup_ac(&node_config);
    let ac = ServerHandle::setup(ac_server);
    debug!("AC started in {} ms", instant.elapsed().as_millis());

    instant = Instant::now();
    let mempool =
        MempoolRuntime::bootstrap(&node_config, mempool_network_sender, mempool_network_events);
    debug!("Mempool started in {} ms", instant.elapsed().as_millis());

    let debug_if = ServerHandle::setup(setup_debug_interface(&node_config));

    let metrics_port = node_config.debug_interface.metrics_server_port;
    let metric_host = node_config.debug_interface.address.clone();
    thread::spawn(move || metric_server::start_server((metric_host.as_str(), metrics_port)));
   //初始化共识模块
    instant = Instant::now();
    let mut consensus_provider = make_consensus_provider(
        &node_config,
        consensus_network_sender,
        consensus_network_events,
    );
   //启动共识模块
    consensus_provider
        .start()
        .expect("Failed to start consensus. Can't proceed.");
    debug!("Consensus started in {} ms", instant.elapsed().as_millis());

    let libra_handle = LibraHandle {
        _ac: ac,
        _mempool: mempool,
        _network_runtime: network_runtime,
        consensus: consensus_provider,
        _execution: execution,
        _storage: storage,
        _debug: debug_if,
    };
    (ac_client, libra_handle)
}

上述NodeConfig是节点的配置,共识相关的配置在其之中,在 。/config/src/config.rs 中 ConsensusConfig结构中定义。

共识模块初始化

初始化的代码在 /consensus/src/consensus_provider.rs 中,该函数返回了一个 ChainedBftProvider 实例,该实例就是LibraBFT实例:

 

//./consensus/src/consensus_provider.rs
/// Helper function to create a ConsensusProvider based on configuration
pub fn make_consensus_provider(
    node_config: &NodeConfig,
    network_sender: ConsensusNetworkSender,
    network_receiver: ConsensusNetworkEvents,
) -> Box<dyn ConsensusProvider> {
//返回ChainedBftProvider实例
    Box::new(ChainedBftProvider::new(
        node_config,
        network_sender,
        network_receiver,
        create_mempool_client(node_config),
        create_execution_client(node_config),
    ))
}

ChainedBftProvider 定义在 。/consensus/src/chained_bft/chained_bft_consensus_provider.rs 中,他有四个成员变量,分别是状态副本实例以及其余各个其他模块交互的客户端

 

/// Supports the implementation of ConsensusProvider using LibraBFT.
pub struct ChainedBftProvider {
    //ChainedBftSMR实例
    smr: ChainedBftSMR<Vec<SignedTransaction>, Author>,
    //MempoolClient实例,用于与mempool模块交互,mempool模块主要用于存放还没有被打包的区块
    mempool_client: Arc<MempoolClient>,
    //ExecutionClient实例,用于与execution模块交互,execution模块主要用于队排好序的事物进行处理,计算执行后的产出,应用于之前的状态
    //并产生新的状态 
    execution_client: Arc<ExecutionClient>,
    //StateynchronizerClient实例,用于与StateSynchronizer模块交互,StateSynchronizer模块主要用于与其他Validator之间的状态同步
    synchronizer_client: Arc<StateSynchronizer>,
}

ChainedBftProvider 的new方法定义了其实例初始化的过程

 

//./sonsensus/src/chained_bft_consensus_provider.rs
impl ChainedBftProvider {
//ChainedBftProvider new方法
    pub fn new(
        node_config: &NodeConfig,
        network_sender: ConsensusNetworkSender,
        network_events: ConsensusNetworkEvents,
        mempool_client: Arc<MempoolClient>,
        execution_client: Arc<ExecutionClient>,
    ) -> Self {
        ......
        //初始化smr实例
        let smr = ChainedBftSMR::new(
            initial_setup.author,
            initial_setup.quorum_size,
            initial_setup.signer,
            proposer,
            network,
            runtime,
            config,
            storage,
            initial_data,
        );
        Self {
            smr,
            mempool_client,
            execution_client,
            synchronizer_client: Arc::new(synchronizer),
        }

至此,共识实例初始化完毕~

共识模块启动&运行流程

前面已经介绍完了共识模块初始化的过程,接下来我们看一下共识服务具体是如何运作的。LibraBFT服务启动函数是 ChainedBftProvider.start()。它实现了Libra共识的通用接口 ConsensusProvider,该接口定义在 。/consensus/src/consensus_provider.rs 中。ChainedBftProvider.start()的主要是启动smr,代码如下:

//./consensus/src/chained_bft/chained_bft_provider.rs
impl ConsensusProvider for ChainedBftProvider {
//librabft启动函数
    fn start(&mut self) -> Result<()> {
    //初始化txn_manager实例
        let txn_manager = Arc::new(MempoolProxy::new(self.mempool_client.clone()));
        //初始state_computer实例
        let state_computer = Arc::new(ExecutionProxy::new(
            self.execution_client.clone(),
            self.synchronizer_client.clone(),
        ));
        debug!("Starting consensus provider.");
        //启动smr实例
        self.smr.start(txn_manager, state_computer)
    }
    //停止libra实例
    fn stop(&mut self) {
        //停止smr实例
        self.smr.stop();
        debug!("Consensus provider stopped.");
    }
}

上述提到的 smr 是一个ChainedBftSMR的实例,ChainedBftSMR是libra StateMachineReplicaTIon接口的具体实现,ChainedBftSMR.start()是启动smr的完整流程。主要包括3个阶段,第一步:首先会同步到网络中的最新状态;第二步:初始化 block_store、proposal_generator、safety_rules、pacemaker、event_processor等;第三步:启动事件处理handler。

目前只是一个系统原型,某些方面做了简化。但是主要有的几个部件都有了,剩下的工作可以在此基础上进行开发。在Libra早期阶段,使用外部认可的基金会成员作为记账员,简化了激励机制以及提高了系统响应速度。

 

Step 1:

//./consensus/src/chained_bft/chained_bft_smr.rs
impl<T: Payload, P: ProposerInfo> StateMachineReplication for ChainedBftSMR<T, P> {
    type Payload = T;
    //ChainedBftSMR启动服务,该函数启动后共识服务就会启动起来,直到stop()方法被调用
    fn start(
        &mut self,
        txn_manager: Arc<dyn TxnManager<Payload = Self::Payload>>,
        state_computer: Arc<dyn StateComputer<Payload = Self::Payload>>,
    ) -> Result<()> {
        let executor = self
            .runtime
            .as_mut()
            .expect("Consensus start: No valid runtime found!")
            .executor();
        let time_service = Arc::new(ClockTimeService::new(executor.clone()));

        // We first start the network and retrieve the network receivers (this function needs a
        // mutable reference).
        // Must do it here before giving the clones of network to other components.
        //Step 1:启动网络模块,节点需要首先强制同步到网络的最新状态,如果同步一直失败,则节点直接panic
        let network_receivers = self.network.start(&executor);
        //获取节点启动是的初始状态
        let initial_data = self
            .initial_data
            .take()
            .expect("already started, initial data is None");
        let consensus_state = initial_data.state();
        let highest_timeout_certificates = initial_data.highest_timeout_certificates().clone();
           //通过节点的初始状态判断节点是否需要与周围节点进行同步
        if initial_data.need_sync() {
           //强制地同步到最新的状态,如果没有成功则直接退出
            loop {
                // make sure we sync to the root state in case we're not
               //进行状态同步
               let status = block_on(state_computer.sync_to(initial_data.root_ledger_info()));
               //对Status结果进行判断
               match status {
               //同步成功,退出循环
                    Ok(SyncStatus::Finished) => break,
                    //同步失败,退出程序
                    Ok(SyncStatus::DownloadFailed) => {
                        warn!("DownloadFailed, we may not establish connection with peers yet, sleep and retry");
                        // we can remove this when we start to handle NewPeer/LostPeer events.
                        thread::sleep(Duration::from_secs(2));
                    }

Step 2

   //Step 2:初始化block_store.proposal_generator、safety_rues、pacemaker、event_processor等
   //block_store是libra内存忠存储区块的实例
   let block_store = Arc::new(block_on(BlockStore::new(
                Arc::clone(&self.storage),
                initial_data,
                signer,
                Arc::clone(&state_computer),
                true,
                self.config.max_pruned_blocks_in_mem,
            )));

            self.block_store = Some(Arc::clone(&block_store));

            // txn manager is required both by proposal generator (to pull the proposers)
            // and by event processor (to update their status).
            //proposal_generator用于产生新的提案,入参例包括txs_manager,txn_manager是proposalGenerator必须的,用于拉取proposers
            let proposal_generator = ProposalGenerator::new(
                block_store.clone(),
                Arc::clone(&txn_manager),
                time_service.clone(),
                self.config.max_block_size,
                true,
            );
            //safety_rules用于保证consensus的一致性,主要包括二个rule,voting规则和commit规则
            let safety_rules = Arc::new(RwLock::new(SafetyRules::new(
                block_store.clone(),
                consensus_state,
            )));

            let (external_timeout_sender, external_timeout_receiver) =
                channel::new(1_024, &counters::PENDING_PACEMAKER_TIMEOUTS);
            let (new_round_events_sender, new_round_events_receiver) =
                channel::new(1_024, &counters::PENDING_NEW_ROUND_EVENTS);
            //pacemaker用于保证consensusliveness,其内部有相关机制保证在某个Leader节点失活的情况下,系统能够恢复对外提供服务
            let pacemaker = self.create_pacemaker(
                executor.clone(),
                self.storage.persistent_liveness_storage(),
                safety_rules.read().unwrap().last_committed_round(),
                block_store.highest_certified_block().round(),
                highest_timeout_certificates,
                time_service.clone(),
                new_round_events_sender,
                external_timeout_sender,
            );

            let (winning_proposals_sender, winning_proposals_receiver) =
                channel::new(1_024, &counters::PENDING_WINNING_PROPOSALS);
            let proposer_election = self.create_proposer_election(winning_proposals_sender);
            let event_processor = Arc::new(futures_locks::RwLock::new(EventProcessor::new(
                self.author,
                Arc::clone(&block_store),
                Arc::clone(&pacemaker),
                Arc::clone(&proposer_election),
                proposal_generator,
                safety_rules,
                state_computer,
                txn_manager,
                self.network.clone(),
                Arc::clone(&self.storage),
                time_service.clone(),
                true,
            )));

Step 3

//Step3:启动事件处理服务,用与处理所收到的所有时间,包括new_round,proposal,winning_proposals,block_retiervals,
//chunk_retievale,chunk_retiewvals,votes,new_round_req,outgoing pacemake timeout等
      self.start_event_processing(
                event_processor,
                executor.clone(),
                new_round_events_receiver,
                winning_proposals_receiver,
                network_receivers,
                external_timeout_receiver,
            );
        } else {
            panic!("start called twice on the same Chained BFT SMR!");
        }

        debug!("Chained BFT SMR started.");
        Ok(())
    }
    //ChainedBftSM停止函数,该函数是个异步的过程,回等所有的子模块执行完毕后再结束
    /// Stop is synchronous: waits for all the worker threads to terminate.
    fn stop(&mut self) {
        if let Some(rt) = self.runtime.take() {
            block_on(rt.shutdown_now().compat()).unwrap();
            debug!("Chained BFT SMR stopped.")
        }
    }

 

6、加密算法

用到的加密算法

SHA-3:作为主要的哈希函数算法。

X25519:用于密钥交换的算法。它用于通过噪声协议框架保证验证器之间的通信安全。它基于x25519-dalek库。

Ed25519:用于共识签名与事务签名的算法。

HKDF:基于hmac的基于RFC 5869的提取扩展key派生函数(HKDF)。它用于从salt(可选)、seed和application-info(可选)生成keys。

BLS12381:门限签名算法。BLS签名目前正在进行标准化过程。

ECVRF:基于curve25519实现一个可核查的VRF算法 。

SLIP-0010:对Ed25519实现通用层次的key推导算法。

 

模块结构

legacy_crypto

legacy_crypto实现了所有初始加密:散列、签名和密钥派生/生成。

 

    legacy_crypto/src
    ├── signing.rs          # Ed25519签名
    ├── hash.rs             # SHA-3哈希
    ├── hkdf.rs             # HKDF实现
    ├── x25519.rs           # X25519 keys产生
    ├── macros/             # SilentDebug和SilentDisplay的派生
    ├── utils.rs            
    ├── unit_tests          
    └── lib.rs

nextgen_crypto

nextgen文件夹包含Libra加密API的未来版本,以及将在未来版本中使用的几种算法。

 

nextgen_crypto/src
├── bls12381.rs         # 对traits.rs的Bls12-381接口签名验证API的实现
├── ed25519.rs          # 对traits.rs的Ed25519接口签名验证API的实现
├── lib.rs
├── slip0010.rs         # 对Ed25519进行通用层次key推导
├── test_utils.rs
├── traits.rs           # 新的API设计和必要的抽象接口
├── unit_tests/         # Tests
└── vrf/                
    ├── ecvrf.rs        # 使用curve25519和SHA512实现ECVRF and SHA512
    ├── mod.rs
    └── unit_tests      # Tests

Secret Service

密钥服务是一个独立的进程,它将管理加密密钥

 

secret_service/src
├── secret_service_server.rs   # Struct SecretServiceServer,它保存生成的密钥的映射,并实现响应请求的API
├── secret_service_client.rs   # 作为一个密钥服务客户端,它提交请求并包装响应
├── secret_service_node.rs     # 打开node_config中指定端口上的连接的服务
├── crypto_wrappers.rs         # 新crypto API的帮助器方法
├── main.rs                    # 运行密钥服务端主程序
├── unit_tests                 # Tests
├── lib.rs
└── proto/              
    └── secret_service.proto    # 可调用函数的Rpc定义、请求和响应消息的格式以及错误代码

7、总结

Libra现阶段主要还是实现了交易的签名、交易池的交易查询、账户创建相关模块。共识模块还是独立实现的模块,还没有和主流程很好的衔接。benchmark的测试也还没有提供测试的脚本或参数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值