GO语言公链开发实战(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-18 17:38:28

点击下载

作者:郑东旭 等

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

GO语言公链开发实战

GO语言公链开发实战试读:

前言

2008年由中本聪第一次提出了区块链的概念,在随后的几年中,区块链成为了电子货币比特币的核心组成部分:作为所有交易的公共账簿。2017年笔者的很多朋友已经在关注区块链技术领域,笔者也在各种技术峰会上分享过多次区块链技术实现细节,在线上也组织了几个区块链技术群。笔者发现有相当多的朋友询问如何深入学习区块链实现技术,但目前市面上很多的资料都仅介绍区块链上的某部分技术,比如加密货币交易、智能合约开发等,并没有完整介绍公链的技术实现。在一次技术峰会演讲后与北京邮电大学区块链实验室的老师交流,受到陈萍老师的鼓励,想到编写一本系统性介绍公链开发的书籍,对学习区块链的初学者会有帮助,于是便开始组织本书的写作。

本书的目标是引导读者全面了解区块链技术实现原理,笔者也一直坚信,了解某一系统最直接的方式就是研读它的源码,所以本书并不是只介绍区块链技术,而是深入分析其背后的实现原理。通过阅读本书,读者可以全面地了解一条公链的技术实现。本书基于比原链的源代码进行分析,比原链是一个开源的有智能合约功能的公共区块链平台,是国内优秀的公链,目前比原链的代码量不多,而且源码结构清晰,特别适合初学者学习。

本书主要内容包括:

第1章介绍公链设计架构,使读者能够宏观地了解区块链技术架构。

第2章介绍比原链相关的交互工具,包括交互工具的操作及代码实现。

第3章介绍比原链的核心进程bytomd,包括启动过程中的初始化等操作。

第4章介绍API Server实现及原理。详解HTTP请求的完整生命周期,并介绍区块链相关的API接口设计。

第5章和第6章详细介绍区块链核心部分,包括区块、区块链、交易的核心数据结构,以及UTXO模型、隔离见证、交易脚本、验证等概念的实现。

第7章和第8章详细讲解比原链智能合约以及智能合约在BVM虚拟机上运行的过程。

第9章介绍区块链钱包的基本概念,包括密钥、账户、资产管理、交易管理等,以及钱包的备份和恢复方式。

第10章详解区块链P2P分布式网络实现原理,以及Kademlia结构化网络算法的实现。

第11章介绍数据持久化存储,以及区块与交易的缓存和存储过程。

第12章和第13章详解PoW与PoS共识机制以及挖矿相关的概念和流程。

第14章介绍区块链技术未来的发展趋势,我们相信区块链能够为人类做出重大贡献。

本书适合区块链开发者、Go语言开发者阅读。由于时间与水平比较有限,我们在编写本书时也难免会出现一些纰漏和错误。读者可以随时通过邮箱weilandeshanhuhai@126.com与我们联系,希望和大家一起学习与讨论区块链技术。

本书在写作过程中得到很多人的帮助,特别是郜策宇、陆志亚、王庆华、朱益祺、阳胜、林浩宇,在此深表感谢。尤其感谢比原链技术团队设计了这样一个优秀的公链,给区块链社区做出了贡献。郑东旭2019年3月14日第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-1 比原链架构图1-2 比原链架构之用户交互层1.3.2 接口层

比原链接口层架构如图1-3所示。图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-4 比原链架构之内核层

当网络中的某个节点接收到一个新的有效区块时,节点会验证新区块。当新的区块并未在现有的主链中找到它的父区块,这个新区块会进入孤块管理中等待父区块。如果从现有的主链中找到了父区块,则将其加入到主链。

当网络中的某个节点接收到一笔交易时,节点会验证交易的合法性。验证成功后,该笔交易放入交易池等待矿工打包。一笔交易从发送到完成的整个生命周期需要经过如下过程:

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所示。图1-5 比原链架构之钱包层

钱包可以类比于我们日常生活中的保险箱,我们关心保险箱的开门方式(密钥)和其中保存的财产(UTXO)。比原链钱包层主要负责保存密钥、管理地址、维护UTXO信息,并处理交易的生成、签名,对外提供钱包、交易相关的接口。

比原链的交易发送分为三步:

1)Build:根据交易的输入和输出,构造交易数据。

2)Sign:使用私钥对每个交易输入进行签名。

3)Submit:将交易提交到网络进行广播,等待打包。1.3.5 共识层

比原链共识层架构如图1-6所示。图1-6 比原链架构之共识层

共识层用于实现全网数据的一致性,区块链是去中心化账本,需要全网对账本达成共识。共识层通过验证区块和交易,保证新的区块在所有节点上以相同的方式产生。简单说,共识机制就是通过某种方式竞争“记账权”,得到记账权的节点可以将自己生成的区块追加到现有区块链的尾部,其他节点可以根据相同的规则,验证并接受这些区块,丢弃那些无法通过验证的区块。

常见的共识机制有工作量证明(Proof-of-Work,PoW)、股权证明(Proof-of-Stake,PoS)等。

PoW共识机制利用复杂的数学难题作为共识机制,目前一般使用“hash函数的计算结果小于特定的值”。由于hash函数的特性,不可能通过函数值来反向计算自变量,所以必须用枚举的方式进行计算,直到找出符合要求的hash值。这一过程需要进行大量运算。PoW的复杂性保证了任何人都需要付出大量的运算来产生新的块,如果要篡改已有的区块,则需要付出的算力比网络上其他节点的总和都大。PoW优缺点对比如表1-1所示。表1-1 PoW优缺点对比

PoS是另一种共识机制,这种方式要求节点将一部分加密货币锁定,并根据数量和锁定的时长等因素来分配记账权。PoS一般不需要大量计算,所以比PoW更加迅速和高效。PoS优缺点对比如表1-2所示。表1-2 PoS优缺点对比

目前还有少量加密数字货币采用其他共识机制,但PoW和PoS是共识机制的主流。由于比原链的特性,结合比原链崇尚“计算即权力”(一种已确定的利益分配的方式。只要计算力高或拥有更多的算力,那就拥有了某些控制权)的主张,需要在多节点上达成较强的共识,对全局一致性、去中心化要求较高,需要在一定程度上牺牲效率,所以比原链选择了PoW作为公链的共识机制。1.3.6 数据存储层

比原链数据存储层架构如图1-7所示。图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所示。图1-8 比原链架构之P2P分布式网络

比原链作为一个去中心化的分布式系统,其底层个体间的通信机制对整个系统的稳定运行十分重要。个体间的数据同步、状态更新都依赖于整个网络中每个个体之间的通信机制。比原链的网络通信基于P2P通信协议,又根据自身业务的特殊性做了特别的设计。比原链的P2P分布式网络,主要分为四大部分:节点发现、区块同步、交易同步和快速广播。

1.节点发现

P2P节点发现主要解决新加入网络的节点如何连接到区块链网络中。新加入的节点能够快速地被网络中其他的节点感知;同时节点自己也能够获得其他节点的信息,与其通信交换数据。比原链中的节点发现使用的是Kademlia算法实现的节点发现机制。Kademlia算法实现是一个结构化的P2P覆盖网络,每个节点都有一个全网唯一的标识,称为Node ID。Node ID被分散地存储在各个节点上。Kademlia将发现的节点存储到k桶(k-bucket)中,每个节点只连接距离自己最近的n个节点。以此形成的网络拓扑结构如下图1-9所示。图1-9 P2P网络拓扑架构

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-sdk1.5 本章小结

本章对比原链的总体架构分层进行了分析,通过比原链的总架构图可以看出一条完整公链的技术架构。然后通过安装部署,介绍了比原链的基础知识。

通过对公链架构的学习,可以从顶层宏观角度对公链设计、功能与价值等诸多方面进行全面了解。第2章交互工具2.1 概述

bytomcli和dashboard是比原链提供的与bytomd进程交互的工具(基于RPC协议)。bytomcli是命令行客户端,dashboard是Web图形界面。dashboard相比bytomcli使用体验更友好,用户可随意选择。

通过交互工具可以完成与token、账户、交易、钱包、挖矿等相关的管理操作。

本章中,我们对bytomcli与bytomd进程的交互过程原理和代码进行分析,并对dashboard做一些简介,主要内容包括:

·bytomcli交互工具介绍。

·dashboard使用方法。2.2 bytomcli交互工具2.2.1 bytomcli命令flag参数

bytomcli的使用方式分为两种:一种是后面接flags参数,bytomcli[flags],bytomcli使用-h参数查看命令的帮助文档;另一种是后面接子命令,bytomcli[command]。所有的命令选项都可以通过执行-h或--help获得指定命令的帮助信息。bytomcli的帮助信息、示例相当详细,简单易懂。建议大家使用帮助信息。$ ./bytomcli -hBytomcli is a commond line client for bytom core (a.k.a. bytomd)Usage: bytomcli [flags] bytomcli [command]Available Commands: build-transaction 创建一笔交易 check-access-token 校验access token 是否合法 create-access-token 创建 accesss token create-account 创建账户 create-account-receiver 创建账户地址 create-asset 创建资产 create-key 创建key create-transaction-feed 创建交易feed过滤器 decode-program 将程序解码为指令和数据 decode-raw-transaction 解码原始交易 delete-access-token 删除access token delete-account 删除账户 delete-key 删除key delete-transaction-feed 删除交易feed 过滤器 estimate-transaction-gas 估算交易费 gas-rate 显示当前交易费比例 get-asset 通过资产id获得资产详情 get-block 根据区块哈希值或高度获取完成区块信息 get-block-count 获取最新区块的数量 get-block-hash 获取最新区块的哈希值 get-block-header 根据区块哈希值或高度获取完成区块的头部信息 get-difficulty 获取最新区块的难度值 get-hash-rate 获取最新区块的nonce值 get-transaction 根据交易hash值获取交易信息 get-transaction-feed 通过别名获取交易feed get-unconfirmed-transaction 根据交易哈希值获取未确认的交易信息 help 显示帮助信息 is-mining 判断客户端是否开启挖矿功能 list-access-tokens 显示access token信息 list-accounts 显示账户信息 list-addresses 显示账户地址信息 list-assets 显示资产信息 list-balances 显示账户余额 list-keys 显示存在的key信息 list-pubkeys 显示账户公钥 list-transaction-feeds 显示所有的交易feed list-transactions 显示交易信息 list-unconfirmed-transactions 显示未确认交易的哈希值 list-unspent-outputs 显示账户未使用的输出 net-info 显示当前网络信息 rescan-wallet 重新扫描块信息到钱包 reset-key-password 重置key 密钥 set-mining 开始/停止挖矿 sign-message 对消息进行签名 sign-transaction 使用账户密钥对交易进行签名 submit-transaction 提交签名的交易 update-asset-alias 更新资产别名 update-transaction-feed 更新交易feed validate-address 校验交易地址 verify-message 校验消息签名 version 显示客户端版本信息 wallet-info 显示钱包信息

以上介绍了bytomcli命令行工具的详细参数。下面,将以一个实际的用例介绍如何使用bytomcli命令行工具。2.2.2 使用bytomcli查看节点状态信息

使用net-info参数可以查看bytomd节点运行的网络状态。首先,使用bytomcli net-info-h查看net-info的帮助信息。命令执行如下:$ ./bytomcli net-info -hPrint the summary of networkUsage: bytomcli net-info [flags]Flags: -h, --help help for net-info

由输出的帮助信息可知,net-info命令仅支持一个可选的flags参数,flags参数列表又仅包含-h参数,可用来查看net-info命令的帮助信息。所以net-info命令的用法是十分简单的,使用bytomcli net-info即可查看节点的网络状态:$ ./bytomcli net-info{ "current_block": 36714, "highest_block": 36714, "listening": true, "mining": false, "network_id": "mainnet", "peer_count": 10, "syncing": false, "version": "1.0.5+2bc2396a"}

net-info参数返回数据如下所示。

·current_block:当前节点的当前区块高度为36714。

·highest_block:网络中最高区块高度为36714,表明节点已经拥有完整的区块数据。

·listening:当前节点处于监听状态。

·mining:当前节点是否启用挖矿功能。

·network_id:标识节点连接的网络类型(mainnet为正式主网,wisdom为测试网络,solonet为单节点网络)。

·peer_count:节点当前连接的其他节点个数。

·syncing:当前节点是否正在同步区块数据。

·version:节点的版本号。2.2.3 bytomcli运行案例

本小节我们以net-info命令为例对bytomcli的源码进行剖析,其他命令参数与net-info参数执行的过程大同小异。

bytomcli相关代码文件结构如下所示:$ tree cmd/bytomcli/cmd/bytomcli/├── bytomcli├── commands commands目录存放bytomcli所有参数的实现│ ├── accesstoken.go token参数相关│ ├── account.go 账户参数相关│ ├── asset.go 资产参数相关│ ├── block.go 块参数相关│ ├── bytomcli.go bytomcli flag解析相关│ ├── key.go key参数相关│ ├── mining.go 挖矿参数相关│ ├── net.go 节点状态参数相关│ ├── program.go 合约参数相关│ ├── template.go 交易模板参数相关│ ├── transaction.go 交易参数相关│ ├── txfeed.go 目前版本该功能未使用│ ├── util.go bytomcli相关输出结构体│ ├── version.go 节点版本参数相关│ └── wallet.go 本地钱包参数相关└── main.go bytomcli入口函数

1.Cobra库介绍

bytomcli命令行工具是基于Cobra实现的。Cobra既可以用来创建强大的现代CLI应用程序库,也可以用来生成应用和程序文件。很多知名的开源软件都使用Cobra实现其CLI部分,例如kubernetes、docker、etcd等。

Cobra基于三个基本的概念——commands、arguments和flags,实现对命令参数的解析和行为控制。commands是应用程序的中心,应用程序支持的每个交互都包含在命令中,命令可以具有子命令并可选地运行子命令。flags是修改命令行为的方法,Cobra支持POSIX标准和GO的flags包,并可以同时作用于父命令和子命令的参数,也支持只在父命令或者子命令有效的参数。

如何使用Cobra库来构建自己的CLI程序呢?下面我们简单介绍Cobra库的使用。(1)安装Cobra库

Cobra是非常容易使用的,使用go get来安装最新版本的库。Cobra库相对比较大,安装它可能需要花费一些时间。安装完成后,在GOPATH/bin目录下应该有已经编译好的Cobra程序。$ go get -v github.com/spf13/cobra/cobra(2)使用cobra命令生成应用程序

假设现在我们要开发一个基于CLI的命令程序,名字为demo。首先打开cmd,切换到GOPATH的src目录下,执行如下命令:$ cobra init demo

在src目录下会生成一个demo的文件夹,如下:$ tree demo/demo/├── LICENSE├── cmd│ └── root.go└── main.go

如果此时应用程序不需要子命令,那么Cobra生成应用程序的操作就结束了。这里我们先实现一个没有子命令的CLI程序,之后再为程序添加子命令。

接下来继续为demo设计功能。我们打开Cobra自动生成的main.go文件查看,如下:package mainimport "demo/cmd"func main() { cmd.Execute()}

main函数执行cmd包的Execute()方法,打开cmd包下的root.go文件查看,发现里面进行了一些初始化操作,并提供了Execute接口。其实,Cobra自动生成的root.go文件中有很多初始化操作是不需要的,其中viper是Cobra集成的配置文件读取的库,这里不需要使用,可以注释掉,如不注释掉则生成的应用程序会大10M左右。

在demo下面新建一个imp包,imp.go内容如下:package impimport( "fmt")func Show(name string, age int) { fmt.Printf("My Name is %s, My age is %d\n", name, age)}

在imp.go文件中,Show函数接收两个参数——name和age,使用fmt打印出来。此时,整个demo项目目录结构如下:$ tree demo/demo/├── LICENSE├── cmd│ └── root.go├── imp│ ├── imp.go└── main.go

Cobra的所有命令都是通过cobra.Command结构体实现的。为了实现demo功能,我们需要修改RootCmd。修改demo/cmd/root.go文件,如下所示:var RootCmd = &cobra.Command{ Use: "demo", Short: "A test demo", Long: `Demo is a test appcation for print things`, // Uncomment the following line if your bare application // has an action associated with it: Run: func(cmd *cobra.Command, args []string) { if len(name) == 0 { cmd.Help() return } imp.Show(name, age) },}

虽然我们已经定义了command结构,也能通过Execute接口调用RootCmd定义的回调方法。但是若要实现demo的功能还需从命令行解析传入的参数,这部分应该如何实现?这部分可以在cmd包的init方法中实现。init()函数会在每个包完成初始化后自动执行,并且执行优先级比main函数高。init()函数通常被用来对变量进行初始化操作。这里我们使用init()函数在main函数执行之前解析命令行参数。修改demo/cmd/root.go文件,如下所示:var ( name string age int)func init() { RootCmd.Flags().StringVarP(&name, "name", "n", "", "person's name") RootCmd.Flags().IntVarP(&age, "age", "a", 0, "person's age")}

至此,demo的功能已经实现了,我们编译运行一下看看实际效果,如下所示:$ go run main.goUsage: demo [flags]Flags: -a, --age int person's age --config string config file (default is $HOME/.demo.yaml) -h, --help help for demo -n, --name string person's name -t, --toggle Help message for toggle

如果我们想实现一个带有子命令的CLI程序,只需要再执行cobra add为程序新增子命令。下面我们为demo程序新增一个server的子命令,如下所示:$ cd demo$ cobra add server

在demo目录下生成了一个cmd/server.go文件,如下所示:$ tree demo/demo/├── LICENSE├── cmd│ ├── root.go│ └── server.go├── imp│ └── imp.go└── main.go

接下来配置server子命令,此操作与前文中修改root.go文件类似效果如下:$ go run main.goUsage: demo [flags] demo [command]Available Commands: help Help about any command server A brief description of your commandFlags: -a, --age int person's age --config string config file (default is $HOME/.demo.yaml) -h, --help help for demo -n, --name string person's name -t, --toggle Help message for toggleUse "demo [command] --help" for more information about a command.

2.bytomcli运行流程与原理

对Cobra库有了了解之后,我们再来学习bytomcli的代码时会感觉比较容易,其运行原理如图2-1所示。同上一节中的demo程序一样,bytomcli在main函数中使用cmd.Execute()来启动应用程序,cmd.Execute()是调用commands包的Execute()方法。在mian.go中引入commands包的时候,给它起了一个别名cmd。cmd/bytomcli/main.gofunc main() { runtime.GOMAXPROCS(runtime.NumCPU()) cmd.Execute()}图2-1 bytomcli运行原理

当程序调用commands包的Execute()方法时,会先执行commands包中所有的init()方法,这些init()主要用来解析命令行参数。当执行完commands包中所有的init()方法之后,才会执行Execute()。在Execute()方法中,首先执行AddCommands()方法,该方法主要用来给BytomcliCmd命令添加子命令;而AddTemplateFunc()方法则是为子命令添加使用模板的。在解析flags参数、添加子命令和添加使用模板这些初始化操作完成之后,才真正进入命令的执行过程。在BytomcliCmd.ExecuteC()方法中,Cobra库会根据用户输入的命令跳转到相应的子命令,同时执行命令定义的Run方法。cmd/bytomcli/commands/bytomcli.gofunc Execute() { AddCommands() AddTemplateFunc() if _, err := BytomcliCmd.ExecuteC(); err != nil { os.Exit(util.ErrLocalExe) }}

下面我们以create-access-token命令为例,看看这个命令的Run方法都执行了哪些操作。首先会取args参数的第一位作为tokenID,然后调用util包下的ClientCall方法请求/create-access-token路径,并将tokenID传入,创建token。bytom/cmd/bytomcli/commands/accesstoken.govar createAccessTokenCmd = &cobra.Command{ Use: "create-access-token ", Short: "Create a new access token", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { var token accessToken token.ID = args[0] data, exitCode := util.ClientCall("/create-access-token", &token) if exitCode != util.Success { os.Exit(exitCode) } printJSON(data) },}

ClientCall方法封装了一个RPC的client,根据用户传入的路径和参数发送请求,并解析RPC server返回的内容。bytom/util/util.gofunc ClientCall(path string, req ...interface{}) (interface{}, int) { var response = &api.Response{} var request interface{} if req != nil { request = req[0] } client := MustRPCClient() client.Call(context.Background(), path, request, response) switch response.Status { case api.FAIL: jww.ERROR.Println(response.Msg) return nil, ErrRemote case "": jww.ERROR.Println("Unable to connect to the bytomd") return nil, ErrConnect } return response.Data, Success}

至此,create-access-token命令执行完成,其生命周期终止。2.3 dashboard交互工具

在比原链中,dashboard是单独一个项目,项目源码地址:https://github.com/Bytom/bytom-dashboard。可能会有读者疑惑,既然dashboard是一个单独的项目,为什么在启动bytomd进程的时候会启用dashboard服务呢?这是因为dashboard编译后被硬编码到bytomd中,源码在dashboard/dashboard.go中。而在API Server下的api/api.go,我们可以看到引用handle信息如下:mux := http.NewServeMux()mux.Handle("/dashboard/", http.StripPrefix("/dashboard/", static.Handler{ Assets: dashboard.Files, Default: "index.html",}))2.3.1 使用dashboard发送一笔交易

在浏览器中输入http://127.0.0.1:9888/,打开dashboard页面。页面左下方显示当前节点同步区块的进度。点击右上角“新建交易”如图2-2所示。图2-2 dashboard示意图

在比原链中,新建交易分为两种,一种是简单交易,一种是高级交易。本节中使用简单交易发送一笔交易。高级交易会在后面章节进行详细讲解。

如图2-3所示,我们从本地钱包derek账户下的BTM资产往bm1q5p9d4gelfm4cc3zq3slj7vh2njx23ma2cf866j地址中打入了8 254 800Neu(诺),其中Gas的手续费约为500 000Neu(诺)。然后输入钱包密码并提交交易。得到结果如图2-4所示。

交易ID为3ebe89ddb64f3a7ef1742e...目前正在往主网中广播,待到交易确认则说明这笔交易最终成功。一般认为,一笔交易经过6个区块的验证后此交易无法逆转。2.3.2 使用dashboard开启挖矿模式

在第1章介绍编译部署及应用时,介绍了如何使用bytomcli命令行交互的方式开启节点的挖矿模式,同样,我们也可以使用dashboard来启用或关停挖矿模式。

如图2-5所示,点击dashboard左上角齿轮按钮,点击核心状态,显示节点的配置信息,如图2-6所示。默认情况下挖矿选项是关闭状态,在这里我们可以启用节点的挖矿模式。图2-3 dashboard“新建交易”页面图2-4 dashboard交易结果图2-5 dashboard示意图图2-6 dashboard示意图2.4 本章小结

本章对用户交互层做了详细介绍,对bytomcli命令行和dashboard进行了分析,对Cobra库的使用做了详细的介绍,并对Cobra如何生成CLI下flag的流程进行阐述。本章从源码的角度深入分析了bytomcli与bytomd的RPC交互过程。最后以dashboard发送一笔交易为例,展示了dashboard的使用方法。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载