- Running the example CorDapp
- Downloading the example CorDapp
- Opening the example CorDapp in IntelliJ
- Running the example CorDapp
- Interacting with the example CorDapp
- Running nodes across machines
- Testing your CorDapp
- Debugging your CorDapp
The example CorDapp allows nodes to agree IOUs with each other, as long as they obey the following contract rules:
- The IOU’s value is strictly positive
- A node is not trying to issue an IOU to itself
We will deploy and run the CorDapp on four test nodes:
- Notary, which runs a notary service
Because data is only propagated on a need-to-know basis, any IOUs agreed between PartyA and PartyB become “shared facts” between PartyA and PartyB only. PartyC won’t be aware of these IOUs.
Start by downloading the example CorDapp from GitHub:
- Set up your machine by following the quickstart guide
- Clone the samples repository from using the following command:
git clone https://github.com/corda/samples
- Change directories to the
Let’s open the example CorDapp in IntelliJ IDEA:
- Open IntelliJ
- A splash screen will appear. Click
open, navigate to and select the
cordapp-examplefolder, and click
- Once the project is open, click
Project Structure. Under
Project SDK:, set the project SDK by clicking
JDK, and navigating to
C:\Program Files\Java\jdk1.8.0_XXXon Windows or
Library/Java/JavaVirtualMachines/jdk1.8.XXXon MacOSX (where
XXXis the latest minor version number). Click
- Again under
Project Structure, select
Import Module, then select the
cordapp-examplefolder and click
Open. Choose to
Import module from external model, select
Finish(leaving the defaults) and
- Gradle will now download all the project dependencies and perform some indexing. This usually takes a minute or so
The example CorDapp has the following structure:
. ├── LICENCE ├── README.md ├── TRADEMARK ├── build.gradle ├── clients │ ├── build.gradle │ └── src │ └── main │ ├── kotlin │ │ └── com │ │ └── example │ │ └── server │ │ ├── MainController.kt │ │ ├── NodeRPCConnection.kt │ │ └── Server.kt │ └── resources │ ├── application.properties │ └── public │ ├── index.html │ └── js │ └── angular-module.js ├── config │ ├── dev │ │ └── log4j2.xml │ └── test │ └── log4j2.xml ├── contracts-java │ ├── build.gradle │ └── src │ └── main │ └── java │ └── com │ └── example │ ├── contract │ │ └── IOUContract.java │ ├── schema │ │ ├── IOUSchema.java │ │ └── IOUSchemaV1.java │ └── state │ └── IOUState.java ├── contracts-kotlin │ ├── build.gradle │ └── src │ └── main │ └── kotlin │ └── com │ └── example │ ├── contract │ │ └── IOUContract.kt │ ├── schema │ │ └── IOUSchema.kt │ └── state │ └── IOUState.kt ├── cordapp-example.iml ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── lib │ ├── README.txt │ └── quasar.jar ├── settings.gradle ├── workflows-java │ ├── build.gradle │ └── src │ ├── integrationTest │ │ └── java │ │ └── com │ │ └── example │ │ └── DriverBasedTests.java │ ├── main │ │ └── java │ │ └── com │ │ └── example │ │ └── flow │ │ └── ExampleFlow.java │ └── test │ └── java │ └── com │ └── example │ ├── NodeDriver.java │ ├── contract │ │ └── IOUContractTests.java │ └── flow │ └── IOUFlowTests.java └── workflows-kotlin ├── build.gradle └── src ├── integrationTest │ └── kotlin │ └── com │ └── example │ └── DriverBasedTests.kt ├── main │ └── kotlin │ └── com │ └── example │ └── flow │ └── ExampleFlow.kt └── test └── kotlin └── com └── example ├── NodeDriver.kt ├── contract │ └── IOUContractTests.kt └── flow └── IOUFlowTests.kt
The key files and directories are as follows:
- The root directory contains some gradle files, a README and a LICENSE
- config contains log4j2 configs
- gradle contains the gradle wrapper, which allows the use of Gradle without installing it yourself and worrying about which version is required
- lib contains the Quasar jar which rewrites our CorDapp’s flows to be checkpointable
- clients contains the source code for spring boot integration
- contracts-java and workflows-java contain the source code for the example CorDapp written in Java
- contracts-kotlin and workflows-kotlin contain the same source code, but written in Kotlin. CorDapps can be developed in either Java and Kotlin
There are two ways to run the example CorDapp:
- Via the terminal
- Via IntelliJ
Both approaches will create a set of test nodes, install the CorDapp on these nodes, and then run the nodes. You can read more about how we generate nodes here.
- Open a terminal window in the
- Run the
deployNodesGradle task to build four nodes with our CorDapp already installed on them:
- Unix/Mac OSX:
- Unix/Mac OSX:
CorDapps can be written in any language targeting the JVM. In our case, we’ve provided the example source in both Kotlin and Java. Since both sets of source files are functionally identical, we will refer to the Kotlin version throughout the documentation.
After the build finishes, you will see the following output in the
- A folder for each generated node
runnodesshell script for running all the nodes simultaneously on osX
runnodes.batbatch file for running all the nodes simultaneously on Windows
Each node in the
nodesfolder will have the following structure:
. nodeName ├── additional-node-infos // ├── certificates ├── corda.jar // The Corda node runtime ├── cordapps // The node's CorDapps │ ├── corda-finance-contracts-4.3.jar │ ├── corda-finance-workflows-4.3.jar │ └── cordapp-example-0.1.jar ├── drivers ├── logs ├── network-parameters ├── node.conf // The node's configuration file ├── nodeInfo-<HASH> // The hash will be different each time you generate a node └── persistence.mv.db // The node's database
Start the nodes by running the following command from the root of the
- Unix/Mac OSX:
Each Spring Boot server needs to be started in its own terminal/command prompt, replace X with A, B and C:
- Unix/Mac OSX:
Look for the Started ServerKt in X seconds message, don’t rely on the % indicator.
On Unix/Mac OSX, do not click/change focus until all seven additional terminal windows have opened, or some
nodes may fail to start. You can run
workflows-kotlin/build/nodes/runnodes --headless to prevent each server from opening in a new terminal window. To interact with the nodes will need to use ssh, see Node shell.
For each node, the
runnodes script creates a node tab/window:
______ __ / ____/ _________/ /___ _ / / __ / ___/ __ / __ `/ Top tip: never say "oops", instead / /___ /_/ / / / /_/ / /_/ / always say "Ah, Interesting!" \____/ /_/ \__,_/\__,_/ --- Corda Open Source corda-4.3 (4157c25) ----------------------------------------------- Logs can be found in : /Users/joeldudley/Desktop/cordapp-example/workflows-kotlin/build/nodes/PartyA/logs Database connection url is : jdbc:h2:tcp://localhost:59472/node Incoming connection address : localhost:10005 Listening on port : 10005 Loaded CorDapps : corda-finance-corda-4.3, cordapp-example-0.1, corda-core-corda-4.3 Node for "PartyA" started up and registered in 38.59 sec Welcome to the Corda interactive shell. Useful commands include 'help' to see what is available, and 'bye' to shut down the node. Fri Mar 02 17:34:02 GMT 2018>>>
It usually takes around 60 seconds for the nodes to finish starting up. Each node will display “Welcome to the Corda interactive shell.” along with a prompt when ready.
Load the project by opening the project folder (Do not use “Import Project” functionality by IntelliJ because it will overwrite the pre-existing configuration)
Follow the prompt to
import Gradle project
Run Example CorDapp - Kotlinrun configuration from the drop-down menu at the top right-hand side of the IDE
Click the green arrow to start the nodes:
cordapp-example.workflows-kotlin.testfor the Use classpath of module field, and then click Run
To stop the nodes, press the red square button at the top right-hand side of the IDE, next to the run configurations
The Spring Boot servers run locally on the following ports:
These ports are defined in
Each Spring Boot server exposes the following endpoints:
partyNamewhich is CN name of a node
There is also a web front-end served from the home web page e.g.
The content is only available for demonstration purposes and does not implement anti-XSS, anti-XSRF or other security techniques. Do not use this code in production.
An IOU can be created by sending a PUT request to the
/api/example/create-iou endpoint directly, or by using the
the web form served from the home directory.
To create an IOU between PartyA and PartyB, run the following command from the command line:
curl -i -X POST 'http://localhost:50005/api/example/create-iou?iouValue=12&partyName=O=PartyC,L=Paris,C=FR' -H 'Content-Type: application/x-www-form-urlencoded'
Note that both PartyA’s port number (
50005) and PartyB are referenced in the PUT request path. This command
instructs PartyA to agree an IOU with PartyB. Once the process is complete, both nodes will have a signed, notarised
copy of the IOU. PartyC will not.
To create an IOU between PartyA and PartyB, navigate to the home directory for the node, click the “create IOU” button at the top-left of the page, and enter the IOU details into the web-form. The IOU must have a positive value. For example:
Counterparty: Select from list Value (Int): 5
And click submit. Upon clicking submit, the modal dialogue will close, and the nodes will agree the IOU.
Assuming all went well, you can view the newly-created IOU by accessing the vault of PartyA or PartyB:
Via the HTTP API:
- PartyA’s vault: Navigate to http://localhost:50005/api/example/ious
- PartyB’s vault: Navigate to http://localhost:50006/api/example/ious
Via home page:
- PartyA: Navigate to http://localhost:50005 and hit the “refresh” button
- PartyB: Navigate to http://localhost:50006 and hit the “refresh” button
The vault and web front-end of PartyC (at
localhost:50007) will not display any IOUs. This is because PartyC was
not involved in this transaction.
Nodes started via the terminal will display an interactive shell:
Welcome to the Corda interactive shell. Useful commands include 'help' to see what is available, and 'bye' to shut down the node. Fri Jul 07 16:36:29 BST 2017>>>
flow list in the shell to see a list of the flows that your node can run. In our case, this will return the
com.example.flow.ExampleFlow$Initiator net.corda.core.flows.ContractUpgradeFlow$Authorise net.corda.core.flows.ContractUpgradeFlow$Deauthorise net.corda.core.flows.ContractUpgradeFlow$Initiate
We can create a new IOU using the
ExampleFlow$Initiator flow. For example, from the interactive shell of PartyA,
you can agree an IOU of 50 with PartyB by running
flow start ExampleFlow$Initiator iouValue: 50, otherParty: "O=PartyB,L=New York,C=US".
This will print out the following progress steps:
✅ Generating transaction based on new IOU. ✅ Verifying contract constraints. ✅ Signing transaction with our private key. ✅ Gathering the counterparty's signature. ✅ Collecting signatures from counterparties. ✅ Verifying collected signatures. ✅ Obtaining notary signature and recording transaction. ✅ Requesting signature by notary service Requesting signature by Notary service Validating response from Notary service ✅ Broadcasting transaction to participants ✅ Done
We can also issue RPC operations to the node via the interactive shell. Type
run to see the full list of available
You can see the newly-created IOU by running
run vaultQuery contractStateType: com.example.state.IOUState.
As before, the interactive shell of PartyC will not display any IOUs.
The nodes can be configured to communicate as a network even when distributed across several machines:
Deploy the nodes as usual:
- Unix/Mac OSX:
- Unix/Mac OSX:
Navigate to the build folder (
For each node, open its
node.conffile and change
p2pAddressto the IP address of the machine where the node will be run (e.g.
These changes require new node-info files to be distributed amongst the nodes. Use the network bootstrapper tool (see Network Bootstrapper) to update the files and have them distributed locally:
java -jar network-bootstrapper.jar workflows-kotlin/build/nodes
Move the node folders to their individual machines (e.g. using a USB key). It is important that none of the nodes - including the notary - end up on more than one machine. Each computer should also have a copy of
For example, you may end up with the following layout:
- Machine 1:
- Machine 2:
- Machine 1:
After starting each node, the nodes will be able to see one another and agree IOUs among themselves
The bootstrapper must be run after the
node.conf files have been modified, but before the nodes
are distributed across machines. Otherwise, the nodes will not be able to communicate.
If you are using H2 and wish to use the same
h2port value for two or more nodes, you must only assign them that
value after the nodes have been moved to their individual machines. The initial bootstrapping process requires access to
the nodes’ databases and if two nodes share the same H2 port, the process will fail.
Corda provides several frameworks for writing unit and integration tests for CorDapps.
You can run the CorDapp’s contract tests by running the
Run Contract Tests - Kotlin run configuration.
You can run the CorDapp’s flow tests by running the
Run Flow Tests - Kotlin run configuration.
You can run the CorDapp’s integration tests by running the
Run Integration Tests - Kotlin run configuration.