Skip to content

Commit

Permalink
refactor(core-api): normalize consortium data model
Browse files Browse the repository at this point in the history
Resolves #351

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
  • Loading branch information
petermetz committed Jan 5, 2021
1 parent 8a60717 commit a78b18d
Show file tree
Hide file tree
Showing 18 changed files with 695 additions and 343 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import exitHook, { IAsyncExitHookDoneCallback } from "async-exit-hook";
import {
CactusNode,
Consortium,
ConsortiumDatabase,
ConsortiumMember,
Ledger,
LedgerType,
} from "@hyperledger/cactus-core-api";

Expand Down Expand Up @@ -110,13 +112,13 @@ export class SupplyChainApp {
const keyPairB = await JWK.generate("EC", "secp256k1");
const keyPairPemB = keyPairB.toPEM(true);

const consortium = this.createConsortium(
const consortiumDatabase = this.createConsortium(
httpApiA,
httpApiB,
keyPairA,
keyPairB
);
const consortiumPrettyJson = JSON.stringify(consortium, null, 4);
const consortiumPrettyJson = JSON.stringify(consortiumDatabase, null, 4);
this.log.info(`Created Consortium definition: %o`, consortiumPrettyJson);

this.log.info(`Configuring Cactus Node for Ledger A...`);
Expand All @@ -127,7 +129,7 @@ export class SupplyChainApp {
plugins: [
new PluginConsortiumManual({
instanceId: "PluginConsortiumManual_A",
consortium,
consortiumDatabase,
keyPairPem: keyPairPemA,
logLevel: this.options.logLevel,
}),
Expand Down Expand Up @@ -168,7 +170,7 @@ export class SupplyChainApp {
plugins: [
new PluginConsortiumManual({
instanceId: "PluginConsortiumManual_B",
consortium,
consortiumDatabase,
keyPairPem: keyPairPemB,
logLevel: this.options.logLevel,
}),
Expand Down Expand Up @@ -219,7 +221,7 @@ export class SupplyChainApp {
serverB: Server,
keyPairA: JWK.ECKey,
keyPairB: JWK.ECKey
): Consortium {
): ConsortiumDatabase {
const consortiumName = "Example Supply Chain Consortium";
const consortiumId = uuidv4();

Expand All @@ -234,20 +236,21 @@ export class SupplyChainApp {
publicKeyPem: keyPairA.toPEM(false),
consortiumId,
id: nodeIdA,
plugins: [],
ledgers: [],
pluginInstanceIds: [],
ledgerIds: [],
};

const memberA: ConsortiumMember = {
id: memberIdA,
nodes: [cactusNodeA],
nodeIds: [cactusNodeA.id],
name: "Example Manufacturer Corp",
};

cactusNodeA.ledgers.push({
const ledger1 = {
id: "BesuDemoLedger",
ledgerType: LedgerType.BESU1X,
});
};
cactusNodeA.ledgerIds.push(ledger1.id);

const memberIdB = uuidv4();
const nodeIdB = uuidv4();
Expand All @@ -260,29 +263,39 @@ export class SupplyChainApp {
publicKeyPem: keyPairB.toPEM(false),
consortiumId,
id: nodeIdB,
plugins: [],
ledgers: [],
pluginInstanceIds: [],
ledgerIds: [],
};

const memberB: ConsortiumMember = {
id: memberIdB,
nodes: [cactusNodeB],
nodeIds: [cactusNodeB.id],
name: "Example Retailer Corp",
};

cactusNodeB.ledgers.push({
const ledger2: Ledger = {
id: "QuorumDemoLedger",
ledgerType: LedgerType.QUORUM2X,
});
};

cactusNodeB.ledgerIds.push(ledger2.id);

const consortium: Consortium = {
id: consortiumId,
name: consortiumName,
mainApiHost: nodeApiHostA,
members: [memberA, memberB],
memberIds: [memberA.id, memberB.id],
};

const consortiumDatabase: ConsortiumDatabase = {
cactusNode: [cactusNodeA, cactusNodeB],
consortium: [consortium],
consortiumMember: [memberA, memberB],
ledger: [ledger1, ledger2],
pluginInstance: [],
};

return consortium;
return consortiumDatabase;
}

public async startNode(
Expand Down
1 change: 1 addition & 0 deletions packages/cactus-api-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"homepage": "https://github.com/hyperledger/cactus#readme",
"dependencies": {
"@hyperledger/cactus-common": "^0.2.0",
"@hyperledger/cactus-core": "^0.2.0",
"@hyperledger/cactus-core-api": "^0.2.0",
"@hyperledger/cactus-plugin-consortium-manual": "^0.2.0",
"axios": "0.19.2",
Expand Down
46 changes: 16 additions & 30 deletions packages/cactus-api-client/src/main/typescript/api-client.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Checks, IAsyncProvider, Objects } from "@hyperledger/cactus-common";
import {
Consortium,
ConsortiumMember,
CactusNode,
Ledger,
} from "@hyperledger/cactus-core-api";

import { ConsortiumDatabase, Ledger } from "@hyperledger/cactus-core-api";

import { ConsortiumRepository } from "@hyperledger/cactus-core";
import { DefaultApi as ApiConsortium } from "@hyperledger/cactus-plugin-consortium-manual";
import { DefaultConsortiumProvider } from "./default-consortium-provider";

Expand Down Expand Up @@ -78,7 +76,7 @@ export class ApiClient extends DefaultApi {
*
* @see {DefaultConsortiumProvider}
*/
public get defaultConsortiumProvider(): IAsyncProvider<Consortium> {
public get defaultConsortiumDbProvider(): IAsyncProvider<ConsortiumDatabase> {
Checks.truthy(this.configuration, "ApiClient#configuration");
const apiClient = new ApiConsortium(this.configuration);
return new DefaultConsortiumProvider({ apiClient });
Expand All @@ -101,20 +99,21 @@ export class ApiClient extends DefaultApi {
*
* @param ledgerOrId The ID of the ledger to obtain an API client object for
* or the `Ledger` object which will be used to get the ledgerId from.
* @param consortiumProvider The provider that can be used to retrieve the
* @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.
*/
public async ofLedger<T extends {}>(
ledgerOrId: string | Ledger,
ctor: new (configuration?: Configuration) => T,
consortiumProvider: IAsyncProvider<Consortium> = this
.defaultConsortiumProvider
consortiumDbProvider?: IAsyncProvider<ConsortiumDatabase>
): Promise<ApiClient & T> {
const fnTags = "ApiClient#forLedgerId()";

const provider = consortiumDbProvider || this.defaultConsortiumDbProvider;

Checks.truthy(ledgerOrId, `${fnTags}:ledgerOrId`);
Checks.truthy(consortiumProvider, `${fnTags}:consortiumProvider`);
Checks.truthy(provider, `${fnTags}:consortiumDbProvider`);

let ledgerId: string;
if (typeof ledgerOrId === "string") {
Expand All @@ -123,22 +122,16 @@ export class ApiClient extends DefaultApi {
ledgerId = ledgerOrId.id;
}

const consortium: Consortium = await consortiumProvider.get();
Checks.truthy(consortiumProvider, `${fnTags}:consortium`);
const db: ConsortiumDatabase = await provider.get();
const repo = new ConsortiumRepository({ db });

// Find a list of nodes in the consortium that have a connector plugin
// running that's associated with the ledger based on ledger ID.
const nodes = consortium.members
.map((member: ConsortiumMember) =>
member.nodes.filter((node: CactusNode) =>
node.ledgers.some((ledger: Ledger) => ledger.id === ledgerId)
)
)
.flat();
const nodes = repo.nodesWithLedger(ledgerId);

// pick a random element from the array of nodes that have a connection to
// the target ledger (based on the ledger ID)
const randomNode = nodes[Math.floor(Math.random() * nodes.length)];
const randomIdx = Math.floor(Math.random() * nodes.length);

const randomNode = nodes[randomIdx];

const configuration = new Configuration({
basePath: randomNode.nodeApiHost,
Expand All @@ -147,10 +140,3 @@ export class ApiClient extends DefaultApi {
return new ApiClient(configuration).extendWith(ctor);
}
}

// type UnionToIntersection<U> =
// (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

// function extendWith<A extends any[]>(...args: A): UnionToIntersection<A[number]> { return null! }

// extendWith(new DefaultApi(), new ApiConsortium());
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
LoggerProvider,
} from "@hyperledger/cactus-common";
import { Checks, IAsyncProvider } from "@hyperledger/cactus-common";
import { Consortium } from "@hyperledger/cactus-core-api";
import { Consortium, ConsortiumDatabase } from "@hyperledger/cactus-core-api";
import {
DefaultApi,
GetConsortiumJwsResponse,
Expand All @@ -15,7 +15,8 @@ export interface IDefaultConsortiumProviderOptions {
apiClient: DefaultApi;
}

export class DefaultConsortiumProvider implements IAsyncProvider<Consortium> {
export class DefaultConsortiumProvider
implements IAsyncProvider<ConsortiumDatabase> {
public static readonly CLASS_NAME = "DefaultConsortiumProvider";

private readonly log: Logger;
Expand All @@ -33,32 +34,36 @@ export class DefaultConsortiumProvider implements IAsyncProvider<Consortium> {
this.log = LoggerProvider.getOrCreate({ level, label });
}

parseConsortiumJws(response: GetConsortiumJwsResponse): Consortium {
parseConsortiumJws(response: GetConsortiumJwsResponse): ConsortiumDatabase {
const fnTag = `DefaultConsortiumProvider#parseConsortiumJws()`;

Checks.truthy(response, `${fnTag}::response`);
Checks.truthy(response.jws, `${fnTag}::response.jws`);
Checks.truthy(response.jws.payload, `${fnTag}::response.jws.payload`);

const json = Buffer.from(response.jws.payload, "base64").toString();
const consortium = JSON.parse(json)?.consortium as Consortium;
const body = JSON.parse(json);
const {
consortiumDatabase,
}: { consortiumDatabase: ConsortiumDatabase } = body;

Checks.truthy(consortium, `${fnTag}::consortium`);
Checks.truthy(consortiumDatabase, `${fnTag}::consortiumDatabase`);

// FIXME Ideally there would be an option here to validate the JWS based on
// all the signatures and the corresponding public keys (which the caller
// would have to be able to supply).
// We do not yet have this crypto functions available in a cross platform
// manner so it is omitted for now but much needed prior to any GA release.
return consortium;
return consortiumDatabase;
}

public async get(): Promise<Consortium> {
public async get(): Promise<ConsortiumDatabase> {
try {
const res = await this.options.apiClient.apiV1PluginsHyperledgerCactusPluginConsortiumManualConsortiumJwsGet();
return this.parseConsortiumJws(res.data);
} catch (ex) {
this.log.error(`Request for Consortium JWS failed: `, ex?.toJSON());
const innerException = (ex.toJSON && ex.toJSON()) || ex;
this.log.error(`Request for Consortium JWS failed: `, innerException);
throw ex;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from "@hyperledger/cactus-common";
import { FORMAT_PLUGIN_ARRAY } from "./convict-plugin-array-format";
import { SelfSignedPkiGenerator, IPki } from "./self-signed-pki-generator";
import { Consortium } from "@hyperledger/cactus-core-api";
import { Consortium, ConsortiumDatabase } from "@hyperledger/cactus-core-api";

convict.addFormat(FORMAT_PLUGIN_ARRAY);
convict.addFormat(ipaddress);
Expand Down Expand Up @@ -411,40 +411,44 @@ export class ConfigService {
const keyPair = JWK.generateSync("EC", "secp256k1", { use: "sig" }, true);
const keyPairPem = keyPair.toPEM(true);
const memberId1 = "Cactus_Example_Consortium_Member_1";
const consortium: Consortium = {
name: "Example Cactus Consortium",
id: uuidV4(),
mainApiHost: apiBaseUrl,
members: [
const nodeId1 = "Cactus_Example_Consortium_Node_1";
const consortium: ConsortiumDatabase = {
cactusNode: [
{
consortiumId: "Cactus_Example_Consortium",
id: nodeId1,
ledgerIds: [],
memberId: memberId1,
pluginInstanceIds: [],
nodeApiHost: apiBaseUrl,
publicKeyPem: keyPair.toPEM(false),
},
],
consortiumMember: [
{
id: memberId1,
name: "Example Cactus Consortium Member 1",
nodes: [
{
consortiumId: "Cactus_Example_Consortium",
id: "Cactus_Example_Consortium_Node_1",
ledgers: [],
memberId: memberId1,
plugins: [],
nodeApiHost: apiBaseUrl,
publicKeyPem: keyPair.toPEM(false),
},
],
nodeIds: [nodeId1],
},
],
ledger: [],
pluginInstance: [],
consortium: [
{
name: "Example Cactus Consortium",
id: uuidV4(),
mainApiHost: apiBaseUrl,
memberIds: [memberId1],
},
],
};

const cockpitTlsEnabled: boolean = (schema.cockpitTlsEnabled as SchemaObj)
.default;
const cockpitTlsEnabled = (schema.cockpitTlsEnabled as SchemaObj).default;
const cockpitHost = (schema.cockpitHost as SchemaObj).default;
const cockpitPort = (schema.cockpitPort as SchemaObj).default;

// const cockpitProtocol = cockpitTlsEnabled ? "https:" : "http";
// const cockpitBaseUrl = `${cockpitProtocol}//${cockpitHost}:${cockpitPort}`;

const pkiGenerator = new SelfSignedPkiGenerator();
const pkiServer: IPki = pkiGenerator.create("localhost");
// const pkiClient: IPki = pkiGenerator.create("localhost", pkiServer);

const plugins = [
{
Expand Down
Loading

0 comments on commit a78b18d

Please sign in to comment.