With the new release of Hyperledger Fabric 2.0 the lifecycle of chaincode has been changed. It implies also the changes in the chaincode deployment process – what basically means that commands used to deploy chaincode in < 2.0 release (no matter if using peer binary or SDK) will not work.

In this article I show how to deploy chaincode to the Hyperledger Fabric 2.0.

Channel configuration changes

One of the most important changes of chaincode lifecycle in the Fabric 2.0 is that the rights to chaincode operations are now encoded in channel definition. In the most basic scenario, the change included in the configtx.yaml indicates who has the right to endorse the chaincode changes. Fabric 2.0 ACL can specify the rights to even single blockchain operations (like querying peer if chaincode exists). We will not focus on the customization but only highlight the minimum change.

Hyperledger Fabric 2.0 chaincode deployment steps

Here are the steps in order to succeed with chaincode deployment in Hyperledger Fabric 2.0

1. Upgrade all the docker images

Upgrade the docker images tags to given values:

  • peer, orderer, fabric-tools: 2.0.0 (I assume that you use Raft orderer, in case of Kafka search for the newest Kafka and Zookeeper tags)
  • couch: 0.4.18
  • CA: 1.4.4 (however this articles doesn’t focus on CA)

2. Update configtx.yaml

I assume you setup fresh Fabric setup otherwise you will have to update blockchain configuration rather than setup it from scratch (updating the configtx.yaml file will allow to generate fresh blockchain configuration). Here is the change which must be done in configtx.yaml in order to apply to new 2.0 specification:

  • For every organization add the Endorsement section in the Policies section with the signature of organization peer. Lack of this entry will for example not allow you to install chaincode with private collections. At least from the tests I’ve done so far, not required for orderer organization. Example:
- &Org1
        Name: Org1MSP
        ID: Org1MSP
        MSPDir: crypto-config/peerOrganizations/org1/msp
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org1MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org1MSP.peer')"
        AnchorPeers:
            - Host: org1-peer0
              Port: 7051
  • Your capabilities section should look like below:
Capabilities:
    Channel: &ChannelCapabilities
        V2_0: true
    Orderer: &OrdererCapabilities
        V2_0: true
    Application: &ApplicationCapabilities
        V2_0: true
  • Your application section should have added 2 new sections LifecycleEndorsementand Endorsement, except the existing Readers, Writers, Admins. Here below is the example section which is not very restrictive (means that every organization can apply the chaincode change). Please align it to your need:
Application: &ApplicationDefaults
    Organizations:
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        LifecycleEndorsement:
            Type: ImplicitMeta
            Rule: "ANY Endorsement"
        Endorsement:
            Type: ImplicitMeta
            Rule: "ANY Endorsement"
    Capabilities:
        <<: *ApplicationCapabilities

3. Regenerate configuration

The configuration must be regenerated (need new genesis block) – use configtxgen tool. You can also regenerate crypto-configwith cryptogen tool if you want and can but it’s not necessary. Run the blockchain with new genesis block, then also recreate your channel with channel transaction.

3. Prepare chaincode deployment container and script

This assumes you load the chaincode using fabric-tools docker image container which has all the keys and environment vars setup. If you was using your cli before upgrade to 2.0 for chaincode deployment you can use this image, just add there the setupchaincode.shscript and your chaincode sources with appropriate path mapping (volumes section in docker compose file definition, take a look on following docker compose file example).

This is minimal container settings for the one I use. It requires you to set your local chaincode path (on local machine). This is the file content (don’t invoke it yet, it requires you to have also the chaincode deployment setupchaincode.sh  script):

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

networks:
  byfn:

services:

  chaincode-deployer:
    container_name: chaincode-deployer
    image: hyperledger/fabric-tools:$IMAGE_TAG
    tty: true
    stdin_open: true
    environment:
      - GOPATH=/opt/gopath
      - FABRIC_LOGGING_SPEC=DEBUG
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: /opt/gopath/src/github.com/hyperledger/fabric/peer/setupchaincode.sh && /bin/bash
    volumes:
      # Change your local chaincode path!!!
      # If you change the location in container also remember to change in setupchaincode.sh
      - ./your/local/chaincode/path:/opt/gopath/src/github.com/chaincode/examplechaincode
      # Change according to your paths
      - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
      - ./setupchaincode.sh:/opt/gopath/src/github.com/hyperledger/fabric/peer/setupchaincode.sh
    networks:
      - byfn
    ports:
      - 15050:15050

This is the setupchaincode.sh script which does the work of chaincode deployment. Configure all the variables according to your configuration:

#!/usr/bin/env bash
## MUST BE CHANGED EVERY BUILD
CHAINCODE_VERSION=1.0

## Chaincode info - CONFIGURE ONCE
CHAINCODE_LANG=node
CHAINCODE_NAME=examplechaincode
CHAINCODE_INIT_ARGS='{"Args":[]}'
CHAINCODE_LABEL=${CHAINCODE_NAME}_${CHAINCODE_VERSION}
CHAINCODE_PACKAGE_NAME=${CHAINCODE_LABEL}.tar.gz
# Source path in the cli container
CHAINCODE_SOURCE_PATH=/opt/gopath/src/github.com/chaincode/examplechaincode

# Other info - CONFIGURE ONCE
CHANNEL_NAME=mychannel
ORDERER=orderer.org1.fabric
ORDERER_ADDRESS=${ORDERER}:7050
ORDERER_CA_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/org1.fabric/orderers/orderer.org1.fabric/msp/tlscacerts/tlsca.org1.fabric-cert.pem

export CORE_PEER_ADDRESS=peer0.org1.fabric:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.fabric/peers/peer0.org1.fabric/tls/server.crt
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.fabric/peers/peer0.org1.fabric/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.fabric/users/Admin@org1.fabric/msp

# Dont change anything below, should work fine

installChaincode() {
  PEER_ADDRESS=$1
  PEER_CERT_PATH=$2
  SEQUENCE=$3
  echo 'Installing chaincode on peer: ' $PEER_ADDRESS
  peer lifecycle chaincode install $CHAINCODE_PACKAGE_NAME >&install-log.txt
  PACKAGE_ID=$(awk '{for(i=1;i<=NF;i++)if($i=="identifier:")print $(i+1)}' install-log.txt)
  peer lifecycle chaincode approveformyorg -o $ORDERER_ADDRESS --tls --cafile $ORDERER_CA_FILE --channelID $CHANNEL_NAME --name $CHAINCODE_NAME --version $CHAINCODE_VERSION --init-required --package-id $PACKAGE_ID --waitForEvent --sequence $SEQUENCE
  peer lifecycle chaincode commit -o $ORDERER_ADDRESS --tls --cafile $ORDERER_CA_FILE --channelID $CHANNEL_NAME --name $CHAINCODE_NAME --version $CHAINCODE_VERSION --sequence $SEQUENCE --init-required
  peer chaincode invoke -o $ORDERER_ADDRESS --tls --cafile $ORDERER_CA_FILE --ordererTLSHostnameOverride $ORDERER -C $CHANNEL_NAME -n $CHAINCODE_NAME --peerAddresses $PEER_ADDRESS --isInit -c $CHAINCODE_INIT_ARGS --tlsRootCertFiles $PEER_CERT_PATH
  echo 'Finished installing chaincode on peer: ' $PEER_ADDRESS
}

# Generate chaincode package - common step
peer lifecycle chaincode package $CHAINCODE_PACKAGE_NAME --path $CHAINCODE_SOURCE_PATH --lang $CHAINCODE_LANG --label $CHAINCODE_LABEL

# Get sequence value
peer lifecycle chaincode querycommitted --channelID $CHANNEL_NAME >&sequence.txt
seq=$(awk '{for(i=1;i<=NF;i++)if($i=="Sequence:")print $(i+1)}' sequence.txt)
SEQUENCE=$(echo "${seq//,}")
if [ -z $SEQUENCE ] ; then
  SEQUENCE=1
  echo 'No sequence yet, initializing with 1, got: '$SEQUENCE
else
  SEQUENCE=$(($SEQUENCE + 1))
  echo 'Incrementing sequence by 1, got: '$SEQUENCE
fi
installChaincode $CORE_PEER_ADDRESS $CORE_PEER_TLS_ROOTCERT_FILE $SEQUENCE

4. Deploy chaincode

Prepare folder and put there:

  • docker compose file for running fabric-tools deployment container (I’ve gave example content, please configure for your needs)
  • current crypto-config
  • setupchaincode.sh (please configure it for your needs)

You can run it with:

docker-compose -f chaincode-deployer.yaml up

The script should install chaincode correctly only if you have the same non restrictive endorsement (single organization approval is enough to install chaincode). Otherwise you will have to repeat peer lifecycle chaincode approveformyorg multiple times (and probably the steps before) before running peer lifecycle chaincode commit.

Summary

Hyperledger Fabric is the permissioned blockchain which is very features rich especially allowing for very wide configuration. The new chaincode deployment model gives more flexibility in the definition of chaincode deployment permissions.

Have got any question? Feel free to ask in the comments.
Przemek