'Counterparty sent session rejection message at unexpected time with message class com.upgrade.CustomContractUpgradeFlow$Initiate is not registered

Project: ContractUpgradeFlow

Project Link: https://github.com/corda/contract-upgrades

I tried to create my own Contract Upgrade flow, so I copied the code for contract upgrade as it is, but after executing it is not able to upgrade the contract.

Steps I followed:

  1. Connect to PartyA and PartyB's nodes via RPC
  2. Issue a state with the old contract
  3. Upgrade the state to use the new contract
  4. Wait ten seconds for the contract upgrade to propagate
  5. Log the state to show that its contract has been upgraded

Please find attached code and error log.

Code:

package com.upgrade

import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.PrivacySalt
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.UpgradedContract
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SignableData
import net.corda.core.crypto.SignatureMetadata
import net.corda.core.flows.*
import net.corda.core.internal.ContractUpgradeUtils
import net.corda.core.transactions.SignedTransaction

object CustomContractUpgradeFlow {

    @StartableByRPC
    class Authorise(
            val stateAndRef: StateAndRef<*>,
            private val upgradedContractClass: Class<out UpgradedContract<*, *>>
    ) : FlowLogic<Void?>() {
        // DOCEND 1
        @Suspendable
        override fun call(): Void? {
            val upgrade = upgradedContractClass.newInstance()
            if (upgrade.legacyContract != stateAndRef.state.contract) {
                throw FlowException("The contract state cannot be upgraded using provided UpgradedContract.")
            }
            serviceHub.contractUpgradeService.storeAuthorisedContractUpgrade(stateAndRef.ref, upgradedContractClass)
            return null
        }
    }

    @InitiatingFlow
    @StartableByRPC
    class Initiate<OldState : ContractState, out NewState : ContractState>(
            originalState: StateAndRef<OldState>,
            newContractClass: Class<out UpgradedContract<OldState, NewState>>
    ) : AbstractStateReplacementFlow.Instigator<OldState, NewState, Class<out UpgradedContract<OldState, NewState>>>(originalState, newContractClass) {

        @Suspendable
        override fun assembleTx(): AbstractStateReplacementFlow.UpgradeTx {
            val tx = ContractUpgradeUtils.assembleUpgradeTx(originalState, modification, PrivacySalt(), serviceHub)
            val participantKeys = originalState.state.data.participants.map { it.owningKey }.toSet()
            val myKey = serviceHub.keyManagementService.filterMyKeys(participantKeys).single()
            val signableData = SignableData(tx.id, SignatureMetadata(serviceHub.myInfo.platformVersion, Crypto.findSignatureScheme(myKey).schemeNumberID))
            val mySignature = serviceHub.keyManagementService.sign(signableData, myKey)
            val stx = SignedTransaction(tx, listOf(mySignature))
            return AbstractStateReplacementFlow.UpgradeTx(stx)
        }
    }
}

Logs:

[WARN ] 2018-06-14T06:30:35,936Z [Node thread-1] flow.[079185a0-c4a4-47eb-9a70-145d42cc2d9d].run - Terminated by unexpected exception {}
net.corda.core.flows.UnexpectedFlowEndException: Counterparty sent session rejection message at unexpected time with message class com.upgrade.CustomContractUpgradeFlow$Initiate is not registered
    at net.corda.node.services.statemachine.FlowStateMachineImpl.erroredEnd(FlowStateMachineImpl.kt:484) ~[corda-node-3.1-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.confirmNoError(FlowStateMachineImpl.kt:471) ~[corda-node-3.1-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.waitForMessage(FlowStateMachineImpl.kt:431) ~[corda-node-3.1-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.receiveInternal(FlowStateMachineImpl.kt:363) ~[corda-node-3.1-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.waitForConfirmation(FlowStateMachineImpl.kt:333) ~[corda-node-3.1-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.initiateSession(FlowStateMachineImpl.kt:423) ~[corda-node-3.1-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.sendAndReceive(FlowStateMachineImpl.kt:185) ~[corda-node-3.1-corda.jar:?]
    at net.corda.node.services.statemachine.FlowSessionImpl.sendAndReceive(FlowSessionImpl.kt:29) ~[corda-node-3.1-corda.jar:?]
    at net.corda.node.services.statemachine.FlowSessionImpl.sendAndReceive(FlowSessionImpl.kt:40) ~[corda-node-3.1-corda.jar:?]
    at net.corda.core.flows.DataVendingFlow.sendPayloadAndReceiveDataRequest(SendTransactionFlow.kt:70) ~[corda-core-3.1-corda.jar:?]
    at net.corda.core.flows.DataVendingFlow.call(SendTransactionFlow.kt:48) ~[corda-core-3.1-corda.jar:?]
    at net.corda.core.flows.DataVendingFlow.call(SendTransactionFlow.kt:31) ~[corda-core-3.1-corda.jar:?]
    at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.1-corda.jar:?]
    at net.corda.core.flows.AbstractStateReplacementFlow$Instigator.getParticipantSignature(AbstractStateReplacementFlow.kt:108) ~[corda-core-3.1-corda.jar:?]
    at net.corda.core.flows.AbstractStateReplacementFlow$Instigator.collectSignatures(AbstractStateReplacementFlow.kt:92) ~[corda-core-3.1-corda.jar:?]
    at net.corda.core.flows.AbstractStateReplacementFlow$Instigator.call(AbstractStateReplacementFlow.kt:68) ~[corda-core-3.1-corda.jar:?]
    at net.corda.core.flows.AbstractStateReplacementFlow$Instigator.call(AbstractStateReplacementFlow.kt:50) ~[corda-core-3.1-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:96) [corda-node-3.1-corda.jar:?]
    at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:44) [corda-node-3.1-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_171]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_171]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_171]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_171]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_171]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_171]
    at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:62) [corda-node-3.1-corda.jar:?]


Solution 1:[1]

AbstractStateReplacementFlow.Instigator will make a call to CollectSignaturesFlow to gather the signatures of the counterparties that need to authorise the upgrade.

You therefore need to provide a responder flow for your CustomContractUpgradeFlow.Initiate that will call SignTransactionFlow.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Joel