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:
- Connect to PartyA and PartyB's nodes via RPC
- Issue a state with the old contract
- Upgrade the state to use the new contract
- Wait ten seconds for the contract upgrade to propagate
- 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:?]
AbstractStateReplacementFlow.Instigator
will make a call toCollectSignaturesFlow
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 callSignTransactionFlow
.