github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/docs/source/chaincode4ade.rst (about)

     1  Writing Your First Chaincode
     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 asset-transfer chaincode sample walkthrough,
    22  and the purpose of each method in the Fabric Contract 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 high level APIs provided by the Fabric Contract API.
    28  To learn more about developing smart contracts using the Fabric contract API, visit the :doc:`developapps/smartcontract` topic.
    29  
    30  Fabric Contract API
    31  -------------------
    32  
    33  The ``fabric-contract-api`` provides the contract interface, a high level API for application developers to implement Smart Contracts.
    34  Within Hechain, Smart Contracts are also known as Chaincode. Working with this API provides a high level entry point to writing business logic.
    35  Documentation of the Fabric Contract API for different languages can be found at the links below:
    36  
    37    - `Go <https://godoc.org/github.com/hyperledger/fabric-contract-api-go/contractapi>`__
    38    - `Node.js <https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/>`__
    39    - `Java <https://hyperledger.github.io/fabric-chaincode-java/{BRANCH}/api/org/hyperledger/fabric/contract/package-summary.html>`__
    40  
    41  
    42  Note that when using the contract api, each chaincode function that is called is passed a transaction context "ctx", from which
    43  you can get the chaincode stub (GetStub() ), which has functions to access the ledger (e.g. GetState() ) and make requests
    44  to update the ledger (e.g. PutState() ). You can learn more at the language-specific links below.
    45  
    46    - `Go <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#Chaincode>`__
    47    - `Node.js <https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-shim.ChaincodeInterface.html>`__
    48    - `Java <https://hyperledger.github.io/fabric-chaincode-java/{BRANCH}/api/org/hyperledger/fabric/shim/Chaincode.html>`__
    49  
    50  
    51  In this tutorial using Go chaincode, we will demonstrate the use of these APIs
    52  by implementing a asset-transfer chaincode application that manages simple "assets".
    53  
    54  .. _Asset Transfer Chaincode:
    55  
    56  Asset Transfer Chaincode
    57  ------------------------
    58  Our application is a basic sample chaincode to initialize a ledger with assets, create, read, update, and delete assets, check to see
    59  if an asset exists, and transfer assets from one owner to another.
    60  
    61  Choosing a Location for the Code
    62  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    63  
    64  If you haven't been doing programming in Go, you may want to make sure that
    65  you have `Go <https://golang.org>`_ installed and your system properly configured. We assume
    66  you are using a version that supports modules.
    67  
    68  Now, you will want to create a directory for your chaincode application.
    69  
    70  To keep things simple, let's use the following command:
    71  
    72  .. code:: bash
    73  
    74    // atcc is shorthand for asset transfer chaincode
    75    mkdir atcc && cd atcc
    76  
    77  Now, let's create the module and the source file that we'll fill in with code:
    78  
    79  .. code:: bash
    80  
    81    go mod init atcc
    82    touch atcc.go
    83  
    84  Housekeeping
    85  ^^^^^^^^^^^^
    86  
    87  First, let's start with some housekeeping. As with every chaincode, it implements the
    88  `fabric-contract-api interface <https://godoc.org/github.com/hyperledger/fabric-contract-api-go/contractapi>`_,
    89  so let's add the Go import statements for the necessary dependencies for our chaincode. We'll import the
    90  fabric contract api package and define our SmartContract.
    91  
    92  .. code:: go
    93  
    94    package main
    95  
    96    import (
    97      "fmt"
    98      "encoding/json"
    99      "log"
   100      "github.com/hyperledger/fabric-contract-api-go/contractapi"
   101    )
   102  
   103    // SmartContract provides functions for managing an Asset
   104    type SmartContract struct {
   105      contractapi.Contract
   106    }
   107  
   108  Next, let's add a struct ``Asset`` to represent simple assets on the ledger.
   109  Note the JSON annotations, which will be used to marshal the asset to JSON which is stored on the ledger.
   110  JSON though is not a deterministic data format - the order of elements can change, whilst still representing the same data semantically.
   111  The challenge, therefore, is to be able to generate a consistent set of JSON.
   112  Below is also shown a good approach to achieve consistency which consists of creating an asset object struct following alphabetic order.
   113  
   114  .. code:: go
   115  
   116    // Asset describes basic details of what makes up a simple asset
   117    // Insert struct field in alphabetic order => to achieve determinism accross languages
   118    // golang keeps the order when marshal to json but doesn't order automatically
   119  
   120    type Asset struct {
   121      AppraisedValue int    `json:"AppraisedValue"`
   122      Color          string `json:"Color"`
   123      ID             string `json:"ID"`
   124      Owner          string `json:"Owner"`
   125      Size           int    `json:"Size"`
   126    }
   127  
   128  Initializing the Chaincode
   129  ^^^^^^^^^^^^^^^^^^^^^^^^^^
   130  
   131  Next, we'll implement the ``InitLedger`` function to populate the ledger with some initial data.
   132  
   133  .. code:: go
   134  
   135    // InitLedger adds a base set of assets to the ledger
   136    func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
   137      assets := []Asset{
   138        {ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300},
   139        {ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400},
   140        {ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500},
   141        {ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600},
   142        {ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700},
   143        {ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800},
   144      }
   145  
   146      for _, asset := range assets {
   147        assetJSON, err := json.Marshal(asset)
   148        if err != nil {
   149            return err
   150        }
   151  
   152        err = ctx.GetStub().PutState(asset.ID, assetJSON)
   153        if err != nil {
   154            return fmt.Errorf("failed to put to world state. %v", err)
   155        }
   156      }
   157  
   158      return nil
   159    }
   160  
   161  Next, we write a function to create an asset on the ledger that does not yet exist. When writing chaincode, it
   162  is a good idea to check for the existence of something on the ledger prior to taking an action on it, as is demonstrated
   163  in the ``CreateAsset`` function below.
   164  
   165  
   166  .. code:: go
   167  
   168      // CreateAsset issues a new asset to the world state with given details.
   169      func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
   170        exists, err := s.AssetExists(ctx, id)
   171        if err != nil {
   172          return err
   173        }
   174        if exists {
   175          return fmt.Errorf("the asset %s already exists", id)
   176        }
   177  
   178        asset := Asset{
   179          ID:             id,
   180          Color:          color,
   181          Size:           size,
   182          Owner:          owner,
   183          AppraisedValue: appraisedValue,
   184        }
   185        assetJSON, err := json.Marshal(asset)
   186        if err != nil {
   187          return err
   188        }
   189  
   190        return ctx.GetStub().PutState(id, assetJSON)
   191      }
   192  
   193  Now that we have populated the ledger with some initial assets and created an asset,
   194  let's write a function ``ReadAsset`` that allows us to read an asset from the ledger.
   195  
   196  .. code:: go
   197  
   198    // ReadAsset returns the asset stored in the world state with given id.
   199    func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {
   200      assetJSON, err := ctx.GetStub().GetState(id)
   201      if err != nil {
   202        return nil, fmt.Errorf("failed to read from world state: %v", err)
   203      }
   204      if assetJSON == nil {
   205        return nil, fmt.Errorf("the asset %s does not exist", id)
   206      }
   207  
   208      var asset Asset
   209      err = json.Unmarshal(assetJSON, &asset)
   210      if err != nil {
   211        return nil, err
   212      }
   213  
   214      return &asset, nil
   215    }
   216  
   217  Now that we have assets on our ledger we can interact with, let's write a chaincode function
   218  ``UpdateAsset`` that allows us to update attributes of the asset that we are allowed to change.
   219  
   220  .. code:: go
   221  
   222    // UpdateAsset updates an existing asset in the world state with provided parameters.
   223    func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
   224      exists, err := s.AssetExists(ctx, id)
   225      if err != nil {
   226        return err
   227      }
   228      if !exists {
   229        return fmt.Errorf("the asset %s does not exist", id)
   230      }
   231  
   232      // overwriting original asset with new asset
   233      asset := Asset{
   234        ID:             id,
   235        Color:          color,
   236        Size:           size,
   237        Owner:          owner,
   238        AppraisedValue: appraisedValue,
   239      }
   240      assetJSON, err := json.Marshal(asset)
   241      if err != nil {
   242        return err
   243      }
   244  
   245      return ctx.GetStub().PutState(id, assetJSON)
   246    }
   247  
   248  There may be cases where we need the ability to delete an asset from the ledger,
   249  so let's write a ``DeleteAsset`` function to handle that requirement.
   250  
   251  .. code:: go
   252  
   253    // DeleteAsset deletes an given asset from the world state.
   254    func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {
   255      exists, err := s.AssetExists(ctx, id)
   256      if err != nil {
   257        return err
   258      }
   259      if !exists {
   260        return fmt.Errorf("the asset %s does not exist", id)
   261      }
   262  
   263      return ctx.GetStub().DelState(id)
   264    }
   265  
   266  
   267  We said earlier that is was a good idea to check to see if an asset exists before
   268  taking an action on it, so let's write a function called ``AssetExists`` to implement that requirement.
   269  
   270  .. code:: go
   271  
   272    // AssetExists returns true when asset with given ID exists in world state
   273    func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
   274      assetJSON, err := ctx.GetStub().GetState(id)
   275      if err != nil {
   276        return false, fmt.Errorf("failed to read from world state: %v", err)
   277      }
   278  
   279      return assetJSON != nil, nil
   280    }
   281  
   282  Next, we'll write a function we'll call ``TransferAsset`` that enables the transfer of an asset from one owner to another.
   283  
   284  .. code:: go
   285  
   286    // TransferAsset updates the owner field of asset with given id in world state.
   287    func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error {
   288      asset, err := s.ReadAsset(ctx, id)
   289      if err != nil {
   290        return err
   291      }
   292  
   293      asset.Owner = newOwner
   294      assetJSON, err := json.Marshal(asset)
   295      if err != nil {
   296        return err
   297      }
   298  
   299      return ctx.GetStub().PutState(id, assetJSON)
   300    }
   301  
   302  Let's write a function we'll call ``GetAllAssets`` that enables the querying of the ledger to
   303  return all of the assets on the ledger.
   304  
   305  .. code:: go
   306  
   307    // GetAllAssets returns all assets found in world state
   308    func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {
   309      // range query with empty string for startKey and endKey does an
   310      // open-ended query of all assets in the chaincode namespace.
   311      resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
   312      if err != nil {
   313        return nil, err
   314      }
   315      defer resultsIterator.Close()
   316  
   317      var assets []*Asset
   318      for resultsIterator.HasNext() {
   319        queryResponse, err := resultsIterator.Next()
   320        if err != nil {
   321          return nil, err
   322        }
   323  
   324        var asset Asset
   325        err = json.Unmarshal(queryResponse.Value, &asset)
   326        if err != nil {
   327          return nil, err
   328        }
   329        assets = append(assets, &asset)
   330      }
   331  
   332      return assets, nil
   333    }
   334  
   335  .. _Chaincode Sample:
   336  
   337  
   338  .. Note:: The full chaincode sample below is presented as a way to
   339            to keep this tutorial as clear and straightforward as possible. In a
   340            real-world implementation, it is likely that packages will be segmented
   341            where a ``main`` package imports the chaincode package to allow for easy unit testing.
   342            To see what this looks like, see the asset-transfer `Go chaincode <https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic/chaincode-go>`__
   343            in fabric-samples. If you look at ``assetTransfer.go``, you will see that
   344            it contains ``package main`` and imports ``package chaincode`` defined in ``smartcontract.go`` and
   345            located at ``fabric-samples/asset-transfer-basic/chaincode-go/chaincode/``.
   346  
   347  
   348  
   349  Pulling it All Together
   350  ^^^^^^^^^^^^^^^^^^^^^^^
   351  
   352  Finally, we need to add the ``main`` function, which will call the
   353  `ContractChaincode.Start <https://godoc.org/github.com/hyperledger/fabric-contract-api-go/contractapi#ContractChaincode.Start>`_
   354  function. Here's the whole chaincode program source.
   355  
   356  .. code:: go
   357  
   358    package main
   359  
   360    import (
   361      "encoding/json"
   362      "fmt"
   363      "log"
   364  
   365      "github.com/hyperledger/fabric-contract-api-go/contractapi"
   366    )
   367  
   368    // SmartContract provides functions for managing an Asset
   369    type SmartContract struct {
   370      contractapi.Contract
   371    }
   372  
   373    // Asset describes basic details of what makes up a simple asset
   374    type Asset struct {
   375      ID             string `json:"ID"`
   376      Color          string `json:"color"`
   377      Size           int    `json:"size"`
   378      Owner          string `json:"owner"`
   379      AppraisedValue int    `json:"appraisedValue"`
   380    }
   381  
   382    // InitLedger adds a base set of assets to the ledger
   383    func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
   384      assets := []Asset{
   385        {ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300},
   386        {ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400},
   387        {ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500},
   388        {ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600},
   389        {ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700},
   390        {ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800},
   391      }
   392  
   393      for _, asset := range assets {
   394        assetJSON, err := json.Marshal(asset)
   395        if err != nil {
   396          return err
   397        }
   398  
   399        err = ctx.GetStub().PutState(asset.ID, assetJSON)
   400        if err != nil {
   401          return fmt.Errorf("failed to put to world state. %v", err)
   402        }
   403      }
   404  
   405      return nil
   406    }
   407  
   408    // CreateAsset issues a new asset to the world state with given details.
   409    func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
   410      exists, err := s.AssetExists(ctx, id)
   411      if err != nil {
   412        return err
   413      }
   414      if exists {
   415        return fmt.Errorf("the asset %s already exists", id)
   416      }
   417  
   418      asset := Asset{
   419        ID:             id,
   420        Color:          color,
   421        Size:           size,
   422        Owner:          owner,
   423        AppraisedValue: appraisedValue,
   424      }
   425      assetJSON, err := json.Marshal(asset)
   426      if err != nil {
   427        return err
   428      }
   429  
   430      return ctx.GetStub().PutState(id, assetJSON)
   431    }
   432  
   433    // ReadAsset returns the asset stored in the world state with given id.
   434    func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {
   435      assetJSON, err := ctx.GetStub().GetState(id)
   436      if err != nil {
   437        return nil, fmt.Errorf("failed to read from world state: %v", err)
   438      }
   439      if assetJSON == nil {
   440        return nil, fmt.Errorf("the asset %s does not exist", id)
   441      }
   442  
   443      var asset Asset
   444      err = json.Unmarshal(assetJSON, &asset)
   445      if err != nil {
   446        return nil, err
   447      }
   448  
   449      return &asset, nil
   450    }
   451  
   452    // UpdateAsset updates an existing asset in the world state with provided parameters.
   453    func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
   454      exists, err := s.AssetExists(ctx, id)
   455      if err != nil {
   456        return err
   457      }
   458      if !exists {
   459        return fmt.Errorf("the asset %s does not exist", id)
   460      }
   461  
   462      // overwriting original asset with new asset
   463      asset := Asset{
   464        ID:             id,
   465        Color:          color,
   466        Size:           size,
   467        Owner:          owner,
   468        AppraisedValue: appraisedValue,
   469      }
   470      assetJSON, err := json.Marshal(asset)
   471      if err != nil {
   472        return err
   473      }
   474  
   475      return ctx.GetStub().PutState(id, assetJSON)
   476    }
   477  
   478    // DeleteAsset deletes an given asset from the world state.
   479    func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {
   480      exists, err := s.AssetExists(ctx, id)
   481      if err != nil {
   482        return err
   483      }
   484      if !exists {
   485        return fmt.Errorf("the asset %s does not exist", id)
   486      }
   487  
   488      return ctx.GetStub().DelState(id)
   489    }
   490  
   491    // AssetExists returns true when asset with given ID exists in world state
   492    func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
   493      assetJSON, err := ctx.GetStub().GetState(id)
   494      if err != nil {
   495        return false, fmt.Errorf("failed to read from world state: %v", err)
   496      }
   497  
   498      return assetJSON != nil, nil
   499    }
   500  
   501    // TransferAsset updates the owner field of asset with given id in world state.
   502    func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error {
   503      asset, err := s.ReadAsset(ctx, id)
   504      if err != nil {
   505        return err
   506      }
   507  
   508      asset.Owner = newOwner
   509      assetJSON, err := json.Marshal(asset)
   510      if err != nil {
   511        return err
   512      }
   513  
   514      return ctx.GetStub().PutState(id, assetJSON)
   515    }
   516  
   517    // GetAllAssets returns all assets found in world state
   518    func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {
   519      // range query with empty string for startKey and endKey does an
   520      // open-ended query of all assets in the chaincode namespace.
   521      resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
   522      if err != nil {
   523        return nil, err
   524      }
   525      defer resultsIterator.Close()
   526  
   527      var assets []*Asset
   528      for resultsIterator.HasNext() {
   529        queryResponse, err := resultsIterator.Next()
   530        if err != nil {
   531          return nil, err
   532        }
   533  
   534        var asset Asset
   535        err = json.Unmarshal(queryResponse.Value, &asset)
   536        if err != nil {
   537          return nil, err
   538        }
   539        assets = append(assets, &asset)
   540      }
   541  
   542      return assets, nil
   543    }
   544  
   545    func main() {
   546      assetChaincode, err := contractapi.NewChaincode(&SmartContract{})
   547      if err != nil {
   548        log.Panicf("Error creating asset-transfer-basic chaincode: %v", err)
   549      }
   550  
   551      if err := assetChaincode.Start(); err != nil {
   552        log.Panicf("Error starting asset-transfer-basic chaincode: %v", err)
   553      }
   554    }
   555  
   556  Chaincode access control
   557  ------------------------
   558  
   559  Chaincode can utilize the client (submitter) certificate for access
   560  control decisions with ``ctx.GetStub().GetCreator()``. Additionally
   561  the Fabric Contract API provides extension APIs that extract client identity
   562  from the submitter's certificate that can be used for access control decisions,
   563  whether that is based on client identity itself, or the org identity,
   564  or on a client identity attribute.
   565  
   566  For example an asset that is represented as a key/value may include the
   567  client's identity as part of the value (for example as a JSON attribute
   568  indicating that asset owner), and only this client may be authorized
   569  to make updates to the key/value in the future. The client identity
   570  library extension APIs can be used within chaincode to retrieve this
   571  submitter information to make such access control decisions.
   572  
   573  
   574  .. _vendoring:
   575  
   576  Managing external dependencies for chaincode written in Go
   577  ----------------------------------------------------------
   578  Your Go chaincode depends on Go packages (like the chaincode shim) that are not
   579  part of the standard library. The source to these packages must be included in
   580  your chaincode package when it is installed to a peer. If you have structured
   581  your chaincode as a module, the easiest way to do this is to "vendor" the
   582  dependencies with ``go mod vendor`` before packaging your chaincode.
   583  
   584  .. code:: bash
   585  
   586    go mod tidy
   587    go mod vendor
   588  
   589  This places the external dependencies for your chaincode into a local ``vendor``
   590  directory.
   591  
   592  Once dependencies are vendored in your chaincode directory, ``peer chaincode package``
   593  and ``peer chaincode install`` operations will then include code associated with the
   594  dependencies into the chaincode package.
   595  
   596  JSON determinism
   597  ----------------
   598  Being able to predictably handle data formats is critical, and also the ability to search the data held within the blockchain.
   599  
   600  Technical Problem
   601  ^^^^^^^^^^^^^^^^^
   602  The format of the data that is stored in Fabric is at the discretion of the user. 
   603  The lowest level API accepts a byte array and stores that - what this represents is not a concern to Fabric.
   604  The important thing is when simulating transactions, given the same inputs chaincode gives the same byte array.
   605  Otherwise, the endorsements may not all match and the transaction will either not be submitted or will be invalidated.
   606  
   607  JSON is often used as the data format to store data on the ledger, and is required if using CouchDB queries.
   608  
   609  JSON though is not a deterministic data format - the order of elements can change,
   610  whilst still representing the same data semantically. The challenge, therefore, is to be able to generate a consistent set of JSON.
   611  
   612  A solution
   613  ^^^^^^^^^^
   614  Generate a consistent set of ``JSON`` across multiple languages.
   615  Each language have different features and libraries that you can use to convert an object to JSON.
   616  The best approach to achieve determinism across different languages is to choose a canonical way as a common guideline to format JSON.
   617  In order to get a consistent hash across languages you can format JSON in alphabetic order.
   618  
   619  Golang
   620  ^^^^^^
   621  In Golang the ``encoding/json`` package is utilized to serialise a Struct Object into JSON.
   622  More specifically the ``Marshal`` function is used, the latter marshals maps in sorted key order and keeps structs in the order that the fields are declared.
   623  Since structs are marshaled in field declaration order, follow alphabetic order when defining a new structure.
   624  
   625  Node.js
   626  ^^^^^^^
   627  In Javascript, when serialising object into JSON, the function ``JSON.stringify()`` is commonly used.
   628  However, to achieve consistent results, a deterministic version of JSON.stringify() is needed; in this way it is possible to get a consistent hash from stringified results.
   629  ``json-stringify-deterministic`` is a good library to do so and can be used combined with ``sort-keys-recursive`` to attain alphabetic order too. 
   630  `Here <https://www.npmjs.com/package/json-stringify-deterministic>`_ for a more in-depth tutorial.
   631  
   632  Java
   633  ^^^^
   634  Java provides several libraries to serialize an object into a JSON string. However not all of them provide consistency and ordering.
   635  The ``Gson`` library, for example, does not provide any consistency and should therefore be avoided for this application. On the other hand,
   636  the ``Genson`` library is a good fit for our purpose as it produces consistent JSON in alphabetic oreder.
   637  
   638  You can find a good exemplification of this practise on the `asset-transfer-basic <https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic>`_ chaincodes.
   639  
   640  .. Note:: 
   641          This is only one of the many approaches which we think can be effective.
   642          When serialising you can utilise various methods to achieve consistency; nevertheless,
   643          considering the different characteristics of the programming languages used in Fabric,
   644          the alphabetic approach represents an easy and efficient solution to the problem.
   645          In conclusion, feel free to employ a different method if it best suites your needs.
   646          P.S. Don’t forget to let us know in the comments if you used a different approach.
   647  
   648  .. Licensed under Creative Commons Attribution 4.0 International License
   649     https://creativecommons.org/licenses/by/4.0/