Create a network to jump start development of your decentralized application on Hyperledger Fabric platform.
The network is run by docker containers and can be deployed to 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 with a particular version of HL Fabric framework export desired version in the
FABRIC_VERSION environment variable. The latest docker image tag is used by default.
export FABRIC_VERSION=1.2.0Generate crypto material and the genesis block for the orderer organization. Using default example.com DOMAIN.
./generate-orderer.shStart docker containers for orderer.
docker-compose -f docker-compose-orderer.yaml upOpen another console. Generate crypto material for the member organization. Using default ORG name org1.
./generate-peer.shStart docker containers for org1.
docker-compose upOpen another console. Add org1 to the consortium as Admin of the orderer organization:
./consortium-add-org.sh org1Create channel common as Admin of org1 and join our peers to the channel:
./channel-create.sh common
./channel-join.sh commonInstall 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 folder
./chaincode/node/reference.
./chaincode-install.sh reference
./chaincode-instantiate.sh common referenceChaincode 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.1When 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 referenceInstall 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 golangUse script network-create-local.sh to create a network with an arbitrary number of member organizations running in docker containers on the local machine.
./network-create-local.sh org1 org2 org3This will create a network with example.com domain and container names like peer0.org1.example.com,
api.org2.example.com and API ports 4000, 4001, 4002; will create a channel named common
and nodejs chaincode reference with its source in this repo ./chaincode/node/reference.
Member organization's docker containers are started with default docker-compose config files
-f docker-compose.yaml -f couchdb.yaml. You can override them by setting env variable DOCKER_COMPOSE_ARGS; for
example to start without a CouchDb container to use LevelDb for storage:
DOCKER_COMPOSE_ARGS="-f docker-compose.yaml" ./network-create-local.shYou can give your network and channel names, set starting API port, override chaincode location, install and instantiate arguments.
DOMAIN=mynetwork.org \
CHANNEL=a-b \
WEBAPP_HOME=/home/oleg/webapp \
CHAINCODE_HOME=/home/oleg/chaincode \
CHAINCODE_INSTALL_ARGS='example02 1.0 chaincode_example02 golang' \
CHAINCODE_INSTANTIATE_ARGS="a-b example02 [\"init\",\"a\",\"10\",\"b\",\"0\"] 1.0 collections.json AND('a.member','b.member')" \
./network-create-local.sh a bTo understand the script please read the below step by step instructions for the network of three member organizations org1, org2, org3.
You can also extend this example by manually adding more than 3 organizations and any number of channels with various membership.
Clean up. Remove all containers, delete local crypto material:
./clean.shGenerate crypto material and start docker containers of the orderer organization:
./generate-orderer.sh
docker-compose -f docker-compose-orderer.yaml upOpen another shell. Generate and start org1.
./generate-peer.sh
docker-compose upOpen another shell. Note since we're reusing the same docker-compose.yaml file we need to redefine COMPOSE_PROJECT_NAME.
Redefine the api port mapped to the host to avoid collision with api.org1.
Generate and start org2.
export COMPOSE_PROJECT_NAME=org2 ORG=org2
export API_PORT=4001Then start the peer
./generate-peer.sh
docker-compose upGenerate and start org3 in another shell:
export COMPOSE_PROJECT_NAME=org3 ORG=org3
export API_PORT=4002
./generate-peer.sh
docker-compose upNow 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 org3Now 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 commonLet'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-org2Install 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-org2Now become org3 to install chaincode reference and join channel common:
export COMPOSE_PROJECT_NAME=org3 ORG=org3
./chaincode-install.sh reference
./channel-join.sh commonLogin 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/channelsreturns
[{"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/2Invoke 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'Install docker-machine.
Install VirtualBox.
Use script network-create-docker-machine.sh to create a network with an arbitrary number of member organizations each running in its own virtual host.
./network-create-docker-machine.sh org1 org2 org3Of course you can override the defaults with env variables.
DOMAIN=mynetwork.org \
CHANNEL=a-b \
WEBAPP_HOME=/home/oleg/webapp \
CHAINCODE_HOME=/home/oleg/chaincode \
CHAINCODE_INSTALL_ARGS='example02 1.0 chaincode_example02 golang' \
CHAINCODE_INSTANTIATE_ARGS="a-b example02 [\"init\",\"a\",\"10\",\"b\",\"0\"] 1.0 collections.json AND('a.member','b.member')" \
./network-create-docker-machine.sh a bThe script network-create-docker-machine.sh combines
host-create.sh to create host machines with docker-machine and
network-create.sh to create container with docker-compose.
If you don't want to recreate hosts every time you can re-run ./network-create.sh with the same arguments and
env variables to recreate the network on the same remote hosts by clearing and creating containers.
Define amazonec2 driver for docker-machine and open ports in docker-machine security group.
Make sure your AWS credentials are saved in env variables or ~/.aws/credentials or passed as arguments
--amazonec2-access-key and --amazonec2-secret-key.
More settings are described on the driver page.
DOCKER_MACHINE_FLAGS="--driver amazonec2 --amazonec2-open-port 80 --amazonec2-open-port 7050 --amazonec2-open-port 7051 --amazonec2-open-port 4000" \
./network-create-docker-machine.sh org1 org2 org3Define azure driver for docker-machine and open ports in network security groups.
Give your subscription id (the one looking like deadbeef-8bad-f00d-989d-5fbe969ccb9e) and the script will prompt you
to login to your Microsoft account and authorize Docker Machine for Azure application to manage your Azure instances.
More settings are described on the driver page.
DOCKER_MACHINE_FLAGS="--driver azure --azure-size Standard_A1 --azure-subscription-id <your subs-id> --azure-open-port 80 --azure-open-port 7050 --azure-open-port 7051 --azure-open-port 4000" \
./network-create-docker-machine.sh org1 org2If you have already created remote hosts in the cloud or on premises you can connect docker-machine to these hosts and operate with the same scripts and commands.
Make sure the remote hosts have open inbound ports for Fabric network: 80, 4000, 7050, 7051 and for docker: 2376.
Connect via generic driver
to hosts orderer, a and b at specified public IPs with ssh private key ~/docker-machine.pem.
docker-machine create --driver generic --generic-ssh-key ~/docker-machine.pem --generic-ssh-user ubuntu \
--generic-ip-address 34.227.123.456 orderer
docker-machine create --driver generic --generic-ssh-key ~/docker-machine.pem --generic-ssh-user ubuntu \
--generic-ip-address 54.173.123.457 a
docker-machine create --driver generic --generic-ssh-key ~/docker-machine.pem --generic-ssh-user ubuntu \
--generic-ip-address 54.152.123.458 bNow the hosts are known to docker-machine and you can run network-create.sh script to create
docker containers running the network and create organizations, channel and chaincode.
DOMAIN=mynetwork.org CHANNEL=a-b WEBAPP_HOME=/home/oleg/webapp CHAINCODE_HOME=/home/oleg/chaincode CHAINCODE_INSTALL_ARGS='example02 1.0 chaincode_example02 golang' CHAINCODE_INSTANTIATE_ARGS="a-b example02 [\"init\",\"a\",\"10\",\"b\",\"0\"] 1.0 collections.json AND('a.member','b.member')" \
./network-create.sh a bTo understand the script please read the below step by step instructions for the network of two member organizations org1 and org2.
Create 3 hosts: orderer and member organizations org1 and org2.
docker-machine create orderer
docker-machine create org1
docker-machine create org2Tell the scripts to use extra multihost docker-compose yaml files.
export MULTIHOST=trueCopy config templates to the orderer host.
docker-machine scp -r templates orderer:templatesConnect docker client to the orderer host. The docker commands that follow will be executed on the host not local machine.
eval "$(docker-machine env orderer)"Inspect created hosts' IPs and collect them into hosts file to copy to the hosts. This file will be mapped to the
docker containers' /etc/hosts to resolve names to IPs.
This is better done by the script.
Alternatively, edit extra_hosts in multihost.yaml and orderer-multihost.yaml to specify host IPs directly.
docker-machine ip orderer
docker-machine ip org1
docker-machine ip org2Generate crypto material for the orderer organization and start its docker containers.
./generate-orderer.sh
docker-compose -f docker-compose-orderer.yaml -f orderer-multihost.yaml up -dOpen a new console. Use env variables to tell the scripts to use multihost config yaml and to name your organization.
export MULTIHOST=true && export ORG=org1Copy templates, chaincode and webapp folders to the host.
docker-machine scp -r templates $ORG:templates && docker-machine scp -r chaincode $ORG:chaincode && docker-machine scp -r webapp $ORG:webappConnect docker client to the organization host.
eval "$(docker-machine env $ORG)"Generate crypto material for the org and start its docker containers.
./generate-peer.sh
docker-compose -f docker-compose.yaml -f multihost.yaml up -dTo create other organizations repeat the above steps in separate consoles
and giving them names by export ORG=org2 in the first step.
Return to the orderer console.
Now the member organizations are up and serving their certificates. The orderer host can download them to add to the consortium definition.
./consortium-add-org.sh org1
./consortium-add-org.sh org2Return to the org1 console.
The first organization creates channel common and joins to it.
./channel-create.sh common
./channel-join.sh commonAnd adds other organizations to channel common.
./channel-add-org.sh common org2And installs and instantiates chaincode reference.
./chaincode-install.sh reference
./chaincode-instantiate.sh common referenceTest the chaincode by invoke and query.
./chaincode-invoke.sh common reference '["put","account","1","{\"name\":\"one\"}"]'
./chaincode-query.sh common reference '["list","account"]'Return to org2 console.
Join common and install reference.
./channel-join.sh common
./chaincode-install.sh referenceTest the chaincode by a query by org2.
./chaincode-query.sh common reference '["list","account"]'As this project doesn't have a defined release cycle yet we create snapshot-{version}-{fabric-version} branches
when we see code is stable enough or before introducing major changes\new features.
Note, the Hyperledger Fabric version which the snapshot is based on is defined in the .env file.
The master branch as well as potentially feature branches are used for development.
Master is assigned to the latest version of Fabric.
Currently issued branches are:
- snapshot-0.1-1.4
- master(development)