DEV Community

Cover image for 
Getting started with Hyperledger Fabric on macOS
capricious_rebel
capricious_rebel

Posted on

Getting started with Hyperledger Fabric on macOS

What is Hyperledger
"Hyperledger Fabric is a modular blockchain framework that acts as a foundation for developing blockchain-based products using plug-and-play components that are aimed for use within private enterprises" - Investopedia

Why Hyperledger
While you may have heard of ethereum, polygon and solana being commonly used for blockchain development, these are public blockchains. As public blockchains, all the code, data and activities are available for anyone to access. For large companies like Walmart, a lot of whose code is IP and not publicly available, this maybe a problem.

Hyperledger allows large enterprises to set up their own copy of the blockchain whether its for just collaboration within a team, within a company or across a fixed set of companies. This gives them more control on their processes within the blockchain.

Several other benefits of Hyperledger are:

  1. Privacy: Hyperledger fabric is a permissioned, private blockchain where organizations can cooperate with other authorized organizations while sharing resources, away from the public view.
  2. Modularity and Reusability: Everything a developer builds on Fabric is reusable.
  3. Scalability: Thanks to the plug-and-play approach, scaling an application becomes a delight.
  4. Support and Credibility: Hyperledger is built under the Linux Foundation, One of the most well-respected communities of developers, and comes with extensive, well-written documentation.

An example of a practical use case: "A B2B Contract"

Suppose business A wants a service from business B, then there is a requirement for a contract to be agreed upon by both the parties. The businesses can join a channel on the fabric network, deploy a chain code that both agree upon, and automate the contract.

Since the blockchain is permissioned, only the two businesses involved can see the contract and interact with it. At the same time, no third party has access to any sensitive/private business information shared over the blockchain.

Installation Steps
In this blog, we will install Hyperledger Fabric on macOS along with Fabric Samples.

  1. Channel is a private 'subnet' of communication between two or more specific network members. Think of it as a private group on the network.

  2. Chaincode is a program, written in Go, node.js, or Java that runs in a secured Docker container on the network. It manages the ledger and implements business logic.

We will be using fabric-samples/test-network scripts and doing the following:

  • Create a test network.
  • Create two example orgs on this test-network.
  • Create a channel and have the two orgs join it.
  • Deploy a chaincode onto the channel after both the orgs approve it.

Step 1: Install pre-requisites.

Homebrew
Install the latest version of Homebrew:

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Enter fullscreen mode Exit fullscreen mode

Along with Homebrew installation, Xcode cli tools are installed (if not already installed).

Ensure Homebrew is installed:

$ brew --version
Homebrew 3.3.12
Homebrew/homebrew-core (git revision b81bc29e8a1; last commit 2022-01-24)
Homebrew/homebrew-cask (git revision 7792a6e065; last commit 2022-01-24)
Enter fullscreen mode Exit fullscreen mode

Git
Install the latest version of Git

$ brew install git
Enter fullscreen mode Exit fullscreen mode

Ensure Git is installed:

$  git --version
git version 2.35.1
Enter fullscreen mode Exit fullscreen mode

cURL

Install the latest version of cURL:

$ brew install curl
Enter fullscreen mode Exit fullscreen mode

Ensure cURL is installed:

$ curl --version
curl 7.64.1 (x86_64-apple-darwin20.0) libcurl/7.64.1 (SecureTransport) LibreSSL/2.8.3 zlib/1.2.11 nghttp2/1.41.0
Release-Date: 2019-03-27
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS GSS-API HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz MultiSSL NTLM NTLM_WB SPNEGO SSL UnixSockets
Enter fullscreen mode Exit fullscreen mode

Docker

Download docker desktop from here

Ensure docker and docker-compose is installed:

$ docker --version
Docker version 20.10.12, build e91ed57
$ docker-compose --version
Docker Compose version v2.2.3 
Enter fullscreen mode Exit fullscreen mode

Go
(for Go chaincode or SDK applications)
Install the latest supported version of go:

$ brew install go@1.17.5
Enter fullscreen mode Exit fullscreen mode

Ensure go is installed:

$ go version
go1.17.5 darwin/amd64
Enter fullscreen mode Exit fullscreen mode

JQ
(for channel configuration transactions)
Install the latest version of jq:

$ brew install jq
Enter fullscreen mode Exit fullscreen mode

Ensure jq is installed:

$ jq --version
jq-1.6
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Fabric and Fabric Samples

Download fabric samples, docker images, and binaries

Make a directory to clone the fabric samples to and cd into it:

$ mkdir -p $HOME/go/src/hyperledger && cd $HOME/go/src/hyperledger
Enter fullscreen mode Exit fullscreen mode

Download the latest version of fabric samples, docker images and binaries:

$ curl -sSL https://bit.ly/2ysbOFE | bash -s
Enter fullscreen mode Exit fullscreen mode

Step 3: Run a test network

Bring up the network along with two example orgs

cd into the test-network directory containing the main network.sh script:

$ cd fabric-samples/test-network
Enter fullscreen mode Exit fullscreen mode

run the following command to bring up a fresh test-network:

$ ./network.sh down && ./network.sh up
Enter fullscreen mode Exit fullscreen mode

run the following command to see the running docker-containers:

$ docker ps -a
Enter fullscreen mode Exit fullscreen mode

You should see 4 containers with the following names:
hyperledger/fabric-tools:latest: 1 container
hyperledger/fabric-orderer:latest: 1 container
hyperledger/fabric-peer:latest: 2 containers

Create a channel and have the two example orgs join it

$ ./network.sh createChannel
Enter fullscreen mode Exit fullscreen mode

You should see the following message at the end of the output:

Channel 'mychannel' joined
Enter fullscreen mode Exit fullscreen mode

Step 4: Deploy a smart contract on the
network

Package the smart contract
Firstly we want to package our go lang smart contract code into a binary file to deploy it onto the network.

Go to the folder containing the golang Chaincode and install golang dependencies there, then return to the current directory:

$ cd ../chaincode/fabcar/go && GO111MODULE=on go mod vendor && cd ../../../test-network
Enter fullscreen mode Exit fullscreen mode

Now add the following variables to your cli:

$ export PATH=${PWD}/../bin:${PWD}:$PATH
$ export FABRIC_CFG_PATH=$PWD/../config/
Enter fullscreen mode Exit fullscreen mode

Finally, create the package for the smart contract:

$ peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/go/ --lang golang --label fabcar_1
Enter fullscreen mode Exit fullscreen mode

Run the following command to ensure that the package has been created:

$ ls | grep fabcar.tar.gz

fabcar.tar.gz
Enter fullscreen mode Exit fullscreen mode

Install the chaincode package on both the orgs

First, let's take up the role of org 1:

$ export CORE_PEER_TLS_ENABLED=true
$ export CORE_PEER_LOCALMSPID="Org1MSP"
$ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
$ export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
$ export CORE_PEER_ADDRESS=localhost:7051
Enter fullscreen mode Exit fullscreen mode

Install the chaincode onto the peer (org1):

$ peer lifecycle chaincode install fabcar.tar.gz
Enter fullscreen mode Exit fullscreen mode

Next, let's take up the role of org 2:

$ export CORE_PEER_LOCALMSPID="Org2MSP"
$ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
$ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
$ export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
$ export CORE_PEER_ADDRESS=localhost:9051
Enter fullscreen mode Exit fullscreen mode

Install the chaincode onto the peer (org2):

$ peer lifecycle chaincode install fabcar.tar.gz
Enter fullscreen mode Exit fullscreen mode

Approve the chaincode on both the orgs

First, let's take up the role of org 1:

$ export CORE_PEER_TLS_ENABLED=true
$ export CORE_PEER_LOCALMSPID="Org1MSP"
$ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
$ export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
$ export CORE_PEER_ADDRESS=localhost:7051
Enter fullscreen mode Exit fullscreen mode

Ensure that the chaincode is installed on org1:

$ peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276, Label: fabcar_1
Enter fullscreen mode Exit fullscreen mode

Copy the Package ID from the result in the previous command, and set the following variable equal to it:

$ CC_PACKAGE_ID=fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276
Enter fullscreen mode Exit fullscreen mode

Approve the chaincode for org1:

$ peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
Enter fullscreen mode Exit fullscreen mode

Next, let's take up the role of org 2:

$ export CORE_PEER_LOCALMSPID="Org2MSP"
$ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
$ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
$ export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
$ export CORE_PEER_ADDRESS=localhost:9051
Enter fullscreen mode Exit fullscreen mode

Ensure that the chaincode is installed onto org 2:

$ peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276, Label: fabcar_1
Enter fullscreen mode Exit fullscreen mode

Copy the Package ID from the result in the previous command, and set the following variable equal to it:

$ CC_PACKAGE_ID=fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276
Enter fullscreen mode Exit fullscreen mode

Now approve the chaincode for org2:

$ peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
Enter fullscreen mode Exit fullscreen mode

Commit the chaincode to the channel

Check if the chaincode is ready to be committed:

$ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json

{
    "approvals": {
        "Org1MSP": true,
        "Org2MSP": true
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, both the orgs have approved the chaincode. Hence, it is ready to be committed to the channel.

Commit the chaincode to the channel:

$ peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
Enter fullscreen mode Exit fullscreen mode

Check if the chaincode is committed:

$ peer lifecycle chaincode querycommitted --channelID mychannel --name fabcar --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

Committed chaincode definition for chaincode 'fabcar' on channel 'mychannel':
Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true]
Enter fullscreen mode Exit fullscreen mode

Invoke the chaincode

Now that we have committed the chaincode onto the channel, finally it's time to have some fun!
Let's invoke various functions of the committed chaincode:

Call the queryAllCars function:

$ peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'

[]
Enter fullscreen mode Exit fullscreen mode

As we can see by the empty array, there are no cars onto the ledger, so let's try adding some.

Call the initLedger function:

$ peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabcar --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"initLedger","Args":[]}'
Enter fullscreen mode Exit fullscreen mode

This should add some cars to the ledger, let's check it by querying all cars again.

Call the queryAllCars function:

$ peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'

[{"Key":"CAR0","Record":{"make":"Toyota","model":"Prius","colour":"blue","owner":"Tomoko"}},{"Key":"CAR1","Record":{"make":"Ford","model":"Mustang","colour":"red","owner":"Brad"}},{"Key":"CAR2","Record":{"make":"Hyundai","model":"Tucson","colour":"green","owner":"Jin Soo"}},{"Key":"CAR3","Record":{"make":"Volkswagen","model":"Passat","colour":"yellow","owner":"Max"}},{"Key":"CAR4","Record":{"make":"Tesla","model":"S","colour":"black","owner":"Adriana"}},{"Key":"CAR5","Record":{"make":"Peugeot","model":"205","colour":"purple","owner":"Michel"}},{"Key":"CAR6","Record":{"make":"Chery","model":"S22L","colour":"white","owner":"Aarav"}},{"Key":"CAR7","Record":{"make":"Fiat","model":"Punto","colour":"violet","owner":"Pari"}},{"Key":"CAR8","Record":{"make":"Tata","model":"Nano","colour":"indigo","owner":"Valeria"}},{"Key":"CAR9","Record":{"make":"Holden","model":"Barina","colour":"brown","owner":"Shotaro"}}]
Enter fullscreen mode Exit fullscreen mode

As we can see, the cars were added to the ledger which confirms that our smart contract (Chaincode) is working!

That's it for this tutorial! You can check out more functions in the Chaincode by heading over to ../chaincode/fabcar/go/fabar.go and try invoking/querying them.

Make sure to run $ ./network.sh down to kill any containers related to fabric samples once you are done.

Thanks for reading!

-This article was written by Smith Pereira, Software Developer at DisruptX

Top comments (0)