This repository has been archived by the owner on May 15, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 150
/
ExampleFlow.kt
117 lines (104 loc) · 5.19 KB
/
ExampleFlow.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package com.example.flow
import co.paralleluniverse.fibers.Suspendable
import com.example.contract.IOUContract
import com.example.flow.ExampleFlow.Acceptor
import com.example.flow.ExampleFlow.Initiator
import com.example.state.IOUState
import net.corda.core.contracts.Command
import net.corda.core.contracts.requireThat
import net.corda.core.flows.*
import net.corda.core.identity.Party
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.ProgressTracker.Step
/**
* This flow allows two parties (the [Initiator] and the [Acceptor]) to come to an agreement about the IOU encapsulated
* within an [IOUState].
*
* In our simple example, the [Acceptor] always accepts a valid IOU.
*
* These flows have deliberately been implemented by using only the call() method for ease of understanding. In
* practice we would recommend splitting up the various stages of the flow into sub-routines.
*
* All methods called within the [FlowLogic] sub-class need to be annotated with the @Suspendable annotation.
*/
object ExampleFlow {
@InitiatingFlow
@StartableByRPC
class Initiator(val iouValue: Int,
val otherParty: Party) : FlowLogic<SignedTransaction>() {
/**
* The progress tracker checkpoints each stage of the flow and outputs the specified messages when each
* checkpoint is reached in the code. See the 'progressTracker.currentStep' expressions within the call() function.
*/
companion object {
object GENERATING_TRANSACTION : Step("Generating transaction based on new IOU.")
object VERIFYING_TRANSACTION : Step("Verifying contract constraints.")
object SIGNING_TRANSACTION : Step("Signing transaction with our private key.")
object GATHERING_SIGS : Step("Gathering the counterparty's signature.") {
override fun childProgressTracker() = CollectSignaturesFlow.tracker()
}
object FINALISING_TRANSACTION : Step("Obtaining notary signature and recording transaction.") {
override fun childProgressTracker() = FinalityFlow.tracker()
}
fun tracker() = ProgressTracker(
GENERATING_TRANSACTION,
VERIFYING_TRANSACTION,
SIGNING_TRANSACTION,
GATHERING_SIGS,
FINALISING_TRANSACTION
)
}
override val progressTracker = tracker()
/**
* The flow logic is encapsulated within the call() method.
*/
@Suspendable
override fun call(): SignedTransaction {
// Obtain a reference to the notary we want to use.
val notary = serviceHub.networkMapCache.notaryIdentities[0]
// Stage 1.
progressTracker.currentStep = GENERATING_TRANSACTION
// Generate an unsigned transaction.
val iouState = IOUState(iouValue, serviceHub.myInfo.legalIdentities.first(), otherParty)
val txCommand = Command(IOUContract.Commands.Create(), iouState.participants.map { it.owningKey })
val txBuilder = TransactionBuilder(notary)
.addOutputState(iouState, IOUContract.ID)
.addCommand(txCommand)
// Stage 2.
progressTracker.currentStep = VERIFYING_TRANSACTION
// Verify that the transaction is valid.
txBuilder.verify(serviceHub)
// Stage 3.
progressTracker.currentStep = SIGNING_TRANSACTION
// Sign the transaction.
val partSignedTx = serviceHub.signInitialTransaction(txBuilder)
// Stage 4.
progressTracker.currentStep = GATHERING_SIGS
// Send the state to the counterparty, and receive it back with their signature.
val otherPartySession = initiateFlow(otherParty)
val fullySignedTx = subFlow(CollectSignaturesFlow(partSignedTx, setOf(otherPartySession), GATHERING_SIGS.childProgressTracker()))
// Stage 5.
progressTracker.currentStep = FINALISING_TRANSACTION
// Notarise and record the transaction in both parties' vaults.
return subFlow(FinalityFlow(fullySignedTx, setOf(otherPartySession), FINALISING_TRANSACTION.childProgressTracker()))
}
}
@InitiatedBy(Initiator::class)
class Acceptor(val otherPartySession: FlowSession) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
val signTransactionFlow = object : SignTransactionFlow(otherPartySession) {
override fun checkTransaction(stx: SignedTransaction) = requireThat {
val output = stx.tx.outputs.single().data
"This must be an IOU transaction." using (output is IOUState)
val iou = output as IOUState
"I won't accept IOUs with a value over 100." using (iou.value <= 100)
}
}
val txId = subFlow(signTransactionFlow).id
return subFlow(ReceiveFinalityFlow(otherPartySession, expectedTxId = txId))
}
}
}