Skcript Technologies Private Limited

← All Articles

Setting up a Blockchain Business Network With Hyperledger Fabric & Composer Running in Multiple Physical Machine

— Written by

Setting up a Blockchain Business Network With Hyperledger Fabric & Composer Running in Multiple Physical Machine

In my previous article, I wrote about how to setup the Hyperledger Fabric Composer Business Network with a basic structure explaining each components of the architecture. This article is focused on how to setup a network with multiple peers running in different physical machines.

The Architecture

Hyperledger Fabric has a set of components each with its own roles and functionalities. Each of these will be running on it’s own Docker instances and are configured to work together. These Docker instances even when running on multiple physical machines, can still communicate with each other. That’s essentially the crux of how a blockchain runs on several physical machines.

Terms

Certificate Authority

The certificate authority is responsible for handling all the access control logic, issuing the identities and permission for the users in the Hyperledger blockchain network.

Orderer

In order to keep the entire network in a synchronized state, the orderer is used. Whenever a new transaction is to be committed, the orderer is the one informing all the peers about the transaction. A network can have multiple orderers, also it’s advised in order to maintain less faults.

Peers

Only peers are allowed to commit transactions in the business network. Also each peer has its own copy of the entire world state. It’s connected with CouchDB instances which acts as the database. An organisation can have multiple peers and one or more anchor peer will be used to communicate with other organisations.

In this example, we’ll be having 1 CA, 1 Orderer, and 3 Peers. With 2 Peers running in the first machine, and the other in a second machine.

Prerequisites

  • Install Docker
  • Install Composer
  • Install Fabric Images (1.0.4)
  • Install Fabric Tools (Use this)

Setting Up

Since all the components are running inside individual Docker instances, we can easily configure them to run separately.

In this example, I’ll be taking the fabric-dev-serverand modify it to run on multiple machines. This is mainly focused towards easier understanding and to use it like a boilerplate.

Here since we’re using only the hlfv1 we’re removing the hlfv11 folder and bringing all the contents of hlfv1 outside.

The Folder Structure

This is how your codebase should look,

Here if you notice, there are three new files docker-compose-peer2.yml, startFabric-Peer2.sh and stopFabric.sh. As the name implies these are related to the third peer which we will be running on a separate machine.

Peer Configurations

The default dev server comes with configuration for running one Peer. So, the certificates are created correspondingly. Since we have three peers in total, we need to generate certificates for all the three.

If you’ve installed the fabric tools with the above mentioned script, you’ll have configtxgen and cryptogen in your system. We’ll be using this to generate the certificates for our peers, and CA.

In cypto-config.yaml change the count under PeerOrgs → Template → Count to number of peers you want. In our case it is 3. Thus the contents of crypto-config.yaml looks like below.

OrdererOrgs:

- Name: Orderer

  Domain: example.com

  Specs:

    - Hostname: orderer

PeerOrgs:

- Name: Org1

  Domain: org1.example.com

  Template:

    Count: 3

  Users:

    Count: 0

And the configtx.yaml looks like,

---

Profiles:



    ComposerOrdererGenesis:

        Orderer:

            <<: *OrdererDefaults

            Organizations:

                - *OrdererOrg

        Consortiums:

            ComposerConsortium:

                Organizations:

                    - *Org1

    ComposerChannel:

        Consortium: ComposerConsortium

        Application:

            <<: *ApplicationDefaults

            Organizations:

                - *Org1



Organizations:



    - &OrdererOrg

        Name: OrdererOrg

        ID: OrdererMSP

        MSPDir: crypto-config/ordererOrganizations/example.com/msp

        AdminPrincipal: Role.MEMBER



    - &Org1

        Name: Org1

        ID: Org1MSP

        MSPDir: crypto-config/peerOrganizations/org1.example.com/msp

        AdminPrincipal: Role.MEMBER

        AnchorPeers:

            - Host: peer0.org1.example.com

              Port: 7051



Orderer: &OrdererDefaults

    OrdererType: solo



    Addresses:

        - orderer.example.com:7050

    BatchTimeout: 2s

    BatchSize:

        MaxMessageCount: 10

        AbsoluteMaxBytes: 98 MB

        PreferredMaxBytes: 512 KB

        

    Kafka:

        Brokers:

            - 127.0.0.1:9092



    Organizations:



Application: &ApplicationDefaults

    Organizations:

Once you made the modifications, run the following inside the composer folder in order to create the certificates for all the peers.

cd "$(dirname "$0")"

cryptogen generate --config=./crypto-config.yaml

export FABRIC_CFG_PATH=$PWD

configtxgen -profile ComposerOrdererGenesis -outputBlock ./composer-genesis.block

configtxgen -profile ComposerChannel -outputCreateChannelTx ./composer-channel.tx -channelID composerchannel

This creates all the certificates and the key under crypto-config folder. We will be using this to configure our Docker image’s environment variables.

Configuring Docker Services

In the docker-compose.yml we have added the following services.

  • ca.org1.example.com
  • orderer.example.com
  • peer0.org1.example.com
  • couchdb
  • peer1.org1.example.com
  • couchdb1

Here the peer0.org1.example.com uses couchdb as the world state database and peer1.org1.example.com uses couchdb1 as world state database.

In order to configure the Certificate Authority, we’ll be using the certificates that have been generated newly. In the command section of ca.org1.example.com make sure to use the proper private key file. It will be located under composer/crypto-config/peerOrganizations/

org1.example.com/ca/ Once you’ve updated it you’re good to go.

version: '2'

services:

ca.org1.example.com:

image: hyperledger/fabric-ca:$ARCH-1.0.4

environment:

  - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server

  - FABRIC_CA_SERVER_CA_NAME=ca.org1.example.com

#      - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/org1.example.com-cert.pem

#      - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/a22daf356b2aab5792ea53e35f66fccef1d7f1aa2b3a2b92dbfbf96a448ea26a_sk



ports:

  - "7054:7054"

command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/d4e3285d47260c640643feda80dd0f4ae76378f0047f1cfba3efca6555600b43_sk -b admin:adminpw -d'

volumes:

  - ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config

container_name: ca.org1.example.com



orderer.example.com:

container_name: orderer.example.com

image: hyperledger/fabric-orderer:$ARCH-1.0.4

environment:

  - ORDERER_GENERAL_LOGLEVEL=debug

  - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0

  - ORDERER_GENERAL_GENESISMETHOD=file

  - ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/composer-genesis.block

  - ORDERER_GENERAL_LOCALMSPID=OrdererMSP

  - ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/msp/orderer/msp

working_dir: /opt/gopath/src/github.com/hyperledger/fabric

command: orderer

ports:

  - 7050:7050

volumes:

    - ./:/etc/hyperledger/configtx

    - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/etc/hyperledger/msp/orderer/msp



peer0.org1.example.com:

container_name: peer0.org1.example.com

image: hyperledger/fabric-peer:$ARCH-1.0.4

environment:

  - CORE_LOGGING_PEER=debug

  - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG

  - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock

  - CORE_PEER_ID=peer0.org1.example.com

  - CORE_PEER_ADDRESS=peer0.org1.example.com:7051

  - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=composer_default

  - CORE_PEER_LOCALMSPID=Org1MSP

  - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/peer/msp

  - CORE_LEDGER_STATE_STATEDATABASE=CouchDB

  - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984

working_dir: /opt/gopath/src/github.com/hyperledger/fabric

command: peer node start --peer-defaultchain=false

ports:

  - 7051:7051

  - 7053:7053

volumes:

    - /var/run/:/host/var/run/

    - ./:/etc/hyperledger/configtx

    - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/peer/msp

    - ./crypto-config/peerOrganizations/org1.example.com/users:/etc/hyperledger/msp/users

depends_on:

  - orderer.example.com

  - couchdb


couchdb:

container_name: couchdb

image: hyperledger/fabric-couchdb:$ARCH-1.0.4

ports:

  - 5984:5984

environment:

  DB_URL: http://localhost:5984/member_db


peer1.org1.example.com:

container_name: peer1.org1.example.com

image: hyperledger/fabric-peer:$ARCH-1.0.4

environment:

  - CORE_LOGGING_PEER=debug

  - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG

  - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock

  - CORE_PEER_ID=peer1.org1.example.com

  - CORE_PEER_ADDRESS=peer1.org1.example.com:7051

  - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=composer_default

  - CORE_PEER_LOCALMSPID=Org1MSP

  - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/peer/msp

  - CORE_LEDGER_STATE_STATEDATABASE=CouchDB

  - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb1:5984

working_dir: /opt/gopath/src/github.com/hyperledger/fabric

command: peer node start --peer-defaultchain=false

ports:

  - 8051:7051

  - 8053:7053

volumes:

    - /var/run/:/host/var/run/

    - ./:/etc/hyperledger/configtx

    - ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/peer/msp

    - ./crypto-config/peerOrganizations/org1.example.com/users:/etc/hyperledger/msp/users

depends_on:

  - orderer.example.com

  - couchdb1



couchdb1:

container_name: couchdb1

image: hyperledger/fabric-couchdb:$ARCH-1.0.4

ports:

  - 6984:5984

environment:

  DB_URL: http://localhost:6984/member_db

Similarly we’ll create a second docker compose file for Peer 2.

version: '2'

services:

  peer2.org1.example.com:

    container_name: peer2.org1.example.com

    image: hyperledger/fabric-peer:$ARCH-1.0.4

    environment:

      - CORE_LOGGING_PEER=debug

      - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG

      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock

      - CORE_PEER_ID=peer2.org1.example.com

      - CORE_PEER_ADDRESS=peer2.org1.example.com:7051

      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=composer_default

      - CORE_PEER_LOCALMSPID=Org1MSP

      - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/peer/msp

      - CORE_LEDGER_STATE_STATEDATABASE=CouchDB

      - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb2:5984

    working_dir: /opt/gopath/src/github.com/hyperledger/fabric

    command: peer node start --peer-defaultchain=false

    ports:

      - 9051:7051

      - 9053:7053

    volumes:

        - /var/run/:/host/var/run/

        - ./:/etc/hyperledger/configtx

        - ./crypto-config/peerOrganizations/org1.example.com/peers/peer2.org1.example.com/msp:/etc/hyperledger/peer/msp

        - ./crypto-config/peerOrganizations/org1.example.com/users:/etc/hyperledger/msp/users

    depends_on:

      - couchdb2



  couchdb2:

    container_name: couchdb2

    image: hyperledger/fabric-couchdb:$ARCH-1.0.4

    ports:

      - 7984:5984

    environment:

      DB_URL: http://localhost:7984/member_db

Configuring the scripts

Now we’re ready to run the Fabric network. We’ll be using the fabric-dev-server’s scripts as the base script with a few modifications as mentioned below.

In the startFabric.sh file, by default the configuration for the first peer (peer0.org1.example.com) to join the channel is provided. Now we need to join the second peer (peer1.org1.example.com) to the same channel.

In order to do that we need to fetch the channel block in the second peer and then use that .block file to join the peer. The following code is used to join the peers to the channel in the network.

# Create the channel

docker exec peer0.org1.example.com peer channel create -o orderer.example.com:7050 -c composerchannel -f /etc/hyperledger/configtx/composer-channel.tx


# Join peer0.org1.example.com to the channel.

docker exec -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer0.org1.example.com peer channel join -b composerchannel.block


# Create the channel

docker exec -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer1.org1.example.com peer channel fetch config -o orderer.example.com:7050 -c composerchannel

# docker exec peer1.org1.example.com peer channel create -o orderer.example.com:7050 -c composerchannel -f /etc/hyperledger/configtx/composer-channel.tx


# Join peer1.org1.example.com to the channel.

docker exec -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer1.org1.example.com peer channel join -b composerchannel_config.block

In the second machine, we’ll be using the same concept of fetching the channel block and joining the channel with the block file.

docker exec -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer2.org1.example.com peer channel fetch config -o orderer.example.com:7050 -c composerchannel

docker exec -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer2.org1.example.com peer channel join -b composerchannel_config.block

Peer Admin Card Creation

Now we need to update the script to create the peer admin card for the network. With the default script createPeerAdminCard.sh we’ll add update the connection profile configuration to add the new peers.

cat << EOF > /tmp/.connection.json

{

    "name": "hlfv1",

    "type": "hlfv1",

    "orderers": \[

       { "url" : "grpc://localhost:7050" }

    \],

    "ca": { 

        "url": "http://localhost:7054", 

        "name": "ca.org1.example.com"

    },

    "peers": \[

        {

            "requestURL": "grpc://localhost:7051",

            "eventURL": "grpc://localhost:7053"

        }, {

            "requestURL": "grpc://localhost:8051",

            "eventURL": "grpc://localhost:8053"

        }, {

            "requestURL": "grpc://<Peer2-IP>:9051",

            "eventURL": "grpc://<Peer2-IP>:9053"

        }

    \],

    "channel": "composerchannel",

    "mspID": "Org1MSP",

    "timeout": 300

}

Also you need to update the PRIVATE_KEY path with the corresponding path to the private key of map keystore.

PRIVATE_KEY="${DIR}"/composer/crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/keystore/<PRIVATE_KEY_NAME>

This is how your script should look,

#!/bin/bash



# Exit on first error

set -e

# Grab the current directory

DIR="$( cd "$( dirname "${BASH_SOURCE\[0\]}" )" && pwd )"



echo

# check that the composer command exists at a version >v0.14

if hash composer 2>/dev/null; then

    composer --version | awk -F. '{if ($2<15) exit 1}'

    if \[ $? -eq 1 \]; then

        echo 'Sorry, Use createConnectionProfile for versions before v0.15.0' 

        exit 1

    else

        echo Using composer-cli at $(composer --version)

    fi

else

    echo 'Need to have composer-cli installed at v0.15 or greater'

    exit 1

fi

# need to get the certificate 



cat << EOF > /tmp/.connection.json

{

    "name": "hlfv1",

    "type": "hlfv1",

    "orderers": \[

       { "url" : "grpc://localhost:7050" }

    \],

    "ca": { 

        "url": "http://localhost:7054", 

        "name": "ca.org1.example.com"

    },

    "peers": \[

        {

            "requestURL": "grpc://localhost:7051",

            "eventURL": "grpc://localhost:7053"

        }, {

            "requestURL": "grpc://localhost:8051",

            "eventURL": "grpc://localhost:8053"

        }, {

            "requestURL": "grpc://192.168.31.12:9051",

            "eventURL": "grpc://192.168.31.12:9053"

        }

    \],

    "channel": "composerchannel",

    "mspID": "Org1MSP",

    "timeout": 300

}

EOF



PRIVATE_KEY="${DIR}"/composer/crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/keystore/7fe58742a0b6d1102c74293808f1736dea010d3451f9e1a804c0b86ecf90baa0_sk

CERT="${DIR}"/composer/crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/signcerts/[email protected]



if composer card list -n PeerAdmin@hlfv1 > /dev/null; then

    composer card delete -n PeerAdmin@hlfv1

fi

composer card create -p /tmp/.connection.json -u PeerAdmin -c "${CERT}" -k "${PRIVATE_KEY}" -r PeerAdmin -r ChannelAdmin --file /tmp/[email protected]

composer card import --file /tmp/[email protected] 



rm -rf /tmp/.connection.json



echo "Hyperledger Composer PeerAdmin card has been imported"

composer card list

That’s it, everything is set and ready to go. Now lets run the following scripts to start the Hyperledger Fabric network on the first machine.

./teardownFabric.sh && ./startFabric.sh && ./createPeerAdminCard.sh

Run the following command on the second machine,

./startFabric-Peer2.sh

If everything is working properly, you’ll notice clean logs and zero errors. Try running docker ps to see all of the services that are running on each of the machines.

In the first machine there are 6 services running.

And in the second machine there are two services running.

When you notice the logs, the peers syncs whenever you create asset of submit transactions. The peer0 will be getting the first transaction submit request and then the orderer distributes to other peers maintaining all the peers in sync.

Checkout this repo for the entire source code of the server : https://github.com/varun-raj/fabric-dev-servers-multipeer


Awesome illustrations by @vectorpocket

Up next

What I will be doing in 2018
Skcript /svr/setting-up-a-blockchain-business-network-with-hyperledger-fabric-and-composer-running-in-multiple-physical-machine/ /svrmedia/heroes/f/blockchain-business-network-with-hyperledger-fabric-composer-running-in-multiple-physical-machine.png
Skcript Technologies Private Limited

Book a free consultation

Book a time with our consultants to discuss your project and get a free quote. No strings attached.