Understanding First Network Example in Hyperledger Fabric (Part 2)

KC Tam
10 min readSep 30, 2018

--

This is the second part of the article. In previous part we have examined the First Network from Hyperledger Fabric tutorials, through the script byfn.sh. In this part we repeat the same steps using the command line instead of this script. As previously, we will keep checking the process behind to get a better understanding on the whole flow.

Note: Since 1.4, there is a change on the port of every peer in First Network (see the file in first-network/base/docker-compose-base.yaml. This document is updated to follow the change. The command in each step is modified, but the screen capture still keeps the old information. So simply follow the command line.

First Network using Command Line

In this section we will do the same thing that byfn.sh performs, but walk through the whole process using Command Line Interface (CLI) instead of running this script.

The steps we are going through are,

  1. Generation of crypto/certificate using cryptogen
  2. Generation of Configuration Transaction using configtxgen
  3. Bring up the nodes based on what is defined in docker-compose file
  4. Use CLI to setup the First Network
  5. Use CLI to install and instantiate the chaincode
  6. Use CLI to invoke the chaincode
  7. Tear down all the setup

Preparation

As we may have something left after our previous setting, check the following.

  • no crypto-config directory in first-network
  • empty in channel-artifacts directory (but keep this directory)
  • no docker containers are running
// remove crypto-config directory
$ cd first-network
$ rm -rf crypto-config/
// empty channel-artifacts directory
$ cd first-network/channel-artifacts
$ rm *
// kill and remove docker containers
$ docker kill $(docker ps -aq) // return error if no running containers
$ docker rm $(docker ps -aq) // return error if no containers
$ docker ps // see no running containers

Step 1: Generation of crypto / certificate

The tool for crypto generation is called cryptogen, which comes as binary tool when first installing the fabric-samples.

We use the crypto-config.yaml to define the required setup. Here is the YAML file.

OrdererOrgs:
- Name: Orderer
Domain: example.com
Specs:
- Hostname: orderer
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

The YAML file has defined the required crypto and certificates for the First Network setup. They are,

Each Node and Admin / Users will have its own signing key and certificate after generation. The directory created is called crypto-config and all of them are stored there.

$ cd first-network
$ ../bin/cryptogen generate --config=./crypto-config.yaml

We see a new directory crypto-config is created, and inside there are directories corresponding to the table shown above. You can browse the sub-directories in each directory and see the directory hierarchy.

Step 2: Generation of Configuration Transaction

The tool for configuration transaction generation is called configtxgen, which also comes as binary tool when first installing the fabric-samples.

The artifacts to be generated in this step are,

  • orderer genesis block
  • channel configuration transaction
  • one anchor peer transaction for each peer organizations (total 2 in our example)

When we use command configtxgen, the configtx.yaml file is referred. Inside this file, the Profiles are where we are interested.

… <above omitted>
Profiles:
TwoOrgsOrdererGenesis:
Capabilities:
<<: *ChannelCapabilities
Orderer:
<<: *OrdererDefaults
Organizations:
- *OrdererOrg
Capabilities:
<<: *OrdererCapabilities
Consortiums:
SampleConsortium:
Organizations:
- *Org1
- *Org2
TwoOrgsChannel:
Consortium: SampleConsortium
Application:
<<: *ApplicationDefaults
Organizations:
- *Org1
- *Org2
Capabilities:
<<: *ApplicationCapabilities

The two profiles defined here are,

  • TwoOrgsOrdererGenesis
  • TwoOrgsChannel

all contents inside the profile section are defined at the upper part of this file (omitted here). We will specify the profile when creating artifacts.

Four files are to be generated and stored in channel-artifacts directory. They are,

  • genesis.block
  • channel.tx
  • Org1MSPanchors.tx
  • Org2MSPanchors.tx

Command to generate the genesis block.

$ export FABRIC_CFG_PATH=$PWD
$ ../bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block

Command to generate the channel transaction (we need to specify the channel name mychannel here).

$ export CHANNEL_NAME=mychannel
$ ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME

Command to generate the transaction for the Anchor Peer in each Peer Organizations

$ ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
$ ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP

After all commands are issued, there are four files created inside channel-artifacts directory.

Step 3: Bring up the nodes according to docker-compose file

With the crypto / certificates and the configuration transaction generated, we are now ready to bring up the First Network.

As mentioned above the First Network is composed of nodes which are running as containers in local host. Docker Compose is the tool to bring up the required containers.

Inside first-network directory there are several docker-compose configuration files. Here we are using docker-compose-cli.yaml.

If we take a look inside docker-compose-cli.yaml, we see docker-compose will bring up total six containers. Besides the five nodes, we also have a CLI container, which is where we issue commands to the First Network later.

Command to bring up the containers

$ docker-compose -f docker-compose-cli.yaml up -d

If we check the running containers before and after the docker-compose commands (docker ps), we will see now six containers are up and running.

Now the infrastructure of First Network (i.e. nodes) is up and running. We are ready to go for configuring the First Network.

Step 4: Use CLI to setup the First Network

From now on, we are going to build and interact with the First Network. All commands will be issued inside CLI when configuring all components for First Network.

Access shell of CLI container from localhost is,

$ docker exec -it cli bash

Note the command prompt is #. And at any time you can quit the CLI container with exit.

Important Note: the CLI tool has default setting on Peer0 of Org1 node. Which means, without specifying environment variables, the command issued is applied to peer0.org1. To issue commands with other peers, we will precede the environment variables in front of it. We will highlight this when we need to do so.

First, go to CLI container.

$ docker exec -it cli bash 
#

Then we create channel, using the channel.tx we created in previous section (already copied to the CLI container when the container is instantiated).

# export CHANNEL_NAME=mychannel
# peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --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

Note that in each command is issued from the Orderer when channel is created.

A file mychannel.block is created. And the peers are joining the channel with this mychannel.block.

After the channel mychannel is created, we can join the peers to the channel.

You may find some comands are extremely long. The reason behind is that the CLI has preset the target on peer0.org1 (through environment variables). If command is issued without changing any variables, it is applied to peer0.org1.

However, if you need to issue command to other nodes, what you need is to specify the variables before the command. The structure is

# <overriding variables> <command>

Here are the overriding variables for all nodes

This table is not updated on container port of each peer per 1.4 change. Right port is specified in commands below.

For peer0.org1 (the default node)

# peer channel join -b mychannel.block

For peer0.org2, we need to specify the environment variables.

# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" 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 peer channel join -b mychannel.block

For peer1.org1,

# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp CORE_PEER_ADDRESS=peer1.org1.example.com:8051 CORE_PEER_LOCALMSPID="Org1MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt peer channel join -b mychannel.block

For peer1.org2,

# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer1.org2.example.com:10051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt peer channel join -b mychannel.block

Here is how to join the four peers to the channel using mychannel.block.

The last step is to update the Anchor Peer on each organization. Here we use the files we created in previous section (Org1MSPanchor.tx and Org2MSPanchor.tx) and apply them to Peer0 of both Org1 and Org2.

For peer0.org1 (the default node),

# peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --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

For peer0.org2, we need to specify environment variables as before,

# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" 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 peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --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

Step 5: Use CLI to install and instantiate the chaincode

There are two steps here.

First we install the chaincode to the peers. In our case, we first install it on both Peer0 Org1 and Peer0 Org2. The chaincode is specified in -p option in the command, and the name of chaincode is mycc.

On peer0.org1 (default node),

# peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/

On peer0.org2,

# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" 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 peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/

After we install the chaincode on these two nodes, let’s take a look on the running containers (use another terminal).

No new containers are running. Installation chaincode does not create new containers.

The second step is to instantiate the chaincode installed from peer0.org2. Note the environment variables we specify here.

# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" 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 peer chaincode instantiate -o orderer.example.com:7050 --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 -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')"

When instantiating the chaincode, we need to specify

  • the required arguments (-c): a JSON to initialize a with value 100, b with 200 (the required argument is defined by chaincode itself, which is not covered in this article)
  • the endorsing policy (-P): here for any invocation, we need both organization to endorse before the transaction is accepted. Note the AND inside the policy

If we check the containers, we see a new container is running, which is the chaincode instantiated in peer0.org2.

So after instantiating the chaincode from peer0.org2, we see one more container running, pairing the peer0.org2.

Now we query the value a from peer0.org1. No envrionment variables are needed as it is the default node.

# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'

If you notice it takes some time to get the result. If we take a look on the container, we see one more container running, the chaincode for peer0.org1.

The query on peer0.org1 causes the chaincode container instantiated. Nevertheless, the result is correct, the value of a is 100.

So if we query a node which the chaincode is not running (yet), a new container is up and running, pairing that node (here it is peer0.org1).

Step 6: Use CLI to invoke the chaincode

We now invoke the chaincode (equivalent to issue a transaction) from peer0.org1.

The command to invoke the chaincode with arguments (in this example we move 10 from a to b) is,

# peer chaincode invoke -o orderer.example.com:7050 --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 -C $CHANNEL_NAME -n mycc --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 --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}'

Note there are many parameters passed in this command. We need to specify the peer addresses (peer0.org1 and peer0.org2) and provide the root certificate.

For sake of demonstration (and to align with what byfn.sh has done) we install the chaincode on peer1.org2. And then query from peer1.org2 for the latest value of a.

Install chaincode on peer1.org2,

# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer1.org2.example.com:10051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/

Now we query the value a from peer1.org2,

# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer1.org2.example.com:10051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'

Again it takes some time (we can expect a new container is running, pairing peer1.org2). First we see the result is 90, which is a correct one after 10 is removed from 100.

We see one more container is running, pairing peer1.org2,

This is the same setup after we run byfn.sh in previous part of article.

Step 7: Tear down all the setup

Remember we build this infrastructure up using docker-compose and the configuration file docker-compose-cli.yaml. We will tear the First Network down using similar command.

In local host, (use exit the CLI shell back to local host)

# exit
$ docker-compose -f docker-compose-cli.yaml down

Note that the docker-compose only tears down those containers specified in docker-compose-cli.yaml file. The three chaincode containers are now stopped but not removed yet. We can use command to remove everything.

$ docker rm $(docker ps -aq)

Summary

Here we have completed all the steps in shell script byfn.sh using command line interface. We examined step-by-step and now have some first understanding steps like setting up a network, and interacting with chaincode such as installation, instantiation, query and invocation. We also notice new container running when chaincode is instantiated and queried.

--

--