diff --git a/fabric-client/lib/BlockDecoder.js b/fabric-client/lib/BlockDecoder.js
index 149a5f3e7e..f96a669290 100644
--- a/fabric-client/lib/BlockDecoder.js
+++ b/fabric-client/lib/BlockDecoder.js
@@ -67,7 +67,7 @@ data
signature -- {byte[]}
payload
header -- {{@link Header}}
- data -- {{@link Config} | {@link Transaction}}
+ data -- {{@link ConfigEnvelope} | {@link Transaction}}
metadata
metadata -- {array} #each array item has it's own layout
[0] #SIGNATURES
@@ -83,15 +83,15 @@ metadata
* @typedef {Object} Block
*
* @example
- * Get the block number:
+ *
Get the block number:
* var block_num = block.header.number;
*
* @example
- * Get the number of transactions, including the invalid transactions:
+ * Get the number of transactions, including the invalid transactions:
* var block_num = block.data.data.legnth;
*
* @example
- * Get the Id of the first transaction in the block:
+ * Get the Id of the first transaction in the block:
* var tx_id = block.data.data[0].payload.header.channel_header.tx_id;
*/
@@ -143,9 +143,12 @@ nonce -- {byte[]}
*/
/**
- * An object that contains channel configurations.
+ * A ConfigEnvelope contains the channel configurations data and is the
+ * main content of a configuration block. Another type of blocks are those
+ * that contain endorser transactions, where the main content is an array
+ * of {@link Transaction}.
*
- * A "Config" will have the following object structure.
+ * A "ConfigEnvelope" will have the following object structure.
config
sequence -- {int}
@@ -154,9 +157,9 @@ last_update
signature -- {byte[]}
payload
header -- {{@link Header}}
- data -- {{@link ConfigUpdate}}
+ data -- {{@link ConfigUpdateEnvelope}}
- * @typedef {Object} Config
+ * @typedef {Object} ConfigEnvelope
*/
/**
@@ -211,32 +214,28 @@ actions {array}
status -- {int}
message -- {string}
payload -- {byte[]}
- endorsements -- {array}
- endorser
- Mspid -- {string]
- IdBytes -- {byte[]}
- signature -- {byte[]}
+ endorsements -- {{@link Endorsement}[]}
* @typedef {Object} Transaction
*/
/**
- * An object of a protobuf message "ConfigUpdate".
+ * An object of a protobuf message "ConfigUpdateEnvelope".
*
- * A "ConfigUpdate" will have the following object structure.
+ * A "ConfigUpdateEnvelope" will have the following object structure.
config_update
channel_id -- {string}
- read_set -- {{@link ChannelConfig}}
- write_set -- {{@link ChannelConfig}}
+ read_set -- {{@link ChannelConfigGroup}}
+ write_set -- {{@link ChannelConfigGroup}}
signatures -- {array}
signature_header -- {{@link SignatureHeader}}
signature -- {byte[]}
- * @typedef {Object} ConfigUpdate
- * @property {ChannelConfig} config_update.read_set A set of the current version numbers of all
+ * @typedef {Object} ConfigUpdateEnvelope
+ * @property {ChannelConfigGroup} config_update.read_set A set of the current version numbers of all
* configuration items being updated
- * @property {ChannelConfig} config_update.write_set A set of all configuration items being updated. Must have a
+ * @property {ChannelConfigGroup} config_update.write_set A set of all configuration items being updated. Must have a
* version number one greater than the version number of the same item
* in the read_set along with the new value.
*/
@@ -257,7 +256,7 @@ groups
Orderer
version -- {int}
groups
- <orderer_org_name> -- {{@link OrganizationConfig}}
+ <orderer_org_name> -- {{@link OrganizationConfigGroup}}
values
ConsensusType
version -- {int}
@@ -301,7 +300,7 @@ groups
Application
version -- {int}
groups
- <peer_org_name> -- {{@link OrganizationConfig}}
+ <peer_org_name> -- {{@link OrganizationConfigGroup}}
values
policies
Admins
@@ -339,10 +338,13 @@ values
value
name -- {string}
- * @typedef {Object} ChannelConfig
- * @property {OrganizationConfig} groups.Orderer.groups.<orderer_org_name> These are the orderer organizatoin names defined on the network
- * @property {OrganizationConfig} groups.Application.groups.<peer_org_name> These are the peer organization names defined on the network
- * @property {ImplicitMetaPolicy} policy These policies point to other policies and specify a threshold as in "ANY", "MAJORITY" or "ALL"
+ * @typedef {Object} ChannelConfigGroup
+ * @property {OrganizationConfigGroup} groups.Orderer.groups.<orderer_org_name> These are the
+ * orderer organizatoin names defined on the network
+ * @property {OrganizationConfigGroup} groups.Application.groups.<peer_org_name> These are the
+ * peer organization names defined on the network
+ * @property {ImplicitMetaPolicy} policy These policies point to other policies and specify a
+ * threshold as in "ANY", "MAJORITY" or "ALL"
*/
/**
@@ -384,7 +386,26 @@ policies
mod_policy -- {string}
policy -- {{@link SignaturePolicy}}
- * @typedef {Object} OrganizationConfig
+ * @typedef {Object} OrganizationConfigGroup
+ */
+
+
+ /**
+ * An endorsement is a signature of an endorser over a proposal response. By
+ * producing an endorsement message, an endorser implicitly "approves" that
+ * proposal response and the actions contained therein. When enough
+ * endorsements have been collected, a transaction can be generated out of a
+ * set of proposal responses
+ *
+ * An endorsement message has the following structure:
+
+endorser
+ Mspid -- {string]
+ IdBytes -- {byte[]}
+signature -- {byte[]}
+
+ *
+ * @typedef {Object} Endorsement
*/
/**
@@ -489,13 +510,27 @@ policy
return block;
};
+ /**
+ * @typedef {Object} ProcessedTransaction
+ * @property {number} validationCode - See [this list]{@link https://github.com/hyperledger/fabric/blob/v1.0.0-beta/protos/peer/transaction.proto#L125}
+ * for all the defined validation codes
+ * @property {Object} transactionEnvelope - Encapsulates the transaction and the signature over it.
+ * It has the following structure:
+
+signature -- {byte[]}
+payload -- {}
+ header -- {{@link Header}}
+ data -- {{@link Transaction}}
+
+ */
+
/**
* Constructs an object containing all decoded values from the
- * protobuf encoded `ProcessedTransaction` bytes
+ * protobuf encoded "ProcessedTransaction" bytes
*
* @param {byte[]} processed_transaction_bytes - The encode bytes of a protobuf
- * message ProcessedTransaction
- * @returns {Object} An object of the fully decoded transaction.ProcessedTransaction
+ * message "ProcessedTransaction"
+ * @returns {ProcessedTransaction} A fully decoded ProcessedTransaction object
*/
static decodeTransaction(processed_transaction_bytes) {
if (!(processed_transaction_bytes instanceof Buffer)) {
diff --git a/fabric-client/lib/Channel.js b/fabric-client/lib/Channel.js
index 4a29a49fc6..94d6a939b2 100755
--- a/fabric-client/lib/Channel.js
+++ b/fabric-client/lib/Channel.js
@@ -56,24 +56,37 @@ const ImplicitMetaPolicy_Rule = {0: 'ANY', 1:'ALL', 2:'MAJORITY'};
var Long = require('long');
/**
- * The class representing a channel with which the client SDK interacts.
- *
- * The “Channel” object captures settings for a channel, which is created by
- * the orderers to isolate transactions delivery to peers participating on channel.
- * A channel must be initialized after it has been configured with the list of peers
- * and orderers. The initialization sends a get configuration block request to the
- * primary orderer to retrieve the configuration settings for this channel.
+ * In fabric v1.0, channels are the recommended way to isolate data and maintain privacy.
+ *
+ * A Channel object captures the settings needed to interact with a fabric backend in the
+ * context of a channel. These settings including the list of participating organizations,
+ * represented by instances of Membership Service Providers (MSP), the list of endorsing peers,
+ * and an orderer.
+ *
+ * A client application can use the Channel object to create new channels with the orderer,
+ * update an existing channel, send various channel-aware requests to the peers such as
+ * invoking chaincodes to process transactions or queries.
+ *
+ * A Channel object is also responsible for verifying endorsement signatures in transaction
+ * proposal responses. A channel object must be initialized after it has been configured with
+ * the list of peers and orderers. The initialization sends a get configuration block request
+ * to the primary orderer to retrieve the configuration settings for this channel.
*
* @class
- * @tutorial app-overview
*/
var Channel = class {
/**
- * @param {string} name to identify different channel instances. The naming of channel instances
- * is enforced by the ordering service and must be unique within the blockchain network
- * @param {Client} clientContext An instance of {@link Client} that provides operational context
- * such as submitting User etc.
+ * Returns a new instance of the class. This is a client-side-only call. To create a new channel
+ * in the fabric, call [createChannel()]{@link Client#createChannel}.
+ *
+ * @param {string} name - Name to identify the channel. This value is used as the identifier
+ * of the channel when making channel-aware requests with the fabric,
+ * such as invoking chaincodes to endorse transactions. The naming of
+ * channels is enforced by the ordering service and must be unique within
+ * the fabric backend
+ * @param {Client} clientContext - The client instance, which provides operational context
+ * such as the signing identity
*/
constructor(name, clientContext) {
// name is required
@@ -106,11 +119,19 @@ var Channel = class {
}
/**
- * Retrieve the configuration from the primary orderer and initializes this channel
- * with those values. Optionally a configuration may be passed in to initialize this channel
- * without making the call to the orderer.
- * @param {byte[]} config_update- Optional - A serialized form of the protobuf configuration update
- * @return a Promise that will resolve when the action is complete
+ * Initializes the channel object with the Membership Service Providers (MSPs). The channel's
+ * MSPs are critical in providing applications the ability to validate certificates and verify
+ * signatures in messages received from the fabric backend. For instance, after calling
+ * [sendTransactionProposal()]{@link Channel#sendTransactionProposal}, the application can
+ * verify the signatures in the proposal response's endorsements to ensure they have not been
+ * tampered with.
+ *
+ * This method retrieves the configuration from the orderer if no "config" parameter is passed in.
+ * Optionally a configuration may be passed in to initialize this channel without making the call
+ * to the orderer.
+ *
+ * @param {byte[]} config - Optional. An encoded (a.k.a un-decoded) byte array of the protobuf "ConfigUpdate"
+ * @return {Promise} A Promise that will resolve when the action is complete
*/
initialize(config_update) {
if(config_update) {
@@ -145,8 +166,8 @@ var Channel = class {
/**
* Get organization identifiers from the MSP's for this channel
- * @returns {string[]} array of MSP identifiers representing the channel's
- * participating organizations
+ * @returns {string[]} Array of MSP identifiers representing the channel's
+ * participating organizations
*/
getOrganizations() {
logger.debug('getOrganizationUnits - start');
@@ -166,12 +187,12 @@ var Channel = class {
}
/**
- * Set the MSP Manager for this channel
- * This utility method will not normally be use as the
- * `initialize()` method will read this channel's
- * current configuration and reset MSPManager with
- * the MSP's found.
- * @param {MSPManager} the msp manager for this channel
+ * Set the MSP Manager for this channel. This utility method will
+ * not normally be use as the [initialize()]{@link Channel#initialize}
+ * method will read this channel's current configuration and reset
+ * MSPManager with the MSP's found in the channel configuration.
+ *
+ * @param {MSPManager} msp_manager - The msp manager for this channel
*/
setMSPManager(msp_manager) {
this._msp_manager = msp_manager;
@@ -186,10 +207,14 @@ var Channel = class {
}
/**
- * Add peer endpoint to channel.
- * @param {Peer} peer An instance of the Peer class that has been initialized with URL,
- * TLS certificate, and enrollment certificate.
- * @throws {Error} if the peer with that url already exists.
+ * Add the peer object to the channel object. A channel object can be optionally
+ * configured with a list of peer objects, which will be used when calling certain
+ * methods such as [sendInstantiateProposal()]{@link Channel#sendInstantiateProposal},
+ * [sendUpgradeProposal()]{@link Channel#sendUpgradeProposal},
+ * [sendTransactionProposal]{@link Channel#sendTransactionProposal}.
+ *
+ * @param {Peer} peer - An instance of the Peer class that has been initialized with URL
+ * and other gRPC options such as TLS credentials and request timeout.
*/
addPeer(peer) {
var url = peer.getUrl();
@@ -206,8 +231,11 @@ var Channel = class {
}
/**
- * Remove peer endpoint from channel.
- * @param {Peer} peer An instance of the Peer class.
+ * Remove the first peer object in the channel object's list of peers
+ * whose endpoint url property matches the url of the peer that is
+ * passed in.
+ *
+ * @param {Peer} peer - An instance of the Peer class.
*/
removePeer(peer) {
var url = peer.getUrl();
@@ -221,7 +249,7 @@ var Channel = class {
}
/**
- * Get peers of a channel from local information.
+ * Returns the list of peers of this channel object.
* @returns {Peer[]} The peer list on the channel.
*/
getPeers() {
@@ -230,13 +258,12 @@ var Channel = class {
}
/**
- * Add orderer endpoint to a channel object, this is a local-only operation.
- * A channel instance may choose to use a single orderer node, which will broadcast
- * requests to the rest of the orderer network. Or if the application does not trust
- * the orderer nodes, it can choose to use more than one by adding them to the channel instance.
- * All APIs concerning the orderer will broadcast to all orderers simultaneously.
- * @param {Orderer} orderer An instance of the Orderer class.
- * @throws {Error} if the orderer with that url already exists.
+ * Add the orderer object to the channel object, this is a client-side-only operation.
+ * An application may add more than one orderer object to the channel object, however
+ * the SDK only uses the first one in the list to send broadcast messages to the
+ * orderer backend.
+ *
+ * @param {Orderer} orderer - An instance of the Orderer class.
*/
addOrderer(orderer) {
var url = orderer.getUrl();
@@ -253,8 +280,11 @@ var Channel = class {
}
/**
- * Remove orderer endpoint from a channel object, this is a local-only operation.
- * @param {Orderer} orderer An instance of the Orderer class.
+ * Remove the first orderer object in the channel object's list of orderers
+ * whose endpoint url property matches the url of the orderer that is
+ * passed in.
+ *
+ * @param {Orderer} orderer - An instance of the Orderer class.
*/
removeOrderer(orderer) {
var url = orderer.getUrl();
@@ -268,20 +298,27 @@ var Channel = class {
}
/**
- * Get orderers of a channel.
+ * Returns the orderers of this channel object.
+ * @returns {Orderer[]} The list of orderers in the channel object
*/
getOrderers() {
return this._orderers;
}
/**
- * Will get the genesis block from the defined orderer that may be
- * used in a join request
- * @param {Object} request - An object containing the following fields:
- *
`txId` : required - {@link TransactionID} object with the transaction id and nonce
+ * @typedef {Object} OrdererRequest
+ * @property {TransactionId} txId
+ */
+
+ /**
+ * A channel's first block is called the "genesis block". This block captures the
+ * initial channel configuration. For a peer node to join the channel, it must be
+ * provided the genesis block. The method [joinChannel()]{@link Channel#joinChannel}
+ * calls this method under the covers to automate the acquisition of the genesis block
+ * and sending it to the target peer to join.
*
- * @returns {Promise} A Promise for a protobuf `Block`
- * @see /protos/peer/proposal_response.proto
+ * @param {OrdererRequest} request - A transaction ID object
+ * @returns {Promise} A Promise for an encoded protobuf "Block"
*/
getGenesisBlock(request) {
logger.debug('getGenesisBlock - start');
@@ -354,17 +391,49 @@ var Channel = class {
}
/**
- * Sends a join channel proposal to one or more endorsing peers
- * Will get the genesis block from the defined orderer to be used
- * in the proposal.
- * @param {Object} request - An object containing the following fields:
- *
`targets` : required - An array of `Peer` objects that will join
- * this channel
- *
`block` : the genesis block of the channel
- * see getGenesisBlock() method
- *
`txId` : required - {@link TransactionID} object with the transaction id and nonce
- * @returns {Promise} A Promise for a `ProposalResponse`
- * @see /protos/peer/proposal_response.proto
+ * A protobuf message that gets returned by endorsing peers on proposal requests.
+ * The peer node runs the target chaincode, as designated by the proposal, and
+ * decides on whether to endorse the proposal or not, and sends back the endorsement
+ * result along with the [read and write sets]{@link http://hyperledger-fabric.readthedocs.io/en/latest/arch-deep-dive.html?highlight=readset#the-endorsing-peer-simulates-a-transaction-and-produces-an-endorsement-signature}
+ * inside the proposal response message.
+ *
+ * @typedef {Object} ProposalResponse
+ * @property {number} version
+ * @property {Timestamp} timestamp - Time the proposal was created by the submitter
+ * @property {Response} response
+ * @property {byte[]} payload - The payload of the response. It is the encoded bytes of
+ * the "ProposalResponsePayload" protobuf message
+ * @property {Endorsement} endorsement - The endorsement of the proposal, basically the
+ * endorser's signature over the payload
+ */
+
+ /**
+ * A response message indicating whether the endorsement of the proposal was successful
+ *
+ * @typedef {Object} Response
+ * @property {number} status - Status code. Follows [HTTP status code definitions]{@link https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html}
+ * @property {string} message - A message associated with the response status code
+ * @property {byte[]} payload - A payload that can be used to include metadata with this response
+ */
+
+ /**
+ * @typedef {Object} JoinChannelRequest
+ * @property {Peer[]} targets - Required. An array of Peer objects that will
+ * be asked to join this channel
+ * @property {byte[]} block - The encoded bytes of the channel's genesis block.
+ * See [getGenesisBlock()]{@link Channel#getGenesisBlock} method
+ * @property {TransactionID} txId - Required. TransactionID object with the transaction id and nonce
+ */
+
+ /**
+ * For a peer node to become part of a channel, it must be sent the genesis
+ * block, as explained [here]{@link Channel#getGenesisBlock}. This method
+ * sends a join channel proposal to one or more endorsing peers. It automatically
+ * acquires the channel's genesis block from the channel object's orderer and
+ * includes the block in the proposal request.
+ *
+ * @param {JoinChannelRequest} request
+ * @returns {Promise} A Promise for an array of {@link ProposalResponse} from the target peers
*/
joinChannel(request) {
logger.debug('joinChannel - start');
@@ -438,11 +507,12 @@ var Channel = class {
}
/**
- * Queries for the current config block for this channel.
- * This transaction will be made to the orderer.
+ * Asks the orderer for the current (latest) configuration block for this channel.
+ * This is similar to [getGenesisBlock()]{@link Channel#getGenesisBlock}, except
+ * that instead of getting block number 0 it gets the latest block that contains
+ * the channel configuration, and only returns the decoded {@link ConfigEnvelope}.
+ *
* @returns {ConfigEnvelope} Object containing the configuration items.
- * @see /protos/orderer/ab.proto
- * @see /protos/common/configtx.proto
*/
getChannelConfig() {
logger.debug('getChannelConfig - start for channel %s',this._name);
@@ -661,12 +731,23 @@ var Channel = class {
return config_items;
}
+ /**
+ * @typedef {Object} BlockchainInfo
+ * @property {number} height - How many blocks exist on the channel's ledger
+ * @property {byte[]} currentBlockHash - A block hash is calculated by hashing over the concatenated
+ * ASN.1 encoded bytes of: the block number, previous block hash,
+ * and current block data hash. It's the chain of the block
+ * hashs that guarantees the immutability of the ledger
+ * @property {byte[]} previousBlockHash - The block hash of the previous block.
+ */
+
/**
* Queries for various useful information on the state of the Channel
* (height, known peers).
- * @param {Peer} target Optional. The peer that is the target for this query. If no target
- * is passed, the query will use the first peer that was added to the channel.
- * @returns {Object} With height, currently the only useful info.
+ *
+ * @param {Peer} target - Optional. The peer that is the target for this query. If no target is passed,
+ * the query will use the first peer that was added to the channel object.
+ * @returns {BlockchainInfo} With blockchain height, current block hash and previous block hash.
*/
queryInfo(target) {
logger.debug('queryInfo - start');
@@ -733,12 +814,12 @@ var Channel = class {
}
/**
- * Queries the ledger for Block by block hash.
- * This query will be made to the primary peer.
- * @param {byte[]} block hash of the Block.
- * @param {Peer} target Optional. The peer that is the target for this query. If no target
- * is passed, the query will use the first peer that was added to the channel.
- * @returns {Object} Object containing the block.
+ * Queries the ledger on the target peer for a Block by block hash.
+ *
+ * @param {byte[]} block hash of the Block in question.
+ * @param {Peer} target - Optional. The peer to send the query to. If no target is passed,
+ * the query is sent to the first peer that was added to the channel object.
+ * @returns {Block} The block matching the hash, fully decoded into an object.
*/
queryBlockByHash(blockHash, target) {
logger.debug('queryBlockByHash - start');
@@ -795,12 +876,12 @@ var Channel = class {
}
/**
- * Queries the ledger for Block by block number.
- * This query will be made to the primary peer.
- * @param {number} blockNumber The number which is the ID of the Block.
- * @param {Peer} target Optional. The peer that is the target for this query. If no target
- * is passed, the query will use the first peer that was added to the channel.
- * @returns {Object} Object containing the block.
+ * Queries the ledger on the target peer for Block by block number.
+ *
+ * @param {number} blockNumber - The number of the Block in question.
+ * @param {Peer} target - Optional. The peer to send this query to. If no target is passed,
+ * the query is sent to the first peer that was added to the channel object.
+ * @returns {Block} The block at the blockNumber slot in the ledger, fully decoded into an object.
*/
queryBlock(blockNumber, target) {
logger.debug('queryBlock - start blockNumber %s',blockNumber);
@@ -859,12 +940,12 @@ var Channel = class {
}
/**
- * Queries the ledger for Transaction by number.
- * This query will be made to the primary peer.
- * @param tx_id The id of the transaction
- * @param {Peer} target Optional. The peer that is the target for this query. If no target
- * is passed, the query will use the first peer that was added to the channel.
- * @returns {Object} Transaction information containing the transaction.
+ * Queries the ledger on the target peer for Transaction by id.
+ *
+ * @param {string} tx_id - The id of the transaction
+ * @param {Peer} target - Optional. The peer to send this query to. If no target is passed,
+ * the query is sent to the first peer that was added to the channel object.
+ * @returns {ProcessedTransaction} The fully decoded ProcessedTransaction object.
*/
queryTransaction(tx_id, target) {
logger.debug('queryTransaction - start transactionID %s',tx_id);
@@ -922,10 +1003,11 @@ var Channel = class {
}
/**
- * Queries the instantiated chaincodes on this channel.
- * @param {Peer} target Optional. The peer that is the target for this query. If no target
- * is passed, the query will use the first peer that was added to the channel.
- * @returns {Object} ChaincodeQueryResponse proto
+ * Queries the ledger on the target peer for instantiated chaincodes on this channel.
+ *
+ * @param {Peer} target - Optional. The peer to send this query to. If no target is passed,
+ * the query is sent to the first peer that was added to the channel object.
+ * @returns {ChaincodeQueryResponse} A fully decoded ChaincodeQueryResponse object
*/
queryInstantiatedChaincodes(target) {
logger.debug('queryInstantiatedChaincodes - start');
@@ -981,31 +1063,25 @@ var Channel = class {
}
/**
- * Sends an instantiate proposal to one or more endorsing peers.
- *
- * @param {Object} request - An object containing the following fields:
- *
`targets` : Optional : An array of endorsing {@link Peer} objects as the
- * targets of the request. The list of endorsing peers will be used if
- * this parameter is omitted.
- *
`chaincodeType` : optional -- Type of chaincode ['golang', 'car', 'java']
- * (default 'golang')
- *
`chaincodePath` : required - String of the path to location of
- * the source code of the chaincode
- *
`chaincodeId` : required - String of the name of the chaincode
- *
`chaincodeVersion` : required - String of the version of the chaincode
- *
`txId` : required - {@link TransactionID} object with the transaction id and nonce
- *
`transientMap` : optional - map that can be used by
- * the chaincode but not saved in the ledger, such as cryptographic information
- * for encryption
- *
`fcn` : optional - String of the function to be called on
- * the chaincode once instantiated (default 'init')
- *
`args` : optional - String Array arguments specific to
- * the chaincode being instantiated
- *
`endorsement-policy` : optional - {@link EndorsementPolicy} object for this
- * chaincode. If not specified, a default policy of "a signature by any member
- * from any of the organizations corresponding to the array of member service
- * providers" is used
- * @example "Signed by any member from one of the organizations"
+ * @typedef {Object} ChaincodeInstantiateUpgradeRequest
+ * @property {Peer[]} targets - Optional. An array of endorsing {@link Peer} objects as the targets of the
+ * request. The list of endorsing peers in the channel object will be used
+ * if this parameter is omitted.
+ * @property {string} chaincodeType - Optional. Type of chaincode. One of 'golang', 'car' or 'java'.
+ * Default is 'golang'. Note that 'java' is not supported as of v1.0.
+ * @property {string} chaincodeId - Required. The name of the chaincode
+ * @property {string} chaincodeVersion - Required. Version string of the chaincode, such as 'v1'
+ * @property {TransactionID} txId - Required. Object with the transaction id and nonce
+ * @property {map} transientMap - Optional. map that can be used by the chaincode during
+ * intialization, but not saved in the ledger. Data such as cryptographic information
+ * for encryption can be passed to the chaincode using this technique
+ * @property {string} fcn - Optional. The function name to be returned when calling stub.GetFunctionAndParameters()
+ * in the target chaincode. Default is 'init'
+ * @property {string[]} args - Optional. Array of string arguments to pass to the function identified by the fcn
value
+ * @property {Object} endorsement-policy - Optional. EndorsementPolicy object for this chaincode (see examples below). If not specified,
+ * a default policy of "a signature by any member from any of the organizations
+ * corresponding to the array of member service providers" is used
+ * @example Endorsement policy: "Signed by any member from one of the organizations"
* {
* identities: [
* { role: { name: "member", mspId: "org1" }},
@@ -1015,7 +1091,7 @@ var Channel = class {
* "1-of": [{ "signed-by": 0 }, { "signed-by": 1 }]
* }
* }
- * @example "Signed by admin of the ordererOrg and any member from one of the peer organizations"
+ * @example Endorsement policy: "Signed by admin of the ordererOrg and any member from one of the peer organizations"
* {
* identities: [
* { role: { name: "member", mspId: "peerOrg1" }},
@@ -1029,35 +1105,40 @@ var Channel = class {
* ]
* }
* }
- * @returns {Promise} A Promise for a `ProposalResponse`
- * @see /protos/peer/proposal_response.proto
+ */
+
+ /**
+ * Sends a chaincode instantiate proposal to one or more endorsing peers.
+ *
+ * A chaincode must be instantiated on a channel-by-channel basis before it can
+ * be used. The chaincode must first be installed on the endorsing peers where
+ * this chaincode is expected to run, by calling [client.installChaincode()]{@link Client#installChaincode}.
+ *
+ * Instantiating a chaincode is a full transaction operation, meaning it must be
+ * first endorsed as a proposal, then the endorsements are sent to the orderer
+ * to be processed for ordering and validation. When the transaction finally gets
+ * committed to the channel's ledger on the peers, the chaincode is then considered
+ * activated and the peers are ready to take requests to process transactions.
+ *
+ * @param {ChaincodeInstantiateUpgradeRequest} request
+ * @returns {Promise} A Promise for the {@link ProposalResponseObject}
*/
sendInstantiateProposal(request) {
return this._sendChaincodeProposal(request, 'deploy');
}
/**
- * Sends an upgrade proposal to one or more endorsing peers.
+ * Sends a chaincode upgrade proposal to one or more endorsing peers.
+ *
+ * Upgrading a chaincode involves steps similar to instantiating a chaincode.
+ * The new chaincode must first be installed on the endorsing peers where
+ * this chaincode is expected to run.
+ *
+ * Similar to instantiating a chaincode, upgrading chaincodes is also a full transaction
+ * operation.
*
- * @param {Object} request - An object containing the following fields:
- *
`targets` : An array of endorsing {@link Peer} objects as the
- * targets of the request
- *
`chaincodeType` : optional -- Type of chaincode ['golang', 'car', 'java']
- * (default 'golang')
- *
`chaincodePath` : required - String of the path to location of
- * the source code of the chaincode
- *
`chaincodeId` : required - String of the name of the chaincode
- *
`chaincodeVersion` : required - String of the version of the chaincode
- *
`txId` : required - {@link TransactionID} object with the transaction id and nonce
- *
`transientMap` : optional - map that can be used by
- * the chaincode but not saved in the ledger, such as cryptographic information
- * for encryption
- *
`fcn` : optional - String of the function to be called on
- * the chaincode once instantiated (default 'init')
- *
`args` : optional - String Array arguments specific to
- * the chaincode being instantiated
- * @returns {Promise} A Promise for a `ProposalResponse`
- * @see /protos/peer/proposal_response.proto
+ * @param {ChaincodeInstantiateUpgradeRequest} request
+ * @returns {Promise} A Promise for the {@link ProposalResponseObject}
*/
sendUpgradeProposal(request) {
return this._sendChaincodeProposal(request, 'upgrade');
@@ -1156,19 +1237,31 @@ var Channel = class {
);
}
+ /**
+ * @typedef {Object} ChaincodeInvokeRequest
+ * @property {Peer[]} targets - Optional. The peers that will receive this request,
+ * when not provided the list of peers added to this channel object will be used.
+ * @property {string} chaincodeId - Required. The id of the chaincode to process the transaction proposal
+ * @property {TransactionID} txId - Required. TransactionID object with the transaction id and nonce
+ * @property {map} transientMap - Optional. map that can be used by the chaincode but not
+ * saved in the ledger, such as cryptographic information for encryption
+ * @property {string} fcn - Optional. The function name to be returned when calling stub.GetFunctionAndParameters()
+ * in the target chaincode. Default is 'invoke'
+ * @property {string[]} args - An array of string arguments specific to the chaincode's 'Invoke' method
+ */
+
/**
* Sends a transaction proposal to one or more endorsing peers.
*
- * @param {Object} request
- *
`targets` : optional -- The peers that will receive this request,
- * when not provided the peers assigned to this channel will be used.
- *
`chaincodeId` : The id of the chaincode to perform the transaction proposal
- *
`txId` : required - {@link TransactionID} object with the transaction id and nonce
- *
`transientMap` : optional - map that can be used by
- * the chaincode but not saved in the ledger, such as cryptographic information
- * for encryption
- *
`args` : an array of arguments specific to the chaincode 'invoke'
- * @returns {Promise} A Promise for a `ProposalResponse`
+ * After a chaincode gets [installed]{@link Client#installChaincode} and
+ * [instantiated]{@link Channel#instantiateChaincode}, it's ready to take endorsement
+ * proposals and participating in transaction processing. A chaincode transaction
+ * starts with a proposal that gets sent to the endorsing peers, which executes
+ * the target chaincode and decides whether the proposal should be endorsed (if it
+ * executes successfully) or not (if the chaincode returns an error).
+ *
+ * @param {ChaincodeInvokeRequest} request
+ * @returns {Promise} A Promise for the {@link ProposalResponseObject}
*/
sendTransactionProposal(request) {
logger.debug('sendTransactionProposal - start');
@@ -1214,7 +1307,6 @@ var Channel = class {
}
var args = [];
- // leaving this for now... but this call is always an invoke and we are not telling caller to include 'fcn' any longer
args.push(Buffer.from(request.fcn ? request.fcn : 'invoke', 'utf8'));
logger.debug('sendTransactionProposal - adding function arg:%s', request.fcn ? request.fcn : 'invoke');
@@ -1267,19 +1359,37 @@ var Channel = class {
}
/**
- * Sends the orderer an endorsed proposal.
- * The caller must use the proposal response returned from the endorser along
- * with the original proposal request sent to the endorser.
+ * @typedef {Object} TransactionRequest
+ * @property {array} proposalResponses - An array or a single {@link ProposalResponse} objects
+ * containing the response from the
+ * [endorsement]{@link Channel#sendTransactionProposal} call
+ * @Property {Object} chaincodeProposal - A Proposal object containing the original
+ * request for endorsement(s)
+ */
+
+ /**
+ * Send the proposal responses that contain the endorsements of a transaction proposal
+ * to the orderer for further processing. This is the 2nd phase of the transaction
+ * lifecycle in the fabric. The orderer will globally order the transactions in the
+ * context of this channel and deliver the resulting blocks to the committing peers for
+ * validation against the chaincode's endorsement policy. When the committering peers
+ * successfully validate the transactions, it will mark the transaction as valid inside
+ * the block. After all transactions in a block have been validated, and marked either as
+ * valid or invalid (with a [reason code]{@link https://github.com/hyperledger/fabric/blob/v1.0.0-beta/protos/peer/transaction.proto#L125}),
+ * the block will be appended (committed) to the channel's ledger on the peer.
+ *
+ * The caller of this method must use the proposal responses returned from the endorser along
+ * with the original proposal that was sent to the endorser. Both of these objects are contained
+ * in the {@link ProposalResponseObject} returned by calls to any of the following methods:
+ * [installChaincode()]{@link Client#installChaincode}
+ * [sendInstantiateProposal()]{@link Channel#sendInstantiateProposal}
+ * [sendUpgradeProposal()]{@link Channel#sendUpgradeProposal}
+ * [sendTransactionProposal()]{@link Channel#sendTransactionProposal}
*
- * @param {Array} proposalResponses - An array or single {ProposalResponse} objects containing
- * the response from the endorsement
- * @see /protos/peer/proposal_response.proto
- * @param {Proposal} chaincodeProposal - A Proposal object containing the original
- * request for endorsement(s)
- * @see /protos/peer/proposal.proto
- * @returns {Promise} A Promise for a `BroadcastResponse`.
- * This will be an acknowledgement from the orderer of successfully submitted transaction.
- * @see /protos/orderer/ab.proto
+ * @param {TransactionRequest} request
+ * @returns {Promise} A Promise for a "BroadcastResponse" message returned by the orderer that contains a
+ * single "status" field for a standard [HTTP response code]{@link https://github.com/hyperledger/fabric/blob/v1.0.0-beta/protos/common/common.proto#L27}.
+ * This will be an acknowledgement from the orderer of successfully submitted transaction.
*/
sendTransaction(request) {
logger.debug('sendTransaction - start :: channel %s',this);
@@ -1293,9 +1403,6 @@ var Channel = class {
if (!request.proposal) {
errorMsg = 'Missing "proposal" parameter in transaction request';
}
- if (!request.header) {
- errorMsg = 'Missing "header" parameter in transaction request';
- }
} else {
errorMsg = 'Missing input request object on the proposal request';
}
@@ -1381,20 +1488,25 @@ var Channel = class {
/**
* Sends a proposal to one or more endorsing peers that will be handled by the chaincode.
- * This request will be presented to the chaincode 'invoke' and must understand
- * from the arguments that this is a query request. The chaincode must also return
+ * In fabric v1.0, there is no difference in how the endorsing peers process a request
+ * to invoke a chaincode for transaction vs. to invoke a chaincode for query. All requests
+ * will be presented to the target chaincode's 'Invoke' method which must be implemented to
+ * understand from the arguments that this is a query request. The chaincode must also return
* results in the byte array format and the caller will have to be able to decode
- * these results
+ * these results.
*
- * @param {Object} request A JSON object with the following
- *
targets : An array or single Endorsing {@link Peer} objects as the targets of the request
- *
chaincodeId : The id of the chaincode to perform the query
- *
`args` : an array of arguments specific to the chaincode 'innvoke'
- * that represent a query invocation on that chaincode
- *
`transientMap` : optional - map that can be used by
- * the chaincode but not saved in the ledger, such as cryptographic information
- * for encryption
- * @returns {Promise} A Promise for an array of byte array results from the chaincode on all Endorsing Peers
+ * @param {ChaincodeInvokeRequest} request - Query requests use the same request objects as for
+ * transaction invocation requests
+ * @returns {Promise} A Promise for an array of byte array results returned from the chaincode
+ * on all Endorsing Peers
+ * @example
+ * Get the list of query results returned by the chaincode
+ * channel.queryByChaincode(request)
+ * .then((response_payloads) => {
+ * for(let i = 0; i < response_payloads.length; i++) {
+ * console.log(util.format('Query result from peer [%s]: %s', i, response_payloads[i].toString('utf8')));
+ * }
+ * });
*/
queryByChaincode(request) {
logger.debug('queryByChaincodel - start');
@@ -1448,21 +1560,22 @@ var Channel = class {
}
/**
- * Utility method to verify a single proposal response.
- * Requires that the initialize method of this channel has been
- * executed to load this channel's MSPs. The MSPs will have the
+ * Utility method to verify a single proposal response. It checks the
+ * following aspects:
+ * The endorser's identity belongs to a legitimate MSP of the channel
+ * and can be successfully deserialized
+ * The endorsement signature can be successfully verified with the
+ * endorser's identity certificate
+ *
+ * This method requires that the initialize method of this channel object
+ * has been called to load this channel's MSPs. The MSPs will have the
* trusted root certificates for this channel.
- * The verifications performed are
- * - validate that the proposal endorsement's signer is trusted
- * - verify that the endorsement signature matches the signer's
- * claimed identity
*
- * @param {ProposalResponse} The endorsement response from the peer,
- * includes the endorser certificate and signature over the
- * proposal, endorsement result and endorser certificate.
- * @see /protos/peer/proposal_reponse.proto
- * @returns {boolean} a boolean value of true when both the identity and
- * the signature are valid, false otherwise.
+ * @param {ProposalResponse} proposal_response - The endorsement response from the peer,
+ * includes the endorser certificate and signature over the
+ * proposal + endorsement result + endorser certificate.
+ * @returns {boolean} A boolean value of true when both the identity and
+ * the signature are valid, false otherwise.
*/
verifyProposalResponse(proposal_response) {
logger.debug('verifyProposalResponse - start');
@@ -1525,8 +1638,8 @@ var Channel = class {
* the same endorsement result write sets.
* This will validate that the endorsing peers all agree on the result
* of the chaincode execution.
+ *
* @param {ProposalResponse[]} The proposal responses from all endorsing peers
- * @see /protos/peer/proposal_reponse.proto
* @returns {boolean} True when all proposals compare equally, false otherwise.
*/
compareProposalResponseResults(proposal_responses) {
@@ -1562,8 +1675,8 @@ var Channel = class {
}
/**
- * return a printable representation of this object
- */
+ * return a printable representation of this channel object
+ */
toString() {
let orderers = '';
for (let i = 0; i < this._orderers.length; i++) {
diff --git a/fabric-client/lib/Client.js b/fabric-client/lib/Client.js
index 77a083f658..7f3c8f3a30 100644
--- a/fabric-client/lib/Client.js
+++ b/fabric-client/lib/Client.js
@@ -637,13 +637,17 @@ var Client = class extends BaseClient {
* folder 'src/mycompany.com/myproject/mypackage/mychaincode', where the
* GO source code resides.
* @property {string} chaincodeType - Optional. Type of chaincode. One of 'golang', 'car' or 'java'.
- * Default is 'golang'.
+ * Default is 'golang'. Note that 'java' is not supported as of v1.0.
*/
/**
- * @typedef {array} ProposalReponseObject
+ * All calls to the endorsing peers for proposal endorsement return this standard
+ * array of objects.
+ *
+ * @typedef {array} ProposalResponseObject
* @property {array} index:0 - Array of ProposalResponse objects from the endorsing peers
- * @property {Object} index:1 - The original Proposal object
+ * @property {Object} index:1 - The original Proposal object needed when sending the transaction
+ * request to the orderer
*/
/**
diff --git a/test/unit/channel.js b/test/unit/channel.js
index f014939ae7..ae406aa6db 100644
--- a/test/unit/channel.js
+++ b/test/unit/channel.js
@@ -965,21 +965,7 @@ test('\n\n ** Channel sendTransaction() tests **\n\n', function (t) {
}
});
- var p4 = _channel.sendTransaction({
- proposalResponses: 'blah',
- proposal: 'blah'
- })
- .then(function () {
- t.fail('Should not have been able to resolve the promise because of missing parameters');
- }, function (err) {
- if (err.message.indexOf('Missing "header" parameter in transaction request') >= 0) {
- t.pass('Successfully caught missing header error');
- } else {
- t.fail('Failed to catch the missing header error. Error: ' + err.stack ? err.stack : err);
- }
- });
-
- Promise.all([p1, p2, p3, p4])
+ Promise.all([p1, p2, p3])
.then(
function (data) {
t.end();