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.
*/
interface IdentityService {
object Type : ServiceType("corda.identity")
fun partyFromKey(key: PublicKey): 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.
*/
interface TimestamperService {
object Type : ServiceType("corda.timestamper")
@Suspendable
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 {
NodeInfo(net.myAddress, storage.myLegalIdentity, findMyLocation())
NodeInfo(net.myAddress, storage.myLegalIdentity, emptySet(), findMyLocation())
}
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
open fun start(): AbstractNode {
require(timestamperAddress == null || timestamperAddress.advertisedServices.contains(ServiceType.Timestamping),
{"Timestamper address must indicate a node that provides timestamping services"})
require(timestamperAddress == null || timestamperAddress.advertisedServices.contains(TimestamperService.Type))
{"Timestamper address must indicate a node that provides timestamping services"}
log.info("Node starting up ...")
storage = initialiseStorageService(dir)
@ -120,7 +120,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
timestamperAddress
} else {
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)
}

View File

@ -12,8 +12,8 @@ import core.messaging.SingleMessageRecipient
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,
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.
*/
interface NetworkMapCache {
object Type : ServiceType("corda.network_map")
val timestampingNodes: List<NodeInfo>
val ratesOracleNodes: List<NodeInfo>
val partyNodes: List<NodeInfo>

View File

@ -25,6 +25,7 @@ import javax.annotation.concurrent.ThreadSafe
* for signing.
*/
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] */
fun parseOneRate(s: String): Pair<FixOf, Fix> {
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!
*/
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
* 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 KeyManagementService {
object Type : ServiceType("corda.key_management")
/** Returns a snapshot of the current pubkey->privkey mapping. */
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.
*/
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.
* 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.
* 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

View File

@ -10,6 +10,7 @@ import core.node.NodeInfo
import core.node.services.DummyTimestampingAuthority
import core.node.services.NodeTimestamperService
import core.node.services.ServiceType
import core.node.services.TimestamperService
import core.utilities.loggerFor
import rx.Observable
import rx.subjects.PublishSubject
@ -151,7 +152,7 @@ class InMemoryMessagingNetwork {
val (handle, builder) = createNode(manuallyPumped)
val node = builder.start().get()
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)
}

View File

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

View File

@ -9,7 +9,9 @@ import core.node.NodeConfiguration
import core.node.NodeConfigurationFromConfig
import core.node.NodeInfo
import core.node.services.ArtemisMessagingService
import core.node.services.NodeInterestRates
import core.node.services.ServiceType
import core.node.services.TimestamperService
import core.testing.MockNetworkMapCache
import core.serialization.deserialize
import core.utilities.BriefLogFormatter
@ -72,7 +74,7 @@ fun main(args: Array<String>) {
null
} else {
try {
nodeInfo(options.valueOf(timestamperNetAddr), options.valueOf(timestamperIdentityFile), setOf(ServiceType.Timestamping))
nodeInfo(options.valueOf(timestamperNetAddr), options.valueOf(timestamperIdentityFile), setOf(TimestamperService.Type))
} catch (e: Exception) {
null
}
@ -83,7 +85,7 @@ fun main(args: Array<String>) {
null
} else {
try {
nodeInfo(options.valueOf(rateOracleNetAddr), options.valueOf(rateOracleIdentityFile), setOf(ServiceType.RatesOracle))
nodeInfo(options.valueOf(rateOracleNetAddr), options.valueOf(rateOracleIdentityFile), setOf(NodeInterestRates.Type))
} catch (e: Exception) {
null
}
@ -128,7 +130,7 @@ fun nodeInfo(hostAndPortString: String, identityFile: String, advertisedServices
val addr = HostAndPort.fromString(hostAndPortString).withDefaultPort(Node.DEFAULT_PORT)
val path = Paths.get(identityFile)
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) {
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

View File

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