diff --git a/docs/build/html/_images/public-key-tree-2.png b/docs/build/html/_images/public-key-tree-2.png
new file mode 100644
index 0000000000..5dc70e11e2
Binary files /dev/null and b/docs/build/html/_images/public-key-tree-2.png differ
diff --git a/docs/build/html/_images/public-key-tree.png b/docs/build/html/_images/public-key-tree.png
new file mode 100644
index 0000000000..66909de006
Binary files /dev/null and b/docs/build/html/_images/public-key-tree.png differ
diff --git a/docs/build/html/_sources/clientrpc.txt b/docs/build/html/_sources/clientrpc.txt
index b691610450..63f83845f2 100644
--- a/docs/build/html/_sources/clientrpc.txt
+++ b/docs/build/html/_sources/clientrpc.txt
@@ -15,6 +15,8 @@ detail on how to use this is provided in the docs for the proxy method.
resources. When you're done with it, cast it to ``Closeable`` or ``AutoCloseable`` and close it. Don't create
one for every call you make - create a proxy and reuse it.
+For a brief tutorial on how one can use the RPC API see :doc:`tutorial-clientrpc-api`.
+
Observables
-----------
@@ -72,4 +74,4 @@ The client RPC wire protocol is not currently documented. To use it you must use
This is likely to change in a future release.
.. _CordaRPCClient: api/com.r3corda.client/-corda-r-p-c-client/index.html
-.. _CordaRPCOps: api/com.r3corda.node.services.messaging/-corda-r-p-c-ops.html
+.. _CordaRPCOps: api/com.r3corda.node.services.messaging/-corda-r-p-c-ops/index.html
diff --git a/docs/build/html/_sources/consensus.txt b/docs/build/html/_sources/consensus.txt
index 8b2da03b7d..d0be66fa03 100644
--- a/docs/build/html/_sources/consensus.txt
+++ b/docs/build/html/_sources/consensus.txt
@@ -42,7 +42,7 @@ will not be regarded as confirmed. After the signature is obtained, the parties
Hence it is the point at which we can say finality has occurred.
Multiple notaries
------------------
+~~~~~~~~~~~~~~~~~
More than one notary can exist in the network. This gives the following benefits:
@@ -56,6 +56,32 @@ This is achieved by using a special type of transaction that doesn't modify anyt
Ensuring that all input states point to the same notary is the responsibility of each involved party
(it is another condition for an output state of the transaction to be **valid**)
+Changing notaries
+~~~~~~~~~~~~~~~~~
+
+To change the notary for an input state, use the ``NotaryChangeProtocol``. For example:
+
+.. sourcecode:: kotlin
+
+ @Suspendable
+ fun changeNotary(originalState: StateAndRef,
+ newNotary: Party): StateAndRef {
+ val protocol = NotaryChangeProtocol.Instigator(originalState, newNotary)
+ return subProtocol(protocol)
+ }
+
+The protocol will:
+
+1. Construct a transaction with the old state as the input and the new state as the output
+
+2. Obtain signatures from all *participants* (a participant is any party that is able to consume this state in a valid transaction, as defined by the state itself)
+
+3. Obtain the *old* notary signature
+
+4. Record and distribute the final transaction to the participants so that everyone possesses the new state
+
+.. note:: Eventually this will be handled automatically on demand.
+
Validation
----------
@@ -114,7 +140,7 @@ By creating a range that can be either closed or open at one end, we allow all o
.. note:: It is assumed that the time feed for a notary is GPS/NaviStar time as defined by the atomic
clocks at the US Naval Observatory. This time feed is extremely accurate and available globally for free.
-Running a Notary Service
+Running a notary service
------------------------
At present we have two basic implementations that store committed input states in memory:
@@ -167,28 +193,3 @@ On conflict the ``NotaryProtocol`` with throw a ``NotaryException`` containing t
data class ConsumingTx(val id: SecureHash, val inputIndex: Int, val requestingParty: Party)
Conflict handling and resolution is currently the responsibility of the protocol author.
-
-Changing notaries
------------------
-
-To change the notary for an input state, use the ``NotaryChangeProtocol``. For example:
-
-.. sourcecode:: kotlin
-
- fun changeNotary(originalState: StateAndRef,
- newNotary: Party): StateAndRef {
- val protocol = NotaryChangeProtocol.Instigator(originalState, newNotary)
- return subProtocol(protocol)
- }
-
-The protocol will:
-
-1. Construct a transaction with the old state as the input and the new state as the output
-
-2. Obtain signatures from all *participants* (a participant is any party that is able to consume this state in a valid transaction, as defined by the state itself)
-
-3. Obtain the *old* notary signature
-
-4. Record and distribute the final transaction to the participants so that everyone possesses the new state
-
-.. note:: Eventually this will be handled automatically on demand.
\ No newline at end of file
diff --git a/docs/build/html/_sources/corda-configuration-files.txt b/docs/build/html/_sources/corda-configuration-files.txt
index adc412f0b2..f4111f1073 100644
--- a/docs/build/html/_sources/corda-configuration-files.txt
+++ b/docs/build/html/_sources/corda-configuration-files.txt
@@ -38,7 +38,6 @@ General node configuration file for hosting the IRSDemo services.
}
artemisAddress : "localhost:31337"
webAddress : "localhost:31339"
- hostNotaryServiceLocally: false
extraAdvertisedServiceIds: "corda.interest_rates"
networkMapAddress : "localhost:12345"
useHTTPS : false
@@ -54,7 +53,6 @@ NetworkMapService plus Simple Notary configuration file.
trustStorePassword : "trustpass"
artemisAddress : "localhost:12345"
webAddress : "localhost:12346"
- hostNotaryServiceLocally: true
extraAdvertisedServiceIds: ""
useHTTPS : false
@@ -85,14 +83,15 @@ Configuration File Fields
.. note:: In practice the ArtemisMQ messaging services bind to all local addresses on the specified port. However, note that the host is the included as the advertised entry in the NetworkMapService. As a result the value listed here must be externally accessible when running nodes across a cluster of machines.
+:messagingServerAddress:
+ The address of the ArtemisMQ broker instance. If not provided the node will run one locally.
+
:webAddress:
The host and port on which the node is available for web operations.
.. note:: If HTTPS is enabled then the browser security checks will require that the accessing url host name is one of either the machine name, fully qualified machine name, or server IP address to line up with the Subject Alternative Names contained within the development certificates. This is addition to requiring the ``/config/dev/corda_dev_ca.cer`` root certificate be installed as a Trusted CA.
-:hostNotaryServiceLocally: If true the Node will host and advertise a verifying Notary service.
-
-:extraAdvertisedServiceIds: A list of ServiceType id strings to be advertised to the NetworkMapService and thus be available when other nodes query the NetworkMapCache for supporting nodes. This can also include plugin services loaded from .jar files in the
+:extraAdvertisedServiceIds: A list of ServiceType id strings to be advertised to the NetworkMapService and thus be available when other nodes query the NetworkMapCache for supporting nodes. This can also include plugin services loaded from .jar files in the plugins folder.
:networkMapAddress: If `null`, or missing the node is declaring itself as the NetworkMapService host. Otherwise the configuration value is the remote HostAndPort string for the ArtemisMQ service on the hosting node.
diff --git a/docs/build/html/_sources/creating-a-cordapp.txt b/docs/build/html/_sources/creating-a-cordapp.txt
index 87d2b7b3eb..8f67960851 100644
--- a/docs/build/html/_sources/creating-a-cordapp.txt
+++ b/docs/build/html/_sources/creating-a-cordapp.txt
@@ -75,6 +75,50 @@ To enable remote debugging of the corda process use a command line such as:
This command line will start the debugger on port 5005 and pause the process awaiting debugger attachment.
+Viewing persisted state of your Node
+------------------------------------
+
+To make examining the persisted contract states of your node or the internal node database tables easier, and providing you are
+using the default database configuration used for demos, you should be able to connect to the internal node database over
+a JDBC connection at the URL that is output to the logs at node start up. That URL will be of the form ``jdbc:h2:tcp://:/node``.
+
+The user name and password for the login are as per the node data source configuration.
+
+The name and column layout of the internal node tables is in a state of flux and should not be relied upon to remain static
+at the present time, and should certainly be treated as read-only.
+
.. _CordaPluginRegistry: api/com.r3corda.core.node/-corda-plugin-registry/index.html
.. _ServiceHubInternal: api/com.r3corda.node.services.api/-service-hub-internal/index.html
-.. _ServiceHub: api/com.r3corda.node.services.api/-service-hub/index.html
\ No newline at end of file
+.. _ServiceHub: api/com.r3corda.node.services.api/-service-hub/index.html
+
+Building Against Corda
+----------------------
+
+.. warning:: This feature is subject to rapid change
+
+Corda now supports publishing to Maven local to build against it. To publish to Maven local run the following in the
+root directory of Corda
+
+.. code-block:: shell
+
+ ./gradlew publishToMavenLocal
+
+This will publish corda-$version.jar, contracts-$version.jar, core-$version.jar and node-$version.jar to the
+group com.r3corda. You can now depend on these as you normally would a Maven dependency.
+
+In Gradle you can depend on these by adding/modifying your build.gradle file to contain the following:
+
+.. code-block:: groovy
+
+ repositories {
+ mavenLocal()
+ ... other repositories here ...
+ }
+
+ dependencies {
+ compile "com.r3corda:core:$corda_version"
+ compile "com.r3corda:contracts:$corda_version"
+ compile "com.r3corda:node:$corda_version"
+ compile "com.r3corda:corda:$corda_version"
+ ... other dependencies here ...
+ }
diff --git a/docs/build/html/_sources/index.txt b/docs/build/html/_sources/index.txt
index e1372461c4..54de8d4cf9 100644
--- a/docs/build/html/_sources/index.txt
+++ b/docs/build/html/_sources/index.txt
@@ -34,6 +34,7 @@ Read on to learn:
transaction-data-types
consensus
messaging
+ persistence
creating-a-cordapp
running-the-demos
node-administration
@@ -47,8 +48,10 @@ Read on to learn:
tutorial-contract
tutorial-contract-clauses
tutorial-test-dsl
+ tutorial-clientrpc-api
protocol-state-machines
oracles
+ tutorial-attachments
event-scheduling
secure-coding-guidelines
@@ -74,4 +77,3 @@ Read on to learn:
network-simulator
codestyle
building-the-docs
-
diff --git a/docs/build/html/_sources/node-administration.txt b/docs/build/html/_sources/node-administration.txt
index 32cb71f587..7cf0211341 100644
--- a/docs/build/html/_sources/node-administration.txt
+++ b/docs/build/html/_sources/node-administration.txt
@@ -1,8 +1,23 @@
Node administration
===================
-When a node is running, it exposes an embedded web server that lets you monitor it, upload and download attachments,
-access a REST API and so on.
+When a node is running, it exposes an embedded database server, an embedded web server that lets you monitor it,
+you can upload and download attachments, access a REST API and so on.
+
+Database access
+---------------
+
+The node exposes its internal database over a socket which can be browsed using any tool that can use JDBC drivers.
+The JDBC URL is printed during node startup to the log and will typically look like this:
+
+ ``jdbc:h2:tcp://192.168.0.31:31339/node``
+
+The username and password can be altered in the :doc:`corda-config-files` but default to username "sa" and a blank
+password.
+
+Any database browsing tool that supports JDBC can be used, but if you have IntelliJ Ultimate edition then there is
+a tool integrated with your IDE. Just open the database window and add an H2 data source with the above details.
+You will now be able to browse the tables and row data within them.
Monitoring your node
--------------------
@@ -15,7 +30,7 @@ some monitoring systems provide a "Java Agent", which is essentially a JVM plugi
them out to a statistics collector over the network. For those systems, follow the instructions provided by the vendor.
Sometimes though, you just want raw access to the data and operations itself. So nodes export them over HTTP on the
-`/monitoring/json` HTTP endpoint, using a program called `Jolokia `_. Jolokia defines the JSON
+``/monitoring/json`` HTTP endpoint, using a program called `Jolokia `_. Jolokia defines the JSON
and REST formats for accessing MBeans, and provides client libraries to work with that protocol as well.
Here are a few ways to build dashboards and extract monitoring data for a node:
diff --git a/docs/build/html/_sources/persistence.txt b/docs/build/html/_sources/persistence.txt
new file mode 100644
index 0000000000..ab8163b465
--- /dev/null
+++ b/docs/build/html/_sources/persistence.txt
@@ -0,0 +1,89 @@
+Persistence
+===========
+
+Corda offers developers the option to expose all or some part of a contract state to an *Object Relational Mapping* (ORM) tool
+to be persisted in a RDBMS. The purpose of this is to assist *vault* development by effectively indexing
+persisted contract states held in the vault for the purpose of running queries over them and to allow relational joins
+between Corda data and private data local to the organisation owning a node.
+
+The ORM mapping is specified using the `Java Persistence API `_ (JPA)
+as annotations and is converted to database table rows by the node automatically every time a state is recorded in the
+node's local vault as part of a transaction.
+
+.. note:: Presently the node includes an instance of the H2 database but any database that supports JDBC is a candidate and
+ the node will in the future support a range of database implementations via their JDBC drivers. Much of the node
+ internal state is also persisted there. You can access the internal H2 database via JDBC, please see the info
+ in ":doc:`node-administration`" for details.
+
+Schemas
+-------
+
+Every ``ContractState`` can implement the ``QueryableState`` interface if it wishes to be inserted into the node's local
+database and accessible using SQL.
+
+.. literalinclude:: ../../core/src/main/kotlin/com/r3corda/core/schemas/PersistentTypes.kt
+ :language: kotlin
+ :start-after: DOCSTART QueryableState
+ :end-before: DOCEND QueryableState
+
+The ``QueryableState`` interface requires the state to enumerate the different relational schemas it supports, for instance in
+cases where the schema has evolved, with each one being represented by a ``MappedSchema`` object return by the
+``supportedSchemas()`` method. Once a schema is selected it must generate that representation when requested via the
+``generateMappedObject()`` method which is then passed to the ORM.
+
+Nodes have an internal ``SchemaService`` which decides what to persist and what not by selecting the ``MappedSchema``
+to use.
+
+.. literalinclude:: ../../node/src/main/kotlin/com/r3corda/node/services/api/SchemaService.kt
+ :language: kotlin
+ :start-after: DOCSTART SchemaService
+ :end-before: DOCEND SchemaService
+
+.. literalinclude:: ../../core/src/main/kotlin/com/r3corda/core/schemas/PersistentTypes.kt
+ :language: kotlin
+ :start-after: DOCSTART MappedSchema
+ :end-before: DOCEND MappedSchema
+
+The ``SchemaService`` can be configured by a node administrator to select the schemas used by each app. In this way the
+relational view of ledger states can evolve in a controlled fashion in lock-step with internal systems or other
+integration points and not necessarily with every upgrade to the contract code.
+It can select from the ``MappedSchema`` offered by a ``QueryableState``, automatically upgrade to a
+later version of a schema or even provide a ``MappedSchema`` not originally offered by the ``QueryableState``.
+
+It is expected that multiple different contract state implementations might provide mappings to some common schema.
+For example an Interest Rate Swap contract and an Equity OTC Option contract might both provide a mapping to a common
+Derivative schema. The schemas should typically not be part of the contract itself and should exist independently of it
+to encourage re-use of a common set within a particular business area or Cordapp.
+
+``MappedSchema`` offer a family name that is disambiguated using Java package style name-spacing derived from the class name
+of a *schema family* class that is constant across versions, allowing the ``SchemaService`` to select a preferred version
+of a schema.
+
+The ``SchemaService`` is also responsible for the ``SchemaOptions`` that can be configured for a particular ``MappedSchema``
+which allow the configuration of a database schema or table name prefixes to avoid any clash with other ``MappedSchema``.
+
+.. note:: It is intended that there should be plugin support for the ``SchemaService`` to offer the version upgrading and
+ additional schemas as part of Cordapps, and that the active schemas be confgurable. However the present implementation
+ offers none of this and simply results in all versions of all schemas supported by a ``QueryableState`` being persisted.
+ This will change in due course. Similarly, it does not currently support configuring ``SchemaOptions`` but will do so in
+ the future.
+
+Object Relational Mapping
+-------------------------
+
+The persisted representation of a ``QueryableState`` should be an instance of a ``PersistentState`` subclass, constructed
+either by the state itself or a plugin to the ``SchemaService``. This allows the ORM layer to always associate a
+``StateRef`` with a persisted representation of a ``ContractState`` and allows joining with the set of unconsumed states
+in the vault.
+
+The ``PersistentState`` subclass should be marked up as a JPA 2.1 *Entity* with a defined table name and having
+properties (in Kotlin, getters/setters in Java) annotated to map to the appropriate columns and SQL types. Additional
+entities can be included to model these properties where they are more complex, for example collections, so the mapping
+does not have to be *flat*. The ``MappedSchema`` must provide a list of all of the JPA entity classes for that schema in order
+to initialise the ORM layer.
+
+Several examples of entities and mappings are provided in the codebase, including ``Cash.State`` and
+``CommercialPaper.State``. For example, here's the first version of the cash schema.
+
+.. literalinclude:: ../../contracts/src/main/kotlin/com/r3corda/schemas/CashSchemaV1.kt
+ :language: kotlin
\ No newline at end of file
diff --git a/docs/build/html/_sources/protocol-state-machines.txt b/docs/build/html/_sources/protocol-state-machines.txt
index b5bce9a70b..1da9d0f7cc 100644
--- a/docs/build/html/_sources/protocol-state-machines.txt
+++ b/docs/build/html/_sources/protocol-state-machines.txt
@@ -91,7 +91,7 @@ Our protocol has two parties (B and S for buyer and seller) and will proceed as
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 protocol in the file ``contracts/protocols/TwoPartyTradeProtocol.kt``.
+You can find the implementation of this protocol in the file ``contracts/src/main/kotlin/com/r3corda/protocols/TwoPartyTradeProtocol.kt``.
Assuming no malicious termination, they both end the protocol being in posession of a valid, signed transaction that
represents an atomic asset swap.
@@ -110,7 +110,6 @@ each side.
.. sourcecode:: kotlin
object TwoPartyTradeProtocol {
- val TOPIC = "platform.trade"
class UnacceptablePriceException(val givenPrice: Amount) : Exception("Unacceptable price: $givenPrice")
class AssetMismatchException(val expectedTypeName: String, val typeName: String) : Exception() {
@@ -118,21 +117,20 @@ each side.
}
// This object is serialised to the network and is the first protocol message the seller sends to the buyer.
- class SellerTradeInfo(
+ data class SellerTradeInfo(
val assetForSale: StateAndRef,
- val price: Amount,
- val sellerOwnerKey: PublicKey,
- val sessionID: Long
+ val price: Amount,
+ val sellerOwnerKey: PublicKey
)
- class SignaturesFromSeller(val timestampAuthoritySig: DigitalSignature.WithKey, val sellerSig: DigitalSignature.WithKey)
+ data class SignaturesFromSeller(val sellerSig: DigitalSignature.WithKey,
+ val notarySig: DigitalSignature.LegallyIdentifiable)
open class Seller(val otherSide: Party,
val notaryNode: NodeInfo,
val assetToSell: StateAndRef,
val price: Amount,
val myKeyPair: KeyPair,
- val buyerSessionID: Long,
override val progressTracker: ProgressTracker = Seller.tracker()) : ProtocolLogic() {
@Suspendable
override fun call(): SignedTransaction {
@@ -143,8 +141,7 @@ each side.
open class Buyer(val otherSide: Party,
val notary: Party,
val acceptablePrice: Amount,
- val typeToBuy: Class,
- val sessionID: Long) : ProtocolLogic() {
+ val typeToBuy: Class) : ProtocolLogic() {
@Suspendable
override fun call(): SignedTransaction {
TODO()
@@ -152,25 +149,17 @@ each side.
}
}
-Let's unpack what this code does:
-
-- It defines a several classes nested inside the main ``TwoPartyTradeProtocol`` singleton. Some of the classes
- are simply protocol messages or exceptions. The other two represent the buyer and seller side of the protocol.
-- It defines the "trade topic", which is just a string that namespaces this protocol. The prefix "platform." is reserved
- by Corda, but you can define your own protocol namespaces using standard Java-style reverse DNS notation.
+This code defines several classes nested inside the main ``TwoPartyTradeProtocol`` singleton. Some of the classes are
+simply protocol messages or exceptions. The other two represent the buyer and seller side of the protocol.
Going through the data needed to become a seller, we have:
-- ``otherSide: SingleMessageRecipient`` - the network address of the node with which you are trading.
+- ``otherSide: 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.
- ``price: Amount`` - the agreed on price that the asset is being sold for (without an issuer constraint).
- ``myKeyPair: KeyPair`` - the key pair that controls the asset being sold. It will be used to sign the transaction.
-- ``buyerSessionID: Long`` - a unique number that identifies this trade to the buyer. It is expected that the buyer
- knows that the trade is going to take place and has sent you such a number already.
-
-.. note:: Session IDs will be automatically handled in a future version of the framework.
And for the buyer:
@@ -178,7 +167,6 @@ And for the buyer:
a price less than or equal to this, then the trade will go ahead.
- ``typeToBuy: Class`` - the type of state that is being purchased. This is used to check that the
sell side of the protocol isn't trying to sell us the wrong thing, whether by accident or on purpose.
-- ``sessionID: Long`` - the session ID that was handed to the seller in order to start the protocol.
Alright, so using this protocol shouldn't be too hard: in the simplest case we can just create a Buyer or Seller
with the details of the trade, depending on who we are. We then have to start the protocol in some way. Just
@@ -221,6 +209,27 @@ protocol are checked against a whitelist, which can be extended by apps themselv
The process of starting a protocol 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.
+In a two party protocol only one side is to be manually started using ``ServiceHub.invokeProtocolAsync``. The other side
+has to be registered by its node to respond to the initiating protocol via ``ServiceHubInternal.registerProtocolInitiator``.
+In our example it doesn't matter which protocol 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:
+
+.. container:: codeset
+
+ .. sourcecode:: kotlin
+
+ val services: ServiceHubInternal = TODO()
+
+ services.registerProtocolInitiator(Seller::class) { otherParty ->
+ val notary = services.networkMapCache.notaryNodes[0]
+ val acceptablePrice = TODO()
+ val typeToBuy = TODO()
+ Buyer(otherParty, notary, acceptablePrice, typeToBuy)
+ }
+
+This is telling the buyer node to fire up an instance of ``Buyer`` (the code in the lambda) when the initiating protocol
+is a seller (``Seller::class``).
+
Implementing the seller
-----------------------
@@ -253,12 +262,10 @@ Let's fill out the ``receiveAndCheckProposedTransaction()`` method.
@Suspendable
private fun receiveAndCheckProposedTransaction(): SignedTransaction {
- val sessionID = random63BitValue()
-
// Make the first message we'll send to kick off the protocol.
- val hello = SellerTradeInfo(assetToSell, price, myKeyPair.public, sessionID)
+ val hello = SellerTradeInfo(assetToSell, price, myKeyPair.public)
- val maybeSTX = sendAndReceive(otherSide, buyerSessionID, sessionID, hello)
+ val maybeSTX = sendAndReceive(otherSide, hello)
maybeSTX.unwrap {
// Check that the tx proposed by the buyer is valid.
@@ -281,11 +288,10 @@ Let's fill out the ``receiveAndCheckProposedTransaction()`` method.
}
}
-Let's break this down. We generate a session ID to identify what's happening on the seller side, fill out
-the initial protocol message, and then call ``sendAndReceive``. This function takes a few arguments:
+Let's break this down. We fill out the initial protocol message with the trade info, and then call ``sendAndReceive``.
+This function takes a few arguments:
-- The topic string that ensures the message is routed to the right bit of code in the other side's node.
-- The session IDs that ensure the messages don't get mixed up with other simultaneous trades.
+- The party on the other side.
- The thing to send. It'll be serialised and sent automatically.
- Finally a type argument, which is the kind of object we're expecting to receive from the other side. If we get
back something else an exception is thrown.
@@ -370,7 +376,7 @@ Here's the rest of the code:
notarySignature: DigitalSignature.LegallyIdentifiable): SignedTransaction {
val fullySigned = partialTX + ourSignature + notarySignature
logger.trace { "Built finished transaction, sending back to secondary!" }
- send(otherSide, buyerSessionID, SignaturesFromSeller(ourSignature, notarySignature))
+ send(otherSide, SignaturesFromSeller(ourSignature, notarySignature))
return fullySigned
}
@@ -406,7 +412,7 @@ OK, let's do the same for the buyer side:
val (ptx, cashSigningPubKeys) = assembleSharedTX(tradeRequest)
val stx = signWithOurKeys(cashSigningPubKeys, ptx)
- val signatures = swapSignaturesWithSeller(stx, tradeRequest.sessionID)
+ val signatures = swapSignaturesWithSeller(stx)
logger.trace { "Got signatures from seller, verifying ... " }
@@ -419,16 +425,14 @@ OK, let's do the same for the buyer side:
@Suspendable
private fun receiveAndValidateTradeRequest(): SellerTradeInfo {
- // Wait for a trade request to come in on our pre-provided session ID.
- val maybeTradeRequest = receive(sessionID)
+ // 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}" }
- // Check the start message for acceptability.
- check(it.sessionID > 0)
if (it.price > acceptablePrice)
throw UnacceptablePriceException(it.price)
if (!typeToBuy.isInstance(asset))
@@ -443,13 +447,13 @@ OK, let's do the same for the buyer side:
}
@Suspendable
- private fun swapSignaturesWithSeller(stx: SignedTransaction, theirSessionID: Long): SignaturesFromSeller {
+ 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, theirSessionID, sessionID, stx).unwrap { it }
+ return sendAndReceive(otherSide, stx).unwrap { it }
}
private fun signWithOurKeys(cashSigningPubKeys: List, ptx: TransactionBuilder): SignedTransaction {
@@ -676,7 +680,6 @@ Future features
The protocol framework is a key part of the platform and will be extended in major ways in future. Here are some of
the features we have planned:
-* Automatic session ID management
* Identity based addressing
* Exposing progress trackers to local (inside the firewall) clients using message queues and/or WebSockets
* Exception propagation and management, with a "protocol hospital" tool to manually provide solutions to unavoidable
diff --git a/docs/build/html/_sources/release-notes.txt b/docs/build/html/_sources/release-notes.txt
index 5eabaed1fe..28ca4a2467 100644
--- a/docs/build/html/_sources/release-notes.txt
+++ b/docs/build/html/_sources/release-notes.txt
@@ -3,8 +3,95 @@ Release notes
Here are brief summaries of what's changed between each snapshot release.
-Unreleased
-----------
+Milestone 4
+-----------
+
+New features in this release:
+
+* Persistence:
+
+ * States can now be written into a relational database and queried using JDBC. The schemas are defined by the
+ smart contracts and schema versioning is supported. It is reasonable to write an app that stores data in a mix
+ of global ledger transactions and local database tables which are joined on demand, using join key slots that
+ are present in many state definitions. Read more about :doc:`persistence`.
+ * The embedded H2 SQL database is now exposed by default to any tool that can speak JDBC. The database URL is
+ printed during node startup and can be used to explore the database, which contains both node internal data
+ and tables generated from ledger states.
+ * Protocol checkpoints are now stored in the database as well. Message processing is now atomic with protocol
+ checkpointing and run under the same RDBMS transaction.
+ * MQ message deduplication is now handled at the app layer and performed under the RDMS transaction, so
+ ensuring messages are only replayed if the RDMS transaction rolled back.
+ * "The wallet" has been renamed to "the vault".
+
+* Client RPC:
+
+ * New RPCs added to subscribe to snapshots and update streams state of the vault, currently executing protocols
+ and other important node information.
+ * New tutorial added that shows how to use the RPC API to draw live transaction graphs on screen.
+
+* Protocol framework:
+
+ * Large simplifications to the API. Session management is now handled automatically. Messages are now routed
+ based on identities rather than node IP addresses.
+
+* Decentralised consensus:
+
+ * A standalone one-node notary backed by a JDBC store has been added.
+ * A prototype RAFT based notary composed of multiple nodes is available on a branch.
+
+* Data model:
+
+ * Compound keys have been added as preparation for merging a distributed RAFT based notary. Compound keys
+ are trees of public keys in which interior nodes can have validity thresholds attached, thus allowing
+ boolean formulas of keys to be created. This is similar to Bitcoin's multi-sig support and the data model
+ is the same as the InterLedger Crypto-Conditions spec, which should aid interop in future. Read more about
+ key trees in the ":doc:`transaction-data-types`" article.
+ * A new tutorial has been added showing how to use transaction attachments in more detail.
+
+* Testnet
+
+ * Permissioning infrastructure phase one is built out. The node now has a notion of developer mode vs normal
+ mode. In developer mode it works like M3 and the SSL certificates used by nodes running on your local
+ machine all self-sign using a developer key included in the source tree. When developer mode is not active,
+ the node won't start until it has a signed certificate. Such a certificate can be obtained by simply running
+ an included command line utility which generates a CSR and submits it to a permissioning service, then waits
+ for the signed certificate to be returned. Note that currently there is no public Corda testnet, so we are
+ not currently running a permissioning service.
+
+* Standalone app development:
+
+ * The Corda libraries that app developers need to link against can now be installed into your local Maven
+ repository, where they can then be used like any other JAR. See :doc:`creating-a-cordapp`.
+
+* User interfaces:
+
+ * Infrastructure work on the node explorer is now complete: it is fully switched to using the MQ based RPC system.
+ * A library of additional reactive collections has been added. This API builds on top of Rx and the observable
+ collections API in Java 8 to give "live" data structures in which the state of the node and ledger can be
+ viewed as an ordinary Java ``List``, ``Map`` and ``Set``, but which also emit callbacks when these views
+ change, and which can have additional views derived in a functional manner (filtered, mapped, sorted, etc).
+ Finally, these views can then be bound directly into JavaFX UIs. This makes for a concise and functional
+ way of building application UIs that render data from the node, and the API is available for third party
+ app developers to use as well. We believe this will be highly productive and enjoyable for developers who
+ have the option of building JavaFX apps (vs web apps).
+ * The visual network simulator tool that was demoed back in April as part of the first Corda live demo has
+ been merged into the main repository.
+
+* Documentation
+
+ * New secure coding guidelines. Corda tries to eliminate as many security mistakes as practical via the type
+ system and other mechanically checkable processes, but there are still things that one must be aware of.
+ * New attachments tutorial.
+ * New Client RPC tutorial.
+ * More tutorials on how to build a standalone CorDapp.
+
+* Testing
+
+ * More integration testing support
+ * New micro-DSLs for expressing expected sequences of operations with more or less relaxed ordering constraints.
+ * QuickCheck generators to create streams of randomised transactions and other basic types. QuickCheck is a way
+ of writing unit tests that perform randomised fuzz testing of code, originally developed by the Haskell
+ community and now also available in Java.
API changes:
@@ -15,6 +102,8 @@ API changes:
* The ``UntrustworthyData.validate`` method has been renamed to ``unwrap`` - the old name is now deprecated.
* The wallet, wallet service, etc. are now vault, vault service, etc. These better reflect the intent that they
are a generic secure data store, rather than something which holds cash.
+* The protocol send/receive APIs have changed to no longer require a session id. Please check the current version
+ of the protocol framework tutorial for more details.
Milestone 3
-----------
@@ -49,7 +138,7 @@ Milestone 2
* Big improvements to the interest rate swap app:
- * A new web app demonstrating the IRS contract has been added. This can x``be used as an example for how to interact with
+ * A new web app demonstrating the IRS contract has been added. This can be used as an example for how to interact with
the Corda API from the web.
* Simplifications to the way the demo is used from the command line.
* :doc:`Detailed documentation on how the contract works and can be used ` has been written.
diff --git a/docs/build/html/_sources/running-the-demos.txt b/docs/build/html/_sources/running-the-demos.txt
index 1544f58e13..3d87db6e32 100644
--- a/docs/build/html/_sources/running-the-demos.txt
+++ b/docs/build/html/_sources/running-the-demos.txt
@@ -143,4 +143,34 @@ Now open your web browser to this URL:
To use the demos click the "Create Deal" button, fill in the form, then click the "Submit" button. Now you will be
able to use the time controls at the top left of the home page to run the fixings. Click any individual trade in the
-blotter to view it.
\ No newline at end of file
+blotter to view it.
+
+
+
+Attachment demo
+----------------
+
+Open two terminals, and in the first run:
+
+**Windows**::
+
+ gradlew.bat & .\build\install\r3prototyping\bin\attachment-demo --role=RECIPIENT
+
+**Other**::
+
+ ./gradlew installDist && ./build/install/r3prototyping/bin/attachment-demo --role=RECIPIENT
+
+It will compile things, if necessary, then create a directory named attachment-demo/buyer with a bunch of files inside and
+start the node. You should see it waiting for a trade to begin.
+
+In the second terminal, run:
+
+**Windows**::
+
+ .\build\install\r3prototyping\bin\attachment-demo --role=SENDER
+
+**Other**::
+
+ ./build/install/r3prototyping/bin/attachment-demo --role=SENDER
+
+You should see some log lines scroll past, and within a few seconds the message "File received - we're happy!" should be printed.
diff --git a/docs/build/html/_sources/secure-coding-guidelines.txt b/docs/build/html/_sources/secure-coding-guidelines.txt
index afa6e5b2e3..d3c9e26d4a 100644
--- a/docs/build/html/_sources/secure-coding-guidelines.txt
+++ b/docs/build/html/_sources/secure-coding-guidelines.txt
@@ -1,5 +1,5 @@
Secure coding guidelines
-------------------------
+========================
The platform does what it can to be secure by default and safe by design. Unfortunately the platform cannot
prevent every kind of security mistake. This document describes what to think about when writing applications
diff --git a/docs/build/html/_sources/transaction-data-types.txt b/docs/build/html/_sources/transaction-data-types.txt
index 9b179df7c5..18bbd8f1cb 100644
--- a/docs/build/html/_sources/transaction-data-types.txt
+++ b/docs/build/html/_sources/transaction-data-types.txt
@@ -145,6 +145,40 @@ that has been signed by a set of parties.
.. note:: These types are provisional and will change significantly in future as the identity framework becomes more
fleshed out.
+Multi-signature support
+-----------------------
+
+Corda supports scenarios where more than one key or party is required to authorise a state object transition, for example:
+"Either the CEO or 3 out of 5 of his assistants need to provide signatures".
+
+Key Trees
+^^^^^^^^^
+
+This is achieved by public key composition, using a tree data structure ``PublicKeyTree``. A ``PublicKeyTree`` stores the
+cryptographic public key primitives in its leaves and the composition logic in the intermediary nodes. Every intermediary
+node specifies a *threshold* of how many child signatures it requires.
+
+An illustration of an *"either Alice and Bob, or Charlie"* public key tree:
+
+.. image:: resources/public-key-tree.png
+:width: 300px
+
+To allow further flexibility, each child node can have an associated custom *weight* (the default is 1). The *threshold*
+then specifies the minimum total weight of all children required. Our previous example can also be expressed as:
+
+.. image:: resources/public-key-tree-2.png
+:width: 300px
+
+Verification
+^^^^^^^^^^^^
+
+Signature verification is performed in two stages:
+
+ 1. Given a list of signatures, each signature is verified against the expected content.
+ 2. The public keys corresponding to the signatures are matched against the leaves of the public key tree in question,
+ and the total combined weight of all children is calculated for every intermediary node. If all thresholds are satisfied,
+ the public key tree requirement is considered to be met.
+
Date support
------------
diff --git a/docs/build/html/_sources/tutorial-attachments.txt b/docs/build/html/_sources/tutorial-attachments.txt
new file mode 100644
index 0000000000..5f503d5ab2
--- /dev/null
+++ b/docs/build/html/_sources/tutorial-attachments.txt
@@ -0,0 +1,99 @@
+.. highlight:: kotlin
+.. raw:: html
+
+Using attachments
+=================
+
+Attachments are (typically large) Zip/Jar files referenced within a transaction, but not included in the transaction
+itself. These files can be requested from the originating node as needed, although in many cases will be cached within
+nodes already. Examples include:
+
+* Contract executable code
+* Metadata about a transaction, such as PDF version of an invoice being settled
+* Shared information to be permanently recorded on the ledger
+
+To add attachments the file must first be added to the node's storage service using ``StorageService.importAttachment()``,
+which returns a unique ID that can be added using ``TransactionBuilder.addAttachment()``. Attachments can also be
+uploaded and downloaded via HTTP, to enable integration with external systems. For instructions on HTTP upload/download
+please see ":doc:`node-administration`".
+
+Normally attachments on transactions are fetched automatically via the ``ResolveTransactionsProtocol`` when verifying
+received transactions. Attachments are needed in order to validate a transaction (they include, for example, the
+contract code), so must be fetched before the validation process can run. ``ResolveTransactionsProtocol`` calls
+``FetchTransactionsProtocol`` to perform the actual retrieval.
+
+It is encouraged that where possible attachments are reusable data, so that nodes can meaningfully cache them.
+
+Attachments demo
+----------------
+
+There is a worked example of attachments, which relays a simple document from one node to another. The "two party
+trade protocol" also includes an attachment, however it is a significantly more complex demo, and less well suited
+for a tutorial.
+
+The demo code is in the file "src/main/kotlin/com/r3corda/demos/attachment/AttachmentDemo.kt", with the core logic
+contained within the two functions ``runRecipient()`` and ``runSender()``. We'll look at the recipient function first;
+this subscribes to notifications of new validated transactions, and if it receives a transaction containing attachments,
+loads the first attachment from storage, and checks it matches the expected attachment ID. ``ResolveTransactionsProtocol``
+has already fetched all attachments from the remote node, and as such the attachments are available from the node's
+storage service. Once the attachment is verified, the node shuts itself down.
+
+.. sourcecode:: kotlin
+
+ private fun runRecipient(node: Node) {
+ val serviceHub = node.services
+
+ // Normally we would receive the transaction from a more specific protocol, but in this case we let [FinalityProtocol]
+ // handle receiving it for us.
+ serviceHub.storageService.validatedTransactions.updates.subscribe { event ->
+ // When the transaction is received, it's passed through [ResolveTransactionsProtocol], which first fetches any
+ // attachments for us, then verifies the transaction. As such, by the time it hits the validated transaction store,
+ // we have a copy of the attachment.
+ val tx = event.tx
+ if (tx.attachments.isNotEmpty()) {
+ val attachment = serviceHub.storageService.attachments.openAttachment(tx.attachments.first())
+ assertEquals(PROSPECTUS_HASH, attachment?.id)
+
+ println("File received - we're happy!\n\nFinal transaction is:\n\n${Emoji.renderIfSupported(event.tx)}")
+ thread {
+ node.stop()
+ }
+ }
+ }
+ }
+
+The sender correspondingly builds a transaction with the attachment, then calls ``FinalityProtocol`` to complete the
+transaction and send it to the recipient node:
+
+
+.. sourcecode:: kotlin
+
+ private fun runSender(node: Node, otherSide: Party) {
+ val serviceHub = node.services
+ // Make sure we have the file in storage
+ if (serviceHub.storageService.attachments.openAttachment(PROSPECTUS_HASH) == null) {
+ com.r3corda.demos.Role::class.java.getResourceAsStream("bank-of-london-cp.jar").use {
+ val id = node.storage.attachments.importAttachment(it)
+ assertEquals(PROSPECTUS_HASH, id)
+ }
+ }
+
+ // Create a trivial transaction that just passes across the attachment - in normal cases there would be
+ // inputs, outputs and commands that refer to this attachment.
+ val ptx = TransactionType.General.Builder(notary = null)
+ ptx.addAttachment(serviceHub.storageService.attachments.openAttachment(PROSPECTUS_HASH)!!.id)
+
+ // Despite not having any states, we have to have at least one signature on the transaction
+ ptx.signWith(ALICE_KEY)
+
+ // Send the transaction to the other recipient
+ val tx = ptx.toSignedTransaction()
+ serviceHub.startProtocol(LOG_SENDER, FinalityProtocol(tx, emptySet(), setOf(otherSide))).success {
+ thread {
+ Thread.sleep(1000L) // Give the other side time to request the attachment
+ node.stop()
+ }
+ }.failure {
+ println("Failed to relay message ")
+ }
+ }
\ No newline at end of file
diff --git a/docs/build/html/_sources/tutorial-clientrpc-api.txt b/docs/build/html/_sources/tutorial-clientrpc-api.txt
new file mode 100644
index 0000000000..dad8d13fc0
--- /dev/null
+++ b/docs/build/html/_sources/tutorial-clientrpc-api.txt
@@ -0,0 +1,83 @@
+.. _graphstream: http://graphstream-project.org/
+
+Client RPC API
+==============
+
+In this tutorial we will build a simple command line utility that connects to a node and dumps the transaction graph to
+the standard output. We will then put some simple visualisation on top. For an explanation on how the RPC works see
+:doc:`clientrpc`.
+
+We start off by connecting to the node itself. For the purposes of the tutorial we will run the Trader demo on some
+local port and connect to the Buyer side. We will pass in the address as a command line argument. To connect to the node
+we also need to access the certificates of the node, we will access the node's ``certificates`` directory directly.
+
+.. literalinclude:: example-code/src/main/kotlin/com/r3corda/docs/ClientRpcTutorial.kt
+ :language: kotlin
+ :start-after: START 1
+ :end-before: END 1
+
+Now we can connect to the node itself:
+
+.. literalinclude:: example-code/src/main/kotlin/com/r3corda/docs/ClientRpcTutorial.kt
+ :language: kotlin
+ :start-after: START 2
+ :end-before: END 2
+
+``proxy`` now exposes the full RPC interface of the node:
+
+.. literalinclude:: ../../node/src/main/kotlin/com/r3corda/node/services/messaging/CordaRPCOps.kt
+ :language: kotlin
+ :start-after: interface CordaRPCOps
+ :end-before: }
+
+The one we need in order to dump the transaction graph is ``verifiedTransactions``. The type signature tells us that the
+RPC 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.
+
+.. literalinclude:: example-code/src/main/kotlin/com/r3corda/docs/ClientRpcTutorial.kt
+ :language: kotlin
+ :start-after: START 3
+ :end-before: END 3
+
+The graph will be defined by nodes and edges between them. Each node represents a transaction and edges represent
+output-input relations. For now let's just print ``NODE `` for the former and ``EDGE `` for the
+latter.
+
+.. literalinclude:: example-code/src/main/kotlin/com/r3corda/docs/ClientRpcTutorial.kt
+ :language: kotlin
+ :start-after: START 4
+ :end-before: END 4
+
+Now we can start the trader demo as per described in :doc:`running-the-demos`::
+
+ # Build the demo
+ ./gradlew installDist
+ # Start the buyer
+ ./build/install/r3prototyping/bin/trader-demo --role=BUYER
+
+In another terminal we can connect to it with our client::
+
+ # Connect to localhost:31337
+ ./docs/source/example-code/build/install/docs/source/example-code/bin/client-rpc-tutorial localhost:31337 Print
+
+We should see some ``NODE``-s printed. This is because the buyer self-issues some cash for the demo.
+Unless we ran the seller before we shouldn't see any ``EDGE``-s because the cash hasn't been spent yet.
+
+In another terminal we can now start the seller::
+
+ # Start sellers in a loop
+ for i in {0..9} ; do ./build/install/r3prototyping/bin/trader-demo --role=SELLER ; done
+
+We should start seeing new ``NODE``-s and ``EDGE``-s appearing.
+
+Now let's try to visualise the transaction graph. We will use a graph drawing library called graphstream_
+
+.. literalinclude:: example-code/src/main/kotlin/com/r3corda/docs/ClientRpcTutorial.kt
+ :language: kotlin
+ :start-after: START 5
+ :end-before: END 5
+
+If we run the client with ``Visualise`` we should see a simple graph being drawn as new transactions are being created
+by the seller runs.
+
+That's it! We saw how to connect to the node and stream data from it.
diff --git a/docs/build/html/api/alltypes/index.html b/docs/build/html/api/alltypes/index.html
index bd7b8b236a..c664978d66 100644
--- a/docs/build/html/api/alltypes/index.html
+++ b/docs/build/html/api/alltypes/index.html
@@ -214,6 +214,14 @@ properties loaded from the attachments. And perhaps the authenticated user for
AssociatedList creates an ObservableMap from an ObservableList by associating each list element with a unique key.
+It is not allowed to have several elements map to the same value
An attachment is a ZIP (or an optionally signed JAR) that contains one or more files. Attachments are meant to
@@ -331,6 +339,21 @@ the same transaction.
First version of a commercial paper contract ORM schema that maps all fields of the CommercialPaper contract state
+as it stood at the time of writing.
Class representing a commodity, as an equivalent to the Currency class. This exists purely to enable the
@@ -492,6 +530,14 @@ internal accounting by the issuer (it might be, for example, a warehouse and/or
Primary purpose is to install Kotlin extensions for Jackson ObjectMapper so data classes work
@@ -500,6 +546,12 @@ and to organise serializers / deserializers for java.time.* classes as necessary
RPC operations that the node exposes to clients using the Java client library. These can be called from
client apps and are implemented by the node in the ServerRPCOps class.
@@ -605,6 +657,13 @@ client apps and are implemented by the node in the ServerRPCOps
A wrapper around a digital signature. The covering field is a generic tag usable by whatever is interpreting the
@@ -694,16 +747,6 @@ building partially signed transactions.
A message which specifies reply destination as a specific endpoint such as a monitoring client. This is of particular
-use where we want to address a specific endpoint, not necessarily a specific user (for example if the same user logs
-in on two machines, we want to consistently deliver messages as part of a session, to the same machine the session
-started on).
-
-
-
-
kotlin.Double (extensions in package com.r3corda.core.contracts)
@@ -884,6 +927,13 @@ attachments are saved to local storage automatically.
This is a temporary handler required for establishing random sessionIDs for the Fixer and Floater as part of
+
This is a temporary handler required for establishing random sessionIDs for the Fixer and Floater as part of
running scheduled fixings for the InterestRateSwap contract.
@@ -1015,12 +1065,6 @@ container), shares of the same class in a specific company are fungible and coun
A Handshake message is sent to initiate communication between two protocol instances. It contains the two session IDs
-the two protocols will need to communicate.
-Note: This is a temperary interface and will be removed once the protocol session work is implemented.
+
A vault observer that extracts Object Relational Mappings for contract states that support it, and persists them with Hibernate.
@@ -1137,6 +1173,13 @@ set via the constructor and the class is immutable.
This is a variant of EasyBind.map where the mapped list is backed, therefore the mapping function will only be run
+when an element is inserted or updated.
+Use this instead of EasyBind.map to trade off memory vs CPU, or if (god forbid) the mapped function is side-effecting.
A database schema that might be configured for this node. As well as a name and version for identifying the schema,
+also list the classes that may be used in the generated object graph in order to configure the ORM tool.
Service which allows external clients to monitor the nodes vault and state machine manager, as well as trigger
-actions within the node. The service also sends requests for user input back to clients, for example to enter
-additional information while a protocol runs, or confirm an action.
+
This model exposes raw event streams to and from the node.
@@ -1691,6 +1759,13 @@ that also encompasses the Vault observer for processing transact
Currently, the node vault service is a very simple RDBMS backed implementation. It will change significantly when
@@ -1784,6 +1859,12 @@ to be netted/merged, with settlement only for any remainder amount.
PartiallyResolvedTransaction holds a SignedTransaction that has zero or more inputs resolved. The intent is
+to prepare clients for cases where an input can only be resolved in the future/cannot be resolved at all (for example
+because of permissioning)
A super class for all mapped states exported to a schema that ensures the StateRef appears on the database row. The
+StateRef will be set to the correct value by the framework (theres no need to set during mapping generation by the state itself).
The interface of ProtocolStateMachineImpl exposing methods and properties required by ProtocolLogic for compilation.
+
A ProtocolStateMachine instance is a suspendable fiber that delegates all actual logic to a ProtocolLogic instance.
+For any given flow there is only one PSM, even if that protocol invokes subprotocols.
A ProtocolStateMachine instance is a suspendable fiber that delegates all actual logic to a ProtocolLogic instance.
-For any given flow there is only one PSM, even if that protocol invokes subprotocols.
@@ -2054,12 +2170,34 @@ For any given flow there is only one PSM, even if that protocol invokes subproto
Container for a cryptographically secure hash value.
@@ -2279,6 +2434,13 @@ Provides utilities for generating a cryptographic hash using different algorithm
Information for an advertised service including the service specific identity information.
+The identity can be used in protocols and is distinct from the Nodes legalIdentity
A service hub simply vends references to the other services a node has. Some of those services may be missing or
@@ -2371,17 +2541,16 @@ functionality and you dont want to hard-code which types in the interface.
A StateMachineManager is responsible for coordination and persistence of multiple ProtocolStateMachine objects.
@@ -2487,12 +2668,38 @@ Each such object represents an instantiation of a (two-party) protocol that has
This is the interface to storage storing state machine -> recorded tx mappings. Any time a transaction is recorded
+during a protocol run addMapping should be called.
A stateref is a pointer (reference) to a state, this is an equivalent of an "outpoint" in Bitcoin. It records which
@@ -2501,6 +2708,12 @@ transaction defined the state and where in that transaction it was.
Changes done to elements of the input list are reflected in the observable list of the respective group, whereas
additions/removals of elements in the underlying list are reflected in the exposed ObservableList<A> by
adding/deleting aggregations as expected.
-
The ordering of the exposed list is based on the hashCode of keys.
+
The ordering of the exposed list is based on the hashCode of keys.
+The ordering of the groups themselves is based on the hashCode of elements.
+
Warning: If there are two elements E in the source list that have the same hashCode then it is not deterministic
+which one will be removed if one is removed from the source list
Example:
val statesGroupedByCurrency = AggregatedList(states, { state -> state.currency }) { currency, group ->
object {
diff --git a/docs/build/html/api/com.r3corda.client.fxutils/-aggregated-list/index.html b/docs/build/html/api/com.r3corda.client.fxutils/-aggregated-list/index.html
index f84492aa58..42f9902162 100644
--- a/docs/build/html/api/com.r3corda.client.fxutils/-aggregated-list/index.html
+++ b/docs/build/html/api/com.r3corda.client.fxutils/-aggregated-list/index.html
@@ -7,13 +7,16 @@
com.r3corda.client.fxutils / AggregatedList
AggregatedList
-class AggregatedList<A, E, K:Any>:TransformationList<A,E>
+class AggregatedList<A, E:Any, K:Any>:TransformationList<A,E>
Given an ObservableList<E> and a grouping key K, AggregatedList groups the elements by the key into a fresh
ObservableList<E> for each group and exposes the groups as an observable list of As by calling assemble on each.
Changes done to elements of the input list are reflected in the observable list of the respective group, whereas
additions/removals of elements in the underlying list are reflected in the exposed ObservableList<A> by
adding/deleting aggregations as expected.
-
The ordering of the exposed list is based on the hashCode of keys.
+
The ordering of the exposed list is based on the hashCode of keys.
+The ordering of the groups themselves is based on the hashCode of elements.
+
Warning: If there are two elements E in the source list that have the same hashCode then it is not deterministic
+which one will be removed if one is removed from the source list
Example:
val statesGroupedByCurrency = AggregatedList(states, { state -> state.currency }) { currency, group ->
object {
@@ -102,9 +105,30 @@ TODO Should we handle this case? It requires additional bookkeeping of sourceInd
AssociatedList creates an ObservableMap from an ObservableList by associating each list element with a unique key.
+It is not allowed to have several elements map to the same value
+
Parameters
+
+sourceList - The source list.
+
+
+toKey - Function returning the key.
+
+
+assemble - The function to assemble the final map element from the list element and the associated key.
+
+
+
+
diff --git a/docs/build/html/api/com.r3corda.client.fxutils/-associated-list/index.html b/docs/build/html/api/com.r3corda.client.fxutils/-associated-list/index.html
new file mode 100644
index 0000000000..e08292d15c
--- /dev/null
+++ b/docs/build/html/api/com.r3corda.client.fxutils/-associated-list/index.html
@@ -0,0 +1,148 @@
+
+
+AssociatedList -
+
+
+
+com.r3corda.client.fxutils / AssociatedList
+
+
AssociatedList creates an ObservableMap from an ObservableList by associating each list element with a unique key.
+It is not allowed to have several elements map to the same value
+
Parameters
+
+sourceList - The source list.
+
+
+toKey - Function returning the key.
+
+
+assemble - The function to assemble the final map element from the list element and the associated key.
+
+
+
AssociatedList creates an ObservableMap from an ObservableList by associating each list element with a unique key.
+It is not allowed to have several elements map to the same value
+
+protectedfun sourceChanged(change:Change<outObservableList<A>>): Unit
+
+
+
+
diff --git a/docs/build/html/api/com.r3corda.client.fxutils/-flattened-list/index.html b/docs/build/html/api/com.r3corda.client.fxutils/-flattened-list/index.html
index 62f1f3d6b8..a7e4a8baf6 100644
--- a/docs/build/html/api/com.r3corda.client.fxutils/-flattened-list/index.html
+++ b/docs/build/html/api/com.r3corda.client.fxutils/-flattened-list/index.html
@@ -90,9 +90,30 @@ are reflected in the exposed list as expected.
+
+sourceMap - The source map.
+
+
+assemble - The function to be called for map each entry to construct the final list elements.
+
+
+
+
diff --git a/docs/build/html/api/com.r3corda.client.fxutils/-map-values-list/index.html b/docs/build/html/api/com.r3corda.client.fxutils/-map-values-list/index.html
new file mode 100644
index 0000000000..b1bc4bd2d7
--- /dev/null
+++ b/docs/build/html/api/com.r3corda.client.fxutils/-map-values-list/index.html
@@ -0,0 +1,159 @@
+
+
+MapValuesList -
+
+
+
+com.r3corda.client.fxutils / MapValuesList
+
+
MapValuesList
+class MapValuesList<K, A, C>:ObservableList<C>
+
MapValuesList takes an ObservableMap and returns its values as an ObservableList.
+The order of returned elements is deterministic but unspecified.
This is a variant of EasyBind.map where the mapped list is backed, therefore the mapping function will only be run
+when an element is inserted or updated.
+Use this instead of EasyBind.map to trade off memory vs CPU, or if (god forbid) the mapped function is side-effecting.
This is a variant of EasyBind.map where the mapped list is backed, therefore the mapping function will only be run
+when an element is inserted or updated.
+Use this instead of EasyBind.map to trade off memory vs CPU, or if (god forbid) the mapped function is side-effecting.
This is a variant of EasyBind.map where the mapped list is backed, therefore the mapping function will only be run
+when an element is inserted or updated.
+Use this instead of EasyBind.map to trade off memory vs CPU, or if (god forbid) the mapped function is side-effecting.
+openclass ReadOnlyBackedObservableMapBase<K, A, B>:ObservableMap<K,A>
+
ReadOnlyBackedObservableMapBase is a base class implementing all abstract functions required for an ObservableMap
+using a backing HashMap that subclasses should modify.
+
Non-read-only API calls throw.
+
+
+
Parameters
+
+K - The key type.
+
+
+A - The exposed map element type.
+
+
+B - Auxiliary data subclasses may wish to store in the backing map.
+
+
+
ReadOnlyBackedObservableMapBase is a base class implementing all abstract functions required for an ObservableMap
+using a backing HashMap that subclasses should modify.
AssociatedList creates an ObservableMap from an ObservableList by associating each list element with a unique key.
+It is not allowed to have several elements map to the same value
fun <A, B, C><ERROR CLASS><A>.foldToObservableList(initialAccumulator:C, folderFun:(A,C,ObservableList<B>)->C): ObservableList<B>
+
foldToObservableList takes an rx.Observable stream and creates an ObservableList out of it, while maintaining
+an accumulator.
+
Parameters
+
+initialAccumulator - The initial value of the accumulator.
+
+
+folderFun - The transformation function to be called on the observable list when a new element is emitted on
+the stream, which should modify the list as needed.
foldToObservableMap takes an rx.Observable stream and creates an ObservableMap out of it, while maintaining
+an accumulator.
+
Parameters
+
+initialAccumulator - The initial value of the accumulator.
+
+
+folderFun - The transformation function to be called on the observable map when a new element is emitted on
+the stream, which should modify the map as needed.
+
+
+
diff --git a/docs/build/html/api/com.r3corda.client.fxutils/fold-to-observable-map.html b/docs/build/html/api/com.r3corda.client.fxutils/fold-to-observable-map.html
new file mode 100644
index 0000000000..a743509bc3
--- /dev/null
+++ b/docs/build/html/api/com.r3corda.client.fxutils/fold-to-observable-map.html
@@ -0,0 +1,24 @@
+
+