[FAB-5898] porting samples to node.js chaincode

Fabric 1.1 supports javascript chaincode. This changeset
addresses porting of the golang chaincode to node.js
chiancode and the corresponding README files

Change-Id: Iae24e713f16ab3508fe0cc18ee062ffa412b8ba6
Signed-off-by: ratnakar <asara.ratnakar@gmail.com>
This commit is contained in:
ratnakar 2017-10-08 22:35:09 -04:00
parent 38ad27885f
commit 44c204d8b6
25 changed files with 1081 additions and 155 deletions

2
.gitignore vendored
View file

@ -19,7 +19,9 @@ chaincode-docker-devmode/chaincode/chaincode_example02/chaincode_example02
# fabric sdk node modules
fabcar/node_modules/
fabcar/package-lock.json
# balance transfer sample
balance-transfer/.DS_Store
balance-transfer/node_modules/*
balance-transfer/package-lock.json

View file

@ -27,6 +27,7 @@ Once you have completed the above setup, you will have provisioned a local netwo
## Running the sample program
There are two options available for running the balance-transfer sample
For each of these options, you may choose to run with chaincode written in golang or in node.js.
### Option 1:
@ -82,10 +83,16 @@ With the application started in terminal 1, next, test the APIs by executing the
```
cd fabric-samples/balance-transfer
./testAPIs.sh
## To use golang chaincode execute the following command
./testAPIs.sh -l golang
## OR use node.js chaincode
./testAPIs.sh -l node
```
## Sample REST APIs Requests
### Login Request
@ -144,9 +151,25 @@ curl -s -X POST \
"peers": ["peer1","peer2"],
"chaincodeName":"mycc",
"chaincodePath":"github.com/example_cc",
"chaincodeType": "golang",
"chaincodeVersion":"v0"
}'
```
**NOTE:** *chaincodeType* must be set to **node** when node.js chaincode is used and *chaincodePath* must be set to the location of the node.js chaincode.
```
ex:
curl -s -X POST \
http://localhost:4000/chaincodes \
-H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \
-H "content-type: application/json" \
-d "{
\"peers\": [\"peer1\",\"peer2\"],
\"chaincodeName\":\"mycc\",
\"chaincodePath\":\"$PWD/artifacts/src/github.com/example_cc/node\",
\"chaincodeType\": \"node\",
\"chaincodeVersion\":\"v0\"
}"
```
### Instantiate chaincode
@ -158,9 +181,11 @@ curl -s -X POST \
-d '{
"chaincodeName":"mycc",
"chaincodeVersion":"v0",
"chaincodeType": "golang",
"args":["a","100","b","200"]
}'
```
**NOTE:** *chaincodeType* must be set to **node** when node.js chaincode is used
### Invoke request

View file

@ -187,10 +187,12 @@ app.post('/chaincodes', function(req, res) {
var chaincodeName = req.body.chaincodeName;
var chaincodePath = req.body.chaincodePath;
var chaincodeVersion = req.body.chaincodeVersion;
var chaincodeType = req.body.chaincodeType;
logger.debug('peers : ' + peers); // target peers list
logger.debug('chaincodeName : ' + chaincodeName);
logger.debug('chaincodePath : ' + chaincodePath);
logger.debug('chaincodeVersion : ' + chaincodeVersion);
logger.debug('chaincodeType : ' + chaincodeType);
if (!peers || peers.length == 0) {
res.json(getErrorMessage('\'peers\''));
return;
@ -207,8 +209,11 @@ app.post('/chaincodes', function(req, res) {
res.json(getErrorMessage('\'chaincodeVersion\''));
return;
}
install.installChaincode(peers, chaincodeName, chaincodePath, chaincodeVersion, req.username, req.orgname)
if (!chaincodeType) {
res.json(getErrorMessage('\'chaincodeType\''));
return;
}
install.installChaincode(peers, chaincodeName, chaincodePath, chaincodeVersion, chaincodeType, req.username, req.orgname)
.then(function(message) {
res.send(message);
});
@ -219,11 +224,13 @@ app.post('/channels/:channelName/chaincodes', function(req, res) {
var chaincodeName = req.body.chaincodeName;
var chaincodeVersion = req.body.chaincodeVersion;
var channelName = req.params.channelName;
var chaincodeType = req.body.chaincodeType;
var fcn = req.body.fcn;
var args = req.body.args;
logger.debug('channelName : ' + channelName);
logger.debug('chaincodeName : ' + chaincodeName);
logger.debug('chaincodeVersion : ' + chaincodeVersion);
logger.debug('chaincodeType : ' + chaincodeType);
logger.debug('fcn : ' + fcn);
logger.debug('args : ' + args);
if (!chaincodeName) {
@ -238,11 +245,15 @@ app.post('/channels/:channelName/chaincodes', function(req, res) {
res.json(getErrorMessage('\'channelName\''));
return;
}
if (!chaincodeType) {
res.json(getErrorMessage('\'chaincodeType\''));
return;
}
if (!args) {
res.json(getErrorMessage('\'args\''));
return;
}
instantiate.instantiateChaincode(channelName, chaincodeName, chaincodeVersion, fcn, args, req.username, req.orgname)
instantiate.instantiateChaincode(channelName, chaincodeName, chaincodeVersion, chaincodeType, fcn, args, req.username, req.orgname)
.then(function(message) {
res.send(message);
});

View file

@ -21,9 +21,9 @@ var config = require('../config.json');
var helper = require('./helper.js');
var logger = helper.getLogger('install-chaincode');
var tx_id = null;
//function installChaincode(org) {
var installChaincode = function(peers, chaincodeName, chaincodePath,
chaincodeVersion, username, org) {
chaincodeVersion, chaincodeType, username, org) {
logger.debug(
'\n============ Install chaincode on organizations ============\n');
helper.setupChaincodeDeploy();
@ -35,7 +35,8 @@ var installChaincode = function(peers, chaincodeName, chaincodePath,
targets: helper.newPeers(peers, org),
chaincodePath: chaincodePath,
chaincodeId: chaincodeName,
chaincodeVersion: chaincodeVersion
chaincodeVersion: chaincodeVersion,
chaincodeType: chaincodeType
};
return client.installChaincode(request);
}, (err) => {

View file

@ -26,7 +26,8 @@ var ORGS = hfc.getConfigSetting('network-config');
var tx_id = null;
var eh = null;
var instantiateChaincode = function(channelName, chaincodeName, chaincodeVersion, functionName, args, username, org) {
var instantiateChaincode = function(channelName, chaincodeName, chaincodeVersion, functionName, chaincodeType,
args, username, org) {
logger.debug('\n============ Instantiate chaincode on organization ' + org +
' ============\n');
@ -46,6 +47,7 @@ var instantiateChaincode = function(channelName, chaincodeName, chaincodeVersion
// send proposal to endorser
var request = {
chaincodeId: chaincodeName,
chaincodeType: chaincodeType,
chaincodeVersion: chaincodeVersion,
args: args,
txId: tx_id

View file

@ -0,0 +1,140 @@
/*
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
*/
const shim = require('fabric-shim');
const util = require('util');
var Chaincode = class {
// Initialize the chaincode
async Init(stub) {
console.info('========= example_cc Init =========');
let ret = stub.getFunctionAndParameters();
console.info(ret);
let args = ret.params;
// initialise only if 4 parameters passed.
if (args.length != 4) {
return shim.error('Incorrect number of arguments. Expecting 4');
}
let A = args[0];
let B = args[2];
let Aval = args[1];
let Bval = args[3];
if (typeof parseInt(Aval) !== 'number' || typeof parseInt(Bval) !== 'number') {
return shim.error('Expecting integer value for asset holding');
}
try {
await stub.putState(A, Buffer.from(Aval));
try {
await stub.putState(B, Buffer.from(Bval));
return shim.success();
} catch (err) {
return shim.error(err);
}
} catch (err) {
return shim.error(err);
}
}
async Invoke(stub) {
let ret = stub.getFunctionAndParameters();
console.info(ret);
let method = this[ret.fcn];
if (!method) {
console.error('no method of name:' + ret.fcn + ' found');
return shim.error('no method of name:' + ret.fcn + ' found');
}
console.info('\nCalling method : ' + ret.fcn);
try {
let payload = await method(stub, ret.params);
return shim.success(payload);
} catch (err) {
console.log(err);
return shim.error(err);
}
}
async move(stub, args) {
if (args.length != 3) {
throw new Error('Incorrect number of arguments. Expecting 3');
}
let A = args[0];
let B = args[1];
if (!A || !B) {
throw new Error('asset holding must not be empty');
}
// Get the state from the ledger
let Avalbytes = await stub.getState(A);
if (!Avalbytes) {
throw new Error('Failed to get state of asset holder A');
}
let Aval = parseInt(Avalbytes.toString());
let Bvalbytes = await stub.getState(B);
if (!Bvalbytes) {
throw new Error('Failed to get state of asset holder B');
}
let Bval = parseInt(Bvalbytes.toString());
// Perform the execution
let amount = parseInt(args[2]);
if (typeof amount !== 'number') {
throw new Error('Expecting integer value for amount to be transaferred');
}
Aval = Aval - amount;
Bval = Bval + amount;
console.info(util.format('Aval = %d, Bval = %d\n', Aval, Bval));
// Write the states back to the ledger
await stub.putState(A, Buffer.from(Aval.toString()));
await stub.putState(B, Buffer.from(Bval.toString()));
}
// Deletes an entity from state
async delete(stub, args) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting 1');
}
let A = args[0];
// Delete the key from the state in ledger
await stub.deleteState(A);
}
// query callback representing the query of a chaincode
async query(stub, args) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting name of the person to query')
}
let jsonResp = {};
let A = args[0];
// Get the state from the ledger
let Avalbytes = await stub.getState(A);
if (!Avalbytes) {
jsonResp.error = 'Failed to get state for ' + A;
throw new Error(JSON.stringify(jsonResp));
}
jsonResp.name = A;
jsonResp.amount = Avalbytes.toString();
console.info('Query Response:');
console.info(jsonResp);
return Avalbytes;
}
};
shim.start(new Chaincode());

View file

@ -0,0 +1,15 @@
{
"name": "example_cc",
"version": "1.0.0",
"description": "node-js version of example_02.go chaincode",
"engines": {
"node": ">=8.4.0",
"npm": ">=5.3.0"
},
"scripts": { "start" : "node example_cc.js" },
"engine-strict": true,
"license": "Apache-2.0",
"dependencies": {
"fabric-shim": "unstable"
}
}

View file

@ -24,8 +24,8 @@
"express-bearer-token": "^2.1.0",
"express-jwt": "^5.1.0",
"express-session": "^1.15.2",
"fabric-ca-client": "^1.0.0",
"fabric-client": "^1.0.0",
"fabric-ca-client": "unstable",
"fabric-client": "unstable",
"fs-extra": "^2.0.0",
"jsonwebtoken": "^7.3.0",
"log4js": "^0.6.38"

View file

@ -11,8 +11,47 @@ if [ $? -ne 0 ]; then
echo
exit 1
fi
starttime=$(date +%s)
# Print the usage message
function printHelp () {
echo "Usage: "
echo " ./testAPIs.sh -l golang|node"
echo " -l <language> - chaincode language (defaults to \"golang\")"
}
# Language defaults to "golang"
LANGUAGE="golang"
# Parse commandline args
while getopts "h?l:" opt; do
case "$opt" in
h|\?)
printHelp
exit 0
;;
l) LANGUAGE=$OPTARG
;;
esac
done
##set chaincode path
function setChaincodePath(){
LANGUAGE=`echo "$LANGUAGE" | tr '[:upper:]' '[:lower:]'`
case "$LANGUAGE" in
"golang")
CC_SRC_PATH="github.com/example_cc/go"
;;
"node")
CC_SRC_PATH="$PWD/artifacts/src/github.com/example_cc/node"
;;
*) printf "\n ------ Language $LANGUAGE is not supported yet ------\n"$
exit 1
esac
}
setChaincodePath
echo "POST request Enroll on Org1 ..."
echo
ORG1_TOKEN=$(curl -s -X POST \
@ -79,28 +118,29 @@ curl -s -X POST \
http://localhost:4000/chaincodes \
-H "authorization: Bearer $ORG1_TOKEN" \
-H "content-type: application/json" \
-d '{
"peers": ["peer1", "peer2"],
"chaincodeName":"mycc",
"chaincodePath":"github.com/example_cc",
"chaincodeVersion":"v0"
}'
-d "{
\"peers\": [\"peer1\", \"peer2\"],
\"chaincodeName\":\"mycc\",
\"chaincodePath\":\"$CC_SRC_PATH\",
\"chaincodeType\": \"$LANGUAGE\",
\"chaincodeVersion\":\"v0\"
}"
echo
echo
echo "POST Install chaincode on Org2"
echo
curl -s -X POST \
http://localhost:4000/chaincodes \
-H "authorization: Bearer $ORG2_TOKEN" \
-H "content-type: application/json" \
-d '{
"peers": ["peer1","peer2"],
"chaincodeName":"mycc",
"chaincodePath":"github.com/example_cc",
"chaincodeVersion":"v0"
}'
-d "{
\"peers\": [\"peer1\",\"peer2\"],
\"chaincodeName\":\"mycc\",
\"chaincodePath\":\"$CC_SRC_PATH\",
\"chaincodeType\": \"$LANGUAGE\",
\"chaincodeVersion\":\"v0\"
}"
echo
echo
@ -110,11 +150,12 @@ curl -s -X POST \
http://localhost:4000/channels/mychannel/chaincodes \
-H "authorization: Bearer $ORG1_TOKEN" \
-H "content-type: application/json" \
-d '{
"chaincodeName":"mycc",
"chaincodeVersion":"v0",
"args":["a","100","b","200"]
}'
-d "{
\"chaincodeName\":\"mycc\",
\"chaincodeVersion\":\"v0\",
\"chaincodeType\": \"$LANGUAGE\",
\"args\":[\"a\",\"100\",\"b\",\"200\"]
}"
echo
echo

View file

@ -1,112 +0,0 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"testing"
"github.com/hyperledger/fabric/core/chaincode/shim"
)
func checkInit(t *testing.T, stub *shim.MockStub, args [][]byte) {
res := stub.MockInit("1", args)
if res.Status != shim.OK {
fmt.Println("Init failed", string(res.Message))
t.FailNow()
}
}
func checkState(t *testing.T, stub *shim.MockStub, name string, value string) {
bytes := stub.State[name]
if bytes == nil {
fmt.Println("State", name, "failed to get value")
t.FailNow()
}
if string(bytes) != value {
fmt.Println("State value", name, "was not", value, "as expected")
t.FailNow()
}
}
func checkQuery(t *testing.T, stub *shim.MockStub, name string, value string) {
res := stub.MockInvoke("1", [][]byte{[]byte("query"), []byte(name)})
if res.Status != shim.OK {
fmt.Println("Query", name, "failed", string(res.Message))
t.FailNow()
}
if res.Payload == nil {
fmt.Println("Query", name, "failed to get value")
t.FailNow()
}
if string(res.Payload) != value {
fmt.Println("Query value", name, "was not", value, "as expected")
t.FailNow()
}
}
func checkInvoke(t *testing.T, stub *shim.MockStub, args [][]byte) {
res := stub.MockInvoke("1", args)
if res.Status != shim.OK {
fmt.Println("Invoke", args, "failed", string(res.Message))
t.FailNow()
}
}
func TestExample02_Init(t *testing.T) {
scc := new(SimpleChaincode)
stub := shim.NewMockStub("ex02", scc)
// Init A=123 B=234
checkInit(t, stub, [][]byte{[]byte("init"), []byte("A"), []byte("123"), []byte("B"), []byte("234")})
checkState(t, stub, "A", "123")
checkState(t, stub, "B", "234")
}
func TestExample02_Query(t *testing.T) {
scc := new(SimpleChaincode)
stub := shim.NewMockStub("ex02", scc)
// Init A=345 B=456
checkInit(t, stub, [][]byte{[]byte("init"), []byte("A"), []byte("345"), []byte("B"), []byte("456")})
// Query A
checkQuery(t, stub, "A", "345")
// Query B
checkQuery(t, stub, "B", "456")
}
func TestExample02_Invoke(t *testing.T) {
scc := new(SimpleChaincode)
stub := shim.NewMockStub("ex02", scc)
// Init A=567 B=678
checkInit(t, stub, [][]byte{[]byte("init"), []byte("A"), []byte("567"), []byte("B"), []byte("678")})
// Invoke A->B for 123
checkInvoke(t, stub, [][]byte{[]byte("invoke"), []byte("A"), []byte("B"), []byte("123")})
checkQuery(t, stub, "A", "444")
checkQuery(t, stub, "B", "801")
// Invoke B->A for 234
checkInvoke(t, stub, [][]byte{[]byte("invoke"), []byte("B"), []byte("A"), []byte("234")})
checkQuery(t, stub, "A", "678")
checkQuery(t, stub, "B", "567")
checkQuery(t, stub, "A", "678")
checkQuery(t, stub, "B", "567")
}

View file

@ -0,0 +1,138 @@
/*
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
*/
const shim = require('fabric-shim');
const util = require('util');
var Chaincode = class {
// Initialize the chaincode
async Init(stub) {
console.info('========= example02 Init =========');
let ret = stub.getFunctionAndParameters();
console.info(ret);
let args = ret.params;
// initialise only if 4 parameters passed.
if (args.length != 4) {
return shim.error('Incorrect number of arguments. Expecting 4');
}
let A = args[0];
let B = args[2];
let Aval = args[1];
let Bval = args[3];
if (typeof parseInt(Aval) !== 'number' || typeof parseInt(Bval) !== 'number') {
return shim.error('Expecting integer value for asset holding');
}
try {
await stub.putState(A, Buffer.from(Aval));
try {
await stub.putState(B, Buffer.from(Bval));
return shim.success();
} catch (err) {
return shim.error(err);
}
} catch (err) {
return shim.error(err);
}
}
async Invoke(stub) {
let ret = stub.getFunctionAndParameters();
console.info(ret);
let method = this[ret.fcn];
if (!method) {
console.log('no method of name:' + ret.fcn + ' found');
return shim.success();
}
try {
let payload = await method(stub, ret.params);
return shim.success(payload);
} catch (err) {
console.log(err);
return shim.error(err);
}
}
async invoke(stub, args) {
if (args.length != 3) {
throw new Error('Incorrect number of arguments. Expecting 3');
}
let A = args[0];
let B = args[1];
if (!A || !B) {
throw new Error('asset holding must not be empty');
}
// Get the state from the ledger
let Avalbytes = await stub.getState(A);
if (!Avalbytes) {
throw new Error('Failed to get state of asset holder A');
}
let Aval = parseInt(Avalbytes.toString());
let Bvalbytes = await stub.getState(B);
if (!Bvalbytes) {
throw new Error('Failed to get state of asset holder B');
}
let Bval = parseInt(Bvalbytes.toString());
// Perform the execution
let amount = parseInt(args[2]);
if (typeof amount !== 'number') {
throw new Error('Expecting integer value for amount to be transaferred');
}
Aval = Aval - amount;
Bval = Bval + amount;
console.info(util.format('Aval = %d, Bval = %d\n', Aval, Bval));
// Write the states back to the ledger
await stub.putState(A, Buffer.from(Aval.toString()));
await stub.putState(B, Buffer.from(Bval.toString()));
}
// Deletes an entity from state
async delete(stub, args) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting 1');
}
let A = args[0];
// Delete the key from the state in ledger
await stub.deleteState(A);
}
// query callback representing the query of a chaincode
async query(stub, args) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting name of the person to query')
}
let jsonResp = {};
let A = args[0];
// Get the state from the ledger
let Avalbytes = await stub.getState(A);
if (!Avalbytes) {
jsonResp.error = 'Failed to get state for ' + A;
throw new Error(JSON.stringify(jsonResp));
}
jsonResp.name = A;
jsonResp.amount = Avalbytes.toString();
console.info('Query Response:');
console.info(jsonResp);
return Avalbytes;
}
};
shim.start(new Chaincode());

View file

@ -0,0 +1,15 @@
{
"name": "chaincode_example02",
"version": "1.0.0",
"description": "chaincode_example02 chaincode implemented in node.js",
"engines": {
"node": ">=8.4.0",
"npm": ">=5.3.0"
},
"scripts": { "start" : "node chaincode_example02.js" },
"engine-strict": true,
"license": "Apache-2.0",
"dependencies": {
"fabric-shim": "unstable"
}
}

View file

@ -0,0 +1,193 @@
/*
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const shim = require('fabric-shim');
const util = require('util');
let Chaincode = class {
// The Init method is called when the Smart Contract 'fabcar' is instantiated by the blockchain network
// Best practice is to have any Ledger initialization in separate function -- see initLedger()
async Init(stub) {
console.info('=========== Instantiated fabcar chaincode ===========');
return shim.success();
}
// The Invoke method is called as a result of an application request to run the Smart Contract
// 'fabcar'. The calling application program has also specified the particular smart contract
// function to be called, with arguments
async Invoke(stub) {
let ret = stub.getFunctionAndParameters();
console.info(ret);
let method = this[ret.fcn];
if (!method) {
console.error('no function of name:' + ret.fcn + ' found');
throw new Error('Received unknown function ' + ret.fcn + ' invocation');
}
try {
let payload = await method(stub, ret.params);
return shim.success(payload);
} catch (err) {
console.log(err);
return shim.error(err);
}
}
async queryCar(stub, args) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting CarNumber ex: CAR01');
}
let carNumber = args[0];
let carAsBytes = await stub.getState(carNumber); //get the car from chaincode state
if (!carAsBytes || carAsBytes.toString().length <= 0) {
throw new Error(carNumber + ' does not exist: ');
}
console.log(carAsBytes.toString());
return carAsBytes;
}
async initLedger(stub, args) {
console.info('============= START : Initialize Ledger ===========');
let cars = [];
cars.push({
make: 'Toyota',
model: 'Prius',
color: 'blue',
owner: 'Tomoko'
});
cars.push({
make: 'Ford',
model: 'Mustang',
color: 'red',
owner: 'Brad'
});
cars.push({
make: 'Hyundai',
model: 'Tucson',
color: 'green',
owner: 'Jin Soo'
});
cars.push({
make: 'Volkswagen',
model: 'Passat',
color: 'yellow',
owner: 'Max'
});
cars.push({
make: 'Tesla',
model: 'S',
color: 'black',
owner: 'Adriana'
});
cars.push({
make: 'Peugeot',
model: '205',
color: 'purple',
owner: 'Michel'
});
cars.push({
make: 'Chery',
model: 'S22L',
color: 'white',
owner: 'Aarav'
});
cars.push({
make: 'Fiat',
model: 'Punto',
color: 'violet',
owner: 'Pari'
});
cars.push({
make: 'Tata',
model: 'Nano',
color: 'indigo',
owner: 'Valeria'
});
cars.push({
make: 'Holden',
model: 'Barina',
color: 'brown',
owner: 'Shotaro'
});
for (let i = 0; i < cars.length; i++) {
cars[i].docType = 'car';
await stub.putState('CAR' + i, Buffer.from(JSON.stringify(cars[i])));
console.info('Added <--> ', cars[i]);
}
console.info('============= END : Initialize Ledger ===========');
}
async createCar(stub, args) {
console.info('============= START : Create Car ===========');
if (args.length != 5) {
throw new Error('Incorrect number of arguments. Expecting 5');
}
var car = {
docType: 'car',
make: args[1],
model: args[2],
color: args[3],
owner: args[4]
};
await stub.putState(args[0], Buffer.from(JSON.stringify(car)));
console.info('============= END : Create Car ===========');
}
async queryAllCars(stub, args) {
let startKey = 'CAR0';
let endKey = 'CAR999';
let iterator = await stub.getStateByRange(startKey, endKey);
let allResults = [];
while (true) {
let res = await iterator.next();
if (res.value && res.value.value.toString()) {
let jsonRes = {};
console.log(res.value.value.toString('utf8'));
jsonRes.Key = res.value.key;
try {
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Record = res.value.value.toString('utf8');
}
allResults.push(jsonRes);
}
if (res.done) {
console.log('end of data');
await iterator.close();
console.info(allResults);
return Buffer.from(JSON.stringify(allResults));
}
}
}
async changeCarowner(stub, args) {
console.info('============= START : changeCarowner ===========');
if (args.length != 2) {
throw new Error('Incorrect number of arguments. Expecting 2');
}
let carAsBytes = await stub.getState(args[0]);
let car = JSON.parse(carAsBytes);
car.owner = args[1];
await stub.putState(args[0], Buffer.from(JSON.stringify(car)));
console.info('============= END : changeCarowner ===========');
}
};
shim.start(new Chaincode());

View file

@ -0,0 +1,15 @@
{
"name": "fabcar",
"version": "1.0.0",
"description": "fabcar chaincode implemented in node.js",
"engines": {
"node": ">=8.4.0",
"npm": ">=5.3.0"
},
"scripts": { "start" : "node fabcar.js" },
"engine-strict": true,
"license": "Apache-2.0",
"dependencies": {
"fabric-shim": "unstable"
}
}

View file

@ -0,0 +1,409 @@
/*
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
*/
// ====CHAINCODE EXECUTION SAMPLES (CLI) ==================
// ==== Invoke marbles ====
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble1","blue","35","tom"]}'
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble2","red","50","tom"]}'
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble3","blue","70","tom"]}'
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["transferMarble","marble2","jerry"]}'
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["transferMarblesBasedOnColor","blue","jerry"]}'
// peer chaincode invoke -C myc1 -n marbles -c '{"Args":["delete","marble1"]}'
// ==== Query marbles ====
// peer chaincode query -C myc1 -n marbles -c '{"Args":["readMarble","marble1"]}'
// peer chaincode query -C myc1 -n marbles -c '{"Args":["getMarblesByRange","marble1","marble3"]}'
// peer chaincode query -C myc1 -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}'
// Rich Query (Only supported if CouchDB is used as state database):
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarblesByOwner","tom"]}'
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"owner\":\"tom\"}}"]}'
'use strict';
const shim = require('fabric-shim');
const util = require('util');
let Chaincode = class {
async Init(stub) {
let ret = stub.getFunctionAndParameters();
console.info(ret);
console.info('=========== Instantiated Marbles Chaincode ===========');
return shim.success();
}
async Invoke(stub) {
console.info('Transaction ID: ' + stub.getTxID());
console.info(util.format('Args: %j', stub.getArgs()));
let ret = stub.getFunctionAndParameters();
console.info(ret);
let method = this[ret.fcn];
if (!method) {
console.log('no function of name:' + ret.fcn + ' found');
throw new Error('Received unknown function ' + ret.fcn + ' invocation');
}
try {
let payload = await method(stub, ret.params, this);
return shim.success(payload);
} catch (err) {
console.log(err);
return shim.error(err);
}
}
// ===============================================
// initMarble - create a new marble
// ===============================================
async initMarble(stub, args, thisClass) {
if (args.length != 4) {
throw new Error('Incorrect number of arguments. Expecting 4');
}
// ==== Input sanitation ====
console.info('--- start init marble ---')
if (args[0].lenth <= 0) {
throw new Error('1st argument must be a non-empty string');
}
if (args[1].lenth <= 0) {
throw new Error('2nd argument must be a non-empty string');
}
if (args[2].lenth <= 0) {
throw new Error('3rd argument must be a non-empty string');
}
if (args[3].lenth <= 0) {
throw new Error('4th argument must be a non-empty string');
}
let marbleName = args[0];
let color = args[1].toLowerCase();
let owner = args[3].toLowerCase();
let size = parseInt(args[2]);
if (typeof size !== 'number') {
throw new Error('3rd argument must be a numeric string');
}
// ==== Check if marble already exists ====
let marbleState = await stub.getState(marbleName);
if (marbleState.toString()) {
throw new Error('This marble already exists: ' + marbleName);
}
// ==== Create marble object and marshal to JSON ====
let marble = {};
marble.docType = 'marble';
marble.name = marbleName;
marble.color = color;
marble.size = size;
marble.owner = owner;
// === Save marble to state ===
await stub.putState(marbleName, Buffer.from(JSON.stringify(marble)));
let indexName = 'color~name'
let colorNameIndexKey = await stub.createCompositeKey(indexName, [marble.color, marble.name]);
console.info(colorNameIndexKey);
// Save index entry to state. Only the key name is needed, no need to store a duplicate copy of the marble.
// Note - passing a 'nil' value will effectively delete the key from state, therefore we pass null character as value
await stub.putState(colorNameIndexKey, Buffer.from('\u0000'));
// ==== Marble saved and indexed. Return success ====
console.info('- end init marble');
}
// ===============================================
// readMarble - read a marble from chaincode state
// ===============================================
async readMarble(stub, args, thisClass) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting name of the marble to query');
}
let name = args[0];
if (!name) {
throw new Error(' marble name must not be empty');
}
let marbleAsbytes = await stub.getState(name); //get the marble from chaincode state
if (!marbleAsbytes.toString()) {
let jsonResp = {};
jsonResp.Error = 'Marble does not exist: ' + name;
throw new Error(JSON.stringify(jsonResp));
}
console.info('=======================================');
console.log(marbleAsbytes.toString());
console.info('=======================================');
return marbleAsbytes;
}
// ==================================================
// delete - remove a marble key/value pair from state
// ==================================================
async delete(stub, args, thisClass) {
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting name of the marble to delete');
}
let marbleName = args[0];
if (!marbleName) {
throw new Error('marble name must not be empty');
}
// to maintain the color~name index, we need to read the marble first and get its color
let valAsbytes = await stub.getState(marbleName); //get the marble from chaincode state
let jsonResp = {};
if (!valAsbytes) {
jsonResp.error = 'marble does not exist: ' + name;
throw new Error(jsonResp);
}
let marbleJSON = {};
try {
marbleJSON = JSON.parse(valAsbytes.toString());
} catch (err) {
jsonResp = {};
jsonResp.error = 'Failed to decode JSON of: ' + marbleName;
throw new Error(jsonResp);
}
await stub.deleteState(marbleName); //remove the marble from chaincode state
// delete the index
let indexName = 'color~name';
let colorNameIndexKey = stub.createCompositeKey(indexName, [marbleJSON.color, marbleJSON.name]);
if (!colorNameIndexKey) {
throw new Error(' Failed to create the createCompositeKey');
}
// Delete index entry to state.
await stub.deleteState(colorNameIndexKey);
}
// ===========================================================
// transfer a marble by setting a new owner name on the marble
// ===========================================================
async transferMarble(stub, args, thisClass) {
// 0 1
// 'name', 'bob'
if (args.length < 2) {
throw new Error('Incorrect number of arguments. Expecting marblename and owner')
}
let marbleName = args[0];
let newOwner = args[1].toLowerCase();
console.info('- start transferMarble ', marbleName, newOwner);
let marbleAsBytes = await stub.getState(marbleName);
if (!marbleAsBytes || !marbleAsBytes.toString()) {
throw new Error('marble does not exist');
}
let marbleToTransfer = {};
try {
marbleToTransfer = JSON.parse(marbleAsBytes.toString()); //unmarshal
} catch (err) {
let jsonResp = {};
jsonResp.error = 'Failed to decode JSON of: ' + marbleName;
throw new Error(jsonResp);
}
console.info(marbleToTransfer);
marbleToTransfer.owner = newOwner; //change the owner
let marbleJSONasBytes = Buffer.from(JSON.stringify(marbleToTransfer));
await stub.putState(marbleName, marbleJSONasBytes); //rewrite the marble
console.info('- end transferMarble (success)');
}
// ===========================================================================================
// getMarblesByRange performs a range query based on the start and end keys provided.
// Read-only function results are not typically submitted to ordering. If the read-only
// results are submitted to ordering, or if the query is used in an update transaction
// and submitted to ordering, then the committing peers will re-execute to guarantee that
// result sets are stable between endorsement time and commit time. The transaction is
// invalidated by the committing peers if the result set has changed between endorsement
// time and commit time.
// Therefore, range queries are a safe option for performing update transactions based on query results.
// ===========================================================================================
async getMarblesByRange(stub, args, thisClass) {
if (args.length < 2) {
throw new Error('Incorrect number of arguments. Expecting 2');
}
let startKey = args[0];
let endKey = args[1];
let resultsIterator = await stub.getStateByRange(startKey, endKey);
let method = thisClass['getAllResults'];
let results = await method(resultsIterator, false);
return Buffer.from(JSON.stringify(results));
}
// ==== Example: GetStateByPartialCompositeKey/RangeQuery =========================================
// transferMarblesBasedOnColor will transfer marbles of a given color to a certain new owner.
// Uses a GetStateByPartialCompositeKey (range query) against color~name 'index'.
// Committing peers will re-execute range queries to guarantee that result sets are stable
// between endorsement time and commit time. The transaction is invalidated by the
// committing peers if the result set has changed between endorsement time and commit time.
// Therefore, range queries are a safe option for performing update transactions based on query results.
// ===========================================================================================
async transferMarblesBasedOnColor(stub, args, thisClass) {
// 0 1
// 'color', 'bob'
if (args.length < 2) {
throw new Error('Incorrect number of arguments. Expecting color and owner');
}
let color = args[0];
let newOwner = args[1].toLowerCase();
console.info('- start transferMarblesBasedOnColor ', color, newOwner);
// Query the color~name index by color
// This will execute a key range query on all keys starting with 'color'
let coloredMarbleResultsIterator = await stub.getStateByPartialCompositeKey('color~name', [color]);
let method = thisClass['transferMarble'];
// Iterate through result set and for each marble found, transfer to newOwner
while (true) {
let responseRange = await coloredMarbleResultsIterator.next();
if (!responseRange || !responseRange.value || !responseRange.value.key) {
return;
}
console.log(responseRange.value.key);
// let value = res.value.value.toString('utf8');
let objectType;
let attributes;
({
objectType,
attributes
} = await stub.splitCompositeKey(responseRange.value.key));
let returnedColor = attributes[0];
let returnedMarbleName = attributes[1];
console.info(util.format('- found a marble from index:%s color:%s name:%s\n', objectType, returnedColor, returnedMarbleName));
// Now call the transfer function for the found marble.
// Re-use the same function that is used to transfer individual marbles
let response = await method(stub, [returnedMarbleName, newOwner]);
}
let responsePayload = util.format('Transferred %s marbles to %s', color, newOwner);
console.info('- end transferMarblesBasedOnColor: ' + responsePayload);
}
// ===== Example: Parameterized rich query =================================================
// queryMarblesByOwner queries for marbles based on a passed in owner.
// This is an example of a parameterized query where the query logic is baked into the chaincode,
// and accepting a single query parameter (owner).
// Only available on state databases that support rich query (e.g. CouchDB)
// =========================================================================================
async queryMarblesByOwner(stub, args, thisClass) {
// 0
// 'bob'
if (args.length < 1) {
throw new Error('Incorrect number of arguments. Expecting owner name.')
}
let owner = args[0].toLowerCase();
let queryString = {};
queryString.selector = {};
queryString.selector.docType = 'marble';
queryString.selector.owner = owner;
let method = thisClass['getQueryResultForQueryString'];
let queryResults = await method(stub, JSON.stringify(queryString), thisClass);
return queryResults; //shim.success(queryResults);
}
// ===== Example: Ad hoc rich query ========================================================
// queryMarbles uses a query string to perform a query for marbles.
// Query string matching state database syntax is passed in and executed as is.
// Supports ad hoc queries that can be defined at runtime by the client.
// If this is not desired, follow the queryMarblesForOwner example for parameterized queries.
// Only available on state databases that support rich query (e.g. CouchDB)
// =========================================================================================
async queryMarbles(stub, args, thisClass) {
// 0
// 'queryString'
if (args.length < 1) {
throw new Error('Incorrect number of arguments. Expecting queryString');
}
let queryString = args[0];
if (!queryString) {
throw new Error('queryString must not be empty');
}
let method = thisClass['getQueryResultForQueryString'];
let queryResults = await method(stub, queryString, thisClass);
return queryResults;
}
async getAllResults(iterator, isHistory) {
let allResults = [];
while (true) {
let res = await iterator.next();
if (res.value && res.value.value.toString()) {
let jsonRes = {};
console.log(res.value.value.toString('utf8'));
if (isHistory && isHistory === true) {
jsonRes.TxId = res.value.tx_id;
jsonRes.Timestamp = res.value.timestamp;
jsonRes.IsDelete = res.value.is_delete.toString();
try {
jsonRes.Value = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Value = res.value.value.toString('utf8');
}
} else {
jsonRes.Key = res.value.key;
try {
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Record = res.value.value.toString('utf8');
}
}
allResults.push(jsonRes);
}
if (res.done) {
console.log('end of data');
await iterator.close();
console.info(allResults);
return allResults;
}
}
}
// =========================================================================================
// getQueryResultForQueryString executes the passed in query string.
// Result set is built and returned as a byte array containing the JSON results.
// =========================================================================================
async getQueryResultForQueryString(stub, queryString, thisClass) {
console.info('- getQueryResultForQueryString queryString:\n' + queryString)
let resultsIterator = await stub.getQueryResult(queryString);
let method = thisClass['getAllResults'];
let results = await method(resultsIterator, false);
return Buffer.from(JSON.stringify(results));
}
async getHistoryForMarble(stub, args, thisClass) {
if (args.length < 1) {
throw new Error('Incorrect number of arguments. Expecting 1')
}
let marbleName = args[0];
console.info('- start getHistoryForMarble: %s\n', marbleName);
let resultsIterator = await stub.getHistoryForKey(marbleName);
let method = thisClass['getAllResults'];
let results = await method(resultsIterator, true);
return Buffer.from(JSON.stringify(results));
}
};
shim.start(new Chaincode());

View file

@ -0,0 +1,15 @@
{
"name": "marbles",
"version": "1.0.0",
"description": "marbles chaincode implemented in node.js",
"engines": {
"node": ">=8.4.0",
"npm": ">=5.3.0"
},
"scripts": { "start" : "node marbles_chaincode.js" },
"engine-strict": true,
"license": "Apache-2.0",
"dependencies": {
"fabric-shim": "unstable"
}
}

View file

@ -7,8 +7,8 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"fabric-ca-client": "^1.0.1",
"fabric-client": "^1.0.1"
"fabric-ca-client": "unstable",
"fabric-client": "unstable"
},
"author": "Anthony O'Dowd",
"license": "Apache-2.0",

View file

@ -9,8 +9,12 @@ set -e
# don't rewrite paths for Windows Git Bash users
export MSYS_NO_PATHCONV=1
starttime=$(date +%s)
LANGUAGE=${1:-"golang"}
CC_SRC_PATH=github.com/fabcar/go
if [ "$LANGUAGE" = "node" -o "$LANGUAGE" = "NODE" ]; then
CC_SRC_PATH=/opt/gopath/src/github.com/fabcar/node
fi
if [ ! -d ~/.hfc-key-store/ ]; then
mkdir ~/.hfc-key-store/
@ -24,8 +28,8 @@ cd ../basic-network
# and prime the ledger with our 10 cars
docker-compose -f ./docker-compose.yml up -d cli
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 fabcar -v 1.0 -p github.com/fabcar
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 fabcar -v 1.0 -c '{"Args":[""]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
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 fabcar -v 1.0 -p "$CC_SRC_PATH" -l "$LANGUAGE"
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 fabcar -l "$LANGUAGE" -v 1.0 -c '{"Args":[""]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
sleep 10
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 fabcar -c '{"function":"initLedger","Args":[""]}'

View file

@ -47,12 +47,14 @@ function printHelp () {
echo " -d <delay> - delay duration in seconds (defaults to 3)"
echo " -f <docker-compose-file> - specify which docker-compose file use (defaults to docker-compose-cli.yaml)"
echo " -s <dbtype> - the database backend to use: goleveldb (default) or couchdb"
echo " -l <language> - the chaincode language: golang (default) or node"
echo
echo "Typically, one would first generate the required certificates and "
echo "genesis block, then bring up the network. e.g.:"
echo
echo " byfn.sh -m generate -c mychannel"
echo " byfn.sh -m up -c mychannel -s couchdb"
echo " byfn.sh -m up -l node"
echo " byfn.sh -m down -c mychannel"
echo
echo "Taking all defaults:"
@ -111,9 +113,9 @@ function networkUp () {
generateChannelArtifacts
fi
if [ "${IF_COUCHDB}" == "couchdb" ]; then
CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=$CLI_TIMEOUT DELAY=$CLI_DELAY docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_COUCH up -d 2>&1
CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=$CLI_TIMEOUT DELAY=$CLI_DELAY LANG=$LANGUAGE docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_COUCH up -d 2>&1
else
CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=$CLI_TIMEOUT DELAY=$CLI_DELAY docker-compose -f $COMPOSE_FILE up -d 2>&1
CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=$CLI_TIMEOUT DELAY=$CLI_DELAY LANG=$LANGUAGE docker-compose -f $COMPOSE_FILE up -d 2>&1
fi
if [ $? -ne 0 ]; then
echo "ERROR !!!! Unable to start network"
@ -312,9 +314,10 @@ CHANNEL_NAME="mychannel"
COMPOSE_FILE=docker-compose-cli.yaml
#
COMPOSE_FILE_COUCH=docker-compose-couch.yaml
# use golang as the default language for chaincode
LANGUAGE=golang
# Parse commandline args
while getopts "h?m:c:t:d:f:s:" opt; do
while getopts "h?m:c:t:d:f:s:l:" opt; do
case "$opt" in
h|\?)
printHelp
@ -332,6 +335,8 @@ while getopts "h?m:c:t:d:f:s:" opt; do
;;
s) IF_COUCHDB=$OPTARG
;;
l) LANGUAGE=$OPTARG
;;
esac
done

View file

@ -67,10 +67,10 @@ services:
- CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME} ${DELAY}; sleep $TIMEOUT'
command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME} ${DELAY} ${LANG}; sleep $TIMEOUT'
volumes:
- /var/run/:/host/var/run/
- ./../chaincode/:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go
- ./../chaincode/:/opt/gopath/src/github.com/
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
@ -82,4 +82,3 @@ services:
- peer1.org2.example.com
networks:
- byfn

View file

@ -11,12 +11,20 @@ echo "Build your first network (BYFN) end-to-end test"
echo
CHANNEL_NAME="$1"
DELAY="$2"
LANGUAGE="$3"
: ${CHANNEL_NAME:="mychannel"}
: ${TIMEOUT:="60"}
: ${LANGUAGE:="golang"}
LANGUAGE=`echo "$LANGUAGE" | tr [:upper:] [:lower:]`
COUNTER=1
MAX_RETRY=5
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
CC_SRC_PATH="github.com/chaincode_example02/go/"
if [ "$LANGUAGE" = "node" ]; then
CC_SRC_PATH="/opt/gopath/src/github.com/chaincode_example02/node/"
fi
echo "Channel name : "$CHANNEL_NAME
# verify the result of the end-to-end test
@ -115,7 +123,7 @@ joinChannel () {
installChaincode () {
PEER=$1
setGlobals $PEER
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 >&log.txt
peer chaincode install -n mycc -v 1.0 -l ${LANGUAGE} -p ${CC_SRC_PATH} >&log.txt
res=$?
cat log.txt
verifyResult $res "Chaincode installation on remote peer PEER$PEER has Failed"
@ -129,9 +137,9 @@ instantiateChaincode () {
# while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),
# lets supply it directly as we know it using the "-o" option
if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" >&log.txt
peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" >&log.txt
else
peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" >&log.txt
peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -l ${LANGUAGE} -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" >&log.txt
fi
res=$?
cat log.txt