Changing network parameters to use node info files instead of by hand… (#288)

* Changing network parameters to use node info files instead of by hand specification of notary

* Addressing review comments

* Different names for notaries

* Updating README
This commit is contained in:
Michal Kit 2018-01-05 15:10:34 +00:00 committed by GitHub
parent a639839a68
commit a83f4fd61b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 26 deletions

View File

@ -158,17 +158,19 @@ networkMapConfig {
### 3. Create notary node and register with the doorman ### 3. Create notary node and register with the doorman
After the doorman service is started, start the notary node for the `initial-registration` process. After the doorman service is started, start the notary node for the `initial-registration` process.
### 4. Add notary identities to the network parameters ### 4. Generate node info files for notary nodes
The network parameters should contain the name and public key of the newly created notaries. 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: Example network parameters file:
notaries : [{ notaries : [{
name: "O=Notary A, L=Port Louis, C=MU, OU=Org Unit, CN=Service Name" notaryNodeInfoFile: "/Path/To/NodeInfo/File1"
key: "GfHq2tTVk9z4eXgyWmExBB3JfHpeuYrk9jUc4zaVVSXpnW8FdCUNDhw6GRGN"
validating: true validating: true
}, { }, {
name: "O=Notary B, L=Bali, C=ID, OU=Org Unit, CN=Service Name" notaryNodeInfoFile: "/Path/To/NodeInfo/File2"
key: "GfHq2tTVk9z4eXgyEshv6vtBDjp7n76QZH5hk6VXLhk3vRTAmKcP9F9tRfPj"
validating: false validating: false
}] }]
minimumPlatformVersion = 1 minimumPlatformVersion = 1

View File

@ -1,10 +1,8 @@
notaries : [{ notaries : [{
name: "O=Notary A, L=Port Louis, C=MU, OU=Org Unit, CN=Service Name" notaryNodeInfoFile: "/Path/To/NodeInfo/File1"
key: "GfHq2tTVk9z4eXgyWmExBB3JfHpeuYrk9jUc4zaVVSXpnW8FdCUNDhw6GRGN"
validating: true validating: true
}, { }, {
name: "O=Notary B, L=Bali, C=ID, OU=Org Unit, CN=Service Name" notaryNodeInfoFile: "/Path/To/NodeInfo/File2"
key: "GfHq2tTVk9z4eXgyEshv6vtBDjp7n76QZH5hk6VXLhk3vRTAmKcP9F9tRfPj"
validating: false validating: false
}] }]
eventHorizonDays = 100 eventHorizonDays = 100

View File

@ -1,16 +1,21 @@
package com.r3.corda.networkmanage.doorman package com.r3.corda.networkmanage.doorman
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigParseOptions import com.typesafe.config.ConfigParseOptions
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.exists 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.days
import net.corda.core.utilities.parsePublicKeyBase58 import net.corda.core.utilities.parsePublicKeyBase58
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.config.parseAs import net.corda.nodeapi.internal.config.parseAs
import net.corda.nodeapi.internal.network.NetworkParameters import net.corda.nodeapi.internal.network.NetworkParameters
import net.corda.nodeapi.internal.network.NotaryInfo import net.corda.nodeapi.internal.network.NotaryInfo
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths
import java.time.Instant 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]. * Data class representing a [NotaryInfo] which can be easily parsed by a typesafe [ConfigFactory].
* @property name the X500Name of the notary. * @property notaryNodeInfoFile path to the node info file of the notary node.
* @property key the public key as serialized by [toBase58String]
* @property validating whether the notary is validating * @property validating whether the notary is validating
*/ */
internal data class NotaryConfiguration(private val name: CordaX500Name, internal data class NotaryConfiguration(private val notaryNodeInfoFile: Path,
private val key: String,
private val validating: Boolean) { private val validating: Boolean) {
fun toNotaryInfo(): NotaryInfo = NotaryInfo(Party(name, parsePublicKeyBase58(key)), validating) fun toNotaryInfo(): NotaryInfo {
val nodeInfo = notaryNodeInfoFile.readAll().deserialize<SignedNodeInfo>().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]. * a modifiedTime initialized with [Instant.now].
*/ */
fun parseNetworkParametersFrom(configFile: Path, epoch: Int = DEFAULT_EPOCH): NetworkParameters { fun parseNetworkParametersFrom(configFile: Path, epoch: Int = DEFAULT_EPOCH): NetworkParameters {
check(configFile.exists()) { "File $configFile does not exist" } return parseNetworkParameters(parseNetworkParametersConfigurationFrom(configFile), epoch)
val networkParametersConfig = ConfigFactory.parseFile(configFile.toFile(), ConfigParseOptions.defaults()) }
.parseAs(NetworkParametersConfiguration::class)
return NetworkParameters(networkParametersConfig.minimumPlatformVersion, internal fun parseNetworkParametersConfigurationFrom(configFile: Path): NetworkParametersConfiguration {
networkParametersConfig.notaries.map { it.toNotaryInfo() }, check(configFile.exists()) { "File $configFile does not exist" }
networkParametersConfig.maxMessageSize, return ConfigFactory.parseFile(configFile.toFile(), ConfigParseOptions.defaults())
networkParametersConfig.maxTransactionSize, .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(), Instant.now(),
epoch) epoch)
} }

View File

@ -1,21 +1,56 @@
package com.r3.corda.networkmanage 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 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.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Rule
import org.junit.Test 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.nio.file.Paths
import java.time.Instant import java.time.Instant
class NetworkParametersConfigurationTest { 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 @Test
fun `reads an existing file`() { fun `reads an existing file`() {
val networkParameters = parseNetworkParametersFrom(validOverrideNetworkConfigPath) val networkParameters = parseNetworkParameters(generateNetworkParametersConfiguration())
assertThat(networkParameters.minimumPlatformVersion).isEqualTo(1) assertThat(networkParameters.minimumPlatformVersion).isEqualTo(1)
val notaries = networkParameters.notaries val notaries = networkParameters.notaries
assertThat(notaries).hasSize(2) assertThat(notaries).hasSize(2)