corda/docs/source/hello-world-running.rst

207 lines
7.2 KiB
ReStructuredText
Raw Normal View History

2017-06-16 13:05:52 +00:00
.. highlight:: kotlin
.. raw:: html
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/codesets.js"></script>
Running our CorDapp
===================
Now that we've written a CorDapp, it's time to test it by running it on some real Corda nodes.
Deploying our CorDapp
---------------------
2017-08-17 11:02:44 +00:00
Let's take a look at the nodes we're going to deploy. Open the project's ``build.gradle`` file and scroll down to the
``task deployNodes`` section. This section defines three nodes. There are two standard nodes (``PartyA`` and
``PartyB``), plus a special network map/notary node that is running the network map service and advertises a validating notary
service.
2017-06-16 13:05:52 +00:00
.. code-block:: none
2017-06-16 13:05:52 +00:00
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
nodeDefaults {
cordapps = [
"net.corda:corda-finance-contracts:$corda_release_version",
"net.corda:corda-finance-workflows:$corda_release_version",
"net.corda:corda-confidential-identities:$corda_release_version"
]
}
directory "./build/nodes"
node {
name "O=Notary,L=London,C=GB"
notary = [validating : true]
p2pPort 10002
rpcPort 10003
}
node {
name "O=PartyA,L=London,C=GB"
p2pPort 10005
rpcPort 10006
webPort 10007
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL]]]
2017-06-16 13:05:52 +00:00
}
node {
name "O=PartyB,L=New York,C=US"
p2pPort 10008
rpcPort 10009
webPort 10010
sshdPort 10024
rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
}
}
2017-06-16 13:05:52 +00:00
We can run this ``deployNodes`` task using Gradle. For each node definition, Gradle will:
* Package the project's source files into a CorDapp jar
* Create a new node in ``build/nodes`` with our CorDapp already installed
We can do that now by running the following commands from the root of the project:
.. code:: bash
2017-06-16 13:05:52 +00:00
// On Windows
gradlew clean deployNodes
// On Mac
./gradlew clean deployNodes
Running the nodes
-----------------
2017-08-17 11:02:44 +00:00
Running ``deployNodes`` will build the nodes under ``build/nodes``. If we navigate to one of these folders, we'll see
the three node folders. Each node folder has the following structure:
2017-06-16 13:05:52 +00:00
.. code:: bash
2017-06-16 13:05:52 +00:00
.
2017-07-07 11:06:28 +00:00
|____corda.jar // The runnable node
|____corda-webserver.jar // The node's webserver (The notary doesn't need a web server)
2017-07-07 11:06:28 +00:00
|____node.conf // The node's configuration file
|____cordapps
|____java/kotlin-source-0.1.jar // Our IOU CorDapp
2017-06-16 13:05:52 +00:00
Let's start the nodes by running the following commands from the root of the project:
.. code:: bash
2017-06-16 13:05:52 +00:00
2017-08-17 11:02:44 +00:00
// On Windows
build/nodes/runnodes.bat
2017-06-16 13:05:52 +00:00
2017-08-17 11:02:44 +00:00
// On Mac
build/nodes/runnodes
2017-06-16 13:05:52 +00:00
This will start a terminal window for each node, and an additional terminal window for each node's webserver - five
2017-06-16 13:05:52 +00:00
terminal windows in all. Give each node a moment to start - you'll know it's ready when its terminal windows displays
the message, "Welcome to the Corda interactive shell.".
.. image:: resources/running_node.png
:scale: 25%
:align: center
Interacting with the nodes
--------------------------
Now that our nodes are running, let's order one of them to create an IOU by kicking off our ``IOUFlow``. In a larger
app, we'd generally provide a web API sitting on top of our node. Here, for simplicity, we'll be interacting with the
node via its built-in CRaSH shell.
Go to the terminal window displaying the CRaSH shell of PartyA. Typing ``help`` will display a list of the available
2017-06-16 13:05:52 +00:00
commands.
.. note:: Local terminal shell is available only in a development mode. In production environment SSH server can be enabled.
2018-01-03 10:00:33 +00:00
More about SSH and how to connect can be found on the :doc:`shell` page.
We want to create an IOU of 99 with PartyB. We start the ``IOUFlow`` by typing:
2017-06-16 13:05:52 +00:00
.. code-block:: bash
start IOUFlow iouValue: 99, otherParty: "O=PartyB,L=New York,C=US"
2017-06-16 13:05:52 +00:00
This single command will cause PartyA and PartyB to automatically agree an IOU. This is one of the great advantages of
the flow framework - it allows you to reduce complex negotiation and update processes into a single function call.
2017-06-16 13:05:52 +00:00
If the flow worked, it should have recorded a new IOU in the vaults of both PartyA and PartyB. Let's check.
We can check the contents of each node's vault by running:
2017-06-16 13:05:52 +00:00
.. code-block:: bash
2017-06-16 13:05:52 +00:00
run vaultQuery contractStateType: com.template.IOUState
2017-06-16 13:05:52 +00:00
The vaults of PartyA and PartyB should both display the following output:
2017-06-16 13:05:52 +00:00
.. code:: bash
2017-06-16 13:05:52 +00:00
states:
2017-06-16 13:05:52 +00:00
- state:
data:
value: 99
lender: "C=GB,L=London,O=PartyA"
borrower: "C=US,L=New York,O=PartyB"
2017-06-16 13:05:52 +00:00
participants:
- "C=GB,L=London,O=PartyA"
- "C=US,L=New York,O=PartyB"
contract: "com.template.contract.IOUContract"
notary: "C=GB,L=London,O=Notary"
2017-06-16 13:05:52 +00:00
encumbrance: null
constraint:
attachmentId: "F578320232CAB87BB1E919F3E5DB9D81B7346F9D7EA6D9155DC0F7BA8E472552"
2017-06-16 13:05:52 +00:00
ref:
txhash: "5CED068E790A347B0DD1C6BB5B2B463406807F95E080037208627565E6A2103B"
index: 0
statesMetadata:
- ref:
txhash: "5CED068E790A347B0DD1C6BB5B2B463406807F95E080037208627565E6A2103B"
2017-06-16 13:05:52 +00:00
index: 0
contractStateClassName: "com.template.state.IOUState"
recordedTime: 1506415268.875000000
consumedTime: null
status: "UNCONSUMED"
notary: "C=GB,L=London,O=Notary"
lockId: null
lockUpdateTime: 1506415269.548000000
totalStatesAvailable: -1
stateTypes: "UNCONSUMED"
otherResults: []
2017-06-16 13:05:52 +00:00
This is the transaction issuing our ``IOUState`` onto a ledger.
However, if we run the same command on the other node (the notary), we will see the following:
.. code:: bash
{
"states" : [ ],
"statesMetadata" : [ ],
"totalStatesAvailable" : -1,
"stateTypes" : "UNCONSUMED",
"otherResults" : [ ]
}
This is the result of Corda's privacy model. Because the notary was not involved in the transaction and had no need to see the data, the
transaction was not distributed to them.
2017-06-16 13:05:52 +00:00
Conclusion
----------
We have written a simple CorDapp that allows IOUs to be issued onto the ledger. Our CorDapp is made up of two key
parts:
2017-06-16 13:05:52 +00:00
* The ``IOUState``, representing IOUs on the blockchain
2017-07-07 11:06:28 +00:00
* The ``IOUFlow``, orchestrating the process of agreeing the creation of an IOU on-ledger
2017-06-16 13:05:52 +00:00
After completing this tutorial, your CorDapp should look like this:
* Java: https://github.com/corda/corda-tut1-solution-java
* Kotlin: https://github.com/corda/corda-tut1-solution-kotlin
2017-06-16 13:05:52 +00:00
Next steps
----------
2017-07-07 11:06:28 +00:00
There are a number of improvements we could make to this CorDapp:
2018-06-21 15:57:30 +00:00
* We could add unit tests, using the contract-test and flow-test frameworks
* We could change ``IOUState.value`` from an integer to a proper amount of a given currency
2017-07-07 11:06:28 +00:00
* We could add an API, to make it easier to interact with the CorDapp
But for now, the biggest priority is to add an ``IOUContract`` imposing constraints on the evolution of each
``IOUState`` over time. This will be the focus of our next tutorial.