* Make CompositeKey implement PublicKey The initial implementation of composite keys as their own distinct class separate from PublicKey means that the keys cannot be used on standard classes such as Certificate. This work is a beginning to modifying CompositeKey to being a PublicKey implementation, although significant further work is required to integrate this properly with the standard Java APIs, especially around verifying signatures using the new key type. * First stage of making CompositeKey implement PublicKey interface. Revert to using PublicKey everywhere we expect a key. * Move algorithm and format into companion object (#432) Move algorithm and format into companion object so that they can be referenced from other classes (i.e. the upcoming signature class). * Add simple invariants to construction of CompositeKey. Builder emits CompositeKeys in simplified normalised form. Forbid keys with single child node, force ordering on children and forbid duplicates on the same level. It's not full semantical normalisation. * Make constructor of CompositeKey private, move NodeWeight inside the class. Add utility function for Kryo deserialization to read list with length constraints.
6.0 KiB
Upgrading Contracts
While every care is taken in development of contract code, inevitably upgrades will be required to fix bugs (in either design or implementation). Upgrades can involve a substitution of one version of the contract code for another or changing to a different contract that understands how to migrate the existing state objects. State objects refer to the contract code (by hash) they are intended for, and even where state objects can be used with different contract versions, changing this value requires issuing a new state object.
Workflow
Here's the workflow for contract upgrades:
- Two banks, A and B negotiate a trade, off-platform
- Banks A and B execute a protocol to construct a state object representing the trade, using contract X, and include it in a transaction (which is then signed and sent to the Uniqueness Service).
- Time passes.
4. The developer of contract X discovers a bug in the contract code, and releases a new version, contract Y. And notify the users (e.g. via a mailing list or CorDapp store). At this point of time all nodes should stop issuing states of contract X.
- Banks A and B review the new contract via standard change control processes and identify the contract states they agreed to upgrade, they can decide not to upgrade some contract states as they might be needed for other obligation contract.
- Banks A and B instruct their Corda nodes (via RPC) to be willing to upgrade state objects of contract X, to state objects for contract Y using agreed upgrade path.
- One of the parties
Instigator
initiates an upgrade of state objects referring to contract X, to a new state object referring to contract Y. - A proposed transaction
Proposal
, taking in the old state and outputting the reissued version, is created and signed with the node's private key. - The node
Instigator
sends the proposed transaction, along with details of the new contract upgrade path it's proposing, to all participants of the state object. - Each counterparty
Acceptor
verifies the proposal, signs or rejects the state reissuance accordingly, and sends a signature or rejection notification back to the initiating node. - If signatures are received from all parties, the initiating node assembles the complete signed transaction and sends it to the consensus service.
Authorising upgrade
Each of the participants in the upgrading contract will have to instruct their node that they are willing to upgrade the state object before the upgrade. Currently the vault service is used to manage the authorisation records. The administrator can use RPC to perform such instructions.
/**
* Authorise a contract state upgrade.
* This will store the upgrade authorisation in the vault, and will be queried by [ContractUpgradeFlow.Acceptor] during contract upgrade process.
* Invoking this method indicate the node is willing to upgrade the [state] using the [upgradedContractClass].
* This method will NOT initiate the upgrade process. To start the upgrade process, see [ContractUpgradeFlow.Instigator].
*/
fun authoriseContractUpgrade(state: StateAndRef<*>, upgradedContractClass: Class<UpgradedContract<*, *>>)
/**Authorise a contract state upgrade.
* This will remove the upgrade authorisation from the vault.
*
*/fun deauthoriseContractUpgrade(state: StateAndRef<*>)
Proposing an upgrade
After all parties have registered the intention of upgrading the contract state, one of the contract participant can initiate the upgrade process by running the contract upgrade flow. The Instigator will create a new state and sent to each participant for signatures, each of the participants (Acceptor) will verify and sign the proposal and returns to the instigator. The transaction will be notarised and persisted once every participant verified and signed the upgrade proposal.
Examples
Lets assume Bank A has entered into an agreement with Bank B, and the contract is translated into contract code DummyContract
with state object DummyContractState
.
Few days after the exchange of contracts, the developer of the contract code discovered a bug/misrepresentation in the contract code. Bank A and Bank B decided to upgrade the contract to DummyContractV2
- Developer will create a new contract extending the
UpgradedContract
class, and a new state objectDummyContractV2.State
referencing the new contract.
/../../core/src/main/kotlin/net/corda/core/contracts/DummyContractV2.kt
- Bank A will instruct its node to accept the contract upgrade to
DummyContractV2
for the contract state.
val rpcClient : CordaRPCClient = << Bank A's Corda RPC Client >>
val rpcA = rpcClient.proxy()
class.java) rpcA.authoriseContractUpgrade(<<StateAndRef of the contract state>>, DummyContractV2::
3. Bank B now initiate the upgrade Flow, this will send a upgrade proposal to all contract participants. Each of the participants of the contract state will sign and return the contract state upgrade proposal once they have validated and agreed with the upgrade. The upgraded transaction state will be recorded in every participant's node at the end of the flow.
val rpcClient : CordaRPCClient = << Bank B's Corda RPC Client >>
val rpcB = rpcClient.proxy()
rpcB.startFlow({ stateAndRef, upgrade -> ContractUpgradeFlow.Instigator(stateAndRef, upgrade) },
<<StateAndRef of the contract state>>,class.java) DummyContractV2::
Note
See ContractUpgradeFlowTest.2 parties contract upgrade using RPC
for more detailed code example.