Create a network to jump start development of your decentralized application on Hyperledger Fabric platform.
The network can be deployed to multiple docker containers on one host for development or to multiple hosts for testing or production.
Scripts of this starter generate crypto material and config files, start the network and deploy your chaincodes. Developers can use REST API to invoke and query chaincodes, explore blocks and transactions.
What's left is to develop your chaincodes and place them into the chaincode folder, and user interface as a single page web app that you can serve by by placing the sources into the www folder.
See also
- fabric-starter-rest REST API server and client built with NodeJS SDK
- fabric-starter-web Starter web application to work with the REST API
- chaincode-node-storage Base class for node.js chaincodes with CRUD functionality
Install prerequisites: docker >=18.06.1
and docker-compose >=1.22.0
.
sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
sudo apt update
sudo apt-get install docker-ce
sudo curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# add yourself to the docker group and re-login
sudo usermod -aG docker ${USER}
Install docker ce
and docker compose
by brew.
brew install docker
To deploy network in a particular version of HL Fabric framework export desired version in the FABRIC_VERSION environment variable:
export FABRIC_VERSION=1.2.0
Generate crypto material and the genesis block for the Orderer organization. Using default example.com DOMAIN.
./generate-orderer.sh
Start docker containers for Orderer.
docker-compose -f docker-compose-orderer.yaml up
Open another console. Generate crypto material for the member organization. Using default ORG name org1.
./generate-peer.sh
Start docker containers for org1.
docker-compose up
Open another console. Add org1 to the consortium as Admin of the Orderer organization:
./consortium-add-org.sh org1
Create channel common as Admin of org1 and join our peers to the channel:
./channel-create.sh common
./channel-join.sh common
Install and instantiate nodejs chaincode reference on channel common.
Using defaults: language node
, version 1.0
, empty args []
.
Note the path to the source code is inside cli
docker container and is mapped to the local
./chaincode/node/reference
.
./chaincode-install.sh reference
./chaincode-instantiate.sh common reference
Chaincode reference extends chaincode-node-storage which provides CRUD functionality.
Invoke chaincode to save entities of type account.
./chaincode-invoke.sh common reference '["put","account","1","{\"name\":\"one\"}"]'
./chaincode-invoke.sh common reference '["put","account","2","{\"name\":\"two\"}"]'
Query chaincode functions list and get.
./chaincode-query.sh common reference '["list","account"]'
./chaincode-query.sh common reference '["get","account","1"]'
Now you can make changes to your chaincode, install a new version 1.1
and upgrade to it.
./chaincode-install.sh reference 1.1
./chaincode-upgrade.sh common reference 1.1 []
When you develop and need to push your changes frequently, this shortcut script will install and instantiate with a new random version
./chaincode-reload.sh common reference
Install and instantiate golang chaincode example02 on channel common.
Source code is in local ./chaincode/go/chaincode_example02
mapped to /opt/gopath/src/chaincode_example02
inside cli
container.
./chaincode-install.sh example02 1.0 chaincode_example02 golang
./chaincode-instantiate.sh common example02 '["init","a","10","b","0"]'
./chaincode-invoke.sh common example02 '["move","a","b","1"]'
./chaincode-query.sh common example02 '["query","a"]'
Reload golang chaincode.
./chaincode-reload.sh common example02 '["init","a","10","b","0"]' chaincode_example02 golang
You can replace default DOMAIN example.com and org1, org2 with the names of your organizations.
Define them via environment variables either in shell or .env
file.
export DOMAIN=example.com ORG=org1
You can also extend this example by adding more than 3 organizations and any number of channels with various membership.
Clean up. Remove all containers, delete local crypto material:
./clean.sh
Generate crypto material and start docker containers of the Orderer organization:
./generate-orderer.sh
docker-compose -f docker-compose-orderer.yaml up
Open another shell. Set environment variables ORGS
and CAS
that define how this org's client will connect to other
organizations' peers and certificate authorities. When moving to multi host deployment they will be need
to be redefined.
Generate and start org1.
export ORGS='{"org1":"peer0.org1.example.com:7051","org2":"peer0.org2.example.com:7051","org3":"peer0.org3.example.com:7051"}' CAS='{"org1":"ca.org1.example.com:7054"}'
./generate-peer.sh
docker-compose up
Open another shell. Note since we're reusing the same docker-compose.yaml
file we need to redefine COMPOSE_PROJECT_NAME
.
Also the ports open to host machine need to be redefined to avoid collision.
Generate and start org2.
export COMPOSE_PROJECT_NAME=org2 ORG=org2
export ORGS='{"org1":"peer0.org1.example.com:7051","org2":"peer0.org2.example.com:7051","org3":"peer0.org3.example.com:7051"}' CAS='{"org2":"ca.org2.example.com:7054"}'
When running on local machine:
export API_PORT=4001 WWW_PORT=8082 CA_PORT=8054 PEER0_PORT=8051 PEER0_EVENT_PORT=8053 PEER1_PORT=8056 PEER1_EVENT_PORT=8058
Then start the peer
./generate-peer.sh
docker-compose up
Generate and start org3 in another shell:
export COMPOSE_PROJECT_NAME=org3 ORG=org3
export ORGS='{"org1":"peer0.org1.example.com:7051","org2":"peer0.org2.example.com:7051","org3":"peer0.org3.example.com:7051"}' CAS='{"org3":"ca.org2.example.com:7054"}'
export API_PORT=4002
./generate-peer.sh
docker-compose up
Now you should have 4 console windows running containers of Orderer, org1, org2, org3 organizations.
Open another console where we'll become an Admin user of the Orderer organization. We'll add orgs to the consortium:
./consortium-add-org.sh org1
./consortium-add-org.sh org2
./consortium-add-org.sh org3
Now all 3 orgs are known in the consortium and can create and join channels.
Open another console where we'll become org1 again. We'll create channel common, add other orgs to it, and join our peers to the channel:
./channel-create.sh common
./channel-add-org.sh common org2
./channel-add-org.sh common org3
./channel-join.sh common
Let's create a bilateral channel between org1 and org2 and join to it:
./channel-create.sh org1-org2
./channel-add-org.sh org1-org2 org2
./channel-join.sh org1-org2
Install and instantiate chaincode reference on channel common. Note the path to the source code is inside cli
docker container and is mapped to the local ./chaincode/node/reference
./chaincode-install.sh reference
./chaincode-instantiate.sh common reference
Install and instantiate chaincode relationship on channel org1-org2:
./chaincode-install.sh relationship
./chaincode-instantiate.sh org1-org2 relationship '["init","a","10","b","0"]'
Open another console where we'll become org2 to install chaincodes reference and relationship and to join channels common and org1-org2:
export COMPOSE_PROJECT_NAME=org2 ORG=org2
./chaincode-install.sh reference
./chaincode-install.sh relationship
./channel-join.sh common
./channel-join.sh org1-org2
Now become org3 to install chaincode reference and join channel common:
export COMPOSE_PROJECT_NAME=org3 ORG=org3
./chaincode-install.sh reference
./channel-join.sh common
Login into org1 as user1 and save returned token into env variable JWT
which we'll use to identify our user
in subsequent requests:
JWT=`(curl -d '{"username":"user1","password":"pass"}' --header "Content-Type: application/json" http://localhost:4000/users | tr -d '"')`
Query channels org1 has joined
curl -H "Authorization: Bearer $JWT" http://localhost:4000/channels
returns
[{"channel_id":"common"},{"channel_id":"org1-org2"}]
Query status, orgs, instantiated chaincodes and block 2 of channel common:
curl -H "Authorization: Bearer $JWT" http://localhost:4000/channels/common
curl -H "Authorization: Bearer $JWT" http://localhost:4000/channels/common/chaincodes
curl -H "Authorization: Bearer $JWT" http://localhost:4000/channels/common/orgs
curl -H "Authorization: Bearer $JWT" http://localhost:4000/channels/common/blocks/2
Invoke function put
of chaincode reference on channel common to save entity of type account
and id 1
:
curl -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
http://localhost:4000/channels/common/chaincodes/reference -d '{"fcn":"put","args":["account","1","{name:\"one\"}"]}'
Query function list
of chaincode reference on channel common with args ["account"]
:
curl -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
'http://localhost:4000/channels/common/chaincodes/reference?fcn=list&args=%5B%22account%22%5D'
There are two approaches for deploying blockchain network on multiple hosts - manual deployment and using docker-machine functionality.
On each node including orderer clone fabric-starter project and export multi-host related flag and WORK_DIR variable specifying absolute path to fabric-starter folder:
export MULTIHOST=1
export WORK_DIR=/home/ubuntu/fabric-starter
Start Swarm manager and join nodes as described in swarm.md If it's undesirable to use Swarm because of security reasons, configure DNS service(s) as described in dns.md
Deploy multi-host network in multihost environment as described below.
Install docker-machine. For local deployment install VirtualBox.
Create and start orderer
docker host as a virtual machine.
For AWS EC2 use --driver amazonec2
and export WORK_DIR=/home/ubuntu
.
docker-machine create --driver virtualbox orderer
See the ip address of the created VM.
docker-machine ls
Returns
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
orderer * virtualbox Running tcp://192.168.99.100:2376 v18.06.1-ce
Connect to orderer
machine by setting env variables.
eval "$(docker-machine env orderer)"
Start docker swarm on orderer
machine. Replace ip address 192.168.99.100
with the actual ip of the remote host interface.
docker swarm init --advertise-addr 192.168.99.100
will output a command to join the swarm by other hosts;
The other hosts will be join to the swarm by the following command (this is an example, use the actual token and ip):
docker swarm join --token SWMTKN-1-4fbasgnyfz5uqhybbesr9gbhg0lqlcj5luotclhij87owzd4ve-4k16civlmj3hfz1q715csr8lf 192.168.99.100:2377
Copy local template files to orderer
home directory (/home/docker
on VirtualBox or /home/ubuntu
on AWS EC2).
docker-machine scp -r templates orderer:templates
Now template files are on the orderer
host and we can run ./generate-orderer.sh
but with a flag
COMPOSE_FLAGS
which adds an extra docker-compose file orderer-multihost.yaml
on top of the base
docker-compose-orderer.yaml
. This file redefines volume mappings from ${PWD}
local to your host machine to
directory on remote host specified by WORK_DIR
(defaulted to VirtualBox's home /home/docker
;
for AWS EC2 do export WORK_DIR=/home/ubuntu
).
Later docker-machine allows to "connect" to created machines by invoking docker-machine env
command for specified machine name (org1):
eval "$(docker-machine env org1)"
After that docker commands running in local console will actually be executed in the (remote) machine.
Connect to orderer machine (with ssh for manual or docker-machine env command for docker machine):
./generate-orderer.sh
Start Orderer containers on orderer
machine.
docker-compose -f docker-compose-orderer.yaml -f orderer-multihost.yaml up -d
For docker-machine deployment create and start org1
docker host as a virtual machine with VirtualBox.
docker-machine create --driver virtualbox org1
and connect to org1
machine by setting env variables.
eval "$(docker-machine env org1)"
Or connect to org1
machine by ssh for manual mode.
Join swarm; this is an example, use the actual command output by orderer
. In orderer console get the command:
docker swarm join-token worker
Execute the output command in org1
console.
docker swarm join --token SWMTKN-1-4rzq6pyg3z2kw7eqhqdnc86isjpwo6t69t1q0ooy84csioieyc-ajcb0rdg3l15ronhytmldc59s 192.168.99.100:2377
Need to run a dummy container on this new host org1
to force join overlay network fabric-overlay
created by docker-compose on orderer
host.
docker run -dit --name alpine --network fabric-overlay alpine
Copy local template and chaincode files to org1
machine.
docker-machine scp -r templates org1:templates
docker-machine scp -r chaincode org1:chaincode
docker-machine scp -r webapp org1:webapp
Generate crypto material for member organization org1.
./generate-peer.sh
Start org1 containers on org1
machine.
docker-compose -f docker-compose.yaml -f multihost.yaml up -d
Now org1
machine is up and running a web container serving root certificates of org1. The orderer can access it
via an overlay network, download certs and add org1.
Connect to orderer
machine by setting env variables or by SSH.
eval "$(docker-machine env orderer)"
Run local script to add to the consortium.
./consortium-add-org.sh org1
Connect to org1
machine by setting env variables.
eval "$(docker-machine env org1)"
Run local scripts to create and join channels.
./channel-create.sh common
./channel-join.sh common
./chaincode-install.sh reference
./chaincode-instantiate.sh common reference
export ORG=org2
export ORGS='{"org1":"peer0.org1.example.com:7051","org2":"peer0.org2.example.com:7051"}' CAS='{"org2":"ca.org2.example.com:7054"}'
docker-machine create --driver virtualbox org2
eval "$(docker-machine env org2)"
docker swarm join --token SWMTKN-1-4fbasgnyfz5uqhybbesr9gbhg0lqlcj5luotclhij87owzd4ve-4k16civlmj3hfz1q715csr8lf 192.168.99.102:2377
docker run -dit --name alpine --network fabric-overlay alpine
docker-machine scp -r templates org2:templates
docker-machine scp -r chaincode org2:chaincode
./generate-peer.sh
docker-compose -f docker-compose.yaml -f multihost.yaml up
Return to org1
machine to add org2 to the channel.
eval "$(docker-machine env org1)"
./channel-add-org.sh common org2
Back to org2
machine to join channel.
export ORG=org2
eval "$(docker-machine env org2)"
./channel-join.sh common
Install chaincode (no need to instantiate) and query.
./chaincode-install.sh reference
./chaincode-query.sh common reference '["list","account"]'
The above steps are collected into a single script that creates a machine, generates crypto material and starts
containers on a remote or virtual host for a new org. This example is for org3; replace swarm token and manager ip
with your own from docker swarm join-token worker
.
./machine-create-peer.sh SWMTKN-1-4fbasgnyfz5uqhybbesr9gbhg0lqlcj5luotclhij87owzd4ve-4k16civlmj3hfz1q715csr8lf 192.168.99.102 org3
See ldap.md