first-network是fabric官方提供的首個示例。這里對此示例的結構和啟動過程做下解析。
結構
使用byfn.sh up
啟動后,會出現9個新容器:
IMAGE | NAME | PORTS |
---|---|---|
dev-peer1.org2.example.com-mycc-1.0-26c2ef32838554aac4f7ad6f100aca865e87959c9a126e86d764c8d01f8346ab | dev-peer1.org2.example.com-mycc-1.0 | - |
dev-peer0.org1.example.com-mycc-1.0-384f11f484b9302df90b453200cfb25174305fce8f53f4e94d45ee3b6cab0ce9 | dev-peer0.org1.example.com-mycc-1.0 | - |
dev-peer0.org2.example.com-mycc-1.0-15b571b3ce849066b7ec74497da3b27e54e0df1345daff3951b94245ce09c42b | dev-peer0.org2.example.com-mycc-1.0 | - |
hyperledger/fabric-tools:latest | cli | - |
hyperledger/fabric-orderer:latest | orderer.example.com | 0.0.0.0:7050->7050/tcp |
hyperledger/fabric-peer:latest | peer1.org1.example.com | 0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp |
hyperledger/fabric-peer:latest | peer0.org1.example.com | 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp |
hyperledger/fabric-peer:latest | peer1.org2.example.com | 0.0.0.0:10051->7051/tcp, 0.0.0.0:10053->7053/tcp |
hyperledger/fabric-peer:latest | peer0.org2.example.com | 0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp |
可見,共啟動了4個peer節點,分別屬于org1和org2;另有一個orderer節點。
還啟動了一個cli,用于控制網絡。
在3個peer節點上,安裝了chaincode,也以容器形式啟動。
分析 byfn.sh
Step.1 byfn.sh generate
generate required certificates and genesis block.
elif [ "${MODE}" == "generate" ]; then ## Generate Artifacts
generateCerts
replacePrivateKey
generateChannelArtifacts
從腳本入口部分可見,generate命令執行了3個函數:
1. generateCerts()
精簡代碼如下:
# Generates Org certs using cryptogen tool
function generateCerts() {
if [ -d "crypto-config" ]; then
rm -Rf crypto-config
fi
cryptogen generate --config=./crypto-config.yaml
}
可見,這一步先清除crypto-config目錄,再調用cryptogen工具,根據crypto-config.yaml生成文件(到crypto-config目錄)。
精簡的crypto-config.yaml:
# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
- Name: Orderer
Domain: example.com
Specs:
- Hostname: orderer
# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
- Name: Org1
Domain: org1.example.com
EnableNodeOUs: true
Template:
Count: 2
Users:
Count: 1
- Name: Org2
Domain: org2.example.com
EnableNodeOUs: true
Template:
Count: 2
Users:
Count: 1
可見,定義了一個OrdererOrg,2個PeerOrgs:Org1,Org2;每個PeerOrg各有2個節點。
生成的文件結構:
$ tree crypto-config -L 4 -d
crypto-config
├── ordererOrganizations
│ └── example.com
│ ├── ca
│ ├── msp
│ │ ├── admincerts
│ │ ├── cacerts
│ │ └── tlscacerts
│ ├── orderers
│ │ └── orderer.example.com
│ ├── tlsca
│ └── users
│ └── Admin@example.com
└── peerOrganizations
├── org1.example.com
│ ├── ca
│ ├── msp
│ │ ├── admincerts
│ │ ├── cacerts
│ │ └── tlscacerts
│ ├── peers
│ │ ├── peer0.org1.example.com
│ │ └── peer1.org1.example.com
│ ├── tlsca
│ └── users
│ ├── Admin@org1.example.com
│ └── User1@org1.example.com
└── org2.example.com
├── ca
├── msp
│ ├── admincerts
│ ├── cacerts
│ └── tlscacerts
├── peers
│ ├── peer0.org2.example.com
│ └── peer1.org2.example.com
├── tlsca
└── users
├── Admin@org2.example.com
└── User1@org2.example.com
2. replacePrivateKey()
精簡代碼如下:
# Using docker-compose-e2e-template.yaml, replace constants with private key file names
# generated by the cryptogen tool and output a docker-compose.yaml specific to this
# configuration
function replacePrivateKey() {
OPTS="-i"
# Copy the template to the file that will be modified to add the private key
cp docker-compose-e2e-template.yaml docker-compose-e2e.yaml
# The next steps will replace the template's contents with the
# actual values of the private key file names for the two CAs.
CURRENT_DIR=$PWD
cd crypto-config/peerOrganizations/org1.example.com/ca/
PRIV_KEY=$(ls *_sk)
cd "$CURRENT_DIR"
sed $OPTS "s/CA1_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose-e2e.yaml
cd crypto-config/peerOrganizations/org2.example.com/ca/
PRIV_KEY=$(ls *_sk)
cd "$CURRENT_DIR"
sed $OPTS "s/CA2_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose-e2e.yaml
}
可見,此函數復制了docker-compose-e2e-template.yaml為docker-compose-e2e.yaml,并根據上一步生成的.../ca/..._sk文件,替換了.yaml中響應路徑。
由于之后我們使用docker-compose-cli.yaml啟動,不使用CA節點,所以這里生成的文件暫時還用不到。
3. generateChannelArtifacts()
精簡代碼:
# Generate orderer genesis block, channel configuration transaction and anchor peer update transactions
function generateChannelArtifacts() {
# Generating Orderer Genesis block
# Note: For some unknown reason (at least for now) the block file can't be
# named orderer.genesis.block or the orderer will fail to launch!
configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
# Generating channel configuration transaction 'channel.tx'
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
# Generating anchor peer update for Org1MSP
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
# Generating anchor peer update for Org2MSP
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate \
./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
可見,此函數功能就是調用configtxgen:
- 生成 orderer genesis block
- 生成 channel configuration transaction
- 為每個組織生成 anchor peer update transactions
最終文件生成在channel-artifacts目錄中:
$ tree channel-artifacts/
channel-artifacts/
├── channel.tx
├── genesis.block
├── Org1MSPanchors.tx
└── Org2MSPanchors.tx
執行完generate命令后,我們得到了:
- 一系列密鑰和證書在crypto-config目錄;
- 一個使用了CA證書的compose配置文件docker-compose-e2e.yaml;
- orderer genesis block、channel configuration transaction、anchor peer update transactions在channel-artifacts目錄。
Step.1 byfn.sh up
#Create the network using docker compose
if [ "${MODE}" == "up" ]; then
networkUp
可見,up命令只執行了networkUp()函數。
networkUp()
精簡代碼:
COMPOSE_FILE=docker-compose-cli.yaml
# Generate the needed certificates, the genesis block and start the network.
function networkUp() {
if [ "${IF_COUCHDB}" == "couchdb" ]; then
IMAGE_TAG=$IMAGETAG docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_COUCH up -d 2>&1
else
IMAGE_TAG=$IMAGETAG docker-compose -f $COMPOSE_FILE up -d 2>&1
fi
# now run the end to end script
docker exec cli scripts/script.sh $CHANNEL_NAME $CLI_DELAY $LANGUAGE $CLI_TIMEOUT $VERBOSE
}
可見,這個函數做了兩件事:
- docker-compose根據docker-compose-cli.yaml編排啟動容器。
- 在cli容器中執行scripts/script.sh腳本。
docker-compose-cli.yaml:
version: '2'
volumes:
orderer.example.com:
peer0.org1.example.com:
peer1.org1.example.com:
peer0.org2.example.com:
peer1.org2.example.com:
networks:
byfn:
services:
orderer.example.com:
extends:
file: base/docker-compose-base.yaml
service: orderer.example.com
container_name: orderer.example.com
networks:
- byfn
peer0.org1.example.com:
container_name: peer0.org1.example.com
extends:
file: base/docker-compose-base.yaml
service: peer0.org1.example.com
networks:
- byfn
peer1.org1.example.com:
container_name: peer1.org1.example.com
extends:
file: base/docker-compose-base.yaml
service: peer1.org1.example.com
networks:
- byfn
peer0.org2.example.com:
container_name: peer0.org2.example.com
extends:
file: base/docker-compose-base.yaml
service: peer0.org2.example.com
networks:
- byfn
peer1.org2.example.com:
container_name: peer1.org2.example.com
extends:
file: base/docker-compose-base.yaml
service: peer1.org2.example.com
networks:
- byfn
cli:
container_name: cli
image: hyperledger/fabric-tools:$IMAGE_TAG
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
#- CORE_LOGGING_LEVEL=DEBUG
- CORE_LOGGING_LEVEL=INFO
- CORE_PEER_ID=cli
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
- 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
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./../chaincode/:/opt/gopath/src/github.com/chaincode
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- orderer.example.com
- peer0.org1.example.com
- peer1.org1.example.com
- peer0.org2.example.com
- peer1.org2.example.com
networks:
- byfn
可見,這個配置文件定義了需要啟動的9個容器的相關信息。9個容器被放在同一個docker network:byfn中。
精簡的script.sh腳本:
#!/bin/bash
## Create channel
createChannel
## Join all the peers to the channel
joinChannel
## Set the anchor peers for each org in the channel
updateAnchorPeers 0 1
updateAnchorPeers 0 2
## Install chaincode on peer0.org1 and peer0.org2
installChaincode 0 1
installChaincode 0 2
# Instantiate chaincode on peer0.org2
instantiateChaincode 0 2
# Query chaincode on peer0.org1
chaincodeQuery 0 1 100
# Invoke chaincode on peer0.org1 and peer0.org2
chaincodeInvoke 0 1 0 2
## Install chaincode on peer1.org2
installChaincode 1 2
# Query on chaincode on peer1.org2, check if the result is 90
chaincodeQuery 1 2 90
除去細節后,script.sh執行了一系列網絡構建工作,包括:
- 創建channel并將所有peers加入channel;
- 設定每個org的anchor peer;
- install chaincode到2個anchor peer,實例化其中一個;
- Query和invoke操作
- install chaincode到另一個節點,并在其上query它
這里進行了一個交易操作,并驗證其結果正確。