github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/docs/source/write_first_app.rst (about) 1 Running a Fabric Application 2 ############################ 3 .. note:: If you're not yet familiar with the fundamental architecture of a Fabric blockchain network, you may want to 4 visit the :doc:`key_concepts` section prior to continuing. 5 6 You should also be familiar with the Fabric Gateway service and how it relates to the application transaction 7 flow, documented in the :doc:`gateway` section. 8 9 This tutorial provides an introduction to how Fabric applications interact with deployed blockchain networks. The 10 tutorial uses sample programs built using the Fabric Gateway application API to invoke a smart contract, which queries 11 and updates the ledger with the smart contract API -- described in detail in :doc:`/developapps/smartcontract`. 12 13 **About Asset Transfer** 14 15 The Asset Transfer (basic) sample demonstrates how to create, update, and query assets. It involves the following two 16 components: 17 18 1. **Sample application:** which makes calls to the blockchain network, invoking transactions 19 implemented in the smart contract. The application is located in the following ``fabric-samples`` directory: 20 21 .. code-block:: text 22 23 asset-transfer-basic/application-gateway-typescript 24 25 2. **Smart contract:** which implements the transactions that interact with the 26 ledger. The smart contract is located in the following ``fabric-samples`` directory: 27 28 .. code-block:: text 29 30 asset-transfer-basic/chaincode-(typescript, go, java) 31 32 For this example, we will be using the TypeScript smart contract. 33 34 This tutorial consists of two principle parts: 35 36 1. **Set up a blockchain network.** 37 Our application needs a blockchain network to interact with, so we will launch a basic network and deploy a smart 38 contract for our application. 39 40 .. image:: images/AppConceptsOverview.png 41 42 2. **Run the sample application to interact with the smart contract.** 43 Our application will use the assetTransfer smart contract to create, query, and update assets on the ledger. We will 44 step through the code of the application and the transactions it invokes, including creating some initial assets, 45 querying an asset, querying a range of assets, creating a new asset, and transferring an asset to a new owner. 46 47 After completing this tutorial you should have a basic understanding of how Fabric applications and smart contracts 48 work together to manage data on the distributed ledger of a blockchain network. 49 50 51 Before you begin 52 ================ 53 In addition to the standard :doc:`prereqs` for Fabric, this tutorial leverages the Fabric Gateway application API 54 for Node. See the `documentation <https://hyperledger.github.io/fabric-gateway/>`_ for a up to date list of supported 55 programming language runtimes and dependencies. 56 57 - Ensure you have a suitable version of Node installed. Instructions for installing Node can be found in the `Node.js 58 documentation <https://nodejs.dev/learn/how-to-install-nodejs>`_. 59 60 - If you are on Windows, you can use npm to install the `windows-build-tools <https://github.com/felixrieseberg/windows-build-tools#readme>`_ 61 which installs all required compilers and tooling by running the following command: 62 63 .. code-block:: bash 64 65 npm install --global windows-build-tools 66 67 - If you are on Linux, you need to install `Python v2.7 <https://www.python.org/download/releases/2.7/>`_, `make <https://www.gnu.org/software/make/>`_, 68 and a C/C++ compiler toolchain such as `GCC <https://gcc.gnu.org/>`_. You can run the following command to install 69 these tools: 70 71 .. code-block:: bash 72 73 sudo apt install build-essential 74 75 76 Set up the blockchain network 77 ============================= 78 If you've already run through :doc:`test_network` tutorial and have a network up and running, this tutorial will bring 79 down your running network before bringing up a new one, to ensure you start with an empty ledger. 80 81 82 Launch the blockchain network 83 ----------------------------- 84 Navigate to the ``test-network`` subdirectory within your local clone of the ``fabric-samples`` repository. 85 86 .. code-block:: bash 87 88 cd fabric-samples/test-network 89 90 If you already have a test network running, bring it down to ensure the environment is clean. 91 92 .. code-block:: bash 93 94 ./network.sh down 95 96 Launch the Fabric test network using the ``network.sh`` shell script. 97 98 .. code-block:: bash 99 100 ./network.sh up createChannel -c mychannel -ca 101 102 This command will deploy the Fabric test network with two peers, an ordering service, and three certificate authorities 103 (Orderer, Org1, Org2). Instead of using the cryptogen tool, we bring up the test network using certificate authorities, 104 hence the ``-ca`` flag. Additionally, the org admin user registration is bootstrapped when the certificate authority is 105 started. 106 107 108 Deploy the smart contract 109 ------------------------- 110 .. note:: This tutorial demonstrates the TypeScript versions of the Asset Transfer smart contract and application, but 111 you may use any smart contract language sample with the TypeScript application sample (e.g TypeScript 112 application calling Go smart contract functions or TypeScript application calling Java smart contract 113 functions, etc.). To try the Go or Java versions of the smart contract, change the ``typescript`` argument 114 for the ``./network.sh deployCC -ccl typescript`` command below to either ``go`` or ``java`` and follow the 115 instructions written to the terminal. 116 117 Next, let's deploy the chaincode package containing the smart contract by calling the ``./network.sh`` script with the 118 chaincode name and language options. 119 120 .. code-block:: bash 121 122 ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-typescript/ -ccl typescript 123 124 This script uses the chaincode lifecycle to package, install, query installed chaincode, approve chaincode for both 125 Org1 and Org2, and finally commit the chaincode. 126 127 If the chaincode package is successfully deployed, the end of the output in your terminal should look similar to below: 128 129 .. code-block:: text 130 131 Committed chaincode definition for chaincode 'basic' on channel 'mychannel': 132 Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true] 133 Query chaincode definition successful on peer0.org2 on channel 'mychannel' 134 Chaincode initialization is not required 135 136 137 Prepare the sample application 138 ------------------------------ 139 Now, let's prepare the sample Asset Transfer `TypeScript application <https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic/application-gateway-typescript>`_ 140 that will be used to interact with the deployed smart contract. 141 142 Open a new terminal, and navigate to the ``application-gateway-typescript`` directory. 143 144 .. code-block:: bash 145 146 cd asset-transfer-basic/application-gateway-typescript 147 148 This directory contains a sample application developed using the Fabric Gateway application API for Node. 149 150 Run the following command to install the dependencies and build the application. It may take some time to complete: 151 152 .. code-block:: bash 153 154 npm install 155 156 This process installs the application dependencies defined in the application's ``package.json``. The most important 157 of which is the ``@hyperledger/fabric-gateway`` Node.js package; this provides the Fabric Gateway application API used 158 to connect a Fabric Gateway and, using a specific client identity, to submit and evaluate transactions, and receive 159 events. 160 161 Once ``npm install`` completes, everything is in place to run the application. 162 163 Let's take a look at the sample TypeScript application files we will be using in this tutorial. Run the following 164 command to list the files in this directory: 165 166 .. code-block:: bash 167 168 ls 169 170 You should see the following: 171 172 .. code-block:: text 173 174 dist 175 node_modules 176 package-lock.json 177 package.json 178 src 179 tsconfig.json 180 181 The ``src`` directory contains the client application source code. The JavaScript output generated from this source 182 code during the install process is located in the ``dist`` directory, and can be ignored. 183 184 185 Run the sample application 186 ========================== 187 When we started the Fabric test network earlier in this tutorial, several identities were created using the Certificate 188 Authorities. These include a user identity for each of the organizations. The application will use the credentials 189 of one of these user identities to transact with the blockchain network. 190 191 Let's run the application and then step through each of the interactions with the smart contract functions. From the 192 ``asset-transfer-basic/application-gateway-typescript`` directory, run the following command: 193 194 .. code-block:: bash 195 196 npm start 197 198 199 First, establish a gRPC connection to the Gateway 200 ------------------------------------------------- 201 The client application establishes a `gRPC <https://grpc.io/>`_ connection to the Fabric Gateway service that it will 202 use to transact with the blockchain network. To do this, it only requires the Fabric Gateway's endpoint address and, if 203 it is configured to use TLS, appropriate TLS certificates. In this sample, the gateway endpoint address is the address 204 of a peer, which provides the Fabric Gateway service. 205 206 .. note:: There is significant overhead associated with establishing gRPC connections, so this connection should be 207 retained by the application and used for all interactions with the Fabric Gateway. 208 209 .. warning:: In order to maintain security of any private data used in transactions, the application should connect to 210 a Fabric Gateway belonging to the same organization as the client identity. If the client identity's 211 organization does not host any gateways, then a trusted gateway in another organization should be used. 212 213 The TypeScript application creates a gRPC connection using the TLS certificate of the signing certificate authority so 214 that the authenticity of the gateway's TLS certificate can be verified. 215 216 For a TLS connection to be successfully established, the endpoint address used by the client must match the address in 217 the gateway's TLS certificate. Since the client accesses the gateway's Docker container at a ``localhost`` address, a 218 gRPC option is specified to force this endpoint address to be interpreted as the gateway's configured hostname. 219 220 .. code-block:: TypeScript 221 222 const peerEndpoint = 'localhost:7051'; 223 224 async function newGrpcConnection(): Promise<grpc.Client> { 225 const tlsRootCert = await fs.readFile(tlsCertPath); 226 const tlsCredentials = grpc.credentials.createSsl(tlsRootCert); 227 return new grpc.Client(peerEndpoint, tlsCredentials, { 228 'grpc.ssl_target_name_override': 'peer0.org1.example.com', 229 }); 230 } 231 232 233 Second, create a Gateway connection 234 ----------------------------------- 235 The application then creates a ``Gateway`` connection, which it uses to access any of the ``Networks`` (analogous to 236 channels) accessible to the Fabric Gateway, and subsequently smart ``Contracts`` deployed to those networks. A 237 ``Gateway`` connection has three requirements: 238 239 1. gRPC connection to the Fabric Gateway. 240 2. Client identity used to transact with the network. 241 3. Signing implementation used to generate digital signatures for the client identity. 242 243 The sample application uses the Org1 user's X.509 certificate as the client identity, and a signing implementation 244 based on that user's private key. 245 246 .. code-block:: TypeScript 247 248 const client = await newGrpcConnection(); 249 250 const gateway = connect({ 251 client, 252 identity: await newIdentity(), 253 signer: await newSigner(), 254 }); 255 256 async function newIdentity(): Promise<Identity> { 257 const credentials = await fs.readFile(certPath); 258 return { mspId: 'Org1MSP', credentials }; 259 } 260 261 async function newSigner(): Promise<Signer> { 262 const privateKeyPem = await fs.readFile(keyPath); 263 const privateKey = crypto.createPrivateKey(privateKeyPem); 264 return signers.newPrivateKeySigner(privateKey); 265 } 266 267 268 Third, access the smart contract to be invoked 269 ---------------------------------------------- 270 The sample application uses the ``Gateway`` connection to get a reference to the ``Network`` and then the default 271 ``Contract`` within a chaincode deployed on that network. 272 273 .. code-block:: TypeScript 274 275 const channelName = 'mychannel'; 276 const chaincodeName = 'basic'; 277 278 const network = gateway.getNetwork(channelName); 279 const contract = network.getContract(chaincodeName); 280 281 When a chaincode package includes multiple smart contracts, you can provide both the name of the chaincode and the name 282 of a specific smart contract as arguments to the `getContract() <https://hyperledger.github.io/fabric-gateway/main/api/node/interfaces/Network.html#getContract>`_ 283 call. For example: 284 285 .. code-block:: TypeScript 286 287 const contract = network.getContract('chaincodeName', 'smartContractName'); 288 289 290 Fourth, populate the ledger with sample assets 291 ---------------------------------------------- 292 Immediately after initial deployment of the chaincode package, the ledger is empty. The application uses 293 ``submitTransaction()`` to invoke the ``InitLedger`` transaction function, which populates the ledger with some sample 294 assets. ``submitTransaction()`` will use the Fabric Gateway to: 295 296 1. Endorse the transaction proposal. 297 2. Submit the endorsed transaction to the ordering service. 298 3. Wait for the transaction to be committed, updating ledger state. 299 300 Sample application ``InitLedger`` call: 301 302 .. code-block:: TypeScript 303 304 await contract.submitTransaction('InitLedger'); 305 306 307 Fifth, invoke transaction functions to read and write assets 308 ------------------------------------------------------------ 309 Now the application is ready to execute business logic that queries, creates additional assets, and modifies assets on 310 the ledger by invoking transactions functions on the smart contract. 311 312 Query all assets 313 ~~~~~~~~~~~~~~~~ 314 The application uses ``evaluateTransaction()`` to query the ledger by performing a read-only transaction invocation. 315 ``evaluateTransaction()`` will use the Fabric Gateway to invoke the transaction function and return its result. The 316 transaction is not sent to the ordering service and no ledger update occurs. 317 318 Below, the sample application is just getting all the assets created in the previous step when we populated the ledger. 319 320 Sample application ``GetAllAssets`` call: 321 322 .. code-block:: TypeScript 323 324 const resultBytes = await contract.evaluateTransaction('GetAllAssets'); 325 326 const resultJson = utf8Decoder.decode(resultBytes); 327 const result = JSON.parse(resultJson); 328 console.log('*** Result:', result); 329 330 .. note:: Transaction function results are always returned as bytes since transaction functions can return any type of 331 data. Often transaction functions return strings; or, as in the case above, a UTF-8 string of JSON data. The 332 application is responsible for correctly interpreting the result bytes. 333 334 The terminal output should look like this: 335 336 .. code-block:: text 337 338 *** Result: [ 339 { 340 AppraisedValue: 300, 341 Color: 'blue', 342 ID: 'asset1', 343 Owner: 'Tomoko', 344 Size: 5, 345 docType: 'asset' 346 }, 347 { 348 AppraisedValue: 400, 349 Color: 'red', 350 ID: 'asset2', 351 Owner: 'Brad', 352 Size: 5, 353 docType: 'asset' 354 }, 355 { 356 AppraisedValue: 500, 357 Color: 'green', 358 ID: 'asset3', 359 Owner: 'Jin Soo', 360 Size: 10, 361 docType: 'asset' 362 }, 363 { 364 AppraisedValue: 600, 365 Color: 'yellow', 366 ID: 'asset4', 367 Owner: 'Max', 368 Size: 10, 369 docType: 'asset' 370 }, 371 { 372 AppraisedValue: 700, 373 Color: 'black', 374 ID: 'asset5', 375 Owner: 'Adriana', 376 Size: 15, 377 docType: 'asset' 378 }, 379 { 380 AppraisedValue: 800, 381 Color: 'white', 382 ID: 'asset6', 383 Owner: 'Michel', 384 Size: 15, 385 docType: 'asset' 386 } 387 ] 388 389 Create a new asset 390 ~~~~~~~~~~~~~~~~~~ 391 The sample application submits a transaction to create a new asset. 392 393 Sample application ``CreateAsset`` call: 394 395 .. code-block:: TypeScript 396 397 const assetId = `asset${Date.now()}`; 398 399 await contract.submitTransaction( 400 'CreateAsset', 401 assetId, 402 'yellow', 403 '5', 404 'Tom', 405 '1300', 406 ); 407 408 .. note:: In the application snippets above, it is important to note that the ``CreateAsset`` transaction is submitted 409 with the same type and number of arguments the chaincode is expecting, and in the correct sequence. In this 410 case the correctly sequenced arguments are: 411 412 .. code-block:: text 413 414 assetId, "yellow", "5", "Tom", "1300" 415 416 The corresponding smart contract's ``CreateAsset`` transaction function is expecting the following sequence 417 of arguments that define the asset object: 418 419 .. code-block:: text 420 421 ID, Color, Size, Owner, AppraisedValue 422 423 Update an asset 424 ~~~~~~~~~~~~~~~ 425 The sample application submits a transaction to transfer ownership of the newly created asset. This time 426 the transaction is invoked using ``submitAsync()``, which returns after successfully submitting the endorsed 427 transaction to the ordering service instead of waiting until the transaction is committed to the ledger. This allows 428 the application to perform work using the transaction result while waiting for it to be committed. 429 430 Sample application ``TransferAsset`` call: 431 432 .. code-block:: TypeScript 433 434 const commit = await contract.submitAsync('TransferAsset', { 435 arguments: [assetId, 'Saptha'], 436 }); 437 const oldOwner = utf8Decoder.decode(commit.getResult()); 438 439 console.log(`*** Successfully submitted transaction to transfer ownership from ${oldOwner} to Saptha`); 440 console.log('*** Waiting for transaction commit'); 441 442 const status = await commit.getStatus(); 443 if (!status.successful) { 444 throw new Error(`Transaction ${status.transactionId} failed to commit with status code ${status.code}`); 445 } 446 447 console.log('*** Transaction committed successfully'); 448 449 Terminal output: 450 451 .. code-block:: text 452 453 *** Successfully submitted transaction to transfer ownership from Tom to Saptha 454 *** Waiting for transaction commit 455 *** Transaction committed successfully 456 457 Query the updated asset 458 ~~~~~~~~~~~~~~~~~~~~~~~ 459 The sample application then evaluates a query for the transferred asset, showing that it was both created with the 460 properties described, and then subsequently transferred to a new owner. 461 462 Sample application ``ReadAsset`` call: 463 464 .. code-block:: TypeScript 465 466 const resultBytes = await contract.evaluateTransaction('ReadAsset', assetId); 467 468 const resultJson = utf8Decoder.decode(resultBytes); 469 const result = JSON.parse(resultJson); 470 console.log('*** Result:', result); 471 472 Terminal output: 473 474 .. code-block:: text 475 476 *** Result: { 477 AppraisedValue: 1300, 478 Color: 'yellow', 479 ID: 'asset1639084597466', 480 Owner: 'Saptha', 481 Size: 5 482 } 483 484 Handle transaction errors 485 ~~~~~~~~~~~~~~~~~~~~~~~~~ 486 The final part of the sequence demonstrates an error submitting a transaction. In this example, the application 487 attempts to submit an ``UpdateAsset`` transaction but specifies an asset ID that does not exist. The transaction 488 function returns an error response, and the ``submitTransaction()`` call fails. 489 490 A ``submitTransaction()`` failure may generate several different types of error, indicating the point in the submit 491 flow that the error occurred, and containing additional information to enable the application to respond appropriately. 492 Consult the `API documentation <https://hyperledger.github.io/fabric-gateway/main/api/node/interfaces/Contract.html#submitTransaction>`_ 493 for details of the different error types that may be generated. 494 495 Sample application failing ``UpdateAsset`` call: 496 497 .. code-block:: TypeScript 498 499 try { 500 await contract.submitTransaction( 501 'UpdateAsset', 502 'asset70', 503 'blue', 504 '5', 505 'Tomoko', 506 '300', 507 ); 508 console.log('******** FAILED to return an error'); 509 } catch (error) { 510 console.log('*** Successfully caught the error: \n', error); 511 } 512 513 Terminal Output (with stack traces removed for clarity): 514 515 .. code-block:: text 516 517 *** Successfully caught the error: 518 EndorseError: 10 ABORTED: failed to endorse transaction, see attached details for more info 519 at ... { 520 code: 10, 521 details: [ 522 { 523 address: 'peer0.org1.example.com:7051', 524 message: 'error in simulation: transaction returned with failure: Error: The asset asset70 does not exist', 525 mspId: 'Org1MSP' 526 } 527 ], 528 cause: Error: 10 ABORTED: failed to endorse transaction, see attached details for more info 529 at ... { 530 code: 10, 531 details: 'failed to endorse transaction, see attached details for more info', 532 metadata: Metadata { internalRepr: [Map], options: {} } 533 }, 534 transactionId: 'a92980d41eef1d6492d63acd5fbb6ef1db0f53252330ad28e548fedfdb9167fe' 535 } 536 537 The ``EndorseError`` type indicates that failure occurred during endorsement, and the 538 `gRPC status code <https://grpc.github.io/grpc/core/md_doc_statuscodes.html>`_ of ``ABORTED`` indicates that the 539 application successfully invoked the Fabric Gateway but that a failure occurred during the endorsement process. A gRPC 540 status code of ``UNAVAILABLE`` or ``DEADLINE_EXCEEDED`` would suggest that the Fabric Gateway was not reachable or a 541 timely response was not received so retrying the operation might be appropriate. 542 543 544 Clean up 545 ======== 546 When you are finished using the asset-transfer sample, you can bring down the test network using the ``network.sh`` 547 script. 548 549 .. code-block:: bash 550 551 ./network.sh down 552 553 This command will bring down the certificate authorities, peers, and ordering nodes of the blockchain network that we 554 created. Note that all of the data on the ledger will be lost. If you want to go through the tutorial again, you will 555 start from a clean initial state. 556 557 558 Summary 559 ======= 560 You have now seen how to set up a blockchain network by launching the test network and deploying a smart contract. You 561 have then run a client application, and examined the application code to understand how it uses the Fabric Gateway 562 application API to query and update the ledger by connecting to a Fabric Gateway and invoking transaction functions on 563 the deployed smart contract. 564 565 566 .. Licensed under Creative Commons Attribution 4.0 International License 567 https://creativecommons.org/licenses/by/4.0/