返回

数据共享演示系统开发

前言

本文记录数据共享演示系统的开发全过程,包括环境搭建、BUG解决、开发思路等……

GitHub仓库

区块链网络

环境搭建

前置准备环境安装参考:传送门,本地开发环境如下:

  • git v2.34.1
  • curl v7.81.0
  • docker v20.10.21
  • docker-compose v1.29.2
  • go v1.20
  • jq v1.6
  • fabric v2.2 fabric-ca v1.4.7

运行测试网络

按照Fabric教程启动测试网络,验证环境搭建是否成功,参考:传送门

改造测试网络

network.sh文件复制到数据共享演示系统项目目录下,从头阅读network.sh文件,将提及的相关文件复制到项目目录下,

生成加密材料时,将组织从两个修改为四个

  • cryptogen
    1. ./organizations/cryptogen中新建crypto-config-org3.yaml、和crypto-config-org4.yaml配置文件
    2. network.sh中的createOrgs()函数中添加生成org3org4加密材料的代码
  • ca
    1. /organizations/fabric-ca/org1/fabric-ca-server-config.yaml/organizations/fabric-ca/org2/fabric-ca-server-config.yaml/organizations/fabric-ca/orderOrg/fabric-ca-server-config.yaml中的affiliations节添加org3、org4的所属部门信息,
    2. docker/docker-compose-ca.yaml中添加ca_org3ca_org4配置项
    3. /organizations/fabric-ca/中新建org3、org4文件夹及其中的fabric-ca-server-config.yaml配置文件
    4. 修改organizations/fabric-ca/registerEnroll.sh中端口号,添加createOrg3()、createOrg4()
    5. network.sh中的createOrgs()函数中调用registerEnroll.shcreateOrg3()、createOrg4()函数
    6. 修改./organizations/ccp-generate.sh中端口号,添加Org3、Org4

修改network.shcreateConsortium()Two->Four

  1. 修改./configtx/configtx.yamlOrganizations:中添加Org3、Org4Profiles:中添加Org3、Org4并且Two->Four

修改./docker/docker-compose-test-net.yamlvolumes中添加org34services中修改org12的端口号并添加org34cli中添加org34

(默认用的levelDB)修改./docker/docker-compose-couch.yaml:添加org34

修改scripts/createChannel.shcreateChannelTx()Two->Fourconfig.yaml中的profiles),最后joinChannel()、setAnchorPeer()调用加34

  • 修改scripts/envVar.sh:添加org4
  • 修改scripts/createChannel.sh:修改端口号,添加org4

修改scripts/deployCC.sh:最后调用函数处添加org34

修改network.shnetworkDown():添加关闭org4容器,删除org34生成的文件和证书

启动测试网络

使用cryptogen

  1. 启动节点容器:此命令创建一个由四个peer节点和一个orderer节点组成的 Fabric 网络,运行此命令时没有创建任何channel
1
./network.sh up
  1. 创建通道:在Org1、Org2、Org3Org4之间创建一个默认名称为mychannel的通道,并将它们的peer节点加入该通道,最后为每个组织设置了锚节点
1
./network.sh createChannel
  1. 安装链码:deployCC子命令将在peer0.org1.example.compeer0.org2.example.com上安装 asset-transfer (basic) 链码。 然后在使用通道标志(或mychannel如果未指定通道)的通道上部署指定的通道的链码
1
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
  1. 初始化链码:
1
2
3
4
5
6
7
8
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:5051
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}'
  1. 查询账本:
1
peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
  1. 调用链码改变账本上的资产所有者:
1
2
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt -c '{"function":"TransferAsset","Args":["asset6","Wyatt"]}'
peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
  1. 切换组织和节点查询账本:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:6051
peer chaincode query -C mychannel -n basic -c '{"Args":["ReadAsset","asset6"]}'

export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org4MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org4.example.com/users/Admin@org4.example.com/msp
export CORE_PEER_ADDRESS=localhost:8051
peer chaincode query -C mychannel -n basic -c '{"Args":["ReadAsset","asset6"]}'
  1. 关闭网络:该命令将停止并删除节点和链码容器,删除组织加密材料,并从Docker Registry移除链码镜像。 该命令还删除之前运行的通道项目和docker
1
./network.sh down

使用 Fabric CA

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
./network.sh up createChannel -ca

./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go

export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:5051

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}'

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt -c '{"function":"TransferAsset","Args":["asset6","Wyatt"]}'

peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'

拷贝Fabric-trace项目的blockchain-explorer,替换本项目的organizations文件夹,修改配置文件,启动explorer

1
2
3
4
docker-compose up -d
docker-compose down -v
docker volume ls
docker volume prune

手动部署Fabcar链码

复制fabric-samples/chaincode目录到Fabric-Data-Sharing

  1. 安装链码依赖项(Go):
1
2
3
./network.sh up createChannel
cd Fabric-Data-Sharing/chaincode/fabcar/go
GO111MODULE=on go mod vendor
  1. 打包链代码:
1
2
3
4
5
6
cd ../../../test-network

export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/

peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/go/ --lang golang --label fabcar_1
  1. 在节点上安装链码包:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:5051

peer lifecycle chaincode install fabcar.tar.gz

export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:6051

peer lifecycle chaincode install fabcar.tar.gz

export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051

peer lifecycle chaincode install fabcar.tar.gz

export CORE_PEER_LOCALMSPID="Org4MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org4.example.com/users/Admin@org4.example.com/msp
export CORE_PEER_ADDRESS=localhost:8051

peer lifecycle chaincode install fabcar.tar.gz
  1. 为组织批准链码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
peer lifecycle chaincode queryinstalled

export CC_PACKAGE_ID=fabcar_1:xxx

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_ADDRESS=localhost:7051

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_ADDRESS=localhost:6051

export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_ADDRESS=localhost:5051

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
  1. 提交链码到通道
1
2
3
4
5
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt

peer lifecycle chaincode querycommitted --channelID mychannel --name fabcar --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
  1. 调用链码
1
2
3
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabcar --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt  -c '{"function":"initLedger","Args":[]}'

peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'
  1. 升级链码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
cd ../chaincode/fabcar/go
GO111MODULE=on go mod vendor
cd ../../../test-network

export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp

peer lifecycle chaincode package fabcar_2.tar.gz --path ../chaincode/fabcar/go/ --lang golang --label fabcar_2

export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:5051

peer lifecycle chaincode install fabcar_2.tar.gz

export NEW_CC_PACKAGE_ID=fabcar_2:xxx

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:6051

peer lifecycle chaincode install fabcar_2.tar.gz

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051

peer lifecycle chaincode install fabcar_2.tar.gz

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

export CORE_PEER_LOCALMSPID="Org4MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org4.example.com/users/Admin@org4.example.com/msp
export CORE_PEER_ADDRESS=localhost:8051

peer lifecycle chaincode install fabcar_2.tar.gz

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 2.0 --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabcar --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt -c '{"function":"initLedger","Args":[]}'

peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabcar --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt -c '{"function":"createCar","Args":["CAR11","Honda","Accord","Black","Tom"]}'

peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'

启动应用程序与区块链交互

复制fabric-samples/fabcarFabric-Data-Sharing目录下

启动网络:

1
2
cd Fabric-Data-Sharing/fabcar
./startFabric.sh go

启动应用程序(Go):

1
2
cd Fabric-Data-Sharing/fabcar/go
go run fabcar.go

关闭网络:

1
2
cd Fabric-Data-Sharing/fabcar
./networkDown.sh

在 Fabric 中使用私有数据

创建集合定义的 JSON 文件:确定私有数据的访问权限

使用链码 API 读写私有数据:读取和写入带有集合定义的私有数据需要使用 GetPrivateData()PutPrivateData() 接口

  1. 启动网络:
1
2
3
4
5
6
7
8
cd chaincode/marbles02_private/go
GO111MODULE=on go mod vendor
cd ../../../test-network

docker rm -f $(docker ps -a | awk '($2 ~ /dev-peer.*.marblesp.*/) {print $1}')
docker rmi -f $(docker images | awk '($1 ~ /dev-peer.*.marblesp.*/) {print $3}')

./network.sh up createChannel -s couchdb
  1. 安装并定义一个带集合的链码:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:5051

peer lifecycle chaincode package marblesp.tar.gz --path ../chaincode/marbles02_private/go/ --lang golang --label marblespv1

peer lifecycle chaincode install marblesp.tar.gz

export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:6051

peer lifecycle chaincode install marblesp.tar.gz

export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051

peer lifecycle chaincode install marblesp.tar.gz

export CORE_PEER_LOCALMSPID="Org4MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org4.example.com/users/Admin@org4.example.com/msp
export CORE_PEER_ADDRESS=localhost:8051

peer lifecycle chaincode install marblesp.tar.gz

peer lifecycle chaincode queryinstalled

export CC_PACKAGE_ID=marblespv1:xxx

export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:5051

export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marblesp --version 1.0 --collections-config ../chaincode/marbles02_private/collections_config.json --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:6051

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marblesp --version 1.0 --collections-config ../chaincode/marbles02_private/collections_config.json --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marblesp --version 1.0 --collections-config ../chaincode/marbles02_private/collections_config.json --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

export CORE_PEER_LOCALMSPID="Org4MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org4.example.com/users/Admin@org4.example.com/msp
export CORE_PEER_ADDRESS=localhost:8051

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marblesp --version 1.0 --collections-config ../chaincode/marbles02_private/collections_config.json --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
export ORG1_CA=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export ORG2_CA=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt 
export ORG3_CA=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export ORG4_CA=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marblesp --version 1.0 --sequence 1 --collections-config ../chaincode/marbles02_private/collections_config.json --tls --cafile $ORDERER_CA --peerAddresses localhost:5051 --tlsRootCertFiles $ORG1_CA --peerAddresses localhost:6051 --tlsRootCertFiles $ORG2_CA --peerAddresses localhost:7051 --tlsRootCertFiles $ORG3_CA --peerAddresses localhost:8051 --tlsRootCertFiles $ORG4_CA
  1. 存储私有数据:Org1 的成员已经被授权使用弹珠私有数据示例中的所有私有数据进行交易,切换回 Org1 节点并提交添加一个弹珠的请求。私有数据 price 将会和私有数据 name, owner, color, size 分开存储。因此, initMarble 方法会调用 PutPrivateData() 接口两次来存储私有数据。另外注意,传递私有数据时使用 --transient 参数。作为瞬态的输入不会被记录到交易中,以此来保证数据的隐私性。瞬态数据会以二进制的方式被传输,所以在 CLI 中使用时,必须使用 base64 编码
1
2
3
4
5
6
7
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:5051

export MARBLE=$(echo -n "{\"name\":\"marble1\",\"color\":\"blue\",\"size\":35,\"owner\":\"tom\",\"price\":99}" | base64 | tr -d \\n)
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marblesp --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt -c '{"Args":["InitMarble"]}' --transient "{\"marble\":\"$MARBLE\"}"
  1. 授权节点查询私有数据:集合定义定义允许 Org1 和 Org2 的所有成员在他们的私有数据库中保存 name, color, size, owner 私有数据,但是只有 Org1 的成员才可以在他们的私有数据库中保存price私有数据。作为一个已授权的 Org1 的节点,我们可以查询两个私有数据集。Org2 的节点的私有数据库中不存在 price 数据。当你尝试查询这个数据时,将只能看到私有数据的公共 hash。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
peer chaincode query -C mychannel -n marblesp -c '{"Args":["ReadMarble","marble1"]}'

peer chaincode query -C mychannel -n marblesp -c '{"Args":["ReadMarblePrivateDetails","marble1"]}'

export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:6051

peer chaincode query -C mychannel -n marblesp -c '{"Args":["ReadMarble","marble1"]}'

peer chaincode query -C mychannel -n marblesp -c '{"Args":["ReadMarblePrivateDetails","marble1"]}'
  1. 清除私有数据:数据在过了一定数量的区块后进行 “清除”,仅仅把数据的哈希作为交易不可篡改的证据保存下来。(知道这个功能就行,时间关系此处不实操)
  2. 使用私有数据索引:可以通过打包链码目录中的索引 META-INF/statedb/couchdb/collections/<collection_name>/indexes 目录,将索引也用于私有数据数据集。在生产环境中部署链码时,建议在链码目录中定义所有索引,这样当链码在通道中的节点上安装和初始化的时候就可以自动作为一个单元自动部署。当使用 --collections-config 标识私有数据集的 JSON 文件路径时,通道上链码初始化的时候相关的索引会自动被部署。
  3. 关闭网络:
1
./network.sh down

使用CouchDB索引完成富查询

  1. 启动网络:
1
2
3
4
cd chaincode/marbles02/go
GO111MODULE=on go mod vendor
cd ../../../test-network
./network.sh up createChannel -s couchdb
  1. 安装、批准、提交和初始化链码:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=${PWD}/../config/
export CORE_PEER_TLS_ENABLED=true

export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:5051

peer lifecycle chaincode package marbles.tar.gz --path ../chaincode/marbles02/go --lang golang --label marbles_1

peer lifecycle chaincode install marbles.tar.gz

peer lifecycle chaincode queryinstalled

export CC_PACKAGE_ID=marbles_1:

export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0 --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:6051

peer lifecycle chaincode install marbles.tar.gz

peer lifecycle chaincode queryinstalled

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0  --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051

peer lifecycle chaincode install marbles.tar.gz

peer lifecycle chaincode queryinstalled

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0  --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

export CORE_PEER_LOCALMSPID="Org4MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org4.example.com/users/Admin@org4.example.com/msp
export CORE_PEER_ADDRESS=localhost:8051

peer lifecycle chaincode install marbles.tar.gz

peer lifecycle chaincode queryinstalled

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0  --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
export ORG1_CA=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export ORG2_CA=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export ORG3_CA=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export ORG4_CA=${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt
peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0 --sequence 1 --init-required --tls --cafile $ORDERER_CA --peerAddresses localhost:5051 --tlsRootCertFiles $ORG1_CA --peerAddresses localhost:6051 --tlsRootCertFiles $ORG2_CA --peerAddresses localhost:7051 --tlsRootCertFiles $ORG3_CA --peerAddresses localhost:8051 --tlsRootCertFiles $ORG4_CA

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --isInit --tls --cafile $ORDERER_CA --peerAddresses localhost:5051 --tlsRootCertFiles $ORG1_CA --peerAddresses localhost:6051 --tlsRootCertFiles $ORG2_CA --peerAddresses localhost:7051 --tlsRootCertFiles $ORG3_CA --peerAddresses localhost:8051 --tlsRootCertFiles $ORG4_CA -c '{"Args":["Init"]}'

docker logs peer0.org1.example.com  2>&1 | grep "CouchDB index"
  1. 查询CouchDB状态数据库
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#使用 Org1 创建一个拥有者是 “tom” 的 marble
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:5051

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marbles --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt -c '{"Args":["initMarble","marble1","blue","35","tom"]}'

# Rich Query with index name explicitly specified:
peer chaincode query -C mychannel -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}'

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marbles --peerAddresses localhost:5051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:6051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --peerAddresses localhost:8051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt -c '{"Args":["initMarble","marble5","red","35","tom"]}'

# Example two: query fully supported by the index with additional data
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\",\"color\":\"red\"}, \"use_index\":[\"/indexOwnerDoc\", \"indexOwner\"]}"]}'

# Example three: query not supported by the index
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"owner\":\"tom\"}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

# Example four: query with $or supported by the index
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"$or\":[{\"docType\":\"marble\"},{\"owner\":\"tom\"}]}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

# Example five: Query with $or not supported by the index
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"$or\":[{\"docType\":\"marble\",\"owner\":\"tom\"},{\"color\":\"yellow\"}]}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

# Rich Query with index name explicitly specified and a page size of 3:
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3",""]}'

peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3","g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkGoOkOWDSOSANIFk2iCyIyVySn5uVBQAGEhRz"]}'

上面的第一个富查询json格式化后:

1
2
3
4
5
6
{
    "Args": [
        "queryMarbles",
        "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"
    ]
}

webdav

使用nginx搭建webdav文件服务器(BUG)

  1. 安装nginx:注意必须安装nginx-full, 默认的nginx里面并不包含webdav模块
1
sudo apt install -y nginx-full
  1. 创建发布目录:
1
2
3
# 用来保存共享文件的位置
sudo mkdir -p /home/dav
sudo chown -R www-data:www-data /home/dav
  1. 配置
1
sudo gedit /etc/nginx/sites-enabled/webdav.conf

内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
server {
    listen 8081;
    server_name localhost;
    
    # 设置使用utf-8编码,防止中文文件名乱码
    charset utf-8;

    # 认证方式
    auth_basic              realm_name;
    # 存放认证用户名、密码文件(确认有对应权限)
    auth_basic_user_file    /etc/nginx/.passwords.list;
    # webdav服务访问的根目录
    root /home/dav/;

    # dav allowed method
    dav_methods     PUT DELETE MKCOL COPY MOVE;
    # Allow current scope perform specified DAV method
    dav_ext_methods PROPFIND OPTIONS;

    # In this folder, newly created folder or file is to have specified permission. If none is given, default is user:rw. If all or group permission is specified, user could be skipped
   # 创建文件的默认权限
    dav_access      user:rw group:rw all:r;

    # 临时文件位置
    client_body_temp_path   /tmp;

    # MAX size of uploaded file, 0 mean unlimited
    client_max_body_size    0;

    # Allow autocreate folder here if necessary
    # 允许自动创建文件夹(如果有需要的话)
    create_full_put_path    on;
}
  1. 测试配置文件
1
sudo nginx -t
  1. 创建用户登录验证信息(用户名-密码)
1
2
echo -n 'username:' | sudo tee -a /etc/nginx/.passwords.list
openssl passwd -apr1 | sudo tee -a /etc/nginx/.passwords.list
  1. 重启nginx服务
1
sudo systemctl restart nginx
  1. 查看nginx状态
1
sudo systemctl status nginx

使用apache搭建webdav文件服务器(不适用)

  1. 安装apache2
1
sudo apt-get install apache2
  1. 启动关联到的模块
1
2
3
sudo a2enmod dav_fs
sudo a2enmod dav
sudo a2enmod dav_lock
  1. 关联文件
1
2
3
4
sudo ln -s /etc/apache2/mods-available/dav.load /etc/apache2/mods-enabled/dav.load
sudo ln -s /etc/apache2/mods-available/dav_fs.load /etc/apache2/mods-enabled/dav_fs.load
sudo ln -s /etc/apache2/mods-available/dav_lock.load /etc/apache2/mods-enabled/dav_lock.load
sudo ln -s /etc/apache2/mods-available/dav_fs.conf /etc/apache2/mods-enabled/dav_fs.conf
  1. 重启服务
1
sudo /etc/init.d/apache2 restart 
  1. 创建共享目录
1
2
sudo mkdir /var/www/sync  # 接受客户端发来的文件,放在sync文件夹里
sudo chown www-data:www-data /var/www/sync 
  1. 创建用户
1
2
3
4
sudo htpasswd -c /var/www/me.dav wyatt
# 这里会要求你设置密码,后面登录时会用到,用户名即为 wyatt
sudo chown root:www-data /var/www/me.dav
sudo chmod 640 /var/www/me.dav
  1. 配置文件
1
sudo gedit /etc/apache2/sites-available/000-default.conf

VirtualHost节点中加入配置信息:(注意:先在 DocumentRoot /var/www/sync/ 前加#, 避免重复)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<VirtualHost *:80>
	# The ServerName directive sets the request scheme, hostname and port that
	# the server uses to identify itself. This is used when creating
	# redirection URLs. In the context of virtual hosts, the ServerName
	# specifies what hostname must appear in the request's Host: header to
	# match this virtual host. For the default virtual host (this file) this
	# value is not decisive as it is used as a last resort host regardless.
	# However, you must set it for any further virtual host explicitly.
	#ServerName www.example.com

	ServerAdmin webmaster@localhost
	DocumentRoot /var/www/html

	# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
	# error, crit, alert, emerg.
	# It is also possible to configure the loglevel for particular
	# modules, e.g.
	#LogLevel info ssl:warn

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

	# For most configuration files from conf-available/, which are
	# enabled or disabled at a global level, it is possible to
	# include a line for only one particular virtual host. For example the
	# following line enables the CGI configuration for this host only
	# after it has been globally disabled with "a2disconf".
	#Include conf-available/serve-cgi-bin.conf
	
	 
	DocumentRoot /var/www/sync/
		    <Directory /var/www/sync/>
		            Options Indexes MultiViews
		            AllowOverride None
		            Order allow,deny
		            allow from all
		    </Directory>
	 
		    Alias /webdav /var/www/sync
	 
		    <Location /webdav>
		       DAV On
		       AuthType Basic
		       AuthName "webdav"
		       AuthUserFile /var/www/me.dav
		       Require valid-user
	 
	 		</Location>  
	
</VirtualHost>

  1. 重启服务并登录
1
2
3
sudo /etc/init.d/apache2 restart
sudo apt-get install cadaver
cadaver http://127.0.0.1/webdav/

Bug1:Apache2无法启动,报错 for apache2.service failed because the control process exited with error code.

原因:端口占用

解决:杀掉占用了端口的进程

1
2
3
4
5
6
# 查看是什么进程占用了端口
netstat -lnp|grep 80
# 按照PID杀掉此进程
kill -9 PID
# 重新启动apache2
sudo /etc/init.d/apache2 start

gin+webdav+vue

数据存储服务:各个参与方都运行一个gin实现的webdav服务器,并将共享目录的文件摘要上传到区块链中记录(智能合约),结合前端技术,实现在数据存储服务页面上设置共享目录,上传下载等操作

  • 上传目前是直接将共享文件放入共享目录,没有写前端上传API

数据共享系统:使用gin编写一个数据共享系统服务器,展示区块链中记录的文件摘要。当用户请求文件时,该数据共享系统请求参与方的数据存储服务,并将请求记录存入区块链

数据存储服务与数据共享系统的区别与联系:

  1. 数据存储服务后台是各个参与方自己管理的一个数据库;数据共享系统展示所有参与方的数据,通过请求响应获取各个参与方的数据
  2. 数据共享系统包含数据存储服务;数据存储服务是数据共享系统的一部分

开发步骤:

  1. 阅读并大概理解ginwebdav源码
  2. 编写智能合约

数据存储服务实操:

  1. 启动网络:链码路径../chaincode/fabcar/go/、使用CAcouchdb、初始化链码
1
2
cd Fabric-Data-Sharing/fabcar
./startFabric.sh go
  1. 启动应用程序(Go):复制fabcar应用程序的代码、证书密钥和配置文件到win下,修改代码和配置文件使之适配新路径,实现在宿主机通过API,连接虚拟机中的区块链网络,调用其智能合约(此路不通,因为区块链网络节点是在本地启动,节点地址都设置为localhost:port,若要在宿主机访问,需要修改为宿主机ip+port)
1
2
3
# 手动启动(不使用goland)
cd Fabric-Data-Sharing/fabcar/go
go run fabcar.go
  1. 关闭网络:
1
2
cd Fabric-Data-Sharing/fabcar
./networkDown.sh

进度表

2023.7.6-2023.7.9

  1. 搭建环境并运行测试网络
  2. 改造测试网络使之适配项目(四个组织一个通道、使用Fabric-CA、使用couchDB)

2023.7.10

  1. 网络浏览器拉取镜像失败(已解决,网络原因)
  2. (BUG)资产转移链码调用失败,显示成功,但是查询后没有改变,在原测试网络再试下能否转移成功(已解决,背书的Peer节点不够,原示例只有org12peer节点背书,未过半数peer节点)

2023.7.11

  1. 网络浏览器启动失败(初步查明原因:签名证书不匹配)
    • 排查原因步骤
      1. fabric-sample试一下能否成功启动(可以启动成功)
      2. 查看容器日志发现无法连接peer节点且pg数据库查询失败
      3. 检查配置的证书文件路径及名称
      4. 检查配置文件格式
      5. 检查数据卷残留(发现有残留,但官方推荐的docker-compose down -v按道理会清除 Postgres data and user wallet数据卷,查看控制台输出发现是由于fabric-test网络在启动中,所以无法关闭,导致报错结束命令执行,怀疑是该原因造成后续删除数据卷的步骤未执行)

2023.7.12

  1. 手动部署fabcar链码(Go)、修改链码、升级链码
  2. 看教程的编写你的第一个应用,实操用应用程序调用fabcar链码,而不是用cli调用

2023.7.13

  1. 逐行看fabcar应用程序的Go代码如何实现
  2. 学习私有数据的概念,在 Fabric 中实操使用私有数据的例程

2023.7.14

  1. 逐行看使用私有数据的marbles例程的链码

2023.7.15

  1. 看如何使用CouchDB
  2. 了解下marbles例程的链码下索引的概念(couchDB的特性)

2023.7.16

  1. 在 Fabric 中实操使用CouchDB的例程(有BUG,无法在节点安装链码)

2023.7.18

  1. 看链码开发者教程
  2. Ubuntu使用nginx搭建webdav文件服务器(BUG,80只显示欢迎页,改到8081后可以输入用户名密码,但验证失败,显示404)

2023.7.22

  1. Ubuntu使用nginx搭建webdav文件服务器(尝试解决BUG失败)

2023.7.23

  1. 使用APACHE建webdav文件服务器

2023.7.29

  1. 看gin+webdav源码
  2. 成功启动webdav服务器

2023.7.30

  1. 尝试在win系统中开发数据存储服务(失败原因:无法连接区块链网络)
  2. 在ubuntu中安装goland,配置环境
  3. 解决ubuntu系统问题:apparmor权限规则问题导致经常黑屏,通过修改apparmor的权限规则文件解决;修改后无黑屏现象,但无法启动通过snap的软件商店安装的goland,故从官网下载goland安装包重新安装

2023.7.31

  1. 在ubuntu中启动webdav服务器
    • 编译错误:缺少io/fs包;解决:升级go版本到1.17
  2. 成功在dataStorage连接区块链网络调用智能合约

2023.8.1

  1. 虚拟机中安装的ubuntu系统频繁出现内核错误,无法解决,故重装系统Ubuntu22.04.2
  2. 在新系统中重新配置项目环境,成功启动区块链网络、webdav服务器、调用智能合约

2023.8.4

  1. 仿照fabcar编写智能合约定义数据结构体,实现简单增删改查,使用fabric-sdk-go完成调用

2023.8.5

  1. 在数据储存服务中提取文件摘要,并调用API上传文件相关信息到区块链,同时也通过API从区块链中查询出文件信息(键查询)
  2. 使用例程学习CouchDB,建立索引,使用富查询完成例程中的资产的查询

2023.8.6

  1. 在链码中添加索引文件(dataHash、dataName),智能合约中完成QueryInfoByHash函数,在客户端应用程序中完成QueryByHash函数,通过gin框架成功调用该接口,使用APIPOST成功通过QueryByHash的测试

2023.8.7

  1. 完成QueryAllInfos、QueryInfoById、QueryInfoByHash、QueryInfoByName、ChangeInfoByName接口测试
    • 包括智能合约返回值的修改
  2. 完善uploadSingleFile接口的内部细节:
    • 查询在区块链中查询是否存在哈希值一样的文件,若存在,则说明是同一文件,不再上传,直接返回提示信息
    • 查询在区块链中查询是否存在文件名一样的文件,上面通过了哈希值校验,说明文件名相同,但内容不同,则覆盖原文件,更新dataVersion(先从区块链中获取version,再更新),区块链中会保存原文件的记录,但内容已被覆盖(BUG:提取DataId时遇到问题)

2023.8.8

  1. 解决uploadSingleFile接口中无法提取到DataId的BUG
  2. 优化代码,抽象出连接区块链的connectToBlockchain函数,减少代码冗余

2023.8.9

  1. 复习javascript基础
  2. 复习Vue2基础
  3. 阅读Vue3官方文档-开始,并动手实践,跟着教程成功使用 Vite + Vue 3 创建了一个项目

2023.8.10-2023.8.17

  1. 学习vue3+typescript+vue-router+pinia+element-plus+axios在项目中如何配置和使用

2023.8.18

  1. 修改Ubuntu的DNS,解决网速慢问题,修改Ubuntu的Dock位置、字体大小
  2. Ubuntu中搭建数据共享演示系统的前端开发环境,完成axios二次封装
  3. 优化项目目录,删除无用文件,重新构建项目启动路径
  4. 将项目的启动和关闭过程记录在README.md
  5. 创建update_json_path脚本文件,实现自动化根据当前区块链网络生成的秘钥修改区块链浏览器配置文件

2023.8.19

  1. 修改中间件:链接区块链网络时事先生成管理员和用户的身份并存储在wallet/
  2. 解决了在GO中使用GO MOD模式导入本地自定义包/函数的问题
  3. 将生成身份填充钱包和连接区块链的代码封装到工具包中

2023.8.20

  1. 替换Fabric生成的身份文件中的\n
  2. 完成后端登录接口开发,后端使用前端发送身份和私钥,与钱包中的身份文件中的私钥做对比,若一致则登录成功;否则登陆失败

2023.8.21

  1. 完善登录接口
    • 编写生成token的函数,利用token实现用户登录状态的保持
  2. 编写请求拦截器,通过GIN的中间件实现,完成token的验证以及用户信息的解析提取
  3. 抽象出http的请求处理函数
  4. Fabric生成的身份文件中\n不能删除,不然会报错秘钥错误,但用户登录时使用的秘钥含有\n又不太美观,后期可以考虑用BASE64优化
  5. 修改上传文件时的上传者为TOKEN中保存的identity
  6. 若header中未携带token则提示登录
  7. 待优化:避免重复登陆,该用户存在TOKEN且未过期的话,返回该TOKEN

2023.8.24

  1. 学习vue项目中的layout模块开发

2023.8.25

  1. 学习vue项目中的登录获取用户信息、退出登录、路由鉴权和真实接口替代mock接口

2023.8.26

  1. 继续学习vue项目中的真实接口替代mock接口、接口ts数据类型定义
  2. 完成数据共享系统的的真实接口替代mock接口、接口ts数据类型定义
  3. 修改后端登录接口获取请求体中RAW数据(JSON),原来是获取表单数据,表单类型适合上传文件

2023.8.27

  1. 首页使用了粒子效果(安装particlesvue3 tsparticles),并将登录框水平垂直居中,输入框加入提示文字
  2. 主题颜色:蓝色、紫色;删除模板的滚动条scss代码
  3. 添加主题切换按钮,借助element-plus的暗色模式,删除原来模板的顶部和主题颜色
  4. 修改折叠后边框宽度使logo和icon水平居中,隐藏logo旁标题
  5. 使用后端的登录接口,新开发后端获取用户信息的接口
  6. 完成前端的退出登录和路由鉴权
  7. 设置用户头像为el组件提供的icon,修改tabbar右侧按钮大小为默认
  8. 学习模板中的主体内容开发

2023.8.28

  1. 学习模板中的主体内容开发
  2. 分析项目的文件管理模块,理清思路

2023.8.29-9.2

  1. 智能合约

    • 文件结构体中新建一个字段说明文件的查看范围(公开/指定一个组织)
    • 新建索引文件indexDataAuthority
    • 编写函数QueryAllInfoByOwnerPrefix,通过字段dataOwner的前缀组织名查询文件信息
    • 编写函数QueryFilesByDataAuthority,通过字段dataAuthority的值(public/Org*)查询文件信息
  2. 后端开发接口

    • /query/myorg获取token中的identity的Org为发布者的所有文件,使用couchdb的模糊查询(正则匹配)
    • /query/public获取文件范围为公开public的所有文件
    • /query/spec获取token中的identityOrg为指定接收者的所有文件
    • 上传文件接口:接收文件返回URL、Hash、Name、Size、Type
    • 上传文件表单接口:接收URL、Hash、Name、Size、Type、文件描述、授权范围
  3. 前端文件管理分为两个个子页面

    • 展示所有公开分享的文件
    • 展示本组织为特定接收方的文件
  4. 点击【分享】按钮分享文件

    • 填写相关信息
      • 文件描述:单选框+补充说明
      • 分享范围:单选框
      • 上传文件
    • 字段校验:除了补充说明均为必填项
  5. 本组织分享的文件:显示【查看】(【修改】按钮暂时不开发)

    • 点击【查看】:浏览器能加载的直接打开,加载不了会下载
    • 点击【修改】:获取文件信息,重新上传(暂时不开发)
    • 关键词搜索文件描述字段:模糊查询
      • 智能合约层面编写查询函数:正则查询dataDeScription,并且dataAuthoritypublic
      • 编写相应的前后端调用方法
      • 前端输入框为空时,【查询】按钮不可用
      • 【重置】按钮:清除关键字,重新获取表格数据
  6. 非本组织分享的文件:显示【请求查看】按钮,点击发送查看请求,记录入区块链,该文件信息在公开页不显示,在我的请求中显示。请求授权过程:发送授权请求=>同意授权=>查看数据

  7. 具体操作:

    • 新加一个菜单项【请求授权】:两个子页面显示【我的请求】、【我的授权】
    • 智能合约:
      • 创建ReqAuthInfo结构体:记录信息类型、请求授权记录ID、请求者、请求的文件ID、请求时间、是否同意、操作者、操作时间
      • 创建QueryReqAuthResult结构体:接收区块链查询结果
      • CreateReqAuthInfo:创建请求授权记录
      • QueryReqAuthInfoByReqUser:根据请求者查询所有的请求授权记录
      • QueryReqAuthInfoByOperator:根据响应者查询所有的请求授权记录
      • QueryReqAuthInfoByReqAuthId:根据请求授权记录ID查询请求授权记录
      • !!!BUG创建KEY:作为区块链中所有记录的ID:由于智能合约安装在多个节点中,所以不能用全局变量,其他节点无法同步变量更新;(解决)改为在后端计数递增然后传递给合约
      • QueryReqAuthInfoByReqUserAndReqDataId:根据请求者和请求的文件ID查询请求授权信息
      • ChangeReqAuthInfoIsAuth:根据KeyreqAuthId修改请求授权记录的IsAuth字段
      • 修改QueryAllInfosQueryAllFileInfos:由于返回字段的结构不一致,故此处改为返回所有文件信息
    • 后端:
      • 中间件:创建对应智能合约的创建记录函数和查询函数
      • 请求处理
        • 新建全局变量REQAUTHID:作为每条请求授权记录信息的ReqAuthId
        • 创建结构体ReqAuthInfo:定义创建请求授权记录
        • 创建对应中间件的创建记录函数和查询函数
        • 修改QueryAllInfosToAllHandlerQueryInfosToPublicByAuthorizedHandler:返回所有公开的且请求授权记录中的该文件使未被授权给该用户的
          • 先查询到所有授权范围为公开的文件信息
          • 再查询到所有该登录用户的请求授权记录信息
          • 再用所有授权范围为公开的文件信息的dataId字段与所有请求授权记录信息中的reqDataId字段的值做比对,哪个文件信息比对成功,说明哪个文件信息被该登录用户请求过,所以从所有授权范围为公开的文件信息中去除比对成功的该条文件信息,所有文件信息全部比对过后,返回所有授权范围为公开且没有被该登录用户请求过文件信息
        • 新建QueryFileInfoByReqUserHandler:根据请求者查询请求过的所有文件信息的接口用于【我的请求】页展示
        • 新建QueryReqAuthInfoByReqUserAndDataIdHandler:根据请求者和请求的文件ID查询请求授权信息
        • 新建QueryFileInfoWithRequestAuthInfoByOperatorHandler:根据登陆用户查询需要授权和授权过的所有请求授权信息和对应的文件信息的接口
        • 修改QueryAllInfosToSpecHandler:查询特定接收方的所有文件信息且过滤掉已经被请求过的文件的接口
        • 修改QueryAllInfosQueryAllFileInfos:返回所有文件信息
    • 前端:
      • 点击【请求】后该文件信息从【公开文件】页移至【我的请求】页
        • 不能重复请求同一文件:点击【请求授权】后在【公开文件】页直接不显示
        • 在【公开文件】页提示文件已移动至【我的请求】页
        • 【我的请求】页展示登录用户所有请求过的文件,未授权的显示【待授权】按钮(禁用),授权了的显示【查看】按钮、(暂时没做:被拒绝的显示【请求被拒绝】按钮)
        • v-ifv-show的判断函数中异步的promise对象总是返回true
      • 【我的授权】页展示登录用户所有的作为操作者的请求授权信息及其对应的文件信息,展示【请求者】和【请求时间】,操作栏显示【查看】和【授权】
        • 点击【授权】后,修改该条请求授权信息中的isAuth字段,然后将按钮变为【已授权】,不可再次点击
  8. 本组织为特定接收方的文件:显示【查看】按钮,点击也要通过请求授权

  9. 在登陆页校验:管理员直接跳转到区块链浏览器,用户首页显示数据统计

    • 历史/今日被请求的文件排行榜
    • 历史/今日被请求的组织排行榜
    • 历史/今日发布文件的组织排行榜
    • 历史发布总文件数(顶部居中)
    • 每天发布文件数的趋势折线图(中间一横排)
    • 实时发布文件的流水图(向下自动划)(右下角)
    • 参考数据大屏、Fabric-trace、hyperledger explorer
    • 调研Fabric关于HISTORY的API
  10. 演示时开两个浏览器代表不同用户

2023.9.17

添加文件访问记录上链功能

  • 智能合约
    • 创建FileAccessInfo结构体:信息类型、文件访问记录ID、文件ID、文件名、访问者、访问时间
    • 创建QueryFileAccessResult结构体:接收区块链查询结果
    • CreateFileAccessInfo:创建文件访问记录
    • QueryAllFileAccessInfos:查询所有的文件访问记录
    • QueryFileAccessInfoByAccessId:通过AccessId查询文件访问记录
  • 后端
    • 中间件:创建对应智能合约的创建记录函数和查询函数
    • 请求处理:
      • CreateFileAccessInfo:创建文件访问记录
      • httpHandlers.go移至gowebdav:避免import cycle
      • 修改webdav客户端的Defaulthandle:将文件访问记录上链
  • 前端
    • 配置webdav服务器的代理
    • requestWebdav:进行axios二次封装,使用请求与响应拦截器
    • src/api/webdav/index.ts:请求webdav服务器的相关API
    • 修改文件管理和请求授权四个子页面的【查看】按钮回调函数:
      • 发送文件访问记录给服务器,服务器将该记录上链,弹窗提示用户文件访问记录上链
      • 显示文件内容

2023.9.19-9.23

  • 学习如何开发用户管理、角色管理和菜单管理模块

2023.9.24

  • 在虚拟机中安装mysql
  • 学习使用gorm进行CRUD

2023.9.25

  • 学习gorm结构体的创建技巧和结合gin使用

2023.9.26-9.30

  • 数据库
    • 角色->一对多->用户(根据用户【多】外键查询到所属角色)
    • 角色->多对多->菜单(根据关联表roles_menus,查询用户拥有的菜单权限)

用户表users

字段名 数据类型 主/外键 允许空 含义
id bigint Y N 自增主键
username varchar(32) N N 用户名
password varchar(255) N N 用户密码
role_id bigint Y Y 角色id
created_at datetime N Y 创建时间
updated_at datetime N Y 更新时间
deleted_at datetime N Y 删除时间
  • 角色表roles
字段名 数据类型 主/外键 允许空 含义
id bigint Y N 自增主键
rolename varchar(32) N N 角色名
created_at datetime N Y 创建时间
updated_at datetime N Y 更新时间
deleted_at datetime N Y 删除时间
  • 菜单表menus
字段名 数据类型 主/外键 允许空 含义
id bigint Y N 自增主键
menuname varchar(32) N N 菜单名
pid bigint N Y 父级菜单ID
code varchar(32) N Y 前端路由值
level bigint N N 级数
created_at datetime N Y 创建时间
updated_at datetime N Y 更新时间
deleted_at datetime N Y 删除时间
  • 连接表roles_menus
字段名 数据类型 主/外键 允许空 含义
menu_id bigint Y N 菜单ID
role_id bigint Y N 角色ID
  • 后端

    • 拆分路由组件到router
    • controller包中统一返回的json响应格式
    • 拆分请求处理函数到controller
    • 修改template.go使得直接访问数据存储服务不显示后台文件数据
    • 使用数据库中用户信息登录相关接口及数据库操作
    • 添加用户、删除用户相关接口及数据库操作
  • 前端

    • 使用数据库中用户信息登录
    • 路由鉴权:不同用户显示不同菜单
    • 404页面
    • 调整侧边栏logo和title显示
    • 完成用户管理页面显示所有用户信息、添加用户和删除用户【软删除】

2023.10.1

数据库、后端、前端

  • 角色管理:显示已有角色、添加角色、删除角色、为角色分配菜单权限

注意:菜单深度写死为三

2023.10.2

智能合约

  • 新建链上情报研究报告文件对象字段:数据类型、题名、编号、密级、完成单位、总页数、作者、审查批准人(职务)、主题词、摘要、版本号、hash、完成日期、版本号

前端、数据库

  • 添加可视化统计菜单,其下有数据大屏和区块信息两个子菜单
  • 前端约束添加的角色名与后端生成的区块链身份相同

后端

  • 上传文件接口
  • Irr类型文件上链的接口(未测试)

2023.10.3

智能合约

  • 添加查询链上全部Irr类型文件的函数
  • 添加查询全部dataReceiver为public的Irr类型的文件信息的接口

数据库

  • 添加发布文件、受控文件相应菜单记录

后端

  • 超级管理员角色连接区块链使用Org1-MSP
  • 测试完成Irr类型文件上链的接口
  • 查询链上全部Irr类型文件的接口
  • 查询全部dataReceiver为public的Irr类型的文件信息的接口

前端

  • 点击区块信息后打开新标签页跳转到区块链浏览器,原页面路由跳转回点击前的路由
  • 文件管理菜单拆分为发布文件、公开文件、受控文件、私有文件四个子菜单
  • 完成文件辑要页显示

2023.9.18迭代需求

  • 基于区块链的数据资源共享系统
  • 发布时选择数据类型:目前支持一种类型——情报研究报告,选择情报研究报告后填写下面字段
  • 字段名DataAuthority->DataReceiver
  • 数据说明字段作为数据描述信息写到链上:题名、编号、密级、完成单位、总页数、作者、审查批准人(职务)、主题词、摘要、版本号、hash、完成日期,
  • 按钮【分享文件】->【发布文件】
  • webdav访问控制:向webdav发送文件请求后,webdav需要做权限的判断。目的是:即使获知了文件的webdav存储地址,直接访问url后也需要权限校验
    • 受控的:根据请求者和请求的数据id查看链上的文件信息的接收者;若为受控的,则再查询请求授权记录
    • 特定接收方的:验证请求的来源是真正的文件信息的接收者:请求者在向webdav发送文件请求时需要带一个自己的私钥签名结果,webdav收到后可以验签机构身份
  • 数据接收者:
    • 公开:不需要请求授权过程,保存文件访问记录
    • 受控:需要请求授权过程,保存文件访问记录
    • 特定目标:不需要请求授权过程,在webdav需要查看文件信息的接收者,保存文件访问记录

2023.11

  • 文件密级:公开、内部
  • 文档:介绍区块链知识、软件工程方法介绍系统

2023.10.4

  • 调整文件辑要页显示的标签宽度/列宽度
  • 关键词查询公开文件
  • 查看【公开文件】时的webdav访问控制(TOKEN)及文件访问记录上链
  • 发布文件及前端表单校验

2023.10.5

  • 完成数据存储服务的文件访问业务
    • 首先校验是否为登录用户
    • 然后校验查询字符串的值是否与请求的文件名匹配
    • 其次校验文件的授权范围
    • 最后将文件访问记录上链
  • 受控文件的webdav访问控制
    • 请求授权记录创建与查询
    • 【受控文件】页的显示
    • webdav的请求者、请求文件与文件授权范围和请求授权记录比对
    • 文件访问记录上链
    • 【我的请求】页的显示
    • 【我的授权】页的显示(未测试)

2023.10.6

  • 完成【我的授权】页
  • 完成【私有文件】页

2024.1

  • 完成一对多私发
  • 每个组织启动一个webdav即可,前后端和区块链网络启动在集群服务器中
  • 为什么用属性基加密而不用对称加密
    • 节省资源
      • 对称加密需要在后端根据请求用户手动判断能否解密
      • 属性基加密的只需要将请求用户作为属性输入解密函数即可判断
    • 安全性高
      • 属性基加密在访问策略在发送方发送时就已经被确定,即使主密钥泄露也无法直接解密密文
      • 对称加密的密钥泄露后可直接解密密文

TODO

  • 开发前端文件上传:通过网络将文件上传到后端服务器指定的共享目录,后端会提取数据摘要上传到区块链网络
  • 主页数据展示、学习菜单权限分析与实现和路由的拆分在12完成后开始,边学边做,结合自己项目
  • 前端登录,后续请求用请求头携带TOKEN
  • 在前端通过请求响应获取Fabric的MSP,实现不同组织的不同用户登录的访问控制
  • 修改文件信息要看登录用户的权限:所属组织、是否管理员、是否上传者;本组织管理员可修改本组织所有文件,上传者可修改自己上传的文件
  • 结合前端技术(Vue+ElementUI),实现在数据存储服务页面上设置共享目录,上传下载等操作
  • 前端表单生成可以试试form-create(没采用该方案,本项目直接使用element-ui组件)
  • 上传文件实际上传的是文件的数据摘要,不是把文件本身传到区块链网络,每个组织都运行一个数据存储服务,该组织下的用户上传文件是上传到该组织的服务器上
  • 项目若要上线,则需要添加日志中间件

2014.1

  • 数据评价:用户可以添加和查看评价数据,未阅读过的文档不能评价,不能重复评价(优良中差)
    • 前端:点评、查看历史点评
      • 【添加评价】抽屉组件,【添加评价】对话框组件,为文件页面添加【查看评价】按钮
      • 添加mock测试数据
      • 添加评价数据类型,添加【创建评价】接口和【查看评价】接口
    • 后端:可对评价进行数据处理
      • 添加创建评价与查看评价【路由】
      • 添加创建评价与查询评价【处理函数】与【中间件】,添加数据评价数据类型,添加【计算平均评价】函数
    • 区块链:新建文件评价结构体,并与具体文件关联
      • 添加评价数据类型,添加创建评价与查询评价接口
    • 评价流程:前端提交评价,后端收到后上传到区块链;返回文件信息时附带评价信息展示在前端
    • 细节:用户只能评价一次
    • 优化方向:基于环签名或零知识证明的匿名评价(隐私保护)
  • 修改部分前端组件,修改文件展示表的列宽,修改按钮为按钮组并更改大小
  • dev脚本增加暴露公网指令
  • 面向特定接收方:一对多
    • 前端:发布文件时,组织一二三四可以多选,公开和受控是单选
    • 合约:按授权范围查找文件的函数改为模糊查询(正则匹配)
  • 面向特定接收方基于属性的加密:一对一加密;一对多加密,加密文件辑要。目的是不将私发文件的辑要明文存储在链上。
    • 前端:未作修改
    • 后端:
      • 添加处理属性基加密的函数文件
      • 修改部分类型定义,添加密文字段
      • 修改部分函数文件,添加加密和解密相关操作代码
      • 修改数据访问记录中的数据访问者为username
    • 区块链
      • 修改部分类型定义,添加密文字段
    • 流程:
      • 后端在初始化时生成一对公共密钥和主密钥
      • 发布文件:当遇到发布私有文件的请求时,使用该文件的辑要信息(明文)、文件接收方(访问策略)和公钥生成密文数据作为文件辑要上链
      • 查看文件辑要:返回私有文件的信息时会取到加密后的文件辑要,根据当前的登录用户(属性)和主密钥生成私钥解密出文件辑要明文返回
  • 了解零知识证明应用
  • 私发一对多授权范围是否需要有自己
    • 需要:给本组织内私发
  • 完善数据大屏
    • 前端:美化
    • 后端:
      • 添加用于数据统计的相应类型结构体
      • 完成数据统计接口:近七天的每日上传&下载量、各组织上传&下载量、各类文件总量、各组织总数据量、各组织用户量、区块链中各类数据量
    • 合约:添加查询所有评论记录和请求授权记录的函数
  • BUG修复:
    • 修复私发文件的数据类型未赋值问题
    • 修改数据评价失败的返回值
  • 加密私发文件的数据访问地址
  • 【超级管理员】角色改为【监管者】
  • 监管者可以看到所有的私发文件
  • 自己上传的文件不可评价【前端按钮的隐藏】
  • 上传文件可拖拽且放在发布页最后

可选项

  • 了解链上数据加密的做法,考虑监管者
  • 数据统计云图tag
  • 基于环签名/零知识证明/对称加密的匿名投票
    • 环签名无法解决双重投票
    • 零知识证明的过程慢
    • 可链接环签名的成熟投票方案较少
    • 对称加密寄希望于中心服务器的安全性
  • 可搜索加密私发文件的基础信息(授权范围)
  • 用户管理的CA注册
  • 请求授权消息通知和首页公告栏

2024.10.26

BUG1:并发问题。由于全局配置的KEY同时读,导致KEY不唯一;解决:后端对KEY加锁

  • 加锁的衍生问题:加锁后后端处理过慢,被阻塞的请求等待时间过长,前端异步无响应,后端实际都上传成功,若此时用户重复点击发布,由于哈希检测是在上传文件时,发布文件时未检测,这将导致重复上传现象;解决:前端增加超时时间限制,防止重复点击
  • 加锁的衍生问题:由于上链时间长,多个下载文件请求同时到后端会堵塞;解决:同上,前端增加超时时间限制,防止重复点击生成多条访问记录;(增加提示信息)

BUG2:虚拟机局域网问题。由于测试环境中webdav服务启动在虚拟机中,所以局域网中其他PC无法通过虚拟机IP访问文件;解决:虚拟机网络用桥接

  • 之所以上传可以成功,下载不成功是因为:上传有代理服务器做请求转发,开发环境下通过vue-cli在宿主机启动一个代理服务器(生产环境下启动nginx作为代理服务器),代理服务器可以和webdav通信,而下载是客户端直接访问虚拟机上的webdav服务,无法被代理服务器捕获到,webdav中虽然配置了cors解决跨域,但虚拟机的网络配置导致其无法被局域网其他PC访问
  • 浏览器访问页面,实际上是从目标服务器获取到index.html等静态资源后在本地浏览器加载,而访问目标服务器时,若目标服务器配有代理服务器,则会先访问到代理服务器,由代理服务器转发请求到实际的目标服务器;在开发环境下,通过vue-cli启动了一个代理服务器,所有该服务的请求都会走该代理服务器

理想的实际架构:区块链和前后端服务启动在保密机器中,各个组织启动各自的webdav服务和peer节点

测试时的架构:区块链(包括所有组织的peer节点)、前后端、webdav(一个)都启动在一台虚拟机中

时间 内容
2023.6.10-2023.7.5 需求分析、总体设计、技术选型
2023.7.6-2023.7.9 1. 搭建环境并运行测试网络;2. 改造测试网络使之适配项目(四个组织一个通道、使用Fabric-CA、使用couchDB)
2023.7.10 1. 网络浏览器拉取镜像失败(已解决,网络原因);2. (BUG)资产转移链码调用失败,显示成功,但是查询后没有改变,在原测试网络再试下能否转移成功(已解决,背书的Peer节点不够,原示例只有org12peer节点背书,未过半数peer节点)
2023.7.11 网络浏览器启动失败(初步查明原因:签名证书不匹配)排查原因步骤:1)用fabric-sample试一下能否成功启动(可以启动成功);2) 查看容器日志发现无法连接peer节点且pg数据库查询失败;3)检查配置的证书文件路径及名称;4)检查配置文件格式;5)检查数据卷残留(发现有残留,但官方推荐的docker-compose down -v按道理会清除 Postgres data and user wallet数据卷,查看控制台输出发现是由于fabric-test网络在启动中,所以无法关闭,导致报错结束命令执行,怀疑是该原因造成后续删除数据卷的步骤未执行)
2023.7.12 1. 手动部署fabcar链码(Go)、修改链码、升级链码;2. 看教程的编写你的第一个应用,实操用应用程序调用fabcar链码,而不是用cli调用
2023.7.13 1. 逐行看fabcar应用程序的Go代码如何实现;2. 学习私有数据的概念,在 Fabric 中实操使用私有数据的例程
2023.7.14 逐行看使用私有数据的marbles例程的链码
2023.7.15 看如何使用CouchDB
2023.7.16 在 Fabric 中实操使用CouchDB的例程(有BUG,无法在节点安装链码)
2023.7.18-2023.9.2 完成系统原型开发:前后端和区块链网络
2023.9.17 添加文件访问记录上链功能
2023.9.19-9.23 学习如何开发用户管理、角色管理和菜单管理模块
2023.9.24 在虚拟机中安装mysql ;学习使用gorm进行CRUD
2023.9.25 学习gorm结构体的创建技巧和结合gin使用
2023.9.26-10.1 完成权限管理菜单下的用户管理和角色管理
2023.10.2-10.6 重构系统功能;结合链上数据添加数据存储服务的权限访问控制
2024.1 完成数据评价和数据统计功能;增加私发一对多功能;对私发数据基于属性加密后上链
Built with Hugo
Theme Stack designed by Jimmy