Hyperledger

Hyperledger Fabric Upgradation of the network from version 1.4.x to 2.2.x

Mkaif Agb
Coinmonks
Published in
9 min readApr 3, 2023

--

Overview

Creating a network can be difficult but migration of a network is cumbersome. It is important to note that upgrading a Hyperledger Fabric network can be a complex and time-consuming process. It is recommended to test the upgrade on a non-production environment before applying it to the production network. It is also advisable to have an experienced Hyperledger Fabric administrator or consultant assist with the upgrade process. There are a lot of steps involved for migrating the network and I will be demonstrating the process with fabric-samples 1.4.9.

Here is a high-level overview of the process:

Upgrade the orderer containers

Upgrade the peer containers

Update channel capabilities

Enable New Chaincode lifecycle

Peer databases upgrade

Define ordering node endpoint per org

Test Network architecture is very simple, a two-organization network setup, one for ordering service and two for peer organizations. Inside each peer organization we have one peer and an optional CA.

Following command can be used to install the required images/binaries for the network.

curl -sSL http://bit.ly/2ysbOFE | bash -s -- 1.4.12 1.4.9 0.4.22

Let’s Start with moving into the working directory which is fabric-samples/first-network and using the byfn script we will build a network and deploy a chaincode.

 ./byfn.sh up -c mychannel -s couchdb -l node 

If everything goes correctly you will have a network up with a single channel called mychannel where a Javascript chaincode will be deployed and the database used is couchdb.

Byfn script end

We can now check if the network is correctly configured and running by Invoking/Query the chaincode.

docker exec -it cli bash
# export env vars
export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
export CHANNEL_NAME=mychannel
export PEER0_ORG1_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export PEER0_ORG2_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
# invoke chaincode
peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA -c '{"Args":["invoke","a","b","10"]}' --tls --cafile $ORDERER_CA
# query chaincode
peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA -c '{"Args":["query","a"]}' --tls --cafile $ORDERER_CA
Invoke/query Successful

Let’s now start with Migrating the network

First we will be upgrading the images/binaries for Orderer then Peer.

Upgrade the Orderer containers

Orderer containers should be upgraded in a rolling fashion (one at a time). At a high level, the orderer upgrade process goes as follows:

  1. Stop the orderer.
  2. Back up the orderer’s ledger and MSP.
  3. Restart the orderer with the latest images.
  4. Verify upgrade completion.

We only have one Orderer in our test network for demo purpose.

docker stop orderer.example.com

export LEDGERS_BACKUP=./ledgers-backup

# Note, replace '2.2.x' with a specific version, for example '2.2.10'.
# Set IMAGE_TAG to 'latest' if you prefer to default to the images tagged 'latest' on your system.

export IMAGE_TAG=$(go env GOARCH)-2.2.10

mkdir -p $LEDGERS_BACKUP

docker cp orderer.example.com:/var/hyperledger/production/orderer/ ./$LEDGERS_BACKUP/orderer.example.com

# Now download and restart the orderer with our new fabric image:
docker-compose -f docker-compose-cli.yaml up -d --no-deps orderer.example.com

Upgrade the peer containers

Peer containers should, like the orderers, be upgraded in a rolling fashion (one at a time). As mentioned during the orderer upgrade, orderers and peers may be upgraded in parallel, but for the purposes of this tutorial we’ve separated the processes out. At a high level, we will perform the following steps:

  1. Stop the peer.
  2. Back up the peer’s ledger and MSP.
  3. Remove chaincode containers and images.
  4. Restart the peer with latest image.
  5. Verify upgrade completion.

We have four peers running in our network. We will perform this process once for each peer, totaling four upgrades.

(Optional to do now as you can do the same later on) You can add “peer node upgrade-dbs” in the command for docker compose to drop database.

export IMAGE_TAG=$(go env GOARCH)-2.2.10

export PEER=peer0.org1.example.com
#export PEER=peer1.org1.example.com
#export PEER=peer0.org2.example.com
#export PEER=peer1.org2.example.com

docker stop $PEER

# Backup the peer’s ledger and MSP
mkdir -p $LEDGERS_BACKUP

docker cp $PEER:/var/hyperledger/production ./$LEDGERS_BACKUP/$PEER

# remove the peer chaincode containers and peer chaincode images
CC_CONTAINERS=$(docker ps | grep dev-$PEER | awk '{print $1}')
if [ -n "$CC_CONTAINERS" ] ; then docker rm -f $CC_CONTAINERS ; fi

CC_IMAGES=$(docker images | grep dev-$PEER | awk '{print $1}')
if [ -n "$CC_IMAGES" ] ; then docker rmi -f $CC_IMAGES ; fi

# re-launch the peer using the v2.2.x image tag
docker-compose -f docker-compose-cli.yaml up -d --no-deps $PEER

Now to check if the network is working fine, we can do invoke/query as shown above but before doing that lets update the image of CLI container.

export IMAGE_TAG=$(go env GOARCH)-2.2.10
docker stop cli
docker-compose -f docker-compose-cli.yaml up -d --no-deps cli

If your Invoke is working fine then the network is using the new Images/Binaries but it doesn’t end here. We now have to do the channel upgradation on both System Channel as well as Application Channel but before that we will be dropping the old couchdb database and rebuild the whole database using 2.x standards.

Peer databases upgrade

The databases of all peers (which include not just the state database but the history database and other internal databases for the peer) must be rebuilt using the v2.0 data format as part of the upgrade to v2.0. To trigger the rebuild, the databases must be dropped before the peer is started. During the process for upgrading your peers, you will need to pass a peer node upgrade-dbs command to drop the databases of the peer.

peer-node-upgrade-dbs

You will have to follow the same process as we did while upgrading peers (Upgrade peer containers)

If everything is done correctly you can check the peer container by docker ps -a and it should show the following logs

peer-dbs-logs

You can also check the database by running the curl request for couchdb

curl -X GET http://127.0.0.1:5984/_all_dbs

If the database has not been dropped by the command given above, You can do it manually using the following command but do keep in mind there are 4 couchdb instance so you will have to do the same for all the instances (5984, 6984, 7984, 8984)

curl -X DELETE http://127.0.0.1:5984/{database-name}

Again you will have to restart the peers in the same way but this time the command in docker compose should indicate “ peer node start “ and you can find the following logs in the running 2.2.x peer

Upgrading System Channel

Make sure you are in the CLI container:

docker exec -it cli bash

Because only ordering organizations admins can update the ordering system channel, we need set environment variables for the system channel that will allow us to carry out these tasks. Issue each of these commands:

CORE_PEER_LOCALMSPID="OrdererMSP"

CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/users/Admin@example.com/msp

ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

CH_NAME=byfn-sys-channel

The first step in updating a channel configuration is getting the latest config block:

peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CH_NAME --tls --cafile $ORDERER_CA

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

jq .data.data[0].payload.data.config config_block.json > config.json

cp config.json modified_config.json

Now lets make the Required Changes in the channel configuration which will allow peers to use new capabilities as well as Chaincode Lifecycle.

Add Capabilities to all the Capabilities section like this. (append)

          "Capabilities": {
"mod_policy": "Admins",
"value": {
"capabilities": {
"V1_4_2": {},
"V2_0": {}
}

# Adding Endorsement to all the organisation before Readers and Writers

                  "Endorsement": {
"mod_policy": "Admins",
"policy": {
"type": 1,
"value": {
"identities": [
{
"principal": {
"msp_identifier": "Org1MSP",
"role": "PEER"
},
"principal_classification": "ROLE"
}
],
"rule": {
"n_out_of": {
"n": 1,
"rules": [
{
"signed_by": 0
}
]
}
},
"version": 0
}
},
"version": "0"
},

# Org2
"Endorsement": {
"mod_policy": "Admins",
"policy": {
"type": 1,
"value": {
"identities": [
{
"principal": {
"msp_identifier": "Org2MSP",
"role": "PEER"
},
"principal_classification": "ROLE"
}
],
"rule": {
"n_out_of": {
"n": 1,
"rules": [
{
"signed_by": 0
}
]
}
},
"version": 0
}
},
"version": "0"
},

# Endorsement and Chaincode Lifecycle changes.
object►channel_group►groups►Application►policies►LifecycleEndorsement►

 "Endorsement": {
"mod_policy": "Admins",
"policy": {
"type": 3,
"value": {
"rule": "MAJORITY",
"sub_policy": "Endorsement"
}
},
"version": "0"
},
"LifecycleEndorsement": {
"mod_policy": "Admins",
"policy": {
"type": 3,
"value": {
"rule": "MAJORITY",
"sub_policy": "Endorsement"
}
},
"version": "0"
},

Adding Orderer Endpoints to the channel values. This will vary with the amount of orderer present in your network

object►channel_group►groups►Consortium►Orderer

              "Endpoints": {
"mod_policy": "Admins",
"value": {
"addresses": [
"orderer.example.com:7050"
]
},
"version": "0"
},

Now we can create the config update:

configtxlator proto_encode --input config.json --type common.Config --output config.pb
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
configtxlator compute_update --channel_id $CH_NAME --original config.pb --updated modified_config.pb --output config_update.pb

Package the config update into a transaction:

configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CH_NAME'", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . > config_update_in_envelope.json
configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output config_update_in_envelope.pb

Submit the config update transaction: (You might require the config update to be signed by both Organisations by setting up required environment variables

First, switch into Org1 and sign the update:

CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
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=peer0.org1.example.com:7051
peer channel signconfigtx -f config_update_in_envelope.pb

And do the same as Org2:

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
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.org1.example.com:7051
peer channel signconfigtx -f config_update_in_envelope.pb

And as the OrdererOrg, Submit the config update transaction

CORE_PEER_LOCALMSPID="OrdererMSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/users/Admin@example.com/msp
peer channel update -f config_update_in_envelope.pb -c $CH_NAME -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA

Now we have to do the same steps on Application Channel. Most of the steps will remain the same only one addition configuration will be added in Application channel related to ACLs (Access Control List)

Application Group

For the application group, we will need to reset the environment variables as one organization:

CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
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=peer0.org1.example.com:7051

CH_NAME=mychannel

peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CH_NAME --tls --cafile $ORDERER_CA
configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
jq .data.data[0].payload.data.config config_block.json > config.json

Follow the same steps as system channel to do the configuration updates

# Upgrading the capabilities to 2.0
"Capabilities": {
"mod_policy": "Admins",
"value": {
"capabilities": {
"V1_4_2": {},
"V2_0": {}
}

# object►channel_group►groups►Application►policies►

"Endorsement": {
"mod_policy": "Admins",
"policy": {
"type": 3,
"value": {
"rule": "MAJORITY",
"sub_policy": "Endorsement"
}
},
"version": "0"
},
"LifecycleEndorsement": {
"mod_policy": "Admins",
"policy": {
"type": 3,
"value": {
"rule": "MAJORITY",
"sub_policy": "Endorsement"
}
},
"version": "0"
},

# Adding Endorsement to all the organisation before Readers and Writers


"Endorsement": {
"mod_policy": "Admins",
"policy": {
"type": 1,
"value": {
"identities": [
{
"principal": {
"msp_identifier": "Org1MSP",
"role": "PEER"
},
"principal_classification": "ROLE"
}
],
"rule": {
"n_out_of": {
"n": 1,
"rules": [
{
"signed_by": 0
}
]
}
},
"version": 0
}
},
"version": "0"
},



"Endorsement": {
"mod_policy": "Admins",
"policy": {
"type": 1,
"value": {
"identities": [
{
"principal": {
"msp_identifier": "Org2MSP",
"role": "PEER"
},
"principal_classification": "ROLE"
}
],
"rule": {
"n_out_of": {
"n": 1,
"rules": [
{
"signed_by": 0
}
]
}
},
"version": 0
}
},
"version": "0"
},
# Adding Orderer Endpoints to the channel values

object►channel_group►groups►Consortium►Orderer

"Endpoints": {
"mod_policy": "Admins",
"value": {
"addresses": [
"orderer.example.com:7050"
]
},
"version": "0"
},
# Adding ACL

"ACLs": {
"value": {
"acls": {
"_lifecycle/CheckCommitReadiness": {
"policy_ref": "/Channel/Application/Writers"
},
"_lifecycle/CommitChaincodeDefinition": {
"policy_ref": "/Channel/Application/Writers"
},
"_lifecycle/QueryChaincodeDefinition": {
"policy_ref": "/Channel/Application/Writers"
},
"_lifecycle/QueryChaincodeDefinitions": {
"policy_ref": "/Channel/Application/Writers"
}
}
}
}

# Create the config update

configtxlator proto_encode --input config.json --type common.Config --output config.pb
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
configtxlator compute_update --channel_id $CH_NAME --original config.pb --updated modified_config.pb --output config_update.pb

configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CH_NAME'", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . > config_update_in_envelope.json
configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output config_update_in_envelope.pb

# Because we’re updating the config of the channel group, the relevant orgs — Org1, Org2, and the OrdererOrg — need to sign it and then parse channel update.
peer channel update -f config_update_in_envelope.pb -c $CH_NAME -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA

Voila!! You now have migrated the network from 1.4 to 2.2 without any data loss. We can verify by making an invoke/query on the network.

export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
export CHANNEL_NAME=mychannel
export PEER0_ORG1_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export PEER0_ORG2_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt

# invoke chaincode
peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA -c '{"Args":["invoke","a","b","10"]}' --tls --cafile $ORDERER_CA

# query chaincode
peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles $PEER0_ORG2_CA -c '{"Args":["query","a"]}' --tls --cafile $ORDERER_CA

New to trading? Try crypto trading bots or copy trading on best crypto exchanges

Join Coinmonks Telegram Channel and Youtube Channel get daily Crypto News

Also, Read

--

--