Skip to content

Instantly share code, notes, and snippets.

@ayinot
Created May 20, 2018 05:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayinot/74fc7a20b63574f40eba93df047062c4 to your computer and use it in GitHub Desktop.
Save ayinot/74fc7a20b63574f40eba93df047062c4 to your computer and use it in GitHub Desktop.
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