转载

Metaverse区块链启动流程浅析

元界区块链启动流程浅析

元界(Metaverse)旨在搭建一个点对点的、由数字资产驱动生活和金融应用的虚拟世界,希望个人以及企业用户可以像现在的互联网一样,方便快捷地使用元界的各项区块链功能,特别是进行点对点的价值的交换过程。元界主链代码 Metaverse 是基于比特币技术体系中,选取以 libbitcoin 为框架,新增了Account、Miner、mongoose 等模块,大幅修改了 consensus 模块,新增了币奖励的 coinbase 交易。

接下来我将分一下 Metaverse 节点程序 mvsd 的启动流程,mvsd 的启动大致可以分为两块:start 与 run。

一,start

mvsd

mvsd 是元界区块链节点运行程序,我们从其 main() 入手分析其启动流程。在 src/mvsd/main.cpp 文件的 main() 函数中,主要是读取配置文件,然后生成 executor 对象,调用其 menu() 方法:

executor host(metadata, cin, *out, *err);
    return host.menu() ? console_result::okay : console_result::failure;

executor

executor 一如其名,是整个节点运转的执行者。其入口是 menu() 方法,在其中解析命令行参数,执行相应的操作。在这里我们只分析节点正常运行的分支,也就是初始化链以及运行:

auto result = do_initchain(); // false means no need to initial chain
    ...
    // There are no command line arguments, just run the server.
    return run();

do_initchain() 中主要干了三件事:

  1. 创建创世区块
  2. 初始化数据库
  3. 设置 admin 账户

主逻辑全都在 run() 中:根据配置创建 server_node ,再将 handle_started 当作回调参数调用其 start() 方法初始化节点链接以加入区块链网络。

server_node

server_node 继承自 p2p_nodep2p_node 又继承自 p2p 。因此对 server_node.start() 调用以及就开启了一条转调基类方法的传递链:

p2p_node.start() 中调用 block_chain_impl.start() 启动区块链

p2p.start() 中初始化线程池,启动订阅器,并将 handle_manual_started() 当作回调调用 manual_session.start() 启动 manual_session()

在回调 p2p.handle_manual_started() 函数中,启动线程池,装载 host 节点,并将 handle_started() 当作回调调用 seed_session.start() 启动 seed_session

在回调 p2p.handle_started() 函数中,转调 executor.handle_started() ,这样调用流程又回到了 executor 中。

至此 start 流程走完,start 主要是链接节点加入区块链网络。

二,run

executor

在回调 executor.handle_started() 中调用 server_node.run() 进入各种服务的处理循环,直到节点退出运行。

server_node

server_node.run() 中:

首先启动 HttpServer (用于处理 RESTful API 请求) 和 WebSocketServer (用于处理 WebSocket 请求),然后将 handle_running 当作回调参数转调父类 p2p_node.run()

p2p_node

p2p_node.run() 中,将 handle_headers_synchronized() 当作回调参数调用 header_sync_session.start() 开始同步区块头数据。区块头数据同步完成后回调 handle_headers_synchronized() 回到 p2p_node 中。接着将 handle_running() 当作回调参数调用 block_sync_session.start() 开始同步区块数据。区块数据同步完成后回调 handle_running() 回到 p2p_node 中。在 handle_running 中设置区块高度,并调用父类 p2p.run()

p2p

p2p.run() 中,将 handle_running() 当作回调参数依次启动 inbound_sessionoutbound_session 用于处理节点的链入与链出。处理完毕之后回调到 p2p.handle_running() ,在这个方法中仅仅是转调回掉函数 server_node.handle_running() ,这样流程又回到了 server_node 中。

server_node

server_node.handle_running() 中启动各种服务:认证、查询、心跳、区块、交易服务。

bool server_node::start_services()
{
    return
        start_authenticator() && start_query_services() &&
        start_heartbeat_services() && start_block_services() &&
        start_transaction_services();
}

然后回调 executor.handle_running() ,绕了一大圈终于又回到了起点 executor

executor

executor.handle_running() 什么也没有干,仅仅是 log 打印了一下,因为各种服务都已经启动完毕,没什么事情需要 executor 操劳了。

启动流程时序图

打开链接 启动流程时序图 ,点击图片区域选择在新窗口打开,即可看到完整的启动流程时序图。

简化实现

由于metaverse代码中大量使用嵌套回调handler,导致调用流程不容易理解,针对上面的 run() 流程,我写了一个简化版调用流程代码metaverse_run.cpp,这样就容易理解了。

// g++ -Wall -std=c++11 metaverse_run.cpp -o metaverse_run

#include <iostream>
#include <functional>

typedef std::function<void(const int&)> result_handler;

void execute_handler(result_handler handler)
{
    handler(1);
}

class p2p
{
public:
    virtual void run(result_handler handler) {
        std::cout << "p2p::run: " << std::endl;
        execute_handler(
            std::bind(&p2p::handle_running,
                this, std::placeholders::_1, handler));
    }

private:
    void handle_running(const int& ec, result_handler handler)
    {
        std::cout << "p2p::handle_running: " << ec << std::endl;
        handler(ec);
    }
};

class p2p_node
  : public p2p
{
public:
    virtual void run(result_handler handler) {
        std::cout << "p2p_node::run: " << std::endl;
        execute_handler(
            std::bind(&p2p_node::handle_running,
                this, std::placeholders::_1, handler));
    }

private:
    void handle_running(const int& ec, result_handler handler)
    {
        std::cout << "p2p_node::handle_running: " << ec << std::endl;
        p2p::run(handler);
    }
};

class server_node
  : public p2p_node
{
public:
    virtual void run(result_handler handler) {
        std::cout << "server_node::run: " << std::endl;
        p2p_node::run(
            std::bind(&server_node::handle_running,
                this, std::placeholders::_1, handler));
    }

private:
    void handle_running(const int& ec, result_handler handler)
    {
        std::cout << "server_node::handle_running: " << ec << std::endl;
        handler(ec);
    }
};

class executor {
public:
    void start() {
        std::cout << "executor::start" << std::endl;
        server_node node;
        node.run(
            std::bind(&executor::handle_running,
                this, std::placeholders::_1));
    }
private:
    void handle_running(const int& ec) {
        std::cout << "executor::handle_running: " << ec << std::endl;
    }
};

int main(){
    executor exec;
    exec.start();
}

运行 ./metaverse_run 即可清楚地看到调用流程如下:

executor::start
server_node::run: 
p2p_node::run: 
p2p_node::handle_running: 1
p2p::run: 
p2p::handle_running: 1
server_node::handle_running: 1
executor::handle_running: 1
原文  https://blog.csdn.net/kesalin/article/details/79917150
正文到此结束
Loading...