diff --git a/docs/tutorials/chaincode-lifecycle.md b/docs/tutorials/chaincode-lifecycle.md index 912e942a55..917aceeaa0 100644 --- a/docs/tutorials/chaincode-lifecycle.md +++ b/docs/tutorials/chaincode-lifecycle.md @@ -24,8 +24,8 @@ The Fabric 2.0 Alpha introduces decentralized governance for chaincode. The new Fabric chaincode lifecycle allows multiple organizations to come to agreement on the parameters of a chaincode, such as the chaincode endorsement policy, before it can be used to interact with the ledger. You will need to enable the -new Fabric chaincode lifecycle on your network by setting the channel -capabilities to `V2_0` to use the steps in this tutorial. +new Fabric chaincode lifecycle on your channel definition by setting the +Applications capabilities to `V2_0: true` to use the steps in this tutorial. Channel members need to complete the following steps before they can start using a chaincode: @@ -166,7 +166,7 @@ const packge_request = { chaincodeType: 'golang', goPath: '/gopath', chaincodePath: '/path/to/code', - metadataPath: '/path/to/metadat' + metadataPath: '/path/to/metadata' } const package = await mychaincode.package(package_request); ``` @@ -292,13 +292,13 @@ const results = await mychannel.sendTransaction(orderer_request); The chaincode is ready to be used after it is defined on a channel. If you did not request the execution of your chaincode's `Init` function, then the chaincode container will start after the first invoke. If you used `setInitRequired(true)` -to request that the `Init` function be executed, then you need to invoke the -`Init` before any other transactions can be executed. +then you need to invoke with `is_init` set to `true` +before any other transactions can be executed. -The following code snippet below requests the execution of the `Init` function. +The following code snippet below requests the initialization of your chaincode. Note that `is_init` needs to be set to `true` as part of the request, and the -`Init` function must be called using `sendTransaction` rather than the -"Invoke" method of your chaincode. +`Init` method will be called rather than the +`Invoke` method of your chaincode. ``` // initialize the chaincode diff --git a/fabric-client/lib/Chaincode.js b/fabric-client/lib/Chaincode.js index a12fcee851..85ee856ce0 100644 --- a/fabric-client/lib/Chaincode.js +++ b/fabric-client/lib/Chaincode.js @@ -339,7 +339,7 @@ const Chaincode = class { /** * Provide the endorsement policy definition for this chaincode. The input is a JSON object. * - * @example Endorsement policy: "Signed by any member from one of the organizations" + * @example Object Endorsement policy: "Signed by any member from one of the organizations" * { * identities: [ * { role: {name: "member", mspId: "org1"}}, @@ -349,7 +349,7 @@ const Chaincode = class { * "1-of": [{"signed-by": 0}, {"signed-by": 1}] * } * } - * @example Endorsement policy: "Signed by admin of the ordererOrg and any member from one of the peer organizations" + * @example Object Endorsement policy: "Signed by admin of the ordererOrg and any member from one of the peer organizations" * { * identities: [ * {role: {name: "member", mspId: "peerOrg1"}}, @@ -363,7 +363,12 @@ const Chaincode = class { * ] * } * } - * @param {string} policy - The JSON representation of an fabric endorsement policy. + * @example String Endorsement policy: "Policy reference of an existing policy in your channel configuration" + * /Channel/Application/Endorsement + * @param {string | object} policy - When the policy is a string it will be + * the canonical path to a policy in the Channel configuration. + * When an object, it will be the fabric-client's JSON representation + * of an fabric endorsement policy. */ setEndorsementPolicyDefinition(policy) { const method = 'setEndorsementPolicyDefinition'; diff --git a/test/scenario/features/chaincode_lifecycle.feature b/test/scenario/features/chaincode_lifecycle.feature index 569f4ca820..6f0e5e3ce1 100644 --- a/test/scenario/features/chaincode_lifecycle.feature +++ b/test/scenario/features/chaincode_lifecycle.feature @@ -23,9 +23,9 @@ Feature: Use the v2.0 chaincode lifecycle process And I can install java chaincode at version v1 named example_cc_java as organization org1 And I can install golang chaincode at version v1 named example_cc_golang as organization org1 - And I can approve node chaincode at version v1 named example_cc_node as organization org1 on channel tokenchannel - And I can approve java chaincode at version v1 named example_cc_java as organization org1 on channel tokenchannel - And I can approve golang chaincode at version v1 named example_cc_golang as organization org1 on channel tokenchannel + And I can approve node chaincode at version v1 named example_cc_node as organization org1 on channel tokenchannel with endorsement policy both_orgs + And I can approve java chaincode at version v1 named example_cc_java as organization org1 on channel tokenchannel with endorsement policy both_orgs + And I can approve golang chaincode at version v1 named example_cc_golang as organization org1 on channel tokenchannel with endorsement policy both_orgs And I can package node chaincode at version v1 named example_cc_node as organization org2 with goPath na located at ../../../../test/fixtures/chaincode/node_cc/example_cc and metadata located at ../../../../test/fixtures/chaincode/metadata And I can package java chaincode at version v1 named example_cc_java as organization org2 with goPath na located at ../../../../test/fixtures/chaincode/java_cc/example_cc and metadata located at ../../../../test/fixtures/chaincode/metadata @@ -35,9 +35,9 @@ Feature: Use the v2.0 chaincode lifecycle process And I can install java chaincode at version v1 named example_cc_java as organization org2 And I can install golang chaincode at version v1 named example_cc_golang as organization org2 - And I can approve node chaincode at version v1 named example_cc_node as organization org2 on channel tokenchannel - And I can approve java chaincode at version v1 named example_cc_java as organization org2 on channel tokenchannel - And I can approve golang chaincode at version v1 named example_cc_golang as organization org2 on channel tokenchannel + And I can approve node chaincode at version v1 named example_cc_node as organization org2 on channel tokenchannel with endorsement policy both_orgs + And I can approve java chaincode at version v1 named example_cc_java as organization org2 on channel tokenchannel with endorsement policy both_orgs + And I can approve golang chaincode at version v1 named example_cc_golang as organization org2 on channel tokenchannel with endorsement policy both_orgs And I can query for chaincode example_cc_node for approval status as organization org1 on channel tokenchannel And I can query for chaincode example_cc_java for approval status as organization org1 on channel tokenchannel diff --git a/test/scenario/features/lib/utils.js b/test/scenario/features/lib/utils.js index ae62ae6e6f..7cb62be805 100644 --- a/test/scenario/features/lib/utils.js +++ b/test/scenario/features/lib/utils.js @@ -413,7 +413,7 @@ async function commitProposal(tx_id, proposalResponses, proposal, channel, peer) logError('Timeout - Failed to receive the event: waiting on ' + channel_event_hub.getPeerAddr()); channel_event_hub.disconnect(); reject('TIMEOUT waiting on ' + channel_event_hub.getPeerAddr()); - }, 15000); + }, 120000); channel_event_hub.registerTxEvent(deployId.toString(), (tx, code) => { logMsg('The chaincode transaction has been committed on peer ' + channel_event_hub.getPeerAddr()); @@ -437,7 +437,13 @@ async function commitProposal(tx_id, proposalResponses, proposal, channel, peer) logMsg('register eventhub tx=' + deployId); promises.push(txPromise); - const results = await Promise.all(promises); + let results = null; + try { + results = await Promise.all(promises); + } catch (error) { + logMsg('Transaction failed ::' + error); + throw error; + } // orderer results are first as it was the first promise if (results && results[0]) { diff --git a/test/scenario/features/steps/chaincode_steps.js b/test/scenario/features/steps/chaincode_steps.js index 1035dc73d5..abe277308a 100644 --- a/test/scenario/features/steps/chaincode_steps.js +++ b/test/scenario/features/steps/chaincode_steps.js @@ -31,18 +31,6 @@ module.exports = function () { const chaincode = client.newChaincode(chaincode_name, chaincode_version); // chaincode.setInitRequired(true); - const ENDORSEMENT_POLICY = { - identities: [ - {role: {name: 'member', mspId: 'Org1MSP'}}, - {role: {name: 'member', mspId: 'Org2MSP'}} - ], - policy: { - '1-of': [{'signed-by': 0}, {'signed-by': 1}] - } - }; - - chaincode.setEndorsementPolicyDefinition(ENDORSEMENT_POLICY); - const request = { chaincodePath: chaincode_path, metadataPath: metadata_path, @@ -81,11 +69,11 @@ module.exports = function () { } }); - this.Then(/^I can approve (.+?) chaincode at version (.+?) named (.+?) as organization (.+?) on channel (.+?)$/, - {timeout: testUtil.TIMEOUTS.SHORT_STEP}, - async (chaincode_type, chaincode_version, chaincode_name, org_name, channel_name) => { + this.Then(/^I can approve (.+?) chaincode at version (.+?) named (.+?) as organization (.+?) on channel (.+?) with endorsement policy (.+?)$/, + {timeout: testUtil.TIMEOUTS.LONG_STEP}, + async (chaincode_type, chaincode_version, chaincode_name, org_name, channel_name, endorsement_policy) => { const step = 'Chaincode approval'; - testUtil.logMsg(format('%s - starting for %s, %s, %s, %s, %s', step, chaincode_type, chaincode_version, chaincode_name, org_name, channel_name)); + testUtil.logMsg(format('%s - starting for %s, %s, %s, %s, %s, %s', step, chaincode_type, chaincode_version, chaincode_name, org_name, channel_name, endorsement_policy)); const cc_save_name = format('chaincode-%s-%s', org_name, chaincode_name); @@ -95,6 +83,31 @@ module.exports = function () { const chaincode = Client.getConfigSetting(cc_save_name).value; const channel = Client.getConfigSetting('channel-' + org_name + '-' + channel_name).value; + + const ENDORSEMENT_POLICY = { + identities: [ + {role: {name: 'member', mspId: 'Org1MSP'}}, + {role: {name: 'member', mspId: 'Org2MSP'}} + ], + policy: { + '1-of': [{'signed-by': 0}, {'signed-by': 1}] + } + }; + + switch (endorsement_policy) { + case 'default': + // leave it blank and let fabric decide + break; + case 'both_orgs': + chaincode.setEndorsementPolicyDefinition(ENDORSEMENT_POLICY); + break; + default: + chaincode.setEndorsementPolicyDefinition(endorsement_policy); + } + + // replace the saved one with the one updated with endorsement policy + Client.setConfigSetting(cc_save_name, {value: chaincode}); + const txId = client.newTransactionID(true); const request = {