github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/docs/source/write_first_app.rst (about)

     1  Writing Your First Application
     2  ==============================
     3  
     4  .. note:: If you're not yet familiar with the fundamental architecture of a
     5            Fabric network, you may want to visit the :doc:`key_concepts` section
     6            prior to continuing.
     7  
     8            It is also worth noting that this tutorial serves as an introduction
     9            to Fabric applications and uses simple smart contracts and
    10            applications. For a more in-depth look at Fabric applications and
    11            smart contracts, check out our
    12            :doc:`developapps/developing_applications` section or the
    13            :doc:`tutorial/commercial_paper`.
    14  
    15  This tutorial provides an introduction to how Fabric applications interact
    16  with deployed blockchain networks. The tutorial uses sample programs built using the
    17  Fabric SDKs -- described in detail in the :doc:`/developapps/application` topic --
    18  to invoke a smart contract which queries and updates the ledger with the smart
    19  contract API -- described in detail in :doc:`/developapps/smartcontract`.
    20  We will also use our sample programs and a deployed Certificate Authority to generate
    21  the X.509 certificates that an application needs to interact with a permissioned
    22  blockchain.
    23  
    24  **About Asset Transfer**
    25  
    26  This Asset Transfer (basic) sample demonstrates how to initialize a ledger with assets, query those assets, create
    27  a new asset, query a single asset based on an asset ID, update an existing asset, and transfer an asset to a new owner.
    28  It involves the following two components:
    29  
    30    1. Sample application: which makes calls to the blockchain network, invoking transactions
    31    implemented in the chaincode (smart contract). The application is located in the following ``fabric-samples`` directory:
    32  
    33    .. code:: bash
    34  
    35      asset-transfer-basic/application-javascript
    36  
    37    2. Smart contract itself, implementing the transactions that involve interactions with the
    38    ledger. The smart contract (chaincode) is located in the following ``fabric-samples`` directory:
    39  
    40    .. code:: bash
    41  
    42      asset-transfer-basic/chaincode-(javascript, java, go, typescript)
    43  
    44  Please note that for the purposes of this tutorial, the terms chaincode and smart contract are used
    45  interchangeably. For this example, we will be using the javascript chaincode.
    46  
    47  We’ll go through three principle steps:
    48  
    49    **1. Setting up a development environment.** Our application needs a network
    50    to interact with, so we'll deploy a basic network for our smart contracts and
    51    application.
    52  
    53    .. image:: images/AppConceptsOverview.png
    54  
    55    **2. Explore a sample smart contract.**
    56    We’ll inspect the sample assetTransfer (javascript) smart contract to learn about the transactions within it,
    57    and how they are used by an application to query and update the ledger.
    58  
    59    **3. Interact with the smart contract with a sample application.** Our application will
    60    use the assetTransfer smart contract to create, query, and update assets on the ledger.
    61    We'll get into the code of the app and the transactions they create, including initializing
    62    the ledger with assets, querying an asset, querying a range of assets, creating a new asset,
    63    and transferring an asset to a new owner.
    64  
    65  After completing this tutorial you should have a basic understanding of how Fabric
    66  applications and smart contracts work together to manage data on the distributed
    67  ledger of a blockchain network.
    68  
    69  Before you begin
    70  ----------------
    71  
    72  In addition to the standard :doc:`prereqs` for Fabric, this tutorial leverages the Hyperledger Fabric SDK for Node.js. See the Node.js SDK `README <https://github.com/hyperledger/fabric-sdk-node#build-and-test>`__ for a up to date list of prerequisites.
    73  
    74  - If you are using macOS, complete the following steps:
    75  
    76    1. Install `Homebrew <https://brew.sh/>`_.
    77    2. Check the Node SDK `prerequisites <https://github.com/hyperledger/fabric-sdk-node#build-and-test>`_ to find out what level of Node to install.
    78    3. Run ``brew install node`` to download the latest version of node or choose a specific version, for example: ``brew install node@10`` according to what is supported in the prerequisites.
    79    4. Run ``npm install``.
    80  
    81  - If you are on Windows,  you can install the `windows-build-tools <https://github.com/felixrieseberg/windows-build-tools#readme>`_ with npm which installs all required compilers and tooling by running the following command:
    82  
    83    .. code:: bash
    84  
    85      npm install --global windows-build-tools
    86  
    87  - 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/>`_, and a C/C++ compiler toolchain such as `GCC <https://gcc.gnu.org/>`_. You can run the following command to install the other tools:
    88  
    89    .. code:: bash
    90  
    91      sudo apt install build-essential
    92  
    93  Set up the blockchain network
    94  -----------------------------
    95  
    96  If you've already run through :doc:`test_network` tutorial and have a network up
    97  and running, this tutorial will bring down your running network before
    98  bringing up a new one.
    99  
   100  
   101  Launch the network
   102  ^^^^^^^^^^^^^^^^^^
   103  
   104  .. note:: This tutorial demonstrates the JavaScript versions of the Asset Transfer
   105            smart contract and application, but the ``fabric-samples`` repository also
   106            contains Go, Java and TypeScript versions of this sample smart contract. To try the
   107            Go, Java or TypeScript versions, change the ``javascript`` argument
   108            for ``./network.sh deployCC -ccl javascript`` below to either ``go``, ``java`` or ``typescript``
   109            and follow the instructions written to the terminal. You may use any chaincode language sample with
   110            the javascript application sample (e.g javascript application calling go chaincode functions or
   111            javascript application calling typescript chaincode functions, etc.)
   112  
   113  Navigate to the ``test-network`` subdirectory within your local clone of the
   114  ``fabric-samples`` repository.
   115  
   116  .. code:: bash
   117  
   118    cd fabric-samples/test-network
   119  
   120  If you already have a test network running, bring it down to ensure the environment is clean.
   121  
   122  .. code:: bash
   123  
   124    ./network.sh down
   125  
   126  Launch the Fabric test network using the ``network.sh`` shell script.
   127  
   128  .. code:: bash
   129  
   130    ./network.sh up createChannel -c mychannel -ca
   131  
   132  This command will deploy the Fabric test network with two peers, an ordering service, and three certificate authorities (Orderer, Org1, Org2).
   133  Instead of using the cryptogen tool, we bring up the test network using Certificate Authorities,
   134  hence the ``-ca`` flag. Additionally, the org admin user registration is bootstrapped when the Certificate Authority is started.
   135  In a later step, we will show how the sample application completes the admin enrollment.
   136  
   137  Next, let's deploy the chaincode by calling the ``./network.sh`` script with the chaincode name and language options.
   138  
   139  .. code:: bash
   140  
   141    ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-javascript/ -ccl javascript
   142  
   143  .. note:: Behind the scenes, this script uses the chaincode lifecycle to package, install,
   144            query installed chaincode, approve chaincode for both Org1 and Org2, and finally commit the chaincode.
   145  
   146  If the chaincode is successfully deployed, the end of the output in your terminal should look similar to below:
   147  
   148  .. code:: bash
   149  
   150    Committed chaincode definition for chaincode 'basic' on channel 'mychannel':
   151    Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true]
   152    ===================== Query chaincode definition successful on peer0.org2 on channel 'mychannel' =====================
   153  
   154    ===================== Chaincode initialization is not required =====================
   155  
   156  
   157  Sample application
   158  ^^^^^^^^^^^^^^^^^^
   159  Next, let's prepare the sample Asset Transfer Javascript application that will be used to interact with the deployed chaincode.
   160  
   161  - `JavaScript application <https://github.com/hyperledger/fabric-samples/blob/master/asset-transfer-basic/application-javascript>`__
   162  
   163  Note that the sample application is also available in Go and Java at the links below:
   164  
   165  - `Go application <https://github.com/hyperledger/fabric-samples/blob/master/asset-transfer-basic/application-go>`__
   166  - `Java application <https://github.com/hyperledger/fabric-samples/blob/master/asset-transfer-basic/application-java>`__
   167  
   168  
   169  Open a new terminal, and navigate to the ``application-javascript`` folder.
   170  
   171  .. code:: bash
   172  
   173    cd asset-transfer-basic/application-javascript
   174  
   175  This directory contains sample programs that were developed using the Fabric
   176  SDK for Node.js. Run the following command to install the application dependencies.
   177  It may take up to a minute to complete:
   178  
   179  .. code:: bash
   180  
   181    npm install
   182  
   183  This process is installing the key application dependencies defined in the application's
   184  ``package.json``. The most important of which is the ``fabric-network`` Node.js module;
   185  it enables an application to use identities, wallets, and gateways to connect to
   186  channels, submit transactions, and wait for notifications. This tutorial also
   187  uses the ``fabric-ca-client`` module to enroll users with their respective
   188  certificate authorities, generating a valid identity which is then used by
   189  the ``fabric-network`` module to interact with the blockchain network.
   190  
   191  Once ``npm install`` completes, everything is in place to run the application.
   192  Let's take a look at the sample JavaScript application files we will be using
   193  in this tutorial. Run the following command to list the files in this directory:
   194  
   195  .. code:: bash
   196  
   197    ls
   198  
   199  You should see the following:
   200  
   201  .. code:: bash
   202  
   203    app.js                  node_modules            package.json       package-lock.json
   204  
   205  .. note:: The first part of the following section involves communication with the Certificate
   206            Authority. You may find it useful to stream the CA logs when running
   207            the upcoming programs by opening a new terminal shell and running
   208            ``docker logs -f ca_org1``.
   209  
   210  When we started the Fabric test network back in the first step, an admin user --- literally called ``admin`` ---
   211  was created as the **registrar** for the Certificate Authority (CA). Our first
   212  step is to generate the private key, public key, and X.509 certificate for
   213  ``admin`` by having the application call the ``enrollAdmin`` . This process uses a **Certificate
   214  Signing Request** (CSR) --- the private and public key are first generated
   215  locally and the public key is then sent to the CA which returns an encoded
   216  certificate for use by the application. These credentials are then stored
   217  in the wallet, allowing us to act as an administrator for the CA.
   218  
   219  Let's run the application and then step through each of the interactions with the smart contract functions. From the
   220  ``asset-transfer-basic/application-javascript`` directory, run the following command:
   221  
   222  .. code:: bash
   223  
   224    node app.js
   225  
   226  
   227  First, the application enrolls the admin user
   228  ---------------------------------------------
   229  
   230  .. note:: It is important to note that enrolling the admin and registering the app user are interactions that
   231            take place between the application and the Certificate Authority, not between the application and the chaincode.
   232            If you examine the chaincode in ``asset-transfer-basic/chaincode-javascript/lib`` you will find that the chaincode
   233            does not contain any functionality that supports enrolling the admin or registering the user.
   234  
   235  In the sample application code below, you will see that after getting reference to the
   236  common connection profile path, making sure the connection profile exists, and specifying where to create the wallet,
   237  ``enrollAdmin()`` is executed and the admin credentials are generated from the Certificate Authority.
   238  
   239  .. code:: bash
   240  
   241    async function main() {
   242      try {
   243        // build an in memory object with the network configuration (also known as a connection profile)
   244        const ccp = buildCCP();
   245  
   246        // build an instance of the fabric ca services client based on
   247        // the information in the network configuration
   248        const caClient = buildCAClient(FabricCAServices, ccp);
   249  
   250        // setup the wallet to hold the credentials of the application user
   251        const wallet = await buildWallet(Wallets, walletPath);
   252  
   253        // in a real application this would be done on an administrative flow, and only once
   254        await enrollAdmin(caClient, wallet);
   255  
   256  This command stores the CA administrator's credentials in the ``wallet`` directory.
   257  You can find administrator's certificate and private key in the ``wallet/admin.id``
   258  file.
   259  
   260  .. note:: If you decide to start over by taking down the network and bringing it back up again, you will
   261            have to delete the ``wallet`` folder and its identities prior to re-running the javascript application
   262            or you will get an error. This happens because the Certificate Authority and its database are taken down
   263            when the test-network is taken down but the original wallet still remains in the application-javascript directory
   264            so it must be deleted.  When you re-run the sample javascript application, a new wallet and credentials will
   265            be generated.
   266  
   267  
   268  If you scroll back up to the beginning of the output in your terminal, it should be similar to below:
   269  
   270  .. code:: bash
   271  
   272    Wallet path: /Users/<your_username>/fabric-samples/asset-transfer-basic/application-javascript/wallet
   273    Successfully enrolled admin user and imported it into the wallet
   274  
   275  Because the admin registration step is bootstrapped when the Certificate Authority
   276  is started, we only need to enroll the admin.
   277  
   278  .. note:: Since the Fabric CA interactions are common across the samples, enrollAdmin() and the other CA
   279            related functions are included in the ``fabric-samples/test-application/javascript/CAUtil.js``
   280            common utility.
   281  
   282  As for the app user, we need the application to register and enroll the user in the next step.
   283  
   284  
   285  Second, the application registers and enrolls an application user
   286  -----------------------------------------------------------------
   287  
   288  Now that we have the administrator's credentials in a wallet, the application uses the ``admin``
   289  user to register and enroll an app user which will be used
   290  to interact with the blockchain network. The section of the application code is shown below.
   291  
   292  .. code:: bash
   293  
   294    // in a real application this would be done only when a new user was required to be added
   295    // and would be part of an administrative flow
   296    await registerUser(caClient, wallet, userId, 'org1.department1');
   297  
   298  Similar to the admin enrollment, this function uses a CSR to register and enroll ``appUser`` and
   299  store its credentials alongside those of ``admin`` in the wallet. We now have
   300  identities for two separate users --- ``admin`` and ``appUser`` --- that can be
   301  used by our application.
   302  
   303  Scrolling further down in your terminal output, you should see confirmation of the app user registration
   304  similar to this:
   305  
   306  .. code:: bash
   307  
   308    Successfully registered and enrolled user appUser and imported it into the wallet
   309  
   310  Third, the sample application prepares a connection to the channel and smart contract
   311  -------------------------------------------------------------------------------------
   312  
   313  In the prior steps, the application generated the admin and app user credentials and placed them in the wallet.
   314  If the credentials exist and have the correct permissions attributes associated with them, the sample application user
   315  will be able to call chaincode functions after getting reference to the channel name and contract name.
   316  
   317  .. note:: Our connection configuration specifies only the peer from your own Org.
   318            We tell node client sdk to use the service discovery (running on the peer),
   319            which fetches other peers that are currently online, metadata like relevant endorsement policies
   320            and any static information it would have otherwise needed to communicate with the rest of the nodes.
   321            The ``asLocalhost`` set to ``true`` tells it to connect as localhost, since our client is running on same network as the other fabric nodes.
   322            In deployments where you are not running the client on the same network as the other fabric nodes,
   323            the ``asLocalhost`` option would be set to ``false``.
   324  
   325  You will notice that in the following lines of application code, the application is getting reference
   326  to the Contract using the contract name and channel name via Gateway:
   327  
   328  .. code:: bash
   329  
   330    // Create a new gateway instance for interacting with the fabric network.
   331    // In a real application this would be done as the backend server session is setup for
   332    // a user that has been verified.
   333    const gateway = new Gateway();
   334  
   335    try {
   336      // setup the gateway instance
   337      // The user will now be able to create connections to the fabric network and be able to
   338      // submit transactions and query. All transactions submitted by this gateway will be
   339      // signed by this user using the credentials stored in the wallet.
   340      await gateway.connect(ccp, {
   341        wallet,
   342        identity: userId,
   343        discovery: {enabled: true, asLocalhost: true} // using asLocalhost as this gateway is using a fabric network deployed locally
   344      });
   345  
   346      // Build a network instance based on the channel where the smart contract is deployed
   347      const network = await gateway.getNetwork(channelName);
   348  
   349  
   350      // Get the contract from the network.
   351      const contract = network.getContract(chaincodeName);
   352  
   353  When a chaincode package includes multiple smart contracts, on the `getContract() API <https://hyperledger.github.io/fabric-sdk-node/release-2.2/module-fabric-network.Network.html#getContract>`__ you can specify both the name of the chaincode package and a specific smart contract to target. For example:
   354  
   355  .. code:: bash
   356  
   357    const contract = await network.getContract('chaincodeName', 'smartContractName');
   358  
   359  Fourth, the application initializes the ledger with some sample data
   360  --------------------------------------------------------------------
   361  
   362  Now that we are at the point where we are actually having the sample application submit transactions, let’s
   363  go through them in sequence. The application code snippets and invoked chaincode snippets
   364  are provided for each called function, as well as the terminal output.
   365  
   366  The submitTransaction() function is used to invoke the chaincode ``InitLedger`` function to populate the
   367  ledger with some sample data. Under the covers, the submitTransaction() function will use service discovery
   368  to find a set of required endorsing peers for the chaincode, invoke the chaincode
   369  on the required number of peers, gather the chaincode endorsed results from those peers,
   370  and finally submit the transaction to the ordering service.
   371  
   372  Sample application ``'InitLedger'`` call
   373  
   374  .. code:: bash
   375  
   376    // Initialize a set of asset data on the channel using the chaincode 'InitLedger' function.
   377    // This type of transaction would only be run once by an application the first time it was started after it
   378    // deployed the first time. Any updates to the chaincode deployed later would likely not need to run
   379    // an "init" type function.
   380    console.log('\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger');
   381    await contract.submitTransaction('InitLedger');
   382    console.log('*** Result: committed');
   383  
   384  Chaincode ``'InitLedger'`` function
   385  
   386  .. code:: bash
   387  
   388     async InitLedger(ctx) {
   389          const assets = [
   390              {
   391                  ID: 'asset1',
   392                  Color: 'blue',
   393                  Size: 5,
   394                  Owner: 'Tomoko',
   395                  AppraisedValue: 300,
   396              },
   397              {
   398                  ID: 'asset2',
   399                  Color: 'red',
   400                  Size: 5,
   401                  Owner: 'Brad',
   402                  AppraisedValue: 400,
   403              },
   404              {
   405                  ID: 'asset3',
   406                  Color: 'green',
   407                  Size: 10,
   408                  Owner: 'Jin Soo',
   409                  AppraisedValue: 500,
   410              },
   411              {
   412                  ID: 'asset4',
   413                  Color: 'yellow',
   414                  Size: 10,
   415                  Owner: 'Max',
   416                  AppraisedValue: 600,
   417              },
   418              {
   419                  ID: 'asset5',
   420                  Color: 'black',
   421                  Size: 15,
   422                  Owner: 'Adriana',
   423                  AppraisedValue: 700,
   424              },
   425              {
   426                  ID: 'asset6',
   427                  Color: 'white',
   428                  Size: 15,
   429                  Owner: 'Michel',
   430                  AppraisedValue: 800,
   431              },
   432          ];
   433  
   434          for (const asset of assets) {
   435              asset.docType = 'asset';
   436              await ctx.stub.putState(asset.ID, Buffer.from(JSON.stringify(asset)));
   437              console.info(`Asset ${asset.ID} initialized`);
   438          }
   439      }
   440  
   441  The terminal output entry should look similar to below:
   442  
   443  .. code:: bash
   444  
   445    Submit Transaction: InitLedger, function creates the initial set of assets on the ledger
   446  
   447  
   448  Fifth, the application invokes each of the chaincode functions
   449  --------------------------------------------------------------
   450  
   451  First, a word about querying the ledger.
   452  
   453  Each peer in a blockchain network hosts a copy of the `ledger <./ledger/ledger.html>`_. An application
   454  program can view the most recent data from the ledger using read-only invocations of
   455  a smart contract running on your peers called a query.
   456  
   457  Here is a simplified representation of how a query works:
   458  
   459  .. image:: tutorial/write_first_app.diagram.1.png
   460  
   461  The most common queries involve the current values of data in the ledger -- its
   462  `world state <./ledger/ledger.html#world-state>`_. The world state is
   463  represented as a set of key-value pairs, and applications can query data for a
   464  single key or multiple keys. Moreover, you can use complex queries to read the
   465  data on the ledger when you use CouchDB as your state database and model your data in JSON.
   466  This can be very helpful when looking for all assets that match certain keywords
   467  with particular values; all assets with a particular owner, for example.
   468  
   469  Below, the sample application is just getting all the assets that we populated in the prior
   470  step when we initialized the ledger with data. The evaluateTransaction() function is
   471  used when you'd like to query a single peer, without submitting a transaction to
   472  the ordering service.
   473  
   474  Sample application ``'GetAllAssets'`` call
   475  
   476  .. code:: bash
   477  
   478    // Let's try a query type operation (function).
   479    // This will be sent to just one peer and the results will be shown.
   480    console.log('\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger');
   481    let result = await contract.evaluateTransaction('GetAllAssets');
   482    console.log(`*** Result: ${prettyJSONString(result.toString())}`);
   483  
   484  Chaincode ``'GetAllAssets'`` function
   485  
   486  .. code:: bash
   487  
   488     // GetAllAssets returns all assets found in the world state.
   489      async GetAllAssets(ctx) {
   490          const allResults = [];
   491          // range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace.
   492          const iterator = await ctx.stub.getStateByRange('', '');
   493          let result = await iterator.next();
   494          while (!result.done) {
   495              const strValue = Buffer.from(result.value.value.toString()).toString('utf8');
   496              let record;
   497              try {
   498                  record = JSON.parse(strValue);
   499              } catch (err) {
   500                  console.log(err);
   501                  record = strValue;
   502              }
   503              allResults.push({ Key: result.value.key, Record: record });
   504              result = await iterator.next();
   505          }
   506          return JSON.stringify(allResults);
   507      }
   508  
   509  The terminal output should look like this:
   510  
   511  .. code:: json
   512  
   513      Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger
   514      Result: [
   515      {
   516        "Key": "asset1",
   517        "Record": {
   518          "ID": "asset1",
   519          "Color": "blue",
   520          "Size": 5,
   521          "Owner": "Tomoko",
   522          "AppraisedValue": 300,
   523          "docType": "asset"
   524        }
   525      },
   526      {
   527        "Key": "asset2",
   528        "Record": {
   529          "ID": "asset2",
   530          "Color": "red",
   531          "Size": 5,
   532          "Owner": "Brad",
   533          "AppraisedValue": 400,
   534          "docType": "asset"
   535        }
   536      },
   537      {
   538        "Key": "asset3",
   539        "Record": {
   540          "ID": "asset3",
   541          "Color": "green",
   542          "Size": 10,
   543          "Owner": "Jin Soo",
   544          "AppraisedValue": 500,
   545          "docType": "asset"
   546        }
   547      },
   548      {
   549        "Key": "asset4",
   550        "Record": {
   551          "ID": "asset4",
   552          "Color": "yellow",
   553          "Size": 10,
   554          "Owner": "Max",
   555          "AppraisedValue": 600,
   556          "docType": "asset"
   557        }
   558      },
   559      {
   560        "Key": "asset5",
   561        "Record": {
   562          "ID": "asset5",
   563          "Color": "black",
   564          "Size": 15,
   565          "Owner": "Adriana",
   566          "AppraisedValue": 700,
   567          "docType": "asset"
   568        }
   569      },
   570      {
   571        "Key": "asset6",
   572        "Record": {
   573          "ID": "asset6",
   574          "Color": "white",
   575          "Size": 15,
   576          "Owner": "Michel",
   577          "AppraisedValue": 800,
   578          "docType": "asset"
   579        }
   580      }
   581    ]
   582  
   583  Next, the sample application submits a transaction to create 'asset13'.
   584  
   585  Sample application ``'CreateAsset'`` call
   586  
   587  .. code:: bash
   588  
   589    // Now let's try to submit a transaction.
   590    // This will be sent to both peers and if both peers endorse the transaction, the endorsed proposal will be sent
   591    // to the orderer to be committed by each of the peer's to the channel ledger.
   592    console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments');
   593    await contract.submitTransaction('CreateAsset', 'asset13', 'yellow', '5', 'Tom', '1300');
   594    console.log('*** Result: committed');
   595  
   596  Chaincode ``'CreateAsset'`` function
   597  
   598  .. code:: bash
   599  
   600    // CreateAsset issues a new asset to the world state with given details.
   601    async CreateAsset(ctx, id, color, size, owner, appraisedValue) {
   602      const asset = {
   603          ID: id,
   604          Color: color,
   605          Size: size,
   606          Owner: owner,
   607          AppraisedValue: appraisedValue,
   608      };
   609      return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
   610    }
   611  
   612  Terminal output:
   613  
   614  .. code:: bash
   615  
   616    Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments
   617  
   618  .. note:: In the application and chaincode snippets above, it is important
   619            to note that the sample application submits the ``'CreateAsset'``
   620            transaction with the same type and number of arguments the chaincode
   621            is expecting, and in the correct sequence. In this case, the transaction
   622            name and correctly sequenced arguments are: ``'CreateAsset'``, ``'asset13'``,
   623            ``'yellow'``, ``'5'``, ``'Tom'``, ``'1300'`` because the corresponding chaincode
   624            CreateAsset is expecting the correct sequence and type of arguments that define the asset object:
   625            sequence: ID, Color, Size, Owner, and AppraisedValue
   626  
   627            type: ID (string), Color (string), Size (int), Owner (string), AppraisedValue (int).
   628  
   629  The sample application then evaluates a query for 'asset13'.
   630  
   631  Sample application ``'ReadAsset'`` call
   632  
   633    .. code:: bash
   634  
   635      console.log('\n--> Evaluate Transaction: ReadAsset, function returns an asset with a given assetID');
   636      result = await contract.evaluateTransaction('ReadAsset', 'asset13');
   637      console.log(`*** Result: ${prettyJSONString(result.toString())}`);
   638  
   639  Chaincode ``'ReadAsset'`` function
   640  
   641    .. code:: bash
   642  
   643      // ReadAsset returns the asset stored in the world state with given id.
   644      async ReadAsset(ctx, id) {
   645        const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state
   646        if (!assetJSON || assetJSON.length === 0) {
   647            throw new Error(`The asset ${id} does not exist`);
   648        }
   649        return assetJSON.toString();
   650      }
   651  
   652    Terminal output:
   653  
   654    .. code:: bash
   655  
   656      Evaluate Transaction: ReadAsset, function returns an asset with a given assetID
   657      Result: {
   658        "ID": "asset13",
   659        "Color": "yellow",
   660        "Size": "5",
   661        "Owner": "Tom",
   662        "AppraisedValue": "1300"
   663      }
   664  
   665  
   666  In the next part of the sequence, the sample application evaluates to see if
   667  ``asset1`` exists, which will return a boolean value of true, because we populated
   668  the ledger with ``asset1`` when we initialized the ledger with assets. You may recall
   669  that the original appraised value of ``asset1`` was ``300``.
   670  The application then submits a transaction to update ``asset1`` with a new appraised value, and
   671  then immediately evaluates to read ``asset1`` from the ledger to show the new appraised value of ``350``.
   672  
   673  Sample application ``'AssetExists'``, ``'UpdateAsset'``, and ``'ReadAsset'`` calls
   674  
   675  .. code:: bash
   676  
   677    console.log('\n--> Evaluate Transaction: AssetExists, function returns "true" if an asset with given assetID exist');
   678    result = await contract.evaluateTransaction('AssetExists', 'asset1');
   679    console.log(`*** Result: ${prettyJSONString(result.toString())}`);
   680  
   681    console.log('\n--> Submit Transaction: UpdateAsset asset1, change the appraisedValue to 350');
   682    await contract.submitTransaction('UpdateAsset', 'asset1', 'blue', '5', 'Tomoko', '350');
   683    console.log('*** Result: committed');
   684  
   685    console.log('\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes');
   686    result = await contract.evaluateTransaction('ReadAsset', 'asset1');
   687    console.log(`*** Result: ${prettyJSONString(result.toString())}`);
   688  
   689  Chaincode ``'AssetExists'``, ``'UpdateAsset'``, and ``'ReadAsset'`` functions
   690  
   691  .. code:: bash
   692  
   693   // AssetExists returns true when asset with given ID exists in world state.
   694      async AssetExists(ctx, id) {
   695          const assetJSON = await ctx.stub.getState(id);
   696          return assetJSON && assetJSON.length > 0;
   697      }
   698   // UpdateAsset updates an existing asset in the world state with provided parameters.
   699      async UpdateAsset(ctx, id, color, size, owner, appraisedValue) {
   700          const exists = await this.AssetExists(ctx, id);
   701          if (!exists) {
   702              throw new Error(`The asset ${id} does not exist`);
   703          }
   704  
   705          // overwriting original asset with new asset
   706          const updatedAsset = {
   707              ID: id,
   708              Color: color,
   709              Size: size,
   710              Owner: owner,
   711              AppraisedValue: appraisedValue,
   712          };
   713          return ctx.stub.putState(id, Buffer.from(JSON.stringify(updatedAsset)));
   714      }
   715    // ReadAsset returns the asset stored in the world state with given id.
   716    async ReadAsset(ctx, id) {
   717        const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state
   718        if (!assetJSON || assetJSON.length === 0) {
   719            throw new Error(`The asset ${id} does not exist`);
   720        }
   721        return assetJSON.toString();
   722    }
   723  
   724  Terminal Output:
   725  
   726  .. code:: bash
   727  
   728    Evaluate Transaction: AssetExists, function returns "true" if an asset with given assetID exist
   729    Result: true
   730  
   731    Submit Transaction: UpdateAsset asset1, change the appraisedValue to 350
   732  
   733    Evaluate Transaction: ReadAsset, function returns "asset1" attributes
   734    Result: {
   735      "ID": "asset1",
   736      "Color": "blue",
   737      "Size": "5",
   738      "Owner": "Tomoko",
   739      "AppraisedValue": "350"
   740    }
   741  
   742  In this part of the sequence, the sample application attempts to submit
   743  an ``'UdpateAsset'`` transaction for an asset that we know does not exist (``asset70``).
   744  We expect that we will get an error because you cannot update an asset that does not exist,
   745  which is why it is a good idea to check if an asset exists prior to attempting an
   746  asset update or deletion.
   747  
   748  Sample application ``'UpdateAsset'`` call
   749  
   750  .. code:: bash
   751  
   752    try {
   753      // How about we try a transactions where the executing chaincode throws an error
   754      // Notice how the submitTransaction will throw an error containing the error thrown by the chaincode
   755      console.log('\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error');
   756      await contract.submitTransaction('UpdateAsset', 'asset70', 'blue', '5', 'Tomoko', '300');
   757      console.log('******** FAILED to return an error');
   758    } catch (error) {
   759      console.log(`*** Successfully caught the error: \n    ${error}`);
   760    }
   761  
   762  Chaincode ``'UpdateAsset'`` function
   763  
   764  .. code:: bash
   765  
   766    // UpdateAsset updates an existing asset in the world state with provided parameters.
   767    async UpdateAsset(ctx, id, color, size, owner, appraisedValue) {
   768        const exists = await this.AssetExists(ctx, id);
   769        if (!exists) {
   770            throw new Error(`The asset ${id} does not exist`);
   771        }
   772  
   773          // overwriting original asset with new asset
   774          const updatedAsset = {
   775              ID: id,
   776              Color: color,
   777              Size: size,
   778              Owner: owner,
   779              AppraisedValue: appraisedValue,
   780          };
   781          return ctx.stub.putState(id, Buffer.from(JSON.stringify(updatedAsset)));
   782      }
   783  
   784  Terminal output:
   785  
   786  .. code:: bash
   787  
   788    Submit Transaction: UpdateAsset asset70
   789    2020-08-02T11:12:12.322Z - error: [Transaction]: Error: No valid responses from any peers. Errors:
   790      peer=peer0.org1.example.com:7051, status=500, message=error in simulation: transaction returned with failure: Error: The asset asset70 does not exist
   791      peer=peer0.org2.example.com:9051, status=500, message=error in simulation: transaction returned with failure: Error: The asset asset70 does not exist
   792    Expected an error on UpdateAsset of non-existing Asset: Error: No valid responses from any peers. Errors:
   793      peer=peer0.org1.example.com:7051, status=500, message=error in simulation: transaction returned with failure: Error: The asset asset70 does not exist
   794      peer=peer0.org2.example.com:9051, status=500, message=error in simulation: transaction returned with failure: Error: The asset asset70 does not exist
   795  
   796  
   797  In this final part of the sample application transaction sequence, the application
   798  submits a transaction to transfer an existing asset to a new owner and then reads the
   799  asset back from the ledger to display the new owner ``Tom``.
   800  
   801  Sample application ``'TransferAsset'``, and ``'ReadAsset'`` calls
   802  
   803  .. code:: bash
   804  
   805    console.log('\n--> Submit Transaction: TransferAsset asset1, transfer to new owner of Tom');
   806    await contract.submitTransaction('TransferAsset', 'asset1', 'Tom');
   807    console.log('*** Result: committed');
   808  
   809    console.log('\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes');
   810    result = await contract.evaluateTransaction('ReadAsset', 'asset1');
   811    console.log(`*** Result: ${prettyJSONString(result.toString())}`);
   812  
   813  Chaincode ``'TransferAsset'``, and ``'ReadAsset'`` functions
   814  
   815  .. code:: bash
   816  
   817    // TransferAsset updates the owner field of asset with given id in the world state.
   818    async TransferAsset(ctx, id, newOwner) {
   819        const assetString = await this.ReadAsset(ctx, id);
   820        const asset = JSON.parse(assetString);
   821        asset.Owner = newOwner;
   822        return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
   823    }
   824     // ReadAsset returns the asset stored in the world state with given id.
   825    async ReadAsset(ctx, id) {
   826        const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state
   827        if (!assetJSON || assetJSON.length === 0) {
   828            throw new Error(`The asset ${id} does not exist`);
   829        }
   830        return assetJSON.toString();
   831    }
   832  
   833  Terminal output:
   834  
   835  .. code:: bash
   836  
   837    Submit Transaction: TransferAsset asset1, transfer to new owner of Tom
   838    Evaluate Transaction: ReadAsset, function returns "asset1" attributes
   839    Result: {
   840      "ID": "asset1",
   841      "Color": "blue",
   842      "Size": "5",
   843      "Owner": "Tom",
   844      "AppraisedValue": "350"
   845    }
   846  
   847  
   848  A closer look
   849  -------------
   850  
   851  Let's take a closer look at how the sample javascript application uses the APIs provided by the
   852  `Fabric Node SDK <https://hyperledger.github.io/fabric-sdk-node/>`__ to
   853  interact with our Fabric network. Use an editor (e.g. atom or visual studio) to
   854  open ``app.js`` located in the ``asset-transfer-basic/application-javascript`` directory.
   855  
   856  The application starts by bringing in scope two key classes from the
   857  ``fabric-network`` module; ``Wallets`` and ``Gateway``. These classes
   858  will be used to locate the ``appUser`` identity in the wallet, and use it to
   859  connect to the network:
   860  
   861  .. code:: bash
   862  
   863    const { Gateway, Wallets } = require('fabric-network');
   864  
   865  First, the program sets up the gateway connection with the userId stored in the wallet and
   866  specifies discovery options.
   867  
   868  .. code:: bash
   869  
   870    // setup the gateway instance
   871    // The user will now be able to create connections to the fabric network and be able to
   872    // submit transactions and query. All transactions submitted by this gateway will be
   873    // signed by this user using the credentials stored in the wallet.
   874    await gateway.connect(ccp, {
   875      wallet,
   876      identity: userId,
   877      discovery: {enabled: true, asLocalhost: true} // using asLocalhost as this gateway is using a fabric network deployed locally
   878    });
   879  
   880  Note at the top of the sample application code we require external utility files to build the CAClient,
   881  registerUser, enrollAdmin, buildCCP (common connection profile), and buildWallet.
   882  These utility programs are located in ``AppUtil.js`` in the ``test-application/javascript`` directory.
   883  
   884  In ``AppUtil.js``, ``ccpPath`` describes the path to the connection profile that our application will use
   885  to connect to our network. The connection profile was loaded from inside the
   886  ``fabric-samples/test-network`` directory and parsed as a JSON file:
   887  
   888  .. code:: bash
   889  
   890    const ccpPath = path.resolve(__dirname, '..', '..', 'test-network','organizations','peerOrganizations','org1.example.com', 'connection-org1.json');
   891  
   892  If you'd like to understand more about the structure of a connection profile,
   893  and how it defines the network, check out
   894  `the connection profile topic <./developapps/connectionprofile.html>`_.
   895  
   896  A network can be divided into multiple channels, and the next important line of
   897  code connects the application to a particular channel within the network,
   898  ``mychannel``, where our smart contract was deployed. Note that we assigned constants
   899  near the top of the sample application to account for the channel name and the contract name:
   900  
   901  .. code:: bash
   902  
   903    const channelName = 'mychannel';
   904    const chaincodeName = 'basic';
   905  
   906  .. code:: bash
   907  
   908    const network = await gateway.getNetwork(channelName);
   909  
   910  Within this channel, we can access the asset-transfer ('basic') smart contract to interact
   911  with the ledger:
   912  
   913  .. code:: bash
   914  
   915    const contract = network.getContract(chaincodeName);
   916  
   917  
   918  Within asset-transfer ('basic') there are many different **transactions**, and our application
   919  initially uses the ``InitLedger`` transaction to populate the ledger world state with
   920  data:
   921  
   922  .. code:: bash
   923  
   924    await contract.submitTransaction('InitLedger');
   925  
   926  The ``evaluateTransaction`` method represents one of the simplest interactions
   927  with a smart contract in blockchain network. It simply picks a peer defined in
   928  the connection profile and sends the request to it, where it is evaluated. The
   929  smart contract queries the assets on the peer's copy of the ledger and returns
   930  the result to the application. This interaction does not result in an update of
   931  the ledger.
   932  
   933  ``submitTransaction`` is much more sophisticated than ``evaluateTransaction``.
   934  Rather than interacting with a single peer, the SDK will send the
   935  ``submitTransaction`` proposal to every required organization's peer in the
   936  blockchain network based on the chaincode's endorsement policy.
   937  Each of these peers will execute the requested smart
   938  contract using this proposal, to generate a transaction response which it endorses (signs)
   939  and returns to the SDK. The SDK collects all the endorsed transaction responses
   940  into a single transaction, which it then submits to the orderer. The orderer
   941  collects and sequences transactions from various application clients into a block of
   942  transactions. These blocks are distributed to every peer in the network,
   943  where every transaction is validated and committed. Finally, the SDK is
   944  notified via an event, allowing it to return control to the application.
   945  
   946  .. note:: ``submitTransaction`` includes an event listener that checks to make
   947            sure the transaction has been validated and committed to the ledger.
   948            Applications should either utilize a commit listener, or
   949            leverage an API like ``submitTransaction`` that does this for you.
   950            Without doing this, your transaction may not have been successfully
   951            ordered, validated, and committed to the ledger.
   952  
   953  ``submitTransaction`` does all this for the application! The process by which
   954  the application, smart contract, peers and ordering service work together to
   955  keep the ledger consistent across the network is called consensus, and it is
   956  explained in detail in this `section <./peers/peers.html>`_.
   957  
   958  Updating the ledger
   959  -------------------
   960  
   961  From an application perspective, updating the ledger is simple. An application
   962  submits a transaction to the blockchain network, and when it has been validated
   963  and committed, the application receives a notification that the transaction has been successful.
   964  Behind the scenes, this involves the process of consensus whereby the different components
   965  of the blockchain network work together to ensure that every proposed update to the ledger
   966  is valid and performed in an agreed and consistent order.
   967  
   968  .. image:: tutorial/write_first_app.diagram.2.png
   969  
   970  The asset-transfer ('basic') smart contract
   971  -------------------------------------------
   972  The smart contract sample is available in the following languages:
   973  
   974  - `Golang <https://github.com/hyperledger/fabric-samples/blob/master/asset-transfer-basic/chaincode-go>`__
   975  - `Java <https://github.com/hyperledger/fabric-samples/blob/master/asset-transfer-basic/chaincode-java>`__
   976  - `JavaScript <https://github.com/hyperledger/fabric-samples/blob/master/asset-transfer-basic/chaincode-javascript>`__
   977  - `Typescript <https://github.com/hyperledger/fabric-samples/blob/master/asset-transfer-basic/chaincode-typescript>`__
   978  
   979  Clean up
   980  --------
   981  
   982  When you are finished using the asset-transfer sample, you can bring down the test
   983  network using ``network.sh`` script.
   984  
   985  
   986  .. code:: bash
   987  
   988    ./network.sh down
   989  
   990  This command will bring down the CAs, peers, and ordering node of the network
   991  that we created. Note that all of the data on the ledger will be lost.
   992  If you want to go through the tutorial again, you will start from a clean initial state.
   993  
   994  Summary
   995  -------
   996  
   997  Now that we’ve seen how the sample application and chaincode are written and how they interact with each other, you should have a pretty
   998  good sense of how applications interact with a blockchain network using a smart
   999  contract to query or update the ledger. You’ve seen the basics of the roles
  1000  smart contracts, APIs, and the SDK play in queries and updates and you should
  1001  have a feel for how different kinds of applications could be used to perform
  1002  other business tasks and operations.
  1003  
  1004  Additional resources
  1005  --------------------
  1006  
  1007  As we said in the introduction, we have a whole section on
  1008  :doc:`developapps/developing_applications` that includes in-depth information on
  1009  smart contracts, process and data design, a tutorial using a more in-depth
  1010  Commercial Paper `tutorial <./tutorial/commercial_paper.html>`_ and a large
  1011  amount of other material relating to the development of applications.
  1012  
  1013  .. Licensed under Creative Commons Attribution 4.0 International License
  1014     https://creativecommons.org/licenses/by/4.0/