From 842eac5c437b9e077c3617a3a61cd707a3d53196 Mon Sep 17 00:00:00 2001 From: Florian Friemel Date: Fri, 28 Sep 2018 09:46:06 +0100 Subject: [PATCH] [CORDA-1926] Implement target version and min platform version (#3899) https://r3-cev.atlassian.net/browse/CORDA-1926 --- .../core/internal/cordapp/CordappImpl.kt | 5 +- .../internal/cordapp/CordappInfoResolver.kt | 65 ++++++++++++++++++ .../cordapp/CordappInfoResolverTest.kt | 42 +++++++++++ docs/source/changelog.rst | 2 + docs/source/cordapp-build-systems.rst | 27 ++++++++ docs/source/versioning.rst | 6 +- ...tachmentsClassLoaderStaticContractTests.kt | 3 +- .../node/services/AttachmentLoadingTests.kt | 4 +- .../main/kotlin/net/corda/node/VersionInfo.kt | 6 +- .../cordapp/JarScanningCordappLoader.kt | 19 ++++- .../node/internal/cordapp/ManifestUtils.kt | 5 +- .../cordapp/CordappProviderImplTests.kt | 6 +- .../cordapp/JarScanningCordappLoaderTest.kt | 63 ++++++++++++++++- .../cordapp/versions/min-2-no-target.jar | Bin 0 -> 30781 bytes .../cordapp/versions/min-2-target-3.jar | Bin 0 -> 30790 bytes .../versions/no-min-or-target-version.jar | Bin 0 -> 12182 bytes .../net/corda/testing/node/MockServices.kt | 6 +- .../node/internal/InternalMockNetwork.kt | 4 +- 18 files changed, 240 insertions(+), 23 deletions(-) create mode 100644 core/src/main/kotlin/net/corda/core/internal/cordapp/CordappInfoResolver.kt create mode 100644 core/src/test/kotlin/net/corda/core/internal/cordapp/CordappInfoResolverTest.kt create mode 100644 node/src/test/resources/net/corda/node/internal/cordapp/versions/min-2-no-target.jar create mode 100644 node/src/test/resources/net/corda/node/internal/cordapp/versions/min-2-target-3.jar create mode 100644 node/src/test/resources/net/corda/node/internal/cordapp/versions/no-min-or-target-version.jar diff --git a/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt b/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt index 5a459783e8..38891ef254 100644 --- a/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt +++ b/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappImpl.kt @@ -40,10 +40,11 @@ data class CordappImpl( override val cordappClasses: List = (rpcFlows + initiatedFlows + services + serializationWhitelists.map { javaClass }).map { it.name } + contractClassNames // TODO Why a seperate Info class and not just have the fields directly in CordappImpl? - data class Info(val shortName: String, val vendor: String, val version: String) { + data class Info(val shortName: String, val vendor: String, val version: String, val minimumPlatformVersion: Int, val targetPlatformVersion: Int) { companion object { private const val UNKNOWN_VALUE = "Unknown" - val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE) + + val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE, 1, 1) } fun hasUnknownFields(): Boolean = arrayOf(shortName, vendor, version).any { it == UNKNOWN_VALUE } diff --git a/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappInfoResolver.kt b/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappInfoResolver.kt new file mode 100644 index 0000000000..835a3c47c0 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/cordapp/CordappInfoResolver.kt @@ -0,0 +1,65 @@ +package net.corda.core.internal.cordapp + +import net.corda.core.utilities.loggerFor +import java.util.concurrent.ConcurrentHashMap + +/** + * Provides a way to acquire information about the calling CorDapp. + */ +object CordappInfoResolver { + private val logger = loggerFor() + private val cordappClasses: ConcurrentHashMap> = ConcurrentHashMap() + + // TODO use the StackWalker API once we migrate to Java 9+ + private var cordappInfoResolver: () -> CordappImpl.Info? = { + Exception().stackTrace + .mapNotNull { cordappClasses[it.className] } + // If there is more than one cordapp registered for a class name we can't determine the "correct" one and return null. + .firstOrNull { it.size < 2 }?.single() + } + + /* + * Associates class names with CorDapps or logs a warning when a CorDapp is already registered for a given class. + * This could happen when trying to run different versions of the same CorDapp on the same node. + */ + @Synchronized + fun register(classes: List, cordapp: CordappImpl.Info) { + classes.forEach { + if (cordappClasses.containsKey(it)) { + logger.warn("More than one CorDapp registered for $it.") + cordappClasses[it] = cordappClasses[it]!! + cordapp + } else { + cordappClasses[it] = setOf(cordapp) + } + } + } + + /* + * This should only be used when making a change that would break compatibility with existing CorDapps. The change + * can then be version-gated, meaning the old behaviour is used if the calling CorDapp's target version is lower + * than the platform version that introduces the new behaviour. + * In situations where a `[CordappProvider]` is available the CorDapp context should be obtained from there. + * + * @return Information about the CorDapp from which the invoker is called, null if called outside a CorDapp or the + * calling CorDapp cannot be reliably determined.. + */ + fun getCorDappInfo(): CordappImpl.Info? = cordappInfoResolver() + + /** + * Temporarily switch out the internal resolver for another one. For use in testing. + */ + @Synchronized + fun withCordappInfoResolution(tempResolver: () -> CordappImpl.Info?, block: () -> Unit) { + val resolver = cordappInfoResolver + cordappInfoResolver = tempResolver + try { + block() + } finally { + cordappInfoResolver = resolver + } + } + + internal fun clear() { + cordappClasses.clear() + } +} \ No newline at end of file diff --git a/core/src/test/kotlin/net/corda/core/internal/cordapp/CordappInfoResolverTest.kt b/core/src/test/kotlin/net/corda/core/internal/cordapp/CordappInfoResolverTest.kt new file mode 100644 index 0000000000..2ae7403e1a --- /dev/null +++ b/core/src/test/kotlin/net/corda/core/internal/cordapp/CordappInfoResolverTest.kt @@ -0,0 +1,42 @@ +package net.corda.core.internal.cordapp + +import org.junit.After +import org.junit.Before +import org.junit.Test +import kotlin.test.assertEquals + +class CordappInfoResolverTest { + + @Before + @After + fun clearCordappInfoResolver() { + CordappInfoResolver.clear() + } + + @Test() + fun `The correct cordapp resolver is used after calling withCordappResolution`() { + val defaultTargetVersion = 222 + + CordappInfoResolver.register(listOf(javaClass.name), CordappImpl.Info("test", "test", "2", 3, defaultTargetVersion)) + assertEquals(defaultTargetVersion, returnCallingTargetVersion()) + + val expectedTargetVersion = 555 + CordappInfoResolver.withCordappInfoResolution( { CordappImpl.Info("foo", "bar", "1", 2, expectedTargetVersion) }) + { + val actualTargetVersion = returnCallingTargetVersion() + assertEquals(expectedTargetVersion, actualTargetVersion) + } + assertEquals(defaultTargetVersion, returnCallingTargetVersion()) + } + + @Test() + fun `When more than one cordapp is registered for the same class, the resolver returns null`() { + CordappInfoResolver.register(listOf(javaClass.name), CordappImpl.Info("test", "test", "2", 3, 222)) + CordappInfoResolver.register(listOf(javaClass.name), CordappImpl.Info("test1", "test1", "1", 2, 456)) + assertEquals(0, returnCallingTargetVersion()) + } + + private fun returnCallingTargetVersion(): Int { + return CordappInfoResolver.getCorDappInfo()?.targetPlatformVersion ?: 0 + } +} \ No newline at end of file diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 187628a4fc..78e75bd607 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -7,6 +7,8 @@ release, see :doc:`upgrade-notes`. Unreleased ---------- +* Introduce minimum and target platform version for CorDapps. + * New overload for ``CordaRPCClient.start()`` method allowing to specify target legal identity to use for RPC call. * Case insensitive vault queries can be specified via a boolean on applicable SQL criteria builder operators. By default queries will be case sensitive. diff --git a/docs/source/cordapp-build-systems.rst b/docs/source/cordapp-build-systems.rst index 7d3a4a8cb7..af785ae777 100644 --- a/docs/source/cordapp-build-systems.rst +++ b/docs/source/cordapp-build-systems.rst @@ -189,3 +189,30 @@ CorDapp configuration can be accessed from ``CordappContext::config`` whenever a There is an example project that demonstrates in ``samples`` called ``cordapp-configuration`` and API documentation in ``_. + + +Minimum and target platform version +----------------------------------- + +CorDapps can advertise their minimum and target platform version. The minimum platform version indicates that a node has to run at least this version in order to be able to run this CorDapp. The target platform version indicates that a CorDapp was tested with this version of the Corda Platform and should be run at this API level if possible. It provides a means of maintaining behavioural compatibility for the cases where the platform's behaviour has changed. These attributes are specified in the JAR manifest of the CorDapp, for example: + +.. sourcecode:: groovy + + 'Min-Platform-Version': 3 + 'Target-Platform-Version': 4 + + +In gradle, this can be achieved by modifying the jar task as shown in this example: + +.. container:: codeset + + .. sourcecode:: groovy + + jar { + manifest { + attributes( + 'Min-Platform-Version': 3 + 'Target-Platform-Version': 4 + ) + } + } diff --git a/docs/source/versioning.rst b/docs/source/versioning.rst index 62b7cdc7a2..9d89d5c7b3 100644 --- a/docs/source/versioning.rst +++ b/docs/source/versioning.rst @@ -19,8 +19,4 @@ and the release version - a change in the major, minor or patch values may or ma The Platform Version is part of the node's ``NodeInfo`` object, which is available from the ``ServiceHub``. This enables a CorDapp to find out which version it's running on and determine whether a desired feature is available. When a node registers with the Network Map Service it will use the node's Platform Version to enforce a minimum version requirement -for the network. - -.. note:: A future release may introduce the concept of a target platform version, which would be similar to Android's - ``targetSdkVersion``, and would provide a means of maintaining behavioural compatibility for the cases where the - platform's behaviour has changed. \ No newline at end of file +for the network. \ No newline at end of file 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 0909707ac4..c699439e19 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 @@ -15,6 +15,7 @@ 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.VersionInfo import net.corda.node.cordapp.CordappLoader import net.corda.node.internal.cordapp.CordappProviderImpl import net.corda.node.internal.cordapp.JarScanningCordappLoader @@ -110,7 +111,7 @@ class AttachmentsClassLoaderStaticContractTests { val cordapps = cordappsForPackages(packages) return testDirectory().let { directory -> cordapps.packageInDirectory(directory) - JarScanningCordappLoader.fromDirectories(listOf(directory)) + JarScanningCordappLoader.fromDirectories(listOf(directory), VersionInfo.UNKNOWN) } } 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 fb17259383..d21de023cb 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 @@ -23,8 +23,10 @@ import net.corda.core.serialization.SerializationFactory import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.contextLogger import net.corda.core.utilities.getOrThrow +import net.corda.node.VersionInfo import net.corda.node.internal.cordapp.JarScanningCordappLoader import net.corda.node.internal.cordapp.CordappProviderImpl +import net.corda.nodeapi.internal.PLATFORM_VERSION import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.DUMMY_BANK_A_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME @@ -50,7 +52,7 @@ class AttachmentLoadingTests { @JvmField val testSerialization = SerializationEnvironmentRule() private val attachments = MockAttachmentStorage() - private val provider = CordappProviderImpl(JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR)), MockCordappConfigProvider(), attachments).apply { + private val provider = CordappProviderImpl(JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR), VersionInfo.UNKNOWN), MockCordappConfigProvider(), attachments).apply { start(testNetworkParameters().whitelistedContractImplementations) } private val cordapp get() = provider.cordapps.first() diff --git a/node/src/main/kotlin/net/corda/node/VersionInfo.kt b/node/src/main/kotlin/net/corda/node/VersionInfo.kt index eacbb25133..b3d0ec0fbb 100644 --- a/node/src/main/kotlin/net/corda/node/VersionInfo.kt +++ b/node/src/main/kotlin/net/corda/node/VersionInfo.kt @@ -1,5 +1,7 @@ package net.corda.node +import net.corda.nodeapi.internal.PLATFORM_VERSION + /** * Encapsulates various pieces of version information of the node. */ @@ -17,6 +19,6 @@ data class VersionInfo( val vendor: String) { companion object { - val UNKNOWN = VersionInfo(1, "Unknown", "Unknown", "Unknown") + val UNKNOWN = VersionInfo(PLATFORM_VERSION, "Unknown", "Unknown", "Unknown") } -} +} \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt index be3c8e4deb..c691af76c7 100644 --- a/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt +++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt @@ -8,6 +8,7 @@ import net.corda.core.crypto.sha256 import net.corda.core.flows.* import net.corda.core.internal.* import net.corda.core.internal.cordapp.CordappImpl +import net.corda.core.internal.cordapp.CordappInfoResolver import net.corda.core.node.services.CordaService import net.corda.core.schemas.MappedSchema import net.corda.core.serialization.SerializationCustomSerializer @@ -35,7 +36,7 @@ import kotlin.streams.toList * @property cordappJarPaths The classpath of cordapp JARs */ class JarScanningCordappLoader private constructor(private val cordappJarPaths: List, - versionInfo: VersionInfo = VersionInfo.UNKNOWN) : CordappLoaderTemplate() { + private val versionInfo: VersionInfo = VersionInfo.UNKNOWN) : CordappLoaderTemplate() { override val cordapps: List by lazy { loadCordapps() + coreCordapp } @@ -104,13 +105,25 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths: serializationWhitelists = listOf(), serializationCustomSerializers = listOf(), customSchemas = setOf(), - info = CordappImpl.Info("corda-core", versionInfo.vendor, versionInfo.releaseVersion), + info = CordappImpl.Info("corda-core", versionInfo.vendor, versionInfo.releaseVersion, 1, versionInfo.platformVersion), allFlows = listOf(), jarPath = ContractUpgradeFlow.javaClass.location, // Core JAR location jarHash = SecureHash.allOnesHash ) - private fun loadCordapps(): List = cordappJarPaths.map { scanCordapp(it).toCordapp(it) } + private fun loadCordapps(): List { + val cordapps = cordappJarPaths.map { scanCordapp(it).toCordapp(it) } + .filter { + if (it.info.minimumPlatformVersion > versionInfo.platformVersion) { + logger.warn("Not loading CorDapp ${it.info.shortName} (${it.info.vendor}) as it requires minimum platform version ${it.info.minimumPlatformVersion} (This node is running version ${versionInfo.platformVersion}).") + false + } else { + true + } + } + cordapps.forEach { CordappInfoResolver.register(it.cordappClasses, it.info) } + return cordapps + } private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl { val info = url.url.openStream().let(::JarInputStream).use { it.manifest }.toCordappInfo(CordappImpl.jarName(url.url)) diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/ManifestUtils.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/ManifestUtils.kt index 08dd924243..c71a5bf7cb 100644 --- a/node/src/main/kotlin/net/corda/node/internal/cordapp/ManifestUtils.kt +++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/ManifestUtils.kt @@ -38,5 +38,8 @@ fun Manifest?.toCordappInfo(defaultShortName: String): CordappImpl.Info { this?.mainAttributes?.getValue("Implementation-Version")?.let { version -> info = info.copy(version = version) } + val minPlatformVersion = this?.mainAttributes?.getValue("Min-Platform-Version")?.toInt() ?: 1 + val targetPlatformVersion = this?.mainAttributes?.getValue("Target-Platform-Version")?.toInt() ?: minPlatformVersion + info = info.copy(minimumPlatformVersion = minPlatformVersion, targetPlatformVersion = targetPlatformVersion) return info -} +} \ No newline at end of file diff --git a/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt b/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt index 8d1f712399..d622f834f8 100644 --- a/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt +++ b/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt @@ -3,6 +3,8 @@ package net.corda.node.internal.cordapp import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import net.corda.core.node.services.AttachmentStorage +import net.corda.node.VersionInfo +import net.corda.nodeapi.internal.PLATFORM_VERSION import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.internal.MockCordappConfigProvider import net.corda.testing.services.MockAttachmentStorage @@ -75,7 +77,7 @@ class CordappProviderImplTests { fun `test cordapp configuration`() { val configProvider = MockCordappConfigProvider() configProvider.cordappConfigs[isolatedCordappName] = validConfig - val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR)) + val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR), VersionInfo.UNKNOWN) val provider = CordappProviderImpl(loader, configProvider, attachmentStore).apply { start(whitelistedContractImplementations) } val expected = provider.getAppContext(provider.cordapps.first()).config @@ -84,7 +86,7 @@ class CordappProviderImplTests { } private fun newCordappProvider(vararg urls: URL): CordappProviderImpl { - val loader = JarScanningCordappLoader.fromJarUrls(urls.toList()) + val loader = JarScanningCordappLoader.fromJarUrls(urls.toList(), VersionInfo.UNKNOWN) return CordappProviderImpl(loader, stubConfigProvider, attachmentStore).apply { start(whitelistedContractImplementations) } } } diff --git a/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt b/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt index e46cb15278..e71786f8b6 100644 --- a/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoaderTest.kt @@ -2,7 +2,9 @@ package net.corda.node.internal.cordapp import co.paralleluniverse.fibers.Suspendable import net.corda.core.flows.* +import net.corda.node.VersionInfo import net.corda.node.cordapp.CordappLoader +import net.corda.nodeapi.internal.PLATFORM_VERSION import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.getTimestampAsDirectoryName import net.corda.testing.node.internal.packageInDirectory @@ -101,13 +103,70 @@ class JarScanningCordappLoaderTest { @Test fun `cordapp classloader can load cordapp classes`() { val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("isolated.jar")!! - val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR)) + val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR), VersionInfo.UNKNOWN) loader.appClassLoader.loadClass(isolatedContractId) loader.appClassLoader.loadClass(isolatedFlowName) } - private fun cordappLoaderForPackages(packages: Iterable): CordappLoader { + @Test + fun `cordapp classloader sets target and min version to 1 if not specified`() { + val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/no-min-or-target-version.jar")!! + val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN) + loader.cordapps.filter { !it.info.shortName.equals("corda-core") }.forEach { + assertThat(it.info.targetPlatformVersion).isEqualTo(1) + assertThat(it.info.minimumPlatformVersion).isEqualTo(1) + } + } + + @Test + fun `cordapp classloader returns correct values for minPlatformVersion and targetVersion`() { + // load jar with min and target version in manifest + // make sure classloader extracts correct values + val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! + val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN) + // exclude the core cordapp + val cordapp = loader.cordapps.filter { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl")}.single() + assertThat(cordapp.info.targetPlatformVersion).isEqualTo(3) + assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2) + } + + @Test + fun `cordapp classloader sets target version to min version if target version is not specified`() { + // load jar with minVersion but not targetVersion in manifest + val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!! + val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN) + // exclude the core cordapp + val cordapp = loader.cordapps.filter { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl")}.single() + assertThat(cordapp.info.targetPlatformVersion).isEqualTo(2) + assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2) + } + + @Test + fun `cordapp classloader does not load apps when their min platform version is greater than the platform version`() { + val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! + val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1)) + // exclude the core cordapp + assertThat(loader.cordapps.size).isEqualTo(1) + } + + @Test + fun `cordapp classloader does load apps when their min platform version is less than the platform version`() { + val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! + val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1000)) + // exclude the core cordapp + assertThat(loader.cordapps.size).isEqualTo(2) + } + + @Test + fun `cordapp classloader does load apps when their min platform version is equal to the platform version`() { + val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! + val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 2)) + // exclude the core cordapp + assertThat(loader.cordapps.size).isEqualTo(2) + } + + private fun cordappLoaderForPackages(packages: Iterable, versionInfo: VersionInfo = VersionInfo.UNKNOWN): CordappLoader { val cordapps = cordappsForPackages(packages) return testDirectory().let { directory -> diff --git a/node/src/test/resources/net/corda/node/internal/cordapp/versions/min-2-no-target.jar b/node/src/test/resources/net/corda/node/internal/cordapp/versions/min-2-no-target.jar new file mode 100644 index 0000000000000000000000000000000000000000..449691584132e7d716bb5276023ef57b16052a11 GIT binary patch literal 30781 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 literal 0 HcmV?d00001 diff --git a/node/src/test/resources/net/corda/node/internal/cordapp/versions/no-min-or-target-version.jar b/node/src/test/resources/net/corda/node/internal/cordapp/versions/no-min-or-target-version.jar new file mode 100644 index 0000000000000000000000000000000000000000..408e70145dbb633f6b5460bb374aa1ac399f3bcf GIT binary patch literal 12182 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

V!<)Yy>$Cenf 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: CordappLoader { + private fun cordappLoaderForPackages(packages: Iterable, versionInfo: VersionInfo = VersionInfo.UNKNOWN): CordappLoader { val cordappPaths = TestCordappDirectories.forPackages(packages) - return JarScanningCordappLoader.fromDirectories(cordappPaths) + return JarScanningCordappLoader.fromDirectories(cordappPaths, versionInfo) } /** diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt index ba52e79e72..cebb7f6d30 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/InternalMockNetwork.kt @@ -276,7 +276,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe } } - open class MockNode(args: MockNodeArgs, cordappLoader: CordappLoader = JarScanningCordappLoader.fromDirectories(args.config.cordappDirectories)) : AbstractNode( + open class MockNode(args: MockNodeArgs, cordappLoader: CordappLoader = JarScanningCordappLoader.fromDirectories(args.config.cordappDirectories, args.version)) : AbstractNode( args.config, TestClock(Clock.systemUTC()), DefaultNamedCacheFactory(), @@ -474,7 +474,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe val cordappDirectories = sharedCorDappsDirectories + TestCordappDirectories.cached(cordapps) doReturn(cordappDirectories).whenever(config).cordappDirectories - val node = nodeFactory(MockNodeArgs(config, this, id, parameters.entropyRoot, parameters.version), JarScanningCordappLoader.fromDirectories(cordappDirectories)) + val node = nodeFactory(MockNodeArgs(config, this, id, parameters.entropyRoot, parameters.version), JarScanningCordappLoader.fromDirectories(cordappDirectories, parameters.version)) _nodes += node if (start) { node.start()