mirror of
https://github.com/corda/corda.git
synced 2024-12-21 22:07:55 +00:00
Extend NetworkMapCache API (#1766)
* Add functions to: ** Return PartyAndCertificate rather than just Party ** Return all NodeInfo entries for a name (rather than just by key) * General documentation improvements
This commit is contained in:
parent
3afe855042
commit
6562579e8e
@ -10,7 +10,11 @@ import java.security.cert.*
|
|||||||
/**
|
/**
|
||||||
* An identity service maintains a directory of parties by their associated distinguished name/public keys and thus
|
* An identity service maintains a directory of parties by their associated distinguished name/public keys and thus
|
||||||
* supports lookup of a party given its key, or name. The service also manages the certificates linking confidential
|
* supports lookup of a party given its key, or name. The service also manages the certificates linking confidential
|
||||||
* identities back to the well known identity (i.e. the identity in the network map) of a party.
|
* identities back to the well known identity.
|
||||||
|
*
|
||||||
|
* Well known identities in Corda are the public identity of a party, registered with the network map directory,
|
||||||
|
* whereas confidential identities are distributed only on a need to know basis (typically between parties in
|
||||||
|
* a transaction being built). See [NetworkMapCache] for retrieving well known identities from the network map.
|
||||||
*/
|
*/
|
||||||
interface IdentityService {
|
interface IdentityService {
|
||||||
val trustRoot: X509Certificate
|
val trustRoot: X509Certificate
|
||||||
@ -43,8 +47,9 @@ interface IdentityService {
|
|||||||
fun getAllIdentities(): Iterable<PartyAndCertificate>
|
fun getAllIdentities(): Iterable<PartyAndCertificate>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the certificate and path for a known identity's owning key.
|
* Resolves a public key to the well known identity [PartyAndCertificate] instance which is owned by the key.
|
||||||
*
|
*
|
||||||
|
* @param owningKey The [PublicKey] to determine well known identity for.
|
||||||
* @return the party and certificate, or null if unknown.
|
* @return the party and certificate, or null if unknown.
|
||||||
*/
|
*/
|
||||||
fun certificateFromKey(owningKey: PublicKey): PartyAndCertificate?
|
fun certificateFromKey(owningKey: PublicKey): PartyAndCertificate?
|
||||||
@ -59,17 +64,18 @@ interface IdentityService {
|
|||||||
fun partyFromKey(key: PublicKey): Party?
|
fun partyFromKey(key: PublicKey): Party?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a party name to the well known identity [Party] instance for this name.
|
* Resolves a party name to the well known identity [Party] instance for this name. Where possible well known identity
|
||||||
* @param name The [CordaX500Name] to search for.
|
* lookup from name should be done from the network map (via [NetworkMapCache]) instead, as it is the authoritative
|
||||||
|
* source of well known identities.
|
||||||
|
*
|
||||||
|
* @param name The [CordaX500Name] to determine well known identity for.
|
||||||
* @return If known the canonical [Party] with that name, else null.
|
* @return If known the canonical [Party] with that name, else null.
|
||||||
*/
|
*/
|
||||||
fun wellKnownPartyFromX500Name(name: CordaX500Name): Party?
|
fun wellKnownPartyFromX500Name(name: CordaX500Name): Party?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the well known identity from an [AbstractParty]. This is intended to resolve the well known identity,
|
* Resolves a (optionally) confidential identity to the corresponding well known identity [Party].
|
||||||
* as visible in the [NetworkMapCache] from a confidential identity.
|
* It transparently handles returning the well known identity back if a well known identity is passed in.
|
||||||
* It transparently handles returning the well known identity back if
|
|
||||||
* a well known identity is passed in.
|
|
||||||
*
|
*
|
||||||
* @param party identity to determine well known identity for.
|
* @param party identity to determine well known identity for.
|
||||||
* @return well known identity, if found.
|
* @return well known identity, if found.
|
||||||
@ -77,11 +83,12 @@ interface IdentityService {
|
|||||||
fun wellKnownPartyFromAnonymous(party: AbstractParty): Party?
|
fun wellKnownPartyFromAnonymous(party: AbstractParty): Party?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the well known identity from a PartyAndReference. This is intended to resolve the well known identity,
|
* Resolves a (optionally) confidential identity to the corresponding well known identity [Party].
|
||||||
* as visible in the [NetworkMapCache] from a confidential identity.
|
* Convenience method which unwraps the [Party] from the [PartyAndReference] and then resolves the
|
||||||
* It transparently handles returning the well known identity back if
|
* well known identity as normal.
|
||||||
* a well known identity is passed in.
|
* It transparently handles returning the well known identity back if a well known identity is passed in.
|
||||||
*
|
*
|
||||||
|
* @param partyRef identity (and reference, which is unused) to determine well known identity for.
|
||||||
* @return the well known identity, or null if unknown.
|
* @return the well known identity, or null if unknown.
|
||||||
*/
|
*/
|
||||||
fun wellKnownPartyFromAnonymous(partyRef: PartyAndReference) = wellKnownPartyFromAnonymous(partyRef.party)
|
fun wellKnownPartyFromAnonymous(partyRef: PartyAndReference) = wellKnownPartyFromAnonymous(partyRef.party)
|
||||||
|
@ -4,6 +4,7 @@ import net.corda.core.concurrent.CordaFuture
|
|||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.messaging.DataFeed
|
import net.corda.core.messaging.DataFeed
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
@ -72,26 +73,42 @@ interface NetworkMapCache {
|
|||||||
/** Look up the node info for a host and port. */
|
/** Look up the node info for a host and port. */
|
||||||
fun getNodeByAddress(address: NetworkHostAndPort): NodeInfo?
|
fun getNodeByAddress(address: NetworkHostAndPort): NodeInfo?
|
||||||
|
|
||||||
fun getPeerByLegalName(name: CordaX500Name): Party? = getNodeByLegalName(name)?.let {
|
/**
|
||||||
it.legalIdentitiesAndCerts.singleOrNull { it.name == name }?.party
|
* Look up a well known identity (including certificate path) of a legal name. This should be used in preference
|
||||||
}
|
* to well known identity lookup in the identity service where possible, as the network map is the authoritative
|
||||||
|
* source of well known identities.
|
||||||
|
*/
|
||||||
|
fun getPeerCertificateByLegalName(name: CordaX500Name): PartyAndCertificate?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up the well known identity of a legal name. This should be used in preference
|
||||||
|
* to well known identity lookup in the identity service where possible, as the network map is the authoritative
|
||||||
|
* source of well known identities.
|
||||||
|
*/
|
||||||
|
fun getPeerByLegalName(name: CordaX500Name): Party? = getPeerCertificateByLegalName(name)?.party
|
||||||
|
|
||||||
/** Return all [NodeInfo]s the node currently is aware of (including ourselves). */
|
/** Return all [NodeInfo]s the node currently is aware of (including ourselves). */
|
||||||
val allNodes: List<NodeInfo>
|
val allNodes: List<NodeInfo>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up the node infos for a specific peer key.
|
* Look up the node information entries for a specific identity key.
|
||||||
* In general, nodes can advertise multiple identities: a legal identity, and separate identities for each of
|
* Note that normally there will be only one node for a key, but for clusters of nodes or distributed services there
|
||||||
* the services it provides. In case of a distributed service – run by multiple nodes – each participant advertises
|
* can be multiple nodes.
|
||||||
* the identity of the *whole group*.
|
|
||||||
*/
|
*/
|
||||||
fun getNodesByLegalIdentityKey(identityKey: PublicKey): List<NodeInfo>
|
fun getNodesByLegalIdentityKey(identityKey: PublicKey): List<NodeInfo>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up the node information entries for a legal name.
|
||||||
|
* Note that normally there will be only one node for a legal name, but for clusters of nodes or distributed services there
|
||||||
|
* can be multiple nodes.
|
||||||
|
*/
|
||||||
|
fun getNodesByLegalName(name: CordaX500Name): List<NodeInfo>
|
||||||
|
|
||||||
/** Returns information about the party, which may be a specific node or a service */
|
/** Returns information about the party, which may be a specific node or a service */
|
||||||
fun getPartyInfo(party: Party): PartyInfo?
|
fun getPartyInfo(party: Party): PartyInfo?
|
||||||
|
|
||||||
// DOCSTART 2
|
// DOCSTART 2
|
||||||
/** Gets a notary identity by the given name. */
|
/** Look up a well known identity of notary by legal name. */
|
||||||
fun getNotary(name: CordaX500Name): Party? = notaryIdentities.firstOrNull { it.name == name }
|
fun getNotary(name: CordaX500Name): Party? = notaryIdentities.firstOrNull { it.name == name }
|
||||||
// DOCEND 2
|
// DOCEND 2
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import net.corda.core.concurrent.CordaFuture
|
|||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.internal.VisibleForTesting
|
import net.corda.core.internal.VisibleForTesting
|
||||||
import net.corda.core.internal.bufferUntilSubscribed
|
import net.corda.core.internal.bufferUntilSubscribed
|
||||||
import net.corda.core.internal.concurrent.map
|
import net.corda.core.internal.concurrent.map
|
||||||
@ -114,7 +115,8 @@ open class PersistentNetworkMapCache(private val serviceHub: ServiceHubInternal)
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNodeByLegalName(name: CordaX500Name): NodeInfo? = serviceHub.database.transaction { queryByLegalName(name).firstOrNull() }
|
override fun getNodeByLegalName(name: CordaX500Name): NodeInfo? = getNodesByLegalName(name).firstOrNull()
|
||||||
|
override fun getNodesByLegalName(name: CordaX500Name): List<NodeInfo> = serviceHub.database.transaction { queryByLegalName(name) }
|
||||||
override fun getNodesByLegalIdentityKey(identityKey: PublicKey): List<NodeInfo> =
|
override fun getNodesByLegalIdentityKey(identityKey: PublicKey): List<NodeInfo> =
|
||||||
serviceHub.database.transaction { queryByIdentityKey(identityKey) }
|
serviceHub.database.transaction { queryByIdentityKey(identityKey) }
|
||||||
override fun getNodeByLegalIdentity(party: AbstractParty): NodeInfo? {
|
override fun getNodeByLegalIdentity(party: AbstractParty): NodeInfo? {
|
||||||
@ -126,6 +128,8 @@ open class PersistentNetworkMapCache(private val serviceHub: ServiceHubInternal)
|
|||||||
|
|
||||||
override fun getNodeByAddress(address: NetworkHostAndPort): NodeInfo? = serviceHub.database.transaction { queryByAddress(address) }
|
override fun getNodeByAddress(address: NetworkHostAndPort): NodeInfo? = serviceHub.database.transaction { queryByAddress(address) }
|
||||||
|
|
||||||
|
override fun getPeerCertificateByLegalName(name: CordaX500Name): PartyAndCertificate? = serviceHub.database.transaction { queryIdentityByLegalName(name) }
|
||||||
|
|
||||||
override fun track(): DataFeed<List<NodeInfo>, MapChange> {
|
override fun track(): DataFeed<List<NodeInfo>, MapChange> {
|
||||||
synchronized(_changed) {
|
synchronized(_changed) {
|
||||||
return DataFeed(partyNodes, _changed.bufferUntilSubscribed().wrapWithDatabaseTransaction())
|
return DataFeed(partyNodes, _changed.bufferUntilSubscribed().wrapWithDatabaseTransaction())
|
||||||
@ -329,6 +333,19 @@ open class PersistentNetworkMapCache(private val serviceHub: ServiceHubInternal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun queryIdentityByLegalName(name: CordaX500Name): PartyAndCertificate? {
|
||||||
|
createSession {
|
||||||
|
val query = it.createQuery(
|
||||||
|
// We do the JOIN here to restrict results to those present in the network map
|
||||||
|
"SELECT DISTINCT l FROM ${NodeInfoSchemaV1.PersistentNodeInfo::class.java.name} n JOIN n.legalIdentitiesAndCerts l WHERE l.name = :name",
|
||||||
|
NodeInfoSchemaV1.DBPartyAndCertificate::class.java)
|
||||||
|
query.setParameter("name", name.toString())
|
||||||
|
val candidates = query.resultList.map { it.toLegalIdentityAndCert() }
|
||||||
|
// The map is restricted to holding a single identity for any X.500 name, so firstOrNull() is correct here.
|
||||||
|
return candidates.firstOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun queryByLegalName(name: CordaX500Name): List<NodeInfo> {
|
private fun queryByLegalName(name: CordaX500Name): List<NodeInfo> {
|
||||||
createSession {
|
createSession {
|
||||||
val query = it.createQuery(
|
val query = it.createQuery(
|
||||||
|
@ -65,6 +65,18 @@ class NetworkMapCacheTest {
|
|||||||
// TODO: Should have a test case with anonymous lookup
|
// TODO: Should have a test case with anonymous lookup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getPeerByLegalName`() {
|
||||||
|
val notaryNode = mockNet.createNotaryNode()
|
||||||
|
val aliceNode = mockNet.createPartyNode(ALICE.name)
|
||||||
|
val notaryCache: NetworkMapCache = notaryNode.services.networkMapCache
|
||||||
|
val expected = aliceNode.info.legalIdentities.single()
|
||||||
|
|
||||||
|
mockNet.runNetwork()
|
||||||
|
val actual = notaryNode.database.transaction { notaryCache.getPeerByLegalName(ALICE.name) }
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `remove node from cache`() {
|
fun `remove node from cache`() {
|
||||||
val notaryNode = mockNet.createNotaryNode()
|
val notaryNode = mockNet.createNotaryNode()
|
||||||
|
Loading…
Reference in New Issue
Block a user