mirror of
https://github.com/corda/corda.git
synced 2024-12-30 01:39:04 +00:00
ENT-2188 fix H2 insecure default configuration (#3692)
Set the "h2.allowedClasses" system property, require database password when exposing H2 server on non-localhost address, samples start H2 server by default (reintroduces the behaviour before h2Settings.address configuration option was added)
This commit is contained in:
parent
7182542724
commit
c23167f08e
@ -86,7 +86,7 @@ absolute path to the node's base directory.
|
|||||||
|
|
||||||
:h2Port: Deprecated. Use ``h2Settings`` instead.
|
:h2Port: Deprecated. Use ``h2Settings`` instead.
|
||||||
|
|
||||||
:h2Settings: Sets the H2 JDBC server port. See :doc:`node-database-access-h2`.
|
:h2Settings: Sets the H2 JDBC server host and port. See :doc:`node-database-access-h2`. For non-localhost address the database passowrd needs to be set in ``dataSourceProperties``.
|
||||||
|
|
||||||
:messagingServerAddress: The address of the ArtemisMQ broker instance. If not provided the node will run one locally.
|
:messagingServerAddress: The address of the ArtemisMQ broker instance. If not provided the node will run one locally.
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
adminAddress "localhost:10013"
|
adminAddress "localhost:10013"
|
||||||
}
|
}
|
||||||
webPort 10004
|
webPort 10004
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10014']
|
||||||
cordapps = []
|
cordapps = []
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
@ -96,6 +97,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
adminAddress "localhost:10016"
|
adminAddress "localhost:10016"
|
||||||
}
|
}
|
||||||
webPort 10007
|
webPort 10007
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10017']
|
||||||
cordapps = []
|
cordapps = []
|
||||||
rpcUsers = [
|
rpcUsers = [
|
||||||
['username' : "user",
|
['username' : "user",
|
||||||
|
@ -32,13 +32,17 @@ If you want H2 to auto-select a port (mimicking the old ``h2Port`` behaviour), y
|
|||||||
address: "localhost:0"
|
address: "localhost:0"
|
||||||
}
|
}
|
||||||
|
|
||||||
If remote access is required, the address can be changed to ``0.0.0.0``. However it is recommended to change the default username and password before doing so.
|
If remote access is required, the address can be changed to ``0.0.0.0``.
|
||||||
|
The node requires a database password to be set when the database is exposed on the network interface to listen on.
|
||||||
|
|
||||||
.. sourcecode:: groovy
|
.. sourcecode:: groovy
|
||||||
|
|
||||||
h2Settings {
|
h2Settings {
|
||||||
address: "0.0.0.0:12345"
|
address: "0.0.0.0:12345"
|
||||||
}
|
}
|
||||||
|
dataSourceProperties {
|
||||||
|
dataSource.password : "strongpassword"
|
||||||
|
}
|
||||||
|
|
||||||
The previous ``h2Port`` syntax is now deprecated. ``h2Port`` will continue to work but the database
|
The previous ``h2Port`` syntax is now deprecated. ``h2Port`` will continue to work but the database
|
||||||
will only be accessible on localhost.
|
will only be accessible on localhost.
|
||||||
|
@ -3,7 +3,24 @@ Node database
|
|||||||
|
|
||||||
Default in-memory database
|
Default in-memory database
|
||||||
--------------------------
|
--------------------------
|
||||||
By default, nodes store their data in an H2 database. You can connect directly to a running node's database to see its
|
By default, nodes store their data in an H2 database.
|
||||||
|
The database (a file persistence.mv.db) is created at the first node startup with the administrator user 'sa' and a blank password.
|
||||||
|
The user name and password can be changed in node configuration:
|
||||||
|
|
||||||
|
.. sourcecode:: groovy
|
||||||
|
|
||||||
|
dataSourceProperties = {
|
||||||
|
dataSource.user = [USER]
|
||||||
|
dataSource.password = [PASSWORD]
|
||||||
|
}
|
||||||
|
|
||||||
|
Note, changing user/password for the existing node in node.conf will not update them in the H2 database,
|
||||||
|
you need to login to the database first to create new user or change the user password.
|
||||||
|
The database password is required only when the H2 database is exposed on non-localhost address (which is disabled by default).
|
||||||
|
The node requires the user with administrator permissions in order to creates tables upon the first startup
|
||||||
|
or after deplying new CorDapps with own tables.
|
||||||
|
|
||||||
|
You can connect directly to a running node's database to see its
|
||||||
stored states, transactions and attachments as follows:
|
stored states, transactions and attachments as follows:
|
||||||
|
|
||||||
* Enable the H2 database access in the node configuration using the following syntax:
|
* Enable the H2 database access in the node configuration using the following syntax:
|
||||||
@ -35,7 +52,8 @@ interface for you to query them using SQL.
|
|||||||
|
|
||||||
The default behaviour is to expose the H2 database on localhost. This can be overridden in the
|
The default behaviour is to expose the H2 database on localhost. This can be overridden in the
|
||||||
node configuration using ``h2Settings.address`` and specifying the address of the network interface to listen on,
|
node configuration using ``h2Settings.address`` and specifying the address of the network interface to listen on,
|
||||||
or simply using ``0.0.0.0:0`` to listen on all interfaces.
|
or simply using ``0.0.0.0:0`` to listen on all interfaces. The node requires a database password to be set when
|
||||||
|
the database is exposed on the network interface to listen on.
|
||||||
|
|
||||||
PostgreSQL
|
PostgreSQL
|
||||||
----------
|
----------
|
||||||
|
@ -28,7 +28,7 @@ class AddressBindingFailureTests {
|
|||||||
fun `rpc admin address`() = assertBindExceptionForOverrides { address -> mapOf("rpcSettings" to mapOf("adminAddress" to address.toString())) }
|
fun `rpc admin address`() = assertBindExceptionForOverrides { address -> mapOf("rpcSettings" to mapOf("adminAddress" to address.toString())) }
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `H2 address`() = assertBindExceptionForOverrides { address -> mapOf("h2Settings" to mapOf("address" to address.toString())) }
|
fun `H2 address`() = assertBindExceptionForOverrides { address -> mapOf("h2Settings" to mapOf("address" to address.toString()), "dataSourceProperties.dataSource.password" to "password") }
|
||||||
|
|
||||||
private fun assertBindExceptionForOverrides(overrides: (NetworkHostAndPort) -> Map<String, Any?>) {
|
private fun assertBindExceptionForOverrides(overrides: (NetworkHostAndPort) -> Map<String, Any?>) {
|
||||||
|
|
||||||
|
@ -0,0 +1,136 @@
|
|||||||
|
package net.corda.node.persistence
|
||||||
|
|
||||||
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
|
import net.corda.client.rpc.CordaRPCClient
|
||||||
|
import net.corda.core.flows.FlowLogic
|
||||||
|
import net.corda.core.flows.StartableByRPC
|
||||||
|
import net.corda.core.messaging.startFlow
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.node.services.Permissions
|
||||||
|
import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException
|
||||||
|
import net.corda.testing.driver.DriverParameters
|
||||||
|
import net.corda.testing.driver.PortAllocation
|
||||||
|
import net.corda.testing.driver.driver
|
||||||
|
import net.corda.testing.node.User
|
||||||
|
import org.junit.Test
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.sql.DriverManager
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class H2SecurityTests {
|
||||||
|
companion object {
|
||||||
|
private val port = PortAllocation.Incremental(21_000)
|
||||||
|
private fun getFreePort() = port.nextPort()
|
||||||
|
private const val h2AddressKey = "h2Settings.address"
|
||||||
|
private const val dbPasswordKey = "dataSourceProperties.dataSource.password"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `h2 server starts when h2Settings are set`() {
|
||||||
|
driver(DriverParameters(inMemoryDB = false, startNodesInProcess = isQuasarAgentSpecified(), notarySpecs = emptyList())) {
|
||||||
|
val port = getFreePort()
|
||||||
|
startNode(customOverrides = mapOf(h2AddressKey to "localhost:$port")).getOrThrow()
|
||||||
|
DriverManager.getConnection("jdbc:h2:tcp://localhost:$port/node", "sa", "").use {
|
||||||
|
assertTrue(it.createStatement().executeQuery("SELECT 1").next())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `h2 server on the host name requires non-default database password`() {
|
||||||
|
driver(DriverParameters(inMemoryDB = false, startNodesInProcess = isQuasarAgentSpecified(), notarySpecs = emptyList())) {
|
||||||
|
assertFailsWith(CouldNotCreateDataSourceException::class) {
|
||||||
|
startNode(customOverrides = mapOf(h2AddressKey to "${InetAddress.getLocalHost().hostName}:${getFreePort()}")).getOrThrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `h2 server on the external host IP requires non-default database password`() {
|
||||||
|
driver(DriverParameters(inMemoryDB = false, startNodesInProcess = isQuasarAgentSpecified(), notarySpecs = emptyList())) {
|
||||||
|
assertFailsWith(CouldNotCreateDataSourceException::class) {
|
||||||
|
startNode(customOverrides = mapOf(h2AddressKey to "${InetAddress.getLocalHost().hostAddress}:${getFreePort()}")).getOrThrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `h2 server on host name requires non-blank database password`() {
|
||||||
|
driver(DriverParameters(inMemoryDB = false, startNodesInProcess = isQuasarAgentSpecified(), notarySpecs = emptyList())) {
|
||||||
|
assertFailsWith(CouldNotCreateDataSourceException::class) {
|
||||||
|
startNode(customOverrides = mapOf(h2AddressKey to "${InetAddress.getLocalHost().hostName}:${getFreePort()}",
|
||||||
|
dbPasswordKey to " ")).getOrThrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `h2 server on external host IP requires non-blank database password`() {
|
||||||
|
driver(DriverParameters(inMemoryDB = false, startNodesInProcess = isQuasarAgentSpecified(), notarySpecs = emptyList())) {
|
||||||
|
assertFailsWith(CouldNotCreateDataSourceException::class) {
|
||||||
|
startNode(customOverrides = mapOf(h2AddressKey to "${InetAddress.getLocalHost().hostAddress}:${getFreePort()}",
|
||||||
|
dbPasswordKey to " ")).getOrThrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `h2 server on localhost runs with the default database password`() {
|
||||||
|
driver(DriverParameters(inMemoryDB = false, startNodesInProcess = false, notarySpecs = emptyList())) {
|
||||||
|
startNode(customOverrides = mapOf(h2AddressKey to "localhost:${getFreePort()}")).getOrThrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `h2 server to loopback IP runs with the default database password`() {
|
||||||
|
driver(DriverParameters(inMemoryDB = false, startNodesInProcess = isQuasarAgentSpecified(), notarySpecs = emptyList())) {
|
||||||
|
startNode(customOverrides = mapOf(h2AddressKey to "127.0.0.1:${getFreePort()}")).getOrThrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `remote code execution via h2 server is disabled`() {
|
||||||
|
driver(DriverParameters(inMemoryDB = false, startNodesInProcess = false, notarySpecs = emptyList())) {
|
||||||
|
val port = getFreePort()
|
||||||
|
startNode(customOverrides = mapOf(h2AddressKey to "localhost:$port", dbPasswordKey to "x")).getOrThrow()
|
||||||
|
DriverManager.getConnection("jdbc:h2:tcp://localhost:$port/node", "sa", "x").use {
|
||||||
|
assertFailsWith(org.h2.jdbc.JdbcSQLException::class) {
|
||||||
|
it.createStatement().execute("CREATE ALIAS SET_PROPERTY FOR \"java.lang.System.setProperty\"")
|
||||||
|
it.createStatement().execute("CALL SET_PROPERTY('abc', '1')")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertNull(System.getProperty("abc"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `malicious flow tries to enable remote code execution via h2 server`() {
|
||||||
|
val user = User("mark", "dadada", setOf(Permissions.startFlow<MaliciousFlow>()))
|
||||||
|
driver(DriverParameters(inMemoryDB = false, startNodesInProcess = false, notarySpecs = emptyList())) {
|
||||||
|
val port = getFreePort()
|
||||||
|
val nodeHandle = startNode(rpcUsers = listOf(user), customOverrides = mapOf(h2AddressKey to "localhost:$port",
|
||||||
|
dbPasswordKey to "x")).getOrThrow()
|
||||||
|
CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
|
||||||
|
it.proxy.startFlow(::MaliciousFlow).returnValue.getOrThrow()
|
||||||
|
}
|
||||||
|
DriverManager.getConnection("jdbc:h2:tcp://localhost:$port/node", "sa", "x").use {
|
||||||
|
assertFailsWith(org.h2.jdbc.JdbcSQLException::class) {
|
||||||
|
it.createStatement().execute("CREATE ALIAS SET_PROPERTY FOR \"java.lang.System.setProperty\"")
|
||||||
|
it.createStatement().execute("CALL SET_PROPERTY('abc', '1')")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertNull(System.getProperty("abc"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
class MaliciousFlow : FlowLogic<Boolean>() {
|
||||||
|
@Suspendable
|
||||||
|
override fun call(): Boolean {
|
||||||
|
System.clearProperty("h2.allowedClasses")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -54,6 +54,7 @@ import net.corda.nodeapi.internal.bridging.BridgeControlListener
|
|||||||
import net.corda.nodeapi.internal.config.User
|
import net.corda.nodeapi.internal.config.User
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
import net.corda.serialization.internal.*
|
import net.corda.serialization.internal.*
|
||||||
|
import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException
|
||||||
import org.h2.jdbc.JdbcSQLException
|
import org.h2.jdbc.JdbcSQLException
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
@ -61,11 +62,13 @@ import rx.Observable
|
|||||||
import rx.Scheduler
|
import rx.Scheduler
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import java.net.BindException
|
import java.net.BindException
|
||||||
|
import java.net.InetAddress
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.time.Clock
|
import java.time.Clock
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import javax.management.ObjectName
|
import javax.management.ObjectName
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
class NodeWithInfo(val node: Node, val info: NodeInfo) {
|
class NodeWithInfo(val node: Node, val info: NodeInfo) {
|
||||||
val services: StartedNodeServices = object : StartedNodeServices, ServiceHubInternal by node.services, FlowStarter by node.flowStarter {}
|
val services: StartedNodeServices = object : StartedNodeServices, ServiceHubInternal by node.services, FlowStarter by node.flowStarter {}
|
||||||
@ -331,13 +334,20 @@ open class Node(configuration: NodeConfiguration,
|
|||||||
|
|
||||||
if (databaseUrl != null && databaseUrl.startsWith(h2Prefix)) {
|
if (databaseUrl != null && databaseUrl.startsWith(h2Prefix)) {
|
||||||
val effectiveH2Settings = configuration.effectiveH2Settings
|
val effectiveH2Settings = configuration.effectiveH2Settings
|
||||||
|
//forbid execution of arbitrary code via SQL except those classes required by H2 itself
|
||||||
|
System.setProperty("h2.allowedClasses", "org.h2.mvstore.db.MVTableEngine,org.locationtech.jts.geom.Geometry,org.h2.server.TcpServer")
|
||||||
if (effectiveH2Settings?.address != null) {
|
if (effectiveH2Settings?.address != null) {
|
||||||
|
if (!InetAddress.getByName(effectiveH2Settings.address.host).isLoopbackAddress
|
||||||
|
&& configuration.dataSourceProperties.getProperty("dataSource.password").isBlank()) {
|
||||||
|
throw CouldNotCreateDataSourceException("Database password is required for H2 server listening on ${InetAddress.getByName(effectiveH2Settings.address.host)}.")
|
||||||
|
}
|
||||||
val databaseName = databaseUrl.removePrefix(h2Prefix).substringBefore(';')
|
val databaseName = databaseUrl.removePrefix(h2Prefix).substringBefore(';')
|
||||||
|
val baseDir = Paths.get(databaseName).parent.toString()
|
||||||
val server = org.h2.tools.Server.createTcpServer(
|
val server = org.h2.tools.Server.createTcpServer(
|
||||||
"-tcpPort", effectiveH2Settings.address.port.toString(),
|
"-tcpPort", effectiveH2Settings.address.port.toString(),
|
||||||
"-tcpAllowOthers",
|
"-tcpAllowOthers",
|
||||||
"-tcpDaemon",
|
"-tcpDaemon",
|
||||||
|
"-baseDir", baseDir,
|
||||||
"-key", "node", databaseName)
|
"-key", "node", databaseName)
|
||||||
// override interface that createTcpServer listens on (which is always 0.0.0.0)
|
// override interface that createTcpServer listens on (which is always 0.0.0.0)
|
||||||
System.setProperty("h2.bindAddress", effectiveH2Settings.address.host)
|
System.setProperty("h2.bindAddress", effectiveH2Settings.address.host)
|
||||||
|
@ -53,6 +53,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
address "localhost:10003"
|
address "localhost:10003"
|
||||||
adminAddress "localhost:10004"
|
adminAddress "localhost:10004"
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10012']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=Bank A,L=London,C=GB"
|
name "O=Bank A,L=London,C=GB"
|
||||||
@ -63,6 +64,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
address "localhost:10006"
|
address "localhost:10006"
|
||||||
adminAddress "localhost:10007"
|
adminAddress "localhost:10007"
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10013']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=Bank B,L=New York,C=US"
|
name "O=Bank B,L=New York,C=US"
|
||||||
@ -74,6 +76,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
webPort 10010
|
webPort 10010
|
||||||
cordapps = []
|
cordapps = []
|
||||||
rpcUsers = ext.rpcUsers
|
rpcUsers = ext.rpcUsers
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10014']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +44,12 @@ class BankOfCordaCordform : CordformDefinition() {
|
|||||||
adminAddress("localhost:10004")
|
adminAddress("localhost:10004")
|
||||||
}
|
}
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:10016"))
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name(BOC_NAME)
|
name(BOC_NAME)
|
||||||
extraConfig = mapOf("custom" to mapOf("issuableCurrencies" to listOf("USD")))
|
extraConfig = mapOf("custom" to mapOf("issuableCurrencies" to listOf("USD")),
|
||||||
|
"h2Settings" to mapOf("address" to "localhost:10017"))
|
||||||
p2pPort(10005)
|
p2pPort(10005)
|
||||||
rpcSettings {
|
rpcSettings {
|
||||||
address("localhost:$BOC_RPC_PORT")
|
address("localhost:$BOC_RPC_PORT")
|
||||||
@ -67,6 +69,7 @@ class BankOfCordaCordform : CordformDefinition() {
|
|||||||
webPort(10010)
|
webPort(10010)
|
||||||
rpcUsers(User(BIGCORP_RPC_USER, BIGCORP_RPC_PWD, setOf(all())))
|
rpcUsers(User(BIGCORP_RPC_USER, BIGCORP_RPC_PWD, setOf(all())))
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:10018"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,11 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
port 10003
|
port 10003
|
||||||
adminPort 10004
|
adminPort 10004
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10005']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=Bank A,L=London,C=GB"
|
name "O=Bank A,L=London,C=GB"
|
||||||
p2pPort 10005
|
p2pPort 10006
|
||||||
cordapps = []
|
cordapps = []
|
||||||
rpcUsers = ext.rpcUsers
|
rpcUsers = ext.rpcUsers
|
||||||
// This configures the default cordapp for this node
|
// This configures the default cordapp for this node
|
||||||
@ -36,10 +37,11 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
port 10007
|
port 10007
|
||||||
adminPort 10008
|
adminPort 10008
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10009']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=Bank B,L=New York,C=US"
|
name "O=Bank B,L=New York,C=US"
|
||||||
p2pPort 10009
|
p2pPort 10010
|
||||||
cordapps = []
|
cordapps = []
|
||||||
rpcUsers = ext.rpcUsers
|
rpcUsers = ext.rpcUsers
|
||||||
// This configures the default cordapp for this node
|
// This configures the default cordapp for this node
|
||||||
@ -50,5 +52,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
port 10011
|
port 10011
|
||||||
adminPort 10012
|
adminPort 10012
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10013']
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -70,6 +70,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
cordapps = ["${project(":finance").group}:finance:$corda_release_version"]
|
cordapps = ["${project(":finance").group}:finance:$corda_release_version"]
|
||||||
rpcUsers = rpcUsersList
|
rpcUsers = rpcUsersList
|
||||||
useTestClock true
|
useTestClock true
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10024']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=Bank A,L=London,C=GB"
|
name "O=Bank A,L=London,C=GB"
|
||||||
@ -81,6 +82,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
cordapps = ["${project(":finance").group}:finance:$corda_release_version"]
|
cordapps = ["${project(":finance").group}:finance:$corda_release_version"]
|
||||||
rpcUsers = rpcUsersList
|
rpcUsers = rpcUsersList
|
||||||
useTestClock true
|
useTestClock true
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10027']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=Bank B,L=New York,C=US"
|
name "O=Bank B,L=New York,C=US"
|
||||||
@ -92,6 +94,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
cordapps = ["${project.group}:finance:$corda_release_version"]
|
cordapps = ["${project.group}:finance:$corda_release_version"]
|
||||||
rpcUsers = rpcUsersList
|
rpcUsers = rpcUsersList
|
||||||
useTestClock true
|
useTestClock true
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10030']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=Regulator,L=Moscow,C=RU"
|
name "O=Regulator,L=Moscow,C=RU"
|
||||||
@ -104,6 +107,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
cordapps = ["${project(":finance").group}:finance:$corda_release_version"]
|
cordapps = ["${project(":finance").group}:finance:$corda_release_version"]
|
||||||
rpcUsers = rpcUsersList
|
rpcUsers = rpcUsersList
|
||||||
useTestClock true
|
useTestClock true
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10033']
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
port 10003
|
port 10003
|
||||||
adminPort 10004
|
adminPort 10004
|
||||||
}
|
}
|
||||||
h2Port 20004
|
extraConfig = ['h2Settings.address' : 'localhost:20004']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=Bank A,L=London,C=GB"
|
name "O=Bank A,L=London,C=GB"
|
||||||
@ -35,6 +35,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
port 10007
|
port 10007
|
||||||
adminPort 10008
|
adminPort 10008
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:0']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=Bank B,L=New York,C=US"
|
name "O=Bank B,L=New York,C=US"
|
||||||
@ -45,5 +46,6 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
port 10011
|
port 10011
|
||||||
adminPort 10012
|
adminPort 10012
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:0']
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -52,7 +52,7 @@ by using the H2 web console:
|
|||||||
Each node outputs its connection string in the terminal window as it starts up. In a terminal window where a **notary** node is running,
|
Each node outputs its connection string in the terminal window as it starts up. In a terminal window where a **notary** node is running,
|
||||||
look for the following string:
|
look for the following string:
|
||||||
|
|
||||||
``Database connection url is : jdbc:h2:tcp://10.18.0.150:56736/node``
|
``Database connection url is : jdbc:h2:tcp://localhost:56736/node``
|
||||||
|
|
||||||
You can use the string on the right to connect to the h2 database: just paste it into the `JDBC URL` field and click *Connect*.
|
You can use the string on the right to connect to the h2 database: just paste it into the `JDBC URL` field and click *Connect*.
|
||||||
You will be presented with a web application that enumerates all the available tables and provides an interface for you to query them using SQL
|
You will be presented with a web application that enumerates all the available tables and provides an interface for you to query them using SQL
|
||||||
|
@ -35,6 +35,7 @@ class BFTNotaryCordform : CordformDefinition() {
|
|||||||
}
|
}
|
||||||
rpcUsers(notaryDemoUser)
|
rpcUsers(notaryDemoUser)
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name(BOB_NAME)
|
name(BOB_NAME)
|
||||||
@ -44,11 +45,13 @@ class BFTNotaryCordform : CordformDefinition() {
|
|||||||
adminAddress("localhost:10106")
|
adminAddress("localhost:10106")
|
||||||
}
|
}
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
}
|
}
|
||||||
val clusterAddresses = (0 until clusterSize).map { NetworkHostAndPort("localhost", 11000 + it * 10) }
|
val clusterAddresses = (0 until clusterSize).map { NetworkHostAndPort("localhost", 11000 + it * 10) }
|
||||||
fun notaryNode(replicaId: Int, configure: CordformNode.() -> Unit) = node {
|
fun notaryNode(replicaId: Int, configure: CordformNode.() -> Unit) = node {
|
||||||
name(notaryNames[replicaId])
|
name(notaryNames[replicaId])
|
||||||
notary(NotaryConfig(validating = false, serviceLegalName = clusterName, bftSMaRt = BFTSMaRtConfiguration(replicaId, clusterAddresses)))
|
notary(NotaryConfig(validating = false, serviceLegalName = clusterName, bftSMaRt = BFTSMaRtConfiguration(replicaId, clusterAddresses)))
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
configure()
|
configure()
|
||||||
}
|
}
|
||||||
notaryNode(0) {
|
notaryNode(0) {
|
||||||
|
@ -23,6 +23,7 @@ class CustomNotaryCordform : CordformDefinition() {
|
|||||||
}
|
}
|
||||||
rpcUsers(notaryDemoUser)
|
rpcUsers(notaryDemoUser)
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name(BOB_NAME)
|
name(BOB_NAME)
|
||||||
@ -32,6 +33,7 @@ class CustomNotaryCordform : CordformDefinition() {
|
|||||||
adminAddress("localhost:10106")
|
adminAddress("localhost:10106")
|
||||||
}
|
}
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name(DUMMY_NOTARY_NAME)
|
name(DUMMY_NOTARY_NAME)
|
||||||
@ -42,6 +44,7 @@ class CustomNotaryCordform : CordformDefinition() {
|
|||||||
}
|
}
|
||||||
notary(NotaryConfig(validating = true, custom = true))
|
notary(NotaryConfig(validating = true, custom = true))
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ class RaftNotaryCordform : CordformDefinition() {
|
|||||||
}
|
}
|
||||||
rpcUsers(notaryDemoUser)
|
rpcUsers(notaryDemoUser)
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name(BOB_NAME)
|
name(BOB_NAME)
|
||||||
@ -44,11 +45,13 @@ class RaftNotaryCordform : CordformDefinition() {
|
|||||||
adminAddress("localhost:10106")
|
adminAddress("localhost:10106")
|
||||||
}
|
}
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
}
|
}
|
||||||
fun notaryNode(index: Int, nodePort: Int, clusterPort: Int? = null, configure: CordformNode.() -> Unit) = node {
|
fun notaryNode(index: Int, nodePort: Int, clusterPort: Int? = null, configure: CordformNode.() -> Unit) = node {
|
||||||
name(notaryNames[index])
|
name(notaryNames[index])
|
||||||
val clusterAddresses = if (clusterPort != null) listOf(NetworkHostAndPort("localhost", clusterPort)) else emptyList()
|
val clusterAddresses = if (clusterPort != null) listOf(NetworkHostAndPort("localhost", clusterPort)) else emptyList()
|
||||||
notary(NotaryConfig(validating = true, serviceLegalName = clusterName, raft = RaftConfig(NetworkHostAndPort("localhost", nodePort), clusterAddresses)))
|
notary(NotaryConfig(validating = true, serviceLegalName = clusterName, raft = RaftConfig(NetworkHostAndPort("localhost", nodePort), clusterAddresses)))
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
configure()
|
configure()
|
||||||
devMode(true)
|
devMode(true)
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ class SingleNotaryCordform : CordformDefinition() {
|
|||||||
}
|
}
|
||||||
rpcUsers(notaryDemoUser)
|
rpcUsers(notaryDemoUser)
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name(BOB_NAME)
|
name(BOB_NAME)
|
||||||
@ -38,6 +39,7 @@ class SingleNotaryCordform : CordformDefinition() {
|
|||||||
adminAddress("localhost:10106")
|
adminAddress("localhost:10106")
|
||||||
}
|
}
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name(DUMMY_NOTARY_NAME)
|
name(DUMMY_NOTARY_NAME)
|
||||||
@ -48,6 +50,7 @@ class SingleNotaryCordform : CordformDefinition() {
|
|||||||
}
|
}
|
||||||
notary(NotaryConfig(validating = true))
|
notary(NotaryConfig(validating = true))
|
||||||
devMode(true)
|
devMode(true)
|
||||||
|
extraConfig = mapOf("h2Settings" to mapOf("address" to "localhost:0"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
extraConfig = [
|
extraConfig = [
|
||||||
custom: [
|
custom: [
|
||||||
jvmArgs: ["-Xmx1g"]
|
jvmArgs: ["-Xmx1g"]
|
||||||
]
|
],
|
||||||
|
'h2Settings.address' : 'localhost:10038'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
@ -98,7 +99,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
extraConfig = [
|
extraConfig = [
|
||||||
custom: [
|
custom: [
|
||||||
jvmArgs: ["-Xmx1g"]
|
jvmArgs: ["-Xmx1g"]
|
||||||
]
|
],
|
||||||
|
'h2Settings.address' : 'localhost:10039'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
@ -116,7 +118,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
extraConfig = [
|
extraConfig = [
|
||||||
custom: [
|
custom: [
|
||||||
jvmArgs: ["-Xmx1g"]
|
jvmArgs: ["-Xmx1g"]
|
||||||
]
|
],
|
||||||
|
'h2Settings.address' : 'localhost:10040'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
@ -134,7 +137,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
extraConfig = [
|
extraConfig = [
|
||||||
custom: [
|
custom: [
|
||||||
jvmArgs: ["-Xmx1g"]
|
jvmArgs: ["-Xmx1g"]
|
||||||
]
|
],
|
||||||
|
'h2Settings.address' : 'localhost:10041'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
address "localhost:10003"
|
address "localhost:10003"
|
||||||
adminAddress "localhost:10004"
|
adminAddress "localhost:10004"
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10014']
|
||||||
cordapps = ["$project.group:finance:$corda_release_version"]
|
cordapps = ["$project.group:finance:$corda_release_version"]
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
@ -65,6 +66,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
address "localhost:10006"
|
address "localhost:10006"
|
||||||
adminAddress "localhost:10007"
|
adminAddress "localhost:10007"
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10015']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=Bank B,L=New York,C=US"
|
name "O=Bank B,L=New York,C=US"
|
||||||
@ -75,6 +77,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
address "localhost:10009"
|
address "localhost:10009"
|
||||||
adminAddress "localhost:10010"
|
adminAddress "localhost:10010"
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10016']
|
||||||
}
|
}
|
||||||
node {
|
node {
|
||||||
name "O=BankOfCorda,L=New York,C=US"
|
name "O=BankOfCorda,L=New York,C=US"
|
||||||
@ -85,6 +88,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
|||||||
address "localhost:10012"
|
address "localhost:10012"
|
||||||
adminAddress "localhost:10013"
|
adminAddress "localhost:10013"
|
||||||
}
|
}
|
||||||
|
extraConfig = ['h2Settings.address' : 'localhost:10017']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user