github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/docs/source/write_first_app.rst (about)

     1  Writing Your First Application
     2  ==============================
     3  
     4  The goal of this document is to show the tasks and provide a baseline for writing
     5  your first application against a Hyperledger Fabric network.
     6  
     7  At the most basic level, applications on a blockchain network are what enable
     8  users to **query** a ledger (asking for specific records it contains), or to
     9  **update** it (adding records to it).
    10  
    11  Our application, composed in Javascript, leverages the Node.js SDK to interact
    12  with the network (where our ledger exists). This tutorial will guide you through
    13  the three steps involved in writing your first application.
    14  
    15    **1. Starting a test Hyperledger Fabric blockchain network.** We need some basic components
    16    in our network in order to query and update the ledger.  These components --
    17    a peer node, ordering node and Certificate Authority -- serve as the backbone of
    18    our network; we'll also have a CLI container used for a few administrative commands.
    19    A single script will download and launch this test network.
    20  
    21    **2. Learning the parameters of the sample smart contract our app will use.** Our
    22    smart contracts contain various functions that allow us to interact with the ledger
    23    in different ways.  For example, we can read data holistically or on a more granular
    24    level.
    25  
    26    **3. Developing the application to be able to query and update records.**
    27    We provide two sample applications -- one for querying the ledger and another for
    28    updating it. Our apps will use the SDK APIs to interact with the network and
    29    ultimately call these functions.
    30  
    31  After completing this tutorial, you should have a basic understanding of how
    32  an application, using the Hyperledger Fabric SDK for Node.js, is programmed
    33  in conjunction with a smart contract to interact with the ledger on a
    34  Hyperledger Fabric network.
    35  
    36  First, let's launch our test network...
    37  
    38  Getting a Test Network
    39  ----------------------
    40  
    41  Visit the :doc:`prereqs` page and ensure you have the necessary dependencies installed
    42  on your machine.
    43  
    44  Now determine a working directory where you want to clone the fabric-samples repo. Issue
    45  the clone command and change into the ``fabcar`` subdirectory
    46  
    47  .. code:: bash
    48  
    49    git clone https://github.com/hyperledger/fabric-samples.git
    50    cd fabric-samples/fabcar
    51  
    52  This subdirectory -- ``fabcar`` -- contains the scripts
    53  and application code to run the sample app.  Issue an ``ls`` from
    54  this directory.  You should see the following:
    55  
    56  .. code:: bash
    57  
    58     chaincode	invoke.js	network		package.json	query.js	startFabric.sh
    59  
    60  Now use the ``startFabric.sh`` script to launch the network.
    61  
    62  .. note:: The following command downloads and extracts the Hyperledger Fabric
    63            Docker images, so it will take a few minutes to complete.
    64  
    65  .. code:: bash
    66  
    67    ./startFabric.sh
    68  
    69  For the sake of brevity, we won't delve into the details of what's happening with
    70  this command.  Here's a quick synopsis:
    71  
    72  * launches a peer node, ordering node, Certificate Authority and CLI container
    73  * creates a channel and joins the peer to the channel
    74  * installs smart contract (i.e. chaincode) onto the peer's file system and instantiates said chaincode on the channel; instantiate starts a chaincode container
    75  * calls the ``initLedger`` function to populate the channel ledger with 10 unique cars
    76  
    77  .. note:: These operations will typically be done by an organizational or peer admin.  The script uses the
    78  	  CLI to execute these commands, however there is support in the SDK as well.
    79  	  Refer to the `Hyperledger Fabric Node SDK repo <https://github.com/hyperledger/fabric-sdk-node>`__
    80  	  for example scripts.
    81  
    82  Issue a ``docker ps`` command to reveal the processes started by the ``startFabric.sh`` script.
    83  You can learn more about the details and mechanics of these operations in the
    84  :doc:`build_network` section.  Here we'll just focus on the application.  The following picture
    85  provides a simplistic representation of how the application interacts with the
    86  Hyperledger Fabric network.
    87  
    88  .. image:: images/AppConceptsOverview.png
    89  
    90  Alright, now that you’ve got a sample network and some code, let’s take a
    91  look at how the different pieces fit together.
    92  
    93  How Applications Interact with the Network
    94  ------------------------------------------
    95  
    96  Applications use **APIs** to invoke smart contracts (referred to as "chaincode").
    97  These smart contracts are hosted in the network and identified by name and version.
    98  For example, our chaincode container is titled - ``dev-peer0.org1.example.com-fabcar-1.0`` - where
    99  the name is ``fabcar``, the version is ``1.0`` and the peer it is running against is ``dev-peer0.org1.example.com``.
   100  
   101  APIs are accessible with a software development kit (SDK). For purposes of this
   102  exercise, we'll be using the `Hyperledger Fabric Node SDK
   103  <https://fabric-sdk-node.github.io/>`__ though there is also a Java SDK and
   104  CLI that can be used to develop applications.
   105  
   106  Querying the Ledger
   107  -------------------
   108  Queries are how you read data from the ledger. You can query for the value
   109  of a single key, multiple keys, or -- if the ledger is written in a rich data storage
   110  format like JSON -- perform complex searches against it (looking for all
   111  assets that contain certain keywords, for example).
   112  
   113  .. image:: images/QueryingtheLedger.png
   114  
   115  As we said earlier, our sample network has an active chaincode container and
   116  a ledger that has been primed with 10 different cars.  We also have some
   117  sample Javascript code - ``query.js`` - in the ``fabcar`` directory that
   118  can be used to query the ledger for details on the cars.
   119  
   120  Before we take a look at how that app works, we need to install the SDK node
   121  modules in order for our program to function.  From your ``fabcar`` directory,
   122  issue the following:
   123  
   124  .. code:: bash
   125  
   126    npm install
   127  
   128  .. note:: You will issue all subsequent commands from the ``fabcar`` directory.
   129  
   130  Now we can run our javascript programs.  First, let's run our ``query.js``
   131  program to return a listing of all the cars on the ledger.  A function that
   132  will query all the cars, ``queryAllCars``, is pre-loaded in the app,
   133  so we can simply run the program as is:
   134  
   135  .. code:: bash
   136  
   137    node query.js
   138  
   139  It should return something like this:
   140  
   141  .. code:: json
   142  
   143    Query result count =  1
   144    Response is  [{"Key":"CAR0", "Record":{"colour":"blue","make":"Toyota","model":"Prius","owner":"Tomoko"}},
   145    {"Key":"CAR1",   "Record":{"colour":"red","make":"Ford","model":"Mustang","owner":"Brad"}},
   146    {"Key":"CAR2", "Record":{"colour":"green","make":"Hyundai","model":"Tucson","owner":"Jin Soo"}},
   147    {"Key":"CAR3", "Record":{"colour":"yellow","make":"Volkswagen","model":"Passat","owner":"Max"}},
   148    {"Key":"CAR4", "Record":{"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}},
   149    {"Key":"CAR5", "Record":{"colour":"purple","make":"Peugeot","model":"205","owner":"Michel"}},
   150    {"Key":"CAR6", "Record":{"colour":"white","make":"Chery","model":"S22L","owner":"Aarav"}},
   151    {"Key":"CAR7", "Record":{"colour":"violet","make":"Fiat","model":"Punto","owner":"Pari"}},
   152    {"Key":"CAR8", "Record":{"colour":"indigo","make":"Tata","model":"Nano","owner":"Valeria"}},
   153    {"Key":"CAR9", "Record":{"colour":"brown","make":"Holden","model":"Barina","owner":"Shotaro"}}]
   154  
   155  These are the 10 cars. A black Tesla Model S owned by Adriana, a red Ford Mustang
   156  owned by Brad, a violet Fiat Punto owned by someone named Pari, and so on. The ledger
   157  is key/value based and in our implementation the key is ``CAR0`` through ``CAR9``.
   158  This will become particularly important in a moment.
   159  
   160  Now let's see what it looks like under the hood (if you'll forgive the pun).
   161  Use an editor (e.g. atom or visual studio) and open the ``query.js`` program.
   162  
   163  The inital section of the application defines certain variables such as chaincode ID, channel name
   164  and network endpoints:
   165  
   166  .. code:: bash
   167  
   168      var options = {
   169  	  wallet_path : path.join(__dirname, './network/creds'),
   170  	  user_id: 'PeerAdmin',
   171  	  channel_id: 'mychannel',
   172  	  chaincode_id: 'fabcar',
   173  	  network_url: 'grpc://localhost:7051',
   174  
   175  This is the chunk where we construct our query:
   176  
   177  .. code:: bash
   178  
   179       // queryCar - requires 1 argument, ex: args: ['CAR4'],
   180       // queryAllCars - requires no arguments , ex: args: [''],
   181       const request = {
   182          chaincodeId: options.chaincode_id,
   183          txId: transaction_id,
   184          fcn: 'queryAllCars',
   185          args: ['']
   186  
   187  We define the ``chaincode_id`` variable as ``fabcar`` -- allowing us to target this specific chaincode -- and
   188  then call the ``queryAllCars`` function defined within that chaincode.
   189  
   190  When we issued the ``node query.js`` command earlier, this specific function was
   191  called to query the ledger.  However, this isn't the only function that we can pass.
   192  
   193  To take a look at the others, navigate to the ``chaincode`` subdirectory and open
   194  ``fabcar.go`` in your editor.  You'll see that we have the following functions available
   195  to call - ``initLedger``, ``queryCar``, ``queryAllCars``, ``createCar`` and ``changeCarOwner``.
   196  Let's take a closer look at the ``queryAllCars`` function to see how it interacts with the
   197  ledger.
   198  
   199  .. code:: bash
   200  
   201     func (s *SmartContract) queryAllCars(APIstub shim.ChaincodeStubInterface) sc.Response {
   202  
   203  	startKey := "CAR0"
   204  	endKey := "CAR999"
   205  
   206  	resultsIterator, err := APIstub.GetStateByRange(startKey, endKey)
   207  
   208  The function uses the shim interface function ``GetStateByRange`` to return
   209  ledger data between the args of ``startKey`` and ``endKey``.  Those keys are
   210  defined as ``CAR0`` and ``CAR999`` respectively.  Therefore, we could theoretically
   211  create 1,000 cars (assuming the keys are tagged properly) and a ``queryAllCars`` would
   212  reveal every one.
   213  
   214  Below is a representation of how an app would call different functions in chaincode.
   215  
   216  .. image:: images/RunningtheSample.png
   217  
   218  We can see our ``queryAllCars`` function up there, as well as one called ``createCar`` that
   219  will allow us to update the ledger and ultimately append a new block to the chain.
   220  But first, let's do another query.
   221  
   222  Go back to the ``query.js`` program and edit the constructor request to query
   223  a specific car.  We'll do this by changing the function from ``queryAllCars``
   224  to ``queryCar`` and passing a specific "Key" to the args parameter.  Let's use
   225  ``CAR4`` here.  So our edited ``query.js`` program should now contain the
   226  following:
   227  
   228  .. code:: bash
   229  
   230    const request = {
   231          chaincodeId: options.chaincode_id,
   232          txId: transaction_id,
   233          fcn: 'queryCar',
   234          args: ['CAR4']
   235  
   236  Save the program and navigate back to your ``fabcar`` directory.  Now run the
   237  program again:
   238  
   239  .. code:: bash
   240  
   241    node query.js
   242  
   243  You should see the following:
   244  
   245  .. code:: json
   246  
   247    {"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}
   248  
   249  So we've gone from querying all cars to querying just one, Adriana's black Tesla
   250  Model S.  Using the ``queryCar`` function, we can query against any key (e.g. ``CAR0``) and
   251  get whatever make, model, color, and owner correspond to that car.
   252  
   253  Great.  Now you should be comfortable with the basic query functions in the chaincode,
   254  and the handful of parameters in the query program.  Time to update the ledger...
   255  
   256  Updating the Ledger
   257  -------------------
   258  
   259  Now that we’ve done a few ledger queries and added a bit of code, we’re ready to
   260  update the ledger. There are a lot of potential updates we could
   261  make, but let's just create a new car for starters.
   262  
   263  Ledger updates start with an application generating a transaction proposal.
   264  Just like query, a request is constructed to identify the channel ID,
   265  function, and specific smart contract to target for the transaction. The program
   266  then calls the ``channel.SendTransactionProposal`` API to send the transaction proposal to the peer(s)
   267  for endorsement.
   268  
   269  The network (i.e. endorsing peer) returns a proposal response, which the application uses
   270  to build and sign a transaction request.  This request is sent to the ordering service by
   271  calling the ``channel.sendTransaction`` API.  The ordering service will bundle the transaction
   272  into a block and then "deliver" the block to all peers on a channel for validation.  (In our
   273  case we have only the single endorsing peer.)
   274  
   275  Finally the application uses the ``eh.setPeerAddr`` API to connect to the peer's
   276  event listener port, and calls ``eh.registerTxEvent`` to register events associated
   277  with a specific transaction ID.  This API allows the application to know the fate of
   278  a transaction (i.e. successfully committed or unsuccessful).  Think of it as a notification mechanism.
   279  
   280  .. note:: We don't go into depth here on a transaction's lifecycle.  Consult the
   281            :doc:`txflow` documentation for lower level details on how a transaction
   282            is ultimately committed to the ledger.
   283  
   284  The goal with our initial invoke is to simply create a new asset (car in this case).  We
   285  have a separate javascript program - ``invoke.js`` - that we will use for these transactions.
   286  Just like query, use an editor to open the program and navigate to the codeblock where we
   287  construct our invocation:
   288  
   289  .. code:: bash
   290  
   291      // createCar - requires 5 args, ex: args: ['CAR11', 'Honda', 'Accord', 'Black', 'Tom'],
   292      // changeCarOwner - requires 2 args , ex: args: ['CAR10', 'Barry'],
   293      // send proposal to endorser
   294      var request = {
   295          targets: targets,
   296          chaincodeId: options.chaincode_id,
   297          fcn: '',
   298          args: [''],
   299          chainId: options.channel_id,
   300          txId: tx_id
   301  
   302  You'll see that we can call one of two functions - ``createCar`` or ``changeCarOwner``.
   303  Let's create a red Chevy Volt and give it to an owner named Nick.  We're up to ``CAR9``
   304  on our ledger, so we'll use ``CAR10`` as the identifying key here.  The updated codeblock
   305  should look like this:
   306  
   307  .. code:: bash
   308  
   309      var request = {
   310          targets: targets,
   311          chaincodeId: options.chaincode_id,
   312          fcn: 'createCar',
   313          args: ['CAR10', 'Chevy', 'Volt', 'Red', 'Nick'],
   314          chainId: options.channel_id,
   315          txId: tx_id
   316  
   317  Save it and run the program:
   318  
   319  .. code:: bash
   320  
   321     node invoke.js
   322  
   323  There will be some output in the terminal about Proposal Response and Transaction ID.  However,
   324  all we're concerned with is this message:
   325  
   326  .. code:: bash
   327  
   328     The transaction has been committed on peer localhost:7053
   329  
   330  The peer emits this event notification, and our application receives it thanks to our
   331  ``eh.registerTxEvent`` API.  So now if we go back to our ``query.js`` program and call
   332  the ``queryCar`` function against an arg of ``CAR10``, we should see the following:
   333  
   334  .. code:: bash
   335  
   336     Response is  {"colour":"Red","make":"Chevy","model":"Volt","owner":"Nick"}
   337  
   338  Finally, let's call our last function - ``changeCarOwner``.  Nick is feeling generous and
   339  he wants to give his Chevy Volt to a man named Barry.  So, we simply edit ``invoke.js``
   340  to reflect the following:
   341  
   342  .. code:: bash
   343  
   344       var request = {
   345          targets: targets,
   346          chaincodeId: options.chaincode_id,
   347          fcn: 'changeCarOwner',
   348          args: ['CAR10', 'Barry'],
   349          chainId: options.channel_id,
   350          txId: tx_id
   351  
   352  Execute the program again - ``node invoke.js`` - and then run the query app one final time.
   353  We are still querying against ``CAR10``, so we should see:
   354  
   355  .. code:: bash
   356  
   357     Response is  {"colour":"Red","make":"Chevy","model":"Volt","owner":"Barry"}
   358  
   359  Additional Resources
   360  --------------------
   361  
   362  The `Hyperledger Fabric Node SDK repo <https://github.com/hyperledger/fabric-sdk-node>`__
   363  is an excellent resource for deeper documentation and sample code.  You can also consult
   364  the Hyperledger Fabric community and component experts on `Hyperledger Rocket Chat <https://chat.hyperledger.org/home>`__.
   365  
   366  .. Licensed under Creative Commons Attribution 4.0 International License
   367     https://creativecommons.org/licenses/by/4.0/