In this article, weโre going to tackle one of the most advanced and unique blockchain platforms โ Hyperledger Fabric. This platform allows you to create private networks, adjusting them to the needs of your project or business.
Weโll discuss the networkโs functionality, strengths, and weaknesses. For a practical task, weโll configure and deploy a basic network and then add custom business logic. After that, weโll compare our solution with other similar implementations based on different platforms.
This article will be useful for both businesses and developers who want more information about Hyperledger Fabric and its use cases.
Contents:
- Why is Hyperledger Fabric suitable for business?
- What is Hyperledger Fabric?
- Hyperledger Fabric vs. Graphene Framework
- Hyperledger Fabric: network architecture components
- Organizations and consortiums
- Chaincode
- Orderers
- Peers
- Channels
- Policies and configuration
- Basic network setup
- Chaincode implementation
- Advanced network configuration
- Implementation comparison
- Conclusion
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 a number of reasons:
- You need 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
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 own 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 definitely the best option for business applications.
Hyperledger Fabric: Network architecture components
Letโs explore the basic elements of the Hyperledger network architecture before building our own 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.
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 in different channels. Not every peer is required to run chaincode in order 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).
Read also:
5 Security Tips for Writing Smart Contracts
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 a 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 own 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 own 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 in order 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="cloak8b19f81c01224453b8cbd9d3bc324381"><a href="mailto:[email protected]">[email protected]</a></span><script type="text/javascript">
document.getElementById('cloak8b19f81c01224453b8cbd9d3bc324381').innerHTML = '';
var prefix = 'ma' + 'il' + 'to';
var path = 'hr' + 'ef' + '=';
var addy8b19f81c01224453b8cbd9d3bc324381 = 'Admin' + '@';
addy8b19f81c01224453b8cbd9d3bc324381 = addy8b19f81c01224453b8cbd9d3bc324381 + 'org1' + '.' + 'example' + '.' + 'com';
var addy_text8b19f81c01224453b8cbd9d3bc324381 = 'Admin' + '@' + 'org1' + '.' + 'example' + '.' + 'com';document.getElementById('cloak8b19f81c01224453b8cbd9d3bc324381').innerHTML += '<a ' + path + '\'' + prefix + ':' + addy8b19f81c01224453b8cbd9d3bc324381 + '\'>'+addy_text8b19f81c01224453b8cbd9d3bc324381+'<\/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="cloakc31b3858547886bd88d9e2373037ccfd"><a href="mailto:[email protected]">[email protected]</a></span><script type="text/javascript">
document.getElementById('cloakc31b3858547886bd88d9e2373037ccfd').innerHTML = '';
var prefix = 'ma' + 'il' + 'to';
var path = 'hr' + 'ef' + '=';
var addyc31b3858547886bd88d9e2373037ccfd = 'Admin' + '@';
addyc31b3858547886bd88d9e2373037ccfd = addyc31b3858547886bd88d9e2373037ccfd + 'org2' + '.' + 'example' + '.' + 'com';
var addy_textc31b3858547886bd88d9e2373037ccfd = 'Admin' + '@' + 'org2' + '.' + 'example' + '.' + 'com';document.getElementById('cloakc31b3858547886bd88d9e2373037ccfd').innerHTML += '<a ' + path + '\'' + prefix + ':' + addyc31b3858547886bd88d9e2373037ccfd + '\'>'+addy_textc31b3858547886bd88d9e2373037ccfd+'<\/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 successfully 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:
- Mint โ for the owner to create new tokens
- Transfer โ for users to transfer tokens
- 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.
// 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.
// 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:
//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:
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.
//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 actually execute the new code.
The rest of the functions are implemented in a similar way. 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:
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:
> docker exec -it cli bash
Then we run our deployed chaincode:
# 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
In this article, we highlighted major strengths and weaknesses of Hyperledger Fabric, briefly described the concept of the networkโs architecture, and created a simple private network.
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.
At Apriorit, we use many technologies and tools, and weโre open to projects of any complexity. Our seasoned specialists are ready to develop an advanced blockchain-driven solution for your project.