Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES-1992: migrate to corda runtime plugin #122

3 changes: 1 addition & 2 deletions .ci/Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
@Library('corda-shared-build-pipeline-steps@5.1') _
@Library('corda-shared-build-pipeline-steps@5.2') _

cordaPipeline(
nexusAppId: 'com.corda.CSDE-kotlin.5.0',
publishRepoPrefix: '',
slimBuild: true,
runUnitTests: false,
Expand Down
33 changes: 17 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
# CSDE-cordapp-template-kotlin
# release-V5 cordapp-template-kotlin
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previously this was the name of the repository; now it is a specific branch name where the code would live, and the target repo name



To help make the process of prototyping CorDapps on Corda 5 release more straight forward we have developed the Cordapp Standard Development Environment (CSDE).

The CSDE is obtained by cloning this CSDE-Cordapp-Template-Kotlin repository to your local machine. The CSDE provides:
This template repository provides:

- A pre-setup Cordapp Project which you can use as a starting point to develop your own prototypes.

- A base Gradle configuration which brings in the dependencies you need to write and test a Corda 5 Cordapp.

- A set of Gradle helper tasks which speed up and simplify the development and deployment process.
- A set of Gradle helper tasks, provided by the [Corda runtime gradle plugin](https://github.com/corda/corda-runtime-os/tree/release/os/5.2/tools/corda-runtime-gradle-plugin#readme), which speed up and simplify the development and deployment process.

- Debug configuration for debugging a local Corda cluster.

- The MyFirstFlow code which forms the basis of this getting started documentation, this is located in package com.r3.developers.csdetemplate.flowexample
- The MyFirstFlow code which forms the basis of this getting started documentation, this is located in package com.r3.developers.cordapptemplate.flowexample

- A UTXO example in package com.r3.developers.csdetemplate.utxoexample packages
- A UTXO example in package com.r3.developers.cordapptemplate.utxoexample packages

- Ability to configure the Members of the Local Corda Network.

To find out how to use the CSDE, please refer to the *Getting Started Using the CSDE* subsection within the *Developing Applications* section in the latest Corda 5 documentation at https://docs.r3.com/
To find out how to use the template, please refer to the *<new section name goes here>* subsection within the *Developing Applications* section in the latest Corda 5 documentation at https://docs.r3.com/


## Chat app
Expand All @@ -31,19 +28,23 @@ In this app you can:
3. Individually query out the history of one chat entry. `GetChatFlowArgs`
4. Continue chatting within the chat entry with the counterparty. `UpdateChatFlow`

### Prerequisites
- Corda CLI; version should matching that of the Corda combined worker image used
- Docker

### Setting up

1. We will begin our test deployment with clicking the `startCorda`. This task will load up the combined Corda workers in docker.
A successful deployment will allow you to open the REST APIs at: https://localhost:8888/api/v1/swagger#. You can test out some of the
A successful deployment will allow you to open the REST APIs at: https://localhost:8888/api/v5_2/swagger#. You can test out some of the
functions to check connectivity. (GET /cpi function call should return an empty list as for now.)
2. We will now deploy the cordapp with a click of `5-vNodeSetup` task. Upon successful deployment of the CPI, the GET /cpi function call should now return the meta data of the cpi you just upload
2. We will now deploy the cordapp with a click of `vNodeSetup` task. Upon successful deployment of the CPI, the GET /cpi function call should now return the meta data of the cpi you just upload



### Running the chat app

In Corda 5, flows will be triggered via `POST /flow/{holdingidentityshorthash}` and flow result will need to be view at `GET /flow/{holdingidentityshorthash}/{clientrequestid}`
* holdingidentityshorthash: the id of the network participants, ie Bob, Alice, Charlie. You can view all the short hashes of the network member with another gradle task called `ListVNodes`
* holdingidentityshorthash: the id of the network participants, ie Bob, Alice, Charlie. You can view all the short hashes of the network member with another gradle task called `listVNodes`
* clientrequestid: the id you specify in the flow requestBody when you trigger a flow.

#### Step 1: Create Chat Entry
Expand All @@ -53,7 +54,7 @@ Go to `POST /flow/{holdingidentityshorthash}`, enter the identity short hash(Ali
```
{
"clientRequestId": "create-1",
"flowClassName": "com.r3.developers.csdetemplate.utxoexample.workflows.CreateNewChatFlow",
"flowClassName": "com.r3.developers.cordapptemplate.utxoexample.workflows.CreateNewChatFlow",
"requestBody": {
"chatName":"Chat with Bob",
"otherMember":"CN=Bob, OU=Test Dept, O=R3, L=London, C=GB",
Expand All @@ -70,7 +71,7 @@ Go to `POST /flow/{holdingidentityshorthash}`, enter the identity short hash(Ali
```
{
"clientRequestId": "list-1",
"flowClassName": "com.r3.developers.csdetemplate.utxoexample.workflows.ListChatsFlow",
"flowClassName": "com.r3.developers.cordapptemplate.utxoexample.workflows.ListChatsFlow",
"requestBody": {}
}
```
Expand All @@ -85,7 +86,7 @@ this message will be recorded as a message from Alice, vice versa. And the id fi
```
{
"clientRequestId": "update-1",
"flowClassName": "com.r3.developers.csdetemplate.utxoexample.workflows.UpdateChatFlow",
"flowClassName": "com.r3.developers.cordapptemplate.utxoexample.workflows.UpdateChatFlow",
"requestBody": {
"id":" ** fill in id **",
"message": "How are you today?"
Expand All @@ -100,7 +101,7 @@ After a few back and forth of the messaging, you can view entire chat history by
```
{
"clientRequestId": "get-1",
"flowClassName": "com.r3.developers.csdetemplate.utxoexample.workflows.GetChatFlow",
"flowClassName": "com.r3.developers.cordapptemplate.utxoexample.workflows.GetChatFlow",
"requestBody": {
"id":" ** fill in id **",
"numberOfRecords":"4"
Expand Down
65 changes: 29 additions & 36 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

import static org.gradle.api.JavaVersion.VERSION_17

plugins {
Expand All @@ -6,40 +8,45 @@ plugins {
id 'org.jetbrains.kotlin.plugin.jpa'
id 'java'
id 'maven-publish'
id 'net.corda.plugins.csde'
id 'net.corda.gradle.plugin'
}

allprojects {
group 'com.r3.developers.csdetemplate'
group 'com.r3.developers.cordapptemplate'
version '1.0-SNAPSHOT'

def javaVersion = VERSION_17

// Configure the CSDE
csde {
// Configure Corda runtime gradle plugin
cordaRuntimeGradlePlugin {
notaryVersion = cordaNotaryPluginsVersion
notaryCpiName = "NotaryServer"
corDappCpiName = "MyCorDapp"
cpiUploadTimeout = "30000"
vnodeRegistrationTimeout = "60000"
cordaProcessorTimeout = "300000"
workflowsModuleName = "workflows"
cordaClusterURL = "https://localhost:8888"
cordaRestUser = "admin"
cordaRestPasswd ="admin"
composeFilePath = "config/combined-worker-kafka-compose.yaml"
networkConfigFile = "config/static-network-config.json"
r3RootCertFile = "config/r3-ca-key.pem"
corDappCpiName = "MyCorDapp"
notaryCpiName = "NotaryServer"
cordaRpcUser = "admin"
cordaRpcPasswd ="admin"
workflowsModuleName = workflowsModule
csdeWorkspaceDir = "workspace"
notaryVersion = cordaNotaryPluginsVersion
combinedWorkerVersion = combinedWorkerJarVersion
postgresJdbcVersion = "42.4.3"
cordaDbContainerName = "CSDEpostgresql"
cordaBinDir = "${System.getProperty("user.home")}/$cordaBinariesDirectory"
cordaCliBinDir = "${System.getProperty("user.home")}/$cordaCliBinariesDirectory"
cpiUploadTimeout = cpiUploadDefault
cordaProcessorTimeout = processorTimeout
vnodeRegistrationTimeout = vnodeRegistrationTimeoutDefault
skipTestsDuringBuildCpis = this.skipTestsDuringBuildCpis
skipTestsDuringBuildCpis = "false"
cordaRuntimePluginWorkspaceDir = "workspace"
cordaBinDir = "${System.getProperty("user.home")}/.corda/corda5"
cordaCliBinDir = "${System.getProperty("user.home")}/.corda/cli"

// Alternatively, you can use a Database-only combined worker:
// composeFilePath = "config/combined-worker-compose.yaml"
Copy link
Contributor Author

@anton-subbotin anton-subbotin Feb 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an example of a Database-only compose file in the plugin's readme; the link to the readme was added to this repo's README.

The question is - do we still want to provide a no-kafka example here in the template repo, including this comment and the compose yaml file in the config?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should steer people to the Kafka enabled version, as it's quicker. We then offer the db only version to those who need it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine to just have the Kafka version here. The non-Kafka version remains documented with the Gradle plugin.


// Only need to supply these if you want to use an unpublished version
artifactoryUsername = findProperty('cordaArtifactoryUsername') ?: System.getenv('CORDA_ARTIFACTORY_USERNAME')
artifactoryPassword = findProperty('cordaArtifactoryPassword') ?: System.getenv('CORDA_ARTIFACTORY_PASSWORD')
}

// Declare the set of Kotlin compiler options we need to build a CorDapp.
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
tasks.withType(KotlinCompile).configureEach {
kotlinOptions {
allWarningsAsErrors = false

Expand Down Expand Up @@ -85,20 +92,6 @@ allprojects {
password = findProperty('cordaArtifactoryPassword') ?: System.getenv('CORDA_ARTIFACTORY_PASSWORD')
}
}
maven {
// Quasar & Antlr
url = "$artifactoryContextUrl/corda-dependencies-dev"
authentication {
basic(BasicAuthentication)
}
credentials {
username = findProperty('cordaArtifactoryUsername') ?: System.getenv('CORDA_ARTIFACTORY_USERNAME')
password = findProperty('cordaArtifactoryPassword') ?: System.getenv('CORDA_ARTIFACTORY_PASSWORD')
}
mavenContent {
snapshotsOnly()
}
}
}

tasks.withType(Test).configureEach {
Expand All @@ -110,7 +103,7 @@ allprojects {
publishing {
publications {
maven(MavenPublication) {
artifactId "corda-CSDE-kotlin-sample"
artifactId "corda-dev-template-kotlin-sample"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is being used anywhere; publishing is disabled in the pipeline

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't really see why it would ever be published.

groupId project.group
artifact jar
}
Expand Down
32 changes: 32 additions & 0 deletions config/combined-worker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
version: '2'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just have the Kafka version...

services:
postgresql:
image: postgres:14.10
restart: unless-stopped
tty: true
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=cordacluster
ports:
- 5432:5432

corda:
image: corda-os-docker.software.r3.com/corda-os-combined-worker:5.2.0.0-RC02
depends_on:
- postgresql
environment:
JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
command: [
"-mbus.busType=DATABASE",
"-spassphrase=password",
"-ssalt=salt",
"-ddatabase.user=user",
"-ddatabase.pass=password",
"-ddatabase.jdbc.url=jdbc:postgresql://postgresql:5432/cordacluster",
"-ddatabase.jdbc.directory=/opt/jdbc-driver/"
]
ports:
- 8888:8888
- 7004:7004
- 5005:5005
72 changes: 72 additions & 0 deletions config/combined-worker-kafka-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
version: '2'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've got some ideas for improvements we can make with this file but they can wait for another day.

services:
postgresql:
image: postgres:14.10
restart: unless-stopped
tty: true
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=cordacluster
ports:
- 5432:5432

kafka:
image: confluentinc/cp-kafka:latest
ports:
- 9092:9092
environment:
KAFKA_NODE_ID: 1
CLUSTER_ID: ZDFiZmU3ODUyMzRiNGI3NG
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,DOCKER_INTERNAL://0.0.0.0:29092,CONTROLLER://0.0.0.0:9093
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092,DOCKER_INTERNAL://kafka:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,DOCKER_INTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: DOCKER_INTERNAL
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_DEFAULT_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"

kafka-create-topics:
image: openjdk:17-jdk
depends_on:
- kafka
volumes:
- ${CORDA_CLI:-~/.corda/cli}:/opt/corda-cli
working_dir: /opt/corda-cli
command: [
"java",
"-jar",
"corda-cli.jar",
"topic",
"-b=kafka:29092",
"create",
"connect"
]

corda:
image: corda-os-docker.software.r3.com/corda-os-combined-worker-kafka:5.2.0.0-RC02
depends_on:
- postgresql
- kafka
- kafka-create-topics
environment:
JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
Copy link
Contributor Author

@anton-subbotin anton-subbotin Feb 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This piece is missing in the examples provided in the plugin's readme.
This is necessary to enable debugger connection on port 5005 - to provide the string in the JAVA_TOOL_OPTIONS variable.
For some reason, if we specify it as one of the args in the command list, it doesn't seem to be applied by JVM (as it does when started on a local JVM outside container), and debug connection fails.

command: [
"-mbus.busType=KAFKA",
"-mbootstrap.servers=kafka:29092",
"-spassphrase=password",
"-ssalt=salt",
"-ddatabase.user=user",
"-ddatabase.pass=password",
"-ddatabase.jdbc.url=jdbc:postgresql://postgresql:5432/cordacluster",
"-ddatabase.jdbc.directory=/opt/jdbc-driver/"
]
ports:
- 8888:8888
- 7004:7004
- 5005:5005
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.r3.developers.csdetemplate.utxoexample.contracts
package com.r3.developers.cordapptemplate.utxoexample.contracts
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename package - change csdetemplate to cordapptemplate; I'm open for suggestions of a better name

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto


import com.r3.developers.csdetemplate.utxoexample.states.ChatState
import com.r3.developers.cordapptemplate.utxoexample.states.ChatState
import net.corda.v5.base.exceptions.CordaRuntimeException
import net.corda.v5.ledger.utxo.Command
import net.corda.v5.ledger.utxo.Contract
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.r3.developers.csdetemplate.utxoexample.states
package com.r3.developers.cordapptemplate.utxoexample.states

import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract
import net.corda.v5.base.types.MemberX500Name
import net.corda.v5.ledger.utxo.BelongsToContract
import net.corda.v5.ledger.utxo.ContractState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import java.security.PublicKey
import java.util.UUID

/**
* The following is the base implementation of the Contract Tests for the Apples CSDE-template-tutorial.
* The following is the base implementation of the Contract Tests for the Apples CorDapp template tutorial.
*
* - The AppleContractTest abstract class implements the ContractTest class.
* - For full contract test coverage, we generally create a class for every command scenario for every state.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package com.r3.developers.csdetemplate.utxoexample.contracts
package com.r3.developers.cordapptemplate.utxoexample.contracts

import com.r3.corda.ledger.utxo.testing.ContractTest
import com.r3.corda.ledger.utxo.testing.buildTransaction
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.CREATE_COMMAND_SHOULD_HAVE_NO_INPUT_STATES
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.CREATE_COMMAND_SHOULD_HAVE_ONLY_ONE_OUTPUT_STATE
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.OUTPUT_STATE_SHOULD_ONLY_HAVE_TWO_PARTICIPANTS
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.REQUIRE_SINGLE_COMMAND
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.TRANSACTION_SHOULD_BE_SIGNED_BY_ALL_PARTICIPANTS
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.UNKNOWN_COMMAND
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Create
import com.r3.developers.csdetemplate.utxoexample.states.ChatState
import net.corda.v5.crypto.SecureHash
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.CREATE_COMMAND_SHOULD_HAVE_NO_INPUT_STATES
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.CREATE_COMMAND_SHOULD_HAVE_ONLY_ONE_OUTPUT_STATE
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.OUTPUT_STATE_SHOULD_ONLY_HAVE_TWO_PARTICIPANTS
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.REQUIRE_SINGLE_COMMAND
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.TRANSACTION_SHOULD_BE_SIGNED_BY_ALL_PARTICIPANTS
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.UNKNOWN_COMMAND
import com.r3.developers.cordapptemplate.utxoexample.states.ChatState
import net.corda.v5.ledger.utxo.Command
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import java.util.*

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.r3.developers.csdetemplate.utxoexample.contracts
package com.r3.developers.cordapptemplate.utxoexample.contracts

import com.r3.corda.ledger.utxo.testing.ContractTest
import com.r3.corda.ledger.utxo.testing.buildTransaction
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.TRANSACTION_SHOULD_BE_SIGNED_BY_ALL_PARTICIPANTS
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.UPDATE_COMMAND_CHATNAME_SHOULD_NOT_CHANGE
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.UPDATE_COMMAND_ID_SHOULD_NOT_CHANGE
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.UPDATE_COMMAND_PARTICIPANTS_SHOULD_NOT_CHANGE
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.UPDATE_COMMAND_SHOULD_HAVE_ONLY_ONE_INPUT_STATE
import com.r3.developers.csdetemplate.utxoexample.contracts.ChatContract.Companion.UPDATE_COMMAND_SHOULD_HAVE_ONLY_ONE_OUTPUT_STATE
import com.r3.developers.csdetemplate.utxoexample.states.ChatState
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.TRANSACTION_SHOULD_BE_SIGNED_BY_ALL_PARTICIPANTS
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.UPDATE_COMMAND_CHATNAME_SHOULD_NOT_CHANGE
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.UPDATE_COMMAND_ID_SHOULD_NOT_CHANGE
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.UPDATE_COMMAND_PARTICIPANTS_SHOULD_NOT_CHANGE
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.UPDATE_COMMAND_SHOULD_HAVE_ONLY_ONE_INPUT_STATE
import com.r3.developers.cordapptemplate.utxoexample.contracts.ChatContract.Companion.UPDATE_COMMAND_SHOULD_HAVE_ONLY_ONE_OUTPUT_STATE
import com.r3.developers.cordapptemplate.utxoexample.states.ChatState
import net.corda.v5.ledger.utxo.StateAndRef
import org.junit.jupiter.api.Test
import java.util.*
Expand Down
Loading