diff --git a/packages/caliper-cli/lib/lib/config.yaml b/packages/caliper-cli/lib/lib/config.yaml index 495b9fa0b..00e1653f5 100644 --- a/packages/caliper-cli/lib/lib/config.yaml +++ b/packages/caliper-cli/lib/lib/config.yaml @@ -42,6 +42,8 @@ sut: 2.2.11: &fabric-v2-lts packages: ['fabric-network@2.2.11'] 2.2: *fabric-v2-lts + 2.4: + packages: ['@hyperledger/fabric-gateway@1.0.1'] latest: *fabric-v1-lts latest-v2-lts: *fabric-v2-lts latest-v2: *fabric-v2-lts diff --git a/packages/caliper-fabric/lib/FabricConnectorFactory.js b/packages/caliper-fabric/lib/FabricConnectorFactory.js index 066f50db9..f4f1f2b21 100644 --- a/packages/caliper-fabric/lib/FabricConnectorFactory.js +++ b/packages/caliper-fabric/lib/FabricConnectorFactory.js @@ -19,53 +19,87 @@ const ConnectorConfigurationFactory = require('./connector-configuration/Connect const Logger = CaliperUtils.getLogger('FabricConnectorFactory'); const semver = require('semver'); -const NEW_V1_NODE_CONNECTOR = './connector-versions/v1/FabricNonGateway.js'; -const NEW_V1_GATEWAY_CONNECTOR = './connector-versions/v1/FabricGateway.js'; -const NEW_V1_WALLET_FACADE_FACTORY = './connector-versions/v1/WalletFacadeFactory.js'; +const V1_NODE_CONNECTOR = './connector-versions/v1/FabricNonGateway.js'; +const V1_GATEWAY_CONNECTOR = './connector-versions/v1/FabricGateway.js'; +const V1_WALLET_FACADE_FACTORY = './connector-versions/v1/WalletFacadeFactory.js'; -const NEW_V2_GATEWAY_CONNECTOR = './connector-versions/v2/FabricGateway.js'; -const NEW_V2_WALLET_FACADE_FACTORY = './connector-versions/v2/WalletFacadeFactory.js'; +const V2_GATEWAY_CONNECTOR = './connector-versions/v2/FabricGateway.js'; +const V2_WALLET_FACADE_FACTORY = './connector-versions/v2/WalletFacadeFactory.js'; + +const PEER_GATEWAY_CONNECTOR = './connector-versions/peer-gateway/PeerGateway.js'; +const PEER_WALLET_FACADE_FACTORY = './connector-versions/peer-gateway/WalletFacadeFactory.js'; /** - * @returns {string} version + * @typedef {Object} Sdk + * @property {String} module - The sdk module name + * @property {String} version - The version of the sdk module */ -const _determineInstalledNodeSDKVersion = () => { +/** + * @returns {Sdk} installedSDKmodule and version + */ +const _determineInstalledNodeSDKandVersion = () => { // Caliper can only work if you use bind and it will pull in fabric network even for non gateway 1.4 + let sdk, packageVersion; + + if (CaliperUtils.moduleIsInstalled('@hyperledger/fabric-gateway')) { + packageVersion = semver.coerce(require('@hyperledger/fabric-gateway/package').version); + sdk = 'fabric-gateway'; + } + if (CaliperUtils.moduleIsInstalled('fabric-network')) { - const packageVersion = require('fabric-network/package').version; - return semver.coerce(packageVersion); - } else { + if (sdk) { + throw new Error('Multiple bindings for fabric have been detected, you need to unbind one or more to ensure only a single bind is present to continue'); + } + packageVersion = semver.coerce(require('fabric-network/package').version); + sdk = 'fabric-network'; + } + + + if (!sdk) { throw new Error('Unable to detect required Fabric binding packages'); } + + return {sdk, packageVersion}; }; -const _loadAppropriateConnectorClass = (installedNodeSDKVersion) => { +const _loadAppropriateConnectorClass = (installedNodeSdk, version) => { let connectorPath; let walletFacadeFactoryPath; - if (semver.satisfies(installedNodeSDKVersion, '=1.x')) { - const useGateway = ConfigUtil.get(ConfigUtil.keys.Fabric.Gateway.Enabled, false); - Logger.info(`Initializing ${useGateway ? 'gateway' : 'standard' } connector compatible with installed SDK: ${installedNodeSDKVersion}`); + if (installedNodeSdk === 'fabric-network') { + if (semver.satisfies(version, '=1.x')) { + const useGateway = ConfigUtil.get(ConfigUtil.keys.Fabric.Gateway.Enabled, false); + Logger.info(`Initializing ${useGateway ? 'gateway' : 'standard' } connector compatible with installed fabric-network SDK: ${version}`); - if (!useGateway) { - connectorPath = NEW_V1_NODE_CONNECTOR; - walletFacadeFactoryPath = NEW_V1_WALLET_FACADE_FACTORY; - } else { - // gateway with default event handlers appears in SDK > 1.4.2 - if (semver.satisfies(installedNodeSDKVersion, '>=1.4.2')) { - connectorPath = NEW_V1_GATEWAY_CONNECTOR; - walletFacadeFactoryPath = NEW_V1_WALLET_FACADE_FACTORY; + if (!useGateway) { + connectorPath = V1_NODE_CONNECTOR; + walletFacadeFactoryPath = V1_WALLET_FACADE_FACTORY; } else { - throw new Error('Caliper currently only supports Fabric gateway based operation using Fabric-SDK 1.4.2 and higher. Please retry with a different SDK binding'); + // gateway with default event handlers appears in SDK > 1.4.2 + if (semver.satisfies(version, '>=1.4.2')) { + connectorPath = V1_GATEWAY_CONNECTOR; + walletFacadeFactoryPath = V1_WALLET_FACADE_FACTORY; + } else { + throw new Error('Caliper currently only supports Fabric gateway based operation using Fabric-SDK 1.4.2 and higher. Please retry with a different SDK binding'); + } } + } else if (semver.satisfies(version, '=2.x')) { + Logger.info(`Initializing gateway connector compatible with installed SDK: ${version}`); + connectorPath = V2_GATEWAY_CONNECTOR; + walletFacadeFactoryPath = V2_WALLET_FACADE_FACTORY; + } else { + throw new Error(`Installed fabric-network SDK version ${version} did not match any compatible Fabric connectors`); } - } else if (semver.satisfies(installedNodeSDKVersion, '=2.x')) { - Logger.info(`Initializing gateway connector compatible with installed SDK: ${installedNodeSDKVersion}`); - connectorPath = NEW_V2_GATEWAY_CONNECTOR; - walletFacadeFactoryPath = NEW_V2_WALLET_FACADE_FACTORY; } else { - throw new Error(`Installed SDK version ${installedNodeSDKVersion} did not match any compatible Fabric connectors`); + // can only be fabric-gateway binding due to check done in _determineInstalledNodeSDKandVersion + if (semver.satisfies(version, '=1.x')) { + Logger.info(`Initializing peer gateway connector compatible with installed fabric-gateway SDK: ${version}`); + connectorPath = PEER_GATEWAY_CONNECTOR; + walletFacadeFactoryPath = PEER_WALLET_FACADE_FACTORY; + } else { + throw new Error(`Installed fabric-gateway SDK version ${version} did not match any compatible Fabric connectors`); + } } const fabricConnectorClass = require(connectorPath); @@ -95,8 +129,9 @@ const connectorFactory = async (workerIndex) => { throw new Error(`Unknown network configuration version ${loadedConnectorConfiguration.version} specified`); } - const installedNodeSDKVersion = _determineInstalledNodeSDKVersion(); - const {fabricConnectorClass, walletFacadeFactoryClass} = _loadAppropriateConnectorClass(installedNodeSDKVersion); + const sdk = _determineInstalledNodeSDKandVersion(); + + const {fabricConnectorClass, walletFacadeFactoryClass} = _loadAppropriateConnectorClass(sdk.sdk, sdk.packageVersion); const connectorConfiguration = await new ConnectorConfigurationFactory().create(connectorConfigurationFile, new walletFacadeFactoryClass()); const fabricConnector = new fabricConnectorClass(connectorConfiguration, workerIndex, 'fabric'); diff --git a/packages/caliper-fabric/test/FabricConnectorFactory.js b/packages/caliper-fabric/test/FabricConnectorFactory.js index 1d5278d34..2aebe7b16 100644 --- a/packages/caliper-fabric/test/FabricConnectorFactory.js +++ b/packages/caliper-fabric/test/FabricConnectorFactory.js @@ -29,6 +29,7 @@ const { ConfigUtil } = require('@hyperledger/caliper-core'); const unsupportedConfig = './sample-configs/LegacyNetworkConfig.yaml'; const v2Config = './sample-configs/NoIdentitiesNetworkConfig.yaml'; const unknownVersionConfig = './sample-configs/UnknownVersionConfig.yaml'; +const peerGatewayConfig = './sample-configs/BasicConfig.yaml'; const DefaultEventHandlerStrategies = {}; const DefaultQueryHandlerStrategies = {}; @@ -163,20 +164,59 @@ describe('A Fabric Connector Factory', () => { mockery.deregisterAll(); }); + it('should create a Peer Gateway Fabric connector if a 1.x fabric-gateway library is bound', async () => { + mockery.registerMock('@hyperledger/fabric-gateway', {}); + mockery.registerMock('@hyperledger/fabric-gateway/package', {version: '1.0.1'}); + mockery.registerMock('@grpc/grpc-js', {}); + ConfigUtil.set(ConfigUtil.keys.NetworkConfig, path.resolve(__dirname, peerGatewayConfig)); + ConfigUtil.set(ConfigUtil.keys.Fabric.Gateway.Enabled, false); + const connector = await ConnectorFactory(1); + connector.constructor.name.should.equal('PeerGateway'); + mockery.deregisterAll(); + }); + it('should throw an error if no fabric library is bound', async () => { - // Can't test this with mockery because really need require to fail trying to - // find `fabric-network` or `fabric-client` + ConfigUtil.set(ConfigUtil.keys.NetworkConfig, path.resolve(__dirname, peerGatewayConfig)); + ConfigUtil.set(ConfigUtil.keys.Fabric.Gateway.Enabled, true); + await ConnectorFactory(1).should.be.rejectedWith(/Unable to detect required Fabric binding packages/); + }); + + it('should throw an error if fabric-gateway library bound is not than v1.x', async () => { + mockery.registerMock('@hyperledger/fabric-gateway', {}); + mockery.registerMock('@hyperledger/fabric-gateway/package', {version: '0.5.0'}); + ConfigUtil.set(ConfigUtil.keys.NetworkConfig, path.resolve(__dirname, peerGatewayConfig)); + ConfigUtil.set(ConfigUtil.keys.Fabric.Gateway.Enabled, true); + await ConnectorFactory(1).should.be.rejectedWith(/Installed fabric-gateway SDK version 0.5.0 did not match any compatible Fabric connectors/); + mockery.deregisterAll(); + mockery.registerMock('@hyperledger/fabric-gateway', {}); + mockery.registerMock('@hyperledger/fabric-gateway/package', {version: '2.5.0'}); + await ConnectorFactory(1).should.be.rejectedWith(/Installed fabric-gateway SDK version 2.5.0 did not match any compatible Fabric connectors/); + mockery.deregisterAll(); + }); + + it('should throw an error if fabric network library bound is not v1.4, v2.x', async () => { + mockery.registerMock('fabric-network', {}); + mockery.registerMock('fabric-network/package', {version: '3.0.0'}); + ConfigUtil.set(ConfigUtil.keys.NetworkConfig, path.resolve(__dirname, v2Config)); + ConfigUtil.set(ConfigUtil.keys.Fabric.Gateway.Enabled, true); + await ConnectorFactory(1).should.be.rejectedWith(/Installed fabric-network SDK version 3.0.0 did not match any compatible Fabric connectors/); + mockery.deregisterAll(); }); - it('should throw an error if fabric library bound is not V1 or V2', async () => { + it('should throw an error if both fabric-network and fabric-gateway are bound', async () => { mockery.registerMock('fabric-network', {}); mockery.registerMock('fabric-network/package', {version: '3.0.0'}); ConfigUtil.set(ConfigUtil.keys.NetworkConfig, path.resolve(__dirname, v2Config)); ConfigUtil.set(ConfigUtil.keys.Fabric.Gateway.Enabled, true); - await ConnectorFactory(1).should.be.rejectedWith(/Installed SDK version 3.0.0 did not match any compatible Fabric connectors/); + mockery.registerMock('@hyperledger/fabric-gateway', {}); + mockery.registerMock('@hyperledger/fabric-gateway/package', {version: '1.0.1'}); + ConfigUtil.set(ConfigUtil.keys.NetworkConfig, path.resolve(__dirname, peerGatewayConfig)); + ConfigUtil.set(ConfigUtil.keys.Fabric.Gateway.Enabled, true); + await ConnectorFactory(1).should.be.rejectedWith(/Multiple bindings for fabric have been detected, you need to unbind one or more to ensure only a single bind is present to continue/); mockery.deregisterAll(); }); + it('should throw a generic error if network configuration version is not 1.0 or 2.0', async () => { mockery.registerMock('fabric-network', {}); mockery.registerMock('fabric-network/package', {version: '1.4.11'}); diff --git a/packages/caliper-fabric/test/connector-versions/peer-gateway/PeerGateway.js b/packages/caliper-fabric/test/connector-versions/peer-gateway/PeerGateway.js index a8a158474..e3bc788ea 100644 --- a/packages/caliper-fabric/test/connector-versions/peer-gateway/PeerGateway.js +++ b/packages/caliper-fabric/test/connector-versions/peer-gateway/PeerGateway.js @@ -118,7 +118,7 @@ describe('A Fabric Peer Gateway sdk gateway', () => { }); - it('should pass a defined grpcClinet in the gateway options', async () => { + it('should pass a defined grpcClient in the gateway options', async () => { const connectorConfiguration = await new ConnectorConfigurationFactory().create(path.resolve(__dirname, configWith2Orgs1AdminInWalletNotMutual), walletFacadeFactory); const peerGateway = new PeerGateway(connectorConfiguration, 1, 'fabric'); await peerGateway.getContext(); @@ -137,16 +137,6 @@ describe('A Fabric Peer Gateway sdk gateway', () => { clock.restore(); }); - it('should pass the default timeout in the gateway options', async () => { - const connectorConfiguration = await new ConnectorConfigurationFactory().create(path.resolve(__dirname, configWith2Orgs1AdminInWalletNotMutual), walletFacadeFactory); - const peerGateway = new PeerGateway(connectorConfiguration, 1, 'fabric'); - const now = new Date(); - const clock = sinon.useFakeTimers(now.getTime()); - await peerGateway.getContext(); - Gateway.connectArgs[0].evaluateOptions().should.be.deep.equal({deadline: now.getTime() + 60000}); - clock.restore(); - }); - it('should pass the timeout from invokeOrQuery in the gateway options', async () => { ConfigUtil.set(ConfigUtil.keys.Fabric.Timeout.InvokeOrQuery, 99); const connectorConfiguration = await new ConnectorConfigurationFactory().create(path.resolve(__dirname, configWith2Orgs1AdminInWalletNotMutual), walletFacadeFactory); @@ -175,6 +165,14 @@ describe('A Fabric Peer Gateway sdk gateway', () => { Gateway.constructed.should.equal(4); }); + + it('should create a Gateway with the specified created identity', async () => { + const connectorConfiguration = await new ConnectorConfigurationFactory().create(path.resolve(__dirname, configWith2Orgs1AdminInWalletNotMutual), walletFacadeFactory); + const peerGateway = new PeerGateway(connectorConfiguration, 1, 'fabric'); + await peerGateway.getContext(); + Gateway.connectArgs[0].identity.should.deep.equal({mspId: 'Org1MSP', credentials: Buffer.from('-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----')}); + }); + it('should a attempt to create a grpc client with default grpc options when not provided through the connection profile', async () => { const connectorConfiguration = await new ConnectorConfigurationFactory().create(path.resolve(__dirname, configWith2Orgs1AdminInWalletNotMutual), walletFacadeFactory); const peerGateway = new PeerGateway(connectorConfiguration, 1, 'fabric');