Here is a brief summary of what we have accomplished so far:
- Part 1 - Generated the crypto material for the various participants.
- Part 2 - Generated the genesis block for the Orderer node and started ordering service (solo node).
- Part 3 - Generated the configuration transaction block to create a new channel.
- Part 4 - Signed the configuration block and created the new channel.
- Part 5 - Make peers of all the organizations join the channel that we created in Part 4.
We now have a channel and peers of our participating organizations have joined, the next step is to provide the business logic that should be executed on this channel. In BlockChain this business logic is typically called Smart Contracts; Hyperledger Fabric call it Chaincode. A Chaincode in Fabric is essentially a program/application written in GoLang that exposes a set of interfaces that can be invoked by the client applications. The entry points of a Chaincode program/application also receives optional arguments and have access to the ledger so that it can read and write data to it.
The hyperledger-fabric-example project makes use of a very simple Chaincode application (chaincode/src/github.com/example_cc/example_cc.go
). The business logic is quite simple and described below:
- Have two entities.
- The names and initial values of these entities are to be passed at the time of initialization.
- You could move portion/part of value from one entity to another entity.
- You could query the current value of an entity.
- You could delete an entity.
If you look at the source code of (chaincode/src/github.com/example_cc/example_cc.go
) you should be able to see corresponding functions to the business logic requirements that I have specified above.
With the description of our business logic (Smart Contract / Chaincode) out of way, the first order of business (pun intended) is to install this application on the peers of various participating organizations.
The steps for performing the installation of Chaincode are done in src/install-chaincode.ts script and here is shown the relevant code snippet that should be descriptive enough for you to know how it is done :
async function installChaincodeOnPeers(org: Organization) {
const client = await getClient(org);
const orderer = await getOrderer(client);
console.log('Creating a Channel object ..');
const channel = client.newChannel(config.CHANNEL_NAME);
console.log('Specifying the orderer to connect to ..');
channel.addOrderer(orderer);
console.log('Getting the peers ..');
const peers = await getPeers(client, org);
// Note-
// The installChaincode is going to pick the chaincodePath
// from the local GOPATH
//
// Below I am just tricking it by setting the GOPATH environment
// variable and pointing it to the directory that contains the
// actual chain code
process.env.GOPATH = path.join(__dirname, '../chaincode');
const proposalResponse = await client.installChaincode({
targets: peers,
chaincodeId: config.CHAIN_CODE_ID,
chaincodePath: 'github.com/example_cc',
chaincodeVersion: 'v0'
});
}
async function main() {
await installChaincodeOnPeers(Organization.ORG1);
await installChaincodeOnPeers(Organization.ORG2);
await installChaincodeOnPeers(Organization.ORG3);
}
main();
You can run the script by issuing following command :
npm run install-chaincode
Once it is installed the next step is to instantiate (initialize) the Chaincode application. The steps for it are shown in src/instantiate-chaincode.ts script.
async function instantiateChaincodeOnPeers(org: Organization) {
const client = await getClient(org);
const orderer = await getOrderer(client);
console.log('Creating a Channel object ..');
const channel = client.newChannel(config.CHANNEL_NAME);
console.log('Specifying the orderer to connect to ..');
channel.addOrderer(orderer);
console.log('Getting the peers ..');
const peers = await getPeers(client, org);
peers.map(p => channel.addPeer(p));
console.log('Initializing the channel ..');
await channel.initialize();
console.log('Sending the Instantiate Proposal ..');
const proposalResponse = await channel.sendInstantiateProposal({
chaincodeId: config.CHAIN_CODE_ID,
chaincodeVersion: 'v0',
fcn: 'init',
args: ["a", "100", "b", "200"],
txId: client.newTransactionID()
});
console.log('Sending the Transaction ..');
const transactionResponse = await channel.sendTransaction({
proposalResponses: proposalResponse[0],
proposal: proposalResponse[1]
});
}
async function main() {
await instantiateChaincodeOnPeers(Organization.ORG1);
await instantiateChaincodeOnPeers(Organization.ORG2);
await instantiateChaincodeOnPeers(Organization.ORG3);
}
main();
You can run the script by issuing following command :
npm run instantiate-chaincode
Pay attention to the request object passed as argument of channel.sendInstantiateProposal
method.
const proposalResponse = await channel.sendInstantiateProposal({
chaincodeId: config.CHAIN_CODE_ID,
chaincodeVersion: 'v0',
fcn: 'init',
args: ["a", "100", "b", "200"],
txId: client.newTransactionID()
});
Here fcn
is the name of the function to be invoked. Look in example_cc.go
file and you would see a corresponding function that is named init
. The arguments that this function expects is an array of keyvalue pair with key being the name of the entity and the value being the value of the asset. So what we are passing are two entities that are named ‘a’ & ‘b’ with values of ‘100’ & ‘200’ respectively.
This marks the completion of bootstrapping a Hyperledger Fabric network with Business logic (Smart Contract / Chaincode) installed and instantiated.