I’m new to Corda. Is there a direct way to execute a repayment as a subflow on the other side back to the sender of a certain amount of cash, when directly calling the recipient node within the CashPaymentFlow, e.g. something like this:
recipient.run {
subFlow(CashPaymentFlow(amount, sender ,anonymous))
}
(This is not working, it’s just an example). I need a more dynamic solution for using it within the demobench. The recipient node for the initital payment is chosen from the demobench UI. The problem is to automatically call or reference to the other side’s node and ask it to execute a repayment (by using e.g. the cashPaymentFlow), when executing the initial payment from the sender side. I now that I can manually “go” to the receiver node and execute a payment back to the sender via the UI or terminal, but this is not the intention.
You can achieve this by making the repayment part of the same flow as the initial payment, as follows:
#InitiatingFlow
#StartableByRPC
class Payer(val initialAmount: Amount<Currency>, val changeAmount: Amount<Currency>, val recipient: Party) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
subFlow(CashPaymentFlow(initialAmount, recipient))
val sessionWithRecipient = initiateFlow(recipient)
sessionWithRecipient.send(changeAmount)
}
}
#InitiatedBy(Payer::class)
class Recipient(val payerSession: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
val changeAmount = payerSession.receive<Amount<Currency>>().unwrap { it }
subFlow(CashPaymentFlow(changeAmount, payerSession.counterparty))
}
}
I would like to pass another variable along with ‘changeAmount’. Is this possible? I tried doing it this way:
#InitiatingFlow
#StartableByRPC
class Payer(val initialAmount: Amount<Currency>, val changeAmount:Amount<Currency>, val recipient: Party) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
subFlow(CashPaymentFlow(initialAmount, recipient))
val sessionWithRecipient = initiateFlow(recipient)
sessionWithRecipient.send(changeAmount)
sessionWithRecipient.send(delay) //second variable
}
}
#InitiatedBy(Payer::class)
class Recipient(val payerSession: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
val changeAmount = payerSession.receive<Amount<Currency>>().unwrap { it }
val delay = payerSession.receive<Duration>().unwrap { it }
for (i in 1..10) //the 10 automated paybacks
{subFlow(CashPaymentFlow(changeAmount, payerSession.counterparty))
sleep(delay)} //usage of the second variable
}
}
Related
i want to use addIssueTokens to add token to TransactionBuilder.
my code
#InitiatingFlow
#StartableByRPC
class Issue(val otherParty: Party) : FlowLogic<SignedTransaction>() {
override val progressTracker = ProgressTracker()
#Suspendable
override fun call() : SignedTransaction{
val jpyToken = createFungibleToken("JPY", 1000, otherParty)
val gbToken = createFungibleToken("GB", 1000, otherParty)
val notary = serviceHub.networkMapCache.notaryIdentities.single()
val txBuilder = TransactionBuilder(notary)
//may be add other output input
//....
//add token to txBuilder
addIssueTokens(txBuilder, listOf(jpyToken,gbToken))
txBuilder.verify(serviceHub)
// Sign the transaction
val ptx = serviceHub.signInitialTransaction(txBuilder, ourIdentity.owningKey)
// Instantiate a network session with the shareholder
val holderSession = initiateFlow(otherParty)
val sessions = listOf(holderSession)
// Ask the shareholder to sign the transaction
val stx = subFlow(CollectSignaturesFlow(ptx, listOf(holderSession)))
return subFlow<SignedTransaction>(FinalityFlow(stx, sessions))
}
fun createFungibleToken(symbol:String,amout:Long,target : AbstractParty) : FungibleToken{
val tokenType = TokenType(symbol, 0)
val issuedTokenType = IssuedTokenType(ourIdentity, tokenType)
val amount = Amount<IssuedTokenType>(amout, issuedTokenType)
return FungibleToken(amount, target)
}
}
#InitiatedBy(Issue::class)
class IssueResponder(val otherPartySession: FlowSession) : FlowLogic<SignedTransaction>() {
#Suspendable
override fun call(): SignedTransaction {
val signTransactionFlow = object : SignTransactionFlow(otherPartySession) {
override fun checkTransaction(stx: SignedTransaction) = requireThat {
}
}
val txId = subFlow(signTransactionFlow).id
return subFlow(ReceiveFinalityFlow(otherPartySession, expectedTxId = txId))
}
}
shell: start flow
>>start com.template.flows.Issue otherParty: "O=PartyB,L=New York,C=US"
Starting
Collecting signatures from counterparties.
Starting
Broadcasting transaction to participants
Done
Flow completed with result: SignedTransaction(id=547B812BA5574168DA8085C87AADFCAFA2A098CF62F375C21D450C0FE2402547)
it seems that Flow completed. but i check partyB database ,there is no data in vault_states table .
why?
ps.i knew how to use com.r3.corda.lib.tokens.workflows.flows.rpc.IssueTokens flow
The holder is not a required signer when issuing tokens; try removing the CollectSignaturesFlow and SignTransactionFlow calls from the initiator and responder flows; only keep FinalityFlow and ReceiveFinalityFlow.
You can see here that the required signers are:
The issuer on issuing.
The holder on moving.
The issuer and holder on redeeming.
But also the contract says here that there could be other signers on issue; so I'm not 100% sure that's the cause of the problem.
Try removing the signature flows and re-run your test; and let me know if it worked.
Another thing, check the logs of the initiating node (the log is inside logs folder inside your node's folder structure); are there any errors?.
In Corda, the required signers on a transaction can be CompositeKeys instead of regular public keys. How do I create a CompositeKey and make it the required signer on the transaction? And how do I gather the corresponding signatures?
Here is a flow that creates a CompositeKey, makes it the required signer on the transaction, and collects the corresponding signatures:
object OurFlow {
#InitiatingFlow
#StartableByRPC
class Initiator(val otherPartyA: Party, val otherPartyB: Party) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
// We create a composite key that requires signatures from ourselves
// and one of the other parties (each weight is one and the threshold is 2)
val compositeKey = CompositeKey.Builder()
.addKey(ourIdentity.owningKey, weight = 1)
.addKey(otherPartyA.owningKey, weight = 1)
.addKey(otherPartyB.owningKey, weight = 1)
.build(2)
// We make the `CompositeKey` the required signer.
val txBuilder = TransactionBuilder(serviceHub.networkMapCache.notaryIdentities[0])
.addCommand(OurContract.Commands.Create(), compositeKey)
.addOutputState(OurState(ourIdentity, otherPartyA, otherPartyB), OurContract.ID)
val partStx = serviceHub.signInitialTransaction(txBuilder)
// We gather the signatures. Note that we cannot use
// `CollectSignaturesFlow` because:
// * The `CompositeKey` does not correspond to a specific
// counterparty
// * The counterparty may refuse to sign
val sessions = listOf(otherPartyA, otherPartyB).map { initiateFlow(it) }
// We filter out any responses that are not
// `TransactionSignature`s (i.e. refusals to sign).
val signatures = sessions
.map { it.sendAndReceive<Any>(partStx).unwrap { it } }
.filter { it is TransactionSignature }
as List<TransactionSignature>
val fullStx = partStx.withAdditionalSignatures(signatures)
subFlow(FinalityFlow(fullStx))
}
}
#InitiatedBy(Initiator::class)
class Acceptor(val otherPartySession: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
otherPartySession.receive<SignedTransaction>().unwrap { partStx ->
// We return either a `TransactionSignature` (if we're willing
// to sign) or `false`.
val payload = if (CONDITION) {
serviceHub.createSignature(partStx)
} else {
false
}
otherPartySession.send(payload)
}
}
}
}
And here is the contract that asserts that the required signer is a CompositeKey, that it has a threshold of two and three children of weight one corresponding to the parties listed in the transaction's output state:
class OurContract : Contract {
companion object {
#JvmStatic
val ID = "com.example.contract.OurContract"
}
override fun verify(tx: LedgerTransaction) {
requireThat {
val command = tx.commands.requireSingleCommand<Commands.Create>()
"There is only one required signer." using (command.signers.size == 1)
"The required signer is a CompositeKey." using (command.signers[0] is CompositeKey)
val signer = command.signers[0] as CompositeKey
"There are only three nodes and weights." using (signer.children.size == 3)
"The threshold is two." using (signer.threshold == 2)
"There is only one output." using (tx.outputStates.size == 1)
"The output is of type OurState." using (tx.outputsOfType<OurState>().size == 1)
val output = tx.outRefsOfType<OurState>().single().state.data
val expectedNodesAndWeights = listOf(output.partyA, output.partyB, output.partyC).map {
CompositeKey.NodeAndWeight(it.owningKey, 1)
}
"All three parties are children with weight 1." using (signer.children.containsAll(expectedNodesAndWeights))
}
}
interface Commands : CommandData {
class Create : Commands
}
}
And finally, here is our state definition:
class OurState(val partyA: Party, val partyB: Party, val partyC: Party) : ContractState {
override val participants = listOf(partyA, partyB, partyC)
}
imaging we have two classes, the Payer Class and the Receiver Class.
is it possible to pass/ send more than one variable by using the method:
FlowSession.send() ?
When trying e.g. the following
sessionWithRecipient.send(Variable1)
sessionWithRecipient.send(Variable2)
it seems that only the first variable will be send to the recipient class.
At the responder flow, I use the command shown below to receive the variable and unwrap it:
val variable1 = initiatorSession.receive<Int>().unwrap { it }
val variable2 = initiatorSession.receive<Int>().unwrap { it }
Could you please help me with a solution to send and receive multiple variables here? Thanks :)
Instead of sending it twice. Just create a wrapper object with all the desired member variables. Then Whitelist this Wrapper object. This way you'll only have to send it once. I find it cleaner this way.
The following works fine, printing Sum is 3. to the console:
#InitiatingFlow
#StartableByRPC
class Initiator(val counterparty: Party) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
val counterpartySession = initiateFlow(counterparty)
counterpartySession.send(1)
counterpartySession.send(2)
}
}
#InitiatedBy(Initiator::class)
class Responder(val counterpartySession: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
val int1 = counterpartySession.receive<Int>().unwrap { it }
val int2 = counterpartySession.receive<Int>().unwrap { it }
logger.info("Sum is ${int1 + int2}.")
}
}
I have a use case where in one atomic transaction I would like to transition two or more states of same type to different lifecycle. ( i.e. )
val x : SomeState
val y : SomeState
x should transition to Approved with Command.Approve
y should transition to Audited with Command.Audit
How can the contract code run the verifyApprove only on x while running verifyAudit on y.
There can be an infinite numbers of SomeState that can transition to different lifecycles in the same atomic transaction.
Do I have to make Command.Approve have a constructor with a List<UniqueIdentitifer> so it can determine on which states to run its corresponding verify function.
Subsequently populate the command in the flow?
Every verify function verifies a transaction in its entirety, and not its individual states. However, you can easily write logic within verify to control how each state type is checked. For example, if the XState and YState states share the same contract, you could do:
class XAndYContract: Contract {
override fun verify(tx: LedgerTransaction) {
val inputXStates = tx.inputsOfType<XState>()
val outputXStates = tx.outputsOfType<XState>()
val inputYStates = tx.inputsOfType<YState>()
val outputYStates = tx.outputsOfType<YState>()
requireThat {
"All XState inputs are unapproved." using (inputXStates.all { it.approved == false })
"All XState outputs are approved" using (outputXStates.all { it.approved == true })
"All YState inputs are unaudited." using (inputYStates.all { it.audited == false })
"All YState outputs are audited" using (outputYStates.all { it.audited == true })
}
}
}
This is just an example. You have the full capabilities of Java/Kotlin at your disposal to control which states are checked and how.
Another option would be to split the logic into two contracts - XContract and YContract. Then you would have:
class XContract : Contract {
override fun verify(tx: LedgerTransaction) {
val inputXStates = tx.inputsOfType<XState>()
val outputXStates = tx.outputsOfType<XState>()
requireThat {
"All XState inputs are unapproved." using (inputXStates.all { it.approved == false })
"All XState outputs are approved" using (outputXStates.all { it.approved == true })
}
}
}
And:
class YContract : Contract {
override fun verify(tx: LedgerTransaction) {
val inputYStates = tx.inputsOfType<YState>()
val outputYStates = tx.outputsOfType<YState>()
requireThat {
"All YState inputs are unaudited." using (inputYStates.all { it.audited == false })
"All YState outputs are audited" using (outputYStates.all { it.audited == true })
}
}
}
Edit: The examples above assume there are two types of states. Suppose there is only one state type:
class MyState(val lifecycle: Lifecycle, override val linearId: UniqueIdentifier) : LinearState {
override val participants = listOf<AbstractParty>()
}
Where Lifecycle is defined as:
enum class Lifecycle {
ISSUED, AUDITED, APPROVED
}
And we want to impose the rule that in each transaction, any inputs in the ISSUED stage are transitioned to APPROVED, and any inputs in the APPROVED stage are transitioned to AUDITED.
We could achieve this using groupStates:
class MyContract : Contract {
override fun verify(tx: LedgerTransaction) {
val groups = tx.groupStates { it: MyState -> it.linearId }
requireThat {
for (group in groups) {
val inputState = group.inputs.single()
val outputState = group.outputs.single()
when (inputState.lifecycle) {
Lifecycle.ISSUED -> {
"Issued states have been transitioned to approved" using (outputState.lifecycle == Lifecycle.APPROVED)
}
Lifecycle.APPROVED -> {
"Approved states have been transitioned to audited" using (outputState.lifecycle == Lifecycle.AUDITED)
}
}
}
}
}
}
groupStates works by grouping inputs and outputs together based on some rule. In our case, we are grouping inputs and outputs that share the same uniqueIdentifier. We can then check that each input has evolved into the corresponding output correctly.
To implement that functionality you just have to use use a switch statement on the command. For example, in verify(tx) you could do something like this:
when (command.value) {
is Commands.Approve -> verifyApprove(tx, setOfSigners)
is Commands.Audit -> verifyAudit(tx, setOfSigners)
else -> throw IllegalArgumentException("Unrecognised command")
}
while the commands could be defined as follows:
interface Commands : CommandData {
class Issue : TypeOnlyCommandData(), Commands
class Transfer : TypeOnlyCommandData(), Commands
}
and in verifyApprove() and verifyAudit(), you can do your verification.
I tried passing states into the command itself so that we know command needs to take care what states. In verify method then don't check for single command.
interface Commands : CommandData {
class Create(val outputStates:List<MyState>): TypeOnlyCommandData(), Commands
class Update(val inOutStates:List<InOutState<MyState>>): TypeOnlyCommandData(), Commands
}
................
#CordaSerializable
data class InOutState<T: ContractState>(val inputState: T, val outputState:T)
............
tx.commands.forEach {
when (it.value) {
is Commands.Create -> {
val cmd = it.value as Commands.Create
requireThat{
"Output states must be present" using (cmd.outputStates.isNotEmpty())
}
}
}
One more pattern is to set the Corda contract Command into the State Object and do the grouping by the Command during time of contract verification
#CordaSerializable
interface CommandAwareState<T:CommandData>: LinearState,QueryableState{
val command: T
}
============
interface LinearStateCommands<T : LinearState> : CommandData {
fun verify(inOutStates: List<InOutState<T>>, tx: LedgerTransaction)
}
===========
data class StateA(val attribX: String, val attribY: String
, override val command: StateAContract.Commands =
StateAContract.Commands.None()):
CommandAwareState<StateAContract.Commands>
============
open class StateAContract : Contract {
companion object {
#JvmStatic
val CONTRACT_ID = "com.myproj.contract.StateAContract"
}
interface Commands : LinearStateCommands<DocumentState> {
class None(): TypeOnlyCommandData(), Commands{
override fun verify(inOutState: List<InOutState<StateA>>, tx:
LedgerTransaction) {
requireThat {
"There should not be any Input and Outputs" using
(inOutState.isEmpty())
}
}
}
class Create(): TypeOnlyCommandData(), Commands{
override fun verify(inOutStates: List<InOutState<DocumentState>>, tx:
LedgerTransaction) {
//WRITE Contract verification
}
}
override fun verify(tx: LedgerTransaction) {
tx.matchLinearStatesByCommand(DocumentState::class.java).forEach{
it.key.verify(it.value,tx)
}
}
}
==========
inline fun <T,reified K : CommandAwareState<T>> LedgerTransaction.matchLinearStatesByCommand(ofType: Class<K>): Map<T,List<InOutState<K>>>{
groupStates<K,UniqueIdentifier> { it.linearId }.let {
var mapByCommand = mutableMapOf<T,MutableList<InOutState<K>>>()
it.forEach {
if(mapByCommand.containsKey(it.outputs.single().command)){
mapByCommand.get(it.outputs.single().command)?.add(InOutState(it.inputs.noneOrSingle(),it.outputs.noneOrSingle()))
}else{
mapByCommand.put(it.outputs.single().command, mutableListOf(InOutState(it.inputs.noneOrSingle(),it.outputs.noneOrSingle())))
}
}
return mapByCommand
}
}
Is there a pattern/technique that supports unit testing shared "initiating flows" that have been implemented in a "shared cordapp.jar" that have multiple corresponding private "responding flows " each of which is implemented in its own "private party name cordapp.jar" ? Hope this question makes sense.
Terminology is as per Can either side of a Corda flow exist in separate Cordapps?.
Thanks for all info.
John
Sure. You just have to define a dummy response flow and register it on each node as an initiated flow:
#InitiatedBy(MyInitiator::class)
class MyTestResponder(val counterpartySession: FlowSession) : FlowLogic<Unit>() {
#Suspendable
override fun call() {
// Implement flow logic here.
}
}
class FlowTests {
lateinit var network: MockNetwork
lateinit var a: StartedNode<MockNode>
lateinit var b: StartedNode<MockNode>
#Before
fun setup() {
setCordappPackages("my.package")
network = MockNetwork()
val nodes = network.createSomeNodes(2)
a = nodes.partyNodes[0]
b = nodes.partyNodes[1]
nodes.partyNodes.forEach {
it.registerInitiatedFlow(MyTestResponder::class.java)
}
network.runNetwork()
}
#After
fun tearDown() {
network.stopNodes()
unsetCordappPackages()
}
#Test
fun `example test`() {
val flow = MyInitiator(b.info.chooseIdentity())
val future = a.services.startFlow(flow).resultFuture
network.runNetwork()
future.getOrThrow()
}
}