Clean up code based on feedback from Mike

* Move advertisedServices parameter in NodeInfo up one in the parameter order
* Change ServiceType away from being an enum
* Tweaked wording around what a NodeInfo is
* Renamed LocationStructures to PhysicalLocationStructures
* Move generator outside of function parameters
This commit is contained in:
Ross Nicoll 2016-04-11 10:01:39 +01:00
parent ca1db997ab
commit 265948dcee
14 changed files with 61 additions and 39 deletions

View File

@ -9,6 +9,7 @@ import java.security.PublicKey
* service would provide. * service would provide.
*/ */
interface IdentityService { interface IdentityService {
object Type : ServiceType("corda.identity")
fun partyFromKey(key: PublicKey): Party? fun partyFromKey(key: PublicKey): Party?
fun partyFromName(name: String): Party? fun partyFromName(name: String): Party?
} }

View File

@ -0,0 +1,33 @@
/*
* Copyright 2016 Distributed Ledger Group LLC. Distributed as Licensed Company IP to DLG Group Members
* pursuant to the August 7, 2015 Advisory Services Agreement and subject to the Company IP License terms
* set forth therein.
*
* All other rights reserved.
*/
package core.node.services
/**
* Identifier for service types a node can expose.
*/
abstract class ServiceType(val id: String) {
init {
// Enforce:
//
// * IDs must start with a lower case letter
// * IDs can only contain alphanumeric, full stop and underscore ASCII characters
require(id.matches(Regex("[a-z][a-zA-Z0-9._]+")))
}
override operator fun equals(other: Any?): Boolean =
if (other is ServiceType) {
id == other.id
} else {
false
}
override fun hashCode(): Int = id.hashCode()
override fun toString(): String = id.toString()
}

View File

@ -15,6 +15,7 @@ import core.serialization.SerializedBytes
* themselves. * themselves.
*/ */
interface TimestamperService { interface TimestamperService {
object Type : ServiceType("corda.timestamper")
@Suspendable @Suspendable
fun timestamp(wtxBytes: SerializedBytes<WireTransaction>): DigitalSignature.LegallyIdentifiable fun timestamp(wtxBytes: SerializedBytes<WireTransaction>): DigitalSignature.LegallyIdentifiable

View File

@ -59,7 +59,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
} }
val info: NodeInfo by lazy { val info: NodeInfo by lazy {
NodeInfo(net.myAddress, storage.myLegalIdentity, findMyLocation()) NodeInfo(net.myAddress, storage.myLegalIdentity, emptySet(), findMyLocation())
} }
protected open fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity] protected open fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity]
@ -91,8 +91,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
lateinit var api: APIServer lateinit var api: APIServer
open fun start(): AbstractNode { open fun start(): AbstractNode {
require(timestamperAddress == null || timestamperAddress.advertisedServices.contains(ServiceType.Timestamping), require(timestamperAddress == null || timestamperAddress.advertisedServices.contains(TimestamperService.Type))
{"Timestamper address must indicate a node that provides timestamping services"}) {"Timestamper address must indicate a node that provides timestamping services"}
log.info("Node starting up ...") log.info("Node starting up ...")
storage = initialiseStorageService(dir) storage = initialiseStorageService(dir)
@ -120,7 +120,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
timestamperAddress timestamperAddress
} else { } else {
inNodeTimestampingService = NodeTimestamperService(net, storage.myLegalIdentity, storage.myLegalIdentityKey, platformClock) inNodeTimestampingService = NodeTimestamperService(net, storage.myLegalIdentity, storage.myLegalIdentityKey, platformClock)
NodeInfo(net.myAddress, storage.myLegalIdentity, advertisedServices = setOf(ServiceType.Timestamping)) NodeInfo(net.myAddress, storage.myLegalIdentity, setOf(TimestamperService.Type))
} }
(services.networkMapCache as MockNetworkMapCache).timestampingNodes.add(tsid) (services.networkMapCache as MockNetworkMapCache).timestampingNodes.add(tsid)
} }

View File

@ -12,8 +12,8 @@ import core.messaging.SingleMessageRecipient
import core.node.services.ServiceType import core.node.services.ServiceType
/** /**
* Info about a network node that acts on behalf of some sort of verified identity. * Info about a network node that acts on behalf of some form of contract party.
*/ */
data class NodeInfo(val address: SingleMessageRecipient, val identity: Party, data class NodeInfo(val address: SingleMessageRecipient, val identity: Party,
val physicalLocation: PhysicalLocation? = null, var advertisedServices: Set<ServiceType> = emptySet(),
var advertisedServices: Set<ServiceType> = emptySet()) val physicalLocation: PhysicalLocation? = null)

View File

@ -17,6 +17,7 @@ import java.util.*
* This interface assumes fast, synchronous access to an in-memory map. * This interface assumes fast, synchronous access to an in-memory map.
*/ */
interface NetworkMapCache { interface NetworkMapCache {
object Type : ServiceType("corda.network_map")
val timestampingNodes: List<NodeInfo> val timestampingNodes: List<NodeInfo>
val ratesOracleNodes: List<NodeInfo> val ratesOracleNodes: List<NodeInfo>
val partyNodes: List<NodeInfo> val partyNodes: List<NodeInfo>

View File

@ -25,6 +25,7 @@ import javax.annotation.concurrent.ThreadSafe
* for signing. * for signing.
*/ */
object NodeInterestRates { object NodeInterestRates {
object Type : ServiceType("corda.interest_rates")
/** Parses a string of the form "LIBOR 16-March-2016 1M = 0.678" into a [FixOf] and [Fix] */ /** Parses a string of the form "LIBOR 16-March-2016 1M = 0.678" into a [FixOf] and [Fix] */
fun parseOneRate(s: String): Pair<FixOf, Fix> { fun parseOneRate(s: String): Pair<FixOf, Fix> {
val (key, value) = s.split('=').map { it.trim() } val (key, value) = s.split('=').map { it.trim() }

View File

@ -1,24 +0,0 @@
/*
* Copyright 2016 Distributed Ledger Group LLC. Distributed as Licensed Company IP to DLG Group Members
* pursuant to the August 7, 2015 Advisory Services Agreement and subject to the Company IP License terms
* set forth therein.
*
* All other rights reserved.
*/
package core.node.services
/**
* Enum for the possible services a node can expose
*/
enum class ServiceType {
Identity,
KeyManagement,
Messaging,
Monitoring,
NetworkMap,
RatesOracle,
Timestamping,
Storage,
Wallet
}

View File

@ -47,6 +47,7 @@ data class Wallet(val states: List<StateAndRef<ContractState>>) {
* consumed by someone else first! * consumed by someone else first!
*/ */
interface WalletService { interface WalletService {
object Type : ServiceType("corda.wallet")
/** /**
* Returns a read-only snapshot of the wallet at the time the call is made. Note that if you consume states or * Returns a read-only snapshot of the wallet at the time the call is made. Note that if you consume states or
* keys in this wallet, you must inform the wallet service so it can update its internal state. * keys in this wallet, you must inform the wallet service so it can update its internal state.
@ -101,6 +102,7 @@ inline fun <reified T : LinearState> WalletService.linearHeadsOfType() = linearH
* interface if/when one is developed. * interface if/when one is developed.
*/ */
interface KeyManagementService { interface KeyManagementService {
object Type : ServiceType("corda.key_management")
/** Returns a snapshot of the current pubkey->privkey mapping. */ /** Returns a snapshot of the current pubkey->privkey mapping. */
val keys: Map<PublicKey, PrivateKey> val keys: Map<PublicKey, PrivateKey>
@ -116,6 +118,7 @@ interface KeyManagementService {
* anything like that, this interface is only big enough to support the prototyping work. * anything like that, this interface is only big enough to support the prototyping work.
*/ */
interface StorageService { interface StorageService {
object Type : ServiceType("corda.storage")
/** /**
* A map of hash->tx where tx has been signature/contract validated and the states are known to be correct. * A map of hash->tx where tx has been signature/contract validated and the states are known to be correct.
* The signatures aren't technically needed after that point, but we keep them around so that we can relay * The signatures aren't technically needed after that point, but we keep them around so that we can relay
@ -172,7 +175,9 @@ interface AttachmentStorage {
* Provides access to various metrics and ways to notify monitoring services of things, for sysadmin purposes. * Provides access to various metrics and ways to notify monitoring services of things, for sysadmin purposes.
* This is not an interface because it is too lightweight to bother mocking out. * This is not an interface because it is too lightweight to bother mocking out.
*/ */
class MonitoringService(val metrics: MetricRegistry) class MonitoringService(val metrics: MetricRegistry) {
object Type : ServiceType("corda.monitoring")
}
/** /**
* A service hub simply vends references to the other services a node has. Some of those services may be missing or * A service hub simply vends references to the other services a node has. Some of those services may be missing or

View File

@ -10,6 +10,7 @@ import core.node.NodeInfo
import core.node.services.DummyTimestampingAuthority import core.node.services.DummyTimestampingAuthority
import core.node.services.NodeTimestamperService import core.node.services.NodeTimestamperService
import core.node.services.ServiceType import core.node.services.ServiceType
import core.node.services.TimestamperService
import core.utilities.loggerFor import core.utilities.loggerFor
import rx.Observable import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
@ -151,7 +152,7 @@ class InMemoryMessagingNetwork {
val (handle, builder) = createNode(manuallyPumped) val (handle, builder) = createNode(manuallyPumped)
val node = builder.start().get() val node = builder.start().get()
NodeTimestamperService(node, DummyTimestampingAuthority.identity, DummyTimestampingAuthority.key) NodeTimestamperService(node, DummyTimestampingAuthority.identity, DummyTimestampingAuthority.key)
timestampingAdvert = NodeInfo(handle, DummyTimestampingAuthority.identity, advertisedServices = setOf(ServiceType.Timestamping)) timestampingAdvert = NodeInfo(handle, DummyTimestampingAuthority.identity, setOf(TimestamperService.Type))
return Pair(timestampingAdvert!!, node) return Pair(timestampingAdvert!!, node)
} }

View File

@ -11,6 +11,7 @@ import core.node.NodeInfo
import core.node.PhysicalLocation import core.node.PhysicalLocation
import core.node.services.FixedIdentityService import core.node.services.FixedIdentityService
import core.node.services.ServiceType import core.node.services.ServiceType
import core.node.services.TimestamperService
import core.utilities.loggerFor import core.utilities.loggerFor
import org.slf4j.Logger import org.slf4j.Logger
import java.nio.file.Files import java.nio.file.Files
@ -131,7 +132,7 @@ class MockNetwork(private val threadPerNode: Boolean = false,
fun createTwoNodes(nodeFactory: Factory = defaultFactory): Pair<MockNode, MockNode> { fun createTwoNodes(nodeFactory: Factory = defaultFactory): Pair<MockNode, MockNode> {
require(nodes.isEmpty()) require(nodes.isEmpty())
return Pair( return Pair(
createNode(null, -1, nodeFactory, setOf(ServiceType.Timestamping)), createNode(null, -1, nodeFactory, setOf(TimestamperService.Type)),
createNode(nodes[0].info, -1, nodeFactory) createNode(nodes[0].info, -1, nodeFactory)
) )
} }

View File

@ -9,7 +9,9 @@ import core.node.NodeConfiguration
import core.node.NodeConfigurationFromConfig import core.node.NodeConfigurationFromConfig
import core.node.NodeInfo import core.node.NodeInfo
import core.node.services.ArtemisMessagingService import core.node.services.ArtemisMessagingService
import core.node.services.NodeInterestRates
import core.node.services.ServiceType import core.node.services.ServiceType
import core.node.services.TimestamperService
import core.testing.MockNetworkMapCache import core.testing.MockNetworkMapCache
import core.serialization.deserialize import core.serialization.deserialize
import core.utilities.BriefLogFormatter import core.utilities.BriefLogFormatter
@ -72,7 +74,7 @@ fun main(args: Array<String>) {
null null
} else { } else {
try { try {
nodeInfo(options.valueOf(timestamperNetAddr), options.valueOf(timestamperIdentityFile), setOf(ServiceType.Timestamping)) nodeInfo(options.valueOf(timestamperNetAddr), options.valueOf(timestamperIdentityFile), setOf(TimestamperService.Type))
} catch (e: Exception) { } catch (e: Exception) {
null null
} }
@ -83,7 +85,7 @@ fun main(args: Array<String>) {
null null
} else { } else {
try { try {
nodeInfo(options.valueOf(rateOracleNetAddr), options.valueOf(rateOracleIdentityFile), setOf(ServiceType.RatesOracle)) nodeInfo(options.valueOf(rateOracleNetAddr), options.valueOf(rateOracleIdentityFile), setOf(NodeInterestRates.Type))
} catch (e: Exception) { } catch (e: Exception) {
null null
} }
@ -128,7 +130,7 @@ fun nodeInfo(hostAndPortString: String, identityFile: String, advertisedServices
val addr = HostAndPort.fromString(hostAndPortString).withDefaultPort(Node.DEFAULT_PORT) val addr = HostAndPort.fromString(hostAndPortString).withDefaultPort(Node.DEFAULT_PORT)
val path = Paths.get(identityFile) val path = Paths.get(identityFile)
val party = Files.readAllBytes(path).deserialize<Party>(includeClassName = true) val party = Files.readAllBytes(path).deserialize<Party>(includeClassName = true)
return NodeInfo(ArtemisMessagingService.makeRecipient(addr), party, advertisedServices = advertisedServices) return NodeInfo(ArtemisMessagingService.makeRecipient(addr), party, advertisedServices)
} catch (e: Exception) { } catch (e: Exception) {
println("Could not find identify file $identityFile. If the file has just been created as part of starting the demo, please restart this node") println("Could not find identify file $identityFile. If the file has just been created as part of starting the demo, please restart this node")
throw e throw e

View File

@ -6,7 +6,7 @@ import core.crypto.sha256
import core.node.NodeConfiguration import core.node.NodeConfiguration
import core.node.NodeInfo import core.node.NodeInfo
import core.node.services.NodeAttachmentService import core.node.services.NodeAttachmentService
import core.node.services.ServiceType import core.node.services.TimestamperService
import core.serialization.OpaqueBytes import core.serialization.OpaqueBytes
import core.testing.MockNetwork import core.testing.MockNetwork
import core.testutils.rootCauseExceptions import core.testutils.rootCauseExceptions
@ -96,7 +96,7 @@ class AttachmentTests {
} }
} }
} }
}, advertisedServices = setOf(ServiceType.Timestamping)) }, advertisedServices = setOf(TimestamperService.Type))
val n1 = network.createNode(n0.info) val n1 = network.createNode(n0.info)
// Insert an attachment into node zero's store directly. // Insert an attachment into node zero's store directly.