github.com/kaituanwang/hyperledger@v2.0.1+incompatible/docs/source/chaincode4ade.rst (about) 1 Chaincode for Developers 2 ======================== 3 4 What is Chaincode? 5 ------------------ 6 7 Chaincode is a program, written in `Go <https://golang.org>`_, `node.js <https://nodejs.org>`_, 8 or `Java <https://java.com/en/>`_ that implements a prescribed interface. 9 Chaincode runs in a secured Docker container isolated from the endorsing peer 10 process. Chaincode initializes and manages the ledger state through transactions 11 submitted by applications. 12 13 A chaincode typically handles business logic agreed to by members of the 14 network, so it similar to a "smart contract". A chaincode can be invoked to update or query 15 the ledger in a proposal transaction. Given the appropriate permission, a chaincode 16 may invoke another chaincode, either in the same channel or in different channels, to access its state. 17 Note that, if the called chaincode is on a different channel from the calling chaincode, 18 only read query is allowed. That is, the called chaincode on a different channel is only a ``Query``, 19 which does not participate in state validation checks in subsequent commit phase. 20 21 In the following sections, we will explore chaincode through the eyes of an 22 application developer. We'll present a simple chaincode sample application 23 and walk through the purpose of each method in the Chaincode Shim API. 24 25 Chaincode API 26 ------------- 27 28 Every chaincode program must implement the ``Chaincode`` interface whose methods 29 are called in response to received transactions. You can find the reference 30 documentation of the Chaincode Shim API for different languages below: 31 32 - `Go <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#Chaincode>`__ 33 - `node.js <https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeInterface.html>`__ 34 - `Java <https://hyperledger.github.io/fabric-chaincode-java/{BRANCH}/api/org/hyperledger/fabric/shim/Chaincode.html>`_ 35 36 In each language, the ``Invoke`` method is called by clients to submit transaction 37 proposals. This method allows you to use the chaincode to read and write data on 38 the channel ledger. 39 40 You also need to include an ``Init`` method that will serve as the initialization 41 function for your chaincode. This method will be called in order to initialize 42 the chaincode when it is started or upgraded. By default, this function is never 43 executed. However, you can use the chaincode definition to request that the ``Init`` 44 function be executed. If execution of ``Init`` is requested, fabric will ensure 45 that ``Init`` is invoked before any other function and is only invoked once. 46 This option provides you additional control over which users can initialize the 47 chaincode and the ability to add initial data to the ledger. If you are using 48 the peer CLI to approve the chaincode definition, use the ``--init-required`` 49 flag to request the execution of the ``Init`` function. Then call the ``Init`` 50 function by using the `peer chaincode invoke` command and passing the 51 ``--isInit`` flag. If you are using the Fabric SDK for Node.js, visit 52 `How to install and start your chaincode <https://hyperledger.github.io/fabric-sdk-node/master/tutorial-chaincode-lifecycle.html>`__. For more information, see :doc:`chaincode4noah`. 53 54 The other interface in the chaincode "shim" APIs is the ``ChaincodeStubInterface``: 55 56 - `Go <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStubInterface>`__ 57 - `node.js <https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html>`__ 58 - `Java <https://hyperledger.github.io/fabric-chaincode-java/{BRANCH}/api/org/hyperledger/fabric/shim/ChaincodeStub.html>`_ 59 60 which is used to access and modify the ledger, and to make invocations between 61 chaincodes. 62 63 In this tutorial using Go chaincode, we will demonstrate the use of these APIs 64 by implementing a simple chaincode application that manages simple "assets". 65 66 .. _Simple Asset Chaincode: 67 68 Simple Asset Chaincode 69 ---------------------- 70 Our application is a basic sample chaincode to create assets 71 (key-value pairs) on the ledger. 72 73 Choosing a Location for the Code 74 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 75 76 If you haven't been doing programming in Go, you may want to make sure that 77 you have :ref:`Golang` installed and your system properly configured. 78 79 Now, you will want to create a directory for your chaincode application as a 80 child directory of ``$GOPATH/src/``. 81 82 To keep things simple, let's use the following command: 83 84 .. code:: bash 85 86 mkdir -p $GOPATH/src/sacc && cd $GOPATH/src/sacc 87 88 Now, let's create the source file that we'll fill in with code: 89 90 .. code:: bash 91 92 touch sacc.go 93 94 Housekeeping 95 ^^^^^^^^^^^^ 96 97 First, let's start with some housekeeping. As with every chaincode, it implements the 98 `Chaincode interface <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#Chaincode>`_ 99 in particular, ``Init`` and ``Invoke`` functions. So, let's add the Go import 100 statements for the necessary dependencies for our chaincode. We'll import the 101 chaincode shim package and the 102 `peer protobuf package <https://godoc.org/github.com/hyperledger/fabric-protos-go/peer>`_. 103 Next, let's add a struct ``SimpleAsset`` as a receiver for Chaincode shim functions. 104 105 .. code:: go 106 107 package main 108 109 import ( 110 "fmt" 111 112 "github.com/hyperledger/fabric-chaincode-go/shim" 113 "github.com/hyperledger/fabric-protos-go/peer" 114 ) 115 116 // SimpleAsset implements a simple chaincode to manage an asset 117 type SimpleAsset struct { 118 } 119 120 Initializing the Chaincode 121 ^^^^^^^^^^^^^^^^^^^^^^^^^^ 122 123 Next, we'll implement the ``Init`` function. 124 125 .. code:: go 126 127 // Init is called during chaincode instantiation to initialize any data. 128 func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response { 129 130 } 131 132 .. note:: Note that chaincode upgrade also calls this function. When writing a 133 chaincode that will upgrade an existing one, make sure to modify the ``Init`` 134 function appropriately. In particular, provide an empty "Init" method if there's 135 no "migration" or nothing to be initialized as part of the upgrade. 136 137 Next, we'll retrieve the arguments to the ``Init`` call using the 138 `ChaincodeStubInterface.GetStringArgs <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.GetStringArgs>`_ 139 function and check for validity. In our case, we are expecting a key-value pair. 140 141 .. code:: go 142 143 // Init is called during chaincode instantiation to initialize any 144 // data. Note that chaincode upgrade also calls this function to reset 145 // or to migrate data, so be careful to avoid a scenario where you 146 // inadvertently clobber your ledger's data! 147 func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response { 148 // Get the args from the transaction proposal 149 args := stub.GetStringArgs() 150 if len(args) != 2 { 151 return shim.Error("Incorrect arguments. Expecting a key and a value") 152 } 153 } 154 155 Next, now that we have established that the call is valid, we'll store the 156 initial state in the ledger. To do this, we will call 157 `ChaincodeStubInterface.PutState <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.PutState>`_ 158 with the key and value passed in as the arguments. Assuming all went well, 159 return a peer.Response object that indicates the initialization was a success. 160 161 .. code:: go 162 163 // Init is called during chaincode instantiation to initialize any 164 // data. Note that chaincode upgrade also calls this function to reset 165 // or to migrate data, so be careful to avoid a scenario where you 166 // inadvertently clobber your ledger's data! 167 func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response { 168 // Get the args from the transaction proposal 169 args := stub.GetStringArgs() 170 if len(args) != 2 { 171 return shim.Error("Incorrect arguments. Expecting a key and a value") 172 } 173 174 // Set up any variables or assets here by calling stub.PutState() 175 176 // We store the key and the value on the ledger 177 err := stub.PutState(args[0], []byte(args[1])) 178 if err != nil { 179 return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0])) 180 } 181 return shim.Success(nil) 182 } 183 184 Invoking the Chaincode 185 ^^^^^^^^^^^^^^^^^^^^^^ 186 187 First, let's add the ``Invoke`` function's signature. 188 189 .. code:: go 190 191 // Invoke is called per transaction on the chaincode. Each transaction is 192 // either a 'get' or a 'set' on the asset created by Init function. The 'set' 193 // method may create a new asset by specifying a new key-value pair. 194 func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 195 196 } 197 198 As with the ``Init`` function above, we need to extract the arguments from the 199 ``ChaincodeStubInterface``. The ``Invoke`` function's arguments will be the 200 name of the chaincode application function to invoke. In our case, our application 201 will simply have two functions: ``set`` and ``get``, that allow the value of an 202 asset to be set or its current state to be retrieved. We first call 203 `ChaincodeStubInterface.GetFunctionAndParameters <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.GetFunctionAndParameters>`_ 204 to extract the function name and the parameters to that chaincode application 205 function. 206 207 .. code:: go 208 209 // Invoke is called per transaction on the chaincode. Each transaction is 210 // either a 'get' or a 'set' on the asset created by Init function. The Set 211 // method may create a new asset by specifying a new key-value pair. 212 func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 213 // Extract the function and args from the transaction proposal 214 fn, args := stub.GetFunctionAndParameters() 215 216 } 217 218 Next, we'll validate the function name as being either ``set`` or ``get``, and 219 invoke those chaincode application functions, returning an appropriate 220 response via the ``shim.Success`` or ``shim.Error`` functions that will 221 serialize the response into a gRPC protobuf message. 222 223 .. code:: go 224 225 // Invoke is called per transaction on the chaincode. Each transaction is 226 // either a 'get' or a 'set' on the asset created by Init function. The Set 227 // method may create a new asset by specifying a new key-value pair. 228 func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 229 // Extract the function and args from the transaction proposal 230 fn, args := stub.GetFunctionAndParameters() 231 232 var result string 233 var err error 234 if fn == "set" { 235 result, err = set(stub, args) 236 } else { 237 result, err = get(stub, args) 238 } 239 if err != nil { 240 return shim.Error(err.Error()) 241 } 242 243 // Return the result as success payload 244 return shim.Success([]byte(result)) 245 } 246 247 Implementing the Chaincode Application 248 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 249 250 As noted, our chaincode application implements two functions that can be 251 invoked via the ``Invoke`` function. Let's implement those functions now. 252 Note that as we mentioned above, to access the ledger's state, we will leverage 253 the `ChaincodeStubInterface.PutState <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.PutState>`_ 254 and `ChaincodeStubInterface.GetState <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.GetState>`_ 255 functions of the chaincode shim API. 256 257 .. code:: go 258 259 // Set stores the asset (both key and value) on the ledger. If the key exists, 260 // it will override the value with the new one 261 func set(stub shim.ChaincodeStubInterface, args []string) (string, error) { 262 if len(args) != 2 { 263 return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value") 264 } 265 266 err := stub.PutState(args[0], []byte(args[1])) 267 if err != nil { 268 return "", fmt.Errorf("Failed to set asset: %s", args[0]) 269 } 270 return args[1], nil 271 } 272 273 // Get returns the value of the specified asset key 274 func get(stub shim.ChaincodeStubInterface, args []string) (string, error) { 275 if len(args) != 1 { 276 return "", fmt.Errorf("Incorrect arguments. Expecting a key") 277 } 278 279 value, err := stub.GetState(args[0]) 280 if err != nil { 281 return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err) 282 } 283 if value == nil { 284 return "", fmt.Errorf("Asset not found: %s", args[0]) 285 } 286 return string(value), nil 287 } 288 289 .. _Chaincode Sample: 290 291 Pulling it All Together 292 ^^^^^^^^^^^^^^^^^^^^^^^ 293 294 Finally, we need to add the ``main`` function, which will call the 295 `shim.Start <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#Start>`_ 296 function. Here's the whole chaincode program source. 297 298 .. code:: go 299 300 package main 301 302 import ( 303 "fmt" 304 305 "github.com/hyperledger/fabric-chaincode-go/shim" 306 "github.com/hyperledger/fabric-protos-go/peer" 307 ) 308 309 // SimpleAsset implements a simple chaincode to manage an asset 310 type SimpleAsset struct { 311 } 312 313 // Init is called during chaincode instantiation to initialize any 314 // data. Note that chaincode upgrade also calls this function to reset 315 // or to migrate data. 316 func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response { 317 // Get the args from the transaction proposal 318 args := stub.GetStringArgs() 319 if len(args) != 2 { 320 return shim.Error("Incorrect arguments. Expecting a key and a value") 321 } 322 323 // Set up any variables or assets here by calling stub.PutState() 324 325 // We store the key and the value on the ledger 326 err := stub.PutState(args[0], []byte(args[1])) 327 if err != nil { 328 return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0])) 329 } 330 return shim.Success(nil) 331 } 332 333 // Invoke is called per transaction on the chaincode. Each transaction is 334 // either a 'get' or a 'set' on the asset created by Init function. The Set 335 // method may create a new asset by specifying a new key-value pair. 336 func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 337 // Extract the function and args from the transaction proposal 338 fn, args := stub.GetFunctionAndParameters() 339 340 var result string 341 var err error 342 if fn == "set" { 343 result, err = set(stub, args) 344 } else { // assume 'get' even if fn is nil 345 result, err = get(stub, args) 346 } 347 if err != nil { 348 return shim.Error(err.Error()) 349 } 350 351 // Return the result as success payload 352 return shim.Success([]byte(result)) 353 } 354 355 // Set stores the asset (both key and value) on the ledger. If the key exists, 356 // it will override the value with the new one 357 func set(stub shim.ChaincodeStubInterface, args []string) (string, error) { 358 if len(args) != 2 { 359 return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value") 360 } 361 362 err := stub.PutState(args[0], []byte(args[1])) 363 if err != nil { 364 return "", fmt.Errorf("Failed to set asset: %s", args[0]) 365 } 366 return args[1], nil 367 } 368 369 // Get returns the value of the specified asset key 370 func get(stub shim.ChaincodeStubInterface, args []string) (string, error) { 371 if len(args) != 1 { 372 return "", fmt.Errorf("Incorrect arguments. Expecting a key") 373 } 374 375 value, err := stub.GetState(args[0]) 376 if err != nil { 377 return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err) 378 } 379 if value == nil { 380 return "", fmt.Errorf("Asset not found: %s", args[0]) 381 } 382 return string(value), nil 383 } 384 385 // main function starts up the chaincode in the container during instantiate 386 func main() { 387 if err := shim.Start(new(SimpleAsset)); err != nil { 388 fmt.Printf("Error starting SimpleAsset chaincode: %s", err) 389 } 390 } 391 392 Building Chaincode 393 ^^^^^^^^^^^^^^^^^^ 394 395 Now let's compile your chaincode. 396 397 .. code:: bash 398 399 go get -u github.com/hyperledger/fabric-chaincode-go 400 go build 401 402 Assuming there are no errors, now we can proceed to the next step, testing 403 your chaincode. 404 405 Testing Using dev mode 406 ^^^^^^^^^^^^^^^^^^^^^^ 407 408 Normally chaincodes are started and maintained by peer. However in “dev 409 mode", chaincode is built and started by the user. This mode is useful 410 during chaincode development phase for rapid code/build/run/debug cycle 411 turnaround. 412 413 We start "dev mode" by leveraging pre-generated orderer and channel artifacts for 414 a sample dev network. As such, the user can immediately jump into the process 415 of compiling chaincode and driving calls. 416 417 Install Hyperledger Fabric Samples 418 ---------------------------------- 419 420 If you haven't already done so, please :doc:`install`. 421 422 Navigate to the ``chaincode-docker-devmode`` directory of the ``fabric-samples`` 423 clone: 424 425 .. code:: bash 426 427 cd chaincode-docker-devmode 428 429 Now open three terminals and navigate to your ``chaincode-docker-devmode`` 430 directory in each. 431 432 Terminal 1 - Start the network 433 ------------------------------ 434 435 .. code:: bash 436 437 docker-compose -f docker-compose-simple.yaml up 438 439 The above starts the network with the ``SingleSampleMSPSolo`` orderer profile and 440 launches the peer in "dev mode". It also launches two additional containers - 441 one for the chaincode environment and a CLI to interact with the chaincode. The 442 commands for create and join channel are embedded in the CLI container, so we 443 can jump immediately to the chaincode calls. 444 445 - Note: the peer is not using TLS because the dev mode does not work with TLS. 446 447 Terminal 2 - Build & start the chaincode 448 ---------------------------------------- 449 450 .. code:: bash 451 452 docker exec -it chaincode sh 453 454 You should see the following: 455 456 .. code:: sh 457 458 /opt/gopath/src/chaincode $ 459 460 Now, compile your chaincode: 461 462 .. code:: sh 463 464 cd sacc 465 go build 466 467 Now run the chaincode: 468 469 .. code:: sh 470 471 CORE_CHAINCODE_ID_NAME=mycc:0 CORE_PEER_TLS_ENABLED=false ./sacc -peer.address peer:7052 472 473 The chaincode is started with peer and chaincode logs indicating successful registration with the peer. 474 Note that at this stage the chaincode is not associated with any channel. This is done in subsequent steps 475 using the ``instantiate`` command. 476 477 Terminal 3 - Use the chaincode 478 ------------------------------ 479 480 Even though you are in ``--peer-chaincodedev`` mode, you still have to install the 481 chaincode so the life-cycle system chaincode can go through its checks normally. 482 This requirement may be removed in future when in ``--peer-chaincodedev`` mode. 483 484 We'll leverage the CLI container to drive these calls. 485 486 .. code:: bash 487 488 docker exec -it cli bash 489 490 .. code:: bash 491 492 peer chaincode install -p chaincodedev/chaincode/sacc -n mycc -v 0 493 peer chaincode instantiate -n mycc -v 0 -c '{"Args":["a","10"]}' -C myc 494 495 Now issue an invoke to change the value of "a" to "20". 496 497 .. code:: bash 498 499 peer chaincode invoke -n mycc -c '{"Args":["set", "a", "20"]}' -C myc 500 501 Finally, query ``a``. We should see a value of ``20``. 502 503 .. code:: bash 504 505 peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C myc 506 507 Testing new chaincode 508 --------------------- 509 510 By default, we mount only ``sacc``. However, you can easily test different 511 chaincodes by adding them to the ``chaincode`` subdirectory and relaunching 512 your network. At this point they will be accessible in your ``chaincode`` container. 513 514 Chaincode access control 515 ------------------------ 516 517 Chaincode can utilize the client (submitter) certificate for access 518 control decisions by calling the GetCreator() function. Additionally 519 the Go shim provides extension APIs that extract client identity 520 from the submitter's certificate that can be used for access control decisions, 521 whether that is based on client identity itself, or the org identity, 522 or on a client identity attribute. 523 524 For example an asset that is represented as a key/value may include the 525 client's identity as part of the value (for example as a JSON attribute 526 indicating that asset owner), and only this client may be authorized 527 to make updates to the key/value in the future. The client identity 528 library extension APIs can be used within chaincode to retrieve this 529 submitter information to make such access control decisions. 530 531 See the `client identity (CID) library documentation <https://github.com/hyperledger/fabric-chaincode-go/blob/master/pkg/cid/README.md>`_ 532 for more details. 533 534 To add the client identity shim extension to your chaincode as a dependency, see :ref:`vendoring`. 535 536 .. _vendoring: 537 538 Managing external dependencies for chaincode written in Go 539 ---------------------------------------------------------- 540 Your Go chaincode requires packages (like the chaincode shim) that are not part 541 of the Go standard library. These packages must be included in your chaincode 542 package. 543 544 There are `many tools available <https://github.com/golang/go/wiki/PackageManagementTools>`__ 545 for managing (or "vendoring") these dependencies. The following demonstrates how to use 546 ``govendor``: 547 548 .. code:: bash 549 550 govendor init 551 govendor add +external // Add all external package, or 552 govendor add github.com/external/pkg // Add specific external package 553 554 This imports the external dependencies into a local ``vendor`` directory. 555 If you are vendoring the Fabric shim or shim extensions, clone the 556 Fabric repository to your $GOPATH/src/github.com/hyperledger directory, 557 before executing the govendor commands. 558 559 Once dependencies are vendored in your chaincode directory, ``peer chaincode package`` 560 and ``peer chaincode install`` operations will then include code associated with the 561 dependencies into the chaincode package. 562 563 .. Licensed under Creative Commons Attribution 4.0 International License 564 https://creativecommons.org/licenses/by/4.0/