Cleanup of FinalityFlow

This commit is contained in:
Shams Asari 2017-09-11 18:48:36 +01:00
parent 64963d587c
commit 9d76c66e5e
2 changed files with 22 additions and 40 deletions

View File

@ -6,12 +6,12 @@ import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TransactionState import net.corda.core.contracts.TransactionState
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.crypto.toStringShort
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.ResolveTransactionsFlow import net.corda.core.internal.ResolveTransactionsFlow
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
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.NonEmptySet
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.toNonEmptySet import net.corda.core.utilities.toNonEmptySet
@ -36,9 +36,8 @@ import net.corda.core.utilities.toNonEmptySet
* @param extraRecipients A list of additional participants to inform of the transaction. * @param extraRecipients A list of additional participants to inform of the transaction.
*/ */
open class FinalityFlow(val transactions: Iterable<SignedTransaction>, open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
val extraRecipients: Set<Party>, private val extraRecipients: Set<Party>,
override val progressTracker: ProgressTracker) : FlowLogic<List<SignedTransaction>>() { override val progressTracker: ProgressTracker) : FlowLogic<List<SignedTransaction>>() {
val extraParticipants: Set<Participant> = extraRecipients.map { it -> Participant(it, it) }.toSet()
constructor(transaction: SignedTransaction, extraParticipants: Set<Party>) : this(listOf(transaction), extraParticipants, tracker()) constructor(transaction: SignedTransaction, extraParticipants: Set<Party>) : this(listOf(transaction), extraParticipants, tracker())
constructor(transaction: SignedTransaction) : this(listOf(transaction), emptySet(), tracker()) constructor(transaction: SignedTransaction) : this(listOf(transaction), emptySet(), tracker())
constructor(transaction: SignedTransaction, progressTracker: ProgressTracker) : this(listOf(transaction), emptySet(), progressTracker) constructor(transaction: SignedTransaction, progressTracker: ProgressTracker) : this(listOf(transaction), emptySet(), progressTracker)
@ -54,8 +53,7 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
fun tracker() = ProgressTracker(NOTARISING, BROADCASTING) fun tracker() = ProgressTracker(NOTARISING, BROADCASTING)
} }
open protected val me open protected val ourIdentity: Party get() = serviceHub.myInfo.legalIdentity
get() = serviceHub.myInfo.legalIdentity
@Suspendable @Suspendable
@Throws(NotaryException::class) @Throws(NotaryException::class)
@ -66,13 +64,16 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
// Lookup the resolved transactions and use them to map each signed transaction to the list of participants. // Lookup the resolved transactions and use them to map each signed transaction to the list of participants.
// Then send to the notary if needed, record locally and distribute. // Then send to the notary if needed, record locally and distribute.
progressTracker.currentStep = NOTARISING progressTracker.currentStep = NOTARISING
val notarisedTxns: List<Pair<SignedTransaction, Set<Participant>>> = resolveDependenciesOf(transactions) val notarisedTxns: List<Pair<SignedTransaction, List<Party>>> = resolveDependenciesOf(transactions)
.map { (stx, ltx) -> Pair(notariseAndRecord(stx), lookupParties(ltx)) } .map { (stx, ltx) -> Pair(notariseAndRecord(stx), lookupParties(ltx)) }
// Each transaction has its own set of recipients, but extra recipients get them all. // Each transaction has its own set of recipients, but extra recipients get them all.
progressTracker.currentStep = BROADCASTING progressTracker.currentStep = BROADCASTING
for ((stx, parties) in notarisedTxns) { for ((stx, parties) in notarisedTxns) {
broadcastTransaction(stx, (parties + extraParticipants).filter { it.wellKnown != me }) val participants = (parties + extraRecipients).filter { it != ourIdentity }.toSet()
if (participants.isNotEmpty()) {
broadcastTransaction(stx, participants.toNonEmptySet())
}
} }
return notarisedTxns.map { it.first } return notarisedTxns.map { it.first }
} }
@ -80,17 +81,13 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
/** /**
* Broadcast a transaction to the participants. By default calls [BroadcastTransactionFlow], however can be * Broadcast a transaction to the participants. By default calls [BroadcastTransactionFlow], however can be
* overridden for more complex transaction delivery protocols (for example where not all parties know each other). * overridden for more complex transaction delivery protocols (for example where not all parties know each other).
* This implementation will filter out any participants for whom there is no well known identity.
* *
* @param participants the participants to send the transaction to. This is expected to include extra participants * @param participants the participants to send the transaction to. This is expected to include extra participants
* and exclude the local node. * and exclude the local node.
*/ */
@Suspendable @Suspendable
open protected fun broadcastTransaction(stx: SignedTransaction, participants: Iterable<Participant>) { open protected fun broadcastTransaction(stx: SignedTransaction, participants: NonEmptySet<Party>) {
val wellKnownParticipants = participants.map { it.wellKnown }.filterNotNull() subFlow(BroadcastTransactionFlow(stx, participants))
if (wellKnownParticipants.isNotEmpty()) {
subFlow(BroadcastTransactionFlow(stx, wellKnownParticipants.toNonEmptySet()))
}
} }
@Suspendable @Suspendable
@ -109,7 +106,6 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
val wtx = stx.tx val wtx = stx.tx
val needsNotarisation = wtx.inputs.isNotEmpty() || wtx.timeWindow != null val needsNotarisation = wtx.inputs.isNotEmpty() || wtx.timeWindow != null
return needsNotarisation && hasNoNotarySignature(stx) return needsNotarisation && hasNoNotarySignature(stx)
} }
private fun hasNoNotarySignature(stx: SignedTransaction): Boolean { private fun hasNoNotarySignature(stx: SignedTransaction): Boolean {
@ -121,19 +117,14 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
/** /**
* Resolve the parties involved in a transaction. * Resolve the parties involved in a transaction.
* *
* @return the set of participants and their resolved well known identities (where known). * The default implementation throws an exception if an unknown party is encountered.
*/ */
open protected fun lookupParties(ltx: LedgerTransaction): Set<Participant> { open protected fun lookupParties(ltx: LedgerTransaction): List<Party> {
// Calculate who is meant to see the results based on the participants involved. // Calculate who is meant to see the results based on the participants involved.
return extractParticipants(ltx) return extractParticipants(ltx).map {
.map(this::partyFromAnonymous) serviceHub.identityService.partyFromAnonymous(it)
.map { participant -> ?: throw IllegalArgumentException("Could not resolve well known identity of participant $it")
if (participant.wellKnown != null) }
participant
else
throw IllegalArgumentException("Could not resolve well known identity of participant ${participant.participant.owningKey.toStringShort()}")
}
.toSet()
} }
/** /**
@ -144,13 +135,6 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
return ltx.outputStates.flatMap { it.participants } + ltx.inputStates.flatMap { it.participants } return ltx.outputStates.flatMap { it.participants } + ltx.inputStates.flatMap { it.participants }
} }
/**
* Helper function which wraps [IdentityService.partyFromAnonymous] so it can be called as a lambda function.
*/
protected fun partyFromAnonymous(anon: AbstractParty): Participant {
return Participant(anon, serviceHub.identityService.partyFromAnonymous(anon))
}
private fun resolveDependenciesOf(signedTransactions: Iterable<SignedTransaction>): List<Pair<SignedTransaction, LedgerTransaction>> { private fun resolveDependenciesOf(signedTransactions: Iterable<SignedTransaction>): List<Pair<SignedTransaction, LedgerTransaction>> {
// Make sure the dependencies come before the dependers. // Make sure the dependencies come before the dependers.
val sorted = ResolveTransactionsFlow.topologicalSort(signedTransactions.toList()) val sorted = ResolveTransactionsFlow.topologicalSort(signedTransactions.toList())
@ -173,6 +157,4 @@ open class FinalityFlow(val transactions: Iterable<SignedTransaction>,
stx to ltx stx to ltx
} }
} }
data class Participant(val participant: AbstractParty, val wellKnown: Party?)
} }

View File

@ -10,11 +10,11 @@ import net.corda.core.utilities.ProgressTracker
* participating parties must be provided manually. * participating parties must be provided manually.
* *
* @param transactions What to commit. * @param transactions What to commit.
* @param extraRecipients A list of additional participants to inform of the transaction. * @param recipients List of participants to inform of the transaction.
*/ */
class ManualFinalityFlow(transactions: Iterable<SignedTransaction>, class ManualFinalityFlow(transactions: Iterable<SignedTransaction>,
recipients: Set<Party>, recipients: Set<Party>,
progressTracker: ProgressTracker) : FinalityFlow(transactions, recipients, progressTracker) { progressTracker: ProgressTracker) : FinalityFlow(transactions, recipients, progressTracker) {
constructor(transaction: SignedTransaction, extraParticipants: Set<Party>) : this(listOf(transaction), extraParticipants, tracker()) constructor(transaction: SignedTransaction, extraParticipants: Set<Party>) : this(listOf(transaction), extraParticipants, tracker())
override fun lookupParties(ltx: LedgerTransaction): Set<Participant> = emptySet() override fun lookupParties(ltx: LedgerTransaction): List<Party> = emptyList()
} }