Remove an Organization from a Running Fabric Network

KC Tam
6 min readAug 8, 2019

Overview

In my previous article I followed the tutorial in Hyperledger Fabric Documentation to add an organization into the First Network.

The whole process, despite a bit tedious and complicated one, gives us a good idea how things work. Inspired by this flow, here I am doing the opposite: remove an organization from a live channel in a fabric network. For sake of demonstration I use a simpler three-org one-channel setup, and the Simple Asset Chaincode (SACC) as the chaincode for demonstration.

Set the Environment: Network and Chaincode

For demo purpose, I have prepared this repository. It comes with the required crypto material (for an orderer and three organizations) and channel artifacts (genesis block and configuration transaction for mychannel). For simplicity we use this set of material.

Here are the steps of setting up this whole environment for our later use.

Step 1: Deploy 3org1ch network with docker compose.

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

Step 2: Set up three terminals.

# for org1
docker exec -it cli bash
# for org2
docker exec -e "CORE_PEER_LOCALMSPID=Org2MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp" -e "CORE_PEER_ADDRESS=peer0.org2.example.com:7051" -it cli bash
# for org3
docker exec -e "CORE_PEER_LOCALMSPID=Org3MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp" -e "CORE_PEER_ADDRESS=peer0.org3.example.com:7051" -it cli bash
Three terminals for Org1, Org2 and Org3 (from top to bottom).

Step 3: Create channel mychannel

# org1
peer channel create -o orderer.example.com:7050 -c mychannel -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/channel.tx
# org1, org2, org3
peer channel join -b mychannel.block

Once the three organizations (peers) join the channel, we can get the information about the latest block. We can see that the height is the same (1), which means that there is just one block (block #0) in this channel.

# org1, org2, org3 check block
peer channel getinfo -c mychannel

Step 4: Install and Instantiate SACC in mychannel. For demonstration we set the endorsing policy as just one endorsement needed.

# org1, org2, org3
peer chaincode install -n sacc -p github.com/chaincode/sacc -v 1
#org1
peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -c '{"Args":["a", "100"]}' -n sacc -v 1 -P "OR('Org1MSP.peer', 'Org2MSP.peer', 'Org3MSP.peer')"

Step 5: Query Result from All Orgs

# org1, org2, org3
peer chaincode query -C mychannel -n sacc -c '{"Args":["get","a"]}'

We see all return the value 100.

Step 6: Invoke from Org1, and check result again from all orgs

# org1
peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n sacc -c '{"Args":["set","a","10"]}'
# org1, org2, org3
peer chaincode query -C mychannel -n sacc -c '{"Args":["get","a"]}'

Now we see all return the value 10.

This ends our fabric network setup, ready for our demonstration on removing Org3 from mychannel.

Removing Org3 from Channel mychannel

The removal of an organization from an established channel requires a construction of a configuration update transaction, which is a difference between “before” and “after”, and apply this transaction update on the channel.

After that we will upgrade the chaincode and observe the behaviour.

Work on Configuration Update Transaction

The flow looks like this.

Step 1: Get the latest configuration block (which should be block #0). We decode the file and only extract the portion useful into the config.json file.

# org1
peer channel fetch config config_block.pb -o orderer.example.com:7050 -c mychannel
configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config > config.json
block #0 is the latest configuration block in mychannel

Step 2: Remove Org3MSP from config.json and keep the result in modified_config.json.

# org1
jq 'del(.channel_group.groups.Application.groups.Org3MSP)' config.json > modified_config.json

We put both files side-by-side, and see the difference.

Org3MSP is removed

Step 3: Encode both config.json and modified_config.json files to PB format. Compute the difference of the two files, saved as update.pb.

# org1
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.pbconfigtxlator compute_update --channel_id mychannel --original config.pb --updated modified_config.pb --output update.pb

Step 4: Add back envelope for update.pb, which first decode it into update.json, add the envelope, and the result is encoded back to update_in_envelope.pb.

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

Again we take a look the update.json inside the envelope.

Step 5: Sign the update_in_envelope.pb by Org1. Org2 sends this file as update (which includes Org2’s signature as well).

# org1
peer channel signconfigtx -f update_in_envelope.pb
# org2
peer channel update -f update_in_envelope.pb -c mychannel -o orderer.example.com:7050

With this, the Orderer sends out a new block, which only goes to Org1 and Org2.

Step 6: Check channel block information.

# org1, org2, org3
peer channel getinfo -c mychannel

We can see that Org1 and Org2 has the same blockchain height and same block, while Org3 keeps the latest block it receives before the whole process. It is interesting to note that the “currentBlockHash” in block #2 (see in Org3) is the “previousBlockHash” (bJtj…KZM=) in block #3 (see in Org1 and Org2). The block is in fact “chained”.

Configuration update transaction (block)

Upgrade the Chaincode

Step 7: Install a new version of SACC on Org1 and Org2, and upgrade chaincode to this new version. Here we use another initial key/value (b, 1) in order to keep the state (a, 10) in my ledger.

# org1, org2
peer chaincode install -n sacc -p github.com/chaincode/sacc -v 2
# org1
peer chaincode upgrade -o orderer.example.com:7050 -C mychannel -c '{"Args":["b", "1"]}' -n sacc -v 2 -P "OR('Org1MSP.peer', 'Org2MSP.peer')"

Step 8: Query from all peers.

# org1, org2, org3
peer chaincode query -C mychannel -n sacc -c '{"Args":["get","a"]}'

We see all 10, that means the ledger of all organizations keep what it has before, even though the Org3 already removed from the channel.

Step 9: Invoke from Org1, and check result again from all orgs.

# org1
peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n sacc -c '{"Args":["set","a","1"]}'
# org1, org2, org3
peer chaincode query -C mychannel -n sacc -c '{"Args":["get","a"]}'
Org3 does not get the block update on mychannel any more.

This is our expected result. Both Org1 and Org2 get updated, while ledger in Org3 remains. That means Org3 no longer receives block update from Orderer after it is removed from the channel.

To confirm we check the latest block in the ledger of all organizations.

Org3 remains at the height before it is removed from channel.

Summary

In this article we set up a testing environment, with three organizations on one channel. After the network was up and running with a chaincode deployed, we removed an organization based on the flow suggested in the Hyperledger Fabric tutorial. Not surprising the removal is easier than the addition of a new organization, as we do not need to involve new crypto material generation. The whole process again is a bit tedious, but the logic is quite neat. After the removal we upgrade the chaincode to reflect the change.

Note that the removal is done at channel level, which means that the removed node is no longer part of the channel. What has been kept before the removal still remains in the peer, unless it is completely removed at container level, database level and/or hardware level.

--

--