Safe parsing of min platform version and target version from CorDapp MANIFEST files (#4031)

Also includes some cleanup
This commit is contained in:
Shams Asari
2018-10-04 16:00:07 +01:00
committed by GitHub
parent 064c72dfb1
commit 85d2a85e85
4 changed files with 37 additions and 39 deletions

View File

@ -42,8 +42,7 @@ data class CordappImpl(
// TODO Why a seperate Info class and not just have the fields directly in CordappImpl? // 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, val minimumPlatformVersion: Int, val targetPlatformVersion: Int) { data class Info(val shortName: String, val vendor: String, val version: String, val minimumPlatformVersion: Int, val targetPlatformVersion: Int) {
companion object { companion object {
private const val UNKNOWN_VALUE = "Unknown" const val UNKNOWN_VALUE = "Unknown"
val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE, 1, 1) val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE, 1, 1)
} }

View File

@ -112,10 +112,12 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
) )
private fun loadCordapps(): List<CordappImpl> { private fun loadCordapps(): List<CordappImpl> {
val cordapps = cordappJarPaths.map { scanCordapp(it).toCordapp(it) } val cordapps = cordappJarPaths
.map { scanCordapp(it).toCordapp(it) }
.filter { .filter {
if (it.info.minimumPlatformVersion > versionInfo.platformVersion) { 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}).") 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 false
} else { } else {
true true
@ -126,7 +128,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
} }
private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl { private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl {
val info = url.url.openStream().let(::JarInputStream).use { it.manifest }.toCordappInfo(CordappImpl.jarName(url.url)) val info = url.url.openStream().let(::JarInputStream).use { it.manifest?.toCordappInfo(CordappImpl.jarName(url.url)) ?: CordappImpl.Info.UNKNOWN }
return CordappImpl( return CordappImpl(
findContractClassNames(this), findContractClassNames(this),
findInitiatedFlows(this), findInitiatedFlows(this),

View File

@ -1,6 +1,7 @@
package net.corda.node.internal.cordapp package net.corda.node.internal.cordapp
import net.corda.core.internal.cordapp.CordappImpl import net.corda.core.internal.cordapp.CordappImpl
import net.corda.core.internal.cordapp.CordappImpl.Info.Companion.UNKNOWN_VALUE
import java.util.jar.Attributes import java.util.jar.Attributes
import java.util.jar.Manifest import java.util.jar.Manifest
@ -23,23 +24,23 @@ fun createTestManifest(name: String, title: String, version: String, vendor: Str
return manifest return manifest
} }
operator fun Manifest.set(key: String, value: String) { operator fun Manifest.set(key: String, value: String): String? {
mainAttributes.putValue(key, value) return mainAttributes.putValue(key, value)
} }
fun Manifest?.toCordappInfo(defaultShortName: String): CordappImpl.Info { operator fun Manifest.get(key: String): String? = mainAttributes.getValue(key)
var info = CordappImpl.Info.UNKNOWN
(this?.mainAttributes?.getValue("Name") ?: defaultShortName).let { shortName -> fun Manifest.toCordappInfo(defaultShortName: String): CordappImpl.Info {
info = info.copy(shortName = shortName) val shortName = this["Name"] ?: defaultShortName
} val vendor = this["Implementation-Vendor"] ?: UNKNOWN_VALUE
this?.mainAttributes?.getValue("Implementation-Vendor")?.let { vendor -> val version = this["Implementation-Version"] ?: UNKNOWN_VALUE
info = info.copy(vendor = vendor) val minPlatformVersion = this["Min-Platform-Version"]?.toIntOrNull() ?: 1
} val targetPlatformVersion = this["Target-Platform-Version"]?.toIntOrNull() ?: minPlatformVersion
this?.mainAttributes?.getValue("Implementation-Version")?.let { version -> return CordappImpl.Info(
info = info.copy(version = version) shortName = shortName,
} vendor = vendor,
val minPlatformVersion = this?.mainAttributes?.getValue("Min-Platform-Version")?.toInt() ?: 1 version = version,
val targetPlatformVersion = this?.mainAttributes?.getValue("Target-Platform-Version")?.toInt() ?: minPlatformVersion minimumPlatformVersion = minPlatformVersion,
info = info.copy(minimumPlatformVersion = minPlatformVersion, targetPlatformVersion = targetPlatformVersion) targetPlatformVersion = targetPlatformVersion
return info )
} }

View File

@ -4,7 +4,6 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.flows.* import net.corda.core.flows.*
import net.corda.node.VersionInfo import net.corda.node.VersionInfo
import net.corda.node.cordapp.CordappLoader 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.cordappsForPackages
import net.corda.testing.node.internal.getTimestampAsDirectoryName import net.corda.testing.node.internal.getTimestampAsDirectoryName
import net.corda.testing.node.internal.packageInDirectory import net.corda.testing.node.internal.packageInDirectory
@ -45,7 +44,7 @@ class JarScanningCordappLoaderTest {
} }
@Test @Test
fun `test that classes that aren't in cordapps aren't loaded`() { fun `classes that aren't in cordapps aren't loaded`() {
// Basedir will not be a corda node directory so the dummy flow shouldn't be recognised as a part of a cordapp // Basedir will not be a corda node directory so the dummy flow shouldn't be recognised as a part of a cordapp
val loader = JarScanningCordappLoader.fromDirectories(listOf(Paths.get("."))) val loader = JarScanningCordappLoader.fromDirectories(listOf(Paths.get(".")))
assertThat(loader.cordapps).containsOnly(loader.coreCordapp) assertThat(loader.cordapps).containsOnly(loader.coreCordapp)
@ -56,10 +55,9 @@ class JarScanningCordappLoaderTest {
val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("isolated.jar")!! val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("isolated.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR)) val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR))
val actual = loader.cordapps.toTypedArray() assertThat(loader.cordapps).hasSize(2)
assertThat(actual).hasSize(2)
val actualCordapp = actual.single { it != loader.coreCordapp } val actualCordapp = loader.cordapps.single { it != loader.coreCordapp }
assertThat(actualCordapp.contractClassNames).isEqualTo(listOf(isolatedContractId)) assertThat(actualCordapp.contractClassNames).isEqualTo(listOf(isolatedContractId))
assertThat(actualCordapp.initiatedFlows.single().name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Acceptor") assertThat(actualCordapp.initiatedFlows.single().name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Acceptor")
assertThat(actualCordapp.rpcFlows).isEmpty() assertThat(actualCordapp.rpcFlows).isEmpty()
@ -113,7 +111,7 @@ class JarScanningCordappLoaderTest {
fun `cordapp classloader sets target and min version to 1 if not specified`() { 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 jar = JarScanningCordappLoaderTest::class.java.getResource("versions/no-min-or-target-version.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN) val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
loader.cordapps.filter { !it.info.shortName.equals("corda-core") }.forEach { loader.cordapps.filter { it.info.shortName != "corda-core" }.forEach {
assertThat(it.info.targetPlatformVersion).isEqualTo(1) assertThat(it.info.targetPlatformVersion).isEqualTo(1)
assertThat(it.info.minimumPlatformVersion).isEqualTo(1) assertThat(it.info.minimumPlatformVersion).isEqualTo(1)
} }
@ -126,7 +124,7 @@ class JarScanningCordappLoaderTest {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN) val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
// exclude the core cordapp // exclude the core cordapp
val cordapp = loader.cordapps.filter { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl")}.single() val cordapp = loader.cordapps.single { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl") }
assertThat(cordapp.info.targetPlatformVersion).isEqualTo(3) assertThat(cordapp.info.targetPlatformVersion).isEqualTo(3)
assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2) assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2)
} }
@ -137,17 +135,17 @@ class JarScanningCordappLoaderTest {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!! val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN) val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
// exclude the core cordapp // exclude the core cordapp
val cordapp = loader.cordapps.filter { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl")}.single() val cordapp = loader.cordapps.single { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl") }
assertThat(cordapp.info.targetPlatformVersion).isEqualTo(2) assertThat(cordapp.info.targetPlatformVersion).isEqualTo(2)
assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2) assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2)
} }
@Test @Test
fun `cordapp classloader does not load apps when their min platform version is greater than the platform version`() { fun `cordapp classloader does not load apps when their min platform version is greater than the node platform version`() {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1)) val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1))
// exclude the core cordapp // exclude the core cordapp
assertThat(loader.cordapps.size).isEqualTo(1) assertThat(loader.cordapps).hasSize(1)
} }
@Test @Test
@ -155,7 +153,7 @@ class JarScanningCordappLoaderTest {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1000)) val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1000))
// exclude the core cordapp // exclude the core cordapp
assertThat(loader.cordapps.size).isEqualTo(2) assertThat(loader.cordapps).hasSize(2)
} }
@Test @Test
@ -163,11 +161,10 @@ class JarScanningCordappLoaderTest {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!! val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 2)) val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 2))
// exclude the core cordapp // exclude the core cordapp
assertThat(loader.cordapps.size).isEqualTo(2) assertThat(loader.cordapps).hasSize(2)
} }
private fun cordappLoaderForPackages(packages: Iterable<String>, versionInfo: VersionInfo = VersionInfo.UNKNOWN): CordappLoader { private fun cordappLoaderForPackages(packages: Iterable<String>): CordappLoader {
val cordapps = cordappsForPackages(packages) val cordapps = cordappsForPackages(packages)
return testDirectory().let { directory -> return testDirectory().let { directory ->
cordapps.packageInDirectory(directory) cordapps.packageInDirectory(directory)
@ -176,7 +173,6 @@ class JarScanningCordappLoaderTest {
} }
private fun testDirectory(): Path { private fun testDirectory(): Path {
return Paths.get("build", getTimestampAsDirectoryName()) return Paths.get("build", getTimestampAsDirectoryName())
} }
} }