Observing Channel and Chaincode in Hyperledger Fabric
Overview
What happens if we deploy the same chaincode to two channels? How about if the same chaincode is deployed twice in a channel? Through observing these different scenarios we can know more about how Hyperledger Fabric is working. Thanks for the latest v2.2, Test Network gives us an easy way to create these setup and make such observations.
First introduced in v2.0, the Test Network setup is simple: one orderer organization serving ordering service (solo), and two peer organizations (Org1 and Org2), each of which has one peer (peer0). The script network.sh
is “upgraded” with full flexibility. Now we can easily create multiple channels and deploy multiple chaincodes onto this Test Network. This gives us an easy way to make observation, as we do not have to generate a lot of material and deal with many files. The script is well coded to build these setup for us.
The purpose of this article is to observe the system behaviour of Hyperledger Fabric when dealing with channel and chaincode. We begin with a baseline setup, in which one channel is created and one chaincode is deployed. Later we will work on two variations. They are,
- Same chaincode deployed in two channels
- Same chaincode deployed twice in a channel
Our observation point is on how ledger is being handled across channels and/or across chaincode deployed. Also we will take a look at chaincode containers and the worldstate database.
Note in Fabric v2.2, the default chaincode is changed from chaincode/fabcar/
to asset-transfer-basic/
, if no chaincode is specified in ./network.sh deployCC
. For simplicity we are using the Simple Asset Chaincode (chaincode/sacc/
) in this article. This provides a simple asset recorded in ledger, with get and set chaincode functions on the assets.
Quick Review on Test Network Script
Test Network in v2.2 comes with a very handy and user friendly script, network.sh
, with a lot of flexibility. You can find more detail about Test Network in the readthedoc. Here we show a summary of the commands we use in this article.
Bring Up Containers
To bring up all the required components for the Test Network.
./network.sh up -s couchdb
This will bring up the three nodes: one orderer and two peers. When -s couchdb
option is specified, two more Couch DB containers are running, one for each peer. We will see totally five containers once the command is executed.
Create Channels
To build channel artifacts, create channel genesis block, join peers, and update anchor peers for a specific channel.
./network.sh createChannel -c <channel_name>
If no channel name is specified, it is by default mychannel.
Note this command can be combined with the previous. For example,
./network.sh up createChannel
Then mychannel is created after all containers are up and running.
Deploy Chaincodes
To deploy chaincode using lifecycle chaincode,
./network.sh deployCC -ccn <chaincode name> -ccp <chaincode path> -c <channel_name>
If we do not specify chaincode name (-ccn
) and chaincode path (-ccp
), the asset-transfer-basic/
will be deployed. If we do not specify channel name, mychannel is the target channel.
Tear Down Test Network
To tear down everything
./network.sh down
This will stop and kill all the running containers, and remove the chaincode container images built during chaincode deployment. It helps when you need a clean setup for testing.
Prepare Two Terminals
As Test Network does not come with a CLI container, we are using localhost to issue peer
commands to the two peers. The easiest way is to prepare two terminals, one for each peer (organization). What we need is to make sure the environment variables are properly set in these terminals.
We prepare two files keeping the environment variables:
file: terminalorg1
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:7051export PATH=$PATH:$PWD/../bin/export FABRIC_CFG_PATH=$PWD/../config/
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
file: terminalorg2
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:9051export PATH=$PATH:$PWD/../bin/export FABRIC_CFG_PATH=$PWD/../config/
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
Here I change the background for the two terminals.
Terminal for Org1 (blue background)
source terminalorg1
Terminal for Org2 (dark violet background)
source terminalorg2
With this we can begin with our baseline setup.
Baseline Setup: One Channel and One Chaincode
We begin with one channel (mychannel) and one chaincode (mycc). Here is the baseline setup.
Bring up Test Network and mychannel
cd fabric-samples/test-network
./network.sh up createChannel -s couchdb
All network components are up and running.
And both peers have joined mychannel.
Deploy chaincode
./network.sh deployCC -ccn mycc -ccp ../chaincode/sacc
After the script is completely executed, we can test the chaincode functions.
Test chaincode
Invoke from either one terminal
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile $ORDERER_CA -C mychannel -n mycc --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["set","name","Alice"]}'
Query from both Org1 and Org2
peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'
The basic setup for single channel and single chaincode deployment is working well. Both peers see the same asset.
Observation
Chaincode container
There are only two chaincode containers running, one for each peer. From the name of container image we learn that it is associated to the peer and the chaincode name, not a channel name. We do not see mychannel shown in the name. Later we can see it supports many channels as far as the name remains.
Worldstate database
We see a database for this deployment. The database is named with channel (mychannel) and chaincode (mycc).
Clean up deployment
./network.sh down
Two channels with the same chaincode
Here we will bring up two channels, channelone and channeltwo, and deploy chaincode to both channels. We will demonstrate that the state is kept in two different ledgers, and stored separately even if the same chaincode is deployed and same asset name is used.
Bring up Test Network and two channels
cd fabric-samples/test-network
./network.sh up -s couchdb
./network.sh createChannel -c channelone
./network.sh createChannel -c channeltwo
After two channels are created, we can check each peer has joined them all.
Deploy chaincode to the two channels
Note that the script ./network.sh deployCC
performs the whole process (packaging, installation, approval and committing). After we use script to deploy chaincode in channelone, which should be straightforward, our attempt to repeat this in channeltwo will fail, as chaincode is already installed in both peers. As a result, we will use peer command to approve and commit chaincode definition on channeltwo.
Deploy chaincode using script for channelone
We first use script to deploy sacc on channelone.
./network.sh deployCC -ccn mycc -ccp ../chaincode/sacc -c channelone
Obtain chaincode package ID
As we need manual approval on channeltwo. First we need the package ID after chaincode is installed in the peer.
peer lifecycle chaincode queryinstalled
Approve chaincode for both Org1 and Org2 to channeltwo
Approval is required for both organizations. Same command for both terminals.
peer lifecycle chaincode approveformyorg --tls --cafile $ORDERER_CA -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID channeltwo --name mycc --version 1 --sequence 1 --waitForEvent --package-id mycc_1.0:366663ea5345d035a3a8aca36db3abe45806c5be6cce5f30fdf9ce81410d7fa5
Commit chaincode for channeltwo
On either terminal
peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations//peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --channelID channeltwo --name mycc --version 1 --sequence 1
With this, we have deployed sacc on channeltwo. We can do a quick check.
On either terminal
peer lifecycle chaincode querycommitted --channelID channelone --name mycc --output jsonpeer lifecycle chaincode querycommitted --channelID channeltwo --name mycc --output json
Although everything is largely identical (we made that), they are on different channels.
Test chaincode
Invoke on channelone on either terminal
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile $ORDERER_CA -C channelone -n mycc --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["set","name","Alice"]}'
Query on channelone from both Org1 and Org2
peer chaincode query -C channelone -n mycc -c '{"Args":["get","name"]}'
We see the asset “name” found in channelone.
Query on channeltwo from both Org1 and Org2
peer chaincode query -C channeltwo -n mycc -c '{"Args":["get","name"]}'
We see the asset “name” not found in channeltwo.
Invoke on channeltwo on either terminal
For demonstration we invoke sacc with the same asset “name” with a different state value.
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile $ORDERER_CA -C channeltwo -n mycc --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["set","name","Bob"]}'
Query the same asset “name” on both channels, both Org1 and Org2
peer chaincode query -C channelone -n mycc -c '{"Args":["get","name"]}'peer chaincode query -C channeltwo -n mycc -c '{"Args":["get","name"]}'
We see that the ledger for each channel is operating separately, even though the same chaincode is deployed and the same asset name is used.
Observation
Chaincode container
Similar to the baseline setup, there are two chaincode containers running, one for each peer. We see that as long as the chaincode name remains the same, the same chaincode container is processing endorsement request and/or query, no matter which channels it is specified.
Worldstate database
From the worldstate database we see two different databases are handling the two channels, even the chaincode name is the same.
Clean up deployment
./network.sh down
Same chaincode deployed twice in a channel
Here we will deploy sacc twice in mychannel. To differentiate the two deployments, we are using different chaincode names: mycc1 and mycc2.
Note: We have to specify different names for chaincodes if they are from the same source. If we are using the same name, we need version to distinguish them. But we can only specify one version in the chaincode definition during approving and committing. This is not what we are demonstrating in this setup.
Bring up Test Network and mychannel
cd fabric-samples/test-network
./network.sh up createChannel -s couchdb
Deploy chaincode
./network.sh deployCC -ccn mycc1 -ccp ../chaincode/sacc./network.sh deployCC -ccn mycc2 -ccp ../chaincode/sacc
After the script is completely executed, we can test the chaincode functions.
Test chaincode
For both chaincodes, invoke from either one terminal
Again we are using the same asset name “name” and different values to different chaincodes.
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile $ORDERER_CA -C mychannel -n mycc1 --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["set","name","Alice"]}'peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile $ORDERER_CA -C mychannel -n mycc2 --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["set","name","Bob"]}'
Query both chaincodes
peer chaincode query -C mychannel -n mycc1 -c '{"Args":["get","name"]}'peer chaincode query -C mychannel -n mycc2 -c '{"Args":["get","name"]}'
Again we see state is handled separately in different chaincodes.
Observation
Chaincode container
Now we see there are two different chaincode containers for each peer, that means, there are totally four containers. It is because the chaincode name is different, and so is the package ID, despite the fact that both are from the same source.
Worldstate database
From the worldstate database we see two different databases are handling the two chaincodes in the same channel.
Clean up deployment
./network.sh down
Summary
The purpose of this article is to help understanding some internal operation of Hyperledger Fabric when handling channel and chaincode. With fabric v2.2 we can easily build an environment to test our objectives. It also shows how easy it is to use script to deploy and test chaincode in the Test Network. Hope you learn something about Hyperledger Fabric and make good use of the script.