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 958f18baf1..6bcdf1d577 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 @@ -209,10 +209,20 @@ class JarScanningCordappLoader(private val cordappJars: Set, "(${newerCordapp.contractVersionId}) than corresponding legacy contract CorDapp " + "'${legacyCordapp.jarFile}' (${legacyCordapp.contractVersionId})" } + checkSignersMatch(legacyCordapp, newerCordapp) } } } + private fun checkSignersMatch(legacyCordapp: CordappImpl, nonLegacyCordapp: CordappImpl) { + val legacySigners = legacyCordapp.jarPath.openStream().let(::JarInputStream).use(JarSignatureCollector::collectSigners) + val nonLegacySigners = nonLegacyCordapp.jarPath.openStream().let(::JarInputStream).use(JarSignatureCollector::collectSigners) + check(legacySigners == nonLegacySigners) { + "Newer contract CorDapp '${nonLegacyCordapp.jarFile}' signers do not match legacy contract CorDapp " + + "'${legacyCordapp.jarFile}' signers." + } + } + private val CordappImpl.contractVersionId: Int get() = when (val info = info) { is Cordapp.Info.Contract -> info.versionId 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 4de05a3910..956f2bd3fd 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 @@ -264,6 +264,33 @@ class JarScanningCordappLoaderTest { assertThat(loader.legacyContractCordapps.single().jarFile).isEqualTo(legacyFinanceContractsJar) } + @Test(timeout=300_000) + fun `exception raised if legacy and non legacy version of same contract signed by differet keys`() { + val jar = currentFinanceContractsJar.duplicate { + tempFolder.root.toPath().generateKey("testAlias", "testPassword", ALICE_NAME.toString()) + tempFolder.root.toPath().signJar(absolutePathString(), "testAlias", "testPassword") + } + assertThatIllegalStateException() + .isThrownBy { JarScanningCordappLoader(setOf(jar), setOf(legacyFinanceContractsJar)).cordapps } + .withMessageContaining("signers do not match legacy contract CorDapp") + } + + @Test(timeout=300_000) + fun `loads legacy and non legacy version of same contract both signed by 2 keys`() { + val jar = currentFinanceContractsJar.duplicate { + tempFolder.root.toPath().generateKey("testAlias", "testPassword", ALICE_NAME.toString()) + tempFolder.root.toPath().signJar(absolutePathString(), "testAlias", "testPassword") + } + val legacyJar = legacyFinanceContractsJar.duplicate(name = "duplicate2.jar") { + tempFolder.root.toPath().signJar(absolutePathString(), "testAlias", "testPassword") + } + val loader = JarScanningCordappLoader(setOf(jar), setOf(legacyJar)) + assertThat(jar.parent.getJarSigners(jar.name)).hasSize(2) + assertThat(legacyJar.parent.getJarSigners(legacyJar.name)).hasSize(2) + assertThat(loader.cordapps).hasSize(1) + assertThat(loader.legacyContractCordapps).hasSize(1) + } + @Test(timeout=300_000) fun `does not load legacy contracts CorDapp without the corresponding current version`() { val loader = JarScanningCordappLoader(setOf(currentFinanceWorkflowsJar), setOf(legacyFinanceContractsJar))