本节对数据共享系统的区块链部分做一个简单的介绍,包括目录结构、文件作用、设计思路。

购买专栏前请认真阅读:《基于区块链与IPFS的数据共享系统》专栏简介

一、区块链部分文件目录简介

├── bin //保存了二进制文件方便启动网络│ ├── configtxgen //生成创世区块和通道材料│ └── cryptogen //生成密钥├── chaincode //链码│ ├── datashare.go│ ├── go.mod│ └── go.sum├── configtx.yaml //来自byfn├── crypto-config.yaml //来自byfn├── docker-compose-byfn.yaml //byfn中的节点配置与IPFS容器配置├── explorer //区块链浏览器│ ├── config.json│ ├── connection-profile│ └── docker-compose.yaml├── start.sh //启动网络脚本├── stop.sh //关闭网络脚本└── tape //fabric压测工具tape├── config-temp.yaml├── tape└── test

二、启动网络脚本 start.sh

启动脚本为启动区块链网络以及IPFS容器,之后使用sed命令更换区块链浏览器、tape配置文件中的私钥。

这里解释一下为什么需要替换私钥文件,因为每次区块链网络重启后都会重新生成私钥文件,区块链浏览器、tape在使用时访问Fabric网络需要使用私钥文件。

具体步骤如下面代码所示,首先是获取私钥文件名称;然后使用模版文件 config-temp.yaml 替换当前的配置文件;使用sed命令替换priv_sk字段,此时配置文件中的私钥就替换好了。

#替换tape配置文件的私钥priv_sk=$(ls crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore)cp -rf ./tape/config-temp.yaml ./tape/config.yamlsed -i "s/priv_sk/$priv_sk/" ./tape/config.yaml

三、关闭网络脚本 ./stop.sh

关闭网络脚本中依次清理区块链网络与区块链浏览器的Docker容器、网络相关材料以及链码容器。

#清理之前的网络docker-compose -f explorer/docker-compose.yaml down -vdocker-compose -f docker-compose-byfn.yaml down -v#清理网络相关材料rm -rf channel-artifactsrm -rf crypto-config#清理链码容器clearContainersremoveUnwantedImages

四、docker-compose-byfn.yaml 文件

这个文件是将BYFN中的first-network默认启动的网络相关的yaml文件整理了一下,整合到了一个yaml文件里,看着会比较清晰。此外,IPFS容器配置也放到了此文件,方便IPFS启动。

五、链码 datashare.go

在本链码中,使用结构体存储数据的传输记录,字段有发送者、接受者、使用发送者公钥加密的文件CID(IPFS Hash)、使用接受者公钥加密的文件CID、文件名称、区块链交易Hash、时间戳。

// 数据传输记录结构体type Record struct {Senderstring `json:"sender"`Receiverstring `json:"receiver"`SenderEncrypted_cid string `json:"secid"`ReceiverEncrypted_cid string `json:"recid"`Filenamestring `json:"filename"`Txidstring `json:"txid"`Timestamp string `json:"timestamp"`}

在invoke中可以看到有两个主要的函数queryRecordsendData,其中queryRecord是用来查询传输记录的,传入的参数为用户的公钥,然后是通过APIstub.GetState()获取Fabric账本中的键为args[0]对应的值。

提示:在Fabric默认使用的levelDB中,数据使用Key-Value键值对存储数据。

sendData函数为负责将传输记录上链,关键代码如下:

# 实例化Record结构体并使用传入的参数赋值var record = Record{Sender: args[0], Receiver: args[1], SenderEncrypted_cid: args[2], ReceiverEncrypted_cid: args[3], Filename: args[4], Timestamp: time, Txid: APIstub.GetTxID()}# 获取用户当前已存的传输记录recordsAsBytes, err := APIstub.GetState(args[1])#使用json反序列化,将json格式的数据转化为结构体,方便操作json.Unmarshal(recordsAsBytes, &records)#添加新的记录到所有的传输记录中records = append(records, record)#将新的传输记录存储至账本中APIstub.PutState(args[1], recordsAsBytes)