|
| 1 | +This document serves as an overview of the new features present in fabric |
| 2 | +v0.6.1-preview release, and outlines the changes you will need to make to |
| 3 | +successfully migrate code originally written for the v0.5-developer-preview |
| 4 | +release that you now wish to run on fabric v0.6.1-preview. |
| 5 | + |
| 6 | +# Migrating chaincode to fabric v0.6.1-preview |
| 7 | + |
| 8 | +* The chaincode shim interface changes for compatibility with the latest |
| 9 | +Hyperledger shim: |
| 10 | + |
| 11 | +The chaincode interface has changed from `shim.ChaincodeStub` to |
| 12 | +`shim.ChaincodeStubInterface`. See the |
| 13 | +[interfaces.go](fabric/core/chaincode/shim/interfaces.go) file for the shim |
| 14 | +source code. The following code snippet from line 74 of chaincode_example02 will |
| 15 | +highlight this alteration. |
| 16 | + |
| 17 | +This change applies to all transaction types: Deploy, Invoke, and Query. |
| 18 | + |
| 19 | + ```go |
| 20 | +func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStub, function string, args []string) ([]byte, error) { |
| 21 | + |
| 22 | +func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { |
| 23 | +``` |
| 24 | +
|
| 25 | +* Chaincode calling chaincode is included in the shim package. |
| 26 | +
|
| 27 | +There are two functions available - **InvokeChaincode** and **QueryChaincode**. |
| 28 | +First, these functions no longer accept the function name as a parameter; |
| 29 | +instead the function must be passed in as an argument. Second, the arguments |
| 30 | +are passed in as a byte array, not a string. A utility is provided to convert |
| 31 | +your strings to a byte array. |
| 32 | +
|
| 33 | +The following code snippets from chaincode_example04 demonstrate the difference. |
| 34 | +Make note of `f`, representing the function invoke. It is removed from the |
| 35 | +InvokeChaincode parameters, and instead passed as an argument to the invokeArgs |
| 36 | +element. The arguments are then converted to a byte array before being passed |
| 37 | +to InvokeChaincode. This change is not optional and must be implemented in |
| 38 | +your code. |
| 39 | +
|
| 40 | + ```go |
| 41 | +// fabric v0.5-developer-preview |
| 42 | +f := "invoke" |
| 43 | +invokeArgs := []string{"a", "b", "10"} |
| 44 | +response, err := stub.InvokeChaincode(chainCodeToCall, f, invokeArgs) |
| 45 | +``` |
| 46 | +
|
| 47 | + ```go |
| 48 | +// fabric v0.6.1-preview code |
| 49 | +f := "invoke" |
| 50 | +// function is removed from InvokeChaincode, now passed as an argument within |
| 51 | +// invokeArgs. invokeArgs is converted to byte array and then passed along. |
| 52 | +invokeArgs := util.ToChaincodeArgs(f, "a", "b", "10") |
| 53 | +response, err := stub.InvokeChaincode(chainCodeToCall, invokeArgs) |
| 54 | +``` |
| 55 | +
|
| 56 | +* Chaincode APIs have changed when constructing REST API payloads and CLI |
| 57 | +commands. |
| 58 | +
|
| 59 | +The function can now be passed within the "args" element as the |
| 60 | +first argument. The following code snippets will demonstrate the changes to a |
| 61 | +basic chaincode invoking transaction from the CLI and through the REST API. |
| 62 | +
|
| 63 | +``` |
| 64 | +peer chaincode invoke -1 golang -n mycc -c '{"Function": "invoke", "Args": ["a", "b", "10"]}' |
| 65 | + |
| 66 | +peer chaincode invoke -1 golang -n mycc -c '{"Args": ["invoke", "a", "b", "10"]}' |
| 67 | +``` |
| 68 | +
|
| 69 | +```JSON |
| 70 | +{ |
| 71 | + "jsonrpc": "2.0", |
| 72 | + "method": "invoke", |
| 73 | + "params": { |
| 74 | + "type": 1, |
| 75 | + "chaincodeID":{ |
| 76 | + "name":"mycc" |
| 77 | + }, |
| 78 | + "ctorMsg": { |
| 79 | + "function":"invoke", |
| 80 | + "args":["a", "b", "10"] |
| 81 | + } |
| 82 | + }, |
| 83 | + "id": 3 |
| 84 | +} |
| 85 | +``` |
| 86 | +
|
| 87 | +```JSON |
| 88 | +{ |
| 89 | + "jsonrpc": "2.0", |
| 90 | + "method": "invoke", |
| 91 | + "params": { |
| 92 | + "type": 1, |
| 93 | + "chaincodeID":{ |
| 94 | + "name":"mycc" |
| 95 | + }, |
| 96 | + "ctorMsg": { |
| 97 | + "args":["invoke", "a", "b", "10"] |
| 98 | + } |
| 99 | + }, |
| 100 | + "id": 3 |
| 101 | +} |
| 102 | +``` |
| 103 | +
|
| 104 | +**Note**: REST API and CLI developed in fabric v0.5-developer-preview will work |
| 105 | +with fabric v0.6.1-preview. However, when using the Java SDK you must implement |
| 106 | +the new format, where the function is passed within the "args" element. |
| 107 | +
|
| 108 | +# New Features |
| 109 | +
|
| 110 | +1. Custom Events & Event handler: |
| 111 | +
|
| 112 | +The fabric now has the ability to create custom events and emit this information |
| 113 | +to a client-side node application leveraging the hfc SDK. This is done by |
| 114 | +implementing the EventHub Service in your node program. The EventHub Service |
| 115 | +listens for events. |
| 116 | +
|
| 117 | +You can customize the eventsender.go code to determine which events you want |
| 118 | +sent. In the example, only the invoke transaction type is coded to send outgoing |
| 119 | +events. See the following code snippet in eventsender.go which demonstrates |
| 120 | +invocations being broadcast by the event sender: |
| 121 | +
|
| 122 | + ```go |
| 123 | +func (t *EventSender) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { |
| 124 | + b, err := stub.GetState("noevents") |
| 125 | + if err != nil { |
| 126 | + return nil, errors.New("Failed to get state") |
| 127 | + } |
| 128 | + // define the construct for the event |
| 129 | + noevts, _ := strconv.Atoi(string(b)) |
| 130 | + |
| 131 | + tosend := "Event " + string(b) |
| 132 | + for _, s := range args { |
| 133 | + tosend = tosend + "," + s |
| 134 | + } |
| 135 | + // create the event based on the construct |
| 136 | + err = stub.PutState("noevents", []byte(strconv.Itoa(noevts+1))) |
| 137 | + if err != nil { |
| 138 | + return nil, err |
| 139 | + } |
| 140 | + // pass the event along for Event Listener service |
| 141 | + err = stub.SetEvent("evtsender", []byte(tosend)) |
| 142 | + if err != nil { |
| 143 | + return nil, err |
| 144 | + } |
| 145 | + return nil, nil |
| 146 | +} |
| 147 | +``` |
| 148 | +
|
| 149 | +Enable the event service in your node program with the following steps: |
| 150 | +
|
| 151 | + ```go |
| 152 | +// set the port where the event service will listen |
| 153 | +chain.eventHubConnect("localhost:7053"); |
| 154 | + |
| 155 | +// Get the eventHub service associated with the chain |
| 156 | +var eventHub = chain.getEventHub(); |
| 157 | + |
| 158 | +// Register on a specific chaincode for a specific event - syntax example only |
| 159 | +eventHub.registerChaincodeEvent(<chaincode ID>, <event name>, <callback>); |
| 160 | +// actual code example |
| 161 | +var registrationId = eh.registerChaincodeEvent("b16cec7aa4466f57dd18f3c159b85d2962e741824c702136fdfcf616addcec01", "evtsender", function(event) { |
| 162 | + console.log(util.format("Custom event received, payload: %j\n", event.payload.toString())); |
| 163 | +}); |
| 164 | + |
| 165 | +//Unregister events or a specific chaincode |
| 166 | +eventHub.unregisterChaincodeEvent(registrationID); |
| 167 | + |
| 168 | +// disconnect when done listening for events |
| 169 | +process.on('exit', function() { |
| 170 | + chain.eventHubDisconnect(); |
| 171 | +}); |
| 172 | +``` |
| 173 | +
|
| 174 | +Explore the full library of the [sample event application](https://github.com/ratnakar-asara/NodeSDKSample/tree/master/events) |
| 175 | +for the application source code and deeper documentation. |
| 176 | +
|
| 177 | +1. Java chaincode shim - new shim library to support java chaincode interacting |
| 178 | +with Hyperledger fabric. See the [java shim](fabric/core/chaincode/shim/java) |
| 179 | +library for the source code. |
| 180 | +
|
| 181 | +1. Ability to call chaincode using a 64encoded string. A custom UnmarshalJSON |
| 182 | +method for ChaincodeInput allows for string-based REST/JSON input, which is then |
| 183 | +converted to []byte-based. This allows browsers to pass in string or binary |
| 184 | +arguments to the application driving the chaincode. |
| 185 | +
|
| 186 | +1. Docker client upgrade to [Docker 1.12](https://blog.docker.com/2016/07/docker-built-in-orchestration-ready-for-production-docker-1-12-goes-ga/). |
| 187 | +
|
| 188 | +1. Peer and Member Service images available on [Hyperledger Dockerhub](https://hub.docker.com/r/hyperledger/). The images are part of the |
| 189 | +continuous integration process and built with every new code change. |
| 190 | +
|
| 191 | +1. New warnings for chaincode development. The following practices can lead to |
| 192 | +malfunctioning and/or non-deterministic chaincode and should be avoided: |
| 193 | +
|
| 194 | +* Iterating using GetRows |
| 195 | +* Using associative arrays with iteration (the order is randomized in Go) |
| 196 | +* Reading list of items from KVS table (the order is not guaranteed). Use ordering |
| 197 | +* Writing thread-unsafe chaincode where invoke and query may be called in parallel |
| 198 | +* Substituting global memory or cache storage for ledger state variables in the chaincode |
| 199 | +* Accessing external services (e.g. databases) directly from the chaincode |
| 200 | +* Using libraries or globabl variables that could introduce non-determinism (e.g. "random" or "time") |
| 201 | +
|
| 202 | +1. For templates of deterministic and properly-written chaincode, see the [examples](fabric/examples/chaincode) library. This directory contains samples |
| 203 | +written in Go and Java. |
| 204 | +
|
| 205 | +1. Fabric Starter Kit - This section describes how to set up a self-contained |
| 206 | +environment for application development with the Hyperledger fabric. The setup |
| 207 | +uses **Docker** to provide a controlled environment with all the necessary |
| 208 | +Hyperledger fabric components to support a Node.js application built with |
| 209 | +the fabric's Node.js SDK, and chaincode written in Go. |
| 210 | +
|
| 211 | +There are three Docker images that, when run, will provide a basic |
| 212 | +network environment. There is an image to run a single `peer`, one to run |
| 213 | +the `membersrvc`, and one to run both your Node.js application and your |
| 214 | +chaincode. |
| 215 | +
|
| 216 | +1. [Fabric boilerplate](https://github.com/IBM-Blockchain/fabric-boilerplate) - |
| 217 | +The public IBM-Blockchain repo now contains a boilerplate application to help |
| 218 | +application developers quickly create a network and deploy and app. The network |
| 219 | +can be spun up locally using Docker containers or through a Bluemix instance of |
| 220 | +the blockchain service. |
| 221 | +
|
| 222 | +1. Fabric v0.6 provides the ability to dynamically register and enroll users |
| 223 | +with attributes through the hfc SDK. |
| 224 | +See [asset-mgmt-with-dynamic-roles.js](fabric/sdk/node/test/unit/asset-mgmt-with-dynamic-roles.js) |
| 225 | +as an example. The hfc SDK previously allowed you to dynamically enroll users, |
| 226 | +but these users were already registered and aligned with attributes/affiliations |
| 227 | +hardcoded in the membersrvc.yml. Now a user with `registrar` authority can |
| 228 | +register and enroll unique users to the network. See the following code snippets |
| 229 | +as an example of dynamic registration: |
| 230 | +
|
| 231 | +```js |
| 232 | +// call the registerAndEnroll function to add a unique user to the network |
| 233 | +// (i.e. a user not present in the membersrvc.yml) |
| 234 | +// below we see "assigner2" being registered and enrolled with two unique |
| 235 | +// attributes - a 'role' with the value of 'client' and an 'account' with the |
| 236 | +// value of 'aliceAccount' |
| 237 | +console.log("enrolling alice2 ..."); |
| 238 | +registerAndEnroll("alice2",[{name:'role',value:'client'},{name:'account',value:aliceAccount}], function(err,user) { |
| 239 | + if (err) return cb(err); |
| 240 | + alice = user; |
| 241 | +``` |
| 242 | +
|
| 243 | +```js |
| 244 | +// define the funtion |
| 245 | +function registerAndEnroll(name, attrs, cb) { |
| 246 | + console.log("registerAndEnroll name=%s attrs=%j",name,attrs); |
| 247 | + var registrationRequest = { |
| 248 | + roles: [ 'client' ], |
| 249 | + enrollmentID: name, |
| 250 | + affiliation: "bank_a", |
| 251 | + attributes: attrs |
| 252 | + }; |
| 253 | + chain.registerAndEnroll(registrationRequest,cb); |
| 254 | +} |
| 255 | +``` |
0 commit comments