March 15, 2019 Abdul Sami

Guide to setting up your first Hyperledger Fabric network (Part 2)

Spread the word!

Overview

In this part, we are going to write a chaincode (smart contract), install and instantiate it, and interact with it. We are going to use the repository that we developed in the previous guide. The repository contains both the network and chaincode as well as useful scripts to automate crucial tasks.

What is chaincode?

Prerequisites to writing chaincode

  • Install Typescript.
npm install typescript -g
  • Create a new directory at the root of the project called chaincode and set set up a new Typescript project.
mkdir chaincode/node
cd chaincode/node
tsc --init
  • Create a package.json file inside the chaincode/node directory
{
"name": "fisr-network-chaincode",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"lint": "tslint --fix -c tslint.json './src/**/*.ts'",
"test": "npm run lint && mocha -r ts-node/register tests/**/*.spec.ts --reporter spec",
"test:w": "npm run lint && mocha -r ts-node/register tests/**/*.spec.ts --reporter spec --watch app/**/*.spec.ts --watch-extensions ts",
"clean": "rm -rf dist",
"start": "node dist/index.js"
},
"author": "xord",
"dependencies": {
"@theledger/fabric-chaincode-utils": "^3.0.2",
"@types/lodash": "^4.14.104",
"fabric-shim": "^1.2.0",
"lodash": "^4.17.5",
"winston": "^2.4.0",
"yup": "^0.24.1"
},
"devDependencies": {
"@theledger/fabric-mock-stub": "^2.0.1",
"@theledger/fabric-shim-crypto-types": "^1.0.4",
"@theledger/fabric-shim-types": "^2.0.7",
"@types/express-serve-static-core": "4.0.49",
"@types/node": "^8.5.8",
"@types/winston": "^2.3.8",
"@types/yup": "^0.24.1",
"nodemon": "^1.12.1",
"ts-node": "^5.0.1",
"tslint": "4.5.1",
"typescript": "^2.6.2"
}
}
view raw package.json hosted with ❤ by GitHub

  • Create tsconfig.json file.
{
"compilerOptions": {
"rootDir": "./src",
"suppressImplicitAnyIndexErrors": true,
"noImplicitAny": true,
"sourceMap": false,
"target": "es5",
"module": "commonjs",
"declaration": false,
"outDir": "./dist",
"types": [
"@theledger/fabric-shim-types",
"@theledger/fabric-shim-crypto-types"
],
"typeRoots": [
"./node_modules/@types"
],
"lib": [
"es2015",
"dom"
]
},
"exclude": [
"./tests/*.ts"
]
}
view raw tsconfig.json hosted with ❤ by GitHub
  • Create yarn.lock file to ensure that you have the right versions of packages being installed.
{
"rules": {
"class-name": true,
"comment-format": [
false
],
"curly": true,
"eofline": false,
"forin": true,
"indent": [
true,
"spaces",
4
],
"label-position": true,
"max-line-length": [
true,
150
],
"member-access": false,
"no-conditional-assignment": true,
"no-require-imports": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"constructor",
"public-instance-method",
"protected-instance-method",
"private-instance-method"
]
}
],
"no-any": false,
"no-arg": true,
"no-bitwise": true,
"no-magic-numbers": false,
"object-literal-key-quotes": [
false
],
"object-literal-shorthand": false,
"no-mergeable-namespace": true,
"no-console": [
false,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-empty-interface": true,
"no-eval": true,
"completed-docs": [
false
],
"no-inferrable-types": [
true
],
"no-invalid-this": [
true
],
"cyclomatic-complexity": [
true,
20
],
"no-shadowed-variable": true,
"no-string-literal": false,
"no-switch-case-fall-through": true,
"no-for-in-array": false,
"no-trailing-whitespace": false,
"no-unused-expression": true,
"no-unused-variable": true,
"no-unsafe-finally": true,
"no-unused-new": false,
"no-parameter-properties": false,
"no-use-before-declare": true,
"use-isnan": true,
"switch-default": true,
"jsdoc-format": false,
"no-var-requires": false,
"no-var-keyword": true,
"no-default-export": true,
"restrict-plus-operands": false,
"object-literal-sort-keys": false,
"prefer-for-of": true,
"no-null-keyword": false,
"new-parens": true,
"no-angle-bracket-type-assertion": false,
"no-consecutive-blank-lines": true,
"max-classes-per-file": [
true,
1
],
"file-header": [
false
],
"align": [
true
],
"array-type": [
false
],
"interface-name": [
false
],
"arrow-parens": false,
"one-variable-per-declaration": [
false
],
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-finally"
],
"quotemark": [
true,
"single",
"avoid-escape"
],
"radix": false,
"semicolon": [
true
],
"trailing-comma": [
false
],
"triple-equals": [
false
],
"typedef": [
true
],
"variable-name": [
true,
"allow-leading-underscore",
"allow-pascal-case"
],
"whitespace": [
false
]
}
}
view raw yarn.lock hosted with ❤ by GitHub
  • Install all the npm packages.
npm install

Writing chaincode

import {Chaincode, StubHelper} from "@theledger/fabric-chaincode-utils";
export default class Firstchaincode extends Chaincode {
async initLedger(stubHelper: StubHelper, args: string[]) {
let cars = [];
cars.push(new Car("1", 'black', "Honda", "Civic"));
cars.push(new Car("2", 'blue', "Toyota", "Prius"));
cars.push(new Car("3", 'red', "Suzuki", "Ciaz"));
for (let i = 0; i < cars.length; i++) {
const car: Car = cars[i];
await stubHelper.putState(car.id, car);
this.logger.info('Added <--> ', car);
}
}
async queryAllCars(stubHelper: StubHelper): Promise<any> {
return stubHelper.getQueryResultAsList(
{selector:{ docType: 'car'}}
);
}
}
class Car {
public docType?: string;
public id: string;
public color: string;
public make: string;
public model: string;
public constructor(id: string, color: string, make: string, model: string) {
this.docType = 'car';
this.id = id;
this.color = color;
this.make = make;
this.model = model;
}
}
view raw chaincode.ts hosted with ❤ by GitHub
import shim = require('fabric-shim');
import Firstchaincode from './chaincode';
shim.start(new Firstchaincode());
view raw index.ts hosted with ❤ by GitHub

If you have experience writing smart contracts using Solidity in Ethereum or other public blockchain, you might notice similarities. We have a chaincode class named FirstChaincode which has two functions that are available to be executed from outside the ledger. initLedger function adds car entries into the ledger. The second function queryAllCars returns all the car objects that have been initialized.

We use the chaincode utils developed by the TheLedger. You will find the chaincode Node.js SDK to be quite different if you look at the official chaincode samples developed by Hyperledger Fabric. These utilities are intended to make writing chaincode easier.

We are going to start the network that we built in the previous article, create and join channels, install and instantiate the chaincode, and finally call functions on the chaincode.

Building the network

Starting the network

docker-compose -f docker-compose.yml up -d

Creating and joining the channel

docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp" peer0.org1.example.com peer channel create -o orderer.example.com:7050 -c mychannel -f /etc/hyperledger/configtx/channel.txdocker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp" peer0.org1.example.com peer channel join -b mychannel.block

Installing the chaincode

  • Building; builds the source code to be installed on peers.
  • Installing; installs the chaincode on peers.
  • Instantiating; instantiates the chaincode interface to become public in the scope of the channel.

Go to the chaincode/node directory.

Building

yarn
yarn run clean
yarn run build

Installing

docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode install -n "firstchaincode" -v "1.0" -p "/opt/gopath/src/github.com/firstchaincode/node" -l "node"

Instantiating

docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n "firstchaincode" -l "node" -v "1.0" -c '{"function":"init","Args":["'1.0'"]}'

Now, that we have the network deployed and chaincode installed and instantiated. We will interact with the chaincode.

Executing a transaction

docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n "firstchaincode" -c '{"function":"initLedger","Args":[""]}'

You should see the following message.

2019-03-14 08:56:24.608 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 04f Chaincode invoke successful. result: status:200

Querying the chaincode

docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode query -o orderer.example.com:7050 -C mychannel -n "firstchaincode" -c '{"function":"queryAllCars","Args":[""]}'

If you see an output like this, your invoke function was successful.

[{"color":"black","docType":"car","id":"1","make":"Honda","model":"Civic"},{"color":"blue","docType":"car","id":"2","make":"Toyota","model":"Prius"},{"color":"red","docType":"car","id":"3","make":"Suzuki","model":"Ciaz"}]

Conclusion

If you want to get your hands on the code, you can get it here.

Get in touch


Spread the word!
, , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

three × 5 =