快速开始
系统规划
千尺链是一种分布式系统,其在物理结构上是分布式部署的,而在逻辑形式上整体统一的。在通常的场景中,以数据的视角来看,千尺链被应用为一种能够连接多个业务参与方的分布式的消息分发、数据处理与共享平台,基于对共识协议、密码学算法和数据结构等技术的组合运用,实现了在逻辑形式上整体统一的数据账本。
千尺链主要由两种部署组件组成:共识节点、服务网关。
共识节点在整个区块链系统中属于核心节点的角色,具有以下核心功能:
- 一组共识节点采用分布式共识协议建立对等连接形成共识网络。
- 每一个共识节点本地维护独有的账本数据库。
- 对通过共识网络提交的业务交易进行具有全局一致性的排序。
- 将从共识网络接收并一致排序后的业务交易清单转交到账本数据库上执行。
- 采用密码学算法校验交易的内容以及交易执行产生的数据变更。
- 在账本数据库中存储交易的内容以及交易执行产生的数据变更。
- 接收对查询指令在账本数据库中检索数据并返回结果。
服务网关在整个区块链系统中属于接入节点的角色,具有以下核心功能:
- 连接到由共识节点组成的共识网络。
- 认证和管理区块链终端的连接。
- 接收区块链终端提交的业务交易。
- 采用密码学算法校验接收到的业务交易。
- 签署合法交易并转发到共识网络。
- 维持终端请求对多个共识节点的负载均衡。
- 监控分布式账本事件并向区块链终端广播事件通知。
- 管理本地化的分布式应用服务。
图1.1 千尺链部署架构
识别业务参与方
在规划部署一套千尺区块链平台时,首先要确定有哪些业务参与方,以及根据每个参与方的需要确定各自部署的节点的类型。共识节点属于全量节点,持有和维护着账本的全量数据,因而需要比服务网关付出更多的运维成本。服务网关属于轻量节点,是跨参与方和终端用户访问分布式应用的入口,不维护账本的数据,因而需要相对少的运维成本。所以,业务参与方通常可以有3中不同的选择: (1)部署共识节点和服务网关; (2)仅部署服务网关; (3)不必部署共识节点和服务网关,以有效的区块链身份账户通过其它参与方的服务网关接入。
在一个具体的规划实例中,可以根据不同参与方的业务角色定位在此3中类型中选择不同方案,并结合业务权限设定可以组合出适合不同场景需要的规划方案。
节点数量与数据规模规划
在开始正式准备物理环境部署前,还需要确定以下3个关键参数:
- 共识节点的数量。
- 服务网关的数量。
- 上链数据的规模。
共识节点数量
确定共识节点的数量与选择的共识协议类型有关。企业场景下通常都建议采用 BFT 这类的共识协议,本系统默认提供的共识协议实现是改进的PBFT共识算法,遵循了共识节点的数量 N 与容错节点数 f 的关系为 N = 3 * f + 1 。在典型的生产环境中需要确保1 个容错共识节点(容忍宕机/断网故障),因此,总的共识节点数 N 的最小值应该为 4 (即 f = 1 , N = 4)。 最后,根据参与方规划时确定的“共识参与方”(即部署共识节点的参与方)的清单,每一个共识参与方可以部署一个共识节点或者多个共识节点,最终使得所有的共识参与方都分配了共识节点,并使得总的共识节点数达到满足 3f + 1 关系的最小值。
服务网关数量
服务网关是区块链共识网络的接入入口,需要绑定到某个参与方的区块链用户密钥对,参与方密钥对被用来对提交上链的交易追加一项节点签名,用以标识交易的通讯入口。
服务网关被设计为一种无状态,这使得可以部署多个服务网关实例,并在多个服务网关实例之前部署负载均衡服务,实现网关接入的高可用和负载能力扩展。
因此,基于服务网关以上的这些设计特点,服务网关的部署数量可以灵活按需确定,无特别要求。
上链数据规模
对上链数据规模规划的目的是预估需要预留多少物理资源才能应对未来一段时期业务发展需要。预估不会是精确的,只是提供了一个物理资源分配的基础模型,实际的资源消耗会受到包括业务内容本身在内的许多因素的影响而与预估产生一定偏差。
上链数据规模可以从两个方面来度量:上链数据总量和单位时间上链数据量。
“上链数据总量”体现的是系统的存储能力,对“上链数据总量”带来直接影响的物理资源是共识节点服务器的存储空间。
“单位时间上链数据量”正向对应于“每秒处理交易数量(TPS)”,体现的是系统的处理速度,对其带来直接影响的物理资源有通讯链路上的网络带宽、共识节点和服务网关的 CPU 处理性能以及内存大小、共识节点的账本存储磁盘的读写性能。
千尺链目前的发布版本上,“上链数据总量”与共识节点存储空间的关系有以下的经验规律:系统采基于 RocksDB 的账本存储实现(这是默认选项),共识节点的账本数据库所在的存储磁盘通常能够以 500 GB 的可用空间支撑超过 1000 万笔以上的业务写交易。
评估系统处理速度与其物理资源的关系是一个复杂的过程,多数情况下只能基于对实际运行环境的观测来获得准确的测量结果,并依据这些测量结果来调整系统,并通过重新观测来评估调整带来的效果。因此,本文档不对与“单位时间上链数据量”方面相关的物理资源提供评估建议。不过,在大多数的企业场景下对系统处理速度要求并不高,当前的服务器硬件和通讯网络的技术发展水平下,千尺链能够以较大的性能冗余度支持绝大多数的企业应用场景。
安装准备
环境要求
推荐按以下配置要求准备服务器:
类型 | 配置要求 | 备注 |
---|---|---|
服务器硬件 | CPU双核 8GHz以上,内存 8 GB以上,磁盘 500GB以上。 | |
操作系统 | 支持Linux(内核3.0以上),Windows,MacOS服务器操作系统或者桌面操作系统。 | |
软件环境 | JDK8 以上,兼容 Hotspot JDK 和 OpenJDK 。 | |
网络环境 | 共识节点进程需要 4 个端口:交易端口、共识端口、数据端口、管理控制端口。服务网关进程需要 2 个端口:服务端口、管理控制端口。需要参照图1.1 的部署架构进行网络配置,如果参与方或者用户需要跨公网访问,还需要追加对相关端口的NAT规划配置。 |
安装包下载
“共识节点”安装包
“网关节点”安装包
部署共识节点
部署共识节点程序的过程有3步:
- 安装共识节点程序。
- 初始化网络配置。
- 初始化管理控制台和密钥库。
要完整部署一套区块链系统,只需要根据规划的共识节点数量,在每一个参与方的共识节点服务器上重复以上的步骤(通常由参与方的IT人员各自独立并行地操作)。 下面以 Linux 操作系统下的部署为例,展示部署一个共识节点的具体操作过程。
安装共识节点程序
安装共识节点程序的过程就是将安装包解压缩到特定目录的过程。
共识节点程序安装包是 zip 格式,将其解压缩到一个目标路径,例如 /usr/local/blockchain/peer,该目录是共识节点程序的根目录,被称为 HOME 目录(以下称为 PEER_HOME)。
## 解压缩安装包后尚未运行之前的共识节点 HOME 目录结构
PEER_HOME
|——bin ##可执行脚本目录
| |__start.sh ##共识节点启动脚本;
|
|——conf
| |__peer.conf ##共识节点服务器参数配置;
| |__consensus.conf ##共识协议参数配置;
|
|__libs ##共识节点程序代码库目录;
设置共识节点的网络参数
通过打开 PEER_HOME/conf/peer.conf 配置文件编辑网络参数相关的属性。 需要重点关注并设置的属性有3类:
- 共识节点的所有服务采用的本机网卡绑定地址和端口:server.address 和 server.port
- 共识节点的所有服务对外的公共访问地址和端口:server.public-address 和 server.public-port
- 共识节点的管理控制台的本机网卡绑定地址和端口:shell.ssh.host 和 shell.ssh.port
需要了解更多的参数说明请查看 peer.conf 配置文件的默认内容,其中包含了对全部参数的完整解释,以下摘取了其中需要重点关注的 6 个参数:
# 节点的通讯服务的本机绑定网卡地址;必选配置;
# 涉及的通讯服务有 3 种:节点的数据查询服务(HTTP)、账本共识服务(TCP)、账本交易服务(TCP);
# 指定 0.0.0.0 将绑定到所有网卡上;
server.address=0.0.0.0
# 节点的数据查询服务(HTTP)的本机端口;必选配置;
server.port=7080
# 节点的通讯服务的公共访问地址;非必选配置,如未配置,则以“本机绑定网卡地址(server.address)”一致;
# 这一个声明式的配置项,不会影响节点的通讯服务的运行,但会影响其它节点、网关以及其它潜在的客户端访问者如何发现节点的服务,因此提供一个正确的配置是必要的;
# 通常在一个共识节点、服务网关跨越了不同网络进行部署的情况下,网络管理员会采用 NAT 方式使得外部访问者得以访问位于内网的服务,因此“公共访问地址”应该配置为“本机绑定网卡地址”对应的 NAT 网络地址;
server.public-address=
# 节点的数据查询服务(HTTP)的公共访问端口;非必选配置,如未配置,则以“本机端口(server.port)”一致;
# 通常在一个共识节点、服务网关跨越了不同网络进行部署的情况下,网络管理员会采用 NAT 方式使得外部访问者得以访问位于内网的服务,因此“公共访问端口”应该配置为“本机端口(server.port)”对应的 NAT 网络端口;
server.public-port=
# SSH 控制台服务绑定的本机IP;如果设置为 127.0.0.1 则只允许从服务器本机连接到控制台;
shell.ssh.host=127.0.0.1
# SSH 控制台服务的端口号;如果在一台服务器上部署多个节点时,请为不同的节点进程指定不同的端口;
shell.ssh.port=7022
启动共识节点
# 进入 bin 目录
cd $PEER_HOME/bin
# 赋予启动脚本可执行权限;
chmod +x *.sh
# 执行启动脚本;
./start.sh
执行启动脚本之后,共识节点以后台方式运行,同时启动脚本会自动进入启动日志查看模式将启动过程的日志显示出来,键入 CTRL+C 可以退出日志查看而不会中断共识节点的运行。
成功的启动将会看到如下的日志输出:
图:3.1 共识节点启动成功的日志输出
初始化管理控制台和密钥库
当共识节点初次启动时,会生成共识节点管理控制台的 root 管理员的初始登录口令,该口令是随机生成的,输出到文本格式的文件 PEER_HOME/logs/root.passwd 。口令只有一行,打开文件复制全部内容。
# 连接共识节点管理控制台;
# 注意,使用 peer.conf 配置文件指定的端口(默认7022),而不是 SSH 终端的默认端口 22
ssh root@127.0.0.1 -p 7022
如图3.2, 输入口令后,由于是首次登录,会提示立即更改管理员口令。
接下来,按照提示进行下一步初始化密钥库。
图3.2 共识节点管理控制台连接与系统初始化
创建区块链账本(建链)
进入SSH管理控制台后,通过执行 new-ledger 命令来创建账本,创建过程的总体步骤如下:
- 在多方的共识节点中选择其中一个作为“协调者”,执行 new-ledger 命令发起账本初始化协调任务。
- 在其它各方共识节点中选择其中一个作为“参与者”,执行 join-new-ledger 命令加入账本初始化协调任务。
- 根据引导提示,每一个共识节点需要选择或者创建一对公私钥对在新建账本中初始化注册成为参与方身份账户。
- 完成引导提示的输入后,协调任务自动在各方对初始化账本的操作进行共识和生成创世区块,完成账本创建。
创建账本的命令程序有详细的引导,具体操作步骤简要呈现如下如下:
“协调者”节点开启账本初始化
从“协调者”节点开启账本初始化任务
图4-1 “协调者”节点开启账本初始化任务
“参与者”共识节点加入
每一个“参与者”节点参与账本初始化任务
图4-2 “参与者”节点参与账本初始化任务
“协调者“节点等待其它“参与者”节点加入
图4-3“协调者“节点等待其它“参与者”节点加入
“参与者“节点等待其它“参与者”节点加入
图4-4“参与者“节点等待其它“参与者”节点加入
“参与者”共识节点共同确认
所有的“参与者”共识节点共同确认参与者信息
图4-5共识节点共同确认参与者信息(协调者视角)
图4-6共识节点共同确认参与者信息(参与者视角)
账本初始化
- 在“参与者”共同确认之后,开始执行账本初始化
当所有参与方都输入Yes确认之后,便立即开始生成创世区块创建账本的过程。
图4-7 执行账本初始化(协调者视角)
图4-8 执行账本初始化(参与者视角)
启动共识网络
完成账本初始化之后,自动启动共识网络
图4-9 完成账本初始化并启动共识网络
查看账本信息
在安装服务网关之前,可以通过“管理控制台”的命令行查询
命令:list-nodes (查看已加载的共识节点实例) / list-ledger-nodes(查看所有账本的共识节点实例)
图5-1 查询已加载的账本信息
安装服务网关
部署服务网关程序的过程有3步:
- 安装服务网关程序。
- 初始化网络配置。
- 初始化管理控制台和密钥库。
下面以 Linux 操作系统下的部署为例,展示部署一个服务网关程序实例的具体操作过程。
安装服务网关程序
安装服务网关程序的过程就是将安装包解压缩到特定目录的过程。
服务网关程序安装包是 zip 格式,将其解压缩到一个目标路径,例如 /usr/local/blockchain/gateway,该目录是服务网关程序的根目录,被称为 HOME 目录(以下称为 GATEWAY_HOME)。
## 解压缩安装包后尚未运行之前的服务网关 HOME 目录结构
GATEWAY_HOME
|——bin ##可执行脚本目录
| |__start.sh ##服务网关启动脚本;
|
|——conf
| |__gateway.conf ##服务网关服务器参数配置;
|
|__libs ##服务网关程序代码库目录;
设置服务网关的网络参数
通过打开 GATEWAY_HOME/conf/gateway.conf 配置文件编辑网络参数相关的属性。 需要重点关注并设置的属性有3类:
- 服务网关的所有服务采用的本机网卡绑定地址和端口:server.address 和 server.port
- 服务网关的所有服务对外的公共访问地址和端口:server.public-address 和 server.public-port
- 服务网关的管理控制台的本机网卡绑定地址和端口:shell.ssh.host 和 shell.ssh.port
需要了解更多的参数说明请查看 gateway.conf 配置文件的默认内容,其中包含了对全部参数的完整解释,以下摘取了其中需要重点关注的 6 个参数:
# 节点的通讯服务的本机绑定网卡地址;必选配置;
# 涉及的通讯服务有 3 种:节点的数据查询服务(HTTP)、账本共识服务(TCP)、账本交易服务(TCP);
# 指定 0.0.0.0 将绑定到所有网卡上;
server.address=0.0.0.0
# 节点的数据查询服务(HTTP)的本机端口;必选配置;
server.port=8080
# 节点的通讯服务的公共访问地址;非必选配置,如未配置,则以“本机绑定网卡地址(server.address)”一致;
# 这一个声明式的配置项,不会影响节点的通讯服务的运行,但会影响其它节点、网关以及其它潜在的客户端访问者如何发现节点的服务,因此提供一个正确的配置是必要的;
# 通常在一个共识节点、服务网关跨越了不同网络进行部署的情况下,网络管理员会采用 NAT 方式使得外部访问者得以访问位于内网的服务,因此“公共访问地址”应该配置为“本机绑定网卡地址”对应的 NAT 网络地址;
server.public-address=
# 节点的数据查询服务(HTTP)的公共访问端口;非必选配置,如未配置,则以“本机端口(server.port)”一致;
# 通常在一个共识节点、服务网关跨越了不同网络进行部署的情况下,网络管理员会采用 NAT 方式使得外部访问者得以访问位于内网的服务,因此“公共访问端口”应该配置为“本机端口(server.port)”对应的 NAT 网络端口;
server.public-port=
# SSH 控制台服务绑定的本机IP;如果设置为 127.0.0.1 则只允许从服务器本机连接到控制台;
shell.ssh.host=127.0.0.1
# SSH 控制台服务的端口号;如果在一台服务器上部署多个节点时,请为不同的节点进程指定不同的端口;
shell.ssh.port=8022
启动服务网关
# 进入 bin 目录
cd $PEER_HOME/bin
# 赋予启动脚本可执行权限;
chmod +x *.sh
# 执行启动脚本;
./start.sh
执行启动脚本之后,服务网关以后台方式运行,同时启动脚本会自动进入启动日志查看模式将启动过程的日志显示出来,键入 CTRL+C 可以退出日志查看而不会中断服务网关的运行。
成功的启动将会看到如下的日志输出:
图:6.3 服务网关启动成功的日志输出
初始化管理控制台和密钥库
当服务网关初次启动时,会生成服务网关管理控制台的 root 管理员的初始登录口令,该口令是随机生成的,输出到文本格式的文件 GATEWAY_HOME/logs/root.passwd 。口令只有一行,打开文件复制全部内容。
# 连接服务网关管理控制台;
# 注意,使用 gateway.conf 配置文件指定的端口(默认8022),而不是 SSH 终端的默认端口 22
ssh root@127.0.0.1 -p 8022
如图6.2, 输入口令后,由于是首次登录,会提示立即更改管理员口令。
接下来,按照提示进行下一步初始化密钥库。
图6.2 服务网关管理控制台连接与系统初始化
配置服务网关
配置参与方密钥对
命令:keyadd (将密钥加入密钥库,通过 --p 参数指定 Base58 格式的公钥)
注:输入命令后按下 TAB 提示命令的参数列表
图7.1 服务网关配置参与方密钥对
接入共识节点
命令:connect-peer (连接共识节点)
服务网关只需要指定连接到共识网络(账本)中的任意一个共识节点,就会自动获得共识网络的节点拓扑结构,进而动态维护与整个共识网络(账本)的所有共识节点的连接。
图7.2 服务网关接入共识节点
通过SDK接口发起区块链交易
千尺链以 SDK 方式提供了编程接口,实现对区块链发送指令执行操作和检索数据。
交易 是区块链指令执行的基本单位,一笔 交易 包含了以 原子性 完成的一组操作指令。所谓的 原子性 是指这一组操作指令只有全部都执行成功才会提交执行结果,如果任意一项操作指令执行失败了都会触发回滚全部一组操作指令的结果。
一笔有效的 交易 需要被合法的区块链用户的私钥进行签署,才会被区块链系统接受并执行。
可以由一个或者多个用户签署一笔 交易 ,以体现相关的业务行为是一人或者多人共同实施的。
一笔 交易 被 SDK 定义并提交到服务网关后,服务网关会对交易进行验证,验证通过后会追加服务网关上绑定的参与方密钥的签名,之后交易被广播到目的账本的共识网络,最终,共识节点通过共识协议接收到一致的交易序列,进行验证、执行和返回交易结果。
通过 SDK 定义一笔交易,通常包括 4 个步骤:
- 加载区块链服务驱动程序。(在全局上下文只需要执行一次)
- 定义交易内容。
- 签署交易。
- 连接网关并提交交易。
SDK 以 Java 代码包方式提供,也可以通过 maven 管理依赖。以下以建立 maven 类型的 Java 项目为例,描述如何通过 SDK 实现与区块链的交互
Java Maven 项目引入 SDK 依赖
<!-- 区块链服务接口 -->
<dependency>
<groupId>cn.linkfo.blockchain</groupId>
<artifactId>service</artifactId>
<version>1.2.3.RELEASE</version>
</dependency>
<!-- 区块链服务驱动实现 -->
<dependency>
<groupId>cn.linkfo.blockchain</groupId>
<artifactId>blockchain-driver-standard</artifactId>
<version>1.2.3.RELEASE </version>
<scope>provided</scope>
</dependency>
注: 需要配置 maven 加入仓库 https://maven.linkgie.com/repository/maven-public/. 有两种可选的配置方式: (1)配置到项目的 pom.xml 中; (2)配置到运行编译的 maven 环境的 settings.xml 文件。
配置方法(1)在 pom.xml 中加入仓库配置
<!-- 依赖包的仓库 -->
<repositories>
<repository>
<id>nexus</id>
<name>nexus</name>
<url>https://maven.linkgie.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<!-- 插件的仓库 -->
<pluginRepositories>
<pluginRepository>
<id>nexus</id>
<name>nexus</name>
<url>https://maven.linkgie.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
配置方法(2)在 settings.xml 中加入仓库配置
<profile>
<id>nexus</id>
<repositories>
<repository>
<id>dev-nexus</id>
<url>https://maven.linkgie.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>dev-nexus</id>
<url>https://maven.linkgie.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
加载驱动
// 加载驱动;
BlockchainDriver driver = BlockchainDriverManager.getDriver();
定义交易内容
// 账本编码;
String ledgerCode = "W4tC3x8z1BhUt2zZ1jEkhv6xz1sQKk1XfFuNCQ4kMDYenAfVv";
// 声明交易;
TransactionStatement txStatement = driver.getTransactionFactory().newTransaction(ledgerCode);
//注册新用户;
IDKey newUserID = driver.getKeyManager().getKeyGenerator().generateKey("SM2");
txStatement.user().register(newUserID.getIdentity());
// 写入数据记录;
String dataAccountAddress = "k033re23ff23cc2kk323nj2h34i2h3ie2h";
txStatement.data().write(dataAccountAddress)//
.setLong("A", 1000L, -1)//
.setLong("B", 2000L, -1);
// 定义合约调用;
String contractAddress = "zZ1jEkhv6xz1sQKk1XfFuNCQ4k";
ContractProxyCallInstructionBuilder<AssetContract> assetContract = txStatement.contract()
.involve(contractAddress, AssetContract.class);
LongReceipt issueReceipt = txStatement.accept(assetContract.call().issue(100));
LongReceipt transferReceipt = txStatement.accept(assetContract.call().transfer(100, "88h32k32n32j3bne2w213"));
String contractAddress2 = "u9932ho213hq38dywhr";
GenericReceipt<PrimitiveObject> callReceipt = txStatement.contract().invoke(contractAddress2).call("issue");
// 生成交易;
Transaction transaction = txStatement.doFinal();
// 读取密钥;
IDKey adminKey = loadAdminKey();
// 签署交易;
TransactionSigner txSigner = driver.getTransactionFactory().signTransaction(transaction);
txSigner.sign(adminKey);
// 生成已签署交易;
SignedTransaction signedTransaction = txSigner.doFinal();
连接服务网关并提交交易
// 连接区块链网关节点;
String host = "192.168.1.100";
int port = 8080;
BlockchainService bcsrv = driver.connect(host, port);
Blockchain testChain = bcsrv.getBlockchain(ledgerCode);
// 提交交易;
TransactionReceipt txReceipt = testChain.transaction().submit(signedTransaction);
// 等待交易返回;
TransactionResponse txResponse = txReceipt.getResponse();
// 获取交易状态;
TransactionResponseStatus txStatus = txResponse.getStatus();
// 获取交易指令执行返回的结果;
long issueResult = issueReceipt.getValue(txResponse);
long transferResult = transferReceipt.getValue(txResponse);
PrimitiveObject callResult = callReceipt.getValue(txResponse);