From fa27fde9a28f83ff29964693be656dc107046517 Mon Sep 17 00:00:00 2001 From: Michal Bajer Date: Fri, 29 Mar 2024 13:06:55 +0100 Subject: [PATCH] feat(cactus-plugin-ledger-connector-iroha): remove deprecated iroha connector - Iroha connector is broken for some time and it's SDK does't seem to be actively supported anymore (in regards of bug or security fixes). Closes: #3159 Part of: #3155 Signed-off-by: Michal Bajer --- .github/workflows/ci.yaml | 46 +- .../workflows/iroha-all-in-one-publish.yaml | 60 - .taprc | 6 - docs-cactus/source/support/iroha.md | 17 - docs/docs/cactus/support/fabric.md | 4 +- docs/docs/cactus/support/iroha.md | 22 - docs/docs/cactus/support/quorum.md | 4 +- jest.config.js | 6 - .../CHANGELOG.md | 89 - .../Dockerfile | 7 - .../README.md | 247 --- .../run-transaction-endpoint-transact.png | Bin 43185 -> 0 bytes .../images/run-transaction-endpoint.png | Bin 38372 -> 0 bytes .../run-transaction-endpoint-transact.puml | 28 - .../run-transaction-endpoint.puml | 29 - .../openapitools.json | 7 - .../package.json | 104 - .../src/main/json/openapi.json | 1111 ---------- .../typescript/api-client/iroha-api-client.ts | 283 --- .../typescript-axios/.openapi-generator/FILES | 5 - .../.openapi-generator/VERSION | 1 - .../generated/openapi/typescript-axios/api.ts | 1457 ------------- .../openapi/typescript-axios/base.ts | 72 - .../openapi/typescript-axios/common.ts | 150 -- .../openapi/typescript-axios/configuration.ts | 101 - .../openapi/typescript-axios/index.ts | 18 - .../src/main/typescript/index.ts | 1 - .../src/main/typescript/index.web.ts | 1 - .../src/main/typescript/iroha-sign-utils.ts | 39 - .../typescript/iroha-transaction-wrapper.ts | 763 ------- .../plugin-factory-ledger-connector.ts | 20 - .../plugin-ledger-connector-iroha.ts | 370 ---- .../prometheus-exporter/data-fetcher.ts | 10 - .../typescript/prometheus-exporter/metrics.ts | 10 - .../prometheus-exporter.ts | 39 - .../prometheus-exporter/response.type.ts | 3 - .../src/main/typescript/public-api.ts | 25 - .../generate-transaction-endpoint.ts | 134 -- ...prometheus-exporter-metrics-endpoint-v1.ts | 96 - .../web-services/iroha-socketio-endpoint.ts | 216 -- .../web-services/run-transaction-endpoint.ts | 119 -- .../integration/api-surface.test.ts | 6 - ...nerate-and-send-signed-transaction.test.ts | 410 ---- .../iroha-iroha-transfer-example.test.ts | 369 ---- .../iroha-socketio-endpoint.test.ts | 469 ----- .../openapi/openapi-validation.test.ts | 243 --- .../run-transaction-endpoint-v1.test.ts | 1813 ----------------- .../test/typescript/unit/api-surface.test.ts | 6 - .../unit/iroha-test-ledger-parameters.test.ts | 35 - ...postgres-test-container-parameters.test.ts | 29 - .../tsconfig.json | 32 - .../typescript/iroha/iroha-test-ledger.ts | 496 ----- .../src/main/typescript/public-api.ts | 7 - .../constructor-validates-options.test.ts | 108 - packages/cactus-verifier-client/README.md | 1 - packages/cactus-verifier-client/package.json | 5 - .../typescript/get-validator-api-client.ts | 11 - packages/cactus-verifier-client/tsconfig.json | 3 - tools/docker/iroha-all-in-one/Dockerfile | 24 - tools/docker/iroha-all-in-one/README.md | 31 - tools/docker/iroha-all-in-one/entrypoint.sh | 45 - tools/docker/iroha-all-in-one/genesis.block | 162 -- tools/docker/iroha-all-in-one/healthcheck.py | 47 - tsconfig.json | 3 - yarn.lock | 391 +--- 65 files changed, 8 insertions(+), 10458 deletions(-) delete mode 100644 .github/workflows/iroha-all-in-one-publish.yaml delete mode 100644 docs-cactus/source/support/iroha.md delete mode 100644 docs/docs/cactus/support/iroha.md delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/CHANGELOG.md delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/Dockerfile delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/README.md delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/docs/architecture/images/run-transaction-endpoint-transact.png delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/docs/architecture/images/run-transaction-endpoint.png delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/docs/architecture/run-transaction-endpoint-transact.puml delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/docs/architecture/run-transaction-endpoint.puml delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/openapitools.json delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/package.json delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/json/openapi.json delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/api-client/iroha-api-client.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/api.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/base.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/common.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/configuration.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/index.ts delete mode 100755 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/index.ts delete mode 100755 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/index.web.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/iroha-sign-utils.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/iroha-transaction-wrapper.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/plugin-factory-ledger-connector.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/plugin-ledger-connector-iroha.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/data-fetcher.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/metrics.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/prometheus-exporter.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/response.type.ts delete mode 100755 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/public-api.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/generate-transaction-endpoint.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/get-prometheus-exporter-metrics-endpoint-v1.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/iroha-socketio-endpoint.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/run-transaction-endpoint.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/api-surface.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/generate-and-send-signed-transaction.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/iroha-iroha-transfer-example.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/iroha-socketio-endpoint.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/openapi/openapi-validation.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/run-transaction-endpoint-v1.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/api-surface.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/iroha-test-ledger-parameters.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/postgres-test-container-parameters.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-iroha/tsconfig.json delete mode 100644 packages/cactus-test-tooling/src/main/typescript/iroha/iroha-test-ledger.ts delete mode 100644 packages/cactus-test-tooling/src/test/typescript/integration/iroha/iroha-test-ledger/constructor-validates-options.test.ts delete mode 100644 tools/docker/iroha-all-in-one/Dockerfile delete mode 100644 tools/docker/iroha-all-in-one/README.md delete mode 100644 tools/docker/iroha-all-in-one/entrypoint.sh delete mode 100644 tools/docker/iroha-all-in-one/genesis.block delete mode 100644 tools/docker/iroha-all-in-one/healthcheck.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 08c67181ba..3e34b03c08 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -57,7 +57,7 @@ jobs: - './packages/cactus-core-api/**!(*.md|*.css|*.html|*.jpg|*.jpeg|*.png)' - './packages/cactus-test-tooling/**!(*.md|*.css|*.html|*.jpg|*.jpeg|*.png)' # - './.github/workflows/ci.yaml' - + plugin-ledger-connector-aries-changed: - './packages/cactus-plugin-ledger-connector-aries/**' - './packages/cactus-common/**' @@ -1507,33 +1507,6 @@ jobs: node-version: ${{ env.NODEJS_VERSION }} - uses: actions/checkout@v4.1.1 - - id: yarn-cache - name: Restore Yarn Cache - uses: actions/cache@v4.0.1 - with: - key: ${{ runner.os }}-yarn-${{ hashFiles('./yarn.lock') }} - path: ./.yarn/ - restore-keys: | - ${{ runner.os }}-yarn-${{ hashFiles('./yarn.lock') }} - - run: ./tools/ci.sh - cactus-plugin-ledger-connector-iroha: - continue-on-error: false - env: - FULL_BUILD_DISABLED: true - JEST_TEST_PATTERN: packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/(unit|integration|benchmark)/.*/*.test.ts - JEST_TEST_RUNNER_DISABLED: false - TAPE_TEST_PATTERN: >- - --files={./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/iroha-iroha-transfer-example.test.ts,./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/openapi/openapi-validation.test.ts,./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/run-transaction-endpoint-v1.test.ts,./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/iroha-test-ledger-parameters.test.ts,./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/postgres-test-container-parameters.test.ts} - TAPE_TEST_RUNNER_DISABLED: false - needs: build-dev - runs-on: ubuntu-22.04 - steps: - - name: Use Node.js ${{ env.NODEJS_VERSION }} - uses: actions/setup-node@v4.0.2 - with: - node-version: ${{ env.NODEJS_VERSION }} - - uses: actions/checkout@v4.1.1 - - id: yarn-cache name: Restore Yarn Cache uses: actions/cache@v4.0.1 @@ -2046,7 +2019,7 @@ jobs: JEST_TEST_PATTERN: packages/cactus-test-tooling/src/test/typescript/(unit|integration|benchmark)/.*/*.test.ts JEST_TEST_RUNNER_DISABLED: false TAPE_TEST_PATTERN: >- - --files={./packages/cactus-test-tooling/src/test/typescript/integration/besu/besu-test-ledger/constructor-validates-options.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/fabric/fabric-test-ledger-v1/constructor-validates-options.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/iroha/iroha-test-ledger/constructor-validates-options.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/postgres/postgres-test-container/constructor-validates-options.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/quorum/quorum-test-ledger/constructor-validates-options.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/rustc-container/rustc-container-target-bundler.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/substrate/substrate-test-ledger-constructor.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/substrate/substrate-test-ledger-multiple-concurrent.test.ts} + --files={./packages/cactus-test-tooling/src/test/typescript/integration/besu/besu-test-ledger/constructor-validates-options.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/fabric/fabric-test-ledger-v1/constructor-validates-options.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/postgres/postgres-test-container/constructor-validates-options.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/quorum/quorum-test-ledger/constructor-validates-options.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/rustc-container/rustc-container-target-bundler.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/substrate/substrate-test-ledger-constructor.test.ts,./packages/cactus-test-tooling/src/test/typescript/integration/substrate/substrate-test-ledger-multiple-concurrent.test.ts} TAPE_TEST_RUNNER_DISABLED: false runs-on: ubuntu-22.04 steps: @@ -2298,21 +2271,6 @@ jobs: ignore-unfixed: true vuln-type: 'os,library' severity: 'CRITICAL,HIGH' - ghcr-iroha-all-in-one: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4.1.1 - - name: ghcr.io/hyperledger/cactus-iroha-all-in-one - run: DOCKER_BUILDKIT=1 docker build ./tools/docker/iroha-all-in-one/ -f ./tools/docker/iroha-all-in-one/Dockerfile -t cactus-iroha-all-in-one - - name: Run Trivy vulnerability scan for cactus-iroha-all-in-one - uses: aquasecurity/trivy-action@0.11.2 - with: - image-ref: 'cactus-iroha-all-in-one' - format: 'table' - exit-code: '1' - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH' ghcr-keychain-vault-server: runs-on: ubuntu-22.04 steps: diff --git a/.github/workflows/iroha-all-in-one-publish.yaml b/.github/workflows/iroha-all-in-one-publish.yaml deleted file mode 100644 index f87fcfec07..0000000000 --- a/.github/workflows/iroha-all-in-one-publish.yaml +++ /dev/null @@ -1,60 +0,0 @@ -name: iroha-all-in-one-publish - -on: - push: - # Publish `main` as Docker `latest` image. - branches: - - main - - # Publish `v1.2.3` tags as releases. - tags: - - v* - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -env: - IMAGE_NAME: cactus-iroha-all-in-one - -jobs: - # Push image to GitHub Packages. - # See also https://docs.docker.com/docker-hub/builds/ - build-tag-push-container: - runs-on: ubuntu-22.04 - env: - DOCKER_BUILDKIT: 1 - DOCKERFILE_PATH: ./tools/docker/iroha-all-in-one/Dockerfile - DOCKER_BUILD_DIR: ./tools/docker/iroha-all-in-one/ - permissions: - packages: write - contents: read - - steps: - - uses: actions/checkout@v4.1.1 - - - name: Build image - run: docker build $DOCKER_BUILD_DIR --file $DOCKERFILE_PATH --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" - - - name: Log in to registry - # This is where you will update the PAT to GITHUB_TOKEN - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - - name: Push image - run: | - SHORTHASH=$(git rev-parse --short "$GITHUB_SHA") - TODAYS_DATE="$(date +%F)" - DOCKER_TAG="$TODAYS_DATE-$SHORTHASH" - IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - # Strip git ref prefix from version - VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') - # Strip "v" prefix from tag name - [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') - # Do not use the `latest` tag at all, tag with date + git short hash if there is no git tag - [ "$VERSION" == "main" ] && VERSION=$DOCKER_TAG - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $IMAGE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION diff --git a/.taprc b/.taprc index fad3ab8a63..a9ecd40dd9 100644 --- a/.taprc +++ b/.taprc @@ -56,11 +56,6 @@ files: - ./packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/deploy-contract/get-block.test.ts - ./packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/v21-besu-get-transaction.test.ts - ./packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/openapi/openapi-validation.test.ts - - ./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/iroha-iroha-transfer-example.test.ts - - ./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/run-transaction-endpoint-v1.test.ts - - ./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/openapi/openapi-validation.test.ts - - ./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/iroha-test-ledger-parameters.test.ts - - ./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/postgres-test-container-parameters.test.ts - ./packages/cactus-plugin-ledger-connector-xdai/src/test/typescript/integration/deploy-contract-from-json-xdai-json-object.test.ts - ./packages/cactus-plugin-ledger-connector-xdai/src/test/typescript/integration/invoke-contract-xdai-json-object.test.ts - ./packages/cactus-plugin-ledger-connector-xdai/src/test/typescript/integration/openapi/openapi-validation.test.ts @@ -96,7 +91,6 @@ files: - ./packages/cactus-test-tooling/src/test/typescript/integration/fabric/fabric-test-ledger-v1/constructor-validates-options.test.ts - ./packages/cactus-test-tooling/src/test/typescript/integration/substrate/substrate-test-ledger-constructor.test.ts - ./packages/cactus-test-tooling/src/test/typescript/integration/substrate/substrate-test-ledger-multiple-concurrent.test.ts - - ./packages/cactus-test-tooling/src/test/typescript/integration/iroha/iroha-test-ledger/constructor-validates-options.test.ts - ./packages/cactus-test-tooling/src/test/typescript/integration/rustc-container/rustc-container-target-bundler.test.ts - ./packages/cactus-test-tooling/src/test/typescript/integration/besu/besu-test-ledger/constructor-validates-options.test.ts - ./packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-single-status-endpoint.test.ts diff --git a/docs-cactus/source/support/iroha.md b/docs-cactus/source/support/iroha.md deleted file mode 100644 index 90767397d1..0000000000 --- a/docs-cactus/source/support/iroha.md +++ /dev/null @@ -1,17 +0,0 @@ -Iroha Support ------------------ - -```{note} -The deployContract feature not yet implemented since Iroha lacks full smart contract support during the initial development stage of the Iroha connector plugin. -``` - -
- Hyperledger Cactus v0.9.0 - - | Iroha version | runTransaction | - | --- | :---: | - | Iroha 1.2.0 and Postgres 9.5 | ✅ [test](https://github.com/hyperledger/cactus/blob/v0.9.0/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/run-transaction-endpoint-v1.test.ts) | - -
- -
\ No newline at end of file diff --git a/docs/docs/cactus/support/fabric.md b/docs/docs/cactus/support/fabric.md index caa1e79f64..bf8d0db23a 100644 --- a/docs/docs/cactus/support/fabric.md +++ b/docs/docs/cactus/support/fabric.md @@ -161,8 +161,8 @@ Fabric 1.4.8 ✅ [test](https://github.com/hyperledger/cactus/blob/v0.4.1/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v1-4-x/run-transaction-endpoint-v1.test.ts) - -[Previous](corda.md "Corda Support") [Next](iroha.md "Iroha Support") + +[Previous](corda.md "Corda Support") [Next](quorum.md "Quorum Support") * * * diff --git a/docs/docs/cactus/support/iroha.md b/docs/docs/cactus/support/iroha.md deleted file mode 100644 index dec2132b10..0000000000 --- a/docs/docs/cactus/support/iroha.md +++ /dev/null @@ -1,22 +0,0 @@ -Iroha Support -============================================================ - -Note - -The deployContract feature not yet implemented since Iroha lacks full smart contract support during the initial development stage of the Iroha connector plugin. - -Hyperledger Cactus v0.9.0 - -Iroha version - -runTransaction - -Iroha 1.2.0 and Postgres 9.5 - -✅ [test](https://github.com/hyperledger/cactus/blob/v0.9.0/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/run-transaction-endpoint-v1.test.ts) - - - -[Previous](fabric.md "Fabric Support") [Next](quorum.md "Quorum Support") - -* * * diff --git a/docs/docs/cactus/support/quorum.md b/docs/docs/cactus/support/quorum.md index 6ad23472bb..341fb2e008 100644 --- a/docs/docs/cactus/support/quorum.md +++ b/docs/docs/cactus/support/quorum.md @@ -161,8 +161,8 @@ Quorum 2.3.0 and Tessera 0.10.0 ✅ [test](https://github.com/hyperledger/cactus/blob/v0.4.1/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/deploy-contract-from-json.test.ts) - -[Previous](iroha.md "Iroha Support") [Next](xdai.md "xDai Support") + +[Previous](fabric.md "Fabric Support") [Next](xdai.md "xDai Support") * * * diff --git a/jest.config.js b/jest.config.js index 59a1dbfdd5..26da294755 100644 --- a/jest.config.js +++ b/jest.config.js @@ -65,11 +65,6 @@ module.exports = { `./packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/deploy-contract/get-block.test.ts`, `./packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/v21-besu-get-transaction.test.ts`, `./packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/openapi/openapi-validation.test.ts`, - `./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/iroha-iroha-transfer-example.test.ts`, - `./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/run-transaction-endpoint-v1.test.ts`, - `./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/openapi/openapi-validation.test.ts`, - `./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/iroha-test-ledger-parameters.test.ts`, - `./packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/postgres-test-container-parameters.test.ts`, `./packages/cactus-plugin-ledger-connector-xdai/src/test/typescript/integration/deploy-contract-from-json-xdai-json-object.test.ts`, `./packages/cactus-plugin-ledger-connector-xdai/src/test/typescript/integration/invoke-contract-xdai-json-object.test.ts`, `./packages/cactus-plugin-ledger-connector-xdai/src/test/typescript/integration/openapi/openapi-validation.test.ts`, @@ -105,7 +100,6 @@ module.exports = { `./packages/cactus-test-tooling/src/test/typescript/integration/fabric/fabric-test-ledger-v1/constructor-validates-options.test.ts`, `./packages/cactus-test-tooling/src/test/typescript/integration/substrate/substrate-test-ledger-constructor.test.ts`, `./packages/cactus-test-tooling/src/test/typescript/integration/substrate/substrate-test-ledger-multiple-concurrent.test.ts`, - `./packages/cactus-test-tooling/src/test/typescript/integration/iroha/iroha-test-ledger/constructor-validates-options.test.ts`, `./packages/cactus-test-tooling/src/test/typescript/integration/rustc-container/rustc-container-target-bundler.test.ts`, `./packages/cactus-test-tooling/src/test/typescript/integration/besu/besu-test-ledger/constructor-validates-options.test.ts`, `./packages/cactus-test-plugin-htlc-eth-besu/src/test/typescript/integration/plugin-htlc-eth-besu/get-single-status-endpoint.test.ts`, diff --git a/packages/cactus-plugin-ledger-connector-iroha/CHANGELOG.md b/packages/cactus-plugin-ledger-connector-iroha/CHANGELOG.md deleted file mode 100644 index 73f375e05b..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/CHANGELOG.md +++ /dev/null @@ -1,89 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [2.0.0-alpha.2](https://github.com/hyperledger/cacti/compare/v2.0.0-alpha.1...v2.0.0-alpha.2) (2023-09-27) - -### Bug Fixes - -* **security:** crash in HeaderParser in dicer ([77fb559](https://github.com/hyperledger/cacti/commit/77fb559532448aae45cfe704da2637119bf93c27)) -* use common conventions: tsconfig.json, package.json ([50f5c02](https://github.com/hyperledger/cacti/commit/50f5c02190ba28b77492c09e81f5d5ba6578e862)), closes [#2216](https://github.com/hyperledger/cacti/issues/2216) - -# [2.0.0-alpha.1](https://github.com/hyperledger/cacti/compare/v2.0.0-alpha-prerelease...v2.0.0-alpha.1) (2023-05-19) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-iroha - -# [2.0.0-alpha-prerelease](https://github.com/hyperledger/cacti/compare/v1.2.0...v2.0.0-alpha-prerelease) (2023-05-11) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-iroha - -# [1.2.0](https://github.com/hyperledger/cactus/compare/v1.1.3...v1.2.0) (2023-03-28) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-iroha - -## [1.1.3](https://github.com/hyperledger/cactus/compare/v1.1.2...v1.1.3) (2022-12-08) - -### Bug Fixes - -* **connector-iroha:** fix review comments and smaller issues ([b2742e8](https://github.com/hyperledger/cactus/commit/b2742e8f6512f9804c6b4a943947b5bbe90785f0)), closes [PR#2048](https://github.com/PR/issues/2048) -* **plugin-ledger-connector-iroha:** running dockerfile locally ([f5faaab](https://github.com/hyperledger/cactus/commit/f5faaab75cecf22f588f0cdcb502952652fee058)), closes [#1874](https://github.com/hyperledger/cactus/issues/1874) - -### Features - -* **connector-iroha:** update-iroha-js ([74929b1](https://github.com/hyperledger/cactus/commit/74929b17869731adb67930429780cb5d33346d4a)) -* monitoring, sync and async requests ([47da608](https://github.com/hyperledger/cactus/commit/47da608d378f5d48ca78b3d388b1c67da4c7aaf3)), closes [#1941](https://github.com/hyperledger/cactus/issues/1941) - -## [1.1.2](https://github.com/hyperledger/cactus/compare/v1.1.1...v1.1.2) (2022-11-11) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-iroha - -## [1.1.1](https://github.com/hyperledger/cactus/compare/v1.1.0...v1.1.1) (2022-11-03) - -### Features - -* **connector-iroha:** add dynamic request params ([a1f908f](https://github.com/hyperledger/cactus/commit/a1f908f4c27b652a15896c9847aee97cc6ea11fd)) - -# [1.1.0](https://github.com/hyperledger/cactus/compare/v1.0.0...v1.1.0) (2022-10-17) - -### Bug Fixes - -* remove skip to pass test case ([99cb9a7](https://github.com/hyperledger/cactus/commit/99cb9a7fb22f112f32de333756f32ac13e588a54)), closes [#1957](https://github.com/hyperledger/cactus/issues/1957) - -### Features - -* **connector-iroha:** sending transactions signed on the client-side ([da94cd6](https://github.com/hyperledger/cactus/commit/da94cd6b4fc5a364761716374ec7f6e7021bc76b)) - -# [1.0.0](https://github.com/hyperledger/cactus/compare/v1.0.0-rc.3...v1.0.0) (2022-03-16) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-iroha - -# [1.0.0-rc.3](https://github.com/hyperledger/cactus/compare/v1.0.0-rc.2...v1.0.0-rc.3) (2021-12-07) - -### Bug Fixes - -* **cmd-api-server:** build occasionally broken - protoc-gen-ts [#1563](https://github.com/hyperledger/cactus/issues/1563) ([c2ecba5](https://github.com/hyperledger/cactus/commit/c2ecba54396d5e72b28d9ad538460d3bde2ca6d0)) - -# [1.0.0-rc.2](https://github.com/hyperledger/cactus/compare/v1.0.0-rc.1...v1.0.0-rc.2) (2021-11-01) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-iroha - -# [1.0.0-rc.1](https://github.com/hyperledger/cactus/compare/v0.10.0...v1.0.0-rc.1) (2021-10-11) - -### Bug Fixes - -* openapi validation test for iroha plugin ([6deed6d](https://github.com/hyperledger/cactus/commit/6deed6d3f070982061e33a11064ffb8d4e752f37)), closes [#1331](https://github.com/hyperledger/cactus/issues/1331) [#847](https://github.com/hyperledger/cactus/issues/847) -* **webpack:** prod build chokes on upgraded ssh2 binaries [#1405](https://github.com/hyperledger/cactus/issues/1405) ([18979fb](https://github.com/hyperledger/cactus/commit/18979fb33880d8ca30e2fda01fb3d598deb839f9)) - -# [0.10.0](https://github.com/hyperledger/cactus/compare/v0.9.0...v0.10.0) (2021-09-28) - -### Features - -* **core-api:** discontinue dedicated HTTP listeners for web service plugins ([3fbd2fc](https://github.com/hyperledger/cactus/commit/3fbd2fcb60d49090bf4e986bea74d4e988348659)), closes [#358](https://github.com/hyperledger/cactus/issues/358) -* **core:** add installOpenapiValidationMiddleware ([1f6ea5f](https://github.com/hyperledger/cactus/commit/1f6ea5fe3aa1ba997a655098d632034f13f232a5)), closes [#847](https://github.com/hyperledger/cactus/issues/847) - -# [0.9.0](https://github.com/hyperledger/cactus/compare/v0.8.0...v0.9.0) (2021-08-31) - -### Features - -* **connector-iroha:** adds connector plugin ([4745df0](https://github.com/hyperledger/cactus/commit/4745df0bee6b9ab5fb9e57bb603ae95d6baeb391)) diff --git a/packages/cactus-plugin-ledger-connector-iroha/Dockerfile b/packages/cactus-plugin-ledger-connector-iroha/Dockerfile deleted file mode 100644 index 09f5169a64..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM ghcr.io/hyperledger/cactus-cmd-api-server:2022-11-14-6ff6aac -RUN npm install -g yarn@1.22.17 - -ENV NODE_ENV=production -ARG NPM_PKG_VERSION=latest - -RUN yarn add @hyperledger/cactus-plugin-ledger-connector-iroha@${NPM_PKG_VERSION} --production --ignore-engines \ No newline at end of file diff --git a/packages/cactus-plugin-ledger-connector-iroha/README.md b/packages/cactus-plugin-ledger-connector-iroha/README.md deleted file mode 100644 index 21b42e9d98..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/README.md +++ /dev/null @@ -1,247 +0,0 @@ -# `@hyperledger/cactus-plugin-ledger-connector-iroha` - -This plugin provides `Cactus` a way to interact with Iroha networks. Using this we can perform: -* Run various Iroha leger commands and queries. -* Build and sign transactions using any arbitrary credential. -## Summary - - - [Getting Started](#getting-started) - - [Architecture](#architecture) - - [Usage](#usage) - - [Runing the tests](#running-the-tests) - - [Built With](#built-with) - - [Contributing](#contributing) - - [License](#license) - - [Acknowledgments](#acknowledgments) - -## Getting Started - -Clone the git repository on your local machine. Follow these instructions that will get you a copy of the project up and running on your local machine for development and testing purposes. - -### Prerequisites - -In the root of the project, execute the command to install the dependencies: -```sh -yarn run configure -``` - -### Compiling - -In the project root folder, run this command to compile the plugin and create the dist directory: -```sh -# For one off builds: -yarn run build:dev:backend -``` - -```sh -# For continuous watching of the source code with -# automatic recompilation (more convenient) -yarn run watch -``` - -### Architecture -The sequence diagrams for various endpoints are mentioned below - -#### run-transaction-endpoint -![run-transaction-endpoint sequence diagram](docs/architecture/images/run-transaction-endpoint.png) - -The above diagram shows the sequence diagram of run-transaction-endpoint. User A (One of the many Users) interacts with the API Client which in turn, calls the API server. The API server then executes `transact()` method which is explained in detailed in the subsequent diagrams. - -![run-transaction-endpoint transact() method](docs/architecture/images/run-transaction-endpoint-transact.png) - -The above diagram shows the sequence diagram of `transact()` method of the `PluginLedgerConnectorIroha` class. The caller to this function, which in reference to the above sequence diagram is API server, sends `RunTransactionRequestV1` object as an argument to the `transact()` method. Based on the exact command name of the request, corresponsing response `RunTransactionResponse` is sent back to the caller. - -### Usage - -To use this import public-api and create new **PluginFactoryLedgerConnector**. Then use it to create a connector. -```typescript - const factory = new PluginFactoryLedgerConnector({ - pluginImportType: PluginImportType.Local, - }); - - const connector: PluginLedgerConnectorIroha = await factory.create({ - rpcToriiPortHost, - instanceId: uuidv4(), - pluginRegistry: new PluginRegistry(), - }); -``` -You can make calls through the connector to the plugin API: - -```typescript -async transact(req: RunTransactionRequestV1):Promise; -``` - -Call example to run an Iroha execute account command: -```typescript - const req = { - commandName: IrohaCommand.CreateAccount, - baseConfig: { - irohaHost: "localhost", - irohaPort: 50051, - creatorAccountId: "admin@test", - privKey: ["f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70"], - quorum: 1, - timeoutLimit: 5000, - }, - const res = await apiClient.runTransactionV1(req); -``` -Call example to run an Iroha get account query: -```typescript - const req = { - commandName: IrohaQuery.GetAccount, - baseConfig: { - irohaHost: "localhost", - irohaPort: 50051, - creatorAccountId: "admin@test", - privKey: ["f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70"], - quorum: 1, - timeoutLimit: 5000, - }, - params: ["admin@test"], - }; - const res = await apiClient.runTransactionV1(req); -``` -> Extensive documentation and examples in the [readthedocs](https://readthedocs.org/projects/hyperledger-cactus/) (WIP) - - -### Building/running the container image locally - -In the Cactus project root say: - -```sh -DOCKER_BUILDKIT=1 docker build -f ./packages/cactus-plugin-ledger-connector-iroha/Dockerfile . -t cplcb -``` - -Build with a specific version of the npm package: -```sh -DOCKER_BUILDKIT=1 docker build --build-arg NPM_PKG_VERSION=latest -f ./packages/cactus-plugin-ledger-connector-iroha/Dockerfile . -t cplcb -``` - -#### Running the container - -Launch container with plugin configuration as an **environment variable**: -```sh -docker run \ - --rm \ - --publish 3000:3000 \ - --publish 4000:4000 \ - --publish 5000:5000 \ - --env AUTHORIZATION_PROTOCOL='NONE' \ - --env AUTHORIZATION_CONFIG_JSON='{}' \ - --env GRPC_TLS_ENABLED=false \ - --env PLUGINS='[{"packageName": "@hyperledger/cactus-plugin-ledger-connector-iroha", "type": "org.hyperledger.cactus.plugin_import_type.LOCAL", "action": "org.hyperledger.cactus.plugin_import_action.INSTALL", "options": {"rpcApiHttpHost": "http://localhost:8545", "rpcToriiPortHost": "http://localhost:8545", "instanceId": "some-unique-iroha-connector-instance-id"}}]' \ - cplcb -``` - -Launch container with plugin configuration as a **CLI argument**: -```sh -docker run \ - --rm \ - --publish 3000:3000 \ - --publish 4000:4000 \ - --publish 5000:5000 \ - --env AUTHORIZATION_PROTOCOL='NONE' \ - --env AUTHORIZATION_CONFIG_JSON='{}' \ - --env GRPC_TLS_ENABLED=false \ - cplcb \ - ./node_modules/.bin/cactusapi \ - --plugins='[{"packageName": "@hyperledger/cactus-plugin-ledger-connector-iroha", "type": "org.hyperledger.cactus.plugin_import_type.LOCAL", "action": "org.hyperledger.cactus.plugin_import_action.INSTALL", "options": {"rpcApiHttpHost": "http://localhost:8545", "rpcToriiPortHost": "http://localhost:8545", "instanceId": "some-unique-iroha-connector-instance-id"}}]' -``` - -Launch container with **configuration file** mounted from host machine: -```sh - -echo '[{"packageName": "@hyperledger/cactus-plugin-ledger-connector-iroha", "type": "org.hyperledger.cactus.plugin_import_type.LOCAL", "action": "org.hyperledger.cactus.plugin_import_action.INSTALL", "options": {"rpcApiHttpHost": "http://localhost:8545", "rpcToriiPortHost": "http://localhost:8545", "instanceId": "some-unique-iroha-connector-instance-id"}}]' > cactus.json - -docker run \ - --rm \ - --publish 3000:3000 \ - --publish 4000:4000 \ - --publish 5000:5000 \ - --env AUTHORIZATION_PROTOCOL='NONE' \ - --env AUTHORIZATION_CONFIG_JSON='{}' \ - --env GRPC_TLS_ENABLED=false \ - --mount type=bind,source="$(pwd)"/cactus.json,target=/cactus.json \ - cplcb \ - ./node_modules/.bin/cactusapi \ - --config-file=/cactus.json -``` - -#### Testing API calls with the container - -Don't have an Iroha network on hand to test with? Test or develop against our Iroha All-In-One dockerfile! - -**Terminal Window 1 (Ledger)** -```sh -docker run -p 0.0.0.0:8545:8545/tcp -p 0.0.0.0:8546:8546/tcp -p 0.0.0.0:8888:8888/tcp -p 0.0.0.0:9001:9001/tcp -p 0.0.0.0:9545:9545/tcp hyperledger/cactus-iroha-all-in-one:latest -``` - -**Terminal Window 2 (Cactus API Server)** -```sh -docker run \ - --network host \ - --rm \ - --publish 3000:3000 \ - --publish 4000:4000 \ - --publish 5000:5000 \ - --env AUTHORIZATION_PROTOCOL='NONE' \ - --env AUTHORIZATION_CONFIG_JSON='{}' \ - --env GRPC_TLS_ENABLED=false \ - --env PLUGINS='[{"packageName": "@hyperledger/cactus-plugin-ledger-connector-iroha", "type": "org.hyperledger.cactus.plugin_import_type.LOCAL", "action": "org.hyperledger.cactus.plugin_import_action.INSTALL", "options": {"rpcApiHttpHost": "http://localhost:8545", "rpcToriiPortHost": "http://localhost:8545", "instanceId": "some-unique-iroha-connector-instance-id"}}]' \ - cplcb -``` - -**Terminal Window 3 (curl - replace transaction request as needed)** -```sh -curl --location --request POST 'http://127.0.0.1:4000/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/run-transaction' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - commandName: 'createAsset', - baseConfig: { - irohaHost: 'localhost', - irohaPort: 50051, - creatorAccountId: 'admin@test', - privKey: [ - 'f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70' - ], - quorum: 1, - timeoutLimit: 5000 - }, - params: [ 'coolcoin', 'test', 3] -}' -``` - -The above should produce a response that looks similar to this: - -```json -{ - "success": true, - "data": { - "transactionReceipt": { - "txHash": "c3ffd772f26950243aa357ab4f21b9703d5172490b66ddc285355230d6df60b8", - "status": "COMMITTED" - } - } -} -``` - -## Running the tests - -To check that all has been installed correctly and that the plugin has no errors run the tests: - -* Run this command at the project's root: -```sh -yarn run test:plugin-ledger-connector-iroha -``` - -## Contributing - -We welcome contributions to Hyperledger Cactus in many forms, and there’s always plenty to do! - -Please review [CONTIRBUTING.md](../../CONTRIBUTING.md) to get started. - -## License - -This distribution is published under the Apache License Version 2.0 found in the [LICENSE](../../LICENSE) file. - -## Acknowledgments diff --git a/packages/cactus-plugin-ledger-connector-iroha/docs/architecture/images/run-transaction-endpoint-transact.png b/packages/cactus-plugin-ledger-connector-iroha/docs/architecture/images/run-transaction-endpoint-transact.png deleted file mode 100644 index 70dcf461860ba86e7980ad20f709856e2f0520e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43185 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

NjzB8@5^3K(N)%1;1Yat|V)SKmKA20Z(D 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 diff --git a/packages/cactus-plugin-ledger-connector-iroha/docs/architecture/run-transaction-endpoint-transact.puml b/packages/cactus-plugin-ledger-connector-iroha/docs/architecture/run-transaction-endpoint-transact.puml deleted file mode 100644 index 6557546360..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/docs/architecture/run-transaction-endpoint-transact.puml +++ /dev/null @@ -1,28 +0,0 @@ -@startuml -title Hyperledger Cactus\nSequence Diagram\nRun Transaction Endpoint\ntransact() method - -skinparam sequenceArrowThickness 2 -skinparam roundcorner 20 -skinparam maxmessagesize 120 -skinparam sequenceParticipant underline - -actor "Caller" as caller -participant "PluginLedgerConnectorIroha" as t << (C,#ADD1B2) class >> - -autoactivate on - -activate caller -caller -> t: transact(RunTransactionRequest) - -alt #LightBlue commandName is an Iroha command - t -> t: generate Iroha commandOptions - return RunTransactionResponse - t --> caller: return RunTransactionResponse -else #LightGreen commandName is an Iroha query - t -> t: generate Iroha queryOptions - return RunTransactionResponse - t --> caller: return RunTransactionResponse -else #LightCoral default - t --> caller: throw RuntimeError("command or query does not exist) -end -@enduml \ No newline at end of file diff --git a/packages/cactus-plugin-ledger-connector-iroha/docs/architecture/run-transaction-endpoint.puml b/packages/cactus-plugin-ledger-connector-iroha/docs/architecture/run-transaction-endpoint.puml deleted file mode 100644 index 91c3724d8e..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/docs/architecture/run-transaction-endpoint.puml +++ /dev/null @@ -1,29 +0,0 @@ -@startuml Sequence Diagram - Transaction - -title Hyperledger Cactus\nSequence Diagram\nRun Transaction Endpoint - -skinparam sequenceArrowThickness 2 -skinparam roundcorner 20 -skinparam maxmessagesize 120 -skinparam sequenceParticipant underline - -box "Users" #LightBlue -actor "User A" as a -end box - -box "Hyperledger Cactus" #LightGray -entity "API Client" as apic -entity "API Server" as apis -end box - -box "Ledger Connector" #LightGreen -database "Iroha" as irohacon -end box - -a --> apic : Tx Iroha Ledger -apic --> apis: Request -apis --> irohacon: transact() -irohacon --> apis: Response -apis --> apic: Formatted Response -apic --> a: RunTransactionResponse -@enduml diff --git a/packages/cactus-plugin-ledger-connector-iroha/openapitools.json b/packages/cactus-plugin-ledger-connector-iroha/openapitools.json deleted file mode 100644 index 225ff1aaae..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/openapitools.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json", - "spaces": 2, - "generator-cli": { - "version": "6.6.0" - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/package.json b/packages/cactus-plugin-ledger-connector-iroha/package.json deleted file mode 100644 index fe573073f1..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/package.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "name": "@hyperledger/cactus-plugin-ledger-connector-iroha", - "version": "2.0.0-alpha.2", - "description": "Allows Cactus nodes to connect to an Iroha ledger.", - "keywords": [ - "Hyperledger", - "Cactus", - "Iroha", - "Integration", - "Blockchain", - "Distributed Ledger Technology" - ], - "homepage": "https://github.com/hyperledger/cacti#readme", - "bugs": { - "url": "https://github.com/hyperledger/cacti/issues" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/hyperledger/cacti.git" - }, - "license": "Apache-2.0", - "author": { - "name": "Hyperledger Cactus Contributors", - "email": "cactus@lists.hyperledger.org", - "url": "https://www.hyperledger.org/use/cacti" - }, - "contributors": [ - { - "name": "Peter Somogyvari", - "email": "peter.somogyvari@accenture.com", - "url": "https://accenture.com" - }, - { - "name": "Han Xu", - "email": "hanxu8@illinois.edu", - "url": "https://github.com/hxlaf" - } - ], - "main": "dist/lib/main/typescript/index.js", - "module": "dist/lib/main/typescript/index.js", - "browser": "dist/cactus-plugin-ledger-connector-iroha.web.umd.js", - "types": "dist/types/main/typescript/index.d.ts", - "files": [ - "dist/*" - ], - "scripts": { - "codegen": "run-p 'codegen:*'", - "codegen:openapi": "npm run generate-sdk", - "generate-sdk": "run-p 'generate-sdk:*'", - "generate-sdk:typescript-axios": "openapi-generator-cli generate -i ./src/main/json/openapi.json -g typescript-axios -o ./src/main/typescript/generated/openapi/typescript-axios/ --reserved-words-mappings protected=protected --ignore-file-override ../../openapi-generator-ignore", - "watch": "npm-watch", - "webpack": "npm-run-all webpack:dev", - "webpack:dev": "npm-run-all webpack:dev:node webpack:dev:web", - "webpack:dev:node": "webpack --env=dev --target=node --config ../../webpack.config.js", - "webpack:dev:web": "webpack --env=dev --target=web --config ../../webpack.config.js" - }, - "dependencies": { - "@grpc/grpc-js": "1.10.3", - "@hyperledger/cactus-common": "2.0.0-alpha.2", - "@hyperledger/cactus-core": "2.0.0-alpha.2", - "@hyperledger/cactus-core-api": "2.0.0-alpha.2", - "@types/google-protobuf": "3.15.5", - "axios": "1.6.0", - "express": "4.19.2", - "fast-safe-stringify": "2.1.1", - "iroha-helpers": "1.5.0", - "key-encoder": "2.0.3", - "openapi-types": "12.1.3", - "prom-client": "13.1.0", - "run-time-error-cjs": "1.4.0", - "rxjs": "7.8.1", - "sanitize-html": "2.12.1", - "socket.io-client-fixed-types": "4.5.4", - "typescript-optional": "2.0.1" - }, - "devDependencies": { - "@hyperledger/cactus-plugin-keychain-memory": "2.0.0-alpha.2", - "@hyperledger/cactus-test-tooling": "2.0.0-alpha.2", - "@types/body-parser": "1.19.4", - "@types/express": "4.17.19", - "@types/sanitize-html": "2.9.5", - "@types/uuid": "9.0.8", - "body-parser": "1.20.2", - "internal-ip": "6.2.0", - "socket.io": "4.5.4", - "uuid": "9.0.1" - }, - "engines": { - "node": ">=18", - "npm": ">=8" - }, - "publishConfig": { - "access": "public" - }, - "browserMinified": "dist/cactus-plugin-ledger-connector-iroha.web.umd.min.js", - "mainMinified": "dist/cactus-plugin-ledger-connector-iroha.node.umd.min.js", - "watch": { - "codegen:openapi": { - "patterns": [ - "./src/main/json/openapi.json" - ] - } - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/json/openapi.json b/packages/cactus-plugin-ledger-connector-iroha/src/main/json/openapi.json deleted file mode 100644 index d4184dd1af..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/json/openapi.json +++ /dev/null @@ -1,1111 +0,0 @@ -{ - "openapi": "3.0.3", - "info": { - "title": "Hyperledger Cactus Plugin - Connector Iroha", - "description": "Can perform basic tasks on a Iroha ledger", - "version": "v2.0.0-alpha.2", - "license": { - "name": "Apache-2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0.html" - } - }, - "components": { - "schemas": { - "IrohaCommand": { - "type": "string", - "enum": [ - "createAccount", - "setAccountDetail", - "setAccountQuorum", - "compareAndSetAccountDetail", - "createAsset", - "addAssetQuantity", - "subtractAssetQuantity", - "transferAsset", - "createDomain", - "createRole", - "detachRole", - "appendRole", - "addSignatory", - "removeSignatory", - "grantPermission", - "revokePermission", - "addPeer", - "removePeer", - "setSettingValue", - "callEngine" - ], - "x-enum-descriptions": [ - "Make entity in the system, capable of sending transactions or queries, storing signatories, personal data and identifiers.", - "Set key-value information for a given account.", - "Set the number of signatories required to confirm the identity of a user, who creates the transaction.", - "Set key-value information for a given account if the old value matches the value passed.", - "Create a new type of asset, unique in a domain. An asset is a countable representation of a commodity.", - "Increase the quantity of an asset on account of transaction creator.", - "Decrease the number of assets on account of transaction creator.", - "Share assets within the account in peer network: in the way that source account transfers assets to the target account.", - "Make new domain in Iroha network, which is a group of accounts.", - "Create a new role in the system from the set of permissions.", - "Detach a role from the set of roles of an account.", - "Promote an account to some created role in the system, where a role is a set of permissions account has to perform an action (command or query).", - "Add an identifier to the account. Such identifier is a public key of another device or a public key of another user.", - "Remove a public key, associated with an identity, from an account", - "Give another account rights to perform actions on the account of transaction sender (give someone right to do something with my account).", - "Revoke or dismiss given granted permission from another account in the network.", - "Write into ledger the fact of peer addition into the peer network.", - "Write into ledger the fact of peer removal from the network.", - "This command is not available for use, it was added for backward compatibility with Iroha.", - "This command is not availalbe for use because it is related to smart contract." - ], - "x-enum-varnames": [ - "CreateAccount", - "SetAccountDetail", - "SetAccountQuorum", - "CompareAndSetAccountDetail", - "CreateAsset", - "AddAssetQuantity", - "SubtractAssetQuantity", - "TransferAsset", - "CreateDomain", - "CreateRole", - "DetachRole", - "AppendRole", - "AddSignatory", - "RemoveSignatory", - "GrantPermission", - "RevokePermission", - "AddPeer", - "RemovePeer", - "SetSettingValue", - "CallEngine" - ] - }, - "IrohaQuery": { - "type": "string", - "enum": [ - "getAccount", - "getAccountDetail", - "getAssetInfo", - "getAccountAssets", - "getTransactions", - "getPendingTransactions", - "getAccountTransactions", - "getAccountAssetTransactions", - "getRoles", - "getSignatories", - "getRolePermissions", - "getBlock", - "getEngineReceipts", - "fetchCommits", - "getPeers" - ], - "x-enum-descriptions": [ - "To get the state of an account", - "To get details of the account.", - "To get information on the given asset (as for now - its precision).", - "To get the state of all assets in an account (a balance).", - "To retrieve information about transactions, based on their hashes.", - "To retrieve a list of pending (not fully signed) multisignature transactions or batches of transactions issued by account of query creator.", - "To retrieve a list of transactions per account.", - "To retrieve all transactions associated with given account and asset.", - "To get existing roles in the system.", - "To get signatories, which act as an identity of the account.", - "To get available permissions per role in the system.", - "To get a specific block, using its height as an identifier.", - "To retrieve a receipt of a CallEngine command. Allows to access the event log created during computations inside the EVM.", - "To get new blocks as soon as they are committed, a user can invoke FetchCommits RPC call to Iroha network.", - "A query that returns a list of peers in Iroha network." - ], - "x-enum-varnames": [ - "GetAccount", - "GetAccountDetail", - "GetAssetInfo", - "GetAccountAssets", - "GetTransactions", - "GetPendingTransactions", - "GetAccountTransactions", - "GetAccountAssetTransactions", - "GetRoles", - "GetSignatories", - "GetRolePermissions", - "GetBlock", - "GetEngineReceipts", - "FetchCommits", - "GetPeers" - ] - }, - "KeyPair": { - "type": "object", - "required": ["publicKey", "privateKey"], - "properties": { - "publicKey": { - "description": "SHA-3 ed25519 public keys of length 64 are recommended.", - "example": "313a07e6384776ed95447710d15e59148473ccfc052a681317a72a69f2a49910", - "type": "string", - "nullable": false - }, - "privateKey": { - "description": "SHA-3 ed25519 private keys of length 64 are recommended.", - "example": "f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70", - "type": "string", - "nullable": false - } - } - }, - "RunTransactionRequestV1Params": { - "oneOf": [ - { - "type": "array", - "items": {} - }, - { - "$ref": "#/components/schemas/AddAssetQuantityRequestParameters" - }, - { - "$ref": "#/components/schemas/AddPeerRequestParameters" - }, - { - "$ref": "#/components/schemas/AddSignatoryRequestParameters" - }, - { - "$ref": "#/components/schemas/AppendRoleRequestParameters" - }, - { - "$ref": "#/components/schemas/CallEngineRequestParameters" - }, - { - "$ref": "#/components/schemas/CreateAccountRequestParameters" - }, - { - "$ref": "#/components/schemas/CreateAssetRequestParameters" - }, - { - "$ref": "#/components/schemas/CreateDomainRequestParameters" - }, - { - "$ref": "#/components/schemas/CreateRoleRequestParameters" - }, - { - "$ref": "#/components/schemas/DetachRoleRequestParameters" - }, - { - "$ref": "#/components/schemas/GrantPermissionRequestParameters" - }, - { - "$ref": "#/components/schemas/RemovePeerRequestParameters" - }, - { - "$ref": "#/components/schemas/RemoveSignatoryRequestParameters" - }, - { - "$ref": "#/components/schemas/RevokePermissionRequestParameters" - }, - { - "$ref": "#/components/schemas/SetAccountDetailRequestParameters" - }, - { - "$ref": "#/components/schemas/SetAccountQuorumRequestParameters" - }, - { - "$ref": "#/components/schemas/SubtractAssetQuantityRequestParameters" - }, - { - "$ref": "#/components/schemas/TransferAssetRequestParameters" - }, - { - "$ref": "#/components/schemas/CompareAndSetAccountDetailRequestParameters" - }, - { - "$ref": "#/components/schemas/GetAccountRequestParameters" - }, - { - "$ref": "#/components/schemas/GetBlockRequestParameters" - }, - { - "$ref": "#/components/schemas/GetSignatoriesRequestParameters" - }, - { - "$ref": "#/components/schemas/GetTransactionsRequestParameters" - }, - { - "$ref": "#/components/schemas/GetPendingTransactionsRequestParameters" - }, - { - "$ref": "#/components/schemas/GetAccountTransactionsRequestParameters" - }, - { - "$ref": "#/components/schemas/GetAccountAssetTransactionsRequestParameters" - }, - { - "$ref": "#/components/schemas/GetAccountAssetsRequestParameters" - }, - { - "$ref": "#/components/schemas/GetAccountDetailRequestParameters" - }, - { - "$ref": "#/components/schemas/GetAssetInfoRequestParameters" - }, - { - "$ref": "#/components/schemas/GetRolePermissionsRequestParameters" - }, - { - "$ref": "#/components/schemas/GetEngineReceiptsRequestParameters" - } - ] - }, - "RunTransactionRequestV1Body": { - "oneOf": [ - { - "$ref": "#/components/schemas/RunTransactionRequestV1" - }, - { - "$ref": "#/components/schemas/RunTransactionSignedRequestV1" - } - ] - }, - "RunTransactionRequestV1": { - "type": "object", - "required": ["commandName", "baseConfig", "params"], - "additionalProperties": false, - "properties": { - "commandName": { - "type": "string", - "nullable": false - }, - "baseConfig": { - "$ref": "#/components/schemas/IrohaBaseConfig" - }, - "params": { - "$ref": "#/components/schemas/RunTransactionRequestV1Params" - } - } - }, - "AddAssetQuantityRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Add Asset Quantity.", - "type": "object", - "required": ["assetId", "amount"], - "properties": { - "assetId": { - "type": "string" - }, - "amount": { - "type": "number" - } - } - }, - "AddPeerRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Add Peer.", - "type": "object", - "required": ["address", "peerKey"], - "properties": { - "address": { - "type": "string" - }, - "peerKey": { - "type": "string" - }, - "tlsCertificate": { - "type": "string" - }, - "syncingPeer": { - "type": "boolean" - } - } - }, - "AddSignatoryRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Add Signatory.", - "type": "object", - "required": ["accountId", "publicKey"], - "properties": { - "accountId": { - "type": "string" - }, - "publicKey": { - "type": "string" - } - } - }, - "AppendRoleRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Append Role.", - "type": "object", - "required": ["accountId", "roleName"], - "properties": { - "accountId": { - "type": "string" - }, - "roleName": { - "type": "string" - } - } - }, - "CallEngineRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Call Engine.", - "type": "object", - "required": ["caller", "callee", "input"], - "properties": { - "caller": { - "type": "string" - }, - "callee": { - "type": "string" - }, - "input": { - "type": "string" - } - } - }, - "CreateAccountRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Create Account.", - "type": "object", - "required": ["accountName", "domainId", "publicKey"], - "properties": { - "accountName": { - "type": "string" - }, - "domainId": { - "type": "string" - }, - "publicKey": { - "type": "string" - } - } - }, - "CreateAssetRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Create Asset.", - "type": "object", - "required": ["assetName", "domainId", "precision"], - "properties": { - "assetName": { - "type": "string" - }, - "domainId": { - "type": "string" - }, - "precision": { - "type": "integer" - } - } - }, - "CreateDomainRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Create Domain.", - "type": "object", - "required": ["domainId", "defaultRole"], - "properties": { - "domainId": { - "type": "string" - }, - "defaultRole": { - "type": "string" - } - } - }, - "CreateRoleRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Create Role.", - "type": "object", - "required": ["roleName", "permissionsList"], - "properties": { - "roleName": { - "type": "string" - }, - "permissionsList": { - "type": "array", - "items": { - "type": "number" - } - } - } - }, - "DetachRoleRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Detach Role.", - "type": "object", - "required": ["accountId", "roleName"], - "properties": { - "accountId": { - "type": "string" - }, - "roleName": { - "type": "string" - } - } - }, - "GrantPermissionRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Grant Permission.", - "type": "object", - "required": ["accountId", "permission"], - "properties": { - "accountId": { - "type": "string" - }, - "permission": { - "type": "string" - } - } - }, - "RemovePeerRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Remove Peer.", - "type": "object", - "required": ["publicKey"], - "properties": { - "publicKey": { - "type": "string" - } - } - }, - "RemoveSignatoryRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Remove Signatory.", - "type": "object", - "required": ["accountId", "publicKey"], - "properties": { - "accountId": { - "type": "string" - }, - "publicKey": { - "type": "string" - } - } - }, - "RevokePermissionRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Revoke Permission.", - "type": "object", - "required": ["accountId", "permission"], - "properties": { - "accountId": { - "type": "string" - }, - "permission": { - "type": "number" - } - } - }, - "SetAccountDetailRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Set Account Detail.", - "type": "object", - "required": ["accountId", "key", "value"], - "properties": { - "accountId": { - "type": "string" - }, - "key": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "SetAccountQuorumRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Set Account Quorum.", - "type": "object", - "required": ["accountId", "quorum"], - "properties": { - "accountId": { - "type": "string" - }, - "quorum": { - "type": "integer" - } - } - }, - "SubtractAssetQuantityRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Subtract Asset Quantity.", - "type": "object", - "required": ["assetId", "amount"], - "properties": { - "assetId": { - "type": "string" - }, - "amount": { - "type": "number" - } - } - }, - "TransferAssetRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Transfer Asset.", - "type": "object", - "required": [ - "srcAccountId", - "destAccountId", - "assetId", - "description", - "amount" - ], - "properties": { - "srcAccountId": { - "type": "string" - }, - "destAccountId": { - "type": "string" - }, - "assetId": { - "type": "string" - }, - "description": { - "type": "string" - }, - "amount": { - "type": "number" - } - } - }, - "CompareAndSetAccountDetailRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Compare And Set Account Detail.", - "type": "object", - "required": ["accountId", "key", "value", "check_empty"], - "properties": { - "accountId": { - "type": "string" - }, - "key": { - "type": "string" - }, - "value": { - "type": "string" - }, - "oldValue": { - "type": "string" - }, - "check_empty": { - "type": "boolean" - } - } - }, - "GetAccountRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Account.", - "type": "object", - "required": ["accountId"], - "properties": { - "accountId": { - "type": "string" - } - } - }, - "GetBlockRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Block.", - "type": "object", - "required": ["height"], - "properties": { - "height": { - "type": "integer" - } - } - }, - "GetSignatoriesRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Signatories.", - "type": "object", - "required": ["accountId"], - "properties": { - "accountId": { - "type": "string" - } - } - }, - "GetTransactionsRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Transactions.", - "type": "object", - "required": ["txHashesList"], - "properties": { - "txHashesList": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "GetPendingTransactionsRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Pending Transactions.", - "type": "object", - "required": ["pageSize"], - "properties": { - "pageSize": { - "type": "integer" - }, - "firstTxHash": { - "type": "string" - }, - "firstTxTime": { - "type": "object" - }, - "lastTxTime": { - "type": "object" - } - } - }, - "GetAccountTransactionsRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Account Transactions.", - "type": "object", - "required": ["accountId", "pageSize", "firstTxHash"], - "properties": { - "accountId": { - "type": "string" - }, - "pageSize": { - "type": "integer" - }, - "firstTxHash": { - "type": "string" - }, - "firstTxTime": { - "type": "object" - }, - "lastTxTime": { - "type": "object" - }, - "firstTxHeight": { - "type": "integer" - }, - "lastTxHeight": { - "type": "integer" - } - } - }, - "GetAccountAssetTransactionsRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Account Asset Transactions.", - "type": "object", - "required": ["accountId", "assetId", "pageSize", "firstTxHash"], - "properties": { - "accountId": { - "type": "string" - }, - "assetId": { - "type": "string" - }, - "pageSize": { - "type": "integer" - }, - "firstTxHash": { - "type": "string" - } - } - }, - "GetAccountAssetsRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Account Assets.", - "type": "object", - "required": ["accountId", "pageSize"], - "properties": { - "accountId": { - "type": "string" - }, - "pageSize": { - "type": "number" - }, - "firstAssetId": { - "type": "string" - } - } - }, - "GetAccountDetailRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Account Detail.", - "type": "object", - "required": ["pageSize", "paginationKey", "paginationWriter"], - "properties": { - "accountId": { - "type": "string" - }, - "key": { - "type": "string" - }, - "writer": { - "type": "string" - }, - "pageSize": { - "type": "integer" - }, - "paginationKey": { - "type": "string" - }, - "paginationWriter": { - "type": "string" - } - } - }, - "GetAssetInfoRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Asset Info.", - "type": "object", - "required": ["assetId"], - "properties": { - "assetId": { - "type": "string" - } - } - }, - "GetRolePermissionsRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Role Permissions.", - "type": "object", - "required": ["roleId"], - "properties": { - "roleId": { - "type": "string" - } - } - }, - "GetEngineReceiptsRequestParameters": { - "description": "The list of arguments to pass in to the transaction request to Get Engine Receipts.", - "type": "object", - "required": ["txHash"], - "properties": { - "txHash": { - "type": "string" - } - } - }, - "RunTransactionSignedRequestV1": { - "type": "object", - "required": ["signedTransaction"], - "properties": { - "signedTransaction": { - "description": "Signed transaction binary data received from generate-transaction endpoint.", - "type": "string" - }, - "baseConfig": { - "$ref": "#/components/schemas/IrohaBaseConfig" - } - } - }, - "GenerateTransactionRequestV1": { - "type": "object", - "required": ["commandName", "commandParams", "creatorAccountId"], - "additionalProperties": false, - "properties": { - "commandName": { - "description": "Iroha command name.", - "type": "IrohaCommand", - "nullable": false - }, - "commandParams": { - "description": "Parameters for iroha command specified in commandName", - "type": "object" - }, - "creatorAccountId": { - "description": "Sender account id", - "type": "string", - "nullable": false - }, - "quorum": { - "description": "Requested transaction quorum", - "type": "number", - "nullable": false, - "default": 1 - } - } - }, - "IrohaBaseConfig": { - "type": "object", - "additionalProperties": true, - "properties": { - "irohaHost": { - "type": "string", - "nullable": false - }, - "irohaPort": { - "type": "number", - "nullable": false - }, - "creatorAccountId": { - "type": "string", - "nullable": false - }, - "privKey": { - "type": "array", - "items": {}, - "default": [], - "nullable": false - }, - "quorum": { - "type": "number", - "nullable": false - }, - "timeoutLimit": { - "type": "number", - "nullable": false - }, - "tls": { - "type": "boolean", - "nullable": false, - "description": "Can only be set to false for an insecure grpc connection." - }, - "monitorMode": { - "type": "boolean", - "nullable": true, - "description": "Flag used for monitoring. It changes default beahviour of transaction wrapper so it return error to caller instead of throwing RuntimeError straight away." - } - } - }, - "RunTransactionResponse": { - "type": "object", - "required": ["transactionReceipt"], - "properties": { - "transactionReceipt": {} - } - }, - "PrometheusExporterMetricsResponse": { - "type": "string", - "nullable": false - }, - "ErrorExceptionJsonResponseV1": { - "type": "object", - "required": ["message"], - "properties": { - "message": { - "type": "string", - "nullable": false - }, - "name": { - "type": "string", - "nullable": false - }, - "error": { - "type": "string", - "nullable": false - }, - "stack": { - "type": "string", - "nullable": false - }, - "cause": { - "type": "string", - "nullable": false - } - } - }, - "ErrorExceptionResponseV1": { - "type": "object", - "required": ["message", "error"], - "properties": { - "message": { - "type": "string", - "nullable": false - }, - "error": { - "type": "string", - "nullable": false - } - } - }, - "WatchBlocksV1": { - "type": "string", - "enum": [ - "org.hyperledger.cactus.api.async.iroha.WatchBlocksV1.Subscribe", - "org.hyperledger.cactus.api.async.iroha.WatchBlocksV1.Next", - "org.hyperledger.cactus.api.async.iroha.WatchBlocksV1.Unsubscribe", - "org.hyperledger.cactus.api.async.iroha.WatchBlocksV1.Error", - "org.hyperledger.cactus.api.async.iroha.WatchBlocksV1.Complete" - ], - "x-enum-varnames": [ - "Subscribe", - "Next", - "Unsubscribe", - "Error", - "Complete", - "SendAsyncRequest", - "SendSyncRequest" - ] - }, - "IrohaSocketIOTransactV1": { - "type": "string", - "enum": [ - "org.hyperledger.cactus.api.async.iroha.IrohaSocketIOTransactV1.SendAsyncRequest", - "org.hyperledger.cactus.api.async.iroha.IrohaSocketIOTransactV1.SendSyncRequest" - ], - "x-enum-varnames": ["SendAsyncRequest", "SendSyncRequest"] - }, - "IrohaBlockResponse": { - "type": "object", - "required": ["payload", "signaturesList"], - "properties": { - "payload": { - "type": "object", - "required": [ - "txNumber", - "transactionsList", - "height", - "prevBlockHash", - "createdTime", - "rejectedTransactionsHashesList" - ], - "properties": { - "transactionsList": { - "type": "array", - "items": {} - }, - "txNumber": { - "type": "number" - }, - "height": { - "type": "number" - }, - "prevBlockHash": { - "type": "string" - }, - "createdTime": { - "type": "number" - }, - "rejectedTransactionsHashesList": { - "type": "array", - "items": {} - } - } - }, - "signaturesList": { - "type": "array", - "items": {} - } - } - }, - "IrohaBlockProgress": { - "type": "object", - "required": ["transactionReceipt"], - "properties": { - "transactionReceipt": { - "$ref": "#/components/schemas/IrohaBlockResponse" - } - } - } - } - }, - "paths": { - "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/run-transaction": { - "post": { - "x-hyperledger-cacti": { - "http": { - "verbLowerCase": "post", - "path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/run-transaction" - } - }, - "operationId": "runTransactionV1", - "summary": "Executes a transaction on a Iroha ledger", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RunTransactionRequestV1Body" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RunTransactionResponse" - } - } - } - }, - "400": { - "description": "Bad Request error.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorExceptionJsonResponseV1" - } - } - } - }, - "405": { - "description": "Method Not Allowed error.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorExceptionJsonResponseV1" - } - } - } - }, - "500": { - "description": "Internal Server Error.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorExceptionJsonResponseV1" - } - } - } - } - } - } - }, - "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/generate-transaction": { - "post": { - "x-hyperledger-cacti": { - "http": { - "verbLowerCase": "post", - "path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/generate-transaction" - } - }, - "operationId": "generateTransactionV1", - "summary": "Generate transaction that can be signed locally.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GenerateTransactionRequestV1" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/octet-stream": { - "schema": { - "type": "string" - } - } - } - }, - "400": { - "description": "Bad Request Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorExceptionResponseV1" - } - } - } - }, - "500": { - "description": "Internal Server Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorExceptionResponseV1" - } - } - } - } - } - } - }, - "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/get-prometheus-exporter-metrics": { - "get": { - "x-hyperledger-cacti": { - "http": { - "verbLowerCase": "get", - "path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/get-prometheus-exporter-metrics" - } - }, - "operationId": "getPrometheusMetricsV1", - "summary": "Get the Prometheus Metrics", - "parameters": [], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/PrometheusExporterMetricsResponse" - } - } - } - } - } - } - } - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/api-client/iroha-api-client.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/api-client/iroha-api-client.ts deleted file mode 100644 index 528fb2a668..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/api-client/iroha-api-client.ts +++ /dev/null @@ -1,283 +0,0 @@ -import { Observable, ReplaySubject, share } from "rxjs"; -import { finalize } from "rxjs/operators"; -import { Socket, io } from "socket.io-client-fixed-types"; -import { Logger, Checks } from "@hyperledger/cactus-common"; -import { LogLevelDesc, LoggerProvider } from "@hyperledger/cactus-common"; -import { Constants, ISocketApiClient } from "@hyperledger/cactus-core-api"; -import { - DefaultApi, - WatchBlocksV1, - IrohaSocketIOTransactV1, - IrohaBlockProgress, - IrohaBaseConfig, -} from "../generated/openapi/typescript-axios"; -import { - Configuration, - ConfigurationParameters, -} from "../generated/openapi/typescript-axios/configuration"; -import { RuntimeError } from "run-time-error-cjs"; - -export interface IrohaApiClientParameters extends ConfigurationParameters { - logLevel?: LogLevelDesc; - wsApiHost?: string; - wsApiPath?: string; - timeoutLimit?: number; -} - -export class IrohaApiClientOptions extends Configuration { - readonly logLevel?: LogLevelDesc; - readonly wsApiHost?: string; - readonly wsApiPath?: string; - readonly timeoutLimit?: number; - - constructor(param: IrohaApiClientParameters = {}) { - super(param); - this.logLevel = param.logLevel; - this.wsApiHost = param.wsApiHost; - this.wsApiPath = param.wsApiPath; - this.timeoutLimit = param.timeoutLimit; - } -} - -export class IrohaApiClient - extends DefaultApi - implements ISocketApiClient -{ - public static readonly CLASS_NAME = "IrohaApiClient"; - private readonly log: Logger; - private readonly wsApiHost: string; - private readonly wsApiPath: string; - public get className(): string { - return IrohaApiClient.CLASS_NAME; - } - - constructor(public readonly options: IrohaApiClientOptions) { - super(options); - const fnTag = `${this.className}#constructor()`; - Checks.truthy(options, `${fnTag} arg options`); - - const level = this.options.logLevel || "INFO"; - const label = this.className; - this.log = LoggerProvider.getOrCreate({ level, label }); - - this.wsApiHost = options.wsApiHost || options.basePath || location.host; - this.wsApiPath = options.wsApiPath || Constants.SocketIoConnectionPathV1; - this.log.debug(`Created ${this.className} OK.`); - this.log.debug(`wsApiHost=${this.wsApiHost}`); - this.log.debug(`wsApiPath=${this.wsApiPath}`); - this.log.debug(`basePath=${this.options.basePath}`); - this.log.debug(`timeoutLimit=${this.options.timeoutLimit}`); - - Checks.nonBlankString( - this.wsApiHost, - `${this.className}::constructor() wsApiHost`, - ); - Checks.nonBlankString( - this.wsApiPath, - `${this.className}::constructor() wsApiPath`, - ); - } - - /** - * Start monitoring for new blocks on the Iroha ledger. - * @param monitorOptions - Options to be passed to validator `startMonitoring` procedure. - * @returns RxJs Observable, `next` - new block, `error` - any error from the validator. - */ - public watchBlocksV1( - monitorOptions?: Record, - ): Observable { - const socket: Socket = io(this.wsApiHost, { path: this.wsApiPath }); - const subject = new ReplaySubject(0); - this.log.debug(monitorOptions); - socket.on(WatchBlocksV1.Next, (data: IrohaBlockProgress) => { - subject.next(data); - }); - - socket.on("connect", () => { - this.log.debug("connected OK..."); - socket.emit(WatchBlocksV1.Subscribe, monitorOptions); - }); - - socket.connect(); - - socket.on("connect_error", (err: Error) => { - this.log.error("Error (connect_error): ", err); - socket.disconnect(); - subject.error(err); - }); - - socket.on("connect_timeout", (err: Record) => { - this.log.error("Error (connect_timeout): ", err); - socket.disconnect(); - subject.error(err); - }); - - socket.on("error", (err: unknown) => { - this.log.error("Error: ", err); - socket.disconnect(); - subject.error(err); - }); - - return subject.pipe( - finalize(() => { - this.log.info("FINALIZE - unsubscribing from the stream..."); - socket.emit(WatchBlocksV1.Unsubscribe); - socket.disconnect(); - }), - share(), - ); - } - - /** - * Immediately sends request to the validator, doesn't report any error or responses. - * @param args - arguments. - * @param method - function / method to be executed by validator. - * @param baseConfig - baseConfig needed to properly connect to ledger - - */ - public sendAsyncRequest( - method: Record, - args: any, - baseConfig?: IrohaBaseConfig, - ): void { - this.log.debug(`inside: sendAsyncRequest()`); - this.log.debug(`baseConfig=${baseConfig}`); - this.log.debug(`methodName=${method.methodName}`); - this.log.debug(`args=${args}`); - - if (!baseConfig) { - throw new RuntimeError("baseConfig object must exist and not be empty"); - } - - Checks.truthy(baseConfig.privKey, "privKey in baseConfig"); - Checks.truthy( - baseConfig.creatorAccountId, - "creatorAccountId in baseConfig", - ); - Checks.truthy(baseConfig.irohaHost, "irohaHost in baseConfig"); - Checks.truthy(baseConfig.irohaPort, "irohaPort in baseConfig"); - Checks.truthy(baseConfig.quorum, "quorum in baseConfig"); - Checks.nonBlankString(method.methodName, "methodName"); - - const socket: Socket = io(this.wsApiHost, { path: this.wsApiPath }); - const asyncRequestData = { - baseConfig: baseConfig, - methodName: method.methodName, - args: args, - }; - - this.log.debug("requestData:", asyncRequestData); - - try { - socket.emit(IrohaSocketIOTransactV1.SendAsyncRequest, asyncRequestData); - - // Connector should disconnect us after receiving this request. - // If he doesn't, disconnect after specified amount of time. - setTimeout( - () => { - if (socket.connected) { - socket.disconnect(); - } - }, - this.options.timeoutLimit ?? 10 * 1000, - ); - } catch (err) { - this.log.error("Exception in: sendAsyncRequest(): ", err); - throw err; - } - } - - /** - * Sends request to be executed on the ledger, watches and reports any error and the response from a ledger. - * @param args - arguments. - * @param method - function / method to be executed by validator. - * @param baseConfig - baseConfig needed to properly connect to ledger - * @returns Promise that will resolve with response from the ledger, or reject when error occurred. - */ - public sendSyncRequest( - method: Record, - args: any, - baseConfig?: IrohaBaseConfig, - ): Promise { - this.log.debug(`inside: sendSyncRequest()`); - this.log.debug(`baseConfig=${baseConfig}`); - this.log.debug(`method=${method}`); - this.log.debug(`args=${args}`); - - if (!baseConfig) { - throw new RuntimeError("baseConfig object must exist and not be empty"); - } - - Checks.truthy(baseConfig.privKey, "privKey in baseConfig"); - Checks.truthy( - baseConfig.creatorAccountId, - "creatorAccountId in baseConfig", - ); - Checks.truthy(baseConfig.irohaHost, "irohaHost in baseConfig"); - Checks.truthy(baseConfig.irohaPort, "irohaPort in baseConfig"); - Checks.truthy(baseConfig.quorum, "quorum in baseConfig"); - Checks.nonBlankString(method.methodName, "methodName"); - - const socket: Socket = io(this.wsApiHost, { path: this.wsApiPath }); - - let responseFlag = false; - - return new Promise((resolve, reject) => { - try { - socket.on("connect_error", (err: Error) => { - this.log.error("Error (connect_error): ", err); - socket.disconnect(); - reject(err); - }); - - socket.on("connect_timeout", (err: Record) => { - this.log.error("Error (connect_timeout): ", err); - socket.disconnect(); - reject(err); - }); - - socket.on("error", (err: unknown) => { - socket.disconnect(); - reject(err); - }); - - socket.on("response", (result: any) => { - responseFlag = true; - this.log.debug("#[recv]response, res:", result); - const resultObj = { - status: result.status, - data: result.txHash, - }; - this.log.debug("resultObj =", resultObj); - socket.disconnect(); - resolve(resultObj); - }); - - const syncRequestData = { - baseConfig: baseConfig, - methodName: method.methodName, - args: args, - }; - - this.log.debug("requestData:", syncRequestData); - - try { - socket.emit(IrohaSocketIOTransactV1.SendSyncRequest, syncRequestData); - } catch (err) { - this.log.error("Exception in: sendAsyncRequest(): ", err); - throw err; - } - - setTimeout(() => { - if (responseFlag === false) { - socket.disconnect(); - resolve({ status: 504 }); - } - }, this.options.timeoutLimit); - } catch (err) { - this.log.error("Exception in: sendSyncRequest(): ", err); - reject(err); - } - }); - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES deleted file mode 100644 index 53250c0269..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES +++ /dev/null @@ -1,5 +0,0 @@ -api.ts -base.ts -common.ts -configuration.ts -index.ts diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION deleted file mode 100644 index cd802a1ec4..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION +++ /dev/null @@ -1 +0,0 @@ -6.6.0 \ No newline at end of file diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/api.ts deleted file mode 100644 index 922e111083..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/api.ts +++ /dev/null @@ -1,1457 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/** - * Hyperledger Cactus Plugin - Connector Iroha - * Can perform basic tasks on a Iroha ledger - * - * The version of the OpenAPI document: v2.0.0-alpha.2 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -import type { Configuration } from './configuration'; -import type { AxiosPromise, AxiosInstance, AxiosRequestConfig } from 'axios'; -import globalAxios from 'axios'; -// Some imports not used depending on template conditions -// @ts-ignore -import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common'; -import type { RequestArgs } from './base'; -// @ts-ignore -import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError } from './base'; - -/** - * The list of arguments to pass in to the transaction request to Add Asset Quantity. - * @export - * @interface AddAssetQuantityRequestParameters - */ -export interface AddAssetQuantityRequestParameters { - /** - * - * @type {string} - * @memberof AddAssetQuantityRequestParameters - */ - 'assetId': string; - /** - * - * @type {number} - * @memberof AddAssetQuantityRequestParameters - */ - 'amount': number; -} -/** - * The list of arguments to pass in to the transaction request to Add Peer. - * @export - * @interface AddPeerRequestParameters - */ -export interface AddPeerRequestParameters { - /** - * - * @type {string} - * @memberof AddPeerRequestParameters - */ - 'address': string; - /** - * - * @type {string} - * @memberof AddPeerRequestParameters - */ - 'peerKey': string; - /** - * - * @type {string} - * @memberof AddPeerRequestParameters - */ - 'tlsCertificate'?: string; - /** - * - * @type {boolean} - * @memberof AddPeerRequestParameters - */ - 'syncingPeer'?: boolean; -} -/** - * The list of arguments to pass in to the transaction request to Add Signatory. - * @export - * @interface AddSignatoryRequestParameters - */ -export interface AddSignatoryRequestParameters { - /** - * - * @type {string} - * @memberof AddSignatoryRequestParameters - */ - 'accountId': string; - /** - * - * @type {string} - * @memberof AddSignatoryRequestParameters - */ - 'publicKey': string; -} -/** - * The list of arguments to pass in to the transaction request to Append Role. - * @export - * @interface AppendRoleRequestParameters - */ -export interface AppendRoleRequestParameters { - /** - * - * @type {string} - * @memberof AppendRoleRequestParameters - */ - 'accountId': string; - /** - * - * @type {string} - * @memberof AppendRoleRequestParameters - */ - 'roleName': string; -} -/** - * The list of arguments to pass in to the transaction request to Call Engine. - * @export - * @interface CallEngineRequestParameters - */ -export interface CallEngineRequestParameters { - /** - * - * @type {string} - * @memberof CallEngineRequestParameters - */ - 'caller': string; - /** - * - * @type {string} - * @memberof CallEngineRequestParameters - */ - 'callee': string; - /** - * - * @type {string} - * @memberof CallEngineRequestParameters - */ - 'input': string; -} -/** - * The list of arguments to pass in to the transaction request to Compare And Set Account Detail. - * @export - * @interface CompareAndSetAccountDetailRequestParameters - */ -export interface CompareAndSetAccountDetailRequestParameters { - /** - * - * @type {string} - * @memberof CompareAndSetAccountDetailRequestParameters - */ - 'accountId': string; - /** - * - * @type {string} - * @memberof CompareAndSetAccountDetailRequestParameters - */ - 'key': string; - /** - * - * @type {string} - * @memberof CompareAndSetAccountDetailRequestParameters - */ - 'value': string; - /** - * - * @type {string} - * @memberof CompareAndSetAccountDetailRequestParameters - */ - 'oldValue'?: string; - /** - * - * @type {boolean} - * @memberof CompareAndSetAccountDetailRequestParameters - */ - 'check_empty': boolean; -} -/** - * The list of arguments to pass in to the transaction request to Create Account. - * @export - * @interface CreateAccountRequestParameters - */ -export interface CreateAccountRequestParameters { - /** - * - * @type {string} - * @memberof CreateAccountRequestParameters - */ - 'accountName': string; - /** - * - * @type {string} - * @memberof CreateAccountRequestParameters - */ - 'domainId': string; - /** - * - * @type {string} - * @memberof CreateAccountRequestParameters - */ - 'publicKey': string; -} -/** - * The list of arguments to pass in to the transaction request to Create Asset. - * @export - * @interface CreateAssetRequestParameters - */ -export interface CreateAssetRequestParameters { - /** - * - * @type {string} - * @memberof CreateAssetRequestParameters - */ - 'assetName': string; - /** - * - * @type {string} - * @memberof CreateAssetRequestParameters - */ - 'domainId': string; - /** - * - * @type {number} - * @memberof CreateAssetRequestParameters - */ - 'precision': number; -} -/** - * The list of arguments to pass in to the transaction request to Create Domain. - * @export - * @interface CreateDomainRequestParameters - */ -export interface CreateDomainRequestParameters { - /** - * - * @type {string} - * @memberof CreateDomainRequestParameters - */ - 'domainId': string; - /** - * - * @type {string} - * @memberof CreateDomainRequestParameters - */ - 'defaultRole': string; -} -/** - * The list of arguments to pass in to the transaction request to Create Role. - * @export - * @interface CreateRoleRequestParameters - */ -export interface CreateRoleRequestParameters { - /** - * - * @type {string} - * @memberof CreateRoleRequestParameters - */ - 'roleName': string; - /** - * - * @type {Array} - * @memberof CreateRoleRequestParameters - */ - 'permissionsList': Array; -} -/** - * The list of arguments to pass in to the transaction request to Detach Role. - * @export - * @interface DetachRoleRequestParameters - */ -export interface DetachRoleRequestParameters { - /** - * - * @type {string} - * @memberof DetachRoleRequestParameters - */ - 'accountId': string; - /** - * - * @type {string} - * @memberof DetachRoleRequestParameters - */ - 'roleName': string; -} -/** - * - * @export - * @interface ErrorExceptionJsonResponseV1 - */ -export interface ErrorExceptionJsonResponseV1 { - /** - * - * @type {string} - * @memberof ErrorExceptionJsonResponseV1 - */ - 'message': string; - /** - * - * @type {string} - * @memberof ErrorExceptionJsonResponseV1 - */ - 'name'?: string; - /** - * - * @type {string} - * @memberof ErrorExceptionJsonResponseV1 - */ - 'error'?: string; - /** - * - * @type {string} - * @memberof ErrorExceptionJsonResponseV1 - */ - 'stack'?: string; - /** - * - * @type {string} - * @memberof ErrorExceptionJsonResponseV1 - */ - 'cause'?: string; -} -/** - * - * @export - * @interface ErrorExceptionResponseV1 - */ -export interface ErrorExceptionResponseV1 { - /** - * - * @type {string} - * @memberof ErrorExceptionResponseV1 - */ - 'message': string; - /** - * - * @type {string} - * @memberof ErrorExceptionResponseV1 - */ - 'error': string; -} -/** - * - * @export - * @interface GenerateTransactionRequestV1 - */ -export interface GenerateTransactionRequestV1 { - /** - * Iroha command name. - * @type {IrohaCommand} - * @memberof GenerateTransactionRequestV1 - */ - 'commandName': IrohaCommand; - /** - * Parameters for iroha command specified in commandName - * @type {object} - * @memberof GenerateTransactionRequestV1 - */ - 'commandParams': object; - /** - * Sender account id - * @type {string} - * @memberof GenerateTransactionRequestV1 - */ - 'creatorAccountId': string; - /** - * Requested transaction quorum - * @type {number} - * @memberof GenerateTransactionRequestV1 - */ - 'quorum'?: number; -} -/** - * The list of arguments to pass in to the transaction request to Get Account Asset Transactions. - * @export - * @interface GetAccountAssetTransactionsRequestParameters - */ -export interface GetAccountAssetTransactionsRequestParameters { - /** - * - * @type {string} - * @memberof GetAccountAssetTransactionsRequestParameters - */ - 'accountId': string; - /** - * - * @type {string} - * @memberof GetAccountAssetTransactionsRequestParameters - */ - 'assetId': string; - /** - * - * @type {number} - * @memberof GetAccountAssetTransactionsRequestParameters - */ - 'pageSize': number; - /** - * - * @type {string} - * @memberof GetAccountAssetTransactionsRequestParameters - */ - 'firstTxHash': string; -} -/** - * The list of arguments to pass in to the transaction request to Get Account Assets. - * @export - * @interface GetAccountAssetsRequestParameters - */ -export interface GetAccountAssetsRequestParameters { - /** - * - * @type {string} - * @memberof GetAccountAssetsRequestParameters - */ - 'accountId': string; - /** - * - * @type {number} - * @memberof GetAccountAssetsRequestParameters - */ - 'pageSize': number; - /** - * - * @type {string} - * @memberof GetAccountAssetsRequestParameters - */ - 'firstAssetId'?: string; -} -/** - * The list of arguments to pass in to the transaction request to Get Account Detail. - * @export - * @interface GetAccountDetailRequestParameters - */ -export interface GetAccountDetailRequestParameters { - /** - * - * @type {string} - * @memberof GetAccountDetailRequestParameters - */ - 'accountId'?: string; - /** - * - * @type {string} - * @memberof GetAccountDetailRequestParameters - */ - 'key'?: string; - /** - * - * @type {string} - * @memberof GetAccountDetailRequestParameters - */ - 'writer'?: string; - /** - * - * @type {number} - * @memberof GetAccountDetailRequestParameters - */ - 'pageSize': number; - /** - * - * @type {string} - * @memberof GetAccountDetailRequestParameters - */ - 'paginationKey': string; - /** - * - * @type {string} - * @memberof GetAccountDetailRequestParameters - */ - 'paginationWriter': string; -} -/** - * The list of arguments to pass in to the transaction request to Get Account. - * @export - * @interface GetAccountRequestParameters - */ -export interface GetAccountRequestParameters { - /** - * - * @type {string} - * @memberof GetAccountRequestParameters - */ - 'accountId': string; -} -/** - * The list of arguments to pass in to the transaction request to Get Account Transactions. - * @export - * @interface GetAccountTransactionsRequestParameters - */ -export interface GetAccountTransactionsRequestParameters { - /** - * - * @type {string} - * @memberof GetAccountTransactionsRequestParameters - */ - 'accountId': string; - /** - * - * @type {number} - * @memberof GetAccountTransactionsRequestParameters - */ - 'pageSize': number; - /** - * - * @type {string} - * @memberof GetAccountTransactionsRequestParameters - */ - 'firstTxHash': string; - /** - * - * @type {object} - * @memberof GetAccountTransactionsRequestParameters - */ - 'firstTxTime'?: object; - /** - * - * @type {object} - * @memberof GetAccountTransactionsRequestParameters - */ - 'lastTxTime'?: object; - /** - * - * @type {number} - * @memberof GetAccountTransactionsRequestParameters - */ - 'firstTxHeight'?: number; - /** - * - * @type {number} - * @memberof GetAccountTransactionsRequestParameters - */ - 'lastTxHeight'?: number; -} -/** - * The list of arguments to pass in to the transaction request to Get Asset Info. - * @export - * @interface GetAssetInfoRequestParameters - */ -export interface GetAssetInfoRequestParameters { - /** - * - * @type {string} - * @memberof GetAssetInfoRequestParameters - */ - 'assetId': string; -} -/** - * The list of arguments to pass in to the transaction request to Get Block. - * @export - * @interface GetBlockRequestParameters - */ -export interface GetBlockRequestParameters { - /** - * - * @type {number} - * @memberof GetBlockRequestParameters - */ - 'height': number; -} -/** - * The list of arguments to pass in to the transaction request to Get Engine Receipts. - * @export - * @interface GetEngineReceiptsRequestParameters - */ -export interface GetEngineReceiptsRequestParameters { - /** - * - * @type {string} - * @memberof GetEngineReceiptsRequestParameters - */ - 'txHash': string; -} -/** - * The list of arguments to pass in to the transaction request to Get Pending Transactions. - * @export - * @interface GetPendingTransactionsRequestParameters - */ -export interface GetPendingTransactionsRequestParameters { - /** - * - * @type {number} - * @memberof GetPendingTransactionsRequestParameters - */ - 'pageSize': number; - /** - * - * @type {string} - * @memberof GetPendingTransactionsRequestParameters - */ - 'firstTxHash'?: string; - /** - * - * @type {object} - * @memberof GetPendingTransactionsRequestParameters - */ - 'firstTxTime'?: object; - /** - * - * @type {object} - * @memberof GetPendingTransactionsRequestParameters - */ - 'lastTxTime'?: object; -} -/** - * The list of arguments to pass in to the transaction request to Get Role Permissions. - * @export - * @interface GetRolePermissionsRequestParameters - */ -export interface GetRolePermissionsRequestParameters { - /** - * - * @type {string} - * @memberof GetRolePermissionsRequestParameters - */ - 'roleId': string; -} -/** - * The list of arguments to pass in to the transaction request to Get Signatories. - * @export - * @interface GetSignatoriesRequestParameters - */ -export interface GetSignatoriesRequestParameters { - /** - * - * @type {string} - * @memberof GetSignatoriesRequestParameters - */ - 'accountId': string; -} -/** - * The list of arguments to pass in to the transaction request to Get Transactions. - * @export - * @interface GetTransactionsRequestParameters - */ -export interface GetTransactionsRequestParameters { - /** - * - * @type {Array} - * @memberof GetTransactionsRequestParameters - */ - 'txHashesList': Array; -} -/** - * The list of arguments to pass in to the transaction request to Grant Permission. - * @export - * @interface GrantPermissionRequestParameters - */ -export interface GrantPermissionRequestParameters { - /** - * - * @type {string} - * @memberof GrantPermissionRequestParameters - */ - 'accountId': string; - /** - * - * @type {string} - * @memberof GrantPermissionRequestParameters - */ - 'permission': string; -} -/** - * - * @export - * @interface IrohaBaseConfig - */ -export interface IrohaBaseConfig { - [key: string]: any; - - /** - * - * @type {string} - * @memberof IrohaBaseConfig - */ - 'irohaHost'?: string; - /** - * - * @type {number} - * @memberof IrohaBaseConfig - */ - 'irohaPort'?: number; - /** - * - * @type {string} - * @memberof IrohaBaseConfig - */ - 'creatorAccountId'?: string; - /** - * - * @type {Array} - * @memberof IrohaBaseConfig - */ - 'privKey'?: Array; - /** - * - * @type {number} - * @memberof IrohaBaseConfig - */ - 'quorum'?: number; - /** - * - * @type {number} - * @memberof IrohaBaseConfig - */ - 'timeoutLimit'?: number; - /** - * Can only be set to false for an insecure grpc connection. - * @type {boolean} - * @memberof IrohaBaseConfig - */ - 'tls'?: boolean; - /** - * Flag used for monitoring. It changes default beahviour of transaction wrapper so it return error to caller instead of throwing RuntimeError straight away. - * @type {boolean} - * @memberof IrohaBaseConfig - */ - 'monitorMode'?: boolean | null; -} -/** - * - * @export - * @interface IrohaBlockProgress - */ -export interface IrohaBlockProgress { - /** - * - * @type {IrohaBlockResponse} - * @memberof IrohaBlockProgress - */ - 'transactionReceipt': IrohaBlockResponse; -} -/** - * - * @export - * @interface IrohaBlockResponse - */ -export interface IrohaBlockResponse { - /** - * - * @type {IrohaBlockResponsePayload} - * @memberof IrohaBlockResponse - */ - 'payload': IrohaBlockResponsePayload; - /** - * - * @type {Array} - * @memberof IrohaBlockResponse - */ - 'signaturesList': Array; -} -/** - * - * @export - * @interface IrohaBlockResponsePayload - */ -export interface IrohaBlockResponsePayload { - /** - * - * @type {Array} - * @memberof IrohaBlockResponsePayload - */ - 'transactionsList': Array; - /** - * - * @type {number} - * @memberof IrohaBlockResponsePayload - */ - 'txNumber': number; - /** - * - * @type {number} - * @memberof IrohaBlockResponsePayload - */ - 'height': number; - /** - * - * @type {string} - * @memberof IrohaBlockResponsePayload - */ - 'prevBlockHash': string; - /** - * - * @type {number} - * @memberof IrohaBlockResponsePayload - */ - 'createdTime': number; - /** - * - * @type {Array} - * @memberof IrohaBlockResponsePayload - */ - 'rejectedTransactionsHashesList': Array; -} -/** - * - * @export - * @enum {string} - */ - -export const IrohaCommand = { - /** - * Make entity in the system, capable of sending transactions or queries, storing signatories, personal data and identifiers. - */ - CreateAccount: 'createAccount', - /** - * Set key-value information for a given account. - */ - SetAccountDetail: 'setAccountDetail', - /** - * Set the number of signatories required to confirm the identity of a user, who creates the transaction. - */ - SetAccountQuorum: 'setAccountQuorum', - /** - * Set key-value information for a given account if the old value matches the value passed. - */ - CompareAndSetAccountDetail: 'compareAndSetAccountDetail', - /** - * Create a new type of asset, unique in a domain. An asset is a countable representation of a commodity. - */ - CreateAsset: 'createAsset', - /** - * Increase the quantity of an asset on account of transaction creator. - */ - AddAssetQuantity: 'addAssetQuantity', - /** - * Decrease the number of assets on account of transaction creator. - */ - SubtractAssetQuantity: 'subtractAssetQuantity', - /** - * Share assets within the account in peer network: in the way that source account transfers assets to the target account. - */ - TransferAsset: 'transferAsset', - /** - * Make new domain in Iroha network, which is a group of accounts. - */ - CreateDomain: 'createDomain', - /** - * Create a new role in the system from the set of permissions. - */ - CreateRole: 'createRole', - /** - * Detach a role from the set of roles of an account. - */ - DetachRole: 'detachRole', - /** - * Promote an account to some created role in the system, where a role is a set of permissions account has to perform an action (command or query). - */ - AppendRole: 'appendRole', - /** - * Add an identifier to the account. Such identifier is a public key of another device or a public key of another user. - */ - AddSignatory: 'addSignatory', - /** - * Remove a public key, associated with an identity, from an account - */ - RemoveSignatory: 'removeSignatory', - /** - * Give another account rights to perform actions on the account of transaction sender (give someone right to do something with my account). - */ - GrantPermission: 'grantPermission', - /** - * Revoke or dismiss given granted permission from another account in the network. - */ - RevokePermission: 'revokePermission', - /** - * Write into ledger the fact of peer addition into the peer network. - */ - AddPeer: 'addPeer', - /** - * Write into ledger the fact of peer removal from the network. - */ - RemovePeer: 'removePeer', - /** - * This command is not available for use, it was added for backward compatibility with Iroha. - */ - SetSettingValue: 'setSettingValue', - /** - * This command is not availalbe for use because it is related to smart contract. - */ - CallEngine: 'callEngine' -} as const; - -export type IrohaCommand = typeof IrohaCommand[keyof typeof IrohaCommand]; - - -/** - * - * @export - * @enum {string} - */ - -export const IrohaQuery = { - /** - * To get the state of an account - */ - GetAccount: 'getAccount', - /** - * To get details of the account. - */ - GetAccountDetail: 'getAccountDetail', - /** - * To get information on the given asset (as for now - its precision). - */ - GetAssetInfo: 'getAssetInfo', - /** - * To get the state of all assets in an account (a balance). - */ - GetAccountAssets: 'getAccountAssets', - /** - * To retrieve information about transactions, based on their hashes. - */ - GetTransactions: 'getTransactions', - /** - * To retrieve a list of pending (not fully signed) multisignature transactions or batches of transactions issued by account of query creator. - */ - GetPendingTransactions: 'getPendingTransactions', - /** - * To retrieve a list of transactions per account. - */ - GetAccountTransactions: 'getAccountTransactions', - /** - * To retrieve all transactions associated with given account and asset. - */ - GetAccountAssetTransactions: 'getAccountAssetTransactions', - /** - * To get existing roles in the system. - */ - GetRoles: 'getRoles', - /** - * To get signatories, which act as an identity of the account. - */ - GetSignatories: 'getSignatories', - /** - * To get available permissions per role in the system. - */ - GetRolePermissions: 'getRolePermissions', - /** - * To get a specific block, using its height as an identifier. - */ - GetBlock: 'getBlock', - /** - * To retrieve a receipt of a CallEngine command. Allows to access the event log created during computations inside the EVM. - */ - GetEngineReceipts: 'getEngineReceipts', - /** - * To get new blocks as soon as they are committed, a user can invoke FetchCommits RPC call to Iroha network. - */ - FetchCommits: 'fetchCommits', - /** - * A query that returns a list of peers in Iroha network. - */ - GetPeers: 'getPeers' -} as const; - -export type IrohaQuery = typeof IrohaQuery[keyof typeof IrohaQuery]; - - -/** - * - * @export - * @enum {string} - */ - -export const IrohaSocketIOTransactV1 = { - SendAsyncRequest: 'org.hyperledger.cactus.api.async.iroha.IrohaSocketIOTransactV1.SendAsyncRequest', - SendSyncRequest: 'org.hyperledger.cactus.api.async.iroha.IrohaSocketIOTransactV1.SendSyncRequest' -} as const; - -export type IrohaSocketIOTransactV1 = typeof IrohaSocketIOTransactV1[keyof typeof IrohaSocketIOTransactV1]; - - -/** - * - * @export - * @interface KeyPair - */ -export interface KeyPair { - /** - * SHA-3 ed25519 public keys of length 64 are recommended. - * @type {string} - * @memberof KeyPair - */ - 'publicKey': string; - /** - * SHA-3 ed25519 private keys of length 64 are recommended. - * @type {string} - * @memberof KeyPair - */ - 'privateKey': string; -} -/** - * The list of arguments to pass in to the transaction request to Remove Peer. - * @export - * @interface RemovePeerRequestParameters - */ -export interface RemovePeerRequestParameters { - /** - * - * @type {string} - * @memberof RemovePeerRequestParameters - */ - 'publicKey': string; -} -/** - * The list of arguments to pass in to the transaction request to Remove Signatory. - * @export - * @interface RemoveSignatoryRequestParameters - */ -export interface RemoveSignatoryRequestParameters { - /** - * - * @type {string} - * @memberof RemoveSignatoryRequestParameters - */ - 'accountId': string; - /** - * - * @type {string} - * @memberof RemoveSignatoryRequestParameters - */ - 'publicKey': string; -} -/** - * The list of arguments to pass in to the transaction request to Revoke Permission. - * @export - * @interface RevokePermissionRequestParameters - */ -export interface RevokePermissionRequestParameters { - /** - * - * @type {string} - * @memberof RevokePermissionRequestParameters - */ - 'accountId': string; - /** - * - * @type {number} - * @memberof RevokePermissionRequestParameters - */ - 'permission': number; -} -/** - * - * @export - * @interface RunTransactionRequestV1 - */ -export interface RunTransactionRequestV1 { - /** - * - * @type {string} - * @memberof RunTransactionRequestV1 - */ - 'commandName': string; - /** - * - * @type {IrohaBaseConfig} - * @memberof RunTransactionRequestV1 - */ - 'baseConfig': IrohaBaseConfig; - /** - * - * @type {RunTransactionRequestV1Params} - * @memberof RunTransactionRequestV1 - */ - 'params': RunTransactionRequestV1Params; -} -/** - * @type RunTransactionRequestV1Body - * @export - */ -export type RunTransactionRequestV1Body = RunTransactionRequestV1 | RunTransactionSignedRequestV1; - -/** - * @type RunTransactionRequestV1Params - * @export - */ -export type RunTransactionRequestV1Params = AddAssetQuantityRequestParameters | AddPeerRequestParameters | AddSignatoryRequestParameters | AppendRoleRequestParameters | Array | CallEngineRequestParameters | CompareAndSetAccountDetailRequestParameters | CreateAccountRequestParameters | CreateAssetRequestParameters | CreateDomainRequestParameters | CreateRoleRequestParameters | DetachRoleRequestParameters | GetAccountAssetTransactionsRequestParameters | GetAccountAssetsRequestParameters | GetAccountDetailRequestParameters | GetAccountRequestParameters | GetAccountTransactionsRequestParameters | GetAssetInfoRequestParameters | GetBlockRequestParameters | GetEngineReceiptsRequestParameters | GetPendingTransactionsRequestParameters | GetRolePermissionsRequestParameters | GetSignatoriesRequestParameters | GetTransactionsRequestParameters | GrantPermissionRequestParameters | RemovePeerRequestParameters | RemoveSignatoryRequestParameters | RevokePermissionRequestParameters | SetAccountDetailRequestParameters | SetAccountQuorumRequestParameters | SubtractAssetQuantityRequestParameters | TransferAssetRequestParameters; - -/** - * - * @export - * @interface RunTransactionResponse - */ -export interface RunTransactionResponse { - /** - * - * @type {any} - * @memberof RunTransactionResponse - */ - 'transactionReceipt': any; -} -/** - * - * @export - * @interface RunTransactionSignedRequestV1 - */ -export interface RunTransactionSignedRequestV1 { - /** - * Signed transaction binary data received from generate-transaction endpoint. - * @type {string} - * @memberof RunTransactionSignedRequestV1 - */ - 'signedTransaction': string; - /** - * - * @type {IrohaBaseConfig} - * @memberof RunTransactionSignedRequestV1 - */ - 'baseConfig'?: IrohaBaseConfig; -} -/** - * The list of arguments to pass in to the transaction request to Set Account Detail. - * @export - * @interface SetAccountDetailRequestParameters - */ -export interface SetAccountDetailRequestParameters { - /** - * - * @type {string} - * @memberof SetAccountDetailRequestParameters - */ - 'accountId': string; - /** - * - * @type {string} - * @memberof SetAccountDetailRequestParameters - */ - 'key': string; - /** - * - * @type {string} - * @memberof SetAccountDetailRequestParameters - */ - 'value': string; -} -/** - * The list of arguments to pass in to the transaction request to Set Account Quorum. - * @export - * @interface SetAccountQuorumRequestParameters - */ -export interface SetAccountQuorumRequestParameters { - /** - * - * @type {string} - * @memberof SetAccountQuorumRequestParameters - */ - 'accountId': string; - /** - * - * @type {number} - * @memberof SetAccountQuorumRequestParameters - */ - 'quorum': number; -} -/** - * The list of arguments to pass in to the transaction request to Subtract Asset Quantity. - * @export - * @interface SubtractAssetQuantityRequestParameters - */ -export interface SubtractAssetQuantityRequestParameters { - /** - * - * @type {string} - * @memberof SubtractAssetQuantityRequestParameters - */ - 'assetId': string; - /** - * - * @type {number} - * @memberof SubtractAssetQuantityRequestParameters - */ - 'amount': number; -} -/** - * The list of arguments to pass in to the transaction request to Transfer Asset. - * @export - * @interface TransferAssetRequestParameters - */ -export interface TransferAssetRequestParameters { - /** - * - * @type {string} - * @memberof TransferAssetRequestParameters - */ - 'srcAccountId': string; - /** - * - * @type {string} - * @memberof TransferAssetRequestParameters - */ - 'destAccountId': string; - /** - * - * @type {string} - * @memberof TransferAssetRequestParameters - */ - 'assetId': string; - /** - * - * @type {string} - * @memberof TransferAssetRequestParameters - */ - 'description': string; - /** - * - * @type {number} - * @memberof TransferAssetRequestParameters - */ - 'amount': number; -} -/** - * - * @export - * @enum {string} - */ - -export const WatchBlocksV1 = { - Subscribe: 'org.hyperledger.cactus.api.async.iroha.WatchBlocksV1.Subscribe', - Next: 'org.hyperledger.cactus.api.async.iroha.WatchBlocksV1.Next', - Unsubscribe: 'org.hyperledger.cactus.api.async.iroha.WatchBlocksV1.Unsubscribe', - Error: 'org.hyperledger.cactus.api.async.iroha.WatchBlocksV1.Error', - Complete: 'org.hyperledger.cactus.api.async.iroha.WatchBlocksV1.Complete' -} as const; - -export type WatchBlocksV1 = typeof WatchBlocksV1[keyof typeof WatchBlocksV1]; - - - -/** - * DefaultApi - axios parameter creator - * @export - */ -export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) { - return { - /** - * - * @summary Generate transaction that can be signed locally. - * @param {GenerateTransactionRequestV1} [generateTransactionRequestV1] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - generateTransactionV1: async (generateTransactionRequestV1?: GenerateTransactionRequestV1, options: AxiosRequestConfig = {}): Promise => { - const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/generate-transaction`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - - - localVarHeaderParameter['Content-Type'] = 'application/json'; - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(generateTransactionRequestV1, localVarRequestOptions, configuration) - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @summary Get the Prometheus Metrics - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - getPrometheusMetricsV1: async (options: AxiosRequestConfig = {}): Promise => { - const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/get-prometheus-exporter-metrics`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @summary Executes a transaction on a Iroha ledger - * @param {RunTransactionRequestV1Body} [runTransactionRequestV1Body] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - runTransactionV1: async (runTransactionRequestV1Body?: RunTransactionRequestV1Body, options: AxiosRequestConfig = {}): Promise => { - const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/run-transaction`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - - - localVarHeaderParameter['Content-Type'] = 'application/json'; - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(runTransactionRequestV1Body, localVarRequestOptions, configuration) - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - } -}; - -/** - * DefaultApi - functional programming interface - * @export - */ -export const DefaultApiFp = function(configuration?: Configuration) { - const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration) - return { - /** - * - * @summary Generate transaction that can be signed locally. - * @param {GenerateTransactionRequestV1} [generateTransactionRequestV1] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async generateTransactionV1(generateTransactionRequestV1?: GenerateTransactionRequestV1, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.generateTransactionV1(generateTransactionRequestV1, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, - /** - * - * @summary Get the Prometheus Metrics - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async getPrometheusMetricsV1(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getPrometheusMetricsV1(options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, - /** - * - * @summary Executes a transaction on a Iroha ledger - * @param {RunTransactionRequestV1Body} [runTransactionRequestV1Body] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async runTransactionV1(runTransactionRequestV1Body?: RunTransactionRequestV1Body, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.runTransactionV1(runTransactionRequestV1Body, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, - } -}; - -/** - * DefaultApi - factory interface - * @export - */ -export const DefaultApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { - const localVarFp = DefaultApiFp(configuration) - return { - /** - * - * @summary Generate transaction that can be signed locally. - * @param {GenerateTransactionRequestV1} [generateTransactionRequestV1] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - generateTransactionV1(generateTransactionRequestV1?: GenerateTransactionRequestV1, options?: any): AxiosPromise { - return localVarFp.generateTransactionV1(generateTransactionRequestV1, options).then((request) => request(axios, basePath)); - }, - /** - * - * @summary Get the Prometheus Metrics - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - getPrometheusMetricsV1(options?: any): AxiosPromise { - return localVarFp.getPrometheusMetricsV1(options).then((request) => request(axios, basePath)); - }, - /** - * - * @summary Executes a transaction on a Iroha ledger - * @param {RunTransactionRequestV1Body} [runTransactionRequestV1Body] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - runTransactionV1(runTransactionRequestV1Body?: RunTransactionRequestV1Body, options?: any): AxiosPromise { - return localVarFp.runTransactionV1(runTransactionRequestV1Body, options).then((request) => request(axios, basePath)); - }, - }; -}; - -/** - * DefaultApi - object-oriented interface - * @export - * @class DefaultApi - * @extends {BaseAPI} - */ -export class DefaultApi extends BaseAPI { - /** - * - * @summary Generate transaction that can be signed locally. - * @param {GenerateTransactionRequestV1} [generateTransactionRequestV1] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof DefaultApi - */ - public generateTransactionV1(generateTransactionRequestV1?: GenerateTransactionRequestV1, options?: AxiosRequestConfig) { - return DefaultApiFp(this.configuration).generateTransactionV1(generateTransactionRequestV1, options).then((request) => request(this.axios, this.basePath)); - } - - /** - * - * @summary Get the Prometheus Metrics - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof DefaultApi - */ - public getPrometheusMetricsV1(options?: AxiosRequestConfig) { - return DefaultApiFp(this.configuration).getPrometheusMetricsV1(options).then((request) => request(this.axios, this.basePath)); - } - - /** - * - * @summary Executes a transaction on a Iroha ledger - * @param {RunTransactionRequestV1Body} [runTransactionRequestV1Body] - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof DefaultApi - */ - public runTransactionV1(runTransactionRequestV1Body?: RunTransactionRequestV1Body, options?: AxiosRequestConfig) { - return DefaultApiFp(this.configuration).runTransactionV1(runTransactionRequestV1Body, options).then((request) => request(this.axios, this.basePath)); - } -} - - diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/base.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/base.ts deleted file mode 100644 index cfd901f2d3..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/base.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/** - * Hyperledger Cactus Plugin - Connector Iroha - * Can perform basic tasks on a Iroha ledger - * - * The version of the OpenAPI document: v2.0.0-alpha.2 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -import type { Configuration } from './configuration'; -// Some imports not used depending on template conditions -// @ts-ignore -import type { AxiosPromise, AxiosInstance, AxiosRequestConfig } from 'axios'; -import globalAxios from 'axios'; - -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); - -/** - * - * @export - */ -export const COLLECTION_FORMATS = { - csv: ",", - ssv: " ", - tsv: "\t", - pipes: "|", -}; - -/** - * - * @export - * @interface RequestArgs - */ -export interface RequestArgs { - url: string; - options: AxiosRequestConfig; -} - -/** - * - * @export - * @class BaseAPI - */ -export class BaseAPI { - protected configuration: Configuration | undefined; - - constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { - if (configuration) { - this.configuration = configuration; - this.basePath = configuration.basePath || this.basePath; - } - } -}; - -/** - * - * @export - * @class RequiredError - * @extends {Error} - */ -export class RequiredError extends Error { - constructor(public field: string, msg?: string) { - super(msg); - this.name = "RequiredError" - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/common.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/common.ts deleted file mode 100644 index 1379bf4877..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/common.ts +++ /dev/null @@ -1,150 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/** - * Hyperledger Cactus Plugin - Connector Iroha - * Can perform basic tasks on a Iroha ledger - * - * The version of the OpenAPI document: v2.0.0-alpha.2 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -import type { Configuration } from "./configuration"; -import type { RequestArgs } from "./base"; -import type { AxiosInstance, AxiosResponse } from 'axios'; -import { RequiredError } from "./base"; - -/** - * - * @export - */ -export const DUMMY_BASE_URL = 'https://example.com' - -/** - * - * @throws {RequiredError} - * @export - */ -export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) { - if (paramValue === null || paramValue === undefined) { - throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`); - } -} - -/** - * - * @export - */ -export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) { - if (configuration && configuration.apiKey) { - const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? await configuration.apiKey(keyParamName) - : await configuration.apiKey; - object[keyParamName] = localVarApiKeyValue; - } -} - -/** - * - * @export - */ -export const setBasicAuthToObject = function (object: any, configuration?: Configuration) { - if (configuration && (configuration.username || configuration.password)) { - object["auth"] = { username: configuration.username, password: configuration.password }; - } -} - -/** - * - * @export - */ -export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) { - if (configuration && configuration.accessToken) { - const accessToken = typeof configuration.accessToken === 'function' - ? await configuration.accessToken() - : await configuration.accessToken; - object["Authorization"] = "Bearer " + accessToken; - } -} - -/** - * - * @export - */ -export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) { - if (configuration && configuration.accessToken) { - const localVarAccessTokenValue = typeof configuration.accessToken === 'function' - ? await configuration.accessToken(name, scopes) - : await configuration.accessToken; - object["Authorization"] = "Bearer " + localVarAccessTokenValue; - } -} - -function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void { - if (parameter == null) return; - if (typeof parameter === "object") { - if (Array.isArray(parameter)) { - (parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key)); - } - else { - Object.keys(parameter).forEach(currentKey => - setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== '' ? '.' : ''}${currentKey}`) - ); - } - } - else { - if (urlSearchParams.has(key)) { - urlSearchParams.append(key, parameter); - } - else { - urlSearchParams.set(key, parameter); - } - } -} - -/** - * - * @export - */ -export const setSearchParams = function (url: URL, ...objects: any[]) { - const searchParams = new URLSearchParams(url.search); - setFlattenedQueryParams(searchParams, objects); - url.search = searchParams.toString(); -} - -/** - * - * @export - */ -export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) { - const nonString = typeof value !== 'string'; - const needsSerialization = nonString && configuration && configuration.isJsonMime - ? configuration.isJsonMime(requestOptions.headers['Content-Type']) - : nonString; - return needsSerialization - ? JSON.stringify(value !== undefined ? value : {}) - : (value || ""); -} - -/** - * - * @export - */ -export const toPathString = function (url: URL) { - return url.pathname + url.search + url.hash -} - -/** - * - * @export - */ -export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) { - return >(axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { - const axiosRequestArgs = {...axiosArgs.options, url: (configuration?.basePath || basePath) + axiosArgs.url}; - return axios.request(axiosRequestArgs); - }; -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/configuration.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/configuration.ts deleted file mode 100644 index d19a116a9a..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/configuration.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/** - * Hyperledger Cactus Plugin - Connector Iroha - * Can perform basic tasks on a Iroha ledger - * - * The version of the OpenAPI document: v2.0.0-alpha.2 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -export interface ConfigurationParameters { - apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); - username?: string; - password?: string; - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); - basePath?: string; - baseOptions?: any; - formDataCtor?: new () => any; -} - -export class Configuration { - /** - * parameter for apiKey security - * @param name security name - * @memberof Configuration - */ - apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); - /** - * parameter for basic security - * - * @type {string} - * @memberof Configuration - */ - username?: string; - /** - * parameter for basic security - * - * @type {string} - * @memberof Configuration - */ - password?: string; - /** - * parameter for oauth2 security - * @param name security name - * @param scopes oauth2 scope - * @memberof Configuration - */ - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); - /** - * override base path - * - * @type {string} - * @memberof Configuration - */ - basePath?: string; - /** - * base options for axios calls - * - * @type {any} - * @memberof Configuration - */ - baseOptions?: any; - /** - * The FormData constructor that will be used to create multipart form data - * requests. You can inject this here so that execution environments that - * do not support the FormData class can still run the generated client. - * - * @type {new () => FormData} - */ - formDataCtor?: new () => any; - - constructor(param: ConfigurationParameters = {}) { - this.apiKey = param.apiKey; - this.username = param.username; - this.password = param.password; - this.accessToken = param.accessToken; - this.basePath = param.basePath; - this.baseOptions = param.baseOptions; - this.formDataCtor = param.formDataCtor; - } - - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/index.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/index.ts deleted file mode 100644 index bf6e9f96fd..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/generated/openapi/typescript-axios/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/** - * Hyperledger Cactus Plugin - Connector Iroha - * Can perform basic tasks on a Iroha ledger - * - * The version of the OpenAPI document: v2.0.0-alpha.2 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -export * from "./api"; -export * from "./configuration"; - diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/index.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/index.ts deleted file mode 100755 index 87cb558397..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./public-api"; diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/index.web.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/index.web.ts deleted file mode 100755 index bdf54028d2..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/index.web.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./generated/openapi/typescript-axios/index"; diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/iroha-sign-utils.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/iroha-sign-utils.ts deleted file mode 100644 index ba4c2ac084..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/iroha-sign-utils.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2020-2022 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * Signing utility functions for HL Iroha ledger. - */ - -import { txHelper } from "iroha-helpers"; -import { Transaction } from "iroha-helpers/lib/proto/transaction_pb"; - -/** - * Sign transaction binary received from `generateTransactionV1()` call. - * Can be signed by multiple Signatories (with multiple keys) or a single key. - * - * @param serializedTx Serialized transaction data. - * To convert binary response from connector into `Uint8Array` required by this function you can use: - * ``` - * const serializedTx = Uint8Array.from(Object.values(genTxResponse.data)); - * ``` - * @param privateKeys One or multiple keys to sign the transaction with. - * @returns Signed transaction data (`Uint8Array`) - */ -export function signIrohaTransaction( - serializedTx: Uint8Array, - privateKeys: string | string[], -): Uint8Array { - const unsignedTx = Transaction.deserializeBinary(serializedTx); - - if (typeof privateKeys === "string") { - privateKeys = [privateKeys]; - } - - const signedTx = privateKeys.reduce( - (tx, key) => txHelper.sign(tx, key), - unsignedTx, - ); - - return signedTx.serializeBinary(); -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/iroha-transaction-wrapper.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/iroha-transaction-wrapper.ts deleted file mode 100644 index 5737bf8b21..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/iroha-transaction-wrapper.ts +++ /dev/null @@ -1,763 +0,0 @@ -import { Checks, Logger } from "@hyperledger/cactus-common"; -import { - LoggerProvider, - LogLevelDesc, - Http405NotAllowedError, -} from "@hyperledger/cactus-common"; -import { - IrohaBaseConfig, - IrohaCommand, - IrohaQuery, - RunTransactionRequestV1, - RunTransactionResponse, -} from "./generated/openapi/typescript-axios"; - -import { RuntimeError } from "run-time-error-cjs"; -import * as grpc from "@grpc/grpc-js"; - -import { - GrantablePermission, - GrantablePermissionMap, -} from "iroha-helpers/lib/proto/primitive_pb"; - -import { CommandService_v1Client as CommandService } from "iroha-helpers/lib/proto/endpoint_grpc_pb"; -import { QueryService_v1Client as QueryService } from "iroha-helpers/lib/proto/endpoint_grpc_pb"; - -import commands from "iroha-helpers/lib/commands/index"; -import queries from "iroha-helpers/lib/queries"; - -export interface IIrohaTransactionWrapperOptions { - logLevel?: LogLevelDesc; -} - -export class IrohaTransactionWrapper { - private readonly log: Logger; - public static readonly CLASS_NAME = "IrohaTransactionWrapper"; - - public get className(): string { - return IrohaTransactionWrapper.CLASS_NAME; - } - - constructor(options: IIrohaTransactionWrapperOptions) { - const level = options.logLevel || "INFO"; - const label = this.className; - this.log = LoggerProvider.getOrCreate({ level, label }); - } - - /** - * Create instances of Iroha SDK CommandService and QueryService from input base config. - * - * @param baseConfig iroha configuration from request, must contain Iroha URL information. - * @returns {commandService, queryService} - */ - public static getIrohaServices(baseConfig: IrohaBaseConfig): { - commandService: CommandService; - queryService: QueryService; - } { - if (!baseConfig || !baseConfig.irohaHost || !baseConfig.irohaPort) { - throw new RuntimeError("Missing Iroha URL information."); - } - const irohaHostPort = `${baseConfig.irohaHost}:${baseConfig.irohaPort}`; - - let grpcCredentials; - if (baseConfig.tls) { - throw new RuntimeError("TLS option is not supported"); - } else { - grpcCredentials = grpc.credentials.createInsecure(); - } - - const commandService = new CommandService( - irohaHostPort, - //TODO:do something in the production environment - grpcCredentials, - ); - const queryService = new QueryService(irohaHostPort, grpcCredentials); - - return { commandService, queryService }; - } - - public async transact( - req: RunTransactionRequestV1, - ): Promise { - const { baseConfig } = req; - Checks.truthy(baseConfig, "baseConfig"); - Checks.truthy(baseConfig.privKey, "privKey in baseConfig"); - Checks.truthy( - baseConfig.creatorAccountId, - "creatorAccountId in baseConfig", - ); - Checks.truthy(baseConfig.quorum, "quorum in baseConfig"); - Checks.truthy(baseConfig.timeoutLimit, "timeoutLimit in baseConfig"); - - if (!baseConfig.privKey || !baseConfig.timeoutLimit) { - // narrow the types - throw new Error("Should never happen - Checks should catch this first"); - } - - const { commandService, queryService } = - IrohaTransactionWrapper.getIrohaServices(baseConfig); - - const commandOptions = { - privateKeys: baseConfig.privKey, //need an array of keys for command - creatorAccountId: baseConfig.creatorAccountId, - quorum: baseConfig.quorum, - commandService: commandService, - timeoutLimit: baseConfig.timeoutLimit, - }; - - const queryOptions = { - privateKey: baseConfig.privKey[0], //only need 1 key for query - creatorAccountId: baseConfig.creatorAccountId as string, - queryService: queryService, - timeoutLimit: baseConfig.timeoutLimit, - }; - - switch (req.commandName) { - case IrohaCommand.AddAssetQuantity: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - assetId: req.params[0], - amount: req.params[1], - }; - } else { - params = req.params; - } - const response = await commands.addAssetQuantity( - commandOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.AddPeer: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - address: req.params[0], - peerKey: req.params[1], - }; - } else { - params = req.params; - } - const response = await commands.addPeer(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.AddSignatory: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - publicKey: req.params[1], - }; - } else { - params = req.params; - } - const response = await commands.addSignatory(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.AppendRole: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - roleName: req.params[1], - }; - } else { - params = req.params; - } - const response = await commands.appendRole(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.CallEngine: { - try { - let params: any; - if (Array.isArray(req.params)) { - params = { - type: req.params[0], - caller: req.params[1], - callee: req.params[2], - input: req.params[3], - }; - } else { - params = req.params; - } - const response = await commands.callEngine(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.CreateAccount: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - accountName: req.params[0], - domainId: req.params[1], - publicKey: req.params[2], - }; - } else { - params = req.params; - } - const response = await commands.createAccount(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.CreateAsset: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - assetName: req.params[0], - domainId: req.params[1], - precision: req.params[2], - }; - } else { - params = req.params; - } - const response = await commands.createAsset(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.CreateDomain: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - domainId: req.params[0], - defaultRole: req.params[1], - }; - params.domainId = req.params[0]; - params.defaultRole = req.params[1]; - } else { - params = req.params; - } - const response = await commands.createDomain(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.CreateRole: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - roleName: req.params[0], - permissionsList: req.params[1], - }; - } else { - params = req.params; - } - const response = await commands.createRole(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.DetachRole: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - roleName: req.params[1], - }; - } else { - params = req.params; - } - const response = await commands.detachRole(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.GrantPermission: { - try { - let params; - type permission = keyof GrantablePermissionMap; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - permission: GrantablePermission[req.params[1] as permission], - }; - } else { - params = req.params; - if ("permission" in params) { - params["permission"] = - GrantablePermission[params["permission"] as permission]; - } - } - const response = await commands.grantPermission( - commandOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.RemovePeer: { - try { - let params: any; - if (Array.isArray(req.params)) { - params = { - publicKey: req.params[0], - }; - } else { - params = req.params; - } - const response = await commands.removePeer(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.RemoveSignatory: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - publicKey: req.params[1], - }; - } else { - params = req.params; - } - const response = await commands.removeSignatory( - commandOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.RevokePermission: { - try { - let params; - type permission = keyof GrantablePermissionMap; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - permission: GrantablePermission[req.params[1] as permission], - }; - } else { - params = req.params; - if ("permission" in params) { - params["permission"] = - GrantablePermission[params["permission"] as permission]; - } - } - const response = await commands.revokePermission( - commandOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.SetAccountDetail: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - key: req.params[1], - value: req.params[2], - }; - } else { - params = req.params; - } - const response = await commands.setAccountDetail( - commandOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.SetAccountQuorum: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - quorum: req.params[1], - }; - } else { - params = req.params; - } - const response = await commands.setAccountQuorum( - commandOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.SubtractAssetQuantity: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - assetId: req.params[0], - amount: req.params[1], - }; - } else { - params = req.params; - } - const response = await commands.subtractAssetQuantity( - commandOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.TransferAsset: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - srcAccountId: req.params[0], - destAccountId: req.params[1], - assetId: req.params[2], - description: req.params[3], - amount: req.params[4], - }; - } else { - params = req.params; - } - const response = await commands.transferAsset(commandOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.CompareAndSetAccountDetail: { - try { - let params: any; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - key: req.params[1], - value: req.params[2], - oldValue: req.params[3], - checkEmpty: req.params[4], - }; - } else { - params = req.params; - } - const response = await commands.compareAndSetAccountDetail( - commandOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaCommand.SetSettingValue: { - throw new Http405NotAllowedError("SetSettingValue is not supported."); - } - case IrohaQuery.GetEngineReceipts: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - txHash: req.params[0], - }; - } else { - params = req.params; - } - const response = await queries.getEngineReceipts( - queryOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetAccount: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - }; - } else { - params = req.params; - } - const queryRes = await queries.getAccount(queryOptions, params); - return { transactionReceipt: queryRes }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetBlock: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - height: req.params[0], - }; - } else { - params = req.params; - } - const response = await queries.getBlock(queryOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetSignatories: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - }; - } else { - params = req.params; - } - const queryRes = await queries.getSignatories(queryOptions, params); - return { transactionReceipt: queryRes }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetTransactions: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - txHashesList: req.params[0], - }; - } else { - params = req.params; - } - const response = await queries.getTransactions(queryOptions, params); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetPendingTransactions: { - try { - let params: any; - if (Array.isArray(req.params)) { - params = { - pageSize: req.params[0], - firstTxHash: req.params[1], - firstTxTime: req.params[2], - lastTxTime: req.params[3], - firstTxHeight: req.params[4], - lastTxHeight: req.params[5], - ordering: { - field: req.params[6], - direction: req.params[7], - }, - }; - } else { - params = req.params; - } - const response = await queries.getPendingTransactions( - queryOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetAccountTransactions: { - try { - let params: any; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - pageSize: req.params[1], - firstTxHash: req.params[2], - firstTxTime: req.params[3], - lastTxTime: req.params[4], - firstTxHeight: req.params[5], - lastTxHeight: req.params[6], - ordering: { - field: req.params[7], - direction: req.params[8], - }, - }; - } else { - params = req.params; - } - const response = await queries.getAccountTransactions( - queryOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetAccountAssetTransactions: { - try { - let params: any; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - assetId: req.params[1], - pageSize: req.params[2], - firstTxHash: req.params[3], - firstTxTime: req.params[4], - lastTxTime: req.params[5], - firstTxHeight: req.params[6], - lastTxHeight: req.params[7], - ordering: { - field: req.params[8], - direction: req.params[9], - }, - }; - } else { - params = req.params; - } - const response = await queries.getAccountAssetTransactions( - queryOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetAccountAssets: { - try { - let params: any; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - pageSize: req.params[1], - firstAssetId: req.params[2], - }; - } else { - params = req.params; - } - const queryRes = await queries.getAccountAssets(queryOptions, params); - return { transactionReceipt: queryRes }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetAccountDetail: { - try { - let params: any; - if (Array.isArray(req.params)) { - params = { - accountId: req.params[0], - key: req.params[1], - writer: req.params[2], - pageSize: req.params[3], - paginationKey: req.params[4], - paginationWriter: req.params[5], - }; - } else { - params = req.params; - } - const queryRes = await queries.getAccountDetail(queryOptions, params); - return { transactionReceipt: queryRes }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetAssetInfo: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - assetId: req.params[0], - }; - } else { - params = req.params; - } - const queryRes = await queries.getAssetInfo(queryOptions, params); - return { transactionReceipt: queryRes }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetRoles: { - try { - const response = await queries.getRoles(queryOptions); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetRolePermissions: { - try { - let params; - if (Array.isArray(req.params)) { - params = { - roleId: req.params[0], - }; - } else { - params = req.params; - } - const response = await queries.getRolePermissions( - queryOptions, - params, - ); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.GetPeers: { - try { - const response = await queries.getPeers(queryOptions); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - case IrohaQuery.FetchCommits: { - try { - const response = await queries.fetchCommits(queryOptions); - return { transactionReceipt: response }; - } catch (err) { - throw new RuntimeError(err as any); - } - } - default: { - throw new RuntimeError( - "command or query does not exist, or is not supported in current version", - ); - } - } - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/plugin-factory-ledger-connector.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/plugin-factory-ledger-connector.ts deleted file mode 100644 index 7734d3d514..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/plugin-factory-ledger-connector.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { - IPluginFactoryOptions, - PluginFactory, -} from "@hyperledger/cactus-core-api"; -import { - IPluginLedgerConnectorIrohaOptions, - PluginLedgerConnectorIroha, -} from "./plugin-ledger-connector-iroha"; - -export class PluginFactoryLedgerConnector extends PluginFactory< - PluginLedgerConnectorIroha, - IPluginLedgerConnectorIrohaOptions, - IPluginFactoryOptions -> { - async create( - pluginOptions: IPluginLedgerConnectorIrohaOptions, - ): Promise { - return new PluginLedgerConnectorIroha(pluginOptions); - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/plugin-ledger-connector-iroha.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/plugin-ledger-connector-iroha.ts deleted file mode 100644 index 3a60f6d9db..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/plugin-ledger-connector-iroha.ts +++ /dev/null @@ -1,370 +0,0 @@ -import { Transaction } from "iroha-helpers/lib/proto/transaction_pb"; -import { TxBuilder } from "iroha-helpers/lib/chain"; -import type { Server as SocketIoServer } from "socket.io"; -import type { Socket as SocketIoSocket } from "socket.io"; -import type { Express } from "express"; - -import { IrohaTransactionWrapper } from "./iroha-transaction-wrapper"; - -import OAS from "../json/openapi.json"; - -import { - ConsensusAlgorithmFamily, - IPluginLedgerConnector, - IWebServiceEndpoint, - IPluginWebService, - ICactusPlugin, - ICactusPluginOptions, -} from "@hyperledger/cactus-core-api"; - -import { - PluginRegistry, - consensusHasTransactionFinality, -} from "@hyperledger/cactus-core"; - -import { - Checks, - Logger, - LoggerProvider, - LogLevelDesc, -} from "@hyperledger/cactus-common"; - -import { RuntimeError } from "run-time-error-cjs"; - -import { - IrohaCommand, - RunTransactionRequestV1, - RunTransactionSignedRequestV1, - GenerateTransactionRequestV1, - RunTransactionResponse, - WatchBlocksV1, - IrohaSocketIOTransactV1, -} from "./generated/openapi/typescript-axios"; - -import { RunTransactionEndpoint } from "./web-services/run-transaction-endpoint"; -import { GenerateTransactionEndpoint } from "./web-services/generate-transaction-endpoint"; -import { PrometheusExporter } from "./prometheus-exporter/prometheus-exporter"; -import { IrohaSocketIOEndpoint } from "./web-services/iroha-socketio-endpoint"; -import { - GetPrometheusExporterMetricsEndpointV1, - IGetPrometheusExporterMetricsEndpointV1Options, -} from "./web-services/get-prometheus-exporter-metrics-endpoint-v1"; - -export const E_KEYCHAIN_NOT_FOUND = "cactus.connector.iroha.keychain_not_found"; - -export interface IPluginLedgerConnectorIrohaOptions - extends ICactusPluginOptions { - rpcToriiPortHost: string; //http host:port - rpcApiWsHost?: string; - pluginRegistry: PluginRegistry; - prometheusExporter?: PrometheusExporter; - logLevel?: LogLevelDesc; - instanceId: string; -} - -export class PluginLedgerConnectorIroha - implements - IPluginLedgerConnector< - never, - never, - RunTransactionSignedRequestV1 | RunTransactionRequestV1, - RunTransactionResponse - >, - ICactusPlugin, - IPluginWebService -{ - private readonly instanceId: string; - public prometheusExporter: PrometheusExporter; - private readonly log: Logger; - - private endpoints: IWebServiceEndpoint[] | undefined; - - public static readonly CLASS_NAME = "PluginLedgerConnectorIroha"; - - public get className(): string { - return PluginLedgerConnectorIroha.CLASS_NAME; - } - - constructor(public readonly options: IPluginLedgerConnectorIrohaOptions) { - const fnTag = `${this.className}#constructor()`; - Checks.truthy(options, `${fnTag} arg options`); - Checks.truthy( - options.rpcToriiPortHost, - `${fnTag} options.rpcToriiPortHost`, - ); - Checks.truthy(options.instanceId, `${fnTag} options.instanceId`); - - const level = this.options.logLevel || "INFO"; - const label = this.className; - this.log = LoggerProvider.getOrCreate({ level, label }); - - this.instanceId = options.instanceId; - this.prometheusExporter = - options.prometheusExporter || - new PrometheusExporter({ pollingIntervalInMin: 1 }); - Checks.truthy( - this.prometheusExporter, - `${fnTag} options.prometheusExporter`, - ); - this.prometheusExporter.startMetricsCollection(); - } - - public getOpenApiSpec(): unknown { - return OAS; - } - - deployContract(): Promise { - throw new RuntimeError("Method not implemented."); - } - - public getPrometheusExporter(): PrometheusExporter { - return this.prometheusExporter; - } - - public async getPrometheusExporterMetrics(): Promise { - const res: string = await this.prometheusExporter.getPrometheusMetrics(); - this.log.debug(`getPrometheusExporterMetrics() response: %o`, res); - return res; - } - - public getInstanceId(): string { - return this.instanceId; - } - - public async onPluginInit(): Promise { - return; - } - - public async shutdown(): Promise { - this.log.info(`Shutting down ${this.className}...`); - } - - async registerWebServices( - app: Express, - wsApi?: SocketIoServer, - ): Promise { - const { logLevel } = this.options; - const webServices = await this.getOrCreateWebServices(); - await Promise.all(webServices.map((ws) => ws.registerExpress(app))); - - if (wsApi) { - wsApi.on("connection", (socket: SocketIoSocket) => { - this.log.debug(`New Socket connected. ID=${socket.id}`); - const irohaSocketEndpoint = new IrohaSocketIOEndpoint({ - socket, - logLevel, - }); - let monitorFlag: boolean; - - socket.on(WatchBlocksV1.Subscribe, (monitorOptions: any) => { - this.log.debug(`Caught event: Subscribe`); - monitorFlag = true; - irohaSocketEndpoint.startMonitor(monitorOptions); - }); - - socket.on(WatchBlocksV1.Unsubscribe, () => { - this.log.debug(`Caught event: Unsubscribe`); - irohaSocketEndpoint.stopMonitor(); - }); - - socket.on( - IrohaSocketIOTransactV1.SendAsyncRequest, - (asyncRequestData: any) => { - this.log.debug(`Caught event: SendAsyncRequest`); - socket.disconnect(true); - irohaSocketEndpoint.sendRequest(asyncRequestData, true); - }, - ); - - socket.on( - IrohaSocketIOTransactV1.SendSyncRequest, - (syncRequestData: any) => { - this.log.debug(`Caught event: SendSyncRequest`); - irohaSocketEndpoint.sendRequest(syncRequestData, false); - }, - ); - - socket.on("disconnect", async (reason: string) => { - this.log.info( - `Session: ${socket.id} disconnected. Reason: ${reason}`, - ); - if (monitorFlag) { - irohaSocketEndpoint.stopMonitor(); - monitorFlag = false; - } - }); - }); - } - - return webServices; - } - - public async getOrCreateWebServices(): Promise { - if (Array.isArray(this.endpoints)) { - return this.endpoints; - } - const endpoints: IWebServiceEndpoint[] = []; - { - const endpoint = new RunTransactionEndpoint({ - connector: this, - logLevel: this.options.logLevel, - }); - endpoints.push(endpoint); - } - { - const opts: IGetPrometheusExporterMetricsEndpointV1Options = { - connector: this, - logLevel: this.options.logLevel, - }; - const endpoint = new GetPrometheusExporterMetricsEndpointV1(opts); - endpoints.push(endpoint); - } - { - const endpoint = new GenerateTransactionEndpoint({ - connector: this, - logLevel: this.options.logLevel, - }); - endpoints.push(endpoint); - } - - this.endpoints = endpoints; - return endpoints; - } - - public getPackageName(): string { - return `@hyperledger/cactus-plugin-ledger-connector-iroha`; - } - - public async getConsensusAlgorithmFamily(): Promise { - return ConsensusAlgorithmFamily.Authority; - } - public async hasTransactionFinality(): Promise { - const currentConsensusAlgorithmFamily = - await this.getConsensusAlgorithmFamily(); - - return consensusHasTransactionFinality(currentConsensusAlgorithmFamily); - } - - /** - * Create and run Iroha transaction based on input arguments. - * Transaction is signed with a private key supplied in the input argument. - * - * @param req `RunTransactionSignedRequestV1` - * @param commandService Iroha SDK `CommandService_v1Client` instance - * @param queryService Iroha SDK `QueryService_v1Client` instance - * @returns `Promise` - */ - private async transactRequest( - req: RunTransactionRequestV1, - ): Promise { - const transaction = new IrohaTransactionWrapper({ - logLevel: this.options.logLevel, - }); - return await transaction.transact(req); - } - - /** - * Run Iroha transaction based on already signed transaction received from the client. - * - * @param req RunTransactionSignedRequestV1 - * @returns `Promise` - */ - private async transactSigned( - req: RunTransactionSignedRequestV1, - ): Promise { - const fnTag = `${this.className}:transactSigned(RunTransactionSignedRequestV1)`; - if (!req.baseConfig || !req.baseConfig.timeoutLimit) { - throw new RuntimeError("baseConfig.timeoutLimit is undefined"); - } - - const { commandService } = IrohaTransactionWrapper.getIrohaServices( - req.baseConfig, - ); - - try { - const signedTxBuffer = Buffer.from(req.signedTransaction, "base64"); - const txBinary = Uint8Array.from(signedTxBuffer); - - const signedTransaction = Transaction.deserializeBinary(txBinary); - this.log.debug("Received signed transaction:", signedTransaction); - - const sendResponse = await new TxBuilder(signedTransaction).send( - commandService, - req.baseConfig.timeoutLimit, - ); - - return { transactionReceipt: sendResponse }; - } catch (ex) { - throw new RuntimeError(`${fnTag} crashed with: `, ex); - } - } - - /** - * Entry point for transact endpoint. - * Validate common `baseConfig` arguments and perapre command and query services. - * Call different transaction logic depending on input arguments. - * - * @note TLS connections are not supported yet. - * @param req `RunTransactionSignedRequestV1 | RunTransactionRequestV1` - * @returns `Promise` - */ - public async transact( - req: RunTransactionSignedRequestV1 | RunTransactionRequestV1, - ): Promise { - if ("signedTransaction" in req) { - return this.transactSigned(req); - } else { - const transaction = new IrohaTransactionWrapper({ - logLevel: this.options.logLevel, - }); - return await transaction.transact(req); - } - } - - /** - * Check if given Iroha command is supported and can be safely called on the `TxBuilder`. - * Command must be listend in OpenAPI interface and be present on the builder object. - * @param builder `TxBuilder` that will be used to call the command on. - * @param command Iroha command name in string format. - * @returns `true` if command is safe, `false` otherwise. - */ - private isSafeIrohaCommand(builder: TxBuilder, command: string): boolean { - // Check if command is listen in the OpenAPI interface - if (!Object.values(IrohaCommand).includes(command as IrohaCommand)) { - this.log.debug("Command not listed in OpenAPI interface"); - return false; - } - - // Check if function is present in builder object - return ( - command in builder && typeof (builder as any)[command] === "function" - ); - } - - /** - * Entry point for generate unsigned transaction endpoint. - * Transaction must be deserialized and signed on the client side. - * It can be then send to transact endpoint for futher processing. - * @param req `GenerateTransactionRequestV1` - * @returns `Uint8Array` of serialized transaction. - */ - public generateTransaction(req: GenerateTransactionRequestV1): Uint8Array { - req.quorum = req.quorum ?? 1; - const builder = new TxBuilder(); - - if (!this.isSafeIrohaCommand(builder, req.commandName)) { - throw new RuntimeError( - `Bad Request: Not supported Iroha command '${req.commandName}' - aborted.`, - ); - } - - try { - return (builder as any) - [req.commandName](req.commandParams) - .addMeta(req.creatorAccountId, req.quorum) - .tx.serializeBinary(); - } catch (error) { - throw new RuntimeError(error as any); - } - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/data-fetcher.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/data-fetcher.ts deleted file mode 100644 index fc752190f8..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/data-fetcher.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Transactions } from "./response.type"; - -import { totalTxCount, K_CACTUS_IROHA_TOTAL_TX_COUNT } from "./metrics"; - -export async function collectMetrics( - transactions: Transactions, -): Promise { - transactions.counter++; - totalTxCount.labels(K_CACTUS_IROHA_TOTAL_TX_COUNT).set(transactions.counter); -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/metrics.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/metrics.ts deleted file mode 100644 index 05f055d5ae..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/metrics.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Gauge } from "prom-client"; - -export const K_CACTUS_IROHA_TOTAL_TX_COUNT = "cactus_iroha_total_tx_count"; - -export const totalTxCount = new Gauge({ - registers: [], - name: "cactus_iroha_total_tx_count", - help: "Total transactions executed", - labelNames: ["type"], -}); diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/prometheus-exporter.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/prometheus-exporter.ts deleted file mode 100644 index c4d2db9bc1..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/prometheus-exporter.ts +++ /dev/null @@ -1,39 +0,0 @@ -import promClient, { Registry } from "prom-client"; -import { Transactions } from "./response.type"; -import { collectMetrics } from "./data-fetcher"; -import { K_CACTUS_IROHA_TOTAL_TX_COUNT } from "./metrics"; -import { totalTxCount } from "./metrics"; - -export interface IPrometheusExporterOptions { - pollingIntervalInMin?: number; -} - -export class PrometheusExporter { - public readonly metricsPollingIntervalInMin: number; - public readonly transactions: Transactions = { counter: 0 }; - public readonly registry: Registry; - - constructor( - public readonly prometheusExporterOptions: IPrometheusExporterOptions, - ) { - this.metricsPollingIntervalInMin = - prometheusExporterOptions.pollingIntervalInMin || 1; - this.registry = new Registry(); - } - - public addCurrentTransaction(): void { - collectMetrics(this.transactions); - } - - public async getPrometheusMetrics(): Promise { - const result = await this.registry.getSingleMetricAsString( - K_CACTUS_IROHA_TOTAL_TX_COUNT, - ); - return result; - } - - public startMetricsCollection(): void { - this.registry.registerMetric(totalTxCount); - promClient.collectDefaultMetrics({ register: this.registry }); - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/response.type.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/response.type.ts deleted file mode 100644 index 3f1bc7f491..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/prometheus-exporter/response.type.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type Transactions = { - counter: number; -}; diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/public-api.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/public-api.ts deleted file mode 100755 index a91a8d7697..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/public-api.ts +++ /dev/null @@ -1,25 +0,0 @@ -export { - E_KEYCHAIN_NOT_FOUND, - IPluginLedgerConnectorIrohaOptions, - PluginLedgerConnectorIroha, -} from "./plugin-ledger-connector-iroha"; - -export { signIrohaTransaction } from "./iroha-sign-utils"; - -export { PluginFactoryLedgerConnector } from "./plugin-factory-ledger-connector"; - -import { IPluginFactoryOptions } from "@hyperledger/cactus-core-api"; -import { PluginFactoryLedgerConnector } from "./plugin-factory-ledger-connector"; - -export { - IrohaApiClient, - IrohaApiClientOptions, -} from "./api-client/iroha-api-client"; - -export * from "./generated/openapi/typescript-axios/api"; - -export async function createPluginFactory( - pluginFactoryOptions: IPluginFactoryOptions, -): Promise { - return new PluginFactoryLedgerConnector(pluginFactoryOptions); -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/generate-transaction-endpoint.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/generate-transaction-endpoint.ts deleted file mode 100644 index 218d3f8871..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/generate-transaction-endpoint.ts +++ /dev/null @@ -1,134 +0,0 @@ -import type { Express, Request, Response } from "express"; -import safeStringify from "fast-safe-stringify"; -import sanitizeHtml from "sanitize-html"; - -import { - Logger, - Checks, - LogLevelDesc, - LoggerProvider, - IAsyncProvider, -} from "@hyperledger/cactus-common"; -import { - IEndpointAuthzOptions, - IExpressRequestHandler, - IWebServiceEndpoint, -} from "@hyperledger/cactus-core-api"; -import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; - -import { PluginLedgerConnectorIroha } from "../plugin-ledger-connector-iroha"; - -import OAS from "../../json/openapi.json"; - -export interface IGenerateTransactionEndpointOptions { - logLevel?: LogLevelDesc; - connector: PluginLedgerConnectorIroha; -} - -export class GenerateTransactionEndpoint implements IWebServiceEndpoint { - public static readonly CLASS_NAME = "GenerateTransactionEndpoint"; - - private readonly log: Logger; - - public get className(): string { - return GenerateTransactionEndpoint.CLASS_NAME; - } - - constructor(public readonly options: IGenerateTransactionEndpointOptions) { - const fnTag = `${this.className}#constructor()`; - Checks.truthy(options, `${fnTag} arg options`); - Checks.truthy(options.connector, `${fnTag} arg options.connector`); - - const level = this.options.logLevel || "INFO"; - const label = this.className; - this.log = LoggerProvider.getOrCreate({ level, label }); - } - - public getOasPath() { - return OAS.paths[ - "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/generate-transaction" - ]; - } - - public getPath(): string { - const apiPath = this.getOasPath(); - return apiPath.post["x-hyperledger-cacti"].http.path; - } - - public getVerbLowerCase(): string { - const apiPath = this.getOasPath(); - return apiPath.post["x-hyperledger-cacti"].http.verbLowerCase; - } - - public getOperationId(): string { - return this.getOasPath().post.operationId; - } - - getAuthorizationOptionsProvider(): IAsyncProvider { - // TODO: make this an injectable dependency in the constructor - return { - get: async () => ({ - isProtected: true, - requiredRoles: [], - }), - }; - } - - public async registerExpress( - expressApp: Express, - ): Promise { - await registerWebServiceEndpoint(expressApp, this); - return this; - } - - public getExpressRequestHandler(): IExpressRequestHandler { - return this.handleRequest.bind(this); - } - - public async handleRequest(req: Request, res: Response): Promise { - const reqTag = `${this.getVerbLowerCase()} - ${this.getPath()}`; - this.log.debug(reqTag); - - try { - const txBytesU8 = this.options.connector.generateTransaction(req.body); - const txBytesBuffer = Buffer.from(txBytesU8); - const txBytesBase64 = txBytesBuffer.toString("base64"); - res.send(txBytesBase64); - } catch (error) { - this.log.error(`Crash while serving ${reqTag}:`, error); - - if (error instanceof Error) { - let status = 500; - let message = "Internal Server Error"; - - if (error.message.includes("Bad Request")) { - status = 400; - message = "Bad Request Error"; - } - - this.log.info(`${message} [${status}]`); - res.status(status).json({ - message, - error: sanitizeHtml(error.stack || error.message, { - allowedTags: [], - allowedAttributes: {}, - }), - }); - } else { - this.log.warn("Unexpected exception that is not instance of Error!"); - res.status(500).json({ - message: "Unexpected Error", - error: sanitizeHtml(safeStringify(error), { - allowedTags: [], - allowedAttributes: {}, - }), - }); - } - } - } -} - -/** - * TODO - * Review main plugin (not done yet) - */ diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/get-prometheus-exporter-metrics-endpoint-v1.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/get-prometheus-exporter-metrics-endpoint-v1.ts deleted file mode 100644 index 209b8f7229..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/get-prometheus-exporter-metrics-endpoint-v1.ts +++ /dev/null @@ -1,96 +0,0 @@ -import type { Express, Request, Response } from "express"; - -import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; - -import OAS from "../../json/openapi.json"; - -import { - IWebServiceEndpoint, - IExpressRequestHandler, - IEndpointAuthzOptions, -} from "@hyperledger/cactus-core-api"; - -import { - LogLevelDesc, - Logger, - LoggerProvider, - Checks, - IAsyncProvider, -} from "@hyperledger/cactus-common"; - -import { PluginLedgerConnectorIroha } from "../plugin-ledger-connector-iroha"; - -export interface IGetPrometheusExporterMetricsEndpointV1Options { - connector: PluginLedgerConnectorIroha; - logLevel?: LogLevelDesc; -} - -export class GetPrometheusExporterMetricsEndpointV1 - implements IWebServiceEndpoint -{ - private readonly log: Logger; - - constructor( - public readonly options: IGetPrometheusExporterMetricsEndpointV1Options, - ) { - const fnTag = "GetPrometheusExporterMetricsEndpointV1#constructor()"; - - Checks.truthy(options, `${fnTag} options`); - Checks.truthy(options.connector, `${fnTag} options.connector`); - - const label = "get-prometheus-exporter-metrics-endpoint"; - const level = options.logLevel || "INFO"; - this.log = LoggerProvider.getOrCreate({ label, level }); - } - - getAuthorizationOptionsProvider(): IAsyncProvider { - // TODO: make this an injectable dependency in the constructor - return { - get: async () => ({ - isProtected: true, - requiredRoles: [], - }), - }; - } - - public getExpressRequestHandler(): IExpressRequestHandler { - return this.handleRequest.bind(this); - } - - getPath(): string { - return OAS.paths[ - "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/get-prometheus-exporter-metrics" - ].get["x-hyperledger-cacti"].http.path; - } - - getVerbLowerCase(): string { - return OAS.paths[ - "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/get-prometheus-exporter-metrics" - ].get["x-hyperledger-cacti"].http.verbLowerCase; - } - - public async registerExpress( - expressApp: Express, - ): Promise { - await registerWebServiceEndpoint(expressApp, this); - return this; - } - - async handleRequest(req: Request, res: Response): Promise { - const fnTag = "GetPrometheusExporterMetrics#handleRequest()"; - const verbUpper = this.getVerbLowerCase().toUpperCase(); - this.log.debug(`${verbUpper} ${this.getPath()}`); - - try { - const resBody = - await this.options.connector.getPrometheusExporterMetrics(); - res.status(200); - res.send(resBody); - } catch (ex) { - this.log.error(`${fnTag} failed to serve request`, ex); - res.status(500); - res.statusMessage = ex.message; - res.json({ error: ex.stack }); - } - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/iroha-socketio-endpoint.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/iroha-socketio-endpoint.ts deleted file mode 100644 index ba6c506163..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/iroha-socketio-endpoint.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { Socket as SocketIoSocket } from "socket.io"; - -import { Logger, Checks } from "@hyperledger/cactus-common"; -import { LogLevelDesc, LoggerProvider } from "@hyperledger/cactus-common"; -import { - RunTransactionRequestV1, - IrohaCommand, - IrohaBaseConfig, -} from "../generated/openapi/typescript-axios"; -import { - WatchBlocksV1, - IrohaQuery, -} from "../generated/openapi/typescript-axios"; - -import { - IrohaTransactionWrapper, - IIrohaTransactionWrapperOptions, -} from "../iroha-transaction-wrapper"; -export interface IIrohaSocketIOEndpoint { - logLevel?: LogLevelDesc; - socket: SocketIoSocket; -} - -export class IrohaSocketIOEndpoint { - public static readonly CLASS_NAME = "IrohaSocketIOEndpoint"; - - private readonly log: Logger; - private readonly socket: SocketIoSocket; - private transaction: IrohaTransactionWrapper; - private currentBlockHeight: number; - private monitorModeEnabled: boolean; - private monitoringInterval: any; - - public get className(): string { - return IrohaSocketIOEndpoint.CLASS_NAME; - } - - constructor(public readonly options: IIrohaSocketIOEndpoint) { - const fnTag = `${this.className}#constructor()`; - - Checks.truthy(options, `${fnTag} arg options`); - Checks.truthy(options.socket, `${fnTag} arg options.socket`); - - this.socket = options.socket; - - const level = this.options.logLevel || "INFO"; - const label = this.className; - this.log = LoggerProvider.getOrCreate({ level, label }); - - const irohaOptions: IIrohaTransactionWrapperOptions = { logLevel: level }; - this.transaction = new IrohaTransactionWrapper(irohaOptions); - this.currentBlockHeight = 1; - this.monitorModeEnabled = false; - } - - private createRequestBody( - config: IrohaBaseConfig, - methodName: string, - params: Array, - ): RunTransactionRequestV1 { - if (this.monitorModeEnabled === true) { - config.monitorModeEnabled = this.monitorModeEnabled; - } - const requestBody = { - commandName: methodName, - params: params, - baseConfig: config, - }; - return requestBody; - } - - private isLastBlockDetected(irohaResponse: unknown) { - const irohaResponseStr = JSON.stringify(irohaResponse).replace(/\\/g, ""); - const responseMatch = irohaResponseStr.match(/Reason: ({.*?})/); - if (!responseMatch || !responseMatch[1]) { - this.log.debug( - "Could not match error reason in response:", - irohaResponseStr, - ); - return false; - } - - const responseObject = JSON.parse(responseMatch[1]); - if (!responseObject) { - this.log.debug( - "Could not parse error object in response:", - irohaResponseStr, - ); - return false; - } - - if (responseObject.reason === 1 && responseObject.errorCode === 3) { - this.log.info(`Initial max block height is: ${this.currentBlockHeight}`); - return true; - } else { - throw responseObject; - } - } - - private async getInitialMaxBlockHeight(requestData: any): Promise { - this.log.debug("Checking max block height..."); - const methodName: string = IrohaQuery.GetBlock; - - let args: Array; - let requestBody: RunTransactionRequestV1; - - try { - while (true) { - args = [this.currentBlockHeight]; - - requestBody = this.createRequestBody(requestData, methodName, args); - this.log.debug(`Iroha requestBody: ${requestBody}`); - const response = await this.transaction.transact(requestBody); - if (this.isLastBlockDetected(response.transactionReceipt)) { - break; - } - this.currentBlockHeight++; - } - } catch (error) { - if (!this.isLastBlockDetected(error)) { - throw error; - } - } - } - - private async monitoringRoutine(baseConfig: any) { - try { - const args = [this.currentBlockHeight]; - const methodName: string = IrohaQuery.GetBlock; - this.log.debug(`Current block: ${this.currentBlockHeight}`); - - const requestBody = this.createRequestBody(baseConfig, methodName, args); - const response = await this.transaction.transact(requestBody); - - if (this.isLastBlockDetected(response.transactionReceipt)) { - this.log.debug("Waiting for new blocks..."); - } else { - this.log.debug(`New block found`); - const transactionReceipt = response.transactionReceipt; - const next = { transactionReceipt }; - this.socket.emit(WatchBlocksV1.Next, next); - this.currentBlockHeight++; - } - } catch (error) { - if (this.isLastBlockDetected(error)) { - this.log.debug("Waiting for new blocks..."); - } else { - throw error; - } - } - } - - public async startMonitor(monitorOptions: any): Promise { - this.log.debug(`${WatchBlocksV1.Subscribe} => ${this.socket.id}`); - this.log.info(`Starting monitoring blocks...`); - - this.monitorModeEnabled = true; - await this.getInitialMaxBlockHeight(monitorOptions.baseConfig); - - this.monitoringInterval = setInterval(() => { - this.monitoringRoutine(monitorOptions.baseConfig); - }, monitorOptions.pollTime); - } - - private async validateMethodName(methodName: string): Promise { - let isValidMethod = false; - - if (Object.values(IrohaQuery as any).includes(methodName)) { - this.log.debug(`Method name: ${methodName} (IrohaQuery) is valid`); - isValidMethod = true; - } - if (Object.values(IrohaCommand as any).includes(methodName)) { - this.log.debug(`Method name: ${methodName} (IrohaCommand) is valid`); - isValidMethod = true; - } - return isValidMethod; - } - - public async stopMonitor(): Promise { - this.log.info(`Stopping monitor...`); - this.monitorModeEnabled = false; - clearInterval(this.monitoringInterval); - } - - public async sendRequest(requestData: any, async: boolean) { - this.log.debug(`Inside ##sendRequest(), async = ${async}`); - this.log.debug(`requestData: ${JSON.stringify(requestData, null, 4)}`); - - this.log.debug(requestData.methodName); - this.log.debug(requestData.args); - this.log.debug(requestData.baseConfig); - - if ((await this.validateMethodName(requestData.methodName)) === true) { - const requestBody = this.createRequestBody( - requestData.baseConfig, - requestData.methodName, - requestData.args, - ); - - const response = await this.transaction.transact(requestBody); - this.log.debug(response); - if (async) { - return response; - } else { - try { - this.socket.emit("response", response.transactionReceipt); - } catch (err: unknown) { - this.socket.emit("error", err); - } - } - } else { - const error = `Unrecognized method name: ${requestData.methodName}`; - this.log.debug(error); - } - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/run-transaction-endpoint.ts b/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/run-transaction-endpoint.ts deleted file mode 100644 index 3de6059ebd..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/main/typescript/web-services/run-transaction-endpoint.ts +++ /dev/null @@ -1,119 +0,0 @@ -import type { Express, Request, Response } from "express"; - -import { - Logger, - Checks, - LogLevelDesc, - LoggerProvider, - IAsyncProvider, - Http405NotAllowedError, -} from "@hyperledger/cactus-common"; -import { - IEndpointAuthzOptions, - IExpressRequestHandler, - IWebServiceEndpoint, -} from "@hyperledger/cactus-core-api"; -import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; - -import { PluginLedgerConnectorIroha } from "../plugin-ledger-connector-iroha"; - -import OAS from "../../json/openapi.json"; - -export interface IRunTransactionEndpointOptions { - logLevel?: LogLevelDesc; - connector: PluginLedgerConnectorIroha; -} - -export class RunTransactionEndpoint implements IWebServiceEndpoint { - public static readonly CLASS_NAME = "RunTransactionEndpoint"; - - private readonly log: Logger; - - public get className(): string { - return RunTransactionEndpoint.CLASS_NAME; - } - - constructor(public readonly options: IRunTransactionEndpointOptions) { - const fnTag = `${this.className}#constructor()`; - Checks.truthy(options, `${fnTag} arg options`); - Checks.truthy(options.connector, `${fnTag} arg options.connector`); - - const level = this.options.logLevel || "INFO"; - const label = this.className; - this.log = LoggerProvider.getOrCreate({ level, label }); - } - - public getOasPath() { - return OAS.paths[ - "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha/run-transaction" - ]; - } - - public getPath(): string { - const apiPath = this.getOasPath(); - return apiPath.post["x-hyperledger-cacti"].http.path; - } - - public getVerbLowerCase(): string { - const apiPath = this.getOasPath(); - return apiPath.post["x-hyperledger-cacti"].http.verbLowerCase; - } - - public getOperationId(): string { - return this.getOasPath().post.operationId; - } - - getAuthorizationOptionsProvider(): IAsyncProvider { - // TODO: make this an injectable dependency in the constructor - return { - get: async () => ({ - isProtected: true, - requiredRoles: [], - }), - }; - } - - public async registerExpress( - expressApp: Express, - ): Promise { - await registerWebServiceEndpoint(expressApp, this); - return this; - } - - public getExpressRequestHandler(): IExpressRequestHandler { - return this.handleRequest.bind(this); - } - - public async handleRequest(req: Request, res: Response): Promise { - const reqTag = `${this.getVerbLowerCase()} - ${this.getPath()}`; - this.log.debug(reqTag); - const reqBody = req.body; - try { - const resBody = await this.options.connector.transact(reqBody); - res.json(resBody); - } catch (ex) { - if (ex instanceof Http405NotAllowedError) { - this.log.debug("Sending back HTTP405 Method Not Allowed error."); - res.status(405); - res.json(ex); - return; - } - /** - * An example output of the error message looks like: - * "Error: Error: Command response error: expected=COMMITTED, actual=REJECTED" - * @see https://iroha.readthedocs.io/en/main/develop/api/commands.html?highlight=CallEngine#id18 - */ - if (ex.message.includes("Error: Command response error")) { - this.log.debug("Sending back HTTP400 Bad Request error."); - res.status(400); - res.json(ex); - return; - } - this.log.error(`Crash while serving ${reqTag}`, ex); - res.status(500).json({ - message: "Internal Server Error", - error: ex?.stack || ex?.message, - }); - } - } -} diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/api-surface.test.ts b/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/api-surface.test.ts deleted file mode 100644 index 34aba3a0ae..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/api-surface.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import * as apiSurface from "../../../main/typescript/public-api"; -import "jest-extended"; - -test("Library can be loaded", async () => { - expect(apiSurface).toBeTruthy(); -}); diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/generate-and-send-signed-transaction.test.ts b/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/generate-and-send-signed-transaction.test.ts deleted file mode 100644 index 77c8041455..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/generate-and-send-signed-transaction.test.ts +++ /dev/null @@ -1,410 +0,0 @@ -/** - * Test sending transactions signed on the BLP (client) side. - * No private keys are shared with the connector in this scenario. - * Test suite contains simple sanity check of regular transaction call as well. - */ - -////////////////////////////////// -// Constants -////////////////////////////////// - -import { IROHA_TEST_LEDGER_DEFAULT_OPTIONS } from "@hyperledger/cactus-test-tooling"; - -// Ledger settings -const ledgerImageName = "ghcr.io/hyperledger/cactus-iroha-all-in-one"; -const ledgerImageVersion = IROHA_TEST_LEDGER_DEFAULT_OPTIONS.imageVersion; -const postgresImageName = "postgres"; -const postgresImageVersion = "9.5-alpine"; - -// Log settings -const testLogLevel: LogLevelDesc = "info"; // default: info -const sutLogLevel: LogLevelDesc = "info"; // default: info - -import { - PostgresTestContainer, - IrohaTestLedger, - pruneDockerAllIfGithubAction, -} from "@hyperledger/cactus-test-tooling"; - -import { - LogLevelDesc, - LoggerProvider, - Logger, - Servers, -} from "@hyperledger/cactus-common"; - -import { PluginRegistry } from "@hyperledger/cactus-core"; - -import { PluginImportType, Configuration } from "@hyperledger/cactus-core-api"; - -import http from "http"; -import express from "express"; -import bodyParser from "body-parser"; -import { AddressInfo } from "net"; -import { v4 as uuidv4 } from "uuid"; -import { v4 as internalIpV4 } from "internal-ip"; -import "jest-extended"; - -import cryptoHelper from "iroha-helpers/lib/cryptoHelper"; - -import { - PluginLedgerConnectorIroha, - DefaultApi as IrohaApi, - PluginFactoryLedgerConnector, - signIrohaTransaction, -} from "../../../main/typescript/public-api"; - -import { - IrohaCommand, - IrohaQuery, -} from "../../../main/typescript/generated/openapi/typescript-axios"; - -// Logger setup -const log: Logger = LoggerProvider.getOrCreate({ - label: "generate-and-send-signed-transaction.test", - level: testLogLevel, -}); - -/** - * Main test suite - */ -describe("Generate and send signed transaction tests", () => { - let postgresContainer: PostgresTestContainer; - let adminKeyPair: { - publicKey: string; - privateKey: string; - }; - let irohaLedger: IrohaTestLedger; - let irohaConnector: PluginLedgerConnectorIroha; - let irohaLedgerHost: string; - let irohaLedgerPort: number; - let irohaAdminID: string; - let connectorServer: http.Server; - let apiClient: IrohaApi; - - ////////////////////////////////// - // Environment Setup - ////////////////////////////////// - - beforeAll(async () => { - log.info("Prune Docker..."); - await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); - - log.info("Run PostgresTestContainer..."); - postgresContainer = new PostgresTestContainer({ - imageName: postgresImageName, - imageVersion: postgresImageVersion, - logLevel: testLogLevel, - }); - await postgresContainer.start(); - const postgresHost = (await internalIpV4()) as string; - const postgresPort = await postgresContainer.getPostgresPort(); - expect(postgresHost).toBeTruthy(); - expect(postgresPort).toBeTruthy(); - log.info(`Postgres running at ${postgresHost}:${postgresPort}`); - - log.info("Generate key pairs..."); - adminKeyPair = cryptoHelper.generateKeyPair(); - const nodeKeyPair = cryptoHelper.generateKeyPair(); - - log.info("Run IrohaTestLedger..."); - irohaLedger = new IrohaTestLedger({ - imageName: ledgerImageName, - imageVersion: ledgerImageVersion, - adminPriv: adminKeyPair.privateKey, - adminPub: adminKeyPair.publicKey, - nodePriv: nodeKeyPair.privateKey, - nodePub: nodeKeyPair.publicKey, - postgresHost: postgresHost, - postgresPort: postgresPort, - logLevel: testLogLevel, - }); - await irohaLedger.start(); - irohaLedgerHost = (await internalIpV4()) as string; - expect(irohaLedgerHost).toBeTruthy(); - irohaLedgerPort = await irohaLedger.getRpcToriiPort(); - expect(irohaLedgerPort).toBeTruthy(); - const rpcToriiPortHost = await irohaLedger.getRpcToriiPortHost(); - expect(rpcToriiPortHost).toBeTruthy(); - const admin = irohaLedger.getDefaultAdminAccount(); - expect(admin).toBeTruthy(); - const domain = irohaLedger.getDefaultDomain(); - expect(domain).toBeTruthy(); - irohaAdminID = `${admin}@${domain}`; - log.info( - "IrohaTestLedger RPC host:", - rpcToriiPortHost, - "irohaAdminID:", - irohaAdminID, - ); - - log.info("Create iroha connector..."); - const expressApp = express(); - expressApp.use(bodyParser.json({ limit: "250mb" })); - connectorServer = http.createServer(expressApp); - const listenOptions = { - hostname: "127.0.0.1", - port: 0, - server: connectorServer, - }; - const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; - const { address, port } = addressInfo; - - const factory = new PluginFactoryLedgerConnector({ - pluginImportType: PluginImportType.Local, - }); - - irohaConnector = await factory.create({ - rpcToriiPortHost, - instanceId: uuidv4(), - pluginRegistry: new PluginRegistry(), - logLevel: sutLogLevel, - }); - await irohaConnector.getOrCreateWebServices(); - await irohaConnector.registerWebServices(expressApp); - log.info(`Iroha connector is running at ${address}:${port}`); - - log.info("Create iroha ApiClient..."); - const apiHost = `http://${address}:${port}`; - const apiConfig = new Configuration({ basePath: apiHost }); - apiClient = new IrohaApi(apiConfig); - }); - - afterAll(async () => { - log.info("FINISHING THE TESTS"); - - if (connectorServer) { - log.info("Stop the iroha connector..."); - await Servers.shutdown(connectorServer); - } - - if (irohaLedger) { - log.info("Stop iroha ledger..."); - await irohaLedger.stop(); - } - - if (postgresContainer) { - log.info("Stop iroha postgres container..."); - await postgresContainer.stop(); - } - - log.info("Prune Docker..."); - await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); - }); - - ////////////////////////////////// - // Test Helpers - ////////////////////////////////// - - /** - * Read iroha account details and check if valid response was received. - * @param accountID account to fetch. - * @returns getAccount command response. - */ - async function getAccountInfo(accountID: string) { - log.debug("Get account info with ID", accountID); - - const getAccReq = { - commandName: IrohaQuery.GetAccount, - baseConfig: { - irohaHost: irohaLedgerHost, - irohaPort: irohaLedgerPort, - creatorAccountId: irohaAdminID, - privKey: [adminKeyPair.privateKey], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [accountID], - }; - - const getAccResponse = await apiClient.runTransactionV1(getAccReq); - expect(getAccResponse).toBeTruthy(); - expect(getAccResponse.data).toBeTruthy(); - expect(getAccResponse.status).toEqual(200); - - return getAccResponse; - } - - ////////////////////////////////// - // Tests - ////////////////////////////////// - - /** - * Check if creating an account with regular transaction works well. - * This test sends private key to the connector to sign the transaction, - * and then reads new account details to confirm it was created. - */ - test("Sanity check if regular create account transaction works", async () => { - const username = "usersanity" + uuidv4().substring(0, 5); - const defaultDomain = irohaLedger.getDefaultDomain(); - const userKeyPair = cryptoHelper.generateKeyPair(); - const userID = `${username}@${defaultDomain}`; - - // 1. Create - log.debug("Create user with ID", userID); - const createAccReq = { - commandName: IrohaCommand.CreateAccount, - baseConfig: { - irohaHost: irohaLedgerHost, - irohaPort: irohaLedgerPort, - creatorAccountId: irohaAdminID, - privKey: [adminKeyPair.privateKey], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [username, defaultDomain, userKeyPair.publicKey], - }; - const createAccResponse = await apiClient.runTransactionV1(createAccReq); - expect(createAccResponse).toBeTruthy(); - expect(createAccResponse.data).toBeTruthy(); - expect(createAccResponse.status).toEqual(200); - expect(createAccResponse.data.transactionReceipt.status[0]).toEqual( - "COMMITTED", - ); - - // 2. Confirm - const getAccResponse = await getAccountInfo(userID); - expect(getAccResponse.data.transactionReceipt).toEqual({ - accountId: userID, - domainId: defaultDomain, - quorum: 1, - jsonData: "{}", - }); - }); - - /** - * Create new account without sharing the private key with the connector. - * This test will first generate the unsigned transaction, use util function from connector package - * to sign the transaction, and finally send the signed transaction. - * Private key is not shared with the connector. - * New account details are read to confirm it was created and committed correctly. - */ - test("Sign transaction on the client (BLP) side", async () => { - const username = "user" + uuidv4().substring(0, 5); - const defaultDomain = irohaLedger.getDefaultDomain(); - const userKeyPair = cryptoHelper.generateKeyPair(); - const userID = `${username}@${defaultDomain}`; - - // Generate transaction - log.info("Call generateTransactionV1 to get unsigned transaction."); - const genTxResponse = await apiClient.generateTransactionV1({ - commandName: IrohaCommand.CreateAccount, - commandParams: { - accountName: username, - domainId: defaultDomain, - publicKey: userKeyPair.publicKey, - }, - creatorAccountId: irohaAdminID, - quorum: 1, - }); - expect(genTxResponse).toBeTruthy(); - expect(genTxResponse.data).toBeTruthy(); - expect(genTxResponse.status).toEqual(200); - - const genTxResponseDataBuffer = Buffer.from(genTxResponse.data, "base64"); - const unsignedTransaction = Uint8Array.from(genTxResponseDataBuffer); - expect(unsignedTransaction).toBeTruthy(); - log.info("Received unsigned transcation"); - log.debug("unsignedTransaction:", unsignedTransaction); - - // Sign - const signedTransaction = signIrohaTransaction( - unsignedTransaction, - adminKeyPair.privateKey, - ); - expect(signedTransaction).toBeTruthy(); - log.info("Transaction signed with local private key"); - log.debug("signedTx:", signedTransaction); - - const signedTxB64 = Buffer.from(signedTransaction).toString("base64"); - - // Send - const sendTransactionResponse = await apiClient.runTransactionV1({ - signedTransaction: signedTxB64, - baseConfig: { - irohaHost: irohaLedgerHost, - irohaPort: irohaLedgerPort, - timeoutLimit: 5000, - tls: false, - }, - }); - expect(sendTransactionResponse).toBeTruthy(); - expect(sendTransactionResponse.status).toEqual(200); - expect(sendTransactionResponse.data).toBeTruthy(); - expect(sendTransactionResponse.data.transactionReceipt).toBeTruthy(); - expect(sendTransactionResponse.data.transactionReceipt.txHash).toBeTruthy(); - expect(sendTransactionResponse.data.transactionReceipt.status[0]).toEqual( - "COMMITTED", - ); - - // 3. Confirm - const getAccResponse = await getAccountInfo(userID); - expect(getAccResponse.data.transactionReceipt).toEqual({ - accountId: userID, - domainId: defaultDomain, - quorum: 1, - jsonData: "{}", - }); - }); - - /** - * Check if exceptions thrown by generateTransactionV1 are properly serialized - * and sanitized, so that response message doesn't contain any malicious data. - */ - test("generateTransactionV1 error responses check", async () => { - const username = "user" + uuidv4().substring(0, 5); - const defaultDomain = irohaLedger.getDefaultDomain(); - const userKeyPair = cryptoHelper.generateKeyPair(); - - // Bad Request Error - try { - log.info( - "Call generateTransactionV1 with invalid command name - should fail.", - ); - await apiClient.generateTransactionV1({ - commandName: - "MaliciousError " as any, - commandParams: { - accountName: username, - domainId: defaultDomain, - publicKey: userKeyPair.publicKey, - }, - creatorAccountId: irohaAdminID, - quorum: 1, - }); - expect(true).toBeFalse(); // Should always fail - } catch (error: any) { - const errorResponse = error.response; - expect(errorResponse).toBeTruthy(); - expect(errorResponse.status).toEqual(400); - expect(errorResponse.data).toBeTruthy(); - expect(errorResponse.data.message).toBeTruthy(); - expect(errorResponse.data.error).toBeTruthy(); - // HTML should be escaped from the response message - expect(errorResponse.data.message).not.toContain(" { - await Containers.logDiagnostics({ logLevel }); -}); - -test("BEFORE " + testCase, async (t: Test) => { - const pruning = pruneDockerAllIfGithubAction({ logLevel }); - await t.doesNotReject(pruning, "Pruning didn't throw OK"); - t.end(); -}); - -// Flaky test, does not always work, fix it once we have time -test.skip(testCase, async (t: Test) => { - const postgres1 = new PostgresTestContainer({ logLevel }); - const postgres2 = new PostgresTestContainer({ logLevel }); - test.onFinish(async () => { - await postgres1.stop(); - await postgres2.stop(); - }); - - await postgres1.start(); - await postgres2.start(); - const postgresHost1 = await internalIpV4(); - const postgresPort1 = await postgres1.getPostgresPort(); - const postgresHost2 = await internalIpV4(); - const postgresPort2 = await postgres2.getPostgresPort(); - if (!postgresHost1 || !postgresHost2) { - throw new RuntimeError("Could not determine the internal IPV4 address."); - } - - //Start the 1st Iroha ledger with default priv/pub key pairs. - const iroha1 = new IrohaTestLedger({ - postgresHost: postgresHost1, - postgresPort: postgresPort1, - logLevel: logLevel, - }); - - //Start the 2nd Iroha ledger with randomly generated priv/pub key pairs. - const keyPairA: KeyPair = cryptoHelper.generateKeyPair(); - const adminPriv2 = keyPairA.privateKey; - const adminPub2 = keyPairA.publicKey; - const keyPairB: KeyPair = cryptoHelper.generateKeyPair(); - const nodePriv2 = keyPairB.privateKey; - const nodePub2 = keyPairB.publicKey; - const iroha2 = new IrohaTestLedger({ - adminPriv: adminPriv2, - adminPub: adminPub2, - nodePriv: nodePriv2, - nodePub: nodePub2, - postgresHost: postgresHost2, - postgresPort: postgresPort2, - logLevel: logLevel, - }); - - test.onFinish(async () => { - await iroha1.stop(); - await iroha2.stop(); - }); - await iroha1.start(); - await iroha2.start(); - const irohaHost1 = await internalIpV4(); - const irohaHost2 = await internalIpV4(); - if (!irohaHost1 || !irohaHost2) { - throw new RuntimeError("Could not determine the internal IPV4 address."); - } - const irohaPort1 = await iroha1.getRpcToriiPort(); - const rpcToriiPortHost1 = await iroha1.getRpcToriiPortHost(); - const irohaPort2 = await iroha2.getRpcToriiPort(); - const rpcToriiPortHost2 = await iroha2.getRpcToriiPortHost(); - - //Start 2 connectors for 2 Iroha ledgers. - const factory1 = new PluginFactoryLedgerConnector({ - pluginImportType: PluginImportType.Local, - }); - - const rpcApiWsHost1 = await iroha1.getRpcApiWsHost(); - const rpcApiWsHost2 = await iroha2.getRpcApiWsHost(); - - const connector1: PluginLedgerConnectorIroha = await factory1.create({ - rpcToriiPortHost: rpcToriiPortHost1, - instanceId: uuidv4(), - rpcApiWsHost: rpcApiWsHost1, - pluginRegistry: new PluginRegistry(), - }); - const factory2 = new PluginFactoryLedgerConnector({ - pluginImportType: PluginImportType.Local, - }); - - const connector2: PluginLedgerConnectorIroha = await factory2.create({ - rpcToriiPortHost: rpcToriiPortHost2, - rpcApiWsHost: rpcApiWsHost2, - instanceId: uuidv4(), - pluginRegistry: new PluginRegistry(), - }); - //register the 2 connectors with 2 express services - const expressApp1 = express(); - expressApp1.use(bodyParser.json({ limit: "250mb" })); - const server1 = http.createServer(expressApp1); - const listenOptions1: IListenOptions = { - hostname: "127.0.0.1", - port: 0, - server: server1, - }; - const addressInfo1 = (await Servers.listen(listenOptions1)) as AddressInfo; - test.onFinish(async () => await Servers.shutdown(server1)); - const apiHost1 = `http://${addressInfo1.address}:${addressInfo1.port}`; - const apiConfig1 = new Configuration({ basePath: apiHost1 }); - const apiClient1 = new IrohaApi(apiConfig1); - - const expressApp2 = express(); - expressApp2.use(bodyParser.json({ limit: "250mb" })); - const server2 = http.createServer(expressApp2); - const listenOptions2: IListenOptions = { - hostname: "127.0.0.1", - port: 0, - server: server2, - }; - const addressInfo2 = (await Servers.listen(listenOptions2)) as AddressInfo; - test.onFinish(async () => await Servers.shutdown(server2)); - const apiHost2 = `http://${addressInfo2.address}:${addressInfo2.port}`; - const apiConfig2 = new Configuration({ basePath: apiHost2 }); - const apiClient2 = new IrohaApi(apiConfig2); - - const wsApi1 = new SocketIoServer(server1, { - path: Constants.SocketIoConnectionPathV1, - }); - - const wsApi2 = new SocketIoServer(server2, { - path: Constants.SocketIoConnectionPathV1, - }); - - await connector1.getOrCreateWebServices(); - await connector1.registerWebServices(expressApp1, wsApi1); - await connector2.getOrCreateWebServices(); - await connector2.registerWebServices(expressApp2, wsApi2); - - const adminPriv1 = await iroha1.getGenesisAccountPrivKey(); - const admin1 = iroha1.getDefaultAdminAccount(); - const domain1 = iroha1.getDefaultDomain(); - const adminID1 = `${admin1}@${domain1}`; - const admin2 = iroha2.getDefaultAdminAccount(); - const domain2 = iroha2.getDefaultDomain(); - const adminID2 = `${admin2}@${domain2}`; - - //Setup: create coolcoin#test for Iroha1 - const asset = "coolcoin"; - const assetID1 = `${asset}#${domain1}`; - const assetID2 = `${asset}#${domain1}`; - { - const req = { - commandName: IrohaCommand.CreateAsset, - baseConfig: { - irohaHost: irohaHost1, - irohaPort: irohaPort1, - creatorAccountId: adminID1, - privKey: [adminPriv1], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [asset, domain1, 3], - }; - const res = await apiClient1.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - //Verify the generated priv/pub keys are equivalent to those pulled from the ledger. - { - const adminPriv2_ = await iroha2.getGenesisAccountPrivKey(); - const adminPub2_ = await iroha2.getGenesisAccountPubKey(); - const { publicKey, privateKey } = await iroha2.getNodeKeyPair(); - t.equal(adminPriv2, adminPriv2_); - t.equal(adminPub2, adminPub2_); - t.equal(nodePriv2, privateKey); - t.equal(nodePub2, publicKey); - } - - //Setup: create coolcoin#test for Iroha2 - { - const req = { - commandName: IrohaCommand.CreateAsset, - baseConfig: { - irohaHost: irohaHost2, - irohaPort: irohaPort2, - creatorAccountId: adminID2, - privKey: [adminPriv2], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [asset, domain2, 3], - }; - const res = await apiClient2.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - //Iroha1's admin is initialized with 100 (coolcoin#test). - { - const req = { - commandName: IrohaCommand.AddAssetQuantity, - baseConfig: { - irohaHost: irohaHost1, - irohaPort: irohaPort1, - creatorAccountId: adminID1, - privKey: [adminPriv1], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [assetID1, "100.000"], - }; - const res = await apiClient1.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - // Iroha1's admin transfers 30 (coolcoin#test) to Iroha2's admin. - // i.e., Iroha1's admin subtracts 30 (coolcoin#test). - { - const req = { - commandName: IrohaCommand.SubtractAssetQuantity, - baseConfig: { - irohaHost: irohaHost1, - irohaPort: irohaPort1, - creatorAccountId: adminID1, - privKey: [adminPriv1], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [assetID1, "30.000"], - }; - const res = await apiClient1.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - //i.e., Iroha2's admin adds 30 (coolcoin#test). - { - const req = { - commandName: IrohaCommand.AddAssetQuantity, - baseConfig: { - irohaHost: irohaHost2, - irohaPort: irohaPort2, - creatorAccountId: adminID2, - privKey: [adminPriv2], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [assetID2, "30.000"], - }; - const res = await apiClient2.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - //Verification: iroha1's admin has 70 (coolcoin#test). - { - const req = { - commandName: IrohaQuery.GetAccountAssets, - baseConfig: { - irohaHost: irohaHost1, - irohaPort: irohaPort1, - creatorAccountId: adminID1, - privKey: [adminPriv1], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID1, 10, assetID1], - }; - const res = await apiClient1.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, [ - { - assetId: assetID1, - accountId: adminID1, - balance: "70.000", - }, - ]); - } - //Verification: iroha2's admin has 30 (coolcoin#test). - { - const req = { - commandName: IrohaQuery.GetAccountAssets, - baseConfig: { - irohaHost: irohaHost2, - irohaPort: irohaPort2, - creatorAccountId: adminID2, - privKey: [adminPriv2], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID2, 10, assetID2], - }; - const res = await apiClient2.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, [ - { - assetId: assetID2, - accountId: adminID2, - balance: "30.000", - }, - ]); - } - - t.end(); -}); - -test("AFTER " + testCase, async (t: Test) => { - const pruning = pruneDockerAllIfGithubAction({ logLevel }); - await t.doesNotReject(pruning, "Pruning didn't throw OK"); - t.end(); -}); diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/iroha-socketio-endpoint.test.ts b/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/iroha-socketio-endpoint.test.ts deleted file mode 100644 index adc9fcd209..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/iroha-socketio-endpoint.test.ts +++ /dev/null @@ -1,469 +0,0 @@ -import "jest-extended"; -import http from "http"; -import { AddressInfo } from "net"; -import KeyEncoder from "key-encoder"; -import { v4 as internalIpV4 } from "internal-ip"; -import { v4 as uuidv4 } from "uuid"; -import { RuntimeError } from "run-time-error-cjs"; -import cryptoHelper from "iroha-helpers/lib/cryptoHelper"; -import express from "express"; -import bodyParser from "body-parser"; -import { Server as SocketIoServer } from "socket.io"; - -import { PluginRegistry } from "@hyperledger/cactus-core"; - -import { PluginKeychainMemory } from "@hyperledger/cactus-plugin-keychain-memory"; -import { - IListenOptions, - KeyFormat, - Logger, - LoggerProvider, - LogLevelDesc, - Secp256k1Keys, - Servers, -} from "@hyperledger/cactus-common"; - -import { - IrohaTestLedger, - PostgresTestContainer, - pruneDockerAllIfGithubAction, -} from "@hyperledger/cactus-test-tooling"; - -import { - IrohaBlockProgress, - IrohaBlockResponse, - IrohaCommand, - KeyPair, -} from "../../../main/typescript/generated/openapi/typescript-axios"; - -import { - IPluginLedgerConnectorIrohaOptions, - IrohaApiClient, - IrohaApiClientOptions, - PluginFactoryLedgerConnector, -} from "../../../main/typescript"; - -import { Constants, PluginImportType } from "@hyperledger/cactus-core-api"; - -const logLevel: LogLevelDesc = "info"; - -const requestTimoutLimit = 10 * 1000; // 10 seconds - -const log: Logger = LoggerProvider.getOrCreate({ - label: "iroha-socketio-endpoint.test", - level: logLevel, -}); - -type IrohaLedgerInfo = { - testLedger: IrohaTestLedger; - host: string; - adminPriv: string; - adminAccount: string; - port: number; - domain: string; -}; - -type PostgresContainerInfo = { - container: PostgresTestContainer; - host: string; - port: number; -}; - -async function setupPostgres(): Promise { - const postgresTestContainer = new PostgresTestContainer({ logLevel }); - - await postgresTestContainer.start(); - - const postgresHost = await internalIpV4(); - const postgresPort = await postgresTestContainer.getPostgresPort(); - - if (!postgresHost) { - throw new RuntimeError("Could not determine the internal IPV4 address."); - } else { - return { - container: postgresTestContainer, - host: postgresHost, - port: postgresPort, - }; - } -} - -async function setupIrohaTestLedger(postgres: any): Promise { - const keyPair1: KeyPair = cryptoHelper.generateKeyPair(); - const adminPriv = keyPair1.privateKey; - const adminPubA = keyPair1.publicKey; - - const keyPair2: KeyPair = cryptoHelper.generateKeyPair(); - const nodePrivA = keyPair2.privateKey; - const nodePubA = keyPair2.publicKey; - - const iroha = new IrohaTestLedger({ - adminPriv: adminPriv, - adminPub: adminPubA, - nodePriv: nodePrivA, - nodePub: nodePubA, - postgresHost: postgres.host, - // postgresHost: "172.17.0.1", for docker - postgresPort: postgres.port, - logLevel: logLevel, - rpcApiWsPort: 50051, - }); - - log.debug("Starting Iroha test ledger"); - await iroha.start(); - - const adminAccount = iroha.getDefaultAdminAccount(); - const irohaHost = await internalIpV4(); - const irohaPort = await iroha.getRpcToriiPort(); - const domain = iroha.getDefaultDomain(); - - if (!irohaHost) { - throw new RuntimeError("Could not determine the internal IPV4 address."); - } else { - return { - testLedger: iroha, - host: irohaHost, - adminPriv: adminPriv, - adminAccount: adminAccount, - port: irohaPort, - domain: domain, - }; - } -} - -async function createPluginRegistry(): Promise { - const keyEncoder: KeyEncoder = new KeyEncoder("secp256k1"); - const keychainRef = uuidv4(); - const keychainId = uuidv4(); - - const { privateKey } = Secp256k1Keys.generateKeyPairsBuffer(); - const keyHex = privateKey.toString("hex"); - const pem = keyEncoder.encodePrivate(keyHex, KeyFormat.Raw, KeyFormat.PEM); - - const keychain = new PluginKeychainMemory({ - backend: new Map([[keychainRef, pem]]), - keychainId, - logLevel, - instanceId: uuidv4(), - }); - - log.debug("Instantiating plugin registry"); - const pluginRegistry = new PluginRegistry({ plugins: [keychain] }); - - return pluginRegistry; -} - -describe("Iroha SocketIo TestSuite", () => { - let postgres: PostgresContainerInfo; - let iroha: IrohaLedgerInfo; - let apiClient: IrohaApiClient; - let server: http.Server; - let wsApi: SocketIoServer; - - beforeAll(async () => { - const pruning = await pruneDockerAllIfGithubAction({ logLevel }); - expect(pruning).toBeTruthy(); - }); - - test("Prepare Iroha test ledger and Postgres Container", async () => { - log.debug("Setting up Postgres"); - postgres = await setupPostgres(); - - log.debug("Setting up Iroha test ledger"); - iroha = await setupIrohaTestLedger(postgres); - - expect(iroha).not.toBe(undefined); - expect(postgres).not.toBe(undefined); - }); - - test("Prepare API client", async () => { - const rpcApiHttpHost = await iroha.testLedger.getRpcToriiPortHost(); - const rpcApiWsHost = await iroha.testLedger.getRpcApiWsHost(); - - log.debug("Instantiating plugin registry"); - const pluginRegistry = await createPluginRegistry(); - - log.debug("Creating API server object"); - const options: IPluginLedgerConnectorIrohaOptions = { - rpcToriiPortHost: rpcApiHttpHost, - rpcApiWsHost: rpcApiWsHost, - pluginRegistry: pluginRegistry, - logLevel: logLevel, - instanceId: uuidv4(), - }; - - const factory = new PluginFactoryLedgerConnector({ - pluginImportType: PluginImportType.Local, - }); - - const connector = await factory.create(options); - - const expressApp = express(); - expressApp.use(bodyParser.json({ limit: "250mb" })); - server = http.createServer(expressApp); - - wsApi = new SocketIoServer(server, { - path: Constants.SocketIoConnectionPathV1, - }); - - const listenOptions: IListenOptions = { - hostname: "127.0.0.1", - port: 0, - server, - }; - - const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; - const { address, port } = addressInfo; - const apiHost = `http://${address}:${port}`; - - const wsBasePath = apiHost + Constants.SocketIoConnectionPathV1; - log.info(`ws base path: ${wsBasePath}`); - - const irohaApiClientOptions = new IrohaApiClientOptions({ - basePath: apiHost, - timeoutLimit: requestTimoutLimit, - }); - apiClient = new IrohaApiClient(irohaApiClientOptions); - - await connector.getOrCreateWebServices(); - await connector.registerWebServices(expressApp, wsApi); - - expect(apiClient).not.toBe(undefined); - }); - - async function testBlock(block: IrohaBlockResponse): Promise { - log.debug("Testing given block..."); - let blockOk = true; - - const topLevelProperties = ["payload", "signaturesList"]; - - const payloadProperties = [ - "transactionsList", - "txNumber", - "height", - "prevBlockHash", - "createdTime", - "rejectedTransactionsHashesList", - ]; - - for (let iter = 0; iter < topLevelProperties.length; iter++) { - if ( - !Object.prototype.hasOwnProperty.call(block, topLevelProperties[iter]) - ) { - log.error( - `Tested block is missing property: ${topLevelProperties[iter]}`, - ); - blockOk = false; - } - if ( - block[topLevelProperties[iter] as keyof IrohaBlockResponse] === - undefined - ) { - log.error( - `Property ${topLevelProperties[iter]} is undefined: ${topLevelProperties[iter]}`, - ); - blockOk = false; - } - } - - for (let iter = 0; iter < payloadProperties.length; iter++) { - if ( - !Object.prototype.hasOwnProperty.call( - block.payload, - payloadProperties[iter], - ) - ) { - log.error( - `Payload in tested block is missing property: ${payloadProperties[iter]}`, - ); - blockOk = false; - } - } - log.debug(`Tested block is: ${blockOk ? "ok" : "not ok"}`); - return blockOk; - } - - async function createSampleAsset(assetID: string) { - // Create asset on ledger to create new block - const assetId = assetID; - - const createAssetRequest = { - commandName: IrohaCommand.CreateAsset, - baseConfig: { - irohaHost: iroha.host, - irohaPort: iroha.port, - creatorAccountId: `${iroha.adminAccount}@${iroha.domain}`, - privKey: [iroha.adminPriv], - quorum: 1, - timeoutLimit: requestTimoutLimit, - tls: false, - }, - params: [assetId, iroha.domain, 3], - }; - await apiClient.runTransactionV1(createAssetRequest); - } - - test("Monitoring", async () => { - const monitoringOptions = { - baseConfig: { - irohaHost: iroha.host, - irohaPort: iroha.port, - creatorAccountId: `${iroha.adminAccount}@${iroha.domain}`, - privKey: [iroha.adminPriv], - quorum: 1, - timeoutLimit: requestTimoutLimit, - }, - pollTime: 5000, - }; - - // Start monitoring - const blocks = apiClient.watchBlocksV1(monitoringOptions); - - // Make sample action on ledger - await createSampleAsset("coolcoin"); - - // Check for arrival of new block - const arrivedBlock = await new Promise( - (resolve, reject) => { - let done = false; - const timerId = setTimeout(() => { - if (!done) { - reject("Waiting for block notification to arrive timed out"); - } - }, 30000); - - const subscription = blocks.subscribe((res: IrohaBlockProgress) => { - subscription.unsubscribe(); - done = true; - clearTimeout(timerId); - resolve(res.transactionReceipt); - }); - }, - ); - - expect(arrivedBlock).not.toBe(undefined); - log.debug(`Block arrived: ${JSON.stringify(arrivedBlock, null, 4)}`); - - // Checking block structure - expect( - Object.prototype.hasOwnProperty.call(arrivedBlock, "payload"), - ).toBeTrue(); - expect(await testBlock(arrivedBlock)).toBeTrue(); - - log.debug("Monitoring successfully completed"); - }); - - test("Async Request", async () => { - // Start monitoring to catch block created in async request - // const blocks = apiClient.watchBlocksV1(requestData); - - const monitoringRequestData = { - baseConfig: { - irohaHost: iroha.host, - irohaPort: iroha.port, - creatorAccountId: `${iroha.adminAccount}@${iroha.domain}`, - privKey: [iroha.adminPriv], - quorum: 1, - timeoutLimit: requestTimoutLimit, - }, - pollTime: 3000, - }; - - const blocks = apiClient.watchBlocksV1(monitoringRequestData); - - // Create new asset to check if request was successfull - const assetID = "eth"; - const commandName = { methodName: IrohaCommand.CreateAsset }; - const baseConfig = { - irohaHost: iroha.host, - irohaPort: iroha.port, - creatorAccountId: `${iroha.adminAccount}@${iroha.domain}`, - privKey: [iroha.adminPriv], - quorum: 1, - timeoutLimit: requestTimoutLimit, - }; - const params = [assetID, iroha.domain, 3]; - - log.debug(`Sending Async Request with ${commandName} command.`); - apiClient.sendAsyncRequest(commandName, params, baseConfig); - - const arrivedBlock = await new Promise( - (resolve, reject) => { - let done = false; - const timerId = setTimeout(() => { - if (!done) { - reject("Waiting for block notification to arrive timed out"); - } - }, 30000); - - const subscription = blocks.subscribe((res: IrohaBlockProgress) => { - subscription.unsubscribe(); - done = true; - clearTimeout(timerId); - resolve(res.transactionReceipt); - }); - }, - ); - - expect(await testBlock(arrivedBlock)).toBeTrue(); - log.debug("Async call successfully completed"); - }); - - test("Sync Request", async () => { - // Get asset info on previously created coolcoin - const assetID = "btc"; - const commandName = { methodName: IrohaCommand.CreateAsset }; - const baseConfig = { - irohaHost: iroha.host, - irohaPort: iroha.port, - creatorAccountId: `${iroha.adminAccount}@${iroha.domain}`, - privKey: [iroha.adminPriv], - quorum: 1, - timeoutLimit: requestTimoutLimit, - }; - const params = [assetID, iroha.domain, 3]; - - log.debug(`Sending Sync Request with ${commandName} command.`); - const response = await apiClient.sendSyncRequest( - commandName, - params, - baseConfig, - ); - - expect(response).not.toBe(undefined || " "); - expect(Object.keys(response)).toContain("status"); - expect(Object.keys(response)).toContain("data"); - expect(response.status).toEqual(["COMMITTED"]); - log.debug("Sync call successfully completed"); - }); - - afterAll(async () => { - if (wsApi) { - log.info("Stop the SocketIO server connector..."); - await new Promise((resolve) => wsApi.close(() => resolve())); - } - - if (server) { - log.info("Stop the HTTP server connector..."); - await new Promise((resolve) => server.close(() => resolve())); - } - - if (iroha) { - log.debug("Stop Iroha ledger..."); - await iroha.testLedger.stop(); - } - - if (postgres) { - log.debug("Stop Postgres container..."); - await postgres.container.stop(); - } - - const pruning = await pruneDockerAllIfGithubAction({ logLevel }); - expect(pruning).toBeTruthy(); - - log.debug("Wait for send request timeouts to expire..."); - await new Promise((resolve) => setTimeout(resolve, 2 * requestTimoutLimit)); - - log.debug("All done."); - }); -}); diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/openapi/openapi-validation.test.ts b/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/openapi/openapi-validation.test.ts deleted file mode 100644 index d004a712a5..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/openapi/openapi-validation.test.ts +++ /dev/null @@ -1,243 +0,0 @@ -import http from "http"; -import { AddressInfo } from "net"; -import test, { Test } from "tape-promise/tape"; -import { v4 as uuidv4 } from "uuid"; -import { v4 as internalIpV4 } from "internal-ip"; -import bodyParser from "body-parser"; -import express from "express"; -import { Server as SocketIoServer } from "socket.io"; - -import { - Containers, - pruneDockerAllIfGithubAction, - PostgresTestContainer, - IrohaTestLedger, -} from "@hyperledger/cactus-test-tooling"; -import { PluginRegistry } from "@hyperledger/cactus-core"; -import { PluginImportType } from "@hyperledger/cactus-core-api"; - -import { - IListenOptions, - LogLevelDesc, - Servers, -} from "@hyperledger/cactus-common"; -import { RuntimeError } from "run-time-error-cjs"; -import { - PluginLedgerConnectorIroha, - DefaultApi as IrohaApi, - PluginFactoryLedgerConnector, -} from "../../../../main/typescript/public-api"; - -import { Configuration } from "@hyperledger/cactus-core-api"; - -import { - IrohaCommand, - KeyPair, - RunTransactionRequestV1, -} from "../../../../main/typescript/generated/openapi/typescript-axios"; -import cryptoHelper from "iroha-helpers/lib/cryptoHelper"; - -import OAS from "../../../../main/json/openapi.json"; -import { installOpenapiValidationMiddleware } from "@hyperledger/cactus-core"; -import { Constants } from "@hyperledger/cactus-core-api"; - -const testCase = "Iroha plugin openapi validation"; -const logLevel: LogLevelDesc = "DEBUG"; - -test.onFailure(async () => { - await Containers.logDiagnostics({ logLevel }); -}); - -test("BEFORE " + testCase, async (t: Test) => { - const pruning = pruneDockerAllIfGithubAction({ logLevel }); - await t.doesNotReject(pruning, "Pruning didn't throw OK"); - t.end(); -}); - -test(testCase, async (t: Test) => { - const postgres = new PostgresTestContainer({ logLevel }); - - test.onFinish(async () => { - await postgres.stop(); - }); - - await postgres.start(); - const postgresHost = await internalIpV4(); - const postgresPort = await postgres.getPostgresPort(); - const irohaHost = await internalIpV4(); - if (!postgresHost || !irohaHost) { - throw new RuntimeError("Could not determine the internal IPV4 address."); - } - - const keyPair1: KeyPair = cryptoHelper.generateKeyPair(); - const adminPriv = keyPair1.privateKey; - const adminPubA = keyPair1.publicKey; - const keyPair2: KeyPair = cryptoHelper.generateKeyPair(); - const nodePrivA = keyPair2.privateKey; - const nodePubA = keyPair2.publicKey; - const keyPair3: KeyPair = cryptoHelper.generateKeyPair(); - const userPub = keyPair3.publicKey; - const iroha = new IrohaTestLedger({ - adminPriv: adminPriv, - adminPub: adminPubA, - nodePriv: nodePrivA, - nodePub: nodePubA, - postgresHost: postgresHost, - postgresPort: postgresPort, - logLevel: logLevel, - }); - - test.onFinish(async () => { - await iroha.stop(); - }); - await iroha.start(); - const irohaPort = await iroha.getRpcToriiPort(); - const rpcToriiPortHost = await iroha.getRpcToriiPortHost(); - const rpcApiWsHost = await iroha.getRpcApiWsHost(); - const factory = new PluginFactoryLedgerConnector({ - pluginImportType: PluginImportType.Local, - }); - - const connector: PluginLedgerConnectorIroha = await factory.create({ - rpcToriiPortHost, - rpcApiWsHost: rpcApiWsHost, - instanceId: uuidv4(), - pluginRegistry: new PluginRegistry(), - }); - - const expressApp = express(); - expressApp.use(bodyParser.json({ limit: "250mb" })); - const server = http.createServer(expressApp); - - const wsApi = new SocketIoServer(server, { - path: Constants.SocketIoConnectionPathV1, - }); - - const listenOptions: IListenOptions = { - hostname: "127.0.0.1", - port: 0, - server, - }; - const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; - test.onFinish(async () => await Servers.shutdown(server)); - const { address, port } = addressInfo; - const apiHost = `http://${address}:${port}`; - const apiConfig = new Configuration({ basePath: apiHost }); - const apiClient = new IrohaApi(apiConfig); - - await installOpenapiValidationMiddleware({ - logLevel, - app: expressApp, - apiSpec: OAS, - }); - - await connector.getOrCreateWebServices(); - await connector.registerWebServices(expressApp, wsApi); - - const admin = iroha.getDefaultAdminAccount(); - const domain = iroha.getDefaultDomain(); - const adminID = `${admin}@${domain}`; - const user = uuidv4().substring(0, 5); - - const fRun = "runTransactionV1"; - const cOk = "without bad request error"; - const cWithoutParams = "not sending all required parameters"; - const cInvalidParams = "sending invalid parameters"; - - test(`${testCase} - ${fRun} - ${cOk}`, async (t2: Test) => { - const parameters = { - commandName: IrohaCommand.CreateAccount, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [user, domain, userPub], - }; - const res = await apiClient.runTransactionV1(parameters); - t2.ok(res); - t2.equal(res.status, 200); - - t2.end(); - }); - - test(`${testCase} - ${fRun} - ${cWithoutParams}`, async (t2: Test) => { - try { - const parameters = { - commandName: IrohaCommand.CreateAccount, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - // params: [user, domain, userPub], - }; - await apiClient.runTransactionV1( - parameters as any as RunTransactionRequestV1, - ); - } catch (e) { - t2.equal( - e.response.status, - 400, - `Endpoint ${fRun} without required params: response.status === 400 OK`, - ); - const fields = e.response.data.map((param: any) => - param.path.replace("/body/", ""), - ); - t2.ok(fields.includes("params"), "Rejected because params is required"); - } - t2.end(); - }); - - test(`${testCase} - ${fRun} - ${cInvalidParams}`, async (t2: Test) => { - try { - const parameters = { - commandName: IrohaCommand.CreateAccount, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [user, domain, userPub], - fake: 4, - }; - await apiClient.runTransactionV1( - parameters as any as RunTransactionRequestV1, - ); - } catch (e) { - t2.equal( - e.response.status, - 400, - `Endpoint ${fRun} with fake=4: response.status === 400 OK`, - ); - const fields = e.response.data.map((param: any) => - param.path.replace("/body/", ""), - ); - t2.ok( - fields.includes("fake"), - "Rejected because fake is not a valid parameter", - ); - } - t2.end(); - }); - - t.end(); -}); - -test("AFTER " + testCase, async (t: Test) => { - const pruning = pruneDockerAllIfGithubAction({ logLevel }); - await t.doesNotReject(pruning, "Pruning didn't throw OK"); - t.end(); -}); diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/run-transaction-endpoint-v1.test.ts b/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/run-transaction-endpoint-v1.test.ts deleted file mode 100644 index a9bc2ab842..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/integration/run-transaction-endpoint-v1.test.ts +++ /dev/null @@ -1,1813 +0,0 @@ -import http from "http"; -import { AddressInfo } from "net"; -import test, { Test } from "tape-promise/tape"; -import { v4 as uuidv4 } from "uuid"; -import { v4 as internalIpV4 } from "internal-ip"; -import bodyParser from "body-parser"; -import express from "express"; -import { Server as SocketIoServer } from "socket.io"; -import { - Containers, - pruneDockerAllIfGithubAction, - PostgresTestContainer, - IrohaTestLedger, -} from "@hyperledger/cactus-test-tooling"; -import { PluginRegistry } from "@hyperledger/cactus-core"; -import { PluginImportType } from "@hyperledger/cactus-core-api"; - -import { - IListenOptions, - LogLevelDesc, - Servers, -} from "@hyperledger/cactus-common"; -import { RuntimeError } from "run-time-error-cjs"; -import { - PluginLedgerConnectorIroha, - DefaultApi as IrohaApi, - PluginFactoryLedgerConnector, -} from "../../../main/typescript/public-api"; - -import { Configuration } from "@hyperledger/cactus-core-api"; - -import { - IrohaCommand, - IrohaQuery, - KeyPair, -} from "../../../main/typescript/generated/openapi/typescript-axios"; -import cryptoHelper from "iroha-helpers/lib/cryptoHelper"; -import { Constants } from "@hyperledger/cactus-core-api"; - -const testCase = "runs tx on an Iroha v1.4.0-patch-3 ledger"; -const logLevel: LogLevelDesc = "INFO"; - -test.onFailure(async () => { - await Containers.logDiagnostics({ logLevel }); -}); - -test("BEFORE " + testCase, async (t: Test) => { - const pruning = pruneDockerAllIfGithubAction({ logLevel }); - await t.doesNotReject(pruning, "Pruning didn't throw OK"); - t.end(); -}); - -// Test fails because Iroha is unable to connect to Postgres for some reason. -test(testCase, async (t: Test) => { - const postgres = new PostgresTestContainer({ logLevel }); - - test.onFinish(async () => { - await postgres.stop(); - }); - - await postgres.start(); - const postgresHost = await internalIpV4(); - const postgresPort = await postgres.getPostgresPort(); - const irohaHost = await internalIpV4(); - if (!postgresHost || !irohaHost) { - throw new RuntimeError("Could not determine the internal IPV4 address."); - } - - const keyPair1: KeyPair = cryptoHelper.generateKeyPair(); - const adminPriv = keyPair1.privateKey; - const adminPubA = keyPair1.publicKey; - const keyPair2: KeyPair = cryptoHelper.generateKeyPair(); - const nodePrivA = keyPair2.privateKey; - const nodePubA = keyPair2.publicKey; - const keyPair3: KeyPair = cryptoHelper.generateKeyPair(); - const userPub = keyPair3.publicKey; - const iroha = new IrohaTestLedger({ - adminPriv: adminPriv, - adminPub: adminPubA, - nodePriv: nodePrivA, - nodePub: nodePubA, - postgresHost: postgresHost, - postgresPort: postgresPort, - logLevel: logLevel, - }); - - test.onFinish(async () => { - await iroha.stop(); - }); - await iroha.start(false); - const irohaPort = await iroha.getRpcToriiPort(); - const rpcToriiPortHost = await iroha.getRpcToriiPortHost(); - const rpcApiWsHost = await iroha.getRpcApiWsHost(); - const internalAddr = iroha.getInternalAddr(); - const factory = new PluginFactoryLedgerConnector({ - pluginImportType: PluginImportType.Local, - }); - - const connector: PluginLedgerConnectorIroha = await factory.create({ - rpcToriiPortHost, - rpcApiWsHost: rpcApiWsHost, - instanceId: uuidv4(), - pluginRegistry: new PluginRegistry(), - }); - - const expressApp = express(); - expressApp.use(bodyParser.json({ limit: "250mb" })); - const server = http.createServer(expressApp); - const listenOptions: IListenOptions = { - hostname: "127.0.0.1", - port: 0, - server, - }; - - const wsApi = new SocketIoServer(server, { - path: Constants.SocketIoConnectionPathV1, - }); - - const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; - test.onFinish(async () => await Servers.shutdown(server)); - const { address, port } = addressInfo; - const apiHost = `http://${address}:${port}`; - const apiConfig = new Configuration({ basePath: apiHost }); - const apiClient = new IrohaApi(apiConfig); - - await connector.getOrCreateWebServices(); - await connector.registerWebServices(expressApp, wsApi); - - let firstTxHash; - const admin = iroha.getDefaultAdminAccount(); - const domain = iroha.getDefaultDomain(); - const adminID = `${admin}@${domain}`; - const user = uuidv4().substring(0, 5); - /** - * An account in Iroha ledger is formatted as: `account_name@domain_id` - * @see https://iroha.readthedocs.io/en/main/concepts_architecture/er_model.html?highlight=%3Casset_name%3E%23%3Cdomain_id%3E#account - */ - const userID = `${user}@${domain}`; - { - const req = { - commandName: IrohaCommand.CreateAccount, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [user, domain, userPub], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.CreateAccount, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { - accountName: "testaccount", - domainId: domain, - publicKey: userPub, - }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaQuery.GetAccount, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, { - accountId: adminID, - domainId: domain, - quorum: 1, - jsonData: "{}", - }); - } - - { - const req = { - commandName: IrohaQuery.GetAccount, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: adminID }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, { - accountId: adminID, - domainId: domain, - quorum: 1, - jsonData: "{}", - }); - } - - const moneyCreatorRole = "money_creator"; - const newDomain = "test2"; - { - const req = { - commandName: IrohaCommand.CreateDomain, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [newDomain, moneyCreatorRole], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.CreateDomain, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { domainId: "testDomain", defaultRole: "money_creator" }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - let asset = "coolcoin"; - /** - * An asset in Iroha ledger is formatted as: `asset_name#domain_id` - * @see https://iroha.readthedocs.io/en/main/concepts_architecture/er_model.html?highlight=%3Casset_name%3E%23%3Cdomain_id%3E#asset - */ - let assetID = `${asset}#${domain}`; - { - const req = { - commandName: IrohaCommand.CreateAsset, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [asset, domain, 3], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - asset = "testcoin"; - assetID = `${asset}#${domain}`; - { - const req = { - commandName: IrohaCommand.CreateAsset, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { assetName: asset, domainId: domain, precision: 3 }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaQuery.GetAssetInfo, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [assetID], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, { - assetId: assetID, - domainId: domain, - precision: 3, - }); - } - - { - const req = { - commandName: IrohaQuery.GetAssetInfo, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { assetId: assetID }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, { - assetId: assetID, - domainId: domain, - precision: 3, - }); - } - - { - const req = { - commandName: IrohaCommand.AddAssetQuantity, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [assetID, "123.123"], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.AddAssetQuantity, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { assetId: assetID, amount: "123.123" }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - const txDescription = uuidv4().substring(0, 5) + Date.now(); - { - const req = { - commandName: IrohaCommand.TransferAsset, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID, userID, assetID, txDescription, "57.75"], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - console.log(res.data.transactionReceipt.txHash); - firstTxHash = res.data.transactionReceipt.txHash[0]; - console.log(firstTxHash); - } - - { - const req = { - commandName: IrohaCommand.TransferAsset, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { - srcAccountId: adminID, - destAccountId: userID, - assetId: assetID, - description: txDescription, - amount: "57.75", - }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - firstTxHash = res.data.transactionReceipt.txHash[0]; - console.log(firstTxHash); - } - - { - const req = { - commandName: IrohaQuery.GetAccountAssets, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID, 100, assetID], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, [ - { - assetId: assetID, - accountId: adminID, - balance: "130.746", - }, - ]); - } - - { - const req = { - commandName: IrohaQuery.GetAccountAssets, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: adminID, pageSize: 100, firstAssetId: assetID }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, [ - { - assetId: assetID, - accountId: adminID, - balance: "130.746", - }, - ]); - } - - { - const req = { - commandName: IrohaQuery.GetAccountAssets, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [userID, 100, assetID], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, [ - { - assetId: assetID, - accountId: userID, - balance: "115.50", - }, - ]); - } - - { - const req = { - commandName: IrohaCommand.SubtractAssetQuantity, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [assetID, "30.123"], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.SubtractAssetQuantity, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { assetId: assetID, amount: "30.123" }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaQuery.GetAccountAssets, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID, 100, assetID], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, [ - { - assetId: assetID, - accountId: adminID, - balance: "70.500", - }, - ]); - } - - { - const req = { - commandName: IrohaQuery.GetSignatories, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEquals(res.data.transactionReceipt, [adminPubA]); - } - - const keyPair4: KeyPair = cryptoHelper.generateKeyPair(); - const adminPubB = keyPair4.publicKey; - { - const req = { - commandName: IrohaCommand.AddSignatory, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID, adminPubB], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - const testKeyPair: KeyPair = cryptoHelper.generateKeyPair(); - const testAdminPub = testKeyPair.publicKey; - { - const req = { - commandName: IrohaCommand.AddSignatory, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: adminID, publicKey: testAdminPub }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaQuery.GetSignatories, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.true(res.data.transactionReceipt.includes(adminPubA)); - t.true(res.data.transactionReceipt.includes(adminPubB)); - } - - { - const req = { - commandName: IrohaQuery.GetSignatories, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: adminID }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.true(res.data.transactionReceipt.includes(adminPubA)); - t.true(res.data.transactionReceipt.includes(adminPubB)); - t.true(res.data.transactionReceipt.includes(testAdminPub)); - } - - { - const req = { - commandName: IrohaCommand.RemoveSignatory, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID, adminPubB], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.RemoveSignatory, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: adminID, publicKey: testAdminPub }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaQuery.GetSignatories, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, [adminPubA]); - } - - { - const req = { - commandName: IrohaQuery.GetRoles, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, [ - "cactus_test", - "cactus_test_full", - "admin", - "user", - moneyCreatorRole, - ]); - } - - { - const req = { - commandName: IrohaQuery.GetRolePermissions, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [moneyCreatorRole], - }; - const res = await apiClient.runTransactionV1(req); - console.log(res.data.transactionReceipt); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - /** - * Iroha Javascript SDK maps each permission to an index number - * @see https://github.com/hyperledger/iroha-javascript/blob/main/src/proto/primitive_pb.d.ts#L193-L247 - */ - const permissionArr = [3, 11, 12, 13]; - t.deepEqual(res.data.transactionReceipt, permissionArr); - } - - { - const req = { - commandName: IrohaQuery.GetRolePermissions, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { roleId: moneyCreatorRole }, - }; - const res = await apiClient.runTransactionV1(req); - console.log(res.data.transactionReceipt); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - /** - * Iroha Javascript SDK maps each permission to an index number - * @see https://github.com/hyperledger/iroha-javascript/blob/main/src/proto/primitive_pb.d.ts#L193-L247 - */ - const permissionArr = [3, 11, 12, 13]; - t.deepEqual(res.data.transactionReceipt, permissionArr); - } - - { - const req = { - commandName: IrohaQuery.GetTransactions, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - /** - * param[0] needs to be an array of transactions - * Example: [[TxHash1, TxHash2, TxHash3]] - * @see https://iroha.readthedocs.io/en/main/develop/api/queries.html?highlight=GetTransactions#id25 - */ - params: [[firstTxHash]], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual( - res.data.transactionReceipt.array[0][0][0][0][0][0].slice(-1)[0], - [adminID, userID, assetID, txDescription, "57.75"], - ); - } - - { - const req = { - commandName: IrohaQuery.GetTransactions, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - /** - * param[0] needs to be an array of transactions - * Example: [[TxHash1, TxHash2, TxHash3]] - * @see https://iroha.readthedocs.io/en/main/develop/api/queries.html?highlight=GetTransactions#id25 - */ - params: { txHashesList: [firstTxHash] }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual( - res.data.transactionReceipt.array[0][0][0][0][0][0].slice(-1)[0], - [adminID, userID, assetID, txDescription, "57.75"], - ); - } - - { - const req = { - commandName: IrohaQuery.GetAccountTransactions, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [ - adminID, - 100, - firstTxHash, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual( - res.data.transactionReceipt.transactionsList[0].payload.reducedPayload - .commandsList, - [ - { - transferAsset: { - srcAccountId: adminID, - destAccountId: userID, - assetId: assetID, - description: txDescription, - amount: "57.75", - }, - }, - ], - ); - t.equal( - res.data.transactionReceipt.transactionsList[0].signaturesList[0] - .publicKey, - adminPubA, - ); - } - - { - const req = { - commandName: IrohaQuery.GetAccountTransactions, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { - accountId: adminID, - pageSize: 100, - firstTxHash: firstTxHash, - firstTxTime: undefined, - lastTxTime: undefined, - firstTxHeight: undefined, - lastTxHeight: undefined, - ordering: { - field: undefined, - direction: undefined, - }, - }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual( - res.data.transactionReceipt.transactionsList[0].payload.reducedPayload - .commandsList, - [ - { - transferAsset: { - srcAccountId: adminID, - destAccountId: userID, - assetId: assetID, - description: txDescription, - amount: "57.75", - }, - }, - ], - ); - t.equal( - res.data.transactionReceipt.transactionsList[0].signaturesList[0] - .publicKey, - adminPubA, - ); - } - - { - const req = { - commandName: IrohaQuery.GetAccountAssetTransactions, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [ - adminID, - assetID, - 100, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ], - }; - const res = await apiClient.runTransactionV1(req); - t.deepEqual( - res.data.transactionReceipt.transactionsList[0].payload.reducedPayload - .commandsList, - [ - { - transferAsset: { - srcAccountId: adminID, - destAccountId: userID, - assetId: assetID, - description: txDescription, - amount: "57.75", - }, - }, - ], - ); - t.equal( - res.data.transactionReceipt.transactionsList[0].signaturesList[0] - .publicKey, - adminPubA, - ); - } - - { - const req = { - commandName: IrohaQuery.GetAccountAssetTransactions, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { - accountId: adminID, - assetId: assetID, - pageSize: 100, - firstTxHash: undefined, - firstTxTime: undefined, - lastTxTime: undefined, - firstTxHeight: undefined, - lastTxHeight: undefined, - ordering: { - field: undefined, - direction: undefined, - }, - }, - }; - const res = await apiClient.runTransactionV1(req); - t.deepEqual( - res.data.transactionReceipt.transactionsList[0].payload.reducedPayload - .commandsList, - [ - { - transferAsset: { - srcAccountId: adminID, - destAccountId: userID, - assetId: assetID, - description: txDescription, - amount: "57.75", - }, - }, - ], - ); - t.equal( - res.data.transactionReceipt.transactionsList[0].signaturesList[0] - .publicKey, - adminPubA, - ); - } - - { - const req = { - commandName: IrohaQuery.GetPeers, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, [ - { - address: internalAddr, - peerKey: nodePubA, - tlsCertificate: "", - }, - ]); - } - - { - const req = { - commandName: IrohaQuery.GetBlock, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [1], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual( - res.data.transactionReceipt.payload.transactionsList[0].payload - .reducedPayload.commandsList[0].addPeer.peer, - { - address: internalAddr, - peerKey: nodePubA, - tlsCertificate: "", - }, - ); - } - - { - const req = { - commandName: IrohaQuery.GetBlock, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { height: 1 }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual( - res.data.transactionReceipt.payload.transactionsList[0].payload - .reducedPayload.commandsList[0].addPeer.peer, - { - address: internalAddr, - peerKey: nodePubA, - tlsCertificate: "", - }, - ); - } - - { - const req = { - commandName: IrohaCommand.AppendRole, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [userID, moneyCreatorRole], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.AppendRole, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: userID, roleName: "cactus_test" }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.DetachRole, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [userID, moneyCreatorRole], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.DetachRole, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: userID, roleName: "cactus_test" }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - let testRole = uuidv4().substring(0, 5); - { - const req = { - commandName: IrohaCommand.CreateRole, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [testRole, [6, 7]], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - testRole = uuidv4().substring(0, 5) + Date.now(); - { - const req = { - commandName: IrohaCommand.CreateRole, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { roleName: testRole, permissionsList: [6, 7] }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.GrantPermission, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: userID, permission: "CAN_CALL_ENGINE_ON_MY_BEHALF" }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.RevokePermission, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: userID, permission: "CAN_CALL_ENGINE_ON_MY_BEHALF" }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.SetAccountDetail, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [userID, "age", "18"], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.SetAccountDetail, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: userID, key: "age", value: "21" }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaQuery.GetAccountDetail, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [userID, "age", adminID, 1, "age", adminID], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, { - "admin@test": { age: "21" }, - }); - } - - { - const req = { - commandName: IrohaQuery.GetAccountDetail, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { - accountId: userID, - key: "age", - writer: adminID, - pageSize: 1, - paginationKey: "age", - paginationWriter: adminID, - }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, { - "admin@test": { age: "21" }, - }); - } - - { - const req = { - commandName: IrohaCommand.CompareAndSetAccountDetail, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [userID, "age", "118", "21", false], //change age from 21 to 118 - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.CompareAndSetAccountDetail, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [userID, "age", "21", "118", false], //change age from 118 to 21 - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaQuery.GetAccountDetail, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [userID, "age", adminID, 1, "age", adminID], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, { - "admin@test": { age: "21" }, - }); - } - - { - const req = { - commandName: IrohaQuery.GetEngineReceipts, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [firstTxHash], - }; - const res = await apiClient.runTransactionV1(req); - t.deepEqual(res.data.transactionReceipt.array, [[]]); - } - - { - const req = { - commandName: IrohaQuery.GetEngineReceipts, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { txHash: firstTxHash }, - }; - const res = await apiClient.runTransactionV1(req); - t.deepEqual(res.data.transactionReceipt.array, [[]]); - } - - const key = uuidv4().substring(0, 5) + Date.now(); - const value = uuidv4().substring(0, 5) + Date.now(); - { - const req = { - commandName: IrohaCommand.SetSettingValue, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [key, value], - }; - await t.rejects( - apiClient.runTransactionV1(req), - /[\s\S]*/, - "SetSettingValue transaction is rejected OK", - ); - } - - /** - * The callee and input values are taken from Iroha doc's example. - * At some point, we should generate it on our own. - * @see https://iroha.readthedocs.io/en/main/develop/api/commands.html?highlight=CallEngine#id18 - */ - const callee = "7C370993FD90AF204FD582004E2E54E6A94F2651"; - const input = - "40c10f19000000000000000000000000969453762b0c739dd285b31635efa00e24c2562800000000000000000000000000000000000000000000000000000000000004d2"; - { - const req = { - commandName: IrohaCommand.CallEngine, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [undefined, adminID, callee, input], - }; - await t.rejects( - apiClient.runTransactionV1(req), - /[\s\S]*/, - "CallEngine transaction is rejected OK", - ); - } - - { - const req = { - commandName: IrohaCommand.CallEngine, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { type: undefined, caller: adminID, callee, input }, - }; - await t.rejects( - apiClient.runTransactionV1(req), - /[\s\S]*/, - "CallEngine transaction is rejected OK", - ); - } - - /** - * FIXME - the Iroha Javascript SDK does not give any output if we try to produce a pending transaction - * This results in an infinite loop and thus the following code cannot be executed. - * Once the Iroha Javascript SDK is justitied. We can safely produce a pending transaction. - * @see https://github.com/hyperledger/iroha-javascript/issues/66 - * Dealing with it will cause the test suite fail, so only testing against an empty pending transaction case. - */ - { - const req = { - commandName: IrohaQuery.GetPendingTransactions, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [ - 5, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, []); - } - - { - const req = { - commandName: IrohaQuery.GetPendingTransactions, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { - pageSize: 5, - firstTxHash: undefined, - firstTxTime: undefined, - lastTxTime: undefined, - firstTxHeight: undefined, - lastTxHeight: undefined, - ordering: { - field: undefined, - direction: undefined, - }, - }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.deepEqual(res.data.transactionReceipt, []); - } - - const keyPair5: KeyPair = cryptoHelper.generateKeyPair(); - const adminPubC = keyPair5.publicKey; - const adminPrivC = keyPair5.privateKey; - { - const req = { - commandName: IrohaCommand.AddSignatory, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: [adminID, adminPubC], - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - { - const req = { - commandName: IrohaCommand.SetAccountQuorum, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv], - quorum: 1, - timeoutLimit: 5000, - tls: false, - }, - params: { accountId: adminID, quorum: 2 }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - console.log(res.data.transactionReceipt); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - - const keyPair6: KeyPair = cryptoHelper.generateKeyPair(); - const nodePubB = keyPair6.publicKey; - /** - * Take advantage of Postgres's address to fake it as the peer address - * since it is different from existing Iroha node's address - */ - const peerAddr = `${postgresHost}:${postgresPort}`; - { - const req = { - commandName: IrohaCommand.AddPeer, - baseConfig: { - irohaHost: irohaHost, - irohaPort: irohaPort, - creatorAccountId: adminID, - privKey: [adminPriv, adminPrivC], - quorum: 2, - timeoutLimit: 5000, - tls: false, - }, - params: { address: peerAddr, peerKey: nodePubB }, - }; - const res = await apiClient.runTransactionV1(req); - t.ok(res); - t.ok(res.data); - t.equal(res.status, 200); - t.equal(res.data.transactionReceipt.status[0], "COMMITTED"); - } - t.end(); -}); - -test("AFTER " + testCase, async (t: Test) => { - const pruning = pruneDockerAllIfGithubAction({ logLevel }); - await t.doesNotReject(pruning, "Pruning didn't throw OK"); - t.end(); -}); diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/api-surface.test.ts b/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/api-surface.test.ts deleted file mode 100644 index 34aba3a0ae..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/api-surface.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import * as apiSurface from "../../../main/typescript/public-api"; -import "jest-extended"; - -test("Library can be loaded", async () => { - expect(apiSurface).toBeTruthy(); -}); diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/iroha-test-ledger-parameters.test.ts b/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/iroha-test-ledger-parameters.test.ts deleted file mode 100644 index e4ddb2420a..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/iroha-test-ledger-parameters.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import test, { Test } from "tape"; -import { IrohaTestLedger } from "@hyperledger/cactus-test-tooling"; - -test("constructor does not throw with the default config", async (t: Test) => { - t.plan(1); - - // No options - const irohaTestLedger = new IrohaTestLedger({ - postgresHost: "127.0.0.1", - postgresPort: 5432, - }); - - t.ok(irohaTestLedger); - t.end(); -}); - -test("Iroha environment variables passed correctly", async (t: Test) => { - t.plan(2); - const simpleEnvVars = [ - "IROHA_POSTGRES_USER=postgres", - "IROHA_POSTGRES_PASSWORD=mysecretpassword", - "KEY=node0", - ]; - - const irohaOptions = { - postgresHost: "127.0.0.1", - postgresPort: 5432, - envVars: simpleEnvVars, - }; - const irohaTestLedger = new IrohaTestLedger(irohaOptions); - - t.equal(irohaTestLedger.envVars, simpleEnvVars); - t.ok(irohaTestLedger); - t.end(); -}); diff --git a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/postgres-test-container-parameters.test.ts b/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/postgres-test-container-parameters.test.ts deleted file mode 100644 index ad8f124108..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/src/test/typescript/unit/postgres-test-container-parameters.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import test, { Test } from "tape"; -import { PostgresTestContainer } from "@hyperledger/cactus-test-tooling"; - -test("constructor does not throw with the default config", async (t: Test) => { - t.plan(1); - - // No options - const postgresTestContainer = new PostgresTestContainer(); - - t.ok(postgresTestContainer); - t.end(); -}); - -test("Postgres environment variables passed correctly", async (t: Test) => { - t.plan(2); - const simpleEnvVars = [ - "POSTGRES_USER=postgres", - "POSTGRES_PASSWORD=mysecretpassword", - ]; - - const postgresOptions = { - envVars: simpleEnvVars, - }; - const postgresTestLedger = new PostgresTestContainer(postgresOptions); - - t.equal(postgresTestLedger.envVars, simpleEnvVars); - t.ok(postgresTestLedger); - t.end(); -}); diff --git a/packages/cactus-plugin-ledger-connector-iroha/tsconfig.json b/packages/cactus-plugin-ledger-connector-iroha/tsconfig.json deleted file mode 100644 index 36b99e2d19..0000000000 --- a/packages/cactus-plugin-ledger-connector-iroha/tsconfig.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "composite": true, - "outDir": "./dist/lib/", - "declarationDir": "dist/types", - "resolveJsonModule": true, - "rootDir": "./src", - "tsBuildInfoFile": "../../.build-cache/cactus-plugin-ledger-connector-iroha.tsbuildinfo" - }, - "include": [ - "./src", - "src/**/*.json" - ], - "references": [ - { - "path": "../cactus-common/tsconfig.json" - }, - { - "path": "../cactus-core/tsconfig.json" - }, - { - "path": "../cactus-core-api/tsconfig.json" - }, - { - "path": "../cactus-plugin-keychain-memory/tsconfig.json" - }, - { - "path": "../cactus-test-tooling/tsconfig.json" - } - ] -} \ No newline at end of file diff --git a/packages/cactus-test-tooling/src/main/typescript/iroha/iroha-test-ledger.ts b/packages/cactus-test-tooling/src/main/typescript/iroha/iroha-test-ledger.ts deleted file mode 100644 index d60711e2bf..0000000000 --- a/packages/cactus-test-tooling/src/main/typescript/iroha/iroha-test-ledger.ts +++ /dev/null @@ -1,496 +0,0 @@ -import Docker, { Container, ContainerInfo } from "dockerode"; -import Joi from "joi"; -import { EventEmitter } from "events"; -import { - LogLevelDesc, - Logger, - LoggerProvider, - Bools, - Checks, -} from "@hyperledger/cactus-common"; -import { ITestLedger } from "../i-test-ledger"; -import { IKeyPair } from "../i-key-pair"; -import { Containers } from "../common/containers"; - -/* - * Contains options for Iroha container - */ -export interface IIrohaTestLedgerOptions { - readonly adminPriv?: string; - readonly adminPub?: string; - readonly nodePriv?: string; - readonly nodePub?: string; - readonly tlsCert?: string; - readonly tlsKey?: string; - readonly toriiTlsPort?: number; - readonly postgresHost: string; - readonly postgresPort: number; - readonly imageVersion?: string; - readonly imageName?: string; - readonly rpcToriiPort?: number; - readonly envVars?: string[]; - readonly logLevel?: LogLevelDesc; - readonly emitContainerLogs?: boolean; - readonly rpcApiWsPort?: number; - readonly healthcheckPort?: number; -} - -/* - * Provides default options for Iroha container - */ -export const IROHA_TEST_LEDGER_DEFAULT_OPTIONS = Object.freeze({ - imageVersion: "2023-07-17-issue-2524", - imageName: "ghcr.io/hyperledger/cactus-iroha-all-in-one", - adminPriv: " ", - adminPub: " ", - nodePriv: " ", - nodePub: " ", - tlsCert: " ", - tlsKey: " ", - healthcheckPort: 50508, - rpcToriiPort: 50051, - toriiTlsPort: 55552, - envVars: [ - "IROHA_MST_EXPIRATION_TIME=1440", - "IROHA_MST_ENABLE=false", - "IROHA_HEALTHCHECK_PORT=50508", - "IROHA_PROPOSAL_CREATION_TIMEOUT=3000", - "IROHA_VOTE_DELAY=5000", - "IROHA_PROPOSAL_DELAY=5000", - "IROHA_MAX_PROPOSAL_SIZE=10", - "IROHA_DATABASE_TYPE=postgres", - "IROHA_INTER_PEER_TLS_KEY_PAIR_PATH=/opt/iroha_data/node0", - "IROHA_TORII_TLS_PARAMS_PORT=55552", - "IROHA_INTERNAL_PORT=10001", - "IROHA_BLOCK_STORE_PATH=/tmp/block_store/", - "IROHA_TORII_PORT=50051", - "IROHA_LOG_LEVEL=info", - "IROHA_POSTGRES_USER=postgres", - "IROHA_POSTGRES_PASSWORD=my-secret-password", - "IROHA_DATABASE_USER=postgres", - "IROHA_DATABASE_PASSWORD=my-secret-password", - "IROHA_DATABASE_WORKING DATABASE=iroha_default", - "IROHA_DATABASE_MAINTENANCE DATABASE=postgres", - "KEY=node0", - ], - rpcApiWsPort: 50052, -}); - -/* - * Provides validations for Iroha container's options - */ -export const IROHA_TEST_LEDGER_OPTIONS_JOI_SCHEMA: Joi.Schema = - Joi.object().keys({ - adminPriv: Joi.string().min(1).max(64).required(), - adminPub: Joi.string().min(1).max(64).required(), - nodePriv: Joi.string().min(1).max(64).required(), - nodePub: Joi.string().min(1).max(64).required(), - tlsCert: Joi.string().min(1).required(), - tlsKey: Joi.string().min(1).required(), - healthcheckPort: Joi.number() - .port() - .default(IROHA_TEST_LEDGER_DEFAULT_OPTIONS.healthcheckPort), - toriiTlsPort: Joi.number().port().required(), - postgresPort: Joi.number().port().required(), - postgresHost: Joi.string().hostname().required(), - imageVersion: Joi.string().min(5).required(), - imageName: Joi.string().min(1).required(), - rpcToriiPort: Joi.number().port().required(), - envVars: Joi.array().allow(null).required(), - }); - -export class IrohaTestLedger implements ITestLedger { - public readonly imageVersion: string; - public readonly imageName: string; - public readonly rpcToriiPort: number; - public readonly envVars: string[]; - public readonly emitContainerLogs: boolean; - public readonly postgresHost: string; - public readonly postgresPort: number; - public readonly adminPriv: string; - public readonly adminPub: string; - public readonly nodePriv: string; - public readonly nodePub: string; - public readonly rpcApiWsPort: number; - public readonly tlsCert?: string; - public readonly tlsKey?: string; - public readonly healthcheckPort?: number; - public readonly toriiTlsPort?: number; - - private readonly log: Logger; - private container: Container | undefined; - private containerId: string | undefined; - - constructor(public readonly options: IIrohaTestLedgerOptions) { - const fnTag = `IrohaTestLedger#constructor()`; - if (!options) { - throw new TypeError(`IrohaTestLedger#ctor options was falsy.`); - } - Checks.nonBlankString(options.postgresHost, `${fnTag} postgresHost`); - Checks.truthy(options.postgresPort, `${fnTag} postgresPort`); - - this.postgresHost = options.postgresHost; - this.postgresPort = options.postgresPort; - this.adminPriv = - options.adminPriv || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.adminPriv; - this.adminPub = - options.adminPub || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.adminPub; - this.nodePriv = - options.nodePriv || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.nodePriv; - this.nodePub = options.nodePub || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.nodePub; - - this.imageVersion = - options.imageVersion || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.imageVersion; - this.imageName = - options.imageName || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.imageName; - this.rpcToriiPort = - options.rpcToriiPort || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.rpcToriiPort; - this.envVars = options.envVars || [ - ...IROHA_TEST_LEDGER_DEFAULT_OPTIONS.envVars, - ]; - this.tlsCert = options.tlsCert || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.tlsCert; - this.tlsKey = options.tlsKey || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.tlsKey; - this.toriiTlsPort = - options.toriiTlsPort || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.toriiTlsPort; - this.rpcApiWsPort = - options.rpcApiWsPort || IROHA_TEST_LEDGER_DEFAULT_OPTIONS.rpcApiWsPort; - this.healthcheckPort = - options.healthcheckPort || - IROHA_TEST_LEDGER_DEFAULT_OPTIONS.healthcheckPort; - - this.envVars.push(`IROHA_DATABASE_HOST=${this.postgresHost}`); - this.envVars.push(`IROHA_DATABASE_PORT=${this.postgresPort}`); - - this.envVars.push(`IROHA_POSTGRES_HOST=${this.postgresHost}`); - this.envVars.push(`IROHA_POSTGRES_PORT=${this.postgresPort}`); - this.envVars.push(`ADMIN_PRIV=${this.adminPriv}`); - this.envVars.push(`ADMIN_PUB=${this.adminPub}`); - this.envVars.push(`NODE_PRIV=${this.nodePriv}`); - this.envVars.push(`NODE_PUB=${this.nodePub}`); - - this.emitContainerLogs = Bools.isBooleanStrict(options.emitContainerLogs) - ? (options.emitContainerLogs as boolean) - : true; - - this.validateConstructorOptions(); - const label = "iroha-test-ledger"; - const level = options.logLevel || "INFO"; - this.log = LoggerProvider.getOrCreate({ level, label }); - } - - public getContainer(): Container { - const fnTag = "IrohaTestLedger#getContainer()"; - if (!this.container) { - throw new Error(`${fnTag} container not yet started by this instance.`); - } else { - return this.container; - } - } - - public get imageFqn(): string { - return `${this.imageName}:${this.imageVersion}`; - } - - public async getRpcToriiPortHost(): Promise { - const ipAddress = "127.0.0.1"; - const hostPort: number = await this.getRpcToriiPort(); - return `http://${ipAddress}:${hostPort}`; - } - - /** - * Output is based on the standard Iroha Torii port number(50051). - * - * @see https://github.com/hyperledger/iroha/blob/main/example/config.docker - */ - public getDefaultToriiPort(): number { - return 50051; - } - - /** - * Output is based on the standard Iroha genesis.block content. - * - * @see https://github.com/hyperledger/iroha/blob/main/example/genesis.block - */ - public getInternalAddr(): string { - return "127.0.0.1:10001"; - } - - /** - * Output is based on the standard Iroha genesis.block content. - * - * @see https://github.com/hyperledger/iroha/blob/main/example/genesis.block - */ - public getDefaultAdminAccount(): string { - return "admin"; - } - - /** - * Output is based on the standard Iroha genesis.block content. - * - * @see https://github.com/hyperledger/iroha/blob/main/example/genesis.block - */ - public getDefaultDomain(): string { - return "test"; - } - - public async getRpcApiWsHost(): Promise { - const { rpcApiWsPort } = this; - const ipAddress = "127.0.0.1"; - const containerInfo = await this.getContainerInfo(); - const port = await Containers.getPublicPort(rpcApiWsPort, containerInfo); - return `ws://${ipAddress}:${port}`; - } - - /** - * Output is based on the standard Iroha admin user public key file location. - * - * @see https://github.com/hyperledger/iroha/blob/main/example/admin%40test.pub - * @see https://github.com/hyperledger/iroha/blob/main/example/genesis.block - */ - public async getGenesisAccountPubKey(): Promise { - const fnTag = `IrohaTestLedger#getGenesisAccountPubKey()`; - if (!this.container) { - throw new Error(`${fnTag} this.container cannot be falsy.`); - } - const publicKey = await Containers.pullFile( - this.container, - "/opt/iroha_data/admin@test.pub", - ); - return publicKey; - } - - /** - * Output is based on the standard Iroha admin user private key file location. - * - * @see https://github.com/hyperledger/iroha/blob/main/example/admin%40test.priv - */ - public async getGenesisAccountPrivKey(): Promise { - const fnTag = `IrohaTestLedger#getGenesisAccountPrivKey()`; - if (!this.container) { - throw new Error(`${fnTag} this.container cannot be falsy.`); - } - const privateKey = await Containers.pullFile( - this.container, - "/opt/iroha_data/admin@test.priv", - ); - return privateKey; - } - - /** - * Output is based on the standard Iroha node private/public keypair file location. - * - * @see https://github.com/hyperledger/iroha/blob/main/example/node0.priv - * @see https://github.com/hyperledger/iroha/blob/main/example/test%40test.pub - */ - public async getNodeKeyPair(): Promise { - const fnTag = `IrohaTestLedger#getNodeKeyPair()`; - if (!this.container) { - throw new Error(`${fnTag} this.container cannot be falsy.`); - } - const publicKey = await Containers.pullFile( - this.container, - "/opt/iroha_data/node0.pub", - ); - const privateKey = await Containers.pullFile( - this.container, - "/opt/iroha_data/node0.priv", - ); - return { publicKey, privateKey }; - } - - public async start(omitPull = false): Promise { - if (this.container) { - await this.container.stop(); - await this.container.remove(); - } - const docker = new Docker(); - if (!omitPull) { - this.log.debug(`Pulling container image ${this.imageFqn} ...`); - await Containers.pullImage(this.imageFqn, {}, this.options.logLevel); - this.log.debug(`Pulled ${this.imageFqn} OK. Starting container...`); - } - - return new Promise((resolve, reject) => { - const admin = this.getDefaultAdminAccount(); - const domain = this.getDefaultDomain(); - const adminID = `${admin}@${domain}`; - const toriiPort = this.getDefaultToriiPort(); - const eventEmitter: EventEmitter = docker.run( - this.imageFqn, - [], - [], - { - ExposedPorts: { - [`${this.rpcToriiPort}/tcp`]: {}, // Iroha RPC - Torii - [`${this.toriiTlsPort}/tcp`]: {}, // Iroha TLS RPC - [`${this.rpcApiWsPort}/tcp`]: {}, // Iroha RPC WS - [`${this.healthcheckPort}/tcp`]: {}, // Iroha Healthcheck Service - }, - Env: this.envVars, - Healthcheck: { - //Healthcheck script usage: python3 /healthcheck.py userID toriiPort - Test: [ - "CMD-SHELL", - `python3 /healthcheck.py ${adminID} ${toriiPort}`, - ], - Interval: 1000000000, // 1 second - Timeout: 3000000000, // 3 seconds - Retries: 299, - StartPeriod: 3000000000, // 3 seconds - }, - HostConfig: { - PublishAllPorts: true, - AutoRemove: true, - }, - }, - {}, - (err: unknown) => { - if (err) { - reject(err); - } - }, - ); - - eventEmitter.once("start", async (container: Container) => { - this.log.debug(`Started container OK. Waiting for healthcheck...`); - this.container = container; - this.containerId = container.id; - - if (this.emitContainerLogs) { - const fnTag = `[${this.imageFqn}]`; - await Containers.streamLogs({ - container: this.container, - tag: fnTag, - log: this.log, - }); - } - - try { - await this.waitForHealthCheck(); - this.log.debug(`Healthcheck passing OK.`); - resolve(container); - } catch (ex) { - reject(ex); - } - }); - }); - } - - public async waitForHealthCheck(timeoutMs = 180000): Promise { - const fnTag = "IrohaTestLedger#waitForHealthCheck()"; - const startedAt = Date.now(); - let isHealthy = false; - do { - if (Date.now() >= startedAt + timeoutMs) { - throw new Error(`${fnTag} timed out (${timeoutMs}ms)`); - } - const containerInfo = await this.getContainerInfo(); - this.log.debug(`ContainerInfo.Status=%o`, containerInfo.Status); - this.log.debug(`ContainerInfo.State=%o`, containerInfo.State); - isHealthy = containerInfo.Status.endsWith("(healthy)"); - if (!isHealthy) { - await new Promise((resolve2) => setTimeout(resolve2, 1000)); - } - } while (!isHealthy); - } - - public stop(): Promise { - return Containers.stop(this.container as Container); - } - - public destroy(): Promise { - const fnTag = "IrohaTestLedger#destroy()"; - if (this.container) { - return this.container.remove(); - } else { - const ex = new Error(`${fnTag} Container not found, nothing to destroy.`); - return Promise.reject(ex); - } - } - - protected async getContainerInfo(): Promise { - const docker = new Docker(); - const image = this.imageFqn; - const containerInfos = await docker.listContainers({}); - - let aContainerInfo; - if (this.containerId !== undefined) { - aContainerInfo = containerInfos.find((ci) => ci.Id === this.containerId); - } - - if (aContainerInfo) { - return aContainerInfo; - } else { - throw new Error(`IrohaTestLedger#getContainerInfo() no image "${image}"`); - } - } - - /** - * Return the randomly allocated Iroha Torii port number - */ - public async getRpcToriiPort(): Promise { - const fnTag = "IrohaTestLedger#getRpcToriiPort()"; - const aContainerInfo = await this.getContainerInfo(); - const { rpcToriiPort: thePort } = this; - const { Ports: ports } = aContainerInfo; - - if (ports.length < 1) { - throw new Error(`${fnTag} no ports exposed or mapped at all`); - } - const mapping = ports.find((x) => x.PrivatePort === thePort); - if (mapping) { - if (!mapping.PublicPort) { - throw new Error(`${fnTag} port ${thePort} mapped but not public`); - } else if (mapping.IP !== "0.0.0.0") { - throw new Error(`${fnTag} port ${thePort} mapped to 127.0.0.1`); - } else { - return mapping.PublicPort; - } - } else { - throw new Error(`${fnTag} no mapping found for ${thePort}`); - } - } - - public async getContainerIpAddress(): Promise { - const fnTag = "IrohaTestLedger#getContainerIpAddress()"; - const aContainerInfo = await this.getContainerInfo(); - - if (aContainerInfo) { - const { NetworkSettings } = aContainerInfo; - const networkNames: string[] = Object.keys(NetworkSettings.Networks); - if (networkNames.length < 1) { - throw new Error(`${fnTag} container not connected to any networks`); - } else { - // return IP address of container on the first network that we found - // it connected to. Make this configurable? - return NetworkSettings.Networks[networkNames[0]].IPAddress; - } - } else { - throw new Error(`${fnTag} cannot find image: ${this.imageName}`); - } - } - - private validateConstructorOptions(): void { - const validationResult = IROHA_TEST_LEDGER_OPTIONS_JOI_SCHEMA.validate({ - adminPriv: this.adminPriv, - adminPub: this.adminPub, - nodePriv: this.nodePriv, - nodePub: this.nodePub, - tlsCert: this.tlsCert, - tlsKey: this.tlsKey, - toriiTlsPort: this.toriiTlsPort, - postgresHost: this.postgresHost, - postgresPort: this.postgresPort, - imageVersion: this.imageVersion, - imageName: this.imageName, - rpcToriiPort: this.rpcToriiPort, - envVars: this.envVars, - }); - - if (validationResult.error) { - throw new Error( - `IrohaTestLedger#ctor ${validationResult.error.annotate()}`, - ); - } - } -} diff --git a/packages/cactus-test-tooling/src/main/typescript/public-api.ts b/packages/cactus-test-tooling/src/main/typescript/public-api.ts index 699fe00d42..1380f8fb59 100755 --- a/packages/cactus-test-tooling/src/main/typescript/public-api.ts +++ b/packages/cactus-test-tooling/src/main/typescript/public-api.ts @@ -69,13 +69,6 @@ export { INDY_TEST_LEDGER_DEFAULT_OPTIONS, } from "./indy/indy-test-ledger"; -export { - IrohaTestLedger, - IIrohaTestLedgerOptions, - IROHA_TEST_LEDGER_DEFAULT_OPTIONS, - IROHA_TEST_LEDGER_OPTIONS_JOI_SCHEMA, -} from "./iroha/iroha-test-ledger"; - export { Iroha2TestLedger, IIroha2TestLedgerOptions, diff --git a/packages/cactus-test-tooling/src/test/typescript/integration/iroha/iroha-test-ledger/constructor-validates-options.test.ts b/packages/cactus-test-tooling/src/test/typescript/integration/iroha/iroha-test-ledger/constructor-validates-options.test.ts deleted file mode 100644 index 92fd7a35a6..0000000000 --- a/packages/cactus-test-tooling/src/test/typescript/integration/iroha/iroha-test-ledger/constructor-validates-options.test.ts +++ /dev/null @@ -1,108 +0,0 @@ -import test, { Test } from "tape-promise/tape"; -import isPortReachable from "is-port-reachable"; -import { v4 as internalIpV4 } from "internal-ip"; -import { Container } from "dockerode"; -import { - IrohaTestLedger, - PostgresTestContainer, - IKeyPair, - isIKeyPair, -} from "../../../../../main/typescript/public-api"; -import { LogLevelDesc } from "@hyperledger/cactus-common"; - -const logLevel: LogLevelDesc = "TRACE"; - -test.skip("constructor throws if invalid input is provided", (t: Test) => { - t.ok(IrohaTestLedger); - t.throws( - () => - new IrohaTestLedger({ - imageVersion: "nope", - postgresHost: "127.0.0.1", - postgresPort: 5432, - }), - ); - t.end(); -}); - -test.skip("constructor does not throw if valid input is provided", (t: Test) => { - t.ok(IrohaTestLedger); - t.doesNotThrow( - () => - new IrohaTestLedger({ - postgresHost: "127.0.0.1", - postgresPort: 5432, - }), - ); - t.end(); -}); - -/** - * Flaky test - we are skipping it for now - * - * ```sh - * Executing task: docker logs --tail 1000 -f e57575c9ba1522c10ecd6675234d1c80caf72b2138d8cef58e3c73749e587e62 < - * key=node0 - * /opt/iroha_data - * NOTE: IROHA_POSTGRES_HOST should match 'host' option in config file - * wait-for-it.sh: waiting 30 seconds for 192.168.66.229:49153 - * wait-for-it.sh: timeout occurred after waiting 30 seconds for 192.168.66.229:49153 - * [2021-09-15 04:32:27.632218734][I][Init]: Irohad version: 1.2.0 - * [2021-09-15 04:32:27.632242961][I][Init]: config initialized - * [2021-09-15 04:32:27.632519876][W][Init]: Using deprecated database connection string! - * [2021-09-15 04:32:27.633029755][I][Irohad]: created - * [2021-09-15 04:32:27.633071877][I][Irohad]: [Init] => pending transactions storage - * [2021-09-15 04:34:38.353932099][E][Irohad]: Storage initialization failed: Could not connect to maintenance database: Cannot establish connection to the database. - * could not connect to server: Connection timed out - * Is the server running on host "192.168.66.229" and accepting - * TCP/IP connections on port 49153? - * - * [2021-09-15 04:34:38.353979081][E][Init]: Failed to initialize storage - * - * ``` - */ - -test.skip("starts/stops/destroys a docker container", async (t: Test) => { - const postgresTestContainer = new PostgresTestContainer({ logLevel }); - - test.onFinish(async () => { - await postgresTestContainer.stop(); - }); - - const postgresContainer: Container = await postgresTestContainer.start(); - const postgresPort = await postgresTestContainer.getPostgresPort(); - const postgresHost = await internalIpV4(); - if (!postgresHost) { - throw new Error("Could not determine the internal IPV4 address."); - } - const irohaTestLedger = new IrohaTestLedger({ - emitContainerLogs: true, - postgresHost, - postgresPort, - logLevel, - }); - - test.onFinish(async () => { - await irohaTestLedger.stop(); - }); - const irohaContainer = await irohaTestLedger.start(); - - t.ok(irohaContainer, "irohaContainer truthy OK"); - t.ok(postgresContainer, "postgresContainer truthy OK"); - const irohaIpAddress = await irohaTestLedger.getContainerIpAddress(); - t.ok(irohaIpAddress, "irohaIpAddress truthy OK"); - t.equal(typeof irohaIpAddress, "string", "typeof irohaIpAddress string OK"); - - const hostPort: number = await irohaTestLedger.getRpcToriiPort(); - t.ok(hostPort, "getRpcApiPublicPort() returns truthy OK"); - t.ok(isFinite(hostPort), "getRpcApiPublicPort() returns finite OK"); - - const isReachable = await isPortReachable(hostPort, { host: "127.0.0.1" }); - t.ok(isReachable, `HostPort ${hostPort} is reachable via 127.0.0.1`); - - const irohaKeyPair: IKeyPair = await irohaTestLedger.getNodeKeyPair(); - t.ok(irohaKeyPair, "getIrohaKeyPair() returns truthy OK"); - t.ok(isIKeyPair(irohaKeyPair)); - - t.end(); -}); diff --git a/packages/cactus-verifier-client/README.md b/packages/cactus-verifier-client/README.md index 77c8fd862b..32c41c16c6 100644 --- a/packages/cactus-verifier-client/README.md +++ b/packages/cactus-verifier-client/README.md @@ -11,7 +11,6 @@ This package provides `Verifier` and `VerifierFactory` components that can be us | QUORUM_2X | cactus-plugin-ledger-connector-quorum | | ETH_1X | cactus-plugin-ledger-connector-ethereum | | CORDA_4X | cactus-plugin-ledger-connector-corda | -| IROHA_1X | cactus-plugin-ledger-connector-iroha | | IROHA_2X | cactus-plugin-ledger-connector-iroha2 | | FABRIC_2X | cactus-plugin-ledger-connector-fabric | | SAWTOOTH_1X | cactus-plugin-ledger-connector-sawtooth | diff --git a/packages/cactus-verifier-client/package.json b/packages/cactus-verifier-client/package.json index abaf84db67..762733ac78 100644 --- a/packages/cactus-verifier-client/package.json +++ b/packages/cactus-verifier-client/package.json @@ -51,7 +51,6 @@ "@hyperledger/cactus-plugin-ledger-connector-corda": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-ledger-connector-ethereum": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-ledger-connector-fabric": "2.0.0-alpha.2", - "@hyperledger/cactus-plugin-ledger-connector-iroha": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-ledger-connector-iroha2": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-ledger-connector-quorum": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-ledger-connector-sawtooth": "2.0.0-alpha.2", @@ -64,7 +63,6 @@ "@hyperledger/cactus-plugin-ledger-connector-corda": "2.x", "@hyperledger/cactus-plugin-ledger-connector-ethereum": "2.x", "@hyperledger/cactus-plugin-ledger-connector-fabric": "2.x", - "@hyperledger/cactus-plugin-ledger-connector-iroha": "2.x", "@hyperledger/cactus-plugin-ledger-connector-iroha2": "2.x", "@hyperledger/cactus-plugin-ledger-connector-quorum": "2.x", "@hyperledger/cactus-plugin-ledger-connector-sawtooth": "2.x" @@ -82,9 +80,6 @@ "@hyperledger/cactus-plugin-ledger-connector-fabric": { "optional": true }, - "@hyperledger/cactus-plugin-ledger-connector-iroha": { - "optional": true - }, "@hyperledger/cactus-plugin-ledger-connector-iroha2": { "optional": true }, diff --git a/packages/cactus-verifier-client/src/main/typescript/get-validator-api-client.ts b/packages/cactus-verifier-client/src/main/typescript/get-validator-api-client.ts index 0c356a6f31..b097333fca 100644 --- a/packages/cactus-verifier-client/src/main/typescript/get-validator-api-client.ts +++ b/packages/cactus-verifier-client/src/main/typescript/get-validator-api-client.ts @@ -25,10 +25,6 @@ import type { CordaApiClient, CordaApiClientOptions, } from "@hyperledger/cactus-plugin-ledger-connector-corda"; -import type { - IrohaApiClient, - IrohaApiClientOptions, -} from "@hyperledger/cactus-plugin-ledger-connector-iroha"; import type { Iroha2ApiClient, Iroha2ApiClientOptions, @@ -73,10 +69,6 @@ export type ClientApiConfig = { in: CordaApiClientOptions; out: CordaApiClient; }; - IROHA_1X: { - in: IrohaApiClientOptions; - out: IrohaApiClient; - }; IROHA_2X: { in: Iroha2ApiClientOptions; out: Iroha2ApiClient; @@ -126,9 +118,6 @@ export async function getValidatorApiClient( case "CORDA_4X": const cordaPackage = require("@hyperledger/cactus-plugin-ledger-connector-corda"); return new cordaPackage.CordaApiClient(options as CordaApiClientOptions); - case "IROHA_1X": - const irohaPackage = require("@hyperledger/cactus-plugin-ledger-connector-iroha"); - return new irohaPackage.IrohaApiClient(options as IrohaApiClientOptions); case "IROHA_2X": const iroha2Package = require("@hyperledger/cactus-plugin-ledger-connector-iroha2"); return new iroha2Package.Iroha2ApiClient( diff --git a/packages/cactus-verifier-client/tsconfig.json b/packages/cactus-verifier-client/tsconfig.json index da75c3d8b9..ca6e0543d2 100644 --- a/packages/cactus-verifier-client/tsconfig.json +++ b/packages/cactus-verifier-client/tsconfig.json @@ -32,9 +32,6 @@ { "path": "../cactus-plugin-ledger-connector-corda/tsconfig.json" }, - { - "path": "../cactus-plugin-ledger-connector-iroha/tsconfig.json" - }, { "path": "../cactus-plugin-ledger-connector-iroha2/tsconfig.json" }, diff --git a/tools/docker/iroha-all-in-one/Dockerfile b/tools/docker/iroha-all-in-one/Dockerfile deleted file mode 100644 index 9c006b9ab6..0000000000 --- a/tools/docker/iroha-all-in-one/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM hyperledger/iroha:1.4.0-patch-3 - -ARG DEBIAN_FRONTEND=noninteractive -RUN set -e && apt-get update && \ - apt-get install -y moreutils jq wget python3 python3-pip && \ - pip install iroha && \ - apt-get purge -y `apt-get -s purge python3-pip | grep '^ ' | tr -d '*'` && \ - apt-get -y clean && \ - rm -rf /var/lib/apt/lists/* - -COPY genesis.block /opt/iroha_data/genesis.block -COPY entrypoint.sh healthcheck.py / -RUN chmod +x /entrypoint.sh - -WORKDIR /opt/iroha_data - -RUN wget https://raw.githubusercontent.com/hyperledger/iroha/v1.4.0-patch-3/example/admin%40test.pub --output-document=admin@test.pub -RUN wget https://raw.githubusercontent.com/hyperledger/iroha/v1.4.0-patch-3/example/admin%40test.priv --output-document=admin@test.priv -RUN wget https://raw.githubusercontent.com/hyperledger/iroha/v1.4.0-patch-3/example/node0.pub -RUN wget https://raw.githubusercontent.com/hyperledger/iroha/v1.4.0-patch-3/example/node0.priv - -ENTRYPOINT ["/entrypoint.sh"] - -CMD ["irohad"] \ No newline at end of file diff --git a/tools/docker/iroha-all-in-one/README.md b/tools/docker/iroha-all-in-one/README.md deleted file mode 100644 index 35f39311aa..0000000000 --- a/tools/docker/iroha-all-in-one/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Iroha All in One Image - -The Iroha All in One Image (Iroha AIO) is a convenient tool for test automation purposes. It is flexible enough to start programmatically without extra dependencies or host machines such as specific Iroha network/volumes, making it labor-saving for us to carry out automated tests. - -Iroha AIO trims everything down to make it as slim as possible but ensures all functionalities of Iroha. This makes it much easier to pull up tests about functionality rather than running a production-grade ledger. The smaller package also makes the production environment more robust since the CI environment machines are not very powerful. An all in one Iroha + Postgres image that uses about 0.5 GB of RAM and one vCPU worth of hardware resources idling. - -The following ports are open on the container: - -```yaml -- 50051:50051/tcp # Iroha RPC - Torii -- 5432:5432/tcp # PostgreSQL -``` - -## Build an image locally - -```sh -DOCKER_BUILDKIT=1 docker build ./tools/docker/iroha-all-in-one/ -t iaio -``` - - -## Shell into a running container: - -```sh -docker run -it --entrypoint bash iaio -``` - -## Logs of Iroha Ledger via shell: - -```sh -docker logs iaio -``` diff --git a/tools/docker/iroha-all-in-one/entrypoint.sh b/tools/docker/iroha-all-in-one/entrypoint.sh deleted file mode 100644 index 6412d693ec..0000000000 --- a/tools/docker/iroha-all-in-one/entrypoint.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash -set -e - -if [ ! $ADMIN_PRIV = *" "* ] && [ -n "$ADMIN_PRIV" ]; then - sed -i "1s/.*/$ADMIN_PRIV/" admin@test.priv -fi - -if [ ! $ADMIN_PUB = *" "* ] && [ -n "$ADMIN_PUB" ]; then - sed -i "1s/.*/$ADMIN_PUB/" admin@test.pub - jq --arg adminPub "${ADMIN_PUB}" \ - '.block_v1.payload.transactions[0].payload.reducedPayload.commands[8].createAccount.publicKey = $adminPub' \ - genesis.block|sponge genesis.block -fi - -if [ ! $NODE_PRIV = *" "* ] && [ -n "$NODE_PRIV" ]; then - sed -i "1s/.*/$NODE_PRIV/" node0.priv -fi - -if [ ! $NODE_PUB = *" "* ] && [ -n "$NODE_PUB" ]; then - sed -i "1s/.*/$NODE_PUB/" node0.pub - jq --arg nodePub "${NODE_PUB}" \ - '.block_v1.payload.transactions[0].payload.reducedPayload.commands[0].addPeer.peer.peerKey = $nodePub' \ - genesis.block|sponge genesis.block -fi - -# if first arg looks like a flag, assume we want to run irohad server -if [ "${1:0:1}" = '-' ]; then - set -- irohad "$@" -fi - -if [ "$1" = 'irohad' ]; then - echo key=$KEY - echo $PWD - if [ -n "$IROHA_POSTGRES_HOST" ]; then - echo "NOTE: IROHA_POSTGRES_HOST should match 'host' option in config file" - PG_PORT=${IROHA_POSTGRES_PORT:-5432} - /wait-for-it.sh -h $IROHA_POSTGRES_HOST -p $PG_PORT -t 30 -- true - else - echo "WARNING: IROHA_POSTGRES_HOST is not defined. - Do not wait for Postgres to become ready. Iroha may fail to start up" - fi - exec "$@" --genesis_block genesis.block --keypair_name $KEY --verbosity=${IROHA_LOG_LEVEL} -fi - -exec "$@" \ No newline at end of file diff --git a/tools/docker/iroha-all-in-one/genesis.block b/tools/docker/iroha-all-in-one/genesis.block deleted file mode 100644 index e7486b21cf..0000000000 --- a/tools/docker/iroha-all-in-one/genesis.block +++ /dev/null @@ -1,162 +0,0 @@ -{ - "block_v1": { - "payload": { - "transactions": [ - { - "payload": { - "reducedPayload": { - "commands": [ - { - "addPeer":{ - "peer":{ - "address":"127.0.0.1:10001", - "peerKey":"bddd58404d1315e0eb27902c5d7c8eb0602c16238f005773df406bc191308929" - } - } - }, - { - "createRole": { - "roleName": "cactus_test", - "permissions": [ - "can_add_peer", - "can_add_signatory", - "can_create_account", - "can_create_domain", - "can_get_all_acc_ast", - "can_get_all_acc_ast_txs", - "can_get_all_acc_detail", - "can_get_all_acc_txs", - "can_get_all_accounts", - "can_get_all_signatories", - "can_get_all_txs", - "can_get_blocks", - "can_get_roles", - "can_read_assets", - "can_remove_signatory", - "can_set_quorum" - ] - } - }, - { - "createRole": { - "roleName": "cactus_test_full", - "permissions": [ - "root" - ] - } - }, - { - "createRole": { - "roleName": "admin", - "permissions": [ - "can_add_peer", - "can_add_signatory", - "can_create_account", - "can_create_domain", - "can_get_all_acc_ast", - "can_get_all_acc_ast_txs", - "can_get_all_acc_detail", - "can_get_all_acc_txs", - "can_get_all_accounts", - "can_get_all_signatories", - "can_get_all_txs", - "can_get_blocks", - "can_get_roles", - "can_read_assets", - "can_remove_signatory", - "can_set_quorum" - ] - } - }, - { - "createRole": { - "roleName": "user", - "permissions": [ - "can_add_signatory", - "can_get_my_acc_ast", - "can_get_my_acc_ast_txs", - "can_get_my_acc_detail", - "can_get_my_acc_txs", - "can_get_my_account", - "can_get_my_signatories", - "can_get_my_txs", - "can_grant_can_add_my_signatory", - "can_grant_can_remove_my_signatory", - "can_grant_can_set_my_account_detail", - "can_grant_can_set_my_quorum", - "can_grant_can_transfer_my_assets", - "can_receive", - "can_remove_signatory", - "can_set_quorum", - "can_transfer" - ] - } - }, - { - "createRole": { - "roleName": "money_creator", - "permissions": [ - "can_add_asset_qty", - "can_create_asset", - "can_receive", - "can_transfer" - ] - } - }, - { - "createDomain": { - "domainId": "test", - "defaultRole": "user" - } - }, - { - "createAsset": { - "assetName": "coin", - "domainId": "test", - "precision": 2 - } - }, - { - "createAccount": { - "accountName": "admin", - "domainId": "test", - "publicKey": "313a07e6384776ed95447710d15e59148473ccfc052a681317a72a69f2a49910" - } - }, - { - "createAccount": { - "accountName": "test", - "domainId": "test", - "publicKey": "716fe505f69f18511a1b083915aa9ff73ef36e6688199f3959750db38b8f4bfc" - } - }, - { - "appendRole": { - "accountId": "admin@test", - "roleName": "admin" - } - }, - { - "appendRole": { - "accountId": "admin@test", - "roleName": "money_creator" - } - }, - { - "appendRole": { - "accountId": "admin@test", - "roleName": "cactus_test_full" - } - } - ], - "quorum": 1 - } - } - } - ], - "txNumber": 1, - "height": "1", - "prevBlockHash": "0000000000000000000000000000000000000000000000000000000000000000" - } - } -} diff --git a/tools/docker/iroha-all-in-one/healthcheck.py b/tools/docker/iroha-all-in-one/healthcheck.py deleted file mode 100644 index cb7a8eeb2b..0000000000 --- a/tools/docker/iroha-all-in-one/healthcheck.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -import sys -from iroha import Iroha, IrohaCrypto, IrohaGrpc - -ADMIN_ACCOUNT_ID = os.getenv("ADMIN_ACCOUNT_ID", "admin@test") -iroha_admin = Iroha(ADMIN_ACCOUNT_ID) -user_account = "admin@test" -iroha_user = Iroha(user_account) - - -def get_account(account: str, port: str): - """Health check function""" - # setup of iroha client address - host = "127.0.0.1" - net = IrohaGrpc(f"{host}:{port}") - query = iroha_user.query("GetAccount", account_id=account) - try: - with open('/opt/iroha_data/admin@test.priv', 'r') as file: - admin_private_key = file.read().strip() - except Exception as e: - print("Unable to read admin private key! Reason:", e) - sys.exit(1) - IrohaCrypto.sign_query(query, admin_private_key) - response = net.send_query(query) - # health check passes when response contains value of account parameter - if response.account_response.account.account_id == user_account: - print("Success!") - sys.exit(0) - # health check fails when response does not contain "admin@test" - else: - print( - f"Successful connection, but account '{account}' does not exist!") - sys.exit(1) - - -if __name__ == "__main__": - if len(sys.argv) != 3: - print("Must pass in 2 parameters as arguments! \n") - print("Example: python3 heathcheck.py account ToriiPort") - sys.exit(1) - else: - try: - get_account(sys.argv[1], sys.argv[2]) - # health check fails when connection with Iroha client cannot establish - except Exception as e: - print("Connection failure! Reason:", e) - sys.exit(1) diff --git a/tsconfig.json b/tsconfig.json index 27a1cb1767..d53718a03c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -76,9 +76,6 @@ { "path": "./packages/cactus-plugin-ledger-connector-cdl/tsconfig.json" }, - { - "path": "./packages/cactus-plugin-ledger-connector-iroha/tsconfig.json" - }, { "path": "./packages/cactus-plugin-ledger-connector-tcs-huawei-socketio/tsconfig.json" }, diff --git a/yarn.lock b/yarn.lock index 9184dcbec3..d9e977d097 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8621,40 +8621,6 @@ __metadata: languageName: unknown linkType: soft -"@hyperledger/cactus-plugin-ledger-connector-iroha@npm:2.0.0-alpha.2, @hyperledger/cactus-plugin-ledger-connector-iroha@workspace:packages/cactus-plugin-ledger-connector-iroha": - version: 0.0.0-use.local - resolution: "@hyperledger/cactus-plugin-ledger-connector-iroha@workspace:packages/cactus-plugin-ledger-connector-iroha" - dependencies: - "@grpc/grpc-js": "npm:1.10.3" - "@hyperledger/cactus-common": "npm:2.0.0-alpha.2" - "@hyperledger/cactus-core": "npm:2.0.0-alpha.2" - "@hyperledger/cactus-core-api": "npm:2.0.0-alpha.2" - "@hyperledger/cactus-plugin-keychain-memory": "npm:2.0.0-alpha.2" - "@hyperledger/cactus-test-tooling": "npm:2.0.0-alpha.2" - "@types/body-parser": "npm:1.19.4" - "@types/express": "npm:4.17.19" - "@types/google-protobuf": "npm:3.15.5" - "@types/sanitize-html": "npm:2.9.5" - "@types/uuid": "npm:9.0.8" - axios: "npm:1.6.0" - body-parser: "npm:1.20.2" - express: "npm:4.19.2" - fast-safe-stringify: "npm:2.1.1" - internal-ip: "npm:6.2.0" - iroha-helpers: "npm:1.5.0" - key-encoder: "npm:2.0.3" - openapi-types: "npm:12.1.3" - prom-client: "npm:13.1.0" - run-time-error-cjs: "npm:1.4.0" - rxjs: "npm:7.8.1" - sanitize-html: "npm:2.12.1" - socket.io: "npm:4.5.4" - socket.io-client-fixed-types: "npm:4.5.4" - typescript-optional: "npm:2.0.1" - uuid: "npm:9.0.1" - languageName: unknown - linkType: soft - "@hyperledger/cactus-plugin-ledger-connector-polkadot@workspace:packages/cactus-plugin-ledger-connector-polkadot": version: 0.0.0-use.local resolution: "@hyperledger/cactus-plugin-ledger-connector-polkadot@workspace:packages/cactus-plugin-ledger-connector-polkadot" @@ -9237,7 +9203,6 @@ __metadata: "@hyperledger/cactus-plugin-ledger-connector-corda": "npm:2.0.0-alpha.2" "@hyperledger/cactus-plugin-ledger-connector-ethereum": "npm:2.0.0-alpha.2" "@hyperledger/cactus-plugin-ledger-connector-fabric": "npm:2.0.0-alpha.2" - "@hyperledger/cactus-plugin-ledger-connector-iroha": "npm:2.0.0-alpha.2" "@hyperledger/cactus-plugin-ledger-connector-iroha2": "npm:2.0.0-alpha.2" "@hyperledger/cactus-plugin-ledger-connector-quorum": "npm:2.0.0-alpha.2" "@hyperledger/cactus-plugin-ledger-connector-sawtooth": "npm:2.0.0-alpha.2" @@ -9249,7 +9214,6 @@ __metadata: "@hyperledger/cactus-plugin-ledger-connector-corda": 2.x "@hyperledger/cactus-plugin-ledger-connector-ethereum": 2.x "@hyperledger/cactus-plugin-ledger-connector-fabric": 2.x - "@hyperledger/cactus-plugin-ledger-connector-iroha": 2.x "@hyperledger/cactus-plugin-ledger-connector-iroha2": 2.x "@hyperledger/cactus-plugin-ledger-connector-quorum": 2.x "@hyperledger/cactus-plugin-ledger-connector-sawtooth": 2.x @@ -9262,8 +9226,6 @@ __metadata: optional: true "@hyperledger/cactus-plugin-ledger-connector-fabric": optional: true - "@hyperledger/cactus-plugin-ledger-connector-iroha": - optional: true "@hyperledger/cactus-plugin-ledger-connector-iroha2": optional: true "@hyperledger/cactus-plugin-ledger-connector-quorum": @@ -9462,17 +9424,6 @@ __metadata: languageName: node linkType: hard -"@improbable-eng/grpc-web@npm:^0.12.0": - version: 0.12.0 - resolution: "@improbable-eng/grpc-web@npm:0.12.0" - dependencies: - browser-headers: "npm:^0.4.0" - peerDependencies: - google-protobuf: ^3.2.0 - checksum: 10/84ce510973ab8990994c42a1effd0372a4d1f4bd4998de8ac719b7e2ed48b20cfcb167493de20b6a1b9048db58d16b6ad44368c72e2b442732e64bb4ffd4e8a1 - languageName: node - linkType: hard - "@ionic-native/core@npm:5.36.0": version: 5.36.0 resolution: "@ionic-native/core@npm:5.36.0" @@ -18375,55 +18326,6 @@ __metadata: languageName: node linkType: hard -"babel-helper-evaluate-path@npm:^0.5.0": - version: 0.5.0 - resolution: "babel-helper-evaluate-path@npm:0.5.0" - checksum: 10/b5d103af0ee6f0d3a7306e53b54c2518b16420a08e5b8cd96f1e3f4c31c1c645e4671b01b721a2c3e9a7ca619c5dbba0edec5e5231f4891d576450b1dca9d52f - languageName: node - linkType: hard - -"babel-helper-flip-expressions@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-helper-flip-expressions@npm:0.4.3" - checksum: 10/52174b03edfca1c722b115fae7046d3ddfd726d2e240cb018c6877b1b9baef7a07f9853ed33a37ee7eeebb5769b1748a0cffbd303f9b5a454e18420e0f0a859b - languageName: node - linkType: hard - -"babel-helper-is-nodes-equiv@npm:^0.0.1": - version: 0.0.1 - resolution: "babel-helper-is-nodes-equiv@npm:0.0.1" - checksum: 10/8621bf12fe5e8238c2de125be278e57f02233fa0e0cf59e0f6b8218b9699eac7a3f71087c8fac5981a80d0941382b34794c642cbbffe363286ac49601b4584ef - languageName: node - linkType: hard - -"babel-helper-is-void-0@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-helper-is-void-0@npm:0.4.3" - checksum: 10/0aa68c822c21b3688161d9748b83cc25062a1d4ea39c342c17c7f59d33993de476338d01a3b6218d99f725287be03638d3119d5fe774319eb87054e04e06cf43 - languageName: node - linkType: hard - -"babel-helper-mark-eval-scopes@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-helper-mark-eval-scopes@npm:0.4.3" - checksum: 10/b78a47e505fb48cf9966da8b5b237b3e4bdf4ca5659a6453db00500f5cf0dc6ee5a7bf038da74dfbdf2524aef802a68870220f5b94fd17f9545d2ec30b32bac2 - languageName: node - linkType: hard - -"babel-helper-remove-or-void@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-helper-remove-or-void@npm:0.4.3" - checksum: 10/6a2c305c31cb0974a2fd6c860a6685612b4a7ad2cd6b056807f183d9ef5c86f669c002f454fe6729bfd594e5f7349b1f7f06b2107acd7e353e1ccfb2e4d8f32e - languageName: node - linkType: hard - -"babel-helper-to-multiple-sequence-expressions@npm:^0.5.0": - version: 0.5.0 - resolution: "babel-helper-to-multiple-sequence-expressions@npm:0.5.0" - checksum: 10/f8f07139eefc87b3e3f7733250b638cb61e03567060bded12934f48800ec07e86a304815e49a4b83610b549234aeb9db9ff1dc71a7bde1442d37e9ebed658ba0 - languageName: node - linkType: hard - "babel-jest@npm:^27.4.2, babel-jest@npm:^27.5.1": version: 27.5.1 resolution: "babel-jest@npm:27.5.1" @@ -18550,104 +18452,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-minify-builtins@npm:^0.5.0": - version: 0.5.0 - resolution: "babel-plugin-minify-builtins@npm:0.5.0" - checksum: 10/590554929e1b9aacaaa2c9553be177c296af99659eede7d506d7467fd8cab46a8bcef4b776980fcf46434d8905c48abb1f31fac008efad84c6701bee6b7061cd - languageName: node - linkType: hard - -"babel-plugin-minify-constant-folding@npm:^0.5.0": - version: 0.5.0 - resolution: "babel-plugin-minify-constant-folding@npm:0.5.0" - dependencies: - babel-helper-evaluate-path: "npm:^0.5.0" - checksum: 10/e6f495cc93e59e65b154f6be32cea90b1bf5e15d95e4f0311e39600339098cc0695e7b8947d4014f588fac228d0e1082bcede76bd908cae2e3929c40ae63fc30 - languageName: node - linkType: hard - -"babel-plugin-minify-dead-code-elimination@npm:^0.5.1": - version: 0.5.1 - resolution: "babel-plugin-minify-dead-code-elimination@npm:0.5.1" - dependencies: - babel-helper-evaluate-path: "npm:^0.5.0" - babel-helper-mark-eval-scopes: "npm:^0.4.3" - babel-helper-remove-or-void: "npm:^0.4.3" - lodash: "npm:^4.17.11" - checksum: 10/afa23e78f64e8039115c102bba4ba9532f88c3ff5cab203a935c6e69b0892edc46c768fe26363379c7fa0dfd9408b62a28b86b6ea9716578e25491542f2d0bbd - languageName: node - linkType: hard - -"babel-plugin-minify-flip-comparisons@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-plugin-minify-flip-comparisons@npm:0.4.3" - dependencies: - babel-helper-is-void-0: "npm:^0.4.3" - checksum: 10/54e068f926083d6ae539a13d096a9fa564339717ee607f9b3bded360344d377fa6dd47ada377ac445f98462d03d78cdf772efcaa366c692888f325c6382ab6a6 - languageName: node - linkType: hard - -"babel-plugin-minify-guarded-expressions@npm:^0.4.4": - version: 0.4.4 - resolution: "babel-plugin-minify-guarded-expressions@npm:0.4.4" - dependencies: - babel-helper-evaluate-path: "npm:^0.5.0" - babel-helper-flip-expressions: "npm:^0.4.3" - checksum: 10/6071558a5bdc64ed811809d66ad9982ea3ead16ac32f09d4f17e41b07b2106d9b0d12641758f89cfa1dff94fdfb3df8afed908ff1c0e50972b0312cc66d09a75 - languageName: node - linkType: hard - -"babel-plugin-minify-infinity@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-plugin-minify-infinity@npm:0.4.3" - checksum: 10/d63d83390286949043adf43016150a46d8d7b4d500cdd684a24322d2ec9153127af0c2df36debe3096e12eff3712d4974935585953d0337a09966f0ec5c81f84 - languageName: node - linkType: hard - -"babel-plugin-minify-mangle-names@npm:^0.5.0": - version: 0.5.0 - resolution: "babel-plugin-minify-mangle-names@npm:0.5.0" - dependencies: - babel-helper-mark-eval-scopes: "npm:^0.4.3" - checksum: 10/657924e7b8584bb25b703ac99fc5d54f9f36b0128477409a513f4fac400605cbfd96bc3cbc55d447479173e7e5dcf195de164a58d7671dbae7a21ce707cc92b0 - languageName: node - linkType: hard - -"babel-plugin-minify-numeric-literals@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-plugin-minify-numeric-literals@npm:0.4.3" - checksum: 10/8327b43e06ead88c13558ecaa5faf32bbca0e3f726fce93b59bac92d423291abbe6912419ba4b9f669253318cdf04381c5d6d6eabacaafd51a69c9242975dc5b - languageName: node - linkType: hard - -"babel-plugin-minify-replace@npm:^0.5.0": - version: 0.5.0 - resolution: "babel-plugin-minify-replace@npm:0.5.0" - checksum: 10/eca0ef9c9197b55b7c6467fb097fe3f266ca64293eda0c1254303897923df11e9f5a9c25888de98da6a4fc32debe2651d50bdcebb667553013be4875543480f6 - languageName: node - linkType: hard - -"babel-plugin-minify-simplify@npm:^0.5.1": - version: 0.5.1 - resolution: "babel-plugin-minify-simplify@npm:0.5.1" - dependencies: - babel-helper-evaluate-path: "npm:^0.5.0" - babel-helper-flip-expressions: "npm:^0.4.3" - babel-helper-is-nodes-equiv: "npm:^0.0.1" - babel-helper-to-multiple-sequence-expressions: "npm:^0.5.0" - checksum: 10/ad857a7de659f054ecd8185a19f369b1fa6887fbd8a94d4205a5c2b66fe53a56aca002fbb26ac2d84a334df031948004eebe375abbe6c21a0568737cbdfc3cbb - languageName: node - linkType: hard - -"babel-plugin-minify-type-constructors@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-plugin-minify-type-constructors@npm:0.4.3" - dependencies: - babel-helper-is-void-0: "npm:^0.4.3" - checksum: 10/2c6cb97aa8a20c990fc17afd1141e586a1920419bc8a93d2231e7f5f6dcdfbc060c1839873c192c7828040f95ff74b65b8b0af6eb5c54b795e86cf62152ba41e - languageName: node - linkType: hard - "babel-plugin-named-asset-import@npm:^0.3.8": version: 0.3.8 resolution: "babel-plugin-named-asset-import@npm:0.3.8" @@ -18729,43 +18533,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-transform-inline-consecutive-adds@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-plugin-transform-inline-consecutive-adds@npm:0.4.3" - checksum: 10/403735ea07d75e7e12ed1b1dcb3af7530b7639d06c5ab9a2d3699affcd9258fb783b634beb30ac3a5460f7bddf575964ae8c86b2235ef801cdf68cf3491f6664 - languageName: node - linkType: hard - -"babel-plugin-transform-member-expression-literals@npm:^6.9.4": - version: 6.9.4 - resolution: "babel-plugin-transform-member-expression-literals@npm:6.9.4" - checksum: 10/0008ca6f50dbeb7642422ed2c8024a05adc3cb9cad89993e7e1f1fa9bf085574bd874e853857fe441aff4b52ff2c1d7ea273c89da0ca6711a43de317ecf35cfb - languageName: node - linkType: hard - -"babel-plugin-transform-merge-sibling-variables@npm:^6.9.4": - version: 6.9.4 - resolution: "babel-plugin-transform-merge-sibling-variables@npm:6.9.4" - checksum: 10/ff09d225c0a0b54c6cdff82974023895d31c94c65592f29ae61d4a31a14a2a72d725e3a860bc11d1d2e360ed7be38d47d7a88ba6a1c9d4bbf7a41bb70e322c3a - languageName: node - linkType: hard - -"babel-plugin-transform-minify-booleans@npm:^6.9.4": - version: 6.9.4 - resolution: "babel-plugin-transform-minify-booleans@npm:6.9.4" - checksum: 10/d8553742aa5ddfbcbc9c34c05bf4dce1148026b6aa860b3f1d0f7c8820f8d88e21dca148387c1ddf1e94b5fa7d7f39476bc8c07f082639aee2b841d8df5afc4c - languageName: node - linkType: hard - -"babel-plugin-transform-property-literals@npm:^6.9.4": - version: 6.9.4 - resolution: "babel-plugin-transform-property-literals@npm:6.9.4" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10/14da12703c8b49841594670688c50dc2f7b2be88b5681c70311f5f88b27a50782747a04e9fe1b232b7d2c2a9f223228c61fe6fe41ae0c4eb8208e3a890b2a19d - languageName: node - linkType: hard - "babel-plugin-transform-react-remove-prop-types@npm:^0.4.24": version: 0.4.24 resolution: "babel-plugin-transform-react-remove-prop-types@npm:0.4.24" @@ -18773,50 +18540,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-transform-regexp-constructors@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-plugin-transform-regexp-constructors@npm:0.4.3" - checksum: 10/242228775b2c9e7d147a3bc3f8e0ce5d903f3baf7b238edc6c4fe4d95d05f84cc4722f37598cae437c26ffc24d63262550abb79d28eefe3c34d98b36be6d4f17 - languageName: node - linkType: hard - -"babel-plugin-transform-remove-console@npm:^6.9.4": - version: 6.9.4 - resolution: "babel-plugin-transform-remove-console@npm:6.9.4" - checksum: 10/1123c3816c6f89c064752199c8796f30265d937f5d8e1e43d3837f1c0e87ed0e6bbd0afa6117ce021c8b93ec1de7154e158674bb22331c7ed6609d10121359df - languageName: node - linkType: hard - -"babel-plugin-transform-remove-debugger@npm:^6.9.4": - version: 6.9.4 - resolution: "babel-plugin-transform-remove-debugger@npm:6.9.4" - checksum: 10/ed34e5200dcd6e3f954debb3547baa58c8e422e084984a7d66cac4789bee158424c2d4ab21e0bac25e6818316d9c8ca758a976cf20ac333073146089eae6d49c - languageName: node - linkType: hard - -"babel-plugin-transform-remove-undefined@npm:^0.5.0": - version: 0.5.0 - resolution: "babel-plugin-transform-remove-undefined@npm:0.5.0" - dependencies: - babel-helper-evaluate-path: "npm:^0.5.0" - checksum: 10/3cdb4fae842bad9bcd907bbf6614f09dc04c819cec9ef7850d3d40a6a70c155caf8e0f4a11d2be8102b6f9a7e1fa0fca43557a2655780c5376cf6f81e47ff88b - languageName: node - linkType: hard - -"babel-plugin-transform-simplify-comparison-operators@npm:^6.9.4": - version: 6.9.4 - resolution: "babel-plugin-transform-simplify-comparison-operators@npm:6.9.4" - checksum: 10/0b51e361d4c8c7a5b8813a4d652232c3185c3a17c0f0529676f706da876be1432a5bfc3a418fb801e266db67f12f2b92d4bef93a1c5f4582a3cb4edd2de457c2 - languageName: node - linkType: hard - -"babel-plugin-transform-undefined-to-void@npm:^6.9.4": - version: 6.9.4 - resolution: "babel-plugin-transform-undefined-to-void@npm:6.9.4" - checksum: 10/dd4d89b3e884ed0a35c0a0690fdfa4cf9d5a1678b796a20bc05467f68fc5e186c5f77bc127870811337deb989afed6f6775fb8eab94646fcc7ed1a454c455a95 - languageName: node - linkType: hard - "babel-preset-current-node-syntax@npm:^1.0.0": version: 1.0.1 resolution: "babel-preset-current-node-syntax@npm:1.0.1" @@ -18863,37 +18586,6 @@ __metadata: languageName: node linkType: hard -"babel-preset-minify@npm:^0.5.1": - version: 0.5.1 - resolution: "babel-preset-minify@npm:0.5.1" - dependencies: - babel-plugin-minify-builtins: "npm:^0.5.0" - babel-plugin-minify-constant-folding: "npm:^0.5.0" - babel-plugin-minify-dead-code-elimination: "npm:^0.5.1" - babel-plugin-minify-flip-comparisons: "npm:^0.4.3" - babel-plugin-minify-guarded-expressions: "npm:^0.4.4" - babel-plugin-minify-infinity: "npm:^0.4.3" - babel-plugin-minify-mangle-names: "npm:^0.5.0" - babel-plugin-minify-numeric-literals: "npm:^0.4.3" - babel-plugin-minify-replace: "npm:^0.5.0" - babel-plugin-minify-simplify: "npm:^0.5.1" - babel-plugin-minify-type-constructors: "npm:^0.4.3" - babel-plugin-transform-inline-consecutive-adds: "npm:^0.4.3" - babel-plugin-transform-member-expression-literals: "npm:^6.9.4" - babel-plugin-transform-merge-sibling-variables: "npm:^6.9.4" - babel-plugin-transform-minify-booleans: "npm:^6.9.4" - babel-plugin-transform-property-literals: "npm:^6.9.4" - babel-plugin-transform-regexp-constructors: "npm:^0.4.3" - babel-plugin-transform-remove-console: "npm:^6.9.4" - babel-plugin-transform-remove-debugger: "npm:^6.9.4" - babel-plugin-transform-remove-undefined: "npm:^0.5.0" - babel-plugin-transform-simplify-comparison-operators: "npm:^6.9.4" - babel-plugin-transform-undefined-to-void: "npm:^6.9.4" - lodash: "npm:^4.17.11" - checksum: 10/48a0045717fce3bf02d3ca0315aa5e2fe94decab4677a413b04310a0b02732285a0ab6323cb3c40133471e4ad24d9ff5457c2afa3a4f78685ef4060a06dfbcf6 - languageName: node - linkType: hard - "babel-preset-react-app@npm:^10.0.1": version: 10.0.1 resolution: "babel-preset-react-app@npm:10.0.1" @@ -19503,13 +19195,6 @@ __metadata: languageName: node linkType: hard -"browser-headers@npm:^0.4.0": - version: 0.4.1 - resolution: "browser-headers@npm:0.4.1" - checksum: 10/0f599f43762104bcc86e1f48c7575ba03ef01dbf44dcbb8a50359cdc165571bfb135cb826268b5ef39f457b7e40f9a2b87f94d3867e27de6a489419add8f4d56 - languageName: node - linkType: hard - "browser-level@npm:^1.0.1": version: 1.0.1 resolution: "browser-level@npm:1.0.1" @@ -19850,16 +19535,6 @@ __metadata: languageName: node linkType: hard -"buffer@npm:5.0.2": - version: 5.0.2 - resolution: "buffer@npm:5.0.2" - dependencies: - base64-js: "npm:^1.0.2" - ieee754: "npm:^1.1.4" - checksum: 10/43589b33cdc4e9eab73c3ec6ae8f8712f06c9348fd0197825daebad4c038559d3ef4cd07f39db49cca25393a4eb545efdde98f34b7cb8d39ca28042f7b0ef369 - languageName: node - linkType: hard - "buffer@npm:6.0.3, buffer@npm:^6.0.0, buffer@npm:^6.0.1, buffer@npm:^6.0.3": version: 6.0.3 resolution: "buffer@npm:6.0.3" @@ -19870,7 +19545,7 @@ __metadata: languageName: node linkType: hard -"buffer@npm:^5.0.5, buffer@npm:^5.2.1, buffer@npm:^5.4.0, buffer@npm:^5.5.0, buffer@npm:^5.6.0": +"buffer@npm:^5.0.5, buffer@npm:^5.2.1, buffer@npm:^5.5.0, buffer@npm:^5.6.0": version: 5.7.1 resolution: "buffer@npm:5.7.1" dependencies: @@ -24298,15 +23973,6 @@ __metadata: languageName: node linkType: hard -"ed25519.js@npm:^1.3.0": - version: 1.3.0 - resolution: "ed25519.js@npm:1.3.0" - dependencies: - buffer: "npm:5.0.2" - checksum: 10/4325bb24b6e97a5ec69787913f949ff8cee9bc223e9604affe7edeb9bbfa9bd8537b2e80ff258ec2cabadca3040ff833de1c1fd1127a320b8a0123377a0187e9 - languageName: node - linkType: hard - "ee-first@npm:1.1.1": version: 1.1.1 resolution: "ee-first@npm:1.1.1" @@ -29359,13 +29025,6 @@ __metadata: languageName: node linkType: hard -"google-protobuf@npm:^3.6.1, google-protobuf@npm:^3.9.1": - version: 3.19.4 - resolution: "google-protobuf@npm:3.19.4" - checksum: 10/3691ec1e72e38a0f18e36573077ec0f7e63301196a8fe786bf84ef926ec2f4ce7b5743b27f2c0b65095cfa924240b9f09647213fad7be4db6d77c410f96509f3 - languageName: node - linkType: hard - "gopd@npm:^1.0.1": version: 1.0.1 resolution: "gopd@npm:1.0.1" @@ -31209,27 +30868,6 @@ __metadata: languageName: node linkType: hard -"iroha-helpers@npm:1.5.0": - version: 1.5.0 - resolution: "iroha-helpers@npm:1.5.0" - dependencies: - "@improbable-eng/grpc-web": "npm:^0.12.0" - babel-preset-minify: "npm:^0.5.1" - buffer: "npm:^5.4.0" - ed25519.js: "npm:^1.3.0" - google-protobuf: "npm:^3.9.1" - js-sha3: "npm:^0.8.0" - lodash.clonedeep: "npm:^4.5.0" - lodash.flow: "npm:^3.5.0" - lodash.isequal: "npm:^4.5.0" - lodash.isplainobject: "npm:^4.0.6" - ts-protoc-gen: "npm:^0.12.0" - tslib: "npm:^1.10.0" - tweetnacl: "npm:^1.0.3" - checksum: 10/a2deabfd5fc4a6860533143bf11cde06c8416e8f6f03e8a6a6251f23d16df1fe265acbd08aff26f1a6179725ae18b5d993d1f58392b9402d31843c46579e2b31 - languageName: node - linkType: hard - "is-accessor-descriptor@npm:^0.1.6": version: 0.1.6 resolution: "is-accessor-descriptor@npm:0.1.6" @@ -35540,13 +35178,6 @@ __metadata: languageName: node linkType: hard -"lodash.flow@npm:^3.5.0": - version: 3.5.0 - resolution: "lodash.flow@npm:3.5.0" - checksum: 10/da39497f388971e1949607882e608d5b2306f025f0b5cc3953f2c25fca7db5a8dba23bd3ddeaed4b0dbd2d44c5aaa6f6f12016b5511b08a3d61de1e1c1f59eb7 - languageName: node - linkType: hard - "lodash.get@npm:^4.4.2": version: 4.4.2 resolution: "lodash.get@npm:4.4.2" @@ -35568,13 +35199,6 @@ __metadata: languageName: node linkType: hard -"lodash.isequal@npm:^4.5.0": - version: 4.5.0 - resolution: "lodash.isequal@npm:4.5.0" - checksum: 10/82fc58a83a1555f8df34ca9a2cd300995ff94018ac12cc47c349655f0ae1d4d92ba346db4c19bbfc90510764e0c00ddcc985a358bdcd4b3b965abf8f2a48a214 - languageName: node - linkType: hard - "lodash.isfunction@npm:^3.0.9": version: 3.0.9 resolution: "lodash.isfunction@npm:3.0.9" @@ -48719,17 +48343,6 @@ __metadata: languageName: node linkType: hard -"ts-protoc-gen@npm:^0.12.0": - version: 0.12.0 - resolution: "ts-protoc-gen@npm:0.12.0" - dependencies: - google-protobuf: "npm:^3.6.1" - bin: - protoc-gen-ts: bin/protoc-gen-ts - checksum: 10/863f0d5360378b84bcf963ab21e7326d50d4f10010a3a0503a8ff88151f9a8cb8b6af0034768c3b4a08680cdedef22df65c408a81bebdae7dbd5c6496729b16f - languageName: node - linkType: hard - "tsconfig-paths@npm:^3.14.2": version: 3.14.2 resolution: "tsconfig-paths@npm:3.14.2" @@ -48800,7 +48413,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.10.0, tslib@npm:^1.13.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3": +"tslib@npm:^1.13.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: 10/7dbf34e6f55c6492637adb81b555af5e3b4f9cc6b998fb440dac82d3b42bdc91560a35a5fb75e20e24a076c651438234da6743d139e4feabf0783f3cdfe1dddb