写点什么

chianmaker 交易初探

作者:liwh1227
  • 2023-02-28
    山东
  • 本文字数:3216 字

    阅读完需:约 11 分钟

chianmaker交易初探

前言

本文基于 chainmaker v2.3.1 版本分析,主要使用 TBFT 的共识算法和 Noraml Tx Pool 的交易池类型,分享 chainmaker 交易的整个生命周期及在各阶段流转过程中不同模块的主要工作。


本文从客户端发起普通合约调用讲起,描述该交易从生成到落盘的整个过程,为了避免陷入细节而引入额外的复杂度,本文未涉及 chainmaker 代码部分,希望读者通过本文对 chainmaker 交易的整个生命周期有所了解。图 1.1 为 chainmaker 核心流程(此图只简述了 chianmaker 的核心模块,未涉及区块链 sdk 模块)。

图1.1 chainmaker核心流程

交易缓存模块:为提高交易并发能力引入的中间缓存,来自 RPC 模块的交易会首先进入到该结构中;

区块提议模块:提议节点发起区块提议,生成必要结构提交至交易调度模块;

交易调度模块:连接核心模块和合约模块,区块的 DAG 结构在此模块中生成;

智能合约模块:智能合约实际运行的模块,该模块将交易执行的读写集结果返回给交易调度模块;

区块验证模块:区块验证模块会接受待验证的区块,模拟执行区块中的交易,并将验证结果提交至共识模块;

共识算法模块:该模块会根据当前网络的共识算法使多个节点达成相同的数据状态;

数据存储模块:将完成共识的区块提交至账本,并进行数据的最终落盘。

交易会在上述各模块中流转,并最终会被打包到区块并记录到磁盘中,下面我们会从交易生成开始。

交易生成

用户的请求给到客户端后,客户端会构建出一笔有效交易,交易中包括以下关键信息:


  1. 发送方:即用户自己的 sdk 客户端,用于表明交易来自何处;

  2. 交易相关的数据:一笔交易往往需要一些用户提供的输入来执行用户期望的操作,这些输入被编码到交易的payload结构中;

  3. 交易签名:为了表明交易确实是由自己发送,用户会向 SDK 提供私钥来让客户端对交易进行签名,其中私钥和用户账户是一一对应的关系。


之后,区块链客户端会再向交易填充一些必要的字段,如用于防交易重放的交易 ID、交易类型等。交易的具体结构和字段含义可以参考chainmaker交易结构,交易构造完成后,客户端随后便通过 RPC 的方式将交易发送给节点(调用节点的 RPC Client)。主要调用过程如图 1.2 所示。

图1.2 交易在客户端流转过程

交易池

交易池即图 1.1 的交易缓存模块。交易池具备主要作用如下:


  • 接收客户端发送过来的交易,并将有效的交易广播给其他的节点;

  • 对交易 ID、时间戳、签名等进行有效性检查以及交易是否存在“双花”的防重检查;

  • 缓存交易,并在共识提案时为核心引擎模块提供一批有效的交易;


添加至交易池的交易来源 TxSource,有三种类型:RPCP2PINTERNAL,不同来源的交易,对应着不同的检查。


  • RPC:对来自 RPC 的交易,交易池不进行交易基础信息的有效性检查(如交易 ID 是否符合规范、时间戳是否过期,交易签名是否有效),只进行防重检查,因为 RPC 模块已做此类检查

  • P2P:对其它节点广播过来的交易,需进行全量的检查,包括交易有效性检查、交易在不在交易池或者已经上链的防重检查;

  • INTERNAL:如果节点在同一高度接收到多个验证有效的区块,当其中某个区块上链后,节点会对同一高度的其他区块进行剪枝,被剪枝区块内的交易会被重新添加进交易池,此时交易池会对这些交易进行有效性和防重检查


一笔交易在交易池中的流转过程如下图。

图1.3 交易池主要逻辑

Queue 队列:缓存通过交易有效性检查和防重检查的待打包交易队列;


Pending 队列:缓存已经被打包进区块正在共识中的交易队列。


  • 接收交易:交易池对不同来源的交易会进行不同的处理

  • 对于来自 RPC 的交易,会将有效的交易缓存到待打包队列 Queue 中并将交易广播给其他节点;

  • 对于来自 P2P 或者 INTERNAL 的交易,验证有效后只会放入交易池的 Queue 队列中。

  • 构造区块:主节点的 Core 模块会从交易池 Fetch 一批交易用于构造新的区块,此时交易池会将该批交易从待打包 Queue 队列移至已打包 Pending 缓存中,防止在 MaxBFT 共识下交易被重复打包。

  • 验证区块:从节点在验证区块时会从交易池 Get 块中的交易,对存在于本节点交易池中的交易,Core 模块只需比对块中交易和交易池中交易哈希是否一致即可(因为交易池已经做了相关检查),对于不在本节点交易池中的交易,Core 模块则需要进行交易有效性检查和防重检查。验证区块有效后,Core 模块会通知交易池将块中交易从待打包 Queue 队列中移至已打包 Pending 缓存中,此操作也是确保在 MaxBFT 共识下交易不会被重复打包。

  • 提交区块:在完成共识并提交区块后,主节点和从节点会对同一高度的其他区块进行剪枝,将被剪枝区块中的交易重新放入待打包 Queue 队列中,并将提交的区块中的交易从交易池 Pending 和 Queue 中移除。

交易执行

提议主节点模块会通过定时监听定时器和交易池信号进行提议操作,然后将交易提交接收的一批交易提交至调度模块,获取候选区块并提交至共识模块。


为了更清晰的说明交易在提议阶段如何流转,图 1.4 截取了并修改了图 1.1 的左上部分内容。


图1.4 交易执行


  1. 提议主节点 core 模块从交易缓存模块(交易池)获取一批交易;

  2. 提议模块会生成 snapshot、block 结构,并连同待执行交易提交至交易调度模块;

  3. 交易调度模块并发的执行所接收的交易,生成交易txSimcontext,并将该结构连同待执行的交易提交至智能合约模块,智能合约模块会根据具体的合约类型和虚拟机类型进行合约的执行;

  4. 智能合约模块将执行后的结果(包括读写集结果)返回给交易调度模块,交易调度模块会根据交易中读写集的结果构建 DAG 结构并将该结构存入 block 中;

  5. core 模块会缓存该区块,并记录当前提议的区块高度和其他相关信息;

交易共识

区块链要求节点间就区块的执行结果达成一致才能出块。如果采用 TBFT 算法保证整个系统的一致性,其大概流程是:


  1. proposal 阶段:即交易执行阶段介绍的区块提议过程,leader 节点会将待 commit 的区块信息广播至其他节点;

  2. prevote 阶段:follwer 节点接收到广播的候选区块后,会在本节点进行区块中信息的验证,包括模拟执行区块中的交易信息验证等,验证完成后,会将 prevote 信息广播至其他区块;

  3. precommit 阶段:其他节点接收到针对 proposal 的 >2/3的 prevote 投票信息后,会将 precommit 投票信息广播至其他节点;

  4. commit 阶段:节点接收到针对 proposal 的>2/3 precommit 投票后,提交 proposal 中的区块到账本;

图1.5 tbft共识算法主要阶段

chainmaker verison >= 2.3.0 的版本中,tbft 加入了随机交易剔除的方法,避免随机交易因素影响共识;

交易落盘

在共识出块后,节点需要将区块中的交易及执行结果写入硬盘永久保存,并更新区块高度与区块哈希的映射表等内容,然后节点会从交易池中剔除已落盘的交易,以开始新一轮的出块流程。用户可以通过交易哈希等信息,在链上的历史数据中查询自己感兴趣的交易数据及回执信息。


  1. 首先将序列化后的区块、读写集数据、以及最新的区块高度写入 Block binary log,用于异常中断后的数据恢复。为了提高性能,加入一层 cache,新区块提交请求在更新完 Block binary log 之后,再将区块数据写入 cache,在更新完 log 和 cache 后,提交即可返回,由后台线程异步更新 Block DB、State DB、ContractEvent DB、History DB 和 Result DB。

  2. 在 Block DB 中记录区块元信息与交易信息,其中交易信息以 TxID 作为主键存储,区块信息以 BlockHeight 作为主键存储,区块元信息中只记录交易 ID 列表,同时索引 BlockHash 到 BlockHeight 的映射关系。Block DB 中额外记录了当前最新的区块高度(LastBlockHeight)作为 checkpoint,用以重启后的数据恢复。

  3. 在 State DB 中保存 state 数据,key 为合约名与对象主键的组合:<contractName, ObjectKey>,同时记录最新的区块高度(LastBlockHeight)作为 checkpoint。

  4. 在 History DB 中记录交易产生的三种类型的索引:

  5. 状态变更历史,以<contractName, ObjectKey,TxId>为索引

  6. 合约调用历史,以<contractName, TxId>为索引

  7. 账户交易历史,以<accountId,TxId>为索引

  8. 在 Result DB 中记录交易的读写集,读写集以 TxID 作为 key,同时记录最新的区块高度(LastBlockHeight)作为 checkpoint。

  9. 在 ContractEventDB 中记录下交易结果的 EventLog,并记录最新区块高度作为 checkpoint。

参考

  1. 长安链官方文档:https://docs.chainmaker.org.cn/#id1

  2. 长安链官方代码库:https://git.chainmaker.org.cn/chainmaker/chainmaker-go

  3. 图 1.1、图 1.3、图 1.5 来自官方文档截图

发布于: 刚刚阅读数: 3
用户头像

liwh1227

关注

还未添加个人签名 2021-04-06 加入

还未添加个人简介

评论

发布
暂无评论
chianmaker交易初探_区块链_liwh1227_InfoQ写作社区