mirror of
https://github.com/corda/corda.git
synced 2025-01-21 03:55:00 +00:00
Update docs relating to the multiple notary support work
This commit is contained in:
parent
a16ae677ed
commit
9f1a4e9254
@ -80,8 +80,12 @@ interface ContractState {
|
||||
val participants: List<PublicKey>
|
||||
}
|
||||
|
||||
/** A wrapper for [ContractState] containing additional platform-level state information. This is the state */
|
||||
/**
|
||||
* A wrapper for [ContractState] containing additional platform-level state information.
|
||||
* This is the definitive state that is stored on the ledger and used in transaction outputs.
|
||||
*/
|
||||
data class TransactionState<out T : ContractState>(
|
||||
/** The custom contract state */
|
||||
val data: T,
|
||||
/** Identity of the notary that ensures the state is not used as an input to a transaction more than once */
|
||||
val notary: Party) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
Consensus Model
|
||||
Consensus model
|
||||
===============
|
||||
|
||||
The fundamental unit of consensus in Corda is the **state**. The concept of consensus can be divided into two parts:
|
||||
@ -15,104 +15,133 @@ Notary
|
||||
------
|
||||
|
||||
We introduce the concept of a **Notary**, which is an authority responsible for attesting that for a given transaction, it had not signed another transaction consuming any of its input states.
|
||||
The data model is extended so that every **state** has an appointed Notary:
|
||||
The data model is extended so that every **state** has an appointed notary:
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
interface ContractState {
|
||||
/** Contract by which the state belongs */
|
||||
val contract: Contract
|
||||
|
||||
/** Identity of the notary that ensures this state is not used as an input to a transaction more than once */
|
||||
val notary: Party
|
||||
/**
|
||||
* A wrapper for [ContractState] containing additional platform-level state information.
|
||||
* This is the definitive state that is stored on the ledger and used in transaction outputs
|
||||
*/
|
||||
data class TransactionState<out T : ContractState>(
|
||||
/** The custom contract state */
|
||||
val data: T,
|
||||
/** Identity of the notary that ensures the state is not used as an input to a transaction more than once */
|
||||
val notary: Party) {
|
||||
...
|
||||
}
|
||||
|
||||
All transactions have to be signed by their input state Notary for the output states to be **valid** (apart from *issue* transactions, containing no input states).
|
||||
All transactions have to be signed by their input state notary for the output states to be **valid** (apart from *issue* transactions, containing no input states).
|
||||
|
||||
.. note:: The Notary is a logical concept and can itself be a distributed entity, potentially a cluster maintained by mutually distrusting parties
|
||||
.. note:: The notary is a logical concept and can itself be a distributed entity, potentially a cluster maintained by mutually distrusting parties
|
||||
|
||||
When the Notary is requested to sign a transaction, it either signs over it, attesting that the outputs are the **unique** successors of the inputs,
|
||||
When the notary is requested to sign a transaction, it either signs over it, attesting that the outputs are the **unique** successors of the inputs,
|
||||
or provides conflict information for any input state that had been consumed by another transaction it had signed before.
|
||||
In doing so, the Notary provides the point of finality in the system. Until the Notary signature is obtained, parties cannot be sure that an equally valid, but conflicting transaction,
|
||||
In doing so, the notary provides the point of finality in the system. Until the notary signature is obtained, parties cannot be sure that an equally valid, but conflicting transaction,
|
||||
will not be regarded as confirmed. After the signature is obtained, the parties know that the inputs to this transaction have been uniquely consumed by this transaction.
|
||||
Hence it is the point at which we can say finality has occurred.
|
||||
|
||||
Multiple notaries
|
||||
-----------------
|
||||
|
||||
More than one notary can exist in the network. This gives the following benefits:
|
||||
|
||||
* **Custom behaviour**. We can have both validating and privacy preserving Notaries -- parties can make a choice based on their specific requirements
|
||||
* **Load balancing**. Spreading the transaction load over multiple Notaries will allow higher transaction throughput in the platform overall
|
||||
* **Low latency**. Latency could be minimised by choosing a notary physically closer the transacting parties
|
||||
|
||||
A transaction should only be signed by a notary if all of its input states point to it.
|
||||
In cases where a transaction involves states controlled by multiple notaries, the states first have to be repointed to the same notary.
|
||||
This is achieved by using a special type of transaction that doesn't modify anything but the notary pointer of the state.
|
||||
Ensuring that all input states point to the same notary is the responsibility of each involved party
|
||||
(it is another condition for an output state of the transaction to be **valid**)
|
||||
|
||||
Validation
|
||||
----------
|
||||
|
||||
The Notary *does not validate* transaction integrity (i.e. does not run contracts or check signatures) to minimise the exposed data.
|
||||
Validation would require the caller to reveal the whole transaction history chain, resulting in a privacy leak.
|
||||
One of the design decisions for a notary is whether or not to **validate** a transaction before committing its input states.
|
||||
|
||||
However, this makes it open to "denial of state" attacks, where a party could submit any invalid transaction to the Notary and thus "block" someone else's states.
|
||||
That is partially alleviated by requiring the calling party to authenticate and storing its identity for the request.
|
||||
If a transaction is not checked for validity, it opens the platform to "denial of state" attacks, where anyone can build an invalid transaction consuming someone else's states and submit it to the notary to get the states "blocked".
|
||||
However, validation of a transaction requires the notary to be able to see the full contents of the transaction in question and its dependencies.
|
||||
This is an obvious privacy leak.
|
||||
|
||||
Our platform is flexible and we currently support both validating and non-validating notary implementations -- a party can select which one to use based on its own privacy requirements.
|
||||
|
||||
.. note:: In the non-validating model the "denial of state" attack is partially alleviated by requiring the calling party to authenticate and storing its identity for the request.
|
||||
The conflict information returned by the Notary specifies the consuming transaction id along with the identity of the party that had requested the commit.
|
||||
If the conflicting transaction is valid, the current one gets aborted; if not – a dispute can be raised and the input states of the conflicting invalid transaction are "un-committed" (to be covered by legal process).
|
||||
If the conflicting transaction is valid, the current one gets aborted; if not – a dispute can be raised and the input states of the conflicting invalid transaction are "un-committed" (to be covered by legal process).
|
||||
|
||||
.. note:: At present the Notary can see the entire transaction, but we have a separate piece of work to replace the parts of the transaction it does not require knowing about with hashes (only input references, timestamp information, overall transaction ID and the necessary digests of the rest of the transaction to prove that the referenced inputs/timestamps really do form part of the stated transaction ID should be visible).
|
||||
|
||||
Multiple Notaries
|
||||
-----------------
|
||||
|
||||
More than one Notary can exist in the network. This gives the following benefits:
|
||||
|
||||
* **Custom behaviour**. We can have both validating and privacy preserving Notaries -- parties can make a choice based on their specific requirements
|
||||
* **Load balancing**. Spreading the transaction load over multiple Notaries will allow higher transaction throughput in the platform overall
|
||||
* **Low latency**. Latency could be minimised by choosing a Notary physically closer the transacting parties
|
||||
|
||||
A transaction should only be signed by a Notary if all of its input states point to it.
|
||||
In cases where a transaction involves states controlled by multiple Notaries, the states first have to be repointed to the same notary.
|
||||
This is achieved by using a special type of transaction that doesn't modify anything but the Notary pointer of the state.
|
||||
Ensuring that all input states point to the same Notary is the responsibility of each involved party
|
||||
(it is another condition for an output state of the transaction to be **valid**)
|
||||
.. note:: At present all notaries can see the entire contents of a transaction, but we have a separate piece of work to replace the parts of the transaction it does not require knowing about with hashes (only input references, timestamp information, overall transaction ID and the necessary digests of the rest of the transaction to prove that the referenced inputs/timestamps really do form part of the stated transaction ID should be visible).
|
||||
|
||||
Timestamping
|
||||
------------
|
||||
|
||||
In this model the Notary also acts as a **Timestamping Authority**, verifying the transaction timestamp command.
|
||||
In this model the notary also acts as a **Timestamping Authority**, verifying the transaction timestamp command.
|
||||
|
||||
For a timestamp to be meaningful, its implications must be binding on the party requesting it.
|
||||
A party can obtain a timestamp signature in order to prove that some event happened before/on/or after a particular point in time.
|
||||
However, if the party is not also compelled to commit to the associated transaction, it has a choice of whether or not to reveal this fact until some point in the future.
|
||||
As a result, we need to ensure that the Notary either has to also sign the transaction within some time tolerance,
|
||||
As a result, we need to ensure that the notary either has to also sign the transaction within some time tolerance,
|
||||
or perform timestamping *and* notarisation at the same time, which is the chosen behaviour for this model.
|
||||
|
||||
Implementation & Usage
|
||||
----------------------
|
||||
Running a Notary Service
|
||||
------------------------
|
||||
|
||||
At present we have single basic implementation of a Notary that uses a :code:`UniquenessProvider` storing committed input states in memory:
|
||||
At present we have two basic implementations that store committed input states in memory:
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
- ``SimpleNotaryService`` -- commits the provided transaction without any validation
|
||||
|
||||
class InMemoryUniquenessProvider() : UniquenessProvider {
|
||||
/** For each input state store the consuming transaction information */
|
||||
private val committedStates = HashMap<StateRef, ConsumingTx>()
|
||||
- ``ValidatingNotaryService`` -- retrieves and validates the whole transaction history (including the given transaction) before committing
|
||||
|
||||
override fun commit(tx: WireTransaction, callerIdentity: Party) {
|
||||
...
|
||||
}
|
||||
}
|
||||
...
|
||||
/**
|
||||
* Specifies the transaction id, the position of the consumed state in the inputs, and
|
||||
* the caller identity requesting the commit
|
||||
*/
|
||||
data class ConsumingTx(val id: SecureHash, val inputIndex: Int, val requestingParty: Party)
|
||||
To run one of these services the node has to simply specify either ``SimpleNotaryService.Type`` or ``ValidatingNotaryService.Type`` in its ``advertisedServices`` set, and the correct type will be initialised.
|
||||
|
||||
To obtain a signature from a Notary use :code:`NotaryProtocol`, passing in a :code:`WireTransaction`.
|
||||
The protocol will work out which Notary needs to be called based on the input states and the timestamp command.
|
||||
Obtaining a signature
|
||||
---------------------
|
||||
|
||||
To obtain a signature from a notary use ``NotaryProtocol.Client``, passing in a ``WireTransaction``.
|
||||
The protocol will work out which notary needs to be called based on the input states and the timestamp command.
|
||||
For example, the following snippet can be used when writing a custom protocol:
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
private fun getNotarySignature(wtx: WireTransaction): DigitalSignature.LegallyIdentifiable {
|
||||
return subProtocol(NotaryProtocol(wtx))
|
||||
fun getNotarySignature(wtx: WireTransaction): DigitalSignature.LegallyIdentifiable {
|
||||
return subProtocol(NotaryProtocol.Client(wtx))
|
||||
}
|
||||
|
||||
On conflict the :code:`NotaryProtocol` with throw a :code:`NotaryException` containing the conflict details:
|
||||
On conflict the ``NotaryProtocol`` with throw a ``NotaryException`` containing the conflict details:
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
/** Specifies the consuming transaction for the conflicting input state */
|
||||
data class Conflict(val stateHistory: Map<StateRef, ConsumingTx>)
|
||||
|
||||
Conflict handling and resolution is currently the responsibility of the protocol author.
|
||||
/**
|
||||
* Specifies the transaction id, the position of the consumed state in the inputs, and
|
||||
* the caller identity requesting the commit
|
||||
*/
|
||||
data class ConsumingTx(val id: SecureHash, val inputIndex: Int, val requestingParty: Party)
|
||||
|
||||
Conflict handling and resolution is currently the responsibility of the protocol author.
|
||||
|
||||
Changing notaries
|
||||
-----------------
|
||||
|
||||
To change the notary for an input state, use the ``NotaryChangeProtocol``. For example:
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
fun changeNotary(originalState: StateAndRef<ContractState>,
|
||||
newNotary: Party): StateAndRef<ContractState> {
|
||||
val protocol = NotaryChangeProtocol.Instigator(originalState, newNotary)
|
||||
return subProtocol(protocol)
|
||||
}
|
||||
|
||||
The protocol will:
|
||||
|
||||
1. Construct a transaction with the old state as the input and the new state as the output
|
||||
|
||||
2. Obtain signatures from all *participants* (a participant is any party that is able to consume this state in a valid transaction, as defined by the state itself)
|
||||
|
||||
3. Obtain the *old* notary signature
|
||||
|
||||
4. Record and distribute the final transaction to the participants so that everyone possesses the new state
|
@ -8,6 +8,20 @@ Unreleased
|
||||
|
||||
Here are changes in git master that haven't yet made it to a snapshot release:
|
||||
|
||||
* Made the ``NotaryService`` extensible, we now have both validating and non-validating notaries.
|
||||
* Added a protocol for changing the notary for a state.
|
||||
* Every ``ContractState`` now has to specify a *participants* field, which is a list of parties that are able to
|
||||
consume this state in a valid transaction. This is used for e.g. making sure all relevant parties obtain the updated
|
||||
state when changing a notary.
|
||||
* Introduced ``TransactionState``, which wraps ``ContractState``, and is used when defining a transaction output.
|
||||
The notary field is moved from ``ContractState`` into ``TransactionState``.
|
||||
* Every transaction now has a *type* field, which specifies custom build & validation rules for that transaction type.
|
||||
Currently two types are supported:
|
||||
|
||||
- **General**. Runs the default build and validation logic.
|
||||
- **NotaryChange**. Contract code is not run during validation, checks that the notary field is the only difference
|
||||
between the inputs and outputs.
|
||||
|
||||
* The cash contract has moved from com.r3corda.contracts to com.r3corda.contracts.cash.
|
||||
* Amount class is now generic, to support non-currency types (such as assets, or currency with additional information).
|
||||
* Refactored the Cash contract to have a new FungibleAsset superclass, to model all countable assets that can be merged
|
||||
|
@ -1,5 +1,5 @@
|
||||
Transaction Data Types
|
||||
======================
|
||||
Data types
|
||||
==========
|
||||
|
||||
There is a large library of data types used in Corda transactions and contract state objects.
|
||||
|
||||
@ -27,15 +27,18 @@ delivered (themselves referring to a currency), an ``Amount`` such as the follow
|
||||
|
||||
Amount<Obligation.State<Currency>>
|
||||
|
||||
Contract State
|
||||
--------------
|
||||
State
|
||||
-----
|
||||
|
||||
A Corda contract is composed of three parts; the executable code, the legal prose, and the state objects that represent
|
||||
the details of the contract (see :doc:`data-model` for further detail). States essentially convert the generic template
|
||||
(code and legal prose) into a specific instance. In a ``WireTransaction``, outputs are provided as ``ContractState``
|
||||
(code and legal prose) into a specific instance. In a ``WireTransaction``, outputs are provided as ``TransactionState``
|
||||
implementations, while the inputs are references to the outputs of a previous transaction. These references are then
|
||||
stored as ``StateRef`` objects, which are converted to ``StateAndRef`` on demand.
|
||||
|
||||
The ``TransactionState`` is a container for a ``ContractState`` (the custom data used by a contract program) and additional
|
||||
platform-level state information, such as the *notary* pointer (see :doc:`consensus`).
|
||||
|
||||
A number of interfaces then extend ``ContractState``, representing standardised functionality for states:
|
||||
|
||||
``OwnableState``
|
||||
@ -64,8 +67,8 @@ interface for its subclasses' state objects to implement. The clear use-case is
|
||||
intended to be readily extensible to cover other assets, for example commodities could be modelled by using a subclass
|
||||
whose state objects include further details (location of the commodity, origin, grade, etc.) as needed.
|
||||
|
||||
Transaction Types
|
||||
-----------------
|
||||
Transaction lifecycle types
|
||||
---------------------------
|
||||
|
||||
The ``WireTransaction`` class contains the core of a transaction without signatures, and with references to attachments
|
||||
in place of the attachments themselves (see also :doc:`data-model`). Once signed these are encapsulated in the
|
||||
@ -84,7 +87,7 @@ for signatures present on the transaction, as well as list of parties for those
|
||||
.. note:: These types are provisional and are likely to change in future, for example to add additional information to
|
||||
``Party``.
|
||||
|
||||
Date Support
|
||||
Date support
|
||||
------------
|
||||
|
||||
There are a number of supporting interfaces and classes for use by contract which deal with dates (especially in the
|
||||
|
Loading…
Reference in New Issue
Block a user