-
Notifications
You must be signed in to change notification settings - Fork 1k
Upgrade Requirements IoT Contracts
#Hyperledger User Chaincode Contract Upgrade This proposal focuses on one main issue (#1127) and related issues in Hyperledger:
- Issue #1127 Chaincode life-cycle
- Issue #1133 Uber chaincode
- Issue #1077 Human readable chaincode address aliases
- Issue #938 System chaincode execution framework
##Introduction to an IoT based Smart Contract Contracts in the IoT space tend to manage (track, etc.) assets (packages, vehicles, etc.) over time and location. The physical assets may have static properties such as a description (which might be a bill of lading for a shipment or a bill of materials for a physical asset such as a vehicle), a date of departure or manufacture, and so on.
In addition to the static asset data, dynamic or operational data is received for assets in the form of events. Event data is added to the asset over time, building up a picture of the asset's location and physical status.
Events arrive at the contract API and are processed to update one or more target assets' state. Each asset is effectively a partition in the database and contracts generally use an asset's ID as a prefix to related state data.
A pattern that the author has found useful in the design of IoT based contracts is Partial State as Event, which defines an event as a subset of an asset's writable state properties (e.g. temperature, location, gforce, etc.) with the asset's ID as mandatory. This offers several benefits:
- only one API required for each of createAsset, updateAsset and deleteAsset (i.e. a CRUD-like API pattern)
- grouping of properties into specific single-property or composite events not required, eliminating both API proliferation and the need for contract upgrades just for API additions
Another pattern that has proven useful is JSON Encoded Object as Event, sent in args[0] as the event. Benefits are:
- replaces manual encode-decode (see example02 in the hyperledger fabric project) with JSON marshal unmarshal
- contract API can be defined with JSON Schema 4.0 compatible schema
- event is defined as writable properties
- state is defined as event plus calculated properties such as compliance, alerts, etc.
In concert with JSON events, a maps over structs pattern for internal event and state management provides benefits such as:
- deep merging to build state up over time
- additional properties can be managed without affecting the contract's behavior
- no extra work involved, allows both application-managed sidecar data and future state data to be included in state
Rules engine is run on the new state after event is processed and merged in order to raise or clear alerts (as but one group of calculated properties.)
##Basic Requirements for Upgrading an IoT based Smart Contract So presuming that a contract is written in this way to manage assets, then upgrading that contract has certain requirements:
- contracts shall not be required to have prior knowledge of the upgrade process
- events shall be handled in real time during the upgrade process and not dropped
- requires that the new contract takes over the old contract's duties with no lag (i.e. a window for race conditions does not exist)
- UUID assigned to the new contract version should be the same as that of the old contract version
- decouples applications from the upgrade process
- events going to either contract version or to different contract versions on different peers shall arrive at the same state and achieve consensus
- is it possible to achieve consensus across different contract versions?
- does this requirement force the sharing of the UUID?
- previous contract version shall accept new application data before the upgraded contract version has propagated through the network
- a property of contract API and data model design
- decouples applications from contract versions
- decouples applications from propagation times in fabric
##Thoughts on the Upgrade Mechanism ###JSON-RPC Methods as Modes As discussed in #1127, the Uber chaincode runs inside a peer, handling user chaincode requests. This assumes a partitioning of existing code from the peer code base.
Implementation of an upgrade facility does not require partitioning of some peer code into Uber chaincode. Partitioning could be performed after upgrade is implemented.
A peer's REST interface forwards messages to the peer / Uber chaincode. Messages target three modes as selected by the message's JSON RPC envelope in the method
parameter: deploy
, invoke
and query
. The peer / Uber chaincode is responsible for delegating these requests.
To clarify the messages' JSON-RPC methods and their implied modes of operation:
-
deploy is a chaincode lifecycle mode that operates in two steps
- step 1: the Uber chaincode fetches the user chaincode files, creates and broadcasts a transaction for consensus, and if achieved deploys the chaincode into its peer (as are all other peers in parallel at this point)
- step 2: in each peer, the user chaincode is spun up and its initialization code (
Init
) invoked to initialize the state of objects or assetswith which it concerns itself
- invoke is a contract state lifecycle mode, where user chaincode functions handle requests that effectively define events intended to change uncommitted contract state
- query is a contract state lifecycle mode, where user chaincode functions handle requests that select portions of committed contract state to be returned to the caller
The upgrade process is performed in deploy
mode. However, there are residual effects on how invoke
and query
modes are handled after the upgrade.
- if using the patterns described in the introduction to IoT contracts above, then invokes and queries need not change at all, unless properties are renamed
- existing state from the previous contract continues to be additive, with new events adding their properties without affecting the contract's behavior
- removed properties can be handled in the updateAsset function if necessary so that state no longer shows those properties, or applications can simply ignore state that no longer matters (which is a useful byproduct of using JSON's tagged message format)
- if using fixed formats where hand-encoded strings populate the args array, then the contract's new version will have to understand both old and new parameter lists in any modified setter or getter
- changes in format will require new code
- additional properties will require new API and code
- removed properties will require new API and code
- state stored in individual property buckets (e.g.
assetID.propertyName
) will require upgrade step in all setters, or a distinct upgrade step that iterates through all existing state during the init for the new version
##Questions Issue #1127 proposes that the new contract version process all events targeted to the previous / upgraded contract version after the new contract version has successfully deployed into the fabric.
Is this accomplished by subsuming the UUID of the previous contract version? That would have the effect of also subsuming the state data.
- guessing no
Does the new human readable alias for the contract (as per #1077) allow redirect of state requests in addition to the redirect of messages targeted for the old contract version?
- guessing no
Does the new contract version physically copy all existing asset data to its own space?
- If so, can it happen over a long time? I.e. leave the old contract version running until the new contract has copied all existing data (which could be years or event never if much of the original data is historical / retired)
Could the Uber chaincode instead rename all of the buckets with the new UUID so that the data is subsumed automatically?
Could the new contract version access state from the old contract version directly?
- Would require GETState to allow a UUID as argument, but this would allow the new contract version to upgrade at its own pace