corda/docs/source/tutorial-cordapp.rst

506 lines
20 KiB
ReStructuredText
Raw Normal View History

2016-10-31 11:30:57 +00:00
.. highlight:: kotlin
.. raw:: html
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/codesets.js"></script>
The example CorDapp
===================
2016-10-31 11:30:57 +00:00
2017-07-21 11:33:31 +00:00
.. contents::
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:
* **NetworkMapAndNotary**, which hosts a validating notary service
* **PartyA**
* **PartyB**
* **PartyC**
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.
2017-07-21 11:33:31 +00:00
Downloading the example CorDapp
-------------------------------
Start by downloading the example CorDapp from GitHub:
* Set up your machine by following the :doc:`quickstart guide <getting-set-up>`
* Clone the example CorDapp from the `cordapp-example repository <https://github.com/corda/cordapp-example>`_ using
the following command: ``git clone https://github.com/corda/cordapp-example``
* Change directories to the freshly cloned repo: ``cd cordapp-example``
2017-07-21 11:33:31 +00:00
Opening the example CorDapp in IntelliJ
---------------------------------------
Let's open the example CorDapp in IntelliJ IDEA:
**If opening a fresh IntelliJ instance**:
* Open IntelliJ
* A dialogue box will appear:
.. image:: resources/intellij-welcome.png
:width: 400
* Click open, navigate to the folder where you cloned the ``cordapp-example``, and click OK
* IntelliJ will show several pop-up windows, one of which requires our attention:
.. image:: resources/unlinked-gradle-project.png
:width: 400
* Click the 'import gradle project' link. Press OK on the dialogue that pops up
* Gradle will now download all the project dependencies and perform some indexing. This usually takes a minute or so
* If the 'import gradle project' pop-up does not appear, click the small green speech bubble at the bottom-right of
the IDE, or simply close and re-open IntelliJ again to make it reappear
**If you already have IntelliJ open**:
* Open the ``File`` menu
* Navigate to ``Open ...``
* Navigate to the directory where you cloned the ``cordapp-example``
* Click OK
2017-07-21 11:33:31 +00:00
Project structure
~~~~~~~~~~~~~~~~~
The example CorDapp has the following structure:
2017-07-21 11:33:31 +00:00
.. sourcecode:: none
2017-07-21 11:33:31 +00:00
.
├── config
│   ├── dev
│   │   └── log4j2.xml
│   └── test
│   └── log4j2.xml
├── doc
│   └── example_flow.plantuml
├── gradle
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── lib
│   ├── README.txt
│   └── quasar.jar
2017-07-21 11:33:31 +00:00
├── java-source
│   └── ...
├── kotlin-source
│   ├── build.gradle
│   └── src
│   ├── main
│   │   ├── kotlin
│   │   │   └── com
│   │   │   └── example
│   │   │   ├── api
│   │   │   │   └── ExampleApi.kt
│   │   │   ├── client
│   │   │   │   └── ExampleClientRPC.kt
│   │   │   ├── contract
│   │   │   │   └── IOUContract.kt
│   │   │   ├── flow
│   │   │   │   └── ExampleFlow.kt
│   │   │   ├── model
│   │   │   │   └── IOU.kt
│   │   │   ├── plugin
│   │   │   │   └── ExamplePlugin.kt
│   │   │   ├── schema
│   │   │   │   └── IOUSchema.kt
│   │   │   └── state
│   │   │   └── IOUState.kt
│   │   └── resources
│   │   ├── META-INF
│   │   │   └── services
│   │   │   └── net.corda.webserver.services.WebServerPluginRegistry
│   │   ├── certificates
│   │   │   ├── readme.txt
│   │   │   ├── sslkeystore.jks
│   │   │   └── truststore.jks
│   │   └── exampleWeb
│   │   ├── index.html
│   │   └── js
│   │   └── angular-module.js
│   └── test
│   └── kotlin
│   └── com
│   └── example
│   ├── Main.kt
│   ├── contract
│   │   └── IOUContractTests.kt
│   └── flow
│   └── IOUFlowTests.kt
├── .gitignore
├── LICENCE
├── README.md
├── TRADEMARK
├── build.gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
2017-07-21 11:33:31 +00:00
└── settings.gradle
The key files and directories are as follows:
2017-07-21 11:33:31 +00:00
* The **root directory** contains some gradle files, a README and a LICENSE
* **config** contains log4j 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
2017-07-21 11:33:31 +00:00
* **kotlin-source** contains the source code for the example CorDapp written in Kotlin
* **kotlin-source/src/main/kotlin** contains the source code for the example CorDapp
* **kotlin-source/src/main/resources** contains the certificate store, some static web content to be served by the
nodes and the WebServerPluginRegistry file
* **kotlin-source/src/test/kotlin** contains unit tests for the contracts and flows, and the driver to run the nodes
via IntelliJ
* **java-source** contains the same source code, but written in Java. CorDapps can be developed in any language
targeting the JVM
2017-07-21 11:33:31 +00:00
Running the example CorDapp
---------------------------
There are two ways to run the example CorDapp:
2017-07-21 11:33:31 +00:00
* 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 :doc:`here <generating-a-node>`.
Running the example CorDapp from the terminal
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Building the example CorDapp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Open a terminal window in the ``cordapp-example`` directory
* Build the test nodes with our CorDapp using the following command:
* Unix/Mac OSX: ``./gradlew deployNodes``
* Windows: ``gradlew.bat deployNodes``
This will automatically build four nodes with our CorDapp already installed
2017-07-21 11:33:31 +00:00
.. note:: CorDapps can be written in any language targeting the JVM. In our case, we've provided the example source in
both Kotlin (``/kotlin-source/src``) and Java (``/java-source/src``). 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 generated nodes in the ``kotlin-source/build/nodes`` folder
* There will be a folder for each generated node, plus a ``runnodes`` shell script (or batch file on Windows) to run
all the nodes simultaneously
* Each node in the ``nodes`` folder has the following structure:
.. sourcecode:: none
. nodeName
├── corda.jar // The Corda node runtime.
├── corda-webserver.jar // The node development webserver.
├── node.conf // The node configuration file.
└── cordapps // The node's CorDapps.
Running the example CorDapp
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Start the nodes by running the following command from the root of the ``cordapp-example`` folder:
2017-07-21 11:33:31 +00:00
* Unix/Mac OSX: ``kotlin-source/build/nodes/runnodes``
* Windows: ``call kotlin-source\build\nodes\runnodes.bat``
.. warning:: On Unix/Mac OSX, do not click/change focus until all seven additional terminal windows have opened, or some
nodes may fail to start.
For each node, the ``runnodes`` script creates a node tab/window:
.. sourcecode:: none
2017-07-21 11:33:31 +00:00
______ __
/ ____/ _________/ /___ _
/ / __ / ___/ __ / __ `/ It's kind of like a block chain but
/ /___ /_/ / / / /_/ / /_/ / cords sounded healthier than chains.
\____/ /_/ \__,_/\__,_/
2017-07-21 11:33:31 +00:00
--- Corda Open Source 0.12.1 (da47f1c) -----------------------------------------------
2017-07-21 11:33:31 +00:00
📚 New! Training now available worldwide, see https://corda.net/corda-training/
Logs can be found in : /Users/username/Desktop/cordapp-example/kotlin-source/build/nodes/PartyA/logs
2017-07-21 11:33:31 +00:00
Database connection url is : jdbc:h2:tcp://10.163.199.132:54763/node
Listening on address : 127.0.0.1:10005
RPC service listening on address : localhost:10006
Loaded plugins : com.example.plugin.ExamplePlugin
Node for "PartyA" started up and registered in 35.0 sec
2017-07-21 11:33:31 +00:00
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 10:33:47 BST 2017>>>
For every node except the network map/notary, the script also creates a webserver terminal tab/window:
.. sourcecode:: none
Logs can be found in /Users/username/Desktop/cordapp-example/kotlin-source/build/nodes/PartyA/logs/web
2017-07-21 11:33:31 +00:00
Starting as webserver: localhost:10007
Webserver started up in 42.02 sec
It usually takes around 60 seconds for the nodes to finish starting up. To ensure that all the nodes are running, you
can query the 'status' end-point located at ``http://localhost:[port]/api/status`` (e.g.
``http://localhost:10007/api/status`` for ``PartyA``).
2017-07-21 11:33:31 +00:00
Running the example CorDapp from IntelliJ
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Select the ``Run Example CorDapp - Kotlin`` run configuration from the drop-down menu at the top right-hand side of
the IDE
2016-10-31 11:30:57 +00:00
* Click the green arrow to start the nodes:
.. image:: resources/run-config-drop-down.png
:width: 400
* To stop the nodes, press the red square button at the top right-hand side of the IDE, next to the run configurations
2017-07-21 11:33:31 +00:00
Interacting with the example CorDapp
------------------------------------
Via HTTP
~~~~~~~~
The nodes' webservers run locally on the following ports:
* PartyA: ``localhost:10007``
* PartyB: ``localhost:10010``
* PartyC: ``localhost:10013``
These ports are defined in each node's node.conf file under ``kotlin-source/build/nodes/NodeX/node.conf``.
Each node webserver exposes the following endpoints:
* ``/api/example/me``
* ``/api/example/peers``
* ``/api/example/ious``
2017-09-25 16:01:14 +00:00
* ``/api/example/create-iou`` with parameters ``iouValue`` and ``partyName`` which is CN name of a node
There is also a web front-end served from ``/web/example``.
2017-07-21 11:33:31 +00:00
.. warning:: The content in ``web/example`` 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.
Creating an IOU via the endpoint
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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 ``/web/example``.
To create an IOU between PartyA and PartyB, run the following command from the command line:
.. sourcecode:: bash
curl -X PUT 'http://localhost:10007/api/example/create-iou?iouValue=1&partyName=O=PartyB,L=New%20York,C=US'
Note that both PartyA's port number (``10007``) 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.
Submitting an IOU via the web front-end
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To create an IOU between PartyA and PartyB, navigate to ``/web/example``, 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:
.. sourcecode:: none
Counter-party: Select from list
2017-07-21 11:33:31 +00:00
Value (Int): 5
2017-07-21 11:33:31 +00:00
And click submit. Upon clicking submit, the modal dialogue will close, and the nodes will agree the IOU.
Checking the output
^^^^^^^^^^^^^^^^^^^
Assuming all went well, you should see some activity in PartyA's web-server terminal window:
.. sourcecode:: none
>> Signing transaction with our private key.
>> Gathering the counterparty's signature.
>> Structural step change in child of Gathering the counterparty's signature.
>> Collecting signatures from counter-parties.
>> Verifying collected signatures.
>> Done
>> Obtaining notary signature and recording transaction.
>> Structural step change in child of Obtaining notary signature and recording transaction.
>> Requesting signature by notary service
>> Broadcasting transaction to participants
>> Done
>> Done
You can view the newly-created IOU by accessing the vault of PartyA or PartyB:
2017-07-21 11:33:31 +00:00
*Via the HTTP API:*
* PartyA's vault: Navigate to http://localhost:10007/api/example/ious
* PartyB's vault: Navigate to http://localhost:10010/api/example/ious
2017-07-21 11:33:31 +00:00
*Via web/example:*
* PartyA: Navigate to http://localhost:10007/web/example and hit the "refresh" button
* PartyA: Navigate to http://localhost:10010/web/example and hit the "refresh" button
The vault and web front-end of PartyC (at ``localhost:10013``) will not display any IOUs. This is because PartyC was
not involved in this transaction.
2017-07-21 11:33:31 +00:00
Via the interactive shell (terminal only)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Nodes started via the terminal will display an interactive shell:
2017-07-21 11:33:31 +00:00
.. sourcecode:: none
2017-07-21 11:33:31 +00:00
Welcome to the Corda interactive shell.
Useful commands include 'help' to see what is available, and 'bye' to shut down the node.
2017-07-21 11:33:31 +00:00
Fri Jul 07 16:36:29 BST 2017>>>
Type ``flow list`` in the shell to see a list of the flows that your node can run. In our case, this will return the
following list:
2017-07-21 11:33:31 +00:00
.. sourcecode:: none
com.example.flow.ExampleFlow$Initiator
net.corda.core.flows.ContractUpgradeFlow$Initiator
net.corda.core.flows.ContractUpgradeFlow$Initiator
net.corda.finance.flows.CashExitFlow
net.corda.finance.flows.CashIssueAndPaymentFlow
net.corda.finance.flows.CashIssueFlow
net.corda.finance.flows.CashPaymentFlow
Creating an IOU via the interactive shell
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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"``.
2017-07-21 11:33:31 +00:00
This will print out the following progress steps:
2017-07-21 11:33:31 +00:00
.. sourcecode:: none
2017-07-21 11:33:31 +00:00
✅ Generating transaction based on new IOU.
✅ Verifying contract constraints.
✅ Signing transaction with our private key.
✅ Gathering the counterparty's signature.
✅ Collecting signatures from counter-parties.
✅ 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
Checking the output
^^^^^^^^^^^^^^^^^^^
2017-07-21 11:33:31 +00:00
We can also issue RPC operations to the node via the interactive shell. Type ``run`` to see the full list of available
operations.
2016-10-31 11:30:57 +00:00
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.
2017-07-21 11:33:31 +00:00
Via the h2 web console
~~~~~~~~~~~~~~~~~~~~~~
You can connect directly to your node's database to see its stored states, transactions and attachments. To do so,
please follow the instructions in :doc:`node-database`.
2016-10-31 11:30:57 +00:00
2017-07-21 11:33:31 +00:00
Using the example RPC client
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``/src/main/kotlin-source/com/example/client/ExampleClientRPC.kt`` defines a simple RPC client that connects to a node,
logs any existing IOUs and listens for any future IOUs. If you haven't created
2017-07-21 11:33:31 +00:00
any IOUs when you first connect to one of the nodes, the client will simply log any future IOUs that are agreed.
2016-10-31 11:30:57 +00:00
Running the client via IntelliJ
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run the 'Run Example RPC Client' run configuration. By default, this run configuration is configured to connect to
PartyA. You can edit the run configuration to connect on a different port.
2016-10-31 11:30:57 +00:00
Running the client via the command line
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run the following gradle task:
2016-10-31 11:30:57 +00:00
``./gradlew runExampleClientRPCKotlin``
This will connect the RPC client to PartyA and log their past and future IOU activity.
2017-07-21 11:33:31 +00:00
You can close the application using ``ctrl+C``.
2016-10-31 11:30:57 +00:00
2017-07-21 11:33:31 +00:00
For more information on the client RPC interface and how to build an RPC client application, see:
* :doc:`Client RPC documentation <clientrpc>`
* :doc:`Client RPC tutorial <tutorial-clientrpc-api>`
2016-10-31 11:30:57 +00:00
Running nodes across machines
2017-07-21 11:33:31 +00:00
-----------------------------
The nodes can be split across machines and configured to communicate across the network.
After deploying the nodes, navigate to the build folder (``kotlin-source/build/nodes``) and move some of the individual
node folders to a different machine (e.g. using a USB key). It is important that none of the nodes - including the
network map/notary node - end up on more than one machine. Each computer should also have a copy of ``runnodes`` and
``runnodes.bat``.
For example, you may end up with the following layout:
* Machine 1: ``NetworkMapAndNotary``, ``PartyA``, ``runnodes``, ``runnodes.bat``
* Machine 2: ``PartyB``, ``PartyC``, ``runnodes``, ``runnodes.bat``
You must now edit the configuration file for each node, including the network map/notary. Open each node's config file,
and make the following changes:
* Change the Artemis messaging address to the machine's IP address (e.g. ``p2pAddress="10.18.0.166:10006"``)
After starting each node, the nodes will be able to see one another and agree IOUs among themselves.
Testing and debugging
---------------------
Testing a CorDapp
~~~~~~~~~~~~~~~~~
Corda provides several frameworks for writing unit and integration tests for CorDapps.
Contract tests
^^^^^^^^^^^^^^
You can run the CorDapp's contract tests by running the ``Run Contract Tests - Kotlin`` run configuration.
Flow tests
^^^^^^^^^^
You can run the CorDapp's flow tests by running the ``Run Flow Tests - Kotlin`` run configuration.
2017-07-21 11:33:31 +00:00
Integration tests
^^^^^^^^^^^^^^^^^
You can run the CorDapp's integration tests by running the ``Run Integration Tests - Kotlin`` run configuration.
Debugging Corda nodes
~~~~~~~~~~~~~~~~~~~~~
Debugging is done via IntelliJ as follows:
1. Start the nodes using the “Run Example CorDapp” run configuration in IntelliJ
2. IntelliJ will build and run the CorDapp. The remote debug ports for each node will be automatically generated and
2017-07-21 11:33:31 +00:00
printed to the terminal. For example:
.. sourcecode:: none
[INFO ] 15:27:59.533 [main] Node.logStartupInfo - Working Directory: /Users/joeldudley/cordapp-example/build/20170707142746/PartyA
2017-07-21 11:33:31 +00:00
[INFO ] 15:27:59.533 [main] Node.logStartupInfo - Debug port: dt_socket:5007
3. Edit the “Debug CorDapp” run configuration with the port of the node you wish to connect to
4. Run the “Debug CorDapp” run configuration
5. Set your breakpoints and interact with the node you've connected to. When the node hits a breakpoint, execution will
pause
* The node webserver runs in a separate process, and is not attached to by the debugger