1. 概述
通过本文你将可以搭建起长安链多节点集群,并使用命令行工具和SDK完成长安链功能的体验。
通过源码搭建长安链并且上链查数据需要以下步骤,本文将一一演示
下载长安链及证书管理工具源码
编译源码
生成节点证书
编译及安装包制作
启动节点集群
查看节点状态
使用CMC工具安装、调用、查询一个合约
使用GO SDK验证合约
2. 环境依赖
2.1. 硬件依赖
配置 | 最低配置 | 推荐配置 |
---|---|---|
CPU | 1.5GHz | 2.4GHz |
内存 | 4GB | 8GB |
核心 | 4核 | 8核 |
带宽 | 2Mb | 10Mb |
2.2. 软件依赖
当前文档在centos7.6操作下完成,以下为本次演示所需的依赖 软件列表如下:
名称 | 版本 | 描述 | 是否必须 |
---|---|---|---|
git | / | 源码管理 | 是 |
golang | 1.15+ | 编译环境 | 是 |
docker | 18+ | 独立运行容器 | 否 |
docker-compose | / | 容器管理组件 | 否 |
gcc | 4+ | 编译环境依赖 | 是 |
glibc | 2.18 | 智能合约执行环境依赖 | 是 |
tmux | / | 默认快速启动命令依赖 | 否 |
wasmer运行时库 libwasmer_runtime_c_api.so | / | 库在chainmaker-go/main 目录下,将该库路径添加至系统PATH环境变量下启动脚本默认包含,单独启动需加上如下配置: cd deployPath/lib cp xxx/main/libwasmer_runtime_c_api.so libwasmer.so export LD_LIBRARY_PATH=deployPath/lib:$LD_LIBRARY_PATH |
是 |
2.2.1. git
下载地址:https://git-scm.com/downloads
安装步骤,请参看:https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
2.2.2. golang
版本为1.15或以上
安装步骤,请参看:https://golang.org/doc/install
2.2.3. docker
若不使用采用
docker
方式搭建集群,可以不安装
2.2.4. docker-compose
若不使用采用
docker
方式搭建集群,可以不安装
3. 环境搭建
3.1. 使用脚本搭建
适用于
Linux
、MacOS
3.1.1. 源码下载
从长安链官网下载源码:https://git.chainmaker.org.cn/chainmaker/chainmaker-go
当前为私有仓库,需要先进行账号注册
下载
chainmaker
源码到本地
$ git clone --recursive -b v1.1.1 https://git.chainmaker.org.cn/chainmaker/chainmaker-go.git
下载证书生成工具源码到本地
$ git clone --recursive https://git.chainmaker.org.cn/chainmaker/chainmaker-cryptogen.git
3.1.2. 源码编译
编译证书生成工具
$ cd chainmaker-cryptogen
$ make
3.1.3. 证书及配置文件生成
将编译好的
chainmaker-cryptogen
,软连接或拷贝到chainmaker-go/tools
目录
# 进入工具目录
$ cd chainmaker-go/tools
# 软连接chainmaker-cryptogen到tools目录下
$ ln -s ../../chainmaker-cryptogen/ .
进入
chainmaker-go/scripts
目录,执行prepare.sh
脚本生成单链4节点集群配置,存于路径chainmaker-go/build
中prepare.sh
脚本支持生成solo
模式节点证书和配置,以及4/7/10/13/16节点的证书和配置
# 进入脚本目录
$ cd ../scripts
# 查看脚本帮助
$ ./prepare.sh -h
Usage:
prepare.sh node_cnt(1/4/7/10/13/16) chain_cnt(1-4) p2p_port_prefix(default:11300) rpc_port_prefix(default:12300)
eg1: prepare.sh 4 1
eg2: prepare.sh 4 1 11300 12300
# 生成单链4节点集群的证书和配置
$ ./prepare.sh 4 1
begin check params...
begin generate certs, cnt: 4
input consensus type(default 1/tbft):
input log level(default INFO):
begin generate node1 config...
begin generate node2 config...
begin generate node3 config...
begin generate node4 config...
# 查看生成好的节点证书和配置
$ tree -L 3 ../build/
../build/
├── config
│ ├── node1
│ │ ├── certs
│ │ ├── chainconfig
│ │ ├── chainmaker.yml
│ │ └── log.yml
│ ├── node2
│ │ ├── certs
│ │ ├── chainconfig
│ │ ├── chainmaker.yml
│ │ └── log.yml
│ ├── node3
│ │ ├── certs
│ │ ├── chainconfig
│ │ ├── chainmaker.yml
│ │ └── log.yml
│ └── node4
│ ├── certs
│ ├── chainconfig
│ ├── chainmaker.yml
│ └── log.yml
├── crypto-config
│ ├── wx-org1.chainmaker.org
│ │ ├── ca
│ │ ├── node
│ │ └── user
│ ├── wx-org2.chainmaker.org
│ │ ├── ca
│ │ ├── node
│ │ └── user
│ ├── wx-org3.chainmaker.org
│ │ ├── ca
│ │ ├── node
│ │ └── user
│ └── wx-org4.chainmaker.org
│ ├── ca
│ ├── node
│ └── user
└── crypto_config.yml
关于自动生成的端口说明
通过prepare.sh
脚本生成的配置,默认是在单台服务器上部署,故自动生成的端口号,是从一个起始端口号开始依次递增,可以通过命令行参数修改起始端口号。
主要有2个端口,p2p
端口(用于节点互联)和rpc
端口(用于客户端与节点通信),p2p
起始端口为11301
,rpc
起始端口为12301
。
如果生成4个节点的配置,p2p
端口分别为:11301、11302、11303、11304
,rpc
端口分别为:12301、12302、12303、12304
如果是在多机部署,希望生成固定的端口号,请参考:【多机部署】
3.1.4. 编译及安装包制作
执行
build_release.sh
脚本,将编译chainmaker-go
模块,并打包成安装包,存于路径chainmaker-go/build/release
中
$ ./build_release.sh
$ tree ../build/release/
../build/release/
├── chainmaker-V1.0.0-wx-org1.chainmaker.org-20210406194833-x86_64.tar.gz
├── chainmaker-V1.0.0-wx-org2.chainmaker.org-20210406194833-x86_64.tar.gz
├── chainmaker-V1.0.0-wx-org3.chainmaker.org-20210406194833-x86_64.tar.gz
├── chainmaker-V1.0.0-wx-org4.chainmaker.org-20210406194833-x86_64.tar.gz
└── crypto-config-20210406194833.tar.gz
3.1.5. 启动节点集群
执行
cluster_quick_start.sh
脚本,会解压各个安装包,调用bin
目录中的start.sh
脚本,启动chainmaker
节点
$ ./cluster_quick_start.sh normal
若需要关闭集群,使用脚本:
$ ./cluster_quick_stop.sh
3.1.6. 查看节点启动使用正常
查看进程是否存在
$ ps -ef|grep chainmaker | grep -v grep
25261 2146 4 19:55 pts/20 00:00:01 ./chainmaker start -c ../config/wx-org1.chainmaker.org/chainmaker.yml
25286 2146 4 19:55 pts/20 00:00:01 ./chainmaker start -c ../config/wx-org2.chainmaker.org/chainmaker.yml
25309 2146 4 19:55 pts/20 00:00:01 ./chainmaker start -c ../config/wx-org3.chainmaker.org/chainmaker.yml
25335 2146 4 19:55 pts/20 00:00:01 ./chainmaker start -c ../config/wx-org4.chainmaker.org/chainmaker.yml
查看端口是否监听
$ netstat -lptn | grep 1230
tcp6 0 0 :::12301 :::* LISTEN 25261/./chainmaker
tcp6 0 0 :::12302 :::* LISTEN 25286/./chainmaker
tcp6 0 0 :::12303 :::* LISTEN 25309/./chainmaker
tcp6 0 0 :::12304 :::* LISTEN 25335/./chainmaker
检查节点是否有
ERROR
日志
$ cat ../build/release/chainmaker-V1.0.0-wx-org1.chainmaker.org/bin/panic.log
$ tail -f ../build/release/chainmaker-V1.0.0-wx-org1.chainmaker.org/log/system.log
$ tail -f ../build/release/chainmaker-V1.0.0-wx-org1.chainmaker.org/log/system.log|grep "ERROR\|put block\|all necessary"
3.2. 使用Docker搭建
适用于
Docker
3.2.1. 编译docker镜像
$ cd chainmaker-go
$ cd main && go mod download
$ cd ..
# 生成镜像名称为:chainmaker:v1.1.1,如需要修改版本,请修改Makefile文件
$ make docker-build
3.2.2. 启停solo节点
为了方便使用,使用的配置文件及证书已放置于目录:
chainmaker-go/scripts/docker/config/solo
如镜像名称有调整,请修改
solo.docker-compose.yml
文件
$ cd chainmaker-go/scripts/docker/
# 启动solo节点
$ ./solo_up.sh
# 关闭solo节点
$ ./solo_down.sh
3.2.3. 启停4节点集群
为了方便使用,使用的配置文件及证书已放置于目录:
chainmaker-go/scripts/docker/config/four-nodes
如镜像名称有调整,请修改
four-nodes.docker-compose.yml
文件
$ cd chainmaker-go/scripts/docker/
# 启动4节点集群
$ ./four-nodes_up.sh
# 关闭4节点集群
$ ./four-nodes_down.sh
4. 功能验证
为了验证所搭建的链功能是否正常,可以通过cmc
命令行工具或sdk
的单元测试用例来进行验证。
4.1. cmc命令行工具验证
请参看:【命令行工具】
4.2. go sdk验证
4.2.1. 下载go sdk源码
$ git clone --recursive -b v1.1.1 https://git.chainmaker.org.cn/chainmaker/chainmaker-sdk-go.git
4.2.2. 关联证书
将通过
prepare.sh
工具生成的crypto-config
目录,软连接到chainmaker-sdk-go/testdata
目录
$ cd chainmaker-sdk-go/testdata
# 若是使用脚本搭建方式,这里使用新生成的用户证书,请先将testdata已有的crypto-config移除
# 若是使用docker搭建,使用已有证书进行测试,需跳过下面两步
$ /bin/rm -rf crypto-config
$ ln -s ../../chainmaker-go/build/crypto-config/ .
4.2.3. 配置修改
修改sdk单元测试使用的配置文件:
chainmaker-sdk-go/testdata/sdk_config.yml
根据需要修改节点地址:
nodes:
- # 节点地址,格式为:IP:端口:连接数
node_addr: "127.0.0.1:12301"
如果证书路径有调整,修改对应的证书路径配置:
# 客户端用户私钥路径
user_key_file_path: "./testdata/crypto-config/wx-org1.chainmaker.org/user/client1/client1.tls.key
# 客户端用户证书路径
user_crt_file_path: "./testdata/crypto-config/wx-org1.chainmaker.org/user/client1/client1.tls.crt"
# 客户端用户交易签名私钥路径(若未设置,将使用user_key_file_path)
user_sign_key_file_path: "./testdata/crypto-config/wx-org1.chainmaker.org/user/client1/client1.sign.key"
# 客户端用户交易签名证书路径(若未设置,将使用user_crt_file_path)
user_sign_crt_file_path: "./testdata/crypto-config/wx-org1.chainmaker.org/user/client1/client1.sign.crt"
4.2.4. 执行存证合约单测
该单测会进行存证合约的部署、调用和查询。
$ cd chainmaker-sdk-go
$ go test -v -run UserContractClaim
看到类似输出,说明功能验证成功:
2021-04-07 21:45:25.510 [DEBUG] [SDK] chainmaker-sdk-go/sdk_client.go:343 [SDK] proposalRequest resp: message:"SUCCESS" contract_result:<result:"{\"file_hash\":\"9387687162f344b79b39385c5e998f97\",\"file_name\":\"file_1617803123443\",\"time\":\"1617803123443\"}" gas_used:25145486 >
4.2.5. 执行资产合约单测
也可以跑资产合约的单测,该单测会创建A、B两个账号,每个账号初始资产为100000,A给B转账100,最后查看A和B的余额,分别为99900
和100100
。
$ go test -v -run UserContractAsset
看到类似输出,说明资产合约功能验证成功:
2021-04-07 21:46:30.439 [DEBUG] [SDK] chainmaker-sdk-go/sdk_client.go:343 [SDK] proposalRequest resp: message:"SUCCESS" contract_result:<result:"99900" gas_used:16058023 >
2021-04-07 21:46:30.448 [DEBUG] [SDK] chainmaker-sdk-go/sdk_client.go:343 [SDK] proposalRequest resp: message:"SUCCESS" contract_result:<result:"100100" gas_used:16120471 >
5. 开发-goland启动链
5.1. 下载安装goland
略
5.2. 下载安装go
5.2.1. 安装go
略
5.2.2. 设置代理
打开终端执行
$ go env -w GOPROXY=https://goproxy.io,direct
5.3. 下载源码
$ git clone --recurse-submodules -b v1.1.1 https://git.chainmaker.org.cn/chainmaker/chainmaker-go.git
5.4. 启动goland
5.4.1. 导入chainmaker-go
略
5.4.2. 配置goland
Ctrl+Alt+S 或者 File->Settings…
Go–>Go Modules –> 勾上Enable Go Modules integration
Go–>GOROOT–>添加已安装的go
5.4.3. 启动项目(SOLO模式)
修改配置文件
chainmaker-go/config/wx-org1/chainconfig/bc1.yml将 consensus.type修改为0:启用solo共识
chainmaker-go/config/wx-org1/log.yml将 log_in_console修改为true:在控制台输出日志
启动
找到文件 chainmaker-go/main/main.go 直接运行,然后点击停止,修改启动参数为start -c ../config/wx-org1/chainmaker.yml
再次点击运行即可;见下图:
5.4.4. 测试
找到文件chainmaker-go/test/send_proposal_request_solo/main.go
直接运行main即可
若遇到文件未找到等错误,请将goland 的配置: working directory修改为当前目录,或者手动修改文件目录
6. 常见问题
此处介绍可能遇到的常见问题
6.1. 视频教程
时间脚本:
• 01-04分钟:长安链简介及大纲介绍;
• 04-09分钟:环境安装演示;
• 09-26分钟:单机部署;
• 26-36分钟:智能合约开发(穿插常见问题);
• 36-54分钟:部署合约(穿插常见问题);
• 54—结束:常见问题及单机&多机部署对照表。
6.2. 编译时错误
编译chainmaker-go及chainmaker-cryptogen时可能出现的错误
6.2.1. missing go.sum entry
Q:
如果执行 ./build_release.sh 时 或者在启动时 报错:misssing go.sum entry: to add it,分别在 chainmaker-go/main 或者 chainmaker-go/common 和 chainmaker-go/tools/cmc 下执行 go mod download ,执行完后 再重试
问题描述如下图:
A:
原因:go1.15 版本 执行go build时会自动下载依赖,会更新mod文档,在go 1.16版本这一行为被禁止了。想要安装、更新依赖只能使用go get, go mod download, go mod tidy等命令,go build和go test将不会再做这类工作。
在go1.16版本中,想要自动更新依赖可以使用 go build -mod=mod,
进入对应目录执行go mod download
# chainmaker-go项目
cd chainmaker-go/main
go mod download
cd chainmaker-go/common
go mod download
cd chainmaker-go/tools/cmc
go mod download
# # chainmaker-cryptogen项目
cd chainmaker-cryptogen/src
go mod download
6.2.2. go.mod no such file or directory
Q:
编译时报错:
go: chainmaker.org/chainmaker-go/blockchain@v0.0.0 requires chainmaker.org/chainmaker-go/common@v0.0.0: parsing ../common/go.mod: open /mnt/d/develop/workspace/go/noSubmodule/chainmaker-go/common/go.mod: no such file or directory
A:
一、可能是因为clone是未使用submodule模式,需初始化submodule,如下命令
$ git submodule init
$ git submodule update
正确的clone方式:
$ git clone --recursive -b v1.1.1 https://git.chainmaker.org.cn/chainmaker/chainmaker-go.git
6.3. 启动时错误
6.3.1. not found GLIBC_2.18
Q:
若出现错误
./chainmaker: /lib64/libc.so.6: version
GLIBC_2.18’ not found (required by /root/git-code/chainmaker-go/module/vm/wasmer/wasmer-go/libwasmer.so)`
A:
在linux下可进入chainmaker-go/scripts/3rd目录安装glibc-2.18.tar.gz依赖
# 注:此操作为安装替换GCC版本,请慎重操作。一旦出错系统将不可用。
$ cd scripts/3rd
$ sh install.sh
6.3.2. restart.sh 权限不足
Q:
[root@localhost scripts]# ./cluster_quick_start.sh normal ===> Staring chainmaker cluster START ==> /home/wx/chainmaker/chainmaker-go/build/release/chainmaker-V1.0.0-wx-org1.chainmaker.org ./cluster_quick_start.sh: line 51: ./restart.sh: Permission denied
A:
如果启动时 出现restart.sh 权限不足问题,给restart.sh 增加执行权限
给项目源文件添加执行权限
$ cd chainmaker-go/script/bin
$ chmod +x *.sh
给部署文件添加执行权限
# 进入四个节点的bin目录下 执行下面命令(以第一个节点 org1 为例)
$ cd chainmaker-go/build/release/chainmaker-V1.0.0-wx-org1.chainmaker.org/bin
$ chmod +x *.sh
6.4. 运行时错误
6.4.1. syscall/js.valueGet not exported
Q:
执行gasm合约时报错:resolve imports: syscall/js.valueGet not exported in module env
A:
tinygo不支持fmt等函数
6.4.2. runtime type error | byte code validation failed
Q:
发送交易成功,但链打印错误信息:contract invoke failed, runtime type error, expect rust:[2], but got 4。同时根据该交易id查询到交易错误信息。
failed to create vm runtime, contract: contract_test, [contract_test], byte code validation failed
A:
执行交易时异步的(查询类交易除外),返回的状态为链成功接收到交易的状态。执行合约是,runtimeType选择错误,需要根据自己的合约语言选择对应的runtimeType。
byte code validation failed:可能原因:1、运行类型错误;2、wasm文件损坏;3、wasm文件非官网指定渠道编译
语言 | 类型 |
---|---|
系统合约 | RuntimeType_NATIVE = 1 |
rust | RuntimeType_WASMER = 2 |
c++ | RuntimeType_WXVM = 3 |
tinygo | RuntimeType_GASM = 4 |
solidity | RuntimeType_EVM = 5 |
6.4.3. 返回成功,但实际执行失败
Q:
使用sdk执行安装、调用合约时,SDK 返回message为ok,但链和交易显示执行失败
A:
交易的执行是异步的。SDK返回的成功信息指的是链成功接收到该交易。
获取查看交易实际结果的方式:
根据txId查询该交易,解析出结果。
使用SDK是选择同步发送交易,等待执行结果。
6.5. 其他关键信息
6.5.1. 出块标记是什么
进入log目录,查看日志文件 筛选
put block
即可
cat system.log|grep "ERROR\|put block"
其中一行解释如下:
2021-04-22 13:50:56.647 [INFO] [Storage] @chain1 store/blockstore_impl.go:241 chain[chain1]: put block[12] (txs:1 bytes:8078), time used (mashal:0, log:2, commit:5, total:7)
时间 [日志级别] [模块] @链名称 文件名.go:行数 链chain[链名称]:put block[区块高度](txs:交易个数 bytes:区块大小), 使用时间毫秒(mashal:0, log:2, commit:5, total:7)
6.5.2. 组网成功标记是什么
组网成功后,即可发送交易。此时接收到的交易将进入到交易池当中,并且会广播给网络的每一个节点(共识、见证节点、轻节点),随后等待共识成功选举leader开始打包区块。
SOLO共识
start blockchain[chain1] success
其他共识
进入log目录,查看日志文件 筛选
all necessary peers connected
和start blockchain[chain1] success
可看到如下日志
cat system.log|grep "init blockchain\|all necessary peers connected"
2021-04-22 16:13:07.520 [INFO] [Net] p2p/libp2p_connection_supervisor.go:91 [ConnSupervisor] all necessary peers connected.
7. Q&A
7.1. 合约开发建议采用哪种开发语言?建议使用的开发工具是什么?
建议开发语言:rust,合约内可以引用大多数外部依赖(如:含随机数的不可用)。 建议开发工具:vscode,+ 插件:rust-analyzer
7.2. 智能合约中PutState有两个参数是什么意思?
func PutState(key string, field string, value string) ResultCode
实际存储到leveldb的key为:contractName + “#” + key + field
长度限制: key:64、 field:64、 value:1M
且key、field符合正则
^[a-zA-Z0-9._-]+$
,只能为英文字母、数字、点、横杠、下划线两个参数的原因:一个逻辑性的命名空间概念,key作为namespace一般为有规律的值
7.3. 不同组织间有没有共同的ca?
不同组织间的CA证书可以使用同一个。但是不建议这样做,建议是一个组织一个CA证书。
# 各组织不同CA配置
trust_roots:
- org_id: "wx-org1.chainmaker.org"
root: "ca1.crt"
- org_id: "wx-org2.chainmaker.org"
root: "ca2.crt"
- org_id: "wx-org3.chainmaker.org"
root: "ca3.crt"
# 各组织相同CA配置
trust_roots:
- org_id: "wx-org1.chainmaker.org"
root: "ca1.crt"
- org_id: "wx-org2.chainmaker.org"
root: "ca1.crt"
- org_id: "wx-org3.chainmaker.org"
root: "ca1.crt"
7.4. 组织间的数据能否实现哪些数据可以公开给对方,哪些数据不能公开给对方
上链数据均共享。可以根据场景需要,采用混合加密、分层身份加密、同态加密、零知识证明等方式保护数据隐私
7.5. 合约代码是否需要每个组织节点都部署?
合约代码部署也是一个交易。发送给某个节点后,该节点会把交易广播到自己的网络中。其他节点也就有了这个交易了。交易上链需要各个节点达成共识,其他共识节点也会执行该交易。