mirror of
https://github.com/corda/corda.git
synced 2025-02-10 21:01:27 +00:00
Improves docs on running Example CorDapp. Debugging info. (#3671)
* Updates instructions for running example CorDapp. * Readds debugging information.
This commit is contained in:
parent
98f4fb7db3
commit
2bea665af2
@ -6,6 +6,7 @@ CorDapps
|
||||
|
||||
cordapp-overview
|
||||
writing-a-cordapp
|
||||
debugging-a-cordapp
|
||||
upgrade-notes
|
||||
upgrading-cordapps
|
||||
cordapp-build-systems
|
||||
|
73
docs/source/debugging-a-cordapp.rst
Normal file
73
docs/source/debugging-a-cordapp.rst
Normal file
@ -0,0 +1,73 @@
|
||||
Debugging a CorDapp
|
||||
===================
|
||||
|
||||
.. contents::
|
||||
|
||||
There are several ways to debug your CorDapp.
|
||||
|
||||
Using a ``MockNetwork``
|
||||
-----------------------
|
||||
|
||||
You can attach the `IntelliJ IDEA debugger <https://www.jetbrains.com/help/idea/debugging-code.html>`_ to a
|
||||
``MockNetwork`` to debug your CorDapp:
|
||||
|
||||
* Define your flow tests as per :doc:`api-testing`
|
||||
|
||||
* In your ``MockNetwork``, ensure that ``threadPerNode`` is set to ``false``
|
||||
|
||||
* Set your breakpoints
|
||||
* Run the flow tests using the debugger. When the tests hit a breakpoint, execution will pause
|
||||
|
||||
Using the node driver
|
||||
---------------------
|
||||
|
||||
You can also attach the `IntelliJ IDEA debugger <https://www.jetbrains.com/help/idea/debugging-code.html>`_ to nodes
|
||||
running via the node driver to debug your CorDapp.
|
||||
|
||||
With the nodes in-process
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
1. Define a network using the node driver as per :doc:`tutorial-integration-testing`
|
||||
|
||||
* In your ``DriverParameters``, ensure that ``startNodesInProcess`` is set to ``true``
|
||||
|
||||
2. Run the driver using the debugger
|
||||
|
||||
3. Set your breakpoints
|
||||
|
||||
4. Interact with your nodes. When execution hits a breakpoint, execution will pause
|
||||
|
||||
* The nodes' webservers always run in a separate process, and cannot be attached to by the debugger
|
||||
|
||||
With remote debugging
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
1. Define a network using the node driver as per :doc:`tutorial-integration-testing`
|
||||
|
||||
* In your ``DriverParameters``, ensure that ``startNodesInProcess`` is set to ``false`` and ``isDebug`` is set to
|
||||
``true``
|
||||
|
||||
2. Run the driver. The remote debug ports for each node will be automatically generated and printed to the terminal.
|
||||
For example:
|
||||
|
||||
.. sourcecode:: none
|
||||
|
||||
[INFO ] 11:39:55,471 [driver-pool-thread-0] (DriverDSLImpl.kt:814) internal.DriverDSLImpl.startOutOfProcessNode -
|
||||
Starting out-of-process Node PartyA, debug port is 5008, jolokia monitoring port is not enabled {}
|
||||
|
||||
3. Attach the debugger to the node of interest on its debug port:
|
||||
|
||||
* In IntelliJ IDEA, create a new run/debug configuration of type ``Remote``
|
||||
* Set the run/debug configuration's ``Port`` to the debug port
|
||||
* Start the run/debug configuration in debug mode
|
||||
|
||||
4. Set your breakpoints
|
||||
|
||||
5. Interact with your node. When execution hits a breakpoint, execution will pause
|
||||
|
||||
* The nodes' webservers always run in a separate process, and cannot be attached to by the debugger
|
||||
|
||||
By enabling remote debugging on a node
|
||||
--------------------------------------
|
||||
|
||||
See :ref:`enabling-remote-debugging`.
|
@ -57,10 +57,12 @@ Optionally run the node's webserver as well by opening a terminal window in the
|
||||
|
||||
.. warning:: The node webserver is for testing purposes only and will be removed soon.
|
||||
|
||||
Starting a node with remote debugging enabled
|
||||
---------------------------------------------
|
||||
To enable remote debugging of the node, run the following from the terminal window:
|
||||
.. _enabling-remote-debugging:
|
||||
|
||||
Enabling remote debugging
|
||||
-------------------------
|
||||
To enable remote debugging of the node, run the node with the following JVM arguments:
|
||||
|
||||
``java -Dcapsule.jvm.args="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" -jar corda.jar``
|
||||
|
||||
This command line will start the debugger on port 5005 and pause the process awaiting debugger attachment.
|
||||
This will allow you to attach a debugger to your node on port 5005.
|
||||
|
@ -9,13 +9,12 @@ The example CorDapp
|
||||
|
||||
.. contents::
|
||||
|
||||
The example CorDapp allows nodes to agree IOUs with each other. Nodes will always agree to the creation of a new IOU
|
||||
if:
|
||||
The example CorDapp allows nodes to agree IOUs with each other, as long as they obey the following contract rules:
|
||||
|
||||
* Its value is strictly positive
|
||||
* The node is not trying to issue the IOU to itself
|
||||
* The IOU's value is strictly positive
|
||||
* A node is not trying to issue an IOU to itself
|
||||
|
||||
We will deploy the CorDapp on 4 test nodes:
|
||||
We will deploy and run the CorDapp on four test nodes:
|
||||
|
||||
* **Notary**, which hosts a validating notary service
|
||||
* **PartyA**
|
||||
@ -27,7 +26,7 @@ facts" between PartyA and PartyB only. PartyC won't be aware of these IOUs.
|
||||
|
||||
Downloading the example CorDapp
|
||||
-------------------------------
|
||||
We need to download the example CorDapp from GitHub.
|
||||
Start by downloading the example CorDapp from GitHub:
|
||||
|
||||
* Set up your machine by following the :doc:`quickstart guide <getting-set-up>`
|
||||
|
||||
@ -36,48 +35,28 @@ We need to download the example CorDapp from GitHub.
|
||||
|
||||
* Change directories to the freshly cloned repo: ``cd cordapp-example``
|
||||
|
||||
.. note:: If you wish to build off the latest, unstable version of the codebase, follow the instructions in
|
||||
:doc:`building against Master <building-against-master>` instead.
|
||||
|
||||
Opening the example CorDapp in IntelliJ
|
||||
---------------------------------------
|
||||
Let's open the example CorDapp in IntelliJ IDEA.
|
||||
|
||||
**If opening a fresh IntelliJ instance**
|
||||
Let's open the example CorDapp in IntelliJ IDEA:
|
||||
|
||||
* Open IntelliJ
|
||||
* A dialogue box will appear:
|
||||
|
||||
.. image:: resources/intellij-welcome.png
|
||||
:width: 400
|
||||
* A splash screen will appear. Click ``open``, navigate to the folder where you cloned the ``cordapp-example``, and
|
||||
click ``OK``
|
||||
|
||||
* Click open, navigate to the folder where you cloned the ``cordapp-example``, and click OK
|
||||
* Once the project is open, click ``File``, then ``Project Structure``. Under ``Project SDK:``, set the project SDK by
|
||||
clicking ``New...``, clicking ``JDK``, and navigating to ``C:\Program Files\Java\jdk1.8.0_XXX`` (where ``XXX`` is the
|
||||
latest minor version number). Click ``OK``
|
||||
|
||||
* IntelliJ will show several pop-up windows, one of which requires our attention:
|
||||
* Again under ``File`` then ``Project Structure``, select ``Modules``. Click ``+``, then ``Import Module``, then select
|
||||
the ``cordapp-example`` folder and click ``Open``. Choose to ``Import module from external model``, select
|
||||
``Gradle``, click ``Next`` then ``Finish`` (leaving the defaults) and ``OK``
|
||||
|
||||
.. 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
|
||||
* Gradle will now download all the project dependencies and perform some indexing. This usually takes a minute or so
|
||||
|
||||
Project structure
|
||||
-----------------
|
||||
The example CorDapp has the following directory structure:
|
||||
~~~~~~~~~~~~~~~~~
|
||||
The example CorDapp has the following structure:
|
||||
|
||||
.. sourcecode:: none
|
||||
|
||||
@ -160,11 +139,13 @@ The key files and directories are as follows:
|
||||
about which version is required
|
||||
* **lib** contains the Quasar jar which rewrites our CorDapp's flows to be checkpointable
|
||||
* **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
|
||||
|
||||
* **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
|
||||
|
||||
@ -175,11 +156,11 @@ There are two ways to run the example CorDapp:
|
||||
* Via the terminal
|
||||
* Via IntelliJ
|
||||
|
||||
In both cases, we will deploy a set of test nodes with our CorDapp installed, then run the nodes. You can read more
|
||||
about how we define the nodes to be deployed :doc:`here <generating-a-node>`.
|
||||
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>`.
|
||||
|
||||
Terminal
|
||||
~~~~~~~~
|
||||
Running the example CorDapp from the terminal
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Building the example CorDapp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -191,29 +172,26 @@ Building the example CorDapp
|
||||
|
||||
* Windows: ``gradlew.bat deployNodes``
|
||||
|
||||
This will automatically build four pre-configured nodes with our CorDapp installed. These nodes are meant for local
|
||||
testing only
|
||||
This will automatically build four nodes with our CorDapp already installed
|
||||
|
||||
.. 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 build throughout the documentation.
|
||||
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 process has finished, you will see the newly-build nodes in the ``kotlin-source/build/nodes`` folder
|
||||
* After the build finishes, you will see the generated nodes in the ``kotlin-source/build/nodes`` folder
|
||||
|
||||
* There will be one folder generated for each node you built, plus a ``runnodes`` shell script (or batch file on
|
||||
Windows) to run all the nodes simultaneously
|
||||
* 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
|
||||
├── node.conf
|
||||
└── cordapps
|
||||
|
||||
``corda.jar`` is the Corda runtime, ``cordapps`` contains our node's CorDapps, and the node's configuration is
|
||||
given by ``node.conf``
|
||||
├── 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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -222,7 +200,7 @@ Start the nodes by running the following command from the root of the ``cordapp-
|
||||
* Unix/Mac OSX: ``kotlin-source/build/nodes/runnodes``
|
||||
* Windows: ``call kotlin-source\build\nodes\runnodes.bat``
|
||||
|
||||
.. warn:: On Unix/Mac OSX, do not click/change focus until all seven additional terminal windows have opened, or some
|
||||
.. 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:
|
||||
@ -240,8 +218,8 @@ For each node, the ``runnodes`` script creates a node tab/window:
|
||||
|
||||
Logs can be found in : /Users/joeldudley/Desktop/cordapp-example/kotlin-source/build/nodes/PartyA/logs
|
||||
Database connection url is : jdbc:h2:tcp://localhost:59472/node
|
||||
Incoming connection address : localhost:10005
|
||||
Listening on port : 10005
|
||||
Incoming connection address : localhost:10007
|
||||
Listening on port : 10007
|
||||
Loaded CorDapps : corda-finance-corda-3.0, cordapp-example-0.1, corda-core-corda-3.0
|
||||
Node for "PartyA" started up and registered in 38.59 sec
|
||||
|
||||
@ -255,16 +233,16 @@ For every node except the notary, the script also creates a webserver terminal t
|
||||
|
||||
.. sourcecode:: none
|
||||
|
||||
Logs can be found in /Users/joeldudley/Desktop/cordapp-example/kotlin-source/build/nodes/PartyA/logs/web
|
||||
Starting as webserver: localhost:10007
|
||||
Logs can be found in /Users/username/Desktop/cordapp-example/kotlin-source/build/nodes/PartyA/logs/web
|
||||
Starting as webserver: localhost:10009
|
||||
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 OK,
|
||||
you can query the 'status' end-point located at ``http://localhost:[port]/api/status`` (e.g.
|
||||
``http://localhost:10007/api/status`` for ``PartyA``).
|
||||
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:10009/api/status`` for ``PartyA``).
|
||||
|
||||
IntelliJ
|
||||
~~~~~~~~
|
||||
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
|
||||
|
||||
@ -273,73 +251,45 @@ IntelliJ
|
||||
.. image:: resources/run-config-drop-down.png
|
||||
:width: 400
|
||||
|
||||
The node driver defined in ``/src/test/kotlin/com/example/Main.kt`` allows you to specify how many nodes you would like
|
||||
to run and the configuration settings for each node. For the example CorDapp, the driver starts up four nodes
|
||||
and adds an RPC user for all but the network map/notary node:
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
// No permissions required as we are not invoking flows.
|
||||
val user = User("user1", "test", permissions = setOf())
|
||||
driver(isDebug = true, waitForNodesToFinish = true) {
|
||||
startNode(getX500Name(O="NetworkMapAndNotary",L="London",C='GB"), setOf(ServiceInfo(ValidatingNotaryService.type)))
|
||||
val (nodeA, nodeB, nodeC) = Futures.allAsList(
|
||||
startNode(getX500Name(O="PartyA",L="London",C="GB"), rpcUsers = listOf(user)),
|
||||
startNode(getX500Name(O="PartyB",L="New York",C="US"), rpcUsers = listOf(user)),
|
||||
startNode(getX500Name(O="PartyC",L="Paris",C="FR"), rpcUsers = listOf(user))).getOrThrow()
|
||||
|
||||
startWebserver(nodeA)
|
||||
startWebserver(nodeB)
|
||||
startWebserver(nodeC)
|
||||
}
|
||||
}
|
||||
|
||||
* To stop the nodes, press the red square button at the top right-hand side of the IDE, next to the run configurations
|
||||
|
||||
Later, we'll look at how the node driver can be useful for `debugging your CorDapp`_.
|
||||
|
||||
Interacting with the example CorDapp
|
||||
------------------------------------
|
||||
|
||||
Via HTTP
|
||||
~~~~~~~~
|
||||
The CorDapp defines several HTTP API end-points and a web front-end. The end-points allow you to list the IOUs a node
|
||||
is involved in, agree new IOUs, and see who is on the network.
|
||||
The nodes' webservers run locally on the following ports:
|
||||
|
||||
The nodes are running locally on the following ports:
|
||||
* PartyA: ``localhost:10009``
|
||||
* PartyB: ``localhost:10012``
|
||||
* PartyC: ``localhost:10015``
|
||||
|
||||
* 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``.
|
||||
|
||||
These ports are defined in build.gradle and in each node's node.conf file under ``kotlin-source/build/nodes/NodeX``.
|
||||
|
||||
As the nodes start up, they should tell you which port their embedded web server is running on. The available API
|
||||
endpoints are:
|
||||
Each node webserver exposes the following endpoints:
|
||||
|
||||
* ``/api/example/me``
|
||||
* ``/api/example/peers``
|
||||
* ``/api/example/ious``
|
||||
* ``/api/example/create-iou`` with parameters ``iouValue`` and ``partyName`` which is CN name of a node
|
||||
|
||||
The web front-end is served from ``/web/example``.
|
||||
|
||||
An IOU can be created by sending a PUT request to the ``api/example/create-iou`` end-point directly, or by using the
|
||||
the web form hosted at ``/web/example``.
|
||||
There is also a web front-end served from ``/web/example``.
|
||||
|
||||
.. warning:: The content in ``web/example`` is only available for demonstration purposes and does not implement
|
||||
anti-XSS, anti-XSRF or any other security techniques. Do not use this code in production.
|
||||
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'
|
||||
curl -X PUT 'http://localhost:10009/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
|
||||
Note that both PartyA's port number (``10009``) 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.
|
||||
|
||||
@ -350,41 +300,26 @@ of the page, and enter the IOU details into the web-form. The IOU must have a po
|
||||
|
||||
.. sourcecode:: none
|
||||
|
||||
Counter-party: Select from list
|
||||
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.
|
||||
|
||||
Once an IOU has been submitted
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
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.
|
||||
>> Collecting signatures from counterparties.
|
||||
>> Verifying collected signatures.
|
||||
>> Done
|
||||
>> 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:
|
||||
Checking the output
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
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:10007/api/example/ious
|
||||
* PartyB's vault: Navigate to http://localhost:10010/api/example/ious
|
||||
* PartyA's vault: Navigate to http://localhost:10009/api/example/ious
|
||||
* PartyB's vault: Navigate to http://localhost:10012/api/example/ious
|
||||
|
||||
*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
|
||||
* PartyA: Navigate to http://localhost:10009/web/example and hit the "refresh" button
|
||||
* PartyB: Navigate to http://localhost:10012/web/example and hit the "refresh" button
|
||||
|
||||
The vault and web front-end of PartyC (on ``localhost:10013``) will not display any IOUs. This is because PartyC was
|
||||
The vault and web front-end of PartyC (at ``localhost:10015``) will not display any IOUs. This is because PartyC was
|
||||
not involved in this transaction.
|
||||
|
||||
Via the interactive shell (terminal only)
|
||||
@ -411,6 +346,8 @@ following list:
|
||||
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"``.
|
||||
@ -432,9 +369,15 @@ This will print out the following progress steps:
|
||||
✅ Broadcasting transaction to participants
|
||||
✅ Done
|
||||
|
||||
Checking the output
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
We can also issue RPC operations to the node via the interactive shell. Type ``run`` to see the full list of available
|
||||
operations.
|
||||
|
||||
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.
|
||||
|
||||
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,
|
||||
@ -442,17 +385,17 @@ please follow the instructions in :doc:`node-database`.
|
||||
|
||||
Using the example RPC client
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The ``/src/main/kotlin-source/com/example/client/ExampleClientRPC.kt`` file is a simple utility that uses the client
|
||||
RPC library to connect to a node. It will log any existing IOUs and listen for any future IOUs. If you haven't created
|
||||
``/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
|
||||
any IOUs when you first connect to one of the nodes, the client will simply log any future IOUs that are agreed.
|
||||
|
||||
*Running the client via IntelliJ:*
|
||||
|
||||
Select the 'Run Example RPC Client' run configuration which, by default, connects to PartyA. Click the green arrow to
|
||||
run the client. You can edit the run configuration to connect on a different port.
|
||||
|
||||
*Running the client via the command line:*
|
||||
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.
|
||||
|
||||
Running the client via the command line
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Run the following gradle task:
|
||||
|
||||
``./gradlew runExampleClientRPCKotlin``
|
||||
@ -466,70 +409,59 @@ For more information on the client RPC interface and how to build an RPC client
|
||||
* :doc:`Client RPC documentation <clientrpc>`
|
||||
* :doc:`Client RPC tutorial <tutorial-clientrpc-api>`
|
||||
|
||||
Running Nodes Across Machines
|
||||
Running nodes across machines
|
||||
-----------------------------
|
||||
The nodes can be split across different machines and configured to communicate across the network.
|
||||
The nodes can be configured to communicate as a network even when distributed across several machines:
|
||||
|
||||
After deploying the nodes, navigate to the build folder (``kotlin-source/build/nodes``) and for each node that needs to
|
||||
be moved to another machine open its config file and change the Artemis messaging address to the IP address of the machine
|
||||
where the node will run (e.g. ``p2pAddress="10.18.0.166:10006"``).
|
||||
* Deploy the nodes as usual:
|
||||
|
||||
These changes require new node-info files to be distributed amongst the nodes. Use the network bootstrapper tool
|
||||
(see :doc:`setting-up-a-corda-network` for more information on this and how to built it) to update the files and have
|
||||
them distributed locally.
|
||||
* Unix/Mac OSX: ``./gradlew deployNodes``
|
||||
* Windows: ``gradlew.bat deployNodes``
|
||||
|
||||
``java -jar network-bootstrapper.jar kotlin-source/build/nodes``
|
||||
* Navigate to the build folder (``kotlin-source/build/nodes``)
|
||||
* For each node, open its ``node.conf`` file and change ``localhost`` in its ``p2pAddress`` to the IP address of the machine
|
||||
where the node will be run (e.g. ``p2pAddress="10.18.0.166:10007"``)
|
||||
* These changes require new node-info files to be distributed amongst the nodes. Use the network bootstrapper tool
|
||||
(see :doc:`network-bootstrapper`) to update the files and have them distributed locally:
|
||||
|
||||
Once that's done move the node folders to their designated 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 ``runnodes``
|
||||
and ``runnodes.bat``.
|
||||
``java -jar network-bootstrapper.jar kotlin-source/build/nodes``
|
||||
|
||||
For example, you may end up with the following layout:
|
||||
* 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 ``runnodes``
|
||||
and ``runnodes.bat``.
|
||||
|
||||
* Machine 1: ``Notary``, ``PartyA``, ``runnodes``, ``runnodes.bat``
|
||||
* Machine 2: ``PartyB``, ``PartyC``, ``runnodes``, ``runnodes.bat``
|
||||
For example, you may end up with the following layout:
|
||||
|
||||
After starting each node, the nodes will be able to see one another and agree IOUs among themselves.
|
||||
* Machine 1: ``Notary``, ``PartyA``, ``runnodes``, ``runnodes.bat``
|
||||
* Machine 2: ``PartyB``, ``PartyC``, ``runnodes``, ``runnodes.bat``
|
||||
|
||||
* After starting each node, the nodes will be able to see one another and agree IOUs among themselves
|
||||
|
||||
.. warning:: 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.
|
||||
|
||||
.. note:: 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.
|
||||
|
||||
Testing your 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.
|
||||
|
||||
Integration tests
|
||||
~~~~~~~~~~~~~~~~~
|
||||
You can run the CorDapp's integration tests by running the ``Run Integration Tests - Kotlin`` run configuration.
|
||||
|
||||
Debugging your CorDapp
|
||||
----------------------
|
||||
Debugging is done via IntelliJ as follows:
|
||||
|
||||
1. Edit the node driver code in ``Main.kt`` based on the number of nodes you wish to start, along with any other
|
||||
configuration options. For example, the code below starts 4 nodes, with one being the network map service and
|
||||
notary. It also sets up RPC credentials for the three non-notary nodes
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
// No permissions required as we are not invoking flows.
|
||||
val user = User("user1", "test", permissions = setOf())
|
||||
driver(isDebug = true, waitForNodesToFinish = true) {
|
||||
startNode(getX500Name(O="NetworkMapAndNotary",L="London",C="GB"), setOf(ServiceInfo(ValidatingNotaryService.type)))
|
||||
val (nodeA, nodeB, nodeC) = Futures.allAsList(
|
||||
startNode(getX500Name(O="PartyA",L=London,C=GB"), rpcUsers = listOf(user)),
|
||||
startNode(getX500Name(O="PartyB",L=New York,C=US"), rpcUsers = listOf(user)),
|
||||
startNode(getX500Name(O="PartyC",L=Paris,C=FR"), rpcUsers = listOf(user))).getOrThrow()
|
||||
|
||||
startWebserver(nodeA)
|
||||
startWebserver(nodeB)
|
||||
startWebserver(nodeC)
|
||||
}
|
||||
}
|
||||
|
||||
2. Select and run the “Run Example CorDapp” run configuration in IntelliJ
|
||||
|
||||
3. IntelliJ will build and run the CorDapp. The remote debug ports for each node will be automatically generated and
|
||||
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
|
||||
[INFO ] 15:27:59.533 [main] Node.logStartupInfo - Debug port: dt_socket:5007
|
||||
|
||||
4. Edit the “Debug CorDapp” run configuration with the port of the node you wish to connect to
|
||||
|
||||
5. Run the “Debug CorDapp” run configuration
|
||||
|
||||
6. Set your breakpoints and start interacting with the node you wish to connect to. When the node hits a breakpoint,
|
||||
execution will pause
|
||||
See :doc:`debugging-a-cordapp`.
|
||||
|
Loading…
x
Reference in New Issue
Block a user