github.com/true-sqn/fabric@v2.1.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 separate process from the peer and initializes and manages 10 the ledger state through transactions submitted by applications. 11 12 A chaincode typically handles business logic agreed to by members of the 13 network, so it similar to a "smart contract". A chaincode can be invoked to update or query 14 the ledger in a proposal transaction. Given the appropriate permission, a chaincode 15 may invoke another chaincode, either in the same channel or in different channels, to access its state. 16 Note that, if the called chaincode is on a different channel from the calling chaincode, 17 only read query is allowed. That is, the called chaincode on a different channel is only a ``Query``, 18 which does not participate in state validation checks in subsequent commit phase. 19 20 In the following sections, we will explore chaincode through the eyes of an 21 application developer. We'll present a simple chaincode sample application 22 and walk through the purpose of each method in the Chaincode Shim API. If you 23 are a network operator who is deploying a chaincode to running network, 24 visit the :doc:`deploy_chaincode` tutorial and the :doc:`chaincode_lifecycle` 25 concept topic. 26 27 This tutorial provides an overview of the low level APIs provided by the Fabric 28 Chaincode Shim API. You can also use the higher level APIs provided by the 29 Fabric Contract API. To learn more about developing smart contracts 30 using the Fabric contract API, visit the :doc:`developapps/smartcontract` topic. 31 32 Chaincode API 33 ------------- 34 35 Every chaincode program must implement the ``Chaincode`` interface whose methods 36 are called in response to received transactions. You can find the reference 37 documentation of the Chaincode Shim API for different languages below: 38 39 - `Go <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#Chaincode>`__ 40 - `Node.js <https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeInterface.html>`__ 41 - `Java <https://hyperledger.github.io/fabric-chaincode-java/{BRANCH}/api/org/hyperledger/fabric/shim/Chaincode.html>`_ 42 43 In each language, the ``Invoke`` method is called by clients to submit transaction 44 proposals. This method allows you to use the chaincode to read and write data on 45 the channel ledger. 46 47 You also need to include an ``Init`` method in your chaincode that will serve as 48 the initialization function. This function is required by the chaincode interface, 49 but does not necessarily need to invoked by your applications. You can use the 50 Fabric chaincode lifecycle process to specify whether the ``Init`` function must 51 be called prior to Invokes. For more information, refer to the initialization 52 parameter in the `Approving a chaincode definition <chaincode_lifecycle.html#step-three-approve-a-chaincode-definition-for-your-organization>`__ 53 step of the Fabric chaincode lifecycle documentation. 54 55 The other interface in the chaincode "shim" APIs is the ``ChaincodeStubInterface``: 56 57 - `Go <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStubInterface>`__ 58 - `Node.js <https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeStub.html>`__ 59 - `Java <https://hyperledger.github.io/fabric-chaincode-java/{BRANCH}/api/org/hyperledger/fabric/shim/ChaincodeStub.html>`_ 60 61 which is used to access and modify the ledger, and to make invocations between 62 chaincodes. 63 64 In this tutorial using Go chaincode, we will demonstrate the use of these APIs 65 by implementing a simple chaincode application that manages simple "assets". 66 67 .. _Simple Asset Chaincode: 68 69 Simple Asset Chaincode 70 ---------------------- 71 Our application is a basic sample chaincode to create assets 72 (key-value pairs) on the ledger. 73 74 Choosing a Location for the Code 75 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 76 77 If you haven't been doing programming in Go, you may want to make sure that 78 you have :ref:`Go` installed and your system properly configured. 79 80 Now, you will want to create a directory for your chaincode application as a 81 child directory of ``$GOPATH/src/``. 82 83 To keep things simple, let's use the following command: 84 85 .. code:: bash 86 87 mkdir -p $GOPATH/src/sacc && cd $GOPATH/src/sacc 88 89 Now, let's create the source file that we'll fill in with code: 90 91 .. code:: bash 92 93 touch sacc.go 94 95 Housekeeping 96 ^^^^^^^^^^^^ 97 98 First, let's start with some housekeeping. As with every chaincode, it implements the 99 `Chaincode interface <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#Chaincode>`_ 100 in particular, ``Init`` and ``Invoke`` functions. So, let's add the Go import 101 statements for the necessary dependencies for our chaincode. We'll import the 102 chaincode shim package and the 103 `peer protobuf package <https://godoc.org/github.com/hyperledger/fabric-protos-go/peer>`_. 104 Next, let's add a struct ``SimpleAsset`` as a receiver for Chaincode shim functions. 105 106 .. code:: go 107 108 package main 109 110 import ( 111 "fmt" 112 113 "github.com/hyperledger/fabric-chaincode-go/shim" 114 "github.com/hyperledger/fabric-protos-go/peer" 115 ) 116 117 // SimpleAsset implements a simple chaincode to manage an asset 118 type SimpleAsset struct { 119 } 120 121 Initializing the Chaincode 122 ^^^^^^^^^^^^^^^^^^^^^^^^^^ 123 124 Next, we'll implement the ``Init`` function. 125 126 .. code:: go 127 128 // Init is called during chaincode instantiation to initialize any data. 129 func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response { 130 131 } 132 133 .. note:: Note that chaincode upgrade also calls this function. When writing a 134 chaincode that will upgrade an existing one, make sure to modify the ``Init`` 135 function appropriately. In particular, provide an empty "Init" method if there's 136 no "migration" or nothing to be initialized as part of the upgrade. 137 138 Next, we'll retrieve the arguments to the ``Init`` call using the 139 `ChaincodeStubInterface.GetStringArgs <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.GetStringArgs>`_ 140 function and check for validity. In our case, we are expecting a key-value pair. 141 142 .. code:: go 143 144 // Init is called during chaincode instantiation to initialize any 145 // data. Note that chaincode upgrade also calls this function to reset 146 // or to migrate data, so be careful to avoid a scenario where you 147 // inadvertently clobber your ledger's data! 148 func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response { 149 // Get the args from the transaction proposal 150 args := stub.GetStringArgs() 151 if len(args) != 2 { 152 return shim.Error("Incorrect arguments. Expecting a key and a value") 153 } 154 } 155 156 Next, now that we have established that the call is valid, we'll store the 157 initial state in the ledger. To do this, we will call 158 `ChaincodeStubInterface.PutState <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.PutState>`_ 159 with the key and value passed in as the arguments. Assuming all went well, 160 return a peer.Response object that indicates the initialization was a success. 161 162 .. code:: go 163 164 // Init is called during chaincode instantiation to initialize any 165 // data. Note that chaincode upgrade also calls this function to reset 166 // or to migrate data, so be careful to avoid a scenario where you 167 // inadvertently clobber your ledger's data! 168 func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response { 169 // Get the args from the transaction proposal 170 args := stub.GetStringArgs() 171 if len(args) != 2 { 172 return shim.Error("Incorrect arguments. Expecting a key and a value") 173 } 174 175 // Set up any variables or assets here by calling stub.PutState() 176 177 // We store the key and the value on the ledger 178 err := stub.PutState(args[0], []byte(args[1])) 179 if err != nil { 180 return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0])) 181 } 182 return shim.Success(nil) 183 } 184 185 Invoking the Chaincode 186 ^^^^^^^^^^^^^^^^^^^^^^ 187 188 First, let's add the ``Invoke`` function's signature. 189 190 .. code:: go 191 192 // Invoke is called per transaction on the chaincode. Each transaction is 193 // either a 'get' or a 'set' on the asset created by Init function. The 'set' 194 // method may create a new asset by specifying a new key-value pair. 195 func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 196 197 } 198 199 As with the ``Init`` function above, we need to extract the arguments from the 200 ``ChaincodeStubInterface``. The ``Invoke`` function's arguments will be the 201 name of the chaincode application function to invoke. In our case, our application 202 will simply have two functions: ``set`` and ``get``, that allow the value of an 203 asset to be set or its current state to be retrieved. We first call 204 `ChaincodeStubInterface.GetFunctionAndParameters <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.GetFunctionAndParameters>`_ 205 to extract the function name and the parameters to that chaincode application 206 function. 207 208 .. code:: go 209 210 // Invoke is called per transaction on the chaincode. Each transaction is 211 // either a 'get' or a 'set' on the asset created by Init function. The Set 212 // method may create a new asset by specifying a new key-value pair. 213 func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 214 // Extract the function and args from the transaction proposal 215 fn, args := stub.GetFunctionAndParameters() 216 217 } 218 219 Next, we'll validate the function name as being either ``set`` or ``get``, and 220 invoke those chaincode application functions, returning an appropriate 221 response via the ``shim.Success`` or ``shim.Error`` functions that will 222 serialize the response into a gRPC protobuf message. 223 224 .. code:: go 225 226 // Invoke is called per transaction on the chaincode. Each transaction is 227 // either a 'get' or a 'set' on the asset created by Init function. The Set 228 // method may create a new asset by specifying a new key-value pair. 229 func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 230 // Extract the function and args from the transaction proposal 231 fn, args := stub.GetFunctionAndParameters() 232 233 var result string 234 var err error 235 if fn == "set" { 236 result, err = set(stub, args) 237 } else { 238 result, err = get(stub, args) 239 } 240 if err != nil { 241 return shim.Error(err.Error()) 242 } 243 244 // Return the result as success payload 245 return shim.Success([]byte(result)) 246 } 247 248 Implementing the Chaincode Application 249 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 250 251 As noted, our chaincode application implements two functions that can be 252 invoked via the ``Invoke`` function. Let's implement those functions now. 253 Note that as we mentioned above, to access the ledger's state, we will leverage 254 the `ChaincodeStubInterface.PutState <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.PutState>`_ 255 and `ChaincodeStubInterface.GetState <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub.GetState>`_ 256 functions of the chaincode shim API. 257 258 .. code:: go 259 260 // Set stores the asset (both key and value) on the ledger. If the key exists, 261 // it will override the value with the new one 262 func set(stub shim.ChaincodeStubInterface, args []string) (string, error) { 263 if len(args) != 2 { 264 return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value") 265 } 266 267 err := stub.PutState(args[0], []byte(args[1])) 268 if err != nil { 269 return "", fmt.Errorf("Failed to set asset: %s", args[0]) 270 } 271 return args[1], nil 272 } 273 274 // Get returns the value of the specified asset key 275 func get(stub shim.ChaincodeStubInterface, args []string) (string, error) { 276 if len(args) != 1 { 277 return "", fmt.Errorf("Incorrect arguments. Expecting a key") 278 } 279 280 value, err := stub.GetState(args[0]) 281 if err != nil { 282 return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err) 283 } 284 if value == nil { 285 return "", fmt.Errorf("Asset not found: %s", args[0]) 286 } 287 return string(value), nil 288 } 289 290 .. _Chaincode Sample: 291 292 Pulling it All Together 293 ^^^^^^^^^^^^^^^^^^^^^^^ 294 295 Finally, we need to add the ``main`` function, which will call the 296 `shim.Start <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#Start>`_ 297 function. Here's the whole chaincode program source. 298 299 .. code:: go 300 301 package main 302 303 import ( 304 "fmt" 305 306 "github.com/hyperledger/fabric-chaincode-go/shim" 307 "github.com/hyperledger/fabric-protos-go/peer" 308 ) 309 310 // SimpleAsset implements a simple chaincode to manage an asset 311 type SimpleAsset struct { 312 } 313 314 // Init is called during chaincode instantiation to initialize any 315 // data. Note that chaincode upgrade also calls this function to reset 316 // or to migrate data. 317 func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response { 318 // Get the args from the transaction proposal 319 args := stub.GetStringArgs() 320 if len(args) != 2 { 321 return shim.Error("Incorrect arguments. Expecting a key and a value") 322 } 323 324 // Set up any variables or assets here by calling stub.PutState() 325 326 // We store the key and the value on the ledger 327 err := stub.PutState(args[0], []byte(args[1])) 328 if err != nil { 329 return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0])) 330 } 331 return shim.Success(nil) 332 } 333 334 // Invoke is called per transaction on the chaincode. Each transaction is 335 // either a 'get' or a 'set' on the asset created by Init function. The Set 336 // method may create a new asset by specifying a new key-value pair. 337 func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 338 // Extract the function and args from the transaction proposal 339 fn, args := stub.GetFunctionAndParameters() 340 341 var result string 342 var err error 343 if fn == "set" { 344 result, err = set(stub, args) 345 } else { // assume 'get' even if fn is nil 346 result, err = get(stub, args) 347 } 348 if err != nil { 349 return shim.Error(err.Error()) 350 } 351 352 // Return the result as success payload 353 return shim.Success([]byte(result)) 354 } 355 356 // Set stores the asset (both key and value) on the ledger. If the key exists, 357 // it will override the value with the new one 358 func set(stub shim.ChaincodeStubInterface, args []string) (string, error) { 359 if len(args) != 2 { 360 return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value") 361 } 362 363 err := stub.PutState(args[0], []byte(args[1])) 364 if err != nil { 365 return "", fmt.Errorf("Failed to set asset: %s", args[0]) 366 } 367 return args[1], nil 368 } 369 370 // Get returns the value of the specified asset key 371 func get(stub shim.ChaincodeStubInterface, args []string) (string, error) { 372 if len(args) != 1 { 373 return "", fmt.Errorf("Incorrect arguments. Expecting a key") 374 } 375 376 value, err := stub.GetState(args[0]) 377 if err != nil { 378 return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err) 379 } 380 if value == nil { 381 return "", fmt.Errorf("Asset not found: %s", args[0]) 382 } 383 return string(value), nil 384 } 385 386 // main function starts up the chaincode in the container during instantiate 387 func main() { 388 if err := shim.Start(new(SimpleAsset)); err != nil { 389 fmt.Printf("Error starting SimpleAsset chaincode: %s", err) 390 } 391 } 392 393 Chaincode access control 394 ------------------------ 395 396 Chaincode can utilize the client (submitter) certificate for access 397 control decisions by calling the GetCreator() function. Additionally 398 the Go shim provides extension APIs that extract client identity 399 from the submitter's certificate that can be used for access control decisions, 400 whether that is based on client identity itself, or the org identity, 401 or on a client identity attribute. 402 403 For example an asset that is represented as a key/value may include the 404 client's identity as part of the value (for example as a JSON attribute 405 indicating that asset owner), and only this client may be authorized 406 to make updates to the key/value in the future. The client identity 407 library extension APIs can be used within chaincode to retrieve this 408 submitter information to make such access control decisions. 409 410 See the `client identity (CID) library documentation <https://github.com/hyperledger/fabric-chaincode-go/blob/{BRANCH}/pkg/cid/README.md>`_ 411 for more details. 412 413 To add the client identity shim extension to your chaincode as a dependency, see :ref:`vendoring`. 414 415 .. _vendoring: 416 417 Managing external dependencies for chaincode written in Go 418 ---------------------------------------------------------- 419 Your Go chaincode requires packages (like the chaincode shim) that are not part 420 of the Go standard library. These packages must be included in your chaincode 421 package. 422 423 There are `many tools available <https://github.com/golang/go/wiki/PackageManagementTools>`__ 424 for managing (or "vendoring") these dependencies. The following demonstrates how to use 425 ``govendor``: 426 427 .. code:: bash 428 429 govendor init 430 govendor add +external // Add all external package, or 431 govendor add github.com/external/pkg // Add specific external package 432 433 This imports the external dependencies into a local ``vendor`` directory. 434 If you are vendoring the Fabric shim or shim extensions, clone the 435 Fabric repository to your $GOPATH/src/github.com/hyperledger directory, 436 before executing the govendor commands. 437 438 Once dependencies are vendored in your chaincode directory, ``peer chaincode package`` 439 and ``peer chaincode install`` operations will then include code associated with the 440 dependencies into the chaincode package. 441 442 .. Licensed under Creative Commons Attribution 4.0 International License 443 https://creativecommons.org/licenses/by/4.0/