主頁 >  其他 > Fabric開發(四) 基于Fabirc1.4.3撰寫你的第一個應用

Fabric開發(四) 基于Fabirc1.4.3撰寫你的第一個應用

2020-09-26 14:27:15 其他

寫在前面(到到底什么是Fabric?)

在第一節的最后,我粗略地說了說到底什么是Fabirc,在這里,我得再問自己一遍,到底什么是Fabirc?
我這個人比較喜歡望文生義,見文知意,顧名思義,,,找Gu爸問問,給如下結果:
在這里插入圖片描述
具體是什么意思,我們暫且按下不表,來看看,我們的另外一個角兒,Hyperledger(超級賬本),對,我們這里講Fabric確切的說只是Hyperledger下的一個專案而已,中文官網描述如下:
在這里插入圖片描述
到這里,我們應該對Hyperledger Fabirc(以下簡稱Fabric)有了進一步的認識,他本質就是一項分布式賬本技術,結合上文的翻譯,Fabric就是一個分布式賬本技術框架,至于對該技術的分析,我們后續文章會進行連載,再問億遍什么是Fabirc, 這里,我們先來撰寫一個應用,看看他到底在做什么,能做什么吧,

基于Fabric撰寫第一個應用程式

我們寫這個程式要干什么呢?
最基本的功能就是要給用戶提供查詢賬本(包含特定記錄)和更新賬本(添加記錄),

而這個程式會基于javascript,通過Node.js SDK與賬本所在的網路進行互動,

Hyperledger中文檔案給出了以下步驟,我們可以照貓畫虎來試試,(畢竟是入門文章,洗掉線覆寫部分可以先不看)

  1. 啟動一個Hyperledger Fabric區塊鏈測驗網路,
    在我們的網路中,我們需要一些最基本的組件來查詢和更新賬本,這些組件<peer節點、ordering節點以及證書管理>是我們網路的基礎,而CLI容器則用來發送一些管理命令,有個簡單的腳本將下載并啟動這個測驗網路,
  2. 學習應用程式中所用到的智能合約例子的引數,
    智能合約包含的各種功能讓我們可以用多種方式和賬本進行互動,如,我們可以讀取整體的資料或者某一部分詳盡的資料,
  3. 開發能夠查詢以及更新記錄的應用程式,
    我們提供兩個程式例子 —— 一個用于查詢賬本,另一個用戶更新賬本,我們的程式將使用SDK APIs來和網路進行互動,并最終呼叫這些功能,

好了,廢話不多說,正文開始

1、首先,啟動測驗網路

上節我們已經下載了的fabric中已經包含了fabric-samples,執行下面操作

cd fabric-samples/fabcar ; ls

可以看到fabcar樣例包含的腳本和程式代碼
在這里插入圖片描述

2、下載并解壓Hyperledger Fabric Docker images

下載鏡像

./startFabric.sh

執行程序如下:

halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar$ ./startFabric.sh 
Stopping for channel 'mychannel' with CLI timeout of '10' seconds and CLI delay of '3' seconds
proceeding ...
WARNING: The BYFN_CA2_PRIVATE_KEY variable is not set. Defaulting to a blank string.
WARNING: The BYFN_CA1_PRIVATE_KEY variable is not set. Defaulting to a blank string.
Stopping cli                    ... done
Stopping peer0.org2.example.com ... done
Stopping orderer.example.com    ... done
Stopping peer1.org2.example.com ... done
Stopping peer1.org1.example.com ... done
Stopping peer0.org1.example.com ... done
Removing cli                    ... done
Removing peer0.org2.example.com ... done
Removing orderer.example.com    ... done
Removing peer1.org2.example.com ... done
Removing peer1.org1.example.com ... done
Removing peer0.org1.example.com ... done
Removing network net_byfn
Removing volume net_peer0.org3.example.com
WARNING: Volume net_peer0.org3.example.com not found.
Removing volume net_peer1.org3.example.com
WARNING: Volume net_peer1.org3.example.com not found.
Removing volume net_orderer2.example.com
WARNING: Volume net_orderer2.example.com not found.
Removing volume net_orderer.example.com
Removing volume net_peer0.org2.example.com
Removing volume net_peer0.org1.example.com
Removing volume net_peer1.org1.example.com
Removing volume net_peer1.org2.example.com
Removing volume net_orderer5.example.com
WARNING: Volume net_orderer5.example.com not found.
Removing volume net_orderer4.example.com
WARNING: Volume net_orderer4.example.com not found.
Removing volume net_orderer3.example.com
WARNING: Volume net_orderer3.example.com not found.
57da35e62075
7727893af4a0
b1fab6da4a8c
Untagged: dev-peer1.org2.example.com-mycc-1.0-26c2ef32838554aac4f7ad6f100aca865e87959c9a126e86d764c8d01f8346ab:latest
Deleted: sha256:a361bdbae52fd3897a325606f2c3f1d7a23fb737d8b12f987a0d927f1e7ddfb2
Deleted: sha256:41880d8787311ec41d2162219382b44ce4c656513c4d8cc5ea8bdb6a1379c51f
Deleted: sha256:d8c907db9d43ebefb2f1c76d89ad11546ca186b55bd3f1cb2ed9ec99eed2d26e
Deleted: sha256:2c4c8355d0acd14eff6fa105568de64b27a9b5cce3523c31a57a32a1afa28891
Untagged: dev-peer0.org1.example.com-mycc-1.0-384f11f484b9302df90b453200cfb25174305fce8f53f4e94d45ee3b6cab0ce9:latest
Deleted: sha256:3425e36582cdcb3d0da871f71976622ab353b9c8a512e0555a73b790bec1ee22
Deleted: sha256:e98f3c309f14bc6306be86a137e11166ee83abdd96ecac89698e658f225be899
Deleted: sha256:cbfe5ddde265d8294e77bdde9314e9bb6a384dae9085922ecab85cb6ceae4547
Deleted: sha256:e962aafc8595469a2b3ec55f05e3e042b0bda3dca52f1e600d0f7311c21f4732
Untagged: dev-peer0.org2.example.com-mycc-1.0-15b571b3ce849066b7ec74497da3b27e54e0df1345daff3951b94245ce09c42b:latest
Deleted: sha256:714e8f05a4ffaf0f544cc710e865022e8c513e95c060a55eacb7a2b818540c64
Deleted: sha256:0a43b52a03c8d649886ad62bb923494c3fc9c7badf65977d816bd7994ecebb0c
Deleted: sha256:2d4758a2f6ea8c70a747bf7b4beb31b199b05f2b7f09ddef3a097e2844151f41
Deleted: sha256:1fae417e6afb0a2e4178d2b43ab673997d66cad0cb55ced26b07e092b5ec8642

Starting for channel 'mychannel' with CLI timeout of '10' seconds and CLI delay of '3' seconds and using database 'couchdb'
proceeding ...
./byfn.sh: line 124: configtxlator: command not found
LOCAL_VERSION=
DOCKER_IMAGE_VERSION=1.4.3
=================== WARNING ===================
  Local fabric binaries and docker images are  
  out of  sync. This may cause problems.       
===============================================
/home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/../bin/cryptogen

##########################################################
##### Generate certificates using cryptogen tool #########
##########################################################
+ cryptogen generate --config=./crypto-config.yaml
org1.example.com
org2.example.com
+ res=0
+ set +x

Generate CCP files for Org1 and Org2
/home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/../bin/configtxgen
##########################################################
#########  Generating Orderer Genesis block ##############
##########################################################
CONSENSUS_TYPE=solo
+ '[' solo == solo ']'
+ configtxgen -profile TwoOrgsOrdererGenesis -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block
2020-09-25 10:38:25.424 CST [common.tools.configtxgen] main -> INFO 001 Loading configuration
2020-09-25 10:38:25.638 CST [common.tools.configtxgen.localconfig] completeInitialization -> INFO 002 orderer type: solo
2020-09-25 10:38:25.638 CST [common.tools.configtxgen.localconfig] Load -> INFO 003 Loaded configuration: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/configtx.yaml
2020-09-25 10:38:25.768 CST [common.tools.configtxgen.localconfig] completeInitialization -> INFO 004 orderer type: solo
2020-09-25 10:38:25.768 CST [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 005 Loaded configuration: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/configtx.yaml
2020-09-25 10:38:25.770 CST [common.tools.configtxgen] doOutputBlock -> INFO 006 Generating genesis block
2020-09-25 10:38:25.771 CST [common.tools.configtxgen] doOutputBlock -> INFO 007 Writing genesis block
+ res=0
+ set +x

#################################################################
### Generating channel configuration transaction 'channel.tx' ###
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
2020-09-25 10:38:25.815 CST [common.tools.configtxgen] main -> INFO 001 Loading configuration
2020-09-25 10:38:25.953 CST [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/configtx.yaml
2020-09-25 10:38:26.139 CST [common.tools.configtxgen.localconfig] completeInitialization -> INFO 003 orderer type: solo
2020-09-25 10:38:26.139 CST [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 004 Loaded configuration: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/configtx.yaml
2020-09-25 10:38:26.139 CST [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 005 Generating new channel configtx
2020-09-25 10:38:26.141 CST [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 006 Writing new channel tx
+ res=0
+ set +x

#################################################################
#######    Generating anchor peer update for Org1MSP   ##########
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
2020-09-25 10:38:26.188 CST [common.tools.configtxgen] main -> INFO 001 Loading configuration
2020-09-25 10:38:26.322 CST [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/configtx.yaml
2020-09-25 10:38:26.451 CST [common.tools.configtxgen.localconfig] completeInitialization -> INFO 003 orderer type: solo
2020-09-25 10:38:26.451 CST [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 004 Loaded configuration: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/configtx.yaml
2020-09-25 10:38:26.451 CST [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 005 Generating anchor peer update
2020-09-25 10:38:26.452 CST [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 006 Writing anchor peer update
+ res=0
+ set +x

#################################################################
#######    Generating anchor peer update for Org2MSP   ##########
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
2020-09-25 10:38:26.491 CST [common.tools.configtxgen] main -> INFO 001 Loading configuration
2020-09-25 10:38:26.632 CST [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/configtx.yaml
2020-09-25 10:38:26.767 CST [common.tools.configtxgen.localconfig] completeInitialization -> INFO 003 orderer type: solo
2020-09-25 10:38:26.767 CST [common.tools.configtxgen.localconfig] LoadTopLevel -> INFO 004 Loaded configuration: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/configtx.yaml
2020-09-25 10:38:26.767 CST [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 005 Generating anchor peer update
2020-09-25 10:38:26.767 CST [common.tools.configtxgen] doOutputAnchorPeersUpdate -> INFO 006 Writing anchor peer update
+ res=0
+ set +x

Creating network "net_byfn" with the default driver
Creating volume "net_peer0.org2.example.com" with default driver
Creating volume "net_peer1.org2.example.com" with default driver
Creating volume "net_peer1.org1.example.com" with default driver
Creating volume "net_peer0.org1.example.com" with default driver
Creating volume "net_orderer.example.com" with default driver
Creating couchdb1 ... 
Creating ca_peerOrg1 ... 
Creating ca_peerOrg2 ... 
Creating couchdb2 ... 
Creating couchdb3 ... 
Creating orderer.example.com ... 
Creating couchdb0 ... 
Creating couchdb1
Creating ca_peerOrg1
Creating orderer.example.com
Creating ca_peerOrg2
Creating couchdb0
Creating couchdb3
Creating couchdb3 ... done
Creating couchdb1 ... done
Creating peer0.org2.example.com ... 
Creating peer1.org2.example.com ... 
Creating peer1.org1.example.com ... 
Creating peer0.org2.example.com
Creating peer0.org1.example.com
Creating peer1.org2.example.com
Creating peer1.org1.example.com ... done
Creating cli ... 
Creating cli ... done
CONTAINER ID        IMAGE                               COMMAND                  CREATED             STATUS                  PORTS                                        NAMES
25db1f49bd0d        hyperledger/fabric-tools:latest     "/bin/bash"              3 seconds ago       Up Less than a second                                                cli
ffa08fe12f45        hyperledger/fabric-peer:latest      "peer node start"        10 seconds ago      Up 3 seconds            0.0.0.0:10051->10051/tcp                     peer1.org2.example.com
db986456e3f1        hyperledger/fabric-peer:latest      "peer node start"        10 seconds ago      Up 3 seconds            0.0.0.0:8051->8051/tcp                       peer1.org1.example.com
6b58e2f9f0fd        hyperledger/fabric-peer:latest      "peer node start"        10 seconds ago      Up 3 seconds            0.0.0.0:7051->7051/tcp                       peer0.org1.example.com
99f1a6861f29        hyperledger/fabric-peer:latest      "peer node start"        10 seconds ago      Up 5 seconds            0.0.0.0:9051->9051/tcp                       peer0.org2.example.com
083ad91dc52d        hyperledger/fabric-couchdb          "tini -- /docker-ent…"   16 seconds ago      Up 10 seconds           4369/tcp, 9100/tcp, 0.0.0.0:7984->5984/tcp   couchdb2
278bd416710a        hyperledger/fabric-couchdb          "tini -- /docker-ent…"   16 seconds ago      Up 10 seconds           4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp   couchdb0
e027cdca24ae        hyperledger/fabric-ca:latest        "sh -c 'fabric-ca-se…"   16 seconds ago      Up 10 seconds           7054/tcp, 0.0.0.0:8054->8054/tcp             ca_peerOrg2
40ba0e78f3a2        hyperledger/fabric-couchdb          "tini -- /docker-ent…"   16 seconds ago      Up 10 seconds           4369/tcp, 9100/tcp, 0.0.0.0:8984->5984/tcp   couchdb3
302ff3534644        hyperledger/fabric-orderer:latest   "orderer"                16 seconds ago      Up 10 seconds           0.0.0.0:7050->7050/tcp                       orderer.example.com
6875e13d9078        hyperledger/fabric-ca:latest        "sh -c 'fabric-ca-se…"   16 seconds ago      Up 10 seconds           0.0.0.0:7054->7054/tcp                       ca_peerOrg1
dfa539ffb0b5        hyperledger/fabric-couchdb          "tini -- /docker-ent…"   16 seconds ago      Up 10 seconds           4369/tcp, 9100/tcp, 0.0.0.0:6984->5984/tcp   couchdb1

 ____    _____      _      ____    _____ 
/ ___|  |_   _|    / \    |  _ \  |_   _|
\___ \    | |     / _ \   | |_) |   | |  
 ___) |   | |    / ___ \  |  _ <    | |  
|____/    |_|   /_/   \_\ |_| \_\   |_|  

Build your first network (BYFN) end-to-end test

Channel name : mychannel
Creating channel...
+ peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
+ res=0
+ set +x
2020-09-25 02:38:45.449 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-09-25 02:38:45.677 UTC [cli.common] readBlock -> INFO 002 Got status: &{NOT_FOUND}
2020-09-25 02:38:45.679 UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized
2020-09-25 02:38:45.916 UTC [cli.common] readBlock -> INFO 004 Received block: 0
===================== Channel 'mychannel' created ===================== 

Having all peers join the channel...
+ peer channel join -b mychannel.block
+ res=1
+ set +x
Error: error getting endorser client for channel: endorser client failed to connect to peer0.org1.example.com:7051: failed to create new connection: connection error: desc = "transport: error while dialing: dial tcp 172.20.0.11:7051: connect: connection refused"
peer0.org1 failed to join the channel, Retry after 3 seconds
+ peer channel join -b mychannel.block
+ res=1
+ set +x
Error: error getting endorser client for channel: endorser client failed to connect to peer0.org1.example.com:7051: failed to create new connection: connection error: desc = "transport: error while dialing: dial tcp 172.20.0.11:7051: connect: connection refused"
peer0.org1 failed to join the channel, Retry after 3 seconds
+ peer channel join -b mychannel.block
+ res=0
+ set +x
2020-09-25 02:38:52.604 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-09-25 02:38:53.046 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer0.org1 joined channel 'mychannel' ===================== 

+ peer channel join -b mychannel.block
+ res=0
+ set +x
2020-09-25 02:38:56.141 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-09-25 02:38:56.324 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer1.org1 joined channel 'mychannel' ===================== 

+ peer channel join -b mychannel.block
+ res=0
+ set +x
2020-09-25 02:38:59.461 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-09-25 02:38:59.669 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer0.org2 joined channel 'mychannel' ===================== 

+ peer channel join -b mychannel.block
+ res=0
+ set +x
2020-09-25 02:39:02.781 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-09-25 02:39:03.110 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer1.org2 joined channel 'mychannel' ===================== 

Updating anchor peers for org1...
+ peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
+ res=0
+ set +x
2020-09-25 02:39:06.210 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-09-25 02:39:06.392 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
===================== Anchor peers updated for org 'Org1MSP' on channel 'mychannel' ===================== 

Updating anchor peers for org2...
+ peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org2MSPanchors.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
+ res=0
+ set +x
2020-09-25 02:39:09.469 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-09-25 02:39:09.496 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
===================== Anchor peers updated for org 'Org2MSP' on channel 'mychannel' ===================== 


========= All GOOD, BYFN execution completed =========== 


 _____   _   _   ____   
| ____| | \ | | |  _ \  
|  _|   |  \| | | | | | 
| |___  | |\  | | |_| | 
|_____| |_| \_| |____/  

+ echo 'Installing smart contract on peer0.org1.example.com'
Installing smart contract on peer0.org1.example.com
+ docker exec -e CORE_PEER_LOCALMSPID=Org1MSP -e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt cli peer chaincode install -n fabcar -v 1.0 -p github.com/chaincode/fabcar/go -l golang
2020-09-25 02:39:13.810 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2020-09-25 02:39:13.810 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2020-09-25 02:39:16.156 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" > 
+ echo 'Installing smart contract on peer1.org1.example.com'
Installing smart contract on peer1.org1.example.com
+ docker exec -e CORE_PEER_LOCALMSPID=Org1MSP -e CORE_PEER_ADDRESS=peer1.org1.example.com:8051 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt cli peer chaincode install -n fabcar -v 1.0 -p github.com/chaincode/fabcar/go -l golang
2020-09-25 02:39:16.543 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2020-09-25 02:39:16.543 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2020-09-25 02:39:16.793 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" > 
+ echo 'Installing smart contract on peer0.org2.example.com'
Installing smart contract on peer0.org2.example.com
+ docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt cli peer chaincode install -n fabcar -v 1.0 -p github.com/chaincode/fabcar/go -l golang
2020-09-25 02:39:17.188 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2020-09-25 02:39:17.188 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2020-09-25 02:39:17.458 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" > 
+ echo 'Installing smart contract on peer1.org2.example.com'
Installing smart contract on peer1.org2.example.com
+ docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e CORE_PEER_ADDRESS=peer1.org2.example.com:10051 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt cli peer chaincode install -n fabcar -v 1.0 -p github.com/chaincode/fabcar/go -l golang
2020-09-25 02:39:17.774 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2020-09-25 02:39:17.774 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2020-09-25 02:39:18.016 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" > 
+ echo 'Instantiating smart contract on mychannel'
Instantiating smart contract on mychannel
+ docker exec -e CORE_PEER_LOCALMSPID=Org1MSP -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp cli peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n fabcar -l golang -v 1.0 -c '{"Args":[]}' -P 'AND('\''Org1MSP.member'\'','\''Org2MSP.member'\'')' --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
2020-09-25 02:39:18.397 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2020-09-25 02:39:18.398 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
+ echo 'Waiting for instantiation request to be committed ...'
Waiting for instantiation request to be committed ...
+ sleep 10
+ echo 'Submitting initLedger transaction to smart contract on mychannel'
Submitting initLedger transaction to smart contract on mychannel
+ echo 'The transaction is sent to all of the peers so that chaincode is built before receiving the following requests'
The transaction is sent to all of the peers so that chaincode is built before receiving the following requests
+ docker exec -e CORE_PEER_LOCALMSPID=Org1MSP -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp cli peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n fabcar -c '{"function":"initLedger","Args":[]}' --waitForEvent --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses peer0.org1.example.com:7051 --peerAddresses peer1.org1.example.com:8051 --peerAddresses peer0.org2.example.com:9051 --peerAddresses peer1.org2.example.com:10051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
2020-09-25 02:41:52.030 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [526e4e9e4df22f304b49bbe0e93b8cdd0b523afc273d7a5277f8ca7e0087e7b2] committed with status (VALID) at peer1.org1.example.com:8051
2020-09-25 02:41:51.979 UTC [chaincodeCmd] ClientWait -> INFO 003 txid [526e4e9e4df22f304b49bbe0e93b8cdd0b523afc273d7a5277f8ca7e0087e7b2] committed with status (VALID) at peer1.org2.example.com:10051
2020-09-25 02:41:51.983 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [526e4e9e4df22f304b49bbe0e93b8cdd0b523afc273d7a5277f8ca7e0087e7b2] committed with status (VALID) at peer0.org2.example.com:9051
2020-09-25 02:41:52.061 UTC [chaincodeCmd] ClientWait -> INFO 004 txid [526e4e9e4df22f304b49bbe0e93b8cdd0b523afc273d7a5277f8ca7e0087e7b2] committed with status (VALID) at peer0.org1.example.com:7051
2020-09-25 02:41:52.100 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 005 Chaincode invoke successful. result: status:200 
+ set +x

Total setup execution time : 225 secs ...

Next, use the FabCar applications to interact with the deployed FabCar contract.
The FabCar applications are available in multiple programming languages.
Follow the instructions for the programming language of your choice:

JavaScript:

  Start by changing into the "javascript" directory:
    cd javascript

  Next, install all required packages:
    npm install

  Then run the following applications to enroll the admin user, and register a new user
  called user1 which will be used by the other applications to interact with the deployed
  FabCar contract:
    node enrollAdmin
    node registerUser

  You can run the invoke application as follows. By default, the invoke application will
  create a new car, but you can update the application to submit other transactions:
    node invoke

  You can run the query application as follows. By default, the query application will
  return all cars, but you can update the application to evaluate other transactions:
    node query

TypeScript:

  Start by changing into the "typescript" directory:
    cd typescript

  Next, install all required packages:
    npm install

  Next, compile the TypeScript code into JavaScript:
    npm run build

  Then run the following applications to enroll the admin user, and register a new user
  called user1 which will be used by the other applications to interact with the deployed
  FabCar contract:
    node dist/enrollAdmin
    node dist/registerUser

  You can run the invoke application as follows. By default, the invoke application will
  create a new car, but you can update the application to submit other transactions:
    node dist/invoke

  You can run the query application as follows. By default, the query application will
  return all cars, but you can update the application to evaluate other transactions:
    node dist/query

Java:

  Start by changing into the "java" directory:
    cd java

  Then, install dependencies and run the test using:
    mvn test

  The test will invoke the sample client app which perform the following:
    - Enroll admin and user1 and import them into the wallet (if they don't already exist there)
    - Submit a transaction to create a new car
    - Evaluate a transaction (query) to return details of this car
    - Submit a transaction to change the owner of this car
    - Evaluate a transaction (query) to return the updated details of this car

halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar$ 

分析上面的日志,我們主要做了哪些事情呢?

  • 停止了上次打開的網路
  • 啟動peer節點、Ordering節點、證書頒發機構以及CLI容器】
  • 創建一個通道,并將peer加入該通道
  • 將智能合約(即鏈碼)安裝到peer節點的檔案系統上,并在通道上實體化該鏈碼;實體化會啟動鏈碼容器
  • 呼叫initLedger功能來向通道賬本寫入10個不同的汽車

最后,還想我們展示了如何來跑這個應用程式 ,以javascript為例,那我們按照命令來試試吧

3、查詢賬本

查詢是指如何從賬本中讀取資料,您可以查詢單個或者多個鍵的值,如果賬本是以類似于JSON這樣的資料存盤格式寫入的,則可以執行更復雜的搜索(如查找包含某些關鍵字的所有資產),

1.具體操作,在javascript中執行以下命令

halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar/javascript$ npm install
npm WARN fabcar@1.0.0 No repository field.

up to date in 4.15s

4 packages are looking for funding
  run `npm fund` for details

halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar/javascript$ node enrollAdmin
Wallet path: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar/javascript/wallet
An identity for the admin user "admin" already exists in the wallet
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar/javascript$ node registerUser
Wallet path: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar/javascript/wallet
Successfully registered and enrolled admin user "user1" and imported it into the wallet
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar/javascript$ node invoke
Wallet path: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar/javascript/wallet
Transaction has been submitted
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar/javascript$ node query
Wallet path: /home/halfape/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar/javascript/wallet
Transaction has been evaluated, result is: [{"Key":"CAR0", "Record":{"colour":"blue","make":"Toyota","model":"Prius","owner":"Tomoko"}},{"Key":"CAR1", "Record":{"colour":"red","make":"Ford","model":"Mustang","owner":"Brad"}},{"Key":"CAR12", "Record":{"colour":"Black","make":"Honda","model":"Accord","owner":"Tom"}},{"Key":"CAR2", "Record":{"colour":"green","make":"Hyundai","model":"Tucson","owner":"Jin Soo"}},{"Key":"CAR3", "Record":{"colour":"yellow","make":"Volkswagen","model":"Passat","owner":"Max"}},{"Key":"CAR4", "Record":{"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}},{"Key":"CAR5", "Record":{"colour":"purple","make":"Peugeot","model":"205","owner":"Michel"}},{"Key":"CAR6", "Record":{"colour":"white","make":"Chery","model":"S22L","owner":"Aarav"}},{"Key":"CAR7", "Record":{"colour":"violet","make":"Fiat","model":"Punto","owner":"Pari"}},{"Key":"CAR8", "Record":{"colour":"indigo","make":"Tata","model":"Nano","owner":"Valeria"}},{"Key":"CAR9", "Record":{"colour":"brown","make":"Holden","model":"Barina","owner":"Shotaro"}}]

我們可以看到
這里有10輛車,一輛屬于Adriana的黑色Tesla Model S、一輛屬于Brad的紅色Ford Mustang、一輛屬于Pari的紫羅蘭色Fiat Punto等等,賬本是基于Key/Value 的,在這里,關鍵字是從CAR0到CAR9,這一點特別重要,

2.代碼分析

我們可以大佬query.js里面的代碼具體做了什么,

const path = require('path');
  
const ccpPath = path.resolve(__dirname, '..', '..', 'first-network', 'connection-org1.json');

async function main() {
    try {

        // Create a new file system based wallet for managing identities.
        const walletPath = path.join(process.cwd(), 'wallet');
        const wallet = new FileSystemWallet(walletPath);
        console.log(`Wallet path: ${walletPath}`);

        // Check to see if we've already enrolled the user.
        const userExists = await wallet.exists('user1');
        if (!userExists) {
            console.log('An identity for the user "user1" does not exist in the wallet');
            console.log('Run the registerUser.js application before retrying');
            return;
        }

        // Create a new gateway for connecting to our peer node.
        const gateway = new Gateway();
        await gateway.connect(ccpPath, { wallet, identity: 'user1', discovery: { enabled: true, asLocalhost: true } });

        // Get the network (channel) our contract is deployed to.
        const network = await gateway.getNetwork('mychannel');

        // Get the contract from the network.
        const contract = network.getContract('fabcar');

        // Evaluate the specified transaction.
        // queryCar transaction - requires 1 argument, ex: ('queryCar', 'CAR4')
        // queryAllCars transaction - requires no arguments, ex: ('queryAllCars')
        const result = await contract.evaluateTransaction('queryAllCars');
        console.log(`Transaction has been evaluated, result is: ${result.toString()}`);

    } catch (error) {
        console.error(`Failed to evaluate transaction: ${error}`);
        process.exit(1);
    }
}

main();

簡單分析:

會發現主要做了創建錢包,給錢包中添加用戶,獲取通道,獲取合約,呼叫合約函式`queryAllCars`的操作完成了查詢,

那我們這個查詢函式具體實作在哪呢?如下

halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric$ ls
bccsp          CODE_OF_CONDUCT.md  devenv         examples    gotools.mk   LICENSE   peer       release_notes    testingInfo.rst   unit-test
CHANGELOG.md   common              discovery      Gopkg.lock  idemix       Makefile  protos     sampleconfig     test-pyramid.png  vendor
ci.properties  CONTRIBUTING.md     docker-env.mk  Gopkg.toml  images       msp       README.md  scripts          token
cmd            core                docs           gossip      integration  orderer   release    settings.gradle  tox.ini
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric$ cd scripts/
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts$ ls
bootstrap.sh  check_deps.sh     check_spelling.sh        compile_protos.sh  generateHelpDocs.sh  goListFiles.sh  multiarch.sh             run-integration-tests.sh
changelog.sh  check_license.sh  check_trailingspaces.sh  fabric-samples     golinter.sh          metrics_doc.sh  pull_build_artifacts.sh
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts$ cd fabric-samples/
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples$ ls
balance-transfer  bin        chaincode-docker-devmode  CODE_OF_CONDUCT.md  CONTRIBUTING.md  fabcar         high-throughput      Jenkinsfile  MAINTAINERS.md  README.md
basic-network     chaincode  ci.properties             commercial-paper    docs             first-network  interest_rate_swaps  LICENSE      off_chain_data  scripts
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples$ cd chaincode
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/chaincode$ ls
abac  chaincode_example02  fabcar  marbles02  marbles02_private  sacc
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/chaincode$ cd fabcar/
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/chaincode/fabcar$ ls
go  java  javascript  javascript-low-level  typescript
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/chaincode/fabcar$ cd javascript
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/chaincode/fabcar/javascript$ ls
index.js  lib  package.json
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/chaincode/fabcar/javascript$ cd lib/
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/chaincode/fabcar/javascript/lib$ ls
fabcar.js
halfape@halfape-VirtualBox:~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/chaincode/fabcar/javascript/lib$ 

打開fabric.js,具體代碼如下

   /*
 * SPDX-License-Identifier: Apache-2.0
 */

'use strict';

const { Contract } = require('fabric-contract-api');

class FabCar extends Contract {

    async initLedger(ctx) {
        console.info('============= START : Initialize Ledger ===========');
        const cars = [
            {
                color: 'blue',
                make: 'Toyota',
                model: 'Prius',
                owner: 'Tomoko',
            },
            {
                color: 'red',
                make: 'Ford',
                model: 'Mustang',
                owner: 'Brad',
            },
            {
                color: 'green',
                make: 'Hyundai',
                model: 'Tucson',
                owner: 'Jin Soo',
            },
            {
                color: 'yellow',
                make: 'Volkswagen',
                model: 'Passat',
                owner: 'Max',
            },
            {
                color: 'black',
                make: 'Tesla',
                model: 'S',
                owner: 'Adriana',
            },
            {
                color: 'purple',
                make: 'Peugeot',
                model: '205',
                owner: 'Michel',
            },
            {
                color: 'white',
                make: 'Chery',
                model: 'S22L',
                owner: 'Aarav',
            },
            {
                color: 'violet',
                make: 'Fiat',
                model: 'Punto',
                owner: 'Pari',
            },
            {
                color: 'indigo',
                make: 'Tata',
                model: 'Nano',
                owner: 'Valeria',
            },
            {
                color: 'brown',
                make: 'Holden',
                model: 'Barina',
                owner: 'Shotaro',
            },
        ];

        for (let i = 0; i < cars.length; i++) {
            cars[i].docType = 'car';
            await ctx.stub.putState('CAR' + i, Buffer.from(JSON.stringify(cars[i])));
            console.info('Added <--> ', cars[i]);
        }
        console.info('============= END : Initialize Ledger ===========');
    }

    async queryCar(ctx, carNumber) {
        const carAsBytes = await ctx.stub.getState(carNumber); // get the car from chaincode state
        if (!carAsBytes || carAsBytes.length === 0) {
            throw new Error(`${carNumber} does not exist`);
        }
        console.log(carAsBytes.toString());
        return carAsBytes.toString();
    }

    async createCar(ctx, carNumber, make, model, color, owner) {
        console.info('============= START : Create Car ===========');

        const car = {
            color,
            docType: 'car',
            make,
            model,
            owner,
        };

        await ctx.stub.putState(carNumber, Buffer.from(JSON.stringify(car)));
        console.info('============= END : Create Car ===========');
    }

    async queryAllCars(ctx) {
        const startKey = 'CAR0';
        const endKey = 'CAR999';

        const iterator = await ctx.stub.getStateByRange(startKey, endKey);

        const allResults = [];
        while (true) {
            const res = await iterator.next();

            if (res.value && res.value.value.toString()) {
                console.log(res.value.value.toString('utf8'));

                const Key = res.value.key;
                let Record;
                try {
                    Record = JSON.parse(res.value.value.toString('utf8'));
                } catch (err) {
                    console.log(err);
                    Record = res.value.value.toString('utf8');
                }
                allResults.push({ Key, Record });
            }
            if (res.done) {
                console.log('end of data');
                await iterator.close();
                console.info(allResults);
                return JSON.stringify(allResults);
            }
        }
    }

    async changeCarOwner(ctx, carNumber, newOwner) {
        console.info('============= START : changeCarOwner ===========');

        const carAsBytes = await ctx.stub.getState(carNumber); // get the car from chaincode state
        if (!carAsBytes || carAsBytes.length === 0) {
            throw new Error(`${carNumber} does not exist`);
        }
        const car = JSON.parse(carAsBytes.toString());
        car.owner = newOwner;

        await ctx.stub.putState(carNumber, Buffer.from(JSON.stringify(car)));
        console.info('============= END : changeCarOwner ===========');
    }

}
mdule.exports = FabCar;

會發現,除了我們的queryCar函式 queryAllCars函式,還有createCar函式和changeCarOwner函式,另外還可以看到在初始化的時候出現了10輛汽車的原因,

queryAllCars中有這么一段

const startKey = 'CAR0';
        const endKey = 'CAR999';
        const iterator = await ctx.stub.getStateByRange(startKey, endKey);

該函式呼叫shim介面函式GetStateByRange來回傳引數在startKey和endKey間的賬本資料,這兩個鍵值分別定義為CAR0和CAR999,因此,我們理論上可以創建1,000輛汽車(假設Keys都被正確使用),queryAllCars函式將會顯示出每一輛汽車的資訊,

既然看懂了代碼,我們來做點小改動,回到剛才的query.js,編輯如下:

const result = await contract.evaluateTransaction('queryCar','CAR4');

然后再來執行,應當只查出CAR4的資訊,我們來看看吧
在這里插入圖片描述
果然結果也是對的,因為車輛資訊是從0開始的,所以這里是黑色特斯拉,

4、更新賬本

我們來看看另外一個獨立的用于交易的程式invoke.js,進行打開

/*
 * SPDX-License-Identifier: Apache-2.0
 */

'use strict';

const { FileSystemWallet, Gateway } = require('fabric-network');
const path = require('path');

const ccpPath = path.resolve(__dirname, '..', '..', 'first-network', 'connection-org1.json');

const ccpPath = path.resolve(__dirname, '..', '..', 'first-network', 'connection-org1.json');

async function main() {
    try {

        // Create a new file system based wallet for managing identities.
        const walletPath = path.join(process.cwd(), 'wallet');
        const wallet = new FileSystemWallet(walletPath);
        console.log(`Wallet path: ${walletPath}`);

        // Check to see if we've already enrolled the user.
        const userExists = await wallet.exists('user1');
        if (!userExists) {
            console.log('An identity for the user "user1" does not exist in the wallet');
            console.log('Run the registerUser.js application before retrying');
            return;
        }

        // Create a new gateway for connecting to our peer node.
        const gateway = new Gateway();
        await gateway.connect(ccpPath, { wallet, identity: 'user1', discovery: { enabled: true, asLocalhost: true } });

        // Get the network (channel) our contract is deployed to.
        const network = await gateway.getNetwork('mychannel');

        // Get the contract from the network.
        const contract = network.getContract('fabcar');

        // Submit the specified transaction.
        // createCar transaction - requires 5 argument, ex: ('createCar', 'CAR12', 'Honda', 'Accord', 'Black', 'Tom')
        // changeCarOwner transaction - requires 2 args , ex: ('changeCarOwner', 'CAR10', 'Dave')
        await contract.submitTransaction('createCar', 'CAR12', 'Honda', 'Accord', 'Black', 'Tom');
        console.log('Transaction has been submitted');

        // Disconnect from the gateway.
        await gateway.disconnect();

    } catch (error) {
        console.error(`Failed to submit transaction: ${error}`);
        process.exit(1);
    }
}

main();
簡單分析會發現主要做了創建錢包,給錢包中添加用戶,呼叫合約函式`createCar`的操作完成了提交交易的操作,

另外我們做一個簡單的修改,然后執行node invoke.js,會顯示交易已經被提交,

await contract.submitTransaction('createCar', 'CAR10', 'Aodi', 'Accord', 'Blue', 'halfape');

此時,我們在vim query.js,修改為查詢CAR10資訊,執行node query.js,則會顯示以下資訊,
在這里插入圖片描述
還有一個chanegCarOwner,大家可以自己試試哈,

Fabric互動應用程式原理分析

下圖演示了一個應用程式如何在鏈碼(智能合約)中呼叫不同功能,
在這里插入圖片描述
從上圖以及上面的例子就可以看出:應用程式通過智能合約(在Fabric中叫做鏈碼)從區塊鏈上獲取資訊或者更新資訊,

在來看一張圖,展示了應用程式是如何我們的Fabric網路進行互動的,
在這里插入圖片描述
相信跟著我一步步除錯到這里,你已經對Fabric又有了新的認識,對區塊鏈又有了新的認識,Say Goodbye~

參考文章:

https://blog.csdn.net/dalang1010/article/details/78940200
https://cn.hyperledger.org/
https://hyperledgercn.github.io/hyperledgerDocs/build_network_zh/

寫在最后

最后,還是得感謝眾多前輩所給的案例以及親身踩過的坑,我才得以成功測驗這個小應用,如果你覺得這篇文章對你有所幫助,關注微信公眾號半路猿,拉你進我們的學習交流群,一起學習,一同成長,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/132281.html

標籤:其他

上一篇:專訪國內頂級商業操盤手卞波,從一年做到10個億的企業家到諄諄傳教者的進階之路

下一篇:html中的塊和行內元素

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more