diff --git a/build.gradle b/build.gradle index c129f56dfc..d27318f913 100644 --- a/build.gradle +++ b/build.gradle @@ -71,7 +71,7 @@ buildscript { ext.h2_version = '1.4.197' // Update docs if renamed or removed. ext.postgresql_version = '42.1.4' ext.rxjava_version = '1.2.4' - ext.dokka_version = '0.9.16-eap-2' + ext.dokka_version = '0.9.17' ext.eddsa_version = '0.3.0' // Performance tuned version for enterprise. ext.dependency_checker_version = '3.1.0' ext.commons_collections_version = '4.1' @@ -101,8 +101,9 @@ buildscript { ext.deterministic_rt_version = '1.0-SNAPSHOT' - // Update 121 is required for ObjectInputFilter and at time of writing 131 was latest: - ext.java8_minUpdateVersion = '131' + // Update 121 is required for ObjectInputFilter. + // Updates [131, 161] also have zip compression bugs on MacOS (High Sierra). + ext.java8_minUpdateVersion = '171' repositories { mavenLocal() @@ -210,6 +211,8 @@ allprojects { } tasks.withType(Test) { + failFast = true + // Prevent the project from creating temporary files outside of the build directory. systemProperty 'java.io.tmpdir', buildDir.absolutePath @@ -491,6 +494,6 @@ if(file('corda-docs-only-build').exists() || (System.getenv('CORDA_DOCS_ONLY_BUI } wrapper { - gradleVersion = "4.4.1" + gradleVersion = "4.8" distributionType = Wrapper.DistributionType.ALL } diff --git a/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/DummyJar.kt b/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/DummyJar.kt index c332860669..7e768fc80b 100644 --- a/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/DummyJar.kt +++ b/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/DummyJar.kt @@ -88,8 +88,7 @@ class DummyJar( jar.write(arrayOfJunk(DATA_SIZE)) // One uncompressed text file - val text = """ -Jar: ${_path.toAbsolutePath()} + val text = """Jar: ${_path.toAbsolutePath()} Class: ${testClass.name} """.toByteArray() jar.putNextEntry(uncompressed("comment.txt", text)) diff --git a/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/JarFilterConfigurationTest.kt b/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/JarFilterConfigurationTest.kt index a124545ae4..1e52fd4198 100644 --- a/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/JarFilterConfigurationTest.kt +++ b/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/JarFilterConfigurationTest.kt @@ -262,7 +262,7 @@ task jarFilter(type: JarFilterTask) { testProjectDir.newFile("build.gradle").writeText(script) return GradleRunner.create() .withProjectDir(testProjectDir.root) - .withArguments(getBasicArgsForTasks("jarFilter", "--stacktrace")) + .withArguments(getBasicArgsForTasks("jarFilter")) .withPluginClasspath() } diff --git a/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/MetaFixConfigurationTests.kt b/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/MetaFixConfigurationTests.kt index bb67dba0c2..84944f6a3f 100644 --- a/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/MetaFixConfigurationTests.kt +++ b/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/MetaFixConfigurationTests.kt @@ -69,7 +69,7 @@ task metafix(type: MetaFixerTask) { testProjectDir.newFile("build.gradle").writeText(script) return GradleRunner.create() .withProjectDir(testProjectDir.root) - .withArguments(getBasicArgsForTasks("metafix", "--stacktrace")) + .withArguments(getBasicArgsForTasks("metafix")) .withPluginClasspath() } diff --git a/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/Utilities.kt b/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/Utilities.kt index 62a0a36cff..b0bc5a6bfb 100644 --- a/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/Utilities.kt +++ b/buildSrc/jarfilter/src/test/kotlin/net/corda/gradle/jarfilter/Utilities.kt @@ -29,7 +29,7 @@ private val testGradleUserHome: String get() = testGradleUserHomeValue ?: throw AssumptionViolatedException("System property 'test.gradle.user.home' not set.") fun getGradleArgsForTasks(vararg taskNames: String): MutableList = getBasicArgsForTasks(*taskNames).apply { add("--info") } -fun getBasicArgsForTasks(vararg taskNames: String): MutableList = mutableListOf(*taskNames, "-g", testGradleUserHome) +fun getBasicArgsForTasks(vararg taskNames: String): MutableList = mutableListOf(*taskNames, "--stacktrace", "-g", testGradleUserHome) @Throws(IOException::class) fun copyResourceTo(resourceName: String, target: Path) { diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt index 794c16c045..59ba95b284 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt @@ -18,16 +18,17 @@ import net.corda.core.context.Trace import net.corda.core.crypto.random63BitValue import net.corda.core.internal.logElapsedTime import net.corda.core.internal.uncheckedCast +import net.corda.core.messaging.ClientRpcSslOptions import net.corda.core.messaging.RPCOps import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.internal.nodeSerializationEnv -import net.corda.core.utilities.* +import net.corda.core.utilities.NetworkHostAndPort +import net.corda.core.utilities.contextLogger import net.corda.nodeapi.ArtemisTcpTransport.Companion.rpcConnectorTcpTransport import net.corda.nodeapi.ArtemisTcpTransport.Companion.rpcConnectorTcpTransportsFromList import net.corda.nodeapi.ArtemisTcpTransport.Companion.rpcInternalClientTcpTransport import net.corda.nodeapi.RPCApi -import net.corda.core.messaging.ClientRpcSslOptions import net.corda.nodeapi.internal.config.SSLConfiguration import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.TransportConfiguration @@ -84,6 +85,8 @@ class RPCClient( } else { ActiveMQClient.createServerLocatorWithoutHA(*haPoolTransportConfigurations.toTypedArray()) }).apply { + connectionTTL = 60000 + clientFailureCheckPeriod = 30000 retryInterval = rpcConfiguration.connectionRetryInterval.toMillis() retryIntervalMultiplier = rpcConfiguration.connectionRetryIntervalMultiplier maxRetryInterval = rpcConfiguration.connectionMaxRetryInterval.toMillis() diff --git a/constants.properties b/constants.properties index d8280be3be..caa3effd56 100644 --- a/constants.properties +++ b/constants.properties @@ -16,7 +16,7 @@ proguardVersion=6.0.3 bouncycastleVersion=1.57 typesafeConfigVersion=1.3.1 jsr305Version=3.0.2 -artifactoryPluginVersion=4.4.18 +artifactoryPluginVersion=4.7.3 snakeYamlVersion=1.19 caffeineVersion=2.6.2 metricsVersion=3.2.5 diff --git a/docs/source/building-against-master.rst b/docs/source/building-against-master.rst index 4c86894ade..fb73283025 100644 --- a/docs/source/building-against-master.rst +++ b/docs/source/building-against-master.rst @@ -1,21 +1,27 @@ -Building CorDapps against Master -================================ +Building CorDapps against a non-release branch +============================================== It is advisable to develop CorDapps against the most recent Corda stable release. However, you may need to build a CorDapp -against the unstable Master branch if your CorDapp uses a very recent feature, or you are using the CorDapp to test a PR +against an unstable non-release branch if your CorDapp uses a very recent feature, or you are using the CorDapp to test a PR on the main codebase. -To work against the Master branch, proceed as follows: +To work against a non-release branch, proceed as follows: 1. Clone the `Corda repository `_ -2. Open a terminal window in the folder where you cloned the Corda repository +2. Check out the branch or commit of the Corda repository you want to work against -3. Use the following command to check out the latest master branch: +3. Make a note of the ``gradlePluginsVersion`` in the root ``constants.properties`` file of the Corda repository + +4. Clone the `Corda Gradle Plugins repository `_ - ``git checkout master; git pull`` +5. Check out the tag of the Corda Gradle Plugins repository corresponding to the ``gradlePluginsVersion`` -4. Publish Corda to your local Maven repository using the following commands: +6. Follow the instructions in the readme of the Corda Gradle Plugins repository to install this version of the Corda Gradle plugins locally + +7. Open a terminal window in the folder where you cloned the Corda repository + +8. Publish Corda to your local Maven repository using the following commands: * Unix/Mac OSX: ``./gradlew install`` * Windows: ``gradlew.bat install`` @@ -23,9 +29,13 @@ To work against the Master branch, proceed as follows: .. warning:: If you do modify your local Corda repository after having published it to Maven local, then you must re-publish it to Maven local for the local installation to reflect the changes you have made. - .. warning:: As the Corda repository evolves on a daily basis, two clones of the Master branch at different points in - time may differ. If you are using a Master release and need help debugging an error, then please let us know the + .. warning:: As the Corda repository evolves on a daily basis, two clones of an unstable branch at different points in + time may differ. If you are using an unstable release and need help debugging an error, then please let us know the **commit** you are working from. This will help us ascertain the issue. + +9. Make a note of the ``corda_release_version`` in the root ``build.gradle`` file of the Corda repository -5. Update the ``ext.corda_release_version`` property in your CorDapp's root ``build.gradle`` file to match the version - here: https://github.com/corda/corda/blob/master/build.gradle#L7 +10. In your CorDapp's root ``build.gradle`` file: + + * Update ``ext.corda_release_version`` to the ``corda_release_version`` noted down earlier + * Update ``corda_gradle_plugins_version`` to the ``gradlePluginsVersion`` noted down earlier diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 99340b4ad1..1948b9074f 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4aea44f296..828ae7f5c8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -10,6 +10,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisMessagingClient.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisMessagingClient.kt index 17775d1669..8a3c98f334 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisMessagingClient.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ArtemisMessagingClient.kt @@ -51,7 +51,7 @@ class ArtemisMessagingClient( // Never time out on our loopback Artemis connections. If we switch back to using the InVM transport this // would be the default and the two lines below can be deleted. connectionTTL = 60000 - clientFailureCheckPeriod = -1 + clientFailureCheckPeriod = 30000 minLargeMessageSize = maxMessageSize isUseGlobalPools = nodeSerializationEnv != null confirmationWindowSize = this@ArtemisMessagingClient.confirmationWindowSize diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/WhitelisGenerator.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/WhitelistGenerator.kt similarity index 100% rename from node-api/src/main/kotlin/net/corda/nodeapi/internal/network/WhitelisGenerator.kt rename to node-api/src/main/kotlin/net/corda/nodeapi/internal/network/WhitelistGenerator.kt diff --git a/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt index c26cb269bb..bc7294b37f 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt @@ -19,13 +19,7 @@ import net.corda.node.internal.Node import net.corda.node.internal.StartedNode import net.corda.testing.internal.IntegrationTestSchemas import net.corda.testing.internal.toDatabaseSchemaName -import net.corda.testing.core.ALICE_NAME -import net.corda.testing.core.BOB_NAME -import net.corda.testing.core.CHARLIE_NAME -import net.corda.testing.core.DUMMY_NOTARY_NAME -import net.corda.testing.core.TestIdentity -import net.corda.testing.core.getTestPartyAndCertificate -import net.corda.testing.core.singleIdentity +import net.corda.testing.core.* import net.corda.testing.node.internal.NodeBasedTest import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatExceptionOfType diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 1e4aa0819a..ca05bce23c 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -212,7 +212,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration, /** Set to non-null once [start] has been successfully called. */ open val started get() = _started - @Volatile private var _started: StartedNode? = null + @Volatile + private var _started: StartedNode? = null /** The implementation of the [CordaRPCOps] interface used by this node. */ open fun makeRPCOps(flowStarter: FlowStarter, smm: StateMachineManager): CordaRPCOps { @@ -348,6 +349,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val smm = makeStateMachineManager(database) val flowLogicRefFactory = FlowLogicRefFactoryImpl(cordappLoader.appClassLoader) val flowStarter = FlowStarterImpl(smm, flowLogicRefFactory) + val cordaServices = installCordaServices(flowStarter) val schedulerService = NodeSchedulerService( platformClock, database, @@ -357,8 +359,20 @@ abstract class AbstractNode(val configuration: NodeConfiguration, flowLogicRefFactory = flowLogicRefFactory, drainingModePollPeriod = configuration.drainingModePollPeriod, nodeProperties = nodeProperties) - runOnStop += { schedulerService.join() } + + tokenizableServices = nodeServices + cordaServices + schedulerService + + try { + verifyCheckpointsCompatible(checkpointStorage, cordappProvider.cordapps, versionInfo.platformVersion, _services, tokenizableServices) + } catch (e: CheckpointIncompatibleException) { + if (configuration.devMode) { + Node.printWarning(e.message) + } else { + throw e + } + } + (serverThread as? ExecutorService)?.let { runOnStop += { // We wait here, even though any in-flight messages should have been drained away because the @@ -372,8 +386,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val rpcOps = makeRPCOps(flowStarter, smm) startMessagingService(rpcOps) installCoreFlows() - val cordaServices = installCordaServices(flowStarter) - tokenizableServices = nodeServices + cordaServices + schedulerService + registerCordappFlows(smm) _services.rpcFlows += cordappLoader.cordapps.flatMap { it.rpcFlows } startShell() @@ -441,7 +454,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration, serial = 0 ) - val nodeInfoFromDb = networkMapCache.getNodeByLegalName(identity.name) + val nodeInfoFromDb = getPreviousNodeInfoIfPresent(networkMapCache, identity) + val nodeInfo = if (potentialNodeInfo == nodeInfoFromDb?.copy(serial = 0)) { // The node info hasn't changed. We use the one from the database to preserve the serial. @@ -471,6 +485,19 @@ abstract class AbstractNode(val configuration: NodeConfiguration, return Pair(keyPairs, nodeInfo) } + private fun getPreviousNodeInfoIfPresent(networkMapCache: NetworkMapCacheBaseInternal, identity: PartyAndCertificate): NodeInfo? { + val nodeInfosFromDb = networkMapCache.getNodesByLegalName(identity.name) + + return when (nodeInfosFromDb.size) { + 0 -> null + 1 -> nodeInfosFromDb[0] + else -> { + log.warn("Found more than one node registration with our legal name, this is only expected if our keypair has been regenerated") + nodeInfosFromDb[0] + } + } + } + // Publish node info on startup and start task that sends every day a heartbeat - republishes node info. private fun tryPublishNodeInfoAsync(signedNodeInfo: SignedNodeInfo, networkMapClient: NetworkMapClient) { // By default heartbeat interval should be set to 1 day, but for testing we may change it. @@ -733,15 +760,6 @@ abstract class AbstractNode(val configuration: NodeConfiguration, networkParameters: NetworkParameters): MutableList { checkpointStorage = DBCheckpointStorage() - try { - verifyCheckpointsCompatible(checkpointStorage, cordappProvider.cordapps, versionInfo.platformVersion) - } catch (e: CheckpointIncompatibleException) { - if (configuration.devMode) { - Node.printWarning(e.message) - } else { - throw e - } - } val keyManagementService = makeKeyManagementService(identityService, keyPairs, database) _services = ServiceHubInternalImpl( @@ -757,7 +775,9 @@ abstract class AbstractNode(val configuration: NodeConfiguration, nodeProperties, networkParameters, servicesForResolution) + network = makeMessagingService(database, nodeInfo, nodeProperties, networkParameters) + return mutableListOf(attachments, network, services.vaultService, services.keyManagementService, services.identityService, platformClock, services.auditService, services.monitoringService, services.networkMapCache, services.schemaService, @@ -847,7 +867,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration, } private fun makeCoreNotaryService(notaryConfig: NotaryConfig, database: CordaPersistence): NotaryService { - val notaryKey = myNotaryIdentity?.owningKey ?: throw IllegalArgumentException("No notary identity initialized when creating a notary service") + val notaryKey = myNotaryIdentity?.owningKey + ?: throw IllegalArgumentException("No notary identity initialized when creating a notary service") return notaryConfig.run { when { raft != null -> { @@ -946,7 +967,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, throw ConfigurationException("The name '$singleName' for $id doesn't match what's in the key store: $subject") } else if (notaryConfig != null && notaryConfig.isClusterConfig && notaryConfig.serviceLegalName != null && subject != notaryConfig.serviceLegalName) { // Note that we're not checking if `notaryConfig.serviceLegalName` is not present for backwards compatibility. - throw ConfigurationException("The name of the notary service '${notaryConfig.serviceLegalName}' for $id doesn't match what's in the key store: $subject. "+ + throw ConfigurationException("The name of the notary service '${notaryConfig.serviceLegalName}' for $id doesn't match what's in the key store: $subject. " + "You might need to adjust the configuration of `notary.serviceLegalName`.") } @@ -968,8 +989,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration, log.info("Starting Jolokia agent on HTTP port: $port") val libDir = Paths.get(configuration.baseDirectory.toString(), "drivers") val jarFilePath = JVMAgentRegistry.resolveAgentJar( - "jolokia-jvm-${NodeBuildProperties.JOLOKIA_AGENT_VERSION}-agent.jar", libDir) ?: - throw Error("Unable to locate agent jar file") + "jolokia-jvm-${NodeBuildProperties.JOLOKIA_AGENT_VERSION}-agent.jar", libDir) + ?: throw Error("Unable to locate agent jar file") log.info("Agent jar file: $jarFilePath") JVMAgentRegistry.attach("jolokia", "port=$port", jarFilePath) } @@ -1005,7 +1026,8 @@ abstract class AbstractNode(val configuration: NodeConfiguration, override val networkMapUpdater: NetworkMapUpdater get() = this@AbstractNode.networkMapUpdater override fun cordaService(type: Class): T { require(type.isAnnotationPresent(CordaService::class.java)) { "${type.name} is not a Corda service" } - return cordappServices.getInstance(type) ?: throw IllegalArgumentException("Corda service ${type.name} does not exist") + return cordappServices.getInstance(type) + ?: throw IllegalArgumentException("Corda service ${type.name} does not exist") } override fun getFlowFactory(initiatingFlowClass: Class>): InitiatedFlowFactory<*>? { diff --git a/node/src/main/kotlin/net/corda/node/internal/CheckpointVerifier.kt b/node/src/main/kotlin/net/corda/node/internal/CheckpointVerifier.kt index 96b7704df3..ad2a7c903d 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CheckpointVerifier.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CheckpointVerifier.kt @@ -3,11 +3,14 @@ package net.corda.node.internal import net.corda.core.cordapp.Cordapp import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic +import net.corda.core.node.ServiceHub import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.deserialize import net.corda.node.services.api.CheckpointStorage import net.corda.node.services.statemachine.SubFlow import net.corda.node.services.statemachine.SubFlowVersion +import net.corda.serialization.internal.SerializeAsTokenContextImpl +import net.corda.serialization.internal.withTokenContext object CheckpointVerifier { @@ -15,10 +18,14 @@ object CheckpointVerifier { * Verifies that all Checkpoints stored in the db can be safely loaded with the currently installed version. * @throws CheckpointIncompatibleException if any offending checkpoint is found. */ - fun verifyCheckpointsCompatible(checkpointStorage: CheckpointStorage, currentCordapps: List, platformVersion: Int) { + fun verifyCheckpointsCompatible(checkpointStorage: CheckpointStorage, currentCordapps: List, platformVersion: Int, serviceHub: ServiceHub, tokenizableServices: List) { + val checkpointSerializationContext = SerializationDefaults.CHECKPOINT_CONTEXT.withTokenContext( + SerializeAsTokenContextImpl(tokenizableServices, SerializationDefaults.SERIALIZATION_FACTORY, SerializationDefaults.CHECKPOINT_CONTEXT, serviceHub) + ) checkpointStorage.getAllCheckpoints().forEach { (_, serializedCheckpoint) -> + val checkpoint = try { - serializedCheckpoint.deserialize(context = SerializationDefaults.CHECKPOINT_CONTEXT) + serializedCheckpoint.deserialize(context = checkpointSerializationContext) } catch (e: Exception) { throw CheckpointIncompatibleException.CannotBeDeserialisedException(e) } diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/InternalRPCMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/InternalRPCMessagingClient.kt index b8d4001a5d..9b5191b312 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/InternalRPCMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/InternalRPCMessagingClient.kt @@ -27,7 +27,7 @@ class InternalRPCMessagingClient(val sslConfig: SSLConfiguration, val serverAddr // Never time out on our loopback Artemis connections. If we switch back to using the InVM transport this // would be the default and the two lines below can be deleted. connectionTTL = 60000 - clientFailureCheckPeriod = -1 + clientFailureCheckPeriod = 30000 minLargeMessageSize = maxMessageSize isUseGlobalPools = nodeSerializationEnv != null } diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt index 75ad11dc1e..187bb2235f 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessagingClient.kt @@ -156,7 +156,7 @@ class P2PMessagingClient(val config: NodeConfiguration, // Never time out on our loopback Artemis connections. If we switch back to using the InVM transport this // would be the default and the two lines below can be deleted. connectionTTL = 60000 - clientFailureCheckPeriod = -1 + clientFailureCheckPeriod = 30000 minLargeMessageSize = maxMessageSize + JOURNAL_HEADER_SIZE isUseGlobalPools = nodeSerializationEnv != null confirmationWindowSize = config.enterpriseConfiguration.tuning.p2pConfirmationWindowSize diff --git a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt index b609904bd8..e13c05f0d0 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt @@ -177,7 +177,7 @@ open class PersistentNetworkMapCache( } } - override fun getNodesByLegalName(name: CordaX500Name): List = database.transaction { queryByLegalName(session, name) } + override fun getNodesByLegalName(name: CordaX500Name): List = database.transaction { queryByLegalName(session, name) }.sortedByDescending { it.serial } override fun getNodesByLegalIdentityKey(identityKey: PublicKey): List = nodesByKeyCache[identityKey]!! diff --git a/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt b/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt index 96f3d76ad7..56e9cedeea 100644 --- a/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/NodeTest.kt @@ -68,7 +68,7 @@ class NodeTest { @Test fun `generateAndSaveNodeInfo works`() { - val configuration = createConfig() + val configuration = createConfig(ALICE_NAME) val info = VersionInfo(789, "3.0", "SNAPSHOT", "R3") configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use { database -> val node = Node(configuration, info, initialiseSerialization = false) @@ -78,7 +78,7 @@ class NodeTest { @Test fun `clear network map cache works`() { - val configuration = createConfig() + val configuration = createConfig(ALICE_NAME) val (nodeInfo, _) = createNodeInfoAndSigned(ALICE_NAME) configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use { it.transaction { @@ -103,6 +103,52 @@ class NodeTest { } } + @Test + fun `Node can start with multiple keypairs for it's identity`() { + val configuration = createConfig(ALICE_NAME) + val (nodeInfo1, _) = createNodeInfoAndSigned(ALICE_NAME) + val (nodeInfo2, _) = createNodeInfoAndSigned(ALICE_NAME) + + + val persistentNodeInfo2 = NodeInfoSchemaV1.PersistentNodeInfo( + id = 0, + hash = nodeInfo2.serialize().hash.toString(), + addresses = nodeInfo2.addresses.map { NodeInfoSchemaV1.DBHostAndPort.fromHostAndPort(it) }, + legalIdentitiesAndCerts = nodeInfo2.legalIdentitiesAndCerts.mapIndexed { idx, elem -> + NodeInfoSchemaV1.DBPartyAndCertificate(elem, isMain = idx == 0) + }, + platformVersion = nodeInfo2.platformVersion, + serial = nodeInfo2.serial + ) + + val persistentNodeInfo1 = NodeInfoSchemaV1.PersistentNodeInfo( + id = 0, + hash = nodeInfo1.serialize().hash.toString(), + addresses = nodeInfo1.addresses.map { NodeInfoSchemaV1.DBHostAndPort.fromHostAndPort(it) }, + legalIdentitiesAndCerts = nodeInfo1.legalIdentitiesAndCerts.mapIndexed { idx, elem -> + NodeInfoSchemaV1.DBPartyAndCertificate(elem, isMain = idx == 0) + }, + platformVersion = nodeInfo1.platformVersion, + serial = nodeInfo1.serial + ) + + configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use { + it.transaction { + session.save(persistentNodeInfo1) + } + it.transaction { + session.save(persistentNodeInfo2) + } + + val node = Node(configuration, rigorousMock().also { + doReturn(10).whenever(it).platformVersion + }, initialiseSerialization = false) + + //this throws an exception with old behaviour + node.generateNodeInfo() + } + } + private fun getAllInfos(database: CordaPersistence): List { return database.transaction { val criteria = session.criteriaBuilder.createQuery(NodeInfoSchemaV1.PersistentNodeInfo::class.java) @@ -111,11 +157,10 @@ class NodeTest { } } - private fun createConfig(): NodeConfiguration { + private fun createConfig(nodeName: CordaX500Name): NodeConfiguration { val dataSourceProperties = makeTestDataSourceProperties() val databaseConfig = DatabaseConfig() val nodeAddress = NetworkHostAndPort("0.1.2.3", 456) - val nodeName = CordaX500Name("Manx Blockchain Corp", "Douglas", "IM") return rigorousMock().also { doReturn(null).whenever(it).relay doReturn(nodeAddress).whenever(it).p2pAddress diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt index f9bc6b6f5e..bd8ffd3a85 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt @@ -30,6 +30,7 @@ import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.TestIdentity import net.corda.testing.internal.LogHelper +import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions.assertThat @@ -165,13 +166,14 @@ class DBCheckpointStorageTests { @Test fun `verify checkpoints compatible`() { + val mockServices = MockServices(emptyList(), ALICE.name) database.transaction { val (id, checkpoint) = newCheckpoint(1) checkpointStorage.addCheckpoint(id, checkpoint) } database.transaction { - CheckpointVerifier.verifyCheckpointsCompatible(checkpointStorage, emptyList(), 1) + CheckpointVerifier.verifyCheckpointsCompatible(checkpointStorage, emptyList(), 1, mockServices, emptyList()) } database.transaction { @@ -181,7 +183,7 @@ class DBCheckpointStorageTests { Assertions.assertThatThrownBy { database.transaction { - CheckpointVerifier.verifyCheckpointsCompatible(checkpointStorage, emptyList(), 1) + CheckpointVerifier.verifyCheckpointsCompatible(checkpointStorage, emptyList(), 1, mockServices, emptyList()) } }.isInstanceOf(CheckpointIncompatibleException::class.java) } diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/RetryFlowMockTest.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/RetryFlowMockTest.kt index 42d79ce2a8..0bf110ba43 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/RetryFlowMockTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/RetryFlowMockTest.kt @@ -30,6 +30,7 @@ import org.junit.Test import java.sql.SQLException import java.time.Duration import java.util.* +import java.util.concurrent.atomic.AtomicInteger import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNull @@ -48,7 +49,7 @@ class RetryFlowMockTest { RetryFlow.count = 0 SendAndRetryFlow.count = 0 RetryInsertFlow.count = 0 - KeepSendingFlow.count = 0 + KeepSendingFlow.count.set(0) } private fun StartedNode.startFlow(logic: FlowLogic): CordaFuture { @@ -115,7 +116,7 @@ class RetryFlowMockTest { } }) // Now short circuit the iterations so the flow finishes soon. - KeepSendingFlow.count = count - 2 + KeepSendingFlow.count.set(count - 2) while (nodeA.smm.allStateMachines.size > 0) { Thread.sleep(10) } @@ -240,8 +241,7 @@ class ReceiveFlow2(private val other: FlowSession) : FlowLogic() { @InitiatingFlow class KeepSendingFlow(private val i: Int, private val other: Party) : FlowLogic() { companion object { - @Volatile - var count = 0 + val count = AtomicInteger(0) } @Suspendable @@ -251,7 +251,7 @@ class KeepSendingFlow(private val i: Int, private val other: Party) : FlowLogic< do { logger.info("Sending... $count") session.send("Boo") - } while (count++ < i) + } while (count.getAndIncrement() < i) } } diff --git a/samples/network-visualiser/README.md b/samples/network-visualiser/README.md deleted file mode 100644 index 4e9f9f8350..0000000000 --- a/samples/network-visualiser/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Network Visualiser - -This package contains a network visualiser that uses a simulation to visualise the interaction and messages between nodes on the Corda network. - -Please see the either the [online documentation](https://docs.corda.net/network-simulator.html) for more info on the network visualiser, or the [included offline version](../../docs/build/html/network-simulator.html). - -From the root directory of the repository, run it like this (Windows): - - gradle samples:network-visualiser:run - -or (Mac / Unix) - - ./gradlew samples:network-visualiser:run \ No newline at end of file diff --git a/samples/network-visualiser/build.gradle b/samples/network-visualiser/build.gradle deleted file mode 100644 index 262e0bd7db..0000000000 --- a/samples/network-visualiser/build.gradle +++ /dev/null @@ -1,90 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -buildscript { - ext { - springBootVersion = '1.5.7.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion" - classpath "io.spring.gradle:dependency-management-plugin:1.0.4.RELEASE" - } -} - -// Spring Boot plugin adds a numerous hardcoded dependencies in the version much lower then Corda expects -// causing the problems in runtime. Those can be changed by manipulating above properties -// See https://github.com/spring-gradle-plugins/dependency-management-plugin/blob/master/README.md#changing-the-value-of-a-version-property -// This has to be repeated here as otherwise the order of files does matter -// See a list here: https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml -ext['artemis.version'] = "$artemis_version" -ext['hibernate.version'] = "$hibernate_version" -ext['jackson.version'] = "$jackson_version" -ext['dropwizard-metrics.version'] = "$metrics_version" -ext['mockito.version'] = "$mockito_version" - -apply plugin: 'java' -apply plugin: 'kotlin' -apply plugin: 'idea' -apply plugin: 'application' -apply plugin: 'org.springframework.boot' -apply plugin: 'net.corda.plugins.quasar-utils' -apply plugin: 'us.kirchmeier.capsule' - -// Spring Boot plugin have to be reimported, however it picks up the settings from irs-demo, so there is no need to -// reconfigure - - -// Warning: The network visualiser is not a Cordapp so please do not use it as an example of how -// to build a cordapp - -dependencies { - testCompile "junit:junit:$junit_version" - - // Corda integration dependencies - compile project(path: ":node:capsule", configuration: 'runtimeArtifacts') - compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') - compile project(':core') - compile project(':finance') - compile project(':node-driver') - compile project(':finance') - compile project(':samples:irs-demo') - - // GraphStream: For visualisation - compileOnly "co.paralleluniverse:capsule:$capsule_version" -} - -idea { - module { - downloadJavadoc = true // defaults to false - downloadSources = true - } -} - -mainClassName = 'net.corda.netmap.NetworkMapVisualiser' - -task deployVisualiser(type: FatCapsule) { - applicationClass 'net.corda.netmap.NetworkMapVisualiser' - reallyExecutable - capsuleManifest { - minJavaVersion = '1.8.0' - javaAgents = [configurations.quasar.singleFile.name] - } -} - -jar { - manifest { - attributes( - 'Automatic-Module-Name': 'net.corda.samples.network.visualiser' - ) - } -} diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/NetworkMapVisualiser.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/NetworkMapVisualiser.kt deleted file mode 100644 index 9110745bfd..0000000000 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/NetworkMapVisualiser.kt +++ /dev/null @@ -1,369 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -package net.corda.netmap - -import javafx.animation.* -import javafx.application.Application -import javafx.application.Platform -import javafx.beans.property.SimpleDoubleProperty -import javafx.beans.value.WritableValue -import javafx.geometry.Insets -import javafx.scene.input.KeyCode -import javafx.scene.input.KeyCodeCombination -import javafx.scene.layout.VBox -import javafx.stage.Stage -import javafx.util.Duration -import net.corda.core.serialization.deserialize -import net.corda.core.utilities.ProgressTracker -import net.corda.netmap.VisualiserViewModel.Style -import net.corda.netmap.simulation.IRSSimulation -import net.corda.node.services.statemachine.* -import net.corda.testing.core.singleIdentity -import net.corda.testing.node.InMemoryMessagingNetwork -import net.corda.testing.node.internal.InternalMockNetwork -import rx.Scheduler -import rx.schedulers.Schedulers -import java.time.format.DateTimeFormatter -import java.time.format.FormatStyle -import java.util.* -import kotlin.concurrent.schedule -import kotlin.concurrent.scheduleAtFixedRate -import kotlin.system.exitProcess - -fun WritableValue.keyValue(endValue: T, interpolator: Interpolator = Interpolator.EASE_OUT) = KeyValue(this, endValue, interpolator) - -// TODO: This code is all horribly ugly. Refactor to use TornadoFX to clean it up. - -class NetworkMapVisualiser : Application() { - enum class NodeType { - BANK, SERVICE - } - - enum class RunPauseButtonLabel { - RUN, PAUSE; - - override fun toString(): String { - return name.toLowerCase().capitalize() - } - } - - sealed class RunningPausedState { - class Running(val tickTimer: TimerTask) : RunningPausedState() - class Paused : RunningPausedState() - - val buttonLabel: RunPauseButtonLabel - get() { - return when (this) { - is RunningPausedState.Running -> RunPauseButtonLabel.PAUSE - is RunningPausedState.Paused -> RunPauseButtonLabel.RUN - } - } - } - - private val view = VisualiserView() - private val viewModel = VisualiserViewModel() - - val timer = Timer() - val uiThread: Scheduler = Schedulers.from { Platform.runLater(it) } - - override fun start(stage: Stage) { - viewModel.view = view - viewModel.presentationMode = "--presentation-mode" in parameters.raw - buildScene(stage) - viewModel.displayStyle = if ("--circle" in parameters.raw) { - Style.CIRCLE - } else { - viewModel.displayStyle - } - - val simulation = viewModel.simulation - // Update the white-backgrounded label indicating what flow step it's up to. - simulation.allFlowSteps.observeOn(uiThread).subscribe { (node, change) -> - val label = viewModel.nodesToWidgets[node]!!.statusLabel - if (change is ProgressTracker.Change.Position) { - // Fade in the status label if it's our first step. - if (label.text == "") { - with(FadeTransition(Duration(150.0), label)) { - fromValue = 0.0 - toValue = 1.0 - play() - } - } - label.text = change.newStep.label - if (change.newStep == ProgressTracker.DONE && change.tracker == change.tracker.topLevelTracker) { - runLater(500, -1) { - // Fade out the status label. - with(FadeTransition(Duration(750.0), label)) { - fromValue = 1.0 - toValue = 0.0 - setOnFinished { label.text = "" } - play() - } - } - } - } else if (change is ProgressTracker.Change.Rendering) { - label.text = change.ofStep.label - } - } - // Fire the message bullets between nodes. - simulation.mockNet.messagingNetwork.sentMessages.observeOn(uiThread).subscribe { msg: InMemoryMessagingNetwork.MessageTransfer -> - val senderNode: InternalMockNetwork.MockNode = simulation.mockNet.addressToNode(msg.sender) - val destNode: InternalMockNetwork.MockNode = simulation.mockNet.addressToNode(msg.recipients) - - if (transferIsInteresting(msg)) { - viewModel.nodesToWidgets[senderNode]!!.pulseAnim.play() - viewModel.fireBulletBetweenNodes(senderNode, destNode, "bank", "bank") - } - } - // Pulse all parties in a trade when the trade completes - simulation.doneSteps.observeOn(uiThread).subscribe { nodes: Collection -> - nodes.forEach { viewModel.nodesToWidgets[it]!!.longPulseAnim.play() } - } - - stage.setOnCloseRequest { exitProcess(0) } - //stage.isMaximized = true - stage.show() - } - - fun runLater(startAfter: Int, delayBetween: Int, body: () -> Unit) { - if (delayBetween != -1) { - timer.scheduleAtFixedRate(startAfter.toLong(), delayBetween.toLong()) { - Platform.runLater { - body() - } - } - } else { - timer.schedule(startAfter.toLong()) { - Platform.runLater { - body() - } - } - } - } - - private fun buildScene(stage: Stage) { - view.stage = stage - view.setup(viewModel.runningPausedState, viewModel.displayStyle, viewModel.presentationMode) - bindSidebar() - bindTopbar() - viewModel.createNodes() - - // Spacebar advances simulation by one step. - stage.scene.accelerators[KeyCodeCombination(KeyCode.SPACE)] = Runnable { onNextInvoked() } - - reloadStylesheet(stage) - - stage.focusedProperty().addListener { _, _, new -> - if (new) { - reloadStylesheet(stage) - } - } - } - - private fun bindTopbar() { - view.resetButton.setOnAction({ reset() }) - view.nextButton.setOnAction { - if (!view.simulateInitialisationCheckbox.isSelected && !viewModel.simulation.networkInitialisationFinished.isDone) { - skipNetworkInitialisation() - } else { - onNextInvoked() - } - } - viewModel.simulation.networkInitialisationFinished.thenAccept { - view.simulateInitialisationCheckbox.isVisible = false - } - view.runPauseButton.setOnAction { - val oldRunningPausedState = viewModel.runningPausedState - val newRunningPausedState = when (oldRunningPausedState) { - is NetworkMapVisualiser.RunningPausedState.Running -> { - oldRunningPausedState.tickTimer.cancel() - - view.nextButton.isDisable = false - view.resetButton.isDisable = false - - NetworkMapVisualiser.RunningPausedState.Paused() - } - is NetworkMapVisualiser.RunningPausedState.Paused -> { - val tickTimer = timer.scheduleAtFixedRate(viewModel.stepDuration.toMillis().toLong(), viewModel.stepDuration.toMillis().toLong()) { - Platform.runLater { - onNextInvoked() - } - } - - view.nextButton.isDisable = true - view.resetButton.isDisable = true - - if (!view.simulateInitialisationCheckbox.isSelected && !viewModel.simulation.networkInitialisationFinished.isDone) { - skipNetworkInitialisation() - } - - NetworkMapVisualiser.RunningPausedState.Running(tickTimer) - } - } - - view.runPauseButton.text = newRunningPausedState.buttonLabel.toString() - viewModel.runningPausedState = newRunningPausedState - } - view.styleChoice.selectionModel.selectedItemProperty() - .addListener { _, _, newValue -> viewModel.displayStyle = newValue } - viewModel.simulation.dateChanges.observeOn(uiThread).subscribe { view.dateLabel.text = it.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)) } - } - - private fun reloadStylesheet(stage: Stage) { - stage.scene.stylesheets.clear() - stage.scene.stylesheets.add(NetworkMapVisualiser::class.java.getResource("styles.css").toString()) - } - - private fun bindSidebar() { - viewModel.simulation.allFlowSteps.observeOn(uiThread).subscribe { (node, change) -> - if (change is ProgressTracker.Change.Position) { - val tracker = change.tracker.topLevelTracker - if (change.newStep == ProgressTracker.DONE) { - if (change.tracker == tracker) { - // Flow done; schedule it for removal in a few seconds. We batch them up to make nicer - // animations. - updateProgressTrackerWidget(change) - println("Flow done for ${node.started!!.info.singleIdentity().name}") - viewModel.doneTrackers += tracker - } else { - // Subflow is done; ignore it. - } - } else if (!viewModel.trackerBoxes.containsKey(tracker)) { - // New flow started up; add. - val extraLabel = viewModel.simulation.extraNodeLabels[node] - val label = node.started!!.info.singleIdentity().name.organisation.let { if (extraLabel != null) "$it: $extraLabel" else it } - val widget = view.buildProgressTrackerWidget(label, tracker.topLevelTracker) - println("Added: $tracker, $widget") - viewModel.trackerBoxes[tracker] = widget - view.sidebar.children += widget.vbox - } else { - updateProgressTrackerWidget(change) - } - } else if (change is ProgressTracker.Change.Structural) { - updateProgressTrackerWidget(change) - } - } - - Timer().scheduleAtFixedRate(0, 500) { - Platform.runLater { - for (tracker in viewModel.doneTrackers) { - val pane = viewModel.trackerBoxes[tracker]!!.vbox - // Slide the other tracker widgets up and over this one. - val slideProp = SimpleDoubleProperty(0.0) - slideProp.addListener { _ -> pane.padding = Insets(0.0, 0.0, slideProp.value, 0.0) } - val timeline = Timeline( - KeyFrame(Duration(250.0), - KeyValue(pane.opacityProperty(), 0.0), - KeyValue(slideProp, -pane.height - 50.0) // Subtract the bottom padding gap. - ) - ) - timeline.setOnFinished { - println("Removed: $tracker") - val vbox = viewModel.trackerBoxes.remove(tracker)?.vbox - view.sidebar.children.remove(vbox) - } - timeline.play() - } - viewModel.doneTrackers.clear() - } - } - } - - private fun updateProgressTrackerWidget(step: ProgressTracker.Change) { - if (step is ProgressTracker.Change.Position) { - // Animate the cursor to the right place. - Platform.runLater { - val tracker: ProgressTracker = step.tracker.topLevelTracker - val widget = viewModel.trackerBoxes[tracker] ?: return@runLater - val allSteps: List> = tracker.allSteps - - // Figure out the index of the new step. - val curStep = allSteps.indexOfFirst { it.second == step.newStep } - with(TranslateTransition(Duration(350.0), widget.cursor)) { - fromY = widget.cursor.translateY - toY = (curStep * view.sideBarStepHeight) + (view.sideBarStepHeight / 2.0) - play() - } - } - } else if (step is ProgressTracker.Change.Structural) { - Platform.runLater { - val tracker: ProgressTracker = step.tracker.topLevelTracker - val widget = viewModel.trackerBoxes[tracker] ?: return@runLater - val new = view.buildProgressTrackerWidget(widget.label.text, tracker) - val prevWidget = viewModel.trackerBoxes[tracker]?.vbox ?: throw AssertionError("No previous widget for tracker: $tracker") - val i = (prevWidget.parent as VBox).children.indexOf(viewModel.trackerBoxes[tracker]?.vbox) - (prevWidget.parent as VBox).children[i] = new.vbox - viewModel.trackerBoxes[tracker] = new - } - } - } - - var started = false - private fun startSimulation() { - if (!started) { - viewModel.simulation.start() - started = true - } - } - - private fun reset() { - viewModel.simulation.stop() - viewModel.simulation = IRSSimulation(true, false, null) - started = false - start(view.stage) - } - - private fun skipNetworkInitialisation() { - startSimulation() - while (!viewModel.simulation.networkInitialisationFinished.isDone) { - iterateSimulation() - } - } - - private fun onNextInvoked() { - if (started) { - iterateSimulation() - } else { - startSimulation() - } - } - - private fun iterateSimulation() { - // Loop until either we ran out of things to do, or we sent an interesting message. - while (true) { - val transfer: InMemoryMessagingNetwork.MessageTransfer = viewModel.simulation.iterate() ?: break - if (transferIsInteresting(transfer)) - break - else - System.err.println("skipping boring $transfer") - } - } - - private fun transferIsInteresting(transfer: InMemoryMessagingNetwork.MessageTransfer): Boolean { - // Loopback messages are boring. - if (transfer.sender == transfer.recipients) return false - val message = transfer.messageData.deserialize() - return when (message) { - is InitialSessionMessage -> message.firstPayload != null - is ExistingSessionMessage -> when (message.payload) { - is ConfirmSessionMessage -> false - is DataSessionMessage -> true - is ErrorSessionMessage -> true - is RejectSessionMessage -> true - is EndSessionMessage -> false - } - } - } -} - -fun main(args: Array) { - Application.launch(NetworkMapVisualiser::class.java, *args) -} diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserUtils.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserUtils.kt deleted file mode 100644 index 2c0d85d824..0000000000 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserUtils.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -package net.corda.netmap - -import javafx.scene.paint.Color - -internal -fun colorToRgb(color: Color): String { - val builder = StringBuilder() - - builder.append("rgb(") - builder.append(Math.round(color.red * 256)) - builder.append(",") - builder.append(Math.round(color.green * 256)) - builder.append(",") - builder.append(Math.round(color.blue * 256)) - builder.append(")") - - return builder.toString() -} \ No newline at end of file diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserView.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserView.kt deleted file mode 100644 index b7fd031158..0000000000 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserView.kt +++ /dev/null @@ -1,315 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -package net.corda.netmap - -import javafx.animation.KeyFrame -import javafx.animation.Timeline -import javafx.application.Platform -import javafx.collections.FXCollections -import javafx.event.EventHandler -import javafx.geometry.Insets -import javafx.geometry.Pos -import javafx.scene.Group -import javafx.scene.Node -import javafx.scene.Scene -import javafx.scene.control.* -import javafx.scene.image.Image -import javafx.scene.image.ImageView -import javafx.scene.input.ZoomEvent -import javafx.scene.layout.* -import javafx.scene.paint.Color -import javafx.scene.shape.Polygon -import javafx.scene.text.Font -import javafx.stage.Stage -import javafx.util.Duration -import net.corda.core.utilities.ProgressTracker -import net.corda.netmap.VisualiserViewModel.Style - -data class TrackerWidget(val vbox: VBox, val cursorBox: Pane, val label: Label, val cursor: Polygon) - -internal class VisualiserView { - lateinit var root: Pane - lateinit var stage: Stage - lateinit var splitter: SplitPane - lateinit var sidebar: VBox - lateinit var resetButton: Button - lateinit var nextButton: Button - lateinit var runPauseButton: Button - lateinit var simulateInitialisationCheckbox: CheckBox - lateinit var styleChoice: ChoiceBox