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/