github.com/true-sqn/fabric@v2.1.1+incompatible/docs/source/chaincode4ade.rst (about)

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