[CORDA-1445]: Raise proper error when starting node in devMode with compatibilityZoneURL. (#3109)

This commit is contained in:
Michele Sollecito 2018-05-10 22:00:47 +07:00 committed by GitHub
parent 15e87050c7
commit 5e0b27cfae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 33 deletions

View File

@ -6,6 +6,8 @@ release, see :doc:`upgrade-notes`.
Unreleased Unreleased
========== ==========
* Node will now gracefully fail to start if ``devMode`` is true and ``compatibilityZoneURL`` is specified.
* Fixed an error thrown by NodeVaultService upon recording a transaction with a number of inputs greater than the default page size. * Fixed an error thrown by NodeVaultService upon recording a transaction with a number of inputs greater than the default page size.
* Fixed incorrect computation of ``totalStates`` from ``otherResults`` in ``NodeVaultService``. * Fixed incorrect computation of ``totalStates`` from ``otherResults`` in ``NodeVaultService``.

View File

@ -1,23 +1,37 @@
package net.corda.node.services.network package net.corda.node.services.network
import net.corda.cordform.CordformNode import net.corda.cordform.CordformNode
import net.corda.core.concurrent.CordaFuture
import net.corda.core.crypto.random63BitValue import net.corda.core.crypto.random63BitValue
import net.corda.core.internal.* import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.bufferUntilSubscribed
import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.concurrent.transpose
import net.corda.core.internal.div
import net.corda.core.internal.exists
import net.corda.core.internal.list
import net.corda.core.internal.readObject
import net.corda.core.messaging.ParametersUpdateInfo import net.corda.core.messaging.ParametersUpdateInfo
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.node.services.config.configureDevKeyAndTrustStores
import net.corda.nodeapi.internal.config.NodeSSLConfiguration
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME import net.corda.nodeapi.internal.network.NETWORK_PARAMS_UPDATE_FILE_NAME
import net.corda.nodeapi.internal.network.SignedNetworkParameters import net.corda.nodeapi.internal.network.SignedNetworkParameters
import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.* import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.core.expect
import net.corda.testing.core.expectEvents
import net.corda.testing.core.sequence
import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.internal.NodeHandleInternal import net.corda.testing.driver.internal.NodeHandleInternal
import net.corda.testing.driver.internal.RandomFree import net.corda.testing.driver.internal.RandomFree
import net.corda.testing.node.internal.CompatibilityZoneParams import net.corda.testing.node.internal.CompatibilityZoneParams
import net.corda.testing.node.internal.DriverDSLImpl
import net.corda.testing.node.internal.internalDriver import net.corda.testing.node.internal.internalDriver
import net.corda.testing.node.internal.network.NetworkMapServer import net.corda.testing.node.internal.network.NetworkMapServer
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
@ -63,7 +77,7 @@ class NetworkMapTest {
initialiseSerialization = false, initialiseSerialization = false,
notarySpecs = emptyList() notarySpecs = emptyList()
) { ) {
val alice = startNode(providedName = ALICE_NAME).getOrThrow() as NodeHandleInternal val alice = startNode(providedName = ALICE_NAME, devMode = false).getOrThrow() as NodeHandleInternal
val nextParams = networkMapServer.networkParameters.copy(epoch = 3, modifiedTime = Instant.ofEpochMilli(random63BitValue())) val nextParams = networkMapServer.networkParameters.copy(epoch = 3, modifiedTime = Instant.ofEpochMilli(random63BitValue()))
val nextHash = nextParams.serialize().hash val nextHash = nextParams.serialize().hash
val snapshot = alice.rpc.networkParametersFeed().snapshot val snapshot = alice.rpc.networkParametersFeed().snapshot
@ -110,7 +124,7 @@ class NetworkMapTest {
initialiseSerialization = false, initialiseSerialization = false,
notarySpecs = emptyList() notarySpecs = emptyList()
) { ) {
val alice = startNode(providedName = ALICE_NAME).getOrThrow() val alice = startNode(providedName = ALICE_NAME, devMode = false).getOrThrow()
val networkParameters = (alice.baseDirectory / NETWORK_PARAMS_FILE_NAME) val networkParameters = (alice.baseDirectory / NETWORK_PARAMS_FILE_NAME)
.readObject<SignedNetworkParameters>() .readObject<SignedNetworkParameters>()
.verified() .verified()
@ -125,17 +139,16 @@ class NetworkMapTest {
internalDriver( internalDriver(
portAllocation = portAllocation, portAllocation = portAllocation,
compatibilityZone = compatibilityZone, compatibilityZone = compatibilityZone,
initialiseSerialization = false initialiseSerialization = false,
notarySpecs = emptyList()
) { ) {
val (aliceNode, bobNode, notaryNode) = listOf( val (aliceNode, bobNode) = listOf(
startNode(providedName = ALICE_NAME), startNode(providedName = ALICE_NAME, devMode = false),
startNode(providedName = BOB_NAME), startNode(providedName = BOB_NAME, devMode = false)
defaultNotaryNode
).transpose().getOrThrow() ).transpose().getOrThrow()
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo) aliceNode.onlySees(aliceNode.nodeInfo, bobNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo) bobNode.onlySees(aliceNode.nodeInfo, bobNode.nodeInfo)
bobNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
} }
} }
@ -144,24 +157,20 @@ class NetworkMapTest {
internalDriver( internalDriver(
portAllocation = portAllocation, portAllocation = portAllocation,
compatibilityZone = compatibilityZone, compatibilityZone = compatibilityZone,
initialiseSerialization = false initialiseSerialization = false,
notarySpecs = emptyList()
) { ) {
val (aliceNode, notaryNode) = listOf( val aliceNode = startNode(providedName = ALICE_NAME, devMode = false).getOrThrow()
startNode(providedName = ALICE_NAME),
defaultNotaryNode
).transpose().getOrThrow()
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo) aliceNode.onlySees(aliceNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo)
val bobNode = startNode(providedName = BOB_NAME).getOrThrow() val bobNode = startNode(providedName = BOB_NAME, devMode = false).getOrThrow()
// Wait for network map client to poll for the next update. // Wait for network map client to poll for the next update.
Thread.sleep(cacheTimeout.toMillis() * 2) Thread.sleep(cacheTimeout.toMillis() * 2)
bobNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo) bobNode.onlySees(aliceNode.nodeInfo, bobNode.nodeInfo)
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo) aliceNode.onlySees(aliceNode.nodeInfo, bobNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
} }
} }
@ -170,25 +179,23 @@ class NetworkMapTest {
internalDriver( internalDriver(
portAllocation = portAllocation, portAllocation = portAllocation,
compatibilityZone = compatibilityZone, compatibilityZone = compatibilityZone,
initialiseSerialization = false initialiseSerialization = false,
notarySpecs = emptyList()
) { ) {
val (aliceNode, bobNode, notaryNode) = listOf( val (aliceNode, bobNode) = listOf(
startNode(providedName = ALICE_NAME), startNode(providedName = ALICE_NAME, devMode = false),
startNode(providedName = BOB_NAME), startNode(providedName = BOB_NAME, devMode = false)
defaultNotaryNode
).transpose().getOrThrow() ).transpose().getOrThrow()
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo) aliceNode.onlySees(aliceNode.nodeInfo, bobNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo) bobNode.onlySees(aliceNode.nodeInfo, bobNode.nodeInfo)
bobNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
networkMapServer.removeNodeInfo(aliceNode.nodeInfo) networkMapServer.removeNodeInfo(aliceNode.nodeInfo)
// Wait for network map client to poll for the next update. // Wait for network map client to poll for the next update.
Thread.sleep(cacheTimeout.toMillis() * 2) Thread.sleep(cacheTimeout.toMillis() * 2)
notaryNode.onlySees(notaryNode.nodeInfo, bobNode.nodeInfo) bobNode.onlySees(bobNode.nodeInfo)
bobNode.onlySees(notaryNode.nodeInfo, bobNode.nodeInfo)
} }
} }
@ -201,3 +208,19 @@ class NetworkMapTest {
assertThat(rpc.networkMapSnapshot()).containsOnly(*nodes) assertThat(rpc.networkMapSnapshot()).containsOnly(*nodes)
} }
} }
private fun DriverDSLImpl.startNode(providedName: CordaX500Name, devMode: Boolean): CordaFuture<NodeHandle> {
var customOverrides = emptyMap<String, String>()
if (!devMode) {
val nodeDir = baseDirectory(providedName)
val nodeSslConfig = object : NodeSSLConfiguration {
override val baseDirectory = nodeDir
override val keyStorePassword = "cordacadevpass"
override val trustStorePassword = "trustpass"
override val crlCheckSoftFail = true
}
nodeSslConfig.configureDevKeyAndTrustStores(providedName)
customOverrides = mapOf("devMode" to "false")
}
return startNode(providedName = providedName, customOverrides = customOverrides)
}

View File

@ -180,6 +180,7 @@ data class NodeConfigurationImpl(
override fun validate(): List<String> { override fun validate(): List<String> {
val errors = mutableListOf<String>() val errors = mutableListOf<String>()
errors += validateDevModeOptions()
errors += validateRpcOptions(rpcOptions) errors += validateRpcOptions(rpcOptions)
return errors return errors
} }
@ -194,6 +195,16 @@ data class NodeConfigurationImpl(
return errors return errors
} }
private fun validateDevModeOptions(): List<String> {
val errors = mutableListOf<String>()
if (devMode) {
compatibilityZoneURL?.let {
errors += "'compatibilityZoneURL': present. Property cannot be set when 'devMode' is true."
}
}
return errors
}
override val transactionCacheSizeBytes: Long override val transactionCacheSizeBytes: Long
get() = transactionCacheSizeMegaBytes?.MB ?: super.transactionCacheSizeBytes get() = transactionCacheSizeMegaBytes?.MB ?: super.transactionCacheSizeBytes
override val attachmentContentCacheSizeBytes: Long override val attachmentContentCacheSizeBytes: Long

View File

@ -6,8 +6,10 @@ import net.corda.core.utilities.seconds
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.tools.shell.SSHDConfiguration import net.corda.tools.shell.SSHDConfiguration
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test import org.junit.Test
import java.net.URI
import java.nio.file.Paths import java.nio.file.Paths
import java.util.* import java.util.*
import kotlin.test.assertFalse import kotlin.test.assertFalse
@ -43,6 +45,15 @@ class NodeConfigurationImplTest {
assertFalse { testConfiguration.copy(noLocalShell = true, sshd = null).shouldInitCrashShell() } assertFalse { testConfiguration.copy(noLocalShell = true, sshd = null).shouldInitCrashShell() }
} }
@Test
fun `validation has error when compatibilityZoneURL is present and devMode is true`() {
val configuration = testConfiguration.copy(devMode = true, compatibilityZoneURL = URI.create("https://r3.com").toURL())
val errors = configuration.validate()
assertThat(errors).hasOnlyOneElementSatisfying { error -> error.contains("compatibilityZoneURL") && error.contains("devMode") }
}
private fun configDebugOptions(devMode: Boolean, devModeOptions: DevModeOptions?): NodeConfiguration { private fun configDebugOptions(devMode: Boolean, devModeOptions: DevModeOptions?): NodeConfiguration {
return testConfiguration.copy(devMode = devMode, devModeOptions = devModeOptions) return testConfiguration.copy(devMode = devMode, devModeOptions = devModeOptions)
} }