区块链技术丛书
点击查看第二章
点击查看第三章
GO语言公链开发实战
郑东旭 杨明珠 潘盈瑜 翟萌 编著
第1章
公链设计架构
1.1 概述
区块链技术起源于2008年中本聪的论文《比特币:一种点对点电子现金系统》,区块链诞生自中本聪的比特币。
区块链是一个分布式账本,一种通过去中心化、去信任的方式集体维护一个可靠数据库分布式账本是一种在网络成员之间共享、复制和同步的数据库,记录网络参与者之间的交易,比如资产或数据的交换。
区块链分类如下。
- 公链:无官方组织及管理机构,无中心服务器。参与的节点按照系统规则自由地接入网络,节点间基于共识机制开展工作。
- 私链:建立在某个企业内部,系统运作规则根据企业要求进行设定,读写权限仅限于少数节点,但仍保留着区块链的真实性和部分去中心化特性。
- 联盟链:若干个机构联合发起,介于公链和私链之间,兼容部分去中心化的特性。
本书基于国内优秀项目比原链(Bytom),为读者展开公链技术的完整实现。如果说比特币代表区块链1.0时代,以太坊拥有图灵完备性代表的是区块链2.0时代的话,比原链则基于UTXO模型支持了更丰富的功能(图灵完备的智能合约、多资产管理、Tensority新型的PoW共识算法等),其代表的是区块链2.5时代。比原链是一个开源项目,整个项目基于GO语言开发,代码托管于GitHub上(https://github.com/Bytom/bytom )。
本书基于比原链的1.0.5版本源码进行分析。读者不用纠结本书为何不使用比特币或以太坊作为示例,所谓“有道无术,术尚可求也,有术无道,止于术”,作者认为大部分区块链技术实现都是相似的。目前主要在共识算法(PoW、PoS)和模型(UTXO或Account模型)方面有所不同。比原链作为国内优秀的公链,代码量并不多,而且清晰的源码结构使得程序员和链圈爱好者的学习成本也不高。我们从中可以学到很多东西,如GO语言程序设计及应用、公链设计架构、公链运行原理等。
本章主要内容包括:
- 比原链的总体架构。
- 比原链架构内部各模块功能。
- 比原链编译部署及应用。
1.2 公链总体架构
比原链(Bytom Blockchain或者Bytom)是一个开源的有智能合约功能的公共区块链平台。比原链公链设计架构如图1-1所示。
1.3 比原链各模块功能
我们将从图1-1所示的比原链总架构图中抽离出各个模块,逐一分析及阐述。
1.3.1 用户交互层
比原链的用户交互层如图1-2所示。
1. bytomcli客户端
bytomcli是用户与bytomd进程在命令行下建立通信的RPC客户端。在已经部署比原链的机器上,用户能够使用bytomcli可执行文件发起对比原链的多个管理请求。
bytomcli发送相应的请求,请求由bytomd进程接收并处理。bytomcli的一次完整生命周期结束。
2. bytom-dashboard
bytom-dashboard与bytomcli功能类似,都是发送请求与bytomd进程建立通信。用户可通过Web页面与bytomd进程进行更为友好的交互通信。
在已经部署比原链机器上,会默认开启bytom-dashboard功能,无须再手动部署bytom-dashboard。实际上通过传入的参数用户可以决定是否开启或关闭bytom-dashboard功能。如传入--web.closed,则可以关闭该功能。项目源码地址:https://github.com/Bytom/bytom-dashboard 。
1.3.2 接口层
比原链接口层架构如图1-3所示。
API Server是比原链中非常重要的一个功能,在比原链的架构中专门服务于bytomcli和dashboard,它的功能是接收、处理并响应与用户和矿池相关的请求。默认启动9888端口。API Server的总之主要功能如下:
- 接收并处理用户或矿池发送的请求。
- 管理交易,包括打包、签名、提交等接口操作。
- 管理本地钱包接口。
- 管理本地P2P节点信息接口。
- 管理本地矿工挖矿操作接口等。
API Server服务过程中,在监听地址listener上接收bytomcli或bytom-dashboard的请求访问,对每一个请求,API Server均会创建一个新的goroutine来处理请求。首先,API Server读取请求内容,解析请求;其次,匹配相应的路由项;再次,调用路由项的Handler回调函数来处理;最后,Handler处理完请求之后给bytomcli响应该请求。
1.3.3 内核层
1. 区块和交易管理
内核层包括区块和交易管理、智能合约、虚拟机。
比原链内核层架构如图1-4所示。
内核层是比原链中最重要的功能,代码量大约占总量的54%。
区块链的基本结构是一个链表。链表由一个个区块串联组成。一个区块链中包含成千上万个区块,而一个区块内又包含一个或多个交易。在比原链内核层有一个重要的功能是对区块和交易进行管理。
当网络中的某个节点接收到一个新的有效区块时,节点会验证新区块。当新的区块并未在现有的主链中找到它的父区块,这个新区块会进入孤块管理中等待父区块。如果从现有的主链中找到了父区块,则将其加入到主链。
当网络中的某个节点接收到一笔交易时,节点会验证交易的合法性。验证成功后,该笔交易放入交易池等待矿工打包。一笔交易从发送到完成的整个生命周期需要经过如下过程:
1)A通过钱包向B发出一笔交易,交易金额为100比原币(BTM)。
2)该笔交易被广播到P2P网络中。
3)矿工收到交易信息,验证交易合法性。
4)打包交易,将多个交易组成一个新区块。
5)新区块加入到一个已经存在的区块链中。
6)交易完成,成为区块链的一部分。
2. 智能合约
从传统意义上来说,合约就是现实生活中的合同。区块链中的智能合约是一种旨在以数字化的方式让验证合约谈判或履行合约规则更加便捷的计算机协议。智能合约本质上是一段运行在虚拟机上的“程序代码”,可以在没有第三方信任机构的情况下执行可信交易。
智能合约具有两个特性:可追踪性和不可逆转性。
智能合约是比原链中最核心、也是最重要的部分。在后面章节中,我们会详细介绍智能合约模型(主流模型:UTXO模型、账户模型)、运行原理,以及BVM虚拟机工作机制。我们还将深入代码,了解区块链上智能合约如何在没有第三方信任机构的情况下进行可信交易。
3. 虚拟机
比原链虚拟机(Bytom Virtual Machine,BVM)是建立在区块链上的代码运行环境,其主要作用是处理比原链系统内的智能合约。BVM是比原链中非常重要的部分,在智能合约存储、执行和验证过程中担当着重要角色。
BVM用Equity语言来编写智能合约。比原链是一个点对点的网络,每一个节点都运行着BVM,并执行相同的指令。BVM是在沙盒中运行,和区块链主链完全分开。
1.3.4 钱包层
比原链钱包层架构如图1-5所示。
钱包可以类比于我们日常生活中的保险箱,我们关心保险箱的开门方式(密钥)和其中保存的财产(UTXO)。比原链钱包层主要负责保存密钥、管理地址、维护UTXO信息,并处理交易的生成、签名,对外提供钱包、交易相关的接口。
比原链的交易发送分为三步:
1)Build:根据交易的输入和输出,构造交易数据。
2)Sign:使用私钥对每个交易输入进行签名。
3)Submit:将交易提交到网络进行广播,等待打包。
1.3.5 共识层
比原链共识层架构如图1-6所示。
共识层用于实现全网数据的一致性,区块链是去中心化账本,需要全网对账本达成共识。共识层通过验证区块和交易,保证新的区块在所有节点上以相同的方式产生。简单说,共识机制就是通过某种方式竞争“记账权”,得到记账权的节点可以将自己生成的区块追加到现有区块链的尾部,其他节点可以根据相同的规则,验证并接受这些区块,丢弃那些无法通过验证的区块。
常见的共识机制有工作量证明(Proof-of-Work,PoW)、股权证明(Proof-of-Stake,PoS)等。
PoW共识机制利用复杂的数学难题作为共识机制,目前一般使用“hash函数的计算结果小于特定的值”。由于hash函数的特性,不可能通过函数值来反向计算自变量,所以必须用枚举的方式进行计算,直到找出符合要求的hash值。这一过程需要进行大量运算。PoW的复杂性保证了任何人都需要付出大量的运算来产生新的块,如果要篡改已有的区块,则需要付出的算力比网络上其他节点的总和都大。PoW优缺点对比如表1-1所示。
PoS是另一种共识机制,这种方式要求节点将一部分加密货币锁定,并根据数量和锁定的时长等因素来分配记账权。PoS一般不需要大量计算,所以比PoW更加迅速和高效。PoS优缺点对比如表1-2所示。
目前还有少量加密数字货币采用其他共识机制,但PoW和PoS是共识机制的主流。由于比原链的特性,结合比原链崇尚“计算即权力”(一种已确定的利益分配的方式。只要计算力高或拥有更多的算力,那就拥有了某些控制权)的主张,需要在多节点上达成较强的共识,对全局一致性、去中心化要求较高,需要在一定程度上牺牲效率,所以比原链选择了PoW作为公链的共识机制。
1.3.6 数据存储层
比原链数据存储层架构如图1-7所示。
比原链在数据存储层上存储所有链上地址、资产交易等信息。数据存储层分为两部分;第一部分为缓存,大部分查询首先从缓存中进行,以减少对磁盘的IO压力;第二部分为持久化存储,当缓存中查询不到数据时,转而从持久化存储中读取,并添加一份到缓存中。
比原链默认使用LevelDB数据库作为持久化存储。LevelDB是Google开发的非常高效的链值数据库。LevelDB是单进程服务,不能同时有多个进程对一个数据库进行读写,同一时间只能有一个进程或一个进程以多并发的方式进行读写。
默认情况下,数据存储在--home参数下的data目录。以Darwin(即MacOS)平台为例,默认数据存储在$HOME/Library/Bytom/data。
数据库包括:
- accesstoken.db:存储token信息(钱包访问控制权限)。
- core.db:存储核心数据库。存储主链相关数据,包括块信息、交易信息、资产信息等。
- discover.db:存储分布式网络中端到端的节点信息。
- trusthistory.db:存储分布式网络中端到端的恶意节点信息。
- txfeeds.db:存储目前比原链代码版本未使用该功能,暂不介绍。
- wallet.db:存储本地钱包数据库。存储用户、资产、交易、UTXO等信息。
1.3.7 P2P分布式网络
比原链分布式网络层的架构如图1-8所示。
比原链作为一个去中心化的分布式系统,其底层个体间的通信机制对整个系统的稳定运行十分重要。个体间的数据同步、状态更新都依赖于整个网络中每个个体之间的通信机制。比原链的网络通信基于P2P通信协议,又根据自身业务的特殊性做了特别的设计。比原链的P2P分布式网络,主要分为四大部分:节点发现、区块同步、交易同步和快速广播。
1. 节点发现
P2P节点发现主要解决新加入网络的节点如何连接到区块链网络中。新加入的节点能够快速地被网络中其他的节点感知;同时节点自己也能够获得其他节点的信息,与其通信交换数据。比原链中的节点发现使用的是Kademlia算法实现的节点发现机制。Kademlia算法实现是一个结构化的P2P覆盖网络,每个节点都有一个全网唯一的标识,称为Node ID。Node ID被分散地存储在各个节点上。Kademlia将发现的节点存储到k桶(k-bucket)中,每个节点只连接距离自己最近的n个节点。以此形成的网络拓扑结构如下图1-9所示。
2. 区块同步
区块链是一种去中心化的分布式记账系统,全节点需要保存完整的区块信息。当一个节点加入到网络之后,需要做的第一件事情就是同步区块,构建完整的区块链。新加入的节点需要与网络中其他节点同步,从高度为1的区块开始到当前全网的最高高度,这样才能构建成一条完整的区块链。
节点启用快速功能时,同步节点每次最多能够同步1~128个区块(当前高度到下一个checkpoint高度的区块)信息。除了快速同步算法之外,还有普通同步算法。节点主要使用普通同步算法同步网络中较新的区块信息。普通同步算法主要为了保证节点中的区块信息不落后,能够及时同步新挖掘的区块。
普通同步和快速同步的区别是快速同步使用get-headers批量获取区块,使用checkpoint的验证来避免PoW工作量验证,从而能极大提高速度;普通同步一次只能获取一个区块。
快速同步和普通同步可以解决不同场景的需求。快速同步使节点能够快速地重建区块链信息,快速地加入到网络中,这是通过新块广播实现的。在不满足快速同步条件时,则用普通同步,每次同步时请求一个区块。
3. 交易同步
比原链网络为了保证交易的安全,每一笔交易达成后,节点需要将交易信息同步到网络中其他的节点,这个过程称作交易同步。交易同步验证的目的是保证安全性,当交易同步到网络中的其他的节点时,节点会验证交易是否合法,只有当交易合法,节点才会将交易写入自己的交易池中。另一方面,同步交易可以将交易同步到更多的节点,交易可以更快地被打包到区块中。
4. 快速广播
为了保证交易信息能够及时被确认和提交到主链上,比原链提供了快速广播。对于接收到的新区块和新交易信息,网络中的节点会快速广播到当前节点已知的其他节点。
1.4 编译部署及应用
比原链的安装方式有多种。本书从源码分析的角度带领读者了解架构,所以使用源码编译的方式来介绍安装过程。
1. 源码编译部署
1)下载源码:
$ git clone https://github.com/Bytom/bytom.git $GOPATH/src/github.com/bytom
2)切换至1.0.5版本:
$ cd $GOPATH/src/github.com/bytom
$ git fetch origin v1.0.5
$ git checkout v1.0.5
3)编译源码:
$ make bytomd
$ make bytomcli
4)初始化:
$ cd ./cmd/bytomd
$ ./bytomd init --chain_id mainnet
目前比原链支持三种网络,使用chain_id进行区分,如下所示:
- mainnet:主网。
- testnet:也称wisdom,测试网。
- solonet:单机模式。
5)启动bytomd进程:
$ ./bytomd node
$ ps -ef|grep bytomd
501 52318 449 0 2:00PM ttys000 0:00.85 ./bytomd node
$ ./bytomcli net-info
{
"current_block": 36714,
"highest_block": 36714,
"listening": true,
"mining": false,
"network_id": "wisdom",
"peer_count": 10,
"syncing": false,
"version": "1.0.5+2bc2396a"
}
当我们执行ps -ef命令看到bytomd进程时,说明进程已经处于运行状态。使用bytomcli获取节点状态信息,可以看到我们已经成功地运行了bytomd进程。
bytomd进程第一次启动后,默认不会开启挖矿功能。此时会从P2P网络种子节点中获取与之相邻的peer节点,建立握手连接并同步区块。我们将在第10章深入分析P2P网络底层工作原理。
2. 源码目录结构
比原链的源码目录如下所示:
$ tree -L 1
.
├── accesstoken Token管理
├── account 账户管理
├── api API Server接口管理
├── asset 资产管理
├── blockchain 交易打包、签名、查询等
├── cmd main入口文件
├── common 公共库
├── config 节点配置文件
├── consensus 共识相关模块
├── crypto 加密库
├── dashboard dashboard页面管理
├── database 数据库管理
├── docs 文档
├── encoding 协议相关的编解码库
├── env 环境变量管理
├── equity 智能合约语言编译器
├── errors 错误及异常管理
├── math 数学计算相关库
├── metrics metrics指标库,用于采集API Server请求相关指标
├── mining 挖矿模块
├── net API Server使用的HTTP基础库
├── netsync 网络同步管理
├── node 当前节点管理模块,环境初始化等
├── p2p 分布式网络管理模块
├── protocol 核心数据结构,包含块、交易、bvm虚拟机等
├── test 单元测试
├── testutil 单元测试工具包
├── util 工具包
├── vendor 第三方库
├── version 版本
└── wallet 钱包管理
3.开启挖矿模式
开启挖矿模式的命令如下:
$ ./bytomcli set-mining true
在默认情况下比原链的挖矿模式是关闭状态。开启挖矿模式有两种方式,第一种方式,使用bytomcli命令行交互,将mining参数设置为true,此时bytomcli会通过RPC协议与bytomd进程交互并启用挖矿模式。关闭挖矿模式则指定set-mining参数为false。第二种方式,使用dashboard页面启用挖矿参数,在这里请读者自行学习dashboard。
4.其他语言SDK简介
比原链技术社区提供了不同语言的SDK,如下所示:
PHP SDK:https://github.com/lxlxw/bytom-php-sdk
Java SDK:https://github.com/chainworld/java-bytom
Java SDK:https://github.com/successli/Bytom-Java-SDK
Python SDK:https://github.com/Bytom-Community/python-bytom
Node SDK:https://github.com/Bytom/node-sdk
1.5 本章小结
本章对比原链的总体架构分层进行了分析,通过比原链的总架构图可以看出一条完整公链的技术架构。然后通过安装部署,介绍了比原链的基础知识。
通过对公链架构的学习,可以从顶层宏观角度对公链设计、功能与价值等诸多方面进行全面了解。