Merge pull request #1149 from corda/merges/june-29-10-20

Merges: June 29 at 10:20
This commit is contained in:
Michele Sollecito 2018-06-29 10:31:34 +01:00 committed by GitHub
commit 9d6a364692
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 79 additions and 41 deletions

View File

@ -157,6 +157,10 @@ allprojects {
apply plugin: 'org.owasp.dependencycheck' apply plugin: 'org.owasp.dependencycheck'
apply plugin: 'kotlin-allopen' apply plugin: 'kotlin-allopen'
// This line works around a serious performance regression in the Kotlin 1.2.50 gradle plugin, it's fixed in 1.2.51
// TODO: Remove when we upgrade past Kotlin 1.2.51
inspectClassesForKotlinIC.enabled = false
allOpen { allOpen {
annotations( annotations(
"javax.persistence.Entity", "javax.persistence.Entity",

View File

@ -276,11 +276,13 @@ absolute path to the node's base directory.
.. note:: This is temporary feature for onboarding network participants that limits their visibility for privacy reasons. .. note:: This is temporary feature for onboarding network participants that limits their visibility for privacy reasons.
:tlsCertCrlDistPoint: CRL distribution point (i.e. URL) for the TLS certificate. Default value is NULL, which indicates no CRL availability for the TLS certificate. :tlsCertCrlDistPoint: CRL distribution point (i.e. URL) for the TLS certificate. Default value is NULL, which indicates no CRL availability for the TLS certificate.
Note: If crlCheckSoftFail is FALSE (meaning that there is the strict CRL checking mode) this value needs to be set.
.. note:: This needs to be set if crlCheckSoftFail is false (i.e. strict CRL checking is on).
:tlsCertCrlIssuer: CRL issuer (given in the X500 name format) for the TLS certificate. Default value is NULL, :tlsCertCrlIssuer: CRL issuer (given in the X500 name format) for the TLS certificate. Default value is NULL,
which indicates that the issuer of the TLS certificate is also the issuer of the CRL. which indicates that the issuer of the TLS certificate is also the issuer of the CRL.
Note: If this parameter is set then the tlsCertCrlDistPoint needs to be set as well.
.. note:: If this parameter is set then `tlsCertCrlDistPoint` needs to be set as well.
:flowMonitorPeriodMillis: ``Duration`` of the period suspended flows waiting for IO are logged. Default value is ``60 seconds``. :flowMonitorPeriodMillis: ``Duration`` of the period suspended flows waiting for IO are logged. Default value is ``60 seconds``.
@ -369,3 +371,22 @@ This is an example of adding/overriding the keyStore password :
.. sourcecode:: shell .. sourcecode:: shell
java -Dcorda.rpcSettings.ssl.keyStorePassword=mypassword -jar node.jar java -Dcorda.rpcSettings.ssl.keyStorePassword=mypassword -jar node.jar
CRL Configuration
-----------------
The Corda Network provides an endpoint serving an empty certificate revocation list for the TLS-level certificates.
This is intended for deployments that do not provide a CRL infrastructure but still require a strict CRL mode checking.
In such a case use the following URL in `tlsCertCrlDistPoint` option configuration:
.. sourcecode:: kotlin
"https://crl.cordaconnect.org/cordatls.crl"
Together with the above configuration `tlsCertCrlIssuer` option needs to be set to the following value:
.. sourcecode:: kotlin
"C=US, L=New York, O=R3 HoldCo LLC, OU=Corda, CN=Corda Root CA"
This set-up ensures that the TLS-level certificates are embedded with the CRL distribution point referencing the CRL issued by R3.
In cases where a proprietary CRL infrastructure is provided those values need to be changed accordingly.

View File

@ -22,6 +22,7 @@ import net.corda.demobench.readErrorLines
import tornadofx.* import tornadofx.*
import java.io.IOException import java.io.IOException
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption.REPLACE_EXISTING import java.nio.file.StandardCopyOption.REPLACE_EXISTING
import java.util.concurrent.Executors import java.util.concurrent.Executors
@ -133,7 +134,7 @@ class Explorer internal constructor(private val explorerController: ExplorerCont
class ExplorerController : Controller() { class ExplorerController : Controller() {
private val jvm by inject<JVMConfig>() private val jvm by inject<JVMConfig>()
private val explorerPath = jvm.applicationDir.resolve("explorer").resolve("node-explorer.jar") private val explorerPath: Path = jvm.applicationDir.resolve("explorer").resolve("node-explorer.jar")
init { init {
log.info("Explorer JAR: $explorerPath") log.info("Explorer JAR: $explorerPath")

View File

@ -31,7 +31,7 @@ class R3Pty(val name: CordaX500Name, settings: SettingsProvider, dimension: Dime
val terminal = JediTermWidget(dimension, settings) val terminal = JediTermWidget(dimension, settings)
val isConnected: Boolean get() = terminal.ttyConnector?.isConnected == true val isConnected: Boolean get() = terminal.ttyConnector?.isConnected ?: false
override fun close() { override fun close() {
log.info("Closing terminal '{}'", name) log.info("Closing terminal '{}'", name)
@ -75,5 +75,5 @@ class R3Pty(val name: CordaX500Name, settings: SettingsProvider, dimension: Dime
@Suppress("unused") @Suppress("unused")
@Throws(InterruptedException::class) @Throws(InterruptedException::class)
fun waitFor(): Int? = terminal.ttyConnector?.waitFor() fun waitFor(): Int = terminal.ttyConnector?.waitFor() ?: -1
} }

View File

@ -22,37 +22,46 @@ import java.util.concurrent.TimeUnit.SECONDS
class NodeRPC(config: NodeConfigWrapper, start: (NodeConfigWrapper, CordaRPCOps) -> Unit, invoke: (CordaRPCOps) -> Unit) : AutoCloseable { class NodeRPC(config: NodeConfigWrapper, start: (NodeConfigWrapper, CordaRPCOps) -> Unit, invoke: (CordaRPCOps) -> Unit) : AutoCloseable {
private companion object { private companion object {
private val log = contextLogger() private val log = contextLogger()
val oneSecond = SECONDS.toMillis(1) private val oneSecond = SECONDS.toMillis(1)
} }
private val rpcClient = CordaRPCClient(NetworkHostAndPort("localhost", config.nodeConfig.rpcAddress.port)) private val rpcClient = CordaRPCClient(NetworkHostAndPort("localhost", config.nodeConfig.rpcAddress.port))
@Volatile
private var rpcConnection: CordaRPCConnection? = null private var rpcConnection: CordaRPCConnection? = null
private val timer = Timer() private val timer = Timer("DemoBench NodeRPC (${config.key})", true)
@Volatile
private var timerThread: Thread? = null
init { init {
val setupTask = object : TimerTask() { val setupTask = object : TimerTask() {
override fun run() { override fun run() {
try { // Grab the timer's thread so that we know which one to interrupt.
val user = config.nodeConfig.rpcUsers[0] // This looks like the simplest way of getting the thread. (Ugh)
val connection = rpcClient.start(user.username, user.password) timerThread = Thread.currentThread()
rpcConnection = connection
val ops = connection.proxy
// Cancel the "setup" task now that we've created the RPC client. val user = config.nodeConfig.rpcUsers[0]
this.cancel() val ops: CordaRPCOps = try {
rpcClient.start(user.username, user.password).let { connection ->
// Run "start-up" task, now that the RPC client is ready. rpcConnection = connection
start(config, ops) connection.proxy
}
// Schedule a new task that will refresh the display once per second.
timer.schedule(object : TimerTask() {
override fun run() {
invoke(ops)
}
}, 0, oneSecond)
} catch (e: Exception) { } catch (e: Exception) {
log.warn("Node '{}' not ready yet (Error: {})", config.nodeConfig.myLegalName, e.message) log.warn("Node '{}' not ready yet (Error: {})", config.nodeConfig.myLegalName, e.message)
return
} }
// Cancel the "setup" task now that we've created the RPC client.
cancel()
// Run "start-up" task, now that the RPC client is ready.
start(config, ops)
// Schedule a new task that will refresh the display once per second.
timer.schedule(object : TimerTask() {
override fun run() {
invoke(ops)
}
}, 0, oneSecond)
} }
} }
@ -63,9 +72,11 @@ class NodeRPC(config: NodeConfigWrapper, start: (NodeConfigWrapper, CordaRPCOps)
override fun close() { override fun close() {
timer.cancel() timer.cancel()
try { try {
// No need to notify the node because it's also shutting down.
rpcConnection?.forceClose() rpcConnection?.forceClose()
} catch (e: Exception) { } catch (e: Exception) {
log.error("Failed to close RPC connection (Error: {})", e.message) log.error("Failed to close RPC connection (Error: {})", e.message)
} }
timerThread?.interrupt()
} }
} }

View File

@ -52,7 +52,7 @@ class NodeTerminalView : Fragment() {
override val root by fxml<VBox>() override val root by fxml<VBox>()
private companion object { private companion object {
val pageSpecification = PageSpecification(1, 1) private val pageSpecification = PageSpecification(1, 1)
} }
private val nodeController by inject<NodeController>() private val nodeController by inject<NodeController>()
@ -96,7 +96,7 @@ class NodeTerminalView : Fragment() {
root.children.add(stack) root.children.add(stack)
root.isVisible = true root.isVisible = true
SwingUtilities.invokeLater({ SwingUtilities.invokeLater {
val r3pty = R3Pty(config.nodeConfig.myLegalName, TerminalSettingsProvider(), Dimension(160, 80), onExit) val r3pty = R3Pty(config.nodeConfig.myLegalName, TerminalSettingsProvider(), Dimension(160, 80), onExit)
pty = r3pty pty = r3pty
@ -122,7 +122,7 @@ class NodeTerminalView : Fragment() {
rpc?.close() rpc?.close()
} }
} }
}) }
} }
/* /*
@ -191,9 +191,9 @@ class NodeTerminalView : Fragment() {
} }
private fun launchRPC(config: NodeConfigWrapper) = NodeRPC( private fun launchRPC(config: NodeConfigWrapper) = NodeRPC(
config = config, config = config,
start = this::initialise, start = ::initialise,
invoke = this::pollCashBalances invoke = ::pollCashBalances
) )
private fun initialise(config: NodeConfigWrapper, ops: CordaRPCOps) { private fun initialise(config: NodeConfigWrapper, ops: CordaRPCOps) {
@ -244,8 +244,8 @@ class NodeTerminalView : Fragment() {
private fun pollCashBalances(ops: CordaRPCOps) { private fun pollCashBalances(ops: CordaRPCOps) {
try { try {
val cashBalances = ops.getCashBalances().entries.joinToString( val cashBalances = ops.getCashBalances().entries.joinToString(
separator = ", ", separator = ", ",
transform = { e -> e.value.toString() } transform = { e -> e.value.toString() }
) )
Platform.runLater { Platform.runLater {
@ -262,21 +262,18 @@ class NodeTerminalView : Fragment() {
header.isDisable = true header.isDisable = true
subscriptions.forEach { subscriptions.forEach {
// Don't allow any exceptions here to halt tab destruction. // Don't allow any exceptions here to halt tab destruction.
try { ignoreExceptions { it.unsubscribe() }
it.unsubscribe()
} catch (e: Exception) {
}
} }
webServer.close() ignoreExceptions { webServer.close() }
explorer.close() ignoreExceptions { explorer.close() }
viewer.close() ignoreExceptions { viewer.close() }
rpc?.close() ignoreExceptions { rpc?.close() }
} }
fun destroy() { fun destroy() {
if (!isDestroyed) { if (!isDestroyed) {
shutdown() shutdown()
pty?.close() ignoreExceptions { pty?.close() }
isDestroyed = true isDestroyed = true
} }
} }
@ -289,6 +286,10 @@ class NodeTerminalView : Fragment() {
} }
} }
private fun ignoreExceptions(op: () -> Unit) {
try { op() } catch (e: Exception) {}
}
class TerminalSettingsProvider : DefaultSettingsProvider() { class TerminalSettingsProvider : DefaultSettingsProvider() {
override fun getDefaultStyle() = TextStyle(TerminalColor.WHITE, TerminalColor.rgb(50, 50, 50)) override fun getDefaultStyle() = TextStyle(TerminalColor.WHITE, TerminalColor.rgb(50, 50, 50))
override fun emulateX11CopyPaste() = true override fun emulateX11CopyPaste() = true