藏川线前段

--- 摄于 2017 年 9 月 藏川线前段

CITA系列之执行器——Executor

写在前面

在之前,chain 和 executor 是一个模块,后来,由于想要支持多执行器并行,将 executor 单独拆出来,目前还有一些冗余代码、一些需要改动的地方,而且,并行计算还没有开始支持。cita 与 以太坊 的架构上有一些不同,以太坊的共识,是直接共识执行结果,而 cita 采用的是复制状态机的模型,共识的是交易的顺序,共识开始(预执行)或者完成后,才进行交易执行,状态更新等操作。

Executor

executor 总共做了两件事:

go 合约的实现类似于 fabric ,用 gRPC 留了一个接口,链上注册函数,执行过程留给外部执行器,等待返回结果并存储,理论上这个模式的执行器可以支持任何语言的合约执行,前提是有对应语言的外部执行器。

executor 的状态机状态如下:

#[derive(Debug, Clone)]
pub enum Stage {
    /// Exeuting block
    ExecutingBlock,
    /// Executing proposal
    ExecutingProposal,
    /// Finish executing proposal and wait
    WaitFinalized,
    /// Finalized
    Idle,
}

注释比较清晰了,这里涉及一个预执行 proposal 的状态,整个流程就是 ExecutingProposal -> WaitFinalized(ExecutingBlock) -> Idle -> ExecutingProposal(ExecutingBlock) 这样的逻辑,内部还有一个标志位 is_interrupted 用来控制交易是否继续执行。

代码分享

gRPC server

代码:https://github.com/cryptape/cita/blob/develop/cita-executor/src/main.rs#L159

thread::spawn(move || loop {
        if server.is_none() {
            server = vm_grpc_server(
                grpc_ext.grpc_port,
                Arc::clone(&service_map),
                Arc::clone(&grpc_ext.ext),
            );
        } else {
            thread::sleep(Duration::new(8, 0));
        }
    });

尝试建立 gRPC server ,发送交易到外部及获取结果在 executor 执行交易处

消息分发及处理

代码:https://github.com/cryptape/cita/blob/develop/cita-executor/src/executor_instance.rs#L82

这里监听 MQ 消息分为几类:

交易执行

代码:https://github.com/cryptape/cita/blob/develop/cita-executor/src/executor_instance.rs#L189

整体思路是,取出 block_map 中对应高度的块,分为三类:

这一块因为存在预执行,所以状态显得比较复杂。块的来源从上面看是有三个的,预执行就是在共识未达成之前,取一个已经签名的 proposal 开始执行,并每执行 255 个交易检查一下是否需要放弃当前块,去执行新的 proposal 或者是 共识块,executor 认为,同一高度后来的 proposal 是趋向于正确的块,打断这一块的代码在如下地址:

https://github.com/cryptape/cita/blob/develop/cita-executor/core/src/libexecutor/block.rs#L421

接到的每个块想要执行首先要经过一系列的验证后才能进入执行阶段,尤其重要的是这个 proof,是共识的证明,如果是共识块,结构体是 block_with_proof,即自带 proof。而同步块的 proof 是在后一个块上,如果是最后一个块,则会把 proof 作为 u64::Max 块发送过来,即要证明当前块有效,必须有下一个块到来,延时确认。这一块同步逻辑会单独作为一篇的主题进行讲解。

总结

目前的 executor,维护了全局状态,导致 executor 和 chain 的状态需要实时同步,并不是单纯的执行器,理论上执行器应该是个类似于 actor 样的东西,接收数据,按照既定逻辑执行,然后返回值,无状态的执行器。这方面的考虑也在进行中,也许后期会直接把状态给剥离掉,变成单纯的执行器。

看到这里的朋友,可以看出其实每个模块里面的一些思路都是类似的,消息分发,超时机制等等,这方面可以抽一个微服务框架出来,最近也在考虑做这个事情,抽离一些不必要的重复逻辑,让每个模块专注于处理自己的事情,框架负责稳定性和消息分发。

好,下一篇应该是 chain,那我们下周再会。

评论区

加载更多

登录后评论