From a88e7c90352337a05f98af160be968dc8b84732b Mon Sep 17 00:00:00 2001 From: Ben Abineri Date: Thu, 30 Nov 2017 10:06:37 +0000 Subject: [PATCH 01/22] enable service instructions --- docs/source/deploying-a-node.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/source/deploying-a-node.rst b/docs/source/deploying-a-node.rst index 2b091fddf8..44d758ffe7 100644 --- a/docs/source/deploying-a-node.rst +++ b/docs/source/deploying-a-node.rst @@ -126,11 +126,11 @@ handling, and ensures the Corda service is run at boot. 9. Provision the required certificates to your node. Contact the network permissioning service or see :doc:`permissioning` -10. You can now start a node and its webserver by running the following ``systemctl`` commands: +10. You can now start a node and its webserver and set the services to start on boot by running the following ``systemctl`` commands: * ``sudo systemctl daemon-reload`` - * ``sudo systemctl corda start`` - * ``sudo systemctl corda-webserver start`` + * ``sudo systemctl enable --now corda`` + * ``sudo systemctl enable --now corda-webserver`` You can run multiple nodes by creating multiple directories and Corda services, modifying the ``node.conf`` and ``service`` files so they are unique. @@ -216,6 +216,7 @@ at boot, and means the Corda service stays running with no users connected to th nssm set cordanode1 AppStdout C:\Corda\service.log nssm set cordanode1 AppStderr C:\Corda\service.log nssm set cordanode1 Description Corda Node - Bank of Breakfast Tea + nssm set cordanode1 Start SERVICE_AUTO_START sc start cordanode1 9. Modify the batch file: From ada1fe243851a1f6a0ed5f0b5a750a0f9a79e7e9 Mon Sep 17 00:00:00 2001 From: joeldudleyr3 Date: Thu, 30 Nov 2017 10:38:06 +0000 Subject: [PATCH 02/22] Documents increasing heap size when running nodes locally. --- docs/source/running-a-node.rst | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/source/running-a-node.rst b/docs/source/running-a-node.rst index b5c2ddf845..eac42fe30b 100644 --- a/docs/source/running-a-node.rst +++ b/docs/source/running-a-node.rst @@ -22,6 +22,12 @@ Start the nodes with ``runnodes`` by running the following command from the root .. warn:: On macOS, do not click/change focus until all the node terminal windows have opened, or some processes may fail to start. +If you receive an ``OutOfMemoryError`` exception when interacting with the nodes, you need to increase the amount of +Java heap memory available to them, which you can do when running them individually. See +:ref:`starting-an-individual-corda-node`. + +.. _starting-an-individual-corda-node: + Starting an individual Corda node --------------------------------- Run the node by opening a terminal window in the node's folder and running: @@ -30,9 +36,18 @@ Run the node by opening a terminal window in the node's folder and running: java -jar corda.jar -.. warning:: By default, the node will look for a configuration file called ``node.conf`` and a CorDapps folder called - ``cordapps`` in the current working directory. You can override the configuration file and workspace paths on the - command line (e.g. ``./corda.jar --config-file=test.conf --base-directory=/opt/r3corda/nodes/test``). +By default, the node will look for a configuration file called ``node.conf`` and a CorDapps folder called ``cordapps`` +in the current working directory. You can override the configuration file and workspace paths on the command line (e.g. +``./corda.jar --config-file=test.conf --base-directory=/opt/corda/nodes/test``). + +You can increase the amount of Java heap memory available to the node using the ``-Xmx`` command line argument. For +example, the following would run the node with a heap size of 2048MB: + +.. code-block:: shell + + java -jar corda.jar -Xmx2048m + +You should do this if you receive an ``OutOfMemoryError`` exception when interacting with the node. Optionally run the node's webserver as well by opening a terminal window in the node's folder and running: From 1e58aedb801cdc6b7c8b2c64984fedd68d4d6044 Mon Sep 17 00:00:00 2001 From: joeldudleyr3 Date: Thu, 30 Nov 2017 11:13:16 +0000 Subject: [PATCH 03/22] Fixes order of xmx commands. --- docs/source/deploying-a-node.rst | 2 +- docs/source/running-a-node.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/deploying-a-node.rst b/docs/source/deploying-a-node.rst index 44d758ffe7..e23f8814e9 100644 --- a/docs/source/deploying-a-node.rst +++ b/docs/source/deploying-a-node.rst @@ -212,7 +212,7 @@ at boot, and means the Corda service stays running with no users connected to th nssm install cordanode1 C:\ProgramData\Oracle\Java\javapath\java.exe nssm set cordanode1 AppDirectory C:\Corda - nssm set cordanode1 AppParameters "-jar corda.jar -Xmx2048m --config-file=C:\corda\node.conf" + nssm set cordanode1 AppParameters "-Xmx2048m -jar corda.jar --config-file=C:\corda\node.conf" nssm set cordanode1 AppStdout C:\Corda\service.log nssm set cordanode1 AppStderr C:\Corda\service.log nssm set cordanode1 Description Corda Node - Bank of Breakfast Tea diff --git a/docs/source/running-a-node.rst b/docs/source/running-a-node.rst index eac42fe30b..34fde7652b 100644 --- a/docs/source/running-a-node.rst +++ b/docs/source/running-a-node.rst @@ -45,7 +45,7 @@ example, the following would run the node with a heap size of 2048MB: .. code-block:: shell - java -jar corda.jar -Xmx2048m + java -Xmx2048m -jar corda.jar You should do this if you receive an ``OutOfMemoryError`` exception when interacting with the node. From e8822ce391e496a7b00add041725bda0c1ad5d21 Mon Sep 17 00:00:00 2001 From: Katelyn Baker Date: Mon, 27 Nov 2017 13:43:30 +0000 Subject: [PATCH 04/22] CORDA-553 - Plumb the transform schema into the AMQP serialisation framework This change doesn't enable anything, it just changes the code to pass around both relevant schemas instead of a single one from the AMQP envelope. The actual evolver will build ontop of this --- .../nodeapi/internal/serialization/amqp/EnumEvolveTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt index 265f4b9a0c..23637f825d 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt @@ -40,4 +40,4 @@ class EnumEvolveTests { File(EvolvabilityTests::class.java.getResource(resource).toURI()).readBytes())) }.isInstanceOf(NotSerializableException::class.java) } -} \ No newline at end of file +} From 6fc736a5f5d8cdf0a004698a179ee0d2ce5a91be Mon Sep 17 00:00:00 2001 From: Katelyn Baker Date: Mon, 27 Nov 2017 19:21:27 +0000 Subject: [PATCH 05/22] CORDA-553 - Enable Enum Evolution --- .../serialization/amqp/AMQPSerializer.kt | 2 +- .../amqp/EnumEvolutionSerializer.kt | 89 +++++ .../serialization/amqp/SerializerFactory.kt | 2 +- .../serialization/amqp/TansformTypes.kt | 50 +++ .../serialization/amqp/TransformsSchema.kt | 104 +++--- .../amqp/EnumEvolvabilityTests.kt | 124 ++++++- .../serialization/amqp/EnumEvolveTests.kt | 323 +++++++++++++++++- .../serialization/amqp/EvolvabilityTests.kt | 4 +- ...volveTests.deserialiseNewerSetToUnknown2.C | Bin 0 -> 873 bytes ...volveTests.deserialiseNewerSetToUnknown2.D | Bin 0 -> 873 bytes ...volveTests.deserialiseNewerSetToUnknown2.E | Bin 0 -> 873 bytes ...EnumEvolveTests.deserialiseNewerWithNoRule | Bin 0 -> 670 bytes ...EnumEvolveTests.deserializeWithRename.1.AA | Bin 0 -> 763 bytes .../EnumEvolveTests.deserializeWithRename.1.B | Bin 0 -> 762 bytes .../EnumEvolveTests.deserializeWithRename.1.C | Bin 0 -> 762 bytes ...EnumEvolveTests.deserializeWithRename.2.AA | Bin 0 -> 792 bytes ...EnumEvolveTests.deserializeWithRename.2.BB | Bin 0 -> 792 bytes .../EnumEvolveTests.deserializeWithRename.2.C | Bin 0 -> 791 bytes ...EnumEvolveTests.deserializeWithRename.3.AA | Bin 0 -> 821 bytes .../EnumEvolveTests.deserializeWithRename.3.C | Bin 0 -> 820 bytes ...EnumEvolveTests.deserializeWithRename.3.XX | Bin 0 -> 821 bytes .../amqp/EnumEvolveTests.multiOperations.1.A | Bin 0 -> 760 bytes .../amqp/EnumEvolveTests.multiOperations.1.B | Bin 0 -> 760 bytes .../amqp/EnumEvolveTests.multiOperations.1.C | Bin 0 -> 760 bytes .../amqp/EnumEvolveTests.multiOperations.1.D | Bin 0 -> 760 bytes .../amqp/EnumEvolveTests.multiOperations.2.A | Bin 0 -> 811 bytes .../amqp/EnumEvolveTests.multiOperations.2.B | Bin 0 -> 811 bytes .../amqp/EnumEvolveTests.multiOperations.2.C | Bin 0 -> 811 bytes .../amqp/EnumEvolveTests.multiOperations.2.D | Bin 0 -> 811 bytes .../amqp/EnumEvolveTests.multiOperations.2.E | Bin 0 -> 811 bytes .../amqp/EnumEvolveTests.multiOperations.3.A | Bin 0 -> 857 bytes .../amqp/EnumEvolveTests.multiOperations.3.B | Bin 0 -> 857 bytes .../EnumEvolveTests.multiOperations.3.BOB | Bin 0 -> 859 bytes .../amqp/EnumEvolveTests.multiOperations.3.C | Bin 0 -> 857 bytes .../amqp/EnumEvolveTests.multiOperations.3.D | Bin 0 -> 857 bytes .../amqp/EnumEvolveTests.multiOperations.4.A | Bin 0 -> 1004 bytes .../amqp/EnumEvolveTests.multiOperations.4.B | Bin 0 -> 1004 bytes .../EnumEvolveTests.multiOperations.4.BOB | Bin 0 -> 1006 bytes .../EnumEvolveTests.multiOperations.4.CAT | Bin 0 -> 1006 bytes .../amqp/EnumEvolveTests.multiOperations.4.D | Bin 0 -> 1004 bytes .../amqp/EnumEvolveTests.multiOperations.4.F | Bin 0 -> 1004 bytes .../amqp/EnumEvolveTests.multiOperations.4.G | Bin 0 -> 1004 bytes .../EnumEvolveTests.multiOperations.5.APPLE | Bin 0 -> 1115 bytes .../amqp/EnumEvolveTests.multiOperations.5.B | Bin 0 -> 1111 bytes .../EnumEvolveTests.multiOperations.5.BBB | Bin 0 -> 1113 bytes .../EnumEvolveTests.multiOperations.5.CAT | Bin 0 -> 1113 bytes .../amqp/EnumEvolveTests.multiOperations.5.D | Bin 0 -> 1111 bytes .../EnumEvolveTests.multiOperations.5.FLUMP | Bin 0 -> 1115 bytes .../amqp/EnumEvolveTests.multiOperations.5.G | Bin 0 -> 1111 bytes 49 files changed, 635 insertions(+), 63 deletions(-) create mode 100644 node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.C create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.D create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.E create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerWithNoRule create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.AA create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.B create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.C create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.AA create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.BB create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.C create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.AA create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.C create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.XX create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.A create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.B create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.C create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.D create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.A create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.B create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.C create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.D create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.E create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.A create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.B create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.BOB create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.C create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.D create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.A create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.B create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.BOB create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.CAT create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.D create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.F create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.G create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.APPLE create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.B create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.BBB create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.CAT create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.D create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.FLUMP create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.G diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializer.kt index d4596c5ec0..e70b55d8fc 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializer.kt @@ -35,5 +35,5 @@ interface AMQPSerializer { /** * Read the given object from the input. The envelope is provided in case the schema is required. */ - fun readObject(obj: Any, schema: SerializationSchemas, input: DeserializationInput): T + fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput): T } \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt new file mode 100644 index 0000000000..f8579fc21e --- /dev/null +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt @@ -0,0 +1,89 @@ +package net.corda.nodeapi.internal.serialization.amqp + +import org.apache.qpid.proton.amqp.Symbol +import org.apache.qpid.proton.codec.Data +import java.io.NotSerializableException +import java.lang.reflect.Type +import java.util.* + +/** + * @property transforms + * + */ +class EnumEvolutionSerializer( + clazz: Type, + factory: SerializerFactory, + private val conversions : Map, + private val ordinals : Map) : AMQPSerializer { + override val type: Type = clazz + override val typeDescriptor = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}")!! + + companion object { + fun MutableMap.mapInPlace(f : (String)->String) { + val i = this.iterator() + while(i.hasNext()) { + val curr = (i.next()) + curr.setValue(f(curr.value)) + } + } + + /** + * @param old + * @param new + */ + fun make(old: RestrictedType, + new: AMQPSerializer, + factory: SerializerFactory, + transformsFromBlob: TransformsSchema): AMQPSerializer { + + val wireTransforms = transformsFromBlob.types[old.name] + val localTransforms = TransformsSchema.get(old.name, factory) + val transforms = if (wireTransforms?.size ?: -1 > localTransforms.size) wireTransforms!! else localTransforms + + // if either of these isn't of the cast type then something has gone terribly wrong + // elsewhere in the code + @Suppress("UNCHECKED_CAST") + val defaultRules = transforms[TransformTypes.EnumDefault] as? List + @Suppress("UNCHECKED_CAST") + val renameRules = transforms[TransformTypes.Rename] as? List + + // What values exist on the enum as it exists on the class path + val localVals = new.type.asClass()!!.enumConstants.map { it.toString() } + + var conversions : MutableMap = new.type.asClass()!!.enumConstants.map { it.toString() } + .union(defaultRules?.map { it.new }?.toSet() ?: emptySet()) + .union(renameRules?.map { it.to } ?: emptySet()) + .associateBy({ it }, { it }) + .toMutableMap() + + val rules : MutableMap = mutableMapOf() + rules.putAll(defaultRules?.associateBy({ it.new }, { it.old }) ?: emptyMap()) + rules.putAll(renameRules?.associateBy({ it.to }, { it.from }) ?: emptyMap()) + + while (conversions.filter { it.value !in localVals }.isNotEmpty()) { + conversions.mapInPlace { rules[it] ?: it } + } + + var idx = 0 + return EnumEvolutionSerializer(new.type, factory, conversions, localVals.associateBy( {it}, { idx++ })) + } + } + + override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput): Any { + var enumName = (obj as List<*>)[0] as String + + if (enumName !in conversions) { + throw NotSerializableException ("No rule to evolve enum constant $type::$enumName") + } + + return type.asClass()!!.enumConstants[ordinals[conversions[enumName]]!!] + } + + override fun writeClassInfo(output: SerializationOutput) { + throw IllegalAccessException("It should be impossible to write an evolution serializer") + } + + override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) { + throw IllegalAccessException("It should be impossible to write an evolution serializer") + } +} \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt index d310f5a6bb..764f0b5458 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt @@ -50,7 +50,7 @@ open class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) { return serializersByDescriptor.computeIfAbsent(typeNotation.descriptor.name!!) { when (typeNotation) { is CompositeType -> EvolutionSerializer.make(typeNotation, newSerializer as ObjectSerializer, this) - is RestrictedType -> throw NotSerializableException("Enum evolution is not currently supported") + is RestrictedType -> EnumEvolutionSerializer.make(typeNotation, newSerializer, this, transforms) } } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt index 5bb6fc05d5..6fd1e4a95f 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt @@ -27,14 +27,62 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType Unknown({ UnknownTransform() }) { override fun getDescriptor(): Any = DESCRIPTOR override fun getDescribed(): Any = ordinal + override fun validate(l : List, constants: Set) { } }, EnumDefault({ a -> EnumDefaultSchemaTransform((a as CordaSerializationTransformEnumDefault).old, a.new) }) { override fun getDescriptor(): Any = DESCRIPTOR override fun getDescribed(): Any = ordinal + + /** + * Validates a list of constant additions to an enumerated types, to be valid a default (the value + * that should be used when we cannot use the new value) must refer to a constant that exists in the + * enum class as it exists now and it cannot refer to itself. + * + * @param l The list of transforms representing new constants and the mapping from that constant to an + * existing value + * @param constants The list of enum constants on the type the transforms are being applied to + */ + override fun validate(l : List, constants: Set) { + @Suppress("UNCHECKED_CAST") (l as List).forEach { + if (!constants.contains(it.old)) { + throw NotSerializableException( + "Enum extension defaults must be to a valid constant: ${it.new} -> ${it.old}. ${it.old} " + + "doesn't exist in constant set $constants") + } + + if (it.old == it.new) { + throw NotSerializableException("Enum extension ${it.new} cannot default to itself") + } + } + } }, Rename({ a -> RenameSchemaTransform((a as CordaSerializationTransformRename).from, a.to) }) { override fun getDescriptor(): Any = DESCRIPTOR override fun getDescribed(): Any = ordinal + + /** + * Validates a list of rename transforms is valid. Such a list isn't valid if we detect a cyclic chain, + * that is a constant is renamed to something that used to exist in the enum. We do this for both + * the same constant (i.e. C -> D -> C) and multiple constants (C->D, B->C) + * + * @param l The list of transforms representing the renamed constants and the mapping between their new + * and old values + * @param constants The list of enum constants on the type the transforms are being applied to + */ + override fun validate(l : List, constants: Set) { + object : Any() { + val from : MutableSet = mutableSetOf() + val to : MutableSet = mutableSetOf() }.apply { + @Suppress("UNCHECKED_CAST") (l as List).forEach { rename -> + if (rename.to in this.to || rename.from in this.from) { + throw NotSerializableException("Cyclic renames are not allowed (${rename.to})") + } + + this.to.add(rename.from) + this.from.add(rename.to) + } + } + } } // Transform used to test the unknown handler, leave this at as the final constant, uncomment // when regenerating test cases - if Java had a pre-processor this would be much neater @@ -45,6 +93,8 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType //} ; + abstract fun validate(l: List, constants: Set) + companion object : DescribedTypeConstructor { val DESCRIPTOR = AMQPDescriptorRegistry.TRANSFORM_ELEMENT_KEY.amqpDescriptor diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt index 974de134b1..a8409a64c3 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt @@ -148,6 +148,8 @@ class EnumDefaultSchemaTransform(val old: String, val new: String) : Transform() * * @property from the name at time of change of the property * @property to the new name of the property + * + * */ class RenameSchemaTransform(val from: String, val to: String) : Transform() { companion object : DescribedTypeConstructor { @@ -192,6 +194,61 @@ data class TransformsSchema(val types: Map { val DESCRIPTOR = AMQPDescriptorRegistry.TRANSFORM_SCHEMA.amqpDescriptor + /** + * Takes a class name and either returns a cached instance of the TransformSet for it or, on a cache miss, + * instantiates the transform set before inserting into the cache and returning it. + * + * @param name fully qualified class name to lookup transforms for + * @param sf the [SerializerFactory] building this transform set. Needed as each can define it's own + * class loader and this dictates which classes we can and cannot see + */ + fun get(name: String, sf: SerializerFactory) = sf.transformsCache.computeIfAbsent(name) { + val transforms = EnumMap>(TransformTypes::class.java) + try { + val clazz = sf.classloader.loadClass(name) + + supportedTransforms.forEach { transform -> + clazz.getAnnotation(transform.type)?.let { list -> + transform.getAnnotations(list).forEach { annotation -> + val t = transform.enum.build(annotation) + + // we're explicitly rejecting repeated annotations, whilst it's fine and we'd just + // ignore them it feels like a good thing to alert the user to since this is + // more than likely a typo in their code so best make it an actual error + if (transforms.computeIfAbsent(transform.enum) { mutableListOf() } + .filter { t == it } + .isNotEmpty()) { + throw NotSerializableException( + "Repeated unique transformation annotation of type ${t.name}") + } + + transforms[transform.enum]!!.add(t) + } + + transform.enum.validate( + transforms[transform.enum] ?: emptyList(), + clazz.enumConstants.map { it.toString() }.toSet()) + } + } + } catch (_: ClassNotFoundException) { + // if we can't load the class we'll end up caching an empty list which is fine as that + // list, on lookup, won't be included in the schema because it's empty + } + + transforms + } + + private fun getAndAdd( + type: String, + sf: SerializerFactory, + map: MutableMap>>) { + get(type, sf).apply { + if (isNotEmpty()) { + map[type] = this + } + } + } + /** * Prepare a schema for encoding, takes all of the types being transmitted and inspects each * one for any transform annotations. If there are any build up a set that can be @@ -200,48 +257,10 @@ data class TransformsSchema(val types: Map>>() - - schema.types.forEach { type -> - sf.transformsCache.computeIfAbsent(type.name) { - val transforms = EnumMap>(TransformTypes::class.java) - try { - val clazz = sf.classloader.loadClass(type.name) - - supportedTransforms.forEach { transform -> - clazz.getAnnotation(transform.type)?.let { list -> - transform.getAnnotations(list).forEach { annotation -> - val t = transform.enum.build(annotation) - - // we're explicitly rejecting repeated annotations, whilst it's fine and we'd just - // ignore them it feels like a good thing to alert the user to since this is - // more than likely a typo in their code so best make it an actual error - if (transforms.computeIfAbsent(transform.enum) { mutableListOf() } - .filter { t == it }.isNotEmpty()) { - throw NotSerializableException( - "Repeated unique transformation annotation of type ${t.name}") - } - - transforms[transform.enum]!!.add(t) - } - } - } - } catch (_: ClassNotFoundException) { - // if we can't load the class we'll end up caching an empty list which is fine as that - // list, on lookup, won't be included in the schema because it's empty - } - - transforms - }.apply { - if (isNotEmpty()) { - rtn[type.name] = this - } - } - } - - return TransformsSchema(rtn) - } + fun build(schema: Schema, sf: SerializerFactory) = TransformsSchema( + mutableMapOf>>().apply { + schema.types.forEach { type -> getAndAdd(type.name, sf, this) } + }) override fun getTypeClass(): Class<*> = TransformsSchema::class.java @@ -286,6 +305,7 @@ data class TransformsSchema(val types: Map(File(path.toURI()).readBytes())) + + assertEquals (DeserializeNewerSetToUnknown.C, obj.e) + } + + // Version of the class as it was serialised + // + // @CordaSerializationTransformEnumDefaults ( + // CordaSerializationTransformEnumDefault("D", "C"), + // CordaSerializationTransformEnumDefault("E", "D")) + // enum class DeserializeNewerSetToUnknown2 { A, B, C, D, E } + // + // Version of the class as it's used in the test + enum class DeserializeNewerSetToUnknown2 { A, B, C } + + @Test + fun deserialiseNewerSetToUnknown2() { + val resource = "${this.javaClass.simpleName}.${testName()}" + val sf = testDefaultFactory() + + data class C(val e: DeserializeNewerSetToUnknown2) + + // Uncomment to re-generate test files + // val so = SerializationOutput(sf) + // File(URI("$localPath/$resource.C")).writeBytes(so.serialize(C(DeserializeNewerSetToUnknown2.C)).bytes) + // File(URI("$localPath/$resource.D")).writeBytes(so.serialize(C(DeserializeNewerSetToUnknown2.D)).bytes) + // File(URI("$localPath/$resource.E")).writeBytes(so.serialize(C(DeserializeNewerSetToUnknown2.E)).bytes) + + val path1 = EvolvabilityTests::class.java.getResource("$resource.C") + val path2 = EvolvabilityTests::class.java.getResource("$resource.D") + val path3 = EvolvabilityTests::class.java.getResource("$resource.E") + + // C will just work + val obj1 = DeserializationInput(sf).deserialize(SerializedBytes(File(path1.toURI()).readBytes())) + // D will transform directly to C + val obj2 = DeserializationInput(sf).deserialize(SerializedBytes(File(path2.toURI()).readBytes())) + // E will have to transform from E -> D -> C to work, so this should exercise that part + // of the evolution code + val obj3 = DeserializationInput(sf).deserialize(SerializedBytes(File(path3.toURI()).readBytes())) + + assertEquals (DeserializeNewerSetToUnknown2.C, obj1.e) + assertEquals (DeserializeNewerSetToUnknown2.C, obj2.e) + assertEquals (DeserializeNewerSetToUnknown2.C, obj3.e) + } + + + // Version of the class as it was serialised, evolve rule purposfuly not included to + // test failure conditions + // + // enum class DeserializeNewerWithNoRule { A, B, C, D } + // + // Class as it exists for the test + enum class DeserializeNewerWithNoRule { A, B, C } + + // Lets test to see if they forgot to provide an upgrade rule + @Test + fun deserialiseNewerWithNoRule() { + val resource = "${this.javaClass.simpleName}.${testName()}" + val sf = testDefaultFactory() + + data class C(val e: DeserializeNewerWithNoRule) + + // Uncomment to re-generate test files + // val so = SerializationOutput(sf) + // File(URI("$localPath/$resource")).writeBytes(so.serialize(C(DeserializeNewerWithNoRule.D)).bytes) + + val path = EvolvabilityTests::class.java.getResource(resource) + Assertions.assertThatThrownBy { - DeserializationInput(sf).deserialize(SerializedBytes( - File(EvolvabilityTests::class.java.getResource(resource).toURI()).readBytes())) + DeserializationInput(sf).deserialize(SerializedBytes(File(path.toURI()).readBytes())) }.isInstanceOf(NotSerializableException::class.java) } + + // Version of class as it was serialized, at some point in the "future" several + // values have been renamed + // + // First Change + // A -> AA + // @CordaSerializationTransformRenames ( + // CordaSerializationTransformRename(from ="A", to = "AA") + // ) + // enum class DeserializeWithRename { AA, B, C } + // + // Second Change + // B -> BB + // @CordaSerializationTransformRenames ( + // CordaSerializationTransformRename(from = "B", to = "BB"), + // CordaSerializationTransformRename(from = "A", to = "AA") + // ) + // enum class DeserializeWithRename { AA, BB, C } + // + // Third Change + // BB -> XX + // @CordaSerializationTransformRenames ( + // CordaSerializationTransformRename(from = "B", to = "BB"), + // CordaSerializationTransformRename(from = "BB", to = "XX"), + // CordaSerializationTransformRename(from = "A", to = "AA") + // ) + // enum class DeserializeWithRename { AA, XX, C } + // + // Finally, the version we're using to test with + enum class DeserializeWithRename { A, B, C } + + @Test + fun deserializeWithRename() { + val resource = "${this.javaClass.simpleName}.${testName()}" + val sf = testDefaultFactory() + + data class C(val e: DeserializeWithRename) + + // Uncomment to re-generate test files, needs to be done in three stages + val so = SerializationOutput(sf) + // First change + // File(URI("$localPath/$resource.1.AA")).writeBytes(so.serialize(C(DeserializeWithRename.AA)).bytes) + // File(URI("$localPath/$resource.1.B")).writeBytes(so.serialize(C(DeserializeWithRename.B)).bytes) + // File(URI("$localPath/$resource.1.C")).writeBytes(so.serialize(C(DeserializeWithRename.C)).bytes) + // Second change + // File(URI("$localPath/$resource.2.AA")).writeBytes(so.serialize(C(DeserializeWithRename.AA)).bytes) + // File(URI("$localPath/$resource.2.BB")).writeBytes(so.serialize(C(DeserializeWithRename.BB)).bytes) + // File(URI("$localPath/$resource.2.C")).writeBytes(so.serialize(C(DeserializeWithRename.C)).bytes) + // Third change + // File(URI("$localPath/$resource.3.AA")).writeBytes(so.serialize(C(DeserializeWithRename.AA)).bytes) + // File(URI("$localPath/$resource.3.XX")).writeBytes(so.serialize(C(DeserializeWithRename.XX)).bytes) + // File(URI("$localPath/$resource.3.C")).writeBytes(so.serialize(C(DeserializeWithRename.C)).bytes) + + // + // Test we can deserialize instances of the class after its first transformation + // + val path1_AA = EvolvabilityTests::class.java.getResource("$resource.1.AA") + val path1_B = EvolvabilityTests::class.java.getResource("$resource.1.B") + val path1_C = EvolvabilityTests::class.java.getResource("$resource.1.C") + + val obj1_AA = DeserializationInput(sf).deserialize(SerializedBytes(File(path1_AA.toURI()).readBytes())) + val obj1_B = DeserializationInput(sf).deserialize(SerializedBytes(File(path1_B.toURI()).readBytes())) + val obj1_C = DeserializationInput(sf).deserialize(SerializedBytes(File(path1_C.toURI()).readBytes())) + + assertEquals(DeserializeWithRename.A, obj1_AA.e) + assertEquals(DeserializeWithRename.B, obj1_B.e) + assertEquals(DeserializeWithRename.C, obj1_C.e) + + // + // Test we can deserialize instances of the class after its second transformation + // + val path2_AA = EvolvabilityTests::class.java.getResource("$resource.2.AA") + val path2_BB = EvolvabilityTests::class.java.getResource("$resource.2.BB") + val path2_C = EvolvabilityTests::class.java.getResource("$resource.2.C") + + val obj2_AA = DeserializationInput(sf).deserialize(SerializedBytes(File(path2_AA.toURI()).readBytes())) + val obj2_BB = DeserializationInput(sf).deserialize(SerializedBytes(File(path2_BB.toURI()).readBytes())) + val obj2_C = DeserializationInput(sf).deserialize(SerializedBytes(File(path2_C.toURI()).readBytes())) + + assertEquals(DeserializeWithRename.A, obj2_AA.e) + assertEquals(DeserializeWithRename.B, obj2_BB.e) + assertEquals(DeserializeWithRename.C, obj2_C.e) + + // + // Test we can deserialize instances of the class after its third transformation + // + val path3_AA = EvolvabilityTests::class.java.getResource("$resource.3.AA") + val path3_XX = EvolvabilityTests::class.java.getResource("$resource.3.XX") + val path3_C = EvolvabilityTests::class.java.getResource("$resource.3.C") + + val obj3_AA = DeserializationInput(sf).deserialize(SerializedBytes(File(path3_AA.toURI()).readBytes())) + val obj3_XX = DeserializationInput(sf).deserialize(SerializedBytes(File(path3_XX.toURI()).readBytes())) + val obj3_C = DeserializationInput(sf).deserialize(SerializedBytes(File(path3_C.toURI()).readBytes())) + + assertEquals(DeserializeWithRename.A, obj3_AA.e) + assertEquals(DeserializeWithRename.B, obj3_XX.e) + assertEquals(DeserializeWithRename.C, obj3_C.e) + } + + // The origional version of the enum, what we'll be eventually deserialising into + // enum class MultiOperations { A, B, C } + // + // First alteration, add D + // @CordaSerializationTransformEnumDefault(old = "C", new = "D") + // enum class MultiOperations { A, B, C, D } + // + // Second, add E + // @CordaSerializationTransformEnumDefaults( + // CordaSerializationTransformEnumDefault(old = "C", new = "D"), + // CordaSerializationTransformEnumDefault(old = "D", new = "E") + // ) + // enum class MultiOperations { A, B, C, D, E } + // + // Third, Rename E to BOB + // @CordaSerializationTransformEnumDefaults( + // CordaSerializationTransformEnumDefault(old = "C", new = "D"), + // CordaSerializationTransformEnumDefault(old = "D", new = "E") + // ) + // @CordaSerializationTransformRename(to = "BOB", from = "E") + // enum class MultiOperations { A, B, C, D, BOB } + // + // Fourth, Rename C to CAT, ADD F and G + // @CordaSerializationTransformEnumDefaults( + // CordaSerializationTransformEnumDefault(old = "F", new = "G"), + // CordaSerializationTransformEnumDefault(old = "BOB", new = "F"), + // CordaSerializationTransformEnumDefault(old = "D", new = "E"), + // CordaSerializationTransformEnumDefault(old = "C", new = "D") + // ) + // @CordaSerializationTransformRenames ( + // CordaSerializationTransformRename(to = "CAT", from = "C"), + // CordaSerializationTransformRename(to = "BOB", from = "E") + // ) + // enum class MultiOperations { A, B, CAT, D, BOB, F, G} + // + // Fifth, Rename F to FLUMP, Rename BOB to BBB, Rename A to APPLE + // @CordaSerializationTransformEnumDefaults( + // CordaSerializationTransformEnumDefault(old = "F", new = "G"), + // CordaSerializationTransformEnumDefault(old = "BOB", new = "F"), + // CordaSerializationTransformEnumDefault(old = "D", new = "E"), + // CordaSerializationTransformEnumDefault(old = "C", new = "D") + // ) + // @CordaSerializationTransformRenames ( + // CordaSerializationTransformRename(to = "APPLE", from = "A"), + // CordaSerializationTransformRename(to = "BBB", from = "BOB"), + // CordaSerializationTransformRename(to = "FLUMP", from = "F"), + // CordaSerializationTransformRename(to = "CAT", from = "C"), + // CordaSerializationTransformRename(to = "BOB", from = "E") + // ) + // enum class MultiOperations { APPLE, B, CAT, D, BBB, FLUMP, G} + // + // Finally, the original version of teh class that we're going to be testing with + enum class MultiOperations { A, B, C } + + @Test + fun multiOperations() { + val resource = "${this.javaClass.simpleName}.${testName()}" + val sf = testDefaultFactory() + + data class C(val e: MultiOperations) + + // Uncomment to re-generate test files, needs to be done in three stages + val so = SerializationOutput(sf) + // First change + // File(URI("$localPath/$resource.1.A")).writeBytes(so.serialize(C(MultiOperations.A)).bytes) + // File(URI("$localPath/$resource.1.B")).writeBytes(so.serialize(C(MultiOperations.B)).bytes) + // File(URI("$localPath/$resource.1.C")).writeBytes(so.serialize(C(MultiOperations.C)).bytes) + // File(URI("$localPath/$resource.1.D")).writeBytes(so.serialize(C(MultiOperations.D)).bytes) + // Second change + // File(URI("$localPath/$resource.2.A")).writeBytes(so.serialize(C(MultiOperations.A)).bytes) + // File(URI("$localPath/$resource.2.B")).writeBytes(so.serialize(C(MultiOperations.B)).bytes) + // File(URI("$localPath/$resource.2.C")).writeBytes(so.serialize(C(MultiOperations.C)).bytes) + // File(URI("$localPath/$resource.2.D")).writeBytes(so.serialize(C(MultiOperations.D)).bytes) + // File(URI("$localPath/$resource.2.E")).writeBytes(so.serialize(C(MultiOperations.E)).bytes) + // Third change + // File(URI("$localPath/$resource.3.A")).writeBytes(so.serialize(C(MultiOperations.A)).bytes) + // File(URI("$localPath/$resource.3.B")).writeBytes(so.serialize(C(MultiOperations.B)).bytes) + // File(URI("$localPath/$resource.3.C")).writeBytes(so.serialize(C(MultiOperations.C)).bytes) + // File(URI("$localPath/$resource.3.D")).writeBytes(so.serialize(C(MultiOperations.D)).bytes) + // File(URI("$localPath/$resource.3.BOB")).writeBytes(so.serialize(C(MultiOperations.BOB)).bytes) + // Fourth change + // File(URI("$localPath/$resource.4.A")).writeBytes(so.serialize(C(MultiOperations.A)).bytes) + // File(URI("$localPath/$resource.4.B")).writeBytes(so.serialize(C(MultiOperations.B)).bytes) + // File(URI("$localPath/$resource.4.CAT")).writeBytes(so.serialize(C(MultiOperations.CAT)).bytes) + // File(URI("$localPath/$resource.4.D")).writeBytes(so.serialize(C(MultiOperations.D)).bytes) + // File(URI("$localPath/$resource.4.BOB")).writeBytes(so.serialize(C(MultiOperations.BOB)).bytes) + // File(URI("$localPath/$resource.4.F")).writeBytes(so.serialize(C(MultiOperations.F)).bytes) + // File(URI("$localPath/$resource.4.G")).writeBytes(so.serialize(C(MultiOperations.G)).bytes) + // Fifth change - { APPLE, B, CAT, D, BBB, FLUMP, G} + // File(URI("$localPath/$resource.5.APPLE")).writeBytes(so.serialize(C(MultiOperations.APPLE)).bytes) + // File(URI("$localPath/$resource.5.B")).writeBytes(so.serialize(C(MultiOperations.B)).bytes) + // File(URI("$localPath/$resource.5.CAT")).writeBytes(so.serialize(C(MultiOperations.CAT)).bytes) + // File(URI("$localPath/$resource.5.D")).writeBytes(so.serialize(C(MultiOperations.D)).bytes) + // File(URI("$localPath/$resource.5.BBB")).writeBytes(so.serialize(C(MultiOperations.BBB)).bytes) + // File(URI("$localPath/$resource.5.FLUMP")).writeBytes(so.serialize(C(MultiOperations.FLUMP)).bytes) + // File(URI("$localPath/$resource.5.G")).writeBytes(so.serialize(C(MultiOperations.G)).bytes) + + val stage1Resources = listOf( + Pair("$resource.1.A", MultiOperations.A), + Pair("$resource.1.B", MultiOperations.B), + Pair("$resource.1.C", MultiOperations.C), + Pair("$resource.1.D", MultiOperations.C)) + + val stage2Resources = listOf( + Pair("$resource.2.A", MultiOperations.A), + Pair("$resource.2.B", MultiOperations.B), + Pair("$resource.2.C", MultiOperations.C), + Pair("$resource.2.D", MultiOperations.C), + Pair("$resource.2.E", MultiOperations.C)) + + val stage3Resources = listOf( + Pair("$resource.3.A", MultiOperations.A), + Pair("$resource.3.B", MultiOperations.B), + Pair("$resource.3.C", MultiOperations.C), + Pair("$resource.3.D", MultiOperations.C), + Pair("$resource.3.BOB", MultiOperations.C)) + + val stage4Resources = listOf( + Pair("$resource.4.A", MultiOperations.A), + Pair("$resource.4.B", MultiOperations.B), + Pair("$resource.4.CAT", MultiOperations.C), + Pair("$resource.4.D", MultiOperations.C), + Pair("$resource.4.BOB", MultiOperations.C), + Pair("$resource.4.F", MultiOperations.C), + Pair("$resource.4.G", MultiOperations.C)) + + val stage5Resources = listOf( + Pair("$resource.5.APPLE", MultiOperations.A), + Pair("$resource.5.B", MultiOperations.B), + Pair("$resource.5.CAT", MultiOperations.C), + Pair("$resource.5.D", MultiOperations.C), + Pair("$resource.5.BBB", MultiOperations.C), + Pair("$resource.5.FLUMP", MultiOperations.C), + Pair("$resource.5.G", MultiOperations.C)) + + fun load(l: List>) = l.map { + Pair (DeserializationInput(sf).deserialize(SerializedBytes( + File(EvolvabilityTests::class.java.getResource(it.first).toURI()).readBytes())), it.second) + } + + load (stage1Resources).forEach { assertEquals(it.second, it.first.e) } + load (stage2Resources).forEach { assertEquals(it.second, it.first.e) } + load (stage3Resources).forEach { assertEquals(it.second, it.first.e) } + load (stage4Resources).forEach { assertEquals(it.second, it.first.e) } + load (stage5Resources).forEach { assertEquals(it.second, it.first.e) } + } } diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolvabilityTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolvabilityTests.kt index 173e7fd87c..10a59e1414 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolvabilityTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolvabilityTests.kt @@ -2,6 +2,7 @@ package net.corda.nodeapi.internal.serialization.amqp import net.corda.core.serialization.DeprecatedConstructorForDeserialization import net.corda.core.serialization.SerializedBytes +import net.corda.testing.common.internal.ProjectStructure.projectRootDir import org.junit.Test import java.io.File import java.io.NotSerializableException @@ -18,7 +19,8 @@ import kotlin.test.assertEquals // 5. Comment back out the generation code and uncomment the actual test class EvolvabilityTests { // When regenerating the test files this needs to be set to the file system location of the resource files - var localPath = "file://////corda/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp" + var localPath = projectRootDir.toUri().resolve( + "node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp") @Test fun simpleOrderSwapSameType() { diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.C new file mode 100644 index 0000000000000000000000000000000000000000..cced4f8de74148db910f0c9c62fb86c1a99ba837 GIT binary patch literal 873 zcmcIi-AV#M7@gVmhqB9_Agmi+(UW1yv= zv9E$vF0FEKM?q9$YU|(jQA*`+#|j>Be54UM1s)}VKxr%B=jfLrBNK^ z`*cZ)Xp>GUzoM}lcGwdOr>vB(TUh%s<$>{+hAkOEU6hi8tbkP9{LiKH?Q*upCAKWP zrWG^tGqX`S3yYNRMX^>)4(7KFTkGT6)H8SHzJL&)oCeS1_@|8hSot!2jQh4 z+E)S6xwOi`9R;Put+s%9&}Ve$VwcA(Y|h!WCdj6=6^2jZUEG$yK7sXmJIhfxzY{|Q{F3QTR+P5v>VFIcNc$9$Z0+texBVaiJVF8ad sv^9S-Hadm*)5T2Aj8YxHepN{r0p^oa}{KBvb)%27--YkW`Ed~cRok(MdF3` zK76^8x_h0dSs8Q2{Tff=Lt~9GCN`ONMgP zUUsLgXg8jw7qUC@dp(WdH(!Tbhq65k{K3_2bH5wRmg%OmH9pT#us^9-j&tCg9D#LH zIJQ?cJ?I&!s^&HV64`>$6-Qi1mJ6Dog5{hhd`~6M1fuEV3K6kR$tFuSY{CjzG#2d3 zRIrF`Sw7?PAlL&^u8wO8GIjU2i2Y;4eK{h**bgku(;wdd vu`p3?!V76}J5sQIW`3St zVs2r9o@-udu4`F-PFZS5YH>-iN=hnBQEGT*Nk&j=USe*linD_&+!p2oYD~oV(cwTg zBU}^9fjIVsjHwHQDRZ3*HrKg2I5;}NZDKocmW?LXIJhok$;m7(f!l;05V#`I;ea(W zTod~N4set%WHdk$14c8W(?Ui=G$H4Oj7D%F&VwyXH1XI$9Yhl14q-YVi-s%ci9G&3KV>@t`jV9JOxGrSL$t*5`+k_qvxZ=>^fHgB* z6Z-)UriDz7jtdzLki^(QvAmGc5KYK=A)^soi1T0z6HPpJPzRBOxI>r@$ReVR>wp0B OLN-VuSjgxIayS6udG(_J literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.C new file mode 100644 index 0000000000000000000000000000000000000000..33425ddb685acc272b5aefd28e6be315eb10e98a GIT binary patch literal 762 zcmYe!FG@*dWME)uIGO|`85kHZFfcGZ1~Ql#7AxhYmgpseR9IEHI$F9Ur)!&gmAd8_ z2Icz)_yifI+u9z`V?cU{kT<3z#b*>H$j!tl!*bba!qlq;Rt_xXmGK)*#HlYUut~hi!V9gBI z#D0K-X(5xN<3dIQBr$eiEITb^G(;0}UdU(!7venF!bB5~9n?W2A?^^S1G0!{<2oR~ PypRo&2o^Frf*cM2=aKcL literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.AA b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.AA new file mode 100644 index 0000000000000000000000000000000000000000..4f75773756defb3f45cade9196fe2f1e9d44f46a GIT binary patch literal 792 zcmYe!FG@*dWME)uIGO|`85kHZFfcHK1eh5XE9Iq@=p}dq60Deo8lQBTw&=7Qpe7;kjc?81Yr>q&?3e+ zP#YN^0~t(kN3b6F$+|EUZo6JyeoAU$L8e}2UP)?EUSf`3acWU!VoqjNVo7Fxo?c>Z zVS%1&UTLmtS$wDojyocxFjPP-#Q4$SKsF;> z6U%`(_Jxe83xg?hoeMVCxjHyFI>BvXJ8+JTCe}E(E@a8cEG~iDgdPyMBGKW14KrL5 z`vDGclrCg6KofIvTF7XKBnFInM(2f$MsOj{gA15w;!LWDG`oFgcq0sueZ{`mj^ literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.BB b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.BB new file mode 100644 index 0000000000000000000000000000000000000000..521bf9ec2fb5712e1369d09c9d110e1c35e348e4 GIT binary patch literal 792 zcmYe!FG@*dWME)uIGO|`85kHZFfcHK1eh5XE9Iq@=p}dq60Deo8lQBTw&=7Qpe7;kjcp@gb{8L6VM{Y zH&7cH9|IXoa5>fkKUo)s!fn^f%TGy7EXdT$%qvMP%1g}AD^4xSOw7rwN-W9D&(llH zEiBM;%`44yEz8d-OASdaE-6+?Nrfp&4bLpe2ujUM%uQ8sc5sE;!hArDi5NdR9LPpE zo8>?p`$ERlg~61$&IOz6Tpb)7o#4)6J8+JTCe}E(E@a8cEG~iDgdPyMBGKW14KrL5 z`vDGMlsY;tWHdk%b8=e9Xow^RjCw}rg^WgUAw%xF3q#?S>*eLAq$U<*>SgAYq!#5R=I9lt7G);pWL71XWaj7TCFT|u z=(*;V=DL>U=ai*}q!yPHtE8mD6s3k|mShB_<|XE)syI8i!d<|8K#hqQFFG8^W`t{E zIS|LbkTG>(FlDZD!R9(w2M0$dxJ_&a&au(N8VA>fEIFCQC2*V20|HkZIvlWJhHGL! zz`?YT$Yg2waiqaKMHc zu8I8s2RKR>G8&+XMMNxQG(-{uMm?kRLPjIF5a+?YOf>P?!Bj*V;tpXt5QcCr*8u_M kg=~;iu#nMdA(Im#q`3|VBIJM)3z;G!;EqMr=m<*10AE!Fs{jB1 literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.C new file mode 100644 index 0000000000000000000000000000000000000000..5e90893cb41986fddc5bc11db303ce07eaa9c5ac GIT binary patch literal 820 zcmYe!FG@*dWME)uIGO|`85kHZFfcI70vXH@LYnJw%xF3q#?y>*eLAq$U<*>SgAYq!#5R=I9lt7G);pWL71XWaj7T zCFT|u=(*;V=DL>U=ai*}q!yPHtE8mD6s3k|mShB_<|XE)syI8i!fjzbpvFXu9~};4 zBb?20AdY<@W9q_S%3SAy&2_F04vtQ6=dm3)$3_!t99$Q&Yg2waiqaKMHc zu8I8s2QW$<9Tzehpov99EMzo95(7p(qw_*WBe)Rf!M#j0@!7#tL>l4_VLA|oa4y#Y k0p^8lkW{dc(P<%*6C$L!4hSOTfD)jT3U@53Mn{mB0parn+5i9m literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.A b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.A new file mode 100644 index 0000000000000000000000000000000000000000..c28d4809779174a1c05252023cecf33dea2f7a9c GIT binary patch literal 760 zcmb`F%Sr<=6ozxAH?&({Kq+p7Sgj}uh3Ryn6dj8)cv+@xl+?L(W?G~x@lAp+k}ll4 zb*WqN9ZW@1Iv@yk6AnNB$@ia}bi=qu0U`A8+)*b&@Pd%>rivVTS_@c;yHm%(#c6Bj z-imAelg>W%{Pv|y&ic3Yy2LQ&hUp6c^F{o4Fu)`t@9`wn zjO_5gZOoKTUN@CwX}UiF)r@2b*vd#v0oxhL7EsgD(&W)t@Q{=0?DLdekgKz`Ez6ah RC{KTf&2FfAd;uz;{RJ)J^H=}? literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.B b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.B new file mode 100644 index 0000000000000000000000000000000000000000..4f5e9ab81cbc80e43fdeef5fdfaae81b06e039e2 GIT binary patch literal 760 zcmb_a%Sr<=6wRH!&~E(!rMMAdwW25#rqhX1bS%o?W0|&5Qs>o~X_2nPKMDRwx^VB- zrEbN4FcnGZfFRgSxSV^Eb8gP6ESiD8b%ulF{_=Ol9CXm|5ybm$!4wcLi{6%7HF3tGoeI`Hu$ z2=A&ebgv*k3!<&XaS-+xjX35(%Hn`}IAJlT9v{<`hXJPkAi^XV`eYP(Bj&OsO)CD- zOL;qD@i!-_G)U7BGp(dpt?C zMt1n$5;LWf*OyANr1EPBsAeEbz*Yuo3fRs-wt$+3mL`wJf`^<`XUkJ|L9WhXTb3(1 RQJ!vx&2Fgrd;!X!{RJ}i^I8A^ literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.C new file mode 100644 index 0000000000000000000000000000000000000000..6fd1917bebb74f5d04da06c2a5de7470f5adec12 GIT binary patch literal 760 zcmb`F%}N6?5XUpyFSJ)*Kq+2?Sgj}uh3$5u6kUt5_;F0zD5?9^-EEPc#5W1PNP6(@ z)uUd;cQ6%6>4G5GOBnw1AAU2L>4tHS0z&BFxuaf$-~}P$O$9mhv=*=wcc+eni__N5 zy%pE`C!Kxj`Rz-aob_+(b%|ll$FKJ`#^)q*;%ImCXmsct-?iL^@)ZpMP1n#ILvi5a z2MF&fnB@xcvmn|Uj)SnrXv8rOQWgi)!wHKy_4t^kJPa`P2N5R0&?lqN8!?w9X;Sfr zUdr1Mi@!ZdrD+n)&dGJ-FT*k3pb^IQM` literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.D b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.D new file mode 100644 index 0000000000000000000000000000000000000000..2ca115091f61d9c20857ac53a92cc78618764afb GIT binary patch literal 760 zcmb`F%}N6?5XUpS{Xl#51(f1Nh}DXsP}sH`rRZ9e#gAj!MoHbT?rw|pB)&=TMbd+J zuO9U(zJsYqN*4sdUc&ItfAX8jOgD^s6c9oW&mDCl1TP2~Zz?d+(^|k%+?_fOE>2rJ z_l>yPKk4jK&u?GaIHJ2PumK>fwaNoO*mrQyvDG`hy6QVCa)k=#7}mk~As% zLoem+h{fNYq};TKe&3Yq#$TGVBmSXRBE83p-TSTMjMBIofW z)r@TOzfH`NPEIEkWl_zqE})W;8UnU5Qd7WoMzRG|wX`&OG#1?Cq%vEck_&QmHnwHC SVv5pqJ8X7C)#nRP1=?Rd9`jxR literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.A b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.A new file mode 100644 index 0000000000000000000000000000000000000000..434b43c42af94e004f5fe4dda370934f73682195 GIT binary patch literal 811 zcmb_a%T59@6z!ei5oOC47~-<=K|(YknE|@dAPhmm(lQijnCalmz`~WkQvH##aPNoc z(yg%=Q^G_O6WKJkr|0&ZlY9Lr9#cRFJv@)}i4eRXWS4beqo)JGQtYo8=fiL~oB30> z7LVH9GjG7-+VsM!*A<2>UT?xCSIe+>c^&(ss^|%i1%q47D_9cT{zk{rI`Hu=2=BVE zjEB5>%gc@t$08atI_H>+l*NJuIAJlT0l%jyj|8US-5e9K2+1-EmaNZ`G^vD(AmyDo zi@!KYrRfm!zpW0fzl3uX1JjgK!=eNx+yC>`-u6Wt$88vmf_g3NSim7N7w{xC8rkr_ zP0Ud@dDB!>#r6Co9A%(}gyRg Xmevc?ViT(8Awhd?88<(?>j2~vLyZGk literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.B b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.B new file mode 100644 index 0000000000000000000000000000000000000000..f216584cdf0704080d97b6b7d079c90cbf993ddc GIT binary patch literal 811 zcmb_a%T59@6z!ei5oOC47~-<=K|(YknE|@dAPhmm(lQijnCalmz`~WkQvH##aPNoc z(yg%=Q^G_O6WKJk=brYQlY9Lr9#cRFJv@)}i4eRXWS4beqo)JGQtYo8=fiL~oB30> z7LVH9GjG7-+VsM!*A<2>UT?xCSIe+>c^&(ss^|%i1%q47D_9a5eK0zf)`5?2L3r1N zWqNt_mX{qPjzu(Pbj~psDT@USaKd6v1Ab3a9tljtyE!Ie5t3yTELoo=X;KLnLCQOG z7JqS)O4A|ce_I_|e+lO(wlSPj!=eNx+yC>`-u6Wt$88v61@&6kv4BHlF5pROG_v7; zo0y|+^5#)d74`gF2}c>IA>lX!H6@&6pq7Nw3`8VU4Yap~Ql2t7QH^otO@AY_+yV56r4!BXt6E6#`Ea5nR& zZY>_QyJy~j$F=E&SFbA!TXnq&n_Ml!-sN@dkE)_4JQfUYbzQ-d(Ck}=V`&b2d;{TK z2b)}8z2#-cz_EzNjLtdcB4x3l0Zv%VX~6Gk$|HekcsIvHEJCu3f+g#-Buy&eB1m~> z&f>3{q|$VVVcY7^`inV7F)&RzH7rVCvi-lg+S_vx$8j5mQBbdi9RnO9a{*6M!^oQd zZDWqQ$(yF4D(d~Y5{@!bL&9-JYDzfCNG%Dc8Hq@!8fkC!Xzkeds=K+TQXiDN`R=Q- YElcZzX|V~_`_Pvup=GA|A+HUPPfmdYUH||9 literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.D b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.D new file mode 100644 index 0000000000000000000000000000000000000000..71b890bdef56632d7dd9f24f3f714cd157a523f4 GIT binary patch literal 811 zcmb_a%T59@6z!ei5oOC47~-<=K|(YknStp>gFJ$SrDZ76Fw?=AfrTr7rTQaf;oc9? zrCVb$ri6(mCbDU6&pquqC-?eMJf?sUdUzh`6Crp($S&)`Mo$NVrPyCH&WGV}HuI-$ zEgrQxXWaphYtxHvy{<59@p=)S@h(mL?*EeP+r zuuLzn-tw|-#IcCRjLtdcB4x3l0Zv%VX~6Gk$|HekcsIvHEJCu3f+g#-Buy&eB1n0A z&f+glQfWHG{BNs6>o4IP#lSqusbNt9ldb>xYHj->j^j3rMnSz6b}Zl!nG1N58jWoD z-zMg$o4k2cR7E{MSHe*SYDhTFKurlJ8OW1xnt_Ofs)6=akJgTJuR5E3D)m9Ro9n(R Y+p@G?7>`Y;o`(eO*)wi_=<5LF6I1&GU;qFB literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.E b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.E new file mode 100644 index 0000000000000000000000000000000000000000..cf15290a05c7320a732ff2f571a2126f75a08ed0 GIT binary patch literal 811 zcmb_a%T59@6z!ei5oOC47~-<=K|(YknE|@dAPhmm(lQijnCalmz`~WkQvH##aPNoc z(yg%=Q^G_O6WKJk=brYQlY9Lr9#cRFJv@)}i4eRXWS4beqo)JGQtYo8=fiL~oB30> z7LVH9GjG7-+VsM!*A<2>UT?xCSIe+>c^&(ss^|%i1%q47D_9apKWB6-tpgw5g7B^j z%k=WtLIBvse6x3^B#{v$Kxqv6B(a47X zZDNkP$(u(-Rn+ryB^+g-hJ@n`)Rb_Nfm#wyGZ2wbHPGJb(b{qDRd=&br9LQkbKO^E YTb9-f(_#~<=OICRZW%W}^mPF830ZXmVgLXD literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.A b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.A new file mode 100644 index 0000000000000000000000000000000000000000..26cbcc8f4ece2138fa2e3359f4e550e669740d4b GIT binary patch literal 857 zcmb_a%SyvQ6rGv0DQ#DRYZp@76k>g#K`7+WY>KsFqqv!jes1_i-xhRd0A?>UEi$J5xw5CHJ_?C=)=_zHkz@InGln;}V+an3k8bk%6o z&rCHto!m^K{+)9@Q}u3_DR7DB9FIJLshxIkKF)bEqENRB9mI9emmvJ$ z6%rn*?5#?NLR<-_F2RwfcwtK75c^6(Vh{V?Jx;x8sNmo>Qmk+mSlQIih)t3-X$3Ps z^@b6N7o4PJYL=KUu`TqMa2g{}G*#GTjY2{P|MN9i_GM|BZU_yTy~`^W&@5Wg#K`7+WY>KsFqqvtEwOc!p& zAJMH_rv)cACr3tHz^# zZmRj|j;Le|`RKj?>$4ZM;^ec3iuk^1 zL#7u8)?n)rZO%`oN3Jm62!-5rPtbqp^9aQOHEqN;iqmMYHHpe+B*X#Xv_-g2Z+Z*1 literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.BOB b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.BOB new file mode 100644 index 0000000000000000000000000000000000000000..87a4636599cc079fdec3c77f650aa529d428d2ca GIT binary patch literal 859 zcmb_a%SyvQ6rGv$VcV79+JzK1g;*bG5DH0}Y>KsFqqvtEwOc!p& zAJMH_rxhnQCX2T@%1?B-P%_ZMeB4}8!qtdqv5f?zh#|wJ+I}MO1tHsjb^+RL?wNoTP2}{xDxu3 zgzvmUqE}|GWjYY@au7NMN3QG!DTxE@$q9*F?74S1b;Cf${!JvC!NfPS(94KLk~C@h z6EAfK5sBxVq}f$X@xR12(O=e68G&M`#4f57659Wtul}MhQ&lxxXjIr+Wyu1nNlTua zq(Y;({BJi?nOzn`RaQk5Y818$kWS%t0qRn?Q-BN#cfUck&oofDC&1eD87+D9>3yEI zh6S0H2dvK4B-)ro#vqrNUxY&L+7NDj=<^lw05vSc*7Io8*{Vbg#K`7+WY>KsFqqvtEwOc!p& zAJMH_rv)cACr3tHz^# zZmRj|g#K`7+8Db|XO;&#%EG@6%58bn<9D}z5WUAPs0 zM7M687M$9kAlS`tIrrQ-_i)cBPCX0(0FTcue*u8607wQeB=EEukz5(g7)OVmnhbk| zsTQZ>n{m>+bFU|=-t964F7e#s;YoO~?Od2a(DrP#(+Zw3Ag+VH1mOp- zkmyy}Ta^xkxDv%4!HKWM?bTo2%hojA5E?Rjmsc#H*|ZY)SuQln z=6}1G#@wnHs<9fspH5+?1Q`_WlpvGB-4bL`xc3dJBPtmKKDsZ!`t${@*!lFKBED}r zkm-wnHQ2gDo3qGRS7|bSZL)()ef>)_tgwSfORw*QD(;`?yC1B|-wyOm4XR=L;C&8O4JVa4m@+5@Jbf~_psqYBn@N6 z;q>6NUmw*^dRk?2t~))|_O}(K(I667;6+glx%vPNCVh2qjQaatcUrxoyc~~#V$6Mb z>cdN4hWsX7@T`U`dCy{=9ax#H{i87=wVgPaXe|2>i>(XRdQJF`Mh62`U z7P%$c$QsVrR*0BWI)dN&CX;)Si9{mCUBsZAf>aDD2`JBFp{W=c>?FWg+QMKr0mVF3 zr{Zb?jCpMg_EJy>gBpYKFEpoeJTptq>G3VYOo|2|ck|x@Sru?G9gwSfORw*QD(;`?yC1B_-wxa~{sL3=ft^{}f#o&*O z3-`Kk)z&&hu5J`iW zaX39VHS5FrNl&Xx&ULq^I-_kxX*7rg=6F$5L!RD8{fVjekCD0Wcc;}W%FFQ>s0Ls< zJk{Z)FF}5jZg>{UlJ_junYiTnLuid`$@UNoJj;D=I52M@<3i z)QjAbWn>L!96LlzY0-k;`X-ZmktK;lq+L`nC@(-N29*?)=dsXK3=DQsV4T{*U^fND zJXNR3)f5=>+8FFDKphNf49dSypUUyfEZL{Ww+s_08i3r*js>zR;9@*xEqH0sE+%Dm z7`;H&7UG|8Yo{3BZlH$D#_|V+CiRTv7Y&{q&3;LNtOz)F20hD#7&H^h8FxOYB|d)u DK!z}6 literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.BOB b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.BOB new file mode 100644 index 0000000000000000000000000000000000000000..b741fceac9f439ca428245dc442d4307deabd70d GIT binary patch literal 1006 zcmb_b%SyvQ6wM@k*mfm|;8v;|A+%Z_RSHSkvZ;5hE~>4L5t2c9`jc%>VGdsufN5(g3E zaC&fR)Q9zxo?4xpYfewG{ViE;G)M)^@y6plYvUi^~eH|U0Eu`GGdVvWg*t~Z3HZ;6(RVBngz7{b6ZZR^HFmgkD5bM1?&J95;q zXOE!{Lll;sk&P_Phe6B<%S}mT_X}i`|I70v0s%|P5F?KP#NGeZ)t#?Pl_XhV8aZkT zSfgI#7AzyFIAdEOVoGTXe(Rh>?(-}uPx3qlG6t0tq+n1@Kn2?ErmSPIodBcM76v;B zDB{tnz@U}@BVHSW-4xWpV2?qC7wS_bnwbUr^!PTL(2@?w-RxK-D*`S>W7dL~ChcNe zW{1^OB&(_T=iAx|#R&*MXugMy=hnJouKZ4*Pd0bDQ|_xf+`yZ z&y;wo#EV~&{1)9ru{8NeW1Y#1t~Y?@&=M^d!I5j)q7O%wX|B?bn(CIe1CaaZm?vujE(BxNfLA8%VpwL2 z(eq?I5ud-U8Do6Aff^ExgwSfORw?Asv#6JF^?;2t(Sh@?Tp zIGi1v_Ugm>Nms8-&keV$I-_kxX*7rg7I4s;qEP2mjgNaL?KZMrEmTV8fv1d6_0LQlF*f$okeNVF7>ye~;6ITy? zCxj*pP*8Fw4zi6A9LJoXq{%wFUm#ojUmhnD2v|~v^h69G?)v8ug6j7fqfV&3{ROtOz)F20hD#7-+HOjJp`rW1l|& DPJS?G literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.F b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.F new file mode 100644 index 0000000000000000000000000000000000000000..b9bedc2502364bada4459213896dd518397395df GIT binary patch literal 1004 zcmb_b%SyvQ6wM@ULfe%ff?KI>gwSfORw*QD(;`?yC1B_-wxa~{GMPSbCAjl127hE+ zxYva%zrlZSQe~P}1;K8HnRCybbLZSU{U93HfaAE^rwh7r9C+q9;gxO#?qS1+NbV<$ z!^y#^RU6b!x_WthZg^eI4YyUbUMDh`v(?@|j zf+mbnT=a%6a*Pm0Q%+oLC_1}eAY1%j9;XlpSW<>q5(W@={#RFLzAjx+RE=qf)D*Bz zy%3iyqv$x}Ix%8Oix&LWH-+3wEJ-2~?V^f7X#vtOD5sztkA;S6Vz83}lhh^#yD2E) zX$DQMq`-vN!eDO!YGY7kQ0|5LR7z%M$v!>4Wtd381mtdZ%#&3C7m_h+!b_WWaav}Z z(eq?&A^!QcR*LcM25QJ`EPqgFP|sL?!Q{!&?3d)pih#v4=-VE|pfRgwSfORw*QD(;`?yC1B_-wxa~{vY9?`CAjl127hE+ zxYva%zrlZS5@niJ1;K8HnRCybbLZSU{a`q-0mpH-PZxCMIPlDI!Ykbf+{1ot2U^eboKJ&-0-@Z8*Zy=y-s8>#~Y8U$TxbZH?g$dF|zi9&a`qxc_NQN+Z34& zPjz_tOOW5B8=l3ofo$=Ad7MHZU`ZKbNf z^+H^-jH2U=>qLktEn4tf-xP8$u_TE|w2LYRr3FaCpqzqoJQftrX+i4b+g?SpJ~Upq{b(g2|Jk*)PeH6#E^K_ju8ap!}2;`0Y% CaxiWH literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.APPLE b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.APPLE new file mode 100644 index 0000000000000000000000000000000000000000..95b55e36de930ecf79bed3e3565b6439581c852e GIT binary patch literal 1115 zcmb_bO;6iE5cRI}A(9iK;@%2zL6|nB5u!r!N1T92WQ)30#cdmwV%2d%Y!bn#QvU&5 zdL8wT?1el05dH(Rfo>KEQl)aScHg|2H}huQ?GFzaF%0A9D1rY`QeT7y;iNuzHe=b8hOCu``KXqOSl_2?%GNg9v#-5xHU#z zg+kE@!?qtywJ2)Q`n@P!#RFA+6va&u0@Z+(_76B4#8#ZXKCUxxZvmOoOj7^= literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.B b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.B new file mode 100644 index 0000000000000000000000000000000000000000..f6aaf7d2ff87ef338bbd9666a6e5fddc2f78ed1c GIT binary patch literal 1111 zcmb_aO;6iE5cRI}A(B(os&^{X3&K!JqY8xN51fEVWQ!VvxGiBR7LJp~CQ&&d@ekm_ zb;KXp3wQV-{0C+O+AK6kNaeEHee-7C%$sd@`v;5|hH-YYkEdafTf->WcrlIZFDcKh zwqz_f*N3z7jp47q{?CnLZ;)>_7TfIi>Z-8FGalc|dP_UuX5hHG*?gGT;%<@@%GalH_sFIAPq)So8SWHF9h+11iun8@Zn^fgc5cRC{L6Z{#aWAU4RJf&-2!Sfu>pB6E$W}23aa+=Dv2dI;b`!w~iGKhW zt|R`)Ubw>#;Xg1Ns?D~f5)!?vcHg|2H~VIWe?zC^zz@f%ak{w9x7&rR zyrE`1>OYxpZuRER-$xIhz6)p7L2qX$j`#M|Hk{+h*X3mQW%4Wz_||5byglj!S#M6f zYYbh^d0I0{jFedCOp@KD3p260`c=o+$a}^3P>MbvR=`5VYR+`lQnxO|T^`dfyB6cG3S`Z4NmnR@Cx6_x!q=_h;bO9v1S1+}%zp!>cT1xH literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.CAT b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.CAT new file mode 100644 index 0000000000000000000000000000000000000000..27d9d766f71d37be47212de7082a1dd244c50e7b GIT binary patch literal 1113 zcmb_bO;6iE5cRI}QIZp)>YWO4L72}*s3?*@Z~|%~Ti~LqwE*?zd`hCiC zt0Ng7Tf3vBmFDQ+r@ys#>J9V#=6Z*HtJlRUdBo#iv;O8`_$hGQm8C5Feo}Md<_LLj zD43oTMN}zKRHC&9NxF=ONvtUT6d_RZR@yt}tRGu(n)5-*5-a0_m?iNqmdCx+V%;Bo z%TLd`{;-z}dBn3kTj-u8c^vflV9d!DJlj{=rdXse8P67+sHB4UQU=1I{eOM6ANS?k zw&N;|5}HEh(Tmb6%h)~?k~qti(o+kb+ng;f$||WWsuYS&7`A*Ms~TLUKwKbe8Z>ji zaUkm&D0w?THZ(}`To;o!HBiblTA$k?kPjLx)0;qQ3Yxh?zb@t5d1b$3-EFK}P*T;1 zi1W#{BHo%%m5*+RpD^4hkOnrV=oRtqN!)Y;oU)-Y{;7c0OdjbJ1rOa*`PGPutD?GA r#GDDGeV(!|2jV=eX?l3vigbN?7$>=RUklG_#l7*r{7lftbq4NVN#g!hc{kpk;v|A(hK&_syGmGjF!j8yqlV7{PW_BYkRb?)Es^N<8SO7d&7LMxzb_3wzh;tp78jOtiSdx+zlLeX(0=b4r@-_93ihn zfz%^Y=}^?6wFg1Eh!?72MR8k%K#5yv?|`#@Y{hBL2PsRej1OX##D7^H_fm^>fA=jv zJ?Z+xUNYnn&+=@(dy?dF(C33OC!6DdYosQF>A?MSDva literal 0 HcmV?d00001 diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.FLUMP b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.FLUMP new file mode 100644 index 0000000000000000000000000000000000000000..86b4ed8e6a5d0a910440392e45bb15de5edb975f GIT binary patch literal 1115 zcmb_bO>fgc5cRI}p(ZB;;!aidQsI^mB2-k#A8`U|B3r>!6}KhbwpJY{jon1$gv399 z3)c~UWG~$559xpCY#MDgrIC=@i?x39X5Q?Z+5T{R#E4-S-~N2TuVIkChEZtZ!8Cra zr#!d%lCj%)Ki%4HPd{GzZ$F%Qlf2ii_1VeZo~V%}9{-$;>IdO|;JDjcS$KNfaN_n9 zc@+x9R_9YUjEYK&q84q;Md?dCP!%hR>mmfI0V^FIaW;yrIL-MuWr>yXamCs# zf|9C6M0{WTR>U(Cs&eU?{FvcPfwZtWMX!kGcjBfS;4NDk&0z=1gPF)8*^c-D$^{r)iCfgc5cRGTM@>$s6?dwNON9$*8X-_5f7CG*iEI^vP;c9GOD!BHjon0WLgF9L zORppT$X>XYAHsiNHdNbfNhBn4S?#`gGjHb24n~s`MhwIF^5Ym!!ywm&QE~8M8s9f_ zUfKi6c+q<`+ujLhZ$1Uj4?g*yIk69~I-)yZCkFdOO=ie0JJ)({P47 zivkG~OX*P5q3s(%`UEdj#j4_06(S{W=c5zO#;Kj=C76*rjlx+L80o#aW4S!RD)}{To1@I4O*jM z`fdWGsezKW4`f$^B+v6Oxutw`gogZd`}~yQPJwi>IYqCFhxg*97vYp$jqz6nwC47cE>Q5%J(b@`sJN=C sXI-qDU>)+D4LK0^W=)I3^H!wmi^Dj{ANRHJ1Fg6}-|UiLfa{FB-(2xa9smFU literal 0 HcmV?d00001 From 541207738a8174d128b1a17381d3cb217bcfa562 Mon Sep 17 00:00:00 2001 From: Katelyn Baker Date: Thu, 30 Nov 2017 13:31:33 +0000 Subject: [PATCH 06/22] CORDA-553 - Documentation --- docs/source/release-notes.rst | 5 +++ .../amqp/EnumEvolutionSerializer.kt | 32 +++++++++++++------ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/docs/source/release-notes.rst b/docs/source/release-notes.rst index 14d9a494cc..79263cfd6e 100644 --- a/docs/source/release-notes.rst +++ b/docs/source/release-notes.rst @@ -6,6 +6,11 @@ Here are release notes for each snapshot release from M9 onwards. Unreleased ---------- +** Enum Class Evolution + With the addition of AMQP serialization Corda now supports enum constant evolution, that is the abilit to alter + an enum constant and, as long as certain rules ar followed and the correct annotations applied, have older and + newer instances of that enumeration be understood. + Release 2.0 ---------- Following quickly on the heels of the release of Corda 1.0, Corda version 2.0 consolidates diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt index f8579fc21e..221954371b 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt @@ -7,7 +7,12 @@ import java.lang.reflect.Type import java.util.* /** - * @property transforms + * @property clazz The enum as it exists now, not as it did when it was seialised (either in the past + * or future). + * @property factory the [SerializerFactory] that is building this serialization object. + * @property conversions A mapping between all potential enum constants that could've been assigned as + * existed at serialisation and those that exist now + * @property ordinals Convenience mapping of constant to ordinality * */ class EnumEvolutionSerializer( @@ -19,7 +24,7 @@ class EnumEvolutionSerializer( override val typeDescriptor = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}")!! companion object { - fun MutableMap.mapInPlace(f : (String)->String) { + private fun MutableMap.mapInPlace(f : (String)->String) { val i = this.iterator() while(i.hasNext()) { val curr = (i.next()) @@ -28,8 +33,14 @@ class EnumEvolutionSerializer( } /** - * @param old - * @param new + * Builds an Enum Evolver serializer. + * + * @param old The description of the enum as it existed at the time of serialisation take from the + * received AMQP header + * @param new The Serializer object we built based on the current state of the enum class on our classpath + * @param factory the [SerializerFactory] that is building this serialization object. + * @param transformsFromBlob the transforms attached to the class in the AMQP header, i.e. the transforms + * known at serialization time */ fun make(old: RestrictedType, new: AMQPSerializer, @@ -48,9 +59,9 @@ class EnumEvolutionSerializer( val renameRules = transforms[TransformTypes.Rename] as? List // What values exist on the enum as it exists on the class path - val localVals = new.type.asClass()!!.enumConstants.map { it.toString() } + val localValues = new.type.asClass()!!.enumConstants.map { it.toString() } - var conversions : MutableMap = new.type.asClass()!!.enumConstants.map { it.toString() } + val conversions : MutableMap = new.type.asClass()!!.enumConstants.map { it.toString() } .union(defaultRules?.map { it.new }?.toSet() ?: emptySet()) .union(renameRules?.map { it.to } ?: emptySet()) .associateBy({ it }, { it }) @@ -60,17 +71,20 @@ class EnumEvolutionSerializer( rules.putAll(defaultRules?.associateBy({ it.new }, { it.old }) ?: emptyMap()) rules.putAll(renameRules?.associateBy({ it.to }, { it.from }) ?: emptyMap()) - while (conversions.filter { it.value !in localVals }.isNotEmpty()) { + while (conversions.filter { it.value !in localValues }.isNotEmpty()) { conversions.mapInPlace { rules[it] ?: it } } + // you'd think this was overkill to get access to the ordinal values for each constant but it's actually + // rather tricky when you don't have access to the actual type, so this is a nice way to be able + // to precompute and pass to the actual object var idx = 0 - return EnumEvolutionSerializer(new.type, factory, conversions, localVals.associateBy( {it}, { idx++ })) + return EnumEvolutionSerializer(new.type, factory, conversions, localValues.associateBy( {it}, { idx++ })) } } override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput): Any { - var enumName = (obj as List<*>)[0] as String + val enumName = (obj as List<*>)[0] as String if (enumName !in conversions) { throw NotSerializableException ("No rule to evolve enum constant $type::$enumName") From 15f677a2fb76f5564a5ccb56becf30e54128b8a4 Mon Sep 17 00:00:00 2001 From: Andrzej Cichocki Date: Fri, 1 Dec 2017 10:10:27 +0000 Subject: [PATCH 07/22] Make rigorousMock callRealMethod by default for concrete methods. (#2159) --- .../services/events/NodeSchedulerServiceTest.kt | 7 ------- .../main/kotlin/net/corda/testing/NodeTestUtils.kt | 5 ----- .../main/kotlin/net/corda/testing/CoreTestUtils.kt | 14 ++++++++++---- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt index 5796609f1c..72b61e053b 100644 --- a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt @@ -12,9 +12,7 @@ import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.node.NodeInfo import net.corda.core.node.ServiceHub -import net.corda.core.node.StatesToRecord import net.corda.core.serialization.SingletonSerializeAsToken -import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.days import net.corda.node.internal.FlowStarterImpl @@ -44,7 +42,6 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import java.nio.file.Paths -import java.security.PublicKey import java.time.Clock import java.time.Instant import java.util.concurrent.CountDownLatch @@ -105,13 +102,9 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { doReturn(MonitoringService(MetricRegistry())).whenever(it).monitoringService doReturn(validatedTransactions).whenever(it).validatedTransactions doReturn(NetworkMapCacheImpl(MockNetworkMapCache(database), identityService)).whenever(it).networkMapCache - doCallRealMethod().whenever(it).signInitialTransaction(any(), any()) doReturn(myInfo).whenever(it).myInfo doReturn(kms).whenever(it).keyManagementService doReturn(CordappProviderImpl(CordappLoader.createWithTestPackages(listOf("net.corda.testing.contracts")), MockAttachmentStorage())).whenever(it).cordappProvider - doCallRealMethod().whenever(it).recordTransactions(any(), any()) - doCallRealMethod().whenever(it).recordTransactions(any>()) - doCallRealMethod().whenever(it).recordTransactions(any(), anyVararg()) doReturn(NodeVaultService(testClock, kms, stateLoader, database.hibernateConfig)).whenever(it).vaultService doReturn(this@NodeSchedulerServiceTest).whenever(it).testReference diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt index 09f1e7918a..2f470d8eb0 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt @@ -2,7 +2,6 @@ package net.corda.testing -import com.nhaarman.mockito_kotlin.doCallRealMethod import com.nhaarman.mockito_kotlin.doReturn import com.nhaarman.mockito_kotlin.whenever import net.corda.core.context.Actor @@ -74,10 +73,6 @@ fun testNodeConfiguration( doReturn(5).whenever(it).messageRedeliveryDelaySeconds doReturn(5.seconds.toMillis()).whenever(it).additionalNodeInfoPollingFrequencyMsec doReturn(null).whenever(it).devModeOptions - doCallRealMethod().whenever(it).certificatesDirectory - doCallRealMethod().whenever(it).trustStoreFile - doCallRealMethod().whenever(it).sslKeystore - doCallRealMethod().whenever(it).nodeKeystore } } diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 2fdb34673d..8b2a2813f2 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -24,6 +24,7 @@ import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.serialization.amqp.AMQP_ENABLED import org.mockito.Mockito.mock import org.mockito.internal.stubbing.answers.ThrowsException +import java.lang.reflect.Modifier import java.nio.file.Files import java.security.KeyPair import java.security.PublicKey @@ -180,11 +181,16 @@ class UndefinedMockBehaviorException(message: String) : RuntimeException(message inline fun rigorousMock() = rigorousMock(T::class.java) /** - * Create a Mockito mock that has [UndefinedMockBehaviorException] as the default behaviour of all methods. - * @param T the type to mock. Note if you want to use [com.nhaarman.mockito_kotlin.doCallRealMethod] on a Kotlin interface, + * Create a Mockito mock that has [UndefinedMockBehaviorException] as the default behaviour of all abstract methods, + * and [org.mockito.invocation.InvocationOnMock.callRealMethod] as the default for all concrete methods. + * @param T the type to mock. Note if you want concrete methods of a Kotlin interface to be invoked, * it won't work unless you mock a (trivial) abstract implementation of that interface instead. */ fun rigorousMock(clazz: Class): T = mock(clazz) { - // Use ThrowsException to hack the stack trace, and lazily so we can customise the message: - ThrowsException(UndefinedMockBehaviorException("Please specify what should happen when '${it.method}' is called, or don't call it. Args: ${Arrays.toString(it.arguments)}")).answer(it) + if (Modifier.isAbstract(it.method.modifiers)) { + // Use ThrowsException to hack the stack trace, and lazily so we can customise the message: + ThrowsException(UndefinedMockBehaviorException("Please specify what should happen when '${it.method}' is called, or don't call it. Args: ${Arrays.toString(it.arguments)}")).answer(it) + } else { + it.callRealMethod() + } } From 1f0571306b147d82e53e1d6ce5ce79e35cc21afa Mon Sep 17 00:00:00 2001 From: Michele Sollecito Date: Fri, 1 Dec 2017 14:31:52 +0000 Subject: [PATCH 08/22] Showcase of closures registered as flows. (#2162) --- .../corda/core/flows/ReceiveAllFlowTests.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/core/src/test/kotlin/net/corda/core/flows/ReceiveAllFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/ReceiveAllFlowTests.kt index dd2dbab17f..2fc6be8955 100644 --- a/core/src/test/kotlin/net/corda/core/flows/ReceiveAllFlowTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/ReceiveAllFlowTests.kt @@ -20,6 +20,42 @@ class ReceiveMultipleFlowTests { mockNet.stopNodes() } + @Test + fun showcase_flows_as_closures() { + + val answer = 10.0 + val message = "Hello Ivan" + + val counterParty = nodes[1].info.singleIdentity() + + val initiatingFlow = @InitiatingFlow object : FlowLogic() { + + @Suspendable + override fun call(): Any { + val session = initiateFlow(counterParty) + return session.sendAndReceive(message).unwrap { it } + } + } + + nodes[1].registerInitiatedFlow(initiatingFlow::class) { session -> + object : FlowLogic() { + @Suspendable + override fun call() { + // this is a closure, meaning you can access variables outside its scope e.g., `answer`. + val receivedMessage = session.receive().unwrap { it } + logger.info("Got message from counterParty: $receivedMessage.") + assertThat(receivedMessage).isEqualTo(message) + session.send(answer) + } + } as FlowLogic + } + + val flow = nodes[0].services.startFlow(initiatingFlow) + mockNet.runNetwork() + val receivedAnswer = flow.resultFuture.getOrThrow() + assertThat(receivedAnswer).isEqualTo(answer) + } + @Test fun `receive all messages in parallel using map style`() { val doubleValue = 5.0 From 32ebd2cc8b7e3e138645f5c3c672ea94e5c29432 Mon Sep 17 00:00:00 2001 From: Katelyn Baker Date: Fri, 1 Dec 2017 16:59:19 +0000 Subject: [PATCH 09/22] CORDA-553 - Review comments --- docs/source/release-notes.rst | 9 ++-- .../amqp/EnumEvolutionSerializer.kt | 42 +++++++++---------- .../serialization/amqp/EvolutionSerializer.kt | 2 +- .../serialization/amqp/TansformTypes.kt | 3 +- .../serialization/amqp/TransformsSchema.kt | 6 +-- .../serialization/amqp/EnumEvolveTests.kt | 10 ++--- 6 files changed, 35 insertions(+), 37 deletions(-) diff --git a/docs/source/release-notes.rst b/docs/source/release-notes.rst index 79263cfd6e..36aeb6c6c5 100644 --- a/docs/source/release-notes.rst +++ b/docs/source/release-notes.rst @@ -6,10 +6,11 @@ Here are release notes for each snapshot release from M9 onwards. Unreleased ---------- -** Enum Class Evolution - With the addition of AMQP serialization Corda now supports enum constant evolution, that is the abilit to alter - an enum constant and, as long as certain rules ar followed and the correct annotations applied, have older and - newer instances of that enumeration be understood. +* **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. Release 2.0 ---------- diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt index 221954371b..701df3732d 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt @@ -1,33 +1,33 @@ package net.corda.nodeapi.internal.serialization.amqp +import net.corda.core.internal.uncheckedCast import org.apache.qpid.proton.amqp.Symbol import org.apache.qpid.proton.codec.Data import java.io.NotSerializableException +import java.lang.UnsupportedOperationException import java.lang.reflect.Type -import java.util.* /** - * @property clazz The enum as it exists now, not as it did when it was seialised (either in the past + * @property clazz The enum as it exists now, not as it did when it was serialized (either in the past * or future). * @property factory the [SerializerFactory] that is building this serialization object. - * @property conversions A mapping between all potential enum constants that could've been assigned as - * existed at serialisation and those that exist now + * @property conversions A mapping between all potential enum constants that could've been assigned to + * an instance of the enum as it existed at serialisation and those that exist now * @property ordinals Convenience mapping of constant to ordinality - * */ class EnumEvolutionSerializer( clazz: Type, factory: SerializerFactory, - private val conversions : Map, - private val ordinals : Map) : AMQPSerializer { + private val conversions: Map, + private val ordinals: Map) : AMQPSerializer { override val type: Type = clazz override val typeDescriptor = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}")!! companion object { - private fun MutableMap.mapInPlace(f : (String)->String) { - val i = this.iterator() - while(i.hasNext()) { - val curr = (i.next()) + private fun MutableMap.mapInPlace(f: (String) -> String) { + val i = iterator() + while (i.hasNext()) { + val curr = i.next() curr.setValue(f(curr.value)) } } @@ -35,7 +35,7 @@ class EnumEvolutionSerializer( /** * Builds an Enum Evolver serializer. * - * @param old The description of the enum as it existed at the time of serialisation take from the + * @param old The description of the enum as it existed at the time of serialisation taken from the * received AMQP header * @param new The Serializer object we built based on the current state of the enum class on our classpath * @param factory the [SerializerFactory] that is building this serialization object. @@ -53,21 +53,19 @@ class EnumEvolutionSerializer( // if either of these isn't of the cast type then something has gone terribly wrong // elsewhere in the code - @Suppress("UNCHECKED_CAST") - val defaultRules = transforms[TransformTypes.EnumDefault] as? List - @Suppress("UNCHECKED_CAST") - val renameRules = transforms[TransformTypes.Rename] as? List + val defaultRules: List? = uncheckedCast(transforms[TransformTypes.EnumDefault]) + val renameRules: List? = uncheckedCast(transforms[TransformTypes.Rename]) // What values exist on the enum as it exists on the class path val localValues = new.type.asClass()!!.enumConstants.map { it.toString() } - val conversions : MutableMap = new.type.asClass()!!.enumConstants.map { it.toString() } + val conversions: MutableMap = localValues .union(defaultRules?.map { it.new }?.toSet() ?: emptySet()) .union(renameRules?.map { it.to } ?: emptySet()) .associateBy({ it }, { it }) .toMutableMap() - val rules : MutableMap = mutableMapOf() + val rules: MutableMap = mutableMapOf() rules.putAll(defaultRules?.associateBy({ it.new }, { it.old }) ?: emptyMap()) rules.putAll(renameRules?.associateBy({ it.to }, { it.from }) ?: emptyMap()) @@ -79,7 +77,7 @@ class EnumEvolutionSerializer( // rather tricky when you don't have access to the actual type, so this is a nice way to be able // to precompute and pass to the actual object var idx = 0 - return EnumEvolutionSerializer(new.type, factory, conversions, localValues.associateBy( {it}, { idx++ })) + return EnumEvolutionSerializer(new.type, factory, conversions, localValues.associateBy({ it }, { idx++ })) } } @@ -87,17 +85,17 @@ class EnumEvolutionSerializer( val enumName = (obj as List<*>)[0] as String if (enumName !in conversions) { - throw NotSerializableException ("No rule to evolve enum constant $type::$enumName") + throw NotSerializableException("No rule to evolve enum constant $type::$enumName") } return type.asClass()!!.enumConstants[ordinals[conversions[enumName]]!!] } override fun writeClassInfo(output: SerializationOutput) { - throw IllegalAccessException("It should be impossible to write an evolution serializer") + throw UnsupportedOperationException("It should be impossible to write an evolution serializer") } override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) { - throw IllegalAccessException("It should be impossible to write an evolution serializer") + throw UnsupportedOperationException("It should be impossible to write an evolution serializer") } } \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolutionSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolutionSerializer.kt index 59f22598a0..411e405aad 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolutionSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolutionSerializer.kt @@ -109,7 +109,7 @@ class EvolutionSerializer( } override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) { - throw IllegalAccessException("It should be impossible to write an evolution serializer") + throw UnsupportedOperationException("It should be impossible to write an evolution serializer") } /** diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt index 6fd1e4a95f..e21498f7b0 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt @@ -1,5 +1,6 @@ package net.corda.nodeapi.internal.serialization.amqp +import net.corda.core.internal.uncheckedCast import net.corda.core.serialization.CordaSerializationTransformEnumDefault import net.corda.core.serialization.CordaSerializationTransformEnumDefaults import net.corda.core.serialization.CordaSerializationTransformRename @@ -43,7 +44,7 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType * @param constants The list of enum constants on the type the transforms are being applied to */ override fun validate(l : List, constants: Set) { - @Suppress("UNCHECKED_CAST") (l as List).forEach { + uncheckedCast, List>(l).forEach { if (!constants.contains(it.old)) { throw NotSerializableException( "Enum extension defaults must be to a valid constant: ${it.new} -> ${it.old}. ${it.old} " + diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt index a8409a64c3..c88addacaa 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt @@ -146,10 +146,8 @@ class EnumDefaultSchemaTransform(val old: String, val new: String) : Transform() /** * Transform applied to either a class or enum where a property is renamed * - * @property from the name at time of change of the property - * @property to the new name of the property - * - * + * @property from the name of the property or constant prior to being changed, i.e. what it was + * @property to the new name of the property or constant after the change has been made, i.e. what it is now */ class RenameSchemaTransform(val from: String, val to: String) : Transform() { companion object : DescribedTypeConstructor { diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt index c28ec8d95f..2b7930c707 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt @@ -27,7 +27,7 @@ class EnumEvolveTests { @Test fun deserialiseNewerSetToUnknown() { - val resource = "${this.javaClass.simpleName}.${testName()}" + val resource = "${javaClass.simpleName}.${testName()}" val sf = testDefaultFactory() data class C (val e : DeserializeNewerSetToUnknown) @@ -55,7 +55,7 @@ class EnumEvolveTests { @Test fun deserialiseNewerSetToUnknown2() { - val resource = "${this.javaClass.simpleName}.${testName()}" + val resource = "${javaClass.simpleName}.${testName()}" val sf = testDefaultFactory() data class C(val e: DeserializeNewerSetToUnknown2) @@ -95,7 +95,7 @@ class EnumEvolveTests { // Lets test to see if they forgot to provide an upgrade rule @Test fun deserialiseNewerWithNoRule() { - val resource = "${this.javaClass.simpleName}.${testName()}" + val resource = "${javaClass.simpleName}.${testName()}" val sf = testDefaultFactory() data class C(val e: DeserializeNewerWithNoRule) @@ -143,7 +143,7 @@ class EnumEvolveTests { @Test fun deserializeWithRename() { - val resource = "${this.javaClass.simpleName}.${testName()}" + val resource = "${javaClass.simpleName}.${testName()}" val sf = testDefaultFactory() data class C(val e: DeserializeWithRename) @@ -265,7 +265,7 @@ class EnumEvolveTests { @Test fun multiOperations() { - val resource = "${this.javaClass.simpleName}.${testName()}" + val resource = "${javaClass.simpleName}.${testName()}" val sf = testDefaultFactory() data class C(val e: MultiOperations) From 7e044e1124537ebb0450355153de7b6c4ae71fc0 Mon Sep 17 00:00:00 2001 From: Katelyn Baker Date: Fri, 1 Dec 2017 19:15:14 +0000 Subject: [PATCH 10/22] CORDA-553 - Review comments --- .../amqp/EnumEvolutionSerializer.kt | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt index 701df3732d..d5690d5f63 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt @@ -8,11 +8,29 @@ import java.lang.UnsupportedOperationException import java.lang.reflect.Type /** + * Used whenever a deserialized enums fingerprint doesn't match the fingerprint of the generated + * serializer object. I.e. the deserializing code has a different version of the code either newer or + * older). The changes will have been documented using the transformation annotations, a copy of which + * are encoded as part of the AMQP envelope. + * + * This function ascertains which version of the enumeration is newer by comparing the length of the + * transformations list. Since transformation annotations should only ever be added, never removed even + * when seemingly unneeded (such as repeated renaming of a single constant), the longer list will dictate + * which is more up to date. + * + * The list of transforms come from two places, the class as it exists on the current class path and the + * class as it exists as it was serialized. In the case of the former we can build the list by using + * reflection on the class. In the case of the latter the transforms are retrieved from the AMQP envelope. + * + * With a set of transforms chosen we calculate the set of all possible constants, then using the + * transformation rules we create a mapping between those values and the values that exist on the + * current class + * * @property clazz The enum as it exists now, not as it did when it was serialized (either in the past * or future). * @property factory the [SerializerFactory] that is building this serialization object. * @property conversions A mapping between all potential enum constants that could've been assigned to - * an instance of the enum as it existed at serialisation and those that exist now + * an instance of the enum as it existed at time of serialisation and those that exist now * @property ordinals Convenience mapping of constant to ordinality */ class EnumEvolutionSerializer( @@ -76,8 +94,8 @@ class EnumEvolutionSerializer( // you'd think this was overkill to get access to the ordinal values for each constant but it's actually // rather tricky when you don't have access to the actual type, so this is a nice way to be able // to precompute and pass to the actual object - var idx = 0 - return EnumEvolutionSerializer(new.type, factory, conversions, localValues.associateBy({ it }, { idx++ })) + return EnumEvolutionSerializer(new.type, factory, conversions, + localValues.mapIndexed { i, s -> Pair (s, i)}.toMap()) } } From 5264072752e5258d92c121c13172ad50fcec4b52 Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Sat, 2 Dec 2017 23:17:36 +0000 Subject: [PATCH 11/22] Renamed n.c.nodeapi.config to n.c.nodeapi.internal.config as that config code is not public API. For the same reason, also moved User into the same internal package. --- .../kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt | 2 +- .../java/net/corda/client/rpc/CordaRPCJavaClientTest.java | 2 +- .../kotlin/net/corda/client/rpc/CordaRPCClientTest.kt | 2 +- .../main/kotlin/net/corda/client/rpc/internal/RPCClient.kt | 2 +- .../corda/java/rpc/StandaloneCordaRPCJavaClientTest.java | 2 +- .../net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt | 2 +- .../src/test/kotlin/net/corda/client/rpc/AbstractRPCTest.kt | 2 +- .../test/kotlin/net/corda/client/rpc/RPCPermissionsTests.kt | 2 +- .../smoke-test/kotlin/net/corda/core/NodeVersioningTest.kt | 2 +- .../kotlin/net/corda/core/cordapp/CordappSmokeTest.kt | 2 +- .../kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt | 2 +- .../kotlin/net/corda/docs/IntegrationTestingTutorial.kt | 2 +- .../src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt | 2 +- .../main/kotlin/net/corda/nodeapi/ArtemisTcpTransport.kt | 3 ++- .../kotlin/net/corda/nodeapi/{ => internal}/ArtemisUtils.kt | 2 +- .../corda/nodeapi/{ => internal}/config/ConfigUtilities.kt | 4 ++-- .../corda/nodeapi/{ => internal}/config/SSLConfiguration.kt | 2 +- .../kotlin/net/corda/nodeapi/{ => internal/config}/User.kt | 5 +---- .../nodeapi/{ => internal}/config/ConfigParsingTest.kt | 2 +- .../src/integration-test/kotlin/net/corda/node/BootTests.kt | 2 +- .../kotlin/net/corda/node/CordappScanningDriverTest.kt | 2 +- .../kotlin/net/corda/node/NodePerformanceTests.kt | 2 +- .../integration-test/kotlin/net/corda/node/SSHServerTest.kt | 2 +- .../net/corda/node/services/DistributedServiceTests.kt | 2 +- .../node/services/statemachine/LargeTransactionsTest.kt | 2 +- .../net/corda/services/messaging/MQSecurityAsNodeTest.kt | 2 +- .../net/corda/services/messaging/MQSecurityAsRPCTest.kt | 2 +- .../kotlin/net/corda/services/messaging/MQSecurityTest.kt | 4 ++-- .../kotlin/net/corda/test/node/NodeStatePersistenceTests.kt | 2 +- .../main/kotlin/net/corda/node/services/RPCUserService.kt | 2 +- .../net/corda/node/services/config/ConfigUtilities.kt | 2 +- .../net/corda/node/services/config/NodeConfiguration.kt | 6 +++--- .../corda/node/services/messaging/ArtemisMessagingClient.kt | 2 +- .../corda/node/services/messaging/ArtemisMessagingServer.kt | 1 + .../net/corda/node/services/messaging/RPCMessagingClient.kt | 2 +- .../kotlin/net/corda/node/services/messaging/RPCServer.kt | 1 + .../node/services/messaging/VerifierMessagingClient.kt | 2 +- .../node/services/transactions/RaftUniquenessProvider.kt | 4 ++-- .../kotlin/net/corda/node/services/RPCUserServiceTest.kt | 2 +- .../net/corda/node/services/config/ConfigOperatorTests.kt | 2 +- .../kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt | 2 +- .../src/main/kotlin/net/corda/attachmentdemo/Main.kt | 2 +- .../kotlin/net/corda/bank/BankOfCordaRPCClientTest.kt | 2 +- .../src/main/kotlin/net/corda/bank/BankOfCordaCordform.kt | 2 +- .../integration-test/kotlin/net/corda/irs/IRSDemoTest.kt | 2 +- .../kotlin/net/corda/notarydemo/SingleNotaryCordform.kt | 2 +- .../kotlin/net/corda/traderdemo/TraderDemoTest.kt | 2 +- .../src/test/kotlin/net/corda/traderdemo/Main.kt | 2 +- .../kotlin/net/corda/testing/FlowStackSnapshotTest.kt | 2 +- .../src/main/kotlin/net/corda/testing/NodeTestUtils.kt | 2 +- .../src/main/kotlin/net/corda/testing/driver/Driver.kt | 4 ++-- .../main/kotlin/net/corda/testing/internal/NodeBasedTest.kt | 2 +- .../src/main/kotlin/net/corda/testing/internal/RPCDriver.kt | 2 +- .../net/corda/testing/internal/demorun/CordformUtils.kt | 4 ++-- .../src/main/kotlin/net/corda/testing/node/NotarySpec.kt | 2 +- .../src/main/kotlin/net/corda/smoketesting/NodeConfig.kt | 2 +- .../src/main/kotlin/net/corda/testing/CoreTestUtils.kt | 2 +- .../kotlin/net/corda/testing/messaging/SimpleMQClient.kt | 2 +- .../main/kotlin/net/corda/demobench/model/InstallFactory.kt | 2 +- .../src/main/kotlin/net/corda/demobench/model/NodeConfig.kt | 4 ++-- .../test/kotlin/net/corda/demobench/model/NodeConfigTest.kt | 4 ++-- .../kotlin/net/corda/demobench/model/NodeControllerTest.kt | 2 +- .../main/kotlin/net/corda/explorer/ExplorerSimulation.kt | 2 +- .../main/kotlin/net/corda/loadtest/LoadTestConfiguration.kt | 2 +- tools/loadtest/src/main/kotlin/net/corda/loadtest/Main.kt | 2 +- .../kotlin/net/corda/verifier/VerifierDriver.kt | 4 ++-- verifier/src/main/kotlin/net/corda/verifier/Verifier.kt | 4 ++-- .../src/main/kotlin/net/corda/webserver/WebServerConfig.kt | 6 +++--- 68 files changed, 82 insertions(+), 82 deletions(-) rename node-api/src/main/kotlin/net/corda/nodeapi/{ => internal}/ArtemisUtils.kt (92%) rename node-api/src/main/kotlin/net/corda/nodeapi/{ => internal}/config/ConfigUtilities.kt (99%) rename node-api/src/main/kotlin/net/corda/nodeapi/{ => internal}/config/SSLConfiguration.kt (93%) rename node-api/src/main/kotlin/net/corda/nodeapi/{ => internal/config}/User.kt (77%) rename node-api/src/test/kotlin/net/corda/nodeapi/{ => internal}/config/ConfigParsingTest.kt (99%) diff --git a/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt b/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt index ad83ee723e..b70d60bd55 100644 --- a/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt +++ b/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt @@ -28,7 +28,7 @@ import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.* import net.corda.testing.driver.driver import org.junit.Test diff --git a/client/rpc/src/integration-test/java/net/corda/client/rpc/CordaRPCJavaClientTest.java b/client/rpc/src/integration-test/java/net/corda/client/rpc/CordaRPCJavaClientTest.java index 698aca77c9..01966d3a97 100644 --- a/client/rpc/src/integration-test/java/net/corda/client/rpc/CordaRPCJavaClientTest.java +++ b/client/rpc/src/integration-test/java/net/corda/client/rpc/CordaRPCJavaClientTest.java @@ -10,7 +10,7 @@ import net.corda.finance.flows.CashPaymentFlow; import net.corda.finance.schemas.CashSchemaV1; import net.corda.node.internal.Node; import net.corda.node.internal.StartedNode; -import net.corda.nodeapi.User; +import net.corda.nodeapi.internal.config.User; import net.corda.testing.CoreTestUtils; import net.corda.testing.internal.NodeBasedTest; import org.junit.After; diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt index fd14bf35d0..5c14c3becb 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt @@ -20,7 +20,7 @@ import net.corda.node.internal.Node import net.corda.node.internal.StartedNode import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.* import net.corda.testing.internal.NodeBasedTest import org.apache.activemq.artemis.api.core.ActiveMQSecurityException diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt index f7318b34b3..756f07216e 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt @@ -15,7 +15,7 @@ import net.corda.core.utilities.* import net.corda.nodeapi.ArtemisTcpTransport.Companion.tcpTransport import net.corda.nodeapi.ConnectionDirection import net.corda.nodeapi.RPCApi -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.TransportConfiguration import org.apache.activemq.artemis.api.core.client.ActiveMQClient diff --git a/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java b/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java index 692cfe381c..d03f020d5b 100644 --- a/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java +++ b/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java @@ -9,7 +9,7 @@ import net.corda.core.messaging.FlowHandle; import net.corda.core.utilities.OpaqueBytes; import net.corda.finance.flows.AbstractCashFlow; import net.corda.finance.flows.CashIssueFlow; -import net.corda.nodeapi.User; +import net.corda.nodeapi.internal.config.User; import net.corda.smoketesting.NodeConfig; import net.corda.smoketesting.NodeProcess; import org.junit.After; diff --git a/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt b/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt index 23018f7bfb..09e739819a 100644 --- a/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt +++ b/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt @@ -21,7 +21,7 @@ import net.corda.finance.contracts.getCashBalance import net.corda.finance.contracts.getCashBalances import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.smoketesting.NodeConfig import net.corda.smoketesting.NodeProcess import org.apache.commons.io.output.NullOutputStream diff --git a/client/rpc/src/test/kotlin/net/corda/client/rpc/AbstractRPCTest.kt b/client/rpc/src/test/kotlin/net/corda/client/rpc/AbstractRPCTest.kt index 0c552f8128..546415e247 100644 --- a/client/rpc/src/test/kotlin/net/corda/client/rpc/AbstractRPCTest.kt +++ b/client/rpc/src/test/kotlin/net/corda/client/rpc/AbstractRPCTest.kt @@ -5,7 +5,7 @@ import net.corda.core.internal.concurrent.flatMap import net.corda.core.internal.concurrent.map import net.corda.core.messaging.RPCOps import net.corda.node.services.messaging.RPCServerConfiguration -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.SerializationEnvironmentRule import net.corda.testing.internal.RPCDriverExposedDSLInterface import net.corda.testing.internal.rpcTestUser diff --git a/client/rpc/src/test/kotlin/net/corda/client/rpc/RPCPermissionsTests.kt b/client/rpc/src/test/kotlin/net/corda/client/rpc/RPCPermissionsTests.kt index 82f5c53afc..6e7de32087 100644 --- a/client/rpc/src/test/kotlin/net/corda/client/rpc/RPCPermissionsTests.kt +++ b/client/rpc/src/test/kotlin/net/corda/client/rpc/RPCPermissionsTests.kt @@ -4,7 +4,7 @@ import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.RPCOps import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.messaging.rpcContext -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.internal.RPCDriverExposedDSLInterface import net.corda.testing.internal.rpcDriver import org.junit.Test diff --git a/core/src/smoke-test/kotlin/net/corda/core/NodeVersioningTest.kt b/core/src/smoke-test/kotlin/net/corda/core/NodeVersioningTest.kt index f9844fbce0..f682bfcb75 100644 --- a/core/src/smoke-test/kotlin/net/corda/core/NodeVersioningTest.kt +++ b/core/src/smoke-test/kotlin/net/corda/core/NodeVersioningTest.kt @@ -7,7 +7,7 @@ import net.corda.core.identity.CordaX500Name import net.corda.core.internal.* import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.smoketesting.NodeConfig import net.corda.smoketesting.NodeProcess import net.corda.testing.common.internal.ProjectStructure diff --git a/core/src/smoke-test/kotlin/net/corda/core/cordapp/CordappSmokeTest.kt b/core/src/smoke-test/kotlin/net/corda/core/cordapp/CordappSmokeTest.kt index 2f826b5f54..1f76e500fd 100644 --- a/core/src/smoke-test/kotlin/net/corda/core/cordapp/CordappSmokeTest.kt +++ b/core/src/smoke-test/kotlin/net/corda/core/cordapp/CordappSmokeTest.kt @@ -11,7 +11,7 @@ import net.corda.core.internal.list import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.unwrap -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.smoketesting.NodeConfig import net.corda.smoketesting.NodeProcess import net.corda.smoketesting.NodeProcess.Companion.CORDAPPS_DIR_NAME diff --git a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt index 3287e4f260..a072d9ec34 100644 --- a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt +++ b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt @@ -19,7 +19,7 @@ import net.corda.finance.flows.CashIssueFlow import net.corda.node.internal.SecureCordaRPCOps import net.corda.node.internal.StartedNode import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.* import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContractV2 diff --git a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt b/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt index 9b192038bf..d8a1b64776 100644 --- a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt +++ b/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt @@ -13,7 +13,7 @@ import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.* import net.corda.testing.driver.driver import org.junit.Test diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt index f68bc82edd..954a67c239 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt @@ -17,7 +17,7 @@ import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.ALICE import net.corda.testing.driver.driver import org.graphstream.graph.Edge diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisTcpTransport.kt b/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisTcpTransport.kt index 947560c257..ab1720934a 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisTcpTransport.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisTcpTransport.kt @@ -3,7 +3,8 @@ package net.corda.nodeapi import net.corda.core.identity.CordaX500Name import net.corda.core.serialization.internal.nodeSerializationEnv import net.corda.core.utilities.NetworkHostAndPort -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration +import net.corda.nodeapi.internal.requireOnDefaultFileSystem import org.apache.activemq.artemis.api.core.TransportConfiguration import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisUtils.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisUtils.kt similarity index 92% rename from node-api/src/main/kotlin/net/corda/nodeapi/ArtemisUtils.kt rename to node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisUtils.kt index 644fdb363a..3f1e887fa8 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisUtils.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisUtils.kt @@ -1,6 +1,6 @@ @file:JvmName("ArtemisUtils") -package net.corda.nodeapi +package net.corda.nodeapi.internal import java.nio.file.FileSystems import java.nio.file.Path diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/ConfigUtilities.kt similarity index 99% rename from node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt rename to node-api/src/main/kotlin/net/corda/nodeapi/internal/config/ConfigUtilities.kt index 19987de81c..33a5e237ff 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/ConfigUtilities.kt @@ -1,6 +1,6 @@ @file:JvmName("ConfigUtilities") -package net.corda.nodeapi.config +package net.corda.nodeapi.internal.config import com.typesafe.config.Config import com.typesafe.config.ConfigFactory @@ -200,4 +200,4 @@ private fun Iterable<*>.toConfigIterable(field: Field): Iterable { } } -private val logger = LoggerFactory.getLogger("net.corda.nodeapi.config") +private val logger = LoggerFactory.getLogger("net.corda.nodeapi.internal.config") diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/config/SSLConfiguration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/SSLConfiguration.kt similarity index 93% rename from node-api/src/main/kotlin/net/corda/nodeapi/config/SSLConfiguration.kt rename to node-api/src/main/kotlin/net/corda/nodeapi/internal/config/SSLConfiguration.kt index 6fb82e508f..90544e92a6 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/config/SSLConfiguration.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/SSLConfiguration.kt @@ -1,4 +1,4 @@ -package net.corda.nodeapi.config +package net.corda.nodeapi.internal.config import net.corda.core.internal.div import java.nio.file.Path diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/User.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/User.kt similarity index 77% rename from node-api/src/main/kotlin/net/corda/nodeapi/User.kt rename to node-api/src/main/kotlin/net/corda/nodeapi/internal/config/User.kt index aa86e64414..13ca193f4b 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/User.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/User.kt @@ -1,7 +1,4 @@ -package net.corda.nodeapi - -import net.corda.nodeapi.config.OldConfig -import net.corda.nodeapi.config.toConfig +package net.corda.nodeapi.internal.config data class User( @OldConfig("user") diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/config/ConfigParsingTest.kt similarity index 99% rename from node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt rename to node-api/src/test/kotlin/net/corda/nodeapi/internal/config/ConfigParsingTest.kt index 5efdeaf439..a6fa2ca169 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/config/ConfigParsingTest.kt @@ -1,4 +1,4 @@ -package net.corda.nodeapi.config +package net.corda.nodeapi.internal.config import com.typesafe.config.Config import com.typesafe.config.ConfigFactory.empty diff --git a/node/src/integration-test/kotlin/net/corda/node/BootTests.kt b/node/src/integration-test/kotlin/net/corda/node/BootTests.kt index a7561d331f..5efb235eb2 100644 --- a/node/src/integration-test/kotlin/net/corda/node/BootTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/BootTests.kt @@ -8,7 +8,7 @@ import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow import net.corda.node.internal.NodeStartup import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.ALICE import net.corda.testing.common.internal.ProjectStructure.projectRootDir import net.corda.testing.driver.driver diff --git a/node/src/integration-test/kotlin/net/corda/node/CordappScanningDriverTest.kt b/node/src/integration-test/kotlin/net/corda/node/CordappScanningDriverTest.kt index 8515b9b4ec..c6464056e1 100644 --- a/node/src/integration-test/kotlin/net/corda/node/CordappScanningDriverTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/CordappScanningDriverTest.kt @@ -8,7 +8,7 @@ import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.unwrap import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.ALICE import net.corda.testing.BOB import net.corda.testing.chooseIdentity diff --git a/node/src/integration-test/kotlin/net/corda/node/NodePerformanceTests.kt b/node/src/integration-test/kotlin/net/corda/node/NodePerformanceTests.kt index 13ca05b46c..15abb2b06d 100644 --- a/node/src/integration-test/kotlin/net/corda/node/NodePerformanceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/NodePerformanceTests.kt @@ -13,7 +13,7 @@ import net.corda.finance.DOLLARS import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.DUMMY_NOTARY import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.driver diff --git a/node/src/integration-test/kotlin/net/corda/node/SSHServerTest.kt b/node/src/integration-test/kotlin/net/corda/node/SSHServerTest.kt index 96c701f761..67b1996596 100644 --- a/node/src/integration-test/kotlin/net/corda/node/SSHServerTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/SSHServerTest.kt @@ -9,7 +9,7 @@ import net.corda.core.identity.Party import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.unwrap -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.ALICE import net.corda.testing.driver.driver import org.bouncycastle.util.io.Streams diff --git a/node/src/integration-test/kotlin/net/corda/node/services/DistributedServiceTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/DistributedServiceTests.kt index ce5f107d93..67a9d8648c 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/DistributedServiceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/DistributedServiceTests.kt @@ -14,7 +14,7 @@ import net.corda.finance.flows.CashPaymentFlow import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.startFlow import net.corda.node.services.transactions.RaftValidatingNotaryService -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.* import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.driver diff --git a/node/src/integration-test/kotlin/net/corda/node/services/statemachine/LargeTransactionsTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/statemachine/LargeTransactionsTest.kt index 980a29bb2e..342485889e 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/statemachine/LargeTransactionsTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/statemachine/LargeTransactionsTest.kt @@ -8,7 +8,7 @@ import net.corda.core.internal.concurrent.transpose import net.corda.core.messaging.startFlow import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.getOrThrow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.* import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyState diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt index bd579f4f17..671c352b44 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt @@ -5,7 +5,7 @@ import net.corda.core.internal.* import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_USER import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEER_USER import net.corda.nodeapi.RPCApi -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.nodeapi.internal.crypto.* import net.corda.testing.MEGA_CORP import net.corda.testing.MINI_CORP diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsRPCTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsRPCTest.kt index cbb75daedd..d4cd7ca4e4 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsRPCTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsRPCTest.kt @@ -1,6 +1,6 @@ package net.corda.services.messaging -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.messaging.SimpleMQClient import org.junit.Test diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt index ecaa0032a0..45ffb4289a 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityTest.kt @@ -22,8 +22,8 @@ import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NOTIFICATI import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.P2P_QUEUE import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEERS_PREFIX import net.corda.nodeapi.RPCApi -import net.corda.nodeapi.User -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.User +import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.testing.* import net.corda.testing.internal.NodeBasedTest import net.corda.testing.messaging.SimpleMQClient diff --git a/node/src/integration-test/kotlin/net/corda/test/node/NodeStatePersistenceTests.kt b/node/src/integration-test/kotlin/net/corda/test/node/NodeStatePersistenceTests.kt index 5a2b531cef..ee94671bca 100644 --- a/node/src/integration-test/kotlin/net/corda/test/node/NodeStatePersistenceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/test/node/NodeStatePersistenceTests.kt @@ -19,7 +19,7 @@ import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.getOrThrow import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.chooseIdentity import net.corda.testing.driver.driver import org.junit.Assume.assumeFalse diff --git a/node/src/main/kotlin/net/corda/node/services/RPCUserService.kt b/node/src/main/kotlin/net/corda/node/services/RPCUserService.kt index e852e764b1..3a7bbdcb9f 100644 --- a/node/src/main/kotlin/net/corda/node/services/RPCUserService.kt +++ b/node/src/main/kotlin/net/corda/node/services/RPCUserService.kt @@ -1,7 +1,7 @@ package net.corda.node.services import net.corda.core.context.AuthServiceId -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User /** * Service for retrieving [User] objects representing RPC users who are authorised to use the RPC system. A [User] diff --git a/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt b/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt index 17c927f3b6..0582ce8768 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt @@ -8,7 +8,7 @@ import net.corda.core.crypto.Crypto import net.corda.core.crypto.SignatureScheme import net.corda.core.identity.CordaX500Name import net.corda.core.internal.* -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.nodeapi.internal.crypto.* import org.bouncycastle.asn1.x509.GeneralName import org.bouncycastle.asn1.x509.GeneralSubtree diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt index 666a14a001..cb104321c0 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt @@ -6,9 +6,9 @@ import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.seconds import net.corda.node.services.messaging.CertificateChainCheckPolicy import net.corda.nodeapi.internal.persistence.DatabaseConfig -import net.corda.nodeapi.User -import net.corda.nodeapi.config.NodeSSLConfiguration -import net.corda.nodeapi.config.parseAs +import net.corda.nodeapi.internal.config.User +import net.corda.nodeapi.internal.config.NodeSSLConfiguration +import net.corda.nodeapi.internal.config.parseAs import java.net.URL import java.nio.file.Path import java.util.* diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingClient.kt index f377087b90..fd36dc9ba7 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingClient.kt @@ -6,7 +6,7 @@ import net.corda.core.utilities.loggerFor import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_USER import net.corda.nodeapi.ArtemisTcpTransport import net.corda.nodeapi.ConnectionDirection -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration import org.apache.activemq.artemis.api.core.client.* import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt index b87ac5f582..2b7e496b32 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt @@ -33,6 +33,7 @@ import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEERS_PREF import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEER_USER import net.corda.nodeapi.internal.ArtemisMessagingComponent.ArtemisPeerAddress import net.corda.nodeapi.internal.ArtemisMessagingComponent.NodeAddress +import net.corda.nodeapi.internal.requireOnDefaultFileSystem import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl import org.apache.activemq.artemis.core.config.BridgeConfiguration diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCMessagingClient.kt index c7033b6baf..4fd197c307 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCMessagingClient.kt @@ -5,7 +5,7 @@ import net.corda.core.messaging.RPCOps import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.NetworkHostAndPort import net.corda.node.services.RPCUserService -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_USER import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.getX509Certificate diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt index 54526a76be..2fe7a4b13d 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt @@ -30,6 +30,7 @@ import net.corda.node.services.RPCUserService import net.corda.node.services.logging.pushToLoggingContext import net.corda.nodeapi.* import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_USER +import net.corda.nodeapi.internal.config.User import org.apache.activemq.artemis.api.core.Message import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/VerifierMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/VerifierMessagingClient.kt index d916e63cc5..8216b6846b 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/VerifierMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/VerifierMessagingClient.kt @@ -11,7 +11,7 @@ import net.corda.node.utilities.* import net.corda.nodeapi.VerifierApi import net.corda.nodeapi.VerifierApi.VERIFICATION_REQUESTS_QUEUE_NAME import net.corda.nodeapi.VerifierApi.VERIFICATION_RESPONSES_QUEUE_NAME_PREFIX -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration import org.apache.activemq.artemis.api.core.RoutingType import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.client.* diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt index 53e7c19fbe..3b7b78a374 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt @@ -29,8 +29,8 @@ import net.corda.core.serialization.serialize import net.corda.core.utilities.contextLogger import net.corda.node.services.config.RaftConfig import net.corda.node.utilities.AppendOnlyPersistentMap -import net.corda.nodeapi.config.NodeSSLConfiguration -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.NodeSSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX import java.nio.file.Path diff --git a/node/src/test/kotlin/net/corda/node/services/RPCUserServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/RPCUserServiceTest.kt index 88bdae5579..0f54c85d1c 100644 --- a/node/src/test/kotlin/net/corda/node/services/RPCUserServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/RPCUserServiceTest.kt @@ -1,7 +1,7 @@ package net.corda.node.services -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.Test diff --git a/node/src/test/kotlin/net/corda/node/services/config/ConfigOperatorTests.kt b/node/src/test/kotlin/net/corda/node/services/config/ConfigOperatorTests.kt index 92f7340b16..8178b88c48 100644 --- a/node/src/test/kotlin/net/corda/node/services/config/ConfigOperatorTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/config/ConfigOperatorTests.kt @@ -1,7 +1,7 @@ package net.corda.node.services.config import com.typesafe.config.ConfigFactory -import net.corda.nodeapi.config.toProperties +import net.corda.nodeapi.internal.config.toProperties import org.junit.Test import kotlin.test.assertEquals diff --git a/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt b/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt index 16c6d62c43..d79c5560f9 100644 --- a/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt +++ b/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt @@ -4,7 +4,7 @@ import net.corda.core.messaging.CordaRPCOps import net.corda.core.utilities.getOrThrow import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.DUMMY_BANK_A import net.corda.testing.DUMMY_BANK_B import net.corda.testing.driver.PortAllocation diff --git a/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/Main.kt b/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/Main.kt index eafecb2fa8..9c3b8a2304 100644 --- a/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/Main.kt +++ b/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/Main.kt @@ -1,7 +1,7 @@ package net.corda.attachmentdemo import net.corda.core.internal.div -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.DUMMY_BANK_A import net.corda.testing.DUMMY_BANK_B import net.corda.testing.driver.driver diff --git a/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaRPCClientTest.kt b/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaRPCClientTest.kt index 229d74ed4b..d53cecafe9 100644 --- a/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaRPCClientTest.kt +++ b/samples/bank-of-corda-demo/src/integration-test/kotlin/net/corda/bank/BankOfCordaRPCClientTest.kt @@ -10,7 +10,7 @@ import net.corda.finance.contracts.asset.Cash import net.corda.finance.flows.CashIssueAndPaymentFlow import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.* import net.corda.testing.driver.driver import org.junit.Test diff --git a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaCordform.kt b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaCordform.kt index 24dda81869..6ac1baa176 100644 --- a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaCordform.kt +++ b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaCordform.kt @@ -13,7 +13,7 @@ import net.corda.core.utilities.NetworkHostAndPort import net.corda.node.services.Permissions.Companion.all import net.corda.node.services.config.NotaryConfig import net.corda.node.services.transactions.ValidatingNotaryService -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.BOC import net.corda.testing.internal.demorun.* import java.util.* diff --git a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt index f47c16a623..bf850cc841 100644 --- a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt +++ b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt @@ -21,7 +21,7 @@ import net.corda.finance.plugin.registerFinanceJSONMappers import net.corda.irs.contract.InterestRateSwap import net.corda.irs.web.IrsDemoWebApplication import net.corda.node.services.config.NodeConfiguration -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.test.spring.springDriver import net.corda.testing.* import net.corda.testing.http.HttpApi diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt index 23381b72d1..ea2366c953 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt @@ -4,7 +4,7 @@ import net.corda.cordform.CordformContext import net.corda.cordform.CordformDefinition import net.corda.node.services.Permissions.Companion.all import net.corda.node.services.config.NotaryConfig -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.ALICE import net.corda.testing.BOB import net.corda.testing.DUMMY_NOTARY diff --git a/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt b/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt index af253af527..a4b7285938 100644 --- a/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt +++ b/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt @@ -8,7 +8,7 @@ import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow import net.corda.node.services.Permissions.Companion.all import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.BOC import net.corda.testing.DUMMY_BANK_A import net.corda.testing.DUMMY_BANK_B diff --git a/samples/trader-demo/src/test/kotlin/net/corda/traderdemo/Main.kt b/samples/trader-demo/src/test/kotlin/net/corda/traderdemo/Main.kt index dce315e84e..b59890ab61 100644 --- a/samples/trader-demo/src/test/kotlin/net/corda/traderdemo/Main.kt +++ b/samples/trader-demo/src/test/kotlin/net/corda/traderdemo/Main.kt @@ -4,7 +4,7 @@ import net.corda.core.internal.div import net.corda.finance.flows.CashIssueFlow import net.corda.node.services.Permissions.Companion.all import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.BOC import net.corda.testing.DUMMY_BANK_A import net.corda.testing.DUMMY_BANK_B diff --git a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/FlowStackSnapshotTest.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/FlowStackSnapshotTest.kt index f33897854c..c6e01c4193 100644 --- a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/FlowStackSnapshotTest.kt +++ b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/FlowStackSnapshotTest.kt @@ -9,7 +9,7 @@ import net.corda.core.internal.read import net.corda.core.messaging.startFlow import net.corda.core.serialization.CordaSerializable import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.driver.driver import net.corda.testing.node.MockNetwork import org.junit.Ignore diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt index 2f470d8eb0..41b4e360ff 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt @@ -20,7 +20,7 @@ import net.corda.node.services.config.CertChainPolicyConfig import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.VerifierType -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import java.nio.file.Path diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt index eab1ebd159..7df5649657 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt @@ -29,8 +29,8 @@ import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.config.* import net.corda.node.utilities.ServiceIdentityGenerator import net.corda.nodeapi.NodeInfoFilesCopier -import net.corda.nodeapi.User -import net.corda.nodeapi.config.toConfig +import net.corda.nodeapi.internal.config.User +import net.corda.nodeapi.internal.config.toConfig import net.corda.nodeapi.internal.addShutdownHook import net.corda.testing.* import net.corda.testing.internal.ProcessUtilities diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/NodeBasedTest.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/NodeBasedTest.kt index 8b32eabd37..ac5b735dcc 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/NodeBasedTest.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/NodeBasedTest.kt @@ -14,7 +14,7 @@ import net.corda.node.services.config.ConfigHelper import net.corda.node.services.config.configOf import net.corda.node.services.config.parseAsNodeConfiguration import net.corda.node.services.config.plus -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.SerializationEnvironmentRule import net.corda.testing.driver.addressMustNotBeBoundFuture import net.corda.testing.getFreeLocalPorts diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/RPCDriver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/RPCDriver.kt index 5956c09c32..7c9a81326f 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/RPCDriver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/RPCDriver.kt @@ -23,7 +23,7 @@ import net.corda.node.services.messaging.RPCServerConfiguration import net.corda.nodeapi.ArtemisTcpTransport import net.corda.nodeapi.ConnectionDirection import net.corda.nodeapi.RPCApi -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.serialization.KRYO_RPC_CLIENT_CONTEXT import net.corda.testing.driver.* import net.corda.testing.node.NotarySpec diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/CordformUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/CordformUtils.kt index dcf0255a9a..9e566a0867 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/CordformUtils.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/CordformUtils.kt @@ -6,8 +6,8 @@ import net.corda.cordform.CordformDefinition import net.corda.cordform.CordformNode import net.corda.core.identity.CordaX500Name import net.corda.node.services.config.NotaryConfig -import net.corda.nodeapi.User -import net.corda.nodeapi.config.toConfig +import net.corda.nodeapi.internal.config.User +import net.corda.nodeapi.internal.config.toConfig fun CordformDefinition.node(configure: CordformNode.() -> Unit) { addNode { cordformNode -> cordformNode.configure() } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/NotarySpec.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/NotarySpec.kt index 852d3e899a..4618bb4717 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/NotarySpec.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/NotarySpec.kt @@ -3,7 +3,7 @@ package net.corda.testing.node import net.corda.core.identity.CordaX500Name import net.corda.node.services.config.VerifierType import net.corda.node.services.transactions.RaftValidatingNotaryService -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User data class NotarySpec( val name: CordaX500Name, diff --git a/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt b/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt index cc003edc6b..40ace413d3 100644 --- a/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt +++ b/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt @@ -6,7 +6,7 @@ import com.typesafe.config.ConfigRenderOptions import com.typesafe.config.ConfigValue import com.typesafe.config.ConfigValueFactory import net.corda.core.identity.CordaX500Name -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User class NodeConfig( val legalName: CordaX500Name, diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 8b2a2813f2..df5d85661c 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -16,7 +16,7 @@ import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.loggerFor import net.corda.finance.contracts.asset.DUMMY_CASH_ISSUER import net.corda.node.services.config.configureDevKeyAndTrustStores -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509CertificateFactory diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/messaging/SimpleMQClient.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/messaging/SimpleMQClient.kt index 705f150f89..235692b111 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/messaging/SimpleMQClient.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/messaging/SimpleMQClient.kt @@ -5,7 +5,7 @@ import net.corda.core.serialization.internal.nodeSerializationEnv import net.corda.core.utilities.NetworkHostAndPort import net.corda.nodeapi.ArtemisTcpTransport import net.corda.nodeapi.ConnectionDirection -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.testing.configureTestSSL import org.apache.activemq.artemis.api.core.client.* diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt index f7709a7ada..2626eb882d 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt @@ -3,7 +3,7 @@ package net.corda.demobench.model import com.typesafe.config.Config import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort -import net.corda.nodeapi.config.parseAs +import net.corda.nodeapi.internal.config.parseAs import tornadofx.* import java.io.IOException import java.nio.file.Files diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt index 8ac6aeefdf..ae5b6deeb1 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt @@ -6,8 +6,8 @@ import net.corda.core.internal.copyToDirectory import net.corda.core.internal.createDirectories import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort -import net.corda.nodeapi.User -import net.corda.nodeapi.config.toConfig +import net.corda.nodeapi.internal.config.User +import net.corda.nodeapi.internal.config.toConfig import java.nio.file.Path import java.nio.file.StandardCopyOption diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt index 8ebcbaf2cc..0c9caca94a 100644 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt +++ b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt @@ -5,8 +5,8 @@ import com.typesafe.config.ConfigValueFactory import net.corda.core.identity.CordaX500Name import net.corda.core.utilities.NetworkHostAndPort import net.corda.node.services.config.parseAsNodeConfiguration -import net.corda.nodeapi.User -import net.corda.nodeapi.config.toConfig +import net.corda.nodeapi.internal.config.User +import net.corda.nodeapi.internal.config.toConfig import net.corda.webserver.WebServerConfig import org.assertj.core.api.Assertions.assertThat import org.junit.Test diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt index 21899794d8..18db310a5b 100644 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt +++ b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt @@ -2,7 +2,7 @@ package net.corda.demobench.model import net.corda.core.identity.CordaX500Name import net.corda.core.utilities.NetworkHostAndPort -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import org.junit.Test import java.nio.file.Path import java.nio.file.Paths diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt index ee1495ebd6..b92dfd144b 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt @@ -21,7 +21,7 @@ import net.corda.finance.flows.* import net.corda.finance.flows.CashExitFlow.ExitRequest import net.corda.finance.flows.CashIssueAndPaymentFlow.IssueAndPaymentRequest import net.corda.node.services.Permissions.Companion.startFlow -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import net.corda.testing.ALICE import net.corda.testing.BOB import net.corda.testing.driver.NodeHandle diff --git a/tools/loadtest/src/main/kotlin/net/corda/loadtest/LoadTestConfiguration.kt b/tools/loadtest/src/main/kotlin/net/corda/loadtest/LoadTestConfiguration.kt index 8e4a962002..9343605434 100644 --- a/tools/loadtest/src/main/kotlin/net/corda/loadtest/LoadTestConfiguration.kt +++ b/tools/loadtest/src/main/kotlin/net/corda/loadtest/LoadTestConfiguration.kt @@ -1,6 +1,6 @@ package net.corda.loadtest -import net.corda.nodeapi.User +import net.corda.nodeapi.internal.config.User import java.nio.file.Path import java.util.concurrent.ForkJoinPool diff --git a/tools/loadtest/src/main/kotlin/net/corda/loadtest/Main.kt b/tools/loadtest/src/main/kotlin/net/corda/loadtest/Main.kt index 0bd12ae78d..eb4e103c73 100644 --- a/tools/loadtest/src/main/kotlin/net/corda/loadtest/Main.kt +++ b/tools/loadtest/src/main/kotlin/net/corda/loadtest/Main.kt @@ -5,7 +5,7 @@ import com.typesafe.config.ConfigParseOptions import net.corda.loadtest.tests.StabilityTest import net.corda.loadtest.tests.crossCashTest import net.corda.loadtest.tests.selfIssueTest -import net.corda.nodeapi.config.parseAs +import net.corda.nodeapi.internal.config.parseAs import java.io.File /** diff --git a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt index bb4099000c..12365b2f65 100644 --- a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt +++ b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt @@ -20,8 +20,8 @@ import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_USER import net.corda.nodeapi.ArtemisTcpTransport import net.corda.nodeapi.ConnectionDirection import net.corda.nodeapi.VerifierApi -import net.corda.nodeapi.config.NodeSSLConfiguration -import net.corda.nodeapi.config.SSLConfiguration +import net.corda.nodeapi.internal.config.NodeSSLConfiguration +import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.testing.driver.* import net.corda.testing.internal.ProcessUtilities import net.corda.testing.node.NotarySpec diff --git a/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt b/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt index 7c04bf1ce9..5db494cad1 100644 --- a/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt +++ b/verifier/src/main/kotlin/net/corda/verifier/Verifier.kt @@ -12,8 +12,8 @@ import net.corda.nodeapi.ArtemisTcpTransport.Companion.tcpTransport import net.corda.nodeapi.ConnectionDirection import net.corda.nodeapi.VerifierApi import net.corda.nodeapi.VerifierApi.VERIFICATION_REQUESTS_QUEUE_NAME -import net.corda.nodeapi.config.NodeSSLConfiguration -import net.corda.nodeapi.config.getValue +import net.corda.nodeapi.internal.config.NodeSSLConfiguration +import net.corda.nodeapi.internal.config.getValue import net.corda.nodeapi.internal.addShutdownHook import net.corda.nodeapi.internal.serialization.* import net.corda.nodeapi.internal.serialization.amqp.AbstractAMQPSerializationScheme diff --git a/webserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt b/webserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt index 53522b8399..b3be74b11b 100644 --- a/webserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt +++ b/webserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt @@ -2,9 +2,9 @@ package net.corda.webserver import com.typesafe.config.Config import net.corda.core.utilities.NetworkHostAndPort -import net.corda.nodeapi.User -import net.corda.nodeapi.config.NodeSSLConfiguration -import net.corda.nodeapi.config.getValue +import net.corda.nodeapi.internal.config.User +import net.corda.nodeapi.internal.config.NodeSSLConfiguration +import net.corda.nodeapi.internal.config.getValue import java.nio.file.Path /** From e257872445913c072a22a59436aefc731e39dc2b Mon Sep 17 00:00:00 2001 From: Katelyn Baker Date: Mon, 4 Dec 2017 09:39:16 +0000 Subject: [PATCH 12/22] CORDA-553 - Review Comments --- .../internal/serialization/amqp/EnumEvolutionSerializer.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt index d5690d5f63..25413d650c 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt @@ -34,11 +34,10 @@ import java.lang.reflect.Type * @property ordinals Convenience mapping of constant to ordinality */ class EnumEvolutionSerializer( - clazz: Type, + override val type: Type, factory: SerializerFactory, private val conversions: Map, private val ordinals: Map) : AMQPSerializer { - override val type: Type = clazz override val typeDescriptor = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}")!! companion object { @@ -87,7 +86,7 @@ class EnumEvolutionSerializer( rules.putAll(defaultRules?.associateBy({ it.new }, { it.old }) ?: emptyMap()) rules.putAll(renameRules?.associateBy({ it.to }, { it.from }) ?: emptyMap()) - while (conversions.filter { it.value !in localValues }.isNotEmpty()) { + while (conversions.filterNot { it.value in localValues }.isNotEmpty()) { conversions.mapInPlace { rules[it] ?: it } } From d2f66acff73fe4d47425f58c90a0427a0545d500 Mon Sep 17 00:00:00 2001 From: Andrzej Cichocki Date: Mon, 4 Dec 2017 12:41:43 +0000 Subject: [PATCH 13/22] Use non-static Rx pool when testing. (#2165) --- .../services/network/NodeInfoWatcherTest.kt | 2 +- .../net/corda/node/internal/AbstractNode.kt | 9 ++++++++- .../main/kotlin/net/corda/node/internal/Node.kt | 4 +++- .../node/services/network/NodeInfoWatcher.kt | 6 ++---- .../services/network/NetworkMapUpdaterTest.kt | 8 ++++---- .../kotlin/net/corda/testing/driver/Driver.kt | 9 ++------- .../net/corda/testing/internal/NodeBasedTest.kt | 17 +++++++++++------ .../kotlin/net/corda/testing/node/MockNode.kt | 3 +++ 8 files changed, 34 insertions(+), 24 deletions(-) diff --git a/node/src/integration-test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt index 1a0be3d57f..224a545e0c 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt @@ -49,7 +49,7 @@ class NodeInfoWatcherTest { fun start() { val identityService = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) keyManagementService = MockKeyManagementService(identityService, ALICE_KEY) - nodeInfoWatcher = NodeInfoWatcher(tempFolder.root.toPath(), scheduler = scheduler) + nodeInfoWatcher = NodeInfoWatcher(tempFolder.root.toPath(), scheduler) nodeInfoPath = tempFolder.root.toPath() / CordformNode.NODE_INFO_DIRECTORY } diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 453afefea0..5a2e6785ad 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -68,6 +68,7 @@ import org.apache.activemq.artemis.utils.ReusableLatch import org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry import org.slf4j.Logger import rx.Observable +import rx.Scheduler import java.io.IOException import java.lang.reflect.InvocationTargetException import java.security.KeyPair @@ -225,7 +226,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, } val networkMapUpdater = NetworkMapUpdater(services.networkMapCache, - NodeInfoWatcher(configuration.baseDirectory, Duration.ofMillis(configuration.additionalNodeInfoPollingFrequencyMsec)), + NodeInfoWatcher(configuration.baseDirectory, getRxIoScheduler(), Duration.ofMillis(configuration.additionalNodeInfoPollingFrequencyMsec)), networkMapClient) runOnStop += networkMapUpdater::close @@ -251,6 +252,12 @@ abstract class AbstractNode(val configuration: NodeConfiguration, } } + /** + * Should be [rx.schedulers.Schedulers.io] for production, + * or [rx.internal.schedulers.CachedThreadScheduler] (with shutdown registered with [runOnStop]) for shared-JVM testing. + */ + protected abstract fun getRxIoScheduler(): Scheduler + open fun startShell(rpcOps: CordaRPCOps) { InteractiveShell.startShell(configuration, rpcOps, userService, _services.identityService, _services.database) } diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 71f3ae581a..2ddba4a393 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -33,6 +33,7 @@ import net.corda.nodeapi.internal.serialization.* import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme import org.slf4j.Logger import org.slf4j.LoggerFactory +import rx.schedulers.Schedulers import java.time.Clock import java.util.concurrent.atomic.AtomicInteger import javax.management.ObjectName @@ -46,7 +47,7 @@ import kotlin.system.exitProcess */ open class Node(configuration: NodeConfiguration, versionInfo: VersionInfo, - val initialiseSerialization: Boolean = true, + private val initialiseSerialization: Boolean = true, cordappLoader: CordappLoader = makeCordappLoader(configuration) ) : AbstractNode(configuration, createClock(configuration), versionInfo, cordappLoader) { companion object { @@ -293,6 +294,7 @@ open class Node(configuration: NodeConfiguration, return started } + override fun getRxIoScheduler() = Schedulers.io()!! private fun initialiseSerialization() { val classloader = cordappLoader.appClassLoader nodeSerializationEnv = SerializationEnvironmentImpl( diff --git a/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt b/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt index 76fcf6c472..df583c4ffe 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt @@ -12,7 +12,6 @@ import net.corda.core.utilities.seconds import net.corda.nodeapi.NodeInfoFilesCopier import rx.Observable import rx.Scheduler -import rx.schedulers.Schedulers import java.io.IOException import java.nio.file.Path import java.time.Duration @@ -31,9 +30,8 @@ import kotlin.streams.toList */ // TODO: Use NIO watch service instead? class NodeInfoWatcher(private val nodePath: Path, - private val pollInterval: Duration = 5.seconds, - private val scheduler: Scheduler = Schedulers.io()) { - + private val scheduler: Scheduler, + private val pollInterval: Duration = 5.seconds) { private val nodeInfoDirectory = nodePath / CordformNode.NODE_INFO_DIRECTORY private val processedNodeInfoFiles = mutableSetOf() private val _processedNodeInfoHashes = mutableSetOf() diff --git a/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt index 3390d32968..f4c4e4ee41 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NetworkMapUpdaterTest.kt @@ -51,7 +51,7 @@ class NetworkMapUpdaterTest { val networkMapClient = mock() val scheduler = TestScheduler() - val fileWatcher = NodeInfoWatcher(baseDir, scheduler = scheduler) + val fileWatcher = NodeInfoWatcher(baseDir, scheduler) val updater = NetworkMapUpdater(networkMapCache, fileWatcher, networkMapClient) // Publish node info for the first time. @@ -100,7 +100,7 @@ class NetworkMapUpdaterTest { } val scheduler = TestScheduler() - val fileWatcher = NodeInfoWatcher(baseDir, scheduler = scheduler) + val fileWatcher = NodeInfoWatcher(baseDir, scheduler) val updater = NetworkMapUpdater(networkMapCache, fileWatcher, networkMapClient) // Test adding new node. @@ -154,7 +154,7 @@ class NetworkMapUpdaterTest { } val scheduler = TestScheduler() - val fileWatcher = NodeInfoWatcher(baseDir, scheduler = scheduler) + val fileWatcher = NodeInfoWatcher(baseDir, scheduler) val updater = NetworkMapUpdater(networkMapCache, fileWatcher, networkMapClient) // Add all nodes. @@ -198,7 +198,7 @@ class NetworkMapUpdaterTest { val networkMapCache = getMockNetworkMapCache() val scheduler = TestScheduler() - val fileWatcher = NodeInfoWatcher(baseDir, scheduler = scheduler) + val fileWatcher = NodeInfoWatcher(baseDir, scheduler) val updater = NetworkMapUpdater(networkMapCache, fileWatcher, null) // Not subscribed yet. diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt index 7df5649657..e46742f885 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt @@ -24,7 +24,6 @@ import net.corda.core.utilities.* import net.corda.node.internal.Node import net.corda.node.internal.NodeStartup import net.corda.node.internal.StartedNode -import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.config.* import net.corda.node.utilities.ServiceIdentityGenerator @@ -33,6 +32,7 @@ import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.config.toConfig import net.corda.nodeapi.internal.addShutdownHook import net.corda.testing.* +import net.corda.testing.internal.InProcessNode import net.corda.testing.internal.ProcessUtilities import net.corda.testing.node.ClusterSpec import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO @@ -940,12 +940,7 @@ class DriverDSL( // Write node.conf writeConfig(nodeConf.baseDirectory, "node.conf", config) // TODO pass the version in? - val node = Node( - nodeConf, - MOCK_VERSION_INFO, - initialiseSerialization = false, - cordappLoader = CordappLoader.createDefaultWithTestPackages(nodeConf, cordappPackages)) - .start() + val node = InProcessNode(nodeConf, MOCK_VERSION_INFO, cordappPackages).start() val nodeThread = thread(name = nodeConf.myLegalName.organisation) { node.internals.run() } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/NodeBasedTest.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/NodeBasedTest.kt index ac5b735dcc..061974adf6 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/NodeBasedTest.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/NodeBasedTest.kt @@ -7,9 +7,11 @@ import net.corda.core.internal.createDirectories import net.corda.core.internal.div import net.corda.core.node.NodeInfo import net.corda.core.utilities.getOrThrow +import net.corda.node.VersionInfo import net.corda.node.internal.Node import net.corda.node.internal.StartedNode import net.corda.node.internal.cordapp.CordappLoader +import net.corda.node.services.config.* import net.corda.node.services.config.ConfigHelper import net.corda.node.services.config.configOf import net.corda.node.services.config.parseAsNodeConfiguration @@ -18,11 +20,12 @@ import net.corda.nodeapi.internal.config.User import net.corda.testing.SerializationEnvironmentRule import net.corda.testing.driver.addressMustNotBeBoundFuture import net.corda.testing.getFreeLocalPorts -import net.corda.testing.node.MockServices +import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO import org.apache.logging.log4j.Level import org.junit.After import org.junit.Rule import org.junit.rules.TemporaryFolder +import rx.internal.schedulers.CachedThreadScheduler import java.nio.file.Path import java.util.concurrent.Executors import kotlin.concurrent.thread @@ -90,11 +93,7 @@ abstract class NodeBasedTest(private val cordappPackages: List = emptyLi ) val parsedConfig = config.parseAsNodeConfiguration() - val node = Node( - parsedConfig, - MockServices.MOCK_VERSION_INFO.copy(platformVersion = platformVersion), - initialiseSerialization = false, - cordappLoader = CordappLoader.createDefaultWithTestPackages(parsedConfig, cordappPackages)).start() + val node = InProcessNode(parsedConfig, MOCK_VERSION_INFO.copy(platformVersion = platformVersion), cordappPackages).start() nodes += node ensureAllNetworkMapCachesHaveAllNodeInfos() thread(name = legalName.organisation) { @@ -117,3 +116,9 @@ abstract class NodeBasedTest(private val cordappPackages: List = emptyLi } } } + +class InProcessNode( + configuration: NodeConfiguration, versionInfo: VersionInfo, cordappPackages: List) : Node( + configuration, versionInfo, false, CordappLoader.createDefaultWithTestPackages(configuration, cordappPackages)) { + override fun getRxIoScheduler() = CachedThreadScheduler(testThreadFactory()).also { runOnStop += it::shutdown } +} diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt index d2452cab8a..2b9a966e3a 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt @@ -38,12 +38,14 @@ import net.corda.node.utilities.AffinityExecutor import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.testing.DUMMY_NOTARY +import net.corda.testing.internal.testThreadFactory import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.setGlobalSerialization import net.corda.testing.testNodeConfiguration import org.apache.activemq.artemis.utils.ReusableLatch import org.apache.sshd.common.util.security.SecurityUtils +import rx.internal.schedulers.CachedThreadScheduler import java.math.BigInteger import java.nio.file.Path import java.security.KeyPair @@ -245,6 +247,7 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete return started } + override fun getRxIoScheduler() = CachedThreadScheduler(testThreadFactory()).also { runOnStop += it::shutdown } private fun advertiseNodeToNetwork(newNode: StartedNode) { mockNet.nodes .mapNotNull { it.started } From ca06132c49661d49ed9feb03ad247230af4e0b72 Mon Sep 17 00:00:00 2001 From: Ben Abineri <32292786+benabineri@users.noreply.github.com> Date: Mon, 4 Dec 2017 14:32:47 +0000 Subject: [PATCH 14/22] add upstart instructions (#2171) * add upstart instructions * Fixes formatting. * slightly clearer wording --- docs/source/deploying-a-node.rst | 86 +++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/docs/source/deploying-a-node.rst b/docs/source/deploying-a-node.rst index e23f8814e9..f2e1b11a3e 100644 --- a/docs/source/deploying-a-node.rst +++ b/docs/source/deploying-a-node.rst @@ -7,9 +7,9 @@ Deploying a node whether they have developed and tested a CorDapp following the instructions in :doc:`generating-a-node` or are deploying a third-party CorDapp. -Linux (systemd): Installing and running Corda as a systemd service ------------------------------------------------------------------- -We recommend creating systemd services to run a node and the optional webserver. This provides logging and service +Linux: Installing and running Corda as a system service +------------------------------------------------------- +We recommend creating system services to run a node and the optional webserver. This provides logging and service handling, and ensures the Corda service is run at boot. **Prerequisites**: @@ -27,10 +27,13 @@ handling, and ensures the Corda service is run at boot. 3. Download the `Corda jar `_ (under ``/VERSION_NUMBER/corda-VERSION_NUMBER.jar``) and place it in ``/opt/corda`` -3. Create a directory called ``plugins`` in ``/opt/corda`` and save your CorDapp jar file to it. Alternatively, download one of +4. (Optional) Download the `Corda webserver jar `_ + (under ``/VERSION_NUMBER/corda-VERSION_NUMBER.jar``) and place it in ``/opt/corda`` + +5. Create a directory called ``plugins`` in ``/opt/corda`` and save your CorDapp jar file to it. Alternatively, download one of our `sample CorDapps `_ to the ``plugins`` directory -4. Save the below as ``/opt/corda/node.conf``. See :doc:`corda-configuration-file` for a description of these options +6. Save the below as ``/opt/corda/node.conf``. See :doc:`corda-configuration-file` for a description of these options .. code-block:: json @@ -59,7 +62,7 @@ handling, and ensures the Corda service is run at boot. } ] -5. Make the following changes to ``/opt/corda/node.conf``: +7. Make the following changes to ``/opt/corda/node.conf``: * Change the ``p2pAddress`` and ``rpcAddress`` values to start with your server's hostname or external IP address. This is the address other nodes or RPC interfaces will use to communicate with your node @@ -74,7 +77,12 @@ handling, and ensures the Corda service is run at boot. * Country (``C=``) is the `ISO 3166-1 alpha-2 code `_ * Change the RPC username and password -6. Create a ``corda.service`` file based on the example below and save it in the ``/etc/systemd/system/`` directory +.. note:: Ubuntu 16.04 and most current Linux distributions use SystemD, so if you are running one of these + distributions follow the steps marked **SystemD**. + If you are running Ubuntu 14.04, follow the instructions for **Upstart**. + +8. **SystemD**: Create a ``corda.service`` file based on the example below and save it in the ``/etc/systemd/system/`` + directory .. code-block:: shell @@ -92,20 +100,41 @@ handling, and ensures the Corda service is run at boot. [Install] WantedBy=multi-user.target -7. Make the following changes to ``corda.service``: +8. **Upstart**: Create a ``corda.conf`` file based on the example below and save it in the ``/etc/init/`` directory + + .. code-block:: shell + + description "Corda Node - Bank of Breakfast Tea" + + start on runlevel [2345] + stop on runlevel [!2345] + + respawn + setuid corda + chdir /opt/corda + exec java -Xmx2048m -jar /opt/corda/corda.jar + +9. Make the following changes to ``corda.service`` or ``corda.conf``: * Make sure the service description is informative - particularly if you plan to run multiple nodes. - * Change the username to the user account you want to use to run Corda. **We recommend that this is not root** + * Change the username to the user account you want to use to run Corda. **We recommend that this user account is + not root** * Set the maximum amount of memory available to the Corda process by changing the ``-Xmx2048m`` parameter - * Make sure the ``corda.service`` file is owned by root with the correct permissions: + * **SystemD**: Make sure the ``corda.service`` file is owned by root with the correct permissions: + * ``sudo chown root:root /etc/systemd/system/corda.service`` * ``sudo chmod 644 /etc/systemd/system/corda.service`` + * **Upstart**: Make sure the ``corda.conf`` file is owned by root with the correct permissions: + + * ``sudo chown root:root /etc/init/corda.conf`` + * ``sudo chmod 644 /etc/init/corda.conf`` + .. note:: The Corda webserver provides a simple interface for interacting with your installed CorDapps in a browser. Running the webserver is optional. -8. Create a ``corda-webserver.service`` file based on the example below and save it in the ``/etc/systemd/system/`` - directory. +10. **SystemD**: Create a ``corda-webserver.service`` file based on the example below and save it in the ``/etc/systemd/system/`` + directory .. code-block:: shell @@ -115,7 +144,7 @@ handling, and ensures the Corda service is run at boot. [Service] Type=simple - User=username + User=corda WorkingDirectory=/opt/corda ExecStart=/usr/bin/java -jar /opt/corda/corda-webserver.jar Restart=on-failure @@ -123,17 +152,40 @@ handling, and ensures the Corda service is run at boot. [Install] WantedBy=multi-user.target -9. Provision the required certificates to your node. Contact the network permissioning service or see - :doc:`permissioning` +10. **Upstart**: Create a ``corda-webserver.conf`` file based on the example below and save it in the ``/etc/init/`` + directory -10. You can now start a node and its webserver and set the services to start on boot by running the following ``systemctl`` commands: + .. code-block:: shell + + description "Webserver for Corda Node - Bank of Breakfast Tea" + + start on runlevel [2345] + stop on runlevel [!2345] + + respawn + setuid corda + chdir /opt/corda + exec java -jar /opt/corda/corda-webserver.jar + +11. Provision the required certificates to your node. Contact the network permissioning service or see + :doc:`permissioning` + +12. **SystemD**: You can now start a node and its webserver and set the services to start on boot by running the + following ``systemctl`` commands: * ``sudo systemctl daemon-reload`` * ``sudo systemctl enable --now corda`` * ``sudo systemctl enable --now corda-webserver`` +12. **Upstart**: You can now start a node and its webserver by running the following commands: + + * ``sudo start corda`` + * ``sudo start corda-webserver`` + +The Upstart configuration files created above tell Upstart to start the Corda services on boot so there is no need to explicitly enable them. + You can run multiple nodes by creating multiple directories and Corda services, modifying the ``node.conf`` and -``service`` files so they are unique. +SystemD or Upstart configuration files so they are unique. Windows: Installing and running Corda as a Windows service ---------------------------------------------------------- From b6427a3128c5a16b7beae11f0c1bbc1775f59aae Mon Sep 17 00:00:00 2001 From: Alberto Arri <30873160+al-r3@users.noreply.github.com> Date: Mon, 4 Dec 2017 15:44:18 +0000 Subject: [PATCH 15/22] remove calls to exitnodes from NodeStartup (#2080) --- node/src/main/kotlin/net/corda/node/Corda.kt | 3 +- .../net/corda/node/internal/NodeStartup.kt | 146 ++++++++++-------- .../registration/NetworkRegistrationHelper.kt | 17 +- 3 files changed, 90 insertions(+), 76 deletions(-) diff --git a/node/src/main/kotlin/net/corda/node/Corda.kt b/node/src/main/kotlin/net/corda/node/Corda.kt index 8b0f638040..5889aacdc7 100644 --- a/node/src/main/kotlin/net/corda/node/Corda.kt +++ b/node/src/main/kotlin/net/corda/node/Corda.kt @@ -4,10 +4,11 @@ package net.corda.node import net.corda.node.internal.NodeStartup +import kotlin.system.exitProcess fun main(args: Array) { // Pass the arguments to the Node factory. In the Enterprise edition, this line is modified to point to a subclass. // It will exit the process in case of startup failure and is not intended to be used by embedders. If you want // to embed Node in your own container, instantiate it directly and set up the configuration objects yourself. - NodeStartup(args).run() + exitProcess(if (NodeStartup(args).run()) 0 else 1) } \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt index 2947700025..ebb245c955 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -34,68 +34,79 @@ open class NodeStartup(val args: Array) { val LOGS_CAN_BE_FOUND_IN_STRING = "Logs can be found in" } - open fun run() { - val startTime = System.currentTimeMillis() - assertCanNormalizeEmptyPath() - val (argsParser, cmdlineOptions) = parseArguments() - - // We do the single node check before we initialise logging so that in case of a double-node start it - // doesn't mess with the running node's logs. - enforceSingleNodeIsRunning(cmdlineOptions.baseDirectory) - - initLogging(cmdlineOptions) - - val versionInfo = getVersionInfo() - - if (cmdlineOptions.isVersion) { - println("${versionInfo.vendor} ${versionInfo.releaseVersion}") - println("Revision ${versionInfo.revision}") - println("Platform Version ${versionInfo.platformVersion}") - exitProcess(0) - } - - // Maybe render command line help. - if (cmdlineOptions.help) { - argsParser.printHelp(System.out) - exitProcess(0) - } - - drawBanner(versionInfo) - Node.printBasicNodeInfo(LOGS_CAN_BE_FOUND_IN_STRING, System.getProperty("log-path")) - val conf0 = loadConfigFile(cmdlineOptions) - - val conf = if (cmdlineOptions.bootstrapRaftCluster) { - if (conf0 is NodeConfigurationImpl) { - println("Bootstrapping raft cluster (starting up as seed node).") - // Ignore the configured clusterAddresses to make the node bootstrap a cluster instead of joining. - conf0.copy(notary = conf0.notary?.copy(raft = conf0.notary?.raft?.copy(clusterAddresses = emptyList()))) - } else { - println("bootstrap-raft-notaries flag not recognized, exiting...") - exitProcess(1) - } - } else { - conf0 - } - - banJavaSerialisation(conf) - preNetworkRegistration(conf) - maybeRegisterWithNetworkAndExit(cmdlineOptions, conf) - logStartupInfo(versionInfo, cmdlineOptions, conf) - + /** + * @return true if the node startup was successful. This value is intended to be the exit code of the process. + */ + open fun run(): Boolean { try { - cmdlineOptions.baseDirectory.createDirectories() - startNode(conf, versionInfo, startTime, cmdlineOptions) - } catch (e: Exception) { - if (e.message?.startsWith("Unknown named curve:") == true) { - logger.error("Exception during node startup - ${e.message}. " + - "This is a known OpenJDK issue on some Linux distributions, please use OpenJDK from zulu.org or Oracle JDK.") - } else - logger.error("Exception during node startup", e) - exitProcess(1) - } + val startTime = System.currentTimeMillis() + assertCanNormalizeEmptyPath() + val (argsParser, cmdlineOptions) = parseArguments() - logger.info("Node exiting successfully") - exitProcess(0) + // We do the single node check before we initialise logging so that in case of a double-node start it + // doesn't mess with the running node's logs. + enforceSingleNodeIsRunning(cmdlineOptions.baseDirectory) + + initLogging(cmdlineOptions) + + val versionInfo = getVersionInfo() + + if (cmdlineOptions.isVersion) { + println("${versionInfo.vendor} ${versionInfo.releaseVersion}") + println("Revision ${versionInfo.revision}") + println("Platform Version ${versionInfo.platformVersion}") + return true + } + + // Maybe render command line help. + if (cmdlineOptions.help) { + argsParser.printHelp(System.out) + return true + } + + drawBanner(versionInfo) + Node.printBasicNodeInfo(LOGS_CAN_BE_FOUND_IN_STRING, System.getProperty("log-path")) + val conf0 = loadConfigFile(cmdlineOptions) + + val conf = if (cmdlineOptions.bootstrapRaftCluster) { + if (conf0 is NodeConfigurationImpl) { + println("Bootstrapping raft cluster (starting up as seed node).") + // Ignore the configured clusterAddresses to make the node bootstrap a cluster instead of joining. + conf0.copy(notary = conf0.notary?.copy(raft = conf0.notary?.raft?.copy(clusterAddresses = emptyList()))) + } else { + println("bootstrap-raft-notaries flag not recognized, exiting...") + return false + } + } else { + conf0 + } + + banJavaSerialisation(conf) + preNetworkRegistration(conf) + if (shouldRegisterWithNetwork(cmdlineOptions, conf)) { + registerWithNetwork(cmdlineOptions, conf) + return true + } + logStartupInfo(versionInfo, cmdlineOptions, conf) + + try { + cmdlineOptions.baseDirectory.createDirectories() + startNode(conf, versionInfo, startTime, cmdlineOptions) + } catch (e: Exception) { + if (e.message?.startsWith("Unknown named curve:") == true) { + logger.error("Exception during node startup - ${e.message}. " + + "This is a known OpenJDK issue on some Linux distributions, please use OpenJDK from zulu.org or Oracle JDK.") + } else { + logger.error("Exception during node startup", e) + } + return false + } + + logger.info("Node exiting successfully") + return true + } catch (e: Exception) { + return false + } } open protected fun preNetworkRegistration(conf: NodeConfiguration) = Unit @@ -155,9 +166,13 @@ open class NodeStartup(val args: Array) { logger.info("Starting as node on ${conf.p2pAddress}") } - open protected fun maybeRegisterWithNetworkAndExit(cmdlineOptions: CmdLineOptions, conf: NodeConfiguration) { + private fun shouldRegisterWithNetwork(cmdlineOptions: CmdLineOptions, conf: NodeConfiguration): Boolean { val compatibilityZoneURL = conf.compatibilityZoneURL - if (!cmdlineOptions.isRegistration || compatibilityZoneURL == null) return + return !(!cmdlineOptions.isRegistration || compatibilityZoneURL == null) + } + + open protected fun registerWithNetwork(cmdlineOptions: CmdLineOptions, conf: NodeConfiguration) { + val compatibilityZoneURL = conf.compatibilityZoneURL!! println() println("******************************************************************") println("* *") @@ -165,15 +180,14 @@ open class NodeStartup(val args: Array) { println("* *") println("******************************************************************") NetworkRegistrationHelper(conf, HTTPNetworkRegistrationService(compatibilityZoneURL)).buildKeystore() - exitProcess(0) } open protected fun loadConfigFile(cmdlineOptions: CmdLineOptions): NodeConfiguration { try { return cmdlineOptions.loadConfig() - } catch (e: ConfigException) { - println("Unable to load the configuration file: ${e.rootCause.message}") - exitProcess(2) + } catch (configException: ConfigException) { + println("Unable to load the configuration file: ${configException.rootCause.message}") + throw configException } } diff --git a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt index c350c3dd97..d9a22e30bc 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt @@ -15,7 +15,6 @@ import java.io.StringWriter import java.security.KeyPair import java.security.KeyStore import java.security.cert.Certificate -import kotlin.system.exitProcess /** * Helper for managing the node registration process, which checks for any existing certificates and requests them if @@ -33,16 +32,16 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v private val privateKeyPassword = config.keyStorePassword /** - * Ensure the initial keystore for a node is set up; note that this function may cause the process to exit under - * some circumstances. + * Ensure the initial keystore for a node is set up. * * This checks the "config.certificatesDirectory" field for certificates required to connect to a Corda network. * If the certificates are not found, a PKCS #10 certification request will be submitted to the * Corda network permissioning server via [NetworkRegistrationService]. This process will enter a polling loop until * the request has been approved, and then the certificate chain will be downloaded and stored in [KeyStore] reside in * the certificates directory. + * + * @throws CertificateRequestException if the certificate retrieved by doorman is invalid. */ - // TODO: Stop killing the calling process from within a called function. fun buildKeystore() { config.certificatesDirectory.createDirectories() val caKeyStore = loadOrCreateKeyStore(config.nodeKeystore, keystorePassword) @@ -62,12 +61,12 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v val certificates = try { pollServerForCertificates(requestId) - } catch (e: CertificateRequestException) { - System.err.println(e.message) - println("Please make sure the details in configuration file are correct and try again.") - println("Corda node will now terminate.") + } catch (certificateRequestException: CertificateRequestException) { + System.err.println(certificateRequestException.message) + System.err.println("Please make sure the details in configuration file are correct and try again.") + System.err.println("Corda node will now terminate.") requestIdStore.deleteIfExists() - exitProcess(1) + throw certificateRequestException } println("Certificate signing request approved, storing private key with the certificate chain.") From 1ff0d881b356cd9746d05b074f8fbf9a28f51b24 Mon Sep 17 00:00:00 2001 From: Katelyn Baker Date: Mon, 4 Dec 2017 15:45:52 +0000 Subject: [PATCH 16/22] CORDA-553 - Better tests for rule breaking changes to enum constants --- .../amqp/EnumEvolutionSerializer.kt | 32 +++++++--- .../serialization/amqp/SerializerFactory.kt | 6 +- .../serialization/amqp/TansformTypes.kt | 22 +++++-- .../serialization/amqp/TransformsSchema.kt | 2 +- .../serialization/amqp/EnumEvolveTests.kt | 56 ++++++++++++++++++ .../amqp/EnumEvolveTests.changedOrdinality | Bin 0 -> 618 bytes 6 files changed, 101 insertions(+), 17 deletions(-) create mode 100644 node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.changedOrdinality diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt index 25413d650c..ec8a61c793 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt @@ -6,6 +6,7 @@ import org.apache.qpid.proton.codec.Data import java.io.NotSerializableException import java.lang.UnsupportedOperationException import java.lang.reflect.Type +import java.util.* /** * Used whenever a deserialized enums fingerprint doesn't match the fingerprint of the generated @@ -62,11 +63,13 @@ class EnumEvolutionSerializer( fun make(old: RestrictedType, new: AMQPSerializer, factory: SerializerFactory, - transformsFromBlob: TransformsSchema): AMQPSerializer { - - val wireTransforms = transformsFromBlob.types[old.name] + schemas: SerializationSchemas): AMQPSerializer { + val wireTransforms = schemas.transforms.types[old.name] ?: EnumMap>(TransformTypes::class.java) val localTransforms = TransformsSchema.get(old.name, factory) - val transforms = if (wireTransforms?.size ?: -1 > localTransforms.size) wireTransforms!! else localTransforms + + // remember, the longer the list the newer we're assuming the transform set it as we assume + // evolution annotations are never removed, only added to + val transforms = if (wireTransforms.size > localTransforms.size) wireTransforms else localTransforms // if either of these isn't of the cast type then something has gone terribly wrong // elsewhere in the code @@ -84,8 +87,12 @@ class EnumEvolutionSerializer( val rules: MutableMap = mutableMapOf() rules.putAll(defaultRules?.associateBy({ it.new }, { it.old }) ?: emptyMap()) - rules.putAll(renameRules?.associateBy({ it.to }, { it.from }) ?: emptyMap()) + val renameRulesMap = renameRules?.associateBy({ it.to }, { it.from }) ?: emptyMap() + rules.putAll(renameRulesMap) + // take out set of all possible constants and build a map from those to the + // existing constants applying the rename and defaulting rules as defined + // in the schema while (conversions.filterNot { it.value in localValues }.isNotEmpty()) { conversions.mapInPlace { rules[it] ?: it } } @@ -93,8 +100,19 @@ class EnumEvolutionSerializer( // you'd think this was overkill to get access to the ordinal values for each constant but it's actually // rather tricky when you don't have access to the actual type, so this is a nice way to be able // to precompute and pass to the actual object - return EnumEvolutionSerializer(new.type, factory, conversions, - localValues.mapIndexed { i, s -> Pair (s, i)}.toMap()) + val ordinals = localValues.mapIndexed { i, s -> Pair(s, i) }.toMap() + + // create a mapping between the ordinal value and the name as it was serialised converted + // to the name as it exists. We want to test any new constants have been added to the end + // of the enum class + val serialisedOrds = ((schemas.schema.types.find { it.name == old.name } as RestrictedType).choices + .associateBy ({ it.value.toInt() }, { conversions[it.name] })) + + if (ordinals.filterNot { serialisedOrds[it.value] == it.key }.isNotEmpty()) { + throw NotSerializableException("Constants have been reordered, additions must be appended to the end") + } + + return EnumEvolutionSerializer(new.type, factory, conversions, ordinals) } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt index 764f0b5458..39abcc58f5 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt @@ -46,11 +46,11 @@ open class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) { private fun getEvolutionSerializer( typeNotation: TypeNotation, newSerializer: AMQPSerializer, - transforms: TransformsSchema): AMQPSerializer { + schemas: SerializationSchemas): AMQPSerializer { return serializersByDescriptor.computeIfAbsent(typeNotation.descriptor.name!!) { when (typeNotation) { is CompositeType -> EvolutionSerializer.make(typeNotation, newSerializer as ObjectSerializer, this) - is RestrictedType -> EnumEvolutionSerializer.make(typeNotation, newSerializer, this, transforms) + is RestrictedType -> EnumEvolutionSerializer.make(typeNotation, newSerializer, this, schemas) } } } @@ -210,7 +210,7 @@ open class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) { // doesn't match that of the serialised object then we are dealing with different // instance of the class, as such we need to build an EvolutionSerialiser if (serialiser.typeDescriptor != typeNotation.descriptor.name) { - getEvolutionSerializer(typeNotation, serialiser, schemaAndDescriptor.schemas.transforms) + getEvolutionSerializer(typeNotation, serialiser, schemaAndDescriptor.schemas) } } catch (e: ClassNotFoundException) { if (sentinel) throw e diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt index e21498f7b0..0003a48ba2 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt @@ -28,14 +28,14 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType Unknown({ UnknownTransform() }) { override fun getDescriptor(): Any = DESCRIPTOR override fun getDescribed(): Any = ordinal - override fun validate(l : List, constants: Set) { } + override fun validate(l : List, constants: Map) { } }, EnumDefault({ a -> EnumDefaultSchemaTransform((a as CordaSerializationTransformEnumDefault).old, a.new) }) { override fun getDescriptor(): Any = DESCRIPTOR override fun getDescribed(): Any = ordinal /** - * Validates a list of constant additions to an enumerated types, to be valid a default (the value + * Validates a list of constant additions to an enumerated type. To be valid a default (the value * that should be used when we cannot use the new value) must refer to a constant that exists in the * enum class as it exists now and it cannot refer to itself. * @@ -43,8 +43,12 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType * existing value * @param constants The list of enum constants on the type the transforms are being applied to */ - override fun validate(l : List, constants: Set) { - uncheckedCast, List>(l).forEach { + override fun validate(list : List, constants: Map) { + uncheckedCast, List>(list).forEach { + if (!constants.contains(it.new)) { + throw NotSerializableException("Unknown enum constant ${it.new}") + } + if (!constants.contains(it.old)) { throw NotSerializableException( "Enum extension defaults must be to a valid constant: ${it.new} -> ${it.old}. ${it.old} " + @@ -54,6 +58,12 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType if (it.old == it.new) { throw NotSerializableException("Enum extension ${it.new} cannot default to itself") } + + if (constants[it.old]!! >= constants[it.new]!!) { + throw NotSerializableException( + "Enum extensions must default to older constants. ${it.new}[${constants[it.new]}] " + + "defaults to ${it.old}[${constants[it.old]}] which is greater") + } } } }, @@ -70,7 +80,7 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType * and old values * @param constants The list of enum constants on the type the transforms are being applied to */ - override fun validate(l : List, constants: Set) { + override fun validate(l : List, constants: Map) { object : Any() { val from : MutableSet = mutableSetOf() val to : MutableSet = mutableSetOf() }.apply { @@ -94,7 +104,7 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType //} ; - abstract fun validate(l: List, constants: Set) + abstract fun validate(l: List, constants: Map) companion object : DescribedTypeConstructor { val DESCRIPTOR = AMQPDescriptorRegistry.TRANSFORM_ELEMENT_KEY.amqpDescriptor diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt index c88addacaa..378675b84e 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt @@ -225,7 +225,7 @@ data class TransformsSchema(val types: Map Pair(s.toString(), i) }.toMap()) } } } catch (_: ClassNotFoundException) { diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt index 2b7930c707..b2939d7fa9 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.kt @@ -355,4 +355,60 @@ class EnumEvolveTests { load (stage4Resources).forEach { assertEquals(it.second, it.first.e) } load (stage5Resources).forEach { assertEquals(it.second, it.first.e) } } + + @CordaSerializationTransformEnumDefault(old = "A", new = "F") + enum class BadNewValue { A, B, C, D } + + @Test + fun badNewValue() { + val sf = testDefaultFactory() + + data class C (val e : BadNewValue) + + Assertions.assertThatThrownBy { + SerializationOutput(sf).serialize(C(BadNewValue.A)) + }.isInstanceOf(NotSerializableException::class.java) + } + + @CordaSerializationTransformEnumDefaults( + CordaSerializationTransformEnumDefault(new = "D", old = "E"), + CordaSerializationTransformEnumDefault(new = "E", old = "A") + ) + enum class OutOfOrder { A, B, C, D, E} + + @Test + fun outOfOrder() { + val sf = testDefaultFactory() + + data class C (val e : OutOfOrder) + + Assertions.assertThatThrownBy { + SerializationOutput(sf).serialize(C(OutOfOrder.A)) + }.isInstanceOf(NotSerializableException::class.java) + } + + // class as it existed as it was serialized + // + // enum class ChangedOrdinality { A, B, C } + // + // class as it exists for the tests + @CordaSerializationTransformEnumDefault("D", "A") + enum class ChangedOrdinality { A, B, D, C } + + @Test + fun changedOrdinality() { + val resource = "${javaClass.simpleName}.${testName()}" + val sf = testDefaultFactory() + + data class C(val e: ChangedOrdinality) + + // Uncomment to re-generate test files, needs to be done in three stages + // File(URI("$localPath/$resource")).writeBytes( + // SerializationOutput(sf).serialize(C(ChangedOrdinality.A)).bytes) + + Assertions.assertThatThrownBy { + DeserializationInput(sf).deserialize(SerializedBytes( + File(EvolvabilityTests::class.java.getResource(resource).toURI()).readBytes())) + }.isInstanceOf(NotSerializableException::class.java) + } } diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.changedOrdinality b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.changedOrdinality new file mode 100644 index 0000000000000000000000000000000000000000..af084de97a4905407e842a4687e7f13323a45017 GIT binary patch literal 618 zcmb`EPfNov7{-%!Yw>Hy@EF__{|p9QOJR7h=*kYerA_FfUD~y=W1jX^f?p&a1dm?4 z`W^fRW*`v@f}of1^6)(To;Pn=R0Kl+!1gK8F97fb0BfoT8$9fDDp0y}49WRCVYiFx z*&y9a#Psyyh^NVVG*SqD^PTx8@uXj`^DJ65H|1sHACp<8eU2sJIR4^TngicHf$&ui zmg&${?_GIi;D{H5;*uf81+6&FQB5m`b9RpfD>%Z-Rf$4=w+x#iZ)i+wQTNgX<{2eX zMVL-7vFQa~Xb84Cuzs_ir!r_l9W{3)q%!(jv!LB9^t`ceD2{q|{vF|kvXiq~7)tvC ge!82dhPDa0%H3U2!o!y2OW1EofrJAi?L9*90ks*$9RL6T literal 0 HcmV?d00001 From f7b87c08d6bf1c386974672b2d44976b4aaf9359 Mon Sep 17 00:00:00 2001 From: Maksymilian Pawlak <120831+m4ksio@users.noreply.github.com> Date: Mon, 4 Dec 2017 17:05:25 +0000 Subject: [PATCH 17/22] Crash dependency upgrade (#2146) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e72f20a51a..a1025ae5fc 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ buildscript { ext.dependency_checker_version = '3.0.1' ext.commons_collections_version = '4.1' ext.beanutils_version = '1.9.3' - ext.crash_version = 'faba68332800f21278c5b600bf14ad55cef5989e' + ext.crash_version = 'cce5a00f114343c1145c1d7756e1dd6df3ea984e' ext.jsr305_version = constants.getProperty("jsr305Version") // Update 121 is required for ObjectInputFilter and at time of writing 131 was latest: From 4374c32a75ae46522cb78965b1989ac2f08edc8a Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Thu, 30 Nov 2017 17:39:51 +0000 Subject: [PATCH 18/22] HttpUtils methods now throw an IOException when a request isn't successful, rather than returning a Boolean. This has been the cause of previous bugs as people forget to check for the false case. --- .../corda/bank/api/BankOfCordaClientApi.kt | 2 -- .../kotlin/net/corda/irs/IRSDemoTest.kt | 4 +-- .../corda/irs/web/demo/IrsDemoClientApi.kt | 8 +++--- .../net/corda/vega/SimmValuationTest.kt | 6 ++--- .../kotlin/net/corda/testing/http/HttpApi.kt | 14 +++++----- .../net/corda/testing/http/HttpUtils.kt | 26 +++++-------------- 6 files changed, 23 insertions(+), 37 deletions(-) diff --git a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaClientApi.kt b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaClientApi.kt index ac0a136f7c..ef020df6ef 100644 --- a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaClientApi.kt +++ b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaClientApi.kt @@ -2,7 +2,6 @@ package net.corda.bank.api import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams import net.corda.client.rpc.CordaRPCClient -import net.corda.core.contracts.Amount import net.corda.core.messaging.startFlow import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.NetworkHostAndPort @@ -10,7 +9,6 @@ import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow import net.corda.finance.flows.CashIssueAndPaymentFlow import net.corda.testing.http.HttpApi -import java.util.* /** * Interface for communicating with Bank of Corda node diff --git a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt index bf850cc841..6b53396fa4 100644 --- a/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt +++ b/samples/irs-demo/src/integration-test/kotlin/net/corda/irs/IRSDemoTest.kt @@ -110,7 +110,7 @@ class IRSDemoTest { private fun runDateChange(nodeApi: HttpApi) { log.info("Running date change against ${nodeApi.root}") - assertThat(nodeApi.putJson("demodate", "\"$futureDate\"")).isTrue() + nodeApi.putJson("demodate", "\"$futureDate\"") } private fun runTrade(nodeApi: HttpApi, oracle: Party) { @@ -123,7 +123,7 @@ class IRSDemoTest { private fun runUploadRates(nodeApi: HttpApi) { log.info("Running upload rates against ${nodeApi.root}") val fileContents = loadResourceFile("net/corda/irs/simulation/example.rates.txt") - assertThat(nodeApi.postPlain("fixes", fileContents)).isTrue() + nodeApi.postPlain("fixes", fileContents) } private fun loadResourceFile(filename: String): String { diff --git a/samples/irs-demo/web/src/test/kotlin/net/corda/irs/web/demo/IrsDemoClientApi.kt b/samples/irs-demo/web/src/test/kotlin/net/corda/irs/web/demo/IrsDemoClientApi.kt index 82e81de047..9bebc4481c 100644 --- a/samples/irs-demo/web/src/test/kotlin/net/corda/irs/web/demo/IrsDemoClientApi.kt +++ b/samples/irs-demo/web/src/test/kotlin/net/corda/irs/web/demo/IrsDemoClientApi.kt @@ -8,7 +8,7 @@ import org.apache.commons.io.IOUtils /** * Interface for communicating with nodes running the IRS demo. */ -class IRSDemoClientApi(private val hostAndPort: NetworkHostAndPort) { +class IRSDemoClientApi(hostAndPort: NetworkHostAndPort) { private val api = HttpApi.fromHostAndPort(hostAndPort, apiRoot) fun runTrade(tradeId: String, oracleName: CordaX500Name) { @@ -17,14 +17,14 @@ class IRSDemoClientApi(private val hostAndPort: NetworkHostAndPort) { api.postJson("deals", tradeFile) } - fun runDateChange(newDate: String): Boolean { - return api.putJson("demodate", "\"$newDate\"") + fun runDateChange(newDate: String) { + api.putJson("demodate", "\"$newDate\"") } // TODO: Add uploading of files to the HTTP API fun runUploadRates() { val fileContents = IOUtils.toString(Thread.currentThread().contextClassLoader.getResourceAsStream("net/corda/irs/simulation/example.rates.txt"), Charsets.UTF_8.name()) - check(api.postPlain("fixes", fileContents)) + api.postPlain("fixes", fileContents) println("Rates successfully uploaded!") } diff --git a/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt b/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt index 2b74779a1c..ee92826c94 100644 --- a/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt +++ b/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt @@ -38,7 +38,7 @@ class SimmValuationTest { val nodeBParty = getPartyWithName(nodeAApi, nodeBLegalName) val nodeAParty = getPartyWithName(nodeBApi, nodeALegalName) - assertThat(createTradeBetween(nodeAApi, nodeBParty, testTradeId)).isTrue() + createTradeBetween(nodeAApi, nodeBParty, testTradeId) assertTradeExists(nodeBApi, nodeAParty, testTradeId) assertTradeExists(nodeAApi, nodeBParty, testTradeId) runValuationsBetween(nodeAApi, nodeBParty) @@ -55,10 +55,10 @@ class SimmValuationTest { return partyApi.getJson("whoami") } - private fun createTradeBetween(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty, tradeId: String): Boolean { + private fun createTradeBetween(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty, tradeId: String) { val trade = SwapDataModel(tradeId, "desc", valuationDate, "EUR_FIXED_1Y_EURIBOR_3M", valuationDate, LocalDate.parse("2020-01-02"), BuySell.BUY, BigDecimal.valueOf(1000), BigDecimal.valueOf(0.1)) - return partyApi.putJson("${counterparty.id}/trades", trade) + partyApi.putJson("${counterparty.id}/trades", trade) } private fun assertTradeExists(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty, tradeId: String) { diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpApi.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpApi.kt index 7e948285dc..b0ffd991e8 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpApi.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpApi.kt @@ -1,6 +1,7 @@ package net.corda.testing.http import com.fasterxml.jackson.databind.ObjectMapper +import net.corda.client.jackson.JacksonSupport import net.corda.core.utilities.NetworkHostAndPort import java.net.URL @@ -29,16 +30,17 @@ class HttpApi(val root: URL, val mapper: ObjectMapper = defaultMapper) { /** * Send a GET request to the path on the API specified. */ - inline fun getJson(path: String, params: Map = mapOf()) = HttpUtils.getJson(URL(root, path), params, mapper) + inline fun getJson(path: String, params: Map = mapOf()): T { + return HttpUtils.getJson(URL(root, path), params, mapper) + } private fun toJson(any: Any) = any as? String ?: HttpUtils.defaultMapper.writeValueAsString(any) companion object { - fun fromHostAndPort(hostAndPort: NetworkHostAndPort, base: String, protocol: String = "http", mapper: ObjectMapper = defaultMapper): HttpApi - = HttpApi(URL("$protocol://$hostAndPort/$base/"), mapper) - - private val defaultMapper: ObjectMapper by lazy { - net.corda.client.jackson.JacksonSupport.createNonRpcMapper() + fun fromHostAndPort(hostAndPort: NetworkHostAndPort, base: String, protocol: String = "http", mapper: ObjectMapper = defaultMapper): HttpApi { + return HttpApi(URL("$protocol://$hostAndPort/$base/"), mapper) } + + private val defaultMapper: ObjectMapper by lazy { JacksonSupport.createNonRpcMapper() } } } diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpUtils.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpUtils.kt index cf1af9b9ab..5e87f4e36b 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpUtils.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/http/HttpUtils.kt @@ -5,7 +5,6 @@ import okhttp3.MediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody -import org.slf4j.LoggerFactory import java.io.IOException import java.net.URL import java.util.concurrent.TimeUnit @@ -14,8 +13,6 @@ import java.util.concurrent.TimeUnit * A small set of utilities for making HttpCalls, aimed at demos and tests. */ object HttpUtils { - private val logger = LoggerFactory.getLogger(javaClass) - private val client by lazy { OkHttpClient.Builder() .connectTimeout(5, TimeUnit.SECONDS) @@ -26,19 +23,19 @@ object HttpUtils { net.corda.client.jackson.JacksonSupport.createNonRpcMapper() } - fun putJson(url: URL, data: String): Boolean { + fun putJson(url: URL, data: String) { val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data) - return makeRequest(Request.Builder().url(url).header("Content-Type", "application/json").put(body).build()) + makeRequest(Request.Builder().url(url).header("Content-Type", "application/json").put(body).build()) } fun postJson(url: URL, data: String) { val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data) - makeExceptionalRequest(Request.Builder().url(url).header("Content-Type", "application/json").post(body).build()) + makeRequest(Request.Builder().url(url).header("Content-Type", "application/json").post(body).build()) } - fun postPlain(url: URL, data: String): Boolean { + fun postPlain(url: URL, data: String) { val body = RequestBody.create(MediaType.parse("text/plain; charset=utf-8"), data) - return makeRequest(Request.Builder().url(url).post(body).build()) + makeRequest(Request.Builder().url(url).post(body).build()) } inline fun getJson(url: URL, params: Map = mapOf(), mapper: ObjectMapper = defaultMapper): T { @@ -47,21 +44,10 @@ object HttpUtils { return mapper.readValue(parameterisedUrl, T::class.java) } - // TODO Move everything to use this instead of makeRequest - private fun makeExceptionalRequest(request: Request) { + private fun makeRequest(request: Request) { val response = client.newCall(request).execute() if (!response.isSuccessful) { throw IOException("${request.method()} to ${request.url()} returned a ${response.code()}: ${response.body().string()}") } } - - private fun makeRequest(request: Request): Boolean { - val response = client.newCall(request).execute() - - if (!response.isSuccessful) { - logger.error("Could not fulfill HTTP request of type ${request.method()} to ${request.url()}. Status Code: ${response.code()}. Message: ${response.body().string()}") - } - - return response.isSuccessful - } } From 426b5eb44ad424cc5cdfda201a47d9cd32d0422e Mon Sep 17 00:00:00 2001 From: Joel Dudley Date: Tue, 5 Dec 2017 10:25:48 +0000 Subject: [PATCH 19/22] Adds an example use of pagination. --- docs/source/api-vault-query.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/source/api-vault-query.rst b/docs/source/api-vault-query.rst index a525a8b413..b0f295268e 100644 --- a/docs/source/api-vault-query.rst +++ b/docs/source/api-vault-query.rst @@ -176,6 +176,17 @@ define a ``PageSpecification`` to correctly process results with efficient memor place to alert API users to the need for pagination where a single query returns more than 200 results and no ``PageSpecification`` has been supplied. +Here's a query that extracts every unconsumed ``ContractState`` from the vault in pages of size 200, starting from the +default page number (page one): + +.. container:: codeset + + .. sourcecode:: kotlin + + val vaultSnapshot = proxy.vaultQueryBy( + QueryCriteria.VaultQueryCriteria(Vault.StateStatus.UNCONSUMED), + PageSpecification(DEFAULT_PAGE_NUM, 200)) + .. note:: A pages maximum size ``MAX_PAGE_SIZE`` is defined as ``Int.MAX_VALUE`` and should be used with extreme caution as results returned may exceed your JVM's memory footprint. From 9adf4bfc57f4a91eb98c59c4ea859566633bb840 Mon Sep 17 00:00:00 2001 From: Joel Dudley Date: Tue, 5 Dec 2017 14:23:41 +0000 Subject: [PATCH 20/22] Removes the maxWidth parameter that caused the docsite to not use the full screen width. --- docs/source/_static/css/custom.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css index c7f2ab9999..ebf9a0e17d 100644 --- a/docs/source/_static/css/custom.css +++ b/docs/source/_static/css/custom.css @@ -71,7 +71,8 @@ a:visited { } .wy-nav-content { - background-color: #fff max-width: 1000px; + background-color: #fff; + max-width: none; } .wy-nav-side { From e4d76204c1dca54ab4865f863a0c812bcd028b53 Mon Sep 17 00:00:00 2001 From: Andrzej Cichocki Date: Tue, 5 Dec 2017 14:50:56 +0000 Subject: [PATCH 21/22] Pass some key constants into MockServices. (#2173) --- .../finance/contracts/CommercialPaperTests.kt | 12 ++++++-- .../finance/contracts/asset/CashTests.kt | 8 +++-- .../services/network/NodeInfoWatcherTest.kt | 3 +- .../identity/InMemoryIdentityService.kt | 19 ++++-------- .../services/vault/VaultQueryJavaTests.java | 10 +++---- .../net/corda/node/InteractiveShellTest.kt | 5 ++-- .../events/NodeSchedulerServiceTest.kt | 2 +- .../identity/InMemoryIdentityServiceTests.kt | 25 +++++++++------- .../PersistentIdentityServiceTests.kt | 7 +++-- .../services/vault/NodeVaultServiceTest.kt | 7 ++++- .../node/services/vault/VaultQueryTests.kt | 8 +++-- .../node/services/vault/VaultWithCashTest.kt | 7 ++++- .../corda/netmap/simulation/IRSSimulation.kt | 5 ++-- .../net/corda/testing/node/MockServices.kt | 29 ++++--------------- 14 files changed, 72 insertions(+), 75 deletions(-) diff --git a/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt b/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt index 0684675724..25d65f3dab 100644 --- a/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt +++ b/finance/src/test/kotlin/net/corda/finance/contracts/CommercialPaperTests.kt @@ -16,6 +16,7 @@ import net.corda.testing.* import net.corda.testing.contracts.VaultFiller import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices +import net.corda.testing.node.makeTestIdentityService import org.junit.Ignore import org.junit.Rule import org.junit.Test @@ -232,7 +233,10 @@ class CommercialPaperTestsGeneric { // @Test @Ignore fun `issue move and then redeem`() = withTestSerialization { - val aliceDatabaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(ALICE_KEY)) + val aliceDatabaseAndServices = makeTestDatabaseAndMockServices( + listOf(ALICE_KEY), + makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)), + initialIdentityName = MEGA_CORP.name) val databaseAlice = aliceDatabaseAndServices.first aliceServices = aliceDatabaseAndServices.second aliceVaultService = aliceServices.vaultService @@ -241,8 +245,10 @@ class CommercialPaperTestsGeneric { alicesVault = VaultFiller(aliceServices, DUMMY_NOTARY, DUMMY_NOTARY_KEY, rngFactory = ::Random).fillWithSomeTestCash(9000.DOLLARS, issuerServices, 1, DUMMY_CASH_ISSUER) aliceVaultService = aliceServices.vaultService } - - val bigCorpDatabaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(BIG_CORP_KEY)) + val bigCorpDatabaseAndServices = makeTestDatabaseAndMockServices( + listOf(BIG_CORP_KEY), + makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)), + initialIdentityName = MEGA_CORP.name) val databaseBigCorp = bigCorpDatabaseAndServices.first bigCorpServices = bigCorpDatabaseAndServices.second bigCorpVaultService = bigCorpServices.vaultService diff --git a/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt b/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt index faa9665f63..bfec19b57d 100644 --- a/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt +++ b/finance/src/test/kotlin/net/corda/finance/contracts/asset/CashTests.kt @@ -25,6 +25,7 @@ import net.corda.testing.contracts.DummyState import net.corda.testing.contracts.VaultFiller import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices +import net.corda.testing.node.makeTestIdentityService import org.junit.After import org.junit.Before import org.junit.Rule @@ -70,9 +71,10 @@ class CashTests { miniCorpServices = MockServices(listOf("net.corda.finance.contracts.asset"), MINI_CORP.name, MINI_CORP_KEY) val notaryServices = MockServices(listOf("net.corda.finance.contracts.asset"), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY) val databaseAndServices = makeTestDatabaseAndMockServices( - cordappPackages = listOf("net.corda.finance.contracts.asset"), - initialIdentityName = CordaX500Name(organisation = "Me", locality = "London", country = "GB"), - keys = listOf(generateKeyPair())) + listOf(generateKeyPair()), + makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)), + listOf("net.corda.finance.contracts.asset"), + CordaX500Name("Me", "London", "GB")) database = databaseAndServices.first ourServices = databaseAndServices.second diff --git a/node/src/integration-test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt index 224a545e0c..32716708de 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt @@ -13,6 +13,7 @@ import net.corda.node.services.identity.InMemoryIdentityService import net.corda.nodeapi.NodeInfoFilesCopier import net.corda.testing.* import net.corda.testing.node.MockKeyManagementService +import net.corda.testing.node.makeTestIdentityService import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.contentOf import org.junit.Before @@ -47,7 +48,7 @@ class NodeInfoWatcherTest { @Before fun start() { - val identityService = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val identityService = makeTestIdentityService() keyManagementService = MockKeyManagementService(identityService, ALICE_KEY) nodeInfoWatcher = NodeInfoWatcher(tempFolder.root.toPath(), scheduler) nodeInfoPath = tempFolder.root.toPath() / CordformNode.NODE_INFO_DIRECTORY diff --git a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt index 7fbbd810b8..97e1c03adc 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt @@ -24,14 +24,8 @@ import javax.annotation.concurrent.ThreadSafe * @param identities initial set of identities for the service, typically only used for unit tests. */ @ThreadSafe -class InMemoryIdentityService(identities: Iterable = emptySet(), - confidentialIdentities: Iterable = emptySet(), - override val trustRoot: X509Certificate, - vararg caCertificates: X509Certificate) : SingletonSerializeAsToken(), IdentityService { - constructor(wellKnownIdentities: Iterable = emptySet(), - confidentialIdentities: Iterable = emptySet(), - trustRoot: X509CertificateHolder) : this(wellKnownIdentities, confidentialIdentities, trustRoot.cert) - +class InMemoryIdentityService(identities: Iterable, + trustRoot: X509CertificateHolder) : SingletonSerializeAsToken(), IdentityService { companion object { private val log = contextLogger() } @@ -40,18 +34,15 @@ class InMemoryIdentityService(identities: Iterable = emptyS * Certificate store for certificate authority and intermediary certificates. */ override val caCertStore: CertStore - override val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null) + override val trustRoot = trustRoot.cert + override val trustAnchor: TrustAnchor = TrustAnchor(this.trustRoot, null) private val keyToParties = ConcurrentHashMap() private val principalToParties = ConcurrentHashMap() init { - val caCertificatesWithRoot: Set = caCertificates.toSet() + trustRoot - caCertStore = CertStore.getInstance("Collection", CollectionCertStoreParameters(caCertificatesWithRoot)) + caCertStore = CertStore.getInstance("Collection", CollectionCertStoreParameters(setOf(this.trustRoot))) keyToParties.putAll(identities.associateBy { it.owningKey }) principalToParties.putAll(identities.associateBy { it.name }) - confidentialIdentities.forEach { identity -> - principalToParties.computeIfAbsent(identity.name) { identity } - } } // TODO: Check the certificate validation logic diff --git a/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java b/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java index c1f2a539eb..838370c38c 100644 --- a/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java +++ b/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java @@ -19,7 +19,6 @@ import net.corda.core.utilities.OpaqueBytes; import net.corda.finance.contracts.DealState; import net.corda.finance.contracts.asset.Cash; import net.corda.finance.schemas.CashSchemaV1; -import net.corda.node.services.identity.InMemoryIdentityService; import net.corda.nodeapi.internal.persistence.CordaPersistence; import net.corda.nodeapi.internal.persistence.DatabaseTransaction; import net.corda.testing.SerializationEnvironmentRule; @@ -48,6 +47,7 @@ import static net.corda.finance.contracts.asset.CashUtilities.*; import static net.corda.testing.CoreTestUtils.*; import static net.corda.testing.TestConstants.*; import static net.corda.testing.node.MockServices.makeTestDatabaseAndMockServices; +import static net.corda.testing.node.MockServicesKt.makeTestIdentityService; import static org.assertj.core.api.Assertions.assertThat; public class VaultQueryJavaTests { @@ -61,14 +61,12 @@ public class VaultQueryJavaTests { @Before public void setUp() throws CertificateException, InvalidAlgorithmParameterException { List cordappPackages = Arrays.asList("net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1.class.getPackage().getName()); - IdentityService identitySvc = new InMemoryIdentityService( - Arrays.asList(getMEGA_CORP_IDENTITY(), getDUMMY_CASH_ISSUER_IDENTITY(), getDUMMY_NOTARY_IDENTITY()), - Collections.emptySet(), - getDEV_TRUST_ROOT()); + IdentityService identitySvc = makeTestIdentityService(Arrays.asList(getMEGA_CORP_IDENTITY(), getDUMMY_CASH_ISSUER_IDENTITY(), getDUMMY_NOTARY_IDENTITY())); Pair databaseAndServices = makeTestDatabaseAndMockServices( Arrays.asList(getMEGA_CORP_KEY(), getDUMMY_NOTARY_KEY()), identitySvc, - cordappPackages); + cordappPackages, + getMEGA_CORP().getName()); issuerServices = new MockServices(cordappPackages, getDUMMY_CASH_ISSUER_NAME(), getDUMMY_CASH_ISSUER_KEY(), getBOC_KEY()); database = databaseAndServices.getFirst(); MockServices services = databaseAndServices.getSecond(); diff --git a/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt b/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt index 3f0a7d40c1..242536a172 100644 --- a/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt +++ b/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt @@ -11,13 +11,12 @@ import net.corda.core.internal.concurrent.openFuture import net.corda.core.messaging.FlowProgressHandleImpl import net.corda.core.utilities.ProgressTracker import net.corda.nodeapi.internal.persistence.DatabaseConfig -import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.shell.InteractiveShell import net.corda.node.internal.configureDatabase -import net.corda.testing.DEV_TRUST_ROOT import net.corda.testing.MEGA_CORP import net.corda.testing.MEGA_CORP_IDENTITY import net.corda.testing.node.MockServices +import net.corda.testing.node.makeTestIdentityService import net.corda.testing.rigorousMock import org.junit.After import org.junit.Before @@ -49,7 +48,7 @@ class InteractiveShellTest { override fun call() = a } - private val ids = InMemoryIdentityService(listOf(MEGA_CORP_IDENTITY), trustRoot = DEV_TRUST_ROOT) + private val ids = makeTestIdentityService(listOf(MEGA_CORP_IDENTITY)) private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory()) private fun check(input: String, expected: String) { diff --git a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt index 72b61e053b..6a91f03ef3 100644 --- a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt @@ -91,7 +91,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { calls = 0 val dataSourceProps = makeTestDataSourceProperties() database = configureDatabase(dataSourceProps, DatabaseConfig(), rigorousMock()) - val identityService = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val identityService = makeTestIdentityService() kms = MockKeyManagementService(identityService, ALICE_KEY) val configuration = testNodeConfiguration(Paths.get("."), CordaX500Name("Alice", "London", "GB")) val validatedTransactions = MockTransactionStorage() diff --git a/node/src/test/kotlin/net/corda/node/services/identity/InMemoryIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/identity/InMemoryIdentityServiceTests.kt index 85857636dd..9ed1ed2a4a 100644 --- a/node/src/test/kotlin/net/corda/node/services/identity/InMemoryIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/identity/InMemoryIdentityServiceTests.kt @@ -23,9 +23,13 @@ import kotlin.test.assertNull * Tests for the in memory identity service. */ class InMemoryIdentityServiceTests { + companion object { + private fun createService(vararg identities: PartyAndCertificate) = InMemoryIdentityService(identities.toSet(), DEV_TRUST_ROOT) + } + @Test fun `get all identities`() { - val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val service = createService() // Nothing registered, so empty set assertNull(service.getAllIdentities().firstOrNull()) @@ -43,7 +47,7 @@ class InMemoryIdentityServiceTests { @Test fun `get identity by key`() { - val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val service = createService() assertNull(service.partyFromKey(ALICE_PUBKEY)) service.verifyAndRegisterIdentity(ALICE_IDENTITY) assertEquals(ALICE, service.partyFromKey(ALICE_PUBKEY)) @@ -52,13 +56,13 @@ class InMemoryIdentityServiceTests { @Test fun `get identity by name with no registered identities`() { - val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val service = createService() assertNull(service.wellKnownPartyFromX500Name(ALICE.name)) } @Test fun `get identity by substring match`() { - val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val service = createService() service.verifyAndRegisterIdentity(ALICE_IDENTITY) service.verifyAndRegisterIdentity(BOB_IDENTITY) val alicente = getTestPartyAndCertificate(CordaX500Name(organisation = "Alicente Worldwide", locality = "London", country = "GB"), generateKeyPair().public) @@ -70,7 +74,7 @@ class InMemoryIdentityServiceTests { @Test fun `get identity by name`() { - val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val service = createService() val identities = listOf("Org A", "Org B", "Org C") .map { getTestPartyAndCertificate(CordaX500Name(organisation = it, locality = "London", country = "GB"), generateKeyPair().public) } assertNull(service.wellKnownPartyFromX500Name(identities.first().name)) @@ -87,7 +91,7 @@ class InMemoryIdentityServiceTests { val rootKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val rootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, rootKey) val txKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) - val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val service = createService() // TODO: Generate certificate with an EdDSA key rather than ECDSA val identity = Party(rootCert.cert) val txIdentity = AnonymousParty(txKey.public) @@ -108,7 +112,7 @@ class InMemoryIdentityServiceTests { val (_, bobTxIdentity) = createParty(ALICE.name, DEV_CA) // Now we have identities, construct the service and let it know about both - val service = InMemoryIdentityService(setOf(alice), emptySet(), DEV_TRUST_ROOT) + val service = createService(alice) service.verifyAndRegisterIdentity(aliceTxIdentity) var actual = service.certificateFromKey(aliceTxIdentity.party.owningKey) @@ -131,8 +135,7 @@ class InMemoryIdentityServiceTests { val (bob, anonymousBob) = createParty(BOB.name, DEV_CA) // Now we have identities, construct the service and let it know about both - val service = InMemoryIdentityService(setOf(alice, bob), emptySet(), DEV_TRUST_ROOT) - + val service = createService(alice, bob) service.verifyAndRegisterIdentity(anonymousAlice) service.verifyAndRegisterIdentity(anonymousBob) @@ -168,7 +171,7 @@ class InMemoryIdentityServiceTests { */ @Test fun `deanonymising a well known identity should return the identity`() { - val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val service = createService() val expected = ALICE service.verifyAndRegisterIdentity(ALICE_IDENTITY) val actual = service.wellKnownPartyFromAnonymous(expected) @@ -180,7 +183,7 @@ class InMemoryIdentityServiceTests { */ @Test fun `deanonymising a false well known identity should return null`() { - val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val service = createService() val notAlice = Party(ALICE.name, generateKeyPair().public) service.verifyAndRegisterIdentity(ALICE_IDENTITY) val actual = service.wellKnownPartyFromAnonymous(notAlice) diff --git a/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt index f3185b58eb..95c17a7863 100644 --- a/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt @@ -17,6 +17,7 @@ import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.testing.* import net.corda.testing.node.MockServices +import net.corda.testing.node.makeTestIdentityService import org.junit.After import org.junit.Before import org.junit.Test @@ -34,7 +35,7 @@ class PersistentIdentityServiceTests { @Before fun setup() { - val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(keys = emptyList(), identityService = PersistentIdentityService(DEV_TRUST_ROOT)) + val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(emptyList(), PersistentIdentityService(DEV_TRUST_ROOT), initialIdentityName = MEGA_CORP.name) database = databaseAndServices.first services = databaseAndServices.second identityService = services.identityService @@ -266,7 +267,7 @@ class PersistentIdentityServiceTests { */ @Test fun `deanonymising a well known identity should return the identity`() { - val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val service = makeTestIdentityService() val expected = ALICE service.verifyAndRegisterIdentity(ALICE_IDENTITY) val actual = service.wellKnownPartyFromAnonymous(expected) @@ -278,7 +279,7 @@ class PersistentIdentityServiceTests { */ @Test fun `deanonymising a false well known identity should return null`() { - val service = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) + val service = makeTestIdentityService() val notAlice = Party(ALICE.name, generateKeyPair().public) service.verifyAndRegisterIdentity(ALICE_IDENTITY) val actual = service.wellKnownPartyFromAnonymous(notAlice) diff --git a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt index e8dbd4be40..94fae003e2 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt @@ -38,6 +38,7 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.testing.* import net.corda.testing.contracts.VaultFiller import net.corda.testing.node.MockServices +import net.corda.testing.node.makeTestIdentityService import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After @@ -72,7 +73,11 @@ class NodeVaultServiceTest { @Before fun setUp() { LogHelper.setLevel(NodeVaultService::class) - val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(cordappPackages = cordappPackages) + val databaseAndServices = MockServices.makeTestDatabaseAndMockServices( + listOf(MEGA_CORP_KEY), + makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)), + cordappPackages, + MEGA_CORP.name) database = databaseAndServices.first services = databaseAndServices.second vaultFiller = VaultFiller(services, DUMMY_NOTARY, DUMMY_NOTARY_KEY) diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt index 0580cca49d..ac7edb2c53 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt @@ -35,6 +35,7 @@ import net.corda.testing.* import net.corda.testing.contracts.* import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices +import net.corda.testing.node.makeTestIdentityService import net.corda.testing.schemas.DummyLinearStateSchemaV1 import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy @@ -79,8 +80,11 @@ class VaultQueryTests { @Before fun setUp() { // register additional identities - val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(MEGA_CORP_KEY, DUMMY_NOTARY_KEY), - cordappPackages = cordappPackages) + val databaseAndServices = makeTestDatabaseAndMockServices( + listOf(MEGA_CORP_KEY, DUMMY_NOTARY_KEY), + makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)), + cordappPackages, + MEGA_CORP.name) database = databaseAndServices.first services = databaseAndServices.second vaultFiller = VaultFiller(services, DUMMY_NOTARY, DUMMY_NOTARY_KEY) diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt index 862a420a63..733082b183 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt @@ -29,6 +29,7 @@ import net.corda.testing.* import net.corda.testing.contracts.* import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices +import net.corda.testing.node.makeTestIdentityService import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.After @@ -60,7 +61,11 @@ class VaultWithCashTest { @Before fun setUp() { LogHelper.setLevel(VaultWithCashTest::class) - val databaseAndServices = makeTestDatabaseAndMockServices(cordappPackages = cordappPackages, keys = listOf(generateKeyPair(), DUMMY_NOTARY_KEY)) + val databaseAndServices = makeTestDatabaseAndMockServices( + listOf(generateKeyPair(), DUMMY_NOTARY_KEY), + makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)), + cordappPackages, + MEGA_CORP.name) database = databaseAndServices.first services = databaseAndServices.second vaultFiller = VaultFiller(services, DUMMY_NOTARY, DUMMY_NOTARY_KEY) diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/IRSSimulation.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/IRSSimulation.kt index 21ac207f72..af8525a222 100644 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/IRSSimulation.kt +++ b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/IRSSimulation.kt @@ -21,10 +21,9 @@ import net.corda.finance.flows.TwoPartyDealFlow.Instigator import net.corda.finance.plugin.registerFinanceJSONMappers import net.corda.irs.contract.InterestRateSwap import net.corda.irs.flows.FixingFlow -import net.corda.node.services.identity.InMemoryIdentityService -import net.corda.testing.DEV_TRUST_ROOT import net.corda.testing.chooseIdentity import net.corda.testing.node.InMemoryMessagingNetwork +import net.corda.testing.node.makeTestIdentityService import net.corda.testing.startFlow import rx.Observable import java.time.LocalDate @@ -45,7 +44,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten private val executeOnNextIteration = Collections.synchronizedList(LinkedList<() -> Unit>()) override fun startMainSimulation(): CompletableFuture { - om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + ratesOracle).flatMap { it.started!!.info.legalIdentitiesAndCerts }, trustRoot = DEV_TRUST_ROOT)) + om = JacksonSupport.createInMemoryMapper(makeTestIdentityService((banks + regulators + ratesOracle).flatMap { it.started!!.info.legalIdentitiesAndCerts })) registerFinanceJSONMappers(om) return startIRSDealBetween(0, 1).thenCompose { diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt index 5dada032a6..56ec594deb 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -45,6 +45,7 @@ import java.sql.Connection import java.time.Clock import java.util.* +fun makeTestIdentityService(identities: Iterable = emptySet()) = InMemoryIdentityService(identities, DEV_TRUST_ROOT) /** * A singleton utility that only provides a mock identity, key and storage service. However, this is sufficient for * building chains of transactions and verifying them. It isn't sufficient for testing flows however. @@ -57,8 +58,6 @@ open class MockServices( vararg val keys: KeyPair ) : ServiceHub, StateLoader by stateLoader { companion object { - private val MOCK_IDENTITIES = listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY) - @JvmStatic val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor") @@ -78,32 +77,16 @@ open class MockServices( return props } - private fun makeTestIdentityService() = InMemoryIdentityService(MOCK_IDENTITIES, trustRoot = DEV_TRUST_ROOT) - /** * Makes database and mock services appropriate for unit tests. - * @param keys a list of [KeyPair] instances to be used by [MockServices]. Defaults to [MEGA_CORP_KEY] - * @param createIdentityService a lambda function returning an instance of [IdentityService]. Defaults to [InMemoryIdentityService]. - * - * @return a pair where the first element is the instance of [CordaPersistence] and the second is [MockServices]. - */ - @JvmStatic - fun makeTestDatabaseAndMockServices(keys: List = listOf(MEGA_CORP_KEY), - identityService: IdentityService = makeTestIdentityService(), - cordappPackages: List = emptyList()): Pair { - return makeTestDatabaseAndMockServices(keys, identityService, cordappPackages, MEGA_CORP.name) - } - - /** - * Makes database and mock services appropriate for unit tests. - * @param keys a list of [KeyPair] instances to be used by [MockServices]. Defaults to [MEGA_CORP_KEY] - * @param createIdentityService a lambda function returning an instance of [IdentityService]. Defauts to [InMemoryIdentityService]. + * @param keys a list of [KeyPair] instances to be used by [MockServices]. + * @param identityService an instance of [IdentityService], see [makeTestIdentityService]. * @param initialIdentityName the name of the first (typically sole) identity the services will represent. * @return a pair where the first element is the instance of [CordaPersistence] and the second is [MockServices]. */ @JvmStatic - fun makeTestDatabaseAndMockServices(keys: List = listOf(MEGA_CORP_KEY), - identityService: IdentityService = makeTestIdentityService(), + fun makeTestDatabaseAndMockServices(keys: List, + identityService: IdentityService, cordappPackages: List = emptyList(), initialIdentityName: CordaX500Name): Pair { val cordappLoader = CordappLoader.createWithTestPackages(cordappPackages) @@ -148,7 +131,7 @@ open class MockServices( final override val attachments = MockAttachmentStorage() val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage = MockStateMachineRecordedTransactionMappingStorage() - override val identityService: IdentityService = makeTestIdentityService() + override val identityService: IdentityService = makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)) override val keyManagementService: KeyManagementService by lazy { MockKeyManagementService(identityService, *keys) } override val vaultService: VaultService get() = throw UnsupportedOperationException() From b0ebf3d7e0b550f21b7c52d11d5ecca2751b4cb8 Mon Sep 17 00:00:00 2001 From: Andrzej Cichocki Date: Tue, 5 Dec 2017 16:22:53 +0000 Subject: [PATCH 22/22] CORDA-654 Various MockServices refactorings (#2167) * Remove MockServices.stateMachineRecordedTransactionMapping which does nothing * Inline StateLoaderImpl * Remove unused MockServices * MockServices well-known identities not needed in a place * A few things don't need a full-blown ServiceHub --- .ci/api-current.txt | 2 +- .../net/corda/core/internal/InternalUtils.kt | 8 +-- .../kotlin/net/corda/core/node/ServiceHub.kt | 4 +- .../core/node/services/TransactionStorage.kt | 12 +++- .../core/transactions/TransactionBuilder.kt | 10 +-- ...tachmentsClassLoaderStaticContractTests.kt | 15 +++-- .../internal/AttachmentsClassLoaderTests.kt | 65 +++++++------------ .../node/services/AttachmentLoadingTests.kt | 36 +++++----- .../net/corda/node/internal/AbstractNode.kt | 13 ++-- .../net/corda/node/internal/StartedNode.kt | 17 ----- ...achineRecordedTransactionMappingStorage.kt | 48 -------------- .../events/NodeSchedulerServiceTest.kt | 6 +- .../PersistentIdentityServiceTests.kt | 11 ++-- .../persistence/DBTransactionStorageTests.kt | 29 +-------- .../net/corda/testing/node/MockServices.kt | 23 ++----- 15 files changed, 91 insertions(+), 208 deletions(-) delete mode 100644 node/src/main/kotlin/net/corda/node/services/persistence/InMemoryStateMachineRecordedTransactionMappingStorage.kt diff --git a/.ci/api-current.txt b/.ci/api-current.txt index 84b4d41817..6c4eac9c83 100644 --- a/.ci/api-current.txt +++ b/.ci/api-current.txt @@ -1873,7 +1873,7 @@ public final class net.corda.core.node.services.TimeWindowChecker extends java.l @org.jetbrains.annotations.NotNull public final java.time.Clock getClock() public final boolean isValid(net.corda.core.contracts.TimeWindow) ## -@net.corda.core.DoNotImplement public interface net.corda.core.node.services.TransactionStorage +@net.corda.core.DoNotImplement public interface net.corda.core.node.services.TransactionStorage extends net.corda.core.node.StateLoader @org.jetbrains.annotations.Nullable public abstract net.corda.core.transactions.SignedTransaction getTransaction(net.corda.core.crypto.SecureHash) @org.jetbrains.annotations.NotNull public abstract rx.Observable getUpdates() @org.jetbrains.annotations.NotNull public abstract net.corda.core.messaging.DataFeed track() diff --git a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt index 33306a984a..36022463ff 100644 --- a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt @@ -2,9 +2,9 @@ package net.corda.core.internal +import net.corda.core.cordapp.CordappProvider import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 -import net.corda.core.node.ServiceHub import net.corda.core.node.ServicesForResolution import net.corda.core.serialization.SerializationContext import net.corda.core.transactions.TransactionBuilder @@ -295,15 +295,15 @@ fun Iterable>.toMultiMap(): Map> = this.groupBy({ i * Provide access to internal method for AttachmentClassLoaderTests * @suppress */ -fun TransactionBuilder.toWireTransaction(services: ServicesForResolution, serializationContext: SerializationContext): WireTransaction { - return toWireTransactionWithContext(services, serializationContext) +fun TransactionBuilder.toWireTransaction(cordappProvider: CordappProvider, serializationContext: SerializationContext): WireTransaction { + return toWireTransactionWithContext(cordappProvider, serializationContext) } /** * Provide access to internal method for AttachmentClassLoaderTests * @suppress */ -fun TransactionBuilder.toLedgerTransaction(services: ServiceHub, serializationContext: SerializationContext) = toLedgerTransactionWithContext(services, serializationContext) +fun TransactionBuilder.toLedgerTransaction(services: ServicesForResolution, serializationContext: SerializationContext) = toLedgerTransactionWithContext(services, serializationContext) /** Convenience method to get the package name of a class literal. */ val KClass<*>.packageName: String get() = java.`package`.name diff --git a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt index 78f1704336..19fd97cec5 100644 --- a/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt +++ b/core/src/main/kotlin/net/corda/core/node/ServiceHub.kt @@ -38,7 +38,9 @@ interface StateLoader { // TODO: future implementation to use a Vault state ref -> contract state BLOB table and perform single query bulk load // as the existing transaction store will become encrypted at some point @Throws(TransactionResolutionException::class) - fun loadStates(stateRefs: Set): Set> + fun loadStates(stateRefs: Set): Set> { + return stateRefs.map { StateAndRef(loadState(it), it) }.toSet() + } } /** diff --git a/core/src/main/kotlin/net/corda/core/node/services/TransactionStorage.kt b/core/src/main/kotlin/net/corda/core/node/services/TransactionStorage.kt index 9b6b713ed2..25053adb67 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/TransactionStorage.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/TransactionStorage.kt @@ -1,8 +1,12 @@ package net.corda.core.node.services import net.corda.core.DoNotImplement +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TransactionResolutionException +import net.corda.core.contracts.TransactionState import net.corda.core.crypto.SecureHash import net.corda.core.messaging.DataFeed +import net.corda.core.node.StateLoader import net.corda.core.transactions.SignedTransaction import rx.Observable @@ -10,12 +14,18 @@ import rx.Observable * Thread-safe storage of transactions. */ @DoNotImplement -interface TransactionStorage { +interface TransactionStorage : StateLoader { /** * Return the transaction with the given [id], or null if no such transaction exists. */ fun getTransaction(id: SecureHash): SignedTransaction? + @Throws(TransactionResolutionException::class) + override fun loadState(stateRef: StateRef): TransactionState<*> { + val stx = getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash) + return stx.resolveBaseTransaction(this).outputs[stateRef.index] + } + /** * Get a synchronous Observable of updates. When observations are pushed to the Observer, the vault will already * incorporate the update. diff --git a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt index b0149dce8d..231f563314 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt @@ -2,6 +2,7 @@ package net.corda.core.transactions import co.paralleluniverse.strands.Strand import net.corda.core.contracts.* +import net.corda.core.cordapp.CordappProvider import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SignableData import net.corda.core.crypto.SignatureMetadata @@ -82,16 +83,16 @@ open class TransactionBuilder( * @returns A new [WireTransaction] that will be unaffected by further changes to this [TransactionBuilder]. */ @Throws(MissingContractAttachments::class) - fun toWireTransaction(services: ServicesForResolution): WireTransaction = toWireTransactionWithContext(services) + fun toWireTransaction(services: ServicesForResolution): WireTransaction = toWireTransactionWithContext(services.cordappProvider) - internal fun toWireTransactionWithContext(services: ServicesForResolution, serializationContext: SerializationContext? = null): WireTransaction { + internal fun toWireTransactionWithContext(cordappProvider: CordappProvider, serializationContext: SerializationContext? = null): WireTransaction { // Resolves the AutomaticHashConstraints to HashAttachmentConstraints for convenience. The AutomaticHashConstraint // allows for less boiler plate when constructing transactions since for the typical case the named contract // will be available when building the transaction. In exceptional cases the TransactionStates must be created // with an explicit [AttachmentConstraint] val resolvedOutputs = outputs.map { state -> if (state.constraint is AutomaticHashConstraint) { - services.cordappProvider.getContractAttachmentID(state.contract)?.let { + cordappProvider.getContractAttachmentID(state.contract)?.let { state.copy(constraint = HashAttachmentConstraint(it)) } ?: throw MissingContractAttachments(listOf(state)) } else { @@ -106,8 +107,7 @@ open class TransactionBuilder( @Throws(AttachmentResolutionException::class, TransactionResolutionException::class) fun toLedgerTransaction(services: ServiceHub) = toWireTransaction(services).toLedgerTransaction(services) - internal fun toLedgerTransactionWithContext(services: ServiceHub, serializationContext: SerializationContext) = toWireTransactionWithContext(services, serializationContext).toLedgerTransaction(services) - + internal fun toLedgerTransactionWithContext(services: ServicesForResolution, serializationContext: SerializationContext) = toWireTransactionWithContext(services.cordappProvider, serializationContext).toLedgerTransaction(services) @Throws(AttachmentResolutionException::class, TransactionResolutionException::class, TransactionVerificationException::class) fun verify(services: ServiceHub) { toLedgerTransaction(services).verify() diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderStaticContractTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderStaticContractTests.kt index 02eee8cd84..3d1bbf8e9b 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderStaticContractTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderStaticContractTests.kt @@ -1,16 +1,20 @@ package net.corda.nodeapi.internal +import com.nhaarman.mockito_kotlin.doReturn +import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.* import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.node.ServicesForResolution import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder +import net.corda.node.internal.cordapp.CordappLoader +import net.corda.node.internal.cordapp.CordappProviderImpl import net.corda.testing.* -import net.corda.testing.node.MockServices +import net.corda.testing.node.MockAttachmentStorage import org.junit.Assert.* -import org.junit.Before import org.junit.Rule import org.junit.Test @@ -44,11 +48,8 @@ class AttachmentsClassLoaderStaticContractTests { } } - private lateinit var serviceHub: MockServices - - @Before - fun `create service hub`() { - serviceHub = MockServices(cordappPackages = listOf("net.corda.nodeapi.internal")) + private val serviceHub = rigorousMock().also { + doReturn(CordappProviderImpl(CordappLoader.createWithTestPackages(listOf("net.corda.nodeapi.internal")), MockAttachmentStorage())).whenever(it).cordappProvider } @Test diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt index a6ab0c6ecc..4f98293c53 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt @@ -19,10 +19,8 @@ import net.corda.nodeapi.internal.serialization.attachmentsClassLoaderEnabledPro import net.corda.nodeapi.internal.serialization.withTokenContext import net.corda.testing.* import net.corda.testing.node.MockAttachmentStorage -import net.corda.testing.node.MockServices import org.apache.commons.io.IOUtils import org.junit.Assert.* -import org.junit.Before import org.junit.Rule import org.junit.Test import java.io.ByteArrayInputStream @@ -52,14 +50,13 @@ class AttachmentsClassLoaderTests { @Rule @JvmField val testSerialization = SerializationEnvironmentRule() - private lateinit var serviceHub: DummyServiceHub - - class DummyServiceHub : MockServices() { - override val cordappProvider: CordappProviderImpl - = CordappProviderImpl(CordappLoader.createDevMode(listOf(ISOLATED_CONTRACTS_JAR_PATH)), attachments) - private val cordapp get() = cordappProvider.cordapps.first() - val attachmentId get() = cordappProvider.getCordappAttachmentId(cordapp)!! - val appContext get() = cordappProvider.getAppContext(cordapp) + private val attachments = MockAttachmentStorage() + private val cordappProvider = CordappProviderImpl(CordappLoader.createDevMode(listOf(ISOLATED_CONTRACTS_JAR_PATH)), attachments) + private val cordapp get() = cordappProvider.cordapps.first() + private val attachmentId get() = cordappProvider.getCordappAttachmentId(cordapp)!! + private val appContext get() = cordappProvider.getAppContext(cordapp) + private val serviceHub = rigorousMock().also { + doReturn(attachments).whenever(it).attachments } // These ClassLoaders work together to load 'AnotherDummyContract' in a disposable way, such that even though @@ -77,12 +74,6 @@ class AttachmentsClassLoaderTests { } class ClassLoaderForTests : URLClassLoader(arrayOf(ISOLATED_CONTRACTS_JAR_PATH), FilteringClassLoader) - - @Before - fun `create service hub`() { - serviceHub = DummyServiceHub() - } - @Test fun `dynamically load AnotherDummyContract from isolated contracts jar`() { ClassLoaderForTests().use { child -> @@ -112,8 +103,8 @@ class AttachmentsClassLoaderTests { @Test fun `test MockAttachmentStorage open as jar`() { - val storage = serviceHub.attachments - val key = serviceHub.attachmentId + val storage = attachments + val key = attachmentId val attachment = storage.openAttachment(key)!! val jar = attachment.openAsJAR() @@ -123,9 +114,8 @@ class AttachmentsClassLoaderTests { @Test fun `test overlapping file exception`() { - val storage = serviceHub.attachments - - val att0 = serviceHub.attachmentId + val storage = attachments + val att0 = attachmentId val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file.txt", "some data"))) val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file.txt", "some other data"))) @@ -136,9 +126,8 @@ class AttachmentsClassLoaderTests { @Test fun `basic`() { - val storage = serviceHub.attachments - - val att0 = serviceHub.attachmentId + val storage = attachments + val att0 = attachmentId val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data"))) val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data"))) @@ -169,9 +158,8 @@ class AttachmentsClassLoaderTests { @Test fun `loading class AnotherDummyContract`() { - val storage = serviceHub.attachments - - val att0 = serviceHub.attachmentId + val storage = attachments + val att0 = attachmentId val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data"))) val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data"))) @@ -194,10 +182,8 @@ class AttachmentsClassLoaderTests { val contract = createContract2Cash() val bytes = contract.serialize() - - val storage = serviceHub.attachments - - val att0 = serviceHub.attachmentId + val storage = attachments + val att0 = attachmentId val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data"))) val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data"))) @@ -222,10 +208,8 @@ class AttachmentsClassLoaderTests { val context2 = SerializationFactory.defaultFactory.defaultContext.withWhitelisted(data.contract.javaClass) val bytes = data.serialize(context = context2) - - val storage = serviceHub.attachments - - val att0 = serviceHub.attachmentId + val storage = attachments + val att0 = attachmentId val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data"))) val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data"))) @@ -276,7 +260,7 @@ class AttachmentsClassLoaderTests { @Test fun `test serialization of WireTransaction with dynamically loaded contract`() { - val child = serviceHub.appContext.classLoader + val child = appContext.classLoader val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, child) val contract = contractClass.newInstance() as DummyContractBackdoor val tx = contract.generateInitial(MEGA_CORP.ref(0), 42, DUMMY_NOTARY) @@ -288,7 +272,7 @@ class AttachmentsClassLoaderTests { .withClassLoader(child) val bytes = run { - val wireTransaction = tx.toWireTransaction(serviceHub, context) + val wireTransaction = tx.toWireTransaction(cordappProvider, context) wireTransaction.serialize(context = context) } val copiedWireTransaction = bytes.deserialize(context = context) @@ -307,13 +291,12 @@ class AttachmentsClassLoaderTests { val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, child) val contract = contractClass.newInstance() as DummyContractBackdoor val tx = contract.generateInitial(MEGA_CORP.ref(0), 42, DUMMY_NOTARY) - - val attachmentRef = serviceHub.attachmentId + val attachmentRef = attachmentId val bytes = run { val outboundContext = SerializationFactory.defaultFactory.defaultContext .withServiceHub(serviceHub) .withClassLoader(child) - val wireTransaction = tx.toWireTransaction(serviceHub, outboundContext) + val wireTransaction = tx.toWireTransaction(cordappProvider, outboundContext) wireTransaction.serialize(context = outboundContext) } // use empty attachmentStorage @@ -340,7 +323,7 @@ class AttachmentsClassLoaderTests { val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, child) val contract = contractClass.newInstance() as DummyContractBackdoor val outboundContext = SerializationFactory.defaultFactory.defaultContext.withClassLoader(child) - val attachmentRef = serviceHub.attachmentId + val attachmentRef = attachmentId // We currently ignore annotations in attachments, so manually whitelist. val inboundContext = SerializationFactory .defaultFactory diff --git a/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt index 4a2a894154..02619d2ff7 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt @@ -1,8 +1,9 @@ package net.corda.node.services +import com.nhaarman.mockito_kotlin.doReturn +import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.Contract import net.corda.core.contracts.PartyAndReference -import net.corda.core.cordapp.CordappProvider import net.corda.core.flows.FlowLogic import net.corda.core.flows.UnexpectedFlowEndException import net.corda.core.identity.CordaX500Name @@ -11,6 +12,8 @@ import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.createDirectories import net.corda.core.internal.div import net.corda.core.internal.toLedgerTransaction +import net.corda.core.node.ServicesForResolution +import net.corda.core.node.services.IdentityService import net.corda.core.serialization.SerializationFactory import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.contextLogger @@ -23,22 +26,19 @@ import net.corda.testing.DUMMY_NOTARY import net.corda.testing.driver.DriverDSLExposedInterface import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.driver -import net.corda.testing.node.MockServices +import net.corda.testing.node.MockAttachmentStorage import org.junit.Assert.assertEquals -import org.junit.Before import org.junit.Test import java.net.URLClassLoader import java.nio.file.Files import kotlin.test.assertFailsWith class AttachmentLoadingTests { - private class Services : MockServices() { - private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR)), attachments) - private val cordapp get() = provider.cordapps.first() - val attachmentId get() = provider.getCordappAttachmentId(cordapp)!! - val appContext get() = provider.getAppContext(cordapp) - override val cordappProvider: CordappProvider = provider - } + private val attachments = MockAttachmentStorage() + private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR)), attachments) + private val cordapp get() = provider.cordapps.first() + private val attachmentId get() = provider.getCordappAttachmentId(cordapp)!! + private val appContext get() = provider.getAppContext(cordapp) private companion object { private val logger = contextLogger() @@ -70,16 +70,17 @@ class AttachmentLoadingTests { } } - private lateinit var services: Services - - @Before - fun setup() { - services = Services() + private val services = rigorousMock().also { + doReturn(attachments).whenever(it).attachments + doReturn(provider).whenever(it).cordappProvider + doReturn(rigorousMock().also { + doReturn(null).whenever(it).partyFromKey(DUMMY_BANK_A.owningKey) + }).whenever(it).identityService } @Test fun `test a wire transaction has loaded the correct attachment`() = withTestSerialization { - val appClassLoader = services.appContext.classLoader + val appClassLoader = appContext.classLoader val contractClass = appClassLoader.loadClass(ISOLATED_CONTRACT_ID).asSubclass(Contract::class.java) val generateInitialMethod = contractClass.getDeclaredMethod("generateInitial", PartyAndReference::class.java, Integer.TYPE, Party::class.java) val contract = contractClass.newInstance() @@ -89,8 +90,7 @@ class AttachmentLoadingTests { contract.verify(ledgerTx) val actual = ledgerTx.attachments.first() - val expected = services.attachments.openAttachment(services.attachmentId)!! - + val expected = attachments.openAttachment(attachmentId)!! assertEquals(expected, actual) } diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 5a2e6785ad..9aca690993 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -192,8 +192,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val (startedImpl, schedulerService) = initialiseDatabasePersistence(schemaService, identityService) { database -> identityService.loadIdentities(info.legalIdentitiesAndCerts) val transactionStorage = makeTransactionStorage(database) - val stateLoader = StateLoaderImpl(transactionStorage) - val nodeServices = makeServices(keyPairs, schemaService, transactionStorage, stateLoader, database, info, identityService) + val nodeServices = makeServices(keyPairs, schemaService, transactionStorage, database, info, identityService) val notaryService = makeNotaryService(nodeServices, database) val smm = makeStateMachineManager(database) val flowStarter = FlowStarterImpl(serverThread, smm) @@ -201,7 +200,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, platformClock, database, flowStarter, - stateLoader, + transactionStorage, unfinishedSchedules = busyNodeLatch, serverThread = serverThread) if (serverThread is ExecutorService) { @@ -498,7 +497,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, * Builds node internal, advertised, and plugin services. * Returns a list of tokenizable services to be added to the serialisation context. */ - private fun makeServices(keyPairs: Set, schemaService: SchemaService, transactionStorage: WritableTransactionStorage, stateLoader: StateLoader, database: CordaPersistence, info: NodeInfo, identityService: IdentityService): MutableList { + private fun makeServices(keyPairs: Set, schemaService: SchemaService, transactionStorage: WritableTransactionStorage, database: CordaPersistence, info: NodeInfo, identityService: IdentityService): MutableList { checkpointStorage = DBCheckpointStorage() val metrics = MetricRegistry() attachments = NodeAttachmentService(metrics) @@ -509,7 +508,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration, keyManagementService, schemaService, transactionStorage, - stateLoader, MonitoringService(metrics), cordappProvider, database, @@ -722,18 +720,17 @@ abstract class AbstractNode(val configuration: NodeConfiguration, override val keyManagementService: KeyManagementService, override val schemaService: SchemaService, override val validatedTransactions: WritableTransactionStorage, - private val stateLoader: StateLoader, override val monitoringService: MonitoringService, override val cordappProvider: CordappProviderInternal, override val database: CordaPersistence, override val myInfo: NodeInfo - ) : SingletonSerializeAsToken(), ServiceHubInternal, StateLoader by stateLoader { + ) : SingletonSerializeAsToken(), ServiceHubInternal, StateLoader by validatedTransactions { override val rpcFlows = ArrayList>>() override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage() override val auditService = DummyAuditService() override val transactionVerifierService by lazy { makeTransactionVerifierService() } override val networkMapCache by lazy { NetworkMapCacheImpl(PersistentNetworkMapCache(database), identityService) } - override val vaultService by lazy { makeVaultService(keyManagementService, stateLoader, database.hibernateConfig) } + override val vaultService by lazy { makeVaultService(keyManagementService, validatedTransactions, database.hibernateConfig) } override val contractUpgradeService by lazy { ContractUpgradeServiceImpl() } override val attachments: AttachmentStorage get() = this@AbstractNode.attachments override val networkService: MessagingService get() = network diff --git a/node/src/main/kotlin/net/corda/node/internal/StartedNode.kt b/node/src/main/kotlin/net/corda/node/internal/StartedNode.kt index e0c63a038f..665102964d 100644 --- a/node/src/main/kotlin/net/corda/node/internal/StartedNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/StartedNode.kt @@ -1,14 +1,11 @@ package net.corda.node.internal -import net.corda.core.contracts.* import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatedBy import net.corda.core.internal.VisibleForTesting import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NodeInfo -import net.corda.core.node.StateLoader import net.corda.core.node.services.NotaryService -import net.corda.core.node.services.TransactionStorage import net.corda.node.services.api.CheckpointStorage import net.corda.node.services.api.StartedNodeServices import net.corda.node.services.messaging.MessagingService @@ -44,17 +41,3 @@ interface StartedNode { return internals.internalRegisterFlowFactory(smm, initiatingFlowClass, flowFactory, initiatedFlowClass, track) } } - -class StateLoaderImpl(private val validatedTransactions: TransactionStorage) : StateLoader { - @Throws(TransactionResolutionException::class) - override fun loadState(stateRef: StateRef): TransactionState<*> { - val stx = validatedTransactions.getTransaction(stateRef.txhash) ?: throw TransactionResolutionException(stateRef.txhash) - return stx.resolveBaseTransaction(this).outputs[stateRef.index] - } - - @Throws(TransactionResolutionException::class) - // TODO: future implementation to retrieve contract states from a Vault BLOB store - override fun loadStates(stateRefs: Set): Set> { - return (stateRefs.map { StateAndRef(loadState(it), it) }).toSet() - } -} diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/InMemoryStateMachineRecordedTransactionMappingStorage.kt b/node/src/main/kotlin/net/corda/node/services/persistence/InMemoryStateMachineRecordedTransactionMappingStorage.kt deleted file mode 100644 index 84dd4974dd..0000000000 --- a/node/src/main/kotlin/net/corda/node/services/persistence/InMemoryStateMachineRecordedTransactionMappingStorage.kt +++ /dev/null @@ -1,48 +0,0 @@ -package net.corda.node.services.persistence - -import net.corda.core.internal.ThreadBox -import net.corda.core.internal.bufferUntilSubscribed -import net.corda.core.crypto.SecureHash -import net.corda.core.flows.StateMachineRunId -import net.corda.core.messaging.DataFeed -import net.corda.core.messaging.StateMachineTransactionMapping -import net.corda.node.services.api.StateMachineRecordedTransactionMappingStorage -import rx.subjects.PublishSubject -import java.util.* -import javax.annotation.concurrent.ThreadSafe - -/** - * This is a temporary in-memory storage of a state machine id -> txhash mapping - * - * TODO persist this instead - */ -@ThreadSafe -class InMemoryStateMachineRecordedTransactionMappingStorage : StateMachineRecordedTransactionMappingStorage { - private class InnerState { - val stateMachineTransactionMap = HashMap>() - val updates = PublishSubject.create()!! - } - - private val mutex = ThreadBox(InnerState()) - - override fun addMapping(stateMachineRunId: StateMachineRunId, transactionId: SecureHash) { - mutex.locked { - stateMachineTransactionMap.getOrPut(stateMachineRunId) { HashSet() }.add(transactionId) - updates.onNext(StateMachineTransactionMapping(stateMachineRunId, transactionId)) - } - } - - override fun track(): - DataFeed, StateMachineTransactionMapping> { - mutex.locked { - return DataFeed( - stateMachineTransactionMap.flatMap { entry -> - entry.value.map { - StateMachineTransactionMapping(entry.key, it) - } - }, - updates.bufferUntilSubscribed() - ) - } - } -} diff --git a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt index 6a91f03ef3..2f686cf17f 100644 --- a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt @@ -16,7 +16,6 @@ import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.days import net.corda.node.internal.FlowStarterImpl -import net.corda.node.internal.StateLoaderImpl import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.internal.cordapp.CordappProviderImpl import net.corda.node.services.api.MonitoringService @@ -95,7 +94,6 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { kms = MockKeyManagementService(identityService, ALICE_KEY) val configuration = testNodeConfiguration(Paths.get("."), CordaX500Name("Alice", "London", "GB")) val validatedTransactions = MockTransactionStorage() - val stateLoader = StateLoaderImpl(validatedTransactions) database.transaction { services = rigorousMock().also { doReturn(configuration).whenever(it).configuration @@ -105,13 +103,13 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { doReturn(myInfo).whenever(it).myInfo doReturn(kms).whenever(it).keyManagementService doReturn(CordappProviderImpl(CordappLoader.createWithTestPackages(listOf("net.corda.testing.contracts")), MockAttachmentStorage())).whenever(it).cordappProvider - doReturn(NodeVaultService(testClock, kms, stateLoader, database.hibernateConfig)).whenever(it).vaultService + doReturn(NodeVaultService(testClock, kms, validatedTransactions, database.hibernateConfig)).whenever(it).vaultService doReturn(this@NodeSchedulerServiceTest).whenever(it).testReference } smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1) mockSMM = StateMachineManagerImpl(services, DBCheckpointStorage(), smmExecutor, database) - scheduler = NodeSchedulerService(testClock, database, FlowStarterImpl(smmExecutor, mockSMM), stateLoader, schedulerGatedExecutor, serverThread = smmExecutor) + scheduler = NodeSchedulerService(testClock, database, FlowStarterImpl(smmExecutor, mockSMM), validatedTransactions, schedulerGatedExecutor, serverThread = smmExecutor) mockSMM.changes.subscribe { change -> if (change is StateMachineManager.Change.Removed && mockSMM.allStateMachines.isEmpty()) { smmHasRemovedAllFlows.countDown() diff --git a/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt index 95c17a7863..0650e74486 100644 --- a/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/identity/PersistentIdentityServiceTests.kt @@ -10,13 +10,15 @@ import net.corda.core.internal.cert import net.corda.core.internal.toX509CertHolder import net.corda.core.node.services.IdentityService import net.corda.core.node.services.UnknownAnonymousPartyException +import net.corda.node.internal.configureDatabase import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.X509CertificateFactory import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.persistence.CordaPersistence +import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.testing.* -import net.corda.testing.node.MockServices +import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.node.makeTestIdentityService import org.junit.After import org.junit.Before @@ -30,15 +32,12 @@ import kotlin.test.assertNull */ class PersistentIdentityServiceTests { private lateinit var database: CordaPersistence - private lateinit var services: MockServices private lateinit var identityService: IdentityService @Before fun setup() { - val databaseAndServices = MockServices.makeTestDatabaseAndMockServices(emptyList(), PersistentIdentityService(DEV_TRUST_ROOT), initialIdentityName = MEGA_CORP.name) - database = databaseAndServices.first - services = databaseAndServices.second - identityService = services.identityService + identityService = PersistentIdentityService(DEV_TRUST_ROOT) + database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), identityService) } @After diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt index f70118e16a..f955fd92d0 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt @@ -5,20 +5,14 @@ import net.corda.core.crypto.Crypto import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SignatureMetadata import net.corda.core.crypto.TransactionSignature -import net.corda.core.node.StatesToRecord import net.corda.core.toFuture import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.WireTransaction -import net.corda.node.services.api.VaultServiceInternal -import net.corda.node.services.schema.HibernateObserver -import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.transactions.PersistentUniquenessProvider -import net.corda.node.services.vault.NodeVaultService import net.corda.node.internal.configureDatabase import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.testing.* -import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import org.assertj.core.api.Assertions.assertThat import org.junit.After @@ -35,32 +29,11 @@ class DBTransactionStorageTests { private lateinit var database: CordaPersistence private lateinit var transactionStorage: DBTransactionStorage - private lateinit var services: MockServices - @Before fun setUp() { LogHelper.setLevel(PersistentUniquenessProvider::class) val dataSourceProps = makeTestDataSourceProperties() - val schemaService = NodeSchemaService() - database = configureDatabase(dataSourceProps, DatabaseConfig(), rigorousMock(), schemaService) - database.transaction { - services = object : MockServices(BOB_KEY) { - override val vaultService: VaultServiceInternal - get() { - val vaultService = NodeVaultService(clock, keyManagementService, stateLoader, database.hibernateConfig) - hibernatePersister = HibernateObserver.install(vaultService.rawUpdates, database.hibernateConfig, schemaService) - return vaultService - } - - override fun recordTransactions(txs: Iterable) { - for (stx in txs) { - validatedTransactions.addTransaction(stx) - } - // Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions. - vaultService.notifyAll(StatesToRecord.ONLY_RELEVANT, txs.map { it.tx }) - } - } - } + database = configureDatabase(dataSourceProps, DatabaseConfig(), rigorousMock()) newTransactionStorage() } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt index 56ec594deb..0d119ddf12 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -4,7 +4,6 @@ import com.google.common.collect.MutableClassToInstanceMap import net.corda.core.cordapp.CordappProvider import net.corda.core.crypto.* import net.corda.core.flows.FlowLogic -import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.CordaX500Name import net.corda.core.identity.PartyAndCertificate import net.corda.core.messaging.DataFeed @@ -16,16 +15,13 @@ import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.SignedTransaction import net.corda.node.VersionInfo -import net.corda.node.internal.StateLoaderImpl import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.services.api.SchemaService -import net.corda.node.services.api.StateMachineRecordedTransactionMappingStorage import net.corda.node.services.api.VaultServiceInternal import net.corda.node.services.api.WritableTransactionStorage import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.keys.freshCertificate import net.corda.node.services.keys.getSigner -import net.corda.node.services.persistence.InMemoryStateMachineRecordedTransactionMappingStorage import net.corda.node.services.schema.HibernateObserver import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.transactions.InMemoryTransactionVerifierService @@ -53,10 +49,9 @@ fun makeTestIdentityService(identities: Iterable = emptySet open class MockServices( cordappLoader: CordappLoader, override val validatedTransactions: WritableTransactionStorage, - protected val stateLoader: StateLoaderImpl = StateLoaderImpl(validatedTransactions), private val initialIdentityName: CordaX500Name = MEGA_CORP.name, vararg val keys: KeyPair -) : ServiceHub, StateLoader by stateLoader { +) : ServiceHub, StateLoader by validatedTransactions { companion object { @JvmStatic val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor") @@ -99,9 +94,7 @@ open class MockServices( override val vaultService: VaultServiceInternal = makeVaultService(database.hibernateConfig, schemaService) override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable) { - for (stx in txs) { - validatedTransactions.addTransaction(stx) - } + super.recordTransactions(statesToRecord, txs) // Refactored to use notifyAll() as we have no other unit test for that method with multiple transactions. vaultService.notifyAll(statesToRecord, txs.map { it.tx }) } @@ -122,15 +115,11 @@ open class MockServices( override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable) { txs.forEach { - stateMachineRecordedTransactionMapping.addMapping(StateMachineRunId.createRandom(), it.id) - } - for (stx in txs) { - validatedTransactions.addTransaction(stx) + validatedTransactions.addTransaction(it) } } final override val attachments = MockAttachmentStorage() - val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage = MockStateMachineRecordedTransactionMappingStorage() override val identityService: IdentityService = makeTestIdentityService(listOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY)) override val keyManagementService: KeyManagementService by lazy { MockKeyManagementService(identityService, *keys) } @@ -149,7 +138,7 @@ open class MockServices( lateinit var hibernatePersister: HibernateObserver fun makeVaultService(hibernateConfig: HibernateConfiguration, schemaService: SchemaService): VaultServiceInternal { - val vaultService = NodeVaultService(Clock.systemUTC(), keyManagementService, stateLoader, hibernateConfig) + val vaultService = NodeVaultService(Clock.systemUTC(), keyManagementService, validatedTransactions, hibernateConfig) hibernatePersister = HibernateObserver.install(vaultService.rawUpdates, hibernateConfig, schemaService) return vaultService } @@ -201,10 +190,6 @@ class MockKeyManagementService(val identityService: IdentityService, } } -class MockStateMachineRecordedTransactionMappingStorage( - val storage: StateMachineRecordedTransactionMappingStorage = InMemoryStateMachineRecordedTransactionMappingStorage() -) : StateMachineRecordedTransactionMappingStorage by storage - open class MockTransactionStorage : WritableTransactionStorage, SingletonSerializeAsToken() { override fun track(): DataFeed, SignedTransaction> { return DataFeed(txns.values.toList(), _updatesPublisher)