Test Network Script Walk-Through
By: Kc Tam
Tags: Hyperledger Fabric, Tutorial, Test Network, Fabric V2

Introduction

I began my learning journey of Hyperledger Fabric by studying First Network two years ago. It was a very good sample setup from which I have learnt a lot about this platform. I know many people are taking a similar path. This article written more than a year ago is still one of my most-read articles.

Fabric v2.0 came with a new sample network: Test Network. In a previous article I have already highlighted the difference between these two sample networks. Here I come up this article just about Test Network. My previous work on First Network was showing a step-by-step execution of script byfn.sh . I took a similar approach in this article as another step-by-step manual execution of script network.sh . During the process I will make some explanation and discussion on relevant items.

I wish this can also provide you a more complete picture of Test Network. Through this you can grasp some basic operation of bringing up a consortium network and deploying chaincode in Fabric v2.0.

Overview: Test Network

Without repeating what is in previous article, here is some quick information about Test Network,

A three-organization setup

One orderer organization: example.com , with one orderer

, with one orderer Two peer organizations: org1.example.com and org2.example.com , each of which has one peer (peer0)

and , each of which has one peer (peer0) One channel mychannel is created and joined by peers of both peer organizations.

Here is how Test Network looks like.

Test Network comes with a script network.sh . And here are commands

network.sh up : bring up network components, one orderer and one peer for each peer organization.

: bring up network components, one orderer and one peer for each peer organization. network.sh up createChannel : bring up network components, create mychannel and have all peers join mychannel.

: bring up network components, create mychannel and have all peers join mychannel. network.sh createChannel : create mychannel and have all peers join mychannel. applicable after network.sh up is executed.

: create mychannel and have all peers join mychannel. applicable after is executed. network.sh deployCC : deploy and interact with Fabcar chaincode. executable after channel is created with network.sh up createChannel or network.sh createChannel .

Note that the crypto material by default is generated through cryptogen . Test Network also supports another way to bring up crypto material using Fabric CA Server. In this article I am using cryptogen . For information about using Fabric CA Server you can refer to my another article.

While network.sh comes with several commands as shown above, I break the execution of network.sh script into several steps, showing how things are done manually. Here are the steps:

Generate Crypto Material with cryptogen Generate Consortium Genesis Block Bring Up Test Network Components Join Peers of Both Organizations to mychannel Deploy Fabric on mychannel Interact with Fabric Chaincode Functions

Demonstration

Step 1–3 is equivalent to executing command ./network.sh up .

Step 1: Generate Crypto Material with cryptogen

Configuration files

We generate crypto material using cryptogen in this tutorial. The configuration file tells cryptogen what type of components and users are needed. In Test Network there are three cryptogen configuration files inside organizations/cryptogen/ .

For orderer organization, organizations/cryptogen/crypto-config-orderer.yaml

For peer organization Org1, organizations/cryptogen/crypto-config-org1.yaml

For peer organization Org2, organizations/cryptogen/crypto-config-org2.yaml

Binary tools

All the tools and commands ( cryptgen , configtxgen , peer , etc.) are stored in fabric-samples/bin/ . Update the PATH to include this directory.

cd fabric-samples/test-network

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

Crypto material generation for all organizations

The resulting materials are all placed inside organizations/ . Orderer organization is stored in organizations/ordererOrganizations/ , and peer organizations in organizations/peerOrganizations/ .

cryptogen generate --config=./organizations/cryptogen/crypto-config-orderer.yaml --output="organizations" cryptogen generate --config=./organizations/cryptogen/crypto-config-org1.yaml --output="organizations" cryptogen generate --config=./organizations/cryptogen/crypto-config-org2.yaml --output="organizations"

Crypto material stored inside organizations/

Crypto material in network components

These crypto materials generated will be placed into the corresponding network components. It is done through docker compose file. Here is the docker/docker-compose-test-net.yaml .

Crypto materials are mapped to each component (container) as volumes

Step 2: Generate Consortium Genesis Block

Configuration file

The consortium configuration is in configtx/configtx.yaml . Here we only show the portion relevant to the consortium genesis block.

Profile for generating consortium genesis block

Consortium genesis block generation

Here is how we generate this consortium genesis block. We specify the profile TwoOrgsOrdererGenesis. The result is kept in system-genesis-block/ .

export FABRIC_CFG_PATH=${PWD}/configtx configtxgen -profile TwoOrgsOrdererGenesis -channelID system-channel -outputBlock ./system-genesis-block/genesis.block

Consortium genesis block in orderer

This consortium genesis block only appears in orderers. In Test Network, it only appears in orderer.example.com. Here is an extract from docker/docker-compose-test-net.yaml .

Consortium genesis block is mapped to orderer.

Step 3: Bring Up Test Network Components

Configuration file

Use docker-compose to bring up the three network components of Test Network. The docker compose configuration file to be used is docker/docker-compose-test-net.yaml .

Three components (collapsed for better display) defined in docker compose file.

Bring up all network components

IMAGE_TAG=latest docker-compose -f docker/docker-compose-test-net.yaml up -d

Here is how the three containers running in localhost.

Three containers are running in localhost with docker compose.

Step 4 is equivalent to executing command ./network.sh createChannel .

Step 4: Join Peers of Both Organizations to mychannel

In Test Network, creating and joining mychannel involves three steps

use configtxgen to generate transactions for mychannel, including configuration transaction and anchor peer update transactions prepare a channel genesis block for mychannel, which is a file join channel using the channel genesis block file

Note: Don’t mix up with this channel genesis block file with the consortium genesis block file in Step 2. Consortium genesis block file contains the setup of the whole consortium of member organizations. A channel is a subset (or a whole set) of the consortium. There can be more than one channels defined in a consortium, to reflect the real business relationship and logic. Each channel begins with a channel genesis block file. In Test Network, we only have one channel, mychannel, and all consortium members, org1 and org2, join this mychannel.

Unlike First Network, Test Network does not come with CLI container. The channel artifacts are generated and stored in localhost, and peer commands are issued directly from localhost.

Generate channel artifacts

Channel artifacts for mychannel includes a configuration transaction and anchor peer update transaction for each peer organization. Note that we are using the profile TwoOrgsChannel specified in configtx/configtx.yaml .

mkdir -p channel-artifacts configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/mychannel.tx -channelID mychannel configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP

The material generated are all kept in channel-artifacts/ .

Channel genesis block file

The channel genesis block file, block #0 for mychannel, is generated using configuration transaction generated previously.

As we need TLS CA certificates when reaching components, we can define these environment variables for tidy display.

export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem export PEER0_ORG1_CA=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt export PEER0_ORG2_CA=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt

We target this peer command from peer0.org1.example.com . Note the variables (in italic) applied in the beginning of this command. We will use this to specify where the peer command is issued.

export FABRIC_CFG_PATH=$PWD/../config/ CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org1MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp CORE_PEER_ADDRESS=localhost:7051 peer channel create -o localhost:7050 -c mychannel --ordererTLSHostnameOverride orderer.example.com -f ./channel-artifacts/mychannel.tx --outputBlock ./channel-artifacts/mychannel.block --tls true --cafile $ORDERER_CA

We specify the following in this peer command

localhost:7050 as orderer. Use ordererTLSHostnameOverride to override with name orderer.example.com. Plus TLS material (orderer CA)

as orderer. Use to override with name orderer.example.com. Plus TLS material (orderer CA) channel name mychannel

channel configuration file ./channel-artifacts/mychannel.tx

output channel genesis block as a file: ./channel-artifacts/mychannel.block .

Now we have the file mychannel.block . We will use it to join peers of both peer organizations.

Join peers to mychannel

Peers of both organizations join mychannel using the block file.

CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org1MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp CORE_PEER_ADDRESS=localhost:7051 peer channel join -b ./channel-artifacts/mychannel.block CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=localhost:9051 peer channel join -b ./channel-artifacts/mychannel.block

And both share the same blockchain, with height 1 (only block #0 exists).

Update anchor peers

Apply the update transaction.

CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org1MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp CORE_PEER_ADDRESS=localhost:7051 peer channel update -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx --tls true --cafile $ORDERER_CA CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=localhost:9051 peer channel update -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c mychannel -f ./channel-artifacts/Org2MSPanchors.tx --tls true --cafile $ORDERER_CA

We specify the following in this peer command

localhost:7050 as orderer. Use ordererTLSHostnameOverride to override with name orderer.example.com. Plus TLS material (orderer CA)

as orderer. Use to override with name orderer.example.com. Plus TLS material (orderer CA) channel name mychannel

update configuration file ./channel-artifacts/OrgnMSPanchors.tx, which we generate in the beginning of this step

Check the blockchain of both peers: now it should be of height 3 (a new block is committed after each anchor peer update). Blockchain content (hash) in both peers remains identical.

With this, mychannel is created and joined by peers of all organizations.

Step 5–6 is equivalent to executing command ./network.sh deployCC .

Step 5: Deploy Fabcar on mychannel

We follow the process of lifecycle chaincode to deploy Fabcar on mychannel. In Fabric v2.0, chaincode deployment is done using lifecycle chaincode. For more detail about lifecycle chaincode, you can refer to my previous article.

Package Fabcar chaincode

We first install dependency on the chaincode if not done yet.

# install dependence if not done before

pushd ../chaincode/fabcar/go

GO111MODULE=on go mod vendor

popd CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org1MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp CORE_PEER_ADDRESS=localhost:7051 peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/go/ --label fabcar_1

The result is the chaincode package file stored locally.

Chaincode package file is created.

Install Fabcar to peers of both organizations

CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org1MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp CORE_PEER_ADDRESS=localhost:7051 peer lifecycle chaincode install fabcar.tar.gz CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=localhost:9051 peer lifecycle chaincode install fabcar.tar.gz

We will get back package ID after chaincode package installation. Note that they are the same in this tutorial, but it is not necessary as v2.0 this process is done by each organizations separately. There are chances that individual organization extends chaincode. See this article for more detail.

We can check if the installation is successful.

Chaincode package is installed on both peers.

Meanwhile, a new chaincode container image is built, one for each peer. They are not instantiated yet (not running as a docker container yet). This is also why it takes some time as images are being built.

Chaincode container images are built, but no chaincode containers are instantiated yet.

For those who are interested in the chaincode container in Fabric v2.0, you can refer to my another article about this.

It is how the setup looks like. Two chaincode container images are built, but not running yet as container.

Two chaincode container images built in localhost.

Approve chaincode definition for both organizations

We first approve for Org1.

CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org1MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp CORE_PEER_ADDRESS=localhost:7051 peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile $ORDERER_CA --channelID mychannel --name fabcar --version 1 --init-required --package-id fabcar_1:2939b5f219f516bc94df2253438bad440d6a91432f6b5bbd17ef05d2228766e8 --sequence 1

With this, we can check readiness of chaincode commit from both organizations. The approval is recorded and both organizations see the same result.

Both peers see the same result: only Org1 has approved chaincode definition.

Now we approve for Org2.

CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=localhost:9051 peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile $ORDERER_CA --channelID mychannel --name fabcar --version 1 --init-required --package-id fabcar_1:2939b5f219f516bc94df2253438bad440d6a91432f6b5bbd17ef05d2228766e8 --sequence 1

And check again the readiness of chaincode commit. Now both organizations approve the chaincode definition.

Both peers see the same result: both Org1 and Org2 have approved chaincode definition.

Commit chaincode definition on mychannel

As this satisfies the lifecycle endorsement policy (majority), the chaincode definition can be committed to mychannel.

CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org1MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp CORE_PEER_ADDRESS=localhost:7051 peer lifecycle chaincode commit -o localhost:7050 --tls true --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses localhost:9051 --tlsRootCertFiles $PEER0_ORG2_CA --channelID mychannel --name fabcar --version 1 --sequence 1 --init-required

And we can check the committed chaincode.

Chaincode is committed and ready for use.

And we see the chaincode containers for both peers are instantiated.

Two chaincode containers, instantiated from chaincode container images, are now running.

Now there are total five containers running in localhost, with the two new chaincode containers, one for each peer.

Chaincode container instantiated from the images after chaincode is committed

Now the chaincode is ready for use.

Step 6: Interact with Fabcar Chaincode Functions

Invoke Chaincode Function

We invoke initLedger() functions, specifying peer of both organizations as endorsers. (Note: in configtx/configtx.yaml , endorsement policy by default is majority. Therefore both organizations are required.)

CORE_PEER_TLS_ENABLED=true CORE_PEER_LOCALMSPID="Org1MSP" CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp CORE_PEER_ADDRESS=localhost:7051 peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile $ORDERER_CA -C mychannel -n fabcar --peerAddresses localhost:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses localhost:9051 --tlsRootCertFiles $PEER0_ORG2_CA --isInit -c '{"function":"initLedger","Args":[]}'

Query Chaincode Function

Then we query function queryAllCars() from both peers.

Both peers return the same result: the chaincode is running correctly.

Summary

We have walked through the script network.sh for Test Network, showing how to prepare crypto material and channel artifacts for a simple three-organization network. We also deploy Fabcar chaincode using lifecycle chaincode and after deployment, invoked chaincode functions to check if everything is working well.

Hope this tutorial helps you understand Test Network more, and you can use it for testing your own network setup or chaincode development.