需求分析
xx工具是一个全网资产探测引擎,其中一个功能是自动发现全网被挂马或者被篡改的网站并记录下来。现在欲将这些资产信息写到区块链上,通过链码实现增删改查的功能,并通过可视化界面进行操作和分类展示。
一条资产数据记录包含ip、port、label、domain、maindata等字段内容。系统最终需能够根据指定字段名或者时间段等过滤展示,因此区块链系统需要支持富查询,故stateDB选择couchDB
系统主要包由区块链系统、链码、网站后台、前端四部分构成。底层基于hyperledger fabric进行构建。
数据源由xx工具收集后经过数据清洗写入到文件中。后台读取文件内容后解析,调用链码写入区块链和couchDB;并通过调用链码实现根据时间段删除以及查询等功能。
资产数据每天采集一次,约10万条左右,数据量较大,因此写入区块链采用go routine实现。
环境搭建
节点拓扑图
工具安装
项目中fabric的运行采用Docker的方式,因此需要安装Docker,docker-compose(用于同时启动多个Docker镜像,且可以共享同一个网络);另外fabric使用golang开发,并且SDK选择了fabric-sdk-go,因此需要安装go。
1.Docker
17.03.0-ce或以上版本,具体安装方式可以在网上找教程,此处以centOS为例
卸载旧版本
1
2
3
4$ sudo yum remove docker \
docker-common \
docker-selinux \
docker-engine安装依赖
1
2
3$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2yum 软件源(否则会很慢)
1 | $ sudo yum-config-manager \ |
安装Docker CE
1
2$ sudo yum makecache fast
$ sudo yum install docker-ce启动Docker CE
1
2$ sudo systemctl enable docker
$ sudo systemctl start docker建立Docker用户组和用户
为了避免使用root用户,需要使用
docker
的用户加入docker
用户组1
2
3$ sudo groupadd docker
$ sudo usermod -aG docker $USER
$ sudo service docker restart查看Docker版本和测试
1
2$ docker -v
$ docker run hello-world
2.docker-compose
1.8或者以上版本
安装
1
2$ sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose && \
sudo chmod +x /usr/local/bin/docker-compose查看版本
1
$ docker-compose version
3.go
1.9.x或者以上版本,以go1.13为例
下载
sudo wget https://dl.google.com/go/go1.13.4.linux-amd64.tar.gz
安装
1
2$ sudo tar -xvf go1.13.4.linux-amd64.tar.gz
$ sudo mv go /usr/local设置环境变量
环境变量需要设置的是
GOROOT
、GOPATH
、PATH
,GOROOT
是安装Go软件包的位置,GOPATH
是工作目录的位置,要设置全局环境变量就把下面代码写入/etc/profile
或者/etc/bashrc
,用户变量就写入~/.profile
,或者~/.bashrc
.1
2
3export GOROOT=/usr/local/go
export GOPATH=$HOME/Projects/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH这里要注意,go的很多包在下载的时候会很慢或失败,可以使用代理或者GOPROXY解决。
代码结构与片段
代码框架图
整个系统采用前后端分离模式,后端通过http接口与前端通信。前端代码不包含在该项目中。后端web采用gin框架。底层搭建fabric环境,通过fabric-sdk-go实现对区块链以及链码进行操作。
fabric部署
1.公私钥和证书
配置文件为fixtures
下的crypto-config.yaml
,根据实际节点情况进行修改,修改好后执行命令:
1 | ./bin/cryptogen generate --config=./crypto-config.yaml |
执行成功会生成crypto-config
目录。
2.创世区块
该步骤需要配置文件configtx.yaml
,该配置中指定了节点组织架构,访问策略等,需要特别说明是的区块的大小以及区块出块时间也在该配置文件中。
1 | $ mkdir artifacts |
3.生成通道
mychannel
为通道id。
1 | $ ./bin/configtxgen -profile OneOrgOrdererGenesis -outputCreateChannelTx ./artifacts/mychannel.tx -channelID mychannel |
4.生成锚节点更新
1 | ./bin/configtxgen -profile OneOrgChannel -outputAnchorPeersUpdate ./artifacts/Org1MSPanchors.tx -channelID dbappchannel -asOrg Org1MSP |
以上步骤1.2.3.4可通过执行fixtures
下的start.sh
脚本一件完成
运行节点
1.准备docker配置文件
配置fixtrues下的docker-compose.yaml文件,包含的服务有orderer.example.com、ca.org1.example.com、peer0.org1.example.com、peer1.org1.example.com和couchdb五个Docker。
配置时要特别注意ORDERER_GENERAL_LOCALMSPID
,FABRIC_CA_SERVER_CA_KEYFILE
,CORE_PEER_NETWORKID
,CORE_PEER_LOCALMSPID
等参数。另外要注意网络问题,特别是多节点部署时,通常后面启动报错是会有网络不通的问题,可通过docker network ls
,docker inspect $network_name
等命令查看网络问题。
2.启动docker
1 | $ cd fixtures && docker-compose up --force-recreate -d |
如果显示有节点Exited,可以用docker logs $containerID
查看错误信息,根据具体错误信息排查。
3.停止docker
1 | cd fixtures && docker-compose down |
安装调用链码
1.命令行方式
启动容器
1
$ docker exec -it cli bash
创建Channel
1
$ peer channel create -o orderer.example.com:7050 -c mychannel -f ./mychannel.tx
Peer加入Channel
1
$ peer channel join -b mychannel.block
安装智能合约
1 | peer chaincode install -n mycc -p projectPath/chaincode/go/example02/cmd/ -v 1.0 |
这里链码使用的是fabric-sample的例子
实例化智能合约
区块初始化数据为a为100,b为200
1
$ peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer')"
查询query
Peer上查询a,显示100
1 | $ peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}' |
调用invoke
1
peer chaincode invoke -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}'
2.fabric-sdk方式
若采用sdk调用链码,需要两个部分,一个是配置文件config.yaml,另一个是调用代码。
config.yaml
配置文件在根目录下,配置时需注意
channels
,mspid
参数要与前面的配置保持一致,否则会报错。代码部分
代码部分需要使用依赖管理工具dep,在Gopkg.toml中指定fabric-sdk-go的版本,当然也可以用其它的包管理工具。
1
2
3
4
5
6ignored = ["github.com/sumapchain/chaincode"]
[[constraint]]
# Release v1.0.0-alpha4
name = "github.com/hyperledger/fabric-sdk-go"
revision = "a906355f73d060d7bf95874a9e90dc17589edbb3"代码实现在sdkInit目录下,start.go的init中指定了参数,该部分需要根据实际情况进行修改。sdk_setup.go实现了三个函数,初始化fabricSDK—SetupSDK(),创建通道并将指定的Peers加入—CreateChannel(),安装并实例化链码—InstallAndInstantiateCC()
调用合约
eduServide.go是对世界状态数据库进行增删改查的操作,通过一下方式进行调用链码,需要注意
Execute
和Query
,新增或者删除操作,是需要发起交易写入区块链的,因此需要用Execute
,若用Query
,则操作无效,但不会报错。1
2req := channel.Request{ChaincodeID: t.ChaincodeID, Fcn: "register", Args: [][]byte{[]byte(key), b}}
respone, err := t.Client.Execute(req)富查询
系统中较多涉及到富查询功能,在实现时通过构造查询语句queryString,将queryString作为参数传递给链码执行返回查询结果。对于富查询语句可参考https://docs.couchdb.org/en/latest/api/database/find.html#find-selectors和https://hyperledger-fabric.readthedocs.io/en/release-2.0/couchdb_tutorial.html#query-the-couchdb-state-database
系统后台
采用gin框架,基本没有什么问题,就是在数据上传时由于数据量大需要采用goroutine。
问题合集
概述
hyperledger fabric的配置是一个较为繁琐的过程,整个系统的开发过程中,遇到了各种问题,特别是在前期的环境搭建过程,到目前为止,对一些配置也没有完全仔细的研究过,对于改变网络架构的情况,应该还会遇到很多意想不到的问题。但在这个简单的项目开发过程中,学习到了很多,对fabric1.4有了更深的认识,以及对docker,go等有了更多的学习。
过程中遇到的问题,只记录了部分,在此记录一下,帮助有需要的朋友少走一点弯路。
Unable to initialize the Fabric SDK: failed to create SDK: failed to initialize configuration: unable to load identity config: failed to initialize identity config from config backend: failed to create identity config from backends: failed to load all CA configs : failed to load server certs: open : no such file or directory
解决办法:检查docker-compose.ymal配置文件,ca的部分是否有错误
stub.DelState()执行不成功
解决办法:要注意Invoke()和Query()的区别,调用的地方不能弄错,删除数据库操作需要Execute
Chaincode installed
Unable to install and instantiate the chaincode: failed to instantiate the chaincode: sending deploy transaction proposal failed: Transaction processing for endorser [localhost:7051]: Chaincode status Code: (500) UNKNOWN. Description: chaincode registration failed: container exited with 0解决办法:peer节点与其他节点之间的网络不通。查看docker-compose.yml文件中的配置,多个docker是不是在同一个网络
链码修改后不生效
解决办法:重启服务前要删除创建链码生成的docker image,删除命令可以参考MakeFile文件
创建应用通道失败: create channel failed: create channel failed: SendEnvelope failed: calling orderer ‘localhost:7050’ failed: Orderer Server Status Code: (400) BAD_REQUEST. Description: error authorizing update: error validating DeltaSet: policy for [Group] /Channel/Application not satisfied: Failed to reach implicit threshold of 1 sub-policies, required 1 remaining
解决办法:检查config.yaml文件中org中mspid是否和docker-compose.yaml以及configtx.yaml中一致。
ca节点报错:Error: Failed to find private key for certificate in ‘/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem’: Could not find matching private key for SKI: Failed getting key for SKI [[139 23 134 41 187 180 28 134 172 114 144 24 14 8 90 144 229 235 246 159 157 108 197 75 176 236 120 190 227 196 237 254]]: Key with SKI 8b178629bbb41c86ac7290180e085a90e5ebf69f9d6cc54bb0ec78bee3c4edfe not found in /etc/hyperledger/fabric-ca-server/msp/keystore
解决办法:重新生成证书后,docker-compose.yaml中ca的私钥
FABRIC_CA_SERVER_CA_KEYFIL
没有更新INFO 003 Endorser and orderer connections initialized
Error: got unexpected status: BAD_REQUEST – error validating channel creation transaction for new channel ‘mychannel’, could not succesfully apply update to template configuration: error authorizing update: error validating DeltaSet: policy for [Group] /Channel/Application not satisfied: implicit policy evaluation failed - 0 sub-policies were satisfied, but this policy requires 1 of the ‘Admins’ sub-policies to be satisfied
解决办法:一种可能,fabric1.4.4版本出现这个报错,检查configtx.yaml文件,修改为下图
1 | Capabilities: |
另一种可能,检查代码ccPolicy := cauthdsl.SignedByAnyMember([]string{"Org1MSP"})
中Org1MSP
部分是否正确(根据实际情况填写)
gRPC Transport Status Code: (4) DeadlineExceeded. Description: context deadline exceeded
解决方法:检查链码返回的数据是否超出grpc定义的最大限度
Failed to get endorsing peers: error getting endorsers from channel response: no endorsement combination can be satisfied
解决方法:查看channel文件capabilities的版本信息
1
./bin/configtxgen -profile OneOrgChannel -inspectChannelCreateTx ./artifacts/channel.tx
是否与configtx.yaml中的
Capabilities
部分一致。否则修改configtx.yaml,重新生成证书和通道配置。couchDB查询结果按顺序排序。根据官方网站给出的语法:https://docs.couchdb.org/en/stable/api/database/find.html#find-sort,在实际运用中会报错“"error": “no_usable_index”,”reason”: “No index exists for this sort, try indexing by the sort fields.””。但数据库中确实已经创建了该索引。
实际上,错误原因是:如果创建的一条索引包含了多条属性,那么查询是指定sort就要包含响应的所有属性。
![image-20200619135756392](基于hyperledger fabric1.4的资产分类系统.assets/image-20200619135756392.png)
下一步工作
目前对fabric有了一个初步认识,但对于具体的功能模块还需要进一步学习,例如:MSP,BCCSP,Fabric-CA,共识机制等等,这将是后面的一部分工作,另外,熟悉原理后将对fabric的算法进行替换,替换为国密,以及对Fabric-CA进行替换等。另外,对于fabric2.0,需要进一步了解与1.4版本的差异之处。
项目地址:
参考文献:
https://docs.couchdb.org/en/latest/api/database/find.html#find-selectors
https://www.cnblogs.com/llongst/p/9571363.html
https://chainhero.io/2018/06/tutorial-build-blockchain-app-v1-1-0/#configuration