Getting started with Hyperledger Fabric on macOS
Tags: web3, tutorial
Published: 2022-02-11 14:47:52

**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](https://www.investopedia.com/terms/h/hyperledger-fabric.asp#:~:text=Hyperledger%20Fabric%20is%20a%20modular,for%20use%20within%20private%20enterprises.)

**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](https://github.com/hyperledger/fabric-samples).

1. [Channel](https://hyperledger-fabric.readthedocs.io/en/release-2.2/channels.html) 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](https://hyperledger-fabric.readthedocs.io/en/release-1.3/chaincode.html) 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](https://brew.sh/):
```
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
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)
```

**Git**
Install the latest version of [Git](https://git-scm.com/download/mac)
```
$ brew install git
```
Ensure Git is installed:
```
$  git --version
git version 2.35.1
```

**cURL**

Install the latest version of [cURL](https://curl.se/download.html):
```
$ brew install curl
```

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
```


**Docker**

Download docker desktop from [here](https://docs.docker.com/desktop/mac/install/)

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 
```

**Go**
*(for Go chaincode or SDK applications)*
Install the latest *supported* version of go:
```
$ brew install go@1.17.5
```

Ensure go is installed:
```
$ go version
go1.17.5 darwin/amd64
```

**JQ**
*(for channel configuration transactions)*
Install the latest version of jq:
```
$ brew install jq
```

Ensure jq is installed:
```
$ jq --version
jq-1.6
```

**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
```


Download the latest version of fabric samples, docker images and binaries:
```
$ curl -sSL https://bit.ly/2ysbOFE | bash -s
```

**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
```

run the following command to bring up a *fresh* test-network:
```
$ ./network.sh down && ./network.sh up
```

run the following command to see the running docker-containers:
```
$ docker ps -a
```

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
```

You should see the following message at the end of the output:
```
Channel 'mychannel' joined
```

**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
```
Now add the following variables to your cli:
```
$ export PATH=${PWD}/../bin:${PWD}:$PATH
$ export FABRIC_CFG_PATH=$PWD/../config/
```

Finally, create the package for the smart contract:
```
$ peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/go/ --lang golang --label fabcar_1
```

Run the following command to ensure that the package has been created:
```
$ ls | grep fabcar.tar.gz

fabcar.tar.gz
```

**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
```

Install the chaincode onto the peer (org1):
```
$ peer lifecycle chaincode install fabcar.tar.gz
```

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
```

Install the chaincode onto the peer (org2):
```
$ peer lifecycle chaincode install fabcar.tar.gz
```

**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
```

Ensure that the chaincode is installed on org1:
```
$ peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276, Label: fabcar_1
```

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
```

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
```

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
```

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
```

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
```

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
```

**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
	}
}
```
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
```

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]
```

**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"]}'

[]
```
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":[]}'
```
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"}}]
```
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](https://www.linkedin.com/in/capriciousrebel/), Software Developer at DisruptX