mirror of
https://github.com/corda/corda.git
synced 2024-12-27 08:22:35 +00:00
Merge remote-tracking branch 'open/master' into kat-merge-180412
This commit is contained in:
commit
5bb9514582
@ -1895,7 +1895,7 @@ public @interface net.corda.core.messaging.RPCReturnsObservables
|
|||||||
@org.jetbrains.annotations.NotNull public final List getNotaries()
|
@org.jetbrains.annotations.NotNull public final List getNotaries()
|
||||||
@org.jetbrains.annotations.NotNull public final Map getWhitelistedContractImplementations()
|
@org.jetbrains.annotations.NotNull public final Map getWhitelistedContractImplementations()
|
||||||
public int hashCode()
|
public int hashCode()
|
||||||
public String toString()
|
@org.jetbrains.annotations.NotNull public String toString()
|
||||||
##
|
##
|
||||||
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.node.NodeInfo extends java.lang.Object
|
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.node.NodeInfo extends java.lang.Object
|
||||||
public <init>(List, List, int, long)
|
public <init>(List, List, int, long)
|
||||||
|
@ -47,6 +47,20 @@ data class NetworkParameters(
|
|||||||
require(maxMessageSize > 0) { "maxMessageSize must be at least 1" }
|
require(maxMessageSize > 0) { "maxMessageSize must be at least 1" }
|
||||||
require(maxTransactionSize > 0) { "maxTransactionSize must be at least 1" }
|
require(maxTransactionSize > 0) { "maxTransactionSize must be at least 1" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return """NetworkParameters {
|
||||||
|
minimumPlatformVersion=$minimumPlatformVersion
|
||||||
|
notaries=$notaries
|
||||||
|
maxMessageSize=$maxMessageSize
|
||||||
|
maxTransactionSize=$maxTransactionSize
|
||||||
|
whitelistedContractImplementations {
|
||||||
|
${whitelistedContractImplementations.entries.joinToString("\n ")}
|
||||||
|
}
|
||||||
|
modifiedTime=$modifiedTime
|
||||||
|
epoch=$epoch
|
||||||
|
}"""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,22 @@ Here's a summary of what's changed in each Corda release. For guidance on how to
|
|||||||
release, see :doc:`upgrade-notes`.
|
release, see :doc:`upgrade-notes`.
|
||||||
|
|
||||||
Unreleased
|
Unreleased
|
||||||
----------
|
==========
|
||||||
|
|
||||||
|
* Fix CORDA-1229. Setter-based serialization was broken with generic types when the property was stored
|
||||||
|
as the raw type, List for example.
|
||||||
|
|
||||||
|
* java.security.cert.CRLReason added to the default Whitelist.
|
||||||
|
|
||||||
|
* java.security.cert.X509CRL serialization support added.
|
||||||
|
|
||||||
|
* Upgraded H2 to v1.4.197.
|
||||||
|
|
||||||
|
* Shell (embedded available only in dev mode or via SSH) connects to the node via RPC instead of using the ``CordaRPCOps`` object directly.
|
||||||
|
To enable RPC connectivity ensure node’s ``rpcSettings.address`` and ``rpcSettings.adminAddress`` settings are present.
|
||||||
|
|
||||||
|
* The network bootstrapper uses the existing network parameters file to update the current contracts whitelist, and no longer
|
||||||
|
needs the whitelist.txt file.
|
||||||
|
|
||||||
* Errors thrown by a Corda node will now reported to a calling RPC client with attention to serialization and obfuscation of internal data.
|
* Errors thrown by a Corda node will now reported to a calling RPC client with attention to serialization and obfuscation of internal data.
|
||||||
|
|
||||||
@ -19,16 +34,12 @@ Unreleased
|
|||||||
only once when it was created. Whilst registering serializers that already exist is essentially a no-op, it's a performance overhead for
|
only once when it was created. Whilst registering serializers that already exist is essentially a no-op, it's a performance overhead for
|
||||||
a very frequent operation that hits a synchronisation point (and is thus flagged as contended by our perfomance suite)
|
a very frequent operation that hits a synchronisation point (and is thus flagged as contended by our perfomance suite)
|
||||||
|
|
||||||
* Update the fast-classpath-scanner dependent library version from 2.0.21 to 2.12.3
|
|
||||||
|
|
||||||
.. note:: Whilst this is not the latest version of this library, that being 2.18.1 at time of writing, versions later
|
|
||||||
than 2.12.3 (including 2.12.4) exhibit a different issue.
|
|
||||||
|
|
||||||
* Node can be shut down abruptly by ``shutdown`` function in `CordaRPCOps` or gracefully (draining flows first) through ``gracefulShutdown`` command from shell.
|
* Node can be shut down abruptly by ``shutdown`` function in `CordaRPCOps` or gracefully (draining flows first) through ``gracefulShutdown`` command from shell.
|
||||||
|
|
||||||
* Carpenter Exceptions will be caught internally by the Serializer and rethrown as a ``NotSerializableException``
|
* Carpenter Exceptions will be caught internally by the Serializer and rethrown as a ``NotSerializableException``
|
||||||
|
|
||||||
* Specific details of the error encountered are logged to the node's log file. More information can be enabled by setting the debug level to ``trace`` ; this will cause the full stack trace of the error to be dumped into the log.
|
* Specific details of the error encountered are logged to the node's log file. More information can be enabled by setting the debug level to
|
||||||
|
``trace`` ; this will cause the full stack trace of the error to be dumped into the log.
|
||||||
|
|
||||||
* Parsing of ``NodeConfiguration`` will now fail if unknown configuration keys are found.
|
* Parsing of ``NodeConfiguration`` will now fail if unknown configuration keys are found.
|
||||||
|
|
||||||
@ -40,51 +51,22 @@ Unreleased
|
|||||||
|
|
||||||
* java.math.BigInteger serialization support added.
|
* java.math.BigInteger serialization support added.
|
||||||
|
|
||||||
* java.security.cert.CRLReason added to the default Whitelist.
|
* Update the fast-classpath-scanner dependent library version from 2.0.21 to 2.12.3
|
||||||
|
|
||||||
* java.security.cert.X509CRL serialization support added.
|
.. note:: Whilst this is not the latest version of this library, that being 2.18.1 at time of writing, versions later
|
||||||
|
than 2.12.3 (including 2.12.4) exhibit a different issue.
|
||||||
|
|
||||||
* Upgraded H2 to v1.4.197.
|
* Updated the api scanner gradle plugin to work the same way as the version in master. These changes make the api scanner more
|
||||||
|
accurate and fix a couple of bugs, and change the format of the api-current.txt file slightly. Backporting these changes
|
||||||
|
to the v3 branch will make it easier for us to ensure that apis are stable for future versions. These changes are
|
||||||
|
released in gradle plugins version 3.0.10. For more information on the api scanner see
|
||||||
|
the `documentation <https://github.com/corda/corda-gradle-plugins/tree/master/api-scanner>`_.
|
||||||
|
|
||||||
* Per CorDapp configuration is now exposed. ``CordappContext`` now exposes a ``CordappConfig`` object that is populated
|
* Fixed security vulnerability when using the ``HashAttachmentConstraint``. Added strict check that the contract JARs
|
||||||
at CorDapp context creation time from a file source during runtime.
|
referenced in a transaction were deployed on the node.
|
||||||
|
|
||||||
* Introduced Flow Draining mode, in which a node continues executing existing flows, but does not start new. This is to support graceful node shutdown/restarts.
|
* Fixed node's behaviour on startup when there is no connectivity to network map. Node continues to work normally if it has
|
||||||
In particular, when this mode is on, new flows through RPC will be rejected, scheduled flows will be ignored, and initial session messages will not be consumed.
|
all the needed network data, waiting in the background for network map to become available.
|
||||||
This will ensure that the number of checkpoints will strictly diminish with time, allowing for a clean shutdown.
|
|
||||||
|
|
||||||
* Make the serialisation finger-printer a pluggable entity rather than hard wiring into the factory
|
|
||||||
|
|
||||||
* Removed blacklisted word checks in Corda X.500 name to allow "Server" or "Node" to be use as part of the legal name.
|
|
||||||
|
|
||||||
* Separated our pre-existing Artemis broker into an RPC broker and a P2P broker.
|
|
||||||
|
|
||||||
* Refactored ``NodeConfiguration`` to expose ``NodeRpcOptions`` (using top-level "rpcAddress" property still works with warning).
|
|
||||||
|
|
||||||
* Modified ``CordaRPCClient`` constructor to take a ``SSLConfiguration?`` additional parameter, defaulted to ``null``.
|
|
||||||
|
|
||||||
* Introduced ``CertificateChainCheckPolicy.UsernameMustMatchCommonName`` sub-type, allowing customers to optionally enforce username == CN condition on RPC SSL certificates.
|
|
||||||
|
|
||||||
* Modified ``DriverDSL`` and sub-types to allow specifying RPC settings for the Node.
|
|
||||||
|
|
||||||
* Modified the ``DriverDSL`` to start Cordformation nodes allowing automatic generation of "rpcSettings.adminAddress" in case "rcpSettings.useSsl" is ``false`` (the default).
|
|
||||||
|
|
||||||
* Introduced ``UnsafeCertificatesFactory`` allowing programmatic generation of X509 certificates for test purposes.
|
|
||||||
|
|
||||||
* JPA Mapping annotations for States extending ``CommonSchemaV1.LinearState`` and ``CommonSchemaV1.FungibleState`` on the
|
|
||||||
`participants` collection need to be moved to the actual class. This allows to properly specify the unique table name per a collection.
|
|
||||||
See: DummyDealStateSchemaV1.PersistentDummyDealState
|
|
||||||
|
|
||||||
* JPA Mapping annotations for States extending ``CommonSchemaV1.LinearState`` and ``CommonSchemaV1.FungibleState`` on the
|
|
||||||
`participants` collection need to be moved to the actual State class. This allows developers to properly specify
|
|
||||||
the table name for the `participants` collection.
|
|
||||||
For an example on how the mapping can be done, see: DummyDealStateSchemaV1.PersistentDummyDealState
|
|
||||||
|
|
||||||
* JDBC drivers for SQL server and PostgresSQL are no longer bundled as part of Corda releases. If you are running a node
|
|
||||||
on such databases you need to provide the associated driver as described in :doc:`node-database`.
|
|
||||||
|
|
||||||
* Shell (embedded shell available only in dev mode or via SSH) connects to the node via RPC instead of using the ``CordaRPCOps`` object directly.
|
|
||||||
To enable RPC connectivity ensure node’s ``rpcSettings.address`` and ``rpcSettings.adminAddress`` settings are present.
|
|
||||||
|
|
||||||
R3 Corda 3.0 Developer Preview
|
R3 Corda 3.0 Developer Preview
|
||||||
------------------------------
|
------------------------------
|
||||||
|
@ -1,20 +1,6 @@
|
|||||||
Release notes
|
Release notes
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Unreleased
|
|
||||||
----------
|
|
||||||
|
|
||||||
* **Enum Class Evolution**
|
|
||||||
With the addition of AMQP serialization Corda now supports enum constant evolution.
|
|
||||||
|
|
||||||
That is the ability to alter an enum constant and, as long as certain rules are followed and the correct
|
|
||||||
annotations applied, have older and newer instances of that enumeration be understood.
|
|
||||||
|
|
||||||
* X.509 certificates now have an extension that specifies the Corda role the certificate is used for, and the role
|
|
||||||
hierarchy is now enforced in the validation code. This only has impact on those developing integrations with external
|
|
||||||
PKI solutions, in most cases it is managed transparently by Corda. A formal specification of the extension can be
|
|
||||||
found at :doc:`permissioning`.
|
|
||||||
|
|
||||||
R3 Corda 3.0 Developer Preview
|
R3 Corda 3.0 Developer Preview
|
||||||
------------------------------
|
------------------------------
|
||||||
This Developer Preview takes us towards the launch of R3 Corda, R3's commercially supported enterprise blockchain platform.
|
This Developer Preview takes us towards the launch of R3 Corda, R3's commercially supported enterprise blockchain platform.
|
||||||
@ -168,8 +154,62 @@ Please note this release is distributed under license and should not be used in
|
|||||||
|
|
||||||
We look forward to hearing your feedback on this Developer Preview.
|
We look forward to hearing your feedback on this Developer Preview.
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
Corda 2.0
|
Corda 2.0
|
||||||
---------
|
---------
|
||||||
|
=======
|
||||||
|
Documentation can be found in :doc:`cordapp-custom-serializers`
|
||||||
|
|
||||||
|
|
||||||
|
Security Auditing
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This version of Corda is the first to have had select components subjected to the newly established security review process
|
||||||
|
by R3's internal security team. Security review will be an on-going process that seeks to provide assurance that the
|
||||||
|
security model of Corda has been implemented to the highest standard, and is in line with industry best practice.
|
||||||
|
|
||||||
|
As part of this security review process, an independent external security audit of the HTTP based components of the code
|
||||||
|
was undertaken and its recommendations were acted upon. The security assurance process will develop in parallel to the
|
||||||
|
Corda platform and will combine code review, automated security testing and secure development practices to ensure Corda
|
||||||
|
fulfils its security guarantees.
|
||||||
|
|
||||||
|
Security fixes
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* Due to a potential privacy leak, there has been a breaking change in the error object returned by the
|
||||||
|
notary service when trying to consume the same state twice: `NotaryError.Conflict` no longer contains the identity
|
||||||
|
of the party that initiated the first spend of the state, and specifies the hash of the consuming transaction id for
|
||||||
|
a state instead of the id itself.
|
||||||
|
|
||||||
|
Without this change, knowing the reference of a particular state, an attacker could construct an invalid
|
||||||
|
double-spend transaction, and obtain the information on the transaction and the party that consumed it. It could
|
||||||
|
repeat this process with the newly obtained transaction id by guessing its output indexes to obtain the forward
|
||||||
|
transaction graph with associated identities. When anonymous identities are used, this could also reveal the identity
|
||||||
|
of the owner of an asset.
|
||||||
|
|
||||||
|
Minor Changes
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* Upgraded gradle to 4.4.1.
|
||||||
|
|
||||||
|
.. note:: To avoid potential incompatibility issues we recommend you also upgrade your CorDapp's gradle
|
||||||
|
plugin to match. Details on how to do this can be found on the official
|
||||||
|
`gradle website <https://docs.gradle.org/current/userguide/gradle_wrapper.html#sec:upgrading_wrapper>`_
|
||||||
|
|
||||||
|
* Cash Spending now allows for sending multiple amounts to multiple parties with a single API call
|
||||||
|
|
||||||
|
- documentation can be found within the JavaDocs on ``TwoPartyTradeFlow``.
|
||||||
|
* Overall improvements to error handling (RPC, Flows, Network Client).
|
||||||
|
* TLS authentication now supports mixed RSA and ECDSA keys.
|
||||||
|
* PrivacySalt computation is faster as it does not depend on the OS's entropy pool directly.
|
||||||
|
* Numerous bug fixes and documentation tweaks.
|
||||||
|
* Removed dependency on Jolokia WAR file.
|
||||||
|
|
||||||
|
.. _release_notes_v2_0:
|
||||||
|
|
||||||
|
Release 2.0
|
||||||
|
-----------
|
||||||
|
>>>>>>> open/master
|
||||||
Following quickly on the heels of the release of Corda 1.0, Corda version 2.0 consolidates
|
Following quickly on the heels of the release of Corda 1.0, Corda version 2.0 consolidates
|
||||||
a number of security updates for our dependent libraries alongside the reintroduction of the Observer node functionality.
|
a number of security updates for our dependent libraries alongside the reintroduction of the Observer node functionality.
|
||||||
This was absent from version 1 but based on user feedback its re-introduction removes the need for complicated "isRelevant()" checks.
|
This was absent from version 1 but based on user feedback its re-introduction removes the need for complicated "isRelevant()" checks.
|
||||||
@ -187,8 +227,15 @@ Adds the facility for transparent forwarding of transactions to some third party
|
|||||||
that entity simply run an Observer node they can simply receive a stream of digitally signed, de-duplicated reports that
|
that entity simply run an Observer node they can simply receive a stream of digitally signed, de-duplicated reports that
|
||||||
can be used for reporting.
|
can be used for reporting.
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
Corda 1.0
|
Corda 1.0
|
||||||
---------
|
---------
|
||||||
|
=======
|
||||||
|
.. _release_notes_v1_0:
|
||||||
|
|
||||||
|
Release 1.0
|
||||||
|
-----------
|
||||||
|
>>>>>>> open/master
|
||||||
Corda 1.0 is finally here!
|
Corda 1.0 is finally here!
|
||||||
|
|
||||||
This critical step in the Corda journey enables the developer community, clients, and partners to build on Corda with confidence.
|
This critical step in the Corda journey enables the developer community, clients, and partners to build on Corda with confidence.
|
||||||
|
@ -93,34 +93,16 @@ If you want to create a *Zone whitelist* (see :doc:`api-contract-constraints`),
|
|||||||
|
|
||||||
``java -jar network-bootstrapper.jar <nodes-root-dir> <path-to-first-corDapp> <path-to-second-corDapp> ..``
|
``java -jar network-bootstrapper.jar <nodes-root-dir> <path-to-first-corDapp> <path-to-second-corDapp> ..``
|
||||||
|
|
||||||
The CorDapp jars will be hashed and scanned for ``Contract`` classes.
|
The CorDapp jars will be hashed and scanned for ``Contract`` classes. These contract class implementations will become part
|
||||||
By default the tool would generate a file named ``whitelist.txt`` containing an entry for each contract with the hash of the jar.
|
of the whitelisted contracts in the network parameters (see ``NetworkParameters.whitelistedContractImplementations`` :doc:`network-map`).
|
||||||
|
If the network already has a set of network parameters defined (i.e. the node directories all contain the same network-parameters
|
||||||
|
file) then the new set of contracts will be appended to the current whitelist.
|
||||||
|
|
||||||
For example:
|
.. note:: The whitelist can only ever be appended to. Once added a contract implementation can never be removed.
|
||||||
|
|
||||||
.. sourcecode:: none
|
By default the bootstrapper tool will whitelist all the contracts found in all the CorDapp jars. To prevent certain
|
||||||
|
contracts from being whitelisted, add their fully qualified class name in the ``exclude_whitelist.txt``. These will instead
|
||||||
net.corda.finance.contracts.asset.Obligation:decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de8
|
use the more restrictive ``HashAttachmentConstraint``.
|
||||||
net.corda.finance.contracts.asset.Cash:decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9
|
|
||||||
|
|
||||||
These will be added to the ``NetworkParameters.whitelistedContractImplementations``. See :doc:`network-map`.
|
|
||||||
|
|
||||||
This means that by default the Network bootstrapper tool will whitelist all contracts found in all passed CorDapps.
|
|
||||||
|
|
||||||
In case there is a ``whitelist.txt`` file in the root dir already, the tool will append the new jar hashes or contracts to it.
|
|
||||||
|
|
||||||
The zone operator will maintain this whitelist file, and, using the tool, will append new versions of CorDapps to it.
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
- The zone operator must ensure that this file is *append only*.
|
|
||||||
- If the operator removes hashes from the list, all transactions pointing to that version will suddenly fail the constraint verification, and the entire chain is compromised.
|
|
||||||
- If a contract is removed from the whitelist, then all states created from that moment on will be constrained by the HashAttachmentConstraint.
|
|
||||||
|
|
||||||
Note: In future releases, we will provider a tamper-proof way of maintaining the contract whitelist.
|
|
||||||
|
|
||||||
For fine-grained control of constraints, in case multiple contracts live in the same jar, the tool reads from another file:
|
|
||||||
``exclude_whitelist.txt``, which contains a list of contracts that should not be whitelisted, and thus default to the very restrictive:
|
|
||||||
``HashAttachmentConstraint``
|
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
@ -129,7 +111,6 @@ For example:
|
|||||||
net.corda.finance.contracts.asset.Cash
|
net.corda.finance.contracts.asset.Cash
|
||||||
net.corda.finance.contracts.asset.CommercialPaper
|
net.corda.finance.contracts.asset.CommercialPaper
|
||||||
|
|
||||||
|
|
||||||
Starting the nodes
|
Starting the nodes
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -140,6 +140,85 @@ Applies to both gradle deployNodes tasks and/or corda node configuration (node.c
|
|||||||
|
|
||||||
notary = [validating : true]
|
notary = [validating : true]
|
||||||
|
|
||||||
|
<<< Fill this in >>>
|
||||||
|
|
||||||
|
v3.0 to v3.1
|
||||||
|
------------
|
||||||
|
|
||||||
|
Gradle Plugin Version
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Corda 3.1 uses version 3.1.0 of the gradle plugins and your ``build.gradle`` file should be updated to reflect this.
|
||||||
|
|
||||||
|
.. sourcecode:: shell
|
||||||
|
|
||||||
|
ext.corda_gradle_plugins_version = '3.1.0'
|
||||||
|
|
||||||
|
You will also need to update the ``corda_release_version`` identifier in your project gradle file.
|
||||||
|
|
||||||
|
.. sourcecode:: shell
|
||||||
|
|
||||||
|
ext.corda_release_version = '3.1-corda'
|
||||||
|
|
||||||
|
V2.0 to V3.0
|
||||||
|
------------
|
||||||
|
|
||||||
|
Gradle Plugin Version
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Corda 3.0 uses version 3.0.9 of the gradle plugins and your ``build.gradle`` file should be updated to reflect this.
|
||||||
|
|
||||||
|
.. sourcecode:: shell
|
||||||
|
|
||||||
|
ext.corda_gradle_plugins_version = '3.0.9'
|
||||||
|
|
||||||
|
You will also need to update the ``corda_release_version`` identifier in your project gradle file.
|
||||||
|
|
||||||
|
.. sourcecode:: shell
|
||||||
|
|
||||||
|
ext.corda_release_version = 'corda-3.0'
|
||||||
|
|
||||||
|
Network Map Service
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
With the re-designed network map service the following changes need to be made:
|
||||||
|
|
||||||
|
* The network map is no longer provided by a node and thus the ``networkMapService`` config is ignored. Instead the
|
||||||
|
network map is either provided by the compatibility zone (CZ) operator (who operates the doorman) and available
|
||||||
|
using the ``compatibilityZoneURL`` config, or is provided using signed node info files which are copied locally.
|
||||||
|
See :doc:`network-map` for more details, and :doc:`setting-up-a-corda-network.rst` on how to use the network
|
||||||
|
bootstrapper for deploying a local network.
|
||||||
|
|
||||||
|
* Configuration for a notary has been simplified. ``extraAdvertisedServiceIds``, ``notaryNodeAddress``, ``notaryClusterAddresses``
|
||||||
|
and ``bftSMaRt`` configs have been replaced by a single ``notary`` config object. See :doc:`corda-configuration-file`
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
* The advertisement of the notary to the rest of the network, and its validation type, is no longer determined by the
|
||||||
|
``extraAdvertisedServiceIds`` config. Instead it has been moved to the control of the network operator via
|
||||||
|
the introduction of network parameters. The network bootstrapper automatically includes the configured notaries
|
||||||
|
when generating the network parameters file for a local deployment.
|
||||||
|
|
||||||
|
* Any nodes defined in a ``deployNodes`` gradle task performing the function of the network map can be removed, or the
|
||||||
|
``NetworkMap`` parameter can be removed for any "controller" node which is both the network map and a notary.
|
||||||
|
|
||||||
|
* For registering a node with the doorman the ``certificateSigningService`` config has been replaced by ``compatibilityZoneURL``.
|
||||||
|
|
||||||
|
Corda Plugins
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
* Corda plugins have been modularised further so the following additional gradle entries are necessary:
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. sourcecode:: groovy
|
||||||
|
dependencies {
|
||||||
|
classpath "net.corda.plugins:cordapp:$corda_gradle_plugins_version"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'net.corda.plugins.cordapp'
|
||||||
|
|
||||||
|
The plugin needs to be applied in all gradle build files where there is a dependency on Corda using any of:
|
||||||
|
cordaCompile, cordaRuntime, cordapp
|
||||||
|
|
||||||
* For existing contract ORM schemas that extend from ``CommonSchemaV1.LinearState`` or ``CommonSchemaV1.FungibleState``,
|
* For existing contract ORM schemas that extend from ``CommonSchemaV1.LinearState`` or ``CommonSchemaV1.FungibleState``,
|
||||||
you will need to explicitly map the ``participants`` collection to a database table. Previously this mapping was done
|
you will need to explicitly map the ``participants`` collection to a database table. Previously this mapping was done
|
||||||
in the superclass, but that makes it impossible to properly configure the table name. The required changes are to:
|
in the superclass, but that makes it impossible to properly configure the table name. The required changes are to:
|
||||||
@ -163,84 +242,66 @@ Applies to both gradle deployNodes tasks and/or corda node configuration (node.c
|
|||||||
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")))
|
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")))
|
||||||
override var participants: MutableSet<AbstractParty>? = null,
|
override var participants: MutableSet<AbstractParty>? = null,
|
||||||
|
|
||||||
* Shell - to use Shell ensure ``rpcSettings.address`` and ``rpcSettings.adminAddress`` settings are present.
|
AMQP
|
||||||
|
^^^^
|
||||||
|
|
||||||
|
Whilst the enablement of AMQP is a transparent change, as noted in the :doc:`serialization` documentation
|
||||||
|
the way classes, and states in particular, should be written to work with this new library may require some
|
||||||
|
alteration to your current implementation.
|
||||||
|
|
||||||
|
* With AMQP enabled Java classes must be compiled with the -parameter flag.
|
||||||
|
|
||||||
|
* If they aren't, then the error message will complain about ``arg<N>`` being an unknown parameter.
|
||||||
|
* If recompilation is not viable, a custom serializer can be written as per :doc:`cordapp-custom-serializers`
|
||||||
|
* It is important to bear in mind that with AMQP there must be an implicit mapping between constructor
|
||||||
|
parameters and properties you wish included in the serialized form of a class.
|
||||||
|
|
||||||
|
* See :doc:`serialization` for more information
|
||||||
|
|
||||||
|
* Error messages of the form
|
||||||
|
|
||||||
|
``Constructor parameter - "<some parameter of a constructor>" - doesn't refer to a property of "class <some.class.being.serialized>"``
|
||||||
|
|
||||||
|
indicate that a class, in the above example ``some.class.being.serialized``, has a parameter on its primary constructor that
|
||||||
|
doesn't correlate to a property of the class. This is a problem because the Corda AMQP serialization library uses a class's
|
||||||
|
constructor (default, primary, or annotated) as the means by which instances of the serialized form are reconstituted.
|
||||||
|
|
||||||
|
See the section "Mismatched Class Properties / Constructor Parameters" in the :doc:`serialization` documentation
|
||||||
|
|
||||||
|
Database schema changes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
An H2 database instance (represented on the filesystem as a file called `persistence.mv.db`) used in Corda 1.0 or 2.0
|
||||||
|
cannot be directly reused with Corda 3.0 due to minor improvements and additions to stabilise the underlying schemas.
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Nodes that do not require SSL to be enabled for RPC clients now need an additional port to be specified as part of their configuration.
|
||||||
|
To do this, add a block as follows to the nodes configuraiton:
|
||||||
|
|
||||||
|
.. sourcecode:: script
|
||||||
|
|
||||||
|
rpcSettings {
|
||||||
|
adminAddress "localhost:10007"
|
||||||
|
}
|
||||||
|
|
||||||
|
to `node.conf` files.
|
||||||
|
|
||||||
|
Also, the property `rpcPort` is now deprecated, so it would be preferable to substitute properties specified that way e.g., `rpcPort=10006` with a block as follows:
|
||||||
|
|
||||||
|
.. sourcecode:: script
|
||||||
|
|
||||||
|
rpcSettings {
|
||||||
|
address "localhost:10006"
|
||||||
|
adminAddress "localhost:10007"
|
||||||
|
}
|
||||||
|
|
||||||
|
Equivalent changes should be performed on classes extending `CordformDefinition`.
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
|
||||||
Contract tests
|
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
* You must now create a ``MockServices`` object.
|
|
||||||
|
|
||||||
``MockServices`` provides a mock identity, key and storage service. ``MockServices`` takes as its first argument a
|
|
||||||
list of the CorDapp packages to scan:
|
|
||||||
|
|
||||||
.. sourcecode:: kotlin
|
|
||||||
|
|
||||||
private val ledgerServices = MockServices(listOf("net.corda.examples.obligation", "net.corda.testing.contracts"))
|
|
||||||
|
|
||||||
``MockServices`` replaces the use of ``setCordappPackages`` and ``unsetCordappPackages``.
|
|
||||||
|
|
||||||
* ``ledger`` is now defined as a ``MockServices`` method. This means that:
|
|
||||||
|
|
||||||
.. sourcecode:: kotlin
|
|
||||||
|
|
||||||
ledger {
|
|
||||||
|
|
||||||
Becomes:
|
|
||||||
|
|
||||||
.. sourcecode:: kotlin
|
|
||||||
|
|
||||||
ledgerServices.ledger {
|
|
||||||
|
|
||||||
* Within a mock ledger transaction, ``ContractState`` instances are passed to ``input`` and ``output`` as objects
|
|
||||||
rather than lambdas. For example:
|
|
||||||
|
|
||||||
.. sourcecode:: kotlin
|
|
||||||
|
|
||||||
ledgerServices.ledger {
|
|
||||||
transaction {
|
|
||||||
input(OBLIGATION_CONTRACT_ID, DummyState())
|
|
||||||
output(OBLIGATION_CONTRACT_ID, oneDollarObligation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
* Within a mock ledger transaction, ``CommandData`` instances are passed to ``input`` and ``output`` as objects
|
|
||||||
rather than lambdas, and the public keys must be passed as a list if there is more than one. For example:
|
|
||||||
|
|
||||||
.. sourcecode:: kotlin
|
|
||||||
|
|
||||||
ledgerServices.ledger {
|
|
||||||
transaction {
|
|
||||||
command(alice.publicKey, ObligationContract.Commands.Issue())
|
|
||||||
command(listOf(alice.publicKey, bob.publicKey), ObligationContract.Commands.Issue())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
* The predefined test identities (e.g. ``ALICE`` and ``MINI_CORP``) have been removed.
|
|
||||||
|
|
||||||
You must now define the test identities explicitly. For example:
|
|
||||||
|
|
||||||
.. sourcecode:: kotlin
|
|
||||||
|
|
||||||
val alice = TestIdentity(CordaX500Name(organisation = "Alice", locality = "TestLand", country = "GB"))
|
|
||||||
|
|
||||||
``TestIdentity`` exposes methods to get the ``name``, ``keyPair``, ``publicKey``, ``party`` and ``identity`` of the
|
|
||||||
underlying ``TestIdentity``
|
|
||||||
|
|
||||||
* Explicit invocation of transaction transformation (ie. using ``TransactionBuilder``) requires serialization engine
|
|
||||||
to be initialized. In unit test this can be achieved by using the following jUnit rule:
|
|
||||||
|
|
||||||
.. sourcecode:: kotlin
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
@JvmField
|
|
||||||
val testSerialization = SerializationEnvironmentRule()
|
|
||||||
|
|
||||||
Flow tests
|
|
||||||
~~~~~~~~~~
|
|
||||||
|
|
||||||
* The registration mechanism for CorDapps in ``MockNetwork`` unit tests has changed:
|
* The registration mechanism for CorDapps in ``MockNetwork`` unit tests has changed:
|
||||||
|
|
||||||
* CorDapp registration is now done via the ``cordappPackages`` constructor parameter of MockNetwork.
|
* CorDapp registration is now done via the ``cordappPackages`` constructor parameter of MockNetwork.
|
||||||
@ -399,6 +460,47 @@ Finance
|
|||||||
* ``CASH_PROGRAM_ID`` has been moved to ``Cash.PROGRAM_ID``, where ``Cash`` is defined in the
|
* ``CASH_PROGRAM_ID`` has been moved to ``Cash.PROGRAM_ID``, where ``Cash`` is defined in the
|
||||||
``import net.corda.finance.contracts.asset`` package
|
``import net.corda.finance.contracts.asset`` package
|
||||||
|
|
||||||
|
* Many classes have been moved between packages, so you will need to update your imports
|
||||||
|
|
||||||
|
.. tip:: We have provided a several scripts (depending upon your operating system of choice) to smooth the upgrade
|
||||||
|
process for existing projects. This can be found at ``tools\scripts\update-test-packages.sh`` for the Bash shell and
|
||||||
|
``tools/scripts/upgrade-test-packages.ps1`` for Windows Power Shell users in the source tree
|
||||||
|
|
||||||
|
* setCordappPackages and unsetCordappPackages have been removed from the ledger/transaction DSL and the flow test framework,
|
||||||
|
and are now set via a constructor parameter or automatically when constructing the MockServices or MockNetwork object
|
||||||
|
|
||||||
|
* Key constants e.g. ``ALICE_KEY`` have been removed; you can now use TestIdentity to make your own
|
||||||
|
|
||||||
|
* The ledger/transaction DSL must now be provided with MockServices as it no longer makes its own
|
||||||
|
* In transaction blocks, input and output take their arguments as ContractStates rather than lambdas
|
||||||
|
* Also in transaction blocks, command takes its arguments as CommandDatas rather than lambdas
|
||||||
|
|
||||||
|
* The MockServices API has changed; please refer to its API documentation
|
||||||
|
|
||||||
|
* TestDependencyInjectionBase has been retired in favour of a JUnit Rule called SerializationEnvironmentRule
|
||||||
|
* This replaces the initialiseSerialization parameter of ledger/transaction and verifierDriver
|
||||||
|
* The withTestSerialization method is obsoleted by SerializationEnvironmentRule and has been retired
|
||||||
|
|
||||||
|
* MockNetwork now takes a MockNetworkParameters builder to make it more Java-friendly, like driver's DriverParameters
|
||||||
|
* Similarly, the MockNetwork.createNode methods now take a MockNodeParameters builder
|
||||||
|
|
||||||
|
* MockNode constructor parameters are now aggregated in MockNodeArgs for easier subclassing
|
||||||
|
|
||||||
|
* MockNetwork.Factory has been retired as you can simply use a lambda
|
||||||
|
|
||||||
|
* testNodeConfiguration has been retired, please use a mock object framework of your choice instead
|
||||||
|
|
||||||
|
* MockNetwork.createSomeNodes and IntegrationTestCategory have been retired with no replacement
|
||||||
|
|
||||||
|
* Starting a flow can now be done directly from a node object. Change calls of the form ``node.getServices().startFlow(...)``
|
||||||
|
to ``node.startFlow(...)``
|
||||||
|
|
||||||
|
* Similarly a tranaction can be executed directly from a node object. Change calls of the form ``node.getDatabase().transaction({ it -> ... })``
|
||||||
|
to ``node.transaction({() -> ... })``
|
||||||
|
|
||||||
|
* ``startFlow`` now returns a ``CordaFuture``, there is no need to call ``startFlow(...).getResultantFuture()``
|
||||||
|
|
||||||
|
|
||||||
V1.0 to V2.0
|
V1.0 to V2.0
|
||||||
------------
|
------------
|
||||||
|
|
||||||
@ -745,4 +847,4 @@ Finance
|
|||||||
|
|
||||||
* Adjust imports of Cash flow references
|
* Adjust imports of Cash flow references
|
||||||
* Adjust the ``StartFlow`` permission in ``gradle.build`` files
|
* Adjust the ``StartFlow`` permission in ``gradle.build`` files
|
||||||
* Adjust imports of the associated flows (``Cash*Flow``, ``TwoPartyTradeFlow``, ``TwoPartyDealFlow``)
|
* Adjust imports of the associated flows (``Cash*Flow``, ``TwoPartyTradeFlow``, ``TwoPartyDealFlow``)
|
||||||
|
@ -12,7 +12,6 @@ package net.corda.nodeapi.internal.network
|
|||||||
|
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import net.corda.cordform.CordformNode
|
import net.corda.cordform.CordformNode
|
||||||
import net.corda.core.crypto.SecureHash.Companion.parse
|
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.internal.concurrent.fork
|
import net.corda.core.internal.concurrent.fork
|
||||||
@ -21,10 +20,13 @@ import net.corda.core.node.NodeInfo
|
|||||||
import net.corda.core.node.NotaryInfo
|
import net.corda.core.node.NotaryInfo
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.serialization.SerializationContext
|
import net.corda.core.serialization.SerializationContext
|
||||||
|
import net.corda.core.serialization.SerializedBytes
|
||||||
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
|
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
|
||||||
import net.corda.core.serialization.internal._contextSerializationEnv
|
import net.corda.core.serialization.internal._contextSerializationEnv
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
|
import net.corda.nodeapi.internal.DEV_ROOT_CA
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.scanJarForContracts
|
import net.corda.nodeapi.internal.scanJarForContracts
|
||||||
import net.corda.nodeapi.internal.serialization.AMQP_P2P_CONTEXT
|
import net.corda.nodeapi.internal.serialization.AMQP_P2P_CONTEXT
|
||||||
@ -33,11 +35,10 @@ import net.corda.nodeapi.internal.serialization.SerializationFactoryImpl
|
|||||||
import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme
|
import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme
|
||||||
import net.corda.nodeapi.internal.serialization.kryo.AbstractKryoSerializationScheme
|
import net.corda.nodeapi.internal.serialization.kryo.AbstractKryoSerializationScheme
|
||||||
import net.corda.nodeapi.internal.serialization.kryo.kryoMagic
|
import net.corda.nodeapi.internal.serialization.kryo.kryoMagic
|
||||||
import java.io.PrintStream
|
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.nio.file.StandardCopyOption
|
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.TimeoutException
|
import java.util.concurrent.TimeoutException
|
||||||
@ -57,12 +58,11 @@ class NetworkBootstrapper {
|
|||||||
)
|
)
|
||||||
|
|
||||||
private const val LOGS_DIR_NAME = "logs"
|
private const val LOGS_DIR_NAME = "logs"
|
||||||
private const val WHITELIST_FILE_NAME = "whitelist.txt"
|
|
||||||
private const val EXCLUDE_WHITELIST_FILE_NAME = "exclude_whitelist.txt"
|
private const val EXCLUDE_WHITELIST_FILE_NAME = "exclude_whitelist.txt"
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val baseNodeDirectory = args.firstOrNull() ?: throw IllegalArgumentException("Expecting first argument which is the nodes' parent directory")
|
val baseNodeDirectory = requireNotNull(args.firstOrNull()) { "Expecting first argument which is the nodes' parent directory" }
|
||||||
val cordapps = if (args.size > 1) args.toList().drop(1) else null
|
val cordapps = if (args.size > 1) args.toList().drop(1) else null
|
||||||
NetworkBootstrapper().bootstrap(Paths.get(baseNodeDirectory).toAbsolutePath().normalize(), cordapps)
|
NetworkBootstrapper().bootstrap(Paths.get(baseNodeDirectory).toAbsolutePath().normalize(), cordapps)
|
||||||
}
|
}
|
||||||
@ -80,15 +80,17 @@ class NetworkBootstrapper {
|
|||||||
try {
|
try {
|
||||||
println("Waiting for all nodes to generate their node-info files...")
|
println("Waiting for all nodes to generate their node-info files...")
|
||||||
val nodeInfoFiles = gatherNodeInfoFiles(processes, nodeDirs)
|
val nodeInfoFiles = gatherNodeInfoFiles(processes, nodeDirs)
|
||||||
println("Distributing all node info-files to all nodes")
|
println("Distributing all node-info files to all nodes")
|
||||||
distributeNodeInfos(nodeDirs, nodeInfoFiles)
|
distributeNodeInfos(nodeDirs, nodeInfoFiles)
|
||||||
|
print("Loading existing network parameters... ")
|
||||||
|
val existingNetParams = loadNetworkParameters(nodeDirs)
|
||||||
|
println(existingNetParams ?: "none found")
|
||||||
println("Gathering notary identities")
|
println("Gathering notary identities")
|
||||||
val notaryInfos = gatherNotaryInfos(nodeInfoFiles)
|
val notaryInfos = gatherNotaryInfos(nodeInfoFiles)
|
||||||
println("Notary identities to be used in network parameters: ${notaryInfos.joinToString("; ") { it.prettyPrint() }}")
|
println("Generating contract implementations whitelist")
|
||||||
val mergedWhiteList = generateWhitelist(directory / WHITELIST_FILE_NAME, directory / EXCLUDE_WHITELIST_FILE_NAME, cordapps?.distinct())
|
val newWhitelist = generateWhitelist(existingNetParams, directory / EXCLUDE_WHITELIST_FILE_NAME, cordapps?.distinct())
|
||||||
println("Updating whitelist")
|
val netParams = installNetworkParameters(notaryInfos, newWhitelist, existingNetParams, nodeDirs)
|
||||||
overwriteWhitelist(directory / WHITELIST_FILE_NAME, mergedWhiteList)
|
println("${if (existingNetParams == null) "New" else "Updated"} $netParams")
|
||||||
installNetworkParameters(notaryInfos, nodeDirs, mergedWhiteList)
|
|
||||||
println("Bootstrapping complete!")
|
println("Bootstrapping complete!")
|
||||||
} finally {
|
} finally {
|
||||||
_contextSerializationEnv.set(null)
|
_contextSerializationEnv.set(null)
|
||||||
@ -106,15 +108,15 @@ class NetworkBootstrapper {
|
|||||||
val nodeName = confFile.fileName.toString().removeSuffix("_node.conf")
|
val nodeName = confFile.fileName.toString().removeSuffix("_node.conf")
|
||||||
println("Generating directory for $nodeName")
|
println("Generating directory for $nodeName")
|
||||||
val nodeDir = (directory / nodeName).createDirectories()
|
val nodeDir = (directory / nodeName).createDirectories()
|
||||||
confFile.moveTo(nodeDir / "node.conf", StandardCopyOption.REPLACE_EXISTING)
|
confFile.moveTo(nodeDir / "node.conf", REPLACE_EXISTING)
|
||||||
webServerConfFiles.firstOrNull { directory.relativize(it).toString().removeSuffix("_web-server.conf") == nodeName }?.moveTo(nodeDir / "web-server.conf", StandardCopyOption.REPLACE_EXISTING)
|
webServerConfFiles.firstOrNull { directory.relativize(it).toString().removeSuffix("_web-server.conf") == nodeName }?.moveTo(nodeDir / "web-server.conf", REPLACE_EXISTING)
|
||||||
Files.copy(cordaJar, (nodeDir / "corda.jar"), StandardCopyOption.REPLACE_EXISTING)
|
cordaJar.copyToDirectory(nodeDir, REPLACE_EXISTING)
|
||||||
}
|
}
|
||||||
Files.delete(cordaJar)
|
Files.delete(cordaJar)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractCordaJarTo(directory: Path): Path {
|
private fun extractCordaJarTo(directory: Path): Path {
|
||||||
val cordaJarPath = (directory / "corda.jar")
|
val cordaJarPath = directory / "corda.jar"
|
||||||
if (!cordaJarPath.exists()) {
|
if (!cordaJarPath.exists()) {
|
||||||
println("No corda jar found in root directory. Extracting from jar")
|
println("No corda jar found in root directory. Extracting from jar")
|
||||||
Thread.currentThread().contextClassLoader.getResourceAsStream("corda.jar").copyTo(cordaJarPath)
|
Thread.currentThread().contextClassLoader.getResourceAsStream("corda.jar").copyTo(cordaJarPath)
|
||||||
@ -147,7 +149,7 @@ class NetworkBootstrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
future.getOrThrow(60.seconds)
|
future.getOrThrow(timeout = 60.seconds)
|
||||||
} catch (e: TimeoutException) {
|
} catch (e: TimeoutException) {
|
||||||
println("...still waiting. If this is taking longer than usual, check the node logs.")
|
println("...still waiting. If this is taking longer than usual, check the node logs.")
|
||||||
future.getOrThrow()
|
future.getOrThrow()
|
||||||
@ -158,7 +160,7 @@ class NetworkBootstrapper {
|
|||||||
for (nodeDir in nodeDirs) {
|
for (nodeDir in nodeDirs) {
|
||||||
val additionalNodeInfosDir = (nodeDir / CordformNode.NODE_INFO_DIRECTORY).createDirectories()
|
val additionalNodeInfosDir = (nodeDir / CordformNode.NODE_INFO_DIRECTORY).createDirectories()
|
||||||
for (nodeInfoFile in nodeInfoFiles) {
|
for (nodeInfoFile in nodeInfoFiles) {
|
||||||
nodeInfoFile.copyToDirectory(additionalNodeInfosDir, StandardCopyOption.REPLACE_EXISTING)
|
nodeInfoFile.copyToDirectory(additionalNodeInfosDir, REPLACE_EXISTING)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,25 +180,67 @@ class NetworkBootstrapper {
|
|||||||
}.distinct() // We need distinct as nodes part of a distributed notary share the same notary identity
|
}.distinct() // We need distinct as nodes part of a distributed notary share the same notary identity
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun installNetworkParameters(notaryInfos: List<NotaryInfo>, nodeDirs: List<Path>, whitelist: Map<String, List<AttachmentId>>) {
|
private fun loadNetworkParameters(nodeDirs: List<Path>): NetworkParameters? {
|
||||||
// TODO Add config for minimumPlatformVersion, maxMessageSize and maxTransactionSize
|
val netParamsFilesGrouped = nodeDirs.mapNotNull {
|
||||||
val copier = NetworkParametersCopier(NetworkParameters(
|
val netParamsFile = it / NETWORK_PARAMS_FILE_NAME
|
||||||
minimumPlatformVersion = 1,
|
if (netParamsFile.exists()) netParamsFile else null
|
||||||
notaries = notaryInfos,
|
}.groupBy { SerializedBytes<SignedNetworkParameters>(it.readAll()) }
|
||||||
modifiedTime = Instant.now(),
|
|
||||||
maxMessageSize = 10485760,
|
|
||||||
maxTransactionSize = Int.MAX_VALUE,
|
|
||||||
epoch = 1,
|
|
||||||
whitelistedContractImplementations = whitelist
|
|
||||||
), overwriteFile = true)
|
|
||||||
|
|
||||||
nodeDirs.forEach { copier.install(it) }
|
when (netParamsFilesGrouped.size) {
|
||||||
|
0 -> return null
|
||||||
|
1 -> return netParamsFilesGrouped.keys.first().deserialize().verifiedNetworkMapCert(DEV_ROOT_CA.certificate)
|
||||||
|
}
|
||||||
|
|
||||||
|
val msg = StringBuilder("Differing sets of network parameters were found. Make sure all the nodes have the same " +
|
||||||
|
"network parameters by copying over the correct $NETWORK_PARAMS_FILE_NAME file.\n\n")
|
||||||
|
|
||||||
|
netParamsFilesGrouped.forEach { bytes, netParamsFiles ->
|
||||||
|
netParamsFiles.map { it.parent.fileName }.joinTo(msg, ", ")
|
||||||
|
msg.append(":\n")
|
||||||
|
val netParamsString = try {
|
||||||
|
bytes.deserialize().verifiedNetworkMapCert(DEV_ROOT_CA.certificate).toString()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
"Invalid network parameters file: $e"
|
||||||
|
}
|
||||||
|
msg.append(netParamsString)
|
||||||
|
msg.append("\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
throw IllegalStateException(msg.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateWhitelist(whitelistFile: Path, excludeWhitelistFile: Path, cordapps: List<String>?): Map<String, List<AttachmentId>> {
|
private fun installNetworkParameters(notaryInfos: List<NotaryInfo>,
|
||||||
val existingWhitelist = if (whitelistFile.exists()) readContractWhitelist(whitelistFile) else emptyMap()
|
whitelist: Map<String, List<AttachmentId>>,
|
||||||
|
existingNetParams: NetworkParameters?,
|
||||||
|
nodeDirs: List<Path>): NetworkParameters {
|
||||||
|
val networkParameters = if (existingNetParams != null) {
|
||||||
|
existingNetParams.copy(
|
||||||
|
notaries = notaryInfos,
|
||||||
|
modifiedTime = Instant.now(),
|
||||||
|
whitelistedContractImplementations = whitelist,
|
||||||
|
epoch = existingNetParams.epoch + 1
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
NetworkParameters(
|
||||||
|
minimumPlatformVersion = 1,
|
||||||
|
notaries = notaryInfos,
|
||||||
|
modifiedTime = Instant.now(),
|
||||||
|
maxMessageSize = 10485760,
|
||||||
|
maxTransactionSize = Int.MAX_VALUE,
|
||||||
|
whitelistedContractImplementations = whitelist,
|
||||||
|
epoch = 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// TODO Add config for minimumPlatformVersion, maxMessageSize and maxTransactionSize
|
||||||
|
val copier = NetworkParametersCopier(networkParameters, overwriteFile = true)
|
||||||
|
nodeDirs.forEach { copier.install(it) }
|
||||||
|
return networkParameters
|
||||||
|
}
|
||||||
|
|
||||||
println(if (existingWhitelist.isEmpty()) "No existing whitelist file found." else "Found existing whitelist: $whitelistFile")
|
private fun generateWhitelist(networkParameters: NetworkParameters?,
|
||||||
|
excludeWhitelistFile: Path,
|
||||||
|
cordapps: List<String>?): Map<String, List<AttachmentId>> {
|
||||||
|
val existingWhitelist = networkParameters?.whitelistedContractImplementations ?: emptyMap()
|
||||||
|
|
||||||
val excludeContracts = if (excludeWhitelistFile.exists()) readExcludeWhitelist(excludeWhitelistFile) else emptyList()
|
val excludeContracts = if (excludeWhitelistFile.exists()) readExcludeWhitelist(excludeWhitelistFile) else emptyList()
|
||||||
if (excludeContracts.isNotEmpty()) {
|
if (excludeContracts.isNotEmpty()) {
|
||||||
@ -210,38 +254,15 @@ class NetworkBootstrapper {
|
|||||||
}
|
}
|
||||||
}?.filter { (contractClassName, _) -> contractClassName !in excludeContracts }?.toMap() ?: emptyMap()
|
}?.filter { (contractClassName, _) -> contractClassName !in excludeContracts }?.toMap() ?: emptyMap()
|
||||||
|
|
||||||
println("Calculating whitelist for current installed CorDapps..")
|
return (newWhiteList.keys + existingWhitelist.keys).map { contractClassName ->
|
||||||
|
|
||||||
val merged = (newWhiteList.keys + existingWhitelist.keys).map { contractClassName ->
|
|
||||||
val existing = existingWhitelist[contractClassName] ?: emptyList()
|
val existing = existingWhitelist[contractClassName] ?: emptyList()
|
||||||
val newHash = newWhiteList[contractClassName]
|
val newHash = newWhiteList[contractClassName]
|
||||||
contractClassName to (if (newHash == null || newHash in existing) existing else existing + newHash)
|
contractClassName to (if (newHash == null || newHash in existing) existing else existing + newHash)
|
||||||
}.toMap()
|
}.toMap()
|
||||||
|
|
||||||
println("CorDapp whitelist " + (if (existingWhitelist.isEmpty()) "generated" else "updated") + " in $whitelistFile")
|
|
||||||
return merged
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun overwriteWhitelist(whitelistFile: Path, mergedWhiteList: Map<String, List<AttachmentId>>) {
|
|
||||||
PrintStream(whitelistFile.toFile().outputStream()).use { out ->
|
|
||||||
mergedWhiteList.forEach { (contract, attachments) ->
|
|
||||||
out.println("$contract:${attachments.joinToString(",")}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun readContractWhitelist(file: Path): Map<String, List<AttachmentId>> {
|
|
||||||
return file.readAllLines()
|
|
||||||
.map { line -> line.split(":") }
|
|
||||||
.map { (contract, attachmentIds) ->
|
|
||||||
contract to (attachmentIds.split(",").map(::parse))
|
|
||||||
}.toMap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readExcludeWhitelist(file: Path): List<String> = file.readAllLines().map(String::trim)
|
private fun readExcludeWhitelist(file: Path): List<String> = file.readAllLines().map(String::trim)
|
||||||
|
|
||||||
private fun NotaryInfo.prettyPrint(): String = "${identity.name} (${if (validating) "" else "non-"}validating)"
|
|
||||||
|
|
||||||
private fun NodeInfo.notaryIdentity(): Party {
|
private fun NodeInfo.notaryIdentity(): Party {
|
||||||
return when (legalIdentities.size) {
|
return when (legalIdentities.size) {
|
||||||
// Single node notaries have just one identity like all other nodes. This identity is the notary identity
|
// Single node notaries have just one identity like all other nodes. This identity is the notary identity
|
||||||
|
@ -315,7 +315,7 @@ fun propertiesForSerializationFromSetters(
|
|||||||
"takes too many arguments")
|
"takes too many arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
val setterType = setter.parameterTypes[0]!!
|
val setterType = setter.genericParameterTypes[0]!!
|
||||||
|
|
||||||
if ((property.value.field != null) &&
|
if ((property.value.field != null) &&
|
||||||
(!(TypeToken.of(property.value.field?.genericType!!).isSupertypeOf(setterType)))) {
|
(!(TypeToken.of(property.value.field?.genericType!!).isSupertypeOf(setterType)))) {
|
||||||
@ -324,11 +324,11 @@ fun propertiesForSerializationFromSetters(
|
|||||||
"${property.value.field?.genericType!!}")
|
"${property.value.field?.genericType!!}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the setter returns the same type (within inheritance bounds) the getter accepts
|
// Make sure the getter returns the same type (within inheritance bounds) the setter accepts.
|
||||||
if (!(TypeToken.of (setterType).isSupertypeOf(getter.returnType))) {
|
if (!(TypeToken.of (getter.genericReturnType).isSupertypeOf(setterType))) {
|
||||||
throw NotSerializableException("Defined setter for parameter ${property.value.field?.name} " +
|
throw NotSerializableException("Defined setter for parameter ${property.value.field?.name} " +
|
||||||
"takes parameter of type $setterType yet the defined getter returns a value of type " +
|
"takes parameter of type $setterType yet the defined getter returns a value of type " +
|
||||||
"${getter.returnType}")
|
"${getter.returnType} [${getter.genericReturnType}]")
|
||||||
}
|
}
|
||||||
this += PropertyAccessorGetterSetter(
|
this += PropertyAccessorGetterSetter(
|
||||||
idx++,
|
idx++,
|
||||||
|
@ -17,6 +17,8 @@ import org.junit.Test;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.io.NotSerializableException;
|
import java.io.NotSerializableException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class SetterConstructorTests {
|
public class SetterConstructorTests {
|
||||||
|
|
||||||
@ -74,6 +76,13 @@ public class SetterConstructorTests {
|
|||||||
public void setC(int c) { this.c = c; }
|
public void setC(int c) { this.c = c; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class CIntList {
|
||||||
|
private List<Integer> l;
|
||||||
|
|
||||||
|
public List getL() { return l; }
|
||||||
|
public void setL(List<Integer> l) { this.l = l; }
|
||||||
|
}
|
||||||
|
|
||||||
static class Inner1 {
|
static class Inner1 {
|
||||||
private String a;
|
private String a;
|
||||||
|
|
||||||
@ -325,4 +334,29 @@ public class SetterConstructorTests {
|
|||||||
Assertions.assertThatThrownBy(() -> new SerializationOutput(factory1).serialize(tm)).isInstanceOf(
|
Assertions.assertThatThrownBy(() -> new SerializationOutput(factory1).serialize(tm)).isInstanceOf(
|
||||||
NotSerializableException.class);
|
NotSerializableException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This not blowing up means it's working
|
||||||
|
@Test
|
||||||
|
public void intList() throws NotSerializableException {
|
||||||
|
CIntList cil = new CIntList();
|
||||||
|
|
||||||
|
List<Integer> l = new ArrayList<>();
|
||||||
|
l.add(1);
|
||||||
|
l.add(2);
|
||||||
|
l.add(3);
|
||||||
|
|
||||||
|
cil.setL(l);
|
||||||
|
|
||||||
|
EvolutionSerializerGetterBase evolutionSerialiserGetter = new EvolutionSerializerGetter();
|
||||||
|
FingerPrinter fingerPrinter = new SerializerFingerPrinter();
|
||||||
|
SerializerFactory factory1 = new SerializerFactory(
|
||||||
|
AllWhitelist.INSTANCE,
|
||||||
|
ClassLoader.getSystemClassLoader(),
|
||||||
|
evolutionSerialiserGetter,
|
||||||
|
fingerPrinter);
|
||||||
|
|
||||||
|
// if we've got super / sub types on the setter vs the underlying type the wrong way around this will
|
||||||
|
// explode. See CORDA-1229 (https://r3-cev.atlassian.net/browse/CORDA-1229)
|
||||||
|
new DeserializationInput(factory1).deserialize(new SerializationOutput(factory1).serialize(cil), CIntList.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1320,6 +1320,5 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
|
|||||||
C(12).serializeE()
|
C(12).serializeE()
|
||||||
}.withMessageContaining("has synthetic fields and is likely a nested inner class")
|
}.withMessageContaining("has synthetic fields and is likely a nested inner class")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user