diff --git a/docs/tutorials/chaincode-lifecycle.md b/docs/tutorials/chaincode-lifecycle.md
new file mode 100644
index 0000000000..670337bfe2
--- /dev/null
+++ b/docs/tutorials/chaincode-lifecycle.md
@@ -0,0 +1,540 @@
+This tutorial illustrates how to handle the lifecycle of your chaincode. The installation, updating, and the starting of chaincode has had been changed with Hyperledger Fabric 2.0 and fabric-client 2.0.
+
+For more information on:
+* getting started with Hyperledger Fabric see
+[Building your first network](http://hyperledger-fabric.readthedocs.io/en/latest/build_network.html).
+* the configuration of a channel in Hyperledger Fabric and the internal
+process of creating and updating see
+[Hyperledger Fabric channel configuration](http://hyperledger-fabric.readthedocs.io/en/latest/configtx.html)
+* [Chaincode Lifecycle](https://hyperledger-fabric.readthedocs.io/en/latest/discovery-overview.html)
+
+The following assumes an understanding of the Hyperledger Fabric network
+(orderers and peers),
+and of Node application development, including the use of the
+Javascript `promise` and `async await`.
+
+### Overview
+This discussion will focus on the steps that are required by an application
+program that will be managing the install, updating and starting of chaincodes
+on your Hyperledger Fabric network. The existing api's for managing the lifecycle
+of your pre 2.0 chaincodes will still be available in fabric-client, however it
+will not be discussed here.
+
+The steps to manage chaincode:
+* `setup` - create the necessary application objects
+* `package` - package the chaincode source artifacts
+* `install` - push to the network
+* `define for organization` - each organization will define a specific chaincode definition
+* `define for the channel` - the channel members will agree to run a specific chaincode definition
+* `initialize` - start the chaincode container and initialize the chaincode
+
+#### New Class
+A new class {@link Chaincode} has been added to the fabric-client to encapsulate
+a chaincode definition.
+A {@link Chaincode} instance will be created by a client instance's
+{@link Client#newChaincode newChaincode()} method.
+Then using the new instance, you will be able to build up a chaincode definition
+with the following methods.
+* {@link Chaincode#setEndorsementPolicy setEndorsementPolicy} - Provide the endorsement policy for this chaincode.
+* {@link Chaincode#setCollectionConfig setCollectionConfig} - Provide the collection configuration for this chaincode.
+* {@link Chaincode#setSequence setSequence} - Provide the modification number for this chaincode.
+* {@link Chaincode#setPackage setPackage} - Provide the package when not packaging this chaincode locally.
+* {@link Chaincode#setHash setHash} - Provide the package hash when not doing an install locally of this chaincode.
+
+The chaincode instance will allow for the packaging and installing of chaincode
+to a peer within your organization with the following methods.
+* {@link Chaincode#package package} Package the files at the locations provided.
+* {@link Chaincode#install install} Install the package on the specified peers.
+
+Once the chaincode definition has all the necessary attributes, it may be used
+by a channel instance to be defined both for an organization and channel wide.
+
+#### New methods on Channel
+The {@link Channel} class has been enhanced to include new methods to define
+a chaincode for an organization and for the channel wide use.
+
+* {@link Channel#defineChaincodeForOrg defineChaincodeForOrg} - Define
+the chaincode for an organization.
+* {@link Channel#defineChaincode defineChaincode} - Define
+the chaincode for a channel.
+
+#### New method on Client
+The {@link Client} class has been enhanced to include new method to create
+a {@link Chaincode} instance.
+
+* {@link Client#newChaincode newChaincode} - Create a {@link Chaincode} instance.
+
+
+### Step 1: Setup
+In this step we will be building
+the application objects needed to perform the operational steps that follow.
+An fabric-client operational environment is required before any of the
+following steps may be performed. A client instance is needed
+that has a user store, crypto suite, and a user assigned. The target peers,
+orderer, and channel instance objects will also be required prior to doing
+the any of the following steps.
+
+The following sample code assumes that all of the normal fabric-client
+setup has been completed and only shows the new chaincode lifecycle
+related calls.
+
+```
+// get the chaincode instance associated with the client
+const mychaincode = client.newChaincode('mychaincode', 'version1');
+
+// The endorsement policy - required.
+const policy_def = {
+ identities: [
+ {role: {name: 'member', mspId: 'org1'}},
+ {role: {name: 'member', mspId: 'org2'}}
+ ],
+ policy: {
+ '1-of': [{'signed-by': 0}, {'signed-by': 1}]
+ }
+};
+mychaincode.setEndorsementPolicy(policy_def);
+
+// The collection configuration - optional.
+const config_def = [{
+ name: 'detailCol',
+ policy: {
+ identities: [
+ {role: {name: 'member', mspId: 'Org1MSP'}},
+ {role: {name: 'member', mspId: 'Org2MSP'}}
+ ],
+ policy: {
+ '1-of': [{'signed-by': 0}, {'signed-by': 1}]
+ }
+ },
+ requiredPeerCount: 1,
+ maxPeerCount: 1,
+ blockToLive: 100
+}];
+mychaincode.setCollectionConfig(config_def));
+
+// set the sequence (modification) number - required.
+mychaincode.setSequence(1); //set to one for a new chaincode
+```
+
+### Step 2: Package
+This step will only be required by a single organization. The organization will
+take the source artifacts, chaincode source code and metadata files, and have
+the fabric-client package them. This package may then be sent to other
+organizations or administrators of your fabric network to be installed on
+the network.
+
+The following example is for the organization that packages the code
+and then will send to other organizations to be installed.
+
+```
+// package the source code
+const packge_request = {
+ chaincodeType: 'golang',
+ goPath: '/gopath',
+ chaincodePath: '/path/to/code',
+ metadataPath: '/path/to/metadat'
+}
+const package = await mychaincode.package(package_request);
+```
+
+The following example is for the organization that has not done the
+packaging, but will do the install.
+
+```
+// use an existing package
+mychaincode.setPackage(package);
+```
+
+### Step 3: Install
+This step will be required by all organizations that will be running the chaincode
+(executing transactions). The install will take the packaged source code artifacts
+and send it to a peer or peers in your organization. Installing chaincode requires
+admin authority for the organization. The peer will return a hash value, a unique
+identifer for this chaincode package. The hash value will be needed later when
+the chaincode is defined. The chaincode object will also store the value for
+the next step.
+
+The following sample assumes that the chaincode object being used has
+been setup and packaged or an error would be thrown.
+
+```
+// install chaincode package on peers
+ const install_request = {
+ targets: [peer1, peer2],
+ request_timeout: 20000 // give the peers some extra time
+ }
+const hash = await mychaincode.install(install_request);
+
+// hash value is stored
+const same_hash = mychaincode.getHash();
+```
+
+For organizations that will not be running the chaincode and are
+still required to approve the chaincode the following example
+shows how they would by pass the install and just assign the
+hash value to the chaincode instance. The hash value must be
+the value that was returned by the peer when the chaincode was installed.
+
+```
+// set hash value instead of doing an install
+mychaincode.setHash(hash);
+```
+
+### Step 4: Define for your organization
+This step wlll define a chaincode for your organization.
+The defining action will be required by enough organizations
+to satisfy the channel's chaincode lifecycle system policy.
+By default this will be a majority of the
+organizations on the channel. Each of these organizations will endorse and
+commit a transaction that defines a chaincode and it's operational settings.
+This may be thought of not only as a definition of the chaincode but a vote
+to authorize the running of the chaincode with these settings.
+These are separate organizational chaincode definitions
+transactions submitted by each organizations and each committed to the
+ledger. This definition is for a specific organization, specific settings,
+and only on this channel.
+The organizational chaincode definition transaction may be submitted at any
+time, but must be submitted prior to being able to execute the chaincode
+on a peer within the organization. This is how a new organization may start
+running an existing chaincode other organization are currently running.
+The transactions must include the exact same chaincode definition.
+The definition does not include the package, it includes the hash value
+that uniquely identifies the chaincode source artifacts.
+An organization will be able to submit the organizational chaincode definition
+transaction without having installed the package, but has received the hash
+value from an organization that did install the package.
+
+The following sample assumes that the chaincode object being used has
+been setup and installed or an error will be thrown.
+```
+// send a define chaincode for organization transaction
+const tx_id = client.newTransactionID();
+const request = {
+ target: peer1,
+ chaincode: mychaincode,
+ txId: tx_id
+}
+// send to the peer to be endorsed
+const {proposalResponses, proposal} = await mychannel.defineChaincodeForOrg(request);
+const orderer_request = {
+ proposalResponses: proposalResponses,
+ proposal, proposal
+}
+// send to the orderer to be committed
+const results = await mychannel.sendTransaction(orderer_request);
+```
+
+### Step 5: Define for the channel
+This step will define a chaincode for your channel. The defining action will
+not change the chaincode or it's settings, but rather confirm the
+organizational chaincode definition for the channel.
+The channel chaincode definition transaction will
+be submitted by only one organization.
+A successful transaction must be endorsed by enough
+organizations to satisfy the channel's chaincode lifecycle system policy
+and there must be enough committed organizational chaincode definition
+transactions committed that also satisfies the
+channel's chaincode lifecycle system policy.
+Think of this step as the tallying of the votes to run the chaincode.
+The action to actually count the votes must be approved by enough members
+and then there must be enough votes before the chaincode will
+be allowed to run.
+When only a chaincode setting has been changed, like an endorsement policy,
+a successful commit of the channel chaincode definition transaction will
+enable the new policy for this chaincode. The initialize step will not be
+required as the chaincode container will not have to change. If this is
+for a new chaincode or an update to the chaincode code, then the initialize
+step will be required.
+
+```
+// send a define chaincode for channel transaction
+const tx_id = client.newTransactionID();
+const request = {
+ targets: [peer1, peer3],
+ chaincode: mychaincode,
+ txId: tx_id
+}
+// send to the peers to be endorsed
+const {proposalResponses, proposal} = await mychannel.defineChaincode(request);
+const orderer_request = {
+ proposalResponses: proposalResponses,
+ proposal, proposal
+}
+// send to the orderer to be committed
+const results = await mychannel.sendTransaction(orderer_request);
+```
+
+### Step 6: Initialize
+This step will start new chaincode on your channel.
+This will be the last step before the chaincode may be used for invokes and
+queries.
+This step will...
+The initialize transaction will start the container and then call the
+`init` method of the chaincode with the provided arguments.
+
+```
+// initialize the chaincode
+const tx_id = client.newTransactionID();
+const request = {
+ chaincodeId : chaincodeId,
+ fcn: 'init',
+ args: args,
+ txId: tx_id
+}
+// starting the container will take longer than the normal request-timeout
+const init_results = await mychannel.sendTransaction(request, 20000);
+const orderer_request = {
+ proposalResponses: init_results[0],
+ proposal: init_results[1]
+}
+// send to the orderer to be committed
+const results = await mychannel.sendTransaction(orderer_request);
+```
+
+
+### Sample situations
+The following samples will show the important snippets needed to perform the
+different situations.
+
+#### New chaincode
+When installing chaincode for the first time, all 6 steps must be run.
+The following sample shows the code needed when the organization
+will be packaging the chaincode, installing it, and being the organization
+to define it for the entire channel and initialize it.
+
+```
+// step 1:
+const mychaincode = client.newChaincode('mychaincode', 'version1');
+const policy_def = { ... };
+mychaincode.setEndorsementPolicy(policy_def);
+mychaincode.setSequence(1); //set to one for a new chaincode
+
+// step 2:
+const packge_request = {
+ chaincodeType: 'golang',
+ goPath: '/gopath',
+ chaincodePath: '/path/to/code',
+ metadataPath: '/path/to/metadat'
+}
+const package = await mychaincode.package(package_request);
+
+// step 3:
+ const install_request = {
+ targets: [peer1, peer2],
+ request_timeout: 20000 // give the peers some extra time
+ }
+const hash = await mychaincode.install(install_request);
+
+// step 4:
+const tx_id = client.newTransactionID();
+const request = {
+ target: peer1,
+ chaincode: mychaincode,
+ txId: tx_id
+}
+const {proposalResponses, proposal} = await mychannel.defineChaincodeForOrg(request);
+const orderer_request = {
+ proposalResponses: proposalResponses,
+ proposal, proposal
+}
+const results = await mychannel.sendTransaction(orderer_request);
+
+//step 5:
+const tx_id = client.newTransactionID();
+const request = {
+ targets: [peer1, peer3],
+ chaincode: mychaincode,
+ txId: tx_id
+}
+const {proposalResponses, proposal} = await mychannel.defineChaincode(request);
+const orderer_request = {
+ proposalResponses: proposalResponses,
+ proposal, proposal
+}
+const results = await mychannel.sendTransaction(orderer_request);
+
+// step 6:
+const tx_id = client.newTransactionID();
+const request = {
+ chaincodeId : chaincodeId,
+ fcn: 'init',
+ args: args,
+ txId: tx_id
+}
+const init_results = await mychannel.sendTransaction(request, 20000);
+const orderer_request = {
+ proposalResponses: init_results[0],
+ proposal: init_results[1]
+}
+const results = await mychannel.sendTransaction(orderer_request);
+```
+
+#### Update the chaincode code
+When updating the chaincode all 6 steps must be performed and care must be
+taken in setting the sequence number to be sure it reflects the current
+modification number of the chaincode definition. In this case no other
+changes have been done to the chaincode definition since it was first
+installed, so the sequence number is 2.
+
+The following sample shows the code needed when the organization
+will be packaging the chaincode, installing it, and being the organization
+to define it for the entire channel and initialize it.
+```
+// step 1:
+const mychaincode = client.newChaincode('mychaincode', 'version2');
+const policy_def = { ... };
+mychaincode.setEndorsementPolicy(policy_def);
+mychaincode.setSequence(2);
+
+// step 2:
+// package the source code
+const packge_request = {
+ chaincodeType: 'golang',
+ goPath: '/gopath',
+ chaincodePath: '/path/to/code',
+ metadataPath: '/path/to/metadat'
+}
+const package = await mychaincode.package(package_request);
+
+// step 3:
+ const install_request = {
+ targets: [peer1, peer2],
+ request_timeout: 20000 // give the peers some extra time
+ }
+const hash = await mychaincode.install(install_request);
+
+// step 4:
+const tx_id = client.newTransactionID();
+const request = {
+ target: peer1,
+ chaincode: mychaincode,
+ txId: tx_id
+}
+const {proposalResponses, proposal} = await mychannel.defineChaincodeForOrg(request);
+const orderer_request = {
+ proposalResponses: proposalResponses,
+ proposal, proposal
+}
+const results = await mychannel.sendTransaction(orderer_request);
+
+//step 5:
+const tx_id = client.newTransactionID();
+const request = {
+ targets: [peer1, peer3],
+ chaincode: mychaincode,
+ txId: tx_id
+}
+// send to the peers to be endorsed
+const {proposalResponses, proposal} = await mychannel.defineChaincode(request);
+const orderer_request = {
+ proposalResponses: proposalResponses,
+ proposal, proposal
+}
+// send to the orderer to be committed
+const results = await mychannel.sendTransaction(orderer_request);
+
+// step 6:
+// initialize the chaincode
+const tx_id = client.newTransactionID();
+const request = {
+ chaincodeId : chaincodeId,
+ fcn: 'init',
+ args: args,
+ txId: tx_id
+}
+// starting the container will take longer than the normal request-timeout
+const init_results = await mychannel.sendTransaction(request, 20000);
+const orderer_request = {
+ proposalResponses: init_results[0],
+ proposal: init_results[1]
+}
+// send to the orderer to be committed
+const results = await mychannel.sendTransaction(orderer_request);
+```
+
+#### Modify the Endorsement policy
+
+When updating the endorsement policy only 4 steps must be performed and care must be
+taken in setting the sequence number to be sure it reflects the current
+modification number of the chaincode definition. In this case let us assume
+that the chaincode has been updated once, so the sequence number is 3.
+step 2 maybe skipped as there will not be a new package. It might
+seem that we can also skip step 3, but we still need the hash value
+to uniquely identify the chaincode source that was installed earlier and has
+not been changed.
+
+The following sample shows the code needed when the organization
+is redefining it and the organization
+to define it for the entire channel.
+```
+// step 1:
+const mychaincode = client.newChaincode('mychaincode', 'version2');
+const new_policy_def = { ... };
+mychaincode.setEndorsementPolicy(new_policy_def);
+mychaincode.setSequence(3);
+
+// step 3:
+mychaincode.setHash(hash);
+
+// step 4:
+const tx_id = client.newTransactionID();
+const request = {
+ target: peer1,
+ chaincode: mychaincode,
+ txId: tx_id
+}
+const {proposalResponses, proposal} = await mychannel.defineChaincodeForOrg(request);
+const orderer_request = {
+ proposalResponses: proposalResponses,
+ proposal, proposal
+}
+const results = await mychannel.sendTransaction(orderer_request);
+
+//step 5:
+const tx_id = client.newTransactionID();
+const request = {
+ targets: [peer1, peer3],
+ chaincode: mychaincode,
+ txId: tx_id
+}
+// send to the peers to be endorsed
+const {proposalResponses, proposal} = await mychannel.defineChaincode(request);
+const orderer_request = {
+ proposalResponses: proposalResponses,
+ proposal, proposal
+}
+// send to the orderer to be committed
+const results = await mychannel.sendTransaction(orderer_request);
+```
+
+#### New organization needs to run the chaincode
+
+When a new organization wishes to run an existing chaincode it will have to
+perform a few of the steps with the existing values.
+```
+// step 1:
+const mychaincode = client.newChaincode('mychaincode', 'version2');
+const policy_def = { ... };
+mychaincode.setEndorsementPolicy(policy_def);
+mychaincode.setSequence(3);
+
+// step 3:
+mychaincode.setHash(hash);
+
+// step 4:
+const tx_id = client.newTransactionID();
+const request = {
+ target: peer1, // this peer is in my org
+ chaincode: mychaincode,
+ txId: tx_id
+}
+const {proposalResponses, proposal} = await mychannel.defineChaincodeForOrg(request);
+const orderer_request = {
+ proposalResponses: proposalResponses,
+ proposal, proposal
+}
+const results = await mychannel.sendTransaction(orderer_request);
+```
+
+
This work is licensed under a Creative Commons Attribution 4.0 International License.
+
diff --git a/docs/tutorials/tutorials.json b/docs/tutorials/tutorials.json
index 455eacdf90..c9e65be3e2 100644
--- a/docs/tutorials/tutorials.json
+++ b/docs/tutorials/tutorials.json
@@ -40,5 +40,8 @@
},
"handlers": {
"title": "fabric-client: How to use the endorsement and commit handlers"
+ },
+ "chaincode-lifecycle": {
+ "title": "fabric-client: How to install and start your chaincode"
}
}
diff --git a/fabric-client/lib/Chaincode.js b/fabric-client/lib/Chaincode.js
new file mode 100644
index 0000000000..71daacffe6
--- /dev/null
+++ b/fabric-client/lib/Chaincode.js
@@ -0,0 +1,576 @@
+/*
+ * 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.
+ */
+
+'use strict';
+const {format} = require('util');
+
+const utils = require('./utils.js');
+const logger = utils.getLogger('Chaincode.js');
+const Policy = require('./Policy.js');
+const CollectionConfig = require('./SideDB.js');
+const fabprotos = require('fabric-protos').protos;
+
+
+
+
+/**
+ * @classdesc
+ * The Chaincode class represents an Chaincode definition in the target
+ * blockchain network.
+ *
+ * see the tutorial {@tutorial chaincode-lifecycle}
+ *
+ * This class allows an application to contain all chaincode attributes and
+ * artifacts in one place during runtime. This will assist the administration
+ * of the chaincode's lifecycle.
+ *
+ * From your {@link Client} instance use the {@link Client#newChaincode} method.
+ * This will return a Chaincode object instance that has been associated with
+ * that client. This will provide access to user credentials used for signing
+ * requests, access to peer, orderer, and channel information.
+ *
+ *
+ * From the new chaincode object you will be able to use it to help you create
+ * a chaincode package. This is a local client operation and does not make an
+ * outbound request. The package may be sent to other organizations to be
+ * installed on their peers.
+ * This package may then be installed on your organization's peers.
+ * The peer will return a hash value representing the package that it
+ * has installed. This unique value will identify your chaincode across
+ * the fabric network and must match all other peers that have installed
+ * the chaincode.
+ *
+ *
+ * Now that we have a hash value we can define a chaincode that our organization
+ * would like to run. The definition will include the hash, the name, the version,
+ * an endorsement policy, the channel and your organization.
+ * The definition must be endorsed by a peer
+ * in your organization and sent to be orderer to be committed to the ledger.
+ * You may want to think of this definition as a vote that your organization
+ * has agreed to run this particular chaincode on this channel.
+ * Once enough organization have also voted by endorsing a chaincode organization
+ * definition and committing that transaction the Chaincode channel definition
+ * may now be processed.
+ *
+ *
+ * When enough organizations have agreed to run this unique chaincode definition,
+ * it may be defined to run on the channel. This is an endorsement sent by a
+ * single client to enough organization's peers to satisfy the chaincode life-cycle
+ * policy.
+ * Once the client gets enough endorsements it will send the transaction to the
+ * orderer to be committed to the ledger.
+ * The chaincode may now be used for endorsements.
+ *
+ *
+ * @example
+ * // create chaincode object
+ * const mychaincode = client.newChaincode('mychaincode', 'version1');
+ *
+ * // package the source code
+ * // - or -
+ * // use an existing package
+ * const packge_request = {
+ * chaincodeType: 'golang',
+ * goPath: '/gopath',
+ * chaincodePath: '/path/to/code',
+ * metadataPath: '/path/to/metadat'
+ * }
+ * await mychaincode.package(package_request);
+ *
+ * // send the package to the other organizations to install
+ * const package = mychaincode.getPackage();
+ * ... < code to send >
+ * // The other organizations will make the package call, they
+ * // will use the setPackage() method to apply an existing chaincode
+ * // package to the chaincode instance object.
+ * mychaincode.setPackage(package);
+ *
+ * // install on my peers
+ * // This step is only required for peers that will execute the
+ * // the chaincode during an endorsement or chaincode query operation.
+ * const install_request = {
+ * targets: [peer1, peer2],
+ * request_timeout: 20000 // give the peers some extra time
+ * }
+ * // The hash value of the package is returned by the peer
+ * // The chaincode instance object will also contain this value.
+ * const hash = await mychaincode.install(install_request);
+ *
+ * // set the endorsement policy and collection config
+ * // The endorsement policy - required.
+ * mychaincode.setEndorsementPolicy(policy_def);
+ * // The collection configuration - optional.
+ * mychaincode.setCollectionConfig(config_def));
+ *
+ * // set the sequence of the definition
+ * mychaincode.setSequence(1);
+ *
+ * // define for my organization
+ * // Each organization will define the chaincode. Think of
+ * // of this step as both defining a chaincode for the organization
+ * // to use and the organization casting a vote for this definition
+ * // the chaincode to be allowed to be executed on the channel.
+ * // Note that an organization that is just voting to allow the chaincode
+ * // on the channel and not planning on actually executing the chaincode
+ * // will only have to an chaincode instance object with
+ * // the name, the version, the hash value, and the sequence number
+ * // attributes set. The package and installing the package will not be
+ * // required.
+ * const tx_id = client.newTransactionID();
+ * const request = {
+ * target: peer1,
+ * chaincode: mychaincode,
+ * txId: tx_id
+ * }
+ * const {proposalResponses, proposal} = await mychannel.defineChaincodeForOrg(request);
+ * const orderer_request = {
+ * proposalResponses: proposalResponses,
+ * proposal, proposal
+ * }
+ * const results = await mychannel.sendTransaction(orderer_request);
+ *
+ *
+ * // define the chaincode for the channel
+ * // One organization will create a transaction that will define this
+ * // chaincode for the channel. The transaction must be endorsed by enough
+ * // organizations on the channel to satisfy the chaincode lifecycle policy.
+ * // This action will not succeed until enough organizations have voted
+ * // (define for organization) for this chaincode definition to run on this
+ * // channel to satisfy the chaincode lifecycle endorsement policy.
+ * const tx_id = client.newTransactionID();
+ * const request = {
+ * targets: [peer1, peer3],
+ * chaincode: mychaincode,
+ * txId: tx_id
+ * }
+ * const {proposalResponses, proposal} = await mychannel.defineChaincode(request);
+ * const orderer_request = {
+ * proposalResponses: proposalResponses,
+ * proposal, proposal
+ * }
+ * const results = await mychannel.sendTransaction(orderer_request);
+ *
+ * // initialize the chaincode
+ * // This action will start the chaincode container and run the 'init' method
+ * // of the chaincode with the provided arguments.
+ * // This action will only be required when the code package is new or
+ * // has changed and a new chaincode container must be initialized.
+ * const tx_id = client.newTransactionID();
+ * const request = {
+ * chaincodeId : chaincodeId,
+ * fcn: 'init',
+ * args: args,
+ * txId: tx_id
+ * }
+ * const init_results = await mychannel.sendTransaction(request);
+ * const orderer_request = {
+ * proposalResponses: init_results[0],
+ * proposal: init_results[1]
+ * }
+ * const results = await mychannel.sendTransaction(orderer_request);
+ *
+ * @class
+ */
+const Chaincode = class {
+
+ /**
+ * Construct a Chaincode object.
+ *
+ * @param {string} name - The name of this chaincode
+ * @param {string} version - The version of this chaincode
+ * @param {Client} client - The Client instance.
+ * @returns {Chaincode} The Chaincode instance.
+ */
+ constructor(name, version, client) {
+ logger.debug('Chaincode.const');
+ if (!name) {
+ throw new Error('Missing name parameter');
+ }
+ if (!version) {
+ throw new Error('Missing version parameter');
+ }
+ if (!client) {
+ throw new Error('Missing client parameter');
+ }
+ this._name = name;
+ this._version = version;
+ this._client = client;
+
+ this._sequence = null;
+ this._package = null;
+ this._hash = null;
+ this._endorsement_policy_proto = null;
+ this._endorsement_policy_json = null;
+ this._collection_config_proto = null;
+ this._collection_config_json = null;
+ }
+
+ /**
+ * Gets the name of this chaincode.
+ *
+ * @returns {string} The name of this chaincode
+ */
+ getName() {
+ return this._name;
+ }
+
+ /**
+ * Gets the version of this chaincode.
+ *
+ * @returns {string} The version of this chaincode
+ */
+ getVersion() {
+ return this._version;
+ }
+
+ /**
+ * Gets the modification sequence of the chaincode definition.
+ *
+ * @returns {number} The sequence of this chaincode
+ */
+ getSequence() {
+ return this._sequence;
+ }
+
+ /**
+ * Sets the modification sequence of the chaincode definition.
+ * The sequence value gives a unique number to a set of attributes for the
+ * the chaincode. When a attribute changes for a chaincode, the sequence
+ * value must be incremented and all organizations must again run
+ * the defineChaincodeForOrg() method to agree to the new definition.
+ * The default is 1, new chaincode.
+ *
+ * @param {number} sequence - sequence of this chaincode
+ */
+ setSequence(sequence) {
+ if (!Number.isInteger(sequence) || sequence < 1) {
+ throw new Error('Sequence value must be an integer greater than zero');
+ }
+ this._sequence = sequence;
+
+ return this;
+ }
+
+ /**
+ * Gets the source code package
+ *
+ * @returns {number} The package of this chaincode
+ */
+ getPackage() {
+
+ return this._package;
+ }
+
+ /**
+ * Sets the chaincode package
+ *
+ * @param {byte[]} package The source package
+ */
+ setPackage(packaged_chaincode) {
+ this._package = packaged_chaincode;
+
+ return this;
+ }
+
+ /**
+ * @typedef {Object} ChaincodeInstallRequest
+ * @property {string} chaincodeType - Required. Type of chaincode. One of
+ * 'golang', 'car', 'node' or 'java'.
+ * @property {string} chaincodePath - Required. The path to the location of
+ * the source code of the chaincode. If the chaincode type is golang,
+ * then this path is the fully qualified package name, such as
+ * 'mycompany.com/myproject/mypackage/mychaincode'
+ * @property {string} metadataPath - Optional. The path to the top-level
+ * directory containing metadata descriptors.
+ * @property {string} goPath - Optional. The path to be used with the golang
+ * chaincode.
+ */
+
+ /**
+ * Package the files at the locations provided.
+ * This method will both return the package and set the
+ * package on this instance.
+ *
+ * @async
+ * @param {ChaincodePackageRequest} request - Required. The parameters to build the
+ * chaincode package.
+ */
+
+
+ async package(request) {
+ const method = 'package';
+ logger.debug('%s - start', method);
+
+ this._package = null;
+ this._hash = null;
+
+ if (!request) {
+ throw new Error('ChaincodeInstallRequest object parameter is required');
+ }
+
+ if (!request.chaincodeType) {
+ throw new Error('Chaincode package "chaincodeType" parameter is required');
+ }
+
+ const _type = Chaincode.translateCCType(request.chaincodeType);
+ if (!_type) {
+ throw new Error(format('Chaincode package "chaincodeType" parameter is not a known type %s', request.chaincodeType));
+ }
+
+
+ return this._package;
+ }
+
+ /**
+ * Method to check if this chaincode instance has a chaincode package assigned.
+ * @returns {boolean} indicates if this chaincode instance has a package
+ */
+ hasPackage() {
+ const method = 'hasPackage';
+ if (this._package) {
+ logger.debug('%s - contains a package', method);
+ return true;
+ } else {
+ logger.debug('%s - does not contains a package', method);
+ return false;
+ }
+ }
+
+ /**
+ * Gets the package hash value
+ *
+ * @returns {string} The hash value as generated by the peer when the
+ * package was installed
+ */
+ getHash() {
+
+ return this._hash;
+ }
+
+ /**
+ * Sets the chaincode package hash
+ *
+ * @param {string} hash The source package hash value
+ */
+ setHash(hash) {
+ this._hash = hash;
+
+ return this;
+ }
+
+ /**
+ * Method to check if this chaincode package hash has been assigned.
+ * The hash value is the unique identifer of this chaincode source package
+ * returned by the peer that installed the chaincode package.
+ * When this chaincode instance has a hash value assigned it will mean
+ * this chaincode has been installed. It also could mean that another
+ * organization did the install and this organization only wants to define
+ * (allow) this chaincode and will not install the package at this time.
+ *
+ * @returns {boolean} indicates if this chaincode instance has the hash value
+ * and this chaincode instance may be used for the chaincode define actions.
+ */
+ hasHash() {
+ const method = 'hasHash';
+ if (this._hash) {
+ logger.debug('%s - contains a package hash', method);
+ return true;
+ } else {
+ logger.debug('%s - does not contains a package hash', method);
+ return false;
+ }
+ }
+
+ // TODO ispackageinstalled
+ // will query the peer to see if this chaincode is installed
+ // should be able to check the hash
+ // TODO isRunning on Channel
+ // will query the peer to see what is running and get info
+ // should be able to verify the hash and sequence
+ // TODO ... is there a way to check the endorsement policy
+
+ /**
+ * @typedef {Object} ChaincodeInstallRequest
+ * @property {Buffer} target Required. The peer to use for this request
+ * @property {number} request_timeout Optional. The amount of time for the
+ * to respond. The default will be the system configuration
+ * value of 'request-timeout'.
+ */
+
+ /**
+ * Install the package on the specified peers.
+ * This method will send the package to the peers provided.
+ * Each peer will return a hash value of the installed
+ * package. When this method is called again and within this call, the hash value
+ * returnd from the peer must be equal to the pervious install.
+ *
+ * @async
+ * @param {ChaincodeInstallRequest} request - The request object with the
+ * install attributes and settings.
+ * @returns {string} The hash value as calculated by the target peer(s).
+ */
+ async install(request) {
+ const method = 'install';
+ logger.debug('%s - start');
+
+ if (!request) {
+ throw new Error('Install operation requires a ChaincodeInstallRequest object parameter');
+ }
+
+ if (!this._package) {
+ throw new Error('Install operation requires a chaincode package be assigned to this chaincode');
+ }
+
+ const peers = request.targets; // TODO validate the targets
+
+ // loop on each peer in the target list
+ for (const peer of peers) {
+ const hash = 'somehash'; // TODO put the install call here to the peer
+ logger.debug('%s - working with peer %s', method, peer);
+
+ // TODO install process here
+
+ if (this._hash) {
+ if (hash === this._hash) {
+ logger.debug('%s - hash values are the same :: %s', method, hash);
+ } else {
+ const msg = utils.format('The install for chaincode: %s version: ' +
+ '%s did not return the same hash value of %s, value was %s',
+ this._name, this._version, this._hash, hash);
+ logger.error(msg);
+ throw new Error(msg);
+ }
+ } else {
+ logger.debug('%s - first install of package returned hash of %s', method, hash);
+ this._hash = hash;
+ }
+ }
+
+ return this._hash;
+ }
+
+ /**
+ * Provide the endorsement policy for this chaincode. The input is a JSON object.
+ *
+ * @example