diff --git a/network-management/README.md b/network-management/README.md index fced2bb2cb..dfbc34e62f 100644 --- a/network-management/README.md +++ b/network-management/README.md @@ -158,17 +158,19 @@ networkMapConfig { ### 3. Create notary node and register with the doorman After the doorman service is started, start the notary node for the `initial-registration` process. -### 4. Add notary identities to the network parameters - The network parameters should contain the name and public key of the newly created notaries. +### 4. Generate node info files for notary nodes + Once notary nodes are registered, run the notary nodes with the `just-generate-node-info` flag. + This will generate the node info files, which then should be referenced in the network parameters configuration. + +### 5. Add notary identities to the network parameters + The network parameters should contain reference to the notaries node info files. Example network parameters file: notaries : [{ - name: "O=Notary A, L=Port Louis, C=MU, OU=Org Unit, CN=Service Name" - key: "GfHq2tTVk9z4eXgyWmExBB3JfHpeuYrk9jUc4zaVVSXpnW8FdCUNDhw6GRGN" + notaryNodeInfoFile: "/Path/To/NodeInfo/File1" validating: true }, { - name: "O=Notary B, L=Bali, C=ID, OU=Org Unit, CN=Service Name" - key: "GfHq2tTVk9z4eXgyEshv6vtBDjp7n76QZH5hk6VXLhk3vRTAmKcP9F9tRfPj" + notaryNodeInfoFile: "/Path/To/NodeInfo/File2" validating: false }] minimumPlatformVersion = 1 diff --git a/network-management/network-parameters.conf b/network-management/network-parameters.conf index e34c230df9..1991bd5f27 100644 --- a/network-management/network-parameters.conf +++ b/network-management/network-parameters.conf @@ -1,10 +1,8 @@ notaries : [{ - name: "O=Notary A, L=Port Louis, C=MU, OU=Org Unit, CN=Service Name" - key: "GfHq2tTVk9z4eXgyWmExBB3JfHpeuYrk9jUc4zaVVSXpnW8FdCUNDhw6GRGN" + notaryNodeInfoFile: "/Path/To/NodeInfo/File1" validating: true }, { - name: "O=Notary B, L=Bali, C=ID, OU=Org Unit, CN=Service Name" - key: "GfHq2tTVk9z4eXgyEshv6vtBDjp7n76QZH5hk6VXLhk3vRTAmKcP9F9tRfPj" + notaryNodeInfoFile: "/Path/To/NodeInfo/File2" validating: false }] eventHorizonDays = 100 diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/NetworkParametersConfiguration.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/NetworkParametersConfiguration.kt index 65e1dc7c61..9392a78ea6 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/NetworkParametersConfiguration.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/NetworkParametersConfiguration.kt @@ -1,16 +1,21 @@ package com.r3.corda.networkmanage.doorman +import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigParseOptions import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.exists +import net.corda.core.internal.readAll +import net.corda.core.serialization.deserialize import net.corda.core.utilities.days import net.corda.core.utilities.parsePublicKeyBase58 +import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.config.parseAs import net.corda.nodeapi.internal.network.NetworkParameters import net.corda.nodeapi.internal.network.NotaryInfo import java.nio.file.Path +import java.nio.file.Paths import java.time.Instant /** @@ -20,14 +25,18 @@ private const val DEFAULT_EPOCH = 1 /** * Data class representing a [NotaryInfo] which can be easily parsed by a typesafe [ConfigFactory]. - * @property name the X500Name of the notary. - * @property key the public key as serialized by [toBase58String] + * @property notaryNodeInfoFile path to the node info file of the notary node. * @property validating whether the notary is validating */ -internal data class NotaryConfiguration(private val name: CordaX500Name, - private val key: String, +internal data class NotaryConfiguration(private val notaryNodeInfoFile: Path, private val validating: Boolean) { - fun toNotaryInfo(): NotaryInfo = NotaryInfo(Party(name, parsePublicKeyBase58(key)), validating) + fun toNotaryInfo(): NotaryInfo { + val nodeInfo = notaryNodeInfoFile.readAll().deserialize().verified() + // It is always the last identity (in the list of identities) that corresponds to the notary identity. + // In case of a single notary, the list has only one element. In case of distributed notaries the list has + // two items and the second one corresponds to the notary identity. + return NotaryInfo(nodeInfo.legalIdentities.last(), validating) + } } /** @@ -50,14 +59,20 @@ internal data class NetworkParametersConfiguration(val minimumPlatformVersion: I * a modifiedTime initialized with [Instant.now]. */ fun parseNetworkParametersFrom(configFile: Path, epoch: Int = DEFAULT_EPOCH): NetworkParameters { - check(configFile.exists()) { "File $configFile does not exist" } - val networkParametersConfig = ConfigFactory.parseFile(configFile.toFile(), ConfigParseOptions.defaults()) - .parseAs(NetworkParametersConfiguration::class) + return parseNetworkParameters(parseNetworkParametersConfigurationFrom(configFile), epoch) +} - return NetworkParameters(networkParametersConfig.minimumPlatformVersion, - networkParametersConfig.notaries.map { it.toNotaryInfo() }, - networkParametersConfig.maxMessageSize, - networkParametersConfig.maxTransactionSize, +internal fun parseNetworkParametersConfigurationFrom(configFile: Path): NetworkParametersConfiguration { + check(configFile.exists()) { "File $configFile does not exist" } + return ConfigFactory.parseFile(configFile.toFile(), ConfigParseOptions.defaults()) + .parseAs(NetworkParametersConfiguration::class) +} + +internal fun parseNetworkParameters(configuration: NetworkParametersConfiguration, epoch: Int = DEFAULT_EPOCH): NetworkParameters { + return NetworkParameters(configuration.minimumPlatformVersion, + configuration.notaries.map { it.toNotaryInfo() }, + configuration.maxMessageSize, + configuration.maxTransactionSize, Instant.now(), epoch) } \ No newline at end of file diff --git a/network-management/src/test/kotlin/com/r3/corda/networkmanage/NetworkParametersConfigurationTest.kt b/network-management/src/test/kotlin/com/r3/corda/networkmanage/NetworkParametersConfigurationTest.kt index 24b6f2451c..b6caa2768a 100644 --- a/network-management/src/test/kotlin/com/r3/corda/networkmanage/NetworkParametersConfigurationTest.kt +++ b/network-management/src/test/kotlin/com/r3/corda/networkmanage/NetworkParametersConfigurationTest.kt @@ -1,21 +1,56 @@ package com.r3.corda.networkmanage +import com.r3.corda.networkmanage.doorman.NetworkParametersConfiguration +import com.r3.corda.networkmanage.doorman.NotaryConfiguration +import com.r3.corda.networkmanage.doorman.parseNetworkParameters import com.r3.corda.networkmanage.doorman.parseNetworkParametersFrom -import net.corda.core.utilities.days +import com.typesafe.config.ConfigFactory +import net.corda.core.identity.CordaX500Name +import net.corda.core.internal.copyTo +import net.corda.core.internal.deleteIfExists +import net.corda.core.serialization.serialize +import net.corda.testing.SerializationEnvironmentRule +import net.corda.testing.internal.createNodeInfoAndSigned import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.Rule import org.junit.Test -import java.io.File +import org.junit.rules.TemporaryFolder +import java.nio.file.Path import java.nio.file.Paths import java.time.Instant class NetworkParametersConfigurationTest { - private val validOverrideNetworkConfigPath = File("network-parameters.conf").toPath() + @Rule + @JvmField + val tempFolder = TemporaryFolder() + + @Rule + @JvmField + val testSerialization = SerializationEnvironmentRule() + + private fun generateNetworkParametersConfiguration() = NetworkParametersConfiguration( + notaries = listOf( + NotaryConfiguration(generateNodeInfoFile("Test1"), true), + NotaryConfiguration(generateNodeInfoFile("Test2"), false) + ), + maxMessageSize = 100, + maxTransactionSize = 100, + minimumPlatformVersion = 1 + ) + + private fun generateNodeInfoFile(organisation: String): Path { + val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name(organisation, "Madrid", "ES")) + val path = tempFolder.newFile().toPath() + path.deleteIfExists() + signedNodeInfo.serialize().open().copyTo(path) + return path + } @Test fun `reads an existing file`() { - val networkParameters = parseNetworkParametersFrom(validOverrideNetworkConfigPath) + val networkParameters = parseNetworkParameters(generateNetworkParametersConfiguration()) assertThat(networkParameters.minimumPlatformVersion).isEqualTo(1) val notaries = networkParameters.notaries assertThat(notaries).hasSize(2)