From 85d2a85e8515be4be46abd80e7fe9603bcb21634 Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Thu, 4 Oct 2018 16:00:07 +0100 Subject: [PATCH 1/7] Safe parsing of min platform version and target version from CorDapp MANIFEST files (#4031) Also includes some cleanup --- .../core/internal/cordapp/CordappImpl.kt | 3 +- .../cordapp/JarScanningCordappLoader.kt | 8 ++-- .../node/internal/cordapp/ManifestUtils.kt | 37 ++++++++++--------- .../cordapp/JarScanningCordappLoaderTest.kt | 28 ++++++-------- 4 files changed, 37 insertions(+), 39 deletions(-) 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 38891ef254..2e1761afa8 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 @@ -42,8 +42,7 @@ data class 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) { companion object { - private const val UNKNOWN_VALUE = "Unknown" - + const val UNKNOWN_VALUE = "Unknown" val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE, 1, 1) } 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 c691af76c7..96d1e4f435 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 @@ -112,10 +112,12 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths: ) private fun loadCordapps(): List { - val cordapps = cordappJarPaths.map { scanCordapp(it).toCordapp(it) } + 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}).") + 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 @@ -126,7 +128,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths: } 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( findContractClassNames(this), findInitiatedFlows(this), 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 c71a5bf7cb..6e10661c86 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 @@ -1,6 +1,7 @@ package net.corda.node.internal.cordapp 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.Manifest @@ -23,23 +24,23 @@ fun createTestManifest(name: String, title: String, version: String, vendor: Str return manifest } -operator fun Manifest.set(key: String, value: String) { - mainAttributes.putValue(key, value) +operator fun Manifest.set(key: String, value: String): String? { + return mainAttributes.putValue(key, value) } -fun Manifest?.toCordappInfo(defaultShortName: String): CordappImpl.Info { - var info = CordappImpl.Info.UNKNOWN - (this?.mainAttributes?.getValue("Name") ?: defaultShortName).let { shortName -> - info = info.copy(shortName = shortName) - } - this?.mainAttributes?.getValue("Implementation-Vendor")?.let { vendor -> - info = info.copy(vendor = vendor) - } - 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 +operator fun Manifest.get(key: String): String? = mainAttributes.getValue(key) + +fun Manifest.toCordappInfo(defaultShortName: String): CordappImpl.Info { + val shortName = this["Name"] ?: defaultShortName + val vendor = this["Implementation-Vendor"] ?: UNKNOWN_VALUE + val version = this["Implementation-Version"] ?: UNKNOWN_VALUE + val minPlatformVersion = this["Min-Platform-Version"]?.toIntOrNull() ?: 1 + val targetPlatformVersion = this["Target-Platform-Version"]?.toIntOrNull() ?: minPlatformVersion + return CordappImpl.Info( + shortName = shortName, + vendor = vendor, + version = version, + minimumPlatformVersion = minPlatformVersion, + targetPlatformVersion = targetPlatformVersion + ) +} 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 e71786f8b6..927852e1e8 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 @@ -4,7 +4,6 @@ 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 @@ -45,7 +44,7 @@ class JarScanningCordappLoaderTest { } @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 val loader = JarScanningCordappLoader.fromDirectories(listOf(Paths.get("."))) assertThat(loader.cordapps).containsOnly(loader.coreCordapp) @@ -56,10 +55,9 @@ class JarScanningCordappLoaderTest { val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("isolated.jar")!! val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR)) - val actual = loader.cordapps.toTypedArray() - assertThat(actual).hasSize(2) + assertThat(loader.cordapps).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.initiatedFlows.single().name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Acceptor") assertThat(actualCordapp.rpcFlows).isEmpty() @@ -113,7 +111,7 @@ class JarScanningCordappLoaderTest { 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 { + loader.cordapps.filter { it.info.shortName != "corda-core" }.forEach { assertThat(it.info.targetPlatformVersion).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 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() + val cordapp = loader.cordapps.single { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl") } assertThat(cordapp.info.targetPlatformVersion).isEqualTo(3) 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 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() + val cordapp = loader.cordapps.single { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl") } 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")!! + 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-no-target.jar")!! val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1)) // exclude the core cordapp - assertThat(loader.cordapps.size).isEqualTo(1) + assertThat(loader.cordapps).hasSize(1) } @Test @@ -155,7 +153,7 @@ class JarScanningCordappLoaderTest { 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) + assertThat(loader.cordapps).hasSize(2) } @Test @@ -163,11 +161,10 @@ class JarScanningCordappLoaderTest { 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) + assertThat(loader.cordapps).hasSize(2) } - private fun cordappLoaderForPackages(packages: Iterable, versionInfo: VersionInfo = VersionInfo.UNKNOWN): CordappLoader { - + private fun cordappLoaderForPackages(packages: Iterable): CordappLoader { val cordapps = cordappsForPackages(packages) return testDirectory().let { directory -> cordapps.packageInDirectory(directory) @@ -176,7 +173,6 @@ class JarScanningCordappLoaderTest { } private fun testDirectory(): Path { - return Paths.get("build", getTimestampAsDirectoryName()) } } From 962e111389be6ec241c000bfde21c70154d01681 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Thu, 4 Oct 2018 17:44:24 +0200 Subject: [PATCH 2/7] Make the reference states design doc render better and more consistently with the other design docs. --- docs/source/design/reference-states/design.md | 84 +++---------------- 1 file changed, 10 insertions(+), 74 deletions(-) diff --git a/docs/source/design/reference-states/design.md b/docs/source/design/reference-states/design.md index 56e012499e..619bbdd094 100644 --- a/docs/source/design/reference-states/design.md +++ b/docs/source/design/reference-states/design.md @@ -1,42 +1,4 @@ -![Corda](https://www.corda.net/wp-content/uploads/2016/11/fg005_corda_b.png) - -# Design - -DOCUMENT MANAGEMENT ---- - -Design documents should follow the standard GitHub version management and pull request (PR) review workflow mechanism. - -## Document Control - -| Title | | -| -------------------- | ---------------------------------------- | -| Date | 27 March 2018 | -| Author | Roger Willis | -| Distribution | Matthew Nesbit, Rick Parker | -| Corda target version | open source and enterprise | -| JIRA reference | No JIRA's raised. | - -## Approvals - -#### Document Sign-off - -| Author | | -| ----------------- | ---------------------------------------- | -| Reviewer(s) | (GitHub PR reviewers) | -| Final approver(s) | (GitHub PR approver(s) from Design Approval Board) | - -#### Design Decisions - -There's only really one way to do this that satisfies our requirements - add a new input `StateAndRef` component group to the transaction classes. Other possible solutions are discussed below and why they are inappropriate. - -## Document History - -* [Version 1](https://github.com/corda/enterprise/blob/779aaefa5c09a6a28191496dd45252b6e207b7f7/docs/source/design/reference-states/design.md) (Received comments from Richard Brown and Mark Oldfield). -* [Version 2](https://github.com/corda/enterprise/blob/a87f1dcb22ba15081b0da92ba1501b6b81ae2baf/docs/source/design/reference-states/design.md) (Version presented to the DRB). - -HIGH LEVEL DESIGN ---- +# Reference states ## Overview @@ -44,13 +6,15 @@ See a prototype implementation here: https://github.com/corda/corda/pull/2889 There is an increasing need for Corda to support use-cases which require reference data which is issued and updated by specific parties, but available for use, by reference, in transactions built by other parties. -Why is this type of reference data required? +Why is this type of reference data required? A key benefit of blockchain systems is that everybody is sure they see the +same as their counterpart - and for this to work in situations where accurate processing depends on reference data +requires everybody to be operating on the same reference data. This, in turn, requires any given piece of reference data +to be uniquely identifiable and, requires that any given transaction must be certain to be operating on the most current +version of that reference data. In cases where the latter condition applies, only the notary can attest to this fact and +this, in turn, means the reference data must be in the form of an unconsumed state. -1. A key benefit of blockchain systems is that everybody is sure they see the same as their counterpart - and for this to work in situations where accurate processing depends on reference data requires everybody to be operating on the same reference data. -2. This, in turn, requires any given piece of reference data to be uniquely identifiable and, requires that any given transaction must be certain to be operating on the most current version of that reference data. -3. In cases where the latter condition applies, only the notary can attest to this fact and this, in turn, means the reference data must be in the form of an unconsumed state. - -This document outlines the approach for adding support for this type of reference data to the Corda transaction model via a new approach called "reference input states". +This document outlines the approach for adding support for this type of reference data to the Corda transaction model +via a new approach called "reference input states". ## Background @@ -71,16 +35,10 @@ However, neither of these solutions are optimal for reasons discussed in later s As such, this design document introduces the concept of a "reference input state" which is a better way to serve "periodically changing subjective reference data" on Corda. -*What is a "reference input state"?* - A reference input state is a `ContractState` which can be referred to in a transaction by the contracts of input and output states but whose contract is not executed as part of the transaction verification process and is not consumed when the transaction is committed to the ledger but _is_ checked for "current-ness". In other words, the contract logic isn't run for the referencing transaction only. It's still a normal state when it occurs in an input or output position. -*What will reference input states enable?* - Reference data states will enable many parties to "reuse" the same state in their transactions as reference data whilst still allowing the reference data state owner the capability to update the state. When data distribution groups are available then reference state owners will be able to distribute updates to subscribers more easily. Currently, distribution would have to be performed manually. -*Roughly, how are reference input states implemented?* - Reference input states can be added to Corda by adding a new transaction component group that allows developers to add reference data `ContractState`s that are not consumed when the transaction is committed to the ledger. This eliminates the problems created by long chains of provenance, contention, and allows developers to use any `ContractState` for reference data. The feature should allow developers to add _any_ `ContractState` available in their vault, even if they are not a `participant` whilst nevertheless providing a guarantee that the state being used is the most recent version of that piece of information. ## Scope @@ -93,14 +51,6 @@ Non-goals (eg. out of scope) * Data distribution groups are required to realise the full potential of reference data states. This design document does not discuss data distribution groups. -## Timeline - -This work should be ready by the release of Corda V4. There is a prototype which is currently good enough for one of the firm's most critical projects, but more work is required: - -* to assess the impact of this change -* write tests -* write documentation - ## Requirements 1. Reference states can be any `ContractState` created by one or more `Party`s and subsequently updated by those `Party`s. E.g. `Cash`, `CompanyData`, `InterestRateSwap`, `FxRate`. Reference states can be `OwnableState`s, but it's more likely they will be `LinearState`s. @@ -222,18 +172,4 @@ It does the following: 4. If the subflow throws a NotaryException because it tried to finalise and failed, that exception is caught and examined. If the failure was due to a conflict on a referenced state, the flow suspends until that state has been updated in the vault (there is an API to do wait for transaction already, but here the flow must wait for a state update). 5. Then it re-does the initial calculation, re-creates the subflow with the new resolved tips using the factory, and re-runs it as a new subflow. -Care must be taken to handle progress tracking correctly in case of loops. - -## Complementary solutions - -See discussion of alternative approaches above in the "design decisions" section. - -## Final recommendation - -Proceed to Implementation - -TECHNICAL DESIGN ---- - -* Summary of changes to be included. -* Summary of outstanding issues to be included. \ No newline at end of file +Care must be taken to handle progress tracking correctly in case of loops. \ No newline at end of file From bffac331a37666415b91c0780d811669885a5d48 Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Fri, 5 Oct 2018 09:28:00 +0100 Subject: [PATCH 3/7] Moved the PLATFORM_VERSION constant to core and added some missing usages (#4026) --- build.gradle | 1 - .../net/corda/client/rpc/CordaRPCClient.kt | 2 +- constants.properties | 6 ++++-- .../kotlin/net/corda/core/internal/CordaUtils.kt | 2 ++ .../kotlin/net/corda/core/NodeVersioningTest.kt | 16 ++++------------ .../corda/nodeapi/internal/NodeInfoConstants.kt | 1 - .../internal/network/NetworkBootstrapperTest.kt | 2 +- .../node/services/AttachmentLoadingTests.kt | 1 - .../main/kotlin/net/corda/node/VersionInfo.kt | 2 +- .../net/corda/node/internal/NodeStartup.kt | 2 +- .../internal/cordapp/CordappProviderImplTests.kt | 1 - .../net/corda/testing/node/MockServices.kt | 2 -- .../corda/testing/node/internal/DriverDSLImpl.kt | 4 +--- .../testing/node/internal/InternalMockNetwork.kt | 2 +- .../corda/testing/node/internal/NodeBasedTest.kt | 9 +++++---- .../main/kotlin/net/corda/bootstrapper/Main.kt | 2 +- 16 files changed, 22 insertions(+), 33 deletions(-) diff --git a/build.gradle b/build.gradle index 233c8be5c1..36872b5fef 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,6 @@ buildscript { // Our version: bump this on release. ext.corda_release_version = "4.0-SNAPSHOT" - // Increment this on any release that changes public APIs anywhere in the Corda platform ext.corda_platform_version = constants.getProperty("platformVersion") ext.gradle_plugins_version = constants.getProperty("gradlePluginsVersion") diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt index 116e6baf84..db445caa55 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt @@ -13,7 +13,7 @@ import net.corda.core.utilities.days import net.corda.core.utilities.minutes import net.corda.core.utilities.seconds import net.corda.nodeapi.internal.ArtemisTcpTransport.Companion.rpcConnectorTcpTransport -import net.corda.nodeapi.internal.PLATFORM_VERSION +import net.corda.core.internal.PLATFORM_VERSION import net.corda.serialization.internal.AMQP_RPC_CLIENT_CONTEXT import java.time.Duration diff --git a/constants.properties b/constants.properties index 8d23d66503..d472994d01 100644 --- a/constants.properties +++ b/constants.properties @@ -1,7 +1,9 @@ gradlePluginsVersion=4.0.29 kotlinVersion=1.2.51 -# When adjusting platformVersion upwards please also modify CordaRPCClientConfiguration.minimumServerProtocolVersion \ -# if there have been any RPC changes. Also please modify InternalMockNetwork.kt:MOCK_VERSION_INFO and NodeBasedTest.startNode +# ***************************************************************# +# When incrementing platformVersion make sure to update # +# net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. # +# ***************************************************************# platformVersion=4 guavaVersion=25.1-jre proguardVersion=6.0.3 diff --git a/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt b/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt index 35ea7158ef..c7651da4cb 100644 --- a/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt @@ -17,6 +17,8 @@ import org.slf4j.MDC // *Internal* Corda-specific utilities +const val PLATFORM_VERSION = 4 + fun ServicesForResolution.ensureMinimumPlatformVersion(requiredMinPlatformVersion: Int, feature: String) { val currentMinPlatformVersion = networkParameters.minimumPlatformVersion if (currentMinPlatformVersion < requiredMinPlatformVersion) { 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 20f7e8cbfd..e118fe0326 100644 --- a/core/src/smoke-test/kotlin/net/corda/core/NodeVersioningTest.kt +++ b/core/src/smoke-test/kotlin/net/corda/core/NodeVersioningTest.kt @@ -10,11 +10,9 @@ import net.corda.core.utilities.getOrThrow import net.corda.nodeapi.internal.config.User import net.corda.smoketesting.NodeConfig import net.corda.smoketesting.NodeProcess -import net.corda.testing.common.internal.ProjectStructure import org.assertj.core.api.Assertions.assertThat import org.junit.Test import java.nio.file.Paths -import java.util.* import java.util.concurrent.atomic.AtomicInteger import java.util.jar.JarFile import kotlin.streams.toList @@ -23,12 +21,6 @@ class NodeVersioningTest { private companion object { val user = User("user1", "test", permissions = setOf("ALL")) val port = AtomicInteger(15100) - - val expectedPlatformVersion = (ProjectStructure.projectRootDir / "constants.properties").read { - val constants = Properties() - constants.load(it) - constants.getProperty("platformVersion").toInt() - } } private val factory = NodeProcess.Factory() @@ -45,7 +37,7 @@ class NodeVersioningTest { @Test fun `platform version in manifest file`() { val manifest = JarFile(factory.cordaJar.toFile()).manifest - assertThat(manifest.mainAttributes.getValue("Corda-Platform-Version").toInt()).isEqualTo(expectedPlatformVersion) + assertThat(manifest.mainAttributes.getValue("Corda-Platform-Version").toInt()).isEqualTo(PLATFORM_VERSION) } @Test @@ -60,9 +52,9 @@ class NodeVersioningTest { factory.create(aliceConfig).use { alice -> alice.connect().use { val rpc = it.proxy - assertThat(rpc.protocolVersion).isEqualTo(expectedPlatformVersion) - assertThat(rpc.nodeInfo().platformVersion).isEqualTo(expectedPlatformVersion) - assertThat(rpc.startFlow(NodeVersioningTest::GetPlatformVersionFlow).returnValue.getOrThrow()).isEqualTo(expectedPlatformVersion) + assertThat(rpc.protocolVersion).isEqualTo(PLATFORM_VERSION) + assertThat(rpc.nodeInfo().platformVersion).isEqualTo(PLATFORM_VERSION) + assertThat(rpc.startFlow(NodeVersioningTest::GetPlatformVersionFlow).returnValue.getOrThrow()).isEqualTo(PLATFORM_VERSION) } } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/NodeInfoConstants.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/NodeInfoConstants.kt index 79cb6844de..371ed2cd57 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/NodeInfoConstants.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/NodeInfoConstants.kt @@ -2,4 +2,3 @@ package net.corda.nodeapi.internal // TODO: Add to Corda node.conf to allow customisation const val NODE_INFO_DIRECTORY = "additional-node-infos" -const val PLATFORM_VERSION = 4 diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapperTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapperTest.kt index 1871ea553f..a3ddb3cc93 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapperTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapperTest.kt @@ -11,7 +11,7 @@ import net.corda.core.serialization.serialize import net.corda.node.services.config.NotaryConfig import net.corda.nodeapi.internal.DEV_ROOT_CA import net.corda.nodeapi.internal.NODE_INFO_DIRECTORY -import net.corda.nodeapi.internal.PLATFORM_VERSION +import net.corda.core.internal.PLATFORM_VERSION import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.config.parseAs import net.corda.nodeapi.internal.config.toConfig 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 d21de023cb..b9e5029fc9 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 @@ -26,7 +26,6 @@ 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 diff --git a/node/src/main/kotlin/net/corda/node/VersionInfo.kt b/node/src/main/kotlin/net/corda/node/VersionInfo.kt index b3d0ec0fbb..01492ee396 100644 --- a/node/src/main/kotlin/net/corda/node/VersionInfo.kt +++ b/node/src/main/kotlin/net/corda/node/VersionInfo.kt @@ -1,6 +1,6 @@ package net.corda.node -import net.corda.nodeapi.internal.PLATFORM_VERSION +import net.corda.core.internal.PLATFORM_VERSION /** * Encapsulates various pieces of version information of the node. 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 74f3b0f40f..1b089a7c63 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -28,7 +28,7 @@ import net.corda.node.utilities.registration.NodeRegistrationException import net.corda.node.utilities.registration.NodeRegistrationHelper import net.corda.node.utilities.saveToKeyStore import net.corda.node.utilities.saveToTrustStore -import net.corda.nodeapi.internal.PLATFORM_VERSION +import net.corda.core.internal.PLATFORM_VERSION import net.corda.nodeapi.internal.addShutdownHook import net.corda.nodeapi.internal.config.UnknownConfigurationKeysException import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException 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 d622f834f8..77d97f5715 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 @@ -4,7 +4,6 @@ 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 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 be91c42c1f..112cf3f19f 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 @@ -28,10 +28,8 @@ import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.transactions.InMemoryTransactionVerifierService import net.corda.node.services.vault.NodeVaultService -import net.corda.nodeapi.internal.PLATFORM_VERSION import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.DatabaseConfig -import net.corda.nodeapi.internal.persistence.HibernateConfiguration import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.TestIdentity import net.corda.testing.internal.DEV_ROOT_CA diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt index 850cf8f8d5..92615f3fd0 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt @@ -28,7 +28,7 @@ import net.corda.node.services.Permissions import net.corda.node.services.config.* import net.corda.node.utilities.registration.HTTPNetworkRegistrationService import net.corda.node.utilities.registration.NodeRegistrationHelper -import net.corda.nodeapi.internal.PLATFORM_VERSION +import net.corda.core.internal.PLATFORM_VERSION import net.corda.nodeapi.internal.DevIdentityGenerator import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.addShutdownHook @@ -54,10 +54,8 @@ import net.corda.testing.node.User import net.corda.testing.node.internal.DriverDSLImpl.Companion.cordappsInCurrentAndAdditionalPackages import okhttp3.OkHttpClient import okhttp3.Request -import rx.Observable import rx.Subscription import rx.schedulers.Schedulers -import rx.subjects.AsyncSubject import java.lang.management.ManagementFactory import java.net.ConnectException import java.net.URL 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 cebb7f6d30..9d6ce49198 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 @@ -74,7 +74,7 @@ import java.time.Clock import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger -val MOCK_VERSION_INFO = VersionInfo(4, "Mock release", "Mock revision", "Mock Vendor") +val MOCK_VERSION_INFO = VersionInfo(PLATFORM_VERSION, "Mock release", "Mock revision", "Mock Vendor") data class MockNodeArgs( val config: NodeConfiguration, diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt index b21df970db..66a4f2408d 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/NodeBasedTest.kt @@ -2,6 +2,7 @@ package net.corda.testing.node.internal import com.typesafe.config.ConfigValueFactory import net.corda.core.identity.CordaX500Name +import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.internal.concurrent.fork import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.createDirectories @@ -31,12 +32,12 @@ import java.nio.file.Path import java.util.concurrent.Executors import kotlin.concurrent.thread -// TODO Some of the logic here duplicates what's in the driver - the reason why it's not straightforward to replace it by using DriverDSLImpl in `init()` and `stopAllNodes()` is because of the platform version passed to nodes (driver doesn't support this, and it's a property of the Corda JAR) +// TODO Some of the logic here duplicates what's in the driver - the reason why it's not straightforward to replace it by +// using DriverDSLImpl in `init()` and `stopAllNodes()` is because of the platform version passed to nodes (driver doesn't +// support this, and it's a property of the Corda JAR) abstract class NodeBasedTest(private val cordappPackages: List = emptyList()) { companion object { private val WHITESPACE = "\\s++".toRegex() - - private val logger = loggerFor() } @Rule @@ -85,7 +86,7 @@ abstract class NodeBasedTest(private val cordappPackages: List = emptyLi @JvmOverloads fun startNode(legalName: CordaX500Name, - platformVersion: Int = 4, + platformVersion: Int = PLATFORM_VERSION, rpcUsers: List = emptyList(), configOverrides: Map = emptyMap()): NodeWithInfo { val baseDirectory = baseDirectory(legalName).createDirectories() diff --git a/tools/bootstrapper/src/main/kotlin/net/corda/bootstrapper/Main.kt b/tools/bootstrapper/src/main/kotlin/net/corda/bootstrapper/Main.kt index 9d382516fa..e3a1967e2e 100644 --- a/tools/bootstrapper/src/main/kotlin/net/corda/bootstrapper/Main.kt +++ b/tools/bootstrapper/src/main/kotlin/net/corda/bootstrapper/Main.kt @@ -2,7 +2,7 @@ package net.corda.bootstrapper import net.corda.cliutils.CordaCliWrapper import net.corda.cliutils.start -import net.corda.nodeapi.internal.PLATFORM_VERSION +import net.corda.core.internal.PLATFORM_VERSION import net.corda.nodeapi.internal.network.NetworkBootstrapper import picocli.CommandLine.Option import java.nio.file.Path From d75fd7bd8a16757a6e92b3178ef64a684e2147bf Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Fri, 5 Oct 2018 11:01:27 +0100 Subject: [PATCH 4/7] CORDA-2030: Resolve build warnings created by adding kotlin-stdlib-jre8 to node. (#4033) --- testing/test-utils/build.gradle | 5 ++++- tools/network-bootstrapper/build.gradle | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/testing/test-utils/build.gradle b/testing/test-utils/build.gradle index 36c44a076b..715c795317 100644 --- a/testing/test-utils/build.gradle +++ b/testing/test-utils/build.gradle @@ -9,7 +9,10 @@ description 'Testing utilities for Corda' dependencies { compile project(':test-common') - compile project(':node') + compile(project(':node')) { + // The Node only needs this for binary compatibility with Cordapps written in Kotlin 1.1. + exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jre8' + } compile project(':client:mock') compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" diff --git a/tools/network-bootstrapper/build.gradle b/tools/network-bootstrapper/build.gradle index 674b97f229..316be6e723 100644 --- a/tools/network-bootstrapper/build.gradle +++ b/tools/network-bootstrapper/build.gradle @@ -16,6 +16,9 @@ configurations { compile { exclude group: "log4j", module: "log4j" exclude group: "org.apache.logging.log4j" + + // The Node only needs this for binary compatibility with Cordapps written in Kotlin 1.1. + exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jre8' } } From fa4c54a080faec87f42899ff51a2ceb64dac81fb Mon Sep 17 00:00:00 2001 From: Konstantinos Chalkias Date: Fri, 5 Oct 2018 12:01:16 +0100 Subject: [PATCH 5/7] [CORDA-2063] Ensure signatures and BC operations always use newSecureRandom (#4020) * special handling for Sphincs due a BC implementation issue * delete all sign operations from DJVM and stub out BC's default RNG * copy Crypto signing functions to deterministic.crypto.CryptoSignUtils as they are required for testing transaction signatures. --- .../deterministic/crypto/CryptoSignUtils.kt | 68 +++++++++++++++++++ .../crypto/TransactionSignatureTest.kt | 7 +- .../kotlin/net/corda/core/crypto/Crypto.kt | 27 +++++++- .../net/corda/core/crypto/CryptoUtils.kt | 5 ++ .../net/corda/core/internal/InternalUtils.kt | 4 ++ .../core/transactions/SignedTransaction.kt | 1 + 6 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/CryptoSignUtils.kt diff --git a/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/CryptoSignUtils.kt b/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/CryptoSignUtils.kt new file mode 100644 index 0000000000..9351d06bc3 --- /dev/null +++ b/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/CryptoSignUtils.kt @@ -0,0 +1,68 @@ +@file:JvmName("CryptoSignUtils") + +package net.corda.deterministic.crypto + +import net.corda.core.crypto.* +import net.corda.core.crypto.Crypto.findSignatureScheme +import net.corda.core.crypto.Crypto.isSupportedSignatureScheme +import net.corda.core.serialization.serialize +import java.security.* + +/** + * This is a slightly modified copy of signing utils from net.corda.core.crypto.Crypto, which are normally removed from DJVM. + * However, we need those for TransactionSignatureTest. + */ +object CryptoSignUtils { + @JvmStatic + @Throws(InvalidKeyException::class, SignatureException::class) + fun doSign(schemeCodeName: String, privateKey: PrivateKey, clearData: ByteArray): ByteArray { + return doSign(findSignatureScheme(schemeCodeName), privateKey, clearData) + } + + /** + * Generic way to sign [ByteArray] data with a [PrivateKey] and a known [Signature]. + * @param signatureScheme a [SignatureScheme] object, retrieved from supported signature schemes, see [Crypto]. + * @param privateKey the signer's [PrivateKey]. + * @param clearData the data/message to be signed in [ByteArray] form (usually the Merkle root). + * @return the digital signature (in [ByteArray]) on the input message. + * @throws IllegalArgumentException if the signature scheme is not supported for this private key. + * @throws InvalidKeyException if the private key is invalid. + * @throws SignatureException if signing is not possible due to malformed data or private key. + */ + @JvmStatic + @Throws(InvalidKeyException::class, SignatureException::class) + fun doSign(signatureScheme: SignatureScheme, privateKey: PrivateKey, clearData: ByteArray): ByteArray { + require(isSupportedSignatureScheme(signatureScheme)) { + "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" + } + require(clearData.isNotEmpty()) { "Signing of an empty array is not permitted!" } + val signature = Signature.getInstance(signatureScheme.signatureName, signatureScheme.providerName) + signature.initSign(privateKey) + signature.update(clearData) + return signature.sign() + } + + /** + * Generic way to sign [SignableData] objects with a [PrivateKey]. + * [SignableData] is a wrapper over the transaction's id (Merkle root) in order to attach extra information, such as + * a timestamp or partial and blind signature indicators. + * @param keyPair the signer's [KeyPair]. + * @param signableData a [SignableData] object that adds extra information to a transaction. + * @return a [TransactionSignature] object than contains the output of a successful signing, signer's public key and + * the signature metadata. + * @throws IllegalArgumentException if the signature scheme is not supported for this private key. + * @throws InvalidKeyException if the private key is invalid. + * @throws SignatureException if signing is not possible due to malformed data or private key. + */ + @JvmStatic + @Throws(InvalidKeyException::class, SignatureException::class) + fun doSign(keyPair: KeyPair, signableData: SignableData): TransactionSignature { + val sigKey: SignatureScheme = findSignatureScheme(keyPair.private) + val sigMetaData: SignatureScheme = findSignatureScheme(keyPair.public) + require(sigKey == sigMetaData) { + "Metadata schemeCodeName: ${sigMetaData.schemeCodeName} is not aligned with the key type: ${sigKey.schemeCodeName}." + } + val signatureBytes = doSign(sigKey.schemeCodeName, keyPair.private, signableData.serialize().bytes) + return TransactionSignature(signatureBytes, keyPair.public, signableData.signatureMetadata) + } +} diff --git a/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/TransactionSignatureTest.kt b/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/TransactionSignatureTest.kt index 4825d4787f..0e9191f308 100644 --- a/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/TransactionSignatureTest.kt +++ b/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/TransactionSignatureTest.kt @@ -37,7 +37,7 @@ class TransactionSignatureTest { // Sign the meta object. val transactionSignature: TransactionSignature = CheatingSecurityProvider().use { - keyPair.sign(signableData) + CryptoSignUtils.doSign(keyPair, signableData) } // Check auto-verification. @@ -52,7 +52,7 @@ class TransactionSignatureTest { fun `Signature metadata full failure clearData has changed`() { val signableData = SignableData(testBytes.sha256(), SignatureMetadata(1, Crypto.findSignatureScheme(keyPair.public).schemeNumberID)) val transactionSignature = CheatingSecurityProvider().use { - keyPair.sign(signableData) + CryptoSignUtils.doSign(keyPair, signableData) } Crypto.doVerify((testBytes + testBytes).sha256(), transactionSignature) } @@ -137,7 +137,8 @@ class TransactionSignatureTest { private fun signOneTx(txId: SecureHash, keyPair: KeyPair): TransactionSignature { val signableData = SignableData(txId, SignatureMetadata(3, Crypto.findSignatureScheme(keyPair.public).schemeNumberID)) return CheatingSecurityProvider().use { - keyPair.sign(signableData) + CryptoSignUtils.doSign(keyPair, signableData) + } } } diff --git a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt index a172f31747..29465d2808 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt @@ -2,6 +2,7 @@ package net.corda.core.crypto import net.corda.core.DeleteForDJVM import net.corda.core.KeepForDJVM +import net.corda.core.StubOutForDJVM import net.corda.core.crypto.internal.* import net.corda.core.serialization.serialize import net.i2p.crypto.eddsa.EdDSAEngine @@ -23,6 +24,7 @@ import org.bouncycastle.asn1.sec.SECObjectIdentifiers import org.bouncycastle.asn1.x509.AlgorithmIdentifier import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo import org.bouncycastle.asn1.x9.X9ObjectIdentifiers +import org.bouncycastle.crypto.CryptoServicesRegistrar import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateKey @@ -381,6 +383,7 @@ object Crypto { * @throws InvalidKeyException if the private key is invalid. * @throws SignatureException if signing is not possible due to malformed data or private key. */ + @DeleteForDJVM @JvmStatic @Throws(InvalidKeyException::class, SignatureException::class) fun doSign(privateKey: PrivateKey, clearData: ByteArray): ByteArray = doSign(findSignatureScheme(privateKey), privateKey, clearData) @@ -395,6 +398,7 @@ object Crypto { * @throws InvalidKeyException if the private key is invalid. * @throws SignatureException if signing is not possible due to malformed data or private key. */ + @DeleteForDJVM @JvmStatic @Throws(InvalidKeyException::class, SignatureException::class) fun doSign(schemeCodeName: String, privateKey: PrivateKey, clearData: ByteArray): ByteArray { @@ -411,6 +415,7 @@ object Crypto { * @throws InvalidKeyException if the private key is invalid. * @throws SignatureException if signing is not possible due to malformed data or private key. */ + @DeleteForDJVM @JvmStatic @Throws(InvalidKeyException::class, SignatureException::class) fun doSign(signatureScheme: SignatureScheme, privateKey: PrivateKey, clearData: ByteArray): ByteArray { @@ -419,7 +424,16 @@ object Crypto { } require(clearData.isNotEmpty()) { "Signing of an empty array is not permitted!" } val signature = Signature.getInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName]) - signature.initSign(privateKey) + // Note that deterministic signature schemes, such as EdDSA, do not require extra randomness, but we have to + // ensure that non-deterministic algorithms (i.e., ECDSA) use non-blocking SecureRandom implementations (if possible). + // TODO consider updating this when the related BC issue for Sphincs is fixed. + if (signatureScheme != SPHINCS256_SHA256) { + signature.initSign(privateKey, newSecureRandom()) + } else { + // Special handling for Sphincs, due to a BC implementation issue. + // As Sphincs is deterministic, it does not require RNG input anyway. + signature.initSign(privateKey) + } signature.update(clearData) return signature.sign() } @@ -436,6 +450,7 @@ object Crypto { * @throws InvalidKeyException if the private key is invalid. * @throws SignatureException if signing is not possible due to malformed data or private key. */ + @DeleteForDJVM @JvmStatic @Throws(InvalidKeyException::class, SignatureException::class) fun doSign(keyPair: KeyPair, signableData: SignableData): TransactionSignature { @@ -1017,5 +1032,15 @@ object Crypto { @JvmStatic fun registerProviders() { providerMap + // Adding our non-blocking newSecureRandom as default for any BouncyCastle operations + // (applies only when a SecureRandom is not specifically defined, i.e., if we call + // signature.initSign(privateKey) instead of signature.initSign(privateKey, newSecureRandom() + // for a BC algorithm, i.e., ECDSA). + setBouncyCastleRNG() + } + + @StubOutForDJVM + private fun setBouncyCastleRNG() { + CryptoServicesRegistrar.setSecureRandom(newSecureRandom()) } } diff --git a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt index 1cc29b5fdd..535f0013ef 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt @@ -24,6 +24,7 @@ import java.security.* * @throws InvalidKeyException if the private key is invalid. * @throws SignatureException if signing is not possible due to malformed data or private key. */ +@DeleteForDJVM @Throws(InvalidKeyException::class, SignatureException::class) fun PrivateKey.sign(bytesToSign: ByteArray): DigitalSignature = DigitalSignature(Crypto.doSign(this, bytesToSign)) @@ -36,6 +37,7 @@ fun PrivateKey.sign(bytesToSign: ByteArray): DigitalSignature = DigitalSignature * @throws InvalidKeyException if the private key is invalid. * @throws SignatureException if signing is not possible due to malformed data or private key. */ +@DeleteForDJVM @Throws(InvalidKeyException::class, SignatureException::class) fun PrivateKey.sign(bytesToSign: ByteArray, publicKey: PublicKey): DigitalSignature.WithKey { return DigitalSignature.WithKey(publicKey, this.sign(bytesToSign).bytes) @@ -49,10 +51,12 @@ fun PrivateKey.sign(bytesToSign: ByteArray, publicKey: PublicKey): DigitalSignat * @throws InvalidKeyException if the private key is invalid. * @throws SignatureException if signing is not possible due to malformed data or private key. */ +@DeleteForDJVM @Throws(InvalidKeyException::class, SignatureException::class) fun KeyPair.sign(bytesToSign: ByteArray): DigitalSignature.WithKey = private.sign(bytesToSign, public) /** Helper function to sign the bytes of [bytesToSign] with a key pair. */ +@DeleteForDJVM @Throws(InvalidKeyException::class, SignatureException::class) fun KeyPair.sign(bytesToSign: OpaqueBytes): DigitalSignature.WithKey = sign(bytesToSign.bytes) @@ -64,6 +68,7 @@ fun KeyPair.sign(bytesToSign: OpaqueBytes): DigitalSignature.WithKey = sign(byte * @throws InvalidKeyException if the private key is invalid. * @throws SignatureException if signing is not possible due to malformed data or private key. */ +@DeleteForDJVM @Throws(InvalidKeyException::class, SignatureException::class) fun KeyPair.sign(signableData: SignableData): TransactionSignature = Crypto.doSign(this, signableData) 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 078cfcaa11..9814502433 100644 --- a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt @@ -457,11 +457,13 @@ $trustAnchor""", e, this, e.index) } } +@DeleteForDJVM inline fun T.signWithCert(signer: (SerializedBytes) -> DigitalSignatureWithCert): SignedDataWithCert { val serialised = serialize() return SignedDataWithCert(serialised, signer(serialised)) } +@DeleteForDJVM fun T.signWithCert(privateKey: PrivateKey, certificate: X509Certificate): SignedDataWithCert { return signWithCert { val signature = Crypto.doSign(privateKey, it.bytes) @@ -469,10 +471,12 @@ fun T.signWithCert(privateKey: PrivateKey, certificate: X509Certificat } } +@DeleteForDJVM inline fun SerializedBytes.sign(signer: (SerializedBytes) -> DigitalSignature.WithKey): SignedData { return SignedData(this, signer(this)) } +@DeleteForDJVM fun SerializedBytes.sign(keyPair: KeyPair): SignedData = SignedData(this, keyPair.sign(this.bytes)) fun ByteBuffer.copyBytes(): ByteArray = ByteArray(remaining()).also { get(it) } diff --git a/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt index f035192a48..601efcd8cf 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt @@ -91,6 +91,7 @@ data class SignedTransaction(val txBits: SerializedBytes, return descriptions } + @DeleteForDJVM @VisibleForTesting fun withAdditionalSignature(keyPair: KeyPair, signatureMetadata: SignatureMetadata): SignedTransaction { val signableData = SignableData(tx.id, signatureMetadata) From 0621efe7c6a29c35c7d54aa715908ed0961f9873 Mon Sep 17 00:00:00 2001 From: Konstantinos Chalkias Date: Fri, 5 Oct 2018 14:11:56 +0100 Subject: [PATCH 6/7] Do not remove entropyToKeyPair from DJVM (it is deterministic anyway and we might use it in tests) (#4036) --- .../net/corda/deterministic/crypto/TransactionSignatureTest.kt | 1 - core/src/main/kotlin/net/corda/core/crypto/Crypto.kt | 2 -- core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt | 1 - 3 files changed, 4 deletions(-) diff --git a/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/TransactionSignatureTest.kt b/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/TransactionSignatureTest.kt index 0e9191f308..ac5e7971eb 100644 --- a/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/TransactionSignatureTest.kt +++ b/core-deterministic/testing/src/test/kotlin/net/corda/deterministic/crypto/TransactionSignatureTest.kt @@ -138,7 +138,6 @@ class TransactionSignatureTest { val signableData = SignableData(txId, SignatureMetadata(3, Crypto.findSignatureScheme(keyPair.public).schemeNumberID)) return CheatingSecurityProvider().use { CryptoSignUtils.doSign(keyPair, signableData) - } } } diff --git a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt index 29465d2808..e131cdc7df 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt @@ -809,7 +809,6 @@ object Crypto { * @return a new [KeyPair] from an entropy input. * @throws IllegalArgumentException if the requested signature scheme is not supported for KeyPair generation using an entropy input. */ - @DeleteForDJVM @JvmStatic fun deriveKeyPairFromEntropy(signatureScheme: SignatureScheme, entropy: BigInteger): KeyPair { return when (signatureScheme) { @@ -825,7 +824,6 @@ object Crypto { * @param entropy a [BigInteger] value. * @return a new [KeyPair] from an entropy input. */ - @DeleteForDJVM @JvmStatic fun deriveKeyPairFromEntropy(entropy: BigInteger): KeyPair = deriveKeyPairFromEntropy(DEFAULT_SIGNATURE_SCHEME, entropy) diff --git a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt index 535f0013ef..a58665c069 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt @@ -150,7 +150,6 @@ fun generateKeyPair(): KeyPair = Crypto.generateKeyPair() * @param entropy a [BigInteger] value. * @return a deterministically generated [KeyPair] for the [Crypto.DEFAULT_SIGNATURE_SCHEME]. */ -@DeleteForDJVM fun entropyToKeyPair(entropy: BigInteger): KeyPair = Crypto.deriveKeyPairFromEntropy(entropy) /** From 39434dcbecdd2cd656e40622530e84d02443b8e2 Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Fri, 5 Oct 2018 18:05:10 +0100 Subject: [PATCH 7/7] Assorted set of clean ups (#4039) --- client/rpc/.attach_pid14784 | 0 .../core/flows/ContractUpgradeFlowTest.kt | 2 +- .../flows/WithReferencedStatesFlowTests.kt | 52 ++++++++--------- .../corda/core/flows/mixins/WithFinality.kt | 27 +++++---- .../docs/java/tutorial/twoparty/IOUFlow.java | 6 +- .../kotlin/tutorial/helloworld/IOUState.kt | 4 +- .../docs/kotlin/tutorial/twoparty/IOUFlow.kt | 8 ++- .../tutorial/twoparty/IOUFlowResponder.kt | 4 +- .../docs/{ => kotlin}/CustomVaultQueryTest.kt | 3 +- .../FxTransactionBuildTutorialTest.kt | 10 +--- .../WorkflowTransactionBuildTutorialTest.kt | 6 +- docs/source/hello-world-flow.rst | 3 +- .../net/corda/loadtest/tests/NotaryTest.kt | 57 ------------------- 13 files changed, 61 insertions(+), 121 deletions(-) delete mode 100644 client/rpc/.attach_pid14784 rename docs/source/example-code/src/test/kotlin/net/corda/docs/{ => kotlin}/CustomVaultQueryTest.kt (98%) rename docs/source/example-code/src/test/kotlin/net/corda/docs/{ => kotlin}/FxTransactionBuildTutorialTest.kt (92%) rename docs/source/example-code/src/test/kotlin/net/corda/docs/{ => kotlin}/WorkflowTransactionBuildTutorialTest.kt (95%) delete mode 100644 tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/NotaryTest.kt diff --git a/client/rpc/.attach_pid14784 b/client/rpc/.attach_pid14784 deleted file mode 100644 index e69de29bb2..0000000000 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 ead8da3ae4..8d30b83b62 100644 --- a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt +++ b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt @@ -52,7 +52,7 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality { @Test fun `2 parties contract upgrade`() { // Create dummy contract. - val signedByA = aliceNode.signDummyContract(alice.ref(1),0, bob.ref(1)) + val signedByA = aliceNode.signDummyContract(alice.ref(1), 0, bob.ref(1)) val stx = bobNode.addSignatureTo(signedByA) aliceNode.finalise(stx, bob) diff --git a/core/src/test/kotlin/net/corda/core/flows/WithReferencedStatesFlowTests.kt b/core/src/test/kotlin/net/corda/core/flows/WithReferencedStatesFlowTests.kt index 2263f85b39..a6d007b549 100644 --- a/core/src/test/kotlin/net/corda/core/flows/WithReferencedStatesFlowTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/WithReferencedStatesFlowTests.kt @@ -24,14 +24,14 @@ import org.junit.After import org.junit.Test import kotlin.test.assertEquals - // A dummy reference state contract. internal class RefState : Contract { companion object { - val CONTRACT_ID = "net.corda.core.flows.RefState" + const val CONTRACT_ID = "net.corda.core.flows.RefState" } override fun verify(tx: LedgerTransaction) = Unit + data class State(val owner: Party, val version: Int = 0, override val linearId: UniqueIdentifier = UniqueIdentifier()) : LinearState { override val participants: List get() = listOf(owner) fun update() = copy(version = version + 1) @@ -46,34 +46,32 @@ internal class CreateRefState : FlowLogic() { @Suspendable override fun call(): SignedTransaction { val notary = serviceHub.networkMapCache.notaryIdentities.first() - return subFlow(FinalityFlow( - transaction = serviceHub.signInitialTransaction(TransactionBuilder(notary = notary).apply { - addOutputState(RefState.State(ourIdentity), RefState.CONTRACT_ID) - addCommand(RefState.Create(), listOf(ourIdentity.owningKey)) - }) - )) + val stx = serviceHub.signInitialTransaction(TransactionBuilder(notary = notary).apply { + addOutputState(RefState.State(ourIdentity), RefState.CONTRACT_ID) + addCommand(RefState.Create(), listOf(ourIdentity.owningKey)) + }) + return subFlow(FinalityFlow(stx)) } } // A flow to update a specific reference state. -internal class UpdateRefState(val stateAndRef: StateAndRef) : FlowLogic() { +internal class UpdateRefState(private val stateAndRef: StateAndRef) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { val notary = serviceHub.networkMapCache.notaryIdentities.first() - return subFlow(FinalityFlow( - transaction = serviceHub.signInitialTransaction(TransactionBuilder(notary = notary).apply { - addInputState(stateAndRef) - addOutputState((stateAndRef.state.data as RefState.State).update(), RefState.CONTRACT_ID) - addCommand(RefState.Update(), listOf(ourIdentity.owningKey)) - }) - )) + val stx = serviceHub.signInitialTransaction(TransactionBuilder(notary = notary).apply { + addInputState(stateAndRef) + addOutputState((stateAndRef.state.data as RefState.State).update(), RefState.CONTRACT_ID) + addCommand(RefState.Update(), listOf(ourIdentity.owningKey)) + }) + return subFlow(FinalityFlow(stx)) } } // A set of flows to share a stateref with all other nodes in the mock network. internal object ShareRefState { @InitiatingFlow - class Initiator(val stateAndRef: StateAndRef) : FlowLogic() { + class Initiator(private val stateAndRef: StateAndRef) : FlowLogic() { @Suspendable override fun call() { val sessions = serviceHub.networkMapCache.allNodes.flatMap { it.legalIdentities }.map { initiateFlow(it) } @@ -85,7 +83,7 @@ internal object ShareRefState { } @InitiatedBy(ShareRefState.Initiator::class) - class Responder(val otherSession: FlowSession) : FlowLogic() { + class Responder(private val otherSession: FlowSession) : FlowLogic() { @Suspendable override fun call() { logger.info("Receiving dependencies.") @@ -99,7 +97,7 @@ internal object ShareRefState { } // A flow to use a reference state in another transaction. -internal class UseRefState(val linearId: UniqueIdentifier) : FlowLogic() { +internal class UseRefState(private val linearId: UniqueIdentifier) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { val notary = serviceHub.networkMapCache.notaryIdentities.first() @@ -108,14 +106,12 @@ internal class UseRefState(val linearId: UniqueIdentifier) : FlowLogic(query).states.single() - return subFlow(FinalityFlow( - transaction = serviceHub.signInitialTransaction(TransactionBuilder(notary = notary).apply { - @Suppress("DEPRECATION") // To be removed when feature is finalised. - addReferenceState(referenceState.referenced()) - addOutputState(DummyState(), DummyContract.PROGRAM_ID) - addCommand(DummyContract.Commands.Create(), listOf(ourIdentity.owningKey)) - }) - )) + val stx = serviceHub.signInitialTransaction(TransactionBuilder(notary = notary).apply { + addReferenceState(referenceState.referenced()) + addOutputState(DummyState(), DummyContract.PROGRAM_ID) + addCommand(DummyContract.Commands.Create(), listOf(ourIdentity.owningKey)) + }) + return subFlow(FinalityFlow(stx)) } } @@ -165,4 +161,4 @@ class WithReferencedStatesFlowTests { assertEquals(updatedRefState.ref, result.tx.references.single()) } -} \ No newline at end of file +} diff --git a/core/src/test/kotlin/net/corda/core/flows/mixins/WithFinality.kt b/core/src/test/kotlin/net/corda/core/flows/mixins/WithFinality.kt index 4e2ac3c5c5..038e360644 100644 --- a/core/src/test/kotlin/net/corda/core/flows/mixins/WithFinality.kt +++ b/core/src/test/kotlin/net/corda/core/flows/mixins/WithFinality.kt @@ -1,37 +1,42 @@ package net.corda.core.flows.mixins import co.paralleluniverse.fibers.Suspendable +import com.natpryce.hamkrest.MatchResult import com.natpryce.hamkrest.Matcher import com.natpryce.hamkrest.equalTo import net.corda.core.flows.FinalityFlow import net.corda.core.flows.FlowLogic import net.corda.core.flows.StartableByRPC import net.corda.core.identity.Party +import net.corda.core.internal.FlowStateMachine import net.corda.core.messaging.CordaRPCOps +import net.corda.core.messaging.FlowHandle import net.corda.core.messaging.startFlow import net.corda.core.transactions.SignedTransaction import net.corda.testing.core.singleIdentity import net.corda.testing.node.internal.TestStartedNode interface WithFinality : WithMockNet { - //region Operations - fun TestStartedNode.finalise(stx: SignedTransaction, vararg additionalParties: Party) = - startFlowAndRunNetwork(FinalityFlow(stx, additionalParties.toSet())) + fun TestStartedNode.finalise(stx: SignedTransaction, vararg additionalParties: Party): FlowStateMachine { + return startFlowAndRunNetwork(FinalityFlow(stx, additionalParties.toSet())) + } - fun TestStartedNode.getValidatedTransaction(stx: SignedTransaction) = - services.validatedTransactions.getTransaction(stx.id)!! + fun TestStartedNode.getValidatedTransaction(stx: SignedTransaction): SignedTransaction { + return services.validatedTransactions.getTransaction(stx.id)!! + } - fun CordaRPCOps.finalise(stx: SignedTransaction, vararg parties: Party) = - startFlow(::FinalityInvoker, stx, parties.toSet()) - .andRunNetwork() + fun CordaRPCOps.finalise(stx: SignedTransaction, vararg parties: Party): FlowHandle { + return startFlow(::FinalityInvoker, stx, parties.toSet()).andRunNetwork() + } //endregion //region Matchers fun visibleTo(other: TestStartedNode) = object : Matcher { override val description = "has a transaction visible to ${other.info.singleIdentity()}" - override fun invoke(actual: SignedTransaction) = - equalTo(actual)(other.getValidatedTransaction(actual)) + override fun invoke(actual: SignedTransaction): MatchResult { + return equalTo(actual)(other.getValidatedTransaction(actual)) + } } //endregion @@ -41,4 +46,4 @@ interface WithFinality : WithMockNet { @Suspendable override fun call(): SignedTransaction = subFlow(FinalityFlow(transaction, extraRecipients)) } -} \ No newline at end of file +} diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java index 5ad1a12ce2..a7dd8c6c22 100644 --- a/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java +++ b/docs/source/example-code/src/main/java/net/corda/docs/java/tutorial/twoparty/IOUFlow.java @@ -66,11 +66,11 @@ public class IOUFlow extends FlowLogic { final SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder); // Creating a session with the other party. - FlowSession otherpartySession = initiateFlow(otherParty); + FlowSession otherPartySession = initiateFlow(otherParty); // Obtaining the counterparty's signature. SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow( - signedTx, ImmutableList.of(otherpartySession), CollectSignaturesFlow.tracker())); + signedTx, ImmutableList.of(otherPartySession), CollectSignaturesFlow.tracker())); // Finalising the transaction. subFlow(new FinalityFlow(fullySignedTx)); @@ -78,4 +78,4 @@ public class IOUFlow extends FlowLogic { return null; // DOCEND 02 } -} \ No newline at end of file +} diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt index f79e3311cd..b66604a504 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/helloworld/IOUState.kt @@ -1,3 +1,5 @@ +@file:Suppress("MemberVisibilityCanBePrivate") + package net.corda.docs.kotlin.tutorial.helloworld import net.corda.core.contracts.ContractState @@ -12,4 +14,4 @@ class IOUState(val value: Int, val borrower: Party) : ContractState { override val participants get() = listOf(lender, borrower) } -// DOCEND 01 \ No newline at end of file +// DOCEND 01 diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt index 22714acd33..bffd19472d 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlow.kt @@ -1,3 +1,5 @@ +@file:Suppress("MemberVisibilityCanBePrivate") + package net.corda.docs.kotlin.tutorial.twoparty // DOCSTART 01 @@ -48,13 +50,13 @@ class IOUFlow(val iouValue: Int, val signedTx = serviceHub.signInitialTransaction(txBuilder) // Creating a session with the other party. - val otherpartySession = initiateFlow(otherParty) + val otherPartySession = initiateFlow(otherParty) // Obtaining the counterparty's signature. - val fullySignedTx = subFlow(CollectSignaturesFlow(signedTx, listOf(otherpartySession), CollectSignaturesFlow.tracker())) + val fullySignedTx = subFlow(CollectSignaturesFlow(signedTx, listOf(otherPartySession), CollectSignaturesFlow.tracker())) // Finalising the transaction. subFlow(FinalityFlow(fullySignedTx)) // DOCEND 02 } -} \ No newline at end of file +} diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt index 45e792abe0..c6ac0704b4 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/tutorial/twoparty/IOUFlowResponder.kt @@ -1,3 +1,5 @@ +@file:Suppress("unused") + package net.corda.docs.kotlin.tutorial.twoparty import co.paralleluniverse.fibers.Suspendable @@ -30,4 +32,4 @@ class IOUFlowResponder(val otherPartySession: FlowSession) : FlowLogic() { subFlow(signTransactionFlow) } } -// DOCEND 01 \ No newline at end of file +// DOCEND 01 diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/CustomVaultQueryTest.kt b/docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/CustomVaultQueryTest.kt similarity index 98% rename from docs/source/example-code/src/test/kotlin/net/corda/docs/CustomVaultQueryTest.kt rename to docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/CustomVaultQueryTest.kt index e5a5ec8786..3738e977a3 100644 --- a/docs/source/example-code/src/test/kotlin/net/corda/docs/CustomVaultQueryTest.kt +++ b/docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/CustomVaultQueryTest.kt @@ -1,4 +1,4 @@ -package net.corda.docs +package net.corda.docs.kotlin import net.corda.core.contracts.Amount import net.corda.core.contracts.ContractState @@ -8,7 +8,6 @@ import net.corda.core.node.services.vault.* import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow import net.corda.docs.java.tutorial.helloworld.IOUFlow -import net.corda.docs.kotlin.TopupIssuerFlow import net.corda.finance.* import net.corda.finance.contracts.getCashBalances import net.corda.finance.flows.CashIssueFlow diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt b/docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt similarity index 92% rename from docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt rename to docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt index 430fc025c8..1a0808fe91 100644 --- a/docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt +++ b/docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/FxTransactionBuildTutorialTest.kt @@ -1,18 +1,12 @@ -package net.corda.docs +package net.corda.docs.kotlin import net.corda.core.identity.Party import net.corda.core.toFuture import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow -import net.corda.docs.kotlin.ForeignExchangeFlow -import net.corda.docs.kotlin.ForeignExchangeRemoteFlow -import net.corda.finance.DOLLARS -import net.corda.finance.GBP -import net.corda.finance.POUNDS -import net.corda.finance.USD +import net.corda.finance.* import net.corda.finance.contracts.getCashBalances import net.corda.finance.flows.CashIssueFlow -import net.corda.finance.issuedBy import net.corda.testing.core.singleIdentity import net.corda.testing.node.MockNetwork import net.corda.testing.node.StartedMockNode diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/WorkflowTransactionBuildTutorialTest.kt b/docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/WorkflowTransactionBuildTutorialTest.kt similarity index 95% rename from docs/source/example-code/src/test/kotlin/net/corda/docs/WorkflowTransactionBuildTutorialTest.kt rename to docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/WorkflowTransactionBuildTutorialTest.kt index ccc0793663..d19fa0c33b 100644 --- a/docs/source/example-code/src/test/kotlin/net/corda/docs/WorkflowTransactionBuildTutorialTest.kt +++ b/docs/source/example-code/src/test/kotlin/net/corda/docs/kotlin/WorkflowTransactionBuildTutorialTest.kt @@ -1,4 +1,4 @@ -package net.corda.docs +package net.corda.docs.kotlin import net.corda.core.contracts.LinearState import net.corda.core.contracts.StateAndRef @@ -9,10 +9,6 @@ import net.corda.core.node.services.queryBy import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.toFuture import net.corda.core.utilities.getOrThrow -import net.corda.docs.kotlin.SubmitCompletionFlow -import net.corda.docs.kotlin.SubmitTradeApprovalFlow -import net.corda.docs.kotlin.TradeApprovalContract -import net.corda.docs.kotlin.WorkflowState import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.BOB_NAME import net.corda.testing.node.MockNetwork diff --git a/docs/source/hello-world-flow.rst b/docs/source/hello-world-flow.rst index b50ff584ec..1454b96498 100644 --- a/docs/source/hello-world-flow.rst +++ b/docs/source/hello-world-flow.rst @@ -73,7 +73,8 @@ annotation out will lead to some very weird error messages! There are also a few more annotations, on the ``FlowLogic`` subclass itself: - * ``@InitiatingFlow`` means that this flow can be started directly by the node + * ``@InitiatingFlow`` means that this flow is part of a flow pair and that it triggers the other side to run the + the counterpart flow. * ``@StartableByRPC`` allows the node owner to start this flow via an RPC call Let's walk through the steps of ``FlowLogic.call`` itself. This is where we actually describe the procedure for diff --git a/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/NotaryTest.kt b/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/NotaryTest.kt deleted file mode 100644 index a8cff6abb9..0000000000 --- a/tools/loadtest/src/main/kotlin/net/corda/loadtest/tests/NotaryTest.kt +++ /dev/null @@ -1,57 +0,0 @@ -package net.corda.loadtest.tests - -import net.corda.client.mock.Generator -import net.corda.core.flows.FinalityFlow -import net.corda.core.flows.FlowException -import net.corda.core.identity.CordaX500Name -import net.corda.core.internal.concurrent.thenMatch -import net.corda.core.messaging.startFlow -import net.corda.core.transactions.SignedTransaction -import net.corda.loadtest.LoadTest -import net.corda.loadtest.NodeConnection -import net.corda.testing.contracts.DummyContract -import net.corda.testing.core.DUMMY_NOTARY_NAME -import net.corda.testing.core.TestIdentity -import net.corda.testing.node.MockServices -import net.corda.testing.node.makeTestIdentityService -import org.slf4j.LoggerFactory - -private val log = LoggerFactory.getLogger("NotaryTest") -private val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10) -private val DUMMY_CASH_ISSUER = dummyCashIssuer.ref(1) -private val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20) -private val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")) -private val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")) - -data class NotariseCommand(val issueTx: SignedTransaction, val moveTx: SignedTransaction, val node: NodeConnection) - -val dummyNotarisationTest = LoadTest( - "Notarising dummy transactions", - generate = { _, _ -> - val issuerServices = MockServices(emptyList(), megaCorp.name, makeTestIdentityService(megaCorp.identity, miniCorp.identity, dummyCashIssuer.identity, dummyNotary.identity), dummyCashIssuer.keyPair) - val generateTx = Generator.pickOne(simpleNodes).flatMap { node -> - Generator.int().map { - val issueBuilder = DummyContract.generateInitial(it, notary.info.legalIdentities[0], DUMMY_CASH_ISSUER) // TODO notary choice - val issueTx = issuerServices.signInitialTransaction(issueBuilder) - val asset = issueTx.tx.outRef(0) - val moveBuilder = DummyContract.move(asset, dummyCashIssuer.party) - val moveTx = issuerServices.signInitialTransaction(moveBuilder) - NotariseCommand(issueTx, moveTx, node) - } - } - Generator.replicate(10, generateTx) - }, - interpret = { _, _ -> }, - execute = { (issueTx, moveTx, node) -> - try { - val proxy = node.proxy - val issueFlow = proxy.startFlow(::FinalityFlow, issueTx) - issueFlow.returnValue.thenMatch({ - proxy.startFlow(::FinalityFlow, moveTx) - }, {}) - } catch (e: FlowException) { - log.error("Failure", e) - } - }, - gatherRemoteState = {} -)