mirror of
https://github.com/corda/corda.git
synced 2025-06-12 20:28:18 +00:00
Merge branch 'master' into wn-redo-node-conf-docs
This commit is contained in:
committed by
GitHub
commit
2f18ce9440
@ -230,6 +230,25 @@ The contract attachment non-downgrade rule is enforced in two locations:
|
||||
A version number is stored in the manifest information of the enclosing JAR file. This version identifier should be a whole number starting
|
||||
from 1. This information should be set using the Gradle cordapp plugin, or manually, as described in :doc:`versioning`.
|
||||
|
||||
|
||||
Uniqueness requirement Contract and Version for Signature Constraint
|
||||
--------------------------------------------------------------------
|
||||
|
||||
CorDapps in Corda 4 may be signed (to use new signature constraints functionality) or unsigned, and versioned.
|
||||
The following controls are enforced for these different types of jars within the attachment store of a node:
|
||||
|
||||
- Signed contract JARs must be uniquely versioned per contract class (or group of).
|
||||
At runtime the node will throw a `DuplicateContractClassException`` exception if this condition is violated.
|
||||
|
||||
- Unsigned contract JARs: there should not exist multiple instances of the same contract jar.
|
||||
When a whitelisted JARs is imported and it doesn't contain a version number, the version will be copied from the position (counting from 1)
|
||||
of this JAR in the whilelist. The same JAR can be present in many lists (if it contains many contracts),
|
||||
in such case the version will be equal to the highest position of the JAR in all lists.
|
||||
The new whitelist needs to be distributed to the node before the JAR is imported, otherwise it will receive default version.
|
||||
At run-time the node will warn of duplicates encountered.
|
||||
The most recent version given by insertionDate into the attachment storage will be used upon transaction building/resolution.
|
||||
|
||||
|
||||
Issues when using the HashAttachmentConstraint
|
||||
----------------------------------------------
|
||||
|
||||
@ -311,70 +330,6 @@ For example:
|
||||
For Contracts that are annotated with ``@NoConstraintPropagation``, the platform requires that the Transaction Builder specifies
|
||||
an actual constraint for the output states (the ``AutomaticPlaceholderConstraint`` can't be used) .
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
Since all tests involving transactions now require attachments it is also required to load the correct attachments
|
||||
for tests. Unit test environments in JVM ecosystems tend to use class directories rather than JARs, and so CorDapp JARs
|
||||
typically aren't built for testing. Requiring this would add significant complexity to the build systems of Corda
|
||||
and CorDapps, so the test suite has a set of convenient functions to generate CorDapps from package names or
|
||||
to specify JAR URLs in the case that the CorDapp(s) involved in testing already exist. You can also just use
|
||||
``AlwaysAcceptAttachmentConstraint`` in your tests to disable the constraints mechanism.
|
||||
|
||||
MockNetwork/MockNode
|
||||
********************
|
||||
|
||||
The simplest way to ensure that a vanilla instance of a MockNode generates the correct CorDapps is to use the
|
||||
``cordappPackages`` constructor parameter (Kotlin) or the ``setCordappPackages`` method on ``MockNetworkParameters`` (Java)
|
||||
when creating the MockNetwork. This will cause the ``AbstractNode`` to use the named packages as sources for CorDapps. All files
|
||||
within those packages will be zipped into a JAR and added to the attachment store and loaded as CorDapps by the
|
||||
``CordappLoader``.
|
||||
|
||||
An example of this usage would be:
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
class SomeTestClass {
|
||||
MockNetwork network = null;
|
||||
|
||||
@Before
|
||||
void setup() {
|
||||
network = new MockNetwork(new MockNetworkParameters().setCordappPackages(Arrays.asList("com.domain.cordapp")))
|
||||
}
|
||||
|
||||
... // Your tests go here
|
||||
}
|
||||
|
||||
|
||||
MockServices
|
||||
************
|
||||
|
||||
If your test uses a ``MockServices`` directly you can instantiate it using a constructor that takes a list of packages
|
||||
to use as CorDapps using the ``cordappPackages`` parameter.
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
MockServices mockServices = new MockServices(Arrays.asList("com.domain.cordapp"))
|
||||
|
||||
However - there is an easier way! If your unit tests are in the same package as the contract code itself, then you
|
||||
can use the no-args constructor of ``MockServices``. The package to be scanned for CorDapps will be the same as the
|
||||
the package of the class that constructed the object. This is a convenient default.
|
||||
|
||||
Driver
|
||||
******
|
||||
|
||||
The driver takes a parameter called ``extraCordappPackagesToScan`` which is a list of packages to use as CorDapps.
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
driver(new DriverParameters().setExtraCordappPackagesToScan(Arrays.asList("com.domain.cordapp"))) ...
|
||||
|
||||
Full Nodes
|
||||
**********
|
||||
|
||||
When testing against full nodes simply place your CorDapp into the cordapps directory of the node.
|
||||
|
||||
Debugging
|
||||
---------
|
||||
If an attachment constraint cannot be resolved, a ``MissingContractAttachments`` exception is thrown. There are two
|
||||
|
@ -1,3 +1,9 @@
|
||||
.. highlight:: kotlin
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/codesets.js"></script>
|
||||
|
||||
API: Core types
|
||||
===============
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
.. highlight:: kotlin
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/codesets.js"></script>
|
||||
|
||||
API: Identity
|
||||
=============
|
||||
|
||||
|
@ -9,24 +9,26 @@ API: Persistence
|
||||
|
||||
.. contents::
|
||||
|
||||
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.
|
||||
Corda offers developers the option to expose all or some parts of a contract state to an *Object Relational Mapping*
|
||||
(ORM) tool to be persisted in a *Relational Database Management System* (RDBMS).
|
||||
|
||||
The ORM mapping is specified using the `Java Persistence API <https://en.wikipedia.org/wiki/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.
|
||||
The purpose of this, is to assist `vault <https://docs.corda.net/vault.html>`_
|
||||
development and allow for the persistence of state data to a custom database table. Persisted states held in the
|
||||
vault are indexed for the purposes of executing queries. This also allows for relational joins between Corda tables
|
||||
and the organization's existing data.
|
||||
|
||||
.. 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.
|
||||
The Object Relational Mapping is specified using `Java Persistence API <https://en.wikipedia.org/wiki/Java_Persistence_API>`_
|
||||
(JPA) annotations. This mapping is persisted to the database as a table row (a single, implicitly structured data item) by the node
|
||||
automatically every time a state is recorded in the node's local vault as part of a transaction.
|
||||
|
||||
.. note:: By default, nodes use an H2 database which is accessed using *Java Database Connectivity* JDBC. Any database
|
||||
with a JDBC driver is a candidate and several integrations have been contributed to by the community.
|
||||
Please see the info in ":doc:`node-database`" 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.
|
||||
Every ``ContractState`` may implement the ``QueryableState`` interface if it wishes to be inserted into a custom table in the node's
|
||||
database and made accessible using SQL.
|
||||
|
||||
.. literalinclude:: ../../core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt
|
||||
:language: kotlin
|
||||
@ -34,12 +36,12 @@ database and accessible using SQL.
|
||||
: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.
|
||||
instance in situations where the schema has evolved. Each relational schema is represented as a ``MappedSchema``
|
||||
object returned by the state's ``supportedSchemas`` method.
|
||||
|
||||
Nodes have an internal ``SchemaService`` which decides what to persist and what not by selecting the ``MappedSchema``
|
||||
to use.
|
||||
Nodes have an internal ``SchemaService`` which decides what data to persist by selecting the ``MappedSchema`` to use.
|
||||
Once a ``MappedSchema`` is selected, the ``SchemaService`` will delegate to the ``QueryableState`` to generate a corresponding
|
||||
representation (mapped object) via the ``generateMappedObject`` method, the output of which is then passed to the *ORM*.
|
||||
|
||||
.. literalinclude:: ../../node/src/main/kotlin/net/corda/node/services/api/SchemaService.kt
|
||||
:language: kotlin
|
||||
@ -51,13 +53,10 @@ to use.
|
||||
: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``.
|
||||
With this framework, the relational view of ledger states can evolve in a controlled fashion in lock-step with internal systems or other
|
||||
integration points and is not dependant on changes to the contract code.
|
||||
|
||||
It is expected that multiple different contract state implementations might provide mappings within a single schema.
|
||||
It is expected that multiple contract state implementations might provide mappings within a single schema.
|
||||
For example an Interest Rate Swap contract and an Equity OTC Option contract might both provide a mapping to
|
||||
a Derivative contract within the same schema. The schemas should typically not be part of the contract itself and should exist independently
|
||||
to encourage re-use of a common set within a particular business area or Cordapp.
|
||||
@ -71,19 +70,19 @@ class name of a *schema family* class that is constant across versions, allowing
|
||||
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
|
||||
``MappedSchema``. These allow the configuration of database schemas or table name prefixes to avoid clashes 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 configurable. 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
|
||||
.. note:: It is intended that there should be plugin support for the ``SchemaService`` to offer version upgrading, implementation
|
||||
of additional schemas, and enable active schemas as being configurable. The present implementation does not include these features
|
||||
and simply results in all versions of all schemas supported by a ``QueryableState`` being persisted.
|
||||
This will change in due course. Similarly, the service does not currently support
|
||||
configuring ``SchemaOptions`` but will do so in the future.
|
||||
|
||||
Custom schema registration
|
||||
--------------------------
|
||||
Custom contract schemas are automatically registered at startup time for CorDapps. The node bootstrap process will scan
|
||||
for schemas (any class that extends the ``MappedSchema`` interface) in the `plugins` configuration directory in your CorDapp jar.
|
||||
Custom contract schemas are automatically registered at startup time for CorDapps. The node bootstrap process will scan for states that implement
|
||||
the Queryable state interface. Tables are then created as specified by the ``MappedSchema``s identified by each states ``supportedSchemas`` method.
|
||||
|
||||
For testing purposes it is necessary to manually register the packages containing custom schemas as follows:
|
||||
|
||||
@ -94,16 +93,16 @@ For testing purposes it is necessary to manually register the packages containin
|
||||
|
||||
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
|
||||
To facilitate the ORM, 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.
|
||||
entities can be included to model these properties where they are more complex, for example collections (:ref:`Persisting Hierarchical Data<persisting-hierarchical-data>`), so
|
||||
the mapping does not have to be *flat*. The ``MappedSchema`` constructor accepts a list of all JPA entity classes for that schema in
|
||||
the ``MappedTypes`` parameter. It must provide this list 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.
|
||||
@ -116,6 +115,218 @@ Several examples of entities and mappings are provided in the codebase, includin
|
||||
Ensure that table and column names are compatible with the naming convention of the database vendors for which the Cordapp will be deployed,
|
||||
e.g. for Oracle database, prior to version 12.2 the maximum length of table/column name is 30 bytes (the exact number of characters depends on the database encoding).
|
||||
|
||||
Persisting Hierarchical Data
|
||||
----------------------------
|
||||
|
||||
You may wish to persist hierarchical relationships within states using multiple database tables
|
||||
|
||||
You may wish to persist hierarchical relationships within state data using multiple database tables. In order to facillitate this, multiple ``PersistentState``
|
||||
subclasses may be implemented. The relationship between these classes is defined using JPA annotations. It is important to note that the ``MappedSchema``
|
||||
constructor requires a list of *all* of these subclasses.
|
||||
|
||||
An example Schema implementing hierarchical relationships with JPA annotations has been implemented below. This Schema will cause ``parent_data`` and ``child_data` tables to be
|
||||
created.
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
@CordaSerializable
|
||||
public class SchemaV1 extends MappedSchema {
|
||||
|
||||
/**
|
||||
* This class must extend the MappedSchema class. Its name is based on the SchemaFamily name and the associated version number abbreviation (V1, V2... Vn).
|
||||
* In the constructor, use the super keyword to call the constructor of MappedSchema with the following arguments: a class literal representing the schema family,
|
||||
* a version number and a collection of mappedTypes (class literals) which represent JPA entity classes that the ORM layer needs to be configured with for this schema.
|
||||
*/
|
||||
|
||||
public SchemaV1() {
|
||||
super(Schema.class, 1, ImmutableList.of(PersistentParentToken.class, PersistentChildToken.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* The @entity annotation signifies that the specified POJO class' non-transient fields should be persisted to a relational database using the services
|
||||
* of an entity manager. The @table annotation specifies properties of the table that will be created to contain the persisted data, in this case we have
|
||||
* specified a name argument which will be used the table's title.
|
||||
*/
|
||||
|
||||
@Entity
|
||||
@Table(name = "parent_data")
|
||||
public static class PersistentParentToken extends PersistentState {
|
||||
|
||||
/**
|
||||
* The @Column annotations specify the columns that will comprise the inserted table and specify the shape of the fields and associated
|
||||
* data types of each database entry.
|
||||
*/
|
||||
|
||||
@Column(name = "owner") private final String owner;
|
||||
@Column(name = "issuer") private final String issuer;
|
||||
@Column(name = "amount") private final int amount;
|
||||
@Column(name = "linear_id") public final UUID linearId;
|
||||
|
||||
/**
|
||||
* The @OneToMany annotation specifies a one-to-many relationship between this class and a collection included as a field.
|
||||
* The @JoinColumn and @JoinColumns annotations specify on which columns these tables will be joined on.
|
||||
*/
|
||||
|
||||
@OneToMany(cascade = CascadeType.PERSIST)
|
||||
@JoinColumns({
|
||||
@JoinColumn(name = "output_index", referencedColumnName = "output_index"),
|
||||
@JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"),
|
||||
})
|
||||
private final List<PersistentChildToken> listOfPersistentChildTokens;
|
||||
|
||||
public PersistentParentToken(String owner, String issuer, int amount, UUID linearId, List<PersistentChildToken> listOfPersistentChildTokens) {
|
||||
this.owner = owner;
|
||||
this.issuer = issuer;
|
||||
this.amount = amount;
|
||||
this.linearId = linearId;
|
||||
this.listOfPersistentChildTokens = listOfPersistentChildTokens;
|
||||
}
|
||||
|
||||
// Default constructor required by hibernate.
|
||||
public PersistentParentToken() {
|
||||
this.owner = "";
|
||||
this.issuer = "";
|
||||
this.amount = 0;
|
||||
this.linearId = UUID.randomUUID();
|
||||
this.listOfPersistentChildTokens = null;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public UUID getLinearId() {
|
||||
return linearId;
|
||||
}
|
||||
|
||||
public List<PersistentChildToken> getChildTokens() { return listOfPersistentChildTokens; }
|
||||
}
|
||||
|
||||
@Entity
|
||||
@CordaSerializable
|
||||
@Table(name = "child_data")
|
||||
public static class PersistentChildToken {
|
||||
// The @Id annotation marks this field as the primary key of the persisted entity.
|
||||
@Id
|
||||
private final UUID Id;
|
||||
@Column(name = "owner")
|
||||
private final String owner;
|
||||
@Column(name = "issuer")
|
||||
private final String issuer;
|
||||
@Column(name = "amount")
|
||||
private final int amount;
|
||||
|
||||
/**
|
||||
* The @ManyToOne annotation specifies that this class will be present as a member of a collection on a parent class and that it should
|
||||
* be persisted with the joining columns specified in the parent class. It is important to note the targetEntity parameter which should correspond
|
||||
* to a class literal of the parent class.
|
||||
*/
|
||||
|
||||
@ManyToOne(targetEntity = PersistentParentToken.class)
|
||||
private final TokenState persistentParentToken;
|
||||
|
||||
|
||||
public PersistentChildToken(String owner, String issuer, int amount) {
|
||||
this.Id = UUID.randomUUID();
|
||||
this.owner = owner;
|
||||
this.issuer = issuer;
|
||||
this.amount = amount;
|
||||
this.persistentParentToken = null;
|
||||
}
|
||||
|
||||
// Default constructor required by hibernate.
|
||||
public PersistentChildToken() {
|
||||
this.Id = UUID.randomUUID();
|
||||
this.owner = "";
|
||||
this.issuer = "";
|
||||
this.amount = 0;
|
||||
this.persistentParentToken = null;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return Id;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public TokenState getPersistentToken() {
|
||||
return persistentToken;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
@CordaSerializable
|
||||
object SchemaV1 : MappedSchema(schemaFamily = Schema::class.java, version = 1, mappedTypes = listOf(PersistentParentToken::class.java, PersistentChildToken::class.java)) {
|
||||
|
||||
@Entity
|
||||
@Table(name = "parent_data")
|
||||
class PersistentParentToken(
|
||||
@Column(name = "owner")
|
||||
var owner: String,
|
||||
|
||||
@Column(name = "issuer")
|
||||
var issuer: String,
|
||||
|
||||
@Column(name = "amount")
|
||||
var currency: Int,
|
||||
|
||||
@Column(name = "linear_id")
|
||||
var linear_id: UUID,
|
||||
|
||||
@JoinColumns(JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"), JoinColumn(name = "output_index", referencedColumnName = "output_index"))
|
||||
|
||||
var listOfPersistentChildTokens: MutableList<PersistentChildToken>
|
||||
) : PersistentState()
|
||||
|
||||
@Entity
|
||||
@CordaSerializable
|
||||
@Table(name = "child_data")
|
||||
class PersistentChildToken(
|
||||
@Id
|
||||
var Id: UUID = UUID.randomUUID(),
|
||||
|
||||
@Column(name = "owner")
|
||||
var owner: String,
|
||||
|
||||
@Column(name = "issuer")
|
||||
var issuer: String,
|
||||
|
||||
@Column(name = "amount")
|
||||
var currency: Int,
|
||||
|
||||
@Column(name = "linear_id")
|
||||
var linear_id: UUID,
|
||||
|
||||
@ManyToOne(targetEntity = PersistentParentToken::class)
|
||||
var persistentParentToken: TokenState
|
||||
|
||||
) : PersistentState()
|
||||
|
||||
|
||||
Identity mapping
|
||||
----------------
|
||||
Schema entity attributes defined by identity types (``AbstractParty``, ``Party``, ``AnonymousParty``) are automatically
|
||||
@ -161,8 +372,8 @@ In addition to ``jdbcSession``, ``ServiceHub`` also exposes the Java Persistence
|
||||
method. This method can be used to persist and query entities which inherit from ``MappedSchema``. This is particularly
|
||||
useful if off-ledger data must be maintained in conjunction with on-ledger state data.
|
||||
|
||||
.. note:: Your entity must be included as a mappedType in as part of a MappedSchema for it to be added to Hibernate
|
||||
as a custom schema. See Samples below.
|
||||
.. note:: Your entity must be included as a mappedType as part of a ``MappedSchema`` for it to be added to Hibernate
|
||||
as a custom schema. If it's not included as a mappedType, a corresponding table will not be created. See Samples below.
|
||||
|
||||
The code snippet below defines a ``PersistentFoo`` type inside ``FooSchemaV1``. Note that ``PersistentFoo`` is added to
|
||||
a list of mapped types which is passed to ``MappedSchema``. This is exactly how state schemas are defined, except that
|
||||
@ -201,7 +412,7 @@ the entity in this case should not subclass ``PersistentState`` (as it is not a
|
||||
class PersistentFoo(@Id @Column(name = "foo_id") var fooId: String, @Column(name = "foo_data") var fooData: String) : Serializable
|
||||
}
|
||||
|
||||
Instances of ``PersistentFoo`` can be persisted inside a flow as follows:
|
||||
Instances of ``PersistentFoo`` can be manually persisted inside a flow as follows:
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
.. highlight:: kotlin
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/codesets.js"></script>
|
||||
|
||||
API: States
|
||||
===========
|
||||
|
||||
|
@ -22,108 +22,20 @@ A ``MockNetwork`` is created as follows:
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
.. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt
|
||||
:language: kotlin
|
||||
:start-after: DOCSTART 1
|
||||
:end-before: DOCEND 1
|
||||
|
||||
class FlowTests {
|
||||
private lateinit var mockNet: MockNetwork
|
||||
.. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java
|
||||
:language: java
|
||||
:start-after: DOCSTART 1
|
||||
:end-before: DOCEND 1
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
network = MockNetwork(listOf("my.cordapp.package", "my.other.cordapp.package"))
|
||||
}
|
||||
}
|
||||
The ``MockNetwork`` requires at a minimum a list of CorDapps to be installed on each ``StartedMockNode``. The CorDapps are looked up on the
|
||||
classpath by package name, using ``TestCordapp.findCordapp``.
|
||||
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
public class IOUFlowTests {
|
||||
private MockNetwork network;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
network = new MockNetwork(ImmutableList.of("my.cordapp.package", "my.other.cordapp.package"));
|
||||
}
|
||||
}
|
||||
|
||||
The ``MockNetwork`` requires at a minimum a list of packages. Each package is packaged into a CorDapp JAR and installed
|
||||
as a CorDapp on each ``StartedMockNode``.
|
||||
|
||||
Configuring the ``MockNetwork``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``MockNetwork`` is configured automatically. You can tweak its configuration using a ``MockNetworkParameters``
|
||||
object, or by using named parameters in Kotlin:
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
val network = MockNetwork(
|
||||
// A list of packages to scan. Any contracts, flows and Corda services within these
|
||||
// packages will be automatically available to any nodes within the mock network
|
||||
cordappPackages = listOf("my.cordapp.package", "my.other.cordapp.package"),
|
||||
// If true then each node will be run in its own thread. This can result in race conditions in your
|
||||
// code if not carefully written, but is more realistic and may help if you have flows in your app that
|
||||
// do long blocking operations.
|
||||
threadPerNode = false,
|
||||
// The notaries to use on the mock network. By default you get one mock notary and that is usually
|
||||
// sufficient.
|
||||
notarySpecs = listOf(MockNetworkNotarySpec(DUMMY_NOTARY_NAME)),
|
||||
// If true then messages will not be routed from sender to receiver until you use the
|
||||
// [MockNetwork.runNetwork] method. This is useful for writing single-threaded unit test code that can
|
||||
// examine the state of the mock network before and after a message is sent, without races and without
|
||||
// the receiving node immediately sending a response.
|
||||
networkSendManuallyPumped = false,
|
||||
// How traffic is allocated in the case where multiple nodes share a single identity, which happens for
|
||||
// notaries in a cluster. You don't normally ever need to change this: it is mostly useful for testing
|
||||
// notary implementations.
|
||||
servicePeerAllocationStrategy = InMemoryMessagingNetwork.ServicePeerAllocationStrategy.Random())
|
||||
|
||||
val network2 = MockNetwork(
|
||||
// A list of packages to scan. Any contracts, flows and Corda services within these
|
||||
// packages will be automatically available to any nodes within the mock network
|
||||
listOf("my.cordapp.package", "my.other.cordapp.package"), MockNetworkParameters(
|
||||
// If true then each node will be run in its own thread. This can result in race conditions in your
|
||||
// code if not carefully written, but is more realistic and may help if you have flows in your app that
|
||||
// do long blocking operations.
|
||||
threadPerNode = false,
|
||||
// The notaries to use on the mock network. By default you get one mock notary and that is usually
|
||||
// sufficient.
|
||||
notarySpecs = listOf(MockNetworkNotarySpec(DUMMY_NOTARY_NAME)),
|
||||
// If true then messages will not be routed from sender to receiver until you use the
|
||||
// [MockNetwork.runNetwork] method. This is useful for writing single-threaded unit test code that can
|
||||
// examine the state of the mock network before and after a message is sent, without races and without
|
||||
// the receiving node immediately sending a response.
|
||||
networkSendManuallyPumped = false,
|
||||
// How traffic is allocated in the case where multiple nodes share a single identity, which happens for
|
||||
// notaries in a cluster. You don't normally ever need to change this: it is mostly useful for testing
|
||||
// notary implementations.
|
||||
servicePeerAllocationStrategy = InMemoryMessagingNetwork.ServicePeerAllocationStrategy.Random())
|
||||
)
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
MockNetwork network = MockNetwork(
|
||||
// A list of packages to scan. Any contracts, flows and Corda services within these
|
||||
// packages will be automatically available to any nodes within the mock network
|
||||
ImmutableList.of("my.cordapp.package", "my.other.cordapp.package"),
|
||||
new MockNetworkParameters()
|
||||
// If true then each node will be run in its own thread. This can result in race conditions in
|
||||
// your code if not carefully written, but is more realistic and may help if you have flows in
|
||||
// your app that do long blocking operations.
|
||||
.setThreadPerNode(false)
|
||||
// The notaries to use on the mock network. By default you get one mock notary and that is
|
||||
// usually sufficient.
|
||||
.setNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(DUMMY_NOTARY_NAME)))
|
||||
// If true then messages will not be routed from sender to receiver until you use the
|
||||
// [MockNetwork.runNetwork] method. This is useful for writing single-threaded unit test code
|
||||
// that can examine the state of the mock network before and after a message is sent, without
|
||||
// races and without the receiving node immediately sending a response.
|
||||
.setNetworkSendManuallyPumped(false)
|
||||
// How traffic is allocated in the case where multiple nodes share a single identity, which
|
||||
// happens for notaries in a cluster. You don't normally ever need to change this: it is mostly
|
||||
// useful for testing notary implementations.
|
||||
.setServicePeerAllocationStrategy(new InMemoryMessagingNetwork.ServicePeerAllocationStrategy.Random()));
|
||||
``MockNetworkParameters`` provides other properties for the network which can be tweaked. They default to sensible values if not specified.
|
||||
|
||||
Adding nodes to the network
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -132,73 +44,21 @@ Nodes are created on the ``MockNetwork`` using:
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
.. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt
|
||||
:language: kotlin
|
||||
:start-after: DOCSTART 2
|
||||
:end-before: DOCEND 2
|
||||
|
||||
class FlowTests {
|
||||
private lateinit var mockNet: MockNetwork
|
||||
lateinit var nodeA: StartedMockNode
|
||||
lateinit var nodeB: StartedMockNode
|
||||
.. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java
|
||||
:language: java
|
||||
:start-after: DOCSTART 2
|
||||
:end-before: DOCEND 2
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
network = MockNetwork(listOf("my.cordapp.package", "my.other.cordapp.package"))
|
||||
nodeA = network.createPartyNode()
|
||||
// We can optionally give the node a name.
|
||||
nodeB = network.createPartyNode(CordaX500Name("Bank B", "London", "GB"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
public class IOUFlowTests {
|
||||
private MockNetwork network;
|
||||
private StartedMockNode a;
|
||||
private StartedMockNode b;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
network = new MockNetwork(ImmutableList.of("my.cordapp.package", "my.other.cordapp.package"));
|
||||
nodeA = network.createPartyNode(null);
|
||||
// We can optionally give the node a name.
|
||||
nodeB = network.createPartyNode(new CordaX500Name("Bank B", "London", "GB"));
|
||||
}
|
||||
}
|
||||
|
||||
Nodes added using ``createPartyNode`` are provided a default set of node parameters. However, it is also possible to
|
||||
provide different parameters to each node using the following methods on ``MockNetwork``:
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
/**
|
||||
* Create a started node with the given parameters.
|
||||
*
|
||||
* @param legalName The node's legal name.
|
||||
* @param forcedID A unique identifier for the node.
|
||||
* @param entropyRoot The initial entropy value to use when generating keys. Defaults to an (insecure) random value,
|
||||
* but can be overridden to cause nodes to have stable or colliding identity/service keys.
|
||||
* @param configOverrides Add/override the default configuration/behaviour of the node
|
||||
* @param extraCordappPackages Extra CorDapp packages to add for this node.
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun createNode(legalName: CordaX500Name? = null,
|
||||
forcedID: Int? = null,
|
||||
entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
|
||||
configOverrides: MockNodeConfigOverrides? = null,
|
||||
extraCordappPackages: List<String> = emptyList()
|
||||
): StartedMockNode
|
||||
|
||||
/** Create a started node with the given parameters. **/
|
||||
fun createNode(parameters: MockNodeParameters = MockNodeParameters()): StartedMockNode
|
||||
|
||||
As you can see above, parameters can be added individually or encapsulated within a ``MockNodeParameters`` object. Of
|
||||
particular interest are ``configOverrides`` which allow you to override some of the default node
|
||||
configuration options. Please refer to the ``MockNodeConfigOverrides`` class for details what can currently be overridden.
|
||||
Also, the ``extraCordappPackages`` parameter allows you to add extra CorDapps to a
|
||||
specific node. This is useful when you wish for all nodes to load a common CorDapp but for a subset of nodes to load
|
||||
CorDapps specific to their role in the network.
|
||||
Nodes added using ``createNode`` are provided a default set of node parameters. However, it is also possible to
|
||||
provide different parameters to each node using ``MockNodeParameters``. Of particular interest are ``configOverrides`` which allow you to
|
||||
override some of the default node configuration options. Please refer to the ``MockNodeConfigOverrides`` class for details what can currently
|
||||
be overridden. Also, the ``additionalCordapps`` parameter allows you to add extra CorDapps to a specific node. This is useful when you wish
|
||||
for all nodes to load a common CorDapp but for a subset of nodes to load CorDapps specific to their role in the network.
|
||||
|
||||
Running the network
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -94,25 +94,24 @@ to "walk the chain" and verify that each input was generated through a valid seq
|
||||
Reference input states
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A reference input state is added to a transaction as a ``ReferencedStateAndRef``. A ``ReferencedStateAndRef`` can be
|
||||
obtained from a ``StateAndRef`` by calling the ``StateAndRef.referenced()`` method which returns a
|
||||
``ReferencedStateAndRef``.
|
||||
|
||||
.. warning:: Reference states are only available on Corda networks with a minimum platform version >= 4.
|
||||
|
||||
A reference input state is added to a transaction as a ``ReferencedStateAndRef``. A ``ReferencedStateAndRef`` can be
|
||||
obtained from a ``StateAndRef`` by calling the ``StateAndRef.referenced()`` method which returns a ``ReferencedStateAndRef``.
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/FlowCookbook.kt
|
||||
:language: kotlin
|
||||
:start-after: DOCSTART 55
|
||||
:end-before: DOCEND 55
|
||||
:dedent: 8
|
||||
:language: kotlin
|
||||
:start-after: DOCSTART 55
|
||||
:end-before: DOCEND 55
|
||||
:dedent: 8
|
||||
|
||||
.. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java
|
||||
:language: java
|
||||
:start-after: DOCSTART 55
|
||||
:end-before: DOCEND 55
|
||||
:dedent: 12
|
||||
.. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/FlowCookbook.java
|
||||
:language: java
|
||||
:start-after: DOCSTART 55
|
||||
:end-before: DOCEND 55
|
||||
:dedent: 12
|
||||
|
||||
**Handling of update races:**
|
||||
|
||||
|
@ -64,7 +64,8 @@ filter criteria:
|
||||
- Use ``queryBy`` to obtain a current snapshot of data (for a given ``QueryCriteria``)
|
||||
- Use ``trackBy`` to obtain both a current snapshot and a future stream of updates (for a given ``QueryCriteria``)
|
||||
|
||||
.. note:: Streaming updates are only filtered based on contract type and state status (UNCONSUMED, CONSUMED, ALL)
|
||||
.. note:: Streaming updates are only filtered based on contract type and state status (UNCONSUMED, CONSUMED, ALL).
|
||||
They will not respect any other criteria that the initial query has been filtered by.
|
||||
|
||||
Simple pagination (page number and size) and sorting (directional ordering using standard or custom property
|
||||
attributes) is also specifiable. Defaults are defined for paging (pageNumber = 1, pageSize = 200) and sorting
|
||||
|
@ -28,7 +28,7 @@ Alter the versions you depend on in your Gradle file like so:
|
||||
.. sourcecode:: groovy
|
||||
|
||||
ext.corda_release_version = '4.0'
|
||||
ext.corda_gradle_plugins_version = '4.0.37'
|
||||
ext.corda_gradle_plugins_version = '4.0.38'
|
||||
ext.kotlin_version = '1.2.71'
|
||||
ext.quasar_version = '0.7.10'
|
||||
|
||||
@ -121,10 +121,13 @@ away to the new API, as otherwise things like business network membership checks
|
||||
|
||||
This is a three step process:
|
||||
|
||||
1. Change the flow that calls ``FinalityFlow``
|
||||
1. Change the flow that calls ``FinalityFlow``.
|
||||
2. Change or create the flow that will receive the finalised transaction.
|
||||
3. Make sure your application's minimum and target version numbers are both set to 4 (see step 2).
|
||||
|
||||
Upgrading a non-initiating flow
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As an example, let's take a very simple flow that finalises a transaction without the involvement of a counterpart flow:
|
||||
|
||||
.. container:: codeset
|
||||
@ -140,7 +143,7 @@ As an example, let's take a very simple flow that finalises a transaction withou
|
||||
:end-before: DOCEND SimpleFlowUsingOldApi
|
||||
:dedent: 4
|
||||
|
||||
To use the new API, this flow needs to be annotated with ``InitiatingFlow`` and a ``FlowSession`` to the participant of the transaction must be
|
||||
To use the new API, this flow needs to be annotated with ``InitiatingFlow`` and a ``FlowSession`` to the participant(s) of the transaction must be
|
||||
passed to ``FinalityFlow`` :
|
||||
|
||||
.. container:: codeset
|
||||
@ -175,10 +178,17 @@ to record the finalised transaction:
|
||||
:end-before: DOCEND SimpleNewResponderFlow
|
||||
:dedent: 4
|
||||
|
||||
For flows which are already initiating counterpart flows then it's a simple matter of using the existing flow session.
|
||||
.. note:: All the nodes in your business network will need the new CorDapp, otherwise they won't know how to receive the transaction. **This
|
||||
includes nodes which previously didn't have the old CorDapp.** If a node is sent a transaction and it doesn't have the new CorDapp loaded
|
||||
then simply restart it with the CorDapp and the transaction will be recorded.
|
||||
|
||||
Upgrading an initiating flow
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For flows which are already initiating counterpart flows then it's a matter of using the existing flow session.
|
||||
Note however, the new ``FinalityFlow`` is inlined and so the sequence of sends and receives between the two flows will
|
||||
change and will be incompatible with your current flows. You can use the flow version API to write your flows in a
|
||||
backwards compatible way.
|
||||
backwards compatible manner.
|
||||
|
||||
Here's what an upgraded initiating flow may look like:
|
||||
|
||||
@ -212,8 +222,9 @@ finalised transaction. If the initiator is written in a backwards compatible way
|
||||
:end-before: DOCEND ExistingResponderFlow
|
||||
:dedent: 12
|
||||
|
||||
The responder flow may be waiting for the finalised transaction to appear in the local node's vault using ``waitForLedgerCommit``.
|
||||
This is no longer necessary with ``ReceiveFinalityFlow`` and the call to ``waitForLedgerCommit`` can be removed.
|
||||
You may already be using ``waitForLedgerCommit`` in your responder flow for the finalised transaction to appear in the local node's vault.
|
||||
Now that it's calling ``ReceiveFinalityFlow``, which effectively does the same thing, this is no longer necessary. The call to
|
||||
``waitForLedgerCommit`` should be removed.
|
||||
|
||||
Step 4. Security: Upgrade your use of SwapIdentitiesFlow
|
||||
--------------------------------------------------------
|
||||
|
@ -52,18 +52,8 @@ Version 4.0
|
||||
|
||||
* Fixed a problem that was preventing `Cash.generateSpend` to be used more than once per transaction (https://github.com/corda/corda/issues/4110).
|
||||
|
||||
* ``SwapIdentitiesFlow``, from the experimental confidential-identities module, is now an inlined flow. Instead of passing in a ``Party`` with
|
||||
whom to exchange the anonymous identity, a ``FlowSession`` to that party is required instead. The flow running on the other side must
|
||||
also call ``SwapIdentitiesFlow``. This change was required as the previous API allowed any counterparty to generate anonoymous identities
|
||||
with a node at will with no checks.
|
||||
|
||||
The result type has changed to a simple wrapper class, instead of a Map, to make extracting the identities easier. Also, the wire protocol
|
||||
of the flow has slightly changed.
|
||||
|
||||
.. note:: V3 and V4 of confidential-identities are not compatible and confidential-identities V3 will not work with a V4 Corda node. CorDapps
|
||||
in such scenarios using confidential-identities must be updated.
|
||||
|
||||
The ``confidential-identities`` dependency in your CorDapp must now be ``compile`` and not ``cordaCompile``.
|
||||
* The experimental confidential-identities is now a separate CorDapp and must now be loaded onto the node alongside any CorDapp that needs it.
|
||||
This also means your gradle dependency for it should be ``cordapp`` and not ``cordaCompile``.
|
||||
|
||||
* Fixed a bug resulting in poor vault query performance and incorrect results when sorting.
|
||||
|
||||
@ -86,6 +76,9 @@ Version 4.0
|
||||
* Introduced new optional network bootstrapper command line options (--register-package-owner, --unregister-package-owner)
|
||||
to register/unregister a java package namespace with an associated owner in the network parameter packageOwnership whitelist.
|
||||
|
||||
* BFT-Smart and Raft notary implementations have been move to the ``net.corda.notary.experimental`` package to emphasise
|
||||
their experimental nature.
|
||||
|
||||
* New "validate-configuration" sub-command to `corda.jar`, allowing to validate the actual node configuration without starting the node.
|
||||
|
||||
* CorDapps now have the ability to specify a minimum platform version in their MANIFEST.MF to prevent old nodes from loading them.
|
||||
@ -99,39 +92,16 @@ Version 4.0
|
||||
|
||||
* ``FinalityFlow`` is now an inlined flow and requires ``FlowSession`` s to each party intended to receive the transaction. This is to fix the
|
||||
security problem with the old API that required every node to accept any transaction it received without any checks. Existing CorDapp
|
||||
binaries relying on this old behaviour will continue to function as previously. However, it is strongly recommended that CorDapps switch to
|
||||
binaries relying on this old behaviour will continue to function as previously. However, it is strongly recommended CorDapps switch to
|
||||
this new API. See :doc:`app-upgrade-notes` for further details.
|
||||
|
||||
* For similar reasons, ``SwapIdentitiesFlow``, from confidential-identities, is also now an inlined flow. The old API has been preserved but
|
||||
it is strongly recommended CorDapps switch to this new API. See :doc:`app-upgrade-notes` for further details.
|
||||
|
||||
* Introduced new optional network bootstrapper command line option (--minimum-platform-version) to set as a network parameter
|
||||
|
||||
* BFT-Smart and Raft notary implementations have been extracted out of node into ``experimental`` CorDapps to emphasise
|
||||
their experimental nature. Moreover, the BFT-Smart notary will only work in dev mode due to its use of Java serialization.
|
||||
|
||||
* Vault storage of contract state constraints metadata and associated vault query functions to retrieve and sort by constraint type.
|
||||
|
||||
* UPGRADE REQUIRED: changes have been made to how notary implementations are configured and loaded.
|
||||
No upgrade steps are required for the single-node notary (both validating and non-validating variants).
|
||||
Other notary implementations have been moved out of the Corda node into individual Cordapps, and require configuration
|
||||
file updates.
|
||||
|
||||
To run a notary you will now need to include the appropriate notary CorDapp in the ``cordapps/`` directory:
|
||||
|
||||
* ``corda-notary-raft`` for the Raft notary.
|
||||
* ``corda-notary-bft-smart`` for the BFT-Smart notary.
|
||||
|
||||
It is now required to specify the fully qualified notary service class name, ``className``, and the legal name of
|
||||
the notary service in case of distributed notaries: ``serviceLegalName``.
|
||||
|
||||
Implementation-specific configuration values have been moved to the ``extraConfig`` configuration block.
|
||||
|
||||
Example configuration changes for the Raft notary:
|
||||
|
||||
.. image:: resources/notary-config-update.png
|
||||
|
||||
Example configuration changes for the BFT-Smart notary:
|
||||
|
||||
.. image:: resources/notary-config-update-bft.png
|
||||
|
||||
* New overload for ``CordaRPCClient.start()`` method allowing to specify target legal identity to use for RPC call.
|
||||
|
||||
* Case insensitive vault queries can be specified via a boolean on applicable SQL criteria builder operators. By default
|
||||
@ -145,7 +115,8 @@ Version 4.0
|
||||
|
||||
* Removed experimental feature ``CordformDefinition``
|
||||
|
||||
* Added ``registerResponderFlow`` method to ``StartedMockNode``, to support isolated testing of responder flow behaviour.
|
||||
* Added new overload of ``StartedMockNode.registerInitiatedFlow`` which allows registering custom initiating-responder flow pairs, which
|
||||
can be useful for testing error cases.
|
||||
|
||||
* "app", "rpc", "p2p" and "unknown" are no longer allowed as uploader values when importing attachments. These are used
|
||||
internally in security sensitive code.
|
||||
@ -340,6 +311,9 @@ Version 4.0
|
||||
* Finance CorDapp is now build as a sealed and signed JAR file.
|
||||
Custom classes can no longer be placed in the packages defined in Finance Cordapp or access it's non-public members.
|
||||
|
||||
* Finance CorDapp was split into two separate apps: ``corda-finance-contracts`` and ``corda-finance-workflows``,
|
||||
``corda-finance`` is kept for backward compatibility, it is recommended to use separated jars.
|
||||
|
||||
* The format of the shell commands' output can now be customized via the node shell, using the ``output-format`` command.
|
||||
|
||||
* The ``node_transaction_mapping`` database table has been folded into the ``node_transactions`` database table as an additional column.
|
||||
|
@ -21,6 +21,8 @@ you.
|
||||
`CordaRPCClient`_ class. You can find an example of how to do this using the popular Spring Boot server
|
||||
`here <https://github.com/corda/spring-webserver>`_.
|
||||
|
||||
.. _clientrpc_connect_ref:
|
||||
|
||||
Connecting to a node via RPC
|
||||
----------------------------
|
||||
To use `CordaRPCClient`_, you must add ``net.corda:corda-rpc:$corda_release_version`` as a ``cordaCompile`` dependency
|
||||
|
@ -50,7 +50,7 @@ Corda incubating modules
|
||||
The following modules don't yet have a completely stable API, but we will do our best to minimise disruption to
|
||||
developers using them until we are able to graduate them into the public API:
|
||||
|
||||
* **net.corda.confidential.identities**: experimental support for confidential identities on the ledger
|
||||
* **net.corda.confidential**: experimental support for confidential identities on the ledger
|
||||
* **net.corda.finance**: a range of elementary contracts (and associated schemas) and protocols, such as abstract fungible assets, cash, obligation and commercial paper
|
||||
* **net.corda.client.jfx**: support for Java FX UI
|
||||
* **net.corda.client.mock**: client mock utilities
|
||||
|
@ -1,545 +0,0 @@
|
||||
Corda Network Foundation : Governance Guidelines
|
||||
================================================
|
||||
|
||||
23 October 2018
|
||||
|
||||
Version 0.95
|
||||
|
||||
DRAFT for discussion
|
||||
|
||||
This is a set of governance guidelines for the Corda Network Foundation. It provides a framework for the Foundation’s
|
||||
Board, to steer and govern Corda Network effectively to realise its potential. It is not a set of binding legal obligations.
|
||||
|
||||
1 Background to Corda and the Network
|
||||
-------------------------------------
|
||||
|
||||
Corda allows multiple independent applications and private networks to coexist, each with their own business models and
|
||||
membership criteria, yet linked by the same underlying network (‘Corda Network’). This Network enables ‘interoperability’,
|
||||
the exchange of data or assets via a secure, efficient ‘internet layer’, in a way that isn’t possible with competing
|
||||
permissioned distributed ledger technologies or legacy systems.
|
||||
|
||||
Corda Network operates the protocol of Corda currently, and is always expected to. The protocol is currently
|
||||
specified in the Corda Open Source Project codebase, but later may be formalised in a protocol specification document,
|
||||
which then will become canonical.
|
||||
|
||||
1.1 Reason for a Corda Network Foundation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
R3 has set up and governs by default Corda Network currently (along with Corda). This includes making key decisions
|
||||
around establishing, maintaining and updating standards, policies, and procedures for participation in, and use of,
|
||||
Corda Network.
|
||||
|
||||
However, it is critically important that a commercial entity should not control Corda Network going forwards. It should
|
||||
be governed transparently (to its Participants), with a fair and stable structure. Analysis and feedback show
|
||||
that Corda Network will be most effectively governed via a Foundation, a not-for-profit, independent entity in which
|
||||
Network Participants elect, and can be elected to, a governing Board.
|
||||
|
||||
A Foundation will enable Network Participants to be involved with, and also understand, how decisions are made (including
|
||||
around issues of identity and permission), building trust and engagement from a wide range of stakeholders. This will
|
||||
bring about the best decisions and outcomes for the Network’s long-term success.
|
||||
|
||||
In other words, to achieve the community's objective of Corda ubiquity, it is necessary to put in place a governance
|
||||
structure which explicitly limits R3’s control of Corda Network, and enables this ubiquity.
|
||||
|
||||
2 The Corda Network Foundation
|
||||
------------------------------
|
||||
|
||||
2.1 Mission and Values
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
Following on from the Corda introduction and technical white papers, we see the mission of the Corda Network Foundation
|
||||
to achieve the vision of Corda - whereby the state of transactions and agreements of business partners can be recorded
|
||||
in a single global database, ending the need for costly reconciliation and error correction, while maintaining privacy.
|
||||
Further details of the vision are laid out in the
|
||||
[Corda Introductory White Paper](https://www.corda.net/content/corda-platform-whitepaper.pdf).
|
||||
|
||||
Achieving this vision in its full ubiquity will involve running and maintaining a stable and secure Network with open
|
||||
and fair governance, while also promoting the Network so as to ensure its more widespread use.
|
||||
|
||||
Following on this, the Corda Network Foundation shall embody the following qualities in executing its mission:
|
||||
|
||||
* Fairness and openness – Participants can join the Network and make up the Network’s governing board, elected through a
|
||||
straightforward voting process.
|
||||
* Democracy and transparency – Key decisions and rationale are shared openly with Participants.
|
||||
* Stability (with a long-term view) with flexibility – Board directors’ terms will last three years with a staggered
|
||||
board, and the governance model will be flexible to adapt where required.
|
||||
* Efficiency – Staying a lean organisation, sufficient to commission and monitor an Operator to run any services,
|
||||
physical infrastructure, or operational processes that may be needed to achieve the vision of Corda. Provide adequate
|
||||
support, through advisory committees.
|
||||
* Cost effectiveness - Funding received through participation fees pays for an Operator to run the Network securely, and
|
||||
the Foundation shall not be a profit-making entity.
|
||||
* Independence – Corda Network Foundation makes its own decisions (within the law), and is not following another
|
||||
entity’s rules.
|
||||
|
||||
More specifically, the Foundation shall focus on the following commitments over the long-term:
|
||||
|
||||
* Maintain the long-term standards, services and open governance model of the Network, ensuring it continues to be
|
||||
updated to the current Corda protocol version.
|
||||
* Hold the Trust Root for the Network, used for creation of operational certificates, independently of the Operator.
|
||||
* Commission the provision and operation of infrastructure and services for the Network, both of technical services, and
|
||||
infrastructure needed for meetings, events and collaborative discussions, and provide structure around the business and
|
||||
technical governance of the Network.
|
||||
* Facilitate a diverse and vibrant community of industry experts, Corda contributors, users and services, including
|
||||
developers, service and solution providers and end users.
|
||||
* Set minimum standards for the external provision of notary and oracle services.
|
||||
* Enable the ubiquity and utility of Corda throughout all applicable industries and commercial use cases.
|
||||
* Balance the divergent interests of a wide range of stakeholders, including business network operators, Corda
|
||||
customers, open source developers, and R3’s shareholders.
|
||||
|
||||
2.2 Structure of the Foundation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The Foundation shall be a not-for-profit entity created exclusively to execute the mission set out in this Constitution.
|
||||
With the advice of international lawyers, this is a ‘Stichting’ domiciled in Holland – a legal entity suited for
|
||||
governance activities, able to act commercially, with limited liability but no shareholders, capital or dividends.
|
||||
|
||||
The Foundation is defined in a set of Articles of Association and By-laws.
|
||||
|
||||
The Foundation governance bodies shall include:
|
||||
|
||||
1. A **Governing Board** (‘the Board’) of 11 representatives (‘Directors’) with privileges and responsibilities as set out
|
||||
in section 3.
|
||||
2. A **Technical Advisory Committee** (‘the TAC’), comprised of representatives of Participant organisations with
|
||||
responsibilities set out in section 6.2.
|
||||
3. A **Governance Advisory Committee**, comprised of representatives of Participant organisations with responsibilities
|
||||
set out in section 6.3.
|
||||
4. A **Network Operator** (‘the Operator’), charging the Foundation reasonable costs for providing network and
|
||||
administration services, paid by the Foundation through membership funds, and accountable directly to the Board, set
|
||||
out in section 7.
|
||||
|
||||
Operating on behalf of:
|
||||
|
||||
* A **General Membership** (‘the Participant Community’), which is open to any organisation participating in Corda Network,
|
||||
and with privileges and responsibilities as set out in section 6.
|
||||
|
||||
Any change to the structure of the Foundation is a constitutional change, described in section 5.1.
|
||||
|
||||
3 Governing Board
|
||||
-----------------
|
||||
|
||||
3.1 Role of the Board
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
The goal of the Board is primarily to ensure the stable and secure operation of the Network, as well as to achieve the
|
||||
vision of Corda laid out in section 2.1. The fundamental responsibility of directors appointed to the Board is to
|
||||
exercise their business judgement to act in what they believe to be the best interests of the Network, taking account
|
||||
of the interests of the Network community as a whole (rather than any one individual interest).
|
||||
|
||||
Directors are expected to comply with the Conflict of Interest policy, which includes a responsibility to disclose
|
||||
promptly any conflicts that may arise, and meet the expected standards specified in the Code of Conduct Guidelines for
|
||||
ethical conduct and breach reporting.
|
||||
|
||||
The Board is the formal decision-making authority of the Foundation, and actions of the Board reflect its collective
|
||||
decision making.
|
||||
|
||||
3.2 Relationship of the Board with the Operator
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
It is the duty of the Board to monitor the Operator’s performance to ensure that the Network operates in an effective,
|
||||
efficient and ethical manner. The Board will also be responsible for overseeing the Operator in the development of the
|
||||
Network’s strategic and tactical plans, ensuring that they will result in broad and open adoption of Corda. The Operator
|
||||
is responsible to the Board for the execution of day to day operations, and the implementation of strategic and tactical
|
||||
change.
|
||||
|
||||
3.3 Composition and Establishment of the Board
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
### 3.3.1 Size
|
||||
The Board shall consist of 11 voting members (‘Directors’) in total, to allow broad representation but maintain an agile
|
||||
decision-making ability. The selection process (using the Participant Community) is intended to ensure that the Board is
|
||||
composed of members who display diversity in geography, culture, skills, experience and perspective, and that the
|
||||
abilities and interests of Directors are aligned with those of Corda.
|
||||
|
||||
R3 shall have the ongoing right to appoint two Directors, as the firm which developed Corda and funded the initial
|
||||
construction of the Network. It represents the interests of its large and diverse alliance of commercial organisations,
|
||||
financial institutions, and regulatory bodies. Similarly to the rest of the board, the Directors will have three-year
|
||||
terms (unless the director resigns or leaves for another reason) and can be re-appointed without limit. Appointment will
|
||||
be effective immediately.
|
||||
|
||||
The Chair of the board will be elected for a one year term by a vote of the Directors of the Board, at the first Board
|
||||
meeting following the Board election.
|
||||
|
||||
#### 3.3.2 Participation Criteria
|
||||
Participants shall be directed to vote to ensure that the Board is composed of Directors who in the aggregate produce
|
||||
the broadest diversity on the Board, consistent with meeting the other criteria. In addition, the Board is to be
|
||||
comprised of individuals who can demonstrate to Participants they meet the following requirements:
|
||||
|
||||
* Hold an understanding and appreciation of the Corda protocol and community purpose.
|
||||
* Have an awareness of cultural and geographic perspectives.
|
||||
* Demonstrate integrity, intelligence and objectivity.
|
||||
* Can work and communicate in written and spoken English.
|
||||
|
||||
To promote diversity, the following guidelines are adopted, in particular for steady-state governance (recognising that
|
||||
these may not be possible to fulfil during the transition period):
|
||||
|
||||
* No corporate group of participants may have more than one Director. In the event of votes for two different candidates
|
||||
representing the same overall corporate group, the candidate with the most votes shall be considered.
|
||||
* Of the nine Directors, there should not be more than three Directors from any broad industry classification, according to
|
||||
company classification data.
|
||||
* Of the nine Directors, there should not be more than three Directors from any continent (one must be based in the Americas,
|
||||
Europe/Africa and Asia, to ensure geographic diversity.
|
||||
* Of the nine Directors, there should not be more than three Directors representing any Corporate Group with more than
|
||||
100,000 employees.
|
||||
* There is no restriction of re-election of Directors or the Chair of the Board.
|
||||
|
||||
### 3.3.3 Establishment of the Board
|
||||
#### 3.3.3.1 Pre-Foundation
|
||||
Initially R3 shall govern the Network to ensure rapid progress on its implementation. Once the Foundation is set-up and
|
||||
at least three business networks are conducting live transactions using the network with at least three Participants each, the
|
||||
'transition period' of one year will commence.
|
||||
#### 3.3.3.2 Transition: Initial set-up of Foundation Board:
|
||||
For the transition year, the first three business networks shall have the right to choose three Participants, to
|
||||
represent the interests of the business network. One of each of these must be based in the Americas, Europe/Africa and
|
||||
Asia, to ensure geographic diversity, if the pool Participants allows. Each selected Participant will appoint a
|
||||
Director, to sit on the Board, making nine Directors in addition to the two Directors from R3.
|
||||
|
||||
After this start-up period, there will be a vote for Board Directors.
|
||||
|
||||
For the first election only, of the nine vacant seats, three will be for a duration of one year, three for two years, and
|
||||
three for three years. This will introduce a staggered board, so there is greater continuity at the end of each term.
|
||||
Candidates with the most votes will fill the three-year seats first, followed by two-year and then one-year seats. In all other
|
||||
respects, the first election will follow the steady state process.
|
||||
#### 3.3.3.3 Steady-State
|
||||
1. Participants may nominate candidates for Director election. Appointments to the nine rotating seats of the Board will be
|
||||
by vote of the Participants, with three seats up for election each year. Any seats vacated mid-term will also be
|
||||
elected at the same time. R3 may not put forward candidates for the nine rotating seats, and these may not be held by
|
||||
R3 employees.
|
||||
2. Candidates will create a personal statement and short biography, which will be shared with all Participants.
|
||||
3. Participants may each cast up to three votes for three separate candidates.
|
||||
4. Subject to meeting certain criteria (including diversity of geography and industry), the most popular candidates
|
||||
will be appointed as Directors.
|
||||
5. Candidates will be considered in sequence from most popular to least, and if a seat is vacant according to the
|
||||
diversity criteria in section 3.3.2, the candidate will be allocated to it. This may mean that occasionally a less
|
||||
popular candidate fills a seat instead of a more popular one.
|
||||
6. R3 shall appoint Directors to the two remaining seats, when appropriate.
|
||||
#### 3.3.4 Removal from the Board and Re-election.
|
||||
Apart from the three-year expiry, Directors can otherwise leave the Board by resignation, prolonged non-attendance of
|
||||
board meetings of more than six months, death, or if necessary, removal by a Mandatory Governance Event. In any case, a
|
||||
vacant seat will be contested at the next annual election.
|
||||
|
||||
3.4 Conduct of Board Meetings
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Attendance may be in person or by video-conference.
|
||||
|
||||
The Board shall meet not less than every six months, and may meet on the request of any Director, but not more than every
|
||||
two months. At least two weeks’ notice shall be given to Directors. By exception, the Chair may convene an emergency
|
||||
meeting with minimal notice, appropriate to the situation in the Chair's judgement.
|
||||
|
||||
The Board shall consider all Governance Events proposed since the previous meeting, except for an emergency convening.
|
||||
|
||||
Board meetings shall be limited to the Board representatives, and shall follow the requirements for quorum and voting
|
||||
outlined in this Constitution.
|
||||
|
||||
The Board may decide whether to allow one named representative to attend as an alternate, and typically these shall be
|
||||
allowed.
|
||||
|
||||
The Board meetings shall be conducted in private, but in the interest of transparency, public minutes shall be
|
||||
published within two weeks following their approval by the Board.
|
||||
|
||||
Participants who do not have representation on the Board may request an observer to be present at a Board meeting.
|
||||
This is subject to a lottery held one week prior to the meeting, a limit of 20 observer places, and a limit of one
|
||||
observer per unrepresented Participant. Observers may participate in discussions but shall not participate in any Board
|
||||
vote, and may be asked to join by video-conference if there are logistical constraints.
|
||||
|
||||
4 Relation of the Foundation to Business Networks
|
||||
---------------------------------------------------
|
||||
|
||||
The global Network shall support the operation of any business networks which may be formed by industry-specific
|
||||
operators on top of the Network. The Board shall ensure that there is a clear separation between areas of governance
|
||||
for the Foundation and Network outlined in this document, and for individual business networks.
|
||||
|
||||
Additionally, the structure and control processes defined for the Foundation shall be documented and made available
|
||||
under a Creative Commons license, both for reuse by business network operators if business networks need a similar
|
||||
governance structure, and so that such governance layers are complementary and not contradictory.
|
||||
|
||||
5 Governance Events
|
||||
---------------------
|
||||
|
||||
All formal changes to the Network and the Foundation shall be controlled through a formal Governance Event process, and
|
||||
the right to initiate this shall be held by all Directors and Participants. In the event of disruptive behaviour by an
|
||||
individual Participant or group of Participants, this right may be curtailed, as described in 5.2.5.
|
||||
|
||||
5.1 Types of Governance Events
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
There are three types of change that affect the Network and the Foundation, which require a controlled change process
|
||||
and a vote described in 5.5, and are defined as Governance Events:
|
||||
|
||||
1. All changes to the Stichting Articles of Association and By-laws are defined as Constitutional Governance Events.
|
||||
2. All changes to Network participation criteria, charges, budgets, change management process and other business areas not
|
||||
defined in Articles of Association or By-laws are defined as Mandatory Governance Events in section 5.2. The Board shall
|
||||
vote to accept or reject all such Mandatory Governance Events, and the outcomes are binding on Participants and the
|
||||
Operator for implementation.
|
||||
3. All changes to technical parameters and notary criteria, which affect the nodes of participants, are defined as
|
||||
Advisory Governance Events in section 5.3. While the Operator can implement these without Board approval, it may ask the
|
||||
Board to provide an advisory (non-binding) vote. Conversely, the Board may require that it is given the opportunity to
|
||||
provide an advisory vote.
|
||||
|
||||
Any other changes in the day to day internal implementation of network services by the Operator, which do not require
|
||||
changes to be implemented on the nodes of participants, are out of scope as Governance Events.
|
||||
|
||||
All Constitutional, Mandatory and Advisory Governance Events shall be supported by a formal proposal, using standard
|
||||
structured documents and containing all relevant background information, to create an efficient process both for the
|
||||
submitter and the Board.
|
||||
Depending on the content of the Governance Event proposal, the Board or Operator may rely on the Governance or Technical
|
||||
Advisory Committee to provide due diligence and make a recommendation for implementation.
|
||||
|
||||
For all Governance Events, decisions and the rationale for the decision shall be published transparently.
|
||||
|
||||
5.2 Mandatory Governance Events
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
### 5.2.1 Access Standards
|
||||
The Corda system can be accessed by using software which implements the set of technical protocols which define
|
||||
compatibility (see 5.3.1) above). The reference implementation of this software is open source and freely accessible at
|
||||
[www.corda.net](https://www.corda.net).
|
||||
|
||||
To join the Network, a participant running Corda compatible software also needs a unique and real-world identity. The
|
||||
Foundation shall enforce this access requirement through the issuance of PKI certificates. Corda has a primary objective
|
||||
to facilitate automation of real-world contracts between real-world parties, and has a particular requirement to ensure
|
||||
that identities on the Network are unique and that all participants understand the basis on which they have been issued.
|
||||
The Foundation shall govern the operation of the technical infrastructure to enable a good level of service for identity
|
||||
issuance.
|
||||
|
||||
The access criteria for proving real world identity shall be defined by the Board and shall be transparent and objective.
|
||||
Any party which can demonstrate they meet these criteria will be issued a certificate without prejudice. The goal to
|
||||
ensure that the Operator which manages the issuance of the network certificates cannot act arbitrarily or
|
||||
discriminatory. But lawful requests from regulatory authorities of the Foundation’s jurisdiction shall be accepted.
|
||||
|
||||
These criteria may be subject to change over time to deal with changing circumstances, like regulatory requirements.
|
||||
However, the changes shall be subject to Mandatory Governance Events. In this way the Network is able to provide its
|
||||
participants with a strong and fair identity framework.
|
||||
|
||||
Arbitration, suspension, and in extreme circumstances, revocation (for example for illegal behaviour or when a
|
||||
participant no longer meets the standards set forth) shall be managed through an Emergency Governance Event, set out in
|
||||
5.4.
|
||||
|
||||
#### 5.2.2 Budget, Expenditure and Participation Fees
|
||||
The Board shall annually prepare and approve a budget for the operations of the Foundation, taking into account the
|
||||
not-for-profit status of the Foundation and the mission to promote the Corda Ecosystem.
|
||||
|
||||
The Foundation shall charge a fee for Membership, as described in section 6.1.
|
||||
|
||||
The Operator shall charge the Foundation for services that the Operator provides under the requirements of the contract
|
||||
with the Foundation, including management of Participants, Network participation and access services, Network map
|
||||
and Operator-provided notary services. The Operator may also provide fee-based services that are supplementary to those
|
||||
needed to participate on the Network.
|
||||
|
||||
#### 5.2.3 Change of Network Operator
|
||||
For three years upon establishment of the Foundation, R3 will undertake the role of Operator. Annually thereafter, the
|
||||
Board will approve the appointment of the Operator, which may be changed with a Mandatory Governance Event and vote.
|
||||
As noted, the Foundation shall hold the Trust Root, and the Operator and any services they operate shall be provisioned
|
||||
with intermediate certificates that derive from this. The Operator must enter into an escrow arrangement upon
|
||||
appointment, so that existing certificates continue to work, certificate revocation lists continue to be published, and
|
||||
there is no disruption to Participants if the Operator is changed.
|
||||
|
||||
#### 5.2.4 Change Management Process
|
||||
The Network will periodically require participating nodes to implement change. A change notification and management
|
||||
process shall be defined and communicated; and any change to the change management process shall be the subject of a
|
||||
Mandatory Governance Event.
|
||||
|
||||
#### 5.2.5 Other Mandatory Governance Events
|
||||
Restrictions on individual Participants or a group to initiate Governance Events; in the event of disruptive behaviour.
|
||||
|
||||
Audit: the Board may request an audit of the activities and services provided by the Operator, no more frequently than
|
||||
every year, unless an emergency audit is authorised through a Mandatory Governance Event.
|
||||
|
||||
Marketing, Trademark and Branding: R3 shall commit to license the Corda trademark to the Foundation. The Foundation
|
||||
shall manage its own brand and any trademarks created.
|
||||
|
||||
Certifications: Where the Foundation provides standards for certification of organisations, individuals or technologies,
|
||||
the Board shall approve the standards and processes for certification.
|
||||
|
||||
Change to the arbitration and dispute resolution process shall be the subject of a Mandatory Governance Event.
|
||||
|
||||
Policies covering areas of operation not covered by the Constitution (e.g. code of conduct for Board Directors).
|
||||
|
||||
5.3 Advisory Governance Events
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
#### 5.3.1 Technical Standards
|
||||
There is a set of technical standards, such as ‘network parameters’, which all Corda Network nodes need to comply with
|
||||
in order to guarantee technical compatibility to other nodes and services within the Network. While Corda has stability
|
||||
and backwards compatibility as key design goals, there may be circumstances under which these standards will need to
|
||||
change. Where these changes require participants in the Network to update to remain compatible, these changes will be
|
||||
subject to Governance Events.
|
||||
|
||||
Changes to technical standards, such as some network parameters, shall require formal design processes, and the Operator may
|
||||
choose to delegate technical due diligence to the Technical Advisory Committee prior to formally accepting a change to
|
||||
the technical standards.
|
||||
|
||||
The Corda open source software is the reference implementation for the core technical standards adopted for the Network.
|
||||
Corda implementations and distributions can vary in their internal details, but their core interfaces and Corda protocol
|
||||
implementation must conform to this standard to be compatible with the Network.
|
||||
|
||||
#### 5.3.2 Consensus Standards
|
||||
The Foundation shall set minimum standards for notary clusters, to allow their use across different business
|
||||
applications. The Operator shall ensure that standards are followed by notary service providers, and shall operate a
|
||||
framework of audit and assessment, review, feedback, and certification, covering the following:
|
||||
|
||||
1. Technical standards, such as meeting strict requirements for high-availability and data replication/security and
|
||||
performance.
|
||||
2. Compliance with necessary laws and regulations (for example privacy and data retention regulations) in the
|
||||
jurisdictions in which they operate.
|
||||
3. Availability for independent audits upon request by the Board.
|
||||
|
||||
Additionally, the Operator shall manage a reference distributed notary service for the Network, using a Board-approved
|
||||
crash or Byzantine fault tolerant (BFT) consensus algorithm, with nodes provided by a minimum number of identified and
|
||||
independent entities.
|
||||
|
||||
#### 5.3.3 Dispute Resolution Process
|
||||
Disputes between Participants arising from the operation of a Corda application are anticipated to be resolved by the
|
||||
business network operator, or directly if no business network is involved. If necessary, Participants may escalate to
|
||||
the Board by creating an Advisory Governance Event.
|
||||
|
||||
5.4 Emergency Governance Events
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Certain Network incidents, which could impact one or more Network participants and that would be the subject of
|
||||
Mandatory or Advisory Governance Events, shall require immediate resolution. In these cases, the Operator may make
|
||||
emergency changes, but these shall be subject to post-event evaluation and standard Governance Event processing. Areas
|
||||
of control that are the subject of Mandatory Governance Events are not expected to require emergency remediation, but
|
||||
the Operator shall be entitled to make emergency changes to preserve the stability and integrity of the Network.
|
||||
|
||||
5.5 Voting
|
||||
^^^^^^^^^^
|
||||
All Constitutional, Mandatory and Advisory Governance Events outlined in sections 5.2 and 5.3 shall be presented to the
|
||||
Board for voting. The representatives of the Board shall vote on a one vote per Director basis to approve or reject the
|
||||
Governance Event.
|
||||
|
||||
Quorum for the Board shall require two thirds of the Directors to vote. Abstention is not a vote. The Board may continue
|
||||
to meet if quorum is not met, but shall be prevented from making any decisions at the meeting. Decisions by electronic
|
||||
vote without a meeting shall require a vote by two thirds majority of all Directors.
|
||||
|
||||
Provided quorum is met, Constitutional Governance Events shall require a three quarters majority vote, and Mandatory
|
||||
Governance Events shall require a two thirds majority vote.
|
||||
|
||||
In the event of a tied vote (the odd number of representatives is intended to avoid tied votes) the vote of the Chair
|
||||
shall carry the vote. If the Chair does not vote in the case of a tied vote, the Event will not be passed.
|
||||
|
||||
All Governance Events proposed for consideration by the Board at a meeting shall be circulated in draft form to the
|
||||
members of the Board at least one week prior to the date of the meeting, and the text of such draft events may be altered
|
||||
at the meeting.
|
||||
|
||||
The Foundation may chose to implement the tracking and voting for Governance Events using an on-ledger Corda application
|
||||
in an attempt to simplify governance, provide transparency and lower costs, provided the application has been tested
|
||||
thoroughly and has sufficient manual override controls.
|
||||
|
||||
6 Participation
|
||||
-----------------
|
||||
|
||||
6.1 General Membership
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
Participation is open to any potential participant on the Network, subject to meeting normal Network access conditions
|
||||
described in section 5.2.1, and paying a nominal annual participation fee to cover both the operational costs of Network
|
||||
services and the Foundation, and to ensure that its activities are sufficiently resourced.
|
||||
|
||||
The Participant Community have the right to:
|
||||
|
||||
1. Propose a formal Governance Event to the Board for voting. This must meet the appropriate standards and formats.
|
||||
2. Request observer representation at a board meeting subject to logistical constraints.
|
||||
3. Utilise any brand and marketing materials that may be provided by the Foundation to Participants.
|
||||
4. Identify themselves as participants of the Foundation.
|
||||
5. Vote in the periodic election of a new Board.
|
||||
6. Participate in conferences, projects and initiatives of the Foundation. Numbers of participants and any additional
|
||||
costs will depend on the individual event.
|
||||
7. Receive an identity necessary to operate a Corda node on the Network.
|
||||
8. Use the Network for live business activities running 'in production'.
|
||||
|
||||
6.2 Technical Advisory Committee
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The Technical Advisory Committee shall have limited participants appointed directly by the Board. Its mandate and
|
||||
charter will be set by the Board. It shall act directly on the instructions of the Board or the Operator, which shall
|
||||
set expected deliverables and timelines. It shall focus on specific technical topics and may have responsibility for
|
||||
the following:
|
||||
|
||||
1. Advise on technical decisions for the Operator.
|
||||
2. Advising the Board in technical matters.
|
||||
3. Provide feedback on the technical roadmap for Corda, from real-world and practical experience gained from observing
|
||||
the operation of the Network.
|
||||
4. Conducting open design reviews and soliciting public input for technical proposals.
|
||||
5. Contributing to the Corda open source community from a Network perspective, to ensure that Corda retains a coherent,
|
||||
elegant and practical system design
|
||||
|
||||
6.3 Governance Advisory Committee
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The Governance Advisory Committee shall have limited participants appointed directly by the board. Its purpose is to
|
||||
recommend actions to the Board for approval on non-technical matters, where additional support is helpful. This may
|
||||
include decisions on:
|
||||
|
||||
1. Operator Due Diligence
|
||||
2. Identity and Permissions
|
||||
3. Risks and Escalations
|
||||
4. Interacting with Regulators
|
||||
5. Complaints and Whistle-blowing
|
||||
|
||||
7 The Corda Network Operator
|
||||
----------------------------
|
||||
|
||||
In order to pursue the mission of the Foundation as set out in section 1, there will need to be a set of operational
|
||||
activities, including technical activities such as hosting services, marketing activities, community management and
|
||||
promotion. These activities shall be funded through the participation fees and overseen by the Board, and they will
|
||||
require operational staffing by the Operator. It is not envisaged (at least during the first year) that the Corda
|
||||
Network Foundation will need separate staff. Administrative operations and meeting facilities will be provided by the
|
||||
Operator.
|
||||
|
||||
The Operator shall invoice the Foundation for the costs of operating the Network and minor administrative expenses,
|
||||
initially on a cost-plus basis, and subject to annual review. Corda Network identity and map technical services
|
||||
have been designed to be highly cacheable, and low-cost in operation.
|
||||
|
||||
For the first three years, R3 shall act as the Operator.
|
||||
|
||||
8 Costs and Participation Fees
|
||||
------------------------------
|
||||
|
||||
8.1 Costs
|
||||
^^^^^^^^^
|
||||
In line with the mission and values of the Foundation, the Network Foundation is not a profit seeking entity. But the
|
||||
Foundation needs to provide governance and technical services, and these will incur costs. The Foundation maintains these
|
||||
cost principles, as ideals but not contractual standards:
|
||||
|
||||
1. Costs for all services should be borne by all users of those services.
|
||||
2. One group of participants should not subsidise another.
|
||||
3. The costs shall be tightly managed, and the Foundation shall seek to provide the most cost-effective implementation
|
||||
of all of its own administration, governance and technical services.
|
||||
4. Costs of one service should not be subsidised by another.
|
||||
5. The Foundation's cost model should be public, to demonstrate that the costs could not reasonably be lower.
|
||||
|
||||
8.2 Participation Fee
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
The Foundation shall meet costs by levying a participation fee and notary fee for all Participants. The participation
|
||||
fee will be independent of organisation size and number of transactions on Corda, to reflect the underlying cost of
|
||||
identity issuance.
|
||||
|
||||
The fee shall be based on the number of Participants divided by an estimate of the cost of running the Foundation,
|
||||
which is set out in section 7. There may be variance in the fee depending on whether the Participant is indirectly using a
|
||||
Corda Network-powered application, and therefore the services which the Participant is able to access.
|
||||
|
||||
Such fees shall be detailed in a separate schedule to be updated annually and approved by the Board by a Mandatory
|
||||
Governance Event.
|
||||
|
||||
The Operator may agree to provide the Foundation with a start-up commercial loan, in order to allow the Foundation to
|
||||
cap fees for Participants initially. This will allow early widespread adoption, when early participant numbers will not
|
||||
offset fixed operating costs. In this case, the fees will not fall to steady-state levels until the loan has been repaid.
|
||||
|
||||
Subsidiaries of large organisations shall apply for membership separately, since the model for Corda usage is for one
|
||||
identity per legal entity, unless varied by Mandatory Governance Event. The fee and voting right shall apply to each
|
||||
subsidiary individually.
|
||||
|
||||
The fee applies even if the Participants chooses not to operate a Corda node on the Network. Therefore, Participants
|
||||
can be potential or active participants.
|
||||
|
||||
8.3 Notary Fee
|
||||
^^^^^^^^^^^^^^
|
||||
Transaction notary fees will be charged separately, on a per-use basis. This reflects the variable cost of providing
|
||||
notary services, with a wide orders-of-magnitude disparity between frequent and infrequent participant transaction
|
||||
volumes. As a principle, notary fees shall not subsidise participation fees, nor vice versa.
|
||||
|
||||
9 Community
|
||||
-----------
|
||||
Corda is a collaborative effort, and part of the Foundation’s mission is to help create and foster a technical community
|
||||
that will benefit all Corda solution providers and users. As such, the Foundation will work to encourage further
|
||||
participation of leading Participants of the ecosystem, including developers, service and solution providers and end
|
||||
users. This community shall work towards furthering the adoption of Corda, and contribute to the specific capabilities
|
||||
identified in the technical white paper.
|
||||
|
||||
The Corda technical community should be broad and open, encouraging participation and active conversations on the
|
||||
technology and applications, but this cannot be mandated by the Foundation.
|
||||
|
||||
9.1 Non-Discrimination
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
The Foundation will welcome any organization able to meet the Participation criteria, regardless of competitive
|
||||
interests with other Participants. The Board shall not seek to exclude any Participant for any reasons other than those
|
||||
that are reasonable, explicit and applied on a non-discriminatory basis to all Participants.
|
||||
|
||||
END
|
@ -1,31 +0,0 @@
|
||||
Governance Structure
|
||||
====================
|
||||
|
||||
It is critically important that a commercial entity should not control Corda Network going forwards, and that it should
|
||||
be governed transparently, with a fair and representative structure that can deliver a stable operating environment for
|
||||
its members in the long term.
|
||||
|
||||
A separate entity called Corda Network Foundation will be set up, using a not-for-profit legal entity type known as a
|
||||
Stichting, residing in the Netherlands. This type is suited for governance activities, able to act commercially, with
|
||||
limited liability but no shareholders, capital or dividends. Its constitution is defined in a set of Articles of
|
||||
Association and By-laws.
|
||||
|
||||
A Foundation will enable Network members to be involved with, and also understand, how decisions are made (including
|
||||
around issues of identity and permission), building trust and engagement from a wide range of stakeholders. We believe
|
||||
this will bring about the best decisions and outcomes for the Network’s long-term success.
|
||||
|
||||
Its governance bodies shall include:
|
||||
|
||||
- A **Governing Board** (‘the Board’) of 11 representatives (‘Directors’).
|
||||
- A **Technical Advisory Committee** (‘the TAC’), comprised of representatives of Participant organisations.
|
||||
- A **Governance Advisory Committee**, comprised of representatives of Participant organisations.
|
||||
- A **Network Operator** (‘the Operator’), charging the Foundation reasonable costs for providing network and administration
|
||||
services, paid by the Foundation through membership funds, and accountable directly to the Board.
|
||||
|
||||
Operating on behalf of:
|
||||
|
||||
- **Participants** (‘Participants’), open to any legal entity participating in Corda Network, and independent of R3
|
||||
alliance membership.
|
||||
|
||||
For more information about the intended governance of the network, please refer to the [Corda Network Foundation :
|
||||
Governance Guidelines](governance-guidelines.md) document.
|
@ -3,60 +3,65 @@ Corda Network
|
||||
|
||||
Introduction to Corda Network
|
||||
-----------------------------
|
||||
Corda Network consists of Corda nodes operated by network participants, in which business transactions are created and
|
||||
validated via Corda Distributed Applications (CorDapps) running on these nodes. Each node is identified by means of a
|
||||
certificate issued by the Network's Certificate Authority, and will also be identifiable on a network map.
|
||||
[Corda Network](https://corda.network/) is a publicly-available internet of Corda nodes operated by network participants. Each
|
||||
node is identified by a certificate issued by the network's identity service, and will also be discoverable on a network map.
|
||||
|
||||
Corda Network enables interoperability – the exchange of data or assets via a secure, efficient internet layer – in a way
|
||||
that isn't possible with competing permissioned distributed ledger technologies or legacy systems.
|
||||
that isn't possible with separate, isolated Corda networks. A common trust root surrounds all transactions, and a consistent set of
|
||||
network parameters ensures all participants may transact with each other.
|
||||
|
||||
The network is due to go live in December 2018, and initially it will be governed by R3. An independent, not-for-profit
|
||||
Foundation is currently being set-up which is intended to govern the Network from mid 2019, after a transition period
|
||||
when control moves entirely to the Foundation. See the [governance model](governance-structure.md) for more detail.
|
||||
The network went live in December 2018, and is currently governed by R3. An independent, not-for-profit foundation has been
|
||||
set up to govern the network, and a transitional board will be selected from initial participants in Spring 2019, which will oversee
|
||||
the foundation until democratic elections are held a year later. See the [governance model](https://corda.network/governance/governance-guidelines.html)
|
||||
for more detail.
|
||||
|
||||
The Network will comprise many sub-groups many sub-groups of participants running particular CorDapps (sometimes but not
|
||||
always referred to as 'business networks'), and such groups will often have a co-ordinating party (the 'Business
|
||||
Network Operator') who manages the distribution of the app and rules (including around membership) for its use.
|
||||
The network will support many sub-groups of participants running particular CorDapps (sometimes referred to as 'business networks'),
|
||||
and these groups will often have a co-ordinating party (the 'business network operator') who manages the distribution of the
|
||||
app and rules, including membership, for its use. There is a clear separation between areas of control for the network as a whole
|
||||
and for individual business networks. Like the internet, Corda Network intends to exist as a background utility.
|
||||
|
||||
Corda Network will support the operation of business networks by industry-specific operators within the Network. There
|
||||
will be a clear separation between areas of governance for the Network and for individual business networks. For example,
|
||||
rules around membership of business networks will be controlled by its Business Network Operators.
|
||||
The main benefit of Corda Network for participants is being able to move cash, digital assets, and identity data from one application
|
||||
or line of business to another. Business network operators also benefit by being able to access network-wide services, and reuse the
|
||||
[trust root](https://corda.network/trust-root/index.html) and network services, instead of building and managing their own.
|
||||
|
||||
The Corda Network website has a [high level overview](https://corda.network/participation/implementation-steps.html) of the joining process.
|
||||
|
||||
Key services
|
||||
============
|
||||
|
||||
Doorman
|
||||
-------
|
||||
The Doorman controls admissions and exits of Participants into and out of Corda Network. The Service receives Certificate
|
||||
Signing Requests (CSRs) from prospective Network Participants (sometimes via a Business Network Operator) and reviews the
|
||||
information submitted. A digitally signed Participation Certificate is returned if:
|
||||
Identity Service
|
||||
----------------
|
||||
The Identity Service controls admissions of participants into Corda Network. The service receives certificate
|
||||
signing requests (CSRs) from prospective network participants (sometimes via a business network operator) and reviews the
|
||||
information submitted. A digitally signed participation certificate is returned if:
|
||||
|
||||
* The prospective Corda Network Participant meets the requirements specified in the documentation;
|
||||
* Evidence is provided by the Participant or Business Network Operator of agreement to the Corda Network Participant Terms
|
||||
of Use.
|
||||
* The participant meets the requirements specified in the [bylaws and policies](https://corda.network/policy/admission-criteria.html)
|
||||
of the foundation (broadly speaking, limited to sanction screening only);
|
||||
* The participant agrees to Corda Network participant [terms of use](https://corda.network/participation/terms-of-use.html).
|
||||
|
||||
The Corda Network Participant can then use the Participation Certificate to register itself with the R3 Network Map Service.
|
||||
The Corda Network node can then use the participation certificate to register itself with the Network Map Service.
|
||||
|
||||
Network Map
|
||||
-----------
|
||||
Network Map Service
|
||||
-------------------
|
||||
The Network Map Service accepts digitally signed documents describing network routing and identifying information from
|
||||
Participants, based on the Participation Certificates signed by the Doorman, and makes this information available to all
|
||||
Corda Network Participants.
|
||||
nodes, based on the participation certificates signed by the Identity Service, and makes this information available to all
|
||||
Corda Network nodes.
|
||||
|
||||
Notary
|
||||
------
|
||||
Corda design separates correctness consensus from uniqueness consensus, and the latter is provided by one or more Notary
|
||||
services. The Notary will digitally sign a transaction presented to it - provided no transaction referring to
|
||||
Notary Service
|
||||
--------------
|
||||
The Corda design separates correctness consensus from uniqueness consensus, and the latter is provided by one or more Notary
|
||||
Services. The Notary will digitally sign a transaction presented to it, provided no transaction referring to
|
||||
any of the same inputs has been previously signed by the Notary, and the transaction timestamp is within bounds.
|
||||
|
||||
Business Network Operators and Network Participants may choose to enter into legal agreements which rely on the presence
|
||||
Business network operators and network participants may choose to enter into legal agreements which rely on the presence
|
||||
of such digital signatures when determining whether a transaction to which they are party, or upon the details of which they
|
||||
otherwise rely, is to be treated as 'confirmed' in accordance with the terms of the underlying agreement.
|
||||
|
||||
Support
|
||||
-------
|
||||
The Support Service is provided to Participants and Business Network Operators to manage / resolve inquiries and incidents
|
||||
relating to the Doorman, Network Map Service and Notary Service, and any other relevant services.
|
||||
|
||||
Support Service
|
||||
---------------
|
||||
The Support Service is provided to participants and business network operators to manage and resolve inquiries and incidents
|
||||
relating to the Identity Service, Network Map Service and Notary Services.
|
||||
|
||||
CRL configuration
|
||||
-----------------
|
||||
@ -71,5 +76,3 @@ In order to use this, add the following to your configuration file:
|
||||
|
||||
This set-up ensures that the TLS-level certificates are embedded with the CRL distribution point referencing the CRL issued by R3.
|
||||
In cases where a proprietary CRL infrastructure is provided those values need to be changed accordingly.
|
||||
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
Joining Corda Network
|
||||
=====================
|
||||
|
||||
Corda Network participation requires each node to possess a recognised Certificate Authority (CA) signed certificate
|
||||
(“Participation Certificate”), which is used to derive other digital certificates required (such as legal entity signing
|
||||
certificates and TLS certificates).
|
||||
|
||||
Identity certificates must be issued by the Corda Network Operator (Doorman / Network Map), which guarantees that the identity
|
||||
listed on the certificate is uniquely held by a single party within the network.
|
||||
|
||||
A high-level outline of steps to join the Network is listed below. This assumes that Participants wish to operate a node
|
||||
and already have access to at least one CorDapp which they wish to deploy. A more detailed step-by-step guide will soon
|
||||
be available.
|
||||
|
||||
1. Obtain Corda software - either the Enterprise version, via a Corda sales representative, or the open source version
|
||||
through [github](https://github.com/corda).
|
||||
2. For the time being, request the trust root certificate from Corda Network Doorman, by emailing doorman@r3.com, which
|
||||
will be sent back as a truststore.jks file. In future, the Corda Network trust root will be packaged in the software
|
||||
distribution.
|
||||
3. [Start the node](https://docs.corda.net/deploying-a-node.html) - where applicable, with help from a Corda
|
||||
representative.
|
||||
4. [Configure the node](https://docs.corda.net/corda-configuration-file.html) – a node.conf file must be included in the
|
||||
root directory of every Corda node. This includes: specifying an email address in relation to the certificate signing
|
||||
request as well as choosing a distinguished name.
|
||||
5. Run the initial registration. This will send a Certificate Signing Request (with the relevant name and email) to the
|
||||
Network Manager service (Doorman / Network Map).
|
||||
6. Sign Participant terms of use, either directly or indirectly:
|
||||
* **Sponsored model**: A Business Network Operator (BNO) requesting approval for a certificate on behalf of the Participant.
|
||||
* **Direct model**: The Participant requesting a certificate for themselves.
|
||||
7. Doorman verification checks – a number of identity-related checks will be conducted, before issuing a certificate,
|
||||
including email and legal entity checks.
|
||||
8. Once identity checks have been completed, a signed CA certificate will be released by the Doorman to the
|
||||
node.
|
||||
9. Completion - the node will then sign its node IP address and submit it to the Network Map, for broadcast to other
|
||||
Participant nodes.
|
||||
|
@ -1,3 +1,9 @@
|
||||
.. highlight:: groovy
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/codesets.js"></script>
|
||||
|
||||
Building and installing a CorDapp
|
||||
=================================
|
||||
|
||||
@ -22,11 +28,11 @@ Build tools
|
||||
In the instructions that follow, we assume you are using Gradle and the ``cordformation`` plugin to build your
|
||||
CorDapp. You can find examples of building a CorDapp using these tools in the
|
||||
`Kotlin CorDapp Template <https://github.com/corda/cordapp-template-kotlin>`_ and the
|
||||
`Java CorDapp Template <https://github.com/corda/cordapp-template-kotlin>`_.
|
||||
`Java CorDapp Template <https://github.com/corda/cordapp-template-java>`_.
|
||||
|
||||
To ensure you are using the correct version of Gradle, you should use the provided Gradle Wrapper by copying across
|
||||
the following folder and files from the `Kotlin CorDapp Template <https://github.com/corda/cordapp-template-kotlin>`_ or the
|
||||
`Java CorDapp Template <https://github.com/corda/cordapp-template-kotlin>`_ to the root of your project:
|
||||
`Java CorDapp Template <https://github.com/corda/cordapp-template-java>`_ to the root of your project:
|
||||
|
||||
* ``gradle/``
|
||||
* ``gradlew``
|
||||
@ -49,7 +55,7 @@ Several ``ext`` variables are used in a CorDapp's ``build.gradle`` file to defin
|
||||
versions can be found here: https://bintray.com/r3/corda/cordapp. If in doubt, you should base yourself on the version
|
||||
numbers used in the ``build.gradle`` file of the
|
||||
`Kotlin CorDapp Template <https://github.com/corda/cordapp-template-kotlin>`_ and the
|
||||
`Java CorDapp Template <https://github.com/corda/cordapp-template-kotlin>`_.
|
||||
`Java CorDapp Template <https://github.com/corda/cordapp-template-java>`_.
|
||||
|
||||
For example, to use version 3.0 of Corda, version 3.0.8 of the Corda gradle plugins, version 0.7.9 of Quasar, and
|
||||
version 1.1.60 of Kotlin, you'd write:
|
||||
@ -99,9 +105,10 @@ Here is an overview of the various Corda dependencies:
|
||||
functionality. Include manually if the utilities are useful or you are writing a library for Corda
|
||||
* ``corda-core-deterministic`` - Used by the Corda node for deterministic contracts. Not likely to be used externally
|
||||
* ``corda-djvm`` - Used by the Corda node for deterministic contracts. Not likely to be used externally
|
||||
* ``corda-finance`` - The Corda finance CorDapp. Only include as a ``cordaCompile`` dependency if using as a dependent
|
||||
Cordapp or if you need access to the Corda finance types. Use as a ``cordapp`` dependency if using as a CorDapp
|
||||
dependency (see below)
|
||||
* ``corda-finance-contracts``, ``corda-finance-workflows`` and deprecated ``corda-finance``. Corda finance CorDapp, use contracts and flows parts respectively.
|
||||
``corda-finance`` is left for backward compatibility purposes and should be replaced by former two where needed.
|
||||
Only include as a ``cordaCompile`` dependency if using as a dependent Cordapp or if you need access to the Corda finance types.
|
||||
Use as a ``cordapp`` dependency if using as a CorDapp dependency (see below)
|
||||
* ``corda-jackson`` - Corda Jackson support. Use if you plan to serialise Corda objects to and/or from JSON
|
||||
* ``corda-jfx`` - JavaFX utilities with some Corda-specific models and utilities. Only use with JavaFX apps
|
||||
* ``corda-mock`` - A small library of useful mocks. Use if the classes are useful to you
|
||||
@ -109,8 +116,6 @@ Here is an overview of the various Corda dependencies:
|
||||
frameworks
|
||||
* ``corda-node-api`` - The node API. Required to bootstrap a local network
|
||||
* ``corda-node-driver`` - Testing utility for programmatically starting nodes from JVM languages. Use for tests
|
||||
* ``corda-notary-bft-smart`` - A Corda notary implementation
|
||||
* ``corda-notary-raft`` - A Corda notary implementation
|
||||
* ``corda-rpc`` - The Corda RPC client library. Used when writing an RPC client
|
||||
* ``corda-serialization`` - The Corda core serialization library. Automatically included by other dependencies
|
||||
* ``corda-serialization-deterministic`` - The Corda core serialization library. Automatically included by other
|
||||
@ -126,7 +131,7 @@ Here is an overview of the various Corda dependencies:
|
||||
|
||||
Dependencies on other CorDapps
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
You CorDapp may also depend on classes defined in another CorDapp, such as states, contracts and flows. There are two
|
||||
Your CorDapp may also depend on classes defined in another CorDapp, such as states, contracts and flows. There are two
|
||||
ways to add another CorDapp as a dependency in your CorDapp's ``build.gradle`` file:
|
||||
|
||||
* ``cordapp project(":another-cordapp")`` (use this if the other CorDapp is defined in a module in the same project)
|
||||
@ -288,7 +293,7 @@ Example
|
||||
Below is a sample of what a CorDapp's Gradle dependencies block might look like. When building your own CorDapp, you
|
||||
should base yourself on the ``build.gradle`` file of the
|
||||
`Kotlin CorDapp Template <https://github.com/corda/cordapp-template-kotlin>`_ or the
|
||||
`Java CorDapp Template <https://github.com/corda/cordapp-template-kotlin>`_.
|
||||
`Java CorDapp Template <https://github.com/corda/cordapp-template-java>`_.
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
@ -297,7 +302,8 @@ should base yourself on the ``build.gradle`` file of the
|
||||
dependencies {
|
||||
// Corda integration dependencies
|
||||
cordaCompile "net.corda:corda-core:$corda_release_version"
|
||||
cordaCompile "net.corda:corda-finance:$corda_release_version"
|
||||
cordaCompile "net.corda:corda-finance-contracts:$corda_release_version"
|
||||
cordaCompile "net.corda:corda-finance-workflows:$corda_release_version"
|
||||
cordaCompile "net.corda:corda-jackson:$corda_release_version"
|
||||
cordaCompile "net.corda:corda-rpc:$corda_release_version"
|
||||
cordaCompile "net.corda:corda-node-api:$corda_release_version"
|
||||
@ -340,6 +346,9 @@ This is typically done by appending the version string to the CorDapp's name. Th
|
||||
once the JAR has been deployed on a node. If it does, make sure no one is relying on ``FlowContext.appName`` in their
|
||||
flows (see :doc:`versioning`).
|
||||
|
||||
|
||||
.. _cordapp_install_ref:
|
||||
|
||||
Installing the CorDapp JAR
|
||||
--------------------------
|
||||
|
||||
@ -465,4 +474,36 @@ For a CorDapp that contains flows and/or services we specify the `workflow` tag:
|
||||
}
|
||||
}
|
||||
|
||||
.. note:: It is possible, but *not recommended*, to include everything in a single CorDapp jar and use both the ``contract`` and ``workflow`` Gradle plugin tags.
|
||||
.. note:: It is possible, but *not recommended*, to include everything in a single CorDapp jar and use both the ``contract`` and ``workflow`` Gradle plugin tags.
|
||||
|
||||
.. _cordapp_contract_attachments_ref:
|
||||
|
||||
CorDapp Contract Attachments
|
||||
----------------------------
|
||||
|
||||
As of Corda 4, CorDapp Contract JARs must be installed on a node by a trusted uploader, either by
|
||||
|
||||
- installing manually as per :ref:`Installing the CorDapp JAR <cordapp_install_ref>` and re-starting the node.
|
||||
|
||||
- uploading the attachment JAR to the node via RPC, either programmatically (see :ref:`Connecting to a node via RPC <clientrpc_connect_ref>`)
|
||||
or via the :doc:`shell` by issuing the following command:
|
||||
|
||||
``>>> run uploadAttachment jar: path/to/the/file.jar``
|
||||
|
||||
Contract attachments that are received from a peer over the p2p network are considered **untrusted** and will throw a `UntrustedAttachmentsException` exception
|
||||
when processed by a listening flow that cannot resolve that attachment from its local attachment storage. The flow will be aborted and sent to the nodes flow hospital for recovery and retry.
|
||||
The untrusted attachment JAR will be stored in the nodes local attachment store for review by a node operator. It can be downloaded for viewing using the following CRaSH shell command:
|
||||
|
||||
``>>> run openAttachment id: <hash of untrusted attachment given by `UntrustedAttachmentsException` exception``
|
||||
|
||||
Should the node operator deem the attachment trustworthy, they may then issue the following CRaSH shell command to reload it as trusted:
|
||||
|
||||
``>>> run uploadAttachment jar: path/to/the/trusted-file.jar``
|
||||
|
||||
and subsequently retry the failed flow (currently this requires a node re-start).
|
||||
|
||||
.. note:: this behaviour is to protect the node from executing contract code that was not vetted. It is a temporary precaution until the
|
||||
Deterministic JVM is integrated into Corda whereby execution takes place in a sandboxed environment which protects the node from malicious code.
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,151 @@
|
||||
# Migration from the hash constraint to the Signature constraint
|
||||
|
||||
|
||||
## Background
|
||||
|
||||
Corda pre-V4 only supports HashConstraints and the WhitelistedByZoneConstraint.
|
||||
The default constraint, if no entry was added to the network parameters is the hash constraint.
|
||||
Thus, it's very likely that most first states were created with the Hash constraint.
|
||||
|
||||
When changes will be required to the contract, the only alternative is the explicit upgrade, which creates a new contract, but inherits the HashConstraint (with the hash of the new jar this time).
|
||||
|
||||
**The current implementation of the explicit upgrade does not support changing the constraint.**
|
||||
|
||||
It's very unlikely that these first deployments actually wanted a non-upgradeable version.
|
||||
|
||||
This design doc is presenting a smooth migration path from the hash constraint to the signature constraint.
|
||||
|
||||
|
||||
## Goals
|
||||
|
||||
CorDapps that were released (states created) with the hash constraint should be able to transition to the signature constraint if the original developer decides to do that.
|
||||
|
||||
A malicious party should not be able to attack this feature, by "taking ownership" of the original code.
|
||||
|
||||
|
||||
## Non-Goals
|
||||
|
||||
Migration from the whitelist constraint was already implemented. so will not be addressed. (The cordapp developer or owner just needs to sign the jar and whitelist the signed jar.)
|
||||
|
||||
Also versioning is being addressed in different design docs.
|
||||
|
||||
|
||||
## Design details
|
||||
|
||||
### Requirements
|
||||
|
||||
To migrate without disruption from the hash constraint, the jar that is attached to a spending transaction needs to satisfy both the hash constraint of the input state, as well as the signature constraint of the output state.
|
||||
|
||||
Also, it needs to reassure future transaction verifiers - when doing transaction resolution - that this was a legitimate transition, and not a malicious attempt to replace the contract logic.
|
||||
|
||||
|
||||
### Process
|
||||
|
||||
To achieve the first part, we can create this convention:
|
||||
|
||||
- Developer signs the original jar (that was used with the hash constraint).
|
||||
- Nodes install it, thus whitelisting it.
|
||||
- The HashConstraint.verify method will be modified to verify the hash with and without signatures.
|
||||
- The nodes create normal transactions that spend an input state with the hashConstraint and output states with the signature constraint. No special spend-to-self transactions should be required.
|
||||
- This transaction would validate correctly as both constraints will pass - the unsigned hash matches, and the signatures are there.
|
||||
- This logic needs to be added to the constraint propagation transition matrix. This could be only enabled for states created pre-v4, when there was no alternative.
|
||||
|
||||
|
||||
For the second part:
|
||||
|
||||
- The developer needs to claim the package (See package ownership). This will give confidence to future verifiers that it was the actual developer that continues to be the owner of that jar.
|
||||
|
||||
|
||||
To summarise, if a CorDapp developer wishes to migrate to the code it controls to the signature constraint for better flexibility:
|
||||
|
||||
1. Claim the package.
|
||||
2. Sign the jar and distribute it.
|
||||
3. In time all states will naturally transition to the signature constraint.
|
||||
4. Release new version as per the signature constraint.
|
||||
|
||||
|
||||
A normal node would just download the signed jar using the normal process for that, and the platform will do the rest.
|
||||
|
||||
|
||||
### Caveats
|
||||
|
||||
###### Someone really wants to issue states with the HashConstraint, and ensure that can never change.
|
||||
|
||||
- As mentioned above the transaction builder could only automatically transition states created pre-v4.
|
||||
|
||||
- If this is the original developer of the cordapp, then they can just hardcode the check in the contract that the constraint must be the HashConstraint.
|
||||
|
||||
- It is actually a third party that uses a contract it doesn't own, but wants to ensure that it's only that code that is used.
|
||||
This should not be allowed, as it would clash with states created without this constraint (that might have higher versions), and create incompatible states.
|
||||
The option in this case is to force such parties to actually create a new contract (maybe subclass the version they want), own it, and hardcode the check as above.
|
||||
|
||||
|
||||
###### Some nodes haven't upgraded all their states by the time a new release is already being used on the network.
|
||||
|
||||
- A transaction mixing an original HashConstraint state, and a v2 Signature constraint state will not pass. The only way out is to strongly "encourage" nodes to upgrade before the new release.
|
||||
|
||||
The problem is that, in a transaction, the attachment needs to pass the constraint of all states.
|
||||
|
||||
If the rightful owner took over the contract of states originally released with the HashConstraint, and started releasing new versions then the following might happen:
|
||||
|
||||
- NodeA did not migrate all his states to the Signature Constraint.
|
||||
- NodeB did, and already has states created with version 2.
|
||||
- If they decide to trade, NodeA will add his HashConstraint state, and NodeB will add his version2 SignatureConstraint state to a new transaction.
|
||||
This is an impossible transaction. Because if you select version1 of the contract you violate the non-downgrade rule. If you select version2 , you violate the initial HashConstraint.
|
||||
|
||||
|
||||
Note: If we consider this to be a real problem, then we can implement a new NoOp Transaction type similar to the Notary change or the contract upgrade. The security implications need to be considered before such work is started.
|
||||
Nodes could use this type of transaction to change the constraint of existing states without the need to transact.
|
||||
|
||||
|
||||
### Implementation details
|
||||
|
||||
- Create a function to return the hash of a signed jar after it stripped the signatures.
|
||||
- Change the HashConstraint to check against any of these 2 hashes.
|
||||
- Change the transaction builder logic to automatically transition constraints that are signed, owned, etc..
|
||||
- Change the constraint propagation transition logic to allow this.
|
||||
|
||||
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
### Migrating from the HashConstraint to the SignatureConstraint via the WhitelistConstraint.
|
||||
|
||||
We already have a strategy to migrate from the WhitelistConstraint to the Signature contraint:
|
||||
|
||||
- Original developer (owner) signs the last version of the jar, and whitelists the signed version.
|
||||
- The platform allows transitioning to the SignatureConstraint as long as all the signers of the jar are in the SignatureConstraint.
|
||||
|
||||
|
||||
We could attempt to extend this strategy with a HashConstraint -> WhitelistConstraint path.
|
||||
|
||||
#### The process would be:
|
||||
|
||||
- Original developer of the contract that used the hashConstraint will make a whitelist contract request, and provide both the original jar and the original jar but signed.
|
||||
- The zone operator needs to make sure that this is the original developer who claims ownership of that corDapp.
|
||||
|
||||
##### Option 1: Skip the WhitelistConstraint when spending states. (InputState = HashConstraint, OutputState = SignatureConstraint)
|
||||
|
||||
- This is not possible as one of the 2 constraints will fail.
|
||||
- Special constraint logic is needed which is risky.
|
||||
|
||||
|
||||
##### Option 2: Go through the WhitelistConstraint when spending states
|
||||
|
||||
- When a state is spent, the transaction builder sees there is a whitelist constraint, and selects the first entry.
|
||||
- The transition matrix will allow the transition from hash to Whitelist.
|
||||
- Next time the state is spent, it will transition from the Whitelist constraint to the signature constraint.
|
||||
|
||||
|
||||
##### Advantage:
|
||||
|
||||
- The tricky step of removing the signature from a jar to calculate the hash is no longer required.
|
||||
|
||||
|
||||
##### Disadvantage:
|
||||
|
||||
- The transition will happen in 2 steps, which will add another layer of surprise and of potential problems.
|
||||
- The No-Op transaction will become mandatory for this, along with all the complexity it brings (all participants signing). It will need to be run twice.
|
||||
- An unnecessary whitelist entry is added. If that developer also decides to claim the package (as probably most will do in the beginning), it will grow the network parameters and increase the workload on the Zone Operator.
|
||||
- We create an unintended migration path from the HashConstraint to the WhitelistConstraint.
|
398
docs/source/design/versioning/contract-versioning.md
Normal file
398
docs/source/design/versioning/contract-versioning.md
Normal file
@ -0,0 +1,398 @@
|
||||
# Contract versioning and ensuring data integrity
|
||||
|
||||
|
||||
## Terminology used in this document:
|
||||
|
||||
- ContractJAR = The code that contains the: State, Command, Contract and (optional) custom persistent Schema. This code is used to verify transactions and is stored on the ledger as an Attachment. (TODO: Find a better name.)
|
||||
- FlowsJAR = Code that contains the flows and services. This is installed on the node and exposes endpoints. (TODO: Find a better name.)
|
||||
- CorDapp = Distributed applications that run on the Corda platform (https://docs.corda.net/cordapp-overview.html). This term does not mean anything in this document, because it is including both of the above!
|
||||
- Attachment = A file that is stored on the "ledger" and is referenced by it's hash. In this document it is usually the ContractJAR.
|
||||
- Contract = The class that contains the verification logic. (lives in the ContractJar)
|
||||
- State schema or State = the fields that compose the ContractState class.
|
||||
|
||||
|
||||
## Background:
|
||||
|
||||
This document addresses "Corda as a platform for applications" concerns.
|
||||
|
||||
These applications that run on Corda - CorDapps - as opposed to other blockchains are allowed to be updated to fix bugs and address new requirements.
|
||||
|
||||
Corda also allows a lot of flexibility so CorDapps can depend on other CorDapps, which have different release cycles, and participants on the network can have any combination installed.
|
||||
|
||||
This document is focused mainly on the "ContractJar" part of the CorDapps, as this is the Smart contract that lives on the ledger.
|
||||
|
||||
Starting with version 3, Corda has introduced the WhitelistedByZone Contract Constraint, which is the first constraint that allows the contract and contract state type to evolve.
|
||||
In version 4 we will introduce the decentralized Signature Constraint, which is also an upgradable (allows evolving) constraint.
|
||||
This introduces a set of new problems that were not present when the Hash Constraint was the only alternative. (The Hash Constraint is non-upgradeable, as it pins the jar version to the hardcoded hash. It can only be upgraded via the "explicit" mechanism.)
|
||||
|
||||
E.g.:
|
||||
Developer MegaCorp develops a token contract: `com.megacorp.tokens.MegaToken`.
|
||||
As various issues are discovered, and requirements change over time, MegaCorp constantly releases new versions and distributes them to node operators, who can use these new versions for new transactions.
|
||||
These versions could in theory either change the verification logic, change the meaning of various state fields, or even add/remove/rename fields.
|
||||
|
||||
Also, this means that at any point in time, different nodes may have different versions of MegaToken installed. (and the associated MegaFlows that build transactions using this contract). But these nodes still need to communicate.
|
||||
|
||||
Also in the vault of different nodes, there are states created by transactions with various versions of the token contract.
|
||||
|
||||
Corda is designed such that the flow that builds the transaction (on its executing node) will have to choose the contract version that will be used to create the output states and also verify the current transaction.
|
||||
|
||||
But because input states are actually output states that are serialised with the previous transaction (built using a potentially different version of the contract), this means that states serialised with a version of the ContractJAR will need to be deserialisable with a different version.
|
||||
|
||||
|
||||
.. image:: resources/tx-chain.png
|
||||
:scale: 25%
|
||||
:align: center
|
||||
|
||||
|
||||
## Goals
|
||||
|
||||
- States should be correctly deserialized as an input state of a transaction that uses a different release of the contract code.
|
||||
After the input states are correctly deserialised they can be correctly verified by the transaction contract.
|
||||
This is critical for the UTXO model of Corda to function correctly.
|
||||
|
||||
- Define a simple process and basic tooling for contract code developers to ensure a consistent release process.
|
||||
|
||||
- Nodes should be prevented to select older buggy contract code for current transactions.
|
||||
|
||||
- Ensure basic mechanism for flows to not miss essential data when communicating with newer flows.
|
||||
|
||||
|
||||
## Non-Goals
|
||||
|
||||
This design is not about:
|
||||
|
||||
- Addressing security issues discovered in an older version of a contract (that was used in transactions) without compromising the trust in the ledger. (There are proposals for this and can be extracted in a separate doc)
|
||||
- Define the concept of "CorDapp identity" useful when flows or contracts are coded against third-party contracts.
|
||||
- Evolve states from the HashConstraint or the Whitelist constraint (addressed in a separate design).
|
||||
- Publishing And Distribution of applications to nodes.
|
||||
- Contract constraints, package ownership, or any operational concerns.
|
||||
|
||||
## Issues considered but postponed for a future version of corda
|
||||
|
||||
- How releasing new versions of contract code interacts with the explicit upgrade functionality.
|
||||
- How contracts depend on other contracts.
|
||||
- Node to node communication using flows, and what impact different contract versions have on that. (Flows depending on contracts)
|
||||
- Versioning of flows and subflows and backwards compatibility concerns.
|
||||
|
||||
|
||||
### Assumptions and trade-offs made for the current version
|
||||
|
||||
##### We assume that ContractStates will never change their semantics in a way that would impact other Contracts or Flows that depend on them.
|
||||
|
||||
E.g.: If various contracts depend on Cash, the assumption is that no new field will be added to Cash that would have an influence over the amount or the owner (the fundamental fields of Cash).
|
||||
It is always safe to mix new CashStates with older states that depend on it.
|
||||
|
||||
This means that we can simplify the contract-to-contract dependency, also given that the UpgradeableContract is actually a contract that depends on another contract, it can be simplified too.
|
||||
|
||||
This is not a very strong definition, so we will have to create more formalised rules in the next releases.
|
||||
|
||||
If any contract breaks this assumption, in Corda 4 there will be no platform support the transition to the new version. The burden of coordinating with all the other cordapp developers and nodes is on the original developer.
|
||||
|
||||
|
||||
##### Flow to Flow communication could be lossy for objects that are not ContractStates or Commands.
|
||||
|
||||
Explanation:
|
||||
Flows communicate by passing around various objects, and eventually the entire TransactionBuilder.
|
||||
As flows evolve, these objects might evolve too, even if the sequence stays the same.
|
||||
The decision was that the node that sends data would decide (if his version is higher) if this new data is relevant for the other party.
|
||||
|
||||
The objects that live on the ledger like ContractStates and Commands that the other party actually has to sign, will not be allowed to lose any data.
|
||||
|
||||
|
||||
##### We assume that cordapp developers will correctly understand all implications and handle backwards compatibility themselves.
|
||||
Basically they will have to realise that any version of a flow can talk to any other version, and code accordingly.
|
||||
|
||||
This get particularly tricky when there are reusable inline subflows involved.
|
||||
|
||||
|
||||
## Design details
|
||||
|
||||
### Possible attack under the current implementation
|
||||
|
||||
Cordapp developer Megacorp wants to release an update to their cordapp, and add support for accumulating debt on the token (which is a placeholder for something you really want to know about).
|
||||
|
||||
- V1: com.megacorp.token.MegaToken(amount: Amount, owner: Party)
|
||||
- V2: com.megacorp.token.MegaToken(amount: Amount, owner: Party, accumulatedDebt: Amount? = 0)
|
||||
|
||||
After they publish the new release, this sort of scenario could happen if we don't have a mechanism to stop it.
|
||||
|
||||
1. Tx1: Alice transfers MegaToken to Bob, and selects V1
|
||||
2. Tx2: Bob transfers to Chuck, but selects V2. The V1 output state will be deserialised with an accumulatedDebt=0, which is correct.
|
||||
3. After a while, Chuck accumulates some debt on this token.
|
||||
4. Txn: Chuck creates a transaction with Dan, but selects V1 as the contract version for this transaction, thus managing to "lose" the `accumulatedDebt`. (V1 does not know about the accumulatedDebt field)
|
||||
|
||||
|
||||
|
||||
### High level description of the solution
|
||||
|
||||
Currently we have the concept of "CorDapp" and, as described in the terminology section, this makes reasoning harder as it is actually composed of 2 parts.
|
||||
|
||||
Contracts and Flows should be able to evolve and be released independently, and have proper names and their own version, even if they share the same gradle multi-module build.
|
||||
|
||||
Contract states need to be seen as evolvable objects that can be different from one version to the next.
|
||||
|
||||
Corda uses a proprietary serialisation engine based on AMQP, which allows evolution of objects: https://docs.corda.net/serialization-enum-evolution.html.
|
||||
|
||||
We can use features already implemented in the serialisation engine and add new features to make sure that data on the ledger is never lost from one transaction to the next.
|
||||
|
||||
|
||||
### Contract Version
|
||||
|
||||
Contract code should live in it's own gradle module. This is already the way our examples are written.
|
||||
|
||||
The Cordapp gradle plugin should be amended to differentiate between a "flows" module and a "contracts" module.
|
||||
|
||||
In the build.gradle file of the contracts module, there should be a `version` property that needs be incremented for each release.
|
||||
|
||||
This `version' will be used for the regular release, and be part of the jar name.
|
||||
|
||||
Also, when packaging the contract for release, the `version` should be added by the plugin to the manifest file, together with other properties like `target-platform-version.
|
||||
|
||||
When loading the contractJar in the attachment storage, the version should be saved as a column, so it is easily accessible.
|
||||
|
||||
The new cordapp plugin should also be able to deploy nodes with different versions of the code so that developers can test compatibility.
|
||||
|
||||
Ideally the driver should be able to do this too.
|
||||
|
||||
|
||||
#### Alternatives considered
|
||||
|
||||
The version can be of the `major.minor` format, so that developers can encode if they actually make a breaking change or not.
|
||||
Given that we assumed that breaking changes are not supported in this version, we can keep it to a simple `major`.
|
||||
|
||||
|
||||
#### Backwards compatibility
|
||||
|
||||
Contracts released before V4 will not have this metadata.
|
||||
|
||||
Assuming that the constraints propagated correctly, when verifying a transaction where the constraint:
|
||||
|
||||
- is the HashConstraint the contract can be considered to have `version=1`
|
||||
- is the WhitelistedByZoneConstraint the contract can be considered: `version= Order_of_the_hash_in_the_whitelist`
|
||||
|
||||
Any signed ContractJars should be only considered valid if they have the version metadata. (As signing is a Corda4 feature)
|
||||
|
||||
|
||||
|
||||
### Protection against losing data on the ledger
|
||||
|
||||
The solution we propose is:
|
||||
|
||||
- States can only evolve by respecting some predefined rules (see below).
|
||||
- The serialisation engine will need a new `Strict mode` feature to enforce the evolution rules.
|
||||
- The `version` metadata of the contract code can be used to make sure that nodes can't spend a state with an older version (downgrade).
|
||||
|
||||
|
||||
#### Contract State evolution
|
||||
|
||||
States need to follow the general serialisation rules: https://docs.corda.net/serialization-default-evolution.html
|
||||
|
||||
These are the possible evolutions based on these general rules:
|
||||
- Adding nullable fields with default values is OK (deserialising old versions would populate the newer fields with the defaults)
|
||||
- Adding non-nullable fields with default values is OK but requires extra serialisation annotation
|
||||
- Removing fields is NotOK if that field was actually used during verification. (the removed field has to still be used by the verification logic.)
|
||||
- Rename fields NOK ( will be possible in the future when the serialisation engine will support it)
|
||||
- Changing type of field NOK (Serialisation engine would most likely fail )
|
||||
- Deprecating fields OK (as long as it's not removed)
|
||||
|
||||
|
||||
Given the above reasoning, it means that states only support a subset of the general rules. Basically they can only evolve by adding new fields.
|
||||
|
||||
Another way to look at this:
|
||||
|
||||
When Contract.verify is written (and compiled), it is in the same project as the current (from it's point of view) version of the State.
|
||||
But, at runtime, the contract state it's operating with can actually be a deserialised version of any previous state.
|
||||
That's why the current one needs to be a superset of all preceding states, and you can't verify with an older version.
|
||||
|
||||
|
||||
The serialisation engine needs to implement the above rules, and needs to run in this `Strict Mode` during transaction verification.
|
||||
This mode can be implemented as a new `SerializationContext`.
|
||||
|
||||
The same serialization evolution `Strict Mode` needs to be enforced any time ContractStates or Commands are serialized.
|
||||
This is to ensure that when flows communicate to older versions, the older node will not sign something that he doesn't know.
|
||||
|
||||
|
||||
##### Backwards compatibility
|
||||
|
||||
The only case when this would break for existing transactions is when the Whitelist Constraint was used and states were evolved not according to the above rules.
|
||||
Should this rule be applied retroactively, or only for after-v4 transactions?
|
||||
|
||||
|
||||
### Non-downgrade rule
|
||||
|
||||
To avoid the possibility of malicious nodes selecting old and buggy contract code when spending newer states, we need to enforce a `Non Downgrade rule`.
|
||||
|
||||
Transactions contain an attachment for each contract. The version of the output states is the version of this contract attachment.
|
||||
(It can be seen as the version of code that instantiated and serialised those classes.)
|
||||
|
||||
The rule is: the version of the code used in the transaction that spends a state needs to be >= any version of the input states. ``spending_version >= creation_version``
|
||||
|
||||
This rule needs to be enforced at verification time, and also during transaction building.
|
||||
|
||||
*Note:* This rule can be implemented as a normal contract constraint, as it is a constraint on the attachments that can be used on the spending transaction.
|
||||
We don't currently support multiple constraints on a state and don't have any delegation mechanism to implement it like that.
|
||||
|
||||
|
||||
#### Considered but decided against - Add Version field on TransactionState
|
||||
|
||||
The `version` could also be stored redundantly to states on the ledger - as a field in ``TransactionState`` and also in the `vault_states` table.
|
||||
|
||||
This would make the verification logic more clear and faster, and also expose the version of the input states to the contract verify code.
|
||||
|
||||
Note:
|
||||
|
||||
- When a transaction is verified the version of the attachment needs to match the version of the output states.
|
||||
|
||||
|
||||
## Actions
|
||||
|
||||
1. Implement the serialization `Strict Mode` and wire that during transaction verification, and more generally whenever it tries to deserialize ContractStates or Commands.
|
||||
Also to define other possible evolutions and decide if possible or not (E.g: adding/removing interfaces).
|
||||
2. Find some good names for the `ContractJar` and the `FlowsJar`.
|
||||
3. Implement the gradle plugin changes to split the 'cordapp' into 'contract' (better name) and 'flows' (better name).
|
||||
4. Implement the versioning strategy proposed above in the 'contract' part of the plugin.
|
||||
5. When importing a ContractJar, read the version and save it as a database column. Also add it as a field to teh `ContractAttachment` class.
|
||||
6. Implement the non-downgrade rule using the above `version`.
|
||||
7. Add support to the `cordapp` plugin and the driver to test multiple versions of the contractJar together.
|
||||
8. Document all the release process.
|
||||
9. Update samples with the new gradle plugin.
|
||||
10. Create an elaborate sample for some more complex flows and contract upgrade scenarios.
|
||||
Ideally with new fields added to the state, new version of the flow protocol, internal flow objects changed, subflows, dependency on other contracts.
|
||||
This would be published as an example for how it should be done.
|
||||
11. Use this elaborate sample to create a comprehensive automated Behave Compatibility Test Suite.
|
||||
|
||||
## Deferred tasks
|
||||
|
||||
1. Formalise the dependency rules between contracts, contracts and flows, and also subflow versioning.
|
||||
2. Find a way to hide the complexity of backwards compatibility from flow devlopers (maybe using a handshake).
|
||||
3. Remove custom contract state schema from ContractJar.
|
||||
|
||||
## Appendix:
|
||||
|
||||
This section contains various hypothetical scenarios to illustrate various issues and how they are solved by the current design.
|
||||
|
||||
These are the possible changes:
|
||||
- changes to the state (fields added/removed from the state)
|
||||
- changes to the verification logic (more restrictive, less restrictive, or both - for different checks)
|
||||
- adding/removing/renaming of commands
|
||||
- Persistent Schema changes (These are out of scope of this document, as they shouldn't be in contract jar in the first place)
|
||||
- any combination of the above
|
||||
|
||||
|
||||
Terminology:
|
||||
|
||||
- V1, V2 - are versions of the contract.
|
||||
- Tx1, Tx2 - are transactions between parties.
|
||||
|
||||
|
||||
#### Scenario 1 - Spending a state with an older contract.
|
||||
- V1: com.megacorp.token.MegaToken(amount: Amount, owner: Party)
|
||||
- V2: com.megacorp.token.MegaToken(amount: Amount, owner: Party, accumulatedDebt: Amount? = 0)
|
||||
|
||||
|
||||
- Tx1: Alice transfers MegaToken to Bob, and selects V1
|
||||
- Tx2: Bob transfers to Chuck, but selects V2. The V1 output state will be deserialised with an accumulatedDebt=0, which is correct.
|
||||
- After a while, Chuck accumulates some debt on this token.
|
||||
- Txn: Chuck creates a transaction with Dan, but selects V1 as the contract version for this transaction, thus managing to "lose" the accumulatedDebt. (V1 does not know about the accumulatedDebt field)
|
||||
|
||||
|
||||
Solution: This was analysed above. It will be solved by the non-downgrade rule and the serialization engine changes.
|
||||
|
||||
|
||||
#### Scenario 2: - Running an explicit upgrade written against an older contract version.
|
||||
- V1: com.megacorp.token.MegaToken(amount: Amount, owner: Party)
|
||||
- V2: com.megacorp.token.MegaToken(amount: Amount, owner: Party, accumulatedDebt: Amount? = 0)
|
||||
- Another company creates a better com.gigacorp.token.GigaToken that is an UpgradedContract designed to replace the MegaToken via an explicit upgrade, but develop against V1 ( as V2 was not released at the time of development).
|
||||
|
||||
Same as before:
|
||||
- Tx1: Alice transfers MegaToken to Bob, and selects V1 (the only version available at that time)
|
||||
- Tx2: Bob transfers to Chuck, but selects V2. The V1 output state will be deserialised with an accumulatedDebt=0, which is correct.
|
||||
- After a while, Chuck accumulates some debt on this token.
|
||||
- Chuck notices the GigaToken does not know about the accumulatedDebt field, so runs an explicit upgrade and transforms his MegaToken with debt into a clean GigaToken.
|
||||
|
||||
Solution: This attack breaks the assumption we made that contracts will not be adding fields that change it fundamentally.
|
||||
|
||||
|
||||
#### Scenario 3 - Flows installed by 2 peers compiled against different contract versions.
|
||||
- Alice runs V1 of the MegaToken FlowsJAR, while Bob runs V2.
|
||||
- Bob builds a new transaction where he transfers a state with accumulatedDebt To Alice.
|
||||
- Alice is not able to correctly evaluate the business proposition, as she does not know that there even exists an accumulatedDebt field, but still signs it as if it was debt free.
|
||||
|
||||
Solution: Solved by the assumption that peer-to-peer communication can be lossy, and the peer with the higher version is responsible to send the right data
|
||||
|
||||
|
||||
#### Scenario 4 - Developer attempts to rename a field from one version to the next.
|
||||
- V1: com.megacorp.token.MegaToken(amount: Amount, owner: Party, accumulatedDebt: Amount )
|
||||
- V2: com.megacorp.token.MegaToken(amount: Amount, owner: Party, currentDebt: Amount)
|
||||
|
||||
This is a rename of a field.
|
||||
This would break as soon as you try to spend a V1 state with V2, because there is no default value for currentDebt.
|
||||
|
||||
Solution: Not possible for now, as it breaks the serialisation evolution rules. Could be added as a new feature in the future.
|
||||
|
||||
|
||||
#### Scenario 5 - Contract verification logic becomes more strict in a new version. General concerns.
|
||||
- V1: check that amount > 10
|
||||
- V2: check that amount > 12
|
||||
|
||||
|
||||
- Tx1: Alice transfers MegaToken(amount=11) to Bob, and selects V1
|
||||
- Tx2: Bob wants to forward it to Charlie, but in the meantime v2 is released, and Bob installs it.
|
||||
|
||||
|
||||
- If Bob selects V2, the contract will fail. So, Bob needs to select V1, but will Charlie accept it?
|
||||
|
||||
The question is how important it is, that amount is >12?
|
||||
- Is it a new regulation active from a date?
|
||||
- Was it actually a (security) bug in V1?
|
||||
- Is it just a change done for not good reason?
|
||||
|
||||
Solution: This is not addressed in the current design doc. It needs to be explored in more depth.
|
||||
|
||||
#### Scenario 6 - Contract verification logic becomes more strict in a new version. ???
|
||||
- V1: check that amount > 10
|
||||
- V2: check that amount > 12
|
||||
|
||||
|
||||
- Alice runs V1 of the MegaToken FlowsJAR, while Bob runs V2. So Alice does not know (yet) that in the future the amount will have to be >12.
|
||||
- Alice builds a transaction that transfers 11 token to Bob. This is a perfectly good transaction (from her point of view), with the V1 attachment.
|
||||
- Should Bob sign this transaction?
|
||||
- This could be encoded in Bob's flow (who should know that the underlying contract has changed this way.).
|
||||
|
||||
Solution: Same as Scenario 5.
|
||||
|
||||
|
||||
#### Scenario 7 - Contract verification logic becomes less strict.
|
||||
- V1: check that amount > 12
|
||||
- V2: check that amount > 10
|
||||
|
||||
Alice runs V1 of the MegaToken FlowsJAR, while Bob runs V2.
|
||||
|
||||
Because there was no change in the actual structure of the state it means the flow that Alice has installed is compatible with the newer version from Bob so Alice could download V2 from Bob.
|
||||
|
||||
Solution: This should not require any change.
|
||||
|
||||
|
||||
#### Scenario 8 - Contract depends on another Contract.
|
||||
- V1: com.megacorp.token.MegaToken(amount: Amount, owner: Party)
|
||||
- V2: com.megacorp.token.MegaToken(amount: Amount, owner: Party, accumulatedDebt: Amount? = 0)
|
||||
|
||||
A contract developed by a thirdparty: com.megabank.tokens.SuperToken depends on com.megacorp.token.MegaToken
|
||||
|
||||
V1 of `com.megabank.tokens.SuperToken` is compiled against V1 of `com.megacorp.token.MegaToken`. So does not know about the new ``accumulatedDebt`` field.
|
||||
|
||||
Alice swaps MegaToken-v2 for SuperToken-v1 with Bob in a transaction. If Alice select v1 of the SuperToken contract attachment, then it will not be able to correctly evaluate the transaction.
|
||||
|
||||
|
||||
Solution: Solved by the assumption we made that contracts don't change fundamentally.
|
||||
|
||||
|
||||
#### Scenario 9 - A new command is added or removed
|
||||
- V1 of com.megacorp.token.MegaToken has 3 Commands: Issue, Move, Exit
|
||||
- V2 of com.megacorp.token.MegaToken has 4 Commands: Issue, Move, Exit, AddDebt
|
||||
- V3 of com.megacorp.token.MegaToken has 3 Commands: Issue, Move, Exit
|
||||
|
||||
There should not be any problem with adding/removing commands, as they apply only to transitions.
|
||||
Spending of a state should not be affected by the command that created it.
|
||||
|
||||
Solution: Does not require any change
|
@ -32,7 +32,7 @@ import static net.corda.testing.core.ExpectKt.expectEvents;
|
||||
import static net.corda.testing.core.TestConstants.ALICE_NAME;
|
||||
import static net.corda.testing.core.TestConstants.BOB_NAME;
|
||||
import static net.corda.testing.driver.Driver.driver;
|
||||
import static net.corda.testing.node.internal.TestCordappsUtilsKt.FINANCE_CORDAPPS;
|
||||
import static net.corda.testing.node.internal.InternalTestUtilsKt.FINANCE_CORDAPPS;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class JavaIntegrationTestingTutorial {
|
||||
|
@ -110,18 +110,21 @@ public class FinalityFlowMigration {
|
||||
@Suspendable
|
||||
@Override
|
||||
public Void call() throws FlowException {
|
||||
|
||||
// DOCSTART ExistingResponderFlow
|
||||
// First we have to run the SignTransactionFlow, which will return a SignedTransaction.
|
||||
SignedTransaction txWeJustSigned = subFlow(new SignTransactionFlow(otherSide) {
|
||||
@Suspendable
|
||||
@Override
|
||||
protected void checkTransaction(@NotNull SignedTransaction stx) throws FlowException {
|
||||
// Do checks here
|
||||
// Implement responder flow transaction checks here
|
||||
}
|
||||
});
|
||||
// DOCSTART ExistingResponderFlow
|
||||
|
||||
if (otherSide.getCounterpartyFlowInfo().getFlowVersion() >= 2) {
|
||||
// The other side is not using the old CorDapp so call ReceiveFinalityFlow to record the finalised transaction.
|
||||
// If SignTransactionFlow is used then we can verify the tranaction we receive for recording is the same one
|
||||
// that was just signed.
|
||||
// that was just signed by passing the transaction id to ReceiveFinalityFlow.
|
||||
subFlow(new ReceiveFinalityFlow(otherSide, txWeJustSigned.getId()));
|
||||
} else {
|
||||
// Otherwise the other side is running the old CorDapp and so we don't need to do anything further. The node
|
||||
|
@ -0,0 +1,35 @@
|
||||
package net.corda.docs.java;
|
||||
|
||||
// DOCSTART 1
|
||||
import net.corda.core.identity.CordaX500Name;
|
||||
import net.corda.testing.node.MockNetwork;
|
||||
import net.corda.testing.node.MockNetworkParameters;
|
||||
import net.corda.testing.node.StartedMockNode;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static net.corda.testing.node.TestCordapp.findCordapp;
|
||||
|
||||
public class MockNetworkTestsTutorial {
|
||||
|
||||
private final MockNetwork mockNet = new MockNetwork(new MockNetworkParameters(singletonList(findCordapp("com.mycordapp.package"))));
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
mockNet.stopNodes();
|
||||
}
|
||||
// DOCEND 1
|
||||
|
||||
// DOCSTART 2
|
||||
private StartedMockNode nodeA;
|
||||
private StartedMockNode nodeB;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
nodeA = mockNet.createNode();
|
||||
// We can optionally give the node a name.
|
||||
nodeB = mockNet.createNode(new CordaX500Name("Bank B", "London", "GB"));
|
||||
}
|
||||
// DOCEND 2
|
||||
}
|
@ -22,6 +22,7 @@ import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.node.User
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.node.internal.FINANCE_CORDAPPS
|
||||
import org.graphstream.graph.Edge
|
||||
import org.graphstream.graph.Node
|
||||
import org.graphstream.graph.implementations.MultiGraph
|
||||
@ -51,7 +52,7 @@ fun main(args: Array<String>) {
|
||||
startFlow<CashExitFlow>(),
|
||||
invokeRpc(CordaRPCOps::nodeInfo)
|
||||
))
|
||||
driver(DriverParameters(driverDirectory = baseDirectory, extraCordappPackagesToScan = listOf("net.corda.finance"), waitForAllNodesToFinish = true)) {
|
||||
driver(DriverParameters(driverDirectory = baseDirectory, cordappsForAllNodes = FINANCE_CORDAPPS, waitForAllNodesToFinish = true)) {
|
||||
val node = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).get()
|
||||
// END 1
|
||||
|
||||
|
@ -70,13 +70,15 @@ class ExistingInitiatingFlow(private val counterparty: Party) : FlowLogic<Signed
|
||||
class ExistingResponderFlow(private val otherSide: FlowSession) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
// DOCSTART ExistingResponderFlow
|
||||
// First we have to run the SignTransactionFlow, which will return a SignedTransaction.
|
||||
val txWeJustSigned = subFlow(object : SignTransactionFlow(otherSide) {
|
||||
@Suspendable
|
||||
override fun checkTransaction(stx: SignedTransaction) {
|
||||
// Do checks here
|
||||
// Implement responder flow transaction checks here
|
||||
}
|
||||
})
|
||||
// DOCSTART ExistingResponderFlow
|
||||
|
||||
if (otherSide.getCounterpartyFlowInfo().flowVersion >= 2) {
|
||||
// The other side is not using the old CorDapp so call ReceiveFinalityFlow to record the finalised transaction.
|
||||
// If SignTransactionFlow is used then we can verify the tranaction we receive for recording is the same one
|
||||
|
@ -0,0 +1,33 @@
|
||||
package net.corda.docs.kotlin
|
||||
|
||||
// DOCSTART 1
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNetworkParameters
|
||||
import net.corda.testing.node.StartedMockNode
|
||||
import net.corda.testing.node.TestCordapp.Companion.findCordapp
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
|
||||
class MockNetworkTestsTutorial {
|
||||
|
||||
private val mockNet = MockNetwork(MockNetworkParameters(listOf(findCordapp("com.mycordapp.package"))))
|
||||
|
||||
@After
|
||||
fun cleanUp() {
|
||||
mockNet.stopNodes()
|
||||
}
|
||||
// DOCEND 1
|
||||
|
||||
// DOCSTART 2
|
||||
private lateinit var nodeA: StartedMockNode
|
||||
private lateinit var nodeB: StartedMockNode
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
nodeA = mockNet.createNode()
|
||||
// We can optionally give the node a name.
|
||||
nodeB = mockNet.createNode(CordaX500Name("Bank B", "London", "GB"))
|
||||
}
|
||||
// DOCEND 2
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
package net.corda.docs.kotlin.tutorial.testdsl
|
||||
|
||||
import com.nhaarman.mockito_kotlin.doReturn
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.contracts.TransactionVerificationException
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
@ -47,7 +48,7 @@ class TutorialTestDSL {
|
||||
// You can also use the alternative parameter initialIdentityName which accepts a
|
||||
// [CordaX500Name]
|
||||
megaCorp,
|
||||
rigorousMock<IdentityService>().also {
|
||||
mock<IdentityService>().also {
|
||||
doReturn(megaCorp.party).whenever(it).partyFromKey(megaCorp.publicKey)
|
||||
doReturn(null).whenever(it).partyFromKey(bigCorp.publicKey)
|
||||
doReturn(null).whenever(it).partyFromKey(alice.publicKey)
|
||||
|
@ -1,3 +1,9 @@
|
||||
.. highlight:: kotlin
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/codesets.js"></script>
|
||||
|
||||
Financial model
|
||||
===============
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
.. highlight:: kotlin
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/codesets.js"></script>
|
||||
|
||||
Configuring Responder Flows
|
||||
===========================
|
||||
|
||||
@ -12,64 +18,9 @@ Subclassing a Flow
|
||||
If you have a workflow which is mostly common, but also requires slight alterations in specific situations, most developers would be familiar
|
||||
with refactoring into `Base` and `Sub` classes. A simple example is shown below.
|
||||
|
||||
java
|
||||
~~~~
|
||||
.. container:: codeset
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
@InitiatingFlow
|
||||
public class Initiator extends FlowLogic<String> {
|
||||
private final Party otherSide;
|
||||
|
||||
public Initiator(Party otherSide) {
|
||||
this.otherSide = otherSide;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String call() throws FlowException {
|
||||
return initiateFlow(otherSide).receive(String.class).unwrap((it) -> it);
|
||||
}
|
||||
}
|
||||
|
||||
@InitiatedBy(Initiator.class)
|
||||
public class BaseResponder extends FlowLogic<Void> {
|
||||
private FlowSession counterpartySession;
|
||||
|
||||
public BaseResponder(FlowSession counterpartySession) {
|
||||
super();
|
||||
this.counterpartySession = counterpartySession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call() throws FlowException {
|
||||
counterpartySession.send(getMessage());
|
||||
return Void;
|
||||
}
|
||||
|
||||
|
||||
protected String getMessage() {
|
||||
return "This Is the Legacy Responder";
|
||||
}
|
||||
}
|
||||
|
||||
public class SubResponder extends BaseResponder {
|
||||
|
||||
public SubResponder(FlowSession counterpartySession) {
|
||||
super(counterpartySession);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMessage() {
|
||||
return "This is the sub responder";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
kotlin
|
||||
~~~~~~
|
||||
|
||||
.. code-block:: kotlin
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
@InitiatedBy(Initiator::class)
|
||||
open class BaseResponder(internal val otherSideSession: FlowSession) : FlowLogic<Unit>() {
|
||||
@ -87,8 +38,53 @@ kotlin
|
||||
}
|
||||
}
|
||||
|
||||
.. sourcecode:: java
|
||||
|
||||
@InitiatingFlow
|
||||
public class Initiator extends FlowLogic<String> {
|
||||
private final Party otherSide;
|
||||
|
||||
public Initiator(Party otherSide) {
|
||||
this.otherSide = otherSide;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String call() throws FlowException {
|
||||
return initiateFlow(otherSide).receive(String.class).unwrap((it) -> it);
|
||||
}
|
||||
}
|
||||
|
||||
@InitiatedBy(Initiator.class)
|
||||
public class BaseResponder extends FlowLogic<Void> {
|
||||
private FlowSession counterpartySession;
|
||||
|
||||
public BaseResponder(FlowSession counterpartySession) {
|
||||
super();
|
||||
this.counterpartySession = counterpartySession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call() throws FlowException {
|
||||
counterpartySession.send(getMessage());
|
||||
return Void;
|
||||
}
|
||||
|
||||
|
||||
protected String getMessage() {
|
||||
return "This Is the Legacy Responder";
|
||||
}
|
||||
}
|
||||
|
||||
public class SubResponder extends BaseResponder {
|
||||
public SubResponder(FlowSession counterpartySession) {
|
||||
super(counterpartySession);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMessage() {
|
||||
return "This is the sub responder";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Corda would detect that both ``BaseResponder`` and ``SubResponder`` are configured for responding to ``Initiator``.
|
||||
|
@ -140,13 +140,18 @@ To copy the same file to all nodes `ext.drivers` can be defined in the top level
|
||||
|
||||
Signing Cordapp JARs
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
Cordform entry ``signing`` configures the signing of CorDapp JARs.
|
||||
The default behaviour of Cordform is to deploy CorDapp JARs "as built":
|
||||
|
||||
- prior to Corda 4 all CorDapp JARs were unsigned.
|
||||
- as of Corda 4, CorDapp JARs created by the Gradle *cordapp* plugin are signed by a Corda development certificate by default.
|
||||
|
||||
The Cordform ``signing`` entry can be used to override and customise the signing of CorDapp JARs.
|
||||
Signing the CorDapp enables its contract classes to use signature constraints instead of other types of the constraints :doc:`api-contract-constraints`.
|
||||
By default all CorDapp JARs are signed by Corda development certificate.
|
||||
|
||||
The sign task may use an external keystore, or create a new one.
|
||||
The ``signing`` entry may contain the following parameters:
|
||||
|
||||
* ``enabled`` the control flag to enable signing process, by default is set to ``true``, set to ``false`` to disable signing
|
||||
* ``enabled`` the control flag to enable signing process, by default is set to ``false``, set to ``true`` to enable signing
|
||||
* ``all`` if set to ``true`` (by default) all CorDapps inside *cordapp* subdirectory will be signed, otherwise if ``false`` then only the generated Cordapp will be signed
|
||||
* ``options`` any relevant parameters of `SignJar ANT task <https://ant.apache.org/manual/Tasks/signjar.html>`_ and `GenKey ANT task <https://ant.apache.org/manual/Tasks/genkey.html>`_,
|
||||
by default the JAR file is signed by Corda development key, the external keystore can be specified,
|
||||
|
@ -107,7 +107,4 @@ We look forward to seeing what you can do with Corda!
|
||||
:maxdepth: 2
|
||||
:if_tag: htmlmode
|
||||
|
||||
corda-network/index.md
|
||||
corda-network/governance-structure.md
|
||||
corda-network/governance-guidelines.md
|
||||
corda-network/joining-corda-network.md
|
||||
corda-network/index.md
|
@ -31,6 +31,7 @@ configuration for PostgreSQL:
|
||||
}
|
||||
|
||||
Note that:
|
||||
|
||||
* Database schema name can be set in JDBC URL string e.g. currentSchema=myschema
|
||||
* Database schema name must either match the ``dataSource.user`` value to end up
|
||||
on the standard schema search path according to the
|
||||
|
@ -13,7 +13,10 @@ Running the UI
|
||||
**Other**::
|
||||
|
||||
./gradlew tools:explorer:run
|
||||
|
||||
|
||||
.. note:: In order to connect to a given node, the node explorer must have access to all CorDapps loaded on that particular node.
|
||||
By default, it only has access to the finance CorDapp.
|
||||
All other CorDapps present on the node must be copied to a ``cordapps`` directory located within the directory from which the node explorer is run.
|
||||
|
||||
Running demo nodes
|
||||
------------------
|
||||
|
@ -269,19 +269,10 @@ Here's an example of it in action from ``FixingFlow.Fixer``.
|
||||
Testing
|
||||
-------
|
||||
|
||||
The ``MockNetwork`` allows the creation of ``MockNode`` instances, which are simplified nodes which can be used for
|
||||
testing (see :doc:`api-testing`). When creating the ``MockNetwork`` you supply a list of packages to scan for CorDapps.
|
||||
Make sure the packages you provide include your oracle service, and it automatically be installed in the test nodes.
|
||||
Then you can create an oracle node on the ``MockNetwork`` and insert any initialisation logic you want to use. In this
|
||||
case, our ``Oracle`` service is in the ``net.corda.irs.api`` package, so the following test setup will install
|
||||
the service in each node. Then an oracle node with an oracle service which is initialised with some data is created on
|
||||
the mock network:
|
||||
|
||||
.. literalinclude:: ../../samples/irs-demo/cordapp/src/test/kotlin/net/corda/irs/api/OracleNodeTearOffTests.kt
|
||||
:language: kotlin
|
||||
:start-after: DOCSTART 1
|
||||
:end-before: DOCEND 1
|
||||
:dedent: 4
|
||||
The ``MockNetwork`` allows the creation of ``MockNode`` instances, which are simplified nodes which can be used for testing (see :doc:`api-testing`).
|
||||
When creating the ``MockNetwork`` you supply a list of ``TestCordapp`` objects which point to CorDapps on
|
||||
the classpath. These CorDapps will be installed on each node on the network. Make sure the packages you provide reference to the CorDapp
|
||||
containing your oracle service.
|
||||
|
||||
You can then write tests on your mock network to verify the nodes interact with your Oracle correctly.
|
||||
|
||||
|
@ -287,7 +287,13 @@ The TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 family of ciphers is retired from the li
|
||||
as it is a legacy cipher family not supported by all native SSL/TLS implementations. We anticipate that this
|
||||
will have no impact on any deployed configurations.
|
||||
|
||||
Miscelleneous changes
|
||||
Confidential identities
|
||||
+++++++++++++++++++++++
|
||||
|
||||
If any of your CorDapps use the experimental confidential-identities module then it also needs to be loaded as a separate CorDapp jar. This
|
||||
includes the demo finance CorDapp.
|
||||
|
||||
Miscellaneous changes
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To learn more about smaller changes, please read the :doc:`changelog`.
|
||||
|
@ -1,3 +1,9 @@
|
||||
.. highlight:: kotlin
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/codesets.js"></script>
|
||||
|
||||
Enum Evolution
|
||||
==============
|
||||
|
||||
|
@ -154,7 +154,7 @@ simple: it's given a class representing the transaction, and if the function ret
|
||||
acceptable. If it throws an exception, the transaction is rejected.
|
||||
|
||||
Each transaction can have multiple input and output states of different types. The set of contracts to run is decided
|
||||
by taking the code references inside each state. Each contract is run only once. As an example, a contract that includes
|
||||
by taking the code references inside each state. Each contract is run only once. As an example, a transaction that includes
|
||||
2 cash states and 1 commercial paper state as input, and has as output 1 cash state and 1 commercial paper state, will
|
||||
run two contracts one time each: Cash and CommercialPaper.
|
||||
|
||||
|
@ -47,8 +47,8 @@ Caveats
|
||||
later re-record the same transaction as an observer. This issue is tracked here:
|
||||
https://r3-cev.atlassian.net/browse/CORDA-883
|
||||
|
||||
* Observer nodes will only record the states of the transactions sent to them, and not any states from any previous
|
||||
transactions in the chain. If the observer node is required to follow the creation and deletion of states, then each
|
||||
transaction in the chain involving those states must be sent individually. This is because the observer node does not
|
||||
necessarily have any visibility into the states of intermediate transactions, and so cannot always determine whether
|
||||
a previous state has been consumed when a new transaction is received.
|
||||
* When an observer node is sent a transaction with the ALL_VISIBLE flag set, any transactions in the transaction history
|
||||
that have not already been received will also have ALL_VISIBLE states recorded. This mean a node that is both an observer
|
||||
and a participant may have some transactions with all states recorded and some with only relevant states recorded, even
|
||||
if those transactions are part of the same chain. As a result, there may be more states present in the vault than would be
|
||||
expected if just those transactions sent with the ALL_VISIBLE recording flag were processed in this way.
|
||||
|
@ -1,3 +1,9 @@
|
||||
.. highlight:: kotlin
|
||||
.. raw:: html
|
||||
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/codesets.js"></script>
|
||||
|
||||
Transaction tear-offs
|
||||
=====================
|
||||
|
||||
|
Reference in New Issue
Block a user