A node that is exporting a network map service should not try to register with itself twice (one internally and once over the network).

Minor renamings and cleanups in the network map code.

Throw an exception if a production node isn't configured with any network map service at all.
This commit is contained in:
Mike Hearn 2016-05-11 16:51:12 +02:00 committed by Mike Hearn
parent 883be19978
commit b714a09881
3 changed files with 42 additions and 23 deletions

View File

@ -35,10 +35,10 @@ import java.util.*
* A base node implementation that can be customised either for production (with real implementations that do real * A base node implementation that can be customised either for production (with real implementations that do real
* I/O), or a mock implementation suitable for unit test environments. * I/O), or a mock implementation suitable for unit test environments.
*/ */
// TODO: Where this node is the initial network map service, currently no initialNetworkMapAddress is provided. // TODO: Where this node is the initial network map service, currently no networkMapService is provided.
// In theory the NodeInfo for the node should be passed in, instead, however currently this is constructed by the // In theory the NodeInfo for the node should be passed in, instead, however currently this is constructed by the
// AbstractNode. It should be possible to generate the NodeInfo outside of AbstractNode, so it can be passed in. // AbstractNode. It should be possible to generate the NodeInfo outside of AbstractNode, so it can be passed in.
abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, val initialNetworkMapAddress: NodeInfo?, abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, val networkMapService: NodeInfo?,
val advertisedServices: Set<ServiceType>, val platformClock: Clock) { val advertisedServices: Set<ServiceType>, val platformClock: Clock) {
companion object { companion object {
val PRIVATE_KEY_FILE_NAME = "identity-private-key" val PRIVATE_KEY_FILE_NAME = "identity-private-key"
@ -91,6 +91,10 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
lateinit var net: MessagingService lateinit var net: MessagingService
lateinit var api: APIServer lateinit var api: APIServer
/** Completes once the node has successfully registered with the network map service. Null until [start] returns. */
@Volatile var networkMapRegistrationFuture: ListenableFuture<Unit>? = null
private set
open fun start(): AbstractNode { open fun start(): AbstractNode {
log.info("Node starting up ...") log.info("Node starting up ...")
@ -113,29 +117,36 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
DataVendingService(net, storage) DataVendingService(net, storage)
startMessagingService() startMessagingService()
networkMapRegistrationFuture = registerWithNetworkMap()
require(initialNetworkMapAddress == null || NetworkMapService.Type in initialNetworkMapAddress.advertisedServices)
{ "Initial network map address must indicate a node that provides a network map service" }
configureNetworkMapCache()
return this return this
} }
/** /**
* Register this node with the network map cache, and load network map from a remote service (and register for * Register this node with the network map cache, and load network map from a remote service (and register for
* updates) if one has been supplied. * updates) if one has been supplied.
*/ */
private fun configureNetworkMapCache() { private fun registerWithNetworkMap(): ListenableFuture<Unit> {
require(networkMapService == null || NetworkMapService.Type in networkMapService.advertisedServices) {
"Initial network map address must indicate a node that provides a network map service"
}
services.networkMapCache.addNode(info) services.networkMapCache.addNode(info)
if (initialNetworkMapAddress != null) { if (networkMapService != null && networkMapService != info) {
// TODO: Return a future so the caller knows these operations may not have completed yet, and can monitor // Only register if we are pointed at a network map service and it's not us.
// if needed // TODO: Return a future so the caller knows these operations may not have completed yet, and can monitor if needed
updateRegistration(initialNetworkMapAddress, AddOrRemove.ADD) updateRegistration(networkMapService, AddOrRemove.ADD)
services.networkMapCache.addMapService(net, initialNetworkMapAddress, true, null) return services.networkMapCache.addMapService(net, networkMapService, true, null)
}
if (inNodeNetworkMapService != null) {
// Register for updates
services.networkMapCache.addMapService(net, info, true, null)
} }
// In the unit test environment, we may run without any network map service sometimes.
if (inNodeNetworkMapService == null)
return noNetworkMapConfigured()
// Register for updates, even if we're the one running the network map.
return services.networkMapCache.addMapService(net, info, true, null)
}
/** This is overriden by the mock node implementation to enable operation without any network map service */
protected open fun noNetworkMapConfigured(): ListenableFuture<Unit> {
// TODO: There should be a consistent approach to configuration error exceptions.
throw IllegalStateException("Configuration error: this node isn't being asked to act as the network map, nor " +
"has any other map node been configured.")
} }
private fun updateRegistration(serviceInfo: NodeInfo, type: AddOrRemove): ListenableFuture<NetworkMapService.RegistrationResponse> { private fun updateRegistration(serviceInfo: NodeInfo, type: AddOrRemove): ListenableFuture<NetworkMapService.RegistrationResponse> {
@ -178,8 +189,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
protected open fun makeIdentityService(): IdentityService { protected open fun makeIdentityService(): IdentityService {
val service = InMemoryIdentityService() val service = InMemoryIdentityService()
if (initialNetworkMapAddress != null) if (networkMapService != null)
service.registerIdentity(initialNetworkMapAddress.identity) service.registerIdentity(networkMapService.identity)
service.registerIdentity(storage.myLegalIdentity) service.registerIdentity(storage.myLegalIdentity)
services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.identity) } services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.identity) }

View File

@ -18,13 +18,13 @@ import core.serialization.deserialize
import core.serialization.serialize import core.serialization.serialize
import core.utilities.AddOrRemove import core.utilities.AddOrRemove
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import protocols.* import protocols.AbstractRequestMessage
import java.security.PrivateKey import java.security.PrivateKey
import java.time.Period
import java.time.Instant import java.time.Instant
import java.util.ArrayList import java.time.Period
import java.util.concurrent.atomic.AtomicInteger import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import javax.annotation.concurrent.ThreadSafe import javax.annotation.concurrent.ThreadSafe

View File

@ -1,6 +1,7 @@
package core.testing package core.testing
import com.google.common.jimfs.Jimfs import com.google.common.jimfs.Jimfs
import com.google.common.util.concurrent.Futures
import core.crypto.Party import core.crypto.Party
import core.messaging.MessagingService import core.messaging.MessagingService
import core.messaging.SingleMessageRecipient import core.messaging.SingleMessageRecipient
@ -27,6 +28,10 @@ import java.util.*
* Mock network nodes require manual pumping by default: they will not run asynchronous. This means that * Mock network nodes require manual pumping by default: they will not run asynchronous. This means that
* for message exchanges to take place (and associated handlers to run), you must call the [runNetwork] * for message exchanges to take place (and associated handlers to run), you must call the [runNetwork]
* method. * method.
*
* You can get a printout of every message sent by using code like:
*
* BriefLogFormatter.initVerbose("+messaging")
*/ */
class MockNetwork(private val threadPerNode: Boolean = false, class MockNetwork(private val threadPerNode: Boolean = false,
private val defaultFactory: Factory = MockNetwork.DefaultFactory) { private val defaultFactory: Factory = MockNetwork.DefaultFactory) {
@ -82,6 +87,9 @@ class MockNetwork(private val threadPerNode: Boolean = false,
override fun generateKeyPair(): KeyPair? = keyPair ?: super.generateKeyPair() override fun generateKeyPair(): KeyPair? = keyPair ?: super.generateKeyPair()
// It's OK to not have a network map service in the mock network.
override fun noNetworkMapConfigured() = Futures.immediateFuture(Unit)
// There is no need to slow down the unit tests by initialising CityDatabase // There is no need to slow down the unit tests by initialising CityDatabase
override fun findMyLocation(): PhysicalLocation? = null override fun findMyLocation(): PhysicalLocation? = null