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>
|
|
|
|
|
|
|
|
Writing the flow
|
|
|
|
================
|
|
|
|
A flow describes the sequence of steps for agreeing a specific ledger update. By installing new flows on our node, we
|
2017-07-07 11:06:28 +00:00
|
|
|
allow the node to handle new business processes. Our flow will allow a node to issue an ``IOUState`` onto the ledger.
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
Flow outline
|
|
|
|
------------
|
|
|
|
Our flow needs to take the following steps for a borrower to issue a new IOU onto the ledger:
|
|
|
|
|
|
|
|
1. Create a valid transaction proposal for the creation of a new IOU
|
|
|
|
2. Verify the transaction
|
|
|
|
3. Sign the transaction ourselves
|
|
|
|
4. Record the transaction in our vault
|
|
|
|
5. Send the transaction to the IOU's lender so that they can record it too
|
|
|
|
|
|
|
|
Subflows
|
|
|
|
^^^^^^^^
|
|
|
|
Although our flow requirements look complex, we can delegate to existing flows to handle many of these tasks. A flow
|
|
|
|
that is invoked within the context of a larger flow to handle a repeatable task is called a *subflow*.
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-09-05 12:11:58 +00:00
|
|
|
In our initiator flow, we can automate steps 4 and 5 using ``FinalityFlow``.
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
All we need to do is write the steps to handle the creation and signing of the proposed transaction.
|
2017-06-16 13:05:52 +00:00
|
|
|
|
|
|
|
FlowLogic
|
|
|
|
---------
|
2017-07-07 11:06:28 +00:00
|
|
|
Flows are implemented as ``FlowLogic`` subclasses. You define the steps taken by the flow by overriding
|
2017-06-16 13:05:52 +00:00
|
|
|
``FlowLogic.call``.
|
|
|
|
|
2017-10-16 13:39:28 +00:00
|
|
|
We'll write our flow in either ``TemplateFlow.java`` or ``App.kt``. Delete both the existing flows in the template, and
|
|
|
|
replace them with the following:
|
2017-06-16 13:05:52 +00:00
|
|
|
|
|
|
|
.. container:: codeset
|
|
|
|
|
2017-10-16 13:39:28 +00:00
|
|
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/tutorial/helloworld/flow.kt
|
|
|
|
:language: kotlin
|
|
|
|
:start-after: DOCSTART 01
|
|
|
|
:end-before: DOCEND 01
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-10-16 13:39:28 +00:00
|
|
|
.. literalinclude:: example-code/src/main/java/net/corda/docs/java/tutorial/helloworld/IOUFlow.java
|
|
|
|
:language: java
|
|
|
|
:start-after: DOCSTART 01
|
|
|
|
:end-before: DOCEND 01
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-08-16 07:36:00 +00:00
|
|
|
If you're following along in Java, you'll also need to rename ``TemplateFlow.java`` to ``IOUFlow.java``.
|
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
We now have our own ``FlowLogic`` subclass that overrides ``FlowLogic.call``. There's a few things to note:
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
* ``FlowLogic.call`` has a return type that matches the type parameter passed to ``FlowLogic`` - this is type returned
|
|
|
|
by running the flow
|
|
|
|
* ``FlowLogic`` subclasses can have constructor parameters, which can be used as arguments to ``FlowLogic.call``
|
2017-06-16 13:05:52 +00:00
|
|
|
* ``FlowLogic.call`` is annotated ``@Suspendable`` - this means that the flow will be check-pointed and serialised to
|
|
|
|
disk when it encounters a long-running operation, allowing your node to move on to running other flows. Forgetting
|
|
|
|
this annotation out will lead to some very weird error messages
|
2017-07-07 11:06:28 +00:00
|
|
|
* There are also a few more annotations, on the ``FlowLogic`` subclass itself:
|
2017-06-16 13:05:52 +00:00
|
|
|
|
|
|
|
* ``@InitiatingFlow`` means that this flow can be started directly by the node
|
2017-09-05 12:11:58 +00:00
|
|
|
* ``@StartableByRPC`` allows the node owner to start this flow via an RPC call
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-08-16 07:36:00 +00:00
|
|
|
* We override the progress tracker, even though we are not providing any progress tracker steps yet. The progress
|
|
|
|
tracker is required for the node shell to establish when the flow has ended
|
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
Let's walk through the steps of ``FlowLogic.call`` one-by-one:
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
Retrieving participant information
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The identity of our counterparty is passed in as a constructor argument. However, we need to use the ``ServiceHub`` to
|
|
|
|
retrieve our identity, as well as the identity of the notary we'll be using for our transaction.
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
You can see that the notary's identity is being retrieved from the node's ``ServiceHub``. Whenever we need
|
|
|
|
information within a flow - whether it's about our own node, its contents, or the rest of the network - we use the
|
|
|
|
node's ``ServiceHub``. In particular, ``ServiceHub.networkMapCache`` provides information about the other nodes on the
|
|
|
|
network and the services that they offer.
|
2017-06-16 13:05:52 +00:00
|
|
|
|
|
|
|
Building the transaction
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
2017-07-07 11:06:28 +00:00
|
|
|
We'll build our transaction proposal in two steps:
|
2017-06-16 13:05:52 +00:00
|
|
|
|
|
|
|
* Creating a transaction builder
|
2017-07-07 11:06:28 +00:00
|
|
|
* Adding the desired items to the builder
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
Creating a transaction builder
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2017-06-16 13:05:52 +00:00
|
|
|
To start building the proposed transaction, we need a ``TransactionBuilder``. This is a mutable transaction class to
|
2017-07-07 11:06:28 +00:00
|
|
|
which we can add inputs, outputs, commands, and any other items the transaction needs. We create a
|
|
|
|
``TransactionBuilder`` that uses the notary we retrieved earlier.
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
Transaction items
|
|
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
Now that we have our ``TransactionBuilder``, we need to add the desired items. Remember that we're trying to build
|
2017-06-16 13:05:52 +00:00
|
|
|
the following transaction:
|
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
.. image:: resources/simple-tutorial-transaction.png
|
|
|
|
:scale: 15%
|
2017-06-16 13:05:52 +00:00
|
|
|
:align: center
|
|
|
|
|
|
|
|
So we'll need the following:
|
|
|
|
|
2017-10-02 08:08:59 +00:00
|
|
|
* The output ``IOUState`` and its associated contract
|
2017-09-05 12:11:58 +00:00
|
|
|
* A ``Create`` command listing the IOU's lender as a signer
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
The command we use pairs the ``IOUContract.Create`` command defined earlier with our public key. Including this command
|
|
|
|
in the transaction makes us one of the transaction's required signers.
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
We add these items to the transaction using the ``TransactionBuilder.withItems`` method, which takes a ``vararg`` of:
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-10-02 08:08:59 +00:00
|
|
|
* ``StateAndContract`` or ``TransactionState`` objects, which are added to the builder as output states
|
|
|
|
* ``StateAndRef`` objects (references to the outputs of previous transactions), which are added to the builder as input
|
2017-06-16 13:05:52 +00:00
|
|
|
state references
|
2017-07-07 11:06:28 +00:00
|
|
|
* ``Command`` objects, which are added to the builder as commands
|
|
|
|
* ``SecureHash`` objects, which are added to the builder as attachments
|
|
|
|
* ``TimeWindow`` objects, which set the time-window of the transaction
|
2017-06-16 13:05:52 +00:00
|
|
|
|
|
|
|
It will modify the ``TransactionBuilder`` in-place to add these components to it.
|
|
|
|
|
|
|
|
Verifying the transaction
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
We've now built our proposed transaction. Before we sign it, we should check that it represents a valid ledger update
|
2017-07-07 11:06:28 +00:00
|
|
|
proposal by verifying the transaction, which will execute each of the transaction's contracts.
|
2017-06-16 13:05:52 +00:00
|
|
|
|
|
|
|
If the verification fails, we have built an invalid transaction. Our flow will then end, throwing a
|
|
|
|
``TransactionVerificationException``.
|
|
|
|
|
|
|
|
Signing the transaction
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^
|
2017-07-07 11:06:28 +00:00
|
|
|
Now that we have a valid transaction proposal, we need to sign it. Once the transaction is signed, no-one will be able
|
|
|
|
to modify the transaction without invalidating our signature, effectively making the transaction immutable.
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-08-04 10:50:52 +00:00
|
|
|
The call to ``ServiceHub.toSignedTransaction`` returns a ``SignedTransaction`` - an object that pairs the
|
2017-06-16 13:05:52 +00:00
|
|
|
transaction itself with a list of signatures over that transaction.
|
|
|
|
|
|
|
|
Finalising the transaction
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
2017-07-07 11:06:28 +00:00
|
|
|
Now that we have a valid signed transaction, all that's left to do is to have it notarised and recorded by all the
|
|
|
|
relevant parties. By doing so, it will become a permanent part of the ledger. As discussed, we'll handle this process
|
|
|
|
automatically using a built-in flow called ``FinalityFlow``:
|
2017-06-16 13:05:52 +00:00
|
|
|
|
|
|
|
``FinalityFlow`` completely automates the process of:
|
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
* Notarising the transaction if required (i.e. if the transaction contains inputs and/or a time-window)
|
2017-06-16 13:05:52 +00:00
|
|
|
* Recording it in our vault
|
2017-07-07 11:06:28 +00:00
|
|
|
* Sending it to the other participants (i.e. the lender) for them to record as well
|
2017-06-16 13:05:52 +00:00
|
|
|
|
2017-07-07 11:06:28 +00:00
|
|
|
Our flow, and our CorDapp, are now ready!
|
2017-06-16 13:05:52 +00:00
|
|
|
|
|
|
|
Progress so far
|
|
|
|
---------------
|
2017-07-07 11:06:28 +00:00
|
|
|
We have now defined a flow that we can start on our node to completely automate the process of issuing an IOU onto the
|
|
|
|
ledger. The final step is to spin up some nodes and test our CorDapp.
|