Click here to Skip to main content
15,867,488 members
Articles / Security / Blockchain

Hyperledger Fabric: Concepts, Configuration, and Deployment

,
Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
19 Aug 2019CPOL15 min read 4.8K   1  
This article will be useful for both businesses and developers who want more information about Hyperledger Fabric and its use cases.

Introduction

Hyperledger Fabric is one of the most advanced and unique blockchain platforms. This platform allows you to create private networks, adjusting them to the needs of your project or business.

In this article, we discuss the network’s functionality, strengths, and weaknesses. For a practical task, we configure and deploy a basic network and then add custom business logic. After that, we compare our solution with other similar implementations based on different platforms.

Contents

Why is Hyperledger Fabric Suitable for Business?

It’s difficult to compare Hyperledger Fabric to any other blockchain network like Bitcoin or Ethereum. Unlike most other networks, Hyperledger isn’t intended for public use.

In fact, there’s no such thing as the Hyperledger mainnet. Hyperledger is a platform for developing custom networks to suit your needs.

You may want to build a custom network for your project for several reasons:

  • You need the functionality that isn’t available in any existing network.
  • Each of your tasks or customers is unique and requires special treatment within the platform.
  • You need to secure your data or keep some of it private.
  • You want to control access to your network.

Apart from the opportunity to adjust a private blockchain to your specific needs, you can also benefit from the absence of commission and independence from external factors such as miners and price movements.

Industries and projects such as the following will benefit from Hyperledger Fabric:

  • Logistics (supply chain management)
  • Finance (audits and accounting)
  • Medical records
  • Distributed databases for managing the electrical grid
  • Educational platforms

possible applications of Hyperledger Fabric

Possible applications of Hyperledger Fabric

However, Hyperledger Fabric is designed for field-specific private networks with explicit access restrictions and data ownership, so it won’t work for use cases such as:

  • Crowdsales
  • Trading
  • Currency exchange and transfer
  • Public auctions, elections, etc.

All of these use cases require a truly decentralized network that provides all users with equal rights to ensure fair conditions – for example, to eliminate the chance of vote-rigging.

What is Hyperledger Fabric?

Hyperledger Fabric is a blockchain platform aimed at creating private business-focused networks. Initially developed by Digital Asset and IBM, Fabric is one of the Hyperledger projects hosted by the Linux Foundation.

Hyperledger Fabric provides developers with an opportunity to build solid applications with a modular architecture. It uses container technology to host an analog of smart contracts, called chaincode.

Key features of the Hyperledger blockchain platform include:

  • Tamper-resistant records of all state transitions
  • Tools for managing identities with a Membership Service Provider (MSP)
  • Efficient processing of transactions without any mining overhead
  • Chaincode functionality to add custom logic that can be invoked by specific transactions
  • Modular design to allow for advanced network customization

Although conventional blockchain networks require consensus protocols like Proof of Work to validate transactions and secure the network, they still allow unknown actors to participate. Members of a Hyperledger Fabric network enroll through a trusted MSP.

The focus on a single private application and strict membership control allows a Hyperledger Fabric network to reduce consensus overhead: eliminating extra mining accelerates block creation, which leads to faster transaction approval.

In Hyperledger, a consensus is simply a verification of a set of transactions in a block. A consensus also includes endorsement policies to make sure each participating organization agrees on the transaction.

Hyperledger Fabric vs Graphene Framework

Both Hyperledger Fabric and the Graphene Framework are designed for creating custom blockchain networks. They provide critical components – data storage, consensus algorithms, and networking – allowing you to focus on the things that are essential for your project.

However, there are a couple of differences between Hyperledger Fabric and Graphene.

The key difference is that Graphene was designed as a source code framework. To create your blockchain network using Graphene, you have to fork its source code, edit it, and compile it. This is useful if you want to change the core components of the network, such as the consensus algorithm. However, you also have to edit the source code if you’re going to add any kind of custom logic to the network.

On the other hand, Hyperledger’s core components were not intended to be heavily customized. Chaincode provides an easy way of adding custom functionality. With features such as access separation through channels, endorsement policies, and built-in membership control, Hyperledger is the best option for business applications.

Hyperledger Fabric vs Graphene Framework

Hyperledger Fabric: Network Architecture Components

Let’s explore the basic elements of the Hyperledger network architecture before building our solution based on the Hyperledger Fabric blockchain. This will give us a better understanding of how the platform performs and what makes Hyperledger Fabric so special.

Hyperledger Fabric architecture components

Organizations and Consortiums

Organizations are the main actors in a Hyperledger Fabric network. In most cases, multiple organizations come together as a consortium to form the network. Their permissions are determined by a set of policies, which are agreed by the consortium when configuring the new network.

Chaincode

In Hyperledger, chaincode is the equivalent to smart contracts. Its functionality is similar to any other smart contract implementation: users can create and upload custom business logic that works with on-chain data. Chaincode runs on different peers and different channels. Not every peer is required to run chaincode to access the ledger.

Chaincode has some unique features. For instance, Hyperledger Fabric allows for managing users’ access to the network. Certain smart contracts (or their functions) may have restricted access. Moreover, since access restriction is integrated into the network, you don’t have to rely on the smart contract developer to ensure that the contract’s functions are safe.

Another great feature is the native runtime for chaincode. Chaincode is written in Go and works as a separate program on the peer node. This ensures extremely high efficiency when compared to networks with virtual machines (Ethereum, EOS).

Orderers

Orderers are the backbone of the network. They form the ordering service, which is a communication fabric that guarantees fair transaction delivery. Ordering service can include a single node, used for development or testing purposes. It can also be a complex system of nodes with defined fault tolerance.

An ordering service provides a shared communication channel to clients and peers, offering a broadcast service for messages containing transactions. Orderers are responsible for ensuring atomic delivery of all messages or consensus of transactions within each channel.

Peers

The network is mostly represented by a set of peer nodes, or simply peers. Peers are one of the key elements of the network, as they take part in almost every aspect of it. Each organization may have one or several peers to suit their needs.

Each peer keeps a local copy of the ledger for each channel and may run chaincode instances locally. Thus, peer nodes are responsible for providing client applications with access to the ledger and the chaincode of their channels.

Channels

A channel is a dedicated line of communication between several peers. It’s a logical structure formed by a combination of peer nodes.

All interactions with channels are done through peers. Network clients may broadcast messages on a channel to deliver them to all peers within that channel. Channels support atomic delivery of all messages. In other words, they output the same messages to all connected peers, so the peers receive messages in the same order.

This atomic communication is also called a total-order broadcast, atomic broadcast, or consensus in the context of distributed systems. The communicated messages are candidate transactions for inclusion in the blockchain state.

Each channel has its independent blockchain state with a completely independent ledger. So we get as many separate blockchains as there are channels. If a peer accesses multiple channels, it will have a separate copy of the ledger for each channel.

Policies and Configuration

There are various types of policies in Hyperledger Fabric, from simple ones like access to administrative functions, channel creation, and chaincode instantiation to complex endorsement (validation) policies that define which peers should confirm each specific transaction.

Policies are agreed by the consortium when the network is originally configured. Network policies can change over time, subject to agreement by all organizations in the consortium.

Basic Network Setup

Now that you know the basic concepts behind Hyperledger Fabric, we can move on to creating our private network.

Let’s create a basic network to see how all of these concepts fit together. First, we have to define the organizations to be part of the network. To do this, we can use the cryptogen tool, which is bundled with the network’s binaries.

cryptogen takes a configuration file that defines each organization and its members and creates the necessary certificates for each member. Our configuration file contains definitions for three organizations, two peers, and one orderer:

# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
  # ---------------------------------------------------------------------------
  # Orderer
  # ---------------------------------------------------------------------------
  - Name: Orderer
    Domain: example.com
    # ---------------------------------------------------------------------------
    # "Specs" - See PeerOrgs below for complete description
    # ---------------------------------------------------------------------------
    Specs:
      - Hostname: orderer
# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
  # ---------------------------------------------------------------------------
  # Org1: A simple organization
  # ---------------------------------------------------------------------------
  - Name: Org1
    Domain: org1.example.com
    EnableNodeOUs: true
    Template:
      Count: 2
    Users:
      Count: 1
  # ---------------------------------------------------------------------------
  # Org2: Another simple organization
  # ---------------------------------------------------------------------------
  - Name: Org2
    Domain: org2.example.com
    EnableNodeOUs: true
    Template:
      Count: 2
    Users:
      Count: 1

Certificates and other cryptographical material for organizations can be generated like this:

# Generate organization keys and certificates using cryptogen tool 
# from configuration specified in crypto-config.yaml
$ ..⁄bin⁄cryptogen generate --config=.⁄crypto-config.yaml
# Generate genesis block using configtx.yaml

Then, we can configure the basic network. To deploy the configurations to the network, we have to perform configuration transactions to send the data. At first, we have to create configuration transactions that define basic parameters for the network.

In total, we’ll need to make four transactions:

  • A genesis block transaction
  • A transaction to create a channel
  • Two transactions to introduce an anchor peer for each of the two organizations within the new channel

To create configuration transactions, we can use the configtxgen tool, which is bundled with Hyperledger. Similar to cryptogen, configtxgen accepts a configuration file. Using configtxgen, you can prepare transactions like these:

$ export FABRIC_CFG_PATH=$PWD # configtx is in current directory
$ ../bin/configtxgen -profile TwoOrgsOrdererGenesis 
  -outputBlock ./channel-artifacts/genesis.block
2018-11-16 16:18:23.008 EET [common/tools/configtxgen] 
 main -> WARN 001 Omitting the channel ID for configtxgen for 
 output operations is deprecated. Explicitly passing the channel ID 
 will be required in the future, defaulting to 'testchainid'.
2018-11-16 16:18:23.008 EET [common/tools/configtxgen] 
           main -> INFO 002 Loading configuration
2018-11-16 16:18:23.048 EET [common/tools/configtxgen] 
           doOutputBlock -> INFO 003 Generating genesis block
2018-11-16 16:18:23.050 EET [common/tools/configtxgen] 
           doOutputBlock -> INFO 004 Writing genesis block
# Create the channel transaction 
# channel.tx contains the definitions for our sample channel
# Using the same configtx.yaml
$ ../bin/configtxgen -profile TwoOrgsChannel 
  -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
2018-11-16 16:23:12.171 EET [common/tools/configtxgen] 
     main -> INFO 001 Loading configuration
2018-11-16 16:23:12.194 EET [common/tools/configtxgen] 
     doOutputChannelCreateTx -> INFO 002 Generating new channel configtx
2018-11-16 16:23:12.202 EET [common/tools/configtxgen] 
     doOutputChannelCreateTx -> INFO 003 Writing new channel tx
# Define the anchor peer for Org1 on the channel
$ ../bin/configtxgen -profile TwoOrgsChannel 
  -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx 
  -channelID mychannel -asOrg Org1MSP
2018-11-16 16:25:02.819 EET [common/tools/configtxgen] 
  main -> INFO 001 Loading configuration
2018-11-16 16:25:02.843 EET [common/tools/configtxgen] 
  doOutputAnchorPeersUpdate -> INFO 002 Generating anchor peer update
2018-11-16 16:25:02.844 EET [common/tools/configtxgen] 
  doOutputAnchorPeersUpdate -> INFO 003 Writing anchor peer update
# Same for org2
$ ../bin/configtxgen -profile TwoOrgsChannel 
  -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx 
  -channelID mychannel -asOrg Org2MSP
2018-11-16 16:26:22.866 EET [common/tools/configtxgen] 
  main -> INFO 001 Loading configuration
2018-11-16 16:26:22.900 EET [common/tools/configtxgen] 
  doOutputAnchorPeersUpdate -> INFO 002 Generating anchor peer update
2018-11-16 16:26:22.900 EET [common/tools/configtxgen] 
  doOutputAnchorPeersUpdate -> INFO 003 Writing anchor peer update

Once these transactions have been performed, we can launch the network.

The Hyperledger Fabric repository contains examples of both configuration files and Docker files to help you get started. For this tutorial, let’s use the basic network example from the Hyperledger GitHub repository.

This particular example starts a network with two peers in a single channel. It launches a separate Docker container for each of the peers.

To start all of the nodes within the network, we use these commands:

# Starting docker container
PS ~\my-network> $Env:IMAGE_TAG="1.3.0"
PS ~\my-network> $Env:COMPOSE_PROJECT_NAME="my-net"
PS ~\my-network> $Env:COMPOSE_CONVERT_WINDOWS_PATHS=1 # optional for ubuntu
PS ~\my-network> docker-compose -f docker-compose-cli.yaml up -d
Creating peer0.org1.example.com ... done
Creating peer1.org2.example.com ... done
Creating peer0.org2.example.com ... done
Creating peer1.org1.example.com ... done
Creating orderer.example.com    ... done
Creating cli                    ... done

Now we can send transactions to configure the network. We’ll use a single container that can connect to each of the nodes since it has every certificate that we generated. This container is used just for convenience.

To sum up, we’ve created a few containers for our network:

  • One orderer service (orderer.example.com)
  • Four peers: two peers for each organization (peerX.orgY.example.com)
  • A convenience client container (cli) to make it easy to access our peers

In the real world, these actions would be done separately by each organization:

PS ~\my-network> docker exec -it cli bash
# Environment vars for connecting to peer from cli
# Variables for peer0 of org1
# can be replaced in docker config or when running
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/
peer/crypto/peerOrganizations/org1.example.com/users/
<span id="cloak684d3fbc3a3931541e63b4511bd18dcc">
<a href="mailto:Admin@org1.example.com">Admin@org1.example.com</a>
</span><script>document.getElementById
('cloak684d3fbc3a3931541e63b4511bd18dcc').innerHTML='';
var prefix='ma'+'il'+'to';var path='hr'+'ef'+'=';
var addy684d3fbc3a3931541e63b4511bd18dcc='Admin'+'@';
addy684d3fbc3a3931541e63b4511bd18dcc=addy684d3fbc3a3931541e63b4511bd18dcc+'org1'+
'.'+'example'+'.'+'com';
 var addy_text684d3fbc3a3931541e63b4511bd18dcc='Admin'+'@'+
'org1'+'.'+'example'+'.'+'com';document.getElementById
('cloak684d3fbc3a3931541e63b4511bd18dcc').innerHTML+='<a '+path+'\''+prefix+':
'+addy684d3fbc3a3931541e63b4511bd18dcc+'\'>'+
addy_text684d3fbc3a3931541e63b4511bd18dcc+'<\/a>';</script>/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export 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
# now run our channel transaction
# uses channel.tx generated earlier. Also uses certificates for authentication 
root@f48febb2a629:/opt/gopath/src/github.com/hyperledger/fabric/
peer# peer channel create -o orderer.example.com:7050 -c mychannel 
-f ./channel-artifacts/channel.tx --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
2018-11-16 15:50:46.693 UTC [channelCmd] InitCmdFactory -> 
INFO 001 Endorser and orderer connections initialized
2018-11-16 15:50:47.058 UTC [cli/common] readBlock -> INFO 002 Received block: 0
# the command created a mychannel.block file with the genesis block
# this block can be used to join the channel
root@f48febb2a629:/opt/gopath/src/github.com/hyperledger/fabric/peer#  
peer channel join -b mychannel.block
2018-11-16 15:54:14.337 UTC [channelCmd] InitCmdFactory -> 
INFO 001 Endorser and orderer connections initialized
2018-11-16 15:54:15.486 UTC [channelCmd] executeJoin -> 
INFO 002 Successfully submitted proposal to join channel
# change env variables and join as other peers 
root@f48febb2a629:/opt/gopath/src/github.com/hyperledger/fabric/
peer# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/
fabric/peer/crypto/peerOrganizations/org2.example.com/users/
<span id="cloakc4d35f5980e63e62517bf3f1a6028fb6">
<a href="mailto:Admin@org2.example.com">Admin@org2.example.com</a>
</span><script>document.getElementById
('cloakc4d35f5980e63e62517bf3f1a6028fb6').innerHTML='';
var prefix='ma'+'il'+'to';var path='hr'+'ef'+'=';
var addyc4d35f5980e63e62517bf3f1a6028fb6='Admin'+'@';
addyc4d35f5980e63e62517bf3f1a6028fb6=addyc4d35f5980e63e62517bf3f1a6028fb6+'org2'+'.'+
'example'+'.'+'com';
 var addy_textc4d35f5980e63e62517bf3f1a6028fb6='Admin'+'@'+'org2'+
'.'+'example'+'.'+'com';document.getElementById
('cloakc4d35f5980e63e62517bf3f1a6028fb6').innerHTML+='<a '+path+'\''+prefix+':
'+addyc4d35f5980e63e62517bf3f1a6028fb6+'\'>'+
addy_textc4d35f5980e63e62517bf3f1a6028fb6+'<\/a>';
</script>/msp CORE_PEER_ADDRESS=peer0.org2.example.com:7051 
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 peer channel join -b mychannel.block 

Chaincode Implementation

Once you have a full network running, you can start adding chaincode to your application. The main difference between chaincode in Hyperledger and smart contracts in Ethereum or EOS is that with chaincode we can configure who exactly can execute a smart contract, since Hyperledger Fabric is a permissioned blockchain.

Another difference is that chaincode runs separately on the peer’s machine itself, without any of the overhead a virtual machine introduces. These factors make chaincode in Hyperledger more secure and efficient than smart contracts on any other platform.

Let’s create an example chaincode program for our network. We’re going to create a simple delivery system. The basic functionality of the chaincode will be:

  • Creating delivery orders (for users)
  • Accepting orders and picking them up (for couriers)
  • Receiving payments for successful completing deliveries (for couriers)
  • Creating a dispute and receiving a refund (for users)

Another part of this chaincode system is a simple token implementation to keep track of payments. The token will be included with the rest of the chaincode and will feature three functions:

  1. Mint – for the owner to create new tokens
  2. Transfer – for users to transfer tokens
  3. Get balance – to get a user’s balance

With these simple requirements in mind, we can start creating the chaincode itself. First of all, we have to implement two lifecycle functions: Init and Invoke.

The Init function is responsible for initializing the chaincode. This function is executed every time the chaincode is instantiated or updated in a channel.

Usually, it would create some basic data structures, set up initial balances, etc. However, since this function is called with each update to the chaincode, it has to be changed with every update so that it won’t override the current state of the ledger.

C++
// Init runs initialization for chaincode
func (t *DeliveryChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
  caller, err := callerCN(stub)
  if err != nil {
    return shim.Error("Error getting caller cn")
  }
  ownerKey, err := getOwnerKey(stub)
  if err != nil {
    return shim.Error("Error getting database key")
  }
  err = stub.PutState(ownerKey, []byte(caller))
  if err != nil {
    return shim.Error("Error saving token data")
  }
  return shim.Success(nil)
}

The second function, Invoke, is called each time you refer to the chaincode. It’s responsible for selecting the action to perform, for example, transferring tokens or placing an order.

Let’s implement both functions. For the Init function, we set up the token parameters and fetch the contract creator’s (owner’s) address. Also, Invoke simply reads arguments and invokes an appropriate action.

C++
// Invoke runs functions of chaincode
func (t *DeliveryChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
  fn, args := stub.GetFunctionAndParameters()
  switch fn {
  case "transfer":
    return t.transfer(stub, args)
  case "mint":
    return t.mint(stub, args)
  case "balance":
    return t.balance(stub, args)
  case "deliveryOrder":
    return t.placeDeliveryOrder(stub, args)
    ...
  }
  return shim.Error("Undefined function")
}

In the Init function, you can see two interesting uses of the chaincode API:

  • Retrieving a user’s address
  • Storing it as the owner of the chaincode

There are no addresses in the Hyperledger network in the same sense as they exist in Ethereum or Bitcoin. You can use any identification method you like in Hyperledger Fabric.

The simplest is the built-in certificate authentication. We can use the certificate domain as the address since the MSP makes sure that each organization has a unique domain. In the end, the implementation for extracting information from a caller’s certificate to use it as the address looks like this:

C++
//CallerCN extracts caller certificate from call data
func callerCN(stub shim.ChaincodeStubInterface) (string, error) {
  data, _ := stub.GetCreator()
  serializedID := msp.SerializedIdentity{}
  err := proto.Unmarshal(data, &serializedID)
  if err != nil {
    return "", errors.New("Could not unmarshal Creator")
  }
  cn, err := cnFromX509(string(serializedID.IdBytes))
  if err != nil {
    return "", err
  }
  return cn, nil
}

After handling all of this data, we have to store it permanently in the ledger. We can use the Hyperledger key-value storage to do that. Both keys and values are completely arbitrary, and once written, they persist forever within the ledger. For example, to store and retrieve balances of users’ tokens, we need to do this:

C++
func (t *DeliveryChaincode) 
setValue(stub shim.ChaincodeStubInterface, key string, balance uint64) error {
  data := make([]byte, 8)
  binary.LittleEndian.PutUint64(data, balance)
  return stub.PutState(key, data)
}
func (t *DeliveryChaincode) getValue(stub shim.ChaincodeStubInterface, key string) 
     (uint64, error) {
  data, err := stub.GetState(key)
  if err != nil {
    return 0, err
  }
  // if the user cn is not in the state, then the balance is 0
  if data == nil {
    return 0, nil
  }
  return binary.LittleEndian.Uint64(data), nil
}

At this point, we can define some data structures for function arguments and storage. Using Golang’s built-in JSON marshaling, we can store all of the data as JSON values and parse them as needed.

For example, when implementing delivery order placement functionality, we have to use two structures: one to receive as the parameter, the second to store delivery data in the ledger.

C++
//Delivery information about a single delivery
type Delivery struct {
  DeliveryID uint64         `json:"ID"`
  Customer   string         `json:"customer"`
  Courier    string         `json:"courier"`
  From       string         `json:"from"`
  To         string         `json:"to"`
  Date       uint64         `json:"date"`
  Payment    uint64         `json:"payment"`
  Status     deliveryStatus `json:"status"`
}
type deliveryParams struct {
  From    string `json:"from"`
  To      string `json:"to"`
  Date    uint64 `json:"date"`
  Payment uint64 `json:"payment"`
}
func (t *DeliveryChaincode) placeDeliveryOrder
(stub shim.ChaincodeStubInterface, args []string) peer.Response {
  params := deliveryParams{}
  caller, _, err := getCallParams(stub, args, params)
  if err != nil {
    return shim.Error(err.Error())
  }
  count, _ := t.getValue(stub, TotalDeliveries)
  t.setValue(stub, TotalDeliveries, count+1)
  var newDelivery = Delivery{
    DeliveryID: count + 1,
    Customer:   caller,
    From:       params.From,
    To:         params.To,
    Date:       params.Date,
    Payment:    params.Payment,
    Status:     available,
  }
  t.setDelivery(stub, newDelivery)
  deliveryJSON := deliveryID{
    DeliveryID: newDelivery.DeliveryID,
  }
  result, _ := json.Marshal(deliveryJSON)
  return shim.Success(result)
}

Once this functionality is implemented, we add an appropriate call from the Invoke function so that users can execute the new code.

The rest of the functions are implemented similarly. At this point, you can focus on adding meaningful business logic and expanding the functionality. While the Hyperledger API for chaincode provides even more advanced tools, the ones described here are enough to get you started with building useful contracts.

For example, using the delivery data structure, token functionality, and owner’s address that we stored earlier, we can easily add a function for the owner to resolve a dispute between a courier and a customer:

C++
type resolveDispute struct {
  DeliveryID uint64 `json:"delivery"`
  Refund     bool   `json:"refund"`
}
func (t *DeliveryChaincode) resolveDispute
     (stub shim.ChaincodeStubInterface, args []string) peer.Response {
  params := resolveDispute{}
  caller, owner, err := getCallParams(stub, args, params)
  if err != nil {
    return shim.Error(err.Error())
  }
  delivery, _ := t.getDelivery(stub, params.DeliveryID)
  // Is delivery available
  if delivery.Status != dispute {
    return shim.Error("Delivery not available.")
  }
  // Check the customer
  if owner != caller {
    return shim.Error("Only owner can resolve a dispute.")
  }
  delivery.Status = complete
  if params.Refund {
    // Pay the customer
    keyCustomer, _ := stub.CreateCompositeKey(BalanceKey, []string{delivery.Customer})
    balance, _ := t.getValue(stub, keyCustomer)
    t.setValue(stub, keyCustomer, balance+delivery.Payment)
  } else {
    // Pay the courier
    keyCourier, _ := stub.CreateCompositeKey(BalanceKey, []string{delivery.Courier})
    balance, _ := t.getValue(stub, keyCourier)
    t.setValue(stub, keyCourier, balance+delivery.Payment)
  }
  t.setDelivery(stub, delivery)
  result, _ := json.Marshal(delivery)
  return shim.Success(result)
}

Deploying the chaincode is very simple. First, we switch to a connected Docker container:

C++
> docker exec -it cli bash

Then we run our deployed chaincode:

C++
# query the chaincode mycc
peer chaincode query -C mychannel -n mycc -c '{"Args":["balance"]}'
#invoke the chaincode
peer chaincode invoke -o orderer.example.com:7050 
-C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 
-c '{"Args":["transfer","org2.example.com","10"]}'

Advanced Network Configuration

Let’s take a look back at our network configuration example. There are two organizations that both run an orderer. Each has a peer within a single channel. There’s a single chaincode running on this channel.

This configuration is far from a real-world scenario. In real life, we may have to deal with far more actors involved in network governance, much more complicated access policies, and probably some inter-channel communications between organizations.

We can improve the example network by adding extra organizations, introducing new channels between them, and deploying separate instances of the chaincode in the new channels.

Another simplification in our network is that the Hyperledger Fabric deployment happens on a single machine. Although you would still use Docker for deploying a real network, a more advanced script with proper separation of peers and orderers would be required.

However, other than the scale and deployment methods, our network and its functionality are fairly realistic. So it serves to demonstrate Hyperledger’s capabilities.

Implementation Comparison

Of course, Hyperledger Fabric isn’t the only network that allows for the creation of custom on-chain business logic. Let’s compare our sample implementation to similar solutions based on different networks.

While comparing, we’ll mostly take into consideration the following factors:

  • Effectiveness (based on performance and scalability)
  • Development costs
  • Ease of use
  • Security

Usually, the go-to choice for creating any kind of application using blockchain technology is the Ethereum network. However, in this particular case, it may not be up to the task. The core logic of our sample application (creating delivery orders, paying for completed orders, handling refunds, etc.) is trivial to implement using smart contracts on Ethereum.

However, the basic Ethereum network applies Proof of Work consensus, which means that transaction processing takes a lot of time and energy. On the other hand, consensus in Hyperledger is much more efficient with a custom algorithm.

Some Ethereum implementations allow for adding Proof of Authority consensus as a plug-in consensus algorithm. However, it comes with the downside of increased production costs, as a new smart contract would have to be implemented for the permissioned functionality, which is present in Hyperledger Fabric by default. This would increase system complexity and lead to potential attack vectors and vulnerabilities.

Another good contender is EOS. It was originally based on the Graphene platform, adding smart contract functionality based on WebAssembly (WASM). EOS features performance similar to Hyperledger thanks to its Delegated Byzantine Fault Tolerance (dBFT) consensus algorithm.

However, just like Ethereum, EOS lacks permissioning features, which would have to be implemented manually. Also, EOS is limited in performance and functionality by its WASM virtual machine, while Hyperledger can leverage native performance with advanced functionality of the Go programming language.

Considering these factors, Hyperledger Fabric is the best choice over other more conventional networks. What Hyperledger lacks in decentralization it makes up for in flexibility, performance, and advanced features.

Conclusion

Hyperledger has unique functionality compared to other popular blockchains. Its permissioned nature, great access control, and scalability make Hyperledger Fabric probably the best choice for building a dedicated blockchain network.

History

  • 19th August, 2019: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Apriorit Inc.
United States United States
ApriorIT is a software research and development company specializing in cybersecurity and data management technology engineering. We work for a broad range of clients from Fortune 500 technology leaders to small innovative startups building unique solutions.

As Apriorit offers integrated research&development services for the software projects in such areas as endpoint security, network security, data security, embedded Systems, and virtualization, we have strong kernel and driver development skills, huge system programming expertise, and are reals fans of research projects.

Our specialty is reverse engineering, we apply it for security testing and security-related projects.

A separate department of Apriorit works on large-scale business SaaS solutions, handling tasks from business analysis, data architecture design, and web development to performance optimization and DevOps.

Official site: https://www.apriorit.com
Clutch profile: https://clutch.co/profile/apriorit
This is a Organisation

33 members

Written By
Apriorit
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --