mirror of
https://github.com/corda/corda.git
synced 2025-01-03 03:36:48 +00:00
Merge pull request #552 from corda/shams-nms-version-check
Introducing Platform Version and its use by the NMS for min version r…
This commit is contained in:
commit
af7f5ef0d7
16
build.gradle
16
build.gradle
@ -4,7 +4,10 @@ buildscript {
|
|||||||
file("$projectDir/constants.properties").withInputStream { constants.load(it) }
|
file("$projectDir/constants.properties").withInputStream { constants.load(it) }
|
||||||
|
|
||||||
// Our version: bump this on release.
|
// Our version: bump this on release.
|
||||||
ext.corda_version = "0.11-SNAPSHOT"
|
ext.corda_release_version = "0.11-SNAPSHOT"
|
||||||
|
// Increment this on any release that changes public APIs anywhere in the Corda platform
|
||||||
|
// TODO This is going to be difficult until we have a clear separation throughout the code of what is public and what is internal
|
||||||
|
ext.corda_platform_version = 1
|
||||||
ext.gradle_plugins_version = constants.getProperty("gradlePluginsVersion")
|
ext.gradle_plugins_version = constants.getProperty("gradlePluginsVersion")
|
||||||
|
|
||||||
// Dependency versions. Can run 'gradle dependencyUpdates' to find new versions of things.
|
// Dependency versions. Can run 'gradle dependencyUpdates' to find new versions of things.
|
||||||
@ -105,8 +108,17 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(Jar) { // Includes War and Ear
|
||||||
|
manifest {
|
||||||
|
attributes('Corda-Release-Version': corda_release_version)
|
||||||
|
attributes('Corda-Platform-Version': corda_platform_version)
|
||||||
|
attributes('Corda-Revision': corda_revision)
|
||||||
|
attributes('Corda-Vendor': 'Corda Open Source')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
group 'net.corda'
|
group 'net.corda'
|
||||||
version "$corda_version"
|
version "$corda_release_version"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
gradlePluginsVersion=0.11.0
|
gradlePluginsVersion=0.11.1
|
||||||
kotlinVersion=1.1.1
|
kotlinVersion=1.1.1
|
||||||
guavaVersion=21.0
|
guavaVersion=21.0
|
||||||
typesafeConfigVersion=1.3.1
|
typesafeConfigVersion=1.3.1
|
||||||
|
@ -50,6 +50,12 @@ sealed class StateMachineUpdate {
|
|||||||
// TODO: The use of Pairs throughout is unfriendly for Java interop.
|
// TODO: The use of Pairs throughout is unfriendly for Java interop.
|
||||||
|
|
||||||
interface CordaRPCOps : RPCOps {
|
interface CordaRPCOps : RPCOps {
|
||||||
|
/**
|
||||||
|
* Returns the RPC protocol version, which is the same the node's Platform Version. Exists since version 1 so guaranteed
|
||||||
|
* to be present.
|
||||||
|
*/
|
||||||
|
override val protocolVersion: Int get() = nodeIdentity().platformVersion
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a pair of currently in-progress state machine infos and an observable of future state machine adds/removes.
|
* Returns a pair of currently in-progress state machine infos and an observable of future state machine adds/removes.
|
||||||
*/
|
*/
|
||||||
|
@ -19,7 +19,7 @@ data class ServiceEntry(val info: ServiceInfo, val identity: Party)
|
|||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
data class NodeInfo(val address: SingleMessageRecipient,
|
data class NodeInfo(val address: SingleMessageRecipient,
|
||||||
val legalIdentity: Party,
|
val legalIdentity: Party,
|
||||||
val version: Version,
|
val platformVersion: Int,
|
||||||
var advertisedServices: List<ServiceEntry> = emptyList(),
|
var advertisedServices: List<ServiceEntry> = emptyList(),
|
||||||
val physicalLocation: PhysicalLocation? = null) {
|
val physicalLocation: PhysicalLocation? = null) {
|
||||||
init {
|
init {
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
package net.corda.core.node
|
|
||||||
|
|
||||||
import net.corda.core.serialization.CordaSerializable
|
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Versions of the same [major] version but with different [minor] versions are considered compatible with each other. One
|
|
||||||
* exception to this is when the major version is 0 - each different minor version should be considered incompatible.
|
|
||||||
*
|
|
||||||
* If two [Version]s are equal (i.e. [equals] returns true) but they are both [snapshot] then they may refer to different
|
|
||||||
* builds of the node. [NodeVersionInfo.revision] would be required to differentiate the two.
|
|
||||||
*/
|
|
||||||
@CordaSerializable
|
|
||||||
data class Version(val major: Int, val minor: Int, val patch: Int?, val snapshot: Boolean) {
|
|
||||||
companion object {
|
|
||||||
private val pattern = Pattern.compile("""(\d+)\.(\d+)(.(\d+))?(-SNAPSHOT)?""")
|
|
||||||
|
|
||||||
fun parse(string: String): Version {
|
|
||||||
val matcher = pattern.matcher(string)
|
|
||||||
require(matcher.matches())
|
|
||||||
val patch = matcher.group(4)?.toInt()
|
|
||||||
return Version(matcher.group(1).toInt(), matcher.group(2).toInt(), patch, matcher.group(5) != null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
val sb = StringBuilder()
|
|
||||||
sb.append(major, ".", minor)
|
|
||||||
if(patch != null) sb.append(".", patch)
|
|
||||||
if(snapshot) sb.append("-SNAPSHOT")
|
|
||||||
return sb.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class NodeVersionInfo(val version: Version, val revision: String, val vendor: String)
|
|
17
core/src/main/kotlin/net/corda/core/node/VersionInfo.kt
Normal file
17
core/src/main/kotlin/net/corda/core/node/VersionInfo.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package net.corda.core.node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates various pieces of version information of the node.
|
||||||
|
*/
|
||||||
|
data class VersionInfo(
|
||||||
|
/**
|
||||||
|
* Platform version of the node which is an integer value which increments on any release where any of the public
|
||||||
|
* API of the entire Corda platform changes. This includes messaging, serialisation, node APIs, etc.
|
||||||
|
*/
|
||||||
|
val platformVersion: Int,
|
||||||
|
/** Release version string of the node. */
|
||||||
|
val releaseVersion: String,
|
||||||
|
/** The exact version control commit ID of the node build. */
|
||||||
|
val revision: String,
|
||||||
|
/** The node vendor */
|
||||||
|
val vendor: String)
|
@ -1,41 +0,0 @@
|
|||||||
package net.corda.core.node
|
|
||||||
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class VersionTest {
|
|
||||||
@Test
|
|
||||||
fun `parse valid non-SNAPSHOT string`() {
|
|
||||||
assertThat(Version.parse("1.2")).isEqualTo(Version(1, 2, null, false))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `parse valid SNAPSHOT string`() {
|
|
||||||
assertThat(Version.parse("2.23-SNAPSHOT")).isEqualTo(Version(2, 23, null, true))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `parse string with just major number`() {
|
|
||||||
assertThatThrownBy {
|
|
||||||
Version.parse("2")
|
|
||||||
}.isInstanceOf(IllegalArgumentException::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `parse string with unknown qualifier`() {
|
|
||||||
assertThatThrownBy {
|
|
||||||
Version.parse("2.3-TEST")
|
|
||||||
}.isInstanceOf(IllegalArgumentException::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `parses patch version`() {
|
|
||||||
assertThat(Version.parse("0.1.2")).isEqualTo(Version(0, 1, 2, false))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `parses snapshot patch version`() {
|
|
||||||
assertThat(Version.parse("0.1.2-SNAPSHOT")).isEqualTo(Version(0, 1, 2, true))
|
|
||||||
}
|
|
||||||
}
|
|
@ -57,11 +57,11 @@ the ``cancel`` method on the future will unsubscribe it from any future value an
|
|||||||
Versioning
|
Versioning
|
||||||
----------
|
----------
|
||||||
|
|
||||||
The client RPC protocol is versioned with a simple incrementing integer. When a proxy is created the server is
|
The client RPC protocol is versioned using the node's Platform Version (see :doc:`versioning`). When a proxy is created
|
||||||
queried for its protocol version, and you can specify your minimum requirement. Methods added in later versions
|
the server is queried for its version, and you can specify your minimum requirement. Methods added in later versions
|
||||||
are tagged with the ``@RPCSinceVersion`` annotation. If you try to use a method that the server isn't advertising
|
are tagged with the ``@RPCSinceVersion`` annotation. If you try to use a method that the server isn't advertising support
|
||||||
support of, an ``UnsupportedOperationException`` is thrown. If you want to know the version of the server, just
|
of, an ``UnsupportedOperationException`` is thrown. If you want to know the version of the server, just use the
|
||||||
use the ``protocolVersion`` property (i.e. ``getProtocolVersion`` in Java).
|
``protocolVersion`` property (i.e. ``getProtocolVersion`` in Java).
|
||||||
|
|
||||||
Thread safety
|
Thread safety
|
||||||
-------------
|
-------------
|
||||||
|
@ -116,6 +116,10 @@ path to the node's base directory.
|
|||||||
:legalName: Legal name of the node. This is required as part of the TLS host verification process. The node will
|
:legalName: Legal name of the node. This is required as part of the TLS host verification process. The node will
|
||||||
reject the connection to the network map service if it provides a TLS common name which doesn't match with this value.
|
reject the connection to the network map service if it provides a TLS common name which doesn't match with this value.
|
||||||
|
|
||||||
|
:minimumPlatformVersion: Used by the node if it's running the network map service to enforce a minimum version requirement
|
||||||
|
on registrations - any node on a Platform Version lower than this value will have their registration rejected.
|
||||||
|
Defaults to 1 if absent.
|
||||||
|
|
||||||
:useHTTPS: If false the node's web server will be plain HTTP. If true the node will use the same certificate and private
|
:useHTTPS: If false the node's web server will be plain HTTP. If true the node will use the same certificate and private
|
||||||
key from the ``<workspace>/certificates/sslkeystore.jks`` file as the ArtemisMQ port for HTTPS. If HTTPS is enabled
|
key from the ``<workspace>/certificates/sslkeystore.jks`` file as the ArtemisMQ port for HTTPS. If HTTPS is enabled
|
||||||
then unencrypted HTTP traffic to the node's **webAddress** port is not supported.
|
then unencrypted HTTP traffic to the node's **webAddress** port is not supported.
|
||||||
|
@ -128,8 +128,8 @@ the following segments to the relevant part of your build.gradle.
|
|||||||
.. code-block:: groovy
|
.. code-block:: groovy
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.corda_version = '<enter the corda version you build against here>'
|
ext.corda_release_version = '<enter the corda version you build against here>'
|
||||||
ext.corda_gradle_plugins_version = '<enter the gradle plugins version here>' // This is usually the same as corda_version.
|
ext.corda_gradle_plugins_version = '<enter the gradle plugins version here>' // This is usually the same as corda_release_version.
|
||||||
... your buildscript ...
|
... your buildscript ...
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@ -155,10 +155,10 @@ the following segments to the relevant part of your build.gradle.
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "net.corda.core:$corda_version"
|
compile "net.corda.core:$corda_release_version"
|
||||||
compile "net.corda.finance:$corda_version"
|
compile "net.corda.finance:$corda_release_version"
|
||||||
compile "net.corda.node:$corda_version"
|
compile "net.corda.node:$corda_release_version"
|
||||||
compile "net.corda.corda:$corda_version"
|
compile "net.corda.corda:$corda_release_version"
|
||||||
... other dependencies here ...
|
... other dependencies here ...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@ Documentation Contents:
|
|||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
:caption: The Corda node
|
:caption: The Corda node
|
||||||
|
|
||||||
|
versioning
|
||||||
shell
|
shell
|
||||||
serialization
|
serialization
|
||||||
clientrpc
|
clientrpc
|
||||||
|
@ -22,12 +22,21 @@ X.500 distinguished names (see RFC 1779 for details on the construction of disti
|
|||||||
* If you are using mock parties for testing, try to standardise on the ``DUMMY_NOTARY``, ``DUMMY_BANK_A``, etc. provided
|
* If you are using mock parties for testing, try to standardise on the ``DUMMY_NOTARY``, ``DUMMY_BANK_A``, etc. provided
|
||||||
in order to ensure consistency.
|
in order to ensure consistency.
|
||||||
|
|
||||||
We have updated DemoBench so that it is installed as "Corda DemoBench" for both Windows and MacOSX. The original version was installed as just "DemoBench", and so will not be overwritten automatically by the new version.
|
We have updated DemoBench so that it is installed as "Corda DemoBench" for both Windows and MacOSX. The original version
|
||||||
|
was installed as just "DemoBench", and so will not be overwritten automatically by the new version.
|
||||||
|
|
||||||
|
We've introduced the concept of platform version which is a single integer value which increments by 1 if a release changes
|
||||||
|
any of the public APIs of the entire Corda platform. This includes the node's public APIs, the messaging protocol,
|
||||||
|
serialisation, etc. The node exposes the platform version it's on and we envision CorDapps will use this to be able to
|
||||||
|
run on older versions of the platform to the one they were compiled against. Platform version borrows heavily from Android's
|
||||||
|
API Level.
|
||||||
|
|
||||||
Milestone 10
|
Milestone 10
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Special thank you to `Qian Hong <https://github.com/fracting>`_, `Marek Skocovsky <https://github.com/marekdapps>`_, `Karel Hajek <https://github.com/polybioz>`_, and `Jonny Chiu <https://github.com/johnnyychiu>`_ for their contributions to Corda in M10.
|
Special thank you to `Qian Hong <https://github.com/fracting>`_, `Marek Skocovsky <https://github.com/marekdapps>`_,
|
||||||
|
`Karel Hajek <https://github.com/polybioz>`_, and `Jonny Chiu <https://github.com/johnnyychiu>`_ for their contributions
|
||||||
|
to Corda in M10.
|
||||||
|
|
||||||
A new interactive **Corda Shell** has been added to the node. The shell lets developers and node administrators
|
A new interactive **Corda Shell** has been added to the node. The shell lets developers and node administrators
|
||||||
easily command the node by running flows, RPCs and SQL queries. It also provides a variety of commands to monitor
|
easily command the node by running flows, RPCs and SQL queries. It also provides a variety of commands to monitor
|
||||||
@ -35,25 +44,34 @@ the node. The Corda Shell is based on the popular `CRaSH project <http://www.cra
|
|||||||
be easily added to the node by simply dropping Groovy or Java files into the node's ``shell-commands`` directory.
|
be easily added to the node by simply dropping Groovy or Java files into the node's ``shell-commands`` directory.
|
||||||
We have many enhancements planned over time including SSH access, more commands and better tab completion.
|
We have many enhancements planned over time including SSH access, more commands and better tab completion.
|
||||||
|
|
||||||
The new "DemoBench" makes it easy to configure and launch local Corda nodes. It is a standalone desktop app that can be bundled with its own JRE and packaged as either EXE (Windows), DMG (MacOS) or RPM (Linux-based). It has the following features:
|
The new "DemoBench" makes it easy to configure and launch local Corda nodes. It is a standalone desktop app that can be
|
||||||
#. New nodes can be added at the click of a button. Clicking "Add node" creates a new tab that lets you edit the most important configuration properties of the node before launch, such as its legal name and which CorDapps will be loaded.
|
bundled with its own JRE and packaged as either EXE (Windows), DMG (MacOS) or RPM (Linux-based). It has the following
|
||||||
|
features:
|
||||||
|
#. New nodes can be added at the click of a button. Clicking "Add node" creates a new tab that lets you edit the most
|
||||||
|
important configuration properties of the node before launch, such as its legal name and which CorDapps will be loaded.
|
||||||
#. Each tab contains a terminal emulator, attached to the pseudoterminal of the node. This lets you see console output.
|
#. Each tab contains a terminal emulator, attached to the pseudoterminal of the node. This lets you see console output.
|
||||||
#. You can launch an Corda Explorer instance for each node at the click of a button. Credentials are handed to the Corda Explorer so it starts out logged in already.
|
#. You can launch an Corda Explorer instance for each node at the click of a button. Credentials are handed to the Corda
|
||||||
|
Explorer so it starts out logged in already.
|
||||||
#. Some basic statistics are shown about each node, informed via the RPC connection.
|
#. Some basic statistics are shown about each node, informed via the RPC connection.
|
||||||
#. Another button launches a database viewer in the system browser.
|
#. Another button launches a database viewer in the system browser.
|
||||||
#. The configurations of all running nodes can be saved into a single ``.profile`` file that can be reloaded later.
|
#. The configurations of all running nodes can be saved into a single ``.profile`` file that can be reloaded later.
|
||||||
|
|
||||||
Soft Locking is a new feature implemented in the vault to prevent a node constructing transactions that attempt to use the same input(s) simultaneously.
|
Soft Locking is a new feature implemented in the vault to prevent a node constructing transactions that attempt to use the
|
||||||
Such transactions would result in naturally wasted effort when the notary rejects them as double spend attempts.
|
same input(s) simultaneously. Such transactions would result in naturally wasted effort when the notary rejects them as
|
||||||
Soft locks are automatically applied to coin selection (eg. cash spending) to ensure that no two transactions attempt to spend the same fungible states.
|
double spend attempts. Soft locks are automatically applied to coin selection (eg. cash spending) to ensure that no two
|
||||||
|
transactions attempt to spend the same fungible states.
|
||||||
|
|
||||||
The basic Amount API has been upgraded to have support for advanced financial use cases and to better integrate with currency reference data.
|
The basic Amount API has been upgraded to have support for advanced financial use cases and to better integrate with
|
||||||
|
currency reference data.
|
||||||
|
|
||||||
We have added optional out-of-process transaction verification. Any number of external verifier processes may be attached to the node which can handle loadbalanced verification requests.
|
We have added optional out-of-process transaction verification. Any number of external verifier processes may be attached
|
||||||
|
to the node which can handle loadbalanced verification requests.
|
||||||
|
|
||||||
We have also delivered the long waited Kotlin 1.1 upgrade in M10! The new features in Kotlin allow us to write even more clean and easy to manage code, which greatly increases our productivity.
|
We have also delivered the long waited Kotlin 1.1 upgrade in M10! The new features in Kotlin allow us to write even more
|
||||||
|
clean and easy to manage code, which greatly increases our productivity.
|
||||||
|
|
||||||
This release contains a large number of improvements, new features, library upgrades and bug fixes. For a full list of changes please see :doc:`changelog`.
|
This release contains a large number of improvements, new features, library upgrades and bug fixes. For a full list of
|
||||||
|
changes please see :doc:`changelog`.
|
||||||
|
|
||||||
Milestone 9
|
Milestone 9
|
||||||
-----------
|
-----------
|
||||||
|
@ -53,8 +53,8 @@ for you from our `public Maven repository <https://bintray.com/r3/corda>`_.
|
|||||||
**Using a Corda SNAPSHOT build.** Alternatively, if you wish to work from the master branch of the Corda repo which contains
|
**Using a Corda SNAPSHOT build.** Alternatively, if you wish to work from the master branch of the Corda repo which contains
|
||||||
the most up-to-date Corda feature set then you will need to clone the ``corda`` repository and publish the latest master
|
the most up-to-date Corda feature set then you will need to clone the ``corda`` repository and publish the latest master
|
||||||
build (or previously tagged releases) to your local Maven repository. You will then need to ensure that Gradle
|
build (or previously tagged releases) to your local Maven repository. You will then need to ensure that Gradle
|
||||||
grabs the correct dependencies for you from Maven local by changing the ``corda_version`` in ``build.gradle``. This will be
|
grabs the correct dependencies for you from Maven local by changing the ``corda_release_version`` in ``build.gradle``.
|
||||||
covered below in `Using a SNAPSHOT release`_.
|
This will be covered below in `Using a SNAPSHOT release`_.
|
||||||
|
|
||||||
Firstly, follow the :doc:`getting set up <getting-set-up>` page to download the JDK, IntelliJ and git if you didn't
|
Firstly, follow the :doc:`getting set up <getting-set-up>` page to download the JDK, IntelliJ and git if you didn't
|
||||||
already have it.
|
already have it.
|
||||||
@ -145,10 +145,10 @@ if you are trying out new features, in this case you can change ``version`` for
|
|||||||
|
|
||||||
.. note:: **A quick point on corda version numbers used by Gradle.**
|
.. note:: **A quick point on corda version numbers used by Gradle.**
|
||||||
|
|
||||||
In the ``build.gradle`` file for your CorDapp, you can specify the ``corda_version`` to use. It is important that when
|
In the ``build.gradle`` file for your CorDapp, you can specify the ``corda_release_version`` to use. It is important
|
||||||
developing your CorDapp that you use the correct version number. For example, when wanting to work from a SNAPSHOT
|
that when developing your CorDapp that you use the correct version number. For example, when wanting to work from a SNAPSHOT
|
||||||
release, the release numbers are suffixed with 'SNAPSHOT', e.g. if the latest milestone release is M6 then the
|
release, the release numbers are suffixed with 'SNAPSHOT', e.g. if the latest milestone release is M6 then the
|
||||||
SNAPSHOT release will be 0.7-SNAPSHOT, and so on. As such, you will set your ``corda_version`` to ``'0.7-SNAPSHOT'``
|
SNAPSHOT release will be 0.7-SNAPSHOT, and so on. As such, you will set your ``corda_release_version`` to ``'0.7-SNAPSHOT'``
|
||||||
in the ``build.gradle`` file in your CorDapp. Gradle will automatically grab the SNAPSHOT dependencies from your local
|
in the ``build.gradle`` file in your CorDapp. Gradle will automatically grab the SNAPSHOT dependencies from your local
|
||||||
Maven repository. Alternatively, if working from a milestone release, you will use the version number only, for example
|
Maven repository. Alternatively, if working from a milestone release, you will use the version number only, for example
|
||||||
``0.6`` or ``0.7``.
|
``0.6`` or ``0.7``.
|
||||||
@ -224,7 +224,7 @@ see all available Gradle tasks.
|
|||||||
* For the Corda repo there will be many project listed, the root project ``corda`` and associated sub-projects: ``core``,
|
* For the Corda repo there will be many project listed, the root project ``corda`` and associated sub-projects: ``core``,
|
||||||
``finance``, ``node``, etc.
|
``finance``, ``node``, etc.
|
||||||
|
|
||||||
.. note:: It's worth noting that when you change branch in the example CorDapp, the ``corda_version`` will change to
|
.. note:: It's worth noting that when you change branch in the example CorDapp, the ``corda_release_version`` will change to
|
||||||
reflect the version of the branch you are working from.
|
reflect the version of the branch you are working from.
|
||||||
|
|
||||||
To execute a task, double click it. The output will be shown in a console window.
|
To execute a task, double click it. The output will be shown in a console window.
|
||||||
@ -712,15 +712,15 @@ are available for use in the rest of the build script. It also specifies version
|
|||||||
things.
|
things.
|
||||||
|
|
||||||
If you are working from a Corda SNAPSHOT release which you have publish to Maven local then ensure that
|
If you are working from a Corda SNAPSHOT release which you have publish to Maven local then ensure that
|
||||||
``corda_version`` is the same as the version of the Corda core modules you published to Maven local. If not then change the
|
``corda_release_version`` is the same as the version of the Corda core modules you published to Maven local. If not then
|
||||||
``kotlin_version`` property. Also, if you are working from a previous cordapp-tutorial milestone release, then be sure to ``git checkout``
|
change the ``kotlin_version`` property. Also, if you are working from a previous cordapp-tutorial milestone release, then
|
||||||
the correct version of the example CorDapp from the ``cordapp-tutorial`` repo.
|
be sure to ``git checkout`` the correct version of the example CorDapp from the ``cordapp-tutorial`` repo.
|
||||||
|
|
||||||
.. sourcecode:: groovy
|
.. sourcecode:: groovy
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.0.4'
|
ext.kotlin_version = '1.0.4'
|
||||||
ext.corda_version = '0.5-SNAPSHOT' // Ensure this version is the same as the corda core modules you are using.
|
ext.corda_release_version = '0.5-SNAPSHOT' // Ensure this version is the same as the corda core modules you are using.
|
||||||
ext.quasar_version = '0.7.6'
|
ext.quasar_version = '0.7.6'
|
||||||
ext.jersey_version = '2.23.1'
|
ext.jersey_version = '2.23.1'
|
||||||
|
|
||||||
@ -747,12 +747,12 @@ code snippet.package. Use the standard format:
|
|||||||
testCompile group: 'junit', name: 'junit', version: '4.11'
|
testCompile group: 'junit', name: 'junit', version: '4.11'
|
||||||
|
|
||||||
// Corda integration dependencies
|
// Corda integration dependencies
|
||||||
compile "net.corda:client:$corda_version"
|
compile "net.corda:client:$corda_release_version"
|
||||||
compile "net.corda:core:$corda_version"
|
compile "net.corda:core:$corda_release_version"
|
||||||
compile "net.corda:contracts:$corda_version"
|
compile "net.corda:contracts:$corda_release_version"
|
||||||
compile "net.corda:node:$corda_version"
|
compile "net.corda:node:$corda_release_version"
|
||||||
compile "net.corda:corda:$corda_version"
|
compile "net.corda:corda:$corda_release_version"
|
||||||
compile "net.corda:test-utils:$corda_version"
|
compile "net.corda:test-utils:$corda_release_version"
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
29
docs/source/versioning.rst
Normal file
29
docs/source/versioning.rst
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Versioning
|
||||||
|
==========
|
||||||
|
|
||||||
|
As the Corda platform evolves and new features are added it becomes important to have a versioning system which allows
|
||||||
|
its users to easily compare versions and know what feature are available to them. Each Corda release uses the standard
|
||||||
|
semantic versioning scheme of ``major.minor.patch``. This is useful when making releases in the public domain but is not
|
||||||
|
friendly for a developer working on the platform. It first has to be parsed and then they have three separate segments on
|
||||||
|
which to determine API differences. The release version is still useful and every MQ message the node sends attaches it
|
||||||
|
to the ``release-version`` header property for debugging purposes.
|
||||||
|
|
||||||
|
Platform Version
|
||||||
|
----------------
|
||||||
|
|
||||||
|
It is much easier to use a single incrementing integer value to represent the API version of the Corda platform, which
|
||||||
|
is called the Platform Version. It is similar to Android's `API Level <https://developer.android.com/guide/topics/manifest/uses-sdk-element.html>`_.
|
||||||
|
It starts at 1 and will increment by exactly 1 for each release which changes any of the publicly exposed APIs in the
|
||||||
|
entire platform. This includes public APIs on the node itself, the RPC system, messaging, serialisation, etc. API backwards
|
||||||
|
compatibility will always be maintained, with the use of deprecation to migrate away from old APIs. In rare situations
|
||||||
|
APIs may have to be removed, for example due to security issues. There is no relationship between the Platform Version
|
||||||
|
and the release version - a change in the major, minor or patch values may or may not increase the Platform Version.
|
||||||
|
|
||||||
|
The Platform Version is part of the node's ``NodeInfo`` object, which is available from the ``ServiceHub``. This enables
|
||||||
|
a CorDapp to find out which version it's running on and determine whether a desired feature is available. When a node
|
||||||
|
registers with the Network Map Service it will use the node's Platform Version to enforce a minimum version requirement
|
||||||
|
for the network.
|
||||||
|
|
||||||
|
.. note:: A future release may introduce the concept of a target platform version, which would be similar to Android's
|
||||||
|
``targetSdkVersion``, and would provide a means of maintaining behavioural compatibility for the cases where the
|
||||||
|
platform's behaviour has changed.
|
@ -274,10 +274,10 @@ class Node {
|
|||||||
*/
|
*/
|
||||||
private File verifyAndGetCordaJar() {
|
private File verifyAndGetCordaJar() {
|
||||||
def maybeCordaJAR = project.configurations.runtime.filter {
|
def maybeCordaJAR = project.configurations.runtime.filter {
|
||||||
it.toString().contains("corda-${project.corda_version}.jar")
|
it.toString().contains("corda-${project.corda_release_version}.jar")
|
||||||
}
|
}
|
||||||
if (maybeCordaJAR.size() == 0) {
|
if (maybeCordaJAR.size() == 0) {
|
||||||
throw new RuntimeException("No Corda Capsule JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-${project.corda_version}.jar\"")
|
throw new RuntimeException("No Corda Capsule JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-${project.corda_release_version}.jar\"")
|
||||||
} else {
|
} else {
|
||||||
def cordaJar = maybeCordaJAR.getSingleFile()
|
def cordaJar = maybeCordaJAR.getSingleFile()
|
||||||
assert(cordaJar.isFile())
|
assert(cordaJar.isFile())
|
||||||
@ -292,10 +292,10 @@ class Node {
|
|||||||
*/
|
*/
|
||||||
private File verifyAndGetWebserverJar() {
|
private File verifyAndGetWebserverJar() {
|
||||||
def maybeJar = project.configurations.runtime.filter {
|
def maybeJar = project.configurations.runtime.filter {
|
||||||
it.toString().contains("corda-webserver-${project.corda_version}.jar")
|
it.toString().contains("corda-webserver-${project.corda_release_version}.jar")
|
||||||
}
|
}
|
||||||
if (maybeJar.size() == 0) {
|
if (maybeJar.size() == 0) {
|
||||||
throw new RuntimeException("No Corda Webserver JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-webserver-${project.corda_version}.jar\"")
|
throw new RuntimeException("No Corda Webserver JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-webserver-${project.corda_release_version}.jar\"")
|
||||||
} else {
|
} else {
|
||||||
def jar = maybeJar.getSingleFile()
|
def jar = maybeJar.getSingleFile()
|
||||||
assert(jar.isFile())
|
assert(jar.isFile())
|
||||||
|
@ -38,12 +38,12 @@ dependencies {
|
|||||||
|
|
||||||
task buildCordaJAR(type: FatCapsule) {
|
task buildCordaJAR(type: FatCapsule) {
|
||||||
applicationClass 'net.corda.node.Corda'
|
applicationClass 'net.corda.node.Corda'
|
||||||
archiveName "corda-${corda_version}.jar"
|
archiveName "corda-${corda_release_version}.jar"
|
||||||
applicationSource = files(project.tasks.findByName('jar'), '../build/classes/main/CordaCaplet.class', '../build/classes/main/CordaCaplet$1.class', 'config/dev/log4j2.xml')
|
applicationSource = files(project.tasks.findByName('jar'), '../build/classes/main/CordaCaplet.class', '../build/classes/main/CordaCaplet$1.class', 'config/dev/log4j2.xml')
|
||||||
from 'NOTICE' // Copy CDDL notice
|
from 'NOTICE' // Copy CDDL notice
|
||||||
|
|
||||||
capsuleManifest {
|
capsuleManifest {
|
||||||
applicationVersion = corda_version
|
applicationVersion = corda_release_version
|
||||||
appClassPath = ["jolokia-agent-war-${project.rootProject.ext.jolokia_version}.war"]
|
appClassPath = ["jolokia-agent-war-${project.rootProject.ext.jolokia_version}.war"]
|
||||||
javaAgents = ["quasar-core-${quasar_version}-jdk8.jar"]
|
javaAgents = ["quasar-core-${quasar_version}-jdk8.jar"]
|
||||||
systemProperties['visualvm.display.name'] = 'Corda'
|
systemProperties['visualvm.display.name'] = 'Corda'
|
||||||
@ -63,12 +63,6 @@ task buildCordaJAR(type: FatCapsule) {
|
|||||||
// This lets you run the file like so: ./corda.jar
|
// This lets you run the file like so: ./corda.jar
|
||||||
// Other than being slightly less typing, this has one big advantage: Ctrl-C works properly in the terminal.
|
// Other than being slightly less typing, this has one big advantage: Ctrl-C works properly in the terminal.
|
||||||
reallyExecutable { trampolining() }
|
reallyExecutable { trampolining() }
|
||||||
|
|
||||||
manifest {
|
|
||||||
attributes('Corda-Version': corda_version)
|
|
||||||
attributes('Corda-Revision': corda_revision)
|
|
||||||
attributes('Corda-Vendor': 'Corda Open Source')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
artifacts {
|
artifacts {
|
||||||
|
@ -15,7 +15,7 @@ import net.corda.node.services.network.NetworkMapService
|
|||||||
import net.corda.node.services.network.NetworkMapService.RegistrationRequest
|
import net.corda.node.services.network.NetworkMapService.RegistrationRequest
|
||||||
import net.corda.node.services.network.NodeRegistration
|
import net.corda.node.services.network.NodeRegistration
|
||||||
import net.corda.node.utilities.AddOrRemove
|
import net.corda.node.utilities.AddOrRemove
|
||||||
import net.corda.testing.MOCK_VERSION
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import net.corda.testing.TestNodeConfiguration
|
import net.corda.testing.TestNodeConfiguration
|
||||||
import net.corda.testing.node.NodeBasedTest
|
import net.corda.testing.node.NodeBasedTest
|
||||||
import net.corda.testing.node.SimpleNode
|
import net.corda.testing.node.SimpleNode
|
||||||
@ -63,7 +63,7 @@ class P2PSecurityTest : NodeBasedTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun SimpleNode.registerWithNetworkMap(registrationName: String): ListenableFuture<NetworkMapService.RegistrationResponse> {
|
private fun SimpleNode.registerWithNetworkMap(registrationName: String): ListenableFuture<NetworkMapService.RegistrationResponse> {
|
||||||
val nodeInfo = NodeInfo(net.myAddress, Party(registrationName, identity.public), MOCK_VERSION)
|
val nodeInfo = NodeInfo(net.myAddress, Party(registrationName, identity.public), MOCK_VERSION_INFO.platformVersion)
|
||||||
val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX)
|
val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX)
|
||||||
val request = RegistrationRequest(registration.toWire(identity.private), net.myAddress)
|
val request = RegistrationRequest(registration.toWire(identity.private), net.myAddress)
|
||||||
return net.sendRequest<NetworkMapService.RegistrationResponse>(NetworkMapService.REGISTER_TOPIC, request, networkMapNode.net.myAddress)
|
return net.sendRequest<NetworkMapService.RegistrationResponse>(NetworkMapService.REGISTER_TOPIC, request, networkMapNode.net.myAddress)
|
||||||
|
@ -6,8 +6,7 @@ import com.jcabi.manifests.Manifests
|
|||||||
import com.typesafe.config.ConfigException
|
import com.typesafe.config.ConfigException
|
||||||
import joptsimple.OptionException
|
import joptsimple.OptionException
|
||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
import net.corda.core.node.NodeVersionInfo
|
import net.corda.core.node.VersionInfo
|
||||||
import net.corda.core.node.Version
|
|
||||||
import net.corda.core.utilities.Emoji
|
import net.corda.core.utilities.Emoji
|
||||||
import net.corda.core.utilities.LogHelper.withLevel
|
import net.corda.core.utilities.LogHelper.withLevel
|
||||||
import net.corda.node.internal.Node
|
import net.corda.node.internal.Node
|
||||||
@ -69,15 +68,17 @@ fun main(args: Array<String>) {
|
|||||||
// Manifest properties are only available if running from the corda jar
|
// Manifest properties are only available if running from the corda jar
|
||||||
fun manifestValue(name: String): String? = if (Manifests.exists(name)) Manifests.read(name) else null
|
fun manifestValue(name: String): String? = if (Manifests.exists(name)) Manifests.read(name) else null
|
||||||
|
|
||||||
val nodeVersionInfo = NodeVersionInfo(
|
val versionInfo = VersionInfo(
|
||||||
manifestValue("Corda-Version")?.let { Version.parse(it) } ?: Version(0, 0, 0, false),
|
manifestValue("Corda-Platform-Version")?.toInt() ?: 1,
|
||||||
|
manifestValue("Corda-Release-Version") ?: "Unknown",
|
||||||
manifestValue("Corda-Revision") ?: "Unknown",
|
manifestValue("Corda-Revision") ?: "Unknown",
|
||||||
manifestValue("Corda-Vendor") ?: "Unknown"
|
manifestValue("Corda-Vendor") ?: "Unknown"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (cmdlineOptions.isVersion) {
|
if (cmdlineOptions.isVersion) {
|
||||||
println("${nodeVersionInfo.vendor} ${nodeVersionInfo.version}")
|
println("${versionInfo.vendor} ${versionInfo.releaseVersion}")
|
||||||
println("Revision ${nodeVersionInfo.revision}")
|
println("Revision ${versionInfo.revision}")
|
||||||
|
println("Platform Version ${versionInfo.platformVersion}")
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ fun main(args: Array<String>) {
|
|||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
drawBanner(nodeVersionInfo)
|
drawBanner(versionInfo)
|
||||||
|
|
||||||
val log = LoggerFactory.getLogger("Main")
|
val log = LoggerFactory.getLogger("Main")
|
||||||
printBasicNodeInfo("Logs can be found in", System.getProperty("log-path"))
|
printBasicNodeInfo("Logs can be found in", System.getProperty("log-path"))
|
||||||
@ -110,9 +111,10 @@ fun main(args: Array<String>) {
|
|||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Version: ${nodeVersionInfo.version}")
|
log.info("Vendor: ${versionInfo.vendor}")
|
||||||
log.info("Vendor: ${nodeVersionInfo.vendor}")
|
log.info("Release: ${versionInfo.releaseVersion}")
|
||||||
log.info("Revision: ${nodeVersionInfo.revision}")
|
log.info("Platform Version: ${versionInfo.platformVersion}")
|
||||||
|
log.info("Revision: ${versionInfo.revision}")
|
||||||
val info = ManagementFactory.getRuntimeMXBean()
|
val info = ManagementFactory.getRuntimeMXBean()
|
||||||
log.info("PID: ${info.name.split("@").firstOrNull()}") // TODO Java 9 has better support for this
|
log.info("PID: ${info.name.split("@").firstOrNull()}") // TODO Java 9 has better support for this
|
||||||
log.info("Main class: ${FullNodeConfiguration::class.java.protectionDomain.codeSource.location.toURI().path}")
|
log.info("Main class: ${FullNodeConfiguration::class.java.protectionDomain.codeSource.location.toURI().path}")
|
||||||
@ -132,7 +134,7 @@ fun main(args: Array<String>) {
|
|||||||
try {
|
try {
|
||||||
cmdlineOptions.baseDirectory.createDirectories()
|
cmdlineOptions.baseDirectory.createDirectories()
|
||||||
|
|
||||||
val node = conf.createNode(nodeVersionInfo)
|
val node = conf.createNode(versionInfo)
|
||||||
node.start()
|
node.start()
|
||||||
printPluginsAndServices(node)
|
printPluginsAndServices(node)
|
||||||
|
|
||||||
@ -236,7 +238,7 @@ private fun messageOfTheDay(): Pair<String, String> {
|
|||||||
return Pair(a, b)
|
return Pair(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun drawBanner(nodeVersionInfo: NodeVersionInfo) {
|
private fun drawBanner(versionInfo: VersionInfo) {
|
||||||
// This line makes sure ANSI escapes work on Windows, where they aren't supported out of the box.
|
// This line makes sure ANSI escapes work on Windows, where they aren't supported out of the box.
|
||||||
AnsiConsole.systemInstall()
|
AnsiConsole.systemInstall()
|
||||||
|
|
||||||
@ -249,7 +251,7 @@ private fun drawBanner(nodeVersionInfo: NodeVersionInfo) {
|
|||||||
/ / __ / ___/ __ / __ `/ """).fgBrightBlue().a(msg1).newline().fgBrightRed().a(
|
/ / __ / ___/ __ / __ `/ """).fgBrightBlue().a(msg1).newline().fgBrightRed().a(
|
||||||
"/ /___ /_/ / / / /_/ / /_/ / ").fgBrightBlue().a(msg2).newline().fgBrightRed().a(
|
"/ /___ /_/ / / / /_/ / /_/ / ").fgBrightBlue().a(msg2).newline().fgBrightRed().a(
|
||||||
"""\____/ /_/ \__,_/\__,_/""").reset().newline().newline().fgBrightDefault().bold().
|
"""\____/ /_/ \__,_/\__,_/""").reset().newline().newline().fgBrightDefault().bold().
|
||||||
a("--- ${nodeVersionInfo.vendor} ${nodeVersionInfo.version} (${nodeVersionInfo.revision.take(7)}) -----------------------------------------------").
|
a("--- ${versionInfo.vendor} ${versionInfo.releaseVersion} (${versionInfo.revision.take(7)}) -----------------------------------------------").
|
||||||
newline().
|
newline().
|
||||||
newline().
|
newline().
|
||||||
a("${Emoji.books}New! ").reset().a("Training now available worldwide, see https://corda.net/corda-training/").
|
a("${Emoji.books}New! ").reset().a("Training now available worldwide, see https://corda.net/corda-training/").
|
||||||
|
@ -101,7 +101,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
|
|
||||||
protected abstract val log: Logger
|
protected abstract val log: Logger
|
||||||
protected abstract val networkMapAddress: SingleMessageRecipient?
|
protected abstract val networkMapAddress: SingleMessageRecipient?
|
||||||
protected abstract val version: Version
|
protected abstract val platformVersion: Int
|
||||||
|
|
||||||
// We will run as much stuff in this single thread as possible to keep the risk of thread safety bugs low during the
|
// We will run as much stuff in this single thread as possible to keep the risk of thread safety bugs low during the
|
||||||
// low-performance prototyping period.
|
// low-performance prototyping period.
|
||||||
@ -296,7 +296,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
private fun makeInfo(): NodeInfo {
|
private fun makeInfo(): NodeInfo {
|
||||||
val advertisedServiceEntries = makeServiceEntries()
|
val advertisedServiceEntries = makeServiceEntries()
|
||||||
val legalIdentity = obtainLegalIdentity()
|
val legalIdentity = obtainLegalIdentity()
|
||||||
return NodeInfo(net.myAddress, legalIdentity, version, advertisedServiceEntries, findMyLocation())
|
return NodeInfo(net.myAddress, legalIdentity, platformVersion, advertisedServiceEntries, findMyLocation())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -445,7 +445,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
protected open fun makeKeyManagementService(): KeyManagementService = PersistentKeyManagementService(partyKeys)
|
protected open fun makeKeyManagementService(): KeyManagementService = PersistentKeyManagementService(partyKeys)
|
||||||
|
|
||||||
open protected fun makeNetworkMapService() {
|
open protected fun makeNetworkMapService() {
|
||||||
inNodeNetworkMapService = PersistentNetworkMapService(services)
|
inNodeNetworkMapService = PersistentNetworkMapService(services, configuration.minimumPlatformVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
open protected fun makeNotaryService(type: ServiceType, tokenizableServices: MutableList<Any>): NotaryService {
|
open protected fun makeNotaryService(type: ServiceType, tokenizableServices: MutableList<Any>): NotaryService {
|
||||||
|
@ -5,14 +5,15 @@ import com.google.common.net.HostAndPort
|
|||||||
import com.google.common.util.concurrent.Futures
|
import com.google.common.util.concurrent.Futures
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import net.corda.core.*
|
import net.corda.core.div
|
||||||
|
import net.corda.core.flatMap
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.node.NodeVersionInfo
|
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.Version
|
import net.corda.core.node.VersionInfo
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.ServiceType
|
import net.corda.core.node.services.ServiceType
|
||||||
import net.corda.core.node.services.UniquenessProvider
|
import net.corda.core.node.services.UniquenessProvider
|
||||||
|
import net.corda.core.success
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.node.printBasicNodeInfo
|
import net.corda.node.printBasicNodeInfo
|
||||||
import net.corda.node.serialization.NodeClock
|
import net.corda.node.serialization.NodeClock
|
||||||
@ -48,14 +49,14 @@ import kotlin.concurrent.thread
|
|||||||
*/
|
*/
|
||||||
class Node(override val configuration: FullNodeConfiguration,
|
class Node(override val configuration: FullNodeConfiguration,
|
||||||
advertisedServices: Set<ServiceInfo>,
|
advertisedServices: Set<ServiceInfo>,
|
||||||
val nodeVersionInfo: NodeVersionInfo,
|
val versionInfo: VersionInfo,
|
||||||
clock: Clock = NodeClock()) : AbstractNode(configuration, advertisedServices, clock) {
|
clock: Clock = NodeClock()) : AbstractNode(configuration, advertisedServices, clock) {
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = loggerFor<Node>()
|
private val logger = loggerFor<Node>()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val log: Logger get() = logger
|
override val log: Logger get() = logger
|
||||||
override val version: Version get() = nodeVersionInfo.version
|
override val platformVersion: Int get() = versionInfo.platformVersion
|
||||||
override val networkMapAddress: NetworkMapAddress? get() = configuration.networkMapService?.address?.let(::NetworkMapAddress)
|
override val networkMapAddress: NetworkMapAddress? get() = configuration.networkMapService?.address?.let(::NetworkMapAddress)
|
||||||
override fun makeTransactionVerifierService() = (net as NodeMessagingClient).verifierService
|
override fun makeTransactionVerifierService() = (net as NodeMessagingClient).verifierService
|
||||||
|
|
||||||
@ -108,32 +109,13 @@ class Node(override val configuration: FullNodeConfiguration,
|
|||||||
|
|
||||||
private lateinit var userService: RPCUserService
|
private lateinit var userService: RPCUserService
|
||||||
|
|
||||||
init {
|
|
||||||
checkVersionUnchanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abort starting the node if an existing deployment with a different version is detected in the base directory.
|
|
||||||
*/
|
|
||||||
private fun checkVersionUnchanged() {
|
|
||||||
val versionFile = configuration.baseDirectory / "version"
|
|
||||||
if (versionFile.exists()) {
|
|
||||||
val previousVersion = Version.parse(versionFile.readAllLines()[0])
|
|
||||||
check(nodeVersionInfo.version.major == previousVersion.major) {
|
|
||||||
"Major version change detected - current: ${nodeVersionInfo.version}, previous: $previousVersion. " +
|
|
||||||
"Node upgrades across major versions are not yet supported."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
versionFile.writeLines(listOf(nodeVersionInfo.version.toString()))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun makeMessagingService(): MessagingServiceInternal {
|
override fun makeMessagingService(): MessagingServiceInternal {
|
||||||
userService = RPCUserServiceImpl(configuration.rpcUsers)
|
userService = RPCUserServiceImpl(configuration.rpcUsers)
|
||||||
val serverAddress = configuration.messagingServerAddress ?: makeLocalMessageBroker()
|
val serverAddress = configuration.messagingServerAddress ?: makeLocalMessageBroker()
|
||||||
val myIdentityOrNullIfNetworkMapService = if (networkMapAddress != null) obtainLegalIdentity().owningKey else null
|
val myIdentityOrNullIfNetworkMapService = if (networkMapAddress != null) obtainLegalIdentity().owningKey else null
|
||||||
return NodeMessagingClient(
|
return NodeMessagingClient(
|
||||||
configuration,
|
configuration,
|
||||||
nodeVersionInfo,
|
versionInfo,
|
||||||
serverAddress,
|
serverAddress,
|
||||||
myIdentityOrNullIfNetworkMapService,
|
myIdentityOrNullIfNetworkMapService,
|
||||||
serverThread,
|
serverThread,
|
||||||
|
@ -2,7 +2,7 @@ package net.corda.node.services.config
|
|||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.core.node.NodeVersionInfo
|
import net.corda.core.node.VersionInfo
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.node.internal.NetworkMapInfo
|
import net.corda.node.internal.NetworkMapInfo
|
||||||
import net.corda.node.internal.Node
|
import net.corda.node.internal.Node
|
||||||
@ -22,6 +22,7 @@ interface NodeConfiguration : SSLConfiguration {
|
|||||||
override val certificatesDirectory: Path get() = baseDirectory / "certificates"
|
override val certificatesDirectory: Path get() = baseDirectory / "certificates"
|
||||||
val myLegalName: String
|
val myLegalName: String
|
||||||
val networkMapService: NetworkMapInfo?
|
val networkMapService: NetworkMapInfo?
|
||||||
|
val minimumPlatformVersion: Int
|
||||||
val nearestCity: String
|
val nearestCity: String
|
||||||
val emailAddress: String
|
val emailAddress: String
|
||||||
val exportJMXto: String
|
val exportJMXto: String
|
||||||
@ -47,6 +48,7 @@ data class FullNodeConfiguration(
|
|||||||
override val dataSourceProperties: Properties,
|
override val dataSourceProperties: Properties,
|
||||||
override val certificateSigningService: URL,
|
override val certificateSigningService: URL,
|
||||||
override val networkMapService: NetworkMapInfo?,
|
override val networkMapService: NetworkMapInfo?,
|
||||||
|
override val minimumPlatformVersion: Int = 1,
|
||||||
override val rpcUsers: List<User>,
|
override val rpcUsers: List<User>,
|
||||||
override val verifierType: VerifierType,
|
override val verifierType: VerifierType,
|
||||||
val useHTTPS: Boolean,
|
val useHTTPS: Boolean,
|
||||||
@ -78,14 +80,14 @@ data class FullNodeConfiguration(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNode(nodeVersionInfo: NodeVersionInfo): Node {
|
fun createNode(versionInfo: VersionInfo): Node {
|
||||||
val advertisedServices = extraAdvertisedServiceIds
|
val advertisedServices = extraAdvertisedServiceIds
|
||||||
.filter(String::isNotBlank)
|
.filter(String::isNotBlank)
|
||||||
.map { ServiceInfo.parse(it) }
|
.map { ServiceInfo.parse(it) }
|
||||||
.toMutableSet()
|
.toMutableSet()
|
||||||
if (networkMapService == null) advertisedServices += ServiceInfo(NetworkMapService.type)
|
if (networkMapService == null) advertisedServices += ServiceInfo(NetworkMapService.type)
|
||||||
|
|
||||||
return Node(this, advertisedServices, nodeVersionInfo, if (useTestClock) TestClock() else NodeClock())
|
return Node(this, advertisedServices, versionInfo, if (useTestClock) TestClock() else NodeClock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import com.google.common.net.HostAndPort
|
|||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.ThreadBox
|
import net.corda.core.ThreadBox
|
||||||
import net.corda.core.messaging.*
|
import net.corda.core.messaging.*
|
||||||
import net.corda.core.node.NodeVersionInfo
|
import net.corda.core.node.VersionInfo
|
||||||
import net.corda.core.node.services.PartyInfo
|
import net.corda.core.node.services.PartyInfo
|
||||||
import net.corda.core.node.services.TransactionVerifierService
|
import net.corda.core.node.services.TransactionVerifierService
|
||||||
import net.corda.core.random63BitValue
|
import net.corda.core.random63BitValue
|
||||||
@ -68,7 +68,7 @@ import java.security.PublicKey
|
|||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
class NodeMessagingClient(override val config: NodeConfiguration,
|
class NodeMessagingClient(override val config: NodeConfiguration,
|
||||||
nodeVersionInfo: NodeVersionInfo,
|
val versionInfo: VersionInfo,
|
||||||
val serverHostPort: HostAndPort,
|
val serverHostPort: HostAndPort,
|
||||||
val myIdentity: PublicKey?,
|
val myIdentity: PublicKey?,
|
||||||
val nodeExecutor: AffinityExecutor,
|
val nodeExecutor: AffinityExecutor,
|
||||||
@ -85,9 +85,10 @@ class NodeMessagingClient(override val config: NodeConfiguration,
|
|||||||
// confusion.
|
// confusion.
|
||||||
private val topicProperty = SimpleString("platform-topic")
|
private val topicProperty = SimpleString("platform-topic")
|
||||||
private val sessionIdProperty = SimpleString("session-id")
|
private val sessionIdProperty = SimpleString("session-id")
|
||||||
private val nodeVersionProperty = SimpleString("node-version")
|
private val cordaVendorProperty = SimpleString("corda-vendor")
|
||||||
private val nodeVendorProperty = SimpleString("node-vendor")
|
private val releaseVersionProperty = SimpleString("release-version")
|
||||||
private val amqDelay: Int = Integer.valueOf(System.getProperty("amq.delivery.delay.ms", "0"))
|
private val platformVersionProperty = SimpleString("platform-version")
|
||||||
|
private val amqDelayMillis = System.getProperty("amq.delivery.delay.ms", "0").toInt()
|
||||||
private val verifierResponseAddress = "$VERIFICATION_RESPONSES_QUEUE_NAME_PREFIX.${random63BitValue()}"
|
private val verifierResponseAddress = "$VERIFICATION_RESPONSES_QUEUE_NAME_PREFIX.${random63BitValue()}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,8 +115,8 @@ class NodeMessagingClient(override val config: NodeConfiguration,
|
|||||||
data class Handler(val topicSession: TopicSession,
|
data class Handler(val topicSession: TopicSession,
|
||||||
val callback: (ReceivedMessage, MessageHandlerRegistration) -> Unit) : MessageHandlerRegistration
|
val callback: (ReceivedMessage, MessageHandlerRegistration) -> Unit) : MessageHandlerRegistration
|
||||||
|
|
||||||
private val nodeVendor = SimpleString(nodeVersionInfo.vendor)
|
private val cordaVendor = SimpleString(versionInfo.vendor)
|
||||||
private val version = SimpleString(nodeVersionInfo.version.toString())
|
private val releaseVersion = SimpleString(versionInfo.releaseVersion)
|
||||||
/** An executor for sending messages */
|
/** An executor for sending messages */
|
||||||
private val messagingExecutor = AffinityExecutor.ServiceAffinityExecutor("Messaging", 1)
|
private val messagingExecutor = AffinityExecutor.ServiceAffinityExecutor("Messaging", 1)
|
||||||
|
|
||||||
@ -409,8 +410,9 @@ class NodeMessagingClient(override val config: NodeConfiguration,
|
|||||||
state.locked {
|
state.locked {
|
||||||
val mqAddress = getMQAddress(target)
|
val mqAddress = getMQAddress(target)
|
||||||
val artemisMessage = session!!.createMessage(true).apply {
|
val artemisMessage = session!!.createMessage(true).apply {
|
||||||
putStringProperty(nodeVendorProperty, nodeVendor)
|
putStringProperty(cordaVendorProperty, cordaVendor)
|
||||||
putStringProperty(nodeVersionProperty, version)
|
putStringProperty(releaseVersionProperty, releaseVersion)
|
||||||
|
putIntProperty(platformVersionProperty, versionInfo.platformVersion)
|
||||||
putStringProperty(topicProperty, SimpleString(message.topicSession.topic))
|
putStringProperty(topicProperty, SimpleString(message.topicSession.topic))
|
||||||
putLongProperty(sessionIdProperty, message.topicSession.sessionID)
|
putLongProperty(sessionIdProperty, message.topicSession.sessionID)
|
||||||
writeBodyBufferBytes(message.data)
|
writeBodyBufferBytes(message.data)
|
||||||
@ -418,8 +420,8 @@ class NodeMessagingClient(override val config: NodeConfiguration,
|
|||||||
putStringProperty(HDR_DUPLICATE_DETECTION_ID, SimpleString(message.uniqueMessageId.toString()))
|
putStringProperty(HDR_DUPLICATE_DETECTION_ID, SimpleString(message.uniqueMessageId.toString()))
|
||||||
|
|
||||||
// For demo purposes - if set then add a delay to messages in order to demonstrate that the flows are doing as intended
|
// For demo purposes - if set then add a delay to messages in order to demonstrate that the flows are doing as intended
|
||||||
if (amqDelay > 0 && message.topicSession.topic == StateMachineManager.sessionTopic.topic) {
|
if (amqDelayMillis > 0 && message.topicSession.topic == StateMachineManager.sessionTopic.topic) {
|
||||||
putLongProperty(HDR_SCHEDULED_DELIVERY_TIME, System.currentTimeMillis() + amqDelay)
|
putLongProperty(HDR_SCHEDULED_DELIVERY_TIME, System.currentTimeMillis() + amqDelayMillis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.trace {
|
log.trace {
|
||||||
|
@ -109,7 +109,8 @@ interface NetworkMapService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
class InMemoryNetworkMapService(services: ServiceHubInternal) : AbstractNetworkMapService(services) {
|
class InMemoryNetworkMapService(services: ServiceHubInternal, minimumPlatformVersion: Int)
|
||||||
|
: AbstractNetworkMapService(services, minimumPlatformVersion) {
|
||||||
|
|
||||||
override val nodeRegistrations: MutableMap<Party, NodeRegistrationInfo> = ConcurrentHashMap()
|
override val nodeRegistrations: MutableMap<Party, NodeRegistrationInfo> = ConcurrentHashMap()
|
||||||
override val subscribers = ThreadBox(mutableMapOf<SingleMessageRecipient, LastAcknowledgeInfo>())
|
override val subscribers = ThreadBox(mutableMapOf<SingleMessageRecipient, LastAcknowledgeInfo>())
|
||||||
@ -126,7 +127,8 @@ class InMemoryNetworkMapService(services: ServiceHubInternal) : AbstractNetworkM
|
|||||||
* subscriber clean up and is simpler to persist than the previous implementation based on a set of missing messages acks.
|
* subscriber clean up and is simpler to persist than the previous implementation based on a set of missing messages acks.
|
||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
abstract class AbstractNetworkMapService(services: ServiceHubInternal) : NetworkMapService, AbstractNodeService(services) {
|
abstract class AbstractNetworkMapService(services: ServiceHubInternal,
|
||||||
|
val minimumPlatformVersion: Int) : NetworkMapService, AbstractNodeService(services) {
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* Maximum credible size for a registration request. Generally requests are around 500-600 bytes, so this gives a
|
* Maximum credible size for a registration request. Generally requests are around 500-600 bytes, so this gives a
|
||||||
@ -152,6 +154,13 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal) : Network
|
|||||||
|
|
||||||
private val handlers = ArrayList<MessageHandlerRegistration>()
|
private val handlers = ArrayList<MessageHandlerRegistration>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(minimumPlatformVersion >= 1) { "minimumPlatformVersion cannot be less than 1" }
|
||||||
|
require(minimumPlatformVersion <= services.myInfo.platformVersion) {
|
||||||
|
"minimumPlatformVersion cannot be greater than the node's own version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected fun setup() {
|
protected fun setup() {
|
||||||
// Register message handlers
|
// Register message handlers
|
||||||
handlers += addMessageHandler(FETCH_TOPIC) { req: FetchMapRequest -> processFetchAllRequest(req) }
|
handlers += addMessageHandler(FETCH_TOPIC) { req: FetchMapRequest -> processFetchAllRequest(req) }
|
||||||
@ -219,21 +228,27 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal) : Network
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processRegistrationRequest(request: RegistrationRequest): RegistrationResponse {
|
private fun processRegistrationRequest(request: RegistrationRequest): RegistrationResponse {
|
||||||
if (request.wireReg.raw.size > MAX_SIZE_REGISTRATION_REQUEST_BYTES) return RegistrationResponse("Request is too big")
|
if (request.wireReg.raw.size > MAX_SIZE_REGISTRATION_REQUEST_BYTES) {
|
||||||
|
return RegistrationResponse("Request is too big")
|
||||||
|
}
|
||||||
|
|
||||||
val change = try {
|
val change = try {
|
||||||
request.wireReg.verified()
|
request.wireReg.verified()
|
||||||
} catch(e: SignatureException) {
|
} catch (e: SignatureException) {
|
||||||
return RegistrationResponse("Invalid signature on request")
|
return RegistrationResponse("Invalid signature on request")
|
||||||
}
|
}
|
||||||
|
|
||||||
val node = change.node
|
val node = change.node
|
||||||
|
|
||||||
|
if (node.platformVersion < minimumPlatformVersion) {
|
||||||
|
return RegistrationResponse("Minimum platform version requirement not met: $minimumPlatformVersion")
|
||||||
|
}
|
||||||
|
|
||||||
// Update the current value atomically, so that if multiple updates come
|
// Update the current value atomically, so that if multiple updates come
|
||||||
// in on different threads, there is no risk of a race condition while checking
|
// in on different threads, there is no risk of a race condition while checking
|
||||||
// sequence numbers.
|
// sequence numbers.
|
||||||
val registrationInfo = try {
|
val registrationInfo = try {
|
||||||
nodeRegistrations.compute(node.legalIdentity) { _: Party, existing: NodeRegistrationInfo? ->
|
nodeRegistrations.compute(node.legalIdentity) { _, existing: NodeRegistrationInfo? ->
|
||||||
require(!((existing == null || existing.reg.type == REMOVE) && change.type == REMOVE)) {
|
require(!((existing == null || existing.reg.type == REMOVE) && change.type == REMOVE)) {
|
||||||
"Attempting to de-register unknown node"
|
"Attempting to de-register unknown node"
|
||||||
}
|
}
|
||||||
@ -263,16 +278,16 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal) : Network
|
|||||||
return RegistrationResponse(null)
|
return RegistrationResponse(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifySubscribers(wireReg: WireNodeRegistration, mapVersion: Int) {
|
private fun notifySubscribers(wireReg: WireNodeRegistration, newMapVersion: Int) {
|
||||||
// TODO: Once we have a better established messaging system, we can probably send
|
// TODO: Once we have a better established messaging system, we can probably send
|
||||||
// to a MessageRecipientGroup that nodes join/leave, rather than the network map
|
// to a MessageRecipientGroup that nodes join/leave, rather than the network map
|
||||||
// service itself managing the group
|
// service itself managing the group
|
||||||
val update = NetworkMapService.Update(wireReg, mapVersion, net.myAddress).serialize().bytes
|
val update = NetworkMapService.Update(wireReg, newMapVersion, net.myAddress).serialize().bytes
|
||||||
val message = net.createMessage(PUSH_TOPIC, DEFAULT_SESSION_ID, update)
|
val message = net.createMessage(PUSH_TOPIC, DEFAULT_SESSION_ID, update)
|
||||||
|
|
||||||
subscribers.locked {
|
subscribers.locked {
|
||||||
// Remove any stale subscribers
|
// Remove any stale subscribers
|
||||||
values.removeIf { lastAckInfo -> mapVersion - lastAckInfo.mapVersion > maxUnacknowledgedUpdates }
|
values.removeIf { (mapVersion) -> newMapVersion - mapVersion > maxUnacknowledgedUpdates }
|
||||||
// TODO: introduce some concept of time in the condition to avoid unsubscribes when there's a message burst.
|
// TODO: introduce some concept of time in the condition to avoid unsubscribes when there's a message burst.
|
||||||
keys.forEach { recipient -> net.send(message, recipient) }
|
keys.forEach { recipient -> net.send(message, recipient) }
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@ import java.util.Collections.synchronizedMap
|
|||||||
* This class needs database transactions to be in-flight during method calls and init, otherwise it will throw
|
* This class needs database transactions to be in-flight during method calls and init, otherwise it will throw
|
||||||
* exceptions.
|
* exceptions.
|
||||||
*/
|
*/
|
||||||
class PersistentNetworkMapService(services: ServiceHubInternal) : AbstractNetworkMapService(services) {
|
class PersistentNetworkMapService(services: ServiceHubInternal, minimumPlatformVersion: Int)
|
||||||
|
: AbstractNetworkMapService(services, minimumPlatformVersion) {
|
||||||
|
|
||||||
private object Table : JDBCHashedTable("${NODE_DATABASE_PREFIX}network_map_nodes") {
|
private object Table : JDBCHashedTable("${NODE_DATABASE_PREFIX}network_map_nodes") {
|
||||||
val nodeParty = party("node_party_name", "node_party_key")
|
val nodeParty = party("node_party_name", "node_party_key")
|
||||||
val registrationInfo = blob("node_registration_info")
|
val registrationInfo = blob("node_registration_info")
|
||||||
|
@ -25,7 +25,7 @@ import net.corda.node.services.transactions.PersistentUniquenessProvider
|
|||||||
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
||||||
import net.corda.node.utilities.configureDatabase
|
import net.corda.node.utilities.configureDatabase
|
||||||
import net.corda.node.utilities.transaction
|
import net.corda.node.utilities.transaction
|
||||||
import net.corda.testing.MOCK_NODE_VERSION_INFO
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import net.corda.testing.TestNodeConfiguration
|
import net.corda.testing.TestNodeConfiguration
|
||||||
import net.corda.testing.freeLocalHostAndPort
|
import net.corda.testing.freeLocalHostAndPort
|
||||||
import net.corda.testing.node.makeTestDataSourceProperties
|
import net.corda.testing.node.makeTestDataSourceProperties
|
||||||
@ -225,7 +225,7 @@ class ArtemisMessagingTests {
|
|||||||
return database.transaction {
|
return database.transaction {
|
||||||
NodeMessagingClient(
|
NodeMessagingClient(
|
||||||
config,
|
config,
|
||||||
MOCK_NODE_VERSION_INFO,
|
MOCK_VERSION_INFO,
|
||||||
server,
|
server,
|
||||||
identity.public,
|
identity.public,
|
||||||
ServiceAffinityExecutor("ArtemisMessagingTests", 1),
|
ServiceAffinityExecutor("ArtemisMessagingTests", 1),
|
||||||
|
@ -5,6 +5,7 @@ import net.corda.core.node.services.ServiceInfo
|
|||||||
import net.corda.node.services.api.ServiceHubInternal
|
import net.corda.node.services.api.ServiceHubInternal
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.utilities.transaction
|
import net.corda.node.utilities.transaction
|
||||||
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import net.corda.testing.node.MockNetwork.MockNode
|
import net.corda.testing.node.MockNetwork.MockNode
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
@ -48,11 +49,11 @@ class PersistentNetworkMapServiceTest : AbstractNetworkMapServiceTest<Persistent
|
|||||||
* state within it is correctly restored.
|
* state within it is correctly restored.
|
||||||
*/
|
*/
|
||||||
private class SwizzleNetworkMapService(val services: ServiceHubInternal) : NetworkMapService {
|
private class SwizzleNetworkMapService(val services: ServiceHubInternal) : NetworkMapService {
|
||||||
var delegate: PersistentNetworkMapService = PersistentNetworkMapService(services)
|
var delegate: PersistentNetworkMapService = PersistentNetworkMapService(services, MOCK_VERSION_INFO.platformVersion)
|
||||||
|
|
||||||
fun swizzle() {
|
fun swizzle() {
|
||||||
delegate.unregisterNetworkHandlers()
|
delegate.unregisterNetworkHandlers()
|
||||||
delegate = PersistentNetworkMapService(services)
|
delegate = PersistentNetworkMapService(services, MOCK_VERSION_INFO.platformVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,12 @@ package net.corda.testing
|
|||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.node.NodeVersionInfo
|
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.Version
|
import net.corda.core.node.VersionInfo
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
import net.corda.core.toFuture
|
import net.corda.core.toFuture
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
@ -83,8 +84,7 @@ val ALL_TEST_KEYS: List<KeyPair> get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, AL
|
|||||||
|
|
||||||
val MOCK_IDENTITY_SERVICE: MockIdentityService get() = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY))
|
val MOCK_IDENTITY_SERVICE: MockIdentityService get() = MockIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY))
|
||||||
|
|
||||||
val MOCK_VERSION = Version(0, 0, 0, false)
|
val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor")
|
||||||
val MOCK_NODE_VERSION_INFO = NodeVersionInfo(MOCK_VERSION, "Mock revision", "Mock Vendor")
|
|
||||||
|
|
||||||
fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0)
|
fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0)
|
||||||
|
|
||||||
@ -156,6 +156,7 @@ data class TestNodeConfiguration(
|
|||||||
override val baseDirectory: Path,
|
override val baseDirectory: Path,
|
||||||
override val myLegalName: String,
|
override val myLegalName: String,
|
||||||
override val networkMapService: NetworkMapInfo?,
|
override val networkMapService: NetworkMapInfo?,
|
||||||
|
override val minimumPlatformVersion: Int = 1,
|
||||||
override val keyStorePassword: String = "cordacadevpass",
|
override val keyStorePassword: String = "cordacadevpass",
|
||||||
override val trustStorePassword: String = "trustpass",
|
override val trustStorePassword: String = "trustpass",
|
||||||
override val rpcUsers: List<User> = emptyList(),
|
override val rpcUsers: List<User> = emptyList(),
|
||||||
@ -166,7 +167,8 @@ data class TestNodeConfiguration(
|
|||||||
override val devMode: Boolean = true,
|
override val devMode: Boolean = true,
|
||||||
override val certificateSigningService: URL = URL("http://localhost"),
|
override val certificateSigningService: URL = URL("http://localhost"),
|
||||||
override val certificateChainCheckPolicies: List<CertChainPolicyConfig> = emptyList(),
|
override val certificateChainCheckPolicies: List<CertChainPolicyConfig> = emptyList(),
|
||||||
override val verifierType: VerifierType = VerifierType.InMemory) : NodeConfiguration
|
override val verifierType: VerifierType = VerifierType.InMemory) : NodeConfiguration {
|
||||||
|
}
|
||||||
|
|
||||||
fun testConfiguration(baseDirectory: Path, legalName: String, basePort: Int): FullNodeConfiguration {
|
fun testConfiguration(baseDirectory: Path, legalName: String, basePort: Int): FullNodeConfiguration {
|
||||||
return FullNodeConfiguration(
|
return FullNodeConfiguration(
|
||||||
|
@ -7,7 +7,7 @@ import net.corda.core.messaging.SingleMessageRecipient
|
|||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.services.NetworkMapCache
|
import net.corda.core.node.services.NetworkMapCache
|
||||||
import net.corda.node.services.network.InMemoryNetworkMapCache
|
import net.corda.node.services.network.InMemoryNetworkMapCache
|
||||||
import net.corda.testing.MOCK_VERSION
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
|
|
||||||
@ -20,8 +20,8 @@ class MockNetworkMapCache : InMemoryNetworkMapCache() {
|
|||||||
data class MockAddress(val id: String) : SingleMessageRecipient
|
data class MockAddress(val id: String) : SingleMessageRecipient
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val mockNodeA = NodeInfo(MockAddress("bankC:8080"), Party("Bank C", DummyPublicKey("Bank C")), MOCK_VERSION)
|
val mockNodeA = NodeInfo(MockAddress("bankC:8080"), Party("Bank C", DummyPublicKey("Bank C")), MOCK_VERSION_INFO.platformVersion)
|
||||||
val mockNodeB = NodeInfo(MockAddress("bankD:8080"), Party("Bank D", DummyPublicKey("Bank D")), MOCK_VERSION)
|
val mockNodeB = NodeInfo(MockAddress("bankD:8080"), Party("Bank D", DummyPublicKey("Bank D")), MOCK_VERSION_INFO.platformVersion)
|
||||||
registeredNodes[mockNodeA.legalIdentity.owningKey] = mockNodeA
|
registeredNodes[mockNodeA.legalIdentity.owningKey] = mockNodeA
|
||||||
registeredNodes[mockNodeB.legalIdentity.owningKey] = mockNodeB
|
registeredNodes[mockNodeB.legalIdentity.owningKey] = mockNodeB
|
||||||
runWithoutMapService()
|
runWithoutMapService()
|
||||||
|
@ -12,7 +12,6 @@ import net.corda.core.messaging.SingleMessageRecipient
|
|||||||
import net.corda.core.node.CordaPluginRegistry
|
import net.corda.core.node.CordaPluginRegistry
|
||||||
import net.corda.core.node.PhysicalLocation
|
import net.corda.core.node.PhysicalLocation
|
||||||
import net.corda.core.node.ServiceEntry
|
import net.corda.core.node.ServiceEntry
|
||||||
import net.corda.core.node.Version
|
|
||||||
import net.corda.core.node.services.*
|
import net.corda.core.node.services.*
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
@ -29,7 +28,7 @@ import net.corda.node.services.transactions.ValidatingNotaryService
|
|||||||
import net.corda.node.services.vault.NodeVaultService
|
import net.corda.node.services.vault.NodeVaultService
|
||||||
import net.corda.node.utilities.AffinityExecutor
|
import net.corda.node.utilities.AffinityExecutor
|
||||||
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
||||||
import net.corda.testing.MOCK_VERSION
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import net.corda.testing.TestNodeConfiguration
|
import net.corda.testing.TestNodeConfiguration
|
||||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
@ -136,7 +135,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
AbstractNode(config, advertisedServices, TestClock(), mockNet.busyLatch) {
|
AbstractNode(config, advertisedServices, TestClock(), mockNet.busyLatch) {
|
||||||
var counter = entropyRoot
|
var counter = entropyRoot
|
||||||
override val log: Logger = loggerFor<MockNode>()
|
override val log: Logger = loggerFor<MockNode>()
|
||||||
override val version: Version get() = MOCK_VERSION
|
override val platformVersion: Int get() = MOCK_VERSION_INFO.platformVersion
|
||||||
override val serverThread: AffinityExecutor =
|
override val serverThread: AffinityExecutor =
|
||||||
if (mockNet.threadPerNode)
|
if (mockNet.threadPerNode)
|
||||||
ServiceAffinityExecutor("Mock node $id thread", 1)
|
ServiceAffinityExecutor("Mock node $id thread", 1)
|
||||||
@ -149,7 +148,15 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
// through the java.nio API which we are already mocking via Jimfs.
|
// through the java.nio API which we are already mocking via Jimfs.
|
||||||
override fun makeMessagingService(): MessagingServiceInternal {
|
override fun makeMessagingService(): MessagingServiceInternal {
|
||||||
require(id >= 0) { "Node ID must be zero or positive, was passed: " + id }
|
require(id >= 0) { "Node ID must be zero or positive, was passed: " + id }
|
||||||
return mockNet.messagingNetwork.createNodeWithID(!mockNet.threadPerNode, id, serverThread, makeServiceEntries(), configuration.myLegalName, database).start().getOrThrow()
|
return mockNet.messagingNetwork.createNodeWithID(
|
||||||
|
!mockNet.threadPerNode,
|
||||||
|
id,
|
||||||
|
serverThread,
|
||||||
|
makeServiceEntries(),
|
||||||
|
configuration.myLegalName,
|
||||||
|
database)
|
||||||
|
.start()
|
||||||
|
.getOrThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun makeIdentityService() = MockIdentityService(mockNet.identities)
|
override fun makeIdentityService() = MockIdentityService(mockNet.identities)
|
||||||
@ -165,7 +172,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun makeNetworkMapService() {
|
override fun makeNetworkMapService() {
|
||||||
inNodeNetworkMapService = InMemoryNetworkMapService(services)
|
inNodeNetworkMapService = InMemoryNetworkMapService(services, platformVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun makeServiceEntries(): List<ServiceEntry> {
|
override fun makeServiceEntries(): List<ServiceEntry> {
|
||||||
|
@ -21,7 +21,7 @@ import net.corda.node.services.transactions.InMemoryTransactionVerifierService
|
|||||||
import net.corda.node.services.vault.NodeVaultService
|
import net.corda.node.services.vault.NodeVaultService
|
||||||
import net.corda.testing.MEGA_CORP
|
import net.corda.testing.MEGA_CORP
|
||||||
import net.corda.testing.MINI_CORP
|
import net.corda.testing.MINI_CORP
|
||||||
import net.corda.testing.MOCK_VERSION
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
@ -68,7 +68,7 @@ open class MockServices(val key: KeyPair = generateKeyPair()) : ServiceHub {
|
|||||||
override val networkMapCache: NetworkMapCache get() = throw UnsupportedOperationException()
|
override val networkMapCache: NetworkMapCache get() = throw UnsupportedOperationException()
|
||||||
override val clock: Clock get() = Clock.systemUTC()
|
override val clock: Clock get() = Clock.systemUTC()
|
||||||
override val schedulerService: SchedulerService get() = throw UnsupportedOperationException()
|
override val schedulerService: SchedulerService get() = throw UnsupportedOperationException()
|
||||||
override val myInfo: NodeInfo get() = NodeInfo(object : SingleMessageRecipient {}, Party("MegaCorp", key.public), MOCK_VERSION)
|
override val myInfo: NodeInfo get() = NodeInfo(object : SingleMessageRecipient {}, Party("MegaCorp", key.public), MOCK_VERSION_INFO.platformVersion)
|
||||||
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2)
|
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2)
|
||||||
|
|
||||||
fun makeVaultService(dataSourceProps: Properties): VaultService {
|
fun makeVaultService(dataSourceProps: Properties): VaultService {
|
||||||
|
@ -16,7 +16,7 @@ import net.corda.node.services.transactions.RaftValidatingNotaryService
|
|||||||
import net.corda.node.utilities.ServiceIdentityGenerator
|
import net.corda.node.utilities.ServiceIdentityGenerator
|
||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
import net.corda.nodeapi.config.parseAs
|
import net.corda.nodeapi.config.parseAs
|
||||||
import net.corda.testing.MOCK_NODE_VERSION_INFO
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import net.corda.testing.getFreeLocalPorts
|
import net.corda.testing.getFreeLocalPorts
|
||||||
import org.apache.logging.log4j.Level
|
import org.apache.logging.log4j.Level
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
@ -141,7 +141,7 @@ abstract class NodeBasedTest {
|
|||||||
) + configOverrides
|
) + configOverrides
|
||||||
)
|
)
|
||||||
|
|
||||||
val node = config.parseAs<FullNodeConfiguration>().createNode(MOCK_NODE_VERSION_INFO)
|
val node = config.parseAs<FullNodeConfiguration>().createNode(MOCK_VERSION_INFO)
|
||||||
node.start()
|
node.start()
|
||||||
nodes += node
|
nodes += node
|
||||||
thread(name = legalName) {
|
thread(name = legalName) {
|
||||||
|
@ -5,6 +5,7 @@ import com.google.common.net.HostAndPort
|
|||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import net.corda.node.services.RPCUserServiceImpl
|
import net.corda.node.services.RPCUserServiceImpl
|
||||||
import net.corda.node.services.api.MonitoringService
|
import net.corda.node.services.api.MonitoringService
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
@ -13,7 +14,6 @@ import net.corda.node.services.messaging.NodeMessagingClient
|
|||||||
import net.corda.node.services.network.InMemoryNetworkMapCache
|
import net.corda.node.services.network.InMemoryNetworkMapCache
|
||||||
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
||||||
import net.corda.node.utilities.configureDatabase
|
import net.corda.node.utilities.configureDatabase
|
||||||
import net.corda.testing.MOCK_NODE_VERSION_INFO
|
|
||||||
import net.corda.node.utilities.transaction
|
import net.corda.node.utilities.transaction
|
||||||
import net.corda.testing.freeLocalHostAndPort
|
import net.corda.testing.freeLocalHostAndPort
|
||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
@ -38,7 +38,7 @@ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeL
|
|||||||
val net = database.transaction {
|
val net = database.transaction {
|
||||||
NodeMessagingClient(
|
NodeMessagingClient(
|
||||||
config,
|
config,
|
||||||
MOCK_NODE_VERSION_INFO,
|
MOCK_VERSION_INFO,
|
||||||
address,
|
address,
|
||||||
identity.public,
|
identity.public,
|
||||||
executor,
|
executor,
|
||||||
|
@ -80,9 +80,8 @@ dependencies {
|
|||||||
jar {
|
jar {
|
||||||
manifest {
|
manifest {
|
||||||
attributes(
|
attributes(
|
||||||
'Corda-Version': corda_version,
|
'Main-Class': mainClassName,
|
||||||
'Main-Class': mainClassName,
|
'Class-Path': configurations.compile.collect { it.getName() }.join(' ')
|
||||||
'Class-Path': configurations.compile.collect { it.getName() }.join(' ')
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,12 +31,12 @@ dependencies {
|
|||||||
|
|
||||||
task buildExplorerJAR(type: FatCapsule) {
|
task buildExplorerJAR(type: FatCapsule) {
|
||||||
applicationClass 'net.corda.explorer.Main'
|
applicationClass 'net.corda.explorer.Main'
|
||||||
archiveName "node-explorer-${corda_version}.jar"
|
archiveName "node-explorer-${corda_release_version}.jar"
|
||||||
applicationSource = files(project.tasks.findByName('jar'), '../build/classes/main/ExplorerCaplet.class')
|
applicationSource = files(project.tasks.findByName('jar'), '../build/classes/main/ExplorerCaplet.class')
|
||||||
classifier 'fat'
|
classifier 'fat'
|
||||||
|
|
||||||
capsuleManifest {
|
capsuleManifest {
|
||||||
applicationVersion = corda_version
|
applicationVersion = corda_release_version
|
||||||
systemProperties['visualvm.display.name'] = 'Node Explorer'
|
systemProperties['visualvm.display.name'] = 'Node Explorer'
|
||||||
minJavaVersion = '1.8.0'
|
minJavaVersion = '1.8.0'
|
||||||
minUpdateVersion['1.8'] = java8_minUpdateVersion
|
minUpdateVersion['1.8'] = java8_minUpdateVersion
|
||||||
@ -49,10 +49,6 @@ task buildExplorerJAR(type: FatCapsule) {
|
|||||||
// If you change these flags, please also update Driver.kt
|
// If you change these flags, please also update Driver.kt
|
||||||
jvmArgs = ['-Xmx200m', '-XX:+UseG1GC']
|
jvmArgs = ['-Xmx200m', '-XX:+UseG1GC']
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest {
|
|
||||||
attributes('Corda-Version': corda_version)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
build.dependsOn buildExplorerJAR
|
build.dependsOn buildExplorerJAR
|
||||||
|
@ -38,7 +38,7 @@ dependencies {
|
|||||||
|
|
||||||
task buildWebserverJar(type: FatCapsule) {
|
task buildWebserverJar(type: FatCapsule) {
|
||||||
applicationClass 'net.corda.webserver.WebServer'
|
applicationClass 'net.corda.webserver.WebServer'
|
||||||
archiveName "corda-webserver-${corda_version}.jar"
|
archiveName "corda-webserver-${corda_release_version}.jar"
|
||||||
applicationSource = files(
|
applicationSource = files(
|
||||||
project.tasks.findByName('jar'),
|
project.tasks.findByName('jar'),
|
||||||
new File(project(':node').rootDir, 'node/build/classes/main/CordaCaplet.class'),
|
new File(project(':node').rootDir, 'node/build/classes/main/CordaCaplet.class'),
|
||||||
@ -48,10 +48,9 @@ task buildWebserverJar(type: FatCapsule) {
|
|||||||
from 'NOTICE' // Copy CDDL notice
|
from 'NOTICE' // Copy CDDL notice
|
||||||
|
|
||||||
capsuleManifest {
|
capsuleManifest {
|
||||||
applicationVersion = corda_version
|
applicationVersion = corda_release_version
|
||||||
javaAgents = ["quasar-core-${quasar_version}-jdk8.jar"]
|
javaAgents = ["quasar-core-${quasar_version}-jdk8.jar"]
|
||||||
systemProperties['visualvm.display.name'] = 'Corda Webserver'
|
systemProperties['visualvm.display.name'] = 'Corda Webserver'
|
||||||
systemProperties['corda.version'] = corda_version
|
|
||||||
minJavaVersion = '1.8.0'
|
minJavaVersion = '1.8.0'
|
||||||
minUpdateVersion['1.8'] = java8_minUpdateVersion
|
minUpdateVersion['1.8'] = java8_minUpdateVersion
|
||||||
caplets = ['CordaCaplet']
|
caplets = ['CordaCaplet']
|
||||||
@ -63,10 +62,6 @@ task buildWebserverJar(type: FatCapsule) {
|
|||||||
// If you change these flags, please also update Driver.kt
|
// If you change these flags, please also update Driver.kt
|
||||||
jvmArgs = ['-Xmx200m', '-XX:+UseG1GC']
|
jvmArgs = ['-Xmx200m', '-XX:+UseG1GC']
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest {
|
|
||||||
attributes('Corda-Version': corda_version)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
artifacts {
|
artifacts {
|
||||||
|
Loading…
Reference in New Issue
Block a user