Fix node integration tests. (#2233)

* Add tests for node registration and communication
This commit is contained in:
Alberto Arri 2017-12-21 11:48:00 +00:00 committed by GitHub
parent ff8d0881b3
commit 6db0490750
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 121 additions and 53 deletions

View File

@ -10,7 +10,6 @@ import net.corda.core.messaging.CordaRPCOps
import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
import net.corda.webserver.services.WebServerPluginRegistry
import java.util.function.Function import java.util.function.Function
import javax.ws.rs.GET import javax.ws.rs.GET
import javax.ws.rs.Path import javax.ws.rs.Path

View File

@ -10,6 +10,7 @@ import net.corda.core.utilities.seconds
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.NetworkParameters import net.corda.nodeapi.internal.network.NetworkParameters
import net.corda.testing.ALICE_NAME import net.corda.testing.ALICE_NAME
import net.corda.testing.ROOT_CA
import net.corda.testing.BOB_NAME import net.corda.testing.BOB_NAME
import net.corda.testing.SerializationEnvironmentRule import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.NodeHandle
@ -49,20 +50,22 @@ class NetworkMapTest {
@Test @Test
fun `node correctly downloads and saves network parameters file on startup`() { fun `node correctly downloads and saves network parameters file on startup`() {
internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone, initialiseSerialization = false) { internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone,
initialiseSerialization = false, notarySpecs = emptyList()) {
val alice = startNode(providedName = ALICE_NAME).getOrThrow() val alice = startNode(providedName = ALICE_NAME).getOrThrow()
val networkParameters = alice.configuration.baseDirectory val networkParameters = alice.configuration.baseDirectory
.list { paths -> paths.filter { it.fileName.toString() == NETWORK_PARAMS_FILE_NAME }.findFirst().get() } .list { paths -> paths.filter { it.fileName.toString() == NETWORK_PARAMS_FILE_NAME }.findFirst().get() }
.readAll() .readAll()
.deserialize<SignedData<NetworkParameters>>() .deserialize<SignedData<NetworkParameters>>()
.verified() .verified()
assertEquals(NetworkMapServer.stubNetworkParameter, networkParameters) assertEquals(networkMapServer.networkParameters, networkParameters)
} }
} }
@Test @Test
fun `nodes can see each other using the http network map`() { fun `nodes can see each other using the http network map`() {
internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone, initialiseSerialization = false) { internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone,
initialiseSerialization = false, onNetworkParametersGeneration = { networkMapServer.networkParameters = it }) {
val alice = startNode(providedName = ALICE_NAME) val alice = startNode(providedName = ALICE_NAME)
val bob = startNode(providedName = BOB_NAME) val bob = startNode(providedName = BOB_NAME)
val notaryNode = defaultNotaryNode.get() val notaryNode = defaultNotaryNode.get()
@ -77,7 +80,8 @@ class NetworkMapTest {
@Test @Test
fun `nodes process network map add updates correctly when adding new node to network map`() { fun `nodes process network map add updates correctly when adding new node to network map`() {
internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone, initialiseSerialization = false) { internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone,
initialiseSerialization = false, onNetworkParametersGeneration = { networkMapServer.networkParameters = it }) {
val alice = startNode(providedName = ALICE_NAME) val alice = startNode(providedName = ALICE_NAME)
val notaryNode = defaultNotaryNode.get() val notaryNode = defaultNotaryNode.get()
val aliceNode = alice.get() val aliceNode = alice.get()
@ -98,7 +102,8 @@ class NetworkMapTest {
@Test @Test
fun `nodes process network map remove updates correctly`() { fun `nodes process network map remove updates correctly`() {
internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone, initialiseSerialization = false) { internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone,
initialiseSerialization = false, onNetworkParametersGeneration = { networkMapServer.networkParameters = it }) {
val alice = startNode(providedName = ALICE_NAME) val alice = startNode(providedName = ALICE_NAME)
val bob = startNode(providedName = BOB_NAME) val bob = startNode(providedName = BOB_NAME)
val notaryNode = defaultNotaryNode.get() val notaryNode = defaultNotaryNode.get()

View File

@ -3,10 +3,12 @@ package net.corda.node.utilities.registration
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.cert import net.corda.core.internal.cert
import net.corda.core.internal.concurrent.transpose
import net.corda.core.internal.toX509CertHolder import net.corda.core.internal.toX509CertHolder
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.messaging.startFlow
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.*
import net.corda.core.utilities.minutes import net.corda.finance.DOLLARS
import net.corda.finance.flows.CashIssueAndPaymentFlow
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509CertificateFactory import net.corda.nodeapi.internal.crypto.X509CertificateFactory
@ -14,11 +16,16 @@ import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_CA import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_CA
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
import net.corda.nodeapi.internal.network.NotaryInfo
import net.corda.testing.ROOT_CA
import net.corda.testing.SerializationEnvironmentRule import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.node.internal.CompatibilityZoneParams
import net.corda.testing.driver.PortAllocation import net.corda.testing.driver.PortAllocation
import net.corda.testing.node.NotarySpec
import net.corda.testing.node.internal.CompatibilityZoneParams
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 net.corda.testing.singleIdentity
import net.corda.testing.singleIdentityAndCert
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.bouncycastle.pkcs.PKCS10CertificationRequest import org.bouncycastle.pkcs.PKCS10CertificationRequest
@ -44,15 +51,13 @@ class NodeRegistrationTest {
@JvmField @JvmField
val testSerialization = SerializationEnvironmentRule(true) val testSerialization = SerializationEnvironmentRule(true)
private val portAllocation = PortAllocation.Incremental(13000) private val portAllocation = PortAllocation.Incremental(13000)
private val rootCertAndKeyPair = createSelfKeyAndSelfSignedCertificate() private val registrationHandler = RegistrationHandler(ROOT_CA)
private val registrationHandler = RegistrationHandler(rootCertAndKeyPair)
private lateinit var server: NetworkMapServer private lateinit var server: NetworkMapServer
private lateinit var serverHostAndPort: NetworkHostAndPort private lateinit var serverHostAndPort: NetworkHostAndPort
@Before @Before
fun startServer() { fun startServer() {
server = NetworkMapServer(1.minutes, portAllocation.nextHostAndPort(), rootCertAndKeyPair, registrationHandler) server = NetworkMapServer(1.minutes, portAllocation.nextHostAndPort(), ROOT_CA, "localhost", registrationHandler)
serverHostAndPort = server.start() serverHostAndPort = server.start()
} }
@ -61,19 +66,47 @@ class NodeRegistrationTest {
server.close() server.close()
} }
// TODO Ideally this test should be checking that two nodes that register are able to transact with each other. However
// starting a second node hangs so that needs to be fixed.
@Test @Test
fun `node registration correct root cert`() { fun `node registration correct root cert`() {
val compatibilityZone = CompatibilityZoneParams(URL("http://$serverHostAndPort"), rootCert = rootCertAndKeyPair.certificate.cert) val compatibilityZone = CompatibilityZoneParams(URL("http://$serverHostAndPort"), rootCert = ROOT_CA.certificate.cert)
internalDriver( internalDriver(
portAllocation = portAllocation, portAllocation = portAllocation,
notarySpecs = emptyList(),
compatibilityZone = compatibilityZone, compatibilityZone = compatibilityZone,
initialiseSerialization = false initialiseSerialization = false,
notarySpecs = listOf(NotarySpec(CordaX500Name(organisation = "NotaryService", locality = "Zurich", country = "CH"), validating = false)),
extraCordappPackagesToScan = listOf("net.corda.finance"),
onNetworkParametersGeneration = { server.networkParameters = it }
) { ) {
startNode(providedName = CordaX500Name("Alice", "London", "GB")).getOrThrow() val notary = defaultNotaryNode.get()
assertThat(registrationHandler.idsPolled).contains("Alice")
val ALICE_NAME = "Alice"
val GENEVIEVE_NAME = "Genevieve"
val nodesFutures = listOf(startNode(providedName = CordaX500Name(ALICE_NAME, "London", "GB")),
startNode(providedName = CordaX500Name(GENEVIEVE_NAME, "London", "GB")))
val (alice, genevieve) = nodesFutures.transpose().get()
val nodes = listOf(alice, genevieve, notary)
assertThat(registrationHandler.idsPolled).contains(ALICE_NAME, GENEVIEVE_NAME)
// Notary identities are generated beforehand hence notary nodes don't go through registration.
// This test isn't specifically testing this, or relying on this behavior, though if this check fail,
// this will probably lead to the rest of the test to fail.
assertThat(registrationHandler.idsPolled).doesNotContain("NotaryService")
// Check each node has each other identity in their network map cache.
val nodeIdentities = nodes.map { it.nodeInfo.singleIdentity() }
for (node in nodes) {
assertThat(node.rpc.networkMapSnapshot().map { it.singleIdentity() }).containsAll(nodeIdentities)
}
// Check we nodes communicate among themselves (and the notary).
val anonymous = false
genevieve.rpc.startFlow(::CashIssueAndPaymentFlow, 1000.DOLLARS, OpaqueBytes.of(12),
alice.nodeInfo.singleIdentity(),
anonymous,
notary.nodeInfo.singleIdentity())
.returnValue
.getOrThrow()
} }
} }
@ -85,6 +118,7 @@ class NodeRegistrationTest {
portAllocation = portAllocation, portAllocation = portAllocation,
notarySpecs = emptyList(), notarySpecs = emptyList(),
compatibilityZone = compatibilityZone, compatibilityZone = compatibilityZone,
initialiseSerialization = false,
// Changing the content of the truststore makes the node fail in a number of ways if started out process. // Changing the content of the truststore makes the node fail in a number of ways if started out process.
startNodesInProcess = true startNodesInProcess = true
) { ) {

View File

@ -5,10 +5,7 @@ import net.corda.core.crypto.sha256
import net.corda.core.internal.cert import net.corda.core.internal.cert
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.testing.ALICE_NAME import net.corda.testing.*
import net.corda.testing.BOB_NAME
import net.corda.testing.DEV_TRUST_ROOT
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.driver.PortAllocation import net.corda.testing.driver.PortAllocation
import net.corda.testing.internal.createNodeInfoAndSigned import net.corda.testing.internal.createNodeInfoAndSigned
import net.corda.testing.node.internal.network.NetworkMapServer import net.corda.testing.node.internal.network.NetworkMapServer
@ -33,7 +30,7 @@ class NetworkMapClientTest {
@Before @Before
fun setUp() { fun setUp() {
server = NetworkMapServer(cacheTimeout, PortAllocation.Incremental(10000).nextHostAndPort()) server = NetworkMapServer(cacheTimeout, PortAllocation.Incremental(10000).nextHostAndPort(), root_ca = ROOT_CA)
val hostAndPort = server.start() val hostAndPort = server.start()
networkMapClient = NetworkMapClient(URL("http://${hostAndPort.host}:${hostAndPort.port}"), DEV_TRUST_ROOT.cert) networkMapClient = NetworkMapClient(URL("http://${hostAndPort.host}:${hostAndPort.port}"), DEV_TRUST_ROOT.cert)
} }
@ -70,7 +67,7 @@ class NetworkMapClientTest {
// The test server returns same network parameter for any hash. // The test server returns same network parameter for any hash.
val networkParameter = networkMapClient.getNetworkParameter(SecureHash.randomSHA256())?.verified() val networkParameter = networkMapClient.getNetworkParameter(SecureHash.randomSHA256())?.verified()
assertNotNull(networkParameter) assertNotNull(networkParameter)
assertEquals(NetworkMapServer.stubNetworkParameter, networkParameter) assertEquals(server.networkParameters, networkParameter)
} }
@Test @Test

View File

@ -193,7 +193,8 @@ fun <A> driver(
notarySpecs = notarySpecs, notarySpecs = notarySpecs,
extraCordappPackagesToScan = extraCordappPackagesToScan, extraCordappPackagesToScan = extraCordappPackagesToScan,
jmxPolicy = jmxPolicy, jmxPolicy = jmxPolicy,
compatibilityZone = null compatibilityZone = null,
onNetworkParametersGeneration = { }
), ),
coerce = { it }, coerce = { it },
dsl = dsl, dsl = dsl,

View File

@ -10,13 +10,12 @@ import net.corda.cordform.CordformContext
import net.corda.cordform.CordformNode import net.corda.cordform.CordformNode
import net.corda.core.concurrent.CordaFuture import net.corda.core.concurrent.CordaFuture
import net.corda.core.concurrent.firstOf import net.corda.core.concurrent.firstOf
import net.corda.core.crypto.generateKeyPair
import net.corda.core.crypto.random63BitValue import net.corda.core.crypto.random63BitValue
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.ThreadBox import net.corda.core.identity.Party
import net.corda.core.internal.*
import net.corda.core.internal.concurrent.* import net.corda.core.internal.concurrent.*
import net.corda.core.internal.copyTo
import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.services.NetworkMapCache import net.corda.core.node.services.NetworkMapCache
import net.corda.core.toFuture import net.corda.core.toFuture
@ -32,6 +31,7 @@ import net.corda.node.services.config.*
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
import net.corda.node.utilities.registration.NetworkRegistrationHelper import net.corda.node.utilities.registration.NetworkRegistrationHelper
import net.corda.nodeapi.internal.IdentityGenerator import net.corda.nodeapi.internal.IdentityGenerator
import net.corda.nodeapi.internal.IdentityGenerator.NODE_IDENTITY_ALIAS_PREFIX
import net.corda.nodeapi.internal.addShutdownHook import net.corda.nodeapi.internal.addShutdownHook
import net.corda.nodeapi.internal.config.User import net.corda.nodeapi.internal.config.User
import net.corda.nodeapi.internal.config.parseAs import net.corda.nodeapi.internal.config.parseAs
@ -46,6 +46,8 @@ import net.corda.nodeapi.internal.network.NotaryInfo
import net.corda.testing.ALICE_NAME import net.corda.testing.ALICE_NAME
import net.corda.testing.BOB_NAME import net.corda.testing.BOB_NAME
import net.corda.testing.DUMMY_BANK_A_NAME import net.corda.testing.DUMMY_BANK_A_NAME
import net.corda.nodeapi.internal.crypto.*
import net.corda.nodeapi.internal.network.NetworkParameters
import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.driver.* import net.corda.testing.driver.*
import net.corda.testing.node.ClusterSpec import net.corda.testing.node.ClusterSpec
@ -89,7 +91,8 @@ class DriverDSLImpl(
extraCordappPackagesToScan: List<String>, extraCordappPackagesToScan: List<String>,
val jmxPolicy: JmxPolicy, val jmxPolicy: JmxPolicy,
val notarySpecs: List<NotarySpec>, val notarySpecs: List<NotarySpec>,
val compatibilityZone: CompatibilityZoneParams? val compatibilityZone: CompatibilityZoneParams?,
val onNetworkParametersGeneration: (NetworkParameters) -> Unit
) : InternalDriverDSL { ) : InternalDriverDSL {
private var _executorService: ScheduledExecutorService? = null private var _executorService: ScheduledExecutorService? = null
val executorService get() = _executorService!! val executorService get() = _executorService!!
@ -104,7 +107,8 @@ class DriverDSLImpl(
private val countObservables = mutableMapOf<CordaX500Name, Observable<Int>>() private val countObservables = mutableMapOf<CordaX500Name, Observable<Int>>()
private lateinit var _notaries: List<NotaryHandle> private lateinit var _notaries: List<NotaryHandle>
override val notaryHandles: List<NotaryHandle> get() = _notaries override val notaryHandles: List<NotaryHandle> get() = _notaries
private var networkParameters: NetworkParametersCopier? = null private var networkParametersCopier: NetworkParametersCopier? = null
lateinit var networkParameters: NetworkParameters
class State { class State {
val processes = ArrayList<Process>() val processes = ArrayList<Process>()
@ -179,8 +183,8 @@ class DriverDSLImpl(
val p2pAddress = portAllocation.nextHostAndPort() val p2pAddress = portAllocation.nextHostAndPort()
// TODO: Derive name from the full picked name, don't just wrap the common name // TODO: Derive name from the full picked name, don't just wrap the common name
val name = providedName ?: CordaX500Name(organisation = "${oneOf(names).organisation}-${p2pAddress.port}", locality = "London", country = "GB") val name = providedName ?: CordaX500Name(organisation = "${oneOf(names).organisation}-${p2pAddress.port}", locality = "London", country = "GB")
val isNotary = name in notarySpecs.map { it.name }
val registrationFuture = if (compatibilityZone?.rootCert != null) { val registrationFuture = if (compatibilityZone?.rootCert != null && !isNotary) {
nodeRegistration(name, compatibilityZone.rootCert, compatibilityZone.url) nodeRegistration(name, compatibilityZone.rootCert, compatibilityZone.url)
} else { } else {
doneFuture(Unit) doneFuture(Unit)
@ -279,7 +283,9 @@ class DriverDSLImpl(
notaryInfos += NotaryInfo(identity, type.validating) notaryInfos += NotaryInfo(identity, type.validating)
} }
networkParameters = NetworkParametersCopier(testNetworkParameters(notaryInfos)) networkParameters = testNetworkParameters(notaryInfos)
onNetworkParametersGeneration(networkParameters)
networkParametersCopier = NetworkParametersCopier(networkParameters)
return cordforms.map { return cordforms.map {
val startedNode = startCordformNode(it) val startedNode = startCordformNode(it)
@ -347,8 +353,10 @@ class DriverDSLImpl(
} }
} }
val notaryInfos = generateNotaryIdentities() val notaryInfos = generateNotaryIdentities()
networkParameters = testNetworkParameters(notaryInfos)
onNetworkParametersGeneration(networkParameters)
// The network parameters must be serialised before starting any of the nodes // The network parameters must be serialised before starting any of the nodes
if (compatibilityZone == null) networkParameters = NetworkParametersCopier(testNetworkParameters(notaryInfos)) networkParametersCopier = NetworkParametersCopier(networkParameters)
val nodeHandles = startNotaries() val nodeHandles = startNotaries()
_notaries = notaryInfos.zip(nodeHandles) { (identity, validating), nodes -> NotaryHandle(identity, validating, nodes) } _notaries = notaryInfos.zip(nodeHandles) { (identity, validating), nodes -> NotaryHandle(identity, validating, nodes) }
} }
@ -504,7 +512,11 @@ class DriverDSLImpl(
val configuration = config.parseAsNodeConfiguration() val configuration = config.parseAsNodeConfiguration()
val baseDirectory = configuration.baseDirectory.createDirectories() val baseDirectory = configuration.baseDirectory.createDirectories()
nodeInfoFilesCopier?.addConfig(baseDirectory) nodeInfoFilesCopier?.addConfig(baseDirectory)
networkParameters?.install(baseDirectory) if (configuration.myLegalName in networkParameters.notaries.map { it.identity.name } || compatibilityZone == null) {
// If a notary is being started, then its identity appears in networkParameters (generated by Driver),
// and Driver itself must pass the network parameters to the notary.
networkParametersCopier?.install(baseDirectory)
}
val onNodeExit: () -> Unit = { val onNodeExit: () -> Unit = {
nodeInfoFilesCopier?.removeConfig(baseDirectory) nodeInfoFilesCopier?.removeConfig(baseDirectory)
countObservables.remove(configuration.myLegalName) countObservables.remove(configuration.myLegalName)
@ -817,7 +829,8 @@ fun <DI : DriverDSL, D : InternalDriverDSL, A> genericDriver(
extraCordappPackagesToScan = extraCordappPackagesToScan, extraCordappPackagesToScan = extraCordappPackagesToScan,
jmxPolicy = jmxPolicy, jmxPolicy = jmxPolicy,
notarySpecs = notarySpecs, notarySpecs = notarySpecs,
compatibilityZone = null compatibilityZone = null,
onNetworkParametersGeneration = {}
) )
) )
val shutdownHook = addShutdownHook(driverDsl::shutdown) val shutdownHook = addShutdownHook(driverDsl::shutdown)
@ -855,6 +868,7 @@ fun <A> internalDriver(
extraCordappPackagesToScan: List<String> = DriverParameters().extraCordappPackagesToScan, extraCordappPackagesToScan: List<String> = DriverParameters().extraCordappPackagesToScan,
jmxPolicy: JmxPolicy = DriverParameters().jmxPolicy, jmxPolicy: JmxPolicy = DriverParameters().jmxPolicy,
compatibilityZone: CompatibilityZoneParams? = null, compatibilityZone: CompatibilityZoneParams? = null,
onNetworkParametersGeneration: (NetworkParameters) -> Unit = {},
dsl: DriverDSLImpl.() -> A dsl: DriverDSLImpl.() -> A
): A { ): A {
return genericDriver( return genericDriver(
@ -870,7 +884,8 @@ fun <A> internalDriver(
notarySpecs = notarySpecs, notarySpecs = notarySpecs,
extraCordappPackagesToScan = extraCordappPackagesToScan, extraCordappPackagesToScan = extraCordappPackagesToScan,
jmxPolicy = jmxPolicy, jmxPolicy = jmxPolicy,
compatibilityZone = compatibilityZone compatibilityZone = compatibilityZone,
onNetworkParametersGeneration = onNetworkParametersGeneration
), ),
coerce = { it }, coerce = { it },
dsl = dsl, dsl = dsl,

View File

@ -121,7 +121,8 @@ fun <A> rpcDriver(
extraCordappPackagesToScan = extraCordappPackagesToScan, extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs, notarySpecs = notarySpecs,
jmxPolicy = jmxPolicy, jmxPolicy = jmxPolicy,
compatibilityZone = null compatibilityZone = null,
onNetworkParametersGeneration = {}
), externalTrace ), externalTrace
), ),
coerce = { it }, coerce = { it },

View File

@ -1,9 +1,15 @@
package net.corda.testing.node.internal.network package net.corda.testing.node.internal.network
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignedData
import net.corda.core.crypto.sha256
import net.corda.core.identity.CordaX500Name
import net.corda.core.crypto.* import net.corda.core.crypto.*
import net.corda.core.internal.cert import net.corda.core.internal.cert
import net.corda.core.internal.toX509CertHolder import net.corda.core.internal.toX509CertHolder
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.serialization.SerializedBytes
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
@ -16,7 +22,6 @@ import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.CertificateType import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.testing.ROOT_CA import net.corda.testing.ROOT_CA
import org.bouncycastle.asn1.x500.X500Name
import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.ServerConnector import org.eclipse.jetty.server.ServerConnector
import org.eclipse.jetty.server.handler.HandlerCollection import org.eclipse.jetty.server.handler.HandlerCollection
@ -37,10 +42,10 @@ import javax.ws.rs.core.Response.ok
class NetworkMapServer(cacheTimeout: Duration, class NetworkMapServer(cacheTimeout: Duration,
hostAndPort: NetworkHostAndPort, hostAndPort: NetworkHostAndPort,
root_ca: CertificateAndKeyPair = ROOT_CA, // Default to ROOT_CA for testing. root_ca: CertificateAndKeyPair = ROOT_CA, // Default to ROOT_CA for testing.
private val myHostNameValue: String = "test.host.name",
vararg additionalServices: Any) : Closeable { vararg additionalServices: Any) : Closeable {
companion object { companion object {
val stubNetworkParameter = NetworkParameters(1, emptyList(), 10485760, 40000, Instant.now(), 10) private val stubNetworkParameters = NetworkParameters(1, emptyList(), 10485760, 40000, Instant.now(), 10)
private val serializedParameters = stubNetworkParameter.serialize()
private fun networkMapKeyAndCert(rootCAKeyAndCert: CertificateAndKeyPair): CertificateAndKeyPair { private fun networkMapKeyAndCert(rootCAKeyAndCert: CertificateAndKeyPair): CertificateAndKeyPair {
val networkMapKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val networkMapKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
@ -48,15 +53,25 @@ class NetworkMapServer(cacheTimeout: Duration,
CertificateType.INTERMEDIATE_CA, CertificateType.INTERMEDIATE_CA,
rootCAKeyAndCert.certificate, rootCAKeyAndCert.certificate,
rootCAKeyAndCert.keyPair, rootCAKeyAndCert.keyPair,
X500Name("CN=Corda Network Map,L=London"), CordaX500Name("Corda Network Map", "R3 Ltd", "London","GB"),
networkMapKey.public).cert networkMapKey.public).cert
// Check that the certificate validates. Nodes will perform this check upon receiving a network map,
// it's better to fail here than there.
X509Utilities.validateCertificateChain(rootCAKeyAndCert.certificate.cert, networkMapCert)
return CertificateAndKeyPair(networkMapCert.toX509CertHolder(), networkMapKey) return CertificateAndKeyPair(networkMapCert.toX509CertHolder(), networkMapKey)
} }
} }
private val server: Server private val server: Server
var networkParameters: NetworkParameters = stubNetworkParameters
set(networkParameters) {
check(field == stubNetworkParameters) { "Network parameters can be set only once" }
field = networkParameters
}
private val serializedParameters get() = networkParameters.serialize()
private val service = InMemoryNetworkMapService(cacheTimeout, networkMapKeyAndCert(root_ca)) private val service = InMemoryNetworkMapService(cacheTimeout, networkMapKeyAndCert(root_ca))
init { init {
server = Server(InetSocketAddress(hostAndPort.host, hostAndPort.port)).apply { server = Server(InetSocketAddress(hostAndPort.host, hostAndPort.port)).apply {
handler = HandlerCollection().apply { handler = HandlerCollection().apply {
@ -95,13 +110,13 @@ class NetworkMapServer(cacheTimeout: Duration,
} }
@Path("network-map") @Path("network-map")
class InMemoryNetworkMapService(private val cacheTimeout: Duration, private val networkMapKeyAndCert: CertificateAndKeyPair) { inner class InMemoryNetworkMapService(private val cacheTimeout: Duration,
private val networkMapKeyAndCert: CertificateAndKeyPair) {
private val nodeInfoMap = mutableMapOf<SecureHash, SignedNodeInfo>() private val nodeInfoMap = mutableMapOf<SecureHash, SignedNodeInfo>()
private val parametersHash = serializedParameters.hash private val parametersHash by lazy { serializedParameters.hash }
private val signedParameters = SignedData( private val signedParameters by lazy { SignedData(
serializedParameters, serializedParameters,
DigitalSignature.WithKey(networkMapKeyAndCert.keyPair.public, Crypto.doSign(networkMapKeyAndCert.keyPair.private, serializedParameters.bytes)) DigitalSignature.WithKey(networkMapKeyAndCert.keyPair.public, Crypto.doSign(networkMapKeyAndCert.keyPair.private, serializedParameters.bytes))) }
)
@POST @POST
@Path("publish") @Path("publish")
@ -151,7 +166,7 @@ class NetworkMapServer(cacheTimeout: Duration,
@GET @GET
@Path("my-hostname") @Path("my-hostname")
fun getHostName(): Response { fun getHostName(): Response {
return Response.ok("test.host.name").build() return Response.ok(myHostNameValue).build()
} }
} }
} }

View File

@ -76,7 +76,8 @@ fun <A> verifierDriver(
extraCordappPackagesToScan = extraCordappPackagesToScan, extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs, notarySpecs = notarySpecs,
jmxPolicy = jmxPolicy, jmxPolicy = jmxPolicy,
compatibilityZone = null compatibilityZone = null,
onNetworkParametersGeneration = { }
) )
), ),
coerce = { it }, coerce = { it },