From 22f389fc311490e5f3959b4f80e7f4caf4ac5804 Mon Sep 17 00:00:00 2001 From: eduv09 Date: Tue, 26 Mar 2024 13:32:50 +0000 Subject: [PATCH] feat(bungee-hermes): viewProof & ethereum strategy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Views have new attribute viewProof * This attribute has the roots of all state proofs and transaction proofs in the view * Added new endpoint to verify integrity of view proofs * Created strategy for bungee-hermes to support the ethereum-connector * Created new test for the strategy-ethereum, and altered the API test to test the new viewProof endpoint * Updated documentation to reflect new changes. * Fixes in Fabric Strategy, stateProofs and error handling Co-authored-by: André Augusto Co-authored-by: Rafael Belchior Signed-off-by: eduv09 --- .cspell.json | 2 + .../cactus-plugin-bungee-hermes/README.md | 33 +- .../cactus-plugin-bungee-hermes/package.json | 7 +- .../src/main/json/openapi.json | 70 ++++ .../kotlin-client/.openapi-generator/FILES | 27 -- .../kotlin-client/.openapi-generator/VERSION | 1 - .../generated/openapi/kotlin-client/README.md | 65 ---- .../openapi/kotlin-client/build.gradle | 38 -- .../generated/openapi/kotlin-client/gradlew | 245 ------------ .../openapi/kotlin-client/gradlew.bat | 92 ----- .../openapi/kotlin-client/settings.gradle | 2 - .../openapitools/client/apis/DefaultApi.kt | 261 ------------- .../client/infrastructure/ApiAbstractions.kt | 23 -- .../client/infrastructure/ApiClient.kt | 245 ------------ .../client/infrastructure/ApiResponse.kt | 43 -- .../infrastructure/BigDecimalAdapter.kt | 17 - .../infrastructure/BigIntegerAdapter.kt | 17 - .../client/infrastructure/ByteArrayAdapter.kt | 12 - .../client/infrastructure/Errors.kt | 18 - .../client/infrastructure/LocalDateAdapter.kt | 19 - .../infrastructure/LocalDateTimeAdapter.kt | 19 - .../infrastructure/OffsetDateTimeAdapter.kt | 19 - .../client/infrastructure/PartConfig.kt | 11 - .../client/infrastructure/RequestConfig.kt | 18 - .../client/infrastructure/RequestMethod.kt | 8 - .../infrastructure/ResponseExtensions.kt | 24 -- .../client/infrastructure/Serializer.kt | 23 -- .../client/infrastructure/URIAdapter.kt | 13 - .../client/infrastructure/UUIDAdapter.kt | 13 - .../client/models/CreateViewRequest.kt | 56 --- .../models/CreateViewRequestNetworkDetails.kt | 39 -- .../client/models/CreateViewResponse.kt | 39 -- .../client/models/GetPublicKeyResponse.kt | 35 -- .../generated/openapi/typescript-axios/api.ts | 101 +++++ .../main/typescript/plugin-bungee-hermes.ts | 18 +- .../main/typescript/strategy/strategy-besu.ts | 82 ++-- .../typescript/strategy/strategy-ethereum.ts | 255 ++++++++++++ .../typescript/strategy/strategy-fabric.ts | 134 +++++-- .../view-creation/transaction-proof.ts | 8 +- .../src/main/typescript/view-creation/view.ts | 60 ++- .../verify-merkle-root-endpoint.ts | 109 ++++++ .../integration/besu-test-pruning.test.ts | 1 - .../integration/bungee-api-test.test.ts | 306 ++++++++++++++- .../integration/ethereum-test-basic.test.ts | 366 ++++++++++++++++++ .../cactus-plugin-bungee-hermes/tsconfig.json | 7 +- yarn.lock | 49 ++- 46 files changed, 1523 insertions(+), 1527 deletions(-) delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/FILES delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/VERSION delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/README.md delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/build.gradle delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/gradlew delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/gradlew.bat delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/settings.gradle delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/OffsetDateTimeAdapter.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewRequest.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewRequestNetworkDetails.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewResponse.kt delete mode 100644 packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/GetPublicKeyResponse.kt create mode 100644 packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-ethereum.ts create mode 100644 packages/cactus-plugin-bungee-hermes/src/main/typescript/web-services/verify-merkle-root-endpoint.ts create mode 100644 packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/ethereum-test-basic.test.ts diff --git a/.cspell.json b/.cspell.json index 0b83f409ef..6d8fb626e0 100644 --- a/.cspell.json +++ b/.cspell.json @@ -111,6 +111,8 @@ "lmify", "LOCALMSPID", "mailru", + "Merkle", + "merkletreejs", "miekg", "mitchellh", "MSPCONFIGPATH", diff --git a/packages/cactus-plugin-bungee-hermes/README.md b/packages/cactus-plugin-bungee-hermes/README.md index e176174ae2..c3ef15d7c0 100644 --- a/packages/cactus-plugin-bungee-hermes/README.md +++ b/packages/cactus-plugin-bungee-hermes/README.md @@ -36,13 +36,14 @@ Know how to use the following plugins of the project: - [cactus-plugin-ledger-connector-fabric](https://github.com/hyperledger/cactus/tree/main/packages/cactus-plugin-ledger-connector-fabric) - [cactus-plugin-ledger-connector-besu](https://github.com/hyperledger/cactus/tree/main/packages/cactus-plugin-ledger-connector-besu) + - [cactus-plugin-ledger-connector-ethereum](https://github.com/hyperledger/cactus/tree/main/packages/cactus-plugin-ledger-connector-ethereum) ## Architecture The plugin interacts with a cactus ledger connector, using strategies with custom logic for each different network. -Note that, so far, only strategies for Fabric and Besu networks were implemented. Smart-contracts in Fabric and Besu must implement the interface provided in the files ITraceableContract.ts and ITraceableContract.sol, in the test directory +Note that, so far, only strategies for Fabric, Besu and Ethereum networks were implemented. Smart-contracts for Fabric and EVM based chains must implement the interface provided in the files ITraceableContract.ts and ITraceableContract.sol, in the test directory The plugin stands _behind_ a cacti-ledger-connector, which is used to fetch information from the ledger to create the snapshot. ```typescript @@ -70,10 +71,12 @@ Endpoints exposed: - CreateViewV1 - GetPublicKey - GetAvailableStrategies + - VerifyMerkleRoot ## Running the tests - **besu-test-basic.test.ts**: A test using strategy-besu and a besu connector, testing creating views for different timeframes and states. + - **ethereum-test-basic.test.ts**: A test using strategy-ethereum and a ethereum connector, testing creating views for different timeframes and states. - **fabric-test-basic.test.ts**: A test using strategy-fabric and a fabric connector, testing creating views for different timeframes and states. - **besu-test-pruning.test.ts**: A test using strategy-besu and a besu connector, testing creating views for specific timeframes. - **fabric-test-pruning.test.ts**: A test using strategy-fabric and a fabric connector, testing creating views for specific timeframes. @@ -149,6 +152,34 @@ Note that each strategy can be used to query different ledgers (ledgers of the s Each strategy implements the logic to query information from each different ledger (i.e. capture set of asset states), while bungee-hermes plugin handles the snapshot and view creation. +'View' object contains a 'viewProof'. viewProof is composed by two merkle trees, one for stateProofs and another for transactionProofs. +One can check if the content of a view has no inconsistencies, by querying the VerifyMerkleRoot endpoint with the appropriate input: + +```typescript + //using a previously created View object + + const stateProofs = view?.getSnapshot() + .getStateBins() + .map((x) => JSON.stringify(x.getStateProof())); + const transactionProofs: string[] = []; + view? + .getAllTransactions() + .forEach((t) => transactionProofs.push(JSON.stringify(t.getProof()))); + + const verifyStateRoot = await bungeeApi.verifyMerkleRoot({ + input: stateProofs?.reverse(), //check integrity, order should not matter + root: proof?.statesMerkleRoot, + }); + expect(verifyStateRoot.data.result).toBeTrue(); + + const verifyTransactionsRoot = await bungeeApi.verifyMerkleRoot({ + input: transactionProofs?.reverse(), //check integrity, order should not matter + root: proof?.transactionsMerkleRoot, + }); + expect(verifyTransactionsRoot.data.result).toBeTrue(); +``` + + ## Contributing We welcome contributions to Hyperledger Cactus in many forms, and there’s always plenty to do! diff --git a/packages/cactus-plugin-bungee-hermes/package.json b/packages/cactus-plugin-bungee-hermes/package.json index 6ca875194f..56d9354181 100644 --- a/packages/cactus-plugin-bungee-hermes/package.json +++ b/packages/cactus-plugin-bungee-hermes/package.json @@ -47,7 +47,6 @@ "codegen": "run-p 'codegen:*'", "codegen:openapi": "npm run generate-sdk", "generate-sdk": "run-p 'generate-sdk:*'", - "generate-sdk:kotlin": "openapi-generator-cli generate -i ./src/main/json/openapi.json -g kotlin -o ./src/main/kotlin/generated/openapi/kotlin-client/ --reserved-words-mappings protected=protected --ignore-file-override ../../openapi-generator-ignore", "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", "pretsc": "npm run generate-sdk", "tsc": "tsc --project ./tsconfig.json", @@ -60,19 +59,21 @@ "@hyperledger/cactus-core-api": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-keychain-memory": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-ledger-connector-besu": "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-object-store-ipfs": "2.0.0-alpha.2", - "@hyperledger/cactus-test-tooling": "2.0.0-alpha.2", "axios": "1.6.0", "body-parser": "1.20.2", "fs-extra": "10.1.0", "key-encoder": "2.0.3", + "merkletreejs": "0.3.11", "typescript-optional": "2.0.1", "uuid": "9.0.1", "web3": "1.6.1", "web3-core": "1.6.1" }, "devDependencies": { + "@hyperledger/cactus-test-geth-ledger": "2.0.0-alpha.2", + "@hyperledger/cactus-test-tooling": "2.0.0-alpha.2", "@types/body-parser": "1.19.4", "@types/crypto-js": "4.0.1", "@types/express": "4.17.19", diff --git a/packages/cactus-plugin-bungee-hermes/src/main/json/openapi.json b/packages/cactus-plugin-bungee-hermes/src/main/json/openapi.json index f4cf10bc34..fcd859943c 100644 --- a/packages/cactus-plugin-bungee-hermes/src/main/json/openapi.json +++ b/packages/cactus-plugin-bungee-hermes/src/main/json/openapi.json @@ -110,6 +110,34 @@ "type": "string", "example": "strategy-fabric" } + }, + "VerifyMerkleRootRequest":{ + "type": "object", + "description": "Set of transaction or state proofs and merkle tree root for verification", + "properties": { + "input":{ + "nullable": false, + "type": "array", + "items":{ + "type": "string", + "example": "transactionProof stringified" + } + }, + "root":{ + "nullable": false, + "type": "string" + } + } + }, + "VerifyMerkleRootResponse": { + "type": "object", + "description": "true or false, wether input matched provided root", + "properties": { + "result":{ + "type": "boolean", + "example": "true" + } + } } } }, @@ -216,6 +244,48 @@ } } } + }, + + "/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/verify-merkle-root": { + "get": { + "x-hyperledger-cacti": { + "http": { + "verbLowerCase": "get", + "path": "/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/verify-merkle-root" + } + }, + "operationId": "verifyMerkleRoot", + "summary": "Checks validity of merkle tree root given an input", + "description": "", + "parameters": [], + "requestBody": { + "required": true, + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyMerkleRootRequest" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyMerkleRootResponse" + }, + "example": {"result": true} + } + } + }, + "404": { + "description": "Could not complete request." + } + } + } } } } \ No newline at end of file diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/FILES b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/FILES deleted file mode 100644 index 6aaf4cd1ed..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/FILES +++ /dev/null @@ -1,27 +0,0 @@ -README.md -build.gradle -gradlew -gradlew.bat -settings.gradle -src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt -src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt -src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt -src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt -src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt -src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt -src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt -src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt -src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt -src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt -src/main/kotlin/org/openapitools/client/infrastructure/OffsetDateTimeAdapter.kt -src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt -src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt -src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt -src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt -src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt -src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt -src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt -src/main/kotlin/org/openapitools/client/models/CreateViewRequest.kt -src/main/kotlin/org/openapitools/client/models/CreateViewRequestNetworkDetails.kt -src/main/kotlin/org/openapitools/client/models/CreateViewResponse.kt -src/main/kotlin/org/openapitools/client/models/GetPublicKeyResponse.kt diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/VERSION b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/VERSION deleted file mode 100644 index cd802a1ec4..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/.openapi-generator/VERSION +++ /dev/null @@ -1 +0,0 @@ -6.6.0 \ No newline at end of file diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/README.md b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/README.md deleted file mode 100644 index 0330f07fe0..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# org.openapitools.client - Kotlin client library for Hyperledger Cactus Plugin - BUNGEE-Hermes - -Can create blockchain views of different networks - -## Overview -This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate an API client. - -- API version: 2.0.0-alpha.2 -- Package version: -- Build package: org.openapitools.codegen.languages.KotlinClientCodegen - -## Requires - -* Kotlin 1.7.21 -* Gradle 7.5 - -## Build - -First, create the gradle wrapper script: - -``` -gradle wrapper -``` - -Then, run: - -``` -./gradlew check assemble -``` - -This runs all tests and packages the library. - -## Features/Implementation Notes - -* Supports JSON inputs/outputs, File inputs, and Form inputs. -* Supports collection formats for query parameters: csv, tsv, ssv, pipes. -* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in OpenAPI definitions. -* Implementation of ApiClient is intended to reduce method counts, specifically to benefit Android targets. - - -## Documentation for API Endpoints - -All URIs are relative to *http://localhost:3000/api/v1/@hyperledger/cactus-plugin-satp-hermes* - -Class | Method | HTTP request | Description ------------- | ------------- | ------------- | ------------- -*DefaultApi* | [**createViewV1**](docs/DefaultApi.md#createviewv1) | **GET** /api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/create-view | Creates a Blockchain View. -*DefaultApi* | [**getAvailableStrategies**](docs/DefaultApi.md#getavailablestrategies) | **GET** /api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/get-available-strategies | Queries plugin's available strategies for ledger capture -*DefaultApi* | [**getPublicKey**](docs/DefaultApi.md#getpublickey) | **GET** /api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/get-public-key | Queries plugin's public key - - - -## Documentation for Models - - - [org.openapitools.client.models.CreateViewRequest](docs/CreateViewRequest.md) - - [org.openapitools.client.models.CreateViewRequestNetworkDetails](docs/CreateViewRequestNetworkDetails.md) - - [org.openapitools.client.models.CreateViewResponse](docs/CreateViewResponse.md) - - [org.openapitools.client.models.GetPublicKeyResponse](docs/GetPublicKeyResponse.md) - - - -## Documentation for Authorization - -Endpoints do not require authorization. - diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/build.gradle b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/build.gradle deleted file mode 100644 index 66a3c68b89..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/build.gradle +++ /dev/null @@ -1,38 +0,0 @@ -group 'org.openapitools' -version '1.0.0' - -wrapper { - gradleVersion = '7.5' - distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" -} - -buildscript { - ext.kotlin_version = '1.7.21' - - repositories { - maven { url "https://repo1.maven.org/maven2" } - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -apply plugin: 'kotlin' -apply plugin: 'maven-publish' - -repositories { - maven { url "https://repo1.maven.org/maven2" } -} - -test { - useJUnitPlatform() -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "com.squareup.moshi:moshi-kotlin:1.13.0" - implementation "com.squareup.moshi:moshi-adapters:1.13.0" - implementation "com.squareup.okhttp3:okhttp:4.10.0" - testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2" -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/gradlew b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/gradlew deleted file mode 100644 index aeb74cbb43..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/gradlew +++ /dev/null @@ -1,245 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/gradlew.bat b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/gradlew.bat deleted file mode 100644 index 93e3f59f13..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/settings.gradle b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/settings.gradle deleted file mode 100644 index 391dcea81d..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ - -rootProject.name = 'kotlin-client' \ No newline at end of file diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt deleted file mode 100644 index aa283d52da..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt +++ /dev/null @@ -1,261 +0,0 @@ -/** - * - * Please note: - * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * Do not edit this file manually. - * - */ - -@file:Suppress( - "ArrayInDataClass", - "EnumEntryName", - "RemoveRedundantQualifierName", - "UnusedImport" -) - -package org.openapitools.client.apis - -import java.io.IOException -import okhttp3.OkHttpClient -import okhttp3.HttpUrl - -import org.openapitools.client.models.CreateViewRequest -import org.openapitools.client.models.CreateViewResponse -import org.openapitools.client.models.GetPublicKeyResponse - -import com.squareup.moshi.Json - -import org.openapitools.client.infrastructure.ApiClient -import org.openapitools.client.infrastructure.ApiResponse -import org.openapitools.client.infrastructure.ClientException -import org.openapitools.client.infrastructure.ClientError -import org.openapitools.client.infrastructure.ServerException -import org.openapitools.client.infrastructure.ServerError -import org.openapitools.client.infrastructure.MultiValueMap -import org.openapitools.client.infrastructure.PartConfig -import org.openapitools.client.infrastructure.RequestConfig -import org.openapitools.client.infrastructure.RequestMethod -import org.openapitools.client.infrastructure.ResponseType -import org.openapitools.client.infrastructure.Success -import org.openapitools.client.infrastructure.toMultiValue - -class DefaultApi(basePath: kotlin.String = defaultBasePath, client: OkHttpClient = ApiClient.defaultClient) : ApiClient(basePath, client) { - companion object { - @JvmStatic - val defaultBasePath: String by lazy { - System.getProperties().getProperty(ApiClient.baseUrlKey, "http://localhost:3000/api/v1/@hyperledger/cactus-plugin-satp-hermes") - } - } - - /** - * Creates a Blockchain View. - * - * @param createViewRequest - * @return CreateViewResponse - * @throws IllegalStateException If the request is not correctly configured - * @throws IOException Rethrows the OkHttp execute method exception - * @throws UnsupportedOperationException If the API returns an informational or redirection response - * @throws ClientException If the API returns a client error response - * @throws ServerException If the API returns a server error response - */ - @Suppress("UNCHECKED_CAST") - @Throws(IllegalStateException::class, IOException::class, UnsupportedOperationException::class, ClientException::class, ServerException::class) - fun createViewV1(createViewRequest: CreateViewRequest) : CreateViewResponse { - val localVarResponse = createViewV1WithHttpInfo(createViewRequest = createViewRequest) - - return when (localVarResponse.responseType) { - ResponseType.Success -> (localVarResponse as Success<*>).data as CreateViewResponse - ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") - ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") - ResponseType.ClientError -> { - val localVarError = localVarResponse as ClientError<*> - throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) - } - ResponseType.ServerError -> { - val localVarError = localVarResponse as ServerError<*> - throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) - } - } - } - - /** - * Creates a Blockchain View. - * - * @param createViewRequest - * @return ApiResponse - * @throws IllegalStateException If the request is not correctly configured - * @throws IOException Rethrows the OkHttp execute method exception - */ - @Suppress("UNCHECKED_CAST") - @Throws(IllegalStateException::class, IOException::class) - fun createViewV1WithHttpInfo(createViewRequest: CreateViewRequest) : ApiResponse { - val localVariableConfig = createViewV1RequestConfig(createViewRequest = createViewRequest) - - return request( - localVariableConfig - ) - } - - /** - * To obtain the request config of the operation createViewV1 - * - * @param createViewRequest - * @return RequestConfig - */ - fun createViewV1RequestConfig(createViewRequest: CreateViewRequest) : RequestConfig { - val localVariableBody = createViewRequest - val localVariableQuery: MultiValueMap = mutableMapOf() - val localVariableHeaders: MutableMap = mutableMapOf() - localVariableHeaders["Content-Type"] = "application/json" - localVariableHeaders["Accept"] = "application/json" - - return RequestConfig( - method = RequestMethod.GET, - path = "/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/create-view", - query = localVariableQuery, - headers = localVariableHeaders, - requiresAuthentication = false, - body = localVariableBody - ) - } - - /** - * Queries plugin's available strategies for ledger capture - * - * @return kotlin.collections.List - * @throws IllegalStateException If the request is not correctly configured - * @throws IOException Rethrows the OkHttp execute method exception - * @throws UnsupportedOperationException If the API returns an informational or redirection response - * @throws ClientException If the API returns a client error response - * @throws ServerException If the API returns a server error response - */ - @Suppress("UNCHECKED_CAST") - @Throws(IllegalStateException::class, IOException::class, UnsupportedOperationException::class, ClientException::class, ServerException::class) - fun getAvailableStrategies() : kotlin.collections.List { - val localVarResponse = getAvailableStrategiesWithHttpInfo() - - return when (localVarResponse.responseType) { - ResponseType.Success -> (localVarResponse as Success<*>).data as kotlin.collections.List - ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") - ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") - ResponseType.ClientError -> { - val localVarError = localVarResponse as ClientError<*> - throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) - } - ResponseType.ServerError -> { - val localVarError = localVarResponse as ServerError<*> - throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) - } - } - } - - /** - * Queries plugin's available strategies for ledger capture - * - * @return ApiResponse?> - * @throws IllegalStateException If the request is not correctly configured - * @throws IOException Rethrows the OkHttp execute method exception - */ - @Suppress("UNCHECKED_CAST") - @Throws(IllegalStateException::class, IOException::class) - fun getAvailableStrategiesWithHttpInfo() : ApiResponse?> { - val localVariableConfig = getAvailableStrategiesRequestConfig() - - return request>( - localVariableConfig - ) - } - - /** - * To obtain the request config of the operation getAvailableStrategies - * - * @return RequestConfig - */ - fun getAvailableStrategiesRequestConfig() : RequestConfig { - val localVariableBody = null - val localVariableQuery: MultiValueMap = mutableMapOf() - val localVariableHeaders: MutableMap = mutableMapOf() - localVariableHeaders["Accept"] = "application/json" - - return RequestConfig( - method = RequestMethod.GET, - path = "/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/get-available-strategies", - query = localVariableQuery, - headers = localVariableHeaders, - requiresAuthentication = false, - body = localVariableBody - ) - } - - /** - * Queries plugin's public key - * - * @return GetPublicKeyResponse - * @throws IllegalStateException If the request is not correctly configured - * @throws IOException Rethrows the OkHttp execute method exception - * @throws UnsupportedOperationException If the API returns an informational or redirection response - * @throws ClientException If the API returns a client error response - * @throws ServerException If the API returns a server error response - */ - @Suppress("UNCHECKED_CAST") - @Throws(IllegalStateException::class, IOException::class, UnsupportedOperationException::class, ClientException::class, ServerException::class) - fun getPublicKey() : GetPublicKeyResponse { - val localVarResponse = getPublicKeyWithHttpInfo() - - return when (localVarResponse.responseType) { - ResponseType.Success -> (localVarResponse as Success<*>).data as GetPublicKeyResponse - ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") - ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") - ResponseType.ClientError -> { - val localVarError = localVarResponse as ClientError<*> - throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) - } - ResponseType.ServerError -> { - val localVarError = localVarResponse as ServerError<*> - throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) - } - } - } - - /** - * Queries plugin's public key - * - * @return ApiResponse - * @throws IllegalStateException If the request is not correctly configured - * @throws IOException Rethrows the OkHttp execute method exception - */ - @Suppress("UNCHECKED_CAST") - @Throws(IllegalStateException::class, IOException::class) - fun getPublicKeyWithHttpInfo() : ApiResponse { - val localVariableConfig = getPublicKeyRequestConfig() - - return request( - localVariableConfig - ) - } - - /** - * To obtain the request config of the operation getPublicKey - * - * @return RequestConfig - */ - fun getPublicKeyRequestConfig() : RequestConfig { - val localVariableBody = null - val localVariableQuery: MultiValueMap = mutableMapOf() - val localVariableHeaders: MutableMap = mutableMapOf() - localVariableHeaders["Accept"] = "application/json" - - return RequestConfig( - method = RequestMethod.GET, - path = "/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/get-public-key", - query = localVariableQuery, - headers = localVariableHeaders, - requiresAuthentication = false, - body = localVariableBody - ) - } - - - private fun encodeURIComponent(uriComponent: kotlin.String): kotlin.String = - HttpUrl.Builder().scheme("http").host("localhost").addPathSegment(uriComponent).build().encodedPathSegments[0] -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt deleted file mode 100644 index ef7a8f1e1a..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.openapitools.client.infrastructure - -typealias MultiValueMap = MutableMap> - -fun collectionDelimiter(collectionFormat: String) = when(collectionFormat) { - "csv" -> "," - "tsv" -> "\t" - "pipe" -> "|" - "space" -> " " - else -> "" -} - -val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" } - -fun toMultiValue(items: Array, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter) - = toMultiValue(items.asIterable(), collectionFormat, map) - -fun toMultiValue(items: Iterable, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List { - return when(collectionFormat) { - "multi" -> items.map(map) - else -> listOf(items.joinToString(separator = collectionDelimiter(collectionFormat), transform = map)) - } -} \ No newline at end of file diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt deleted file mode 100644 index ea4b7b6593..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt +++ /dev/null @@ -1,245 +0,0 @@ -package org.openapitools.client.infrastructure - -import okhttp3.OkHttpClient -import okhttp3.RequestBody -import okhttp3.RequestBody.Companion.asRequestBody -import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.FormBody -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull -import okhttp3.ResponseBody -import okhttp3.MediaType.Companion.toMediaTypeOrNull -import okhttp3.Request -import okhttp3.Headers -import okhttp3.Headers.Companion.toHeaders -import okhttp3.MultipartBody -import okhttp3.Call -import okhttp3.Callback -import okhttp3.Response -import okhttp3.internal.EMPTY_REQUEST -import java.io.BufferedWriter -import java.io.File -import java.io.FileWriter -import java.io.IOException -import java.net.URLConnection -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.LocalTime -import java.time.OffsetDateTime -import java.time.OffsetTime -import java.util.Locale -import com.squareup.moshi.adapter - -open class ApiClient(val baseUrl: String, val client: OkHttpClient = defaultClient) { - companion object { - protected const val ContentType = "Content-Type" - protected const val Accept = "Accept" - protected const val Authorization = "Authorization" - protected const val JsonMediaType = "application/json" - protected const val FormDataMediaType = "multipart/form-data" - protected const val FormUrlEncMediaType = "application/x-www-form-urlencoded" - protected const val XmlMediaType = "application/xml" - - val apiKey: MutableMap = mutableMapOf() - val apiKeyPrefix: MutableMap = mutableMapOf() - var username: String? = null - var password: String? = null - var accessToken: String? = null - const val baseUrlKey = "org.openapitools.client.baseUrl" - - @JvmStatic - val defaultClient: OkHttpClient by lazy { - builder.build() - } - - @JvmStatic - val builder: OkHttpClient.Builder = OkHttpClient.Builder() - } - - /** - * Guess Content-Type header from the given file (defaults to "application/octet-stream"). - * - * @param file The given file - * @return The guessed Content-Type - */ - protected fun guessContentTypeFromFile(file: File): String { - val contentType = URLConnection.guessContentTypeFromName(file.name) - return contentType ?: "application/octet-stream" - } - - protected inline fun requestBody(content: T, mediaType: String?): RequestBody = - when { - content is File -> content.asRequestBody((mediaType ?: guessContentTypeFromFile(content)).toMediaTypeOrNull()) - mediaType == FormDataMediaType -> - MultipartBody.Builder() - .setType(MultipartBody.FORM) - .apply { - // content's type *must* be Map> - @Suppress("UNCHECKED_CAST") - (content as Map>).forEach { (name, part) -> - if (part.body is File) { - val partHeaders = part.headers.toMutableMap() + - ("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") - val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() - addPart( - partHeaders.toHeaders(), - part.body.asRequestBody(fileMediaType) - ) - } else { - val partHeaders = part.headers.toMutableMap() + - ("Content-Disposition" to "form-data; name=\"$name\"") - addPart( - partHeaders.toHeaders(), - parameterToString(part.body).toRequestBody(null) - ) - } - } - }.build() - mediaType == FormUrlEncMediaType -> { - FormBody.Builder().apply { - // content's type *must* be Map> - @Suppress("UNCHECKED_CAST") - (content as Map>).forEach { (name, part) -> - add(name, parameterToString(part.body)) - } - }.build() - } - mediaType == null || mediaType.startsWith("application/") && mediaType.endsWith("json") -> - if (content == null) { - EMPTY_REQUEST - } else { - Serializer.moshi.adapter(T::class.java).toJson(content) - .toRequestBody((mediaType ?: JsonMediaType).toMediaTypeOrNull()) - } - mediaType == XmlMediaType -> throw UnsupportedOperationException("xml not currently supported.") - // TODO: this should be extended with other serializers - else -> throw UnsupportedOperationException("requestBody currently only supports JSON body and File body.") - } - - @OptIn(ExperimentalStdlibApi::class) - protected inline fun responseBody(body: ResponseBody?, mediaType: String? = JsonMediaType): T? { - if(body == null) { - return null - } - if (T::class.java == File::class.java) { - // return tempFile - // Attention: if you are developing an android app that supports API Level 25 and bellow, please check flag supportAndroidApiLevel25AndBelow in https://openapi-generator.tech/docs/generators/kotlin#config-options - val tempFile = java.nio.file.Files.createTempFile("tmp.org.openapitools.client", null).toFile() - tempFile.deleteOnExit() - body.byteStream().use { inputStream -> - tempFile.outputStream().use { tempFileOutputStream -> - inputStream.copyTo(tempFileOutputStream) - } - } - return tempFile as T - } - val bodyContent = body.string() - if (bodyContent.isEmpty()) { - return null - } - return when { - mediaType==null || (mediaType.startsWith("application/") && mediaType.endsWith("json")) -> - Serializer.moshi.adapter().fromJson(bodyContent) - else -> throw UnsupportedOperationException("responseBody currently only supports JSON body.") - } - } - - - protected inline fun request(requestConfig: RequestConfig): ApiResponse { - val httpUrl = baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.") - - val url = httpUrl.newBuilder() - .addEncodedPathSegments(requestConfig.path.trimStart('/')) - .apply { - requestConfig.query.forEach { query -> - query.value.forEach { queryValue -> - addQueryParameter(query.key, queryValue) - } - } - }.build() - - // take content-type/accept from spec or set to default (application/json) if not defined - if (requestConfig.body != null && requestConfig.headers[ContentType].isNullOrEmpty()) { - requestConfig.headers[ContentType] = JsonMediaType - } - if (requestConfig.headers[Accept].isNullOrEmpty()) { - requestConfig.headers[Accept] = JsonMediaType - } - val headers = requestConfig.headers - - if (headers[Accept].isNullOrEmpty()) { - throw kotlin.IllegalStateException("Missing Accept header. This is required.") - } - - val contentType = if (headers[ContentType] != null) { - // TODO: support multiple contentType options here. - (headers[ContentType] as String).substringBefore(";").lowercase(Locale.US) - } else { - null - } - - val request = when (requestConfig.method) { - RequestMethod.DELETE -> Request.Builder().url(url).delete(requestBody(requestConfig.body, contentType)) - RequestMethod.GET -> Request.Builder().url(url) - RequestMethod.HEAD -> Request.Builder().url(url).head() - RequestMethod.PATCH -> Request.Builder().url(url).patch(requestBody(requestConfig.body, contentType)) - RequestMethod.PUT -> Request.Builder().url(url).put(requestBody(requestConfig.body, contentType)) - RequestMethod.POST -> Request.Builder().url(url).post(requestBody(requestConfig.body, contentType)) - RequestMethod.OPTIONS -> Request.Builder().url(url).method("OPTIONS", null) - }.apply { - headers.forEach { header -> addHeader(header.key, header.value) } - }.build() - - val response = client.newCall(request).execute() - - val accept = response.header(ContentType)?.substringBefore(";")?.lowercase(Locale.US) - - // TODO: handle specific mapping types. e.g. Map> - return when { - response.isRedirect -> Redirection( - response.code, - response.headers.toMultimap() - ) - response.isInformational -> Informational( - response.message, - response.code, - response.headers.toMultimap() - ) - response.isSuccessful -> Success( - responseBody(response.body, accept), - response.code, - response.headers.toMultimap() - ) - response.isClientError -> ClientError( - response.message, - response.body?.string(), - response.code, - response.headers.toMultimap() - ) - else -> ServerError( - response.message, - response.body?.string(), - response.code, - response.headers.toMultimap() - ) - } - } - - protected fun parameterToString(value: Any?): String = when (value) { - null -> "" - is Array<*> -> toMultiValue(value, "csv").toString() - is Iterable<*> -> toMultiValue(value, "csv").toString() - is OffsetDateTime, is OffsetTime, is LocalDateTime, is LocalDate, is LocalTime -> - parseDateToQueryString(value) - else -> value.toString() - } - - protected inline fun parseDateToQueryString(value : T): String { - /* - .replace("\"", "") converts the json object string to an actual string for the query parameter. - The moshi or gson adapter allows a more generic solution instead of trying to use a native - formatter. It also easily allows to provide a simple way to define a custom date format pattern - inside a gson/moshi adapter. - */ - return Serializer.moshi.adapter(T::class.java).toJson(value).replace("\"", "") - } -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt deleted file mode 100644 index cf2cfaa95d..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt +++ /dev/null @@ -1,43 +0,0 @@ -package org.openapitools.client.infrastructure - -enum class ResponseType { - Success, Informational, Redirection, ClientError, ServerError -} - -interface Response - -abstract class ApiResponse(val responseType: ResponseType): Response { - abstract val statusCode: Int - abstract val headers: Map> -} - -class Success( - val data: T, - override val statusCode: Int = -1, - override val headers: Map> = mapOf() -): ApiResponse(ResponseType.Success) - -class Informational( - val statusText: String, - override val statusCode: Int = -1, - override val headers: Map> = mapOf() -) : ApiResponse(ResponseType.Informational) - -class Redirection( - override val statusCode: Int = -1, - override val headers: Map> = mapOf() -) : ApiResponse(ResponseType.Redirection) - -class ClientError( - val message: String? = null, - val body: Any? = null, - override val statusCode: Int = -1, - override val headers: Map> = mapOf() -) : ApiResponse(ResponseType.ClientError) - -class ServerError( - val message: String? = null, - val body: Any? = null, - override val statusCode: Int = -1, - override val headers: Map> -): ApiResponse(ResponseType.ServerError) diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt deleted file mode 100644 index 064b57fc6b..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.openapitools.client.infrastructure - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import java.math.BigDecimal - -class BigDecimalAdapter { - @ToJson - fun toJson(value: BigDecimal): String { - return value.toPlainString() - } - - @FromJson - fun fromJson(value: String): BigDecimal { - return BigDecimal(value) - } -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt deleted file mode 100644 index 7df6057b45..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.openapitools.client.infrastructure - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import java.math.BigInteger - -class BigIntegerAdapter { - @ToJson - fun toJson(value: BigInteger): String { - return value.toString() - } - - @FromJson - fun fromJson(value: String): BigInteger { - return BigInteger(value) - } -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt deleted file mode 100644 index ff5e2a81ee..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.openapitools.client.infrastructure - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson - -class ByteArrayAdapter { - @ToJson - fun toJson(data: ByteArray): String = String(data) - - @FromJson - fun fromJson(data: String): ByteArray = data.toByteArray() -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt deleted file mode 100644 index b5310e71f1..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt +++ /dev/null @@ -1,18 +0,0 @@ -@file:Suppress("unused") -package org.openapitools.client.infrastructure - -import java.lang.RuntimeException - -open class ClientException(message: kotlin.String? = null, val statusCode: Int = -1, val response: Response? = null) : RuntimeException(message) { - - companion object { - private const val serialVersionUID: Long = 123L - } -} - -open class ServerException(message: kotlin.String? = null, val statusCode: Int = -1, val response: Response? = null) : RuntimeException(message) { - - companion object { - private const val serialVersionUID: Long = 456L - } -} \ No newline at end of file diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt deleted file mode 100644 index b2e1654479..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.openapitools.client.infrastructure - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import java.time.LocalDate -import java.time.format.DateTimeFormatter - -class LocalDateAdapter { - @ToJson - fun toJson(value: LocalDate): String { - return DateTimeFormatter.ISO_LOCAL_DATE.format(value) - } - - @FromJson - fun fromJson(value: String): LocalDate { - return LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE) - } - -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt deleted file mode 100644 index e082db9481..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.openapitools.client.infrastructure - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter - -class LocalDateTimeAdapter { - @ToJson - fun toJson(value: LocalDateTime): String { - return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(value) - } - - @FromJson - fun fromJson(value: String): LocalDateTime { - return LocalDateTime.parse(value, DateTimeFormatter.ISO_LOCAL_DATE_TIME) - } - -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/OffsetDateTimeAdapter.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/OffsetDateTimeAdapter.kt deleted file mode 100644 index 87437871a3..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/OffsetDateTimeAdapter.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.openapitools.client.infrastructure - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import java.time.OffsetDateTime -import java.time.format.DateTimeFormatter - -class OffsetDateTimeAdapter { - @ToJson - fun toJson(value: OffsetDateTime): String { - return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value) - } - - @FromJson - fun fromJson(value: String): OffsetDateTime { - return OffsetDateTime.parse(value, DateTimeFormatter.ISO_OFFSET_DATE_TIME) - } - -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt deleted file mode 100644 index be00e38fba..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.openapitools.client.infrastructure - -/** - * Defines a config object for a given part of a multi-part request. - * NOTE: Headers is a Map because rfc2616 defines - * multi-valued headers as csv-only. - */ -data class PartConfig( - val headers: MutableMap = mutableMapOf(), - val body: T? = null -) diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt deleted file mode 100644 index 625a19002b..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.openapitools.client.infrastructure - -/** - * Defines a config object for a given request. - * NOTE: This object doesn't include 'body' because it - * allows for caching of the constructed object - * for many request definitions. - * NOTE: Headers is a Map because rfc2616 defines - * multi-valued headers as csv-only. - */ -data class RequestConfig( - val method: RequestMethod, - val path: String, - val headers: MutableMap = mutableMapOf(), - val query: MutableMap> = mutableMapOf(), - val requiresAuthentication: Boolean, - val body: T? = null -) \ No newline at end of file diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt deleted file mode 100644 index 931b12b8bd..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.openapitools.client.infrastructure - -/** - * Provides enumerated HTTP verbs - */ -enum class RequestMethod { - GET, DELETE, HEAD, OPTIONS, PATCH, POST, PUT -} \ No newline at end of file diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt deleted file mode 100644 index 9bd2790dc1..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt +++ /dev/null @@ -1,24 +0,0 @@ -package org.openapitools.client.infrastructure - -import okhttp3.Response - -/** - * Provides an extension to evaluation whether the response is a 1xx code - */ -val Response.isInformational : Boolean get() = this.code in 100..199 - -/** - * Provides an extension to evaluation whether the response is a 3xx code - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER") -val Response.isRedirect : Boolean get() = this.code in 300..399 - -/** - * Provides an extension to evaluation whether the response is a 4xx code - */ -val Response.isClientError : Boolean get() = this.code in 400..499 - -/** - * Provides an extension to evaluation whether the response is a 5xx (Standard) through 999 (non-standard) code - */ -val Response.isServerError : Boolean get() = this.code in 500..999 diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt deleted file mode 100644 index e22592e47d..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.openapitools.client.infrastructure - -import com.squareup.moshi.Moshi -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory - -object Serializer { - @JvmStatic - val moshiBuilder: Moshi.Builder = Moshi.Builder() - .add(OffsetDateTimeAdapter()) - .add(LocalDateTimeAdapter()) - .add(LocalDateAdapter()) - .add(UUIDAdapter()) - .add(ByteArrayAdapter()) - .add(URIAdapter()) - .add(KotlinJsonAdapterFactory()) - .add(BigDecimalAdapter()) - .add(BigIntegerAdapter()) - - @JvmStatic - val moshi: Moshi by lazy { - moshiBuilder.build() - } -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt deleted file mode 100644 index 927522757d..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.openapitools.client.infrastructure - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import java.net.URI - -class URIAdapter { - @ToJson - fun toJson(uri: URI) = uri.toString() - - @FromJson - fun fromJson(s: String): URI = URI.create(s) -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt deleted file mode 100644 index 7ccf7dc25d..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.openapitools.client.infrastructure - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import java.util.UUID - -class UUIDAdapter { - @ToJson - fun toJson(uuid: UUID) = uuid.toString() - - @FromJson - fun fromJson(s: String): UUID = UUID.fromString(s) -} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewRequest.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewRequest.kt deleted file mode 100644 index 74f718ad22..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewRequest.kt +++ /dev/null @@ -1,56 +0,0 @@ -/** - * - * Please note: - * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * Do not edit this file manually. - * - */ - -@file:Suppress( - "ArrayInDataClass", - "EnumEntryName", - "RemoveRedundantQualifierName", - "UnusedImport" -) - -package org.openapitools.client.models - -import org.openapitools.client.models.CreateViewRequestNetworkDetails - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -/** - * Request object for createViewV1 endpoint - * - * @param strategyId - * @param networkDetails - * @param stateIds - * @param tI - * @param tF - * @param viewID - */ - - -data class CreateViewRequest ( - - @Json(name = "strategyId") - val strategyId: kotlin.String, - - @Json(name = "networkDetails") - val networkDetails: CreateViewRequestNetworkDetails, - - @Json(name = "stateIds") - val stateIds: kotlin.collections.List? = null, - - @Json(name = "tI") - val tI: kotlin.String? = null, - - @Json(name = "tF") - val tF: kotlin.String? = null, - - @Json(name = "viewID") - val viewID: kotlin.String? = null - -) - diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewRequestNetworkDetails.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewRequestNetworkDetails.kt deleted file mode 100644 index 748c488a5a..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewRequestNetworkDetails.kt +++ /dev/null @@ -1,39 +0,0 @@ -/** - * - * Please note: - * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * Do not edit this file manually. - * - */ - -@file:Suppress( - "ArrayInDataClass", - "EnumEntryName", - "RemoveRedundantQualifierName", - "UnusedImport" -) - -package org.openapitools.client.models - - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -/** - * - * - * @param connectorApiPath - * @param participant - */ - - -data class CreateViewRequestNetworkDetails ( - - @Json(name = "connectorApiPath") - val connectorApiPath: kotlin.String, - - @Json(name = "participant") - val participant: kotlin.String - -) - diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewResponse.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewResponse.kt deleted file mode 100644 index fd3bca7f79..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/CreateViewResponse.kt +++ /dev/null @@ -1,39 +0,0 @@ -/** - * - * Please note: - * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * Do not edit this file manually. - * - */ - -@file:Suppress( - "ArrayInDataClass", - "EnumEntryName", - "RemoveRedundantQualifierName", - "UnusedImport" -) - -package org.openapitools.client.models - - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -/** - * This is the response for a viewRequests - * - * @param view - * @param signature - */ - - -data class CreateViewResponse ( - - @Json(name = "view") - val view: kotlin.String? = null, - - @Json(name = "signature") - val signature: kotlin.String? = null - -) - diff --git a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/GetPublicKeyResponse.kt b/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/GetPublicKeyResponse.kt deleted file mode 100644 index 7131884f72..0000000000 --- a/packages/cactus-plugin-bungee-hermes/src/main/kotlin/generated/openapi/kotlin-client/src/main/kotlin/org/openapitools/client/models/GetPublicKeyResponse.kt +++ /dev/null @@ -1,35 +0,0 @@ -/** - * - * Please note: - * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * Do not edit this file manually. - * - */ - -@file:Suppress( - "ArrayInDataClass", - "EnumEntryName", - "RemoveRedundantQualifierName", - "UnusedImport" -) - -package org.openapitools.client.models - - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -/** - * public key from bungee-hermes plugin instance - * - * @param pubKey - */ - - -data class GetPublicKeyResponse ( - - @Json(name = "pubKey") - val pubKey: kotlin.String? = null - -) - diff --git a/packages/cactus-plugin-bungee-hermes/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-bungee-hermes/src/main/typescript/generated/openapi/typescript-axios/api.ts index a1e5d31bc4..816addfb7b 100644 --- a/packages/cactus-plugin-bungee-hermes/src/main/typescript/generated/openapi/typescript-axios/api.ts +++ b/packages/cactus-plugin-bungee-hermes/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -117,6 +117,38 @@ export interface GetPublicKeyResponse { */ 'pubKey'?: string; } +/** + * Set of transaction or state proofs and merkle tree root for verification + * @export + * @interface VerifyMerkleRootRequest + */ +export interface VerifyMerkleRootRequest { + /** + * + * @type {Array} + * @memberof VerifyMerkleRootRequest + */ + 'input'?: Array; + /** + * + * @type {string} + * @memberof VerifyMerkleRootRequest + */ + 'root'?: string; +} +/** + * true or false, wether input matched provided root + * @export + * @interface VerifyMerkleRootResponse + */ +export interface VerifyMerkleRootResponse { + /** + * + * @type {boolean} + * @memberof VerifyMerkleRootResponse + */ + 'result'?: boolean; +} /** * DefaultApi - axios parameter creator @@ -215,6 +247,42 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Checks validity of merkle tree root given an input + * @param {VerifyMerkleRootRequest} verifyMerkleRootRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + verifyMerkleRoot: async (verifyMerkleRootRequest: VerifyMerkleRootRequest, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'verifyMerkleRootRequest' is not null or undefined + assertParamExists('verifyMerkleRoot', 'verifyMerkleRootRequest', verifyMerkleRootRequest) + const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/verify-merkle-root`; + // 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; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(verifyMerkleRootRequest, localVarRequestOptions, configuration) + return { url: toPathString(localVarUrlObj), options: localVarRequestOptions, @@ -261,6 +329,17 @@ export const DefaultApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.getPublicKey(options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @summary Checks validity of merkle tree root given an input + * @param {VerifyMerkleRootRequest} verifyMerkleRootRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async verifyMerkleRoot(verifyMerkleRootRequest: VerifyMerkleRootRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.verifyMerkleRoot(verifyMerkleRootRequest, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, } }; @@ -299,6 +378,16 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa getPublicKey(options?: any): AxiosPromise { return localVarFp.getPublicKey(options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Checks validity of merkle tree root given an input + * @param {VerifyMerkleRootRequest} verifyMerkleRootRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + verifyMerkleRoot(verifyMerkleRootRequest: VerifyMerkleRootRequest, options?: any): AxiosPromise { + return localVarFp.verifyMerkleRoot(verifyMerkleRootRequest, options).then((request) => request(axios, basePath)); + }, }; }; @@ -342,6 +431,18 @@ export class DefaultApi extends BaseAPI { public getPublicKey(options?: AxiosRequestConfig) { return DefaultApiFp(this.configuration).getPublicKey(options).then((request) => request(this.axios, this.basePath)); } + + /** + * + * @summary Checks validity of merkle tree root given an input + * @param {VerifyMerkleRootRequest} verifyMerkleRootRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public verifyMerkleRoot(verifyMerkleRootRequest: VerifyMerkleRootRequest, options?: AxiosRequestConfig) { + return DefaultApiFp(this.configuration).verifyMerkleRoot(verifyMerkleRootRequest, options).then((request) => request(this.axios, this.basePath)); + } } diff --git a/packages/cactus-plugin-bungee-hermes/src/main/typescript/plugin-bungee-hermes.ts b/packages/cactus-plugin-bungee-hermes/src/main/typescript/plugin-bungee-hermes.ts index 8b0e906d68..899aae22d3 100644 --- a/packages/cactus-plugin-bungee-hermes/src/main/typescript/plugin-bungee-hermes.ts +++ b/packages/cactus-plugin-bungee-hermes/src/main/typescript/plugin-bungee-hermes.ts @@ -34,6 +34,8 @@ import { import { CreateViewEndpointV1 } from "./web-services/create-view-endpoint"; import { GetPublicKeyEndpointV1 } from "./web-services/get-public-key-endpoint"; import { GetAvailableStrategiesEndpointV1 } from "./web-services/get-available-strategies-endpoint"; +import MerkleTree from "merkletreejs"; +import { VerifyMerkleRootEndpointV1 } from "./web-services/verify-merkle-root-endpoint"; export interface IKeyPair { publicKey: Uint8Array; @@ -106,7 +108,7 @@ export class PluginBungeeHermes implements ICactusPlugin, IPluginWebService { if (this.strategies.get(strategyId) == undefined) { this.strategies.set(strategyId, strategy); } else { - throw Error("Strategy " + strategyId + " already exists."); + throw new Error("Strategy " + strategyId + " already exists."); } } public getStrategy(strategyId: string): ObtainLedgerStrategy | undefined { @@ -151,11 +153,15 @@ export class PluginBungeeHermes implements ICactusPlugin, IPluginWebService { const availableStrategiesEndpoint = new GetAvailableStrategiesEndpointV1({ bungee: this, }); + const verifyMerkleProofEndpoint = new VerifyMerkleRootEndpointV1({ + bungee: this, + }); this.endpoints = [ viewEndpoint, pubKeyEndpoint, availableStrategiesEndpoint, + verifyMerkleProofEndpoint, ]; return this.endpoints; } @@ -222,7 +228,7 @@ export class PluginBungeeHermes implements ICactusPlugin, IPluginWebService { ): Promise { const strategy = this.getStrategy(strategyId); if (strategy == undefined) { - throw Error("Strategy " + strategyId + " is undefined/unsupported"); + throw new Error("Strategy " + strategyId + " is undefined/unsupported"); } const ledgerStates = await strategy.generateLedgerStates( @@ -247,4 +253,12 @@ export class PluginBungeeHermes implements ICactusPlugin, IPluginWebService { return snapshot; } + + public verifyMerkleProof(input: string[], root: string): boolean { + const tree = new MerkleTree(input, undefined, { + sort: true, + hashLeaves: true, + }); + return tree.getRoot().toString("hex") == root; + } } diff --git a/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-besu.ts b/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-besu.ts index 42d45707be..cf26e702bd 100644 --- a/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-besu.ts +++ b/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-besu.ts @@ -1,5 +1,6 @@ import { NetworkDetails, ObtainLedgerStrategy } from "./obtain-ledger-strategy"; import { + Checks, LogLevelDesc, Logger, LoggerProvider, @@ -22,7 +23,6 @@ import { Transaction } from "../view-creation/transaction"; import Web3 from "web3"; import { Proof } from "../view-creation/proof"; import { TransactionProof } from "../view-creation/transaction-proof"; - export interface BesuNetworkDetails extends NetworkDetails { signingCredential: Web3SigningCredential; keychainId: string; @@ -40,21 +40,22 @@ export class StrategyBesu implements ObtainLedgerStrategy { level, }); } - public async generateLedgerStates( stateIds: string[], networkDetails: BesuNetworkDetails, ): Promise> { + const fnTag = `${StrategyBesu.CLASS_NAME}#generateLedgerStates()`; this.log.debug(`Generating ledger snapshot`); + Checks.truthy(networkDetails, `${fnTag} networkDetails`); + const config = new Configuration({ basePath: networkDetails.connectorApiPath, }); const besuApi = new BesuApi(config); - const ledgerStates = new Map(); const assetsKey = stateIds.length == 0 - ? ((await this.getAllAssetsKey(networkDetails, besuApi)) as string[]) + ? await this.getAllAssetsKey(networkDetails, besuApi) : stateIds; this.log.debug("Current assets detected to capture: " + assetsKey); for (const assetKey of assetsKey) { @@ -83,7 +84,7 @@ export class StrategyBesu implements ObtainLedgerStrategy { blockSigners: [], // FIXME: query blocksigners (blockchain specific) }); } - state.setStateProof([]); + state.setStateProof([stateProof]); ledgerStates.set(assetKey, state); } return ledgerStates; @@ -92,7 +93,7 @@ export class StrategyBesu implements ObtainLedgerStrategy { async getAllAssetsKey( networkDetails: BesuNetworkDetails, api: BesuApi, - ): Promise { + ): Promise { const parameters = { contractName: networkDetails.contractName, keychainId: networkDetails.keychainId, @@ -105,11 +106,20 @@ export class StrategyBesu implements ObtainLedgerStrategy { const response = await api.invokeContractV1( parameters as InvokeContractV1Request, ); - if (response != undefined) { - return response.data.callOutput; - } - return "response undefined"; + if (response.status >= 200 && response.status < 300) { + if (response.data.callOutput) { + return response.data.callOutput as string[]; + } else { + throw new Error( + `${StrategyBesu.CLASS_NAME}#getAllAssetsKey: contract ${networkDetails.contractName} method getAllAssetsIDs output is falsy`, + ); + } + } + throw new Error( + `${StrategyBesu.CLASS_NAME}#getAllAssetsKey: BesuAPI error with status ${response.status}: ` + + response.data, + ); } async getAllInfoByKey( @@ -122,17 +132,24 @@ export class StrategyBesu implements ObtainLedgerStrategy { blocks: Map; }> { const req = { + fromBlock: "earliest", + toBlock: "latest", address: networkDetails.contractAddress, topics: [[null], [Web3.utils.keccak256(key)]], //filter logs by asset key }; const response = await api.getPastLogsV1(req as GetPastLogsV1Request); - if (response == undefined) { - return { - transactions: [], - values: [], - blocks: new Map(), - }; + if (response.status < 200 || response.status >= 300) { + throw new Error( + `${StrategyBesu.CLASS_NAME}#getAllInfoByKey: BesuAPI getPastLogsV1 error with status ${response.status}: ` + + response.data, + ); + } + if (!response.data.logs) { + throw new Error( + `${StrategyBesu.CLASS_NAME}#getAllInfoByKey: BesuAPI getPastLogsV1 API call successfull but output data is falsy`, + ); } + const decoded = response.data.logs as EvmLog[]; const transactions: Transaction[] = []; const blocks: Map = new Map(); @@ -144,19 +161,34 @@ export class StrategyBesu implements ObtainLedgerStrategy { transactionHash: log.transactionHash, } as GetTransactionV1Request); + if (txTx.status < 200 || txTx.status >= 300) { + throw new Error( + `${StrategyBesu.CLASS_NAME}#getAllInfoByKey: BesuAPI getTransactionV1 error with status ${txTx.status}: ` + + txTx.data, + ); + } + if (!txTx.data.transaction) { + throw new Error( + `${StrategyBesu.CLASS_NAME}#getAllInfoByKey: BesuAPI getTransactionV1 call successfull but output data is falsy`, + ); + } + const txBlock = await api.getBlockV1({ blockHashOrBlockNumber: log.blockHash, } as GetBlockV1Request); - if (txTx == undefined || txBlock == undefined) { - this.log.debug( - "some error occurred fetching transaction or block info in ", + + if (txBlock.status < 200 || txBlock.status >= 300) { + throw new Error( + `${StrategyBesu.CLASS_NAME}#getAllInfoByKey: BesuAPI getBlockV1 error with status ${txBlock.status}: ` + + txBlock.data, ); - return { - transactions: [], - values: [], - blocks: new Map(), - }; } + if (!txBlock.data.block) { + throw new Error( + `${StrategyBesu.CLASS_NAME}#getAllInfoByKey: BesuAPI getBlockV1 call successfull but output data is falsy`, + ); + } + this.log.debug( "Transaction: " + log.transactionHash + @@ -170,7 +202,7 @@ export class StrategyBesu implements ObtainLedgerStrategy { const transaction: Transaction = new Transaction( log.transactionHash, txBlock.data.block.timestamp, - new TransactionProof(proof), + new TransactionProof(proof, log.transactionHash), ); transaction.setStateId(key); transaction.setTarget(networkDetails.contractAddress as string); diff --git a/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-ethereum.ts b/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-ethereum.ts new file mode 100644 index 0000000000..c77824b727 --- /dev/null +++ b/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-ethereum.ts @@ -0,0 +1,255 @@ +import { + Logger, + LogLevelDesc, + LoggerProvider, + Checks, +} from "@hyperledger/cactus-common"; +import { + Web3SigningCredential, + DefaultApi as EthereumApi, + EthContractInvocationType, + InvokeContractV1Request, + InvokeRawWeb3EthMethodV1Request, +} from "@hyperledger/cactus-plugin-ledger-connector-ethereum"; +import { NetworkDetails, ObtainLedgerStrategy } from "./obtain-ledger-strategy"; +import { Configuration } from "@hyperledger/cactus-core-api"; +import { State } from "../view-creation/state"; +import { StateProof } from "../view-creation/state-proof"; +import Web3 from "web3"; +import { Proof } from "../view-creation/proof"; +import { TransactionProof } from "../view-creation/transaction-proof"; +import { Transaction } from "../view-creation/transaction"; + +interface EvmLog { + address: string; + data: string; + blockHash: string; + transactionHash: string; + topics: Array; + logIndex: number; + transactionIndex: number; + blockNumber: number; +} + +interface EvmBlock { + number?: number; + hash?: string; + parentHash?: string; + nonce?: string; + sha3Uncles?: string; + logsBloom?: string; + transactionsRoot?: string; + stateRoot?: string; + miner?: string; + difficulty?: number; + totalDifficulty?: number; + extraData?: string; + size?: number; + gasLimit?: number; + gasUsed?: number; + timestamp?: string; + transactions?: Array; + uncles?: Array; +} +export interface EthereumNetworkDetails extends NetworkDetails { + signingCredential: Web3SigningCredential; + keychainId: string; + contractName: string; + contractAddress: string; +} +export class StrategyEthereum implements ObtainLedgerStrategy { + public static readonly CLASS_NAME = "StrategyEthereum"; + + public log: Logger; + + constructor(level: LogLevelDesc) { + this.log = LoggerProvider.getOrCreate({ + label: StrategyEthereum.CLASS_NAME, + level, + }); + } + + public async generateLedgerStates( + stateIds: string[], + networkDetails: EthereumNetworkDetails, + ): Promise> { + const fnTag = `${StrategyEthereum.CLASS_NAME}#generateLedgerStates()`; + this.log.debug(`Generating ledger snapshot`); + Checks.truthy(networkDetails, `${fnTag} networkDetails`); + + const config = new Configuration({ + basePath: networkDetails.connectorApiPath, + }); + const ethereumApi = new EthereumApi(config); + + const ledgerStates = new Map(); + const assetsKey = + stateIds.length == 0 + ? await this.getAllAssetsKey(networkDetails, ethereumApi) + : stateIds; + this.log.debug("Current assets detected to capture: " + assetsKey); + for (const assetKey of assetsKey) { + const { transactions, values, blocks } = await this.getAllInfoByKey( + assetKey, + networkDetails, + ethereumApi, + ); + + const state = new State(assetKey, values, transactions); + + const stateProof = new StateProof( + state.getValue(), + parseInt(state.getVersion()), + state.getId(), + ); + const blocksHash: string[] = []; + for (const block of blocks.values()) { + if (blocksHash.indexOf(block.hash as string) !== -1) { + continue; + } + blocksHash.push(block.hash as string); + stateProof.addBlock({ + blockHash: block.hash as string, + blockCreator: block.miner as string, + blockSigners: [], // Non applicable for ethereum + }); + } + state.setStateProof([stateProof]); + ledgerStates.set(assetKey, state); + } + return ledgerStates; + } + + async getAllAssetsKey( + networkDetails: EthereumNetworkDetails, + api: EthereumApi, + ): Promise { + const parameters = { + contract: { + contractName: networkDetails.contractName, + keychainId: networkDetails.keychainId, + }, + invocationType: EthContractInvocationType.Call, + methodName: "getAllAssetsIDs", + params: [], + signingCredential: networkDetails.signingCredential, + }; + const response = await api.invokeContractV1( + parameters as InvokeContractV1Request, + ); + if (response.status >= 200 && response.status < 300) { + if (response.data.callOutput) { + return response.data.callOutput as string[]; + } else { + throw new Error( + `${StrategyEthereum.CLASS_NAME}#getAllAssetsKey: contract ${networkDetails.contractName} method getAllAssetsIDs output is falsy`, + ); + } + } + throw new Error( + `${StrategyEthereum.CLASS_NAME}#getAllAssetsKey: EthereumAPI error with status ${response.status}: ` + + response.data, + ); + } + + async getAllInfoByKey( + key: string, + networkDetails: EthereumNetworkDetails, + api: EthereumApi, + ): Promise<{ + transactions: Transaction[]; + values: string[]; + blocks: Map; + }> { + const filter = { + fromBlock: "earliest", + toBlock: "latest", + address: networkDetails.contractAddress, + topics: [null, Web3.utils.keccak256(key)], //filter logs by asset key + }; + const getLogsReq: InvokeRawWeb3EthMethodV1Request = { + methodName: "getPastLogs", + params: [filter], + }; + const response = await api.invokeWeb3EthMethodV1(getLogsReq); + if (response.status < 200 || response.status >= 300) { + throw new Error( + `${StrategyEthereum.CLASS_NAME}#getAllInfoByKey: BesuAPI getPastLogsV1 error with status ${response.status}: ` + + response.data, + ); + } + if (!response.data.data) { + throw new Error( + `${StrategyEthereum.CLASS_NAME}#getAllInfoByKey: BesuAPI getPastLogsV1 API call successfull but output data is falsy`, + ); + } + const decoded = response.data.data as EvmLog[]; + const transactions: Transaction[] = []; + const blocks: Map = new Map(); + const values: string[] = []; + this.log.debug("Getting transaction logs for asset: " + key); + + for (const log of decoded) { + const getTransactionReq: InvokeRawWeb3EthMethodV1Request = { + methodName: "getTransaction", + params: [log.transactionHash], + }; + const txTx = await api.invokeWeb3EthMethodV1(getTransactionReq); + + if (txTx.status < 200 || txTx.status >= 300) { + throw new Error( + `${StrategyEthereum.CLASS_NAME}#getAllInfoByKey: EthereumAPI invokeWeb3EthMethodV1 getTransaction error with status ${txTx.status}: ` + + txTx.data, + ); + } + if (!txTx.data.data) { + throw new Error( + `${StrategyEthereum.CLASS_NAME}#getAllInfoByKey: EthereumAPI invokeWeb3EthMethodV1 getTransaction successfull but output data is falsy`, + ); + } + + const getBlockReq: InvokeRawWeb3EthMethodV1Request = { + methodName: "getBlock", + params: [log.blockHash], + }; + const txBlock = await api.invokeWeb3EthMethodV1(getBlockReq); + + if (txBlock.status < 200 || txBlock.status >= 300) { + throw new Error( + `${StrategyEthereum.CLASS_NAME}#getAllInfoByKey: EthereumAPI invokeWeb3EthMethodV1 getBlock error with status ${txBlock.status}: ` + + txBlock.data, + ); + } + if (!txBlock.data.data) { + throw new Error( + `${StrategyEthereum.CLASS_NAME}#getAllInfoByKey: EthereumAPI invokeWeb3EthMethodV1 getBlock successfull but output data is falsy`, + ); + } + + this.log.debug( + "Transaction: " + + log.transactionHash + + "\nData: " + + JSON.stringify(log.data) + + "\n =========== \n", + ); + const proof = new Proof({ + creator: txTx.data.data.from as string, //no sig for ethereum + }); + const transaction: Transaction = new Transaction( + log.transactionHash, + txBlock.data.data.timestamp, + new TransactionProof(proof, log.transactionHash), + ); + transaction.setStateId(key); + transaction.setTarget(networkDetails.contractAddress as string); + transaction.setPayload(txTx.data.data.input ? txTx.data.data.input : ""); //FIXME: payload = transaction input ? + transactions.push(transaction); + values.push(JSON.stringify(log.data)); + + blocks.set(transaction.getId(), txBlock.data.data); + } + + return { transactions: transactions, values: values, blocks: blocks }; + } +} diff --git a/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-fabric.ts b/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-fabric.ts index 1a9d61a4c7..106958db7b 100644 --- a/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-fabric.ts +++ b/packages/cactus-plugin-bungee-hermes/src/main/typescript/strategy/strategy-fabric.ts @@ -7,6 +7,7 @@ import { } from "@hyperledger/cactus-plugin-ledger-connector-fabric"; import { NetworkDetails, ObtainLedgerStrategy } from "./obtain-ledger-strategy"; import { + Checks, LogLevelDesc, Logger, LoggerProvider, @@ -38,7 +39,9 @@ export class StrategyFabric implements ObtainLedgerStrategy { stateIds: string[], networkDetails: FabricNetworkDetails, ): Promise> { - this.log.info(`Generating ledger snapshot`); + const fnTag = `${StrategyFabric.CLASS_NAME}#generateLedgerStates()`; + this.log.debug(`Generating ledger snapshot`); + Checks.truthy(networkDetails, `${fnTag} networkDetails`); const config = new Configuration({ basePath: networkDetails.connectorApiPath, @@ -57,6 +60,7 @@ export class StrategyFabric implements ObtainLedgerStrategy { const txs = await this.getAllTxByKey(assetKey, fabricApi, networkDetails); //For each tx get receipt + let last_receipt; for (const tx of txs) { const receipt = JSON.parse( await this.fabricGetTxReceiptByTxIDV1( @@ -65,11 +69,15 @@ export class StrategyFabric implements ObtainLedgerStrategy { networkDetails, ), ); - + tx.getProof().setCreator( + new Proof({ + creator: receipt.transactionCreator.creatorID, + mspid: receipt.transactionCreator.mspid, + }), + ); assetValues.push(JSON.parse(receipt.rwsetWriteData).Value.toString()); tx.setStateId(assetKey); - //tx.setPayload(); //FIXME check what to assign here - //tx.setTarget(); + tx.setTarget(receipt.channelID + ": " + receipt.chainCodeName); for (const endorsement of receipt.transactionEndorsement) { const signature64 = Buffer.from(endorsement.signature).toString( @@ -84,13 +92,13 @@ export class StrategyFabric implements ObtainLedgerStrategy { ); } txWithTimeS.push(tx); + last_receipt = receipt; } const block = await this.fabricGetBlockByTxID( txs[txs.length - 1].getId(), fabricApi, networkDetails, ); - const state = new State(assetKey, assetValues, txWithTimeS); ledgerStates.set(assetKey, state); const stateProof = new StateProof( @@ -101,9 +109,14 @@ export class StrategyFabric implements ObtainLedgerStrategy { //only adding last block for each state, in the state proof stateProof.addBlock({ blockHash: block.hash, - blockCreator: "", + blockCreator: JSON.stringify({ + mspid: last_receipt.blockMetaData.mspid, + id: last_receipt.blockMetaData.blockCreatorID, + }), blockSigners: block.signers, }); + + state.setStateProof([stateProof]); } return ledgerStates; } @@ -121,25 +134,38 @@ export class StrategyFabric implements ObtainLedgerStrategy { methodName: "GetBlockByTxID", params: [networkDetails.channelName, transactionId], } as RunTransactionRequest); - return JSON.stringify(receiptLockRes?.data); + + if (receiptLockRes.status >= 200 && receiptLockRes.status < 300) { + if (receiptLockRes.data) { + return JSON.stringify(receiptLockRes.data); + } else { + throw new Error( + `${StrategyFabric.CLASS_NAME}#fabricGetTxReceiptByTxIDV1: contract qscc method GetBlockByTxID invocation output is falsy`, + ); + } + } + throw new Error( + `${StrategyFabric.CLASS_NAME}#fabricGetTxReceiptByTxIDV1: FabricAPI error with status 500: ` + + receiptLockRes.data, + ); } async fabricGetBlockByTxID( txId: string, api: FabricApi, - netwokDetails: FabricNetworkDetails, + networkDetails: FabricNetworkDetails, ): Promise<{ hash: string; signers: string[] }> { const gatewayOptions = { - identity: netwokDetails.signingCredential.keychainRef, + identity: networkDetails.signingCredential.keychainRef, wallet: { keychain: { - keychainId: netwokDetails.signingCredential.keychainId, - keychainRef: netwokDetails.signingCredential.keychainRef, + keychainId: networkDetails.signingCredential.keychainId, + keychainRef: networkDetails.signingCredential.keychainRef, }, }, }; const getBlockReq = { - channelName: netwokDetails.channelName as string, + channelName: networkDetails.channelName as string, gatewayOptions, query: { transactionId: txId, @@ -149,6 +175,18 @@ export class StrategyFabric implements ObtainLedgerStrategy { const getBlockResponse = await api.getBlockV1(getBlockReq); + if (getBlockResponse.status < 200 || getBlockResponse.status >= 300) { + throw new Error( + `${StrategyFabric.CLASS_NAME}#fabricGetTxReceiptByTxIDV1: FabricAPI getBlockV1 error with status ${getBlockResponse.status}: ` + + getBlockResponse.data, + ); + } + if (!getBlockResponse.data) { + throw new Error( + `${StrategyFabric.CLASS_NAME}#fabricGetBlockByTxID: getBlockV1 API call output data is falsy`, + ); + } + const block = JSON.parse( JSON.stringify(getBlockResponse?.data), ).decodedBlock; @@ -156,9 +194,17 @@ export class StrategyFabric implements ObtainLedgerStrategy { const blockSig = block.metadata.metadata[0].signatures; const sigs = []; for (const sig of blockSig) { - sigs.push(JSON.stringify(sig)); + const decoded = { + creator: { + mspid: sig.signature_header.creator.mspid, + id: Buffer.from(sig.signature_header.creator.id_bytes.data).toString( + "hex", + ), + }, + signature: Buffer.from(sig.signature.data).toString("hex"), + }; + sigs.push(JSON.stringify(decoded)); } - return { hash: Buffer.from(block.header.data_hash.data).toString("hex"), signers: sigs, @@ -167,43 +213,59 @@ export class StrategyFabric implements ObtainLedgerStrategy { async getAllAssetsKey( api: FabricApi, - netwokDetails: FabricNetworkDetails, + networkDetails: FabricNetworkDetails, ): Promise { const response = await api.runTransactionV1({ - signingCredential: netwokDetails.signingCredential, - channelName: netwokDetails.channelName, - contractName: netwokDetails.contractName, + signingCredential: networkDetails.signingCredential, + channelName: networkDetails.channelName, + contractName: networkDetails.contractName, methodName: "GetAllAssetsKey", invocationType: FabricContractInvocationType.Call, params: [], } as RunTransactionRequest); - if (response != undefined) { - return response.data.functionOutput; + if (response.status >= 200 && response.status < 300) { + if (response.data.functionOutput) { + return response.data.functionOutput; + } else { + throw new Error( + `${StrategyFabric.CLASS_NAME}#getAllAssetsKey: contract ${networkDetails.contractName} method GetAllAssetsKey invocation output is falsy`, + ); + } } - - return "response undefined"; + throw new Error( + `${StrategyFabric.CLASS_NAME}#getAllAssetsKey: FabricAPI error with status 500: ` + + response.data, + ); } async getAllTxByKey( key: string, api: FabricApi, - netwokDetails: FabricNetworkDetails, + networkDetails: FabricNetworkDetails, ): Promise { const response = await api.runTransactionV1({ - signingCredential: netwokDetails.signingCredential, - channelName: netwokDetails.channelName, - contractName: netwokDetails.contractName, + signingCredential: networkDetails.signingCredential, + channelName: networkDetails.channelName, + contractName: networkDetails.contractName, methodName: "GetAllTxByKey", invocationType: FabricContractInvocationType.Call, params: [key], } as RunTransactionRequest); - if (response != undefined) { - return this.txsStringToTxs(response.data.functionOutput); + if (response.status >= 200 && response.status < 300) { + if (response.data.functionOutput) { + return this.txsStringToTxs(response.data.functionOutput); + } else { + throw new Error( + `${StrategyFabric.CLASS_NAME}#getAllTxByKey: contract ${networkDetails.contractName} method GetAllTxByKey invocation output is falsy`, + ); + } } - - return []; + throw new Error( + `${StrategyFabric.CLASS_NAME}#getAllTxByKey: FabricAPI error with status 500: ` + + response.data, + ); } // Receive transactions in string format and parses to Transaction [] @@ -213,13 +275,13 @@ export class StrategyFabric implements ObtainLedgerStrategy { for (const tx of txs) { const txId = tx.value.txId; const ts = tx.value.timestamp.seconds; - transactions.push( - new Transaction( - txId, - ts, - new TransactionProof(new Proof({ creator: "" })), - ), + const transaction = new Transaction( + txId, + ts, + new TransactionProof(new Proof({ creator: "" }), txId), //transaction proof details are set in function 'generateLedgerStates' ); + transaction.setPayload(JSON.stringify(tx.value)); + transactions.push(transaction); } return transactions.reverse(); } diff --git a/packages/cactus-plugin-bungee-hermes/src/main/typescript/view-creation/transaction-proof.ts b/packages/cactus-plugin-bungee-hermes/src/main/typescript/view-creation/transaction-proof.ts index fe4b91a8b1..1e3f51f065 100644 --- a/packages/cactus-plugin-bungee-hermes/src/main/typescript/view-creation/transaction-proof.ts +++ b/packages/cactus-plugin-bungee-hermes/src/main/typescript/view-creation/transaction-proof.ts @@ -6,9 +6,10 @@ export class TransactionProof { //set of signed endorsements //only existent for some ledgers (example Fabric) private endorsements?: Proof[] = []; - - constructor(transactionCreator: Proof) { + private hash: string; + constructor(transactionCreator: Proof, hash: string) { this.transactionCreator = transactionCreator; + this.hash = hash; } public addEndorser(endorser: Proof) { @@ -32,6 +33,9 @@ export class TransactionProof { public getCreator(): Proof { return this.transactionCreator; } + public setCreator(transactionCreator: Proof) { + this.transactionCreator = transactionCreator; + } public getEndorsements(): Proof[] | undefined { return this.endorsements; diff --git a/packages/cactus-plugin-bungee-hermes/src/main/typescript/view-creation/view.ts b/packages/cactus-plugin-bungee-hermes/src/main/typescript/view-creation/view.ts index 6c8db87fa0..8053996094 100644 --- a/packages/cactus-plugin-bungee-hermes/src/main/typescript/view-creation/view.ts +++ b/packages/cactus-plugin-bungee-hermes/src/main/typescript/view-creation/view.ts @@ -1,12 +1,17 @@ import { v4 as uuidV4 } from "uuid"; import { Snapshot } from "./snapshot"; - +import MerkleTree from "merkletreejs"; +import { Transaction } from "./transaction"; export class View { private key: string; private snapshot: Snapshot; - private tI; - private tF; - private participant; + private tI: string; + private tF: string; + private participant: string; + private viewProof: { + transactionsMerkleRoot: string; + statesMerkleRoot: string; + }; constructor( tI: string, @@ -20,10 +25,41 @@ export class View { this.snapshot = snapshot; this.participant = snapshot.getParticipant(); snapshot.pruneStates(this.tI, this.tF); + this.viewProof = this.generateViewProof(); } public getKey() { return this.key; } + public getSnapshot(): Snapshot { + return this.snapshot; + } + private generateViewProof(): { + transactionsMerkleRoot: string; + statesMerkleRoot: string; + } { + const states: string[] = []; + const transactions: string[] = []; + + for (const state of this.snapshot.getStateBins()) { + states.push(JSON.stringify(state.getStateProof())); + for (const transaction of state.getTransactions()) { + transactions.push(JSON.stringify(transaction.getProof())); + } + } + + const statesTree = new MerkleTree(states, undefined, { + sort: true, + hashLeaves: true, + }); + const transactionsTree = new MerkleTree(transactions, undefined, { + sort: true, + hashLeaves: true, + }); + return { + transactionsMerkleRoot: transactionsTree.getRoot().toString("hex"), + statesMerkleRoot: statesTree.getRoot().toString("hex"), + }; + } public getViewStr(): string { const viewStr = { tI: this.tI, @@ -33,4 +69,20 @@ export class View { return JSON.stringify(viewStr); // return this.snapshot.getSnapshotJson(); } + public getViewProof(): { + transactionsMerkleRoot: string; + statesMerkleRoot: string; + } { + return this.viewProof; + } + + public getAllTransactions(): Transaction[] { + const transactions: Transaction[] = []; + this.snapshot.getStateBins().forEach((state) => { + state.getTransactions().forEach((transaction) => { + transactions.push(transaction); + }); + }); + return transactions; + } } diff --git a/packages/cactus-plugin-bungee-hermes/src/main/typescript/web-services/verify-merkle-root-endpoint.ts b/packages/cactus-plugin-bungee-hermes/src/main/typescript/web-services/verify-merkle-root-endpoint.ts new file mode 100644 index 0000000000..94cbcbb32f --- /dev/null +++ b/packages/cactus-plugin-bungee-hermes/src/main/typescript/web-services/verify-merkle-root-endpoint.ts @@ -0,0 +1,109 @@ +import type { Express, Request, Response } from "express"; + +import { + IWebServiceEndpoint, + IExpressRequestHandler, + IEndpointAuthzOptions, +} from "@hyperledger/cactus-core-api/"; + +import { + Logger, + Checks, + LogLevelDesc, + LoggerProvider, + IAsyncProvider, +} from "@hyperledger/cactus-common"; + +import { + handleRestEndpointException, + registerWebServiceEndpoint, +} from "@hyperledger/cactus-core"; + +import OAS from "../../json/openapi.json"; +import { PluginBungeeHermes } from "../plugin-bungee-hermes"; + +export interface VerifyMerkleRootEndpointOptions { + logLevel?: LogLevelDesc; + bungee: PluginBungeeHermes; +} + +export class VerifyMerkleRootEndpointV1 implements IWebServiceEndpoint { + public static readonly CLASS_NAME = "ClientEndpointV1"; + + private readonly log: Logger; + + public get className(): string { + return VerifyMerkleRootEndpointV1.CLASS_NAME; + } + + constructor(public readonly options: VerifyMerkleRootEndpointOptions) { + const fnTag = `${this.className}#constructor()`; + Checks.truthy(options, `${fnTag} arg options`); + Checks.truthy(options.bungee, `${fnTag} arg options.connector`); + + const level = this.options.logLevel || "INFO"; + const label = this.className; + this.log = LoggerProvider.getOrCreate({ level, label }); + } + + public getExpressRequestHandler(): IExpressRequestHandler { + return this.handleRequest.bind(this); + } + + public getPath(): string { + const apiPath = + OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/verify-merkle-root" + ]; + return apiPath.get["x-hyperledger-cacti"].http.path; + } + + public getVerbLowerCase(): string { + const apiPath = + OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/verify-merkle-root" + ]; + return apiPath.get["x-hyperledger-cacti"].http.verbLowerCase; + } + + public getOperationId(): string { + return OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/verify-merkle-root" + ].get.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 async handleRequest(req: Request, res: Response): Promise { + const fnTag = `${this.className}#handleRequest()`; + const reqTag = `${this.getVerbLowerCase()} - ${this.getPath()}`; + this.log.debug(reqTag); + try { + const result = { + result: await this.options.bungee.verifyMerkleProof( + req.body.input, + req.body.root, + ), + }; + res.status(200).json(result); + } catch (ex: unknown) { + const errorMsg = `${fnTag} request handler fn crashed for: ${reqTag}`; + handleRestEndpointException({ errorMsg, log: this.log, error: ex, res }); + } + } +} diff --git a/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/besu-test-pruning.test.ts b/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/besu-test-pruning.test.ts index 4171629bd0..4bd8df5822 100644 --- a/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/besu-test-pruning.test.ts +++ b/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/besu-test-pruning.test.ts @@ -48,7 +48,6 @@ const logLevel: LogLevelDesc = "INFO"; let besuLedger: BesuTestLedger; let contractName: string; -//let besuServer: Server; let rpcApiHttpHost: string; let rpcApiWsHost: string; diff --git a/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/bungee-api-test.test.ts b/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/bungee-api-test.test.ts index 6f2af71084..355da3bbe8 100644 --- a/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/bungee-api-test.test.ts +++ b/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/bungee-api-test.test.ts @@ -64,6 +64,18 @@ import { BesuNetworkDetails, StrategyBesu, } from "../../../main/typescript/strategy/strategy-besu"; +import { + PluginLedgerConnectorEthereum, + DefaultApi as EthereumApi, +} from "@hyperledger/cactus-plugin-ledger-connector-ethereum"; +import { + GethTestLedger, + WHALE_ACCOUNT_ADDRESS, +} from "@hyperledger/cactus-test-geth-ledger"; +import { + EthereumNetworkDetails, + StrategyEthereum, +} from "../../../main/typescript/strategy/strategy-ethereum"; const logLevel: LogLevelDesc = "INFO"; @@ -89,6 +101,13 @@ const log = LoggerProvider.getOrCreate({ label: "BUNGEE - Hermes", }); +let ethereumSigningCredential; +let ethereumKeychainId: string; +let ethereumContractAddress: string; +let ethereumNetworkDetails: EthereumNetworkDetails; +let ethereumServer: Server; +let ethereumLedger: GethTestLedger; + let fabricKeychainPlugin: PluginKeychainMemory; let configFabric: Configuration; let fabricLedger: FabricTestLedgerV1; @@ -106,6 +125,7 @@ let bungeeServer: Server; const BESU_STRATEGY = "BESU"; const FABRIC_STRATEGY = "FABRIC"; +const ETH_STRATEGY = "ETHEREUM"; beforeAll(async () => { pruneDockerAllIfGithubAction({ logLevel }) @@ -120,6 +140,7 @@ beforeAll(async () => { { log.info(await setupFabricTestLedger()); log.info(await setupBesuTestLedger()); + log.info(await setupEthereumTestLedger()); } }); @@ -132,11 +153,12 @@ test("tests bungee api using different strategies", async () => { }; const bungee = new PluginBungeeHermes(pluginBungeeHermesOptions); - //add both strategies to BUNGEE - Hermes + //add strategies to BUNGEE - Hermes bungee.addStrategy(FABRIC_STRATEGY, new StrategyFabric("INFO")); bungee.addStrategy(BESU_STRATEGY, new StrategyBesu("INFO")); + bungee.addStrategy(ETH_STRATEGY, new StrategyEthereum("INFO")); - //store network details for both networks + //store network details for Fabric and Besu networks const besuNetworkDetails: BesuNetworkDetails = { signingCredential: besuSigningCredential, contractName: besuContractName, @@ -171,8 +193,7 @@ test("tests bungee api using different strategies", async () => { const config = new Configuration({ basePath: bungeePath }); const bungeeApi = new BungeeApi(config); - //View creation for both networks, using the respective strategies - + //View creation for all networks, using the respective strategies const viewFabric = await bungeeApi.createViewV1({ strategyId: FABRIC_STRATEGY, networkDetails: fabricNetworkDetails, @@ -189,20 +210,91 @@ test("tests bungee api using different strategies", async () => { expect(viewBesu.status).toEqual(200); expect(viewBesu.data.view).toBeTruthy(); + const viewEth = await bungeeApi.createViewV1({ + strategyId: ETH_STRATEGY, + networkDetails: ethereumNetworkDetails, + }); + //expect to return a view + expect(viewEth.status).toEqual(200); + expect(viewEth.data.view).toBeTruthy(); + const strategyReq = await bungeeApi.getAvailableStrategies(); const pubKeyReq = await bungeeApi.getPublicKey(); for (const strategy of strategyReq.data) { - expect([BESU_STRATEGY, FABRIC_STRATEGY]).toInclude(strategy); + expect([BESU_STRATEGY, FABRIC_STRATEGY, ETH_STRATEGY]).toInclude(strategy); } expect(pubKeyReq.data).toEqual( Buffer.from(keyPair.publicKey).toString("hex"), ); + + const viewFabric1 = bungee.generateView( + await bungee.generateSnapshot([], FABRIC_STRATEGY, fabricNetworkDetails), + "0", + Number.MAX_SAFE_INTEGER.toString(), + undefined, + ); + const proof = viewFabric1.view?.getViewProof(); + const stateProofs = viewFabric1.view + ?.getSnapshot() + .getStateBins() + .map((x) => JSON.stringify(x.getStateProof())); + const transactionProofs: string[] = []; + viewFabric1.view + ?.getAllTransactions() + .forEach((t) => transactionProofs.push(JSON.stringify(t.getProof()))); + const verifyStateRoot = await bungeeApi.verifyMerkleRoot({ + input: stateProofs?.reverse(), //check integrity, order should not matter + root: proof?.statesMerkleRoot, + }); + expect(verifyStateRoot.status).toEqual(200); + expect(verifyStateRoot.data.result).toBeTrue(); + + const verifyTransactionsRoot = await bungeeApi.verifyMerkleRoot({ + input: transactionProofs?.reverse(), //check integrity, order should not matter + root: proof?.transactionsMerkleRoot, + }); + + expect(verifyTransactionsRoot.status).toEqual(200); + expect(verifyTransactionsRoot.data.result).toBeTrue(); + + const viewEth1 = bungee.generateView( + await bungee.generateSnapshot([], ETH_STRATEGY, ethereumNetworkDetails), + "0", + Number.MAX_SAFE_INTEGER.toString(), + undefined, + ); + const proof1 = viewEth1.view?.getViewProof(); + const stateProofs1 = viewEth1.view + ?.getSnapshot() + .getStateBins() + .map((x) => JSON.stringify(x.getStateProof())); + const transactionProofs1: string[] = []; + viewEth1.view + ?.getAllTransactions() + .forEach((t) => transactionProofs1.push(JSON.stringify(t.getProof()))); + const verifyStateRoot1 = await bungeeApi.verifyMerkleRoot({ + input: stateProofs1?.reverse(), //check integrity, order should not matter + root: proof1?.statesMerkleRoot, + }); + expect(verifyStateRoot1.status).toEqual(200); + expect(verifyStateRoot1.data.result).toBeTrue(); + + const verifyTransactionsRoot1 = await bungeeApi.verifyMerkleRoot({ + input: transactionProofs1?.reverse(), //check integrity, order should not matter + root: proof1?.transactionsMerkleRoot, + }); + + expect(verifyTransactionsRoot1.status).toEqual(200); + expect(verifyTransactionsRoot1.data.result).toBeTrue(); }); afterAll(async () => { await Servers.shutdown(besuServer); await Servers.shutdown(fabricServer); await Servers.shutdown(bungeeServer); + await Servers.shutdown(ethereumServer); + await ethereumLedger.stop(); + await ethereumLedger.destroy(); await besuLedger.stop(); await besuLedger.destroy(); await fabricLedger.stop(); @@ -218,7 +310,7 @@ afterAll(async () => { }); }); -async function setupFabricTestLedger(): Promise { +async function setupFabricTestLedger(): Promise { const channelId = "mychannel"; fabricChannelName = channelId; @@ -462,7 +554,7 @@ async function setupFabricTestLedger(): Promise { ); return "Fabric Network setup successful"; } -async function setupBesuTestLedger(): Promise { +async function setupBesuTestLedger(): Promise { besuLedger = new BesuTestLedger({ logLevel, emitContainerLogs: true, @@ -590,6 +682,38 @@ async function setupBesuTestLedger(): Promise { log.info("Besu asset created successfully"); + const res1 = await besuConnector.invokeContract({ + contractName: besuContractName, + keychainId: besuKeychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.Send, + methodName: "lockAsset", + params: [BESU_ASSET_ID], + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: besuKeyPair.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + gas: 1000000, + }); + expect(res1).toBeTruthy(); + expect(res1.success).toBeTruthy(); + + const res2 = await besuConnector.invokeContract({ + contractName: besuContractName, + keychainId: besuKeychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.Send, + methodName: "unLockAsset", + params: [BESU_ASSET_ID], + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: besuKeyPair.privateKey, + type: Web3SigningCredentialType.PrivateKeyHex, + }, + gas: 1000000, + }); + expect(res2).toBeTruthy(); + expect(res2.success).toBeTruthy(); + besuSigningCredential = { ethAccount: firstHighNetWorthAccount, secret: besuKeyPair.privateKey, @@ -598,3 +722,171 @@ async function setupBesuTestLedger(): Promise { besuContractAddress = deployOut.transactionReceipt.contractAddress as string; return "Besu Network setup successful"; } + +async function setupEthereumTestLedger(): Promise { + const containerImageName = "ghcr.io/hyperledger/cacti-geth-all-in-one"; + const containerImageVersion = "2023-07-27-2a8c48ed6"; + + const keychainEntryKey = uuidv4(); + const ETH_ASSET_NAME = uuidv4(); + const expressApp = express(); + expressApp.use(bodyParser.json({ limit: "250mb" })); + const server = http.createServer(expressApp); + ethereumServer = server; + // set to address Type Error returned by Response.json() + // "Can't serialize BigInt" + expressApp.set("json replacer", stringifyBigIntReplacer); + + const wsApi = new SocketIoServer(server, { + path: Constants.SocketIoConnectionPathV1, + }); + + const ledger = new GethTestLedger({ + containerImageName, + containerImageVersion, + }); + ethereumLedger = ledger; + await ledger.start(); + + const listenOptions: IListenOptions = { + hostname: "127.0.0.1", + port: 5000, + server, + }; + const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; + const { address, port } = addressInfo; + const apiHost = `http://${address}:${port}`; + const apiConfig = new Configuration({ basePath: apiHost }); + const apiClient = new EthereumApi(apiConfig); + const rpcApiHttpHost = await ledger.getRpcApiHttpHost(); + const web3 = new Web3(rpcApiHttpHost); + const testEthAccount = web3.eth.accounts.create(); + + const keychainEntryValue = testEthAccount.privateKey; + const keychainPlugin = new PluginKeychainMemory({ + instanceId: uuidv4(), + keychainId: uuidv4(), + // pre-provision keychain with mock backend holding the private key of the + // test account that we'll reference while sending requests with the + // signing credential pointing to this keychain entry. + backend: new Map([[keychainEntryKey, keychainEntryValue]]), + logLevel: logLevel, + }); + keychainPlugin.set( + LockAssetContractJson.contractName, + JSON.stringify(LockAssetContractJson), + ); + const connector = new PluginLedgerConnectorEthereum({ + instanceId: uuidv4(), + rpcApiHttpHost, + logLevel: logLevel, + pluginRegistry: new PluginRegistry({ plugins: [keychainPlugin] }), + }); + + // Instantiate connector with the keychain plugin that already has the + // private key we want to use for one of our tests + await connector.getOrCreateWebServices(); + await connector.registerWebServices(expressApp, wsApi); + + const initTransferValue = web3.utils.toWei("5000", "ether"); + await apiClient.runTransactionV1({ + web3SigningCredential: { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.GethKeychainPassword, + }, + transactionConfig: { + from: WHALE_ACCOUNT_ADDRESS, + to: testEthAccount.address, + value: initTransferValue, + }, + }); + + const balance = await web3.eth.getBalance(testEthAccount.address); + expect(balance).toBeTruthy(); + expect(balance.toString()).toBe(initTransferValue); + + const deployOut = await apiClient.deployContract({ + contract: { + contractName: LockAssetContractJson.contractName, + keychainId: keychainPlugin.getKeychainId(), + }, + web3SigningCredential: { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.GethKeychainPassword, + }, + }); + expect(deployOut).toBeTruthy(); + expect(deployOut.data).toBeTruthy(); + expect(deployOut.data.transactionReceipt).toBeTruthy(); + expect(deployOut.data.transactionReceipt.contractAddress).toBeTruthy(); + log.info("contract deployed successfully"); + const contractAddress = deployOut.data.transactionReceipt + .contractAddress as string; + expect(typeof contractAddress).toBe("string"); + expect(contractAddress).toBeTruthy(); + + const invokeOut = await apiClient.invokeContractV1({ + contract: { + contractName: LockAssetContractJson.contractName, + keychainId: keychainPlugin.getKeychainId(), + }, + invocationType: EthContractInvocationType.Send, + methodName: "createAsset", + params: [ETH_ASSET_NAME, 10], + web3SigningCredential: { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.GethKeychainPassword, + }, + }); + expect(invokeOut).toBeTruthy(); + expect(invokeOut.data).toBeTruthy(); + log.info("contract call successfull"); + + const lockAsset = await apiClient.invokeContractV1({ + contract: { + contractName: LockAssetContractJson.contractName, + keychainId: keychainPlugin.getKeychainId(), + }, + invocationType: EthContractInvocationType.Send, + methodName: "lockAsset", + params: [ETH_ASSET_NAME], + web3SigningCredential: { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.GethKeychainPassword, + }, + }); + expect(lockAsset).not.toBeUndefined(); + expect(lockAsset.status).toBe(200); + + ethereumSigningCredential = { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.PrivateKeyHex, + }; + ethereumKeychainId = keychainPlugin.getKeychainId(); + + ethereumContractAddress = deployOut.data.transactionReceipt + .contractAddress as string; + + ethereumNetworkDetails = { + signingCredential: ethereumSigningCredential, + contractName: LockAssetContractJson.contractName, + connectorApiPath: apiHost, + keychainId: ethereumKeychainId, + contractAddress: ethereumContractAddress, + participant: WHALE_ACCOUNT_ADDRESS, + }; + + return "Ethereum Network setup successful"; +} + +function stringifyBigIntReplacer(key: string, value: bigint): string { + if (typeof value === "bigint") { + return value.toString(); + } + return value; +} diff --git a/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/ethereum-test-basic.test.ts b/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/ethereum-test-basic.test.ts new file mode 100644 index 0000000000..f4a6ec2987 --- /dev/null +++ b/packages/cactus-plugin-bungee-hermes/src/test/typescript/integration/ethereum-test-basic.test.ts @@ -0,0 +1,366 @@ +/** + * Tests for deploying a contract and invoking it's method by directly sending contract JSON. + * + * @note all tests must be run in order, don't use `skip()` or `only()`. @todo - fix that + */ + +////////////////////////////////// +// Constants +////////////////////////////////// + +// Log settings +const testLogLevel: LogLevelDesc = "info"; + +import "jest-extended"; +import express from "express"; +import bodyParser from "body-parser"; +import http from "http"; +import { v4 as uuidV4 } from "uuid"; +import { AddressInfo } from "net"; +import { Server as SocketIoServer } from "socket.io"; +import Web3 from "web3"; + +import { + LogLevelDesc, + IListenOptions, + Servers, + Logger, + LoggerProvider, + Secp256k1Keys, +} from "@hyperledger/cactus-common"; +import { PluginRegistry } from "@hyperledger/cactus-core"; +import { Configuration, Constants } from "@hyperledger/cactus-core-api"; +import { + Containers, + pruneDockerAllIfGithubAction, +} from "@hyperledger/cactus-test-tooling"; +import { PluginKeychainMemory } from "@hyperledger/cactus-plugin-keychain-memory"; +import { + GethTestLedger, + WHALE_ACCOUNT_ADDRESS, +} from "@hyperledger/cactus-test-geth-ledger"; + +import LockAssetContractJson from "../../typescript/solidity/lock-asset-contract/LockAsset.json"; +import { + EthContractInvocationType, + PluginLedgerConnectorEthereum, + Web3SigningCredentialType, + DefaultApi as EthereumApi, + Web3SigningCredential, +} from "@hyperledger/cactus-plugin-ledger-connector-ethereum"; +import { Account } from "web3-core"; +import { + IPluginBungeeHermesOptions, + PluginBungeeHermes, +} from "../../../main/typescript"; +import { + EthereumNetworkDetails, + StrategyEthereum, +} from "../../../main/typescript/strategy/strategy-ethereum"; + +const log: Logger = LoggerProvider.getOrCreate({ + label: "geth-invoke-web3-contract-v1.test", + level: testLogLevel, +}); + +log.info("Test started"); +const containerImageName = "ghcr.io/hyperledger/cacti-geth-all-in-one"; +const containerImageVersion = "2023-07-27-2a8c48ed6"; + +describe("Ethereum contract deploy and invoke using keychain", () => { + const keychainEntryKey = uuidV4(); + let testEthAccount: Account, + web3: InstanceType, + addressInfo, + address: string, + port: number, + contractAddress: string, + apiHost: string, + apiConfig, + ledger: GethTestLedger, + apiClient: EthereumApi, + connector: PluginLedgerConnectorEthereum, + rpcApiHttpHost: string, + keychainPlugin: PluginKeychainMemory; + + let bungeeSigningCredential: Web3SigningCredential; + let bungeeKeychainId: string; + let bungeeContractAddress: string; + let pluginBungeeHermesOptions: IPluginBungeeHermesOptions; + const ETH_ASSET_NAME = uuidV4(); + const expressApp = express(); + expressApp.use(bodyParser.json({ limit: "250mb" })); + const server = http.createServer(expressApp); + + // set to address Type Error returned by Response.json() + // "Can't serialize BigInt" + expressApp.set("json replacer", stringifyBigIntReplacer); + + const wsApi = new SocketIoServer(server, { + path: Constants.SocketIoConnectionPathV1, + }); + + ////////////////////////////////// + // Setup + ////////////////////////////////// + + beforeAll(async () => { + pruneDockerAllIfGithubAction({ logLevel: testLogLevel }) + .then(() => { + log.info("Pruning throw OK"); + }) + .catch(async () => { + await Containers.logDiagnostics({ logLevel: testLogLevel }); + fail("Pruning didn't throw OK"); + }); + + ledger = new GethTestLedger({ + containerImageName, + containerImageVersion, + }); + await ledger.start(); + + const listenOptions: IListenOptions = { + hostname: "127.0.0.1", + port: 5000, + server, + }; + addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; + ({ address, port } = addressInfo); + apiHost = `http://${address}:${port}`; + apiConfig = new Configuration({ basePath: apiHost }); + apiClient = new EthereumApi(apiConfig); + rpcApiHttpHost = await ledger.getRpcApiHttpHost(); + web3 = new Web3(rpcApiHttpHost); + testEthAccount = web3.eth.accounts.create(); + + const keychainEntryValue = testEthAccount.privateKey; + keychainPlugin = new PluginKeychainMemory({ + instanceId: uuidV4(), + keychainId: uuidV4(), + // pre-provision keychain with mock backend holding the private key of the + // test account that we'll reference while sending requests with the + // signing credential pointing to this keychain entry. + backend: new Map([[keychainEntryKey, keychainEntryValue]]), + logLevel: testLogLevel, + }); + keychainPlugin.set( + LockAssetContractJson.contractName, + JSON.stringify(LockAssetContractJson), + ); + connector = new PluginLedgerConnectorEthereum({ + instanceId: uuidV4(), + rpcApiHttpHost, + logLevel: testLogLevel, + pluginRegistry: new PluginRegistry({ plugins: [keychainPlugin] }), + }); + + // Instantiate connector with the keychain plugin that already has the + // private key we want to use for one of our tests + await connector.getOrCreateWebServices(); + await connector.registerWebServices(expressApp, wsApi); + + const initTransferValue = web3.utils.toWei("5000", "ether"); + await apiClient.runTransactionV1({ + web3SigningCredential: { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.GethKeychainPassword, + }, + transactionConfig: { + from: WHALE_ACCOUNT_ADDRESS, + to: testEthAccount.address, + value: initTransferValue, + }, + }); + + const balance = await web3.eth.getBalance(testEthAccount.address); + expect(balance).toBeTruthy(); + expect(balance.toString()).toBe(initTransferValue); + + const deployOut = await apiClient.deployContract({ + contract: { + contractName: LockAssetContractJson.contractName, + keychainId: keychainPlugin.getKeychainId(), + }, + web3SigningCredential: { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.GethKeychainPassword, + }, + }); + expect(deployOut).toBeTruthy(); + expect(deployOut.data).toBeTruthy(); + expect(deployOut.data.transactionReceipt).toBeTruthy(); + expect(deployOut.data.transactionReceipt.contractAddress).toBeTruthy(); + log.info("contract deployed successfully"); + contractAddress = deployOut.data.transactionReceipt + .contractAddress as string; + expect(typeof contractAddress).toBe("string"); + expect(contractAddress).toBeTruthy(); + + const invokeOut = await apiClient.invokeContractV1({ + contract: { + contractName: LockAssetContractJson.contractName, + keychainId: keychainPlugin.getKeychainId(), + }, + invocationType: EthContractInvocationType.Send, + methodName: "createAsset", + params: [ETH_ASSET_NAME, 10], + web3SigningCredential: { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.GethKeychainPassword, + }, + }); + expect(invokeOut).toBeTruthy(); + expect(invokeOut.data).toBeTruthy(); + log.info("contract call successfull"); + + bungeeSigningCredential = { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.PrivateKeyHex, + }; + bungeeKeychainId = keychainPlugin.getKeychainId(); + + bungeeContractAddress = deployOut.data.transactionReceipt + .contractAddress as string; + + pluginBungeeHermesOptions = { + keyPair: Secp256k1Keys.generateKeyPairsBuffer(), + instanceId: uuidV4(), + logLevel: testLogLevel, + }; + }); + + afterAll(async () => { + await ledger.stop(); + await ledger.destroy(); + await Servers.shutdown(server); + + const pruning = pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); + await expect(pruning).resolves.toBeTruthy(); + }); + test("test creation of views for different timeframes and states", async () => { + const bungee = new PluginBungeeHermes(pluginBungeeHermesOptions); + const strategy = "ETH"; + bungee.addStrategy(strategy, new StrategyEthereum("INFO")); + const networkDetails: EthereumNetworkDetails = { + signingCredential: bungeeSigningCredential, + contractName: LockAssetContractJson.contractName, + connectorApiPath: apiHost, + keychainId: bungeeKeychainId, + contractAddress: bungeeContractAddress, + participant: WHALE_ACCOUNT_ADDRESS, + }; + + const snapshot = await bungee.generateSnapshot( + [], + strategy, + networkDetails, + ); + const view = bungee.generateView( + snapshot, + "0", + Number.MAX_SAFE_INTEGER.toString(), + undefined, + ); + + //expect to return a view + expect(view.view).toBeTruthy(); + expect(view.signature).toBeTruthy(); + + //expect the view to have capture the new asset ETH_ASSET_NAME, and attributes to match + expect(snapshot.getStateBins().length).toEqual(1); + expect(snapshot.getStateBins()[0].getId()).toEqual(ETH_ASSET_NAME); + expect(snapshot.getStateBins()[0].getTransactions().length).toEqual(1); + + const view1 = bungee.generateView(snapshot, "0", "9999", undefined); + + //expects nothing to limit time of 9999 + expect(view1.view).toBeUndefined(); + expect(view1.signature).toBeUndefined(); + + //changing ETH_ASSET_NAME value + const lockAsset = await apiClient.invokeContractV1({ + contract: { + contractName: LockAssetContractJson.contractName, + keychainId: keychainPlugin.getKeychainId(), + }, + invocationType: EthContractInvocationType.Send, + methodName: "lockAsset", + params: [ETH_ASSET_NAME], + web3SigningCredential: { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.GethKeychainPassword, + }, + }); + expect(lockAsset).not.toBeUndefined(); + expect(lockAsset.status).toBe(200); + + //changing ETH_ASSET_NAME value + const new_asset_id = uuidV4(); + const depNew = await apiClient.invokeContractV1({ + contract: { + contractName: LockAssetContractJson.contractName, + keychainId: keychainPlugin.getKeychainId(), + }, + invocationType: EthContractInvocationType.Send, + methodName: "createAsset", + params: [new_asset_id, 10], + web3SigningCredential: { + ethAccount: WHALE_ACCOUNT_ADDRESS, + secret: "", + type: Web3SigningCredentialType.GethKeychainPassword, + }, + }); + expect(depNew).not.toBeUndefined(); + expect(depNew.status).toBe(200); + + const snapshot1 = await bungee.generateSnapshot( + [], + strategy, + networkDetails, + ); + const view2 = bungee.generateView( + snapshot1, + "0", + Number.MAX_SAFE_INTEGER.toString(), + undefined, + ); + //expect to return a view + expect(view2.view).toBeTruthy(); + expect(view2.signature).toBeTruthy(); + + const stateBins = snapshot1.getStateBins(); + expect(stateBins.length).toEqual(2); //expect to have captured state for both assets + + const bins = [stateBins[0].getId(), stateBins[1].getId()]; + + //checks if values match: + // - new value of ETH_ASSET_NAME state in new snapshot different than value from old snapshot) + // - successfully captured transaction that created the new asset + if (bins[0] === ETH_ASSET_NAME) { + expect(snapshot1.getStateBins()[0].getTransactions().length).toEqual(2); + expect(snapshot1.getStateBins()[0].getValue()).not.toEqual( + snapshot.getStateBins()[0].getValue(), + ); + expect(snapshot1.getStateBins()[1].getTransactions().length).toEqual(1); + } else { + expect(snapshot1.getStateBins()[0].getTransactions().length).toEqual(1); + expect(snapshot1.getStateBins()[1].getTransactions().length).toEqual(2); + expect(snapshot1.getStateBins()[1].getValue()).not.toEqual( + snapshot.getStateBins()[0].getValue(), + ); + } + }); +}); + +function stringifyBigIntReplacer(key: string, value: bigint): string { + if (typeof value === "bigint") { + return value.toString(); + } + return value; +} diff --git a/packages/cactus-plugin-bungee-hermes/tsconfig.json b/packages/cactus-plugin-bungee-hermes/tsconfig.json index 22c39860a8..90f5d51571 100644 --- a/packages/cactus-plugin-bungee-hermes/tsconfig.json +++ b/packages/cactus-plugin-bungee-hermes/tsconfig.json @@ -32,10 +32,13 @@ "path": "../cactus-test-tooling/tsconfig.json" }, { - "path": "../cactus-core/tsconfig.json" + "path": "../cactus-plugin-ledger-connector-ethereum/tsconfig.json" + }, + { + "path": "../cactus-test-geth-ledger/tsconfig.json" }, { - "path": "../../extensions/cactus-plugin-object-store-ipfs/tsconfig.json" + "path": "../cactus-core/tsconfig.json" } ] } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 14acbac5d1..9ca3ed82da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8225,8 +8225,9 @@ __metadata: "@hyperledger/cactus-core-api": "npm:2.0.0-alpha.2" "@hyperledger/cactus-plugin-keychain-memory": "npm:2.0.0-alpha.2" "@hyperledger/cactus-plugin-ledger-connector-besu": "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-object-store-ipfs": "npm:2.0.0-alpha.2" + "@hyperledger/cactus-test-geth-ledger": "npm:2.0.0-alpha.2" "@hyperledger/cactus-test-tooling": "npm:2.0.0-alpha.2" "@types/body-parser": "npm:1.19.4" "@types/crypto-js": "npm:4.0.1" @@ -8240,6 +8241,7 @@ __metadata: fabric-network: "npm:2.2.20" fs-extra: "npm:10.1.0" key-encoder: "npm:2.0.3" + merkletreejs: "npm:0.3.11" socket.io: "npm:4.5.4" typescript-optional: "npm:2.0.1" uuid: "npm:9.0.1" @@ -19531,6 +19533,13 @@ __metadata: languageName: node linkType: hard +"buffer-reverse@npm:^1.0.1": + version: 1.0.1 + resolution: "buffer-reverse@npm:1.0.1" + checksum: 10/e350872a89b17af0a7e1bd7a73239a535164f3f010b0800add44f2e52bd0511548dc5b96c20309effba969868c385023d2d02a0add6155f6a76da7b3073b77bd + languageName: node + linkType: hard + "buffer-to-arraybuffer@npm:^0.0.5": version: 0.0.5 resolution: "buffer-to-arraybuffer@npm:0.0.5" @@ -22126,7 +22135,7 @@ __metadata: languageName: node linkType: hard -"crypto-js@npm:4.2.0": +"crypto-js@npm:4.2.0, crypto-js@npm:^4.2.0": version: 4.2.0 resolution: "crypto-js@npm:4.2.0" checksum: 10/c7bcc56a6e01c3c397e95aa4a74e4241321f04677f9a618a8f48a63b5781617248afb9adb0629824792e7ec20ca0d4241a49b6b2938ae6f973ec4efc5c53c924 @@ -36295,6 +36304,19 @@ __metadata: languageName: node linkType: hard +"merkletreejs@npm:0.3.11": + version: 0.3.11 + resolution: "merkletreejs@npm:0.3.11" + dependencies: + bignumber.js: "npm:^9.0.1" + buffer-reverse: "npm:^1.0.1" + crypto-js: "npm:^4.2.0" + treeify: "npm:^1.1.0" + web3-utils: "npm:^1.3.4" + checksum: 10/a93520ef768648d1e4ebd175182bd3d304270b8eb0700df5be99395fb3ad8805407bdaf3231d13b1649e87de799aa06d71c616db047ad039025764eb23b02244 + languageName: node + linkType: hard + "methods@npm:^1.1.2, methods@npm:~1.1.2": version: 1.1.2 resolution: "methods@npm:1.1.2" @@ -48076,6 +48098,13 @@ __metadata: languageName: node linkType: hard +"treeify@npm:^1.1.0": + version: 1.1.0 + resolution: "treeify@npm:1.1.0" + checksum: 10/5241976a751168fb9894a12d031299f1f6337b7f2cbd3eff22ee86e6777620352a69a1cab0d4709251317ff307eeda0dc45918850974fc44f4c7fc50e623b990 + languageName: node + linkType: hard + "treeverse@npm:^3.0.0": version: 3.0.0 resolution: "treeverse@npm:3.0.0" @@ -52166,6 +52195,22 @@ __metadata: languageName: node linkType: hard +"web3-utils@npm:^1.3.4": + version: 1.10.4 + resolution: "web3-utils@npm:1.10.4" + dependencies: + "@ethereumjs/util": "npm:^8.1.0" + bn.js: "npm:^5.2.1" + ethereum-bloom-filters: "npm:^1.0.6" + ethereum-cryptography: "npm:^2.1.2" + ethjs-unit: "npm:0.1.6" + number-to-bn: "npm:1.7.0" + randombytes: "npm:^2.1.0" + utf8: "npm:3.0.0" + checksum: 10/3e586b638cdae9fa45b7698e8a511ae2cbf60e219a900351ae38d384beaaf67424ac6e1d9c5098c3fb8f2ff3cc65a70d977a20bdce3dad542cb50deb666ea2a3 + languageName: node + linkType: hard + "web3-utils@npm:^4.0.7": version: 4.0.7 resolution: "web3-utils@npm:4.0.7"