mirror of
https://github.com/corda/corda.git
synced 2024-12-23 14:52:29 +00:00
Cleanup of FinalityFlow
This commit is contained in:
parent
64963d587c
commit
9d76c66e5e
@ -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?)
|
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user