There are two ways to go about building applications on Hyperledger Fabric framework. The first method is to use Composer and the other is work directly on core Fabric and writing chaincode using Golang, Node.js, or Java.
Hyperledger Composer is a set of tools that makes the whole process of building blockchain application faster and easier. Composer speeds up the development time significantly and provides RESTful APIs for your applications to interact with.
Composer also abstracts away essential development steps that would otherwise prove crucial to understand critical parts of the Fabric framework. While the tool is helpful for rapid prototyping and can prove vital for a non-technical or a beginner to get started, however it does abstract away the most interesting parts of the technology.
Composer is helpful to get started on learning the technology but it you wish to understand the ins and outs of technology, Composer is not the way to go.
Here, we will be building a small network with one ordering service and one organization. We will be creating one channel for that organization and bootstrap one anchor peer in this part.
In the next part, we will then be using Typescript to write chaincode in Node.js environment and install it on the peer to provide access to the ledger.
If you wish to get your hands on the code, you can find the repository here.
If you haven’t already set up the development environment for Hyperledger Fabric, I urge you to head to this article I wrote a week ago.
We will be creating a simple network with one ordering service (orderer), one organization with one peer. We will create one channel and then install chaincode on that channel. In real life, one channel with one organization makes no sense but we are building it like this for the sake of simplicity.
If you are not familiar with the terms that I used and want to learn the basic of Fabric, there is no better place than the official documentation.
We will have following directory structure.
-> first-network -> /network -- /crypto-config.yaml
We define the orderer and different organizations that we want to be part of the network in a .yaml file. We normally call it crypto-config.yaml. Put the following in the crypto-config.yaml file.
OrdererOrgs: - Name: Orderer Domain: example.com Specs: - Hostname: orderer PeerOrgs: - Name: Org1 Domain: org1.example.com Template: Count: 1 Users: Count: 1
As we can see, we have defined one orderer and one organization. The domain/ID of the orderer is orderer.example.com and the domain of the peer organization is org1.example.com. The Template Count defines the number of peers that we want to bootstrap as part of the network and Users Count defines the number of users that will belong to that organization when the network is first created.
Create a new file called configtx.yaml inside the network directory. The project structure will now look like this.
-> first-network -> /network -- /crypto-config.yaml -- /configtx.yaml
Paste this in configtx.yaml file.
Organizations: - &OrdererOrg Name: OrdererOrg ID: OrdererMSP MSPDir: crypto-config/ordererOrganizations/example.com/msp - &Org1 Name: Org1MSP ID: Org1MSP MSPDir: crypto-config/peerOrganizations/org1.example.com/msp AnchorPeers: - Host: peer0.org1.example.com Port: 7051 Application: &ApplicationDefaults Organizations: Capabilities: Global: &ChannelCapabilities V1_1: true Orderer: &OrdererCapabilities V1_1: true Application: &ApplicationCapabilities V1_2: true Orderer: &OrdererDefaults OrdererType: solo Addresses: - orderer.example.com:7050 BatchTimeout: 2s BatchSize: MaxMessageCount: 10 AbsoluteMaxBytes: 99 MB PreferredMaxBytes: 512 KB Kafka: Brokers: - 127.0.0.1:9092 Organizations: Profiles: OneOrgOrdererGenesis: Capabilities: <<: *ChannelCapabilities Orderer: <<: *OrdererDefaults Organizations: - *OrdererOrg Capabilities: <<: *OrdererCapabilities Consortiums: SampleConsortium: Organizations: - *Org1 OneOrgChannel: Consortium: SampleConsortium Application: <<: *ApplicationDefaults Organizations: - *Org1 Capabilities: <<: *ApplicationCapabilities
First we define the MSP IDs of our Orderer and Org1 and also define the paths to the certificates that we will generate later. The path that we define in MSPDir does not exist right now. We will generate the certificates and create the paths later. Here, we also define the domain and port of anchor peers for our organization.
The we configure the capabilities of our network as having the ability to create new channels, etc,. Then we define Orderer specifications as running on solo consensus algorithm and its port.
Finally, we define Profiles that we will be using to refer to these specifications. We define the genesis block for our Orderer as OneOrgOrdererGenesis. The thing that we need to understand here is that there is no global blockchain ledger in the Fabric framework and ledgers are only available at the channel level. And there are two types of channels in a Fabric network, a system channel that is used by different orderers in the network and application channels that are composed of different peers at the application level. OneOrgOrdererGenesis is the profile name of the genesis block of the ledger in the system channel that is used to start the Orderer.
Then we define a consortium called SampleConsortium with Org1 as part of that consortium. And then we have the profile name of our channel called OneOrgChannel with Org1 as a member of that channel.
Open a terminal window in the /first-network/network directory and execute these commands.
cryptogen generate --config=./crypto-config.yaml
The Cryptogen tool that we installed in the previous article will be used to generate crypto materials to be used when signing transactions. This will create a new directory and output two more directories inside it. Our project looks like this now.
-> first-network -> /network -> /crypto-config -> /ordererOrganizations -> /peerOrganizations -- /crypto-config.yaml -- /configtx.yaml
The new directories will have the crypto material for our orderer and peer organization.
Execute the following commands to generate a genesis block, a channel transaction, and an anchor peer configuration transaction. We will then use these configuration transactions to bootstrap a Fabric network.
Configtxgen tool that we installed in the previous article will be used to generate configuration transactions.
mkdir config
configtxgen -profile OneOrgOrdererGenesis -outputBlock ./config/genesis.block
configtxgen uses the profile that we defined in the configtx.yaml file. The tool will look for the profile named OneOrgOrdererGenesis in the configtx.yaml.
configtxgen -profile OneOrgChannel -outputCreateChannelTx ./config/channel.tx -channelID mychannel
The tool will look for a channel profile named OneOrgChannel and output a configuration transaction named channel.tx in the /config directory. We also provided the ID of the channel.
configtxgen -profile OneOrgChannel -outputAnchorPeersUpdate ./config/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
The above command will create anchor peer configuration transaction called Org1MSPanchors.tx in the /config/ directory.
The project structure now looks like this.
-> first-network -> /network -> /config -> /channel.tx -> /genesis.block -> /Org1MSPanchors.tx -> /crypto-config -> /ordererOrganizations -> /peerOrganizations -- /crypto-config.yaml -- /configtx.yaml
Now that we have the configuration transactions, we will now move on to using these configuration transactions to start Orderer and create a channel.
We will be using a tool called docker-compose to start multiple docker containers that will work to simulate a Fabric network. To make things simpler, we will not be using multiple machines, we will be taking advantage of the power of docker and docker-compose to simulate multiple machines.
We will not be talking much about docker-compose here. If you want to learn more, visit docker’s documentation.
Create a new file called docker-compose.yml inside /first-network/network directory.
Paste this in docker-compose.yml.
version: '2' networks: basic: services: ca.example.com: image: hyperledger/fabric-ca environment: - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server - FABRIC_CA_SERVER_CA_NAME=ca.example.com - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/c8934e1a2f95d83d34852d9615f7c92880947bc1a077a9c0ae393fa33e8e6454_sk ports: - "7054:7054" command: sh -c 'fabric-ca-server start -b admin:adminpw -d' volumes: - ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config container_name: ca.example.com networks: - basic orderer.example.com: container_name: orderer.example.com image: hyperledger/fabric-orderer environment: - ORDERER_GENERAL_LOGLEVEL=debug - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 - ORDERER_GENERAL_GENESISMETHOD=file - ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block - ORDERER_GENERAL_LOCALMSPID=OrdererMSP - ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/msp/orderer/msp working_dir: /opt/gopath/src/github.com/hyperledger/fabric/orderer command: orderer ports: - 7050:7050 volumes: - ./config/:/etc/hyperledger/configtx - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/:/etc/hyperledger/msp/orderer - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/:/etc/hyperledger/msp/peerOrg1 networks: - basic peer0.org1.example.com: container_name: peer0.org1.example.com image: hyperledger/fabric-peer environment: - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - CORE_PEER_ID=peer0.org1.example.com - CORE_LOGGING_PEER=debug - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG - CORE_PEER_LOCALMSPID=Org1MSP - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/ - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 # # the following setting starts chaincode containers on the same # # bridge network as the peers # # https://docs.docker.com/compose/networking/ - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_basic - CORE_LEDGER_STATE_STATEDATABASE=CouchDB - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984 # The CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME and CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD # provide the credentials for ledger to connect to CouchDB. The username and password must # match the username and password set for the associated CouchDB. - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME= - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD= working_dir: /opt/gopath/src/github.com/hyperledger/fabric command: peer node start # command: peer node start --peer-chaincodedev=true ports: - 7051:7051 - 7053:7053 volumes: - /var/run/:/host/var/run/ - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/msp/peer - ./crypto-config/peerOrganizations/org1.example.com/users:/etc/hyperledger/msp/users - ./config:/etc/hyperledger/configtx depends_on: - orderer.example.com - couchdb networks: - basic couchdb: container_name: couchdb image: hyperledger/fabric-couchdb # Populate the COUCHDB_USER and COUCHDB_PASSWORD to set an admin user and password # for CouchDB. This will prevent CouchDB from operating in an "Admin Party" mode. environment: - COUCHDB_USER= - COUCHDB_PASSWORD= ports: - 5984:5984 networks: - basic cli: container_name: cli image: hyperledger/fabric-tools tty: true environment: - GOPATH=/opt/gopath - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - CORE_LOGGING_LEVEL=DEBUG - CORE_PEER_ID=cli - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 - CORE_PEER_LOCALMSPID=Org1MSP - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/A[email protected]/msp - CORE_CHAINCODE_KEEPALIVE=10 working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: /bin/bash volumes: - /var/run/:/host/var/run/ - ./../chaincode/:/opt/gopath/src/github.com/phr - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ networks: - basic
As you can probably guess, we will be using docker-compose to start five containers namely ca.example.com, orderer.example.com, peer0.org.example.com, couchdb, and cli.
The orderer container uses the genesis.block that we generated earlier to start the orderer.
Before we start the network, we need to do a very important change in the docker-compose.yml.
Execute this command from the network directory.
ls crypto-config/peerOrganizations/org1.example.com/ca
You will see a file with _sk appended at the end. Copy the name of the file, the secret key of our CA. Go back to docker-compose.yml file and search for the keyword “secret_key_here”. Replace the phrase “secret_key_here” with the name of the file you just copied. We are good to go now.
Run the command to start the network.
docker-compose -f docker-compose.yml up -d ca.example.com orderer.example.com peer0.org1.example.com couchdb
The command will start four containers that will form our network.
You can verify the containers that are running by executing the command.
docker ps
You should see an output like this.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 621bbda9f6ac hyperledger/fabric-peer "peer node start" 4 seconds ago Up 3 seconds 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer0.org1.example.com 1e3f3476f727 hyperledger/fabric-orderer "orderer" 7 seconds ago Up 4 seconds 0.0.0.0:7050->7050/tcp orderer.example.com 32fcf0d2baa9 hyperledger/fabric-ca "sh -c 'fabric-ca-se…" 7 seconds ago Up 4 seconds 0.0.0.0:7054->7054/tcp ca.example.com de9b898e3c09 hyperledger/fabric-couchdb "tini -- /docker-ent…" 7 seconds ago Up 4 seconds 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb
If you see a similar output as above, you have successfully started a Hyperledger Fabric network.
Now, we will create a channel and join Org1 to that channel.
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer0.org1.example.com peer channel create -o orderer.example.com:7050 -c mychannel -f /etc/hyperledger/configtx/channel.tx
The above command will use channel.tx configuration transaction that we generated earlier to create a new channel.
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/[email protected]/msp" peer0.org1.example.com peer channel join -b mychannel.block
Now, our peer from Org1 is joined to the channel mychannel.
We created the simplest network with one orderer and one organization. In reality, there are multiple orderers and multiple organizations connected to multiple channels. We might get into exploring it later down the line.
If you want to get your hands on the code, you can get it here.
In the next part, we will learn to code chaincode in Node.js and install it on our peer.
UPDATE: The part 2 is available here
Interested in starting your own blockchain project, but don’t know how? Get in touch at https://xord.solutions/contact
Share: