diff --git a/packages/cactus-api-client/src/main/typescript/api-client.ts b/packages/cactus-api-client/src/main/typescript/api-client.ts index df344f0f204..fc83341720a 100644 --- a/packages/cactus-api-client/src/main/typescript/api-client.ts +++ b/packages/cactus-api-client/src/main/typescript/api-client.ts @@ -1,6 +1,10 @@ import { Checks, IAsyncProvider, Objects } from "@hyperledger/cactus-common"; -import { ConsortiumDatabase, Ledger } from "@hyperledger/cactus-core-api"; +import { + Capability, + ConsortiumDatabase, + Ledger, +} from "@hyperledger/cactus-core-api"; import { ConsortiumRepository } from "@hyperledger/cactus-core"; import { DefaultApi as ApiConsortium } from "@hyperledger/cactus-plugin-consortium-manual"; @@ -83,6 +87,8 @@ export class ApiClient extends BaseAPI { ledgerOrId: string | Ledger, ctor: new (configuration?: Configuration) => T, ctorArgs: Record, + consortiumDbProvider?: IAsyncProvider, + capabilities?: Capability[], ): Promise; /** * Constructs a new `ApiClient` object that is tied to whichever Cactus node @@ -100,12 +106,14 @@ export class ApiClient extends BaseAPI { * @param consortiumDbProvider The provider that can be used to retrieve the * consortium metadata at runtime for the purposes of looking up ledgers by * the provided `ledgerId` parameter. + * @param capabilities The capabilities or plugins we want the nodes to have. */ public async ofLedger( ledgerOrId: string | Ledger, ctor: new (configuration?: Configuration) => T, ctorArgs: Record, consortiumDbProvider?: IAsyncProvider, + capabilities?: Capability[], ): Promise { const fnTags = "ApiClient#forLedgerId()"; @@ -124,7 +132,7 @@ export class ApiClient extends BaseAPI { const db: ConsortiumDatabase = await provider.get(); const repo = new ConsortiumRepository({ db }); - const nodes = repo.nodesWithLedger(ledgerId); + const nodes = repo.nodesWithLedger(ledgerId, capabilities); // pick a random element from the array of nodes that have a connection to // the target ledger (based on the ledger ID) diff --git a/packages/cactus-core-api/src/main/json/openapi.json b/packages/cactus-core-api/src/main/json/openapi.json index dc1e45be8ff..5d16e00e641 100644 --- a/packages/cactus-core-api/src/main/json/openapi.json +++ b/packages/cactus-core-api/src/main/json/openapi.json @@ -101,6 +101,16 @@ "description": "String that uniquely identifies a plugin instance within a Cactus consortium so that requests can be addressed/routed directly to individual plugins when necessary.", "$ref": "#/components/schemas/PrimaryKey" }, + "Capability": { + "description": "String that represents a capability, i.e. if the gateway has the plugin with a certain capability", + "enum": [ + "org.hyperledger.cactus.capability.SATPHermes", + "org.hyperledger.cactus.capability.BUNGEEHermes", + "org.hyperledger.cactus.capability.FabricConnector", + "org.hyperledger.cactus.capability.BesuConnector", + "org.hyperledger.cactus.capability.EthConnector" + ] + }, "ConsortiumDatabase": { "required": [ "consortium", @@ -317,6 +327,16 @@ "items": { "$ref": "#/components/schemas/PluginInstanceId" } + }, + "capabilities": { + "type": "array", + "nullable": false, + "minItems": 0, + "maxItems": 2048, + "default": [], + "items": { + "$ref": "#/components/schemas/Capability" + } } } } @@ -809,4 +829,4 @@ } }, "paths": {} -} +} \ No newline at end of file diff --git a/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/FILES b/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/FILES index a5d2479a178..1cdb3d14779 100644 --- a/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/FILES +++ b/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/FILES @@ -23,6 +23,7 @@ src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt src/main/kotlin/org/openapitools/client/models/CactusNode.kt src/main/kotlin/org/openapitools/client/models/CactusNodeAllOf.kt src/main/kotlin/org/openapitools/client/models/CactusNodeMeta.kt +src/main/kotlin/org/openapitools/client/models/Capability.kt src/main/kotlin/org/openapitools/client/models/ConsensusAlgorithmFamiliesWithOutTxFinality.kt src/main/kotlin/org/openapitools/client/models/ConsensusAlgorithmFamiliesWithTxFinality.kt src/main/kotlin/org/openapitools/client/models/ConsensusAlgorithmFamily.kt diff --git a/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/README.md b/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/README.md index d87e2dca7b8..1fc18167932 100644 --- a/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/README.md +++ b/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/README.md @@ -52,6 +52,7 @@ Class | Method | HTTP request | Description - [org.openapitools.client.models.CactusNode](docs/CactusNode.md) - [org.openapitools.client.models.CactusNodeAllOf](docs/CactusNodeAllOf.md) - [org.openapitools.client.models.CactusNodeMeta](docs/CactusNodeMeta.md) + - [org.openapitools.client.models.Capability](docs/Capability.md) - [org.openapitools.client.models.ConsensusAlgorithmFamiliesWithOutTxFinality](docs/ConsensusAlgorithmFamiliesWithOutTxFinality.md) - [org.openapitools.client.models.ConsensusAlgorithmFamiliesWithTxFinality](docs/ConsensusAlgorithmFamiliesWithTxFinality.md) - [org.openapitools.client.models.ConsensusAlgorithmFamily](docs/ConsensusAlgorithmFamily.md) diff --git a/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CactusNode.kt b/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CactusNode.kt index 020128ccb68..7c86c692af7 100644 --- a/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CactusNode.kt +++ b/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CactusNode.kt @@ -15,6 +15,7 @@ package org.openapitools.client.models +import org.openapitools.client.models.Capability import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @@ -29,6 +30,7 @@ import com.squareup.moshi.JsonClass * @param memberId * @param ledgerIds Stores an array of Ledger entity IDs that are reachable (routable) via this Cactus Node. This information is used by the client side SDK API client to figure out at runtime where to send API requests that are specific to a certain ledger such as requests to execute transactions. * @param pluginInstanceIds + * @param capabilities */ @@ -55,7 +57,10 @@ data class CactusNode ( val ledgerIds: kotlin.collections.List = arrayListOf(), @Json(name = "pluginInstanceIds") - val pluginInstanceIds: kotlin.collections.List = arrayListOf() + val pluginInstanceIds: kotlin.collections.List = arrayListOf(), + + @Json(name = "capabilities") + val capabilities: kotlin.collections.List? = arrayListOf() ) diff --git a/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CactusNodeAllOf.kt b/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CactusNodeAllOf.kt index 895eb1c8a63..3e4397f6f12 100644 --- a/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CactusNodeAllOf.kt +++ b/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CactusNodeAllOf.kt @@ -15,6 +15,7 @@ package org.openapitools.client.models +import org.openapitools.client.models.Capability import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @@ -27,6 +28,7 @@ import com.squareup.moshi.JsonClass * @param memberId * @param ledgerIds Stores an array of Ledger entity IDs that are reachable (routable) via this Cactus Node. This information is used by the client side SDK API client to figure out at runtime where to send API requests that are specific to a certain ledger such as requests to execute transactions. * @param pluginInstanceIds + * @param capabilities */ @@ -46,7 +48,10 @@ data class CactusNodeAllOf ( val ledgerIds: kotlin.collections.List = arrayListOf(), @Json(name = "pluginInstanceIds") - val pluginInstanceIds: kotlin.collections.List = arrayListOf() + val pluginInstanceIds: kotlin.collections.List = arrayListOf(), + + @Json(name = "capabilities") + val capabilities: kotlin.collections.List? = arrayListOf() ) diff --git a/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/Capability.kt b/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/Capability.kt new file mode 100644 index 00000000000..3934ae5238e --- /dev/null +++ b/packages/cactus-core-api/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/Capability.kt @@ -0,0 +1,72 @@ +/** + * + * Please note: + * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + * + */ + +@file:Suppress( + "ArrayInDataClass", + "EnumEntryName", + "RemoveRedundantQualifierName", + "UnusedImport" +) + +package org.openapitools.client.models + + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +/** + * String that represents a capability, i.e. if the gateway has the plugin with a certain capability + * + * Values: sATPHermes,bUNGEEHermes,fabricConnector,besuConnector,ethConnector + */ + +@JsonClass(generateAdapter = false) +enum class Capability(val value: kotlin.String) { + + @Json(name = "org.hyperledger.cactus.capability.SATPHermes") + sATPHermes("org.hyperledger.cactus.capability.SATPHermes"), + + @Json(name = "org.hyperledger.cactus.capability.BUNGEEHermes") + bUNGEEHermes("org.hyperledger.cactus.capability.BUNGEEHermes"), + + @Json(name = "org.hyperledger.cactus.capability.FabricConnector") + fabricConnector("org.hyperledger.cactus.capability.FabricConnector"), + + @Json(name = "org.hyperledger.cactus.capability.BesuConnector") + besuConnector("org.hyperledger.cactus.capability.BesuConnector"), + + @Json(name = "org.hyperledger.cactus.capability.EthConnector") + ethConnector("org.hyperledger.cactus.capability.EthConnector"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use + * the actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that + * the client sends the correct enum values to the server always. + */ + override fun toString(): String = value + + companion object { + /** + * Converts the provided [data] to a [String] on success, null otherwise. + */ + fun encode(data: kotlin.Any?): kotlin.String? = if (data is Capability) "$data" else null + + /** + * Returns a valid [Capability] for [data], null otherwise. + */ + fun decode(data: kotlin.Any?): Capability? = data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> + it == value || normalizedData == "$value".lowercase() + } + } + } +} + diff --git a/packages/cactus-core-api/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-core-api/src/main/typescript/generated/openapi/typescript-axios/api.ts index 34ce3b3146e..10ad9e47778 100644 --- a/packages/cactus-core-api/src/main/typescript/generated/openapi/typescript-axios/api.ts +++ b/packages/cactus-core-api/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -71,6 +71,12 @@ export interface CactusNode { * @memberof CactusNode */ 'pluginInstanceIds': Array; + /** + * + * @type {Array} + * @memberof CactusNode + */ + 'capabilities'?: Array; } /** * @@ -108,6 +114,12 @@ export interface CactusNodeAllOf { * @memberof CactusNodeAllOf */ 'pluginInstanceIds': Array; + /** + * + * @type {Array} + * @memberof CactusNodeAllOf + */ + 'capabilities'?: Array; } /** * A Cactus node meta information @@ -128,6 +140,23 @@ export interface CactusNodeMeta { */ 'publicKeyPem': string; } +/** + * String that represents a capability, i.e. if the gateway has the plugin with a certain capability + * @export + * @enum {string} + */ + +export const Capability = { + SatpHermes: 'org.hyperledger.cactus.capability.SATPHermes', + BungeeHermes: 'org.hyperledger.cactus.capability.BUNGEEHermes', + FabricConnector: 'org.hyperledger.cactus.capability.FabricConnector', + BesuConnector: 'org.hyperledger.cactus.capability.BesuConnector', + EthConnector: 'org.hyperledger.cactus.capability.EthConnector' +} as const; + +export type Capability = typeof Capability[keyof typeof Capability]; + + /** * Enumerates a list of consensus algorithm families that do not provide immediate finality * @export diff --git a/packages/cactus-core/src/main/typescript/consortium-repository.ts b/packages/cactus-core/src/main/typescript/consortium-repository.ts index 092342b272f..efd682d169e 100644 --- a/packages/cactus-core/src/main/typescript/consortium-repository.ts +++ b/packages/cactus-core/src/main/typescript/consortium-repository.ts @@ -5,7 +5,11 @@ import { LoggerProvider, } from "@hyperledger/cactus-common"; -import { CactusNode, ConsortiumDatabase } from "@hyperledger/cactus-core-api"; +import { + CactusNode, + Capability, + ConsortiumDatabase, +} from "@hyperledger/cactus-core-api"; export interface IConsortiumRepositoryOptions { logLevel?: LogLevelDesc; @@ -55,10 +59,19 @@ export class ConsortiumRepository { * @param ledgerId The ID of the ledger to filter nodes based on. * @throws {Error} If `ledgerId` is falsy or blank. */ - public nodesWithLedger(ledgerId: string): CactusNode[] { + public nodesWithLedger( + ledgerId: string, + capabilities: Capability[] = [], + ): CactusNode[] { const fnTag = `${this.className}#nodesWithLedger()`; Checks.nonBlankString(ledgerId, `${fnTag}:ledgerId`); - - return this.allNodes.filter((cn) => cn.ledgerIds.includes(ledgerId)); + const pre_filter = this.allNodes.filter((cn) => + cn.ledgerIds.includes(ledgerId), + ); + let final = pre_filter; + for (const capability of capabilities) { + final = pre_filter.filter((cn) => cn.capabilities?.includes(capability)); + } + return final; } } diff --git a/packages/cactus-plugin-satp-hermes/src/test/typescript/integration/deploy-satp-in-cactus-api-server.test.ts b/packages/cactus-plugin-satp-hermes/src/test/typescript/integration/deploy-satp-in-cactus-api-server.test.ts new file mode 100644 index 00000000000..e1c5b961213 --- /dev/null +++ b/packages/cactus-plugin-satp-hermes/src/test/typescript/integration/deploy-satp-in-cactus-api-server.test.ts @@ -0,0 +1,324 @@ +import "jest-extended"; +import { + Containers, + pruneDockerAllIfGithubAction, +} from "@hyperledger/cactus-test-tooling"; +import { + LogLevelDesc, + LoggerProvider, + Servers, +} from "@hyperledger/cactus-common"; +import { TransactionApi as SATPTransactionApi } from "../../../main/typescript/public-api"; +import { + generateKeyPair, + exportSPKI, + exportPKCS8, + GenerateKeyPairResult, +} from "jose"; +import { ApiClient } from "@hyperledger/cactus-api-client"; +import { v4 as uuidV4 } from "uuid"; +import { + IPluginFactoryOptions, + Ledger, + LedgerType, + PluginImportType, +} from "@hyperledger/cactus-core-api"; +import { + CactusNode, + Consortium, + ConsortiumDatabase, + ConsortiumMember, +} from "@hyperledger/cactus-core-api"; +import { + ApiServer, + AuthorizationProtocol, + ConfigService, +} from "@hyperledger/cactus-cmd-api-server"; +import { + IPluginConsortiumManualOptions, + PluginConsortiumManual, + Configuration, +} from "@hyperledger/cactus-plugin-consortium-manual"; + +const logLevel: LogLevelDesc = "INFO"; +const logger = LoggerProvider.getOrCreate({ + level: "INFO", + label: "create consortium", +}); + +import { AddressInfo } from "net"; +import { PluginRegistry } from "@hyperledger/cactus-core"; +import { + SATPGateway, + SATPGatewayConfig, +} from "../../../main/typescript/plugin-satp-hermes-gateway"; +import { SupportedChain } from "../../../main/typescript/core/types"; +import { PluginFactorySATPGateway } from "../../../main/typescript/factory/plugin-factory-gateway-orchestrator"; +const consortiumId = uuidV4(); +const consortiumName = "Example Corp. & Friends Crypto Consortium"; + +let keyPair1: GenerateKeyPairResult; +let pubKeyPem1: string; +let member1: ConsortiumMember; +let node1: CactusNode; +const memberId1 = uuidV4(); +let apiServer1: ApiServer; +let addressInfo1: AddressInfo; +let node1Host: string; +let httpServer1: any; + +let keyPair2: GenerateKeyPairResult; +let pubKeyPem2: string; +let member2: ConsortiumMember; +let node2: CactusNode; +const memberId2 = uuidV4(); +let apiServer2: ApiServer; +let addressInfo2: AddressInfo; +let node2Host: string; +let httpServer2: any; + +let gateway1: SATPGateway; +let gateway2: SATPGateway; + +const ledger1: Ledger = { + id: "DLT1", + ledgerType: LedgerType.Fabric14X, +}; +const ledger2: Ledger = { + id: "DLT2", + ledgerType: LedgerType.Fabric14X, +}; + +const factoryOptions: IPluginFactoryOptions = { + pluginImportType: PluginImportType.Local, +}; +const factory = new PluginFactorySATPGateway(factoryOptions); + +beforeAll(async () => { + pruneDockerAllIfGithubAction({ logLevel }) + .then(() => { + logger.info("Pruning throw OK"); + }) + .catch(async () => { + await Containers.logDiagnostics({ logLevel }); + fail("Pruning didn't throw OK"); + }); +}); + +test("create consortium and test api-server routing", async () => { + const options1: SATPGatewayConfig = { + logLevel: "INFO", + gid: { + id: "mockID1", + name: "CustomGateway", + version: [ + { + Core: "v02", + Architecture: "v02", + Crash: "v02", + }, + ], + supportedDLTs: [SupportedChain.FABRIC, SupportedChain.BESU], + proofID: "mockProofID102", + gatewayServerPort: 3010, + gatewayClientPort: 3011, + address: "https://localhost", + }, + }; + gateway1 = await factory.create(options1); + + const options2: SATPGatewayConfig = { + logLevel: "INFO", + gid: { + id: "mockID2", + name: "CustomGateway", + version: [ + { + Core: "v02", + Architecture: "v02", + Crash: "v02", + }, + ], + supportedDLTs: [SupportedChain.FABRIC, SupportedChain.BESU], + proofID: "mockProofID101", + gatewayServerPort: 3050, + gatewayClientPort: 3051, + address: "https://localhost", + }, + }; + gateway2 = await factory.create(options2); + + await gateway1.startup(); + await gateway2.startup(); + + httpServer1 = await Servers.startOnPreferredPort(3010); + addressInfo1 = httpServer1.address() as AddressInfo; + node1Host = `http://${addressInfo1.address}:${addressInfo1.port}`; + + httpServer2 = await Servers.startOnPreferredPort(3050); + addressInfo2 = httpServer2.address() as AddressInfo; + node2Host = `http://${addressInfo2.address}:${addressInfo2.port}`; + + keyPair1 = await generateKeyPair("ES256K"); + pubKeyPem1 = await exportSPKI(keyPair1.publicKey); + + keyPair2 = await generateKeyPair("ES256K"); + pubKeyPem2 = await exportSPKI(keyPair2.publicKey); + + node1 = { + nodeApiHost: node1Host, + publicKeyPem: pubKeyPem1, + consortiumId, + id: uuidV4(), + ledgerIds: [ledger1.id], + memberId: memberId1, + pluginInstanceIds: [], + capabilities: ["org.hyperledger.cactus.capability.SATPHermes"], + }; + + member1 = { + id: memberId1, + name: "Example Corp 1", + nodeIds: [node1.id], + }; + + node2 = { + nodeApiHost: node2Host, + publicKeyPem: pubKeyPem2, + consortiumId, + id: uuidV4(), + ledgerIds: [ledger2.id], + memberId: memberId2, + pluginInstanceIds: [], + capabilities: ["org.hyperledger.cactus.capability.SATPHermes"], + }; + + member2 = { + id: memberId2, + name: "Example Corp 2", + nodeIds: [node2.id], + }; + + const consortium: Consortium = { + id: consortiumId, + mainApiHost: node1Host, + name: consortiumName, + memberIds: [member1.id, member2.id], + }; + + const consortiumDatabase: ConsortiumDatabase = { + cactusNode: [node1, node2], + consortium: [consortium], + consortiumMember: [member1, member2], + ledger: [ledger1, ledger2], + pluginInstance: [], + }; + + { + const pluginRegistry = new PluginRegistry({ plugins: [] }); + + const keyPairPem = await exportPKCS8(keyPair1.privateKey); + const options: IPluginConsortiumManualOptions = { + instanceId: uuidV4(), + pluginRegistry, + keyPairPem: keyPairPem, + consortiumDatabase, + logLevel, + }; + const pluginConsortiumManual = new PluginConsortiumManual(options); + + const configService = new ConfigService(); + const apiServerOptions = await configService.newExampleConfig(); + apiServerOptions.authorizationProtocol = AuthorizationProtocol.NONE; + apiServerOptions.configFile = ""; + apiServerOptions.apiCorsDomainCsv = "*"; + apiServerOptions.apiPort = addressInfo1.port; + apiServerOptions.cockpitPort = 0; + apiServerOptions.grpcPort = 0; + apiServerOptions.crpcPort = 0; + apiServerOptions.logLevel = logLevel || "INFO"; + apiServerOptions.apiTlsEnabled = false; + const config = + await configService.newExampleConfigConvict(apiServerOptions); + + pluginRegistry.add(pluginConsortiumManual); + pluginRegistry.add(gateway1); + + apiServer1 = new ApiServer({ + httpServerApi: httpServer1, + config: config.getProperties(), + pluginRegistry, + }); + + await apiServer1.start(); + logger.info("initiated api-server 1"); + } + + { + const pluginRegistry = new PluginRegistry({ plugins: [] }); + + const keyPairPem = await exportPKCS8(keyPair2.privateKey); + const options: IPluginConsortiumManualOptions = { + instanceId: uuidV4(), + pluginRegistry, + keyPairPem: keyPairPem, + consortiumDatabase, + logLevel, + }; + const pluginConsortiumManual = new PluginConsortiumManual(options); + + const configService = new ConfigService(); + const apiServerOptions = await configService.newExampleConfig(); + apiServerOptions.authorizationProtocol = AuthorizationProtocol.NONE; + apiServerOptions.configFile = ""; + apiServerOptions.apiCorsDomainCsv = "*"; + apiServerOptions.apiPort = addressInfo2.port; + apiServerOptions.logLevel = logLevel || "INFO"; + apiServerOptions.cockpitPort = 0; + apiServerOptions.grpcPort = 0; + apiServerOptions.crpcPort = 0; //default is 6000 , have to change so it does not break + apiServerOptions.apiTlsEnabled = false; + const config = + await configService.newExampleConfigConvict(apiServerOptions); + + pluginRegistry.add(pluginConsortiumManual); + pluginRegistry.add(gateway2); + + apiServer2 = new ApiServer({ + httpServerApi: httpServer2, + config: config.getProperties(), + pluginRegistry, + }); + + await apiServer2.start(); + logger.info("initiated api-server 2"); + } + + const config = new Configuration({ basePath: consortium.mainApiHost }); + const mainApiClient = new ApiClient(config); + + const apiClient1 = await mainApiClient.ofLedger( + ledger1.id, + SATPTransactionApi, + {}, + ); + + const apiClient2 = await mainApiClient.ofLedger( + ledger2.id, + SATPTransactionApi, + {}, + undefined, + ["org.hyperledger.cactus.capability.SATPHermes"], + ); + logger.info(JSON.stringify(apiClient1)); + logger.info(JSON.stringify(apiClient2)); + + expect(JSON.stringify(apiClient1)).not.toEqual(JSON.stringify(apiClient2)); +}); + +afterAll(async () => { + await gateway1.shutdown(); + await gateway2.shutdown(); + await apiServer2.shutdown(); + await apiServer1.shutdown(); +});