Как получить подпись от одной и той же стороны, несколько раз в одном потоке? - PullRequest
0 голосов
/ 26 ноября 2018

Мне нужно реализовать сценарий как, есть CentralParty, PartyA, PartyB.CentralParty необходимо инициировать поток, в котором в цикле будет 3 транзакции, где инициатор всегда является центральной стороной, а другая сторона будет стороной А 2 раза.

т.е. я пытаюсь собрать подпись у одного и того же контрагента несколько разиз одного потока путем ссылки на следующую ссылку

Corda, возвращающий несколько транзакций в одном вызове потока ()

val flowSessionMap = mutableMapOf<Party, FlowSession>()
var ftx:MutableList<SignedTransaction> = mutableListOf<SignedTransaction>()
var signedTransaction:SignedTransaction

val fullySignedTransactions = matchingStateList.forEach { matchingState ->

    val txCommand = Command(IOUContract.Commands.Matching(), matchingState.participants.map { it.owningKey })
    val txBuilder = TransactionBuilder(notary)
            .addOutputState(matchingState, IOU_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, ourIdentity.owningKey)


    val sessions = (listOf(PartyA).map { signer ->
        flowSessionMap.getOrPut(signer) {
            initiateFlow(signer)
        }
    })

    val fullySignedTransaction = subFlow(CollectSignaturesInitiatingFlow(
        partSignedTx, sessions)
    )

    signedTransaction = fullySignedTransaction

    ftx.add(signedTransaction)
}

for (transaction in ftx) {
    subFlow(FinalityFlow(transaction))
}

Поток респондента определяется следующим образом:

 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 Matching State transaction." using (output is MatchingState)
                val Match = output as MatchingState
                "I won't accept IOUs with a value over 100." using (iou.value <= 100)
            }
        }

        return subFlow(signTransactionFlow)
    }
}

Где CollectSignaturesInitiatingFlow определяется следующим образом:

 @InitiatingFlow
class CollectSignaturesInitiatingFlow(val signedTransaction: SignedTransaction, val sessions: List<FlowSession>): FlowLogic<SignedTransaction>() {
    override fun call(): SignedTransaction {
        return subFlow(CollectSignaturesFlow(signedTransaction, sessions))
    }
}

А ответчик для CollectSignaturesInitiatingFlow определяется следующим образом:

    @InitiatedBy(CollectSignaturesInitiatingFlow::class)
class CollectSignaturesInitiatingFlowResponder(val otherPartyFlow: FlowSession) : FlowLogic<SignedTransaction>() {
    @Suspendable
    override fun call(): SignedTransaction {
        val signTransactionFlow = object : SignTransactionFlow(otherPartyFlow) {
            override fun checkTransaction(stx: SignedTransaction) {
                TODO("Check the transaction here.")
            }
        }

        return subFlow(signTransactionFlow)
    }
}

При выполнении того же кода я получилошибка типа

[WARN ] 15:43:18,817 [Node thread-1] (FlowStateMachineImpl.kt:111) flow.[82900238-9223-4ace-ba78-9ecc45121b11].run - Terminated by unexpected exception {}
net.corda.core.flows.UnexpectedFlowEndException: Counterparty flow on O=PartyA, L=London, C=GB has completed without sending data
    at net.corda.node.services.statemachine.FlowStateMachineImpl.confirmNoError(FlowStateMachineImpl.kt:488) ~[corda-node-3.2-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.waitForMessage(FlowStateMachineImpl.kt:444) ~[corda-node-3.2-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.sendAndReceiveInternal(FlowStateMachineImpl.kt:385) ~[corda-node-3.2-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.sendAndReceive(FlowStateMachineImpl.kt:203) ~[corda-node-3.2-corda.jar:?]
    at net.corda.node.services.statemachine.FlowSessionImpl.sendAndReceive(FlowSessionImpl.kt:29) ~[corda-node-3.2-corda.jar:?]
    at net.corda.node.services.statemachine.FlowSessionImpl.sendAndReceive(FlowSessionImpl.kt:40) ~[corda-node-3.2-corda.jar:?]
    at net.corda.core.flows.DataVendingFlow.sendPayloadAndReceiveDataRequest(SendTransactionFlow.kt:70) ~[corda-core-3.2-corda.jar:?]
    at net.corda.core.flows.DataVendingFlow.call(SendTransactionFlow.kt:48) ~[corda-core-3.2-corda.jar:?]
    at net.corda.core.flows.DataVendingFlow.call(SendTransactionFlow.kt:31) ~[corda-core-3.2-corda.jar:?]
    at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?]
    at net.corda.core.flows.CollectSignatureFlow.call(CollectSignaturesFlow.kt:142) ~[corda-core-3.2-corda.jar:?]
    at net.corda.core.flows.CollectSignatureFlow.call(CollectSignaturesFlow.kt:135) ~[corda-core-3.2-corda.jar:?]
    at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?]
    at net.corda.core.flows.CollectSignaturesFlow.call(CollectSignaturesFlow.kt:114) ~[corda-core-3.2-corda.jar:?]
    at net.corda.core.flows.CollectSignaturesFlow.call(CollectSignaturesFlow.kt:64) ~[corda-core-3.2-corda.jar:?]
    at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?]
    at com.example.flow.ExampleFlowMatching$CollectSignaturesInitiatingFlow.call(ExampleFlowMatching.kt:260) ~[classes/:?]
    at com.example.flow.ExampleFlowMatching$CollectSignaturesInitiatingFlow.call(ExampleFlowMatching.kt:258) ~[classes/:?]
    at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.2-corda.jar:?]
    at com.example.flow.ExampleFlowMatching$ExampleFlowMatchingInitiator.call(ExampleFlowMatching.kt:202) ~[classes/:?]
    at com.example.flow.ExampleFlowMatching$ExampleFlowMatchingInitiator.call(ExampleFlowMatching.kt:45) ~[classes/:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:96) [corda-node-3.2-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:44) [corda-node-3.2-corda.jar:?]
    at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) [quasar-core-0.7.9-jdk8.jar:0.7.9]
    at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) [quasar-core-0.7.9-jdk8.jar:0.7.9]
    at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) [quasar-core-0.7.9-jdk8.jar:0.7.9]
    at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) [quasar-core-0.7.9-jdk8.jar:0.7.9]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_191]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_191]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_191]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_191]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_191]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_191]
    at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:62) [corda-node-3.2-corda.jar:?]

1 Ответ

0 голосов
/ 27 ноября 2018

Проблема в том, что вы инициируете сеансы потока в своем основном потоке, ExampleFlowMatchingInitiator, а не внутри CollectSignaturesInitiatingFlow.

Когда вы вызываете initiateFlow, он запускает сеанс потока с контрагентомв контексте текущего InitiatingFlow.Поэтому, когда вы звоните initiateFlow в ExampleFlowMatchingInitiator, контрагент проверит, зарегистрированы ли у него респонденты для ExampleFlowMatchingInitiator.Это делает - Acceptor - поэтому он начинает сеанс потока, чтобы поговорить с контрагентом, используя Acceptor.

Если вы вместо этого вызовете initiateFlow внутри CollectSignaturesInitiatingFlow, контрагент проверит, есть ли у него респондентызарегистрирован на CollectSignaturesInitiatingFlow.Это делает - CollectSignaturesInitiatingFlowResponder - поэтому он начинает сеанс потока, чтобы поговорить с контрагентом, используя вместо этого CollectSignaturesInitiatingFlowResponder.

...