DEV Community

Bukhori M. Aqid
Bukhori M. Aqid

Posted on • Updated on

Extending Fabric 2 Test Network

What is Fabric 2
Hyperledger Fabric is a private blockchain platform that enables you to create permissioned blockchain network. The main elements in Hyperledger Fabric are:

  • Peer & Organization: Peer node hosts and execute ledger transactions and smart contracts. Peer belongs to Organization. Some peers can be endorsing peers.
  • Orderer: Orderer provides ordering service (packages transactions into blocks to be delivered to peers on a channel).
  • Channel: Channel are logical structure formed by collection of peers.
  • Chaincode / Smart Contract: Smart Contract is software that defines the business logic, contains assets and related transactions. Hyperledger Fabric smart contracts are called chaincode and may specify an endorsement policy which defines transaction validity.

The approach that is taken by Hyperledger Fabric (in my opinion) is beneficial for industrial use cases because it enables cooperation between organization (using channels) while to certain extent having a privacy inside the organization.

To explore the capabilities of Fabric, there are some examples provided that serves certain use cases. For a simple introduction, there are 2 examples that should be used: First Network and Test Network. Due to a major upgrade in Hyperledger Fabric, there are 2 major versions available 1.4.x and 2.x.x - First Network is suitable if you want to learn Fabric 1.4.x but Test Network would be preferable for Fabric 2.x.x. Also good to know that Test Network is a replacement for First Network so you should use that whenever possible.

The striking difference between First Network and Test Network is the number of nodes. First Networks comes with 2 peers for each organization, and 5 orderers while Test Network only comes with 1 peer per organization and 1 orderer. This might be limited for some scenario that you want to run. This article will help you extend the test network with some helpful bash scripts. The underlying assumption is that you already have a Test Network running with command ./network.sh up createChannel && ./network.sh deployCC

TL;DR

To extend Test Network, we need to extend fabric key with cryptogen, update system-channel definition, compose orderer nodes, compose peer nodes, join application channel and deploy the chaincode. For an easy setup, clone this repository and run ./extend-network.sh after setting up your local Test Network. Or to make things easier, just run ./setup-fabric-extended.sh that will setup local Test Network as well as extends it.


Extending Fabric Key
Before extending the network, we need to generate all the necessary key for each new orderer and peer that we want to create. The easiest way to do that is by using cryptogen command. cryptogen is an utility for generating Hyperledger Fabric key material. It is provided as a means of preconfiguring a network for testing purposes. It would normally not be used in the operation of a production network.

cryptogen extend --config=crypto-config.yaml --input="organizations"
Enter fullscreen mode Exit fullscreen mode

The --config parameter should point to the new network configuration, not the existing test network configuration. In this case, we want a total of 3 orderers, with 3 peers for each organization.

OrdererOrgs:
- Name: Orderer
  Domain: example.com
  EnableNodeOUs: true

  Specs:
    - Hostname: orderer
    - Hostname: orderer1
    - Hostname: orderer2

PeerOrgs:
- Name: Org1
  Domain: org1.example.com
  EnableNodeOUs: true

  Template:
      Count: 3
      SANS:
        - localhost
  Users:
      Count: 1

- Name: Org2
  Domain: org2.example.com
  EnableNodeOUs: true

  Template:
      Count: 3
      SANS:
        - localhost
  Users:
      Count: 1
Enter fullscreen mode Exit fullscreen mode

Extending Test Network Orderer
First, we need to update system-channel configuration so that we can run new orderer node. The steps needed to update system-channel are as follows:

  1. Fetch (and decode) latest configuration
  2. Add new orderer certificate generated by cryptogen to orderer consenters and modify the configuration
  3. Apply the change to blockchain

To fetch and decode latest configuration, we need to execute:

peer channel fetch config ./out/config_block.pb -o $ORDERER_ADDRESS -c $2 --tls --cafile $TLS_ROOT_CA

configtxlator proto_decode --input ./out/config_block.pb --type common.Block --output ./out/config_block.json

jq .data.data[0].payload.data.config ./out/config_block.json > ./out/config.json
Enter fullscreen mode Exit fullscreen mode

The commands above will get the latest config and store the result in out folder. The default orderer address is export ORDERER_ADDRESS=localhost:7050 and the TLS_ROOT_CAshould be test-network/organizations/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem

Next is adding new orderer certificate to the new configuration. We can achieve that by executing commands below:

# add new orderer certificate
echo "{\"client_tls_cert\":\"$(cat $ORDERER_TLS | base64 -w 0)\",\"host\":\"orderer$1.example.com\",\"port\":7$150,\"server_tls_cert\":\"$(cat $ORDERER_TLS | base64 -w 0)\"}" > $PWD/out/ord$1consenter.json

jq ".channel_group.groups.Orderer.values.ConsensusType.value.metadata.consenters += [$(cat ./out/ord$1consenter.json)]" ./out/config.json > ./out/modified_config.json

# calculate config differences
configtxlator proto_encode --input ./out/config.json --type common.Config --output ./out/config.pb

configtxlator proto_encode --input ./out/modified_config.json --type common.Config --output ./out/modified_config.pb

configtxlator compute_update --channel_id $2 --original ./out/config.pb --updated ./out/modified_config.pb --output ./out/config_update.pb
Enter fullscreen mode Exit fullscreen mode

$1 refers to our orderer address, $2 refer to channel name (system-channel) and $ORDERER_TLS should refer to TLS certificate for the corresponding orderer.

The final step before starting the node is applying the changes via update transaction

# "applying changes"
configtxlator proto_decode --input ./out/config_update.pb --type common.ConfigUpdate --output ./out/config_update.json

echo '{"payload":{"header":{"channel_header":{"channel_id":"'$2'", "type":2}},"data":{"config_update":'$(cat ./out/config_update.json)'}}}' | jq . > ./out/config_update_in_envelope.json

configtxlator proto_encode --input ./out/config_update_in_envelope.json --type common.Envelope --output ./out/config_update_in_envelope.pb

# "submit update transaction"
peer channel update -f ./out/config_update_in_envelope.pb -c $2 -o $ORDERER_ADDRESS --tls --cafile $TLS_ROOT_CA
Enter fullscreen mode Exit fullscreen mode

The final step is actually creating and running the orderer node. The easiest way is to use docker compose and add the service definition below

  orderer1.example.com:
    container_name: orderer1.example.com
    extends: 
      file: orderer-base.yaml
      service: orderer-base
    environment: 
      - ORDERER_GENERAL_LISTENPORT=7150
    volumes:
      - ${FABRIC_SAMPLES_DIR}/test-network/system-genesis-block/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
      - ${FABRIC_SAMPLES_DIR}/test-network/organizations/ordererOrganizations/example.com/orderers/orderer1.example.com/msp:/var/hyperledger/orderer/msp
      - ${FABRIC_SAMPLES_DIR}/test-network/organizations/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/:/var/hyperledger/orderer/tls
      - orderer1.example.com:/var/hyperledger/production/orderer
    ports:
      - 7150:7150
Enter fullscreen mode Exit fullscreen mode

with orderer-base.yaml defined below

version: '2'

services:
  orderer-base:
      image: hyperledger/fabric-orderer:$IMAGE_TAG
      environment:
        - FABRIC_LOGGING_SPEC=INFO
        - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
        - ORDERER_GENERAL_GENESISMETHOD=file
        - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
        - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
        - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
        # enabled TLS
        - ORDERER_GENERAL_TLS_ENABLED=true
        - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
        - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
        - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
        - ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1
        - ORDERER_KAFKA_VERBOSE=true
        - ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt
        - ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key
        - ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
      working_dir: /opt/gopath/src/github.com/hyperledger/fabric
      command: orderer
      networks:
        - net_test # docker network for Test Network
Enter fullscreen mode Exit fullscreen mode

Extending Test Network Peer
Extending peer node is easier. After you've generated all the required key, you can directly compose the node. One of the sample configuration for your node container is given below

  peer1.org1.example.com:
    container_name: peer1.org1.example.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      # Peer specific variabes
      - CORE_PEER_ID=peer1.org1.example.com
      - CORE_PEER_ADDRESS=peer1.org1.example.com:7151
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7151
      - CORE_PEER_CHAINCODEADDRESS=peer1.org1.example.com:7152
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7152
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org1.example.com:7151
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:7151
      - CORE_PEER_LOCALMSPID=Org1MSP
    volumes:
      - /var/run/:/host/var/run/
      - ${FABRIC_SAMPLES_DIR}/test-network/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp
      - ${FABRIC_SAMPLES_DIR}/test-network/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls
      - peer1.org1.example.com:/var/hyperledger/production
    ports:
      - 7151:7151
Enter fullscreen mode Exit fullscreen mode

with peer-base.yaml defined below

version: '2'

services:
    peer-base:
        image: hyperledger/fabric-peer:$IMAGE_TAG
        environment:
            # Generic peer variables
            - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
            - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_test
            - FABRIC_LOGGING_SPEC=WARN:cauthdsl=info:policies=debug:msp=info
            - CORE_PEER_TLS_ENABLED=true
            - CORE_PEER_GOSSIP_USELEADERELECTION=true
            - CORE_PEER_GOSSIP_ORGLEADER=false
            - CORE_PEER_PROFILE_ENABLED=true
            - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
            - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
            - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
        working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
        command: peer node start
        networks:
            - net_test # docker network for Test Network
Enter fullscreen mode Exit fullscreen mode

That's basically it. Make sure that all certificates and keys are pointing in the correct and existing folder and you're good to go.

Enjoy your new network!

Latest comments (6)

Collapse
 
carolwa40156642 profile image
Carol Watson

Also the CLI is great but SDK is most suited for production. Can you link me some tutorials to begin with NodeJs or Java

Collapse
 
bukhorimuhammad profile image
Bukhori M. Aqid

Yes, this is mostly for extending test network, which is not suitable for production. SDK is for client application to interact with blockchain network, which is not the purpose of network setup. When I create application clients, I might write a follow up tutorial :)

Collapse
 
carolwa40156642 profile image
Carol Watson

I forgot to mention that the script requires the file ./out/config_block.pb and other related files so you could provide it. The command peer channel fetch config ./out/config_block.pb -o $ORDERER_ADDRESS -c $2 --tls --cafile $TLS_ROOT_CA produces

2020-06-30 09:38:43.595 CEST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-06-30 09:38:43.631 CEST [cli.common] readBlock -> INFO 002 Expect block, but got status: &{NOT_FOUND}
Error: can't read the block: &{NOT_FOUND}

Collapse
 
bukhorimuhammad profile image
Bukhori M. Aqid

Weird. all the files needed should be fetched and contained in out folder. Need to check that

Collapse
 
carolwa40156642 profile image
Carol Watson

Hi,
There folder out/ needed to fetch the configuration is missing. Would you please upload it in your github repo?

Collapse
 
bukhorimuhammad profile image
Bukhori M. Aqid

Ah, thanks for the information! you can create it yourself since it is originally an empty directory. I will update the script to create the directory first before fetching configuration