diff --git a/docs/build/doctrees/clientrpc.doctree b/docs/build/doctrees/clientrpc.doctree
index e595d5606b..dc90584d50 100644
Binary files a/docs/build/doctrees/clientrpc.doctree and b/docs/build/doctrees/clientrpc.doctree differ
diff --git a/docs/build/doctrees/corda-plugins.doctree b/docs/build/doctrees/corda-plugins.doctree
new file mode 100644
index 0000000000..81e70de0f6
Binary files /dev/null and b/docs/build/doctrees/corda-plugins.doctree differ
diff --git a/docs/build/doctrees/creating-a-cordapp.doctree b/docs/build/doctrees/creating-a-cordapp.doctree
index 371fe90d2f..7eb0eceb31 100644
Binary files a/docs/build/doctrees/creating-a-cordapp.doctree and b/docs/build/doctrees/creating-a-cordapp.doctree differ
diff --git a/docs/build/doctrees/environment.pickle b/docs/build/doctrees/environment.pickle
index 55fc0bcaf8..207b67d742 100644
Binary files a/docs/build/doctrees/environment.pickle and b/docs/build/doctrees/environment.pickle differ
diff --git a/docs/build/doctrees/flow-state-machines.doctree b/docs/build/doctrees/flow-state-machines.doctree
index ff6386200c..88f175a717 100644
Binary files a/docs/build/doctrees/flow-state-machines.doctree and b/docs/build/doctrees/flow-state-machines.doctree differ
diff --git a/docs/build/doctrees/flow-testing.doctree b/docs/build/doctrees/flow-testing.doctree
new file mode 100644
index 0000000000..6136790524
Binary files /dev/null and b/docs/build/doctrees/flow-testing.doctree differ
diff --git a/docs/build/doctrees/further-notes-on-kotlin.doctree b/docs/build/doctrees/further-notes-on-kotlin.doctree
index 79ca2b7ffc..c821773917 100644
Binary files a/docs/build/doctrees/further-notes-on-kotlin.doctree and b/docs/build/doctrees/further-notes-on-kotlin.doctree differ
diff --git a/docs/build/doctrees/getting-set-up-fault-finding.doctree b/docs/build/doctrees/getting-set-up-fault-finding.doctree
index 2ee693ba24..634532cba5 100644
Binary files a/docs/build/doctrees/getting-set-up-fault-finding.doctree and b/docs/build/doctrees/getting-set-up-fault-finding.doctree differ
diff --git a/docs/build/doctrees/getting-set-up.doctree b/docs/build/doctrees/getting-set-up.doctree
index 99c916d6a1..82f7cfba57 100644
Binary files a/docs/build/doctrees/getting-set-up.doctree and b/docs/build/doctrees/getting-set-up.doctree differ
diff --git a/docs/build/doctrees/index.doctree b/docs/build/doctrees/index.doctree
index ac6662b26d..5f9781beb3 100644
Binary files a/docs/build/doctrees/index.doctree and b/docs/build/doctrees/index.doctree differ
diff --git a/docs/build/doctrees/loadtesting.doctree b/docs/build/doctrees/loadtesting.doctree
index 5f962c5d4c..9beba04587 100644
Binary files a/docs/build/doctrees/loadtesting.doctree and b/docs/build/doctrees/loadtesting.doctree differ
diff --git a/docs/build/doctrees/network-simulator.doctree b/docs/build/doctrees/network-simulator.doctree
index 8dbd787779..f1c3d7ef84 100644
Binary files a/docs/build/doctrees/network-simulator.doctree and b/docs/build/doctrees/network-simulator.doctree differ
diff --git a/docs/build/doctrees/node-administration.doctree b/docs/build/doctrees/node-administration.doctree
index d0b1b0c968..a1512c5b68 100644
Binary files a/docs/build/doctrees/node-administration.doctree and b/docs/build/doctrees/node-administration.doctree differ
diff --git a/docs/build/doctrees/node-explorer.doctree b/docs/build/doctrees/node-explorer.doctree
index baf9ce87b3..307cdce765 100644
Binary files a/docs/build/doctrees/node-explorer.doctree and b/docs/build/doctrees/node-explorer.doctree differ
diff --git a/docs/build/doctrees/tutorial-contract.doctree b/docs/build/doctrees/tutorial-contract.doctree
index 3ba5d4f1f0..460138e34e 100644
Binary files a/docs/build/doctrees/tutorial-contract.doctree and b/docs/build/doctrees/tutorial-contract.doctree differ
diff --git a/docs/build/html/_images/contract-cp-state.png b/docs/build/html/_images/contract-cp-state.png
new file mode 100644
index 0000000000..767d87b5cf
Binary files /dev/null and b/docs/build/html/_images/contract-cp-state.png differ
diff --git a/docs/build/html/_images/contract-cp.png b/docs/build/html/_images/contract-cp.png
new file mode 100644
index 0000000000..54fbb8e836
Binary files /dev/null and b/docs/build/html/_images/contract-cp.png differ
diff --git a/docs/build/html/_images/dashboard.png b/docs/build/html/_images/dashboard.png
index 12e28f8cd0..8a7e801a92 100644
Binary files a/docs/build/html/_images/dashboard.png and b/docs/build/html/_images/dashboard.png differ
diff --git a/docs/build/html/_images/login.png b/docs/build/html/_images/login.png
index a2779c3e13..6f08bdb285 100644
Binary files a/docs/build/html/_images/login.png and b/docs/build/html/_images/login.png differ
diff --git a/docs/build/html/_images/network.png b/docs/build/html/_images/network.png
new file mode 100644
index 0000000000..f72e90e985
Binary files /dev/null and b/docs/build/html/_images/network.png differ
diff --git a/docs/build/html/_images/newTransaction.png b/docs/build/html/_images/newTransaction.png
index b01da505f9..166dea4a31 100644
Binary files a/docs/build/html/_images/newTransaction.png and b/docs/build/html/_images/newTransaction.png differ
diff --git a/docs/build/html/_images/settings.png b/docs/build/html/_images/settings.png
new file mode 100644
index 0000000000..6cdf15e631
Binary files /dev/null and b/docs/build/html/_images/settings.png differ
diff --git a/docs/build/html/_images/transactionView.png b/docs/build/html/_images/transactionView.png
index 2fbbdf2a6f..3ca439d6e0 100644
Binary files a/docs/build/html/_images/transactionView.png and b/docs/build/html/_images/transactionView.png differ
diff --git a/docs/build/html/_images/vault.png b/docs/build/html/_images/vault.png
index 7909d92d3b..d0f7210e02 100644
Binary files a/docs/build/html/_images/vault.png and b/docs/build/html/_images/vault.png differ
diff --git a/docs/build/html/_sources/corda-plugins.txt b/docs/build/html/_sources/corda-plugins.txt
new file mode 100644
index 0000000000..bddc9cce4b
--- /dev/null
+++ b/docs/build/html/_sources/corda-plugins.txt
@@ -0,0 +1,98 @@
+The Corda Plugin Framework
+==========================
+
+The intention is that Corda is a common platform, which will be extended
+by numerous application extensions (CorDapps). These extensions will
+package together all of the Corda contract code, state structures,
+protocols/flows to create and modify state as well as RPC extensions for
+node clients. Details of writing these CorDapps is given elsewhere
+:doc:`creating-a-cordapp`.
+
+To enable these plugins to register dynamically with the Corda framework
+the node uses the Java ``ServiceLoader`` to locate and load the plugin
+components during the ``AbstractNode.start`` call. Therefore,
+to be recognised as a plugin the component must:
+
+1. Include a default constructable class extending from
+``net.corda.core.node.CordaPluginRegistry`` which overrides the relevant
+registration methods.
+
+2. Include a resource file named
+``net.corda.core.node.CordaPluginRegistry`` in the ``META-INF.services``
+path. This must include a line containing the fully qualified name of
+the ``CordaPluginRegistry`` implementation class. Multiple plugin
+registries are allowed in this file if desired.
+
+3. The plugin component must be on the classpath. In the normal use this
+means that it should be present within the plugins subfolder of the
+node's workspace.
+
+4. As a plugin the registered components are then allowed access to some
+of the node internal subsystems.
+
+5. The overridden properties on the registry class information about the different
+extensions to be created, or registered at startup. In particular:
+
+ a. The ``webApis`` property is a list of JAX-RS annotated REST access
+ classes. These classes will be constructed by the embedded web server
+ and must have a single argument constructor taking a ``ServiceHub``
+ reference. This reference provides acccess to functions such as querying
+ for states through the ``VaultService`` interface, or access to the
+ ``NetworkMapCache`` to identify services on remote nodes. The framework will
+ provide a database transaction in scope during the lifetime of the web
+ call, so full access to database data is valid. Unlike
+ ``servicePlugins`` the ``webApis`` cannnot register new protocols, or
+ initiate threads. (N.B. The intent is to move the Web support into a
+ separate helper process using the RPC mechanism to control access.)
+
+ b. The ``staticServeDirs`` property maps static web content to virtual
+ paths and allows simple web demos to be distributed within the CorDapp
+ jars. (N.B. The intent is to move the Web support into a separate helper
+ process using the RPC mechanism to control access.)
+
+ c. The ``requiredFlows`` property is used to declare new protocols in
+ the plugin jar. Specifically the property must return a map with a key
+ naming each exposed top level flow class and a value which is a set
+ naming every parameter class that will be passed to the flow's
+ constructor. Standard ``java.lang.*`` and ``kotlin.*`` types do not need
+ to be included, but all other parameter types, or concrete interface
+ implementations need declaring. Declaring a specific flow in this map
+ white lists it for activation by the ``FlowLogicRefFactory``. White
+ listing is not strictly required for ``subFlows`` used internally, but
+ is required for any top level flow, or a flow which is invoked through
+ the scheduler.
+
+ d. The ``servicePlugins`` property returns a list of classes which will
+ be instantiated once during the ``AbstractNode.start`` call. These
+ classes must provide a single argument constructor which will receive a
+ ``PluginServiceHub`` reference. These singleton instances are regarded
+ as trusted components and can be used for a number of purposes.
+
+ i. Firstly, they can call ``PluginServiceHub.registerFlowInitiator`` and
+ register flows that will be initiated locally in response to remote flow
+ requests.
+
+ ii. Second, the service can hold a long lived reference to the
+ PluginServiceHub and to other private data, so the service can be used
+ to provide Oracle functionality. This Oracle functionality would
+ typically be exposed to other nodes by flows which are given a reference
+ to the service plugin when initiated (as defined by the
+ ``registerFlowInitiator`` call). The flow can then call into functions
+ on the plugin service singleton. Note, care should be taken to not allow
+ flows to hold references to plugin services, or fields which are not
+ also ``SingletonSerializeAsToken``, otherwise Quasar suspension in the
+ ``StateMachineManager`` will fail with exceptions. An example oracle can
+ be seen in ``NodeInterestRates.kt`` in the irs-demo sample.
+
+ iii. The final
+ use case for service plugins is that they can spawn threads, or register
+ to monitor vault updates. This allows them to provide long lived active
+ functions inside the node, for instance to initiate workflows when
+ certain conditions are met.
+
+ e. The ``registerRPCKryoTypes`` function allows custom Kryo serialisers
+ to be registered and whitelisted for the RPC client interface. For
+ instance new state types passed to flows started via RPC will need
+ to be explicitly registered. This will be called at various points on
+ various threads and needs to be stable and thread safe.
+
diff --git a/docs/build/html/_sources/creating-a-cordapp.txt b/docs/build/html/_sources/creating-a-cordapp.txt
index 4a9ea9c8bf..cae637d740 100644
--- a/docs/build/html/_sources/creating-a-cordapp.txt
+++ b/docs/build/html/_sources/creating-a-cordapp.txt
@@ -178,9 +178,6 @@ To build against Corda and the plugins that cordapps use, update your build.grad
... your tasks ...
- // Sets the classes for Quasar to scan. Loaded by the the quasar-utils plugin.
- quasarScan.dependsOn('classes', ... your dependent subprojects...)
-
// Standard way to publish Cordapps to maven local with the maven-publish and publish-utils plugin.
publishing {
publications {
diff --git a/docs/build/html/_sources/flow-state-machines.txt b/docs/build/html/_sources/flow-state-machines.txt
index 3f39a15bd7..1e3c3500d8 100644
--- a/docs/build/html/_sources/flow-state-machines.txt
+++ b/docs/build/html/_sources/flow-state-machines.txt
@@ -4,10 +4,10 @@
-Flow state machines
-===================
+Writing flows
+=============
-This article explains our experimental approach to modelling financial flows in code. It explains how the
+This article explains our approach to modelling financial flows in code. It explains how the
platform's state machine framework is used, and takes you through the code for a simple 2-party asset trading flow
which is included in the source.
@@ -91,7 +91,7 @@ Our flow has two parties (B and S for buyer and seller) and will proceed as foll
it lacks a signature from S authorising movement of the asset.
3. S signs it and hands the now finalised ``SignedTransaction`` back to B.
-You can find the implementation of this flow in the file ``finance/src/main/kotlin/net.corda.flows/TwoPartyTradeFlow.kt``.
+You can find the implementation of this flow in the file ``finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt``.
Assuming no malicious termination, they both end the flow being in posession of a valid, signed transaction that
represents an atomic asset swap.
@@ -120,13 +120,13 @@ each side.
data class SellerTradeInfo(
val assetForSale: StateAndRef,
val price: Amount,
- val sellerOwnerKey: PublicKey
+ val sellerOwnerKey: CompositeKey
)
data class SignaturesFromSeller(val sellerSig: DigitalSignature.WithKey,
val notarySig: DigitalSignature.LegallyIdentifiable)
- open class Seller(val otherSide: Party,
+ open class Seller(val otherParty: Party,
val notaryNode: NodeInfo,
val assetToSell: StateAndRef,
val price: Amount,
@@ -138,7 +138,7 @@ each side.
}
}
- open class Buyer(val otherSide: Party,
+ open class Buyer(val otherParty: Party,
val notary: Party,
val acceptablePrice: Amount,
val typeToBuy: Class) : FlowLogic() {
@@ -154,7 +154,7 @@ simply flow messages or exceptions. The other two represent the buyer and seller
Going through the data needed to become a seller, we have:
-- ``otherSide: Party`` - the party with which you are trading.
+- ``otherParty: Party`` - the party with which you are trading.
- ``notaryNode: NodeInfo`` - the entry in the network map for the chosen notary. See ":doc:`consensus`" for more
information on notaries.
- ``assetToSell: StateAndRef`` - a pointer to the ledger entry that represents the thing being sold.
@@ -197,20 +197,23 @@ when messages arrive. It provides the send/receive/sendAndReceive calls that let
interaction and it will save/restore serialised versions of the fiber at the right times.
Flows can be invoked in several ways. For instance, they can be triggered by scheduled events,
-see ":doc:`event-scheduling`" to learn more about this. Or they can be triggered via the HTTP API. Or they can
-be triggered directly via the Java-level node APIs from your app code.
+see ":doc:`event-scheduling`" to learn more about this. Or they can be triggered directly via the Java-level node RPC
+APIs from your app code.
-You request a flow to be invoked by using the ``ServiceHub.invokeFlowAsync`` method. This takes a
+You request a flow to be invoked by using the ``CordaRPCOps.startFlowDynamic`` method. This takes a
Java reflection ``Class`` object that describes the flow class to use (in this case, either ``Buyer`` or ``Seller``).
It also takes a set of arguments to pass to the constructor. Because it's possible for flow invocations to
be requested by untrusted code (e.g. a state that you have been sent), the types that can be passed into the
-flow are checked against a whitelist, which can be extended by apps themselves at load time.
+flow are checked against a whitelist, which can be extended by apps themselves at load time. There are also a series
+of inlined extension functions of the form ``CordaRPCOps.startFlow`` which help with invoking flows in a type
+safe manner.
-The process of starting a flow returns a ``ListenableFuture`` that you can use to either block waiting for
-the result, or register a callback that will be invoked when the result is ready.
+The process of starting a flow returns a ``FlowHandle`` that you can use to either observe
+the result, observe its progress and which also contains a permanent identifier for the invoked flow in the form
+of the ``StateMachineRunId``.
-In a two party flow only one side is to be manually started using ``ServiceHub.invokeFlowAsync``. The other side
-has to be registered by its node to respond to the initiating flow via ``ServiceHubInternal.registerFlowInitiator``.
+In a two party flow only one side is to be manually started using ``CordaRPCOps.startFlow``. The other side
+has to be registered by its node to respond to the initiating flow via ``PluginServiceHub.registerFlowInitiator``.
In our example it doesn't matter which flow is the initiator and which is the initiated. For example, if we are to
take the seller as the initiator then we would register the buyer as such:
@@ -218,8 +221,7 @@ take the seller as the initiator then we would register the buyer as such:
.. sourcecode:: kotlin
- val services: ServiceHubInternal = TODO()
-
+ val services: PluginServiceHub = TODO()
services.registerFlowInitiator(Seller::class) { otherParty ->
val notary = services.networkMapCache.notaryNodes[0]
val acceptablePrice = TODO()
@@ -266,25 +268,21 @@ Let's fill out the ``receiveAndCheckProposedTransaction()`` method.
@Suspendable
private fun receiveAndCheckProposedTransaction(): SignedTransaction {
// Make the first message we'll send to kick off the flow.
- val hello = SellerTradeInfo(assetToSell, price, myKeyPair.public)
+ val myPublicKey = myKeyPair.public.composite
+ val hello = SellerTradeInfo(assetToSell, price, myPublicKey)
val maybeSTX = sendAndReceive(otherSide, hello)
maybeSTX.unwrap {
// Check that the tx proposed by the buyer is valid.
- val missingSigs: Set = it.verifySignatures(throwIfSignaturesAreMissing = false)
- val expected = setOf(myKeyPair.public, notaryNode.identity.owningKey)
- if (missingSigs != expected)
- throw SignatureException("The set of missing signatures is not as expected: ${missingSigs.toStringsShort()} vs ${expected.toStringsShort()}")
-
- val wtx: WireTransaction = it.tx
+ val wtx: WireTransaction = it.verifySignatures(myPublicKey, notaryNode.notaryIdentity.owningKey)
logger.trace { "Received partially signed transaction: ${it.id}" }
// Download and check all the things that this transaction depends on and verify it is contract-valid,
// even though it is missing signatures.
- subFlow(ResolveTransactionsFlow(wtx, otherSide))
+ subFlow(ResolveTransactionsFlow(wtx, otherParty))
- if (wtx.outputs.map { it.data }.sumCashBy(myKeyPair.public).withoutIssuer() != price)
+ if (wtx.outputs.map { it.data }.sumCashBy(myPublicKey).withoutIssuer() != price)
throw IllegalArgumentException("Transaction is not sending us the right amount of cash")
return it
@@ -306,7 +304,9 @@ needs human interaction!
.. note:: There are a couple of rules you need to bear in mind when writing a class that will be used as a continuation.
The first is that anything on the stack when the function is suspended will be stored into the heap and kept alive by
- the garbage collector. So try to avoid keeping enormous data structures alive unless you really have to.
+ the garbage collector. So try to avoid keeping enormous data structures alive unless you really have to. You can
+ always use private methods to keep the stack uncluttered with temporary variables, or to avoid objects that
+ Kryo is not able to serialise correctly.
The second is that as well as being kept on the heap, objects reachable from the stack will be serialised. The state
of the function call may be resurrected much later! Kryo doesn't require objects be marked as serialisable, but even so,
@@ -372,18 +372,18 @@ Here's the rest of the code:
.. sourcecode:: kotlin
- open fun computeOurSignature(partialTX: SignedTransaction) = myKeyPair.signWithECDSA(partialTX.txBits)
+ open fun calculateOurSignature(partialTX: SignedTransaction) = myKeyPair.signWithECDSA(partialTX.id)
@Suspendable
private fun sendSignatures(allPartySignedTX: SignedTransaction, ourSignature: DigitalSignature.WithKey,
- notarySignature: DigitalSignature.LegallyIdentifiable): SignedTransaction {
+ notarySignature: DigitalSignature.WithKey): SignedTransaction {
val fullySigned = allPartySignedTX + notarySignature
logger.trace { "Built finished transaction, sending back to secondary!" }
send(otherSide, SignaturesFromSeller(ourSignature, notarySignature))
return fullySigned
}
-It's all pretty straightforward from now on. Here ``txBits`` is the raw byte array representing the serialised
+It's all pretty straightforward from now on. Here ``id`` is the secure hash representing the serialised
transaction, and we just use our private key to calculate a signature over it. As a reminder, in Corda signatures do
not cover other signatures: just the core of the transaction data.
@@ -405,98 +405,15 @@ Implementing the buyer
OK, let's do the same for the buyer side:
-.. container:: codeset
-
- .. sourcecode:: kotlin
-
- @Suspendable
- override fun call(): SignedTransaction {
- val tradeRequest = receiveAndValidateTradeRequest()
- val (ptx, cashSigningPubKeys) = assembleSharedTX(tradeRequest)
- val stx = signWithOurKeys(cashSigningPubKeys, ptx)
-
- val signatures = swapSignaturesWithSeller(stx)
-
- logger.trace { "Got signatures from seller, verifying ... " }
-
- val fullySigned = stx + signatures.sellerSig + signatures.notarySig
- fullySigned.verifySignatures()
-
- logger.trace { "Signatures received are valid. Trade complete! :-)" }
- return fullySigned
- }
-
- @Suspendable
- private fun receiveAndValidateTradeRequest(): SellerTradeInfo {
- // Wait for a trade request to come in from the other side
- val maybeTradeRequest = receive(otherParty)
- maybeTradeRequest.unwrap {
- // What is the seller trying to sell us?
- val asset = it.assetForSale.state.data
- val assetTypeName = asset.javaClass.name
- logger.trace { "Got trade request for a $assetTypeName: ${it.assetForSale}" }
-
- if (it.price > acceptablePrice)
- throw UnacceptablePriceException(it.price)
- if (!typeToBuy.isInstance(asset))
- throw AssetMismatchException(typeToBuy.name, assetTypeName)
-
- // Check the transaction that contains the state which is being resolved.
- // We only have a hash here, so if we don't know it already, we have to ask for it.
- subFlow(ResolveTransactionsFlow(setOf(it.assetForSale.ref.txhash), otherSide))
-
- return it
- }
- }
-
- @Suspendable
- private fun swapSignaturesWithSeller(stx: SignedTransaction): SignaturesFromSeller {
- progressTracker.currentStep = SWAPPING_SIGNATURES
- logger.trace { "Sending partially signed transaction to seller" }
-
- // TODO: Protect against the seller terminating here and leaving us in the lurch without the final tx.
-
- return sendAndReceive(otherSide, stx).unwrap { it }
- }
-
- private fun signWithOurKeys(cashSigningPubKeys: List, ptx: TransactionBuilder): SignedTransaction {
- // Now sign the transaction with whatever keys we need to move the cash.
- for (k in cashSigningPubKeys) {
- val priv = serviceHub.keyManagementService.toPrivate(k)
- ptx.signWith(KeyPair(k, priv))
- }
-
- return ptx.toSignedTransaction(checkSufficientSignatures = false)
- }
-
- private fun assembleSharedTX(tradeRequest: SellerTradeInfo): Pair> {
- val ptx = TransactionType.General.Builder(notary)
- // Add input and output states for the movement of cash, by using the Cash contract to generate the states.
- val wallet = serviceHub.walletService.currentWallet
- val cashStates = wallet.statesOfType()
- val cashSigningPubKeys = Cash().generateSpend(ptx, tradeRequest.price, tradeRequest.sellerOwnerKey, cashStates)
- // Add inputs/outputs/a command for the movement of the asset.
- ptx.addInputState(tradeRequest.assetForSale)
- // Just pick some new public key for now. This won't be linked with our identity in any way, which is what
- // we want for privacy reasons: the key is here ONLY to manage and control ownership, it is not intended to
- // reveal who the owner actually is. The key management service is expected to derive a unique key from some
- // initial seed in order to provide privacy protection.
- val freshKey = serviceHub.keyManagementService.freshKey()
- val (command, state) = tradeRequest.assetForSale.state.data.withNewOwner(freshKey.public)
- ptx.addOutputState(state, tradeRequest.assetForSale.state.notary)
- ptx.addCommand(command, tradeRequest.assetForSale.state.data.owner)
-
- // And add a request for timestamping: it may be that none of the contracts need this! But it can't hurt
- // to have one.
- val currentTime = serviceHub.clock.instant()
- ptx.setTime(currentTime, 30.seconds)
- return Pair(ptx, cashSigningPubKeys)
- }
+.. literalinclude:: ../../finance/src/main/kotlin/net/corda/flows/TwoPartyTradeFlow.kt
+ :language: kotlin
+ :start-after: DOCSTART 1
+ :end-before: DOCEND 1
This code is longer but no more complicated. Here are some things to pay attention to:
1. We do some sanity checking on the received message to ensure we're being offered what we expected to be offered.
-2. We create a cash spend in the normal way, by using ``Cash().generateSpend``. See the contracts tutorial if this
+2. We create a cash spend in the normal way, by using ``VaultService.generateSpend``. See the vault documentation if this
part isn't clear.
3. We access the *service hub* when we need it to access things that are transient and may change or be recreated
whilst a flow is suspended, things like the wallet or the network map.
@@ -559,108 +476,6 @@ and linked ahead of time.
In future, the progress tracking framework will become a vital part of how exceptions, errors, and other faults are
surfaced to human operators for investigation and resolution.
-Unit testing
-------------
-
-A flow can be a fairly complex thing that interacts with many services and other parties over the network. That
-means unit testing one requires some infrastructure to provide lightweight mock implementations. The MockNetwork
-provides this testing infrastructure layer; you can find this class in the node module
-
-A good example to examine for learning how to unit test flows is the ``ResolveTransactionsFlow`` tests. This
-flow takes care of downloading and verifying transaction graphs, with all the needed dependencies. We start
-with this basic skeleton:
-
-.. container:: codeset
-
- .. sourcecode:: kotlin
-
- class ResolveTransactionsFlowTest {
- lateinit var net: MockNetwork
- lateinit var a: MockNetwork.MockNode
- lateinit var b: MockNetwork.MockNode
- lateinit var notary: Party
-
- @Before
- fun setup() {
- net = MockNetwork()
- val nodes = net.createSomeNodes()
- a = nodes.partyNodes[0]
- b = nodes.partyNodes[1]
- notary = nodes.notaryNode.info.identity
- net.runNetwork()
- }
-
- @After
- fun tearDown() {
- net.stopNodes()
- }
- }
-
-We create a mock network in our ``@Before`` setup method and create a couple of nodes. We also record the identity
-of the notary in our test network, which will come in handy later. We also tidy up when we're done.
-
-Next, we write a test case:
-
-.. container:: codeset
-
- .. sourcecode:: kotlin
-
- @Test
- fun resolveFromTwoHashes() {
- val (stx1, stx2) = makeTransactions()
- val p = ResolveTransactionsFlow(setOf(stx2.id), a.info.identity)
- val future = b.services.startFlow("resolve", p)
- net.runNetwork()
- val results = future.get()
- assertEquals(listOf(stx1.id, stx2.id), results.map { it.id })
- assertEquals(stx1, b.storage.validatedTransactions.getTransaction(stx1.id))
- assertEquals(stx2, b.storage.validatedTransactions.getTransaction(stx2.id))
- }
-
-We'll take a look at the ``makeTransactions`` function in a moment. For now, it's enough to know that it returns two
-``SignedTransaction`` objects, the second of which spends the first. Both transactions are known by node A
-but not node B.
-
-The test logic is simple enough: we create the flow, giving it node A's identity as the target to talk to.
-Then we start it on node B and use the ``net.runNetwork()`` method to bounce messages around until things have
-settled (i.e. there are no more messages waiting to be delivered). All this is done using an in memory message
-routing implementation that is fast to initialise and use. Finally, we obtain the result of the flow and do
-some tests on it. We also check the contents of node B's database to see that the flow had the intended effect
-on the node's persistent state.
-
-Here's what ``makeTransactions`` looks like:
-
-.. container:: codeset
-
- .. sourcecode:: kotlin
-
- private fun makeTransactions(): Pair {
- // Make a chain of custody of dummy states and insert into node A.
- val dummy1: SignedTransaction = DummyContract.generateInitial(MEGA_CORP.ref(1), 0, notary).let {
- it.signWith(MEGA_CORP_KEY)
- it.signWith(DUMMY_NOTARY_KEY)
- it.toSignedTransaction(false)
- }
- val dummy2: SignedTransaction = DummyContract.move(dummy1.tx.outRef(0), MINI_CORP_PUBKEY).let {
- it.signWith(MEGA_CORP_KEY)
- it.signWith(DUMMY_NOTARY_KEY)
- it.toSignedTransaction()
- }
- a.services.recordTransactions(dummy1, dummy2)
- return Pair(dummy1, dummy2)
- }
-
-We're using the ``DummyContract``, a simple test smart contract which stores a single number in its states, along
-with ownership and issuer information. You can issue such states, exit them and re-assign ownership (move them).
-It doesn't do anything else. This code simply creates a transaction that issues a dummy state (the issuer is
-``MEGA_CORP``, a pre-defined unit test identity), signs it with the test notary and MegaCorp keys and then
-converts the builder to the final ``SignedTransaction``. It then does so again, but this time instead of issuing
-it re-assigns ownership instead. The chain of two transactions is finally committed to node A by sending them
-directly to the ``a.services.recordTransaction`` method (note that this method doesn't check the transactions are
-valid).
-
-And that's it: you can explore the documentation for the `MockNode API `_ here.
-
Versioning
----------
@@ -684,11 +499,10 @@ The flow framework is a key part of the platform and will be extended in major w
the features we have planned:
* Identity based addressing
-* Exposing progress trackers to local (inside the firewall) clients using message queues and/or WebSockets
* Exception propagation and management, with a "flow hospital" tool to manually provide solutions to unavoidable
problems (e.g. the other side doesn't know the trade)
-* Being able to interact with internal apps and tools via HTTP and similar
+* Being able to interact with internal apps and tools via RPC
* Being able to interact with people, either via some sort of external ticketing system, or email, or a custom UI.
For example to implement human transaction authorisations.
* A standard library of flows that can be easily sub-classed by local developers in order to integrate internal
- reporting logic, or anything else that might be required as part of a communications lifecycle.
+ reporting logic, or anything else that might be required as part of a communications lifecycle.
\ No newline at end of file
diff --git a/docs/build/html/_sources/flow-testing.txt b/docs/build/html/_sources/flow-testing.txt
new file mode 100644
index 0000000000..010d83c886
--- /dev/null
+++ b/docs/build/html/_sources/flow-testing.txt
@@ -0,0 +1,83 @@
+.. highlight:: kotlin
+.. raw:: html
+
+
+
+
+Writing flow tests
+==================
+
+A flow can be a fairly complex thing that interacts with many services and other parties over the network. That
+means unit testing one requires some infrastructure to provide lightweight mock implementations. The MockNetwork
+provides this testing infrastructure layer; you can find this class in the test-utils module.
+
+A good example to examine for learning how to unit test flows is the ``ResolveTransactionsFlow`` tests. This
+flow takes care of downloading and verifying transaction graphs, with all the needed dependencies. We start
+with this basic skeleton:
+
+.. container:: codeset
+
+ .. sourcecode:: kotlin
+
+ class ResolveTransactionsFlowTest {
+ lateinit var net: MockNetwork
+ lateinit var a: MockNetwork.MockNode
+ lateinit var b: MockNetwork.MockNode
+ lateinit var notary: Party
+
+ @Before
+ fun setup() {
+ net = MockNetwork()
+ val nodes = net.createSomeNodes()
+ a = nodes.partyNodes[0]
+ b = nodes.partyNodes[1]
+ notary = nodes.notaryNode.info.notaryIdentity
+ net.runNetwork()
+ }
+
+ @After
+ fun tearDown() {
+ net.stopNodes()
+ }
+ }
+
+We create a mock network in our ``@Before`` setup method and create a couple of nodes. We also record the identity
+of the notary in our test network, which will come in handy later. We also tidy up when we're done.
+
+Next, we write a test case:
+
+.. literalinclude:: ../../core/src/test/kotlin/net/corda/core/flows/ResolveTransactionsFlowTest.kt
+ :language: kotlin
+ :start-after: DOCSTART 1
+ :end-before: DOCEND 1
+
+We'll take a look at the ``makeTransactions`` function in a moment. For now, it's enough to know that it returns two
+``SignedTransaction`` objects, the second of which spends the first. Both transactions are known by node A
+but not node B.
+
+The test logic is simple enough: we create the flow, giving it node A's identity as the target to talk to.
+Then we start it on node B and use the ``net.runNetwork()`` method to bounce messages around until things have
+settled (i.e. there are no more messages waiting to be delivered). All this is done using an in memory message
+routing implementation that is fast to initialise and use. Finally, we obtain the result of the flow and do
+some tests on it. We also check the contents of node B's database to see that the flow had the intended effect
+on the node's persistent state.
+
+Here's what ``makeTransactions`` looks like:
+
+.. literalinclude:: ../../core/src/test/kotlin/net/corda/core/flows/ResolveTransactionsFlowTest.kt
+ :language: kotlin
+ :start-after: DOCSTART 2
+ :end-before: DOCEND 2
+
+We're using the ``DummyContract``, a simple test smart contract which stores a single number in its states, along
+with ownership and issuer information. You can issue such states, exit them and re-assign ownership (move them).
+It doesn't do anything else. This code simply creates a transaction that issues a dummy state (the issuer is
+``MEGA_CORP``, a pre-defined unit test identity), signs it with the test notary and MegaCorp keys and then
+converts the builder to the final ``SignedTransaction``. It then does so again, but this time instead of issuing
+it re-assigns ownership instead. The chain of two transactions is finally committed to node A by sending them
+directly to the ``a.services.recordTransaction`` method (note that this method doesn't check the transactions are
+valid) inside a ``databaseTransaction``. All node flows run within a database transaction in the nodes themselves,
+but any time we need to use the database directly from a unit test, you need to provide a database transaction as shown
+here.
+
+And that's it: you can explore the documentation for the `MockNode API `_ here.
diff --git a/docs/build/html/_sources/index.txt b/docs/build/html/_sources/index.txt
index 8da12fa870..112b1043ab 100644
--- a/docs/build/html/_sources/index.txt
+++ b/docs/build/html/_sources/index.txt
@@ -49,6 +49,7 @@ Read on to learn:
persistence
node-administration
corda-configuration-files
+ corda-plugins
node-services
.. toctree::
@@ -67,6 +68,7 @@ Read on to learn:
tutorial-test-dsl
tutorial-clientrpc-api
flow-state-machines
+ flow-testing
oracles
tutorial-attachments
event-scheduling
diff --git a/docs/build/html/_sources/node-administration.txt b/docs/build/html/_sources/node-administration.txt
index 28651bc625..e950131de0 100644
--- a/docs/build/html/_sources/node-administration.txt
+++ b/docs/build/html/_sources/node-administration.txt
@@ -7,11 +7,14 @@ you can upload and download attachments, access a REST API and so on.
Logging
-------
-Logs are stored to the logs subdirectory of the node directory and are rotated from time to time. You can
+In the default configuration logs are stored to the logs subdirectory of the node directory and are rotated from time to time. You can
have logging printed to the console as well by passing the ``--log-to-console`` command line flag. Corda
-uses the log4j2 framework to manage its logging, so you can also configure it in more detail by writing
-a custom logging configuration file and passing ``-Dlog4j.configurationFile=my-config-file.xml`` on the
-command line as well.
+uses the SL4J logging façade which is configured with the log4j2 binding framework to manage its logging,
+so you can also configure it in more detail by writing a custom log4j2 logging configuration file and passing ``-Dlog4j.configurationFile=my-config-file.xml``
+on the command line as well. The default configuration is copied during the build from ``config/dev/log4j2.xml``, or for the test sourceSet from ``config/test/log4j2.xml``.
+
+In corda code a logger is typically instantiated via the ``net.corda.core.utilities.loggerFor`` utility method which will create an SL4J ``Logger`` with a name based on the type parameter.
+Also, available in ``net.corda.core.utilities``, are extension methods to take a lazily evaluated logging lambda for trace and debug level, which will not evaluate the lambda if the LogLevel threshold is higher.
Database access
---------------
diff --git a/docs/build/html/_sources/node-explorer.txt b/docs/build/html/_sources/node-explorer.txt
index 18141dc460..b9152c9d6a 100644
--- a/docs/build/html/_sources/node-explorer.txt
+++ b/docs/build/html/_sources/node-explorer.txt
@@ -34,18 +34,19 @@ Running Demo Nodes
Interface
---------
Login
- User can login to any Corda node using the explorer, alternately, `gradlew explorer:runDemoNodes` can be used to start up demo nodes for testing.
+ User can login to any Corda node using the explorer. Alternatively, ``gradlew explorer:runDemoNodes`` can be used to start up demo nodes for testing.
Corda node address, username and password are required for login, the address is defaulted to localhost:0 if leave blank.
- Username and password can be configured in node's configuration file; for demo nodes, it is defaulted to ``user1`` and ``test``.
-
+ Username and password can be configured via the ``rpcUsers`` field in node's configuration file; for demo nodes, it is defaulted to ``user1`` and ``test``.
+
.. note:: If you are connecting to the demo nodes, only Alice and Bob (20004, 20006) are accessible using user1 credential, you won't be able to connect to the notary.
.. image:: resources/explorer/login.png
:scale: 50 %
:align: center
-Home
- Home view shows the top level state of node and vault; currently, it shows your cash balance and the numbers of transaction executed.
+Dashboard
+ The dashboard shows the top level state of node and vault.
+ Currently, it shows your cash balance and the numbers of transaction executed.
The dashboard is intended to house widgets from different CordApp's and provide useful information to system admin at a glance.
.. image:: resources/explorer/dashboard.png
@@ -56,6 +57,13 @@ Cash
.. image:: resources/explorer/vault.png
+New cash transaction
+ This is where you can create new cash transactions.
+ The user can choose from three transaction types (issue, pay and exit) and any party visible on the network.
+ The result of the transaction will be visible in the transaction screen when executed.
+
+.. image:: resources/explorer/newTransaction.png
+
Transactions
The transaction view contains all transactions handled by the node in a table view. It shows basic information on the table e.g. Transaction ID,
command type, USD equivalence value etc. User can expand the row by double clicking to view the inputs,
@@ -63,9 +71,17 @@ Transactions
.. image:: resources/explorer/transactionView.png
-New Transaction
- This is where you can create new transaction; currently only the cash contract is supported.
- The user can choose from three transaction types (issue, move and exit) and any party visible on the network.
- The result of the transaction will be visible in the transaction screen when executed.
+Network
+ The network view shows the network information on the world map. Currently only the user's node is rendered on the map.
+ This will be extended to other peers in a future release.
+ The map provides a intuitive way of visualizing the Corda network and the participants.
-.. image:: resources/explorer/newTransaction.png
+.. image:: resources/explorer/network.png
+
+
+Settings
+ User can configure the client preference in this view.
+.. note:: Although the reporting currency is configurable, FX conversion won't be applied to the values as we don't have an FX service yet.
+
+
+.. image:: resources/explorer/settings.png
diff --git a/docs/build/html/_sources/tutorial-contract.txt b/docs/build/html/_sources/tutorial-contract.txt
index 63799f2f03..2db18bdf4f 100644
--- a/docs/build/html/_sources/tutorial-contract.txt
+++ b/docs/build/html/_sources/tutorial-contract.txt
@@ -7,28 +7,52 @@
Writing a contract
==================
-This tutorial will take you through how the commercial paper contract works. This uses a simple contract structure of
-everything being in one contract class, while most actual contracts in Corda are broken into clauses (which we'll
-discuss in the next tutorial). Clauses help reduce tedious boilerplate, but it's worth understanding how a
-contract is built without them before starting.
+This tutorial will take you through writing a contract, using a simple commercial paper contract as an example.
+Smart contracts in Corda have three key elements:
-You can see the full Kotlin version of this contract in the code as ``CommercialPaperLegacy``. The code in this
-tutorial is available in both Kotlin and Java. You can quickly switch between them to get a feeling for how
-Kotlin syntax works.
+* Executable code (validation logic)
+* State objects
+* Commands
+
+The core of a smart contract is the executable code which validates changes to state objects in transactions. State
+objects are the data held on the ledger, which represent the current state of an instance of a contract, and are used as
+inputs and outputs of transactions. Commands are additional data included in transactions to describe what is going on,
+used to instruct the executable code on how to verify the transaction. For example an ``Issue`` command may indicate
+that the validation logic should expect to see an output which does not exist as an input, issued by the same entity
+that signed the command.
+
+The first thing to think about with a new contract is the lifecycle of contract states, how are they issued, what happens
+to them after they are issued, and how are they destroyed (if applicable). For the commercial paper contract, states are
+issued by a legal entity which wishes to create a contract to pay money in the future (the maturity date), in return for
+a lesser payment now. They are then transferred (moved) to another owner as part of a transaction where the issuer
+receives funds in payment, and later (after the maturity date) are destroyed (redeemed) by paying the owner the face
+value of the commercial paper.
+
+This lifecycle for commercial paper is illustrated in the diagram below:
+
+.. image:: contract-cp.png
Where to put your code
----------------------
-A CorDapp is a collection of contracts, state definitions, flows and other ways to extend the server. To create
-one you would just create a Java-style project as normal, with your choice of build system (Maven, Gradle, etc).
-Then add a dependency on ``net.corda.core:0.X`` where X is the milestone number you are depending on. The core
-module defines the base classes used in this tutorial.
+A CorDapp is a collection of contracts, state definitions, flows and other ways to extend the Corda platform.
+To create one you would typically clone the CorDapp template project ("cordapp-template"), which provides an example
+structure for the code. Alternatively you can just create a Java-style project as normal, with your choice of build
+system (Maven, Gradle, etc), then add a dependency on ``net.corda.core:0.X`` where X is the milestone number you are
+depending on. The core module defines the base classes used in this tutorial.
Starting the commercial paper class
-----------------------------------
-A smart contract is a class that implements the ``Contract`` interface. This can be either implemented directly, or
-by subclassing an abstract contract such as ``OnLedgerAsset``.
+A smart contract is a class that implements the ``Contract`` interface. This can be either implemented directly, as done
+here, or by subclassing an abstract contract such as ``OnLedgerAsset``. The heart of any contract in Corda is the
+``verify()`` function, which determined whether any given transaction is valid. This example shows how to write a
+``verify()`` function from scratch. A later tutorial will introduce "clauses", which are reusable chunks of verification
+logic, but first it's worth understanding how a contract is built without them.
+
+You can see the full Kotlin version of this contract in the code as ``CommercialPaperLegacy``. The code in this
+tutorial is available in both Kotlin and Java. You can quickly switch between them to get a feeling for how
+Kotlin syntax works.
.. container:: codeset
@@ -71,7 +95,10 @@ piece of issued paper.
States
------
-A state is a class that stores data that is checked by the contract.
+A state is a class that stores data that is checked by the contract. A commercial paper state is structured as below:
+
+.. image:: contract-cp-state.png
+
.. container:: codeset
@@ -174,7 +201,7 @@ A state is a class that stores data that is checked by the contract.
We define a class that implements the ``ContractState`` interface.
The ``ContractState`` interface requires us to provide a ``getContract`` method that returns an instance of the
-contract class itself. In future, this will change to support dynamic loading of contracts with versioning
+contract class itself. In future, this may change to support dynamic loading of contracts with versioning
and signing constraints, but for now this is how it's written.
We have four fields in our state:
@@ -202,8 +229,9 @@ The Java code compiles to almost identical bytecode as the Kotlin version, but a
Commands
--------
-The logic for a contract may vary depending on what stage of a lifecycle it is automating. So it can be useful to
-pass additional data into the contract code that isn't represented by the states which exist permanently in the ledger.
+The validation logic for a contract may vary depending on what stage of a state's lifecycle it is automating. So it can
+be useful to pass additional data into the contract code that isn't represented by the states which exist permanently
+in the ledger, in order to clarify intent of a transaction.
For this purpose we have commands. Often they don't need to contain any data at all, they just need to exist. A command
is a piece of data associated with some *signatures*. By the time the contract runs the signatures have already been
diff --git a/docs/build/html/api/index-outline.html b/docs/build/html/api/index-outline.html
index 95334d55eb..82fb30949b 100644
--- a/docs/build/html/api/index-outline.html
+++ b/docs/build/html/api/index-outline.html
@@ -684,6 +684,7 @@
protected fun parseKeyFromQueueName(name: String): CompositeKey
protected fun tcpTransport(direction: ConnectionDirection, host: String, port: Int): <ERROR CLASS>
fun toHostAndPort(target: MessageRecipients): <ERROR CLASS>
+protected fun toMyAddress(myIdentity: CompositeKey?, myHostPort: <ERROR CLASS>): SingleMessageRecipient
protected fun toQueueName(target: MessageRecipients): <ERROR CLASS>