Extract identity helpers (#1636)

* First compiling version.  internal package accessed from finance and irsdemo

* Renaming
This commit is contained in:
Rick Parker 2017-09-25 17:49:34 +01:00 committed by josecoll
parent 7cc23f007d
commit 175e53d3d2
8 changed files with 96 additions and 78 deletions

View File

@ -7,6 +7,8 @@ import net.corda.core.contracts.StateRef
import net.corda.core.crypto.TransactionSignature import net.corda.core.crypto.TransactionSignature
import net.corda.core.crypto.isFulfilledBy import net.corda.core.crypto.isFulfilledBy
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.excludeHostNode
import net.corda.core.identity.groupAbstractPartyByWellKnownParty
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
@ -90,7 +92,7 @@ abstract class AbstractStateReplacementFlow {
* Initiate sessions with parties we want signatures from. * Initiate sessions with parties we want signatures from.
*/ */
open fun getParticipantSessions(): List<Pair<FlowSession, List<AbstractParty>>> { open fun getParticipantSessions(): List<Pair<FlowSession, List<AbstractParty>>> {
return serviceHub.excludeMe(serviceHub.groupAbstractPartyByWellKnownParty(originalState.state.data.participants)).map { initiateFlow(it.key) to it.value } return excludeHostNode(serviceHub, groupAbstractPartyByWellKnownParty(serviceHub, originalState.state.data.participants)).map { initiateFlow(it.key) to it.value }
} }
@Suspendable @Suspendable

View File

@ -4,6 +4,7 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.crypto.TransactionSignature import net.corda.core.crypto.TransactionSignature
import net.corda.core.crypto.isFulfilledBy import net.corda.core.crypto.isFulfilledBy
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.groupPublicKeysByWellKnownParty
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
@ -102,7 +103,7 @@ class CollectSignaturesFlow @JvmOverloads constructor (val partiallySignedTx: Si
// If the unsigned counter-parties list is empty then we don't need to collect any more signatures here. // If the unsigned counter-parties list is empty then we don't need to collect any more signatures here.
if (unsigned.isEmpty()) return partiallySignedTx if (unsigned.isEmpty()) return partiallySignedTx
val partyToKeysMap = serviceHub.groupPublicKeysByWellKnownParty(unsigned) val partyToKeysMap = groupPublicKeysByWellKnownParty(serviceHub, unsigned)
// Check that we have a session for all parties. No more, no less. // Check that we have a session for all parties. No more, no less.
require(sessionsToCollectFrom.map { it.counterparty }.toSet() == partyToKeysMap.keys) { require(sessionsToCollectFrom.map { it.counterparty }.toSet() == partyToKeysMap.keys) {
"The Initiator of CollectSignaturesFlow must pass in exactly the sessions required to sign the transaction." "The Initiator of CollectSignaturesFlow must pass in exactly the sessions required to sign the transaction."
@ -241,7 +242,7 @@ abstract class SignTransactionFlow(val otherSideSession: FlowSession,
} }
@Suspendable private fun checkSignatures(stx: SignedTransaction) { @Suspendable private fun checkSignatures(stx: SignedTransaction) {
val signingWellKnownIdentities = serviceHub.groupPublicKeysByWellKnownParty(stx.sigs.map(TransactionSignature::by)) val signingWellKnownIdentities = groupPublicKeysByWellKnownParty(serviceHub, stx.sigs.map(TransactionSignature::by))
require(otherSideSession.counterparty in signingWellKnownIdentities) { require(otherSideSession.counterparty in signingWellKnownIdentities) {
"The Initiator of CollectSignaturesFlow must have signed the transaction. Found ${signingWellKnownIdentities}, expected ${otherSideSession}" "The Initiator of CollectSignaturesFlow must have signed the transaction. Found ${signingWellKnownIdentities}, expected ${otherSideSession}"
} }

View File

@ -3,6 +3,7 @@ package net.corda.core.flows
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.core.crypto.isFulfilledBy import net.corda.core.crypto.isFulfilledBy
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.groupAbstractPartyByWellKnownParty
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
@ -92,7 +93,7 @@ class FinalityFlow(val transaction: SignedTransaction,
private fun getPartiesToSend(ltx: LedgerTransaction): Set<Party> { private fun getPartiesToSend(ltx: LedgerTransaction): Set<Party> {
val participants = ltx.outputStates.flatMap { it.participants } + ltx.inputStates.flatMap { it.participants } val participants = ltx.outputStates.flatMap { it.participants } + ltx.inputStates.flatMap { it.participants }
return serviceHub.groupAbstractPartyByWellKnownParty(participants).keys + extraRecipients return groupAbstractPartyByWellKnownParty(serviceHub, participants).keys + extraRecipients
} }
private fun verifyTx(): LedgerTransaction { private fun verifyTx(): LedgerTransaction {

View File

@ -0,0 +1,79 @@
@file:JvmName("IdentityUtils")
package net.corda.core.identity
import net.corda.core.internal.toMultiMap
import net.corda.core.node.ServiceHub
import net.corda.core.transactions.SignedTransaction
import java.security.PublicKey
/**
* Group each [PublicKey] by the well known party using the [ServiceHub.identityService], in preparation for
* creating [FlowSession]s, for example.
*
* @param publicKeys the [PublicKey]s to group.
* @param ignoreUnrecognisedParties if this is false, throw an exception if some of the [PublicKey]s cannot be mapped
* to a [Party].
* @return a map of well known [Party] to associated [PublicKey]s.
*/
@Throws(IllegalArgumentException::class)
fun groupPublicKeysByWellKnownParty(serviceHub: ServiceHub, publicKeys: Collection<PublicKey>, ignoreUnrecognisedParties: Boolean): Map<Party, List<PublicKey>> =
groupAbstractPartyByWellKnownParty(serviceHub, publicKeys.map { AnonymousParty(it) }, ignoreUnrecognisedParties).mapValues { it.value.map { it.owningKey } }
/**
* Group each [PublicKey] by the well known party using the [ServiceHub.identityService], in preparation for
* creating [FlowSession]s, for example. Throw an exception if some of the [PublicKey]s cannot be mapped
* to a [Party].
*
* @param publicKeys the [PublicKey]s to group.
* @return a map of well known [Party] to associated [PublicKey]s.
*/
// Cannot use @JvmOverloads in interface
@Throws(IllegalArgumentException::class)
fun groupPublicKeysByWellKnownParty(serviceHub: ServiceHub, publicKeys: Collection<PublicKey>): Map<Party, List<PublicKey>> = groupPublicKeysByWellKnownParty(serviceHub, publicKeys, false)
/**
* Group each [AbstractParty] by the well known party using the [ServiceHub.identityService], in preparation for
* creating [FlowSession]s, for example.
*
* @param parties the [AbstractParty]s to group.
* @param ignoreUnrecognisedParties if this is false, throw an exception if some of the [AbstractParty]s cannot be mapped
* to a [Party].
* @return a map of well known [Party] to associated [AbstractParty]s.
*/
@Throws(IllegalArgumentException::class)
fun groupAbstractPartyByWellKnownParty(serviceHub: ServiceHub, parties: Collection<AbstractParty>, ignoreUnrecognisedParties: Boolean): Map<Party, List<AbstractParty>> {
val partyToPublicKey: Iterable<Pair<Party, AbstractParty>> = parties.mapNotNull {
(serviceHub.identityService.wellKnownPartyFromAnonymous(it) ?: if (ignoreUnrecognisedParties) return@mapNotNull null else throw IllegalArgumentException("Could not find Party for $it")) to it
}
return partyToPublicKey.toMultiMap()
}
/**
* Group each [AbstractParty] by the well known party using the [ServiceHub.identityService], in preparation for
* creating [FlowSession]s, for example. Throw an exception if some of the [AbstractParty]s cannot be mapped
* to a [Party].
*
* @param parties the [AbstractParty]s to group.
* @return a map of well known [Party] to associated [AbstractParty]s.
*/
// Cannot use @JvmOverloads in interface
@Throws(IllegalArgumentException::class)
fun groupAbstractPartyByWellKnownParty(serviceHub: ServiceHub, parties: Collection<AbstractParty>): Map<Party, List<AbstractParty>> {
return groupAbstractPartyByWellKnownParty(serviceHub, parties, false)
}
/**
* Remove this node from a map of well known [Party]s.
*
* @return a new copy of the map, with he well known [Party] for this node removed.
*/
fun <T> excludeHostNode(serviceHub: ServiceHub, map: Map<Party, T>): Map<Party, T> = map.filterKeys { !serviceHub.myInfo.isLegalIdentity(it) }
/**
* Remove the [Party] associated with the notary of a [SignedTransaction] from the a map of [Party]s. It is a no-op
* if the notary is null.
*
* @return a new copy of the map, with the well known [Party] for the notary removed.
*/
fun <T> excludeNotary(map: Map<Party, T>, stx: SignedTransaction): Map<Party, T> = map.filterKeys { it != stx.notary }

View File

@ -275,75 +275,4 @@ interface ServiceHub : ServicesForResolution {
* @return A new [Connection] * @return A new [Connection]
*/ */
fun jdbcSession(): Connection fun jdbcSession(): Connection
/**
* Group each [PublicKey] by the well known party using the [ServiceHub.identityService], in preparation for
* creating [FlowSession]s, for example.
*
* @param publicKeys the [PublicKey]s to group.
* @param ignoreUnrecognisedParties if this is false, throw an exception if some of the [PublicKey]s cannot be mapped
* to a [Party].
* @return a map of well known [Party] to associated [PublicKey]s.
*/
@Throws(IllegalArgumentException::class)
fun groupPublicKeysByWellKnownParty(publicKeys: Collection<PublicKey>, ignoreUnrecognisedParties: Boolean): Map<Party, List<PublicKey>> =
groupAbstractPartyByWellKnownParty(publicKeys.map { AnonymousParty(it) }, ignoreUnrecognisedParties).mapValues { it.value.map { it.owningKey } }
/**
* Group each [PublicKey] by the well known party using the [ServiceHub.identityService], in preparation for
* creating [FlowSession]s, for example. Throw an exception if some of the [PublicKey]s cannot be mapped
* to a [Party].
*
* @param publicKeys the [PublicKey]s to group.
* @return a map of well known [Party] to associated [PublicKey]s.
*/
// Cannot use @JvmOverloads in interface
@Throws(IllegalArgumentException::class)
fun groupPublicKeysByWellKnownParty(publicKeys: Collection<PublicKey>): Map<Party, List<PublicKey>> = groupPublicKeysByWellKnownParty(publicKeys, false)
/**
* Group each [AbstractParty] by the well known party using the [ServiceHub.identityService], in preparation for
* creating [FlowSession]s, for example.
*
* @param parties the [AbstractParty]s to group.
* @param ignoreUnrecognisedParties if this is false, throw an exception if some of the [AbstractParty]s cannot be mapped
* to a [Party].
* @return a map of well known [Party] to associated [AbstractParty]s.
*/
@Throws(IllegalArgumentException::class)
fun groupAbstractPartyByWellKnownParty(parties: Collection<AbstractParty>, ignoreUnrecognisedParties: Boolean): Map<Party, List<AbstractParty>> {
val partyToPublicKey: Iterable<Pair<Party, AbstractParty>> = parties.mapNotNull {
(identityService.wellKnownPartyFromAnonymous(it) ?: if (ignoreUnrecognisedParties) return@mapNotNull null else throw IllegalArgumentException("Could not find Party for $it")) to it
}
return partyToPublicKey.toMultiMap()
}
/**
* Group each [AbstractParty] by the well known party using the [ServiceHub.identityService], in preparation for
* creating [FlowSession]s, for example. Throw an exception if some of the [AbstractParty]s cannot be mapped
* to a [Party].
*
* @param parties the [AbstractParty]s to group.
* @return a map of well known [Party] to associated [AbstractParty]s.
*/
// Cannot use @JvmOverloads in interface
@Throws(IllegalArgumentException::class)
fun groupAbstractPartyByWellKnownParty(parties: Collection<AbstractParty>): Map<Party, List<AbstractParty>> {
return groupAbstractPartyByWellKnownParty(parties, false)
}
/**
* Remove this node from a map of well known [Party]s.
*
* @return a new copy of the map, with he well known [Party] for this node removed.
*/
fun <T> excludeMe(map: Map<Party, T>): Map<Party, T> = map.filterKeys { !myInfo.isLegalIdentity(it) }
/**
* Remove the [Party] associated with the notary of a [SignedTransaction] from the a map of [Party]s. It is a no-op
* if the notary is null.
*
* @return a new copy of the map, with the well known [Party] for the notary removed.
*/
fun <T> excludeNotary(map: Map<Party, T>, stx: SignedTransaction): Map<Party, T> = map.filterKeys { it != stx.notary }
} }

View File

@ -5,6 +5,8 @@ import net.corda.core.contracts.Command
import net.corda.core.contracts.StateAndContract import net.corda.core.contracts.StateAndContract
import net.corda.core.contracts.requireThat import net.corda.core.contracts.requireThat
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.excludeHostNode
import net.corda.core.identity.groupAbstractPartyByWellKnownParty
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
@ -114,7 +116,7 @@ class CollectSignaturesFlowTests {
val command = Command(DummyContract.Commands.Create(), myInputKeys) val command = Command(DummyContract.Commands.Create(), myInputKeys)
val builder = TransactionBuilder(notary).withItems(StateAndContract(state, DUMMY_PROGRAM_ID), command) val builder = TransactionBuilder(notary).withItems(StateAndContract(state, DUMMY_PROGRAM_ID), command)
val ptx = serviceHub.signInitialTransaction(builder) val ptx = serviceHub.signInitialTransaction(builder)
val sessions = serviceHub.excludeMe(serviceHub.groupAbstractPartyByWellKnownParty(state.owners)).map { initiateFlow(it.key) } val sessions = excludeHostNode(serviceHub, groupAbstractPartyByWellKnownParty(serviceHub, state.owners)).map { initiateFlow(it.key) }
val stx = subFlow(CollectSignaturesFlow(ptx, sessions, myInputKeys)) val stx = subFlow(CollectSignaturesFlow(ptx, sessions, myInputKeys))
return subFlow(FinalityFlow(stx)) return subFlow(FinalityFlow(stx))
} }

View File

@ -7,6 +7,8 @@ import net.corda.core.crypto.TransactionSignature
import net.corda.core.flows.* import net.corda.core.flows.*
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.excludeNotary
import net.corda.core.identity.groupPublicKeysByWellKnownParty
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
@ -112,7 +114,7 @@ object TwoPartyDealFlow {
// DOCSTART 1 // DOCSTART 1
// Get signatures of other signers // Get signatures of other signers
val sessionsForOtherSigners = serviceHub.excludeNotary(serviceHub.groupPublicKeysByWellKnownParty(ptxSignedByOtherSide.getMissingSigners()), ptxSignedByOtherSide).map { initiateFlow(it.key) } val sessionsForOtherSigners = excludeNotary(groupPublicKeysByWellKnownParty(serviceHub, ptxSignedByOtherSide.getMissingSigners()), ptxSignedByOtherSide).map { initiateFlow(it.key) }
val stx = subFlow(CollectSignaturesFlow(ptxSignedByOtherSide, sessionsForOtherSigners, additionalSigningPubKeys)) val stx = subFlow(CollectSignaturesFlow(ptxSignedByOtherSide, sessionsForOtherSigners, additionalSigningPubKeys))
// DOCEND 1 // DOCEND 1

View File

@ -2,6 +2,8 @@ package net.corda.irs.flows
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.core.flows.* import net.corda.core.flows.*
import net.corda.core.identity.excludeHostNode
import net.corda.core.identity.groupAbstractPartyByWellKnownParty
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
import net.corda.finance.contracts.DealState import net.corda.finance.contracts.DealState
@ -45,7 +47,7 @@ object AutoOfferFlow {
require(serviceHub.networkMapCache.notaryIdentities.isNotEmpty()) { "No notary nodes registered" } require(serviceHub.networkMapCache.notaryIdentities.isNotEmpty()) { "No notary nodes registered" }
val notary = serviceHub.networkMapCache.notaryIdentities.first() // TODO We should pass the notary as a parameter to the flow, not leave it to random choice. val notary = serviceHub.networkMapCache.notaryIdentities.first() // TODO We should pass the notary as a parameter to the flow, not leave it to random choice.
// need to pick which ever party is not us // need to pick which ever party is not us
val otherParty = serviceHub.excludeMe(serviceHub.groupAbstractPartyByWellKnownParty(dealToBeOffered.participants)).keys.single() val otherParty = excludeHostNode(serviceHub, groupAbstractPartyByWellKnownParty(serviceHub, dealToBeOffered.participants)).keys.single()
progressTracker.currentStep = DEALING progressTracker.currentStep = DEALING
val session = initiateFlow(otherParty) val session = initiateFlow(otherParty)
val instigator = Instigator( val instigator = Instigator(