Demo of Multi-Channel Network in Hyperledger Fabric
Note: When I wrote this article, I was using release 1.3.0. This does not work with release 1.4.3. I have updated the configuration files such that they work on release 1.4.3. You can refer to this repository.
Mục Lục
Overview
We will build the whole network according to the logic in First Network, except that we have to modify the configuration files to fit our setup.
Overall Setup
We are building a network of three organizations, Org1, Org2 and Org3, each of which has one peer Peer0. We have two channels, ChannelAll (Org1, Org2 and Org3) and Channel12 (Org1 and Org2). On these two channels we are deploying the same chaincode Simple Asset Chaincode, provided in the Fabric Samples.
Steps
Step 1: Obtain the Software and Tools for Hyperledger Fabric
We are using Hyperledger Fabric v1.3 in this setup.
You can check whether you have already installed the required software and tools or not, by checking,
- directory fabric-samples, inside which you have the tools under bin directory. The tools we are using are cryptogen and configtxgen.
- docker images for v1.3 ($ docker images hyperledger/fabric*) and all the v1.3 images are tagged as latest.
If not, proceed with the download process.
Prepare the working directory.
$ mkdir hyperledgerfabric13
$ cd hyperledgefabric13
$ curl -sSL http://bit.ly/2ysbOFE | bash -s 1.3.0
It takes time to download the platform tools. If you have not downloaded docker images before, it may even take much longer.
After it completes, you will see the directory fabric-samples, and the required docker images are already downloaded as well.
And you will see the docker images for v1.3, and they are all tagged as latest.
Step 2: Design a Multi Channel Network
Overall Business Network Setup
As mentioned before, here is the architecture of our demo network
- an organization for Orderer (OrderOrg) with one Orderer node
- three organizations (Org1, Org2 and Org3), and one peer on each organization
- two channels are established (ChannelAll and Channel12), such that ChannelAll is for Org1, Org2 and Org3, and Channel12 is only for Org1 and Org2.
And we will deploy the same chaincode SACC (Simple Asset Chaincode) provided in the fabric-samples to these two channels, and see how they are working independently.
This step we are construct three files we need to establish this network in next step. We will first build a new directory under hyperledgerfabric13/fabric-samples.
$ mkdir multi-channel-network
$ cd multi-channel-network
Step 2.1 Construct crypto-config.yaml
This configuration file is used for generating the necessary certificates for different parties, including nodes and administrators.
Step 2.2 Construct configtx.yaml
This file keeps all the business network we are building. It is how the network is actually built. Among many by default setup, we focus on the Profiles (the lower part of this file). The profiles are used to generate genesis block and transactions needed to bring up the network.
The profile for genesis block is OrdererGenesis, and three organizations are included in this.
The profile for channels are ChannelAll and Channel12, corresponding to the two channels in our network.
Step 2.3 Construct docker-compose.yaml
As Hyperledger Fabric network is deployed in Docker containers, a Docker Compose file is needed to bring up the network nodes (peer and orderer) as containers.
Step 2.4 Prepare .env file
Finally prepare the .env containing the variable used in docker-compose.yaml.
$ echo COMPOSE_PROJECT_NAME=net > .env
Step 3: Generate the Certificates and Configuration Transactions
In Step 2 we have prepared the configuration files. The files crypto-config.yaml and configtx.yaml files are used for generating the configuration files that will be used when bringing up our network.
The two tools are stored in fabric-samples/bin. They are cryptogen and configtxgen, respectively.
Step 3.1: Generate the Certificates for Organizations, Administrators and Users
All the certificates are generated using the tool cryptogen with configuration file crypto-config.yaml. The result is a directory crypto-config newly created and all the certificates are stored inside.
$ ../bin/cryptogen generate --config=./crypto-config.yaml
Step 3.2: Generate the Configuration Transactions for the Channels
The tool we are using is configtxgen and the configuration file is configtx.yaml. Note that we need to create a directory channel-artifacts as the results are stored in this directory. You will see error if you do not have this directory.
$ mkdir channel-artifacts
First we generate the genesis block using profile OrdererGenesis. The result is a file called genesis.block.
$ ../bin/configtxgen -profile OrdererGenesis -outputBlock ./channel-artifacts/genesis.block
We will first define some environment variables.
$ export CHANNEL_ONE_NAME=channelall
$ export CHANNEL_ONE_PROFILE=ChannelAll
$ export CHANNEL_TWO_NAME=channel12
$ export CHANNEL_TWO_PROFILE=Channel12
Then we generate the Channel Transactions. We have two channels. We will generate the configuration transaction for both channels. The result is the <channel_name>.tx. In our case it is channelall.tx and channel12.tx.
$ ../bin/configtxgen -profile ${CHANNEL_ONE_PROFILE} -outputCreateChannelTx ./channel-artifacts/${CHANNEL_ONE_NAME}.tx -channelID $CHANNEL_ONE_NAME
$ ../bin/configtxgen -profile ${CHANNEL_TWO_PROFILE} -outputCreateChannelTx ./channel-artifacts/${CHANNEL_TWO_NAME}.tx -channelID $CHANNEL_TWO_NAME
Finally we are generating the Anchor Peer update file for each channel. In our design, we will have all peers as anchor peers in each channel. Therefore we will have five new files: three for ChannelAll, and two for Channel12.
For ChannelAll (Org1, Org2 and Org3),
$ ../bin/configtxgen -profile ${CHANNEL_ONE_PROFILE} -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors_${CHANNEL_ONE_NAME}.tx -channelID $CHANNEL_ONE_NAME -asOrg Org1MSP
$ ../bin/configtxgen -profile ${CHANNEL_ONE_PROFILE} -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors_${CHANNEL_ONE_NAME}.tx -channelID $CHANNEL_ONE_NAME -asOrg Org2MSP
$ ../bin/configtxgen -profile ${CHANNEL_ONE_PROFILE} -outputAnchorPeersUpdate ./channel-artifacts/Org3MSPanchors_${CHANNEL_ONE_NAME}.tx -channelID $CHANNEL_ONE_NAME -asOrg Org3MSP
For Channel12 (Org1 and Org2),
$ ../bin/configtxgen -profile ${CHANNEL_TWO_PROFILE} -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors_${CHANNEL_TWO_NAME}.tx -channelID $CHANNEL_TWO_NAME -asOrg Org1MSP
$ ../bin/configtxgen -profile ${CHANNEL_TWO_PROFILE} -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors_${CHANNEL_TWO_NAME}.tx -channelID $CHANNEL_TWO_NAME -asOrg Org2MSP
Now we see all the files generated in channel-artifacts directory: the genesis block file, the transactions for two channels and total five anchor peers.
Step 4: Bring Up the Infrastructure (Containers)
We use docker-compose to bring up the our hyperledger fabric network, with the configuration file docker-compose.yaml.
$ docker-compose -f docker-compose.yaml up -d
After the commands are executed, we can check the running containers, which should corresponding to the setup of our network. There will be total five running containers
- one orderer
- three peers, each for one organization
- one CLI
Note the CLI will be used to initiate command.
$ docker ps
Step 5: Configure Channels on the Infrastructure
Now we have the containers running. We start configuring the channel on the peers.
All the commands are issued from CLI containers with docker exec. The CLI container has a default setting on peer0.org1. For easy access, we will launch three new terminals (or split the terminals into three as shown below), each of which for the peer of organizations. Our commands will later be issued on Terminal.
Those files created in Step 3.1 (in crypto-config directory) are copied to the corresponding containers.
Those files created in Step 3.2 (in channel-artifacts directory) are copied to containers, and they are used for configure channel.
Prepare Multiple Terminals
We designate the three new terminals for Org1, Org2 and Org3.
For Org1 (default)
$ docker exec -it cli bash
For Org2 (specifying the environment variables for Org2)
$ docker exec -e "CORE_PEER_LOCALMSPID=Org2MSP" -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" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp" -e "CORE_PEER_ADDRESS=peer0.org2.example.com:7051" -it cli bash
For Org3 (specifying the environment variables for Org3)
$ docker exec -e "CORE_PEER_LOCALMSPID=Org3MSP" -e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/users/[email protected]/msp" -e "CORE_PEER_ADDRESS=peer0.org3.example.com:7051" -it cli bash
For easy access, export this parameter ORDERER_CA in all three terminals.
# export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
Here are the three terminals, from top to bottom, for Org1, Org2 and Org3.
Flow of Configuring Channels
Step 5.1 ChannelAll
Create the channel block file (any Terminal)
# peer channel create -o orderer.example.com:7050 -c channelall -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/channelall.tx --tls --cafile $ORDERER_CA
Now a file channelall.block is created.
Join the three peers to this channel and update the anchor peer for each peer.
Org1 Terminal
# peer channel join -b channelall.block --tls --cafile $ORDERER_CA
# peer channel update -o orderer.example.com:7050 -c channelall -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org1MSPanchors_channelall.tx --tls --cafile $ORDERER_CA
Org2 Terminal
# peer channel join -b channelall.block --tls --cafile $ORDERER_CA
# peer channel update -o orderer.example.com:7050 -c channelall -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org2MSPanchors_channelall.tx --tls --cafile $ORDERER_CA
Org3 Terminal
# peer channel join -b channelall.block --tls --cafile $ORDERER_CA
# peer channel update -o orderer.example.com:7050 -c channelall -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org3MSPanchors_channelall.tx --tls --cafile $ORDERER_CA
Step 5.2: Channel12
Create the channel block file (any Terminal)
# peer channel create -o orderer.example.com:7050 -c channel12 -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/channel12.tx --tls --cafile $ORDERER_CA
Now a file channel12.block is created.
Join the two peers to this channel and update the anchor peer for each peer.
Org1 Terminal
# peer channel join -b channel12.block --tls --cafile $ORDERER_CA
# peer channel update -o orderer.example.com:7050 -c channel12 -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org1MSPanchors_channel12.tx --tls --cafile $ORDERER_CA
Org2 Terminal
# peer channel join -b channel12.block --tls --cafile $ORDERER_CA
# peer channel update -o orderer.example.com:7050 -c channel12 -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org2MSPanchors_channel12.tx --tls --cafile $ORDERER_CA
Step 6: Install Simple Asset Chaincode (SACC)
Now our network is up and running, ready for deploying chaincode.
We are using the SACC coming with in the fabric-samples. Here is the chaincode:
The logic of this chaincode is quite straight forward.
- When chaincode is instantiated, the Init() is executed. Two arguments are expected, which corresponding to a “key” and a “value”.
- This key/value pair is stored in the ledger (using PutState).
- After instantiated, transactions are handled by Invoke(). The parameter is composed of a function (or command) and argument(s).
- If function = set, two arguments are expected. it is either a brand-new key/value, or overrides the value if key exists. Function set() is called, and the result is stored in the ledger (using PutState)
- If function = anything (e.g. get), one argument is expected as key. Function get() is called. GetState is used to obtain the state from the ledger. If key exists then the value is returned. Otherwise it is shown “Asset not found”.
By installing the chaincode, it loads the chaincode onto each peer. Note that chaincode is not yet useable until it is being instantiated.
To install the chaincode, on each terminal,
# peer chaincode install -n sacc -p github.com/chaincode/sacc -v 1.0
We should see the last message as:
Now all the the nodes have the chaincode installed. We are ready for instantiating this chaincode.
Step 7: Instantiate and Interact with Chaincode on ChannelAll
We will first focus on ChannelAll.
On Org1 Terminal, we instantiate the code on ChannelAll.
# peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C channelall -c '{"Args":["a", "100"]}' -n sacc -v 1.0 -P "OR('Org1MSP.peer', 'Org2MSP.peer', 'Org3MSP.peer')"
We have set the initial key/value pair as a/100. Beside we specify the endorsing policy: one of the three organizations needed (OR is used).
We will query the value of key “a” in ChannelAll.
On Org1 Terminal,
# peer chaincode query -C channelall -n sacc -c '{"Args":["get","a"]}'
ChannelAll on Org1 Terminal
Now on Org2 Terminal,
# peer chaincode query -C channelall -n sacc -c '{"Args":["get","a"]}'
ChannelAll on Org2 Terminal
And on Org3 Terminal,
# peer chaincode query -C channelall -n sacc -c '{"Args":["get","a"]}'
ChannelAll on Org3 Terminal
We now see that the three peers has the same value obtained. They are sharing the same ledger.
Step 8: Instantiate and Interact with Chaincode on Channel12
Now we instantiate the same SACC on Channel12.
On Org1 Terminal,
# peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C channel12 -c '{"Args":["b", "200"]}' -n sacc -v 1.0 -P "OR('Org1MSP.peer', 'Org2MSP.peer')"
This time we are setting initial key/value pair as b/200. And endorsing policy requires endorsement from either one organization.
Then again we begin with Org1 Terminal.
# peer chaincode query -C channel12 -n sacc -c '{"Args":["get","b"]}'
Channel12 on Org1 Terminal
Then on Org2 Terminal.
# peer chaincode query -C channel12 -n sacc -c '{"Args":["get","b"]}'
Channel12 on Org2 Terminal
And if we issue the same command on Org3 Terminal, we see access denied message. It is because Org3 is not in Channel12.
# peer chaincode query -C channel12 -n sacc -c '{"Args":["get","b"]}'
Channel12 on Org3 Terminal: Access Denied
If we try to get the value of key “a” on Channel12, we find that “a” is not defined. Each channel has its own ledger and the state is not shared.
On Org1 or Org2 Terminal,
# peer chaincode query -C channel12 -n sacc -c '{"Args":["get","a"]}'
Key “a” not defined in Channel12
Step 9: Clean Up Everything
After everything is complete, it is good practice to clean up everything, including the docker containers and those files generated for this demo.
To shutdown all containers and remove them, we use docker-compose to remove those created through the configuration files.
$ docker-compose -f docker-compose.yaml down
There are still some stopped containers (see it from docker ps -a). They are the chaincode after instantiation. We will remove them all as well.
$ docker ps -a
$ docker rm $(docker ps -aq)
While we are removing the channel artifacts, it is recommended to keep channel-artifacts directory as this is needed on next demo (or you need to create it again).
$ rm channel-artifacts/*
Finally we remove the whole directory of crypto-config. The directory will be created next time by the cryptogen.
$ rm -r crypto-config
Summary
We have completed the multi-channel setup for a three-organization Hyperledger Fabric network. We begin with configuration files and bring up our network according to our setup. By deploying the same chaincode on different channels, we observe that each channel has its own ledger, and the states are not shared each other.