CORDA-2684 Added new guide on CorDapp Constraints Migration procedures. (#4837)

* Added new guide on CorDapp Constraints Migration procedures.

* Apply formatting and upper/lowercase changes.

* Updated following PR review feedback from RGB and MH.

* Minor clarification and cleanup.

* Clarify step to ensure there is only one version ("signed") of the same Contracts CorDapp in the nodes /cordapp folder

* Incorporating feedback from SS.

* Replaced "propagate" with "transition".
Adjust terminology to be consistent.

* Removed confusing statement.
This commit is contained in:
josecoll 2019-03-07 09:32:16 +00:00 committed by GitHub
parent 3bb996d22f
commit f6ba9a0819
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 212 additions and 63 deletions

View File

@ -24,7 +24,7 @@ to it.
There are several types of constraint:
1. Hash constraint: exactly one version of the app can be used with this state.
2. Zone whitelist constraint: the compatibility zone operator lists the hashes of the versions that can be used with this contract class name.
2. Compatibility zone whitelisted (or CZ whitelisted) constraint: the compatibility zone operator lists the hashes of the versions that can be used with this contract class name.
3. Signature constraint: any version of the app signed by the given ``CompositeKey`` can be used.
4. Always accept constraint: any app can be used at all. This is insecure but convenient for testing.
@ -46,6 +46,8 @@ to issue the states was signed by Alice and Bob, every transaction must use an a
the constraint used by equivalent output states (i.e. output states that use the same contract class name) must match the
input state, so it can't be changed and you can't combine states with incompatible constraints together in the same transaction.
.. _implicit_vs_explicit_upgrades:
**Implicit vs explicit.** Constraints are not the only way to manage upgrades to transactions. There are two ways of handling
upgrades to a smart contract in Corda:
@ -136,15 +138,15 @@ From there it's suspended waiting to be retried on node restart.
This gives the node operator the opportunity to recover from those errors, which in the case of constraint violations means
adding the right cordapp jar to the ``cordapps`` folder.
.. _relax_hash_constraints_checking_ref:
Hash constrained states in private networks
-------------------------------------------
Where private networks started life using CorDapps with hash constrained states, we have introduced a mechanism to relax the checking of
these hash constrained states when upgrading to signed CorDapps using signature constraints.
The following java system property may be set to relax the hash constraint checking behaviour:
-Dnet.corda.node.disableHashConstraints="true"
The Java system property ``-Dnet.corda.node.disableHashConstraints="true"`` may be set to relax the hash constraint checking behaviour.
This mode should only be used upon "out of band" agreement by all participants in a network.
@ -191,58 +193,11 @@ During transaction building the ``AutomaticPlaceholderConstraint`` for output st
will be selected based on a variety of factors so that the above holds true. If it can't find attachments in storage or there are no
possible constraints, the ``TransactionBuilder`` will throw an exception.
Constraints migration to Corda 4
--------------------------------
.. _constraints_whitelist_to_signature_ref:
How to use the ``SignatureAttachmentConstraint`` if states were already created on the network with the ``WhitelistedByZoneAttachmentConstraint``
-------------------------------------------------------------------------------------------------------------------------------------------------
1. As the original developer of the corDapp, the first step is to sign the latest version of the JAR that was released (see :doc:`cordapp-build-systems`).
The key used for signing will be used to sign all subsequent releases, so it should be stored appropriately. The JAR can be signed by multiple keys owned
by different parties and it will be expressed as a ``CompositeKey`` in the ``SignatureAttachmentConstraint`` (See :doc:`api-core-types`).
Use `JAR signing and verification tool <https://docs.oracle.com/javase/tutorial/deployment/jar/verify.html>`_ to sign the existing JAR.
The signing capability of :ref:`corda-gradle-plugins <cordapp_build_system_signing_cordapp_jar_ref>` cannot be used in this context as it signs the JAR while building it from source.
2. Whitelist this newly signed JAR with the Zone operator. The Zone operator should check that the JAR is signed and not allow any
more versions of it to be whitelisted in the future. From now on the developer(s) who signed the JAR are responsible for new versions.
3. Any flows that build transactions using this Cordapp will have the responsibility of transitioning states to the ``SignatureAttachmentConstraint``.
This is done explicitly in the code by setting the constraint of the output states to signers of the latest version of the whitelisted jar.
In the near future we will make this transition automatic if we detect that the previous 2 steps were executed.
4. As a node operator you need to add the new signed version of the contracts cordapp to the "cordapps" folder together with the latest version of the flows jar
that will contain code like:
.. container:: codeset
.. sourcecode:: kotlin
// This will read the signers for the deployed cordapp.
val attachment = this.serviceHub.cordappProvider.getContractAttachmentID(contractClass)
val signers = this.serviceHub.attachments.openAttachment(attachment!!)!!.signerKeys
// Create the key that will have to pass for all future versions.
val ownersKey = signers.first()
val txBuilder = TransactionBuilder(notary)
// Set the Signature constraint on the new state to migrate away from the WhitelistConstraint.
.addOutputState(outputState, constraint = SignatureAttachmentConstraint(ownersKey))
...
.. sourcecode:: java
// This will read the signers for the deployed cordapp.
SecureHash attachment = this.getServiceHub().getCordappProvider().getContractAttachmentID(contractClass);
List<PublicKey> signers = this.getServiceHub().getAttachments().openAttachment(attachment).getSignerKeys();
// Create the key that will have to pass for all future versions.
PublicKey ownersKey = signers.get(0);
TransactionBuilder txBuilder = new TransactionBuilder(notary)
// Set the Signature constraint on the new state to migrate away from the WhitelistConstraint.
.addOutputState(outputState, myContract, new SignatureAttachmentConstraint(ownersKey))
...
Please read :doc:`cordapp-constraint-migration` to understand how to consume and evolve pre-Corda 4 issued hash or CZ whitelisted constrained states
using a Corda 4 signed CorDapp (using signature constraints).
Debugging
---------
@ -278,7 +233,7 @@ The same example in Java:
});
Staring a node missing CorDapp(s)
Starting a node missing CorDapp(s)
*********************************
When running the Corda node ensure all CordDapp JARs are placed in ``cordapps`` directory of each node.

View File

@ -376,6 +376,9 @@ automatically use them if your application JAR is signed. **We recommend all JAR
with developer certificates is deployed to a production node, the node will refuse to start. Therefore to deploy apps built for Corda 4
to production you will need to generate signing keys and integrate them with the build process.
.. note:: Please read the :doc:`cordapp-constraint-migration` guide to understand how to upgrade CorDapps to use Corda 4 signature constraints and consume
existing states on ledger issued with older constraint types (e.g. Corda 3.x states issued with **hash** or **CZ whitelisted** constraints).
Step 10. Security: Package namespace handling
---------------------------------------------

View File

@ -0,0 +1,185 @@
.. highlight:: kotlin
.. role:: kotlin(code)
:language: kotlin
.. raw:: html
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/codesets.js"></script>
CorDapp constraints migration
=============================
.. note:: Before reading this page, you should be familiar with the key concepts of :doc:`Contract Constraints <api-contract-constraints>`.
Corda 4 introduces and recommends building signed CorDapps that issue states with signature constraints.
Existing on ledger states issued before Corda 4 are not automatically transitioned to new signature constraints when building transactions in Corda 4.
This document explains how to modify existing CorDapp flows to explicitly consume and evolve pre Corda 4 states, and outlines a future mechanism
where such states will transition automatically (without explicit migration code).
Faced with the exercise of upgrading an existing Corda 3.x CorDapp to Corda 4, you need to consider the following:
* What existing unconsumed states have been issued on ledger by a previous version of this CorDapp and using other constraint types?
If you have existing **hash** constrained states see :ref:`Migrating hash constraints<hash_constraint_migration>`.
If you have existing **CZ whitelisted** constrained states see :ref:`Migrating CZ whitelisted constraints<cz_whitelisted_constraint_migration>`.
If you have existing **always accept** constrained states these are not consumable nor evolvable as they offer no security and should only
be used in test environments.
* What type of contract states does my CorDapp use?
**Linear states** typically evolve over an extended period of time (defined by the lifecycle of the associated business use case), and
thus are prime candidates for constraints migration.
**Fungible states** are created by an issuer and transferred around a Corda network until explicitly exited (by the same issuer).
They do not evolve as linear states, but are transferred between participants on a network. Their consumption may produce additional new
output states to represent adjustments to the original state (e.g. change when spending cash). For the purposes of constraints migration,
it is desirable that any new output states are produced using the new Corda 4 signature constraint types.
Where you have long transaction chains of fungible states, it may be advisable to send them back to the issuer for re-issuance (this is
called "chain snipping" and has performance advantages as well as simplifying constraints type migration).
* Should I use the **implicit** or **explicit** upgrade path?
The general recommendation for Corda 4 is to use **implicit** upgrades for the reasons described :ref:`here <implicit_vs_explicit_upgrades>`.
**Implicit** upgrades allow pre-authorising multiple implementations of the contract ahead of time.
They do not require additional coding and do not incur a complex choreographed operational upgrade process.
.. warning:: The steps outlined in this page assume you are using the same CorDapp Contract (eg. same state definition, commands and verification code) and
wish to use that CorDapp to leverage the upgradeability benefits of Corda 4 signature constraints. If you are looking to upgrade code within an existing
Contract CorDapp please read :ref:`Contract and state versioning<contract_upgrading_ref>` and :doc:`cordapp-upgradeability` to understand your options.
Please also remember that *states are always consumable if the version of the CorDapp that issued (created) them is installed*.
In the simplest of scenarios it may be easier to re-issue existing hash or CZ whitelist constrained states (eg. exit them from the ledger using
the original unsigned CorDapp and re-issuing them using the new signed CorDapp).
.. _hash_constraint_migration:
Hash constraints migration
--------------------------
.. note:: These instructions only apply to CorDapp Contract JARs (unless otherwise stated).
Corda 4.0
~~~~~~~~~
Corda 4.0 requires some additional steps to consume and evolve pre-existing on-ledger **hash** constrained states:
1. All Corda Nodes in the same CZ or business network that may encounter a transaction chain with a hash constrained state must be started using
relaxed hash constraint checking mode as described in :ref:`relax_hash_constraints_checking_ref`.
2. CorDapp flows that build transactions using pre-existing *hash-constrained* states must explicitly set output states to use *signature constraints*
and specify the related public key(s) used in signing the associated CorDapp Contract JAR:
.. container:: codeset
.. sourcecode:: kotlin
// This will read the signers for the deployed CorDapp.
val attachment = this.serviceHub.cordappProvider.getContractAttachmentID(contractClass)
val signers = this.serviceHub.attachments.openAttachment(attachment!!)!!.signerKeys
// Create the key that will have to pass for all future versions.
val ownersKey = signers.first()
val txBuilder = TransactionBuilder(notary)
// Set the Signature constraint on the new state to migrate away from the hash constraint.
.addOutputState(outputState, constraint = SignatureAttachmentConstraint(ownersKey))
.. sourcecode:: java
// This will read the signers for the deployed CorDapp.
SecureHash attachment = this.getServiceHub().getCordappProvider().getContractAttachmentID(contractClass);
List<PublicKey> signers = this.getServiceHub().getAttachments().openAttachment(attachment).getSignerKeys();
// Create the key that will have to pass for all future versions.
PublicKey ownersKey = signers.get(0);
TransactionBuilder txBuilder = new TransactionBuilder(notary)
// Set the Signature constraint on the new state to migrate away from the hash constraint.
.addOutputState(outputState, myContract, new SignatureAttachmentConstraint(ownersKey))
3. As a node operator you need to add the new signed version of the contracts CorDapp to the ``/cordapps`` folder together with the latest version of the flows jar.
Please also ensure that the original unsigned contracts CorDapp is removed from the ``/cordapps`` folder (this will already be present in the
nodes attachments store) to ensure the lookup code in step 2 retrieves the correct signed contract CorDapp JAR.
Later releases
~~~~~~~~~~~~~~
The next version of Corda will provide automatic transition of *hash constrained* states. This means that signed CorDapps running on a Corda 4.x node will
automatically propagate any pre-existing on-ledger *hash-constrained* states (and generate *signature-constrained* outputs) when the system property
to break constraints is set.
.. _cz_whitelisted_constraint_migration:
CZ whitelisted constraints migration
-------------------------------------
.. note:: These instructions only apply to CorDapp Contract JARs (unless otherwise stated).
Corda 4.0
~~~~~~~~~
Corda 4.0 requires some additional steps to consume and evolve pre-existing on-ledger **CZ whitelisted** constrained states:
1. As the original developer of the CorDapp, the first step is to sign the latest version of the JAR that was released (see :doc:`cordapp-build-systems`).
The key used for signing will be used to sign all subsequent releases, so it should be stored appropriately. The JAR can be signed by multiple keys owned
by different parties and it will be expressed as a ``CompositeKey`` in the ``SignatureAttachmentConstraint`` (See :doc:`api-core-types`).
2. The new Corda 4 signed CorDapp JAR must be registered with the CZ network operator (as whitelisted in the network parameters which are distributed
to all nodes in that CZ). The CZ network operator should check that the JAR is signed and not allow any more versions of it to be whitelisted in the future.
From now on the development organisation that signed the JAR is responsible for signing new versions.
The process of CZ network CorDapp whitelisting depends on how the Corda network is configured:
- if using a hosted CZ network (such as `The Corda Network <https://docs.corda.net/head/corda-network/index.html>`_ or
`UAT Environment <https://docs.corda.net/head/corda-network/UAT.html>`_ ) running an Identity Operator (formerly known as Doorman) and
Network Map Service, you should manually send the hashes of the two JARs to the CZ network operator and request these be added using
their network parameter update process.
- if using a local network created using the Network Bootstrapper tool, please follow the instructions in
:ref:`Updating the contract whitelist for bootstrapped networks <bootstrapper_updating_whitelisted_contracts>` to can add both CorDapp Contract JAR hashes.
3. Any flows that build transactions using this CorDapp will have the responsibility of transitioning states to the ``SignatureAttachmentConstraint``.
This is done explicitly in the code by setting the constraint of the output states to signers of the latest version of the whitelisted jar:
.. container:: codeset
.. sourcecode:: kotlin
// This will read the signers for the deployed CorDapp.
val attachment = this.serviceHub.cordappProvider.getContractAttachmentID(contractClass)
val signers = this.serviceHub.attachments.openAttachment(attachment!!)!!.signerKeys
// Create the key that will have to pass for all future versions.
val ownersKey = signers.first()
val txBuilder = TransactionBuilder(notary)
// Set the Signature constraint on the new state to migrate away from the WhitelistConstraint.
.addOutputState(outputState, constraint = SignatureAttachmentConstraint(ownersKey))
.. sourcecode:: java
// This will read the signers for the deployed CorDapp.
SecureHash attachment = this.getServiceHub().getCordappProvider().getContractAttachmentID(contractClass);
List<PublicKey> signers = this.getServiceHub().getAttachments().openAttachment(attachment).getSignerKeys();
// Create the key that will have to pass for all future versions.
PublicKey ownersKey = signers.get(0);
TransactionBuilder txBuilder = new TransactionBuilder(notary)
// Set the Signature constraint on the new state to migrate away from the WhitelistConstraint.
.addOutputState(outputState, myContract, new SignatureAttachmentConstraint(ownersKey))
4. As a node operator you need to add the new signed version of the contracts CorDapp to the ``/cordapps`` folder together with the latest version of the flows jar.
Please also ensure that the original unsigned contracts CorDapp is removed from the ``/cordapps`` folder (this will already be present in the
nodes attachments store) to ensure the lookup code in step 3 retrieves the correct signed contract CorDapp JAR.
Later releases
~~~~~~~~~~~~~~
The next version of Corda will provide automatic transition of *CZ whitelisted* constrained states. This means that signed CorDapps running on a Corda 4.x node will
automatically propagate any pre-existing on-ledger *CZ whitelisted* constrained states (and generate *signature* constrained outputs).

View File

@ -20,10 +20,10 @@ The following guarantees are made for CorDapps running on Corda 4.0
- CorDapp Contract states generated on ledger using hash constraints are not directly migratable to signature constraints in this release.
Your compatibility zone operator may whitelist a JAR previously used to issue hash constrained states, and then you can follow the manual
process described in the paragraph below to migrate these to signature constraints.
process described in the paragraph below to migrate these to signature constraints. See :doc:`cordapp-constraint-migration` for more information.
- CorDapp Contract states generated on ledger using CZ whitelisted constraints are migratable to signature constraints using a manual process
that requires programmatic code changes. See :ref:`constraints_whitelist_to_signature_ref` for more information.
that requires programmatic code changes. See :ref:`cz_whitelisted_constraint_migration` for more information.
- Explicit Contract Upgrades are only supported for hash and CZ whitelisted constraint types. See :ref:`explicit_contract_upgrades_ref` for more information.

View File

@ -76,6 +76,8 @@ alongside the config files. For example, if your directory has this structure:
The ``cordapp-a.jar`` and ``cordapp-b.jar`` will be installed in each node directory, and any contracts within them will be
added to the Contract Whitelist (see below).
.. _bootstrapper_whitelisting_contracts:
Whitelisting contracts
----------------------
@ -191,6 +193,8 @@ such a generated keys, will be unaffected.
the same machine. If a network needs to be updated using the Bootstrapper once deployed, the nodes will need
collecting back together.
.. _bootstrapper_updating_whitelisted_contracts:
Updating the contract whitelist for bootstrapped networks
---------------------------------------------------------

View File

@ -259,7 +259,7 @@ a drain is complete there should be no outstanding checkpoints or running flows.
A node can be drained or undrained via RPC using the ``setFlowsDrainingModeEnabled`` method, and via the shell using
the standard ``run`` command to invoke the RPC. See :doc:`shell` to learn more.
.. _explicit_contract_upgrades_ref:
.. _contract_upgrading_ref:
Contract and state versioning
-----------------------------
@ -271,7 +271,12 @@ There are two types of contract/state upgrade:
2. *Explicit:* By creating a special *contract upgrade transaction* and getting all participants of a state to sign it
using the contract upgrade flows
This section of the documentation focuses only on *explicit* upgrades.
The general recommendation for Corda 4 is to use **implicit** upgrades for the reasons described :ref:`here <implicit_vs_explicit_upgrades>`.
.. _explicit_contract_upgrades_ref:
Performing explicit contract and state upgrades
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In an explicit upgrade, contracts and states can be changed in arbitrary ways, if and only if all of the state's
participants agree to the proposed upgrade. The following combinations of upgrades are possible:
@ -280,9 +285,6 @@ participants agree to the proposed upgrade. The following combinations of upgrad
* A state is upgraded while the contract stays the same
* The state and the contract are updated simultaneously
Performing explicit contract and state upgrades
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Preserve the existing state and contract definitions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Currently, all nodes must **permanently** keep **all** old state and contract definitions on their node's classpath