Skip to content

Commit

Permalink
create Hyperledger 0.6 versions of all contracts
Browse files Browse the repository at this point in the history
Change stub interface
Change UUID accessor
Clean up lint issues in simple contract
Add missing .gitignore to building, cashManager, carbon_trading
  • Loading branch information
kletkeman committed Nov 3, 2016
1 parent de24fbb commit c7d0014
Show file tree
Hide file tree
Showing 169 changed files with 53,156 additions and 5,601 deletions.
1 change: 1 addition & 0 deletions contracts/advanced/iot_sample_contract.0.6/.gitignore
@@ -0,0 +1 @@
iot_sample_contract.0.6
32 changes: 32 additions & 0 deletions contracts/advanced/iot_sample_contract.0.6/README.MD
@@ -0,0 +1,32 @@
#A Hyperledger Sample Contract with Trade Lane Schema

> Updated for Hyperledger 0.6
> **This smart contract is described in a set of documents in the `/docs` folder. See the [README](./docs/README.md) for more informarmation. And please read the introduction and customization documents therein before proceeding through the code base.**
This contract is originally derived from the openblockchain contract in the folder `trade_lane_contract` to adapt it to the hyperledger project. The intent is for the `iot_` variant to evolve as a generic template for Hyperledger chaincode development with IoTP device event mapping.

The `iot_` variant of the contract will be advanced along with Hyperledger itself while the `trade_lane_` variant will be advanced in lock step with Hyperledger Bluemix.

----

This sample contract implements a simple Trade Lane scenario, moving *assets* from one place to another. It consists of several modules in `package main` that are all small enough to avoid creating separate packages in this first version. These add features that can be used without changing the code.

This sample is used to explore features and patterns that are of interest to smart contract writers in the IoT domain. These are:

- A single contract instance that manages multiple assets
- A CRUD-like API for the assets
- An event that is also a partial state
- A deep merge of events to state
- a `JSON Schema 4` compatible schema and a script written in Go that generates object samples and object schemas when `go generate` commands are issued
- A mechanism for storing asset history (note, this mechanism is early work and will change for better scaling)
- A mechanism for storing the most recent updates to any asset, most recent first. An asset can appear only once in the list and jumps to the top each time it is updated.
- An alerts mechanism that tracks active alerts and marks the threshold events as raised or cleared.
- A rules engine that performs threshold tests (e.g. temperature too high) and raises or clears alerts as necessary (and note that the rules need not be limited to alerts testing etc, they can in fact generate read-only properties directly if need be)
- A set of map utilities that enable deep merging of incoming JSON events into the state that is stored in the ledger. This is necessary to implement a pattern where a partial state is used as an event.
- Optional case-insensitivity for JSON tags for the convenience of clients that do not want to be held to the strictness of the JSON-RPC standard (note: insensitivity is not recommended, but can be explored with this sample)
- A logging facility that can be adjusted in real time in order to debug a deployed contract without disrupting it in any way

Generic UIs exist in other folders in this project, driven from the schema in this and other contracts. Plugins for React are used to generate forms from the schema, and of course processing the schema directly would enable a host of other schema-driven features.

To enable application access to the schema, contract APIs `getAssetSamples` and `getAssetSchemas` return generated samples and schemas in JSON object form. This is used by the generic UIs and by the Watson IoT Platform for automated integration.
Expand Up @@ -19,71 +19,66 @@ Kim Letkeman - Initial Contribution
// KL 16 Feb 2016 Initial alert package
// KL 22 Feb 2016 add AllClear method and associated constant
// KL 18 Apr 2016 Adapt new external JSON alerts (names instead of booleans) from orig 3.1/4.0
// KL 28 Jun 2016 Remove OVERTEMP and add ACHECK and BCHECK
// KL 30 Jun 2016 Copy new function to clear the raised and cleared status from
// simple aviation contract 4.2sa
// ************************************

package main

import (
)

// Alerts exists so that strict type checking can be applied
type Alerts int32

const (
// AlertsACHECK the needs 10 cycle inspection alert
AlertsACHECK Alerts = 0
// AlertsBCHECK the needs 10 cycle inspection alert
AlertsBCHECK Alerts = 1
// AlertsOVERTEMP the over temperature alert
AlertsOVERTEMP Alerts = 0

// AlertsSIZE is to be maintained always as 1 greater than the last alert, giving a size
AlertsSIZE Alerts = 2
// AlertsSIZE is to be maintained always as 1 greater than the last alert, giving a size
AlertsSIZE Alerts = 1
)

// AlertsName is a map of ID to name
var AlertsName = map[int]string{
0: "ACHECK",
1: "BCHECK",
0: "OVERTEMP",
}

// AlertsValue is a map of name to ID
var AlertsValue = map[string]int32{
"ACHECK": 0,
"BCHECK": 1,
"OVERTEMP": 0,
}

func (x Alerts) String() string {
return AlertsName[int(x)]
return AlertsName[int(x)]
}

// AlertArrayInternal is used to store the list of active, raised or cleared alerts
// for internal processing
type AlertArrayInternal [AlertsSIZE]bool

// AlertNameArray is used for external alerts in JSON
type AlertNameArray []string

// NOALERTSACTIVEINTERNAL is the zero value of an internal alerts array (bools)
var NOALERTSACTIVEINTERNAL = AlertArrayInternal{}

// NOALERTSACTIVE is the zero value of an external alerts array (string names)
var NOALERTSACTIVE = AlertNameArray{}

// AlertStatusInternal contains the three possible statuses for alerts as booleans
// AlertStatusInternal contains the three possible statuses for alerts
type AlertStatusInternal struct {
Active AlertArrayInternal
Raised AlertArrayInternal
Cleared AlertArrayInternal
Active AlertArrayInternal
Raised AlertArrayInternal
Cleared AlertArrayInternal
}

// AlertStatus contains the three possible statuses for alerts as string names
type AlertStatus struct {
Active AlertNameArray `json:"active"`
Raised AlertNameArray `json:"raised"`
Cleared AlertNameArray `json:"cleared"`
Active AlertNameArray `json:"active"`
Raised AlertNameArray `json:"raised"`
Cleared AlertNameArray `json:"cleared"`
}

// convert from external representation with slice of names
// to full length array of bools
func (a *AlertStatus) asAlertStatusInternal() (AlertStatusInternal) {
// to full length array of bools
func (a *AlertStatus) asAlertStatusInternal() AlertStatusInternal {
var aOut = AlertStatusInternal{}
for i := range a.Active {
aOut.Active[AlertsValue[a.Active[i]]] = true
Expand All @@ -97,9 +92,9 @@ func (a *AlertStatus) asAlertStatusInternal() (AlertStatusInternal) {
return aOut
}

// convert from internal representation with full length array of bools
// convert from internal representation with full length array of bools
// to slice of names
func (a *AlertStatusInternal) asAlertStatus() (AlertStatus) {
func (a *AlertStatusInternal) asAlertStatus() AlertStatus {
var aOut = newAlertStatus()
for i := range a.Active {
if a.Active[i] {
Expand All @@ -119,7 +114,7 @@ func (a *AlertStatusInternal) asAlertStatus() (AlertStatus) {
return aOut
}

func (a *AlertStatusInternal) raiseAlert (alert Alerts) {
func (a *AlertStatusInternal) raiseAlert(alert Alerts) {
if a.Active[alert] {
// already raised
// this is tricky, should not say this event raised an
Expand All @@ -136,7 +131,7 @@ func (a *AlertStatusInternal) raiseAlert (alert Alerts) {
}
}

func (a *AlertStatusInternal) clearAlert (alert Alerts) {
func (a *AlertStatusInternal) clearAlert(alert Alerts) {
if a.Active[alert] {
// clearing alert
a.Active[alert] = false
Expand All @@ -153,7 +148,7 @@ func (a *AlertStatusInternal) clearAlert (alert Alerts) {
}
}

func (a *AlertStatusInternal) clearRaisedAndClearedStatus () {
func (a *AlertStatusInternal) clearRaisedAndClearedStatus() {
for i := range a.Active {
if a.Active[i] {
a.Raised[i] = false
Expand All @@ -163,48 +158,47 @@ func (a *AlertStatusInternal) clearRaisedAndClearedStatus () {
}
}


func newAlertStatus() (AlertStatus) {
func newAlertStatus() AlertStatus {
var a AlertStatus
a.Active = make([]string, 0, AlertsSIZE)
a.Raised = make([]string, 0, AlertsSIZE)
a.Cleared = make([]string, 0, AlertsSIZE)
return a
}

func (a *AlertStatus) alertStatusFromMap (aMap map[string]interface{}) () {
func (a *AlertStatus) alertStatusFromMap(aMap map[string]interface{}) {
a.Active.copyFrom(aMap["active"].([]interface{}))
a.Raised.copyFrom(aMap["raised"].([]interface{}))
a.Cleared.copyFrom(aMap["cleared"].([]interface{}))
}
}

func (arr *AlertNameArray) copyFrom (s []interface{}) {
func (arr *AlertNameArray) copyFrom(s []interface{}) {
// a conversion like this must assert type at every level
for i := 0; i < len(s); i++ {
*arr = append(*arr, s[i].(string))
}
}

// NoAlertsActive returns true when no alerts are active in the asset's status at this time
func (a *AlertStatusInternal) NoAlertsActive() (bool) {
return (a.Active == NOALERTSACTIVEINTERNAL)
func (arr *AlertStatusInternal) NoAlertsActive() bool {
return (arr.Active == NOALERTSACTIVEINTERNAL)
}

// AllClear returns true when no alerts are active, raised or cleared in the asset's status at this time
func (a *AlertStatusInternal) AllClear() (bool) {
return (a.Active == NOALERTSACTIVEINTERNAL) &&
(a.Raised == NOALERTSACTIVEINTERNAL) &&
(a.Cleared == NOALERTSACTIVEINTERNAL)
func (arr *AlertStatusInternal) AllClear() bool {
return (arr.Active == NOALERTSACTIVEINTERNAL) &&
(arr.Raised == NOALERTSACTIVEINTERNAL) &&
(arr.Cleared == NOALERTSACTIVEINTERNAL)
}

// NoAlertsActive returns true when no alerts are active in the asset's status at this time
func (a *AlertStatus) NoAlertsActive() (bool) {
func (a *AlertStatus) NoAlertsActive() bool {
return len(a.Active) == 0
}

// AllClear returns true when no alerts are active, raised or cleared in the asset's status at this time
func (a *AlertStatus) AllClear() (bool) {
return len(a.Active) == 0 &&
len(a.Raised) == 0 &&
len(a.Cleared) == 0
}
func (a *AlertStatus) AllClear() bool {
return len(a.Active) == 0 &&
len(a.Raised) == 0 &&
len(a.Cleared) == 0
}
113 changes: 113 additions & 0 deletions contracts/advanced/iot_sample_contract.0.6/assethistory.go
@@ -0,0 +1,113 @@
/*
Copyright (c) 2016 IBM Corporation and other Contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
Contributors:
Howard McKinney- Initial Contribution
Kim Letkeman - Initial Contribution
*/

// v3.0 HM 25 Feb 2016 Moved the asset state history code into a separate package.
// v3.0.1 HM 03 Mar 2016 Store the state history in descending order.

package main

import (
"encoding/json"

"github.com/hyperledger/fabric/core/chaincode/shim"
)

const STATEHISTORYKEY string = ".StateHistory"

type AssetStateHistory struct {
AssetHistory []string `json:"assetHistory"`
}

// Create a new history entry in the ledger for an asset.,\
func createStateHistory(stub shim.ChaincodeStubInterface, assetID string, stateJSON string) error {

var ledgerKey = assetID + STATEHISTORYKEY
var assetStateHistory = AssetStateHistory{make([]string, 1)}
assetStateHistory.AssetHistory[0] = stateJSON

assetState, err := json.Marshal(&assetStateHistory)
if err != nil {
return err
}

log.Debugf("CreateStateHistory: putting to state ==>%s<==", string(assetState))

return stub.PutState(ledgerKey, []byte(assetState))

}

// Update the ledger with new state history for an asset. States are stored in the ledger in descending order by timestamp.
func updateStateHistory(stub shim.ChaincodeStubInterface, assetID string, stateJSON string) error {

var ledgerKey = assetID + STATEHISTORYKEY
var historyBytes []byte
var assetStateHistory AssetStateHistory

historyBytes, err := stub.GetState(ledgerKey)
if err != nil {
return err
}

err = json.Unmarshal(historyBytes, &assetStateHistory)
if err != nil {
return err
}

var newSlice []string = make([]string, 0)
newSlice = append(newSlice, stateJSON)
newSlice = append(newSlice, assetStateHistory.AssetHistory...)
assetStateHistory.AssetHistory = newSlice

assetState, err := json.Marshal(&assetStateHistory)
if err != nil {
return err
}

log.Debugf("UpdateStateHistory: putting to state ==>%s<==", string(assetState))

return stub.PutState(ledgerKey, []byte(assetState))

}

// Delete an state history from the ledger.
func deleteStateHistory(stub shim.ChaincodeStubInterface, assetID string) error {

var ledgerKey = assetID + STATEHISTORYKEY
return stub.DelState(ledgerKey)

}

// Get the state history for an asset.
func readStateHistory(stub shim.ChaincodeStubInterface, assetID string) (AssetStateHistory, error) {

var ledgerKey = assetID + STATEHISTORYKEY
var assetStateHistory AssetStateHistory
var historyBytes []byte

historyBytes, err := stub.GetState(ledgerKey)
if err != nil {
return assetStateHistory, err
}

err = json.Unmarshal(historyBytes, &assetStateHistory)
if err != nil {
return assetStateHistory, err
}

return assetStateHistory, nil

}

0 comments on commit c7d0014

Please sign in to comment.