2016-10-04 12:56:31 +00:00
|
|
|
.. _graphstream: http://graphstream-project.org/
|
|
|
|
|
2017-06-05 12:37:23 +00:00
|
|
|
Using the client RPC API
|
|
|
|
========================
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2017-10-02 09:11:33 +00:00
|
|
|
In this tutorial we will build a simple command line utility that connects to a node, creates some cash transactions
|
|
|
|
and dumps the transaction graph to the standard output. We will then put some simple visualisation on top. For an
|
|
|
|
explanation on how RPC works in Corda see :doc:`clientrpc`.
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2017-05-10 10:28:25 +00:00
|
|
|
We start off by connecting to the node itself. For the purposes of the tutorial we will use the Driver to start up a notary
|
2017-10-02 09:11:33 +00:00
|
|
|
and a Alice node that can issue, move and exit cash.
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2017-10-02 09:11:33 +00:00
|
|
|
Here's how we configure the node to create a user that has the permissions to start the ``CashIssueFlow``,
|
|
|
|
``CashPaymentFlow``, and ``CashExitFlow``:
|
2016-11-15 12:36:17 +00:00
|
|
|
|
|
|
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt
|
2016-10-04 12:56:31 +00:00
|
|
|
:language: kotlin
|
|
|
|
:start-after: START 1
|
|
|
|
:end-before: END 1
|
|
|
|
|
2017-10-02 09:11:33 +00:00
|
|
|
Now we can connect to the node itself using a valid RPC user login and start generating transactions in a different
|
|
|
|
thread using ``generateTransactions`` (to be defined later):
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2016-11-15 12:36:17 +00:00
|
|
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt
|
2016-10-04 12:56:31 +00:00
|
|
|
:language: kotlin
|
|
|
|
:start-after: START 2
|
|
|
|
:end-before: END 2
|
2017-10-02 09:11:33 +00:00
|
|
|
:dedent: 8
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2017-10-02 09:11:33 +00:00
|
|
|
``proxy`` exposes the full RPC interface of the node:
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2017-05-03 10:02:56 +00:00
|
|
|
.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt
|
2016-10-04 12:56:31 +00:00
|
|
|
:language: kotlin
|
|
|
|
:start-after: interface CordaRPCOps
|
|
|
|
:end-before: }
|
|
|
|
|
2017-10-02 09:11:33 +00:00
|
|
|
The RPC operation we need in order to dump the transaction graph is ``internalVerifiedTransactionsFeed``. The type
|
|
|
|
signature tells us that the RPC operation will return a list of transactions and an ``Observable`` stream. This is a
|
|
|
|
general pattern, we query some data and the node will return the current snapshot and future updates done to it.
|
|
|
|
Observables are described in further detail in :doc:`clientrpc`
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2016-11-15 12:36:17 +00:00
|
|
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt
|
2016-10-04 12:56:31 +00:00
|
|
|
:language: kotlin
|
|
|
|
:start-after: START 3
|
|
|
|
:end-before: END 3
|
2017-10-02 09:11:33 +00:00
|
|
|
:dedent: 8
|
|
|
|
|
|
|
|
The graph will be defined as follows:
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2017-10-02 09:11:33 +00:00
|
|
|
* Each transaction is a vertex, represented by printing ``NODE <txhash>``
|
|
|
|
* Each input-output relationship is an edge, represented by prining ``EDGE <txhash> <txhash>``
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2016-11-15 12:36:17 +00:00
|
|
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt
|
2016-10-04 12:56:31 +00:00
|
|
|
:language: kotlin
|
|
|
|
:start-after: START 4
|
|
|
|
:end-before: END 4
|
2017-10-02 09:11:33 +00:00
|
|
|
:dedent: 8
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2016-11-15 12:36:17 +00:00
|
|
|
Now we just need to create the transactions themselves!
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2016-11-15 12:36:17 +00:00
|
|
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt
|
|
|
|
:language: kotlin
|
|
|
|
:start-after: START 6
|
|
|
|
:end-before: END 6
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2017-05-10 10:28:25 +00:00
|
|
|
We utilise several RPC functions here to query things like the notaries in the node cluster or our own vault. These RPC
|
|
|
|
functions also return ``Observable`` objects so that the node can send us updated values. However, we don't need updates
|
2017-10-02 09:11:33 +00:00
|
|
|
here and so we mark these observables as ``notUsed`` (as a rule, you should always either subscribe to an ``Observable``
|
|
|
|
or mark it as not used. Failing to do so will leak resources in the node).
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2016-11-15 12:36:17 +00:00
|
|
|
Then in a loop we generate randomly either an Issue, a Pay or an Exit transaction.
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2017-10-02 09:11:33 +00:00
|
|
|
The RPC we need to initiate a cash transaction is ``startFlow`` which starts an arbitrary flow given sufficient
|
|
|
|
permissions to do so.
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2017-05-10 10:28:25 +00:00
|
|
|
Finally we have everything in place: we start a couple of nodes, connect to them, and start creating transactions while
|
2017-10-02 09:11:33 +00:00
|
|
|
listening on successfully created ones, which are dumped to the console. We just need to run it!
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2016-11-28 10:12:23 +00:00
|
|
|
.. code-block:: text
|
2016-11-21 16:39:46 +00:00
|
|
|
|
2016-11-15 12:36:17 +00:00
|
|
|
# Build the example
|
|
|
|
./gradlew docs/source/example-code:installDist
|
|
|
|
# Start it
|
|
|
|
./docs/source/example-code/build/install/docs/source/example-code/bin/client-rpc-tutorial Print
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2017-10-02 09:11:33 +00:00
|
|
|
Now let's try to visualise the transaction graph. We will use a graph drawing library called graphstream_.
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2016-11-15 12:36:17 +00:00
|
|
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt
|
2016-10-04 12:56:31 +00:00
|
|
|
:language: kotlin
|
|
|
|
:start-after: START 5
|
|
|
|
:end-before: END 5
|
2017-10-02 09:11:33 +00:00
|
|
|
:dedent: 8
|
2016-10-04 12:56:31 +00:00
|
|
|
|
2016-11-15 12:36:17 +00:00
|
|
|
If we run the client with ``Visualise`` we should see a simple random graph being drawn as new transactions are being created.
|
2016-11-15 17:16:33 +00:00
|
|
|
|
2017-02-28 08:12:18 +00:00
|
|
|
Whitelisting classes from your CorDapp with the Corda node
|
|
|
|
----------------------------------------------------------
|
2016-11-15 17:16:33 +00:00
|
|
|
|
2017-02-28 08:12:18 +00:00
|
|
|
As described in :doc:`clientrpc`, you have to whitelist any additional classes you add that are needed in RPC
|
|
|
|
requests or responses with the Corda node. Here's an example of both ways you can do this for a couple of example classes.
|
2016-11-15 17:16:33 +00:00
|
|
|
|
|
|
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt
|
|
|
|
:language: kotlin
|
|
|
|
:start-after: START 7
|
|
|
|
:end-before: END 7
|
|
|
|
|
2017-06-05 12:37:23 +00:00
|
|
|
See more on plugins in :doc:`running-a-node`.
|
2016-11-15 17:16:33 +00:00
|
|
|
|
2016-11-25 17:56:56 +00:00
|
|
|
Security
|
|
|
|
--------
|
2017-10-02 09:11:33 +00:00
|
|
|
RPC credentials associated with a Client must match the permission set configured on the server node.
|
2016-11-29 09:41:50 +00:00
|
|
|
This refers to both authentication (username and password) and role-based authorisation (a permissioned set of RPC operations an
|
2016-11-25 17:56:56 +00:00
|
|
|
authenticated user is entitled to run).
|
|
|
|
|
2017-05-10 10:28:25 +00:00
|
|
|
.. note:: Permissions are represented as *String's* to allow RPC implementations to add their own permissioning. Currently
|
|
|
|
the only permission type defined is *StartFlow*, which defines a list of whitelisted flows an authenticated use may
|
|
|
|
execute. An administrator user (or a developer) may also be assigned the ``ALL`` permission, which grants access to
|
|
|
|
any flow.
|
2016-11-29 09:41:50 +00:00
|
|
|
|
2016-11-25 17:56:56 +00:00
|
|
|
In the instructions above the server node permissions are configured programmatically in the driver code:
|
|
|
|
|
|
|
|
.. code-block:: text
|
|
|
|
|
|
|
|
driver(driverDirectory = baseDirectory) {
|
2016-11-29 09:41:50 +00:00
|
|
|
val user = User("user", "password", permissions = setOf(startFlowPermission<CashFlow>()))
|
2017-06-20 15:58:00 +00:00
|
|
|
val node = startNode("CN=Alice Corp,O=Alice Corp,L=London,C=GB", rpcUsers = listOf(user)).get()
|
2016-11-25 17:56:56 +00:00
|
|
|
|
|
|
|
When starting a standalone node using a configuration file we must supply the RPC credentials as follows:
|
|
|
|
|
|
|
|
.. code-block:: text
|
|
|
|
|
|
|
|
rpcUsers : [
|
2017-08-21 15:40:28 +00:00
|
|
|
{ username=user, password=password, permissions=[ StartFlow.net.corda.finance.flows.CashFlow ] }
|
2016-11-25 17:56:56 +00:00
|
|
|
]
|
|
|
|
|
2017-05-10 10:28:25 +00:00
|
|
|
When using the gradle Cordformation plugin to configure and deploy a node you must supply the RPC credentials in a similar
|
|
|
|
manner:
|
2016-11-25 17:56:56 +00:00
|
|
|
|
|
|
|
.. code-block:: text
|
|
|
|
|
|
|
|
rpcUsers = [
|
2017-04-07 10:23:25 +00:00
|
|
|
['username' : "user",
|
2016-11-25 17:56:56 +00:00
|
|
|
'password' : "password",
|
2017-08-21 15:40:28 +00:00
|
|
|
'permissions' : ["StartFlow.net.corda.finance.flows.CashFlow"]]
|
2016-11-25 17:56:56 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
You can then deploy and launch the nodes (Notary and Alice) as follows:
|
|
|
|
|
2016-11-28 10:12:23 +00:00
|
|
|
.. code-block:: text
|
2016-11-25 17:56:56 +00:00
|
|
|
|
2016-11-28 10:12:23 +00:00
|
|
|
# to create a set of configs and installs under ``docs/source/example-code/build/nodes`` run
|
|
|
|
./gradlew docs/source/example-code:deployNodes
|
|
|
|
# to open up two new terminals with the two nodes run
|
|
|
|
./docs/source/example-code/build/nodes/runnodes
|
|
|
|
# followed by the same commands as before:
|
|
|
|
./docs/source/example-code/build/install/docs/source/example-code/bin/client-rpc-tutorial Print
|
|
|
|
./docs/source/example-code/build/install/docs/source/example-code/bin/client-rpc-tutorial Visualise
|
2016-11-25 17:56:56 +00:00
|
|
|
|
2017-05-10 10:28:25 +00:00
|
|
|
With regards to the start flow RPCs, there is an extra layer of security whereby the flow to be executed has to be
|
|
|
|
annotated with ``@StartableByRPC``. Flows without this annotation cannot execute using RPC.
|
|
|
|
|
2017-10-02 09:11:33 +00:00
|
|
|
See more on security in :doc:`secure-coding-guidelines`, node configuration in :doc:`corda-configuration-file` and
|
|
|
|
Cordformation in :doc:`running-a-node`.
|