Skip to content

Commit

Permalink
feat(connector-corda): add vaultQueryV1 REST API operation + endpoint
Browse files Browse the repository at this point in the history
Primary change(s):
-----------------

1. Adds a (for now) simplistic endpoint to query ledger state which allows
us to retrieve identifiers needed to construct flow requests in certain
use-cases.
2. This expands the number of supported use-cases for the Corda v4 (JVM)
connector.

Notes:
-------
Automated testing is work in progress, but it depends on a few other
big(er) changes so in an effort to limit the size of this pull request
I'm only submitting the steps for manual testing as documented in the
package's README.md file. These are steps which I have executed myself
and can vouch that they work as expected.

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
  • Loading branch information
petermetz committed Jul 8, 2024
1 parent ad08788 commit d2bf145
Show file tree
Hide file tree
Showing 24 changed files with 527 additions and 26 deletions.
9 changes: 8 additions & 1 deletion openapi-generator-ignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,11 @@
**/.gitignore
**/generated/openapi/kotlin-client/docs/**
**/generated/openapi/kotlin-client/gradle/**
**/generated/**/.openapi-generator-ignore
**/generated/**/.openapi-generator-ignore

# TODO: Figure out a better way to generalize these ignore patterns that are
# currently specific to the corda connector server v4
packages/cactus-plugin-ledger-connector-corda/src/main-server/kotlin/gen/kotlin-spring/pom.xml
packages/cactus-plugin-ledger-connector-corda/src/main-server/kotlin/gen/kotlin-spring/build.gradle.kts
packages/cactus-plugin-ledger-connector-corda/src/main-server/kotlin/gen/kotlin-spring/src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/Application.kt
packages/cactus-plugin-ledger-connector-corda/src/main-server/kotlin/gen/kotlin-spring/src/test/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/api/ApiPluginLedgerConnectorCordaTest.kt
106 changes: 106 additions & 0 deletions packages/cactus-plugin-ledger-connector-corda/README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/cactus-plugin-ledger-connector-corda/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"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/ --ignore-file-override ../../openapi-generator-ignore",
"generate-server": "yarn run --top-level openapi-generator-cli generate -i ./src/main/json/openapi.json -g kotlin-spring -o ./src/main-server/kotlin/gen/kotlin-spring/ -c ./src/main-server/openapi-generator-config.yaml",
"generate-server": "yarn run --top-level openapi-generator-cli generate -i ./src/main/json/openapi.json -g kotlin-spring -o ./src/main-server/kotlin/gen/kotlin-spring/ -c ./src/main-server/openapi-generator-config.yaml --ignore-file-override ../../openapi-generator-ignore",
"watch": "npm-watch",
"webpack": "npm-run-all webpack:dev",
"webpack:dev": "npm-run-all webpack:dev:node webpack:dev:web",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
README.md
pom.xml
settings.gradle
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/api/ApiPluginLedgerConnectorCordaController.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/api/ApiPluginLedgerConnectorCordaService.kt
Expand Down Expand Up @@ -38,5 +37,6 @@ src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/mode
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/StartMonitorV1Response.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/StopMonitorV1Request.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/StopMonitorV1Response.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/VaultQueryV1Request.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/X500Principal.kt
src/main/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

group = "org.hyperledger.cactus.plugin.ledger.connector.corda.server"
version = project.properties["version"]!!

val corda_release_group = "net.corda"
val corda_core_release_group = "net.corda"
val corda_release_version = "4.6"
Expand All @@ -19,9 +22,6 @@ buildscript {
}
}

group = "org.hyperledger.cactus.plugin.ledger.connector.corda.server"
version = "0.3.0"

repositories {
maven { url = uri("https://repo1.maven.org/maven2") }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version = 2.0.0-rc.2
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.StartMo
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.StartMonitorV1Response
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.StopMonitorV1Request
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.StopMonitorV1Response
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.VaultQueryV1Request
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
Expand Down Expand Up @@ -153,4 +154,15 @@ class ApiPluginLedgerConnectorCordaController(@Autowired(required = true) val se
fun stopMonitorV1( @Valid @RequestBody(required = false) stopMonitorV1Request: StopMonitorV1Request?): ResponseEntity<StopMonitorV1Response> {
return ResponseEntity(service.stopMonitorV1(stopMonitorV1Request), HttpStatus.valueOf(200))
}


@RequestMapping(
method = [RequestMethod.POST],
value = ["/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/vault-query"],
produces = ["application/json"],
consumes = ["application/json"]
)
fun vaultQueryV1( @Valid @RequestBody(required = false) vaultQueryV1Request: VaultQueryV1Request?): ResponseEntity<kotlin.Any> {
return ResponseEntity(service.vaultQueryV1(vaultQueryV1Request), HttpStatus.valueOf(200))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.StartMo
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.StartMonitorV1Response
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.StopMonitorV1Request
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.StopMonitorV1Response
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.VaultQueryV1Request

interface ApiPluginLedgerConnectorCordaService {

Expand Down Expand Up @@ -113,4 +114,14 @@ interface ApiPluginLedgerConnectorCordaService {
* @see ApiPluginLedgerConnectorCorda#stopMonitorV1
*/
fun stopMonitorV1(stopMonitorV1Request: StopMonitorV1Request?): StopMonitorV1Response

/**
* POST /api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/vault-query
* Queryes the vault service for state references based on JVM class names. Custom filters are not supported by this endpoint.
*
* @param vaultQueryV1Request (optional)
* @return OK (status code 200)
* @see ApiPluginLedgerConnectorCorda#vaultQueryV1
*/
fun vaultQueryV1(vaultQueryV1Request: VaultQueryV1Request?): kotlin.Any
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package org.hyperledger.cactus.plugin.ledger.connector.corda.server.impl

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.ObjectWriter
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.*
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.springframework.stereotype.Service
import net.corda.core.contracts.ContractState
import net.corda.core.flows.FlowLogic
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.FlowProgressHandle
Expand All @@ -21,15 +18,15 @@ import net.schmizz.sshj.userauth.password.PasswordUtils
import net.schmizz.sshj.xfer.InMemorySourceFile
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.api.ApiPluginLedgerConnectorCordaService
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.*
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Service
import org.springframework.web.server.ResponseStatusException
import org.springframework.web.util.HtmlUtils.htmlEscape
import java.io.IOException
import java.io.InputStream
import java.lang.RuntimeException
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.IllegalArgumentException
import net.corda.core.contracts.ContractState
import org.springframework.web.util.HtmlUtils.htmlEscape
import kotlin.Exception


// TODO Look into this project for powering the connector of ours:
// https://github.com/180Protocol/codaptor
Expand All @@ -50,6 +47,7 @@ class ApiPluginLedgerConnectorCordaServiceImpl(
val mapper: ObjectMapper = jacksonObjectMapper()
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
// .registerModule(JavaTimeModule())

val writer: ObjectWriter = mapper.writer()

Expand Down Expand Up @@ -255,7 +253,7 @@ class ApiPluginLedgerConnectorCordaServiceImpl(
logger.debug("${it.filename} has db migrations declared, executing those now...")
val session = ssh.startSession()
session.allocateDefaultPTY()
val migrateCmd = "java -jar ${cdc.cordaJarPath} run-migration-scripts --app-schemas --base-directory=${cdc.nodeBaseDirPath}"
val migrateCmd = "java -jar ${cdc.cordaJarPath} run-migration-scripts --verbose --app-schemas --base-directory=${cdc.nodeBaseDirPath}"
logger.debug("migrateCmd=$migrateCmd")
val migrateCmdRes = session.exec(migrateCmd)
val migrateCmdOut = net.schmizz.sshj.common.IOUtils.readFully(migrateCmdRes.inputStream).toString()
Expand Down Expand Up @@ -355,6 +353,35 @@ class ApiPluginLedgerConnectorCordaServiceImpl(
return nodeInfoList
}

override fun vaultQueryV1(vaultQueryV1Request: VaultQueryV1Request?): Any {
if (vaultQueryV1Request == null) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "QueryBySimpleV1Request cannot be null")
}
if (vaultQueryV1Request.contractStateType == null) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "QueryBySimpleV1Request.contractStateType cannot be null")
}
logger.trace("ENTER vaultQueryV1() vaultQueryV1Request.contractStateType={}", vaultQueryV1Request.contractStateType);
val contractStateType = vaultQueryV1Request.contractStateType;

val clazz: Class<out ContractState>;
try {
clazz = jsonJvmObjectDeserializer.getOrInferType(contractStateType) as Class<out ContractState>
} catch (ex: Throwable) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Could not load $contractStateType class from classpath:", ex)
}

if(!ContractState::class.java.isAssignableFrom(clazz)) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Provided QueryBySimpleV1Request.contractStateType (${contractStateType}) must be assignable from (e.g. a sub-class of) ${ContractState::class.java.name}")
}

logger.debug("vaultQueryV1() Querying Corda vault...");
val results = rpc.proxy.vaultQuery(clazz)
logger.debug("vaultQueryV1() Queried Corda vault OK");
logger.trace("EXIT vaultQueryV1() results={}", results);

return results
}

/**
* Start monitoring state changes for clientAppID of stateClass specified in the request body.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.hyperledger.cactus.plugin.ledger.connector.corda.server.model

import java.util.Objects
import com.fasterxml.jackson.annotation.JsonProperty
import javax.validation.constraints.DecimalMax
import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Email
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import javax.validation.Valid

/**
*
* @param contractStateType Valid, fully qualified JVM class name which will be fed into Class.forName(...)
*/
data class VaultQueryV1Request(

@get:Size(min=1)
@get:JsonProperty("contractStateType") val contractStateType: kotlin.String? = null
) {

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#!/bin/bash

for i in 1 2 3 4 5; do java -jar ${APP}/kotlin-spring/build/libs/cactus-connector-corda-server-0.3.0.jar && break || sleep 15; done
# Without these we get crashes on JDK 17 an above since the introduction of the
# Java Modules system.
EXTRA_JVM_ARGS=""

for i in 1 2 3; do java $EXTRA_JVM_ARGS -jar ${APP}/kotlin-spring/build/libs/cactus-connector-corda-server-2.0.0-rc.2.jar && break || sleep 5; done
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"openapi": "3.0.3",
"info": {
"title": "Hyperledger Cactus Plugin - Connector Corda",
"title": "Hyperledger Cacti Plugin - Connector Corda",
"description": "Can perform basic tasks on a Corda ledger",
"version": "2.0.0-rc.2",
"license": {
Expand Down Expand Up @@ -864,10 +864,58 @@
"PrometheusExporterMetricsResponse": {
"type": "string",
"nullable": false
},
"VaultQueryV1Request": {
"type": "object",
"additionalProperties": false,
"properties": {
"contractStateType": {
"type": "string",
"description": "Valid, fully qualified JVM class name which will be fed into Class.forName(...)",
"minLength": 1
}
}
},
"VaultQueryV1Response": {
"type": "object"
}
}
},
"paths": {
"/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/vault-query": {
"post": {
"operationId": "vaultQueryV1",
"x-hyperledger-cactus": {
"http": {
"path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/vault-query",
"verbLowerCase": "post"
}
},
"description": "Queryes the vault service for state references based on JVM class names. Custom filters are not supported by this endpoint.",
"parameters": [],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VaultQueryV1Request"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VaultQueryV1Response"
}
}
}
}
}
}
},
"/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/deploy-contract-jars": {
"post": {
"operationId": "deployContractJarsV1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"openapi": "3.0.3",
"info": {
"title": "Hyperledger Cactus Plugin - Connector Corda",
"title": "Hyperledger Cacti Plugin - Connector Corda",
"description": "Can perform basic tasks on a Corda ledger",
"version": "2.0.0-rc.2",
"license": {
Expand Down Expand Up @@ -864,10 +864,58 @@
"PrometheusExporterMetricsResponse": {
"type": "string",
"nullable": false
},
"VaultQueryV1Request": {
"type": "object",
"additionalProperties": false,
"properties": {
"contractStateType": {
"type": "string",
"description": "Valid, fully qualified JVM class name which will be fed into Class.forName(...)",
"minLength": 1
}
}
},
"VaultQueryV1Response": {
"type": "object"
}
}
},
"paths": {
"/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/vault-query": {
"post": {
"operationId": "vaultQueryV1",
"x-hyperledger-cactus": {
"http": {
"path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/vault-query",
"verbLowerCase": "post"
}
},
"description": "Queryes the vault service for state references based on JVM class names. Custom filters are not supported by this endpoint.",
"parameters": [],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VaultQueryV1Request"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VaultQueryV1Response"
}
}
}
}
}
}
},
"/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/deploy-contract-jars": {
"post": {
"operationId": "deployContractJarsV1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@ src/main/kotlin/org/openapitools/client/models/StartMonitorV1Request.kt
src/main/kotlin/org/openapitools/client/models/StartMonitorV1Response.kt
src/main/kotlin/org/openapitools/client/models/StopMonitorV1Request.kt
src/main/kotlin/org/openapitools/client/models/StopMonitorV1Response.kt
src/main/kotlin/org/openapitools/client/models/VaultQueryV1Request.kt
src/main/kotlin/org/openapitools/client/models/X500Principal.kt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# org.openapitools.client - Kotlin client library for Hyperledger Cactus Plugin - Connector Corda
# org.openapitools.client - Kotlin client library for Hyperledger Cacti Plugin - Connector Corda

Can perform basic tasks on a Corda ledger

Expand Down Expand Up @@ -54,6 +54,7 @@ Class | Method | HTTP request | Description
*DefaultApi* | [**networkMapV1**](docs/DefaultApi.md#networkmapv1) | **POST** /api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/network-map |
*DefaultApi* | [**startMonitorV1**](docs/DefaultApi.md#startmonitorv1) | **POST** /api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/start-monitor | Start monitoring corda changes (transactions) of given state class
*DefaultApi* | [**stopMonitorV1**](docs/DefaultApi.md#stopmonitorv1) | **DELETE** /api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/stop-monitor | Stop monitoring corda changes (transactions) of given state class
*DefaultApi* | [**vaultQueryV1**](docs/DefaultApi.md#vaultqueryv1) | **POST** /api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/vault-query |


<a id="documentation-for-models"></a>
Expand Down Expand Up @@ -93,6 +94,7 @@ Class | Method | HTTP request | Description
- [org.openapitools.client.models.StartMonitorV1Response](docs/StartMonitorV1Response.md)
- [org.openapitools.client.models.StopMonitorV1Request](docs/StopMonitorV1Request.md)
- [org.openapitools.client.models.StopMonitorV1Response](docs/StopMonitorV1Response.md)
- [org.openapitools.client.models.VaultQueryV1Request](docs/VaultQueryV1Request.md)
- [org.openapitools.client.models.X500Principal](docs/X500Principal.md)


Expand Down
Loading

0 comments on commit d2bf145

Please sign in to comment.