平台介绍
FISCO BCOS是一个区块链底层平台,由金融区块链合作联盟(深圳)(以下简称:金链盟)开源工作组以金融业务实践为参考样本,在BCOS开源平台基础上进行模块升级与功能重塑。特点:深度定制的安全可控、适用于金融行业且完全开源。金链盟开源工作组的首批成员包括:微众银行、深证通、腾讯、华为、神州信息、四方精创、博彦科技、越秀金科、亦笔科技等9家单位。
FISCO BCOS 2.0
FISCO BCOS 2.0版本在原有基础上进行架构升级和优化,在可扩展性、性能、易用性等方面取得了重大突破,其中包括:
- 实现群组架构,在多个节点组成的一个全局网络中,可以存在多个节点子集组成的子网络,这些子网络维护一个独立的账本。这些账本之间的共识、存储都是相互独立的,具备良好的扩展性和安全性。在群组架构中,可以更好地实现平行扩展,满足金融级高频交易场景的需求。同时,群组架构可以快速支持组链需求,极大降低运维难度,真正能够实现企业间建链就像建“聊天群”一样简便。
- 支持分布式存储,使存储突破单机限制,支持横向扩展。计算和存储分离,提高了系统健壮性,即使节点执行服务器故障,数据也不会受影响。分布式存储定义了标准的数据访问CRUD接口,可以适配多种存储系统,同时支持SQL和NoSQL两种数据管理方式,可以更简便地支持多种业务场景。
- 实现预编译合约框架,突破EVM性能瓶颈。支持交易并发处理,大幅提升交易处理吞吐量。预编译合约采用C++实现,内置于底层系统中,区块链自动识别调用合约的交易互斥信息,构建DAG依赖,规划出一个高效的并行交易执行路径。最佳情况下,性能提升N倍(N=CPU核数)。
系统设计
整体架构
整体架构上,FISCO BCOS划分成基础层、核心层、管理层和接口层:
- 基础层:提供区块链的基础数据结构和算法库
- 核心层: 实现了区块链的核心逻辑,核心层分为两大部分:
- 链核心层: 实现区块链的链式数据结构、交易执行引擎和存储驱动
- 互联核心层: 实现区块链的基础P2P网络通信、共识机制和区块同步机制
- 管理层: 实现区块链的管理功能,包括参数配置、账本管理和AMOP
- 接口层: 面向区块链用户,提供多种协议的RPC接口、SDK和交互式控制台
FISCO BCOS基于多群组架构实现了强扩展性的群组多账本,基于清晰的模块设计,构建了稳定、健壮的区块系统。
FISCO BCOS的群组架构和系统运行时的交易流(包括交易提交、打包、执行和上链)。
同步
同步基础流程
同步,是区块链节点非常重要的功能。它是共识的辅助,给共识提供必需的运行条件。同步分为交易的同步和状态的同步。交易的同步,确保了每笔交易能正确的到达每个节点上。状态的同步,能确保区块落后的节点能正确的回到最新的状态。只有持有最新区块状态的节点,才能参与到共识中去。
区块同步优化
为了增强区块链系统在网络带宽受限情况下的可扩展性,FISCO BCOS v2.2.0对区块同步进行了优化:
- 为了降低单个节点的出带宽,消除网络带宽对网络规模的限制,支持更大网络规模,采用树状拓扑进行区块同步
- 采用gossip协议来保障树状拓扑区块同步的健壮性,定期同步区块状态,使得在部分节点网络断连的情况下,所有节点均能同步到最新区块状态。
交易同步优化
区块链系统中,为了保障客户端发送的交易能到达所有节点,SDK直连的区块链节点需要将收到的交易广播给其他节点,如下图所示:
显然,SDK直连节点的出带宽与区块链节点总数成正比,随着区块链系统节点数的增加,该节点必然成为整个系统的瓶颈。
此外,为了保障节点网络断连的情况下,交易也能尽量到达所有节点,还引入了交易转发逻辑,节点收到其他节点广播过来的交易后,会随机选取25%的邻居节点转发收到的交易,在网络全连的情况下,这种交易转发策略无疑会带来巨大的带宽浪费,且节点数目越多,因交易转发带来的数据包冗余越多。
为降低SDK直连节点的出带宽、降低交易转发引起的大量冗余消息包,提升区块链系统的可扩展性,FISCO BCOS v2.2.0提出了交易广播优化策略和交易转发优化策略。
共识算法
区块链系统通过共识算法保障系统一致性。 理论上,共识是对某个提案(proposal)达成一致意见的过程,分布式系统中提案的含义十分宽泛,包括事件发生顺序、谁是leader等。区块链系统中,共识是各个共识节点对交易执行结果达成一致的过程。
共识算法分类
根据是否容忍 拜占庭错误 ,共识算法可分为容错(Crash Fault Tolerance, CFT)类算法和拜占庭容错(Byzantine Fault Tolerance, BFT)类算法:
- CFT类算法 :普通容错类算法,当系统出现网络、磁盘故障,服务器宕机等普通故障时,仍能针对某个提议达成共识,经典的算法包括Paxos、Raft等,这类算法性能较好、处理速度较快、可以容忍不超过一半的故障节点;
- BFT类算法 :拜占庭容错类算法,除了容忍系统共识过程中出现的普通故障外,还可容忍部分节点故意欺骗(如伪造交易执行结果)等拜占庭错误,经典算法包括PBFT等,这类算法性能较差,能容忍不超过三分之一的故障节点。
FISCO BCOS共识算法
FISCO BCOS基于多群组架构实现了插件化的共识算法,不同群组可运行不同的共识算法,组与组之间的共识过程互不影响,FISCO BCOS目前支持PBFT(Practical Byzantine Fault Tolerance)和Raft(Replication and Fault Tolerant)两种共识算法:
- PBFT共识算法: BFT类算法,可容忍不超过三分之一的故障节点和作恶节点,可达到最终一致性;
- Raft共识算法: CFT类算法, 可容忍一半故障节点,不能防止节点作恶,可达到一致性。
虚拟机与合约
交易的执行是区块链节点上的一个重要的功能。交易的执行,是把交易中的智能合约二进制代码取出来,用执行器(Executor)执行。共识模块(Consensus)把交易从交易池(TxPool)中取出,打包成区块,并调用执行器去执行区块中的交易。在交易的执行过程中,会对区块链的状态(State)进行修改,形成新区块的状态储存下来(Storage)。执行器在这个过程中,类似于一个黑盒,输入是智能合约代码,输出是状态的改变。
随着技术的发展,人们开始关注执行器的性能和易用性。一方面,人们希望智能合约在区块链上能有更快的执行速度,满足大规模交易的需求。另一方面,人们希望能用更熟悉更好用的语言进行开发。进而出现了一些替代传统的执行器(EVM)的方案,如:JIT、 WASM_甚至JVM。然而,传统的EVM是耦合在节点代码中的。首先要做的,是将执行器的接口抽象出来,兼容各种虚拟机的实现。因此,EVMC被设计出来。
EVMC (Ethereum Client-VM Connector API),是以太坊抽象出来的执行器的接口,旨在能够对接各种类型的执行器。FISCO BCOS目前采用了以太坊的智能合约语言Solidity,因此也沿用了以太坊对执行器接口的抽象。
在节点上,共识模块会调用EVMC,将打包好的交易交由执行器执行。执行器执行时,对状态进行的读写,会通过EVMC的回调反过来操作节点上的状态数据。
经过EVMC一层的抽象,FISCO BCOS能够对接今后出现的更高效、易用性更强的执行器。目前,FISCO BCOS采用的是传统的EVM根据EVMC抽象出来的执行器—Interpreter。因此能够支持基于Solidity语言的智能合约。目前其他类型的执行器发展尚未成熟,后续将持续跟进。
存储模块
FISCO BCOS继承以太坊存储的同时,引入了高扩展性、高吞吐量、高可用、高性能的分布式存储。存储模块主要包括两部分:
世界状态: 可进一步划分成 MPTState 和 StorageState
- MPTState: 使用MPT树存储账户的状态,与以太坊一致
- StorageState: 使用分布式存储的表结构存储账户状态,不存历史信息,去掉了对MPT树的依赖,性能更高
分布式存储(Advanced Mass Database,AMDB): 通过抽象表结构,实现了SQL和NOSQL的统一,通过实现对应的存储驱动,可以支持各类数据库,目前已经支持LevelDB和MySQL。
安全控制
为了保障节点间通信安全性,以及对节点数据访问的安全性,FISCO BCOS引入了节点准入机制、CA黑名单和权限控制三种机制,在网络和存储层面上做了严格的安全控制。
网络层面安全控制
- 节点使用 SSL连接 ,保障了通信数据的机密性
- 引入 网络准入机制 ,可将指定群组的作恶节点从共识节点列表或群组中删除,保障了系统安全性
- 通过 群组白名单机制 ,保证每个群组仅可接收相应群组的消息,保证群组间通信数据的隔离性
- 引入 CA黑名单机制 ,可及时与作恶节点断开网络连接
- 提出 分布式存储权限控制 机制,灵活、细粒度地控制外部账户部署合约和创建、插入、删除和更新用户表的权限。
存储层面安全控制
基于分布式存储,提出分布式存储权限控制的机制,以灵活、细粒度的方式进行有效的权限控制,设计并实现了权限控制机制限制外部账户(tx.origin)对存储的访问,权限控制范围包括合约部署、表的创建、表的写操作。
P2P网络
设计目标
FISCO BCOS P2P模块提供高效、通用和安全的网络通信基础功能,支持区块链消息的单播、组播和广播,支持区块链节点状态同步,支持多种协议。
P2P主要功能
- 区块链节点标识
通过区块链节点标识唯一标识一个区块链节点,在区块链网络上通过区块链节点标识对区块链节点进行寻址 - 管理网络连接
维持区块链网络上区块链节点间的TCP长连接,自动断开异常连接,自动发起重连 - 消息收发
在区块链网络的区块链节点间,进行消息的单播、组播或广播 - 状态同步
在区块链节点间同步状态
区块链节点标识
区块链节点标识由ECC算法的公钥生成,每个区块链节点必须有唯一的ECC密钥对,区块链节点标识在区块链网络中唯一标识一个区块链节点
通常情况下,一个节点要加入区块链网络,至少要准备三个文件:
- node.key 节点密钥,ECC格式
- node.crt 节点证书,由CA颁发
- ca.crt CA证书,CA机构提供
区块链节点除了有唯一区块链节点标识,还能关注Topic,供寻址使用
区块链节点寻址:
- 区块链节点标识寻址
通过区块链节点标识,在区块链网络中定位唯一的区块链节点 - Topic寻址
通过Topic,在区块链网络中定位一组关注该Topic的节点
管理网络连接
区块链节点间,会自动发起和维持TCP长连接,在系统故障、网络异常时,主动发起重连
区块链节点间建立连接时,会使用CA证书进行认证
区块链节点间消息支持单播、组播和广播
- 单播,单个区块链节点向单个区块链节点发送消息,通过区块链节点标识寻址
- 组播,单个区块链节点向一组区块链节点发送消息,通过Topic寻址
- 广播,单个区块链节点向所有区块链节点发送消息
状态同步
每个节点会维护自身的状态,并将状态的Seq在全网定时广播,与其它节点同步
RPC
RPC(Remote Procedure Call,远程过程调用)是客户端与区块链系统交互的一套协议和接口。用户通过RPC接口可查询区块链相关信息(如块高、区块、节点连接等)和发送交易。
名词解释
JSON(JavaScript Object Notation):一种轻量级的数据交换格式。它可以表示数字、字符串、有序序列和键值对。
JSON-RPC:一种无状态、轻量级的远程过程调用协议。 该规范主要定义了几个数据结构及其处理规则。它允许运行在基于socket,http等诸多不同消息传输环境的同一进程中。它使用JSON (RFC 4627)作为数据格式。FISCO BCOS采用JSON-RPC 2.0协议。
模块架构
RPC模块负责提供FISCO BCOS的外部接口,客户端通过RPC发送请求,RPC通过调用账本管理模块和p2p模块获取相关响应,并将响应返回给客户端。其中账本管理模块通过多账本机制管理区块链底层的相关模块,具体包括共识模块,同步模块,区块管理模块,交易池模块以及区块验证模块。
数据定义
客户端请求
客户端请求发送至区块链节点会触发RPC调用,客户端请求包括下列数据成员:
- jsonrpc: 指定JSON-RPC协议版本的字符串,必须准确写为“2.0”。
- method: 调用方法的名称。
- params: 调用方法所需要的参数,方法参数可选。由于FISCO BCOS 2.0启用了多账本机制,因此本规范要求传入的第一个参数必须为群组ID。
- id: 已建立客户端的唯一标识ID,ID必须是一个字符串、数值或NULL空值。如果不包含该成员则被认定为是一个通知。
RPC请求包格式示例:
{"jsonrpc": "2.0", "method": "getBlockNumber", "params": [1], "id": 1}
注:
- 在请求对象中不建议使用NULL作为id值,因为该规范将使用空值认定为未知id的请求。
- 在请求对象中不建议使用小数作为id值,因为具有不确定性。
服务端响应
当发起一个RPC调用时,除通知之外,区块链节点都必须回复响应。响应表示为一个JSON对象,使用以下成员:
- jsonrpc: 指定JSON-RPC协议版本的字符串。必须准确写为“2.0”。
- result: 正确结果字段。该成员在响应处理成功时必须包含,当调用方法引起错误时必须不包含该成员。
- error: 错误结果字段。该成员在失败是必须包含,当没有引起错误的时必须不包含该成员。该成员参数值必须为3.3节中定义的对象。
- id: 响应id。该成员必须包含,该成员值必须与对应客户端请求中的id值一致。若检查请求对象的id错误(例如参数错误或无效请求),则该值必须为空值。
RPC响应包格式示例:
{"jsonrpc": "2.0", "result": "0x1", "id": 1}
注: 服务端响应必须包含result或error成员,但两个成员不能同时包含。
错误对象
当一个RPC调用遇到错误时,返回的响应对象必须包含error错误结果字段,相关的描述和错误码.
RPC接口的设计
FISCO BCOS提供丰富的RPC接口供客户端调用。其中分为3类:
- 以get开头命名的查询接口:例如[getBlockNumber]接口,查询最新的区块高度。
- [sendRawTransaction]接口: 执行一笔签名的交易,将等待区块链共识后才返回响应。
- [call]接口: 执行一个请求将不会创建一笔交易,不需要区块链共识,而是获取响应立刻返回。
数据结构与编码协议
交易结构及其RLP编码描述
FISCO BCOS的交易结构在原以太坊的交易结构的基础上,有所增减字段。FISCO BCOS 2.0+的交易结构字段如下:
name | type | description | RLP index RC1 | RLP index RC2 |
---|---|---|---|---|
type | enum | 交易类型,表明该交易是创建合约还是调用合约交易,初始为空合约 | - | - |
nonce | u256 | 消息发送方提供的随机数,用于唯一标识交易 | 0 | 0 |
value | u256 | 转账数额,目前去币化的FISCO BCOS不使用该字段 | 5 | 5 |
receiveAddress | h160 | 交易接收方地址,type为创建合约时该地址为0x0 | 4 | 4 |
gasPrice | u256 | 本次交易的gas的单价,FISCO BCOS中为固定值300000000 | 1 | 1 |
gas | u256 | 本次交易允许最多消耗的gas数量,FISCO BCOS可配置该值 | 2 | 2 |
data | vector< byte > | 与交易相关的数据,或者是创建合约时的初始化参数 | 6 | 6 |
chainId | u256 | 记录本次交易所属的链信息/业务信息 | - | 7 |
groupId | u256 | 记录本次交易所属的群组 | - | 8 |
extraData | vector< byte > | 预留字段,记录交易信息,内部使用“#”分割信息 | - | 9 |
vrs | SignatureStruct | 交易发送方对交易7字段RLP编码后的哈希值签名生成的数据 | 7,8,9 | 10,11,12 |
hashWith | h256 | 交易结构所有字段(含签名信息)RLP编码后的哈希值 | - | - |
sender | h160 | 交易发送方地址,基于vrs生成 | - | - |
blockLimit | u256 | 交易生命周期,该交易最晚被处理的块高,FISCO BCOS新增字段 | 3 | 3 |
importTime | u256 | 交易进入交易池的unix时间戳,FISCO BCOS新增字段 | - | - |
rpcCallback | function | 交易出块后RPC回调,FISCO BCOS新增字段 | - | - |
RC1的hashWith字段(也称交易hash/交易唯一标识)的生成流程如下:
RC2的生成流程也类似,只是在第一步rlp+hash的transaction结构体中增加chainId、groupId和extraData三个字段。
区块结构及其RLP编码描述
FISCO BCOS的区块由以下五部分组成
rc1版本
name | description | RLP index |
---|---|---|
blockHeader | 区块头RLP编码 | 0 |
transactions | 交易列表RLP编码 | 1 |
transactionReceipts | 交易回执列表RLP编码 | 2 |
hash | 区块头RLP编码后的哈希值 | 3 |
sigList | PBFT共识落盘阶段收集到的节点签名信息,Raft不使用 | 4 |
rc2、rc3、2.0及以上版本
name | description | RLP index |
---|---|---|
blockHeader | 区块头RLP编码 | 0 |
transactions | 交易列表RLP编码 | 1 |
hash | 区块头RLP编码后的哈希值 | 2 |
sigList | PBFT共识落盘阶段收集到的节点签名信息,Raft不使用 | 3 |
transactionReceipts | 交易回执列表RLP编码 | 4 |
FISCO BCOS的区块头中每个字段意义如下:
name | type | description | RLP index |
---|---|---|---|
parentHash | h256 | 父区块的哈希值 | 0 |
stateRoot | h256 | 状态树的根哈希值 | 1 |
transactionsRoot | h256 | 交易树的根哈希值 | 2 |
receiptsRoot | h256 | 收据树的根哈希值 | 3 |
dbHash | h256 | 分布式存储通过计算哈希值来记录一区块中写入的数据,FISCO BCOS新增字段 | 4 |
logBloom | LogBloom | 交易收据日志组成的Bloom过滤器,FISCO BCOS目前尚未使用 | 5 |
number | int64_t | 本区块的块号,块号从0号开始计算 | 6 |
gasLimit | u256 | 本区块中所有交易消耗的Gas上限 | 7 |
gasUsed | u256 | 本区块中所有交易使用的Gas之和 | 8 |
timestamp | int64_t | 打包区块的unix时间戳 | 9 |
extraData | vector | 区块的附加数据,FISCO BCOS目前只用于在第0块中记录群组genesis文件信息 | 10 |
sealer | u256 | 打包区块的节点在共识节点列表中的索引,FISCO BCOS新增字段 | 11 |
sealerList | vector | 区块的共识节点列表(不含观察节点),FISCO BCOS新增字段 | 12 |
hash | h256 | 区块头前13个字段RLP编码后的哈希值,FISCO BCOS新增字段 | - |
交易收据
name | type | description | RLP index |
---|---|---|---|
stateRoot | h256 | 区块状态根 | 0 |
gasUsed | u256 | 交易消耗的gas | 1 |
contractAddress | Address | 部署合约的地址 | 2 |
bloom | h2048 | 布隆滤波器 | 3 |
status | h256 | 交易执行结果的状态码 | 4 |
output | LogBloom | 交易返回值 | 5 |
logs | LogEntry[] | event logs | 6 |
网络传输协议
FISCO BCOS 目前有两类数据包格式,节点与节点间通信的数据包为P2PMessage格式,节点与SDK间通信的数据包为ChannelMessage格式。
交易并行
名词解释
- DAG
一个无环的有向图称做有向无环图(Directed Acyclic Graph),简称DAG图。在一批交易中,可以通过一定方法识别出每笔交易需要占用的互斥资源,再根据交易在Block中的顺序及互斥资源的占用关系构造出一个交易依赖DAG图,如下图所示,凡是入度为0(无被依赖的前序任务)的交易均可以并行执行。如下图所示,基于左图的原始交易列表的顺序进行拓扑排序后,可以得到右图的交易DAG。
模块架构
其中主要流程包括:
- 用户直接或间接通过SDK发起交易。交易可以是能够并行执行的交易和不能并行执行的交易;
- 交易进入节点的交易池中,等待打包;
- 交易被Sealer打包为区块,经过共识后,发送至BlockVerifier进行验证;
- BlockVerifier根据区块中的交易列表生成交易DAG;
- BlockVerifier构造执行上下文,并行执行交易DAG;
- 区块验证通过后,区块上链。