Published on

Working with Hyperledger Fabric Chaincode

Authors

Today we got to the point where we could start deploying chaincode (the Fabric equivalent of smart contracts) to Hyperledger Fabric. This experience demonstrated to me more clearly how the Fabric peer and orderer interact with one another.

A client would communicate with the peer and the orderer. The client would likely be in the form of an application communicating with the Fabric components using one of the Fabric SDKs or the Fabric peer cli tool.

The general chaincode life cycle is as follows:

  • Install the chaincode on peers that will interact with the code (validators)
  • Instantiate (deploy) the chaincode
  • Reading data from the blockchain via the chaincode
  • Writing data to the blockchain via the chaincode

Installing the Chaincode

This involves:

  1. The client sending the code they want to eventually end up on the chain to endorsing peers (these are peers that will validate code execution)
    1. These peers are specified in the endorsement policy which is needed as part of the chaincode instantiation process (which is detailed below)
  2. The peer validates the code:
    1. A success code is returned if successful
    2. Otherwise an error response is returned

A small snippet of the parts of the API that would do this is:

await client.installChaincode(chainCodeRequest)

This outputs the following in the logs:

2018-10-02 15:04:29.731 UTC [lscc] executeInstall -> INFO 0b9 Installed Chaincode [your-chain-code] Version [v1] to peer
2018-10-02 15:04:31.485 UTC [golang-platform] GenerateDockerBuild -> INFO 0ba building chaincode with ldflagsOpt: '-ldflags "-linkmode external -extldflags '-static'"'
2018-10-02 15:04:31.485 UTC [golang-platform] GenerateDockerBuild -> INFO 0bb building chaincode with tags:

This can be represented by the following sequence diagram:

sequenceDiagram
   Client ->> Peer: Chain code sent
   Peer ->> Peer: Chain code validated
  alt is valid
      Peer ->> Peer: Chain code installed on validating peers
      Peer ->> Client: Success code
  else is invalid
      Peer ->> Client: Error
  end

Installing is basically validating that the code is correct. The code is not put onto the chain at this point. But is installed onto peers that will be responsible for validating code (known as endorsing peers).

Instantiating or Writing to Chaincode

This involves:

  1. The client sending a proposal to instantiate code to the peer/s which includes a number of parameters including the endorsement policy
    1. If this is an invocation request (i.e. writing to the chain) then a function name needs to be provided together with 0 or more args to this function
  2. The peer/s validating this proposal:
    1. If valid then send on to the orderer
    2. If invalid then return an error response to the client
  3. The orderer ordering the transactions based on the context of the current channel
  4. The orderer returning the blocks to committing peers
  5. Committing peers validating the chaincode against the endorsement policy (which was specified during when the code proposal was submitted in step 1)
  6. The peer then adding a block to its ledger as described here
    1. If there was an error validating the code then a reason code is included with this block
  7. A response message with the details of the execution being returned to the client

A small snippet of the parts of the API that would do this is:

/* Instantiate chaincode */
results = await channel.sendInstantiateProposal(request, 600000)
//if results status is a 200 then proceed
await channel.sendTransaction(ordererReq, 60000)

This outputs the following in the logs:

2018-10-02 15:04:29.731 UTC [lscc] executeInstall -> INFO 0b9 Installed Chaincode [your-chain-code] Version [v1] to peer
2018-10-02 15:04:31.485 UTC [golang-platform] GenerateDockerBuild -> INFO 0ba building chaincode with ldflagsOpt: '-ldflags "-linkmode external -extldflags '-static'"'
2018-10-02 15:04:31.485 UTC [golang-platform] GenerateDockerBuild -> INFO 0bb building chaincode with tags:
...
2018-10-02 15:13:33.509 UTC [kvledger] CommitWithPvtData -> INFO 0bf Channel [your-channel]: Committed block [29] with 1 transaction(s)

This can be represented by the following sequence diagram:

sequenceDiagram
    Client ->> Peer: code instantiate proposal
    Peer ->> Peer: proposal validated by all endorsing peers
   alt is valid
       Peer ->> Peer: Code signed
       Peer ->> Orderer: Signed code
       Orderer ->> Orderer: Confirm code signed by peer and other checks
       Orderer ->> Orderer: Order transactions based on the current channel
       Orderer ->> Peer: Ordered transactions
       Peer ->> Peer: Validate chaincode against endorsement policy
       Peer ->> Orderer: Transaction based on proposal
       Peer ->> Peer: Add block to ledger (include error reason code if there was an error)
       Peer ->> Client: Message with details of the transaction
   else is invalid
       Peer ->> Client: Error
   end

The client can then use the chainID they assigned to their code to interact with it.

Reading data from the blockchain via the chaincode

This involves:

  1. The client sending a request to the peer containing:
    1. The target peer
    2. The name of the chaincode
    3. The name of the function they want to invoke on the chaincode
    4. The arguments that go to the chaincode function
  2. The peer runs executes the target function and returns the associated data or an error

A small snippet of the parts of the API that would do this is:

await channel.queryByChaincode(request)

This can be represented by the following sequence diagram:

sequenceDiagram
    Client ->> Peer: readRequest(fnName, args)
    Peer ->> Peer: Execute function with given arguments and name
   alt is valid
       Peer ->> Client: Result of executing function against chain
   else is invalid
       Peer ->> Client: Error
   end