mirror of
https://github.com/corda/corda.git
synced 2024-12-22 14:22:28 +00:00
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:
parent
ca1db997ab
commit
265948dcee
@ -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?
|
||||||
}
|
}
|
||||||
|
33
core/src/main/kotlin/core/node/services/ServiceType.kt
Normal file
33
core/src/main/kotlin/core/node/services/ServiceType.kt
Normal 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()
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
@ -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() }
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user