Our Corda network has 3 nodes in addition to the notary. The image shows what each node should do.
Only in this scenario we are in trouble "Need to move tokens from account holder to Party B"
Flow code:
class TransferETokenDiffNodeFlow(val actualHolder: AbstractParty, val newHolder: AbstractParty, val numEtokens: Double, val observables: MutableList = mutableListOf()) : FlowLogic() { private fun notary() = serviceHub.networkMapCache.notaryIdentities.first() @Suspendable override fun call(): SignedTransaction { progressTracker.currentStep = INITIALIZING val txBuilder = TransactionBuilder(notary()) val actualHolderStateRef = accountService.accountInfo(actualHolder.owningKey) ?: throw AccountNotFoundException("Account not found exception.") val actualHolderInfo = actualHolderStateRef.state.data val actualHolderSession = initiateFlow(actualHolderInfo.host) actualHolderSession.send(numEtokens) actualHolderSession.send(actualHolder) actualHolderSession.send(newHolder) val inputs = subFlow(ReceiveStateAndRefFlow(actualHolderSession)) val tokens: List = actualHolderSession.receive>().unwrap { it -> it} progressTracker.currentStep = BUILDING addMoveTokens(txBuilder, inputs, tokens) progressTracker.currentStep = SIGNING val initialSignedTrnx = serviceHub.signInitialTransaction(txBuilder) progressTracker.currentStep = GATHERING_SIGS val fulySignedTx= subFlow(CollectSignaturesFlow(initialSignedTrnx, listOf(actualHolderSession))) progressTracker.currentStep = FINALISING_CREATE val stx = subFlow(FinalityFlow(fulySignedTx, listOf(actualHolderSession))) progressTracker.currentStep = FINALISING val statesTx = stx.tx.outRefsOfType() statesTx.forEach { state -> observables.forEach { observable -> subFlow(ShareStateAndSyncAccounts(state, observable)) } } return stx } } //ResponderFlow code: class TransferETokenDiffNodeFlowResponder(val counterpartySession: FlowSession) : FlowLogic() { @Suspendable override fun call(): SignedTransaction { val numEtokens = counterpartySession.receive().unwrap { it } val actualHolder = counterpartySession.receive().unwrap { it } val newHolder = counterpartySession.receive().unwrap { it } val partyAndAmount = PartyAndAmount(newHolder, numEtokens of EnergyTokenType.getInstance("ENERGY")) val actualHolderStateRef = accountService.accountInfo(actualHolder.owningKey) ?: throw AccountNotFoundException("Account not found exception.") val actualHolderInfo = actualHolderStateRef.state.data val criteria = QueryCriteria.VaultQueryCriteria(externalIds = listOf(actualHolderInfo.identifier.id), status = Vault.StateStatus.UNCONSUMED) val selector = DatabaseTokenSelection(serviceHub) val (inputs, outputs) = selector.generateMove(listOf(partyAndAmount).toPairs(), actualHolder, TokenQueryBy(queryCriteria = criteria), runId.uuid) subFlow(SendStateAndRefFlow(counterpartySession, inputs)) counterpartySession.send(outputs) subFlow(object : SignTransactionFlow(counterpartySession) { @Throws(FlowException::class) override fun checkTransaction(stx: SignedTransaction) { } }) return subFlow(ReceiveFinalityFlow(counterpartySession)) } }
We need to execute the flow at Party C and the actualHolder is the account holder and the newHolder is Party B.
With this code the returns an error: net.corda.core.CordaRuntimeException: java.lang.IllegalArgumentException: Flow sessions were not provided for the following transaction participants: [O = Party B, L = Curitiba, C = BR]
But if I change the code and add the Party B session, it returns the error: java.lang.IllegalArgumentException: The Initiator of CollectSignaturesFlow must pass in exactly the sessions required to sign the transaction.
The question is, why doesn't addMoveTokens put newHolder as a required signer? And how can I solve this problem?