What is Fabric 2
Hyperledger Fabric is a private blockchain platform that enables you to create permissioned blockchain network. The main elements in Hyperledger Fabric are:
- Peer & Organization: Peer node hosts and execute ledger transactions and smart contracts. Peer belongs to Organization. Some peers can be endorsing peers.
- Orderer: Orderer provides ordering service (packages transactions into blocks to be delivered to peers on a channel).
- Channel: Channel are logical structure formed by collection of peers.
- Chaincode / Smart Contract: Smart Contract is software that defines the business logic, contains assets and related transactions. Hyperledger Fabric smart contracts are called chaincode and may specify an endorsement policy which defines transaction validity.
The approach that is taken by Hyperledger Fabric (in my opinion) is beneficial for industrial use cases because it enables cooperation between organization (using channels) while to certain extent having a privacy inside the organization.
To explore the capabilities of Fabric, there are some examples provided that serves certain use cases. For a simple introduction, there are 2 examples that should be used: First Network and Test Network. Due to a major upgrade in Hyperledger Fabric, there are 2 major versions available 1.4.x and 2.x.x - First Network is suitable if you want to learn Fabric 1.4.x but Test Network would be preferable for Fabric 2.x.x. Also good to know that Test Network is a replacement for First Network so you should use that whenever possible.
The striking difference between First Network and Test Network is the number of nodes. First Networks comes with 2 peers for each organization, and 5 orderers while Test Network only comes with 1 peer per organization and 1 orderer. This might be limited for some scenario that you want to run. This article will help you extend the test network with some helpful bash scripts. The underlying assumption is that you already have a Test Network running with command ./network.sh up createChannel && ./network.sh deployCC
TL;DR
To extend Test Network, we need to extend fabric key with cryptogen
, update system-channel
definition, compose orderer nodes, compose peer nodes, join application channel and deploy the chaincode. For an easy setup, clone this repository and run ./extend-network.sh
after setting up your local Test Network. Or to make things easier, just run ./setup-fabric-extended.sh
that will setup local Test Network as well as extends it.
Extending Fabric Key
Before extending the network, we need to generate all the necessary key for each new orderer and peer that we want to create. The easiest way to do that is by using cryptogen
command. cryptogen
is an utility for generating Hyperledger Fabric key material. It is provided as a means of preconfiguring a network for testing purposes. It would normally not be used in the operation of a production network.
cryptogen extend --config=crypto-config.yaml --input="organizations"
The --config
parameter should point to the new network configuration, not the existing test network configuration. In this case, we want a total of 3 orderers, with 3 peers for each organization.
OrdererOrgs:
- Name: Orderer
Domain: example.com
EnableNodeOUs: true
Specs:
- Hostname: orderer
- Hostname: orderer1
- Hostname: orderer2
PeerOrgs:
- Name: Org1
Domain: org1.example.com
EnableNodeOUs: true
Template:
Count: 3
SANS:
- localhost
Users:
Count: 1
- Name: Org2
Domain: org2.example.com
EnableNodeOUs: true
Template:
Count: 3
SANS:
- localhost
Users:
Count: 1
Extending Test Network Orderer
First, we need to update system-channel
configuration so that we can run new orderer node. The steps needed to update system-channel
are as follows:
- Fetch (and decode) latest configuration
- Add new orderer certificate generated by
cryptogen
to orderer consenters and modify the configuration - Apply the change to blockchain
To fetch and decode latest configuration, we need to execute:
peer channel fetch config ./out/config_block.pb -o $ORDERER_ADDRESS -c $2 --tls --cafile $TLS_ROOT_CA
configtxlator proto_decode --input ./out/config_block.pb --type common.Block --output ./out/config_block.json
jq .data.data[0].payload.data.config ./out/config_block.json > ./out/config.json
The commands above will get the latest config and store the result in out
folder. The default orderer address is export ORDERER_ADDRESS=localhost:7050
and the TLS_ROOT_CA
should be test-network/organizations/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem
Next is adding new orderer certificate to the new configuration. We can achieve that by executing commands below:
# add new orderer certificate
echo "{\"client_tls_cert\":\"$(cat $ORDERER_TLS | base64 -w 0)\",\"host\":\"orderer$1.example.com\",\"port\":7$150,\"server_tls_cert\":\"$(cat $ORDERER_TLS | base64 -w 0)\"}" > $PWD/out/ord$1consenter.json
jq ".channel_group.groups.Orderer.values.ConsensusType.value.metadata.consenters += [$(cat ./out/ord$1consenter.json)]" ./out/config.json > ./out/modified_config.json
# calculate config differences
configtxlator proto_encode --input ./out/config.json --type common.Config --output ./out/config.pb
configtxlator proto_encode --input ./out/modified_config.json --type common.Config --output ./out/modified_config.pb
configtxlator compute_update --channel_id $2 --original ./out/config.pb --updated ./out/modified_config.pb --output ./out/config_update.pb
$1
refers to our orderer address, $2
refer to channel name (system-channel) and $ORDERER_TLS
should refer to TLS certificate for the corresponding orderer.
The final step before starting the node is applying the changes via update transaction
# "applying changes"
configtxlator proto_decode --input ./out/config_update.pb --type common.ConfigUpdate --output ./out/config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"'$2'", "type":2}},"data":{"config_update":'$(cat ./out/config_update.json)'}}}' | jq . > ./out/config_update_in_envelope.json
configtxlator proto_encode --input ./out/config_update_in_envelope.json --type common.Envelope --output ./out/config_update_in_envelope.pb
# "submit update transaction"
peer channel update -f ./out/config_update_in_envelope.pb -c $2 -o $ORDERER_ADDRESS --tls --cafile $TLS_ROOT_CA
The final step is actually creating and running the orderer node. The easiest way is to use docker compose and add the service definition below
orderer1.example.com:
container_name: orderer1.example.com
extends:
file: orderer-base.yaml
service: orderer-base
environment:
- ORDERER_GENERAL_LISTENPORT=7150
volumes:
- ${FABRIC_SAMPLES_DIR}/test-network/system-genesis-block/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ${FABRIC_SAMPLES_DIR}/test-network/organizations/ordererOrganizations/example.com/orderers/orderer1.example.com/msp:/var/hyperledger/orderer/msp
- ${FABRIC_SAMPLES_DIR}/test-network/organizations/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/:/var/hyperledger/orderer/tls
- orderer1.example.com:/var/hyperledger/production/orderer
ports:
- 7150:7150
with orderer-base.yaml
defined below
version: '2'
services:
orderer-base:
image: hyperledger/fabric-orderer:$IMAGE_TAG
environment:
- FABRIC_LOGGING_SPEC=INFO
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
- ORDERER_GENERAL_GENESISMETHOD=file
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
# enabled TLS
- ORDERER_GENERAL_TLS_ENABLED=true
- ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
- ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1
- ORDERER_KAFKA_VERBOSE=true
- ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: orderer
networks:
- net_test # docker network for Test Network
Extending Test Network Peer
Extending peer node is easier. After you've generated all the required key, you can directly compose the node. One of the sample configuration for your node container is given below
peer1.org1.example.com:
container_name: peer1.org1.example.com
extends:
file: peer-base.yaml
service: peer-base
environment:
# Peer specific variabes
- CORE_PEER_ID=peer1.org1.example.com
- CORE_PEER_ADDRESS=peer1.org1.example.com:7151
- CORE_PEER_LISTENADDRESS=0.0.0.0:7151
- CORE_PEER_CHAINCODEADDRESS=peer1.org1.example.com:7152
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7152
- CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org1.example.com:7151
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:7151
- CORE_PEER_LOCALMSPID=Org1MSP
volumes:
- /var/run/:/host/var/run/
- ${FABRIC_SAMPLES_DIR}/test-network/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp
- ${FABRIC_SAMPLES_DIR}/test-network/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls
- peer1.org1.example.com:/var/hyperledger/production
ports:
- 7151:7151
with peer-base.yaml
defined below
version: '2'
services:
peer-base:
image: hyperledger/fabric-peer:$IMAGE_TAG
environment:
# Generic peer variables
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_test
- FABRIC_LOGGING_SPEC=WARN:cauthdsl=info:policies=debug:msp=info
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
networks:
- net_test # docker network for Test Network
That's basically it. Make sure that all certificates and keys are pointing in the correct and existing folder and you're good to go.
Enjoy your new network!
Top comments (6)
I forgot to mention that the script requires the file ./out/config_block.pb and other related files so you could provide it. The command
peer channel fetch config ./out/config_block.pb -o $ORDERER_ADDRESS -c $2 --tls --cafile $TLS_ROOT_CA
produces2020-06-30 09:38:43.595 CEST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-06-30 09:38:43.631 CEST [cli.common] readBlock -> INFO 002 Expect block, but got status: &{NOT_FOUND}
Error: can't read the block: &{NOT_FOUND}
Weird. all the files needed should be fetched and contained in out folder. Need to check that
Hi,
There folder
out/
needed to fetch the configuration is missing. Would you please upload it in your github repo?Ah, thanks for the information! you can create it yourself since it is originally an empty directory. I will update the script to create the directory first before fetching configuration
Also the CLI is great but SDK is most suited for production. Can you link me some tutorials to begin with NodeJs or Java
Yes, this is mostly for extending test network, which is not suitable for production. SDK is for client application to interact with blockchain network, which is not the purpose of network setup. When I create application clients, I might write a follow up tutorial :)