A Complete Guide to Designing and Shipping a Blockchain Solution for a Business
Learn by creating a professional blockchain network solution for a logistics company.

The complex nature of logistics and supply-chain makes it difficult to gain an accurate, real-time overview of a shipment’s status because logistics and supply-chain usually involve multiple participants(e.g. consumers of goods, retailers, distributors, manufacturers, suppliers, and brokers), each of which maintains its own record of a transaction. These records are often unsynchronized, making it tough to get a big-picture view of the situation. However, a blockchain-based supply chain network can provide greater visibility and transparency, upping efficiency and boosting value.
Trade finance and logistics terms
There are a lot of terms used in trade finance and logistics that can be confusing for newcomers to the industry. The following terms refer to certain instruments and artifacts that are in play in our trade scenario. The application we will build in this article uses simplified forms of these instruments:
Letter of credit: A letter of credit (L/C) is basically a bank’s way of saying, “We promise to pay this person for the goods they shipped, as long as they can show us proof that they actually shipped them.” It’s a pretty important document, and the importer’s bank will issue one at the request of its client — the importer.
The L/C outlines the papers that verify the shipment was made, how much needs to be paid, and who will get that money (in our case, the exporter). A sample L/C is illustrated below:

Export license: An export license is an approval granted by a regulatory authority to ship specified goods. In this blog, we will refer to it as E/L for short. A sample E/L is illustrated in the screenshot below:

Bill of lading: A bill of lading (B/L) is a document that proves that the carrier has taken possession of the shipment. It also acts as a contract between the carrier and the exporter and proves that the exporter owns the goods.
- a shipment receipt
- a contract where the carrier agrees to transport the goods to a specified destination in return for a fee
- an ownership title of goods
The bill of lading is also listed in the letter of credit and serves as proof of shipment that will automatically trigger a payment clearance.

Process Workflow
Our workflow involves breaking down transactions into simpler steps in order to make the process more efficient and easier to follow. By deconstructing the interactions among different sets of entities into smaller, more manageable parts, we can streamline the testing process and make it more effective.

- Importer requests goods from the exporter in exchange for money
- Exporter accepts the trade deal
- Importer asks its bank for an L/C in favour of the exporter
- The importer’s bank supplies an L/C in favour of the exporter and is payable to the latter’s bank
- The exporter’s bank accepts the L/C on behalf of the exporter
- Exporter applies for an E/L from the regulatory authority
- Regulatory authority supplies an E/L to the exporter
- The exporter prepares a shipment and hands it off to the carrier
- The carrier accepts the goods after validating the E/L and then supplies a B/L to the exporter
- The exporter’s bank claims half the payment from the importer’s bank
- The importer’s bank transfers half the amount to the exporter’s bank
- The carrier ships the goods to the destination
- The importer’s bank pays the remaining amount to the exporter’s bank
Shared Assets and Data
The participants in the previous workflow must share some information in order for all parties to be aware of the trade arrangement and its progress at any given moment. This includes sharing assets such as documentary and monetary assets, as you can see in the table below:


Participants’ Roles and Capabilities
In our case, there are 6 types of participants: exporters, importers, the exporters’ bank, the importers’ bank, the shipping company, and some regulatory authority. Everyone has different abilities and limitations, which are listed below:
- Only an importer may apply for an L/C
- Only an importer’s bank may supply an L/C
- Only an exporter’s bank may accept an L/C
- Only an exporter may request an E/L
- Only a regulatory authority may supply an E/L
- Only an exporter may prepare a shipment
- Only a carrier may supply a B/L
- Only a carrier may update a shipment location
- Only an importer’s bank may send money, and only an exporter’s bank may receive money
Setting Up the Environment
Installing prerequisites
Now we have design of network in hand, let’s install the prerequisite tools:
- Ensure that you have the latest version of Docker using https://docs.docker.com/install/ and Docker-Compose using: https://docs.docker.com/compose/install/
- Install the software required for the business network example: https://hyperledger.github.io/composer/latest/installing/ installing-prereqs.
- Fabric is implemented using the Go programming language. Note that Go has a syntax similar to C++. We will also use Go to write our chaincode. Go can be installed from the link https://golang.org/.
- Set up our environmental variables.
GOPATH
points to a workspace for thego
source code, for example:
$ export GOPATH=$HOME/go
PATH
needs to include the Go bin
directory in order to store libraries and executables. This can be seen in the following snippet:
$ export PATH=$PATH:$GOPATH/bin
6. Check if you need to install make
it on your system. On a Debian/Ubuntu system, you can install it using sudo apt-get install make
.
Forking and Cloning the Trade- Finance-Logistics Repository
It is essential that we first fork the repository on GitHub so that we have our own copy of the original source code. We can then clone the source code into a local machine directory by following these steps:
- In GitHub, navigate to the following repository: https://github.com/HyperledgerHandsOn/trade-finance-logistics.git
$ cd $GOPATH/src
$ git clone https://github.com/YOUR-USERNAME/trade-finance-logistics
We now have a local copy of all the trade-finance-logistics tutorial materials.
Preparing the Network
To build Fabric
and Fabric-CA
, you may need to install some dependencies first, such as the gcc
, libtool
, and ltdl
libraries. (On Ubuntu systems, you can install all of the necessary prerequisites by running sudo apt install libltdl-dev
and on mac by running brew install libtool
). We need to perform the following steps before generating network cryptographic material:
- Clone the Fabric (https://github.com/hyperledger/fabric/tree/release-1.1) source code repository by adding the parameter
-b release-1.1
. Make sure the cloned fabric folder is either present or symbolically linked in$GOPATH/src/github.com/hyperledger/
. This is necessary so that when you attempt to build Fabric, it will look for the required libraries in this path. - Run
make docker
build Docker images for the peers and orderers - Run
make configtxgen cryptogen
to generate the necessary tools to run the network creation commands described in this section - Clone the Fabric-CA from https://github.com/hyperledger/fabric-ca/tree/release-1.1. Make sure the cloned
fabric-ca
folder is either present or symbolically linked, in$GOPATH/src/github.com/hyperledger/
. This is necessary so that when you attempt to build Fabric-CA, it will look for the required libraries in this path. - Run
make docker
to build the Docker images for the managed service providers(MSPs).
Generate Network Cryptographic Material
The first step in the configuration of a network involves the creation of certificates and signing keys for the MSP of each peer and orderer organization, and for TLS-based communication. We also need to create certificates and keys for each peer and orderer node to be able to communicate with each other and with their respective MSPs.
This setting must be identified in a crypto-config.yaml
within the network folder of our codebase. For example, take a look at the definition of the importer’s organization within the file as such:
PeerOrgs:
- Name: ImporterOrg
Domain: importerorg.trade.com
EnableNodeOUs: true
Template:
Count: 1
Users:
Count: 2
This config indicates that the ImporterOrg
organization will have one peer. Additionally, two non-admin users will be created. The organization domain name usable by the peer is also defined.
To create cryptographic material for all the organizations, run the cryptogen
command as follows:
cryptogen generate --config=./crypto-config.yaml
The output is saved in the crypto-config
folder.
Generate Channel Artifacts
To build a network that accurately reflects an organization’s structure, and to establish a channel, the following materials are necessary:
- The genesis block contains organization-specific certificates that initialize the Fabric blockchain.
- Channel configuration information
- Anchor peer configurations for each organization ensure that the blockchain is properly maintained.
The crypto-config.yaml
file contains the channel properties while configtx.yaml
file, located in the network folder, defines the high-level structure of our trade network as shown in the Profiles
section:
As we can see, the channel we are going to create is named FourOrgsTradeChannel,
which is defined in the profile. The 4 organizations participating in this channel are labelled ExporterOrg
, ImporterOrg
, CarrierOrg
, and RegulatorOrg
, each of which refers to a subsection defined in the Organisations
section. The orderer belongs to its own organization called TradeOrdererOrg
.
Each organization listed below contains information about its MSP (ID as well as the location of the cryptographic material, such as keys and certificates) and the hostname and port info for its anchor peers. As an example, the ExporterOrg
section contains the following:
- &ExporterOrg
Name: ExporterOrgMSP
ID: ExporterOrgMSP
MSPDir: crypto-config/peerOrganizations/exporterorg.trade.com/msp
AnchorPeers:
- Host: peer0.exporterorg.trade.com
Port: 7051
As you can see, the MSPDir
variable (representing a folder) in this specification references the cryptographic material we generated earlier using the cryptogen
tool.
The configtxgen
tool is used to generate channel artifacts. To generate the genesis block, run the following command from the network
folder:
configtxgen -profile FourOrgsTradeOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
The FourOrgsTradeOrdererGenesis
keyword corresponds to the profile name in the Profiles
section. The genesis block will be saved in the genesis.block
file in the channel-artifacts
folder. To generate the channel configuration, run the following code:
configtxgen -profile FourOrgsTradeChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID tradechannel
The channel we will create is named tradechannel
, and its configuration is stored in channel-artifacts/channel.tx
. To generate the anchor peer configuration for the exporter organization, run:
configtxgen -profile FourOrgsTradeChannel -outputAnchorPeersUpdate ./channel-artifacts/ExporterOrgMSPanchors.tx -channelID tra
The same process should be repeated for the other three organizations while changing the organization names in the preceding command.
You need to set the environment variable
FABRIC_CFG_PATH
to the folder that has theconfigtx.yaml
file in order for theconfigtxgen
tool to work. The script filetrade.sh
has a line that makes sure theYAML
file is loaded from the folder the command is run in:export FABRIC_CFG_PATH=${PWD}
Generate the Configuration in One Operation
The trade.sh
script is configured to generate channel artifacts and cryptographic material using the commands and configuration files described previously. To do this, simply run the following command from within the network
folder:
./trade.sh generate -c tradechannel
Although you can name any channel you want here, it’s important to note that the configurations used to develop the middleware later in this article will depend on that name.
The
GOPATH
variable is set to/opt/gopath
in the container that runs the peer.
Compose a Sample Trade Network
The previous command also creates a network configuration file docker-compose-e2e.yaml
, which can be used to start the network as a set of Docker containers using the docker-compose tool. This file is based on the statically configured files base/peer-base.yaml
and base/docker-compose-base.yaml
.
These files work together to specify services and their attributes, which allows us to run all the services we need within Docker containers. This is opposed to having to manually run each individual service on one or more machines. The services we need to run are:
- Four instances of a
Fabric
peer, one in each organization - One instance of a
Fabric
ordered - Five instances of a
Fabric CA
, corresponding to the MSPs of each organization
Docker images for each component can be found on the Hyperledger project on Docker Hub (https://hub.docker.com/u/hyperledger/). The images are hyperledger/fabric-peer
, hyperledger/fabric-orderer
, hyperledger/fabric-ca
for peers, orderers, and Certificate Authorities (CAs) respectively.
The base config of a peer can be as follows (see base/peer-base.yaml
):
You can configure fabric settings here, but if you use the pre-built Docker image for fabric-peer
, the defaults are usually sufficient to get a peer service running. The command to start the peer service is usually specified in the last line of the configuration as peer node start
. Also, make sure you configure the logging level using the CORE_LOGGING_LEVEL
variable.
In our configuration, the variable is set to INFO
, which means that only informational, warning, and error messages will be logged. However, if you wish to debug a peer and need more extensive logging, you can set this variable to DEBUG
.
The
IMAGE_TAG
variable is set to “latest” in the.env
file in thenetwork
folder, but you can set a specific tag if you want to pull older images.
It is essential that we configure the hostnames and ports for each peer, and synchronize the cryptographic material generated (using cryptogen
) to the container filesystem. The peer in the exporter organization is configured as follows in base/docker-compose-base.yaml
:
As specified by the extends
parameter, this configuration inherits from the base configuration. Please note that the ID (CORE_PEER_ID
) corresponds with the peer’s ID specified inconfigtx.yaml
. This identity will be used as the hostname for the peer running in the exporter organization and will be referenced in the middleware code later on in this article.
The volumes section establishes the protocol for copying the cryptographic material produced in the crypto-config
folder to the container. The peer service itself listens on port 7051
, and the port that clients can use to subscribe to events is designated as 7053
.
In this file, you will notice that the in-container ports are the same across all peers. However, they are mapped to different ports on the host machine. Also, please take note that the MSP ID specified here corresponds with the one found in
configtx.yaml
.
The configuration of the orderer service is similar to the following snippet from base/docker-compose-base.yaml
indicates:
orderer.trade.com:
container_name: orderer.trade.com
image: hyperledger/fabric-orderer:$IMAGE_TAG
environment:
- ORDERER_GENERAL_LOGLEVEL=INFO
…… command: orderer
……
The command to initiate the orderer is simply orderer
, as the code demonstrates. The logging level can be customized using the ORDERER_GENERAL_LOGLEVEL
variable and is set to INFO
in our configuration.
The network configuration that we will use is based on a file named docker-compose-e2e.yaml
. This file is not in the repository but rather is generated by the command ./trade.sh generate -c tradechannel
, which we ran earlier to generate the channel and cryptographic material. This file uses base/docker-compose-base.yaml
(and indirectly base/peer-base.yaml
) as you can see by examining the file contents.
It is generated from a YAML template file called docker-compose-e2e-template.yaml
, which can be found in the network folder. The template file contains variables that are replaced with actual filenames within the crypto-config
folder when docker-compose-e2e.yaml
is generated.
For example, consider the exporter-ca section in docker-compose-e2e-template.yaml
:
exporter-ca:
image: hyperledger/fabric-ca:$IMAGE_TAG
environment:
…… - FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/EXPORTER_CA_PRIVATE_KEY
…… command: sh -c ‘fabric-ca-server start — ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.exporterorg.trade.com-cert.pem
Now, look at the same section in the generated file docker-compose-e2e.yaml
:
exporter-ca:
image: hyperledger/fabric-ca:$IMAGE_TAG
environment:
……
- FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/ cc58284b6af2c33812cfaef9e40b8c911dbbefb83ca2e7564
…… command: sh -c ‘fabric-ca-server start — ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.exporterorg.trade.com-cert.pem
As you can see, the variable EXPORTER_CA_PRIVATE_KEY
has been replaced with cc58284b6af2c33812cfaef9e40b8c911dbbefb83ca2e7564e8fbf5e7039c22e_sk
, both in the env and in the command. If you now examine the contents of the crypto-config
folder, you will notice that there is a file named cc58284b6af2c33812cfaef9e40b8c911dbbefb83ca2e7564e8fbf5e7039c22e_sk
in the folder crypto- config/peerOrganizations/exporterorg.trade.com/ca/
. This file contains the exporter organization’s MSP’s private (secret) signing key.
The code snippet before this contains the outcome of a test run. The main file name will be different every time you run the cryptographic tool.
Now, look at the configuration of an MSP in more detail, taking the example of the exporter organization MSP, as specified in docker-compose-e2e.yaml
:
The service that will run in the MSP is the fabric-ca-server
, listening on port 7054
, bootstrapped with the certificates and keys created using cryptogen
, and using the default login and password (admin
and adminpw
, respectively) configured in the fabric-ca image. The command to start a Fabric CA
server instance is fabric-ca-server start
, as you can see in the preceding code.
Peers and CAs are configured for TLS-based communication, as indicated in the preceding configurations. The reader must note that if TLS is disabled in one, it must be disabled in the other too.
Also, as can be observed by examining docker-compose-e2e.yaml
, we do not create a Fabric CA
server (and container) for the orderer’s organization. For the exercise we will go through in this book, statically created admin users and credentials for the orderer are sufficient; we will not be registering new orderer organization users dynamically, so a Fabric CA
server is not needed.
Network Components’ Configuration Files
We have demonstrated how peers, orderers, and CAs can be configured in docker-compose YAML files. But such configurations are meant to override settings that have already been made by default in the components’ respective images. Though a detailed description of these configurations is beyond the scope of this book, we will list the respective files and mention how a user may make changes to them.
For a peer, acore.yaml
file contains all of the important runtime settings, including but not limited to addresses, port numbers, security and privacy, and the gossip protocol. You can create your own file and sync it to the container using a custom Dockerfile instead of the one that is used by the hyperledger/fabric-peer
image by default. If you log in to a running peer container (let’s take the Exporter organization’s peer’s container from the network we just launched):
docker exec -it f86e50e6fc76 bash
Then you will find the core.yaml
file in the folder/etc/hyperledger/fabric/
.
Similarly, an orderer’s default configuration lies in orderer.yaml
, which is also synced to /etc/hyperledger/fabric/
on the container running the hyperledger/fabric-orderer
image. Keep in mind that both the core.yaml
and orderer.yaml
files are synced to the peer and orderer containers, so if you wish to create custom files, you will need to sync these YAML files to both containers.
A Fabric CA
server also has a configuration file called fabric-ca-server-config.yaml
, which is synced to /etc/hyperledger/fabric-ca-server/
on the container running the hyperledger/fabric-ca
image. You can create and sync custom configurations as you would for a peer or an orderer.
Launching a Sample Trade Network
So, now that we have all the configuration for our network, and also the channel artifacts and cryptographic material required to run it, all we need to do is start the network using the docker-compose
command, as follows:
docker-compose -f docker-compose-e2e.yaml up
You can run this as a background process and redirect the standard output to a log file if you so choose. Otherwise, you will see the various containers starting up and logs from each displayed on the console.
On some OS configurations, setting up
Fabri
c can be tricky. If you run into problems, consult the documentation. A detailed description of how to install a Fabric network and examples is provided at https://hyperledger-fabric.readthedocs.io/en/release-1.1/samples.html.
The network can be launched in the background using our trade.sh
script as well. Just run the following:
./trade.sh up
From a different terminal window, if you run docker ps -a
, you will see something as follows:

We have four peers, four MSPs, and an orderer running in separate containers. Our trade network is up and ready to run our application!
To view the running logs of a given container, note the container ID (first column in the preceding list) and simply run:
docker logs <container-ID>
To bring the network down, you can use either the docker-compose command:
docker-compose -f docker-compose-e2e.yaml down
Or our trade.sh script:./trade.sh down
.
Summary
In this article, we introduced the business use case. We have also deployed our first Hyperledger Fabric network and have now transitioned from theory to practice. Well done!