This is a continuation of the article that introduced Hyperledger Fabric, published in the previous issue of OSFY. It explores the internal workings of Hyperledger Fabric and takes a look at transaction flow.
In a distributed ledger system, consensus is the process of reaching an agreement on the next set of transactions to be added to the ledger. In Hyperledger Fabric, consensus involves three distinct steps:
- Transaction endorsement
- Validation and commitment
These three steps ensure the policies of a network are upheld. We will look at how these steps are implemented by exploring the transaction flow.
Transaction flow (Step 1)
Within a Hyperledger Fabric network, transactions start out with client applications sending transaction proposals or, in other words, proposing a transaction to endorsing peers.
Client applications are commonly referred to as applications or clients, and allow people to communicate with the blockchain network. Application developers can leverage the Hyperledger Fabric network through the application’s SDK.
Transaction flow (Step 2)
Each endorsing peer simulates the proposed transaction, without updating the ledger. The endorsing peers will capture the sets of read and written data, called RW sets. These RW sets capture what was read from the current world state while simulating the transaction, as well as what would have been written to the world state, had the transaction been executed. These RW sets are then signed by the endorsing peer, and returned to the client application to be used in future steps of the transaction flow.
This is the second step of the transaction flow, when endorsers simulate transactions, generate RW sets, and return the signed RW sets back to the client application. Endorsing peers must hold smart contracts in order to simulate the transaction proposals.
Transaction flow (Step 3)
The application then submits the endorsed transaction and the RW sets to the ordering service. Ordering happens across the network, in parallel with endorsed transactions and RW sets submitted by other applications.
Transaction flow (Step 4)
The ordering service takes the endorsed transactions and RW sets, orders this information into a block, and delivers the block to all committing peers. This is Step 4 of the transaction flow, where the orderer sends the ordered transactions in a block to all committing peers.
The ordering service, which is made up of a cluster of orderers, does not process transactions, smart contracts, or maintain the shared ledger. It only accepts the endorsed transactions and specifies the order in which those transactions will be committed to the ledger. The Fabric v1.0 architecture has been designed such that the specific implementation of ‘ordering’ (Solo, Kafka and BFT) becomes a pluggable component. The default ordering service for Hyperledger Fabric is Kafka. Therefore, the ordering service is a modular component of Hyperledger Fabric.
Transaction flow (Step 5)
The committing peer validates the transaction by checking to make sure that the RW sets still match the current world state—specifically, that the read data that existed when the endorsers simulated the transaction is identical to the current world state. When the committing peer validates the transaction, the transaction is written to the ledger, and the world state is updated with the write data from the RW set.
This is the fifth step of the transaction flow, where committing peers validate each transaction in the block. If the transaction fails, that is, if the committing peer finds that the RW set does not match the current world state, the transaction ordered into a block will still be included in that block, but it will be marked as invalid, and the world state will not be updated. Committing peers are responsible for adding blocks of transactions to the shared ledger and updating the world state. They may hold smart contracts, but it is not a requirement.
Transaction flow (Step 6)
Lastly, the committing peers asynchronously notify the client application of the success or failure of the transaction. Applications will be notified by each committing peer.
In Hyperledger Fabric, chaincode is the ‘smart contract’ that runs on the peers and creates transactions. More broadly, it enables users to create transactions in the Hyperledger Fabric network’s shared ledger and update the world state of the assets.
Chaincode is programmable code, written in Go, and instantiated on a channel. Developers use chaincode to develop business contracts, asset definitions, and collectively-managed decentralised applications. The chaincode manages the ledger state through transactions invoked by applications. Assets are created and updated by a specific chaincode, and cannot be accessed by another chaincode.
Applications interact with the blockchain ledger through the chaincode. Therefore, the chaincode needs to be installed on every peer that will endorse a transaction and is instantiated on the channel.
There are two ways to develop smart contracts with Hyperledger Fabric:
- Code individual contracts into standalone instances of chaincode.
- A more efficient way is to use chaincode to create decentralised applications that manage the life cycle of one or multiple types of business contracts, and let the end users instantiate instances of contracts within these applications.
Overview of a chaincode program
When creating a chaincode, there are two methods that you will need to implement:
- Init: This is called when a chaincode receives an instantiate or upgrade transaction. This is where you will initialise any application state.
- Invoke: This is called when the invoke transaction is received to process any transaction proposals.
As a developer, you must create both an Init and an Invoke method within your chaincode. The chaincode must be installed using the peer chaincode install command, and instantiated using the peer chaincode instantiate command before the chaincode can be invoked. Then, transactions can be created using the peer chaincode invoke or peer chaincode query commands.
Important interfaces that you can use when writing your chaincode are defined by Hyperledger Fabric —ChaincodeStub and ChaincodeStubInterface. The former provides functions that allow you to interact with the underlying ledger to query, update and delete assets. The key APIs for chaincode include:
func (stub *ChaincodeStub) GetState(key string) (byte, error)
The above command returns the value of the specified key from the ledger. Note that GetState doesn’t read data from the write set, which has not been committed to the ledger. In other words, GetState doesn’t consider data modified by PutState that has not been committed. If the key does not exist in the state database, (nil, nil) is returned.
func (stub *ChaincodeStub) PutState(key string, value byte) error
The above command puts the specified key and value into the transaction’s write set as a data-write proposal. PutState doesn’t affect the ledger until the transaction is validated and successfully committed.
func (stub *ChaincodeStub) DelState(key string) error
The above command records the specified key to be deleted in the write set of the transaction proposal. The key and its value will be deleted from the ledger when the transaction is validated and successfully committed.
With this tutorial, we complete the learning part related to Hyperledger Fabric. In my next article, we will walk through using Fabric for a specific use case.