mirror of
https://github.com/corda/corda.git
synced 2025-05-11 21:13:08 +00:00
Docs: fix various issues for C4.
- Delete information about hash->signature constraint migration. That won't work for C4.0 - Rewrite parts of the api-contract-constraints.rst file to fix grammar problems and reduce the weight of the page. Some detail isn't really necessary at this point in the docs. - Mention more things in the upgrade notes.
This commit is contained in:
parent
5f70abfeca
commit
ca49c5e94d
@ -7,52 +7,42 @@ API: Contract Constraints
|
|||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
|
|
||||||
Contract constraints
|
*Contract constraints* solve two problems faced by any decentralised ledger that supports evolution of data and code:
|
||||||
--------------------
|
|
||||||
|
|
||||||
Corda separates verification of states from their definition. Whilst you might have expected the ``ContractState``
|
1. Controlling and agreeing upon upgrades
|
||||||
interface to define a verify method, or perhaps to do verification logic in the constructor, instead it is primarily
|
2. Preventing attacks
|
||||||
done by a method on a ``Contract`` class. This is because what we're actually checking is the
|
|
||||||
validity of a *transaction*, which is more than just whether the individual states are internally consistent.
|
|
||||||
The transition between two valid states may be invalid, if the rules of the application are not being respected.
|
|
||||||
For instance, two cash states of $100 and $200 may both be internally valid, but replacing the first with the second
|
|
||||||
isn't allowed unless you're a cash issuer - otherwise you could print money for free.
|
|
||||||
|
|
||||||
For a transaction to be valid, the ``verify`` function associated with each state must run successfully. However,
|
Upgrades and security are intimately related because if an attacker can "upgrade" your data to a version of an app that gives them
|
||||||
for this to be secure, it is not sufficient to specify the ``verify`` function by name as there may exist multiple
|
a back door, they would be able to do things like print money or edit states in any way they want. That's why it's important for
|
||||||
different implementations with the same method signature and enclosing class. This normally will happen as applications
|
participants of a state to agree on what kind of upgrades will be allowed.
|
||||||
evolve, but could also happen maliciously as anyone can create a JAR with a class of that name.
|
|
||||||
|
|
||||||
Contract constraints solve this problem by allowing a state creator to constrain which ``verify`` functions out of
|
Every state on the ledger contains the fully qualified class name of a ``Contract`` implementation, and also a *constraint*.
|
||||||
the universe of implementations can be used (i.e. the universe is everything that matches the class name and contract
|
This constraint specifies which versions of an application can be used to provide the named class. There are several types:
|
||||||
constraints restrict this universe to a subset). Constraints are satisfied by attachments (JARs). You are not allowed to
|
|
||||||
attach two JARs that both define the same application due to the *no overlap rule*. This rule specifies that two
|
|
||||||
attachment JARs may not provide the same file path. If they do, the transaction is considered invalid. Because each
|
|
||||||
state specifies both a constraint over attachments *and* a Contract class name to use, the specified class must appear
|
|
||||||
in only one attachment.
|
|
||||||
|
|
||||||
.. note:: With the introduction of signature constraints in Corda 4, a new attachments classloader will verify that
|
1. Hash constraint: exactly one version of the app can be used with this state.
|
||||||
both signed and unsigned versions of an associated contract jar contain identical classes. This allows for automatic
|
2. Zone whitelist constraint: the compatibility zone operator lists the hashes of the versions that can be used with this contract class name.
|
||||||
migration of hash-constrained states (created with pre-Corda 4 unsigned contract jars) to signature constrained states
|
3. Signature constraint: any version of the app signed by the given ``CompositeKey`` can be used.
|
||||||
when used as outputs in new transactions using signed Corda 4 contract jars.
|
4. Always accept constraint: any app can be used at all. This is insecure but convenient for testing.
|
||||||
|
|
||||||
Recap: A corda transaction transitions input states to output states. Each state is composed of data, the name of the class that verifies the transition(contract), and
|
The actual app version used is defined by the attachments on a transaction: the JAR containing the state and contract classes, and optionally
|
||||||
the contract constraint. The transaction also contains a list of attachments (normal JARs) from where these classes will be loaded. There must be only one JAR containing each contract.
|
its dependencies, are all attached to the transaction. Other nodes will download these JARs from a node if they haven't seen them before,
|
||||||
The contract constraints are responsible to ensure the attachment JARs are following the rules set by the creators of the input states (in a continuous chain to the issue).
|
so they can be used for verification. The ``TransactionBuilder`` will manage the details of constraints for you, by selecting both constraints
|
||||||
This way, we have both valid data and valid code that checks the transition packed into the transaction.
|
and attachments to ensure they line up correctly. Therefore you only need to have a basic understanding of this topic unless you are
|
||||||
|
doing something sophisticated.
|
||||||
|
|
||||||
So who picks the attachment to use? It is chosen by the creator of the transaction but has to satisfy the constraints of the input states.
|
The best kind of constraint to use is the **signature constraint**. If you sign your application it will be used automatically.
|
||||||
This is because any node doing transaction resolution will actually verify the selected attachment against all constraints,
|
We recommend signature constraints because they let you release new versions of your application. Hash and zone
|
||||||
so the transaction will only be valid if it passes those checks.
|
whitelist constraints still work, but are left over from earlier Corda versions before signature constraints were
|
||||||
For example, when the input state is constrained by the ``HashAttachmentConstraint``, can only attach the JAR with that hash to the transaction.
|
implemented. They make it harder to upgrade applications than when using signature constraints, so they're best avoided.
|
||||||
|
Signature constraints can specify flexible policies but if you use the automatic support, then a state will require the attached app
|
||||||
|
to be signed by every key that the first attachment was signed by. Thus if the app that was used to issue the states was signed by
|
||||||
|
Alice and Bob, every transaction must use an attachment signed by Alice and Bob.
|
||||||
|
|
||||||
The transaction creator also gets to pick the constraints used by any output states.
|
**Constraint propagation.** Constraints are picked when a state is created for the first time in an issuance transaction. Once created,
|
||||||
When building a transaction, the default constraint on output states is ``AutomaticPlaceholderConstraint``, which means that corda will select the appropriate constraint.
|
the constraint used by the equivalent output state must match the input state, so it can't be changed and you can't combine states with
|
||||||
Unless specified otherwise, attachment constraints will propagate from input to output states. (The rules are described below)
|
incompatible constraints together in the same transaction.
|
||||||
Constraint propagation is also enforced during transaction verification, where for normal transactions (not explicit upgrades, or notary changes),
|
|
||||||
the constraints of the output states are required to "inherit" the constraint of the input states. ( See below for details)
|
|
||||||
|
|
||||||
There are two ways of handling upgrades to a smart contract in Corda:
|
**Implicit vs explicit.** There are two ways of handling upgrades to a smart contract in Corda:
|
||||||
|
|
||||||
1. *Implicit:* By allowing multiple implementations of the contract ahead of time, using constraints.
|
1. *Implicit:* By allowing multiple implementations of the contract ahead of time, using constraints.
|
||||||
2. *Explicit:* By creating a special *contract upgrade transaction* and getting all participants of a state to sign it using the
|
2. *Explicit:* By creating a special *contract upgrade transaction* and getting all participants of a state to sign it using the
|
||||||
@ -121,135 +111,14 @@ CorDapp is 4 or greater, then transaction verification will fail with a ``Transa
|
|||||||
the owning ``Contract`` *can* be identified, but the ``ContractState`` has been bundled with a different contract, then
|
the owning ``Contract`` *can* be identified, but the ``ContractState`` has been bundled with a different contract, then
|
||||||
transaction verification will fail with a ``TransactionContractConflictException``.
|
transaction verification will fail with a ``TransactionContractConflictException``.
|
||||||
|
|
||||||
How constraints work
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
In Corda 4 there are three types of constraint that can be used in production environments: hash, zone whitelist and signature.
|
|
||||||
For development purposes the ``AlwaysAcceptAttachmentConstraint`` allows any attachment to be selected.
|
|
||||||
|
|
||||||
Hash and zone whitelist constraints were available in Corda 3, with hash constraints being used as default.
|
|
||||||
In Corda 4 the default constraint is the signature constraint if the jar is signed. Otherwise,
|
|
||||||
the default constraint type is either a zone constraint, if the network parameters in effect when the
|
|
||||||
transaction is built contain an entry for that contract class, or a hash constraint if not.
|
|
||||||
|
|
||||||
**Hash constraints.** The behaviour provided by public blockchain systems like Bitcoin and Ethereum is that once data is placed on the ledger,
|
|
||||||
the program that controls it is fixed and cannot be changed. There is no support for upgrades at all. This implements a
|
|
||||||
form of "code is law", assuming you trust the community of that blockchain to not release a new version of the platform
|
|
||||||
that invalidates or changes the meaning of your program.
|
|
||||||
|
|
||||||
This is supported by Corda using a hash constraint. This specifies exactly one hash of a CorDapp JAR that contains the
|
|
||||||
contract and states any consuming transaction is allowed to use. Once such a state is created, other nodes will only
|
|
||||||
accept a transaction if it uses that exact JAR file as an attachment. By implication, any bugs in the contract code
|
|
||||||
or state definitions cannot be fixed except by using an explicit upgrade process via ``ContractUpgradeFlow``.
|
|
||||||
|
|
||||||
.. note:: Corda does not support any way to create states that can never be upgraded at all, but the same effect can be
|
|
||||||
obtained by using a hash constraint and then simply refusing to agree to any explicit upgrades. Hash
|
|
||||||
constraints put you in control by requiring an explicit agreement to any upgrade.
|
|
||||||
|
|
||||||
**Zone constraints.** Often a hash constraint will be too restrictive. You do want the ability to upgrade an app,
|
|
||||||
and you don't mind the upgrade taking effect "just in time" when a transaction happens to be required for other business
|
|
||||||
reasons. In this case you can use a zone constraint. This specifies that the network parameters of a compatibility zone
|
|
||||||
(see :doc:`network-map`) is expected to contain a map of class name to hashes of JARs that are allowed to provide that
|
|
||||||
class. The process for upgrading an app then involves asking the zone operator to add the hash of your new JAR to the
|
|
||||||
parameters file, and trigger the network parameters upgrade process. This involves each node operator running a shell
|
|
||||||
command to accept the new parameters file and then restarting the node. Node owners who do not restart their node in
|
|
||||||
time effectively stop being a part of the network.
|
|
||||||
|
|
||||||
**Signature constraints.** These enforce an association between a state and its associated contract JAR which must be
|
|
||||||
signed by a specified identity, via the regular Java ``jarsigner`` tool. This is the most flexible type
|
|
||||||
and the smoothest to deploy: no restarts or contract upgrade transactions are needed.
|
|
||||||
When a CorDapp is build using :ref:`corda-gradle-plugin <cordapp_build_system_signing_cordapp_jar_ref>` the JAR is signed
|
|
||||||
by Corda development key by default, an external keystore can be configured or signing can be disabled.
|
|
||||||
|
|
||||||
.. warning:: CorDapps can only use signature constraints when participating in a Corda network using a minimum platform version of 4.
|
|
||||||
An auto downgrade rule applies to signed CorDapps built and tested with Corda 4 but running on a Corda network of a lower version:
|
|
||||||
if the associated contract class is whitelisted in the network parameters then zone constraints are applied, otherwise hash constraints are used.
|
|
||||||
|
|
||||||
A ``TransactionState`` has a ``constraint`` field that represents that state's attachment constraint. When a party
|
|
||||||
constructs a ``TransactionState``, or adds a state using ``TransactionBuilder.addOutput(ContractState)`` without
|
|
||||||
specifying the constraint parameter, a default value (``AutomaticPlaceholderConstraint``) is used. This default will be
|
|
||||||
automatically resolved to a specific ``HashAttachmentConstraint`` or a ``WhitelistedByZoneAttachmentConstraint``.
|
|
||||||
This automatic resolution occurs when a ``TransactionBuilder`` is converted to a ``WireTransaction``. This reduces
|
|
||||||
the boilerplate that would otherwise be involved.
|
|
||||||
|
|
||||||
Finally, an ``AlwaysAcceptAttachmentConstraint`` can be used which accepts anything, though this is intended for
|
|
||||||
testing only, and a warning will be shown if used by a contract.
|
|
||||||
|
|
||||||
Please note that the ``AttachmentConstraint`` interface is marked as ``@DoNotImplement``. You are not allowed to write
|
|
||||||
new constraint types. Only the platform may implement this interface. If you tried, other nodes would not understand
|
|
||||||
your constraint type and your transaction would not verify.
|
|
||||||
|
|
||||||
.. warning:: An AlwaysAccept constraint is effectively the same as disabling security for those states entirely.
|
|
||||||
Nothing stops you using this constraint in production, but that degrades Corda to being effectively a form
|
|
||||||
of distributed messaging with optional contract logic being useful only to catch mistakes, rather than potentially
|
|
||||||
malicious action. If you are deploying an app for which malicious actors aren't in your threat model, using an
|
|
||||||
AlwaysAccept constraint might simplify things operationally.
|
|
||||||
|
|
||||||
An example below shows how to construct a ``TransactionState`` with an explicitly specified hash constraint from within
|
|
||||||
a flow:
|
|
||||||
|
|
||||||
.. sourcecode:: java
|
|
||||||
|
|
||||||
// Constructing a transaction with a custom hash constraint on a state
|
|
||||||
TransactionBuilder tx = new TransactionBuilder();
|
|
||||||
|
|
||||||
Party notaryParty = ... // a notary party
|
|
||||||
|
|
||||||
tx.addInputState(...)
|
|
||||||
tx.addInputState(...)
|
|
||||||
|
|
||||||
DummyState contractState = new DummyState();
|
|
||||||
|
|
||||||
TransactionState transactionState = new TransactionState(contractState, DummyContract.Companion.getPROGRAMID(), notaryParty, null, HashAttachmentConstraint(myhash));
|
|
||||||
tx.addOutputState(transactionState);
|
|
||||||
WireTransaction wtx = tx.toWireTransaction(serviceHub); // This is where an automatic constraint would be resolved.
|
|
||||||
LedgerTransaction ltx = wtx.toLedgerTransaction(serviceHub);
|
|
||||||
ltx.verify(); // Verifies both the attachment constraints and contracts
|
|
||||||
|
|
||||||
.. _contract_non-downgrade_rule_ref:
|
.. _contract_non-downgrade_rule_ref:
|
||||||
|
|
||||||
Contract attachment non-downgrade rule
|
App versioning with signature constraints
|
||||||
--------------------------------------
|
-----------------------------------------
|
||||||
Contract code is versioned and deployed as an independent JAR that gets imported into a node's database as a contract attachment (either explicitly
|
|
||||||
uploaded via RPC or automatically loaded from disk). When constructing new transaction it is paramount to ensure
|
|
||||||
that the contract version of code associated with new output states is the same or newer than the highest version of any existing input states.
|
|
||||||
This is to prevent the possibility of nodes selecting older, potentially malicious or buggy contract code when creating new states from
|
|
||||||
existing consumed states.
|
|
||||||
|
|
||||||
Transactions contain an attachment for each contract. The version of the output states is the version of this contract attachment.
|
|
||||||
See :doc:`versioning` for more details on how these versions are set. These can be seen as the version of the code that instantiated and
|
|
||||||
serialised those classes.
|
|
||||||
|
|
||||||
The non-downgrade rule specifies that the version of the code used in the transaction that spends a state needs to be greater than or equal to
|
|
||||||
the highest version of the input states (i.e. spending_version >= creation_version)
|
|
||||||
|
|
||||||
The contract attachment non-downgrade rule is enforced in two locations:
|
|
||||||
|
|
||||||
1. Transaction building, upon creation of new output states. During this step, the node also selects the latest available attachment
|
|
||||||
(i.e. the contract code with the latest contract class version).
|
|
||||||
2. Transaction verification, upon resolution of existing transaction chains.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
Signed apps require a version number to be provided, see :doc:`versioning`. You can't import two different JARs that claim to be the same
|
||||||
|
version, export the same contract classes and which are both signed. At runtime the node will throw a
|
||||||
|
``DuplicateContractClassException`` exception if this condition is violated.
|
||||||
|
|
||||||
Issues when using the HashAttachmentConstraint
|
Issues when using the HashAttachmentConstraint
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
@ -262,16 +131,16 @@ 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
|
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.
|
adding the right cordapp jar to the ``cordapps`` folder.
|
||||||
|
|
||||||
|
|
||||||
CorDapps as attachments
|
CorDapps as attachments
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
CorDapp JARs (see :doc:`cordapp-overview`) that contain classes implementing the ``Contract`` interface are automatically
|
CorDapp JARs (see :doc:`cordapp-overview`) that contain classes implementing the ``Contract`` interface are automatically
|
||||||
loaded into the ``AttachmentStorage`` of a node, and made available as ``ContractAttachments``.
|
loaded into the ``AttachmentStorage`` of a node, and made available as ``ContractAttachments``.
|
||||||
They are retrievable by hash using ``AttachmentStorage.openAttachment``.
|
|
||||||
These JARs can either be installed on the node or fetched from the network using the ``FetchAttachmentsFlow``.
|
|
||||||
|
|
||||||
.. note:: The obvious way to write a CorDapp is to put all you states, contracts, flows and support code into a single
|
They are retrievable by hash using ``AttachmentStorage.openAttachment``. These JARs can either be installed on the
|
||||||
|
node or will be automatically fetched over the network when receiving a transaction.
|
||||||
|
|
||||||
|
.. warning:: The obvious way to write a CorDapp is to put all you states, contracts, flows and support code into a single
|
||||||
Java module. This will work but it will effectively publish your entire app onto the ledger. That has two problems:
|
Java module. This will work but it will effectively publish your entire app onto the ledger. That has two problems:
|
||||||
(1) it is inefficient, and (2) it means changes to your flows or other parts of the app will be seen by the ledger
|
(1) it is inefficient, and (2) it means changes to your flows or other parts of the app will be seen by the ledger
|
||||||
as a "new app", which may end up requiring essentially unnecessary upgrade procedures. It's better to split your
|
as a "new app", which may end up requiring essentially unnecessary upgrade procedures. It's better to split your
|
||||||
@ -282,15 +151,12 @@ These JARs can either be installed on the node or fetched from the network using
|
|||||||
Constraints propagation
|
Constraints propagation
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
As was mentioned above, the TransactionBuilder API gives the CorDapp developer or even malicious node owner the possibility
|
As was mentioned above, the ``TransactionBuilder`` API gives the CorDapp developer or even malicious node owner the possibility
|
||||||
to construct output states with a constraint of his choosing.
|
to construct output states with a constraint of his choosing.
|
||||||
Also, as listed above, some constraints are more restrictive then others.
|
|
||||||
For example, the ``HashAttachmentConstraint`` is the most restrictive, basically reducing the universe of possible attachments
|
|
||||||
to 1 (see migrating from hash constraints in note below), while the ``AlwaysAcceptAttachmentConstraint`` allows any attachment to be selected.
|
|
||||||
|
|
||||||
For the ledger to remain in a consistent state, the expected behavior is for output state to inherit the constraints of input states.
|
For the ledger to remain in a consistent state, the expected behavior is for output state to inherit the constraints of input states.
|
||||||
This guarantees that for example, a transaction can't output a state with the ``AlwaysAcceptAttachmentConstraint`` when the
|
This guarantees that for example, a transaction can't output a state with the ``AlwaysAcceptAttachmentConstraint`` when the
|
||||||
corresponding input state was the ``HashAttachmentConstraint``. Translated, this means that if this rule is enforced, it ensures
|
corresponding input state was the ``SignatureAttachmentConstraint``. Translated, this means that if this rule is enforced, it ensures
|
||||||
that the output state will be spent under similar conditions as it was created.
|
that the output state will be spent under similar conditions as it was created.
|
||||||
|
|
||||||
Before version 4, the constraint propagation logic was expected to be enforced in the contract verify code, as it has access to the entire Transaction.
|
Before version 4, the constraint propagation logic was expected to be enforced in the contract verify code, as it has access to the entire Transaction.
|
||||||
@ -298,47 +164,21 @@ Before version 4, the constraint propagation logic was expected to be enforced i
|
|||||||
Starting with version 4 of Corda, the constraint propagation logic has been implemented and enforced directly by the platform,
|
Starting with version 4 of Corda, the constraint propagation logic has been implemented and enforced directly by the platform,
|
||||||
unless disabled using ``@NoConstraintPropagation`` - which reverts to the previous behavior.
|
unless disabled using ``@NoConstraintPropagation`` - which reverts to the previous behavior.
|
||||||
|
|
||||||
For Contracts that are not annotated with ``@NoConstraintPropagation``, the platform implements a fairly simple constraint transition policy
|
For contracts that are not annotated with ``@NoConstraintPropagation``, the platform implements a fairly simple constraint transition policy
|
||||||
to ensure security and also allow the possibility to transition to the new ``SignatureAttachmentConstraint``.
|
to ensure security and also allow the possibility to transition to the new ``SignatureAttachmentConstraint``.
|
||||||
|
|
||||||
.. note:: Migration from hash to signature constraints is automatic if the transaction building node has a signed version of the
|
|
||||||
original contract jar (used in previous transactions generating hash constrained states). Additionally, it is a requirement that
|
|
||||||
the owner of this signed jar register the java package namespace of the encompassing contract classes with the network parameters.
|
|
||||||
See :ref:`package_namespace_ownership` introduced in Corda 4.
|
|
||||||
|
|
||||||
During transaction building the ``AutomaticPlaceholderConstraint`` for output states will be resolved and the best contract attachment versions
|
During transaction building the ``AutomaticPlaceholderConstraint`` for output states will be resolved and the best contract attachment versions
|
||||||
will be selected based on a variety of factors so that the above holds true.
|
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
|
||||||
If it can't find attachments in storage or there are no possible constraints, the Transaction Builder will fail early.
|
possible constraints, the ``TransactionBuilder`` will throw an exception.
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
- In the simple case, if a ``MyContract`` input state is constrained by the ``HashAttachmentConstraint``, then the constraints of all output states of that type will be resolved
|
|
||||||
to the ``HashAttachmentConstraint`` with the same hash, and the attachment with that hash will be selected.
|
|
||||||
|
|
||||||
- For upgradeable constraints like the ``WhitelistedByZoneAttachmentConstraint``, the output states will inherit the same,
|
|
||||||
and the selected attachment will be the latest version installed on the node.
|
|
||||||
|
|
||||||
- A more complex case is when for ``MyContract``, one input state is constrained by the ``HashAttachmentConstraint``, while another
|
|
||||||
state by the ``WhitelistedByZoneAttachmentConstraint``. To respect the rule from above, if the hash of the ``HashAttachmentConstraint``
|
|
||||||
is whitelisted by the network, then the output states will inherit the ``HashAttachmentConstraint``, as it is more restrictive.
|
|
||||||
If the hash was not whitelisted, then the builder will fail as it is unable to select a correct constraint.
|
|
||||||
|
|
||||||
- The ``SignatureAttachmentConstraint`` is an upgradeable constraint, same as the ``WhitelistedByZoneAttachmentConstraint``.
|
|
||||||
By convention we allow states to transition to the ``SignatureAttachmentConstraint`` from the ``WhitelistedByZoneAttachmentConstraint`` as long as the Signatures
|
|
||||||
from new constraints are all the jarsigners from the whitelisted attachment. We also allow transitioning of states from ``HashAttachmentConstraint`` to
|
|
||||||
``SignatureAttachmentConstraint`` where both the unsigned and signed versions of the associated contract attachment are loaded in a node, and the java
|
|
||||||
package namespace of encompassing contract classes is registered with the network parameters using the same signing key as the signed contract jar.
|
|
||||||
|
|
||||||
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) .
|
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
---------
|
---------
|
||||||
If an attachment constraint cannot be resolved, a ``MissingContractAttachments`` exception is thrown. There are two
|
If an attachment constraint cannot be resolved, a ``MissingContractAttachments`` exception is thrown. There are three common sources of
|
||||||
common sources of ``MissingContractAttachments`` exceptions:
|
``MissingContractAttachments`` exceptions:
|
||||||
|
|
||||||
Not setting CorDapp packages in tests
|
Not setting CorDapp packages in tests
|
||||||
*************************************
|
*************************************
|
||||||
|
|
||||||
You are running a test and have not specified the CorDapp packages to scan.
|
You are running a test and have not specified the CorDapp packages to scan.
|
||||||
When using ``MockNetwork`` ensure you have provided a package containing the contract class in ``MockNetworkParameters``. See :doc:`api-testing`.
|
When using ``MockNetwork`` ensure you have provided a package containing the contract class in ``MockNetworkParameters``. See :doc:`api-testing`.
|
||||||
|
|
||||||
@ -374,6 +214,7 @@ See :doc:`generating-a-node` for detailed instructions.
|
|||||||
|
|
||||||
Wrong fully-qualified contract name
|
Wrong fully-qualified contract name
|
||||||
***********************************
|
***********************************
|
||||||
|
|
||||||
You are specifying the fully-qualified name of the contract incorrectly. For example, you've defined ``MyContract`` in
|
You are specifying the fully-qualified name of the contract incorrectly. For example, you've defined ``MyContract`` in
|
||||||
the package ``com.mycompany.myapp.contracts``, but the fully-qualified contract name you pass to the
|
the package ``com.mycompany.myapp.contracts``, but the fully-qualified contract name you pass to the
|
||||||
``TransactionBuilder`` is ``com.mycompany.myapp.MyContract`` (instead of ``com.mycompany.myapp.contracts.MyContract``).
|
``TransactionBuilder`` is ``com.mycompany.myapp.MyContract`` (instead of ``com.mycompany.myapp.contracts.MyContract``).
|
@ -17,10 +17,20 @@ However, there are usually new features and other opt-in changes that may improv
|
|||||||
application that are worth considering for any actively maintained software. This guide shows you how to upgrade your app to benefit
|
application that are worth considering for any actively maintained software. This guide shows you how to upgrade your app to benefit
|
||||||
from the new features in the latest release.
|
from the new features in the latest release.
|
||||||
|
|
||||||
|
.. warning:: The sample apps found in the Corda repository and the Corda samples repository are not intended to be used in production.
|
||||||
|
If you are using them you should re-namespace them to a package namespace you control, and sign/version them yourself.
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
:depth: 3
|
:depth: 3
|
||||||
|
|
||||||
Step 1. Adjust the version numbers in your Gradle build files
|
Step 1. Switch any RPC clients to use the new RPC library
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
Although the RPC API is backwards compatible with Corda 3, the RPC wire protocol isn't. Therefore RPC clients like web servers need to be
|
||||||
|
updated in lockstep with the node to use the new version of the RPC library. Corda 4 delivers RPC wire stability and therefore in future you
|
||||||
|
will be able to update the node and apps without updating RPC clients.
|
||||||
|
|
||||||
|
Step 2. Adjust the version numbers in your Gradle build files
|
||||||
-------------------------------------------------------------
|
-------------------------------------------------------------
|
||||||
|
|
||||||
Alter the versions you depend on in your Gradle file like so:
|
Alter the versions you depend on in your Gradle file like so:
|
||||||
@ -43,7 +53,7 @@ You should also ensure you're using Gradle 4.10 (but not 5). If you use the Grad
|
|||||||
|
|
||||||
Otherwise just upgrade your installed copy in the usual manner for your operating system.
|
Otherwise just upgrade your installed copy in the usual manner for your operating system.
|
||||||
|
|
||||||
Step 2. Update your Gradle build file
|
Step 3. Update your Gradle build file
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
There are several adjustments that are beneficial to make to your Gradle build file, beyond simply incrementing the versions
|
There are several adjustments that are beneficial to make to your Gradle build file, beyond simply incrementing the versions
|
||||||
@ -110,7 +120,7 @@ starting from 1.
|
|||||||
If you use the finance demo app, you should adjust your dependencies so you depend on the finance-contracts
|
If you use the finance demo app, you should adjust your dependencies so you depend on the finance-contracts
|
||||||
and finance-workflows artifacts from your own contract and workflow JAR respectively.
|
and finance-workflows artifacts from your own contract and workflow JAR respectively.
|
||||||
|
|
||||||
Step 3. Security: Upgrade your use of FinalityFlow
|
Step 4. Security: Upgrade your use of FinalityFlow
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
||||||
The previous ``FinalityFlow`` API is insecure. It doesn't have a receive flow, so requires counterparty nodes to accept any and
|
The previous ``FinalityFlow`` API is insecure. It doesn't have a receive flow, so requires counterparty nodes to accept any and
|
||||||
@ -224,7 +234,7 @@ You may already be using ``waitForLedgerCommit`` in your responder flow for the
|
|||||||
Now that it's calling ``ReceiveFinalityFlow``, which effectively does the same thing, this is no longer necessary. The call to
|
Now that it's calling ``ReceiveFinalityFlow``, which effectively does the same thing, this is no longer necessary. The call to
|
||||||
``waitForLedgerCommit`` should be removed.
|
``waitForLedgerCommit`` should be removed.
|
||||||
|
|
||||||
Step 4. Security: Upgrade your use of SwapIdentitiesFlow
|
Step 5. Security: Upgrade your use of SwapIdentitiesFlow
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|
||||||
The :ref:`confidential_identities_ref` API is experimental in Corda 3 and remains so in Corda 4. In this release, the ``SwapIdentitiesFlow``
|
The :ref:`confidential_identities_ref` API is experimental in Corda 3 and remains so in Corda 4. In this release, the ``SwapIdentitiesFlow``
|
||||||
@ -232,7 +242,7 @@ has been adjusted in the same way as ``FinalityFlow`` above, to close problems w
|
|||||||
outside of other flow context. Old code will still work, but it is recommended to adjust your call sites so a session is passed into
|
outside of other flow context. Old code will still work, but it is recommended to adjust your call sites so a session is passed into
|
||||||
the ``SwapIdentitiesFlow``.
|
the ``SwapIdentitiesFlow``.
|
||||||
|
|
||||||
Step 5. Possibly, adjust test code
|
Step 6. Possibly, adjust test code
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
``MockNodeParameters`` and functions creating it no longer use a lambda expecting a ``NodeConfiguration`` object.
|
``MockNodeParameters`` and functions creating it no longer use a lambda expecting a ``NodeConfiguration`` object.
|
||||||
@ -283,7 +293,7 @@ For instance, if you have 2 CorDapps containing the packages ``net.corda.example
|
|||||||
.. note:: If you have any CorDapp code (e.g. flows/contracts/states) that is only used by the tests and located in the same test module, it won't be discovered now.
|
.. note:: If you have any CorDapp code (e.g. flows/contracts/states) that is only used by the tests and located in the same test module, it won't be discovered now.
|
||||||
You will need to move them in the main module of one of your CorDapps or create a new, separate CorDapp for them, in case you don't want this code to live inside your production CorDapps.
|
You will need to move them in the main module of one of your CorDapps or create a new, separate CorDapp for them, in case you don't want this code to live inside your production CorDapps.
|
||||||
|
|
||||||
Step 6. Security: Add BelongsToContract annotations
|
Step 7. Security: Add BelongsToContract annotations
|
||||||
---------------------------------------------------
|
---------------------------------------------------
|
||||||
|
|
||||||
In versions of the platform prior to v4, it was the responsibility of contract and flow logic to ensure that ``TransactionState`` objects
|
In versions of the platform prior to v4, it was the responsibility of contract and flow logic to ensure that ``TransactionState`` objects
|
||||||
@ -300,7 +310,7 @@ to be governed by a contract that is either:
|
|||||||
Learn more by reading ":ref:`implicit_constraint_types`". If an app targets Corda 3 or lower (i.e. does not specify a target version),
|
Learn more by reading ":ref:`implicit_constraint_types`". If an app targets Corda 3 or lower (i.e. does not specify a target version),
|
||||||
states that point to contracts outside their package will trigger a log warning but validation will proceed.
|
states that point to contracts outside their package will trigger a log warning but validation will proceed.
|
||||||
|
|
||||||
Step 7. Learn about signature constraints and JAR signing
|
Step 8. Learn about signature constraints and JAR signing
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
|
|
||||||
:doc:`design/data-model-upgrades/signature-constraints` are a new data model feature introduced in Corda 4. They make it much easier to
|
:doc:`design/data-model-upgrades/signature-constraints` are a new data model feature introduced in Corda 4. They make it much easier to
|
||||||
@ -314,7 +324,7 @@ 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
|
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.
|
to production you will need to generate signing keys and integrate them with the build process.
|
||||||
|
|
||||||
Step 8. Security: Package namespace handling
|
Step 9. Security: Package namespace handling
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
Almost no apps will be affected by these changes, but they're important to know about.
|
Almost no apps will be affected by these changes, but they're important to know about.
|
||||||
@ -331,7 +341,7 @@ In the unlikely event that you were injecting code into ``net.corda.finance.*``
|
|||||||
into a new package, e.g. ``net/corda/finance/flows/MyClass.java`` can be moved to ``com/company/corda/finance/flows/MyClass.java``.
|
into a new package, e.g. ``net/corda/finance/flows/MyClass.java`` can be moved to ``com/company/corda/finance/flows/MyClass.java``.
|
||||||
As a consequence your classes are no longer able to access non-public members of finance CorDapp classes.
|
As a consequence your classes are no longer able to access non-public members of finance CorDapp classes.
|
||||||
|
|
||||||
When recompiling your JARs for Corda 4, your own apps will also become sealed, meaning other JARs cannot place classes into your own packages.
|
When signing your JARs for Corda 4, your own apps will also become sealed, meaning other JARs cannot place classes into your own packages.
|
||||||
This is a security upgrade that ensures package-private visibility in Java code works correctly. If other apps could define classes in your own
|
This is a security upgrade that ensures package-private visibility in Java code works correctly. If other apps could define classes in your own
|
||||||
packages, they could call package-private methods, which may not be expected by the developers.
|
packages, they could call package-private methods, which may not be expected by the developers.
|
||||||
|
|
||||||
@ -342,9 +352,8 @@ Whilst this feature is optional and not strictly required, it may be helpful to
|
|||||||
where type names may be taken "as read". You can learn more about this feature and the motivation for it by reading
|
where type names may be taken "as read". You can learn more about this feature and the motivation for it by reading
|
||||||
":doc:`design/data-model-upgrades/package-namespace-ownership`".
|
":doc:`design/data-model-upgrades/package-namespace-ownership`".
|
||||||
|
|
||||||
|
Step 10. Consider adding extension points to your flows
|
||||||
Step 9. Consider adding extension points to your flows
|
-------------------------------------------------------
|
||||||
------------------------------------------------------
|
|
||||||
|
|
||||||
In Corda 4 it is possible for flows in one app to subclass and take over flows from another. This allows you to create generic, shared
|
In Corda 4 it is possible for flows in one app to subclass and take over flows from another. This allows you to create generic, shared
|
||||||
flow logic that individual users can customise at pre-agreed points (protected methods). For example, a site-specific app could be developed
|
flow logic that individual users can customise at pre-agreed points (protected methods). For example, a site-specific app could be developed
|
||||||
@ -353,16 +362,15 @@ into shared business logic, but it makes perfect sense to put into a user-specif
|
|||||||
|
|
||||||
If your flows could benefit from being extended in this way, read ":doc:`flow-overriding`" to learn more.
|
If your flows could benefit from being extended in this way, read ":doc:`flow-overriding`" to learn more.
|
||||||
|
|
||||||
Step 10. Possibly update Vault state queries
|
Step 11. Possibly update vault state queries
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
Queries made on a node's vault can filter by the relevancy of those states to the node in Corda 4. As this functionality does not exist in
|
In Corda 4 queries made on a node's vault can filter by the relevancy of those states to the node. As this functionality does not exist in
|
||||||
Corda 3, apps targeting that release will continue to receive all states in any vault queries. In Corda 4, the default is to return all
|
Corda 3, apps will continue to receive all states in any vault queries. However, it may make sense to migrate queries expecting just those states relevant
|
||||||
states in the vault, to maintain backwards compatibility. However, it may make sense to migrate queries expecting just those states relevant
|
|
||||||
to the node in question to query for only relevant states. See :doc:`api-vault-query.rst` for more details on how to do this. Not doing this
|
to the node in question to query for only relevant states. See :doc:`api-vault-query.rst` for more details on how to do this. Not doing this
|
||||||
may result in queries returning more states than expected if the node is using Observer node functionality (see ":doc:`tutorial-observer-nodes.rst`").
|
may result in queries returning more states than expected if the node is using observer functionality (see ":doc:`tutorial-observer-nodes.rst`").
|
||||||
|
|
||||||
Step 10. Explore other new features that may be useful
|
Step 12. Explore other new features that may be useful
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
|
|
||||||
Corda 4 adds several new APIs that help you build applications. Why not explore:
|
Corda 4 adds several new APIs that help you build applications. Why not explore:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user