Created
May 20, 2018 03:20
-
-
Save ayinot/cb2afe45f8e26db94d4261d9a1321cae to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.flow | |
import co.paralleluniverse.fibers.Suspendable | |
import com.example.contract.LoanContract | |
import com.example.contract.LoanContract.Companion.Loan_CONTRACT_ID | |
import com.example.flow.LoanRequestFlow.Acceptor | |
import com.example.flow.LoanRequestFlow.Initiator | |
import com.example.state.LoanState | |
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 Loan encapsulated | |
* within an [LoanState]. | |
* | |
* In our simple example, the [Acceptor] always accepts a valid Loan Request. | |
* | |
* 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 LoanRequestFlow { | |
@InitiatingFlow | |
@StartableByRPC | |
class Initiator(val loanAmount: Int, | |
val interestRate: Int, | |
val otherParty: List<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 LoanRequest.") | |
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 loanState = LoanState(loanAmount, serviceHub.myInfo.legalIdentities.first(),interestRate, otherParty) | |
val txCommand = Command(LoanContract.Commands.Borrow(), loanState.participants.map { it.owningKey }) | |
val txBuilder = TransactionBuilder(notary) | |
.addOutputState(loanState, Loan_CONTRACT_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. | |
// In Loan request all the other parties should be involved. So we are gathering signature from other two nodes. | |
val otherPartyFlow1 = initiateFlow(otherParty[0]) | |
val otherPartyFlow2 = initiateFlow(otherParty[1]) | |
val fullySignedTx = subFlow(CollectSignaturesFlow(partSignedTx, setOf(otherPartyFlow1,otherPartyFlow2), GATHERING_SIGS.childProgressTracker())) | |
// Stage 5. | |
progressTracker.currentStep = FINALISING_TRANSACTION | |
// Notarise and record the transaction in both parties' vaults. | |
return subFlow(FinalityFlow(fullySignedTx, FINALISING_TRANSACTION.childProgressTracker())) | |
} | |
} | |
@InitiatedBy(Initiator::class) | |
class Acceptor(val otherPartyFlow: FlowSession) : FlowLogic<SignedTransaction>() { | |
@Suspendable | |
override fun call(): SignedTransaction { | |
val signTransactionFlow = object : SignTransactionFlow(otherPartyFlow) { | |
override fun checkTransaction(stx: SignedTransaction) = requireThat { | |
val output = stx.tx.outputs.single().data | |
"This must be an IOU transaction." using (output is LoanState) | |
val iou = output as LoanState | |
} | |
} | |
return subFlow(signTransactionFlow) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment