Skip to content

Commit

Permalink
feat(cactus-plugin-ledger-connector-aries): add new connector plugin
Browse files Browse the repository at this point in the history
- Add new plugin for connecting with aries agents and indy ledger.
- Currently it supports only connecting to other aries agents and verifying
    proofs.
- Add integration tests in `cactus-test-plugin-ledger-connector-aries`.
- Update `cactus-example-discounted-asset-trade` to use the connector instead
    of plain aries agent.

Depends on #2946

Signed-off-by: Michal Bajer <[email protected]>
  • Loading branch information
outSH committed Jan 22, 2024
1 parent f4373a9 commit e29cbff
Show file tree
Hide file tree
Showing 49 changed files with 5,391 additions and 154 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1901,6 +1901,33 @@ jobs:
restore-keys: |
${{ runner.os }}-yarn-${{ hashFiles('./yarn.lock') }}
- run: ./tools/ci.sh
cactus-test-plugin-ledger-connector-aries:
continue-on-error: false
env:
FULL_BUILD_DISABLED: true
JEST_TEST_PATTERN: packages/cactus-test-plugin-ledger-connector-aries/src/test/typescript/(unit|integration|benchmark)/.*/*.test.ts
JEST_TEST_RUNNER_DISABLED: false
TAPE_TEST_RUNNER_DISABLED: true
needs: build-dev
runs-on: ubuntu-20.04
steps:
- name: Use Node.js v16.14.2
uses: actions/[email protected]
with:
node-version: v16.14.2
- uses: actions/[email protected]
- id: yarn-cache-dir-path
name: Get yarn cache directory path
run: echo "::set-output name=dir::$(yarn cache dir)"
- id: yarn-cache
name: Restore Yarn Cache
uses: actions/[email protected]
with:
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
restore-keys: |
${{ runner.os }}-yarn-
- run: ./tools/ci.sh
cactus-test-plugin-ledger-connector-ethereum:
continue-on-error: false
env:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,18 @@
"@hyperledger/anoncreds-nodejs": "0.2.0-dev.4",
"@hyperledger/aries-askar-nodejs": "0.2.0-dev.1",
"@hyperledger/indy-vdr-nodejs": "0.2.0-dev.3",
"axios": "1.5.1",
"axios": "1.6.0",
"inquirer": "8.2.6",
"loglevel": "1.8.1"
},
"devDependencies": {
"@aries-framework/anoncreds": "0.5.0-alpha.58",
"@aries-framework/anoncreds-rs": "0.5.0-alpha.58",
"@aries-framework/askar": "0.5.0-alpha.58",
"@aries-framework/core": "0.5.0-alpha.58",
"@aries-framework/indy-sdk": "0.5.0-alpha.58",
"@aries-framework/indy-vdr": "0.5.0-alpha.58",
"@aries-framework/node": "0.5.0-alpha.58",
"@aries-framework/anoncreds": "0.5.0-alpha.71",
"@aries-framework/anoncreds-rs": "0.5.0-alpha.71",
"@aries-framework/askar": "0.5.0-alpha.71",
"@aries-framework/core": "0.5.0-alpha.71",
"@aries-framework/indy-sdk": "0.5.0-alpha.71",
"@aries-framework/indy-vdr": "0.5.0-alpha.71",
"@aries-framework/node": "0.5.0-alpha.71",
"@types/inquirer": "8.2.6"
},
"engines": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/

import * as log from "loglevel";
import * as path from "node:path";
import * as os from "node:os";
import { readFileSync } from "fs";

import { AskarModule } from "@aries-framework/askar";
Expand Down Expand Up @@ -51,16 +53,21 @@ const ISSUER_AGENT_PORT = 3004;
const ISSUER_DID_SEED = "000000000000000000000000Steward1";
const DID_INDY_NAMESPACE = "cacti:test";

const WALLET_PATH = path.join(
os.homedir(),
".cacti/cactus-example-discounted-asset-trade/wallet",
);

// Read Genesis transactions
const genesisTransactionsPath =
"/etc/cactus/indy-all-in-one/pool_transactions_genesis";
log.info(
"Reading Indy genesis transactions from file:",
genesisTransactionsPath,
);
const genesisTransactions = readFileSync(
"/etc/cactus/indy-all-in-one/pool_transactions_genesis",
).toString("utf-8");
const genesisTransactions = readFileSync(genesisTransactionsPath).toString(
"utf-8",
);

/**
* Configuration for local indy-all-in-one ledger.
Expand Down Expand Up @@ -142,11 +149,17 @@ export async function setupAgent(
name: string,
port: number,
): Promise<AnoncredAgent> {
const walletPath = path.join(WALLET_PATH, `${name}.sqlite`);

const config: InitConfig = {
label: name,
walletConfig: {
id: name,
key: name,
storage: {
type: "sqlite",
path: walletPath,
},
},
endpoints: [`http://localhost:${port}`],
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,12 @@ export async function connectAgents(
* Block until given connection is operational.
*
* @param agent Aries agent
* @param outOfBandRecordId connection outOfBandRecordId
* @param outOfBandId connection outOfBandId
* @param timeout operation timeout (will throw exception if timeout exceeded)
*/
export async function waitForConnectionReady(
export async function waitForConnectionReadyV1(
agent: Agent,
outOfBandRecordId: string,
outOfBandId: string,
timeout = WAIT_FOR_CLIENT_ACCEPT_TIMEOUT,
): Promise<void> {
let connection: ConnectionRecord | undefined;
Expand All @@ -218,11 +218,11 @@ export async function waitForConnectionReady(
);

connection = (
await agent.connections.findAllByOutOfBandId(outOfBandRecordId)
await agent.connections.findAllByOutOfBandId(outOfBandId)
).pop();
} while (counter > 0 && (!connection || !connection.isReady));

if (counter <= 0) {
throw new Error("waitForConnectionReady() timeout reached!");
throw new Error("waitForConnectionReadyV1() timeout reached!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export async function registerCredentialDefinition(
options: {
endorserMode: "internal",
endorserDid: did,
supportRevocation: false,
},
});

Expand Down
57 changes: 37 additions & 20 deletions examples/cactus-example-discounted-asset-trade/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ Alice knows that Acme Corp. provides digital certificates. She asks Acme Corp. t
popd
```

1. Create settings directory and make sure you have write permission on it

```bash
sudo mkdir /etc/cactus
sudo chown -R __YOUR_USERNAME__ /etc/cactus/
```

1. Start the ledgers:

```
Expand All @@ -84,7 +91,7 @@ Alice knows that Acme Corp. provides digital certificates. She asks Acme Corp. t
- Use `setup-credentials` script from `cactus-example-discounted-asset-trade-client`.

```bash
# In separat shell (can be used later for client app)
# In separate shell (can be used later for client app)
cd ./examples/cactus-example-discounted-asset-trade-client
yarn setup-credentials
popd
Expand Down Expand Up @@ -294,33 +301,43 @@ Action: Get assets

1. Press `Ctrl+C` in `docker-compose` console to stop the application.
1. Run cleanup script
```
sudo ./script-cleanup.sh # for root owned files
./script-cleanup.sh # for user owner files
```
```
sudo ./script-cleanup.sh # for root owned files
./script-cleanup.sh # for user owner files
```

#### Manual cleanup instructions

1. Remove the config files on your machine
```
sudo rm -r ./etc/cactus/
```
```
sudo rm -r ./etc/cactus/
```
1. Stop the docker containers of Ethereum, Fabric and Indy

- `docker stop geth1 asset_trade_faio2x_testnet asset_trade_indy_all_in_one`
- `docker rm geth1 asset_trade_faio2x_testnet asset_trade_indy_all_in_one`
- `docker stop geth1 asset_trade_faio2x_testnet asset_trade_indy_all_in_one`
- `docker rm geth1 asset_trade_faio2x_testnet asset_trade_indy_all_in_one`

1. Clear indy-all-in-one

```
pushd ../../tools/docker/indy-all-in-one/
./script-cleanup.sh
popd
```
```
pushd ../../tools/docker/indy-all-in-one/
./script-cleanup.sh
popd
```

1. Remove geth files
```
pushd ../../tools/docker/geth-testnet/
rm -fr ./data-geth1/geth/
popd
```
```
pushd ../../tools/docker/geth-testnet/
rm -fr ./data-geth1/geth/
popd
```

```
152 changes: 152 additions & 0 deletions examples/cactus-example-discounted-asset-trade/aries-connector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { IListenOptions, Servers } from "@hyperledger/cactus-common";
import { Constants, Configuration } from "@hyperledger/cactus-core-api";
import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server";
import {
PluginLedgerConnectorAries,
AriesApiClient,
} from "@hyperledger/cactus-plugin-ledger-connector-aries";

import * as path from "node:path";
import * as os from "node:os";
import http from "http";
import express from "express";
import bodyParser from "body-parser";
import { readFileSync } from "fs";
import { AddressInfo } from "net";
import { v4 as uuidv4 } from "uuid";
import { getLogger } from "log4js";
import { Server as SocketIoServer } from "socket.io";

const config: any = ConfigUtil.getConfig();
const moduleName = "aries-connector";
const logger = getLogger(`${moduleName}`);
logger.level = config.logLevel;

// Constants
const BLP_AGENT_NAME = "cactiDiscountedAssetTradeAgent";
const BLP_AGENT_INBOUND_URL = "http://127.0.0.1:5035";
const DID_INDY_NAMESPACE = "cacti:test";

const ARIES_WALLET_PATH = path.join(
os.homedir(),
".cacti/cactus-example-discounted-asset-trade/wallet",
);

// Read Genesis transactions
const genesisTransactionsPath =
"/etc/cactus/indy-all-in-one/pool_transactions_genesis";
logger.info(
"Reading Indy genesis transactions from file:",
genesisTransactionsPath,
);
const genesisTransactions = readFileSync(genesisTransactionsPath).toString(
"utf-8",
);

/**
* Configuration for local indy-all-in-one ledger.
*/
export const localTestNetwork = {
isProduction: false,
genesisTransactions,
indyNamespace: DID_INDY_NAMESPACE,
connectOnStartup: true,
};

// Single Aries connector instance
let ariesConnectorPlugin: PluginLedgerConnectorAries | undefined = undefined;
let ariesApiClient: AriesApiClient | undefined = undefined;

async function createAriesConnector() {
if (ariesConnectorPlugin) {
ariesConnectorPlugin.shutdown();
ariesConnectorPlugin = undefined;
}

ariesConnectorPlugin = new PluginLedgerConnectorAries({
instanceId: `ariesAssetTrade-${uuidv4()}`,
logLevel: config.logLevel,
walletPath: ARIES_WALLET_PATH,
ariesAgents: [
{
name: BLP_AGENT_NAME,
walletKey: BLP_AGENT_NAME,
indyNetworks: [localTestNetwork],
inboundUrl: BLP_AGENT_INBOUND_URL,
autoAcceptConnections: true,
},
],
});

await ariesConnectorPlugin.onPluginInit();

// Run http server
const expressApp = express();
expressApp.use(bodyParser.json({ limit: "250mb" }));
const connectorServer = http.createServer(expressApp);
const listenOptions: IListenOptions = {
hostname: "127.0.0.1",
port: 0,
server: connectorServer,
};
const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo;
const apiHost = `http://${addressInfo.address}:${addressInfo.port}`;

// Run socketio server
const socketioServer = new SocketIoServer(connectorServer, {
path: Constants.SocketIoConnectionPathV1,
});

// Register services
await ariesConnectorPlugin.getOrCreateWebServices();
await ariesConnectorPlugin.registerWebServices(expressApp, socketioServer);

// Create ApiClient
const apiConfig = new Configuration({ basePath: apiHost });
ariesApiClient = new AriesApiClient(apiConfig);
}

/**
* Create aries connector
*/
export async function initAriesConnector(): Promise<void> {
if (!ariesConnectorPlugin) {
await createAriesConnector();
logger.info("initAriesConnector() done.");
} else {
logger.info("initAriesConnector() Aries connector already initialized");
}
}

/**
* Get instance of aries connector, initialize it if not done yet.
*/
export async function getAriesConnector(): Promise<PluginLedgerConnectorAries> {
if (!ariesConnectorPlugin) {
await initAriesConnector();
}

if (ariesConnectorPlugin) {
return ariesConnectorPlugin;
} else {
throw new Error("Could not initialize new aries connector!");
}
}

/**
* Get instance of aries api client.
*/
export function getAriesApiClient(): AriesApiClient {
if (ariesApiClient) {
return ariesApiClient;
} else {
throw new Error("Aries connector not initialized yet!");
}
}

/**
* Get BLP agent name registered in connector
*/
export function getBlpAgentName(): string {
return BLP_AGENT_NAME;
}
Loading

0 comments on commit e29cbff

Please sign in to comment.