Illustrating Endorsement Policy in Lifecycle Chaincode (Hyperledger Fabric Release 2.0)

Overview

This is another article on Hyperledger Fabric release 2.0. In my previous work I have demonstrated the chaincode operation using lifecycle chaincode provided in 2.0, and compared the difference of the way we are used to in release 1.4. Now we will explore further on the lifecycle chaincode, and specifically about the endorsement policy. We will also see how to set endorsing policy on the application chaincode during the chaincode operation. As usual, to illustrate how things work, we will bring up a network and make some observation on this topic.

Two Types of Chaincodes

As we will involve two types of chaincode here, namely the lifecycle chaincode and application chaincode (or just simply chaincode). Let’s first do a quick introduction here.

Lifecycle chaincode is a system chaincode responsible for chaincode operation. It is all about deploying an application chaincode to a fabric network such that permissioned users can invoke the functions coded in the application chaincode. We do not need to install lifecycle chaincode as It is an integral part of Hyperledger Fabric software. We can use command line interface (CLI) or software development kit (SDK) to interact with the lifecycle chaincode functionality.

Application chaincode (or simply chaincode) is the “smart contract” functionality we always refer to in Hyperledger Fabric projects. It is closely tied to real business world, containing the business logic that the member organizations in a channel agree. Chaincode designers and developers build the chaincode according to the real business needs. The chaincode (and therefore the business application) is useable after being deployed in a fabric network.

This is where the two types of chaincode “meet”. We use lifecycle chaincode functions to make the application chaincode useable. A typical process for deploying an application involves the following steps (see documentation).

This is how the lifecycle chaincode and application chaincode interacts.

Image for post
Image for post
Lifecycle chaincode deploys application chaincode in a fabric network.

Bear in mind that these are two separate chaincodes in a fabric system. Our interest here is to inspect the endorsement policy on lifecycle chaincode. Concretely, how endorsement requirement is met before an application chaincode is useable. To make a contrast, we also show the endorsement policy of application chaincode, which can be different from lifecycle chaincode. We will show this in our illustration.

Setup

In this illustration we use one fabric host which is installed with the fabric images, tools and fabric-sample repository. It can be built based on the documentation (prerequisite and installation). The configuration is largely adapted from First Network, with modification to meet my demonstration purpose.

My fabric network contains

Clone the repository and follow the instruction to generate the crypto material and channel artifacts.

Once we have both the crypto material and channel artifacts generated, we can use the following script to start a network.

./bringupnetwork.sh

After the script completes, we will have a fabric network setup for our demonstration.

And use this script to tear down all containers and images.

./teardownall.sh

Demonstration Flow

Our application chaincode is Simple Asset Chaincode (SACC), which comes in fabric-samples. This chaincode is simply a key/value store in the ledger, with two functions, set() and get(). Note: SACC comes with Init(). However the Init() has no impact on the chaincode illustration. As a result, in this demonstration we are NOT flag the init-required when approving and committing chaincode.

If we take a look on configtx.yaml, we will see the endorsement policy for both lifecycle chaincode and application chaincode is MAJORITY.

Image for post
Image for post
Extract from configtx.yaml

As mentioned before, for illustration purpose, we keep the endorsement policy of lifecycle chaincode of majority, and change the endorsement policy for SACC with “any one of member organizations is good enough”, this is translated into OR(Org1, Org2, Org3) if you are familiarized with the endorsement policy expression. Concretely, every organization can invoke and endorse proposal, and does not require endorsement from other organizations. We will not make modification in configtx.yaml. Instead we will specify when dealing with SACC in chaincode operation.

Image for post
Image for post
Lifecycle chaincode and application chaincode can have independent endorsement policy.

The demonstration is to simulate the chaincode operation (lifecycle chaincode) on SACC. The flow is like this

Let’s start now.

Step 1: Package Chaincode

Package SACC. The result is a tar.gz file which is being used in next step.

# If not done before
pushd ../chaincode/sacc
GO111MODULE=on go mod vendor
popd
docker exec cli peer lifecycle chaincode package sacc.tar.gz --path github.com/hyperledger/fabric-samples/chaincode/sacc/ --label sacc_1

Step 2: Install chaincode package to peers of all organizations

# peer0.org1
docker exec cli peer lifecycle chaincode install sacc.tar.gz
# peer0.org2
docker exec -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:9051 -e CORE_PEER_LOCALMSPID="Org2MSP" -e 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 cli peer lifecycle chaincode install sacc.tar.gz
# peer0.org3
docker exec -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:11051 -e CORE_PEER_LOCALMSPID="Org3MSP" -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt cli peer lifecycle chaincode install sacc.tar.gz

A Package ID is received. And we will use this Package ID in coming steps when referring to this chaincode package for SACC.

Step 3: Chaincode commit fails if endorsement policy for lifecycle chaincode is not met

Org1 approves chaincode. Note that we have specified the signature-policy. This is the endorsement policy for the application chaincode (i.e. SACC) we are overriding, as the default is majority. Here we change it to either one of the member organizations.

docker exec cli peer lifecycle chaincode approveformyorg --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name mycc --version 1 --sequence 1 --waitForEvent --signature-policy "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')" --package-id sacc_1:bf57e4926742fd0dbd8716058897cbb60d3530914529a4b9b46817d2324f6399
Image for post
Image for post

Check the chaincode commit readiness now. We see only Org1 has made approval.

docker exec cli peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name mycc --version 1 --sequence 1 --signature-policy "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')" --output json
Image for post
Image for post

Now try to commit chaincode.

docker exec cli peer lifecycle chaincode commit -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --channelID mychannel --name mycc --version 1 --sequence 1 --signature-policy "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')"
Image for post
Image for post

The chaincode commit fails, and the error message shows it is due to the endorsement policy failure. Lifecycle chaincode requires endorsement of majority, which is not met as only one organization has made approval so far.

Step 4: Successful chaincode commit after one more organization approves chaincode

Let Org3 approve the chaincode package.

docker exec -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:11051 -e CORE_PEER_LOCALMSPID="Org3MSP" -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt cli peer lifecycle chaincode approveformyorg --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name mycc --version 1 --sequence 1 --waitForEvent --signature-policy "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')" --package-id sacc_1:bf57e4926742fd0dbd8716058897cbb60d3530914529a4b9b46817d2324f6399
Image for post
Image for post

And check the chaincode commit readiness again.

docker exec cli peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name mycc --version 1 --sequence 1 --signature-policy "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')" --output json
Image for post
Image for post

Now commit chaincode. Note that we need to specify peerAddresses of both Org1 and Org3 (and their CA as TLS is enabled).

docker exec cli peer lifecycle chaincode commit -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org3.example.com:11051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt --channelID mychannel --name mycc --version 1 --sequence 1 --signature-policy "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')"
Image for post
Image for post

And we check the status of chaincode commit.

docker exec cli peer lifecycle chaincode querycommitted --channelID mychannel --name mycc --output json
Image for post
Image for post

Now the SACC chaincode is committed and useable in the fabric network.

Step 5: Endorsement policy on application chaincode SACC

Org1 invokes set() with key “name” and value “kc”.

docker exec cli peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc -c '{"Args":["set","name","kc"]}'
Image for post
Image for post

And check the value of key “name”,

docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'
Image for post
Image for post

We see Org1 is able to invoke chaincode function. As the chaincode endorsement policy requires only peer from one organization, endorsement by itself (peer0.org1.example.com) is good enough.

Step 6: Organization having not approved chaincode cannot invoke chaincode functions.

Now let Org2 invoke set().

docker exec -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:9051 -e CORE_PEER_LOCALMSPID="Org2MSP" -e 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 cli peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc -c '{"Args":["set","name","someone"]}'
Image for post
Image for post

We see the invoke fails. The reason is that Org2 has not approved the SACC chaincode.

Now we switch back to lifecycle chaincode, to let Org2 approve the chaincode first before invoke set() again.

Step 7: After organization approves chaincode, it can invoke the chaincode functions.

We now make Org2 approve the chaincode, as Org1 and Org3 did before. Note that it is done after the application chaincode is already committed.

docker exec -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:9051 -e CORE_PEER_LOCALMSPID="Org2MSP" -e 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 cli peer lifecycle chaincode approveformyorg --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name mycc --version 1 --sequence 1 --waitForEvent --signature-policy "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')" --package-id sacc_1:bf57e4926742fd0dbd8716058897cbb60d3530914529a4b9b46817d2324f6399
Image for post
Image for post

And now check the chaincode commit status again. We see Org2 has made the approval.

docker exec cli peer lifecycle chaincode querycommitted --channelID mychannel --name mycc --output json
Image for post
Image for post

Org2 invokes set() with a new value for the same key “name”.

docker exec -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:9051 -e CORE_PEER_LOCALMSPID="Org2MSP" -e 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 cli peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc -c '{"Args":["set","name","someone"]}'
Image for post
Image for post

And check the value of key “name”,

docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'
Image for post
Image for post

Org2 can use SACC chaincode after approval is made.

This ends our demonstration.

Observation

We have walked through the demonstration. Here is some observation.

Chaincode approval is made by consortium member organizations individually. The approval process is a kind of consent that the organization accepts this chaincode. An organization of the consortium can keep “not approving” a chaincode, but it cannot stop the chaincode being useable (committed) as far as the pre-agreed endorsement policy is met. In our example, Org2 can keep “not approving” the chaincode, but as far as majority is met, the chaincode is still committed and useable by those organizations which have made approval.

Those organizations “not approving” chaincode can use the chaincode once they make approval on it, even after the chaincode is already committed and used. In our example, Org2 can use chaincode immediately after it makes approval on a committed chaincode.

An important note is that, even though organizations “not approving” chaincode cannot use the chaincode, they still receive new blocks from ordering service and their ledger is updated. In our example, Org2 will receive all the new blocks and its ledger gets updated even though Org2 has not made approval yet. New blocks arrive in all peers in the channel. The RWSet inside the transactions are used to update the ledger World State in each peer. This ledger update does not involve and rely on any application chaincode. The application chaincode is needed when the peer is to perform chaincode functions defined in the chaincode. It is needed when the peer is an endorsing peer, or query through chaincode functions is made on the peer.

Summary

Through this illustration, we know more about the lifecycle chaincode, and how the endorsement policy is working in an application chaincode. We also show the difference of application chaincode from lifecycle chaincode, and the application chaincode can have a different endorsement policy. All we need is to specify the desired endorsement policy of the application chaincode during we approve and commit it.

Written by

Happy to share what I learn on blockchain. Visit http://www.ledgertech.biz/kcarticles.html for my works. or reach me on https://www.linkedin.com/in/ktam1/.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store