├── .gitignore ├── README.md └── fabric ├── configtx.yml ├── crypto-config.yaml ├── docker-compose.yaml ├── fabricOps.sh └── scripts ├── channelname.sh ├── instantiate.sh ├── invoke.sh └── upgrade.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | fabric/tools/ 3 | fabric/channel-artifacts/ 4 | fabric/crypto-config/ 5 | fabric/logs/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The purpose of this document is to provide you with minimal knowledge of Go and Hyperledger Fabric (Fabric for short) infrastructure to enable you to start writing and debugging chaincode. This is not an extensive lession but you will have gained sufficient knowledge to move on to developing real-world chaincode. 4 | 5 | This document is intended for anyone with programming experience but having **no** or **very little experience** of Go and chaincode development. However, you are expected to be sufficiently familiar with the concept of compilation and packaging, as Go is a compiled, not scripting, langauge. 6 | 7 | In this document, you will learn to: 8 | 9 | * [Setup for chaincode development](#setupDevEnv) 10 | 11 | * [Minimal Go for chaincode development](#learnGo) 12 | 13 | * [Write chaincodes](#goForChaincode) 14 | 15 | * [Hyperledger fabric for chaincode development](#fabricForDevelopment) 16 | 17 | * [Debugging chaincode](#debugChaincode) 18 | 19 | * [Moving on](#movingOn) 20 | 21 | # Setup for chaincode development 22 | 23 | Setting up a development environment for chaincode projects is no different from setting up for other non chaincode Go projects. 24 | 25 | For a basic (terminal and command-line) environment for chaincode development, please follow the following steps: 26 | 27 | 1. Install [Go tools](http://golang.org/dl). 28 | 29 | * for macOS, we recommend installing via [homebrew](http://brew.sh/); 30 | 31 | * for other platforms please refer to [installation guide](https://golang.org/doc/install). 32 | 33 | Additional notes for this setp: 34 | 35 | * Please also ensure that you also install C++ compiler. Refer to your respective platform documentation for instructions. 36 | 37 | * On Ubuntu you may also need to install a library call `ltdl` (please refer to `apt-get install ltdl-dev`). 38 | 39 | 1. Set the environmental variable `GOPATH` to a reference a directory to host your Go source codes and binaries (i.e. Go workspace). For example, 40 | 41 | ``` 42 | export GOPATH=$HOME/go-projects 43 | ``` 44 | 45 | 1. Navigate to the `$GOPATH` directory and install a Go application call [Govendor](https://github.com/kardianos/govendor) by executing this command: 46 | 47 | ``` 48 | go get -u github.com/kardianos/govendor 49 | ``` 50 | 51 | At the completion of the command, you will find in `$GOPATH` three directories: 52 | 53 | ``` 54 | drwxr-xr-x 3 102 3 Feb 15:44 bin 55 | drwxr-xr-x 3 102 3 Feb 15:44 pkg 56 | drwxr-xr-x 3 102 3 Feb 15:44 src 57 | ``` 58 | 59 | This structure is dictated by Go tooling and will be your primary workspace for organising your chaincodes and and other dependencies such as third parties codes, tooling extensions, etc. 60 | 61 | In the context of chaincode development, you will be working mainly with Go sources. Hence, you only need to concern yourself with organising stuff within `src` directory. 62 | 63 | Additional notes for this step: 64 | 65 | * This step is not strictly needed. You could have create the workspace directories manually. 66 | 67 | * [Govendor](https://github.com/kardianos/govendor) is a package or dependency management tool. It is one of many tools you can use to manage Go dependencies. The choice of `Govendor` is purely based on familarity. You could elect to install [other tools](https://github.com/golang/go/wiki/PackageManagementTools)). 68 | 69 | 1. Add the `$GOPATH/bin` to your `PATH` environmental variable. For example: 70 | 71 | ``` 72 | export PATH=$GOPATH/bin:$PATH 73 | ``` 74 | 75 | `$GOPATH/bin` is a directory for binaries generated from Go compilations. Some of these binaries may be used to extend the functionalities of Go tooling or any other support tools. If you are using [Visual Studio Code](https://code.visualstudio.com/), you will find extensions to the editor such as code completion or syntax highlighting, served from this directory. 76 | 77 | 1. Get the Fabric dependencies (the framework to support your chaincode developmemnt) by issuing the following commands: 78 | 79 | ``` 80 | go get -d github.com/hyperledger/fabric 81 | ``` 82 | 83 | At the completion of this command, you will see this message: 84 | 85 | ``` 86 | package github.com/hyperledger/fabric: no buildable Go source files in /Users/blockchain/workspace/misc/src/github.com/hyperledger/fabric 87 | ``` 88 | 89 | There is no need to worry. Go tooling typically pull source code and then tries to build a binary but in this case the hyperledger fabric dependencies have nothing to be built. 90 | 91 | If you wish to ensure that the dependencies have been pulled down, simply navigate to `$GOPATH/src/github.com` and if you see the directory `hyperledger` it means that dependencies have been downloaded. 92 | 93 | # Minimal Go for Chaincode 94 | 95 | If you are already and experience Go programmer you can skip this section. 96 | 97 | To learn about Go progranmning language, please refer to these resources: 98 | 99 | * [Go playground](https://play.golang.org/) - This a a web-base development environment where you can learn to code in Go without the need to setup a local development environment. 100 | 101 | * [Go by example](https://gobyexample.com/) - This is a series of code snippets demonstrating features of Go by theme. 102 | 103 | To create a minimal chaincode focus your learning on these areas 104 | 105 | * [data types](https://gobyexample.com/variables); 106 | 107 | * [functions](https://gobyexample.com/functions); 108 | 109 | * [structs](https://gobyexample.com/structs); 110 | 111 | * [interfaces](https://gobyexample.com/interfaces). 112 | 113 | You will also need to be aware that all your Go codes (and chaincodes) have to be organised around `$GOPATH/src` directory. For example, here is a hypothetical structure: 114 | 115 | ``` 116 | $GOPATH/src 117 | git.ng.bluemix.net/project/repo 118 | cmd 119 | main.go 120 | helper 121 | math.go 122 | github/spf13/corbra // Third parties code 123 | .... 124 | ``` 125 | 126 | Organise your code and dependencies to reflect the way codes would be stored in a typical Git-like repository. Please refer to the official documentation about [code organisation](https://golang.org/doc/code.html#Organization). 127 | 128 | # Writing chaincode 129 | 130 | In this section you will learn to: 131 | 132 | * [write the smallest unit of executable chaincode](#smallestchaincode); 133 | 134 | * [organise your chaincode project](#organiseChaincode). 135 | 136 | ### Smallest unit of executable chaincode 137 | 138 | A minimal executable Go code is this: 139 | 140 | ``` 141 | package main 142 | 143 | import "fmt" 144 | 145 | func main() { 146 | fmt.Printf("Hello, world.\n") 147 | } 148 | 149 | ``` 150 | 151 | To compile and execute this code all you need to do is to issue the command `go run`. It will run in your macOS, Linux, Windows or any compatible platform. 152 | 153 | In the case of chaincode, the [smallest unit of executable code](http://hyperledger-fabric.readthedocs.io/en/latest/chaincode4ade.html) is this: 154 | 155 | ``` 156 | package main 157 | 158 | import ( 159 | "fmt" 160 | 161 | "github.com/hyperledger/fabric/core/chaincode/shim" 162 | pb "github.com/hyperledger/fabric/protos/peer" 163 | ) 164 | 165 | type SimpleChaincode struct{} 166 | 167 | func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { 168 | return shim.Success([]byte("Init called")) 169 | } 170 | 171 | func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 172 | return shim.Success([]byte("Invoke called")) 173 | } 174 | 175 | func main() { 176 | err := shim.Start(new(SimpleChaincode)) 177 | if err != nil { 178 | fmt.Printf("Error: %s", err) 179 | } 180 | } 181 | ``` 182 | 183 | Place your code in the file `chaincode.go` under the appropriate part of your Go workspace for example, `$GOPATH/src/github.com/user/repo/chaincode.go`. 184 | 185 | To get a sense of whether the code is workable, navigate to the directory containing your main chaincode file and execute `go run` command. For example: 186 | 187 | ``` 188 | cd $GOPATH/src/github.com/user/repo/ 189 | go run chaincode.go 190 | ``` 191 | 192 | You will see the following output: 193 | 194 | ``` 195 | [shim] SetupChaincodeLogging -> INFO 001 Chaincode log level not provided; defaulting to: INFO 196 | [shim] getPeerAddress -> CRIT 002 peer.address not configured, can't connect to peer 197 | exit status 1 198 | ``` 199 | 200 | This simply indicates that the chaincode has been successfully compiled and your code has been executed. However, there is no running Fabric infastructure to interact with so you see this error message. 201 | 202 | Unlike normal Go program, you can't just compile and run chaincode in macOS, Linux, Windows, etc. Instead you will need to bundle the code and deploy it to a running Fabric platform known as a **Fabric peer** (see [architecture](http://hyperledger-fabric.readthedocs.io/en/latest/arch-deep-dive.html#system-architecture) for detailed explanation). 203 | 204 | A Fabric peer typically runs in a Docker container. You could "natively" deploy a peer as part of a component of macOS, Linux, Windows, etc., but is beyond the scope of this document to discuss these types of configuration. We'll only focus on the Docker deployment here. 205 | 206 |
207 | 208 | **Note** 209 | 210 | * In the `import` clause of your chaincode, you'll see this `github.com/hyperledger/fabric/core/chaincode/shim`, which is a Fabric component (i.e. think library if you are C++ programmer). 211 | 212 | * The `import` is derived from `$GOPATH/src/github.com/hyperledger/fabric`. 213 | 214 |
215 | 216 | ### Organising your chaincode project 217 | 218 | It is extremely unusual to create a chaincode from a single file. 219 | 220 | You may want to re-use aspects of a Go code developed by third parties and/or separate out your functional from non-functional (e.g. string formatter) dependencies. Hence, you may want to distribute chaincode in different files and/or directories. 221 | 222 | If you were working on a Go project you would organise your dependencies this way: 223 | 224 | ``` 225 | $GOPATH/ 226 | src/ 227 | github.com/anotheruser/repo/ 228 | anothersrc.go 229 | github.com/user/repo/ 230 | mypkg/ 231 | mysrc1.go 232 | mysrc2.go 233 | cmd/mycmd/ 234 | main.go 235 | ``` 236 | 237 | Your Go project `github.com/user/repo` is dependent on `github.com/anotheruser/repo` to provide a service. This is a sufficient structure to compile and run code on macOS, Linux, Windows, etc. 238 | 239 | In the case of chaincode development, that structure will not work. You will need to organise all your dependencies under one root directory and then deploy the root directory to a Fabric peer. 240 | 241 | Here is an example of a hypothetical chaincode project with dependencies in a vendor folder: 242 | 243 | ``` 244 | $GOPATH/ 245 | src/ 246 | github.com/user/repo/ 247 | mychaincode/ 248 | util/ 249 | mymaths.go 250 | chaincode.go 251 | vendor/ 252 | github.com/anotheruser/repo 253 | anothersrc1.go 254 | anothersrc2.go 255 | vendor.json 256 | ``` 257 | In this example: 258 | 259 | * `mychaincode` is the root directory encapsulating your entire chaincode artifacts including dependencies; 260 | 261 | * `util` is an example custom directory created by you to support your chaincode; 262 | 263 | * `vendor` is a special directory (with a file `vendor.json`) typically to package dependencies not located at the chaincode root or dependencies from third parties (see detailed explanations of the use of [vendor folder](https://blog.gopheracademy.com/advent-2015/vendor-folder/)); 264 | 265 | * `github.com/anotheruser/repo` is a dependency that is referenced by `chaincode.go`, which would have existed outside you chaincode root folder but it is now in the vendor folder. 266 | 267 | You can manually create and provision the `vendor` directory but using tools makes it easier. As per the [setup step](#setupDevEnv), let's use `Govendor` to `vendor` your dependencies: 268 | 269 | 1. Navigate to `$GOPATH/src/github.com/user/repo/mychaincode` and execute this command: 270 | 271 | ``` 272 | govendor init 273 | ``` 274 | 275 | You should see a directory call `vendor`. 276 | 277 | 1. In the directory `vendor` add the following line to `vendor.json`: 278 | 279 | ``` 280 | "ignore": "test github.com/hyperledger/fabric" 281 | ``` 282 | 283 | This line tells `govendor` not to include `github.com/hyperledger/fabric` and test dependencies. You don't need to include hyperledger fabric dependency because it is part of the fabric peer infrastructure. 284 | 285 | 1. We are going to `vendor` a third party dependency `github.com/anotheruser/repo` by issuing this command: 286 | 287 | ``` 288 | govendor fetch github.com/anotheruser/repo 289 | ``` 290 | 291 | If no error you will see the dependencies stored in `vendor` directory. 292 | 293 |
294 | 295 | **Note:** 296 | 297 | * Go (and chaincode) tooling typically search for dependencies from $GOPATH but the presence of `vendor` will enable Go tool to search there first. 298 | 299 | * What if I wish to re-use another project that is outside the chaincode root directory in the Go workspace but not yet in say github.com repo? 300 | 301 | * For example, this is my code structure: 302 | 303 | ``` 304 | $GOPATH/ 305 | src/ 306 | github.com/user/another-repo/ 307 | support/ 308 | superduper-support.go 309 | superduper-algo.go 310 | github.com/user/repo/ 311 | mychaincode/ 312 | chaincode.go 313 | util/ 314 | mymaths.go 315 | vendor/ 316 | github.com/user/another-repo 317 | support/ 318 | superduper-support.go 319 | superduper-algo.go 320 | vendor.json 321 | ``` 322 | 323 | I wish to vendor `github.com/user/another-repo/`, but it does not yet exists in my `github.com` repo, into `mychaincode` directory. 324 | 325 | In this case run the command `govendor add github.com/user/another-repo`. You could also use this command `govendor add +external`. This will pull **ALL** the artefacts in `$GOPATH` into `vendor` folder. 326 | 327 | It is beyond the scope of this document to discuss all use cases pertaining to `govendor`. Please refer to [Govendor documentation](https://github.com/kardianos/govendor) for details. 328 | 329 |
330 | 331 | # Fabric for chaincode development 332 | 333 | In this section, you will learn: 334 | 335 | * [about roles of the components of a minimal Fabric](#minimalFabric); 336 | 337 | * [setup a minimal Fabric infrastructure](#setupMinimalFabric) 338 | 339 | ### Roles of minimal Fabric infrastructure 340 | 341 | In order to see your chaincode in action, you'll need to setup Fabric infrastructure and deploy your chaincode there. A full featured running Fabric infrastructure has many components. 342 | 343 | For the purpose of document, we'll focus on the most minimal Fabric infrastructure to enable you to probe a running chaincode. 344 | 345 | We'll be using Docker. If you have not setup Docker please refer to [documentation](https://www.docker.com/community-edition#/download). You can see an example of a minimal infrastructure configuration [here](./fabric/docker-compose.yml). 346 | 347 | The docker containers that comprise a minimal Fabric infastructure are: 348 | 349 | * `orderer.example.com` where it's role is beyond the scope of document and for simplicity just think of it as a manager for the next component; 350 | 351 | * `peer0.org1.example.com` is the container that will be responsible for spinning up another container to support your running chaincode; 352 | 353 | * `cli` is a command line container that you use to interact with `peer0.org1.example.com`. 354 | 355 |
356 | 357 | **NOTE** 358 | 359 | This is not an setup for use in, or representative of, any mission critical blockchain use case. This is only to support a simple chaincode development process by enabling developer to get feedback from a running chaincode. 360 | 361 | There are also other aspects of the hyperledger fabric infrastructure that is beyond the scope of this document. These are cryptography components, which need not concern you for current discussion. 362 | 363 | For detailed descriptions of the roles of hyperledger fabric components, please refer to hyperledger fabric [architecture explained](http://hyperledger-fabric.readthedocs.io/en/latest/arch-deep-dive.html). 364 | 365 |
366 | 367 | ### Setup a minimal hyperledger fabric 368 | 369 | The components to enable you to orchestrate a minimal hyperledger fabric infrastructure is provided together with this document when you check-out this repo. You can find it [here](./fabric). 370 | 371 | Navigate to location containing the minimal fabric component `cd $GOPATH/src/github.com/hlf-go/writing-chaincode/fabric`. You will find the following items 372 | 373 | * `docker-compose.yml` for configuring docker containers; 374 | 375 | * membership polcy assets configuration file (`configtx.yml`) and crypto config (`crypto-config.yaml`) file; 376 | 377 | * a collection of scripts to install, instantiate and invoke chaincode (see folder `scripts`); 378 | 379 | * a script to help you generate your tiny fabric network (`fabricOps.sh`). 380 | 381 | In the case of [fabricOps.sh](.fabric/fabricOps.sh), you use it to: 382 | 383 | | Command | Action | Comments | 384 | |---|---|---| 385 | | `fabricOps.sh start` | Start a running fabric infrastructure | This command will generate cryptographic assets based on `configtx.yml` and `crypto config` that are needed for `peer0.org1.example.com` to work with `orderer.example.com` containers as specified in the `docker-compose.yaml` file | 386 | | `fabricOps.sh status` | Check status of docker containers | This operation is used to check the status of your docker containers.

This example shows all the relevant containers are running properly:
dev-peer0.org1.example.com-mycc-1.0: Up 24 seconds
peer0.org1.example.com: Up 26 minutes
cli: Up 26 minutes
orderer.example.com: Up 26 minutes
| 387 | | `fabricOps.sh clean` | Reset the fabric infrastructure | This operation removes cryptographic and docker artefacts.

**NOTES:**
This will remove **ALL** docker containers and images that are currently running in your machine. There is an option to only remove containers that are only responsible for running chaincodes (typically with a name containing `dev-` prefix). It should not impact any docker containers that you may already have in operation. Please modify `fabricOps.sh` accordingly. | 388 | | `fabricOps.sh cli` | This operation gives you access to fabric `cli` | You will be given access to `cli`'s own terminal. From there you can then execute chaincode related operations which we'll discussion on the next sections | 389 | | `ccview ` | View output of a particular chaincode and version | Specify the named you assigned to the chaincode `` e.g. "mycc" and the version of chaincode `` e.g. 1.0, 1.1, etc. You will be able to see output generated by Go console logging statement (e.g. `fmt.Print`) | 390 | 391 |
392 | 393 | **Windows** 394 | 395 | There is currently no out-of-the-box support for Windows platform. The script `fabricOps.sh` only supports macOS or Linux. 396 | 397 | For Windows user, please study the script and modify a version that is appropriate for your platform. 398 | 399 |
400 | 401 | # Debugging chaincode 402 | 403 | In this section, you will learn to execute a simple chaincode and debug your chaincode using the infrastructure described above. 404 | 405 | To help you get going with your learning, please follow the following steps: 406 | 407 | 1. Assume you have gone through the [setup minimal fabric step](#setupMinimalFabric), you should find the following in your Go workspace: 408 | 409 | ``` 410 | $GOPATH/src/github.com/hlf-go/ 411 | writing-chaincode/ 412 | fabric 413 | ``` 414 | 415 | Please refer to the `README.md` for instruction on how to attach and detach chaincodes for debugging. 416 | 417 | 1. When you execute `fabric.sh` (any commands) it will download `github.com/hlf-go/example-chaincodes`. You will find this in your Go workspace: 418 | 419 | ``` 420 | $GOPATH/src/github.com/hlf-go/ 421 | writing-chaincode/ 422 | fabric/ 423 | example-chaincodes/ 424 | minimalcc/ 425 | chaincode.go 426 | .... 427 | ``` 428 | 429 | 1. Navigate to `$GOPATH/src/github.com/hlf-go/writing-chaincode/fabric` and execute this command (on macOS and Linux only): 430 | 431 | ``` 432 | ./fabricOps.sh start 433 | ``` 434 | 435 | This will take sometime. The process will download docker images and setup your docker containers. 436 | 437 | 1. Execute the following command: 438 | 439 | ``` 440 | ./fabricOps.sh cli 441 | ``` 442 | 443 | In your bash terminal, you will be presented with the terminal running from the `cli` container: 444 | 445 | ``` 446 | root@:/opt/gopath/src/github.com/hyperledger/fabric/peer# 447 | ``` 448 | 1. In the `cli` execute appropriate commands: 449 | 450 | * To deploy a brand new chaincode. 451 | ``` 452 | root@:/opt/gopath/src/github.com/hyperledger/fabric/peer# ./scripts/instantiate.sh 453 | ``` 454 | You can get instruction on the appropriate flag settings by running the command `instantiate.sh`. 455 | 456 | * To deploy an upgraded version of the chaincode 457 | ``` 458 | root@:/opt/gopath/src/github.com/hyperledger/fabric/peer# ./scripts/upgrade.sh 459 | ``` 460 | You can get instruction on the appropriate flag settings by running the command `install.sh`. 461 | 462 | * To invoke a particular chaincode transaction. 463 | ``` 464 | root@:/opt/gopath/src/github.com/hyperledger/fabric/peer# ./scripts/invoke.sh 465 | ``` 466 |
467 | 468 | **Note:** 469 | 470 | * All the chaincode for deployment are held in directory `/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go` in the `cli` container. When using the script to deploy the chaincode all you need to do is to specify the root folder containing the chaincode of your choice. For example, if you have a chaincode packaged in `/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go/minimalcc`, simply specify the name `minimalcc` as the chaincode package you wish to deploy. 471 | 472 | * The term "deploy" is used loosely here. It is actually a two-step process. You perform an installation and then instantiation or upgrade of a chaincode. 473 | 474 | * If you deploy and invoke [`$GOPATH/src/github.com/hlf-go/example-chaincodes/minimalcc/chaincode.go`](https://github.com/hlf-go/example-chaincodes/blob/master/minimalcc/chaincode.go). It will produce the following console output `Hello Init` when the chaincode method `Init` is called. `Hello Invoke` when the chaincode method `Invoke` is called. 475 | 476 |
477 | 478 | 1. Open another terminal, navigate to `$GOPATH/src/github.com/hlf-go/writing-chaincode/fabric` and execute this command: 479 | 480 | ``` 481 | ./fabricOps.sh ccview 482 | ``` 483 | Specify the chaincode and its version you wish to inspect. For example, if you wish to inspect the chaincode name `minimalcc` and version `1.0`. 484 | 485 | ``` 486 | ./fabricOps.sh ccview minimalcc 1.0 487 | ``` 488 | 489 | Assuming the chaincode has been properly deployed and invoked, it should produce the following output: 490 | 491 | ``` 492 | Hello Init 493 | Hello Invoke 494 | ``` 495 | 496 | # Moving on 497 | 498 | The training materials presented here are extremely stunted to help you understand basic concepts. It does not necessarily represent the only way of working. There are other ways of approaching your chaincode development. 499 | 500 | Once you have mastered basic concepts, you are encourage to: 501 | 502 | * Consider the use of more sophisticated testing framework to verify your chaincode. Use Go unit testing framework and Fabric's mock. 503 | 504 | * Develop more complex chaincode. Please reference the [hyperledger fabric samples](https://github.com/hyperledger/fabric-samples) or [here](https://github.com/hlf-go/example-chaincodes) for inspiration. 505 | 506 | * Work with more complex Fabric configurations, please refer to this [repo](https://github.com/ibm-silvergate/netcomposer) for more complex Fabric setup. 507 | 508 | * Organise all your Go and non-Go (Java, Javascripts, etc) projects based on Go-style workspace as this will help you reference projects easily via the variable `$GOPATH`. Here is an example: 509 | 510 | ``` 511 | $GOPATH/ 512 | bin/ 513 | 514 | pkg/ 515 | config-files/ 516 | ..... 517 | / 518 | ..... 519 | src/ 520 | github.com/user/ 521 | javascript-ui/ 522 | ..... 523 | package.json 524 | fabric-node-sdk-middleware/ 525 | ..... 526 | package.json 527 | fabric-go-sdk-middleware/ 528 | ...... 529 | main.go 530 | chaincodes/ 531 | chaincode.go 532 | github.com/thirdparty/ 533 | some-project/ 534 | ...... 535 | ``` 536 | 537 | # Disclaimer 538 | 539 | The methodologies discussed in this document and artefacts in this repository are intended only to illustrate concepts and are for educational purpose. 540 | 541 | There is no guarantee that these artefacts are free from defects and are **NOT** intended for used in any mission critical, corporate or regulated projects. Should you choose to use them for these types of projects, you do so at your own risk. 542 | 543 | Unless otherwise specified, the artefacts in this repository are distributed under Apache 2 license. In particular, the chaincodes are provided on "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 544 | 545 | -------------------------------------------------------------------------------- /fabric/configtx.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ################################################################################ 3 | # 4 | # Profile 5 | # 6 | # - Different configuration profiles may be encoded here to be specified 7 | # as parameters to the configtxgen tool 8 | # 9 | ################################################################################ 10 | Profiles: 11 | 12 | MyOrgsOrdererGenesis: 13 | Orderer: 14 | <<: *OrdererDefaults 15 | Organizations: 16 | - *OrdererOrg 17 | Consortiums: 18 | MyConsortium: 19 | Organizations: 20 | - *Org1 21 | MyOrgsChannel: 22 | Consortium: MyConsortium 23 | Application: 24 | <<: *ApplicationDefaults 25 | Organizations: 26 | - *Org1 27 | 28 | ################################################################################ 29 | # 30 | # Section: Organizations 31 | # 32 | # - This section defines the different organizational identities which will 33 | # be referenced later in the configuration. 34 | # 35 | ################################################################################ 36 | Organizations: 37 | 38 | # SampleOrg defines an MSP using the sampleconfig. It should never be used 39 | # in production but may be used as a template for other definitions 40 | - &OrdererOrg 41 | # DefaultOrg defines the organization which is used in the sampleconfig 42 | # of the fabric.git development environment 43 | Name: OrdererOrg 44 | 45 | # ID to load the MSP definition as 46 | ID: OrdererMSP 47 | 48 | # MSPDir is the filesystem path which contains the MSP configuration 49 | MSPDir: crypto-config/ordererOrganizations/example.com/msp 50 | 51 | # turn off security for the channel 52 | AdminPrincipal: Role.MEMBER 53 | 54 | - &Org1 55 | # DefaultOrg defines the organization which is used in the sampleconfig 56 | # of the fabric.git development environment 57 | Name: Org1 58 | 59 | # ID to load the MSP definition as 60 | ID: Org1MSP 61 | 62 | MSPDir: crypto-config/peerOrganizations/org1.example.com/msp 63 | 64 | # turn off security for the peer 65 | AdminPrincipal: Role.MEMBER 66 | 67 | AnchorPeers: 68 | # AnchorPeers defines the location of peers which can be used 69 | # for cross org gossip communication. Note, this value is only 70 | # encoded in the genesis block in the Application section context 71 | - Host: peer0.org1.example.com 72 | Port: 7051 73 | 74 | ################################################################################ 75 | # 76 | # SECTION: Orderer 77 | # 78 | # - This section defines the values to encode into a config transaction or 79 | # genesis block for orderer related parameters 80 | # 81 | ################################################################################ 82 | Orderer: &OrdererDefaults 83 | 84 | # Orderer Type: The orderer implementation to start 85 | # Available types are "solo" and "kafka" 86 | OrdererType: solo 87 | 88 | Addresses: 89 | - orderer.example.com:7050 90 | 91 | # Batch Timeout: The amount of time to wait before creating a batch 92 | BatchTimeout: 2s 93 | 94 | # Batch Size: Controls the number of messages batched into a block 95 | BatchSize: 96 | 97 | # Max Message Count: The maximum number of messages to permit in a batch 98 | MaxMessageCount: 10 99 | 100 | # Absolute Max Bytes: The absolute maximum number of bytes allowed for 101 | # the serialized messages in a batch. 102 | AbsoluteMaxBytes: 98 MB 103 | 104 | # Preferred Max Bytes: The preferred maximum number of bytes allowed for 105 | # the serialized messages in a batch. A message larger than the preferred 106 | # max bytes will result in a batch larger than preferred max bytes. 107 | PreferredMaxBytes: 512 KB 108 | 109 | Kafka: 110 | # Brokers: A list of Kafka brokers to which the orderer connects 111 | # NOTE: Use IP:port notation 112 | Brokers: 113 | - 127.0.0.1:9092 114 | 115 | # Organizations is the list of orgs which are defined as participants on 116 | # the orderer side of the network 117 | Organizations: 118 | 119 | ################################################################################ 120 | # 121 | # SECTION: Application 122 | # 123 | # - This section defines the values to encode into a config transaction or 124 | # genesis block for application related parameters 125 | # 126 | ################################################################################ 127 | Application: &ApplicationDefaults 128 | 129 | # Organizations is the list of orgs which are defined as participants on 130 | # the application side of the network 131 | Organizations: -------------------------------------------------------------------------------- /fabric/crypto-config.yaml: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------- 2 | # "OrdererOrgs" - Definition of organizations managing orderer nodes 3 | # --------------------------------------------------------------------------- 4 | OrdererOrgs: 5 | # --------------------------------------------------------------------------- 6 | # Orderer 7 | # --------------------------------------------------------------------------- 8 | - Name: Orderer 9 | Domain: example.com 10 | # --------------------------------------------------------------------------- 11 | # "Specs" - See PeerOrgs below for complete description 12 | # --------------------------------------------------------------------------- 13 | Specs: 14 | - Hostname: orderer 15 | # --------------------------------------------------------------------------- 16 | # "PeerOrgs" - Definition of organizations managing peer nodes 17 | # --------------------------------------------------------------------------- 18 | PeerOrgs: 19 | # --------------------------------------------------------------------------- 20 | # Org1 21 | # --------------------------------------------------------------------------- 22 | - Name: Org1 23 | Domain: org1.example.com 24 | # --------------------------------------------------------------------------- 25 | # "Specs" 26 | # --------------------------------------------------------------------------- 27 | # Uncomment this section to enable the explicit definition of hosts in your 28 | # configuration. Most users will want to use Template, below 29 | # 30 | # Specs is an array of Spec entries. Each Spec entry consists of two fields: 31 | # - Hostname: (Required) The desired hostname, sans the domain. 32 | # - CommonName: (Optional) Specifies the template or explicit override for 33 | # the CN. By default, this is the template: 34 | # 35 | # "{{.Hostname}}.{{.Domain}}" 36 | # 37 | # which obtains its values from the Spec.Hostname and 38 | # Org.Domain, respectively. 39 | # --------------------------------------------------------------------------- 40 | # Specs: 41 | # - Hostname: foo # implicitly "foo.org1.example.com" 42 | # CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above 43 | # - Hostname: bar 44 | # - Hostname: baz 45 | # --------------------------------------------------------------------------- 46 | # "Template" 47 | # --------------------------------------------------------------------------- 48 | # Allows for the definition of 1 or more hosts that are created sequentially 49 | # from a template. By default, this looks like "peer%d" from 0 to Count-1. 50 | # You may override the number of nodes (Count), the starting index (Start) 51 | # or the template used to construct the name (Hostname). 52 | # 53 | # Note: Template and Specs are not mutually exclusive. You may define both 54 | # sections and the aggregate nodes will be created for you. Take care with 55 | # name collisions 56 | # --------------------------------------------------------------------------- 57 | Template: 58 | Count: 1 59 | # Start: 5 60 | # Hostname: {{.Prefix}}{{.Index}} # default 61 | # --------------------------------------------------------------------------- 62 | # "Users" 63 | # --------------------------------------------------------------------------- 64 | # Count: The number of user accounts _in addition_ to Admin 65 | # --------------------------------------------------------------------------- 66 | Users: 67 | Count: 1 -------------------------------------------------------------------------------- /fabric/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | orderer.example.com: 6 | container_name: orderer.example.com 7 | image: hyperledger/fabric-orderer 8 | environment: 9 | - ORDERER_GENERAL_LOGLEVEL=DEBUG 10 | - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 11 | - ORDERER_GENERAL_GENESISMETHOD=file 12 | - ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block 13 | - ORDERER_GENERAL_LOCALMSPID=OrdererMSP 14 | - ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/crypto/orderer/msp 15 | working_dir: /opt/gopath/src/github.com/hyperledger/fabric 16 | command: orderer 17 | ports: 18 | - 7050:7050 19 | volumes: 20 | - ./channel-artifacts:/etc/hyperledger/configtx 21 | - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/etc/hyperledger/crypto/orderer/msp 22 | 23 | peer0.org1.example.com: 24 | container_name: peer0.org1.example.com 25 | image: hyperledger/fabric-peer 26 | environment: 27 | # Base configuration 28 | - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock 29 | - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric_default 30 | - CORE_LOGGING_LEVEL=DEBUG 31 | - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp 32 | # Peer specific configuraton 33 | - CORE_PEER_ID=peer0.org1.example.com 34 | - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 35 | - CORE_PEER_LOCALMSPID=Org1MSP 36 | working_dir: /opt/gopath/src/github.com/hyperledger/fabric 37 | command: peer node start --peer-defaultchain=false 38 | ports: 39 | - 7051:7051 40 | - 7053:7053 41 | volumes: 42 | - /var/run/:/host/var/run/ 43 | - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/msp/peer 44 | - ./crypto-config/peerOrganizations/org1.example.com/users:/etc/hyperledger/msp/users 45 | - ./channel-artifacts:/etc/hyperledger/channel-artifacts 46 | 47 | cli: 48 | container_name: cli 49 | image: hyperledger/fabric-tools 50 | tty: true 51 | environment: 52 | # Go tooling 53 | - GOPATH=/opt/gopath 54 | # Base configuration 55 | - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock 56 | - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric_default 57 | - CORE_LOGGING_LEVEL=DEBUG 58 | - CORE_CHAINCODE_LOGGING_LEVEL=DEBUG 59 | # cli peer specific setting 60 | - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 61 | - CORE_PEER_ID=cli 62 | - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 63 | - CORE_PEER_LOCALMSPID=Org1MSP 64 | working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer 65 | volumes: 66 | - /var/run/:/host/var/run/ 67 | - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto 68 | - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts 69 | - $GOPATH/src/github.com/hlf-go/example-chaincodes:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go 70 | -------------------------------------------------------------------------------- /fabric/fabricOps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ./scripts/channelname.sh 4 | 5 | PROJECT_DIR=$PWD 6 | 7 | ARGS_NUMBER="$#" 8 | COMMAND="$1" 9 | ARG_1="$2" 10 | ARG_2="$3" 11 | 12 | usage_message="Useage: $0 start | status | clean | cli | peer | ccview " 13 | 14 | function verifyArg() { 15 | 16 | if [ $ARGS_NUMBER -gt 3 -a $ARGS_NUMBER -lt 1 ]; then 17 | echo $usage_message 18 | exit 1; 19 | fi 20 | } 21 | 22 | function verifyGOPATH(){ 23 | 24 | if [ -z "$GOPATH" ]; then 25 | echo "Please set GOPATH" 26 | exit 1 27 | fi 28 | } 29 | 30 | OS_ARCH=$(echo "$(uname -s|tr '[:upper:]' '[:lower:]'|sed 's/mingw64_nt.*/windows/')-$(uname -m | sed 's/x86_64/amd64/g')" | awk '{print tolower($0)}') 31 | FABRIC_ROOT=$GOPATH/src/github.com/hyperledger/fabric 32 | 33 | function pullDockerImages(){ 34 | local FABRIC_TAG="x86_64-1.0.0" 35 | for IMAGES in peer orderer ccenv tools; do 36 | echo "==> FABRIC IMAGE: $IMAGES" 37 | echo 38 | docker pull hyperledger/fabric-$IMAGES:$FABRIC_TAG 39 | docker tag hyperledger/fabric-$IMAGES:$FABRIC_TAG hyperledger/fabric-$IMAGES 40 | done 41 | } 42 | 43 | function generateCerts(){ 44 | 45 | if [ ! -f $GOPATH/bin/cryptogen ]; then 46 | go get github.com/hyperledger/fabric/common/tools/cryptogen 47 | fi 48 | 49 | echo 50 | echo "----------------------------------------------------------" 51 | echo "----- Generate certificates using cryptogen tool ---------" 52 | echo "----------------------------------------------------------" 53 | if [ -d ./crypto-config ]; then 54 | rm -rf ./crypto-config 55 | fi 56 | 57 | $GOPATH/bin/cryptogen generate --config=./crypto-config.yaml 58 | echo 59 | } 60 | 61 | 62 | function generateChannelArtifacts(){ 63 | 64 | if [ ! -d ./channel-artifacts ]; then 65 | mkdir channel-artifacts 66 | fi 67 | 68 | if [ ! -f $GOPATH/bin/configtxgen ]; then 69 | go get github.com/hyperledger/fabric/common/configtx/tool/configtxgen 70 | fi 71 | 72 | echo 73 | echo "-----------------------------------------------------------------" 74 | echo "--- Generating channel configuration transaction 'channel.tx' ---" 75 | echo "-----------------------------------------------------------------" 76 | 77 | $GOPATH/bin/configtxgen -profile MyOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block 78 | 79 | echo 80 | echo "-------------------------------------------------" 81 | echo "--- Generating anchor peer update for Org1MSP ---" 82 | echo "-------------------------------------------------" 83 | $GOPATH/bin/configtxgen -profile MyOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNELNAME 84 | 85 | } 86 | 87 | function startNetwork() { 88 | 89 | echo 90 | echo "----------------------------" 91 | echo "--- Starting the network ---" 92 | echo "----------------------------" 93 | cd $PROJECT_DIR 94 | docker-compose up -d 95 | 96 | echo 97 | echo "----------------------------" 98 | echo "--- Initialising network ---" 99 | echo "----------------------------" 100 | docker exec peer0.org1.example.com peer channel create -o orderer.example.com:7050 -c $CHANNELNAME -f /etc/hyperledger/channel-artifacts/channel.tx 101 | docker exec peer0.org1.example.com peer channel join -b $CHANNELNAME.block 102 | 103 | } 104 | 105 | function cleanNetwork() { 106 | cd $PROJECT_DIR 107 | 108 | if [ -d ./channel-artifacts ]; then 109 | rm -rf ./channel-artifacts 110 | fi 111 | 112 | if [ -d ./crypto-config ]; then 113 | rm -rf ./crypto-config 114 | fi 115 | 116 | if [ -d ./tools ]; then 117 | rm -rf ./tools 118 | fi 119 | 120 | # This operations removes all docker containers and images regardless 121 | # 122 | docker rm -f $(docker ps -aq) 123 | docker rmi -f $(docker images -q) 124 | 125 | # This removes containers used to support the running chaincode. 126 | #docker rm -f $(docker ps --filter "name=dev" --filter "name=peer0.org1.example.com" --filter "name=cli" --filter "name=orderer.example.com" -q) 127 | 128 | # This removes only images hosting a running chaincode, and in this 129 | # particular case has the prefix dev-* 130 | #docker rmi $(docker images | grep dev | xargs -n 1 docker images --format "{{.ID}}" | xargs -n 1 docker rmi -f) 131 | } 132 | 133 | function networkStatus() { 134 | docker ps --format "{{.Names}}: {{.Status}}" | grep '[peer0* | orderer* | cli ]' 135 | } 136 | 137 | function dockerCli(){ 138 | docker exec -it cli /bin/bash 139 | } 140 | 141 | function ccview(){ 142 | docker logs dev-peer0.org1.example.com-$1-$2 143 | } 144 | 145 | function downloadExampleChaincodes(){ 146 | if [ ! -d $GOPATH/src/github.com/hlf-go/example-chaincodes ]; then 147 | go get -d github.com/hlf-go/example-chaincodes 148 | fi 149 | } 150 | 151 | # Network operations 152 | verifyArg 153 | verifyGOPATH 154 | downloadExampleChaincodes 155 | case $COMMAND in 156 | "start") 157 | generateCerts 158 | generateChannelArtifacts 159 | pullDockerImages 160 | startNetwork 161 | ;; 162 | "status") 163 | networkStatus 164 | ;; 165 | "clean") 166 | cleanNetwork 167 | ;; 168 | "cli") 169 | dockerCli 170 | ;; 171 | "ccview") 172 | if [ $ARGS_NUMBER -ne 3 ]; then 173 | echo $ARGS_NUMBER 174 | exit 1 175 | fi 176 | ccview $ARG_1 $ARG_2 177 | ;; 178 | *) 179 | echo $usage_message 180 | exit 1 181 | esac 182 | 183 | -------------------------------------------------------------------------------- /fabric/scripts/channelname.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CHANNELNAME="mychannel" -------------------------------------------------------------------------------- /fabric/scripts/instantiate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ./scripts/channelname.sh 4 | 5 | function usage(){ 6 | echo "Usage: $0 " 7 | echo "Mandatory:" 8 | echo " -c A unique string identifier" 9 | echo " -v A numeric number" 10 | echo " -p A name of folder containing chaincodes" 11 | echo "Optional:" 12 | echo " -a Must be in the form [\"method\", \"method-arg-1\", \"method-arg-2\"]" 13 | } 14 | 15 | if [ "$#" -eq "0" ]; then 16 | usage 17 | exit 18 | fi 19 | 20 | while getopts "a:c:p:v:" opt; do 21 | case $opt in 22 | a) 23 | CHAINCODE_CONSTRUCTOR=$OPTARG 24 | ;; 25 | c) 26 | CHAINCODEID=$OPTARG 27 | ;; 28 | p) 29 | CCHAINCODE_PACKAGE=$OPTARG 30 | ;; 31 | v) 32 | CHAINCODE_VERSION=$OPTARG 33 | ;; 34 | \?) 35 | usage 36 | exit 1 37 | ;; 38 | :) 39 | usage 40 | exit 1 41 | ;; 42 | esac 43 | done 44 | 45 | if [ -z $CHAINCODE_CONSTRUCTOR ]; then 46 | CHAINCODE_CONSTRUCTOR="[]" 47 | fi 48 | 49 | if [[ ! -z $CHAINCODEID && ! -z $CHAINCODE_VERSION && ! -z $CCHAINCODE_PACKAGE ]]; then 50 | 51 | path_to_chaincode="github.com/hyperledger/fabric/examples/chaincode/go/$CCHAINCODE_PACKAGE" 52 | echo "INSTALLING chaincode $CHAINCODEID version $CHAINCODE_VERSION in $path_to_chaincode" 53 | echo 54 | peer chaincode install -n $CHAINCODEID -v $CHAINCODE_VERSION -p $path_to_chaincode 55 | 56 | constructor="{\"Args\":$CHAINCODE_CONSTRUCTOR}" 57 | echo "INSTANTIATING chaincode $CHAINCODEID version $CHAINCODE_VERSION in $CHANNELNAME" 58 | echo "with constructor $constructor" 59 | echo 60 | peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNELNAME -n $CHAINCODEID -v $CHAINCODE_VERSION -c $constructor -P "OR ('Org1MSP.member')" 61 | else 62 | usage 63 | fi 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /fabric/scripts/invoke.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ./scripts/channelname.sh 4 | 5 | function usage(){ 6 | echo "Usage: $0 " 7 | echo "Mandatory:" 8 | echo " -c A unique string identifier" 9 | echo "Optional:" 10 | echo " -a Must be in the form [\"method\", \"method-arg-1\", \"method-arg-2\"]" 11 | } 12 | 13 | if [ "$#" -eq "0" ]; then 14 | usage 15 | exit 1 16 | fi 17 | 18 | while getopts "a:c:" opt; do 19 | case $opt in 20 | a) 21 | CHAINCODE_CONSTRUCTOR=$OPTARG 22 | ;; 23 | c) 24 | CHAINCODEID=$OPTARG 25 | ;; 26 | \?) 27 | usage 28 | exit 1 29 | ;; 30 | :) 31 | usage 32 | exit 1 33 | ;; 34 | esac 35 | done 36 | 37 | if [ -z $CHAINCODE_CONSTRUCTOR ]; then 38 | CHAINCODE_CONSTRUCTOR="[]" 39 | fi 40 | 41 | if [ ! -z $CHAINCODEID ]; then 42 | echo "INVOKING chaincode $CHAINCODEID in $CHANNELNAME" 43 | constructor="{\"Args\":$CHAINCODE_CONSTRUCTOR}" 44 | echo "with constructor $constructor" 45 | peer chaincode invoke -o orderer.example.com:7050 -C $CHANNELNAME -n $CHAINCODEID -c $constructor 46 | else 47 | usage 48 | fi 49 | -------------------------------------------------------------------------------- /fabric/scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ./scripts/channelname.sh 4 | 5 | function usage(){ 6 | echo "Usage: $0 " 7 | echo "Usage: $0 " 8 | echo "Mandatory:" 9 | echo " -c A unique string identifier" 10 | echo " -v A numeric number" 11 | echo " -p A name of folder containing chaincodes" 12 | echo "Optional:" 13 | echo " -a must be in the form [\"method\", \"method-arg-1\", \"method-arg-2\"]" 14 | } 15 | 16 | if [ "$#" -eq "0" ]; then 17 | usage 18 | exit 19 | fi 20 | 21 | while getopts "a:c:p:v:" opt; do 22 | case $opt in 23 | a) 24 | CHAINCODE_CONSTRUCTOR=$OPTARG 25 | ;; 26 | c) 27 | CHAINCODEID=$OPTARG 28 | ;; 29 | p) 30 | CCHAINCODE_PACKAGE=$OPTARG 31 | ;; 32 | v) 33 | CHAINCODE_VERSION=$OPTARG 34 | ;; 35 | \?) 36 | usage 37 | exit 1 38 | ;; 39 | :) 40 | usage 41 | exit 1 42 | ;; 43 | esac 44 | done 45 | 46 | if [ -z $CHAINCODE_CONSTRUCTOR ]; then 47 | CHAINCODE_CONSTRUCTOR="[]" 48 | fi 49 | 50 | if [[ ! -z $CHAINCODE_VERSION && ! -z $CHAINCODEID && ! -z $CCHAINCODE_PACKAGE ]]; then 51 | 52 | path_to_chaincode="github.com/hyperledger/fabric/examples/chaincode/go/$CCHAINCODE_PACKAGE" 53 | echo "INSTALLING chaincode $CHAINCODEID version $CHAINCODE_VERSION in $path_to_chaincode" 54 | echo 55 | peer chaincode install -n $CHAINCODEID -v $CHAINCODE_VERSION -p $path_to_chaincode 56 | 57 | echo "UPGRADING chaincode $CHAINCODEID to version $CHAINCODE_VERSION" 58 | echo "in $CHANNELNAME" 59 | echo "with constructor $CHAINCODE_CONSTRUCTOR" 60 | constructor="{\"Args\":$CHAINCODE_CONSTRUCTOR}" 61 | 62 | peer chaincode upgrade -o orderer.example.com:7050 -C $CHANNELNAME -n $CHAINCODEID -v $CHAINCODE_VERSION -c $constructor 63 | else 64 | usage 65 | fi 66 | 67 | --------------------------------------------------------------------------------